mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-08 17:31:56 -10:00
shell-redesign V1 pre-release CLI/daemon Item 1 fix: project ConfigStore rotation tunables into daemon launch env
Closes the production-reachability gap where transcripts.lines and
transcripts.poll_interval_seconds were resident in ConfigStore +
SETTINGS_VALID_KEYS but never reached the spawned daemon process. The
rotation hook only consulted shell env vars, so
`rig config set transcripts.lines 500` followed by `rig daemon
restart` had no observable effect on the rotation cadence.
Wire-up:
- StartOptions (cli/daemon-lifecycle.ts) extends with optional
transcriptsLines + transcriptsPollIntervalSeconds.
- buildDaemonEnv emits OPENRIG_TRANSCRIPTS_LINES and
OPENRIG_TRANSCRIPTS_POLL_INTERVAL_SECONDS only when the opts are
defined; explicit opts override any inherited base-env value, same
shape as the existing OPENRIG_PORT / OPENRIG_DB / OPENRIG_TRANSCRIPTS_*
override pattern.
- The `rig daemon start` command path reads
config.transcripts.lines and config.transcripts.pollIntervalSeconds
from the resolved ConfigStore and threads them through startDaemon
→ buildDaemonEnv → daemon process env, where
getTranscriptRotationOptionsFromEnv inside the rotation module
picks them up at session-start.
Tests:
- 3 new buildDaemonEnv unit tests:
- emits OPENRIG_TRANSCRIPTS_LINES + OPENRIG_TRANSCRIPTS_POLL_INTERVAL_SECONDS
when opts provided.
- omits both env vars when opts undefined (rotation falls back to
its own defaults).
- explicit opts override inherited OPENRIG_TRANSCRIPTS_* from base
env (file-stored ConfigStore wins over stale shell vars).
- 1 new ConfigStore roundtrip test:
ConfigStore.set('transcripts.lines', '500') +
set('transcripts.poll_interval_seconds', '5') → resolve() returns
500 / 5 (proves the file-stored values reach the daemon-launch
read site).
- VALID_KEYS exhaustive-list test refreshed to include the 2 V1
pre-release keys plus the previously-stale Phase 4 / Phase 5
additions, matching the equivalent fix in the daemon settings-
store test.
Verification:
- npx tsc --noEmit on packages/cli/tsconfig.json: clean
- npx vitest run daemon-lifecycle + config-store-extended: 85/85 PASS
SC-29 EXCEPTION #4 scope unchanged: the env-var emission path is the
existing OPENRIG_TRANSCRIPTS_* mechanism, just with two more allowed
keys.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
a7a34ca1ed
commit
5270545432
4 files changed
+102
-2
No files matched your search
@@ -112,6 +112,13 @@ export function daemonCommand(depsOverride?: LifecycleDeps): Command {
|
||||
db: opts.db ?? config.db.path,
|
||||
transcriptsEnabled: config.transcripts.enabled,
|
||||
transcriptsPath: config.transcripts.path,
|
||||
// V1 pre-release CLI/daemon Item 1 — project the
|
||||
// ConfigStore-resolved rotation tunables into the daemon
|
||||
// process env so file-stored values
|
||||
// (`rig config set transcripts.lines 500`) actually
|
||||
// reach the rotation hook.
|
||||
transcriptsLines: config.transcripts.lines,
|
||||
transcriptsPollIntervalSeconds: config.transcripts.pollIntervalSeconds,
|
||||
},
|
||||
getDeps(),
|
||||
);
|
||||
|
||||
@@ -31,6 +31,11 @@ export interface StartOptions {
|
||||
db?: string;
|
||||
transcriptsEnabled?: boolean;
|
||||
transcriptsPath?: string;
|
||||
// V1 pre-release CLI/daemon Item 1 — capture-pane rotation tunables.
|
||||
// Threaded through to the daemon process env so the rotation hook
|
||||
// picks up file-stored ConfigStore values, not just shell env.
|
||||
transcriptsLines?: number;
|
||||
transcriptsPollIntervalSeconds?: number;
|
||||
}
|
||||
|
||||
export interface LifecycleDeps {
|
||||
@@ -193,7 +198,18 @@ const ENV_SCRUB_EXACT = new Set([
|
||||
|
||||
export function buildDaemonEnv(
|
||||
baseEnv: Record<string, string>,
|
||||
opts: { port: number; host: string; db: string; transcriptsEnabled?: boolean; transcriptsPath?: string },
|
||||
opts: {
|
||||
port: number;
|
||||
host: string;
|
||||
db: string;
|
||||
transcriptsEnabled?: boolean;
|
||||
transcriptsPath?: string;
|
||||
// V1 pre-release CLI/daemon Item 1 — projected from ConfigStore so
|
||||
// the rotation hook honors file-stored values, not just inherited
|
||||
// shell env.
|
||||
transcriptsLines?: number;
|
||||
transcriptsPollIntervalSeconds?: number;
|
||||
},
|
||||
): Record<string, string> {
|
||||
const env: Record<string, string> = {};
|
||||
|
||||
@@ -213,6 +229,12 @@ export function buildDaemonEnv(
|
||||
if (opts.transcriptsPath) {
|
||||
env["OPENRIG_TRANSCRIPTS_PATH"] = opts.transcriptsPath;
|
||||
}
|
||||
if (opts.transcriptsLines !== undefined) {
|
||||
env["OPENRIG_TRANSCRIPTS_LINES"] = String(opts.transcriptsLines);
|
||||
}
|
||||
if (opts.transcriptsPollIntervalSeconds !== undefined) {
|
||||
env["OPENRIG_TRANSCRIPTS_POLL_INTERVAL_SECONDS"] = String(opts.transcriptsPollIntervalSeconds);
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
@@ -261,6 +283,8 @@ export async function startDaemon(opts: StartOptions, deps: LifecycleDeps): Prom
|
||||
db,
|
||||
transcriptsEnabled: opts.transcriptsEnabled,
|
||||
transcriptsPath: opts.transcriptsPath,
|
||||
transcriptsLines: opts.transcriptsLines,
|
||||
transcriptsPollIntervalSeconds: opts.transcriptsPollIntervalSeconds,
|
||||
}),
|
||||
stdio: ["ignore", logFd, logFd],
|
||||
detached: true,
|
||||
|
||||
@@ -68,20 +68,45 @@ describe("ConfigStore — extended namespaces (User Settings v0)", () => {
|
||||
restoreEnv();
|
||||
});
|
||||
|
||||
it("VALID_KEYS includes legacy, user-settings, ui.preview, and recovery keys", () => {
|
||||
it("VALID_KEYS includes legacy, user-settings, ui.preview, recovery, agents, feed, and transcript-rotation keys", () => {
|
||||
const expected = [
|
||||
"daemon.port", "daemon.host", "db.path",
|
||||
"transcripts.enabled", "transcripts.path",
|
||||
// V1 pre-release CLI/daemon Item 1 — capture-pane rotation tunables.
|
||||
"transcripts.lines", "transcripts.poll_interval_seconds",
|
||||
"workspace.root", "workspace.slices_root", "workspace.steering_path",
|
||||
"workspace.field_notes_root", "workspace.specs_root",
|
||||
"files.allowlist", "progress.scan_roots",
|
||||
"ui.preview.refresh_interval_seconds", "ui.preview.max_pins", "ui.preview.default_lines",
|
||||
"recovery.auto_drive_provider_prompts",
|
||||
"recovery.provider_auth_env_allowlist",
|
||||
// V1 attempt-3 Phase 4 — Advisor/Operator placeholders.
|
||||
"agents.advisor_session", "agents.operator_session",
|
||||
// V1 attempt-3 Phase 5 P5-3 — For You feed subscription toggles.
|
||||
"feed.subscriptions.action_required",
|
||||
"feed.subscriptions.approvals",
|
||||
"feed.subscriptions.shipped",
|
||||
"feed.subscriptions.progress",
|
||||
"feed.subscriptions.audit_log",
|
||||
];
|
||||
expect([...VALID_KEYS]).toEqual(expected);
|
||||
});
|
||||
|
||||
it("transcripts.lines + transcripts.poll_interval_seconds roundtrip — set → resolve reflects file-stored values for daemon launch projection", () => {
|
||||
const store = new ConfigStore(configPath);
|
||||
// Defaults BEFORE set.
|
||||
const before = store.resolve();
|
||||
expect(before.transcripts.lines).toBe(1000);
|
||||
expect(before.transcripts.pollIntervalSeconds).toBe(2);
|
||||
|
||||
store.set("transcripts.lines", "500");
|
||||
store.set("transcripts.poll_interval_seconds", "5");
|
||||
|
||||
const after = store.resolve();
|
||||
expect(after.transcripts.lines).toBe(500);
|
||||
expect(after.transcripts.pollIntervalSeconds).toBe(5);
|
||||
});
|
||||
|
||||
it("legacy 5-key behavior preserved: get/set/reset still work", () => {
|
||||
const store = new ConfigStore(configPath);
|
||||
store.set("daemon.port", "9999");
|
||||
|
||||
@@ -917,4 +917,48 @@ describe("buildDaemonEnv", () => {
|
||||
expect(result["OPENRIG_PORT"]).toBe("7433");
|
||||
expect(result["OPENRIG_DB"]).toBe("/new/path.db");
|
||||
});
|
||||
|
||||
describe("V1 pre-release CLI/daemon Item 1 — transcript rotation tunables projection", () => {
|
||||
it("projects transcriptsLines + transcriptsPollIntervalSeconds into OPENRIG_* env vars when provided", () => {
|
||||
const baseEnv: Record<string, string> = { HOME: "/Users/tester", PATH: "/usr/bin" };
|
||||
const result = buildDaemonEnv(baseEnv, {
|
||||
port: 7433,
|
||||
host: "127.0.0.1",
|
||||
db: "/tmp/test.db",
|
||||
transcriptsLines: 500,
|
||||
transcriptsPollIntervalSeconds: 5,
|
||||
});
|
||||
expect(result["OPENRIG_TRANSCRIPTS_LINES"]).toBe("500");
|
||||
expect(result["OPENRIG_TRANSCRIPTS_POLL_INTERVAL_SECONDS"]).toBe("5");
|
||||
});
|
||||
|
||||
it("omits the transcript rotation env vars when the opts are undefined so the rotation hook falls back to its own defaults", () => {
|
||||
const baseEnv: Record<string, string> = { HOME: "/Users/tester", PATH: "/usr/bin" };
|
||||
const result = buildDaemonEnv(baseEnv, {
|
||||
port: 7433,
|
||||
host: "127.0.0.1",
|
||||
db: "/tmp/test.db",
|
||||
});
|
||||
expect(result["OPENRIG_TRANSCRIPTS_LINES"]).toBeUndefined();
|
||||
expect(result["OPENRIG_TRANSCRIPTS_POLL_INTERVAL_SECONDS"]).toBeUndefined();
|
||||
});
|
||||
|
||||
it("scrubs inherited OPENRIG_TRANSCRIPTS_* from the base env when opts override is set, so the daemon honors the file-stored ConfigStore value", () => {
|
||||
const baseEnv: Record<string, string> = {
|
||||
HOME: "/Users/tester",
|
||||
PATH: "/usr/bin",
|
||||
OPENRIG_TRANSCRIPTS_LINES: "9999",
|
||||
OPENRIG_TRANSCRIPTS_POLL_INTERVAL_SECONDS: "60",
|
||||
};
|
||||
const result = buildDaemonEnv(baseEnv, {
|
||||
port: 7433,
|
||||
host: "127.0.0.1",
|
||||
db: "/tmp/test.db",
|
||||
transcriptsLines: 500,
|
||||
transcriptsPollIntervalSeconds: 5,
|
||||
});
|
||||
expect(result["OPENRIG_TRANSCRIPTS_LINES"]).toBe("500");
|
||||
expect(result["OPENRIG_TRANSCRIPTS_POLL_INTERVAL_SECONDS"]).toBe("5");
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user