* refactor: tighten sdk-first architecture seams
Refs #3312
* refactor: finish state document seam cleanup
Refs #3312
* test: harden minimal install cleanup assertion
* ci: support sdk-scoped package lock
* fix(3316): restore root package-lock.json and align changeset pr ref
Reverts dec57a83 ("ci: support sdk-scoped package lock") and restores
the root package-lock.json that c249d34d deleted. The deletion was the
wrong direction:
- The root package.json declares its own runtime and dev deps
(@anthropic-ai/claude-agent-sdk, ws, c8). Without a root lockfile,
`npm install --no-package-lock` resolves whatever satisfies semver at
install time — CI today and CI in six months can install different
transitive trees, defeating reproducibility.
- The lockfile has been part of every release on this repo (long
history on main); removing it loses the npm audit / Dependabot
target without compensating benefit.
- The CI workaround pattern (cache-dependency-path: sdk/package-lock.json
+ `npm install --no-package-lock`) papered over the symptom rather
than fix the cause.
Also fix the changeset pr: from 3312 (issue) to 3316 (PR). CONTEXT.md
flags this exact failure mode as a recurring CodeRabbit finding.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address coderabbit review findings
* fix: close remaining coderabbit threads
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(#2618): thread --ws through query dispatch for state and init handlers
Gap 1 of #2618: the query dispatcher already accepts a workstream via
registry.dispatch(cmd, args, projectDir, ws), but several handlers drop it
before reaching planningPaths() / getMilestoneInfo() / findPhase() — so
stateJson and the init.* handlers return root-scoped results even when --ws
is provided.
Changes:
- sdk/src/query/state.ts: forward workstream into getMilestoneInfo() and
extractCurrentMilestone() so buildStateFrontmatter resolves milestone data
from the workstream ROADMAP/STATE instead of the root mirror.
- sdk/src/query/init.ts: thread workstream through initExecutePhase,
initPlanPhase, initPhaseOp, and getPhaseInfoWithFallback (which fans out
to findPhase() and roadmapGetPhase()). Also switch hardcoded
join(projectDir, '.planning') to relPlanningPath(workstream) so returned
state_path/roadmap_path/config_path reflect the workstream layout.
Regression test: stateJson with --ws workstream reads STATE.md from
.planning/workstreams/<name>/ when workstream is provided.
Closes#2618 (gap 1)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(#2618): sync root .planning/STATE.md mirror on workstream.set
Gap 2 of #2618: setActiveWorkstream only flips the active-workstream
pointer file; the root .planning/STATE.md mirror stays stale. Downstream
consumers (statusline, gsd-sdk query progress, any tool that reads the
root STATE.md) continue to see the previous workstream's state.
After setActiveWorkstream(), copy .planning/workstreams/<name>/STATE.md
verbatim to .planning/STATE.md via writeFileSync. The workstream STATE.md
is authoritative; the root file is a pass-through mirror. Missing source
STATE.md is a no-op rather than an error — a freshly created workstream
with no STATE.md yet should still activate cleanly.
The response now includes `mirror_synced: boolean` so callers can
observe whether the root mirror was updated.
Regression test: workstreamSet root STATE.md mirror sync — switches
from a stale root mirror to a workstream STATE.md with different
frontmatter and asserts the root file now matches.
Closes#2618 (gap 2)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>