diff --git a/src/web/routes/session-routes.ts b/src/web/routes/session-routes.ts index b52ae759..7174d2d8 100644 --- a/src/web/routes/session-routes.ts +++ b/src/web/routes/session-routes.ts @@ -298,14 +298,18 @@ export function registerSessionRoutes( } // Plan-usage statusLine exporter (App Settings → Display → "Plan Usage - // Limits"). Claude-only. Runs for ANY working dir — including linked cases / - // real repos, which is where most sessions actually run — mirroring - // updateCaseModel above (which likewise writes settings.local.json - // unconditionally). Safe against a user's own statusLine: applyStatusLineConfig - // only ever removes a statusLine that is OURS (marker-guarded), and adds/removes - // ours so toggling the setting off cleans up on the next create. - if ((body.mode ?? 'claude') === 'claude') { - await applyStatusLineConfig(workingDir, body.statusLineTelemetry === true); + // Limits"). Claude-only; runs for ANY working dir (linked cases / real repos, + // where most sessions live), mirroring updateCaseModel above. + // + // ADD-ONLY: we never remove on create. Sessions in a repo share one + // settings.local.json, so a single create-with-false (e.g. a client whose + // synced setting hadn't loaded yet) must NOT yank the statusLine out from + // under other live sessions in that repo — that breaks their footer + the + // chip's data feed for everyone. The exporter is benign when the chip is off + // (the footer just shows session status). isOurs-guarded so a user's own + // statusLine is never touched. + if ((body.mode ?? 'claude') === 'claude' && body.statusLineTelemetry === true) { + await applyStatusLineConfig(workingDir, true); } // Check OpenCode availability if requested diff --git a/src/web/routes/system-routes.ts b/src/web/routes/system-routes.ts index 0c2f6379..033d2063 100644 --- a/src/web/routes/system-routes.ts +++ b/src/web/routes/system-routes.ts @@ -26,6 +26,7 @@ import { } from '../schemas.js'; import { subagentWatcher } from '../../subagent-watcher.js'; import { imageWatcher } from '../../image-watcher.js'; +import { applyStatusLineConfig } from '../../hooks-config.js'; import { getLifecycleLog } from '../../session-lifecycle-log.js'; import { findSessionOrFail, @@ -546,6 +547,21 @@ export function registerSystemRoutes( } }); + // Plan-usage chip (App Settings → Display → "Plan Usage Limits"): reconcile + // the statusLine exporter across all ACTIVE Claude sessions' working dirs the + // moment the setting is toggled — server-side and authoritative, so it works + // immediately for every user/session without depending on any client's synced + // state or on creating a new session. Enable injects; disable removes (ours + // only, marker-guarded). Each dir handled once. + if ('showPlanUsageLimits' in settings) { + const enabled = settings.showPlanUsageLimits === true; + const dirs = new Set(); + for (const session of ctx.sessions.values()) { + if (session.mode === 'claude' && session.workingDir) dirs.add(session.workingDir); + } + await Promise.all([...dirs].map((dir) => applyStatusLineConfig(dir, enabled).catch(() => {}))); + } + // Handle tunnel toggle dynamically if ('tunnelEnabled' in settings) { const tunnelEnabled = settings.tunnelEnabled as boolean;