fix(usage): make plan-usage chip work for every user, not just on enable

Two changes so the feature works for any user the moment they enable it,
without manual steps or per-client state:

- Reconcile on settings change: PUT /api/settings now applies the statusLine
  exporter across all ACTIVE Claude sessions' working dirs when
  showPlanUsageLimits is toggled (inject on enable, remove on disable). This is
  server-side and authoritative, so existing sessions get the footer + feed the
  chip immediately — no need to create a new session, no dependency on a
  browser's synced localStorage.

- Create is now ADD-ONLY: never remove the statusLine on session 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) was yanking the statusLine
  out from under all other live sessions in that repo, killing their footer and
  the chip's data feed. Removal now happens only via the explicit settings toggle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arkon
2026-06-14 06:00:30 +02:00
co-authored by Claude Opus 4.8
parent 4d9d93dfff
commit eae225bf9a
2 changed files with 28 additions and 8 deletions
+12 -8
View File
@@ -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
+16
View File
@@ -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<string>();
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;