From 1026c762a9aa850b288c53eee16c52d3600dcf80 Mon Sep 17 00:00:00 2001 From: Croissant Le Doux Date: Fri, 10 Jul 2026 16:09:59 -0400 Subject: [PATCH] De-mock Settings + empty Capture braindump + resolve connection status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More static mocks found by poking the live app: - Settings was ~80% mock: a fake Sync card (webhook endpoint :48731, poll fallback, 'last reconcile 3.2s · 500 issues'), a fake dual-model 'router' (gemma-4b/qwen-72b with hardcoded URLs), and an unwired Rituals card. Replaced with honest/live content: the Sync card now describes the real on-demand reconcile + stale-cache model; the Model card shows the actual probed model from model.status(); dropped Rituals and the duplicate 'Forget' button. - Settings showed 'Not connected' while the app was clearly connected: config:get returned only the *saved* config, so a .env.local/env connection read as null. It now falls back to a public view of the resolved connection — Settings and the rail host label reflect the real christian/commitea connection. - Capture braindump was pre-filled with a fake example ('auth is flaky…'); now starts empty with just the placeholder. Verified live: Settings shows christian/commitea connected + google/gemma-4-26b reachable; Capture empty; a live Reginald chat turn runs the agent loop. desktop tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/desktop/src/main/gitea.ts | 18 +- .../src/components/screens/capture-screen.tsx | 5 +- .../components/screens/settings-screen.tsx | 167 +++++++++--------- 3 files changed, 106 insertions(+), 84 deletions(-) diff --git a/apps/desktop/src/main/gitea.ts b/apps/desktop/src/main/gitea.ts index d75b37b..f66216c 100644 --- a/apps/desktop/src/main/gitea.ts +++ b/apps/desktop/src/main/gitea.ts @@ -365,7 +365,23 @@ export function registerGiteaIpc(): void { }) // ---- config (team onboarding) ---- - ipcMain.handle('config:get', () => publicConfig()) + // The saved config's public view, or — when running off a .env.local / env + // fallback (dev) — a public view of the *resolved* connection, so Settings and + // the rail reflect what the app is actually connected to, not just the store. + ipcMain.handle('config:get', () => { + const saved = publicConfig() + if (saved) return saved + const c = resolveConfig() + if (!c) return null + return { + baseUrl: c.baseUrl, + owner: c.owner, + repo: c.repo, + pmStateRepo: pmStateRepoName(c), + modelUrl: process.env.MODEL_BASE_URL ?? undefined, + hasToken: !!c.token, + } + }) ipcMain.handle('config:set', (_event, cfg: AppConfig) => { saveConfig(cfg) diff --git a/apps/desktop/src/renderer/src/components/screens/capture-screen.tsx b/apps/desktop/src/renderer/src/components/screens/capture-screen.tsx index 9ac3229..d80eecb 100644 --- a/apps/desktop/src/renderer/src/components/screens/capture-screen.tsx +++ b/apps/desktop/src/renderer/src/components/screens/capture-screen.tsx @@ -24,10 +24,7 @@ interface Question { export function CaptureScreen({ onDone }: { onDone: () => void }) { const [stage, setStage] = React.useState<'dump' | 'interview' | 'review' | 'filed'>('dump') - const [dump, setDump] = React.useState( - 'auth is flaky — token refresh dies silently, sometimes session storage goes stale. ' + - 'also the webhook debounce thing keeps double-firing. and we owe docs for auth setup' - ) + const [dump, setDump] = React.useState('') const [qi, setQi] = React.useState(0) const [log, setLog] = React.useState<{ q: string; a: string }[]>([]) const [split, setSplit] = React.useState(null) diff --git a/apps/desktop/src/renderer/src/components/screens/settings-screen.tsx b/apps/desktop/src/renderer/src/components/screens/settings-screen.tsx index b0a1545..5f2e32d 100644 --- a/apps/desktop/src/renderer/src/components/screens/settings-screen.tsx +++ b/apps/desktop/src/renderer/src/components/screens/settings-screen.tsx @@ -1,9 +1,9 @@ import React from 'react' import type { PublicConfig } from '../../global.js' -import { Badge, Button, Card, Icon, IconButton, Input, Radio, Select, Switch, Tag } from '../ui/index.js' +import { Badge, Button, Card, Icon, Radio, Tag } from '../ui/index.js' -// Settings — gitea connection, sync, model roles, labels, rituals, appearance +// Settings — gitea connection, sync behaviour, model, label schema, appearance. export function SettingsScreen({ dark, setDark, @@ -17,10 +17,20 @@ export function SettingsScreen({ onReconnect?: () => void onDisconnect?: () => void }) { - const [webhooks, setWebhooks] = React.useState(true) - const [reconcile, setReconcile] = React.useState(true) - const [poll, setPoll] = React.useState(true) - const [nag, setNag] = React.useState(true) + const [model, setModel] = React.useState<{ configured: boolean; model: string | null } | null>(null) + + React.useEffect(() => { + let alive = true + window.commitea.model + .status() + .then((s) => { + if (alive) setModel(s) + }) + .catch(() => {}) + return () => { + alive = false + } + }, []) const Row = ({ children, style }: { children: React.ReactNode; style?: React.CSSProperties }) => (
{children}
@@ -33,128 +43,127 @@ export function SettingsScreen({

Settings

-

config lives in pm-state · versioned, portable

+

+ connection lives on this machine · the plan lives in gitea +

{connection ? ( <> - + - {connection.owner}/{connection.repo} - connected + + {connection.owner}/{connection.repo} + + + connected + - {connection.baseUrl} + + {connection.baseUrl} - sidecar: {connection.pmStateRepo ?? `${connection.repo}-pm-state`} - - - model: {connection.modelUrl ?? 'not set — chat off'} + + sidecar: {connection.pmStateRepo ?? `${connection.repo}-pm-state`} Your token is stored encrypted on this machine. Delete the sidecar and resync — no truth is lost. - - + + ) : ( Not connected. - + )}
-
- - setWebhooks(e.target.checked)} /> - endpoint :48731 · healthy +
+ + + + Reconciles on launch and after every write + - setReconcile(e.target.checked)} /> - - setPoll(e.target.checked)} /> -
- - - -
- - hot memory ≤ 2k tokens · math is never delegated to either - -

- The small one writes my standup; the large one argues with your estimates. Neither is allowed near the arithmetic. -

+ +
+ {model?.configured ? ( + + + {model.model} + + reachable + + + ) : ( + + + + Chat is off — no model reachable. + + + + )} + + An OpenAI-compatible endpoint (set it in Reconfigure). Reginald names, negotiates and explains; it never + does the arithmetic — the scheduler and Monte Carlo do that. +
- {['est/1d', 'est/2d', 'est/3d', 'est/5d', 'est/8d'].map((l) => )} + {['est/1d', 'est/2d', 'est/3d', 'est/5d', 'est/8d'].map((l) => ( + + ))} - {['p/1', 'p/2', 'p/3', 'p/4'].map((l) => )} + {['p/1', 'p/2', 'p/3', 'p/4'].map((l) => ( + + ))} Fixed sets, human-meaningful, visible in gitea. Not configurable — that is rather the point.
- -
- - Morning standup -
- -
-
-
-
-
setDark(false)} /> setDark(true)} />
- - - -
-
Forget this gitea
- Removes the connection and the local cache. Gitea itself is untouched. -
- -
-
) }