mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 07:29:42 +02:00
fix(statusline): sticky telemetry collection, footer print-through, EOF fix
Responds to Ark0N's review round on the ephemeral-CLI-flag statusline injection rework: - Rebase-detail fixes: registry-gated telemetry eligibility via getCli(mode)?.capabilities.statusLineTelemetry instead of a hardcoded mode === 'claude' check, using the capability flag master's CLI-registry refactor already declares for exactly this purpose. - Design question settled: sticky (a). Rather than persisting the toggle as a new field and threading it through every session-creation path (cron, Ralph Loop API, quick-start), eliminated the per-session field entirely. readPlanUsageTelemetryEnabled() (hooks-config.ts) reads the existing showPlanUsageLimits setting fresh from settings.json at every claude create/respawn (TmuxManager.createSession/respawnPane) - no per-session state to survive a restart, and it applies uniformly to every creation path for free, since they all flow through the same TmuxManager methods. This required fixing a real bug found along the way: showPlanUsageLimits was not actually round-tripping through settings.json on save - settings-ui.js explicitly excluded it from the PUT body as a pure per-device display key. It now flows through normally (both true and false); the load-side per-device merge behavior is unchanged. Removed entirely as a result: the statusLineTelemetry field from CreateSessionSchema/SettingsUpdateSchema, CreateSessionOptions/ RespawnPaneOptions, Session._statusLineTelemetry (this is what makes the restart-persistence bug moot rather than patched), and the frontend send sites. - Footer print-through restored: the no-user-statusline branch of the exporter script now runs the telemetry POST in the foreground so its own stdout becomes the in-terminal footer, falling back to a plain "codeman" marker only on curl failure. - Background-subshell EOF fix: the wrap-a-real-statusline branch closes stdin too, not just stdout/stderr (`>/dev/null 2>&1 </dev/null &`) - the un-redirected subshell process itself, not curl, was what held a reader-to-EOF's pipe open for however long curl took to finish. Added curl --max-time 5 so a hung (not just refused) Codeman cannot wedge the render. Tests: real-shell-execution tests for the footer/EOF fixes (fake curl stand-in on PATH, real sh subprocess spawns, real elapsed-time measurements - verified non-vacuous against a hand-reconstructed old-style script), unit tests for readPlanUsageTelemetryEnabled. Adapted two existing tests whose payloads referenced the removed field. Fixed during independent code review: a stray indentation break and a test exercising the wrong (legacy) exporter code path. Docs synced: CLAUDE.md, docs/usage-limits-display-plan.md (old disk-based section marked superseded, kept for history), docs/architecture-invariants.md. Full suite green: 352 files, 6780 passed, 12 skipped, 0 failed. tsc/lint/format:check/frontend-syntax all clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e15e8e43e8
commit
d5b75af628
@@ -156,7 +156,7 @@ describe('POST /api/sessions workspace hooks', () => {
|
||||
const cwdSettings = join(process.cwd(), '.claude', 'settings.local.json');
|
||||
const before = existsSync(cwdSettings) ? await readFile(cwdSettings, 'utf-8') : null;
|
||||
|
||||
const res = await createSession({ name: 'hooks-no-dir', mode: 'claude', statusLineTelemetry: true });
|
||||
const res = await createSession({ name: 'hooks-no-dir', mode: 'claude' });
|
||||
expect(res.statusCode).toBe(200);
|
||||
|
||||
const after = existsSync(cwdSettings) ? await readFile(cwdSettings, 'utf-8') : null;
|
||||
@@ -166,8 +166,9 @@ describe('POST /api/sessions workspace hooks', () => {
|
||||
it('never writes hooks for a remote attach (workingDir is a user@host pseudo-path)', async () => {
|
||||
// A claude-mode attachRemoteSession create overwrites workingDir with
|
||||
// `user@host:session` — locally a RELATIVE path, so a mkdir would create it
|
||||
// as a junk directory under the server cwd. statusLineTelemetry rides along:
|
||||
// applyStatusLineConfig mkdirs the same way and used to run for remote attaches.
|
||||
// as a junk directory under the server cwd. The statusLine exporter rides
|
||||
// along: applyStatusLineConfig mkdirs the same way and used to run for
|
||||
// remote attaches.
|
||||
// SAFETY (2026-08-29): write straight to `getDataDir()` — `test/setup.ts`
|
||||
// already sandboxes the data dir for the whole file (temp HOME, inherited
|
||||
// CODEMAN_DATA_DIR stripped; same convention as the docker-hosts fixtures
|
||||
@@ -188,7 +189,6 @@ describe('POST /api/sessions workspace hooks', () => {
|
||||
const res = await createSession({
|
||||
name: 'hooks-remote',
|
||||
mode: 'claude',
|
||||
statusLineTelemetry: true,
|
||||
attachRemoteSession: { hostId: 'h1', remoteSessionName: 'codeman-ssh-abc123' },
|
||||
});
|
||||
expect(res.statusCode).toBe(200);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* The three service toggles (subagent watcher, workflow-run watcher, image
|
||||
* watcher) used to read the RAW REQUEST BODY with `??` defaults, so any key the
|
||||
* caller omitted was treated as "apply the default". A body of just
|
||||
* `{statusLineTelemetry:true}` therefore STARTED the subagent watcher (`?? true`)
|
||||
* `{showPlanUsageLimits:true}` therefore STARTED the subagent watcher (`?? true`)
|
||||
* and STOPPED the workflow + image watchers (`?? false`), silently undoing the
|
||||
* persisted config. Nothing triggered it in practice only because every shipped
|
||||
* client sends a full settings payload rebuilt from the DOM.
|
||||
@@ -91,8 +91,8 @@ describe('PUT /api/settings — partial body must not reset service toggles', ()
|
||||
const res = await harness.app.inject({
|
||||
method: 'PUT',
|
||||
url: '/api/settings',
|
||||
// Action-only body: the exact shape that used to flip all three watchers.
|
||||
payload: { statusLineTelemetry: true },
|
||||
// Minimal single-key body: the exact shape that used to flip all three watchers.
|
||||
payload: { showPlanUsageLimits: true },
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
|
||||
Reference in New Issue
Block a user