Cache provider status and gate desktop startup#1962
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Non-atomic ref update causes concurrent provider data loss
- Replaced the non-atomic Ref.get/Ref.set sequence in upsertProviders with a single atomic Ref.modify call that performs the read-merge-write in one step, preventing concurrent fibers from overwriting each other's updates.
- ✅ Fixed: Options spread can override internal abort signal
- Reversed the spread order in the object literal so that
...optionscomes beforesignal: controller.signal, ensuring the internal abort signal always takes precedence.
- Reversed the spread order in the object literal so that
Or push these changes by commenting:
@cursor push 1963e414b1
Preview (1963e414b1)
diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts
--- a/apps/desktop/src/main.ts
+++ b/apps/desktop/src/main.ts
@@ -365,8 +365,8 @@
try {
await waitForHttpReady(baseUrl, {
+ ...options,
signal: controller.signal,
- ...options,
});
} finally {
if (backendReadinessAbortController === controller) {
diff --git a/apps/server/src/provider/Layers/ProviderRegistry.ts b/apps/server/src/provider/Layers/ProviderRegistry.ts
--- a/apps/server/src/provider/Layers/ProviderRegistry.ts
+++ b/apps/server/src/provider/Layers/ProviderRegistry.ts
@@ -108,17 +108,21 @@
readonly publish?: boolean;
},
) {
- const previousProviders = yield* Ref.get(providersRef);
- const mergedProviders = new Map(
- previousProviders.map((provider) => [provider.provider, provider] as const),
- );
+ const [previousProviders, providers] = yield* Ref.modify(
+ providersRef,
+ (previousProviders) => {
+ const mergedProviders = new Map(
+ previousProviders.map((provider) => [provider.provider, provider] as const),
+ );
- for (const provider of nextProviders) {
- mergedProviders.set(provider.provider, provider);
- }
+ for (const provider of nextProviders) {
+ mergedProviders.set(provider.provider, provider);
+ }
- const providers = orderProviderSnapshots([...mergedProviders.values()]);
- yield* Ref.set(providersRef, providers);
+ const providers = orderProviderSnapshots([...mergedProviders.values()]);
+ return [[previousProviders, providers] as const, providers];
+ },
+ );
if (haveProvidersChanged(previousProviders, providers)) {
yield* Effect.forEach(nextProviders, persistProvider, {You can send follow-ups to the cloud agent here.
ApprovabilityVerdict: Needs human review This PR introduces significant behavioral changes to desktop startup gating and provider status caching. The changes affect when the main window appears and how provider status is initialized, with a noted race condition on first run where providers may appear empty until background refresh completes. You can customize Macroscope's approvability policy. Learn more. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Refresh with publish:false silently suppresses provider status updates
- Removed
{ publish: false }from allsyncProvidercalls insiderefresh, so the refresh path now publishes tochangesPubSubwhen providers change, allowing WebSocket clients to receive updated provider statuses.
- Removed
Or push these changes by commenting:
@cursor push b58d42d5d6
Preview (b58d42d5d6)
diff --git a/apps/server/src/provider/Layers/ProviderRegistry.ts b/apps/server/src/provider/Layers/ProviderRegistry.ts
--- a/apps/server/src/provider/Layers/ProviderRegistry.ts
+++ b/apps/server/src/provider/Layers/ProviderRegistry.ts
@@ -150,20 +150,20 @@
switch (provider) {
case "codex":
return yield* codexProvider.refresh.pipe(
- Effect.flatMap((nextProvider) => syncProvider(nextProvider, { publish: false })),
+ Effect.flatMap((nextProvider) => syncProvider(nextProvider)),
);
case "claudeAgent":
return yield* claudeProvider.refresh.pipe(
- Effect.flatMap((nextProvider) => syncProvider(nextProvider, { publish: false })),
+ Effect.flatMap((nextProvider) => syncProvider(nextProvider)),
);
default:
return yield* Effect.all(
[
codexProvider.refresh.pipe(
- Effect.flatMap((nextProvider) => syncProvider(nextProvider, { publish: false })),
+ Effect.flatMap((nextProvider) => syncProvider(nextProvider)),
),
claudeProvider.refresh.pipe(
- Effect.flatMap((nextProvider) => syncProvider(nextProvider, { publish: false })),
+ Effect.flatMap((nextProvider) => syncProvider(nextProvider)),
),
],
{You can send follow-ups to the cloud agent here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: No window created when backend readiness times out
- Replaced the catch handler's log-only behavior with a call to handleFatalStartupError so the user sees an error dialog and the app quits gracefully instead of running invisibly.
- ✅ Fixed: Primary environment skips config subscription and provider refresh
- Added kind === "primary" to the config subscription condition so primary environments subscribe to subscribeServerConfig and trigger the provider refresh immediately.
Or push these changes by commenting:
@cursor push c5c27df020
Preview (c5c27df020)
diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts
--- a/apps/desktop/src/main.ts
+++ b/apps/desktop/src/main.ts
@@ -448,10 +448,7 @@
if (isBackendReadinessAborted(error)) {
return;
}
- writeDesktopLogHeader(
- `bootstrap backend readiness warning message=${formatErrorMessage(error)}`,
- );
- console.warn("[desktop] backend readiness check timed out during packaged bootstrap", error);
+ handleFatalStartupError("backend-readiness", error);
})
.finally(() => {
if (backendInitialWindowOpenInFlight === nextOpen) {
diff --git a/apps/web/src/environments/runtime/connection.ts b/apps/web/src/environments/runtime/connection.ts
--- a/apps/web/src/environments/runtime/connection.ts
+++ b/apps/web/src/environments/runtime/connection.ts
@@ -264,7 +264,7 @@
);
const unsubConfig =
- input.kind === "saved" || input.onConfigSnapshot
+ input.kind === "saved" || input.kind === "primary" || input.onConfigSnapshot
? input.client.server.subscribeConfig(
(event: Parameters<Parameters<WsRpcClient["server"]["subscribeConfig"]>[0]>[0]) => {
if (event.type !== "snapshot") {You can send follow-ups to the cloud agent here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Duplicate pending provider factory functions across providers
- Extracted a shared
makePendingProviderSnapshothelper inproviderSnapshot.tsparameterized by provider name, display name, built-in models, custom models, default capabilities, and enabled flag, then replaced bothmakePendingClaudeProviderandmakePendingCodexProviderwith one-liner calls to it.
- Extracted a shared
Or push these changes by commenting:
@cursor push 94bcdd9864
Preview (94bcdd9864)
diff --git a/apps/server/src/provider/Layers/ClaudeProvider.ts b/apps/server/src/provider/Layers/ClaudeProvider.ts
--- a/apps/server/src/provider/Layers/ClaudeProvider.ts
+++ b/apps/server/src/provider/Layers/ClaudeProvider.ts
@@ -21,6 +21,7 @@
detailFromResult,
extractAuthBoolean,
isCommandMissingCause,
+ makePendingProviderSnapshot,
parseGenericCliVersion,
providerModelsFromSettings,
spawnAndCollect,
@@ -663,45 +664,15 @@
});
});
-const makePendingClaudeProvider = (claudeSettings: ClaudeSettings): ServerProvider => {
- const checkedAt = new Date().toISOString();
- const models = providerModelsFromSettings(
- BUILT_IN_MODELS,
- PROVIDER,
- claudeSettings.customModels,
- DEFAULT_CLAUDE_MODEL_CAPABILITIES,
- );
-
- if (!claudeSettings.enabled) {
- return buildServerProvider({
- provider: PROVIDER,
- enabled: false,
- checkedAt,
- models,
- probe: {
- installed: false,
- version: null,
- status: "warning",
- auth: { status: "unknown" },
- message: "Claude is disabled in T3 Code settings.",
- },
- });
- }
-
- return buildServerProvider({
+const makePendingClaudeProvider = (claudeSettings: ClaudeSettings): ServerProvider =>
+ makePendingProviderSnapshot({
provider: PROVIDER,
- enabled: true,
- checkedAt,
- models,
- probe: {
- installed: false,
- version: null,
- status: "warning",
- auth: { status: "unknown" },
- message: "Claude provider status has not been checked in this session yet.",
- },
+ displayName: "Claude",
+ builtInModels: BUILT_IN_MODELS,
+ customModels: claudeSettings.customModels,
+ defaultCapabilities: DEFAULT_CLAUDE_MODEL_CAPABILITIES,
+ enabled: claudeSettings.enabled,
});
-};
export const ClaudeProviderLive = Layer.effect(
ClaudeProvider,
diff --git a/apps/server/src/provider/Layers/CodexProvider.ts b/apps/server/src/provider/Layers/CodexProvider.ts
--- a/apps/server/src/provider/Layers/CodexProvider.ts
+++ b/apps/server/src/provider/Layers/CodexProvider.ts
@@ -28,6 +28,7 @@
detailFromResult,
extractAuthBoolean,
isCommandMissingCause,
+ makePendingProviderSnapshot,
parseGenericCliVersion,
providerModelsFromSettings,
spawnAndCollect,
@@ -552,45 +553,15 @@
});
});
-const makePendingCodexProvider = (codexSettings: CodexSettings): ServerProvider => {
- const checkedAt = new Date().toISOString();
- const models = providerModelsFromSettings(
- BUILT_IN_MODELS,
- PROVIDER,
- codexSettings.customModels,
- DEFAULT_CODEX_MODEL_CAPABILITIES,
- );
-
- if (!codexSettings.enabled) {
- return buildServerProvider({
- provider: PROVIDER,
- enabled: false,
- checkedAt,
- models,
- probe: {
- installed: false,
- version: null,
- status: "warning",
- auth: { status: "unknown" },
- message: "Codex is disabled in T3 Code settings.",
- },
- });
- }
-
- return buildServerProvider({
+const makePendingCodexProvider = (codexSettings: CodexSettings): ServerProvider =>
+ makePendingProviderSnapshot({
provider: PROVIDER,
- enabled: true,
- checkedAt,
- models,
- probe: {
- installed: false,
- version: null,
- status: "warning",
- auth: { status: "unknown" },
- message: "Codex provider status has not been checked in this session yet.",
- },
+ displayName: "Codex",
+ builtInModels: BUILT_IN_MODELS,
+ customModels: codexSettings.customModels,
+ defaultCapabilities: DEFAULT_CODEX_MODEL_CAPABILITIES,
+ enabled: codexSettings.enabled,
});
-};
export const CodexProviderLive = Layer.effect(
CodexProvider,
diff --git a/apps/server/src/provider/providerSnapshot.ts b/apps/server/src/provider/providerSnapshot.ts
--- a/apps/server/src/provider/providerSnapshot.ts
+++ b/apps/server/src/provider/providerSnapshot.ts
@@ -151,6 +151,53 @@
};
}
+export function makePendingProviderSnapshot(input: {
+ provider: ServerProvider["provider"];
+ displayName: string;
+ builtInModels: ReadonlyArray<ServerProviderModel>;
+ customModels: ReadonlyArray<string>;
+ defaultCapabilities: ModelCapabilities;
+ enabled: boolean;
+}): ServerProvider {
+ const checkedAt = new Date().toISOString();
+ const models = providerModelsFromSettings(
+ input.builtInModels,
+ input.provider,
+ input.customModels,
+ input.defaultCapabilities,
+ );
+
+ if (!input.enabled) {
+ return buildServerProvider({
+ provider: input.provider,
+ enabled: false,
+ checkedAt,
+ models,
+ probe: {
+ installed: false,
+ version: null,
+ status: "warning",
+ auth: { status: "unknown" },
+ message: `${input.displayName} is disabled in T3 Code settings.`,
+ },
+ });
+ }
+
+ return buildServerProvider({
+ provider: input.provider,
+ enabled: true,
+ checkedAt,
+ models,
+ probe: {
+ installed: false,
+ version: null,
+ status: "warning",
+ auth: { status: "unknown" },
+ message: `${input.displayName} provider status has not been checked in this session yet.`,
+ },
+ });
+}
+
export const collectStreamAsString = <E>(
stream: Stream.Stream<Uint8Array, E>,
): Effect.Effect<string, E> =>You can send follow-ups to the cloud agent here.
| message: "Claude provider status has not been checked in this session yet.", | ||
| }, | ||
| }); | ||
| }; |
There was a problem hiding this comment.
Duplicate pending provider factory functions across providers
Low Severity
makePendingClaudeProvider and makePendingCodexProvider have nearly identical structure: compute checkedAt, derive models from settings, and return a buildServerProvider call with the same shape — differing only in the provider constant, settings type, built-in models, capabilities, and message strings. This duplication could be extracted into a shared helper parameterized by those values.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7f6ff53. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Debug console.log statements left in production files
- Removed all three debug console.log statements from index.html (line 12) and main.tsx (lines 1 and 32) that were logging startup timestamps to the browser console.
Or push these changes by commenting:
@cursor push dc8cb2f5b3
Preview (dc8cb2f5b3)
diff --git a/apps/web/index.html b/apps/web/index.html
--- a/apps/web/index.html
+++ b/apps/web/index.html
@@ -9,9 +9,6 @@
<link rel="icon" href="/favicon.ico" sizes="48x48" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<script>
- console.log("index.html loaded at", new Date().toISOString());
- </script>
- <script>
(() => {
const LIGHT_BACKGROUND = "#ffffff";
const DARK_BACKGROUND = "#161616";
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx
--- a/apps/web/src/main.tsx
+++ b/apps/web/src/main.tsx
@@ -1,5 +1,3 @@
-console.log("main.tsx loaded at", new Date().toISOString());
-
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "@tanstack/react-router";
@@ -28,5 +26,3 @@
<RouterProvider router={router} />
</React.StrictMode>,
);
-
-console.log("main.tsx rendered at", new Date().toISOString());You can send follow-ups to the cloud agent here.
- Persist provider snapshots between sessions - Open the packaged desktop window when the backend is listening or HTTP-ready
- ProviderRegistry: Use Ref.modify for atomic read-modify-write in upsertProviders to prevent concurrent provider data loss when multiple fibers update providersRef simultaneously. - Desktop main: Reorder spread in waitForBackendHttpReady so the internal abort controller signal always takes precedence over any signal passed via options. Applied via @cursor push command
…ch WebSocket clients Applied via @cursor push command
- Keep the desktop window hidden until it is ready to show - Log static client requests with request type, source, and duration - Mirror backend output to console in development
Co-authored-by: codex <codex@users.noreply.github.com>
f6ca1f1 to
a0b1d06
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 4 total unresolved issues (including 2 from previous reviews).
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Measurement script checks for HTML that no longer exists
- Changed the check from
body.includes('<div id="root"></div>')tobody.includes('<div id="root">')so it matches the root div even when it contains splash screen content.
- Changed the check from
- ✅ Fixed: Console.log timestamps committed to production HTML and entry
- Removed all three
console.logtimestamp calls fromindex.htmlandmain.tsxthat were debug instrumentation not intended for production.
- Removed all three
Or push these changes by commenting:
@cursor push e62c107eef
Preview (e62c107eef)
diff --git a/apps/web/index.html b/apps/web/index.html
--- a/apps/web/index.html
+++ b/apps/web/index.html
@@ -9,9 +9,6 @@
<link rel="icon" href="/favicon.ico" sizes="48x48" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<script>
- console.log("index.html loaded at", new Date().toISOString());
- </script>
- <script>
(() => {
const LIGHT_BACKGROUND = "#ffffff";
const DARK_BACKGROUND = "#161616";
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx
--- a/apps/web/src/main.tsx
+++ b/apps/web/src/main.tsx
@@ -1,5 +1,3 @@
-console.log("main.tsx loaded at", new Date().toISOString());
-
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "@tanstack/react-router";
@@ -28,5 +26,3 @@
<RouterProvider router={router} />
</React.StrictMode>,
);
-
-console.log("main.tsx rendered at", new Date().toISOString());
diff --git a/scripts/measure-react-startup.ts b/scripts/measure-react-startup.ts
--- a/scripts/measure-react-startup.ts
+++ b/scripts/measure-react-startup.ts
@@ -159,7 +159,7 @@
const body = await response.text();
if (
response.ok &&
- body.includes('<div id="root"></div>') &&
+ body.includes('<div id="root">') &&
body.includes('<script type="module"')
) {
return {You can send follow-ups to the cloud agent here.
| ); | ||
| const providersRef = yield* Ref.make<ReadonlyArray<ServerProvider>>(cachedProviders); |
There was a problem hiding this comment.
🟢 Low Layers/ProviderRegistry.ts:91
On first run without cache files, getProviders returns an empty array because cachedProviders filters out all undefined values from missing cache files, and fallbackProviders is never used to seed the initial state. This creates a race where callers receive empty results until the background stream handlers emit provider updates. Consider initializing providersRef with fallbackProviders when no cached providers exist.
const providersRef = yield* Ref.make<ReadonlyArray<ServerProvider>>(cachedProviders);🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/server/src/provider/Layers/ProviderRegistry.ts around lines 91-92:
On first run without cache files, `getProviders` returns an empty array because `cachedProviders` filters out all `undefined` values from missing cache files, and `fallbackProviders` is never used to seed the initial state. This creates a race where callers receive empty results until the background stream handlers emit provider updates. Consider initializing `providersRef` with `fallbackProviders` when no cached providers exist.
Evidence trail:
apps/server/src/provider/Layers/ProviderRegistry.ts lines 50-83 (fallbackProviders loaded but only used in hydrateCachedProvider when cache exists), lines 72-75 (returns undefined when cachedProvider is undefined instead of using fallbackProvider), lines 78-80 (filters out undefined values), line 83 (providersRef initialized with potentially empty cachedProviders), line 151 (getProviders returns Ref.get(providersRef))
apps/server/src/provider/providerStatusCache.ts lines 54-58 (readProviderStatusCache returns undefined when file doesn't exist)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Activate handler silently no-ops in development mode
- Added an explicit isDevelopment check in the activate handler that calls createWindow() directly, bypassing ensureInitialBackendWindowOpen() which has an early return guard for development mode.
Or push these changes by commenting:
@cursor push 28c13607db
Preview (28c13607db)
diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts
--- a/apps/desktop/src/main.ts
+++ b/apps/desktop/src/main.ts
@@ -2022,6 +2022,10 @@
revealWindow(existingWindow);
return;
}
+ if (isDevelopment) {
+ mainWindow = createWindow();
+ return;
+ }
ensureInitialBackendWindowOpen();
});
})You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit a2f6ad2. Configure here.
ensureInitialBackendWindowOpen() has an early return when isDevelopment is true, which is correct for the initial bootstrap path but prevents window creation when the macOS dock icon is clicked after all windows are closed. Handle development mode explicitly in the activate handler by calling createWindow() directly. Applied via @cursor push command
Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: codex <codex@users.noreply.github.com>
Integrates upstream/main (d22c6f5) into the fork while preserving all multi-provider support (codex, claudeAgent, copilot, cursor, opencode, geminiCli, amp, kilo) and fork UI/UX additions. Highlights adopted from upstream: - Nightly release channel + update channel selector (pingdotgg#2012, pingdotgg#2049, pingdotgg#1969) - Filesystem browse API + command palette project picker (pingdotgg#2024) - Launch Args setting for Claude provider (pingdotgg#1971) - Kiro editor support in open picker (pingdotgg#1974) - Claude plan events for TodoWrite during input streaming (pingdotgg#1541) - Lost provider session recovery (pingdotgg#1938) - Cache provider status and gate desktop startup (pingdotgg#1962) - LegendList migration for chat scrolling and branch lists (pingdotgg#1953) - Shell snapshot queries + backfill migration (pingdotgg#1973, pingdotgg#2004) - PATH hydration + fallback detection (pingdotgg#1799) - Warm sidebar thread subscriptions (pingdotgg#2001) - Full thread title tooltip (pingdotgg#1994) - Markdown file link UX (pingdotgg#1956), composer polish (pingdotgg#1944, pingdotgg#1992, pingdotgg#1985) - Worktree/branch state + draft reuse fixes (pingdotgg#2005, pingdotgg#2003, pingdotgg#1995, pingdotgg#1936) - Window controls overlay for Windows/Linux (pingdotgg#1969) - Backend readiness timeout 10s→30s (pingdotgg#1979) - Clear tracked RPCs on reconnect, live stream subscriptions (pingdotgg#2000, pingdotgg#1972) - Various misc fixes (pingdotgg#2051, pingdotgg#2052, pingdotgg#2025, pingdotgg#2027, pingdotgg#2049, pingdotgg#1997, pingdotgg#1975) Fork features preserved and reconciled: - All 8 provider adapters + conformance tests - Extended ProviderKind union across contracts/model/settings/provider - appearance/accentColor/themeConfig/ProviderLogo UI system - customModels + gitTextGeneration + providerModelOptions - Migration IDs 23 (NormalizeLegacyProviderKinds) and 24 (RepairProjectionThreadProposedPlanImplementationColumns) kept; new upstream migrations registered at IDs 25-26 to avoid breaking deployed fork databases - DesktopBridge: log directory channels (LOG_DIR/LIST/READ/OPEN_DIR) retained; getWsUrl replaced by upstream's getAppBranding - PROVIDER_CACHE_IDS extended to all 8 providers



Summary
Testing
bun fmtbun lintbun typecheckbun run testNote
Medium Risk
Changes desktop startup sequencing and backend readiness detection, plus adds on-disk caching for provider status; regressions could delay window creation or show stale/incorrect provider states if cache/hydration logic is wrong.
Overview
Improves perceived startup readiness for both desktop and server provider status. Desktop now delays creating/showing the packaged main window until the backend is either detected as listening via log output or becomes HTTP-ready, instead of unconditionally polling a fixed endpoint.
Provider health snapshots (Codex/Claude) are now persisted to disk and rehydrated on startup, while managed providers start from a settings-derived pending snapshot and only probe on explicit
refresh/streams. WebsocketsubscribeServerConfignow triggers a background refresh on subscription and debouncesproviderStatusesevents (200ms), which also changes initial snapshots to potentially start with an emptyproviderslist until refresh completes.Reviewed by Cursor Bugbot for commit 46c5eed. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Cache provider status and gate desktop window creation on backend readiness
providerStatusCacheDir, so the UI can show last-known provider status without waiting for health probes.BrowserWindowis now created only after the backend signals readiness — either via aListening on http://log line (serverListeningDetector.ts) or HTTP probe — with a 60s timeout.waitForHttpReadynow accepts a configurable path and predicate instead of probing the hardcoded/api/auth/sessionendpoint.welcomeevent immediately at startup; if auto-bootstrap is enabled, a secondwelcomewith project/thread IDs follows once resolved.ready-to-show; packaged builds load the backend URL directly rather than going throughresolveDesktopWindowUrl.Macroscope summarized 46c5eed.