Follow-up to #5. The test infrastructure (vitest) and a seed spec now exist — see src/core/settings.spec.ts for the established pattern (co-located *.spec.ts, bare it/expect globals, a throwaway temp dir via mkdtempSync(tmpdir()) in beforeEach/afterEach). This issue covers the delicate core of #5: the init settings.json patching contract.
Scope
src/commands/init.ts (+ backup in src/core/settings.ts). Drive cmdInit against a temp HOME / temp dir so no test ever touches a real ~/.claude.
Cases to cover
- Fresh install writes the executable script + a
statusLine block into settings.json.
- Idempotent re-run: re-running with the same target produces no duplicate and reports
confirmed; a settings.json.bak backup is created when the file already existed.
- Preserves unrelated keys already present in
settings.json (merge only the statusLine key).
- Conflict without
--force (a different statusLine present): refuses, exits 1, writes nothing.
- Conflict with
--force: replaces the block.
- Invalid JSON: refuses to overwrite, prints the manual block, exits
1 (pairs with the already-covered readSettings → data: null).
--dry-run writes nothing (no script, no settings, no backup).
- Exit codes:
0 on success, 1 on every refusal path (process.exitCode).
Notes
SCRIPT_SOURCE resolves relative to the built CLI; point the copy at a fixture or the repo's tokenline.sh so the temp-dir test is hermetic.
- Follow the seed spec's temp-dir + cleanup pattern; keep it dependency-light and synchronous.
Acceptance
pnpm test stays green locally and in CI.
- The cases above are covered.
Follow-up to #5. The test infrastructure (vitest) and a seed spec now exist — see
src/core/settings.spec.tsfor the established pattern (co-located*.spec.ts, bareit/expectglobals, a throwaway temp dir viamkdtempSync(tmpdir())inbeforeEach/afterEach). This issue covers the delicate core of #5: theinitsettings.json patching contract.Scope
src/commands/init.ts(+backupinsrc/core/settings.ts). DrivecmdInitagainst a tempHOME/ temp dir so no test ever touches a real~/.claude.Cases to cover
statusLineblock intosettings.json.confirmed; asettings.json.bakbackup is created when the file already existed.settings.json(merge only thestatusLinekey).--force(a differentstatusLinepresent): refuses, exits1, writes nothing.--force: replaces the block.1(pairs with the already-coveredreadSettings→data: null).--dry-runwrites nothing (no script, no settings, no backup).0on success,1on every refusal path (process.exitCode).Notes
SCRIPT_SOURCEresolves relative to the built CLI; point the copy at a fixture or the repo'stokenline.shso the temp-dir test is hermetic.Acceptance
pnpm teststays green locally and in CI.