mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 06:59:42 +02:00
fix(statusline): inject plan-usage telemetry via ephemeral CLI flag, never disk
Codeman's plan-usage chip wrote a statusLine.command into the case's
.claude/settings.local.json to receive Claude Code's rate_limits blob.
That file-based statusLine took precedence over the user's own
global/project statusline for ANY `claude` run in that directory,
including entirely outside Codeman, with no disclosure in the App
Settings UI (labeled only as a header-display toggle) and no way to
remove it once written (the removal code path was unreachable dead
code — nothing ever called it with false).
Replace the disk write with an EPHEMERAL `claude --settings
'{"statusLine":{...}}'` CLI flag, resolved fresh at spawn time
(resolveStatusLineCliCommand in hooks-config.ts) and merged with
effort/ultracode into one --settings object (buildClaudeSettingsFlag
in tmux-manager.ts, since Claude Code accepts only one --settings
flag). Never touches disk, so a plain `claude` run outside Codeman is
untouched. Self-healing: any legacy disk-written exporter from an
older build is stripped the first time a session starts in that
workspace again. Still respects a user's own hand-authored statusLine
(skips the flag entirely rather than overriding it).
Mid-fix bug found and fixed: the exporter's command legitimately
depends on $CODEMAN_SESSION_ID/$CODEMAN_API_URL/$CODEMAN_HOOK_SECRET_FILE
and an internal $INPUT, all meant to be expanded only when Claude Code
itself executes the statusline, using the pane's tmux-setenv'd
environment. Passing that text through --settings routed it through
execSync's own implicit /bin/sh -c first (tmux respawn-pane's
`bash -c "..."` wrapper) — POSIX double quotes don't suppress $
expansion, so those vars got expanded prematurely against the
server's own environment (unset there), producing malformed JSON that
printed as literal error text in the statusline. Fixed by writing the
exporter as a real, shared script file (ensureStatusLineExporterScript,
marker-versioned so stale copies self-heal) and passing only its bare
path via --settings — nothing for any intermediate shell to mangle.
Verified against a real Claude CLI on an isolated tmux socket, and via
direct execSync reproduction of the exact nested wrapping
createSession/respawnPane use.
A hard "never inject, even ephemerally" kill-switch was added and then
removed in the same pass: with the disk-leak fixed, disabling
injection only cost the plan-usage telemetry the feature exists to
provide, for no remaining benefit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GyMnFWnUzc41TDeHg9juW
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a164c07f92
commit
d4aa3c8cca
@@ -67,6 +67,7 @@ import {
|
||||
legacyConfigForMode,
|
||||
} from './session-cli-registry-bridge.js';
|
||||
import type { CliEntry } from './config/cli-registry/types.js';
|
||||
import { resolveStatusLineCliCommand } from './hooks-config.js';
|
||||
import {
|
||||
buildSshConnectionArgs,
|
||||
defaultRemoteCommandForMode,
|
||||
@@ -661,6 +662,8 @@ export function buildSpawnCommand(options: {
|
||||
ompConfig?: OmpConfig;
|
||||
resumeSessionId?: string;
|
||||
effort?: EffortLevel;
|
||||
/** Resolved by resolveStatusLineCliCommand (hooks-config.ts) — undefined skips the exporter. Claude only. */
|
||||
statusLineCommand?: string;
|
||||
/** Codeman session name, passed to claude as `--name` (version-gated, sanitized; local spawns only). */
|
||||
sessionName?: string;
|
||||
/**
|
||||
@@ -1729,6 +1732,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
resumeSessionId,
|
||||
envOverrides,
|
||||
effort,
|
||||
statusLineTelemetry,
|
||||
historyLimit = DEFAULT_TMUX_HISTORY_LIMIT,
|
||||
remote,
|
||||
docker,
|
||||
@@ -1787,6 +1791,15 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
|
||||
const envExportsStr = this.buildEnvExports(sessionId, muxName, mode).join(' && ');
|
||||
|
||||
// Claude-only, local spawns only (remote/docker have their own separate
|
||||
// command builders — out of scope here). Also self-heals: strips any
|
||||
// legacy disk-written exporter from an older Codeman build the first
|
||||
// time a session starts in that workspace again.
|
||||
const statusLineCommand =
|
||||
mode === 'claude' && !remote && !docker
|
||||
? await resolveStatusLineCliCommand(workingDir, statusLineTelemetry === true)
|
||||
: undefined;
|
||||
|
||||
const baseCmd = buildSpawnCommand({
|
||||
mode,
|
||||
sessionId,
|
||||
@@ -1803,6 +1816,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
ompConfig,
|
||||
resumeSessionId,
|
||||
effort,
|
||||
statusLineCommand,
|
||||
sessionName: name,
|
||||
});
|
||||
|
||||
@@ -2027,6 +2041,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
resumeSessionId,
|
||||
envOverrides,
|
||||
effort,
|
||||
statusLineTelemetry,
|
||||
remote,
|
||||
docker,
|
||||
name,
|
||||
@@ -2042,6 +2057,12 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
|
||||
const envExportsStr = this.buildEnvExports(sessionId, muxName, mode).join(' && ');
|
||||
|
||||
// See createSession()'s identical resolution for rationale.
|
||||
const statusLineCommand =
|
||||
mode === 'claude' && !remote && !docker
|
||||
? await resolveStatusLineCliCommand(workingDir, statusLineTelemetry === true)
|
||||
: undefined;
|
||||
|
||||
const baseCmd = buildSpawnCommand({
|
||||
mode,
|
||||
sessionId,
|
||||
@@ -2058,6 +2079,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
ompConfig,
|
||||
resumeSessionId,
|
||||
effort,
|
||||
statusLineCommand,
|
||||
sessionName: name,
|
||||
});
|
||||
const config = niceConfig || DEFAULT_NICE_CONFIG;
|
||||
|
||||
Reference in New Issue
Block a user