b533f71857ab96d1ccec3286294d669c60b0d0fc
26 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b533f71857 |
chore: introduce CommandRoutingHub and migrate phase-command-router (PoC) (#3828)
* feat(routing): add CommandRoutingHub with behavioral test suite (#3788) Introduces createHub({ mode, sdkLoader, cjsRegistry, manifest }) and hub.dispatch({ family, subcommand, args, cwd, raw }) -> Result with a closed 6-value ERROR_KINDS frozen enum. Hub never throws, never prints, and enforces no transparent fallback between sdk/cjs modes. 34 behavioral tests cover all errorKind values, mode fixation, and the no-throw contract. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(routing): migrate phase-command-router to CommandRoutingHub (#3788) Rewrites phase-command-router.cjs to dispatch through CommandRoutingHub. Public entry point routePhaseCommand({ phase, args, cwd, raw, error }) is unchanged. The adapter determines mode (sdk/cjs) from env + tryLoadSdk(), constructs a hub, dispatches, and translates the pure Result back to output()/error() calls. New behavioral test suite (23 tests) replaces the old mock-heavy approach and includes two integration tests through the real hub. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(routing): ADR + glossary + changeset for CommandRoutingHub (#3788) Adds ADR-3788 documenting the hub's design contract (pure result, fixed mode, closed 6-value errorKind enum, no transparent fallback). Adds Command Routing Hub glossary entry to CONTEXT.md and a one-paragraph reference to ARCHITECTURE.md. Changeset fragment records the Changed entry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(docs): rename ADR to sequential convention 0012 (#3788) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(inventory): register CommandRoutingHub in INVENTORY (#3788) Add command-routing-hub.cjs row to docs/INVENTORY.md CLI Modules table, bump headline count from 72 to 73, and regenerate INVENTORY-MANIFEST.json via scripts/gen-inventory-manifest.cjs --write. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(adr): add 0012 to ADR index (#3788) Add entry for 0012-command-routing-hub.md to the index table in docs/adr/README.md so the enh-3271-sdk-adr-structure lint passes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(lint): bump phase test-file ceiling to accommodate command-router suite (#3788) phase-command-router.test.cjs added by the CommandRoutingHub migration pushes the phase prefix cluster from 4 to 5 test files. Bump the allowlist ceiling from 4 to 5 (issue 3788) so lint-test-file-count passes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(routing): preserve phase.mvp-mode JSON error and ROADMAP scan through hub (#3788) mvp-mode was never registered in the SDK; the pre-#3788 CJS router always dispatched it via the CJS handler even when sdkAvailable was true. After the hub migration, SDK-mode hubs (Docker, where the SDK build exists) sent mvp-mode to the SDK bridge, which returned SdkDispatchFailed with reason 'unknown' instead of the expected 'usage' code, and failed ROADMAP lookups. Fix by short-circuiting mvp-mode to the CJS handler before hub construction, matching the pre-migration observable behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(adr): note SDK-incomplete subcommand limitation in ADR-0012 (#3788) * fix(inventory): bump CLI Modules headline to 74 after rebase onto main (#3788) Upstream added code-review-flags.cjs (72→73) at the same time our branch added command-routing-hub.cjs. After rebase both modules exist (74 total) but the headline stayed at 73; bump to 74. * fix(routing): remove dead mvp-mode handler from cjsRegistry (#3788) The cjsRegistry['phase']['mvp-mode'] handler (previously lines 65–68) was unreachable: the early-return bypass at line 56 intercepts mvp-mode before hub construction in CJS mode, and in SDK mode cjsRegistry is passed as undefined. Remove the dead handler; all 57 tests still pass. * docs(adr): correct router count in ADR-0012 (#3788) The context section cited "eight" routers including "frontmatter" but there is no frontmatter-command-router.cjs. The actual count is seven: phase, phases, roadmap, state, verify, validate, init. * fix(routing): guard missing subcommand + use ERROR_KINDS constant (#3788) Two fixes in phase-command-router.cjs: 1. Add early-return for missing subcommand before hub construction. Pre-#3788 the routeCjsCommandFamily fell through to error() for undefined args[1]; post-#3788 the hub's manifest check skips falsy subcommands, which would have sent bare 'phase' into SDK dispatch in SDK mode instead of the expected "Available: ..." error message. 2. Switch on ERROR_KINDS.UnknownCommand instead of bare 'UnknownCommand' string, per ADR-0012's closed-enum contract ("callers switch on ERROR_KINDS values, not bare string literals"). * docs(routing): fix factual errors in ARCHITECTURE, ADR-0012, changeset (#3788) Three corrections: 1. ARCHITECTURE.md: softened "All CJS command family routers dispatch through CommandRoutingHub" — only phase-command-router.cjs is migrated in this PR; remaining routers still use routeCjsCommandFamily and migrate in follow-up issues. 2. ADR-0012: corrected the SDK mvp-mode claim. The ADR said "the SDK has no equivalent entry" but sdk/src/query/command-static-catalog- domain.ts:104-105 registers phase.mvp-mode. The actual reason for the early-return bypass is divergent ROADMAP scan behaviour and error reason codes, not SDK absence. 3. .changeset/mellow-tigers-gather.md: corrected pr: 1 → pr: 3828. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
b8fa89b5b6 | fix(3663): address CodeRabbit surface/layout follow-ups | ||
|
|
fb2f251010 |
docs(3663): accept ADR-3660; add Phase 1 implementation status
Flip status from Proposed → Accepted and record the branch, implementation reference, and Phase 2 dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
3eb1fec1c9 |
docs(3660): ADR + CONTEXT.md entry for Runtime Artifact Layout Module (#3661)
* docs(3660): add Runtime Artifact Layout Module ADR + CONTEXT.md entry Records the architectural decision to add a Runtime Artifact Layout Module that owns per-runtime artifact placement (commands / agents / skills) as a typed seam. Closes the bug class behind #3659 where the Runtime Surface Module forgets artifact kinds the install/uninstall pipelines track. CONTEXT.md gains the new module entry directly after the Skill Surface Budget Module since the two seams compose. Pure docs — no code changes. Phase 1 implementation lands in a separate PR. Closes #3660 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(3660): fix ADR parity and clarify phase boundaries --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
e437ded6fc |
docs(3524): CJS↔SDK hard-seam ADR + phased PRD (#3529)
* docs(3524): propose CJS↔SDK hard-seam ADR + phased PRD Adds docs/adr/3524-cjs-sdk-hard-seam.md (Proposed) and docs/prd/3524-cjs-sdk-hard-seam.md (Reference) tracking #3524. Updates the ADR and PRD index READMEs. The ADR defines one canonical owner per responsibility across the CJS (bin/lib/*.cjs) and SDK (sdk/src/**/*.ts) sides, eliminating the recurring drift bug class (#1535, #1542, #2047, #2638, #2653, #2687, #2798, #3055, #3523). Three layers: shared data (sdk/shared/*.json), shared core logic (sdk/src/core/ → dual CJS+ESM build), thin adapters. Enforcement is layered: build-time grep, type-level contract test, mutation parity test, CODEOWNERS gate, in-file banner. The PRD phases the migration in five independently shippable steps — shared data first (closes constant drift), then config consolidation (closes #3523 class), then project-root + path projection, then state and verify handlers, then enforcement hardening + retrospective. * docs(3524): revise seam ADR + PRD after architecture review Architecture-review pass (via /improve-codebase-architecture) found seven deepening opportunities; this commit applies all of them. 1. Re-anchor on the existing generator precedent. The repo already has sdk/scripts/gen-command-aliases.ts emitting both .generated.ts and .generated.cjs from one TS source, with sdk/scripts/check-command-aliases-fresh.mjs as the CI freshness gate. The ADR's invented dual CJS+ESM bundler pipeline is dropped. Each Shared Module gets one generator script and one freshness check, modeled on that precedent. 2. Drop the generic sdk/src/core/ container. The canonical-owner table is now indexed by Module, using the CONTEXT.md domain vocabulary (STATE.md Document Module, Configuration Module, etc.) rather than file-path-based pseudo-modules. 3. Split the coarse "State management" row into three: the pure STATE.md Document Module (already a character-identical hand-synced pair — perfect Phase 1 target), the Planning Workspace Module (defer to ADR-0004), and per-side state I/O Adapters (legitimately differ sync vs async). 4. Defer to existing ADRs. Planning Path Projection (ADR-0006), Model Catalog (ADR-0003), Planning Workspace (ADR-0004), Dispatch Policy (ADR-0001), Shell Command Projection (ADR-0009 post-Phase 3-4 expansion which absorbed superseded ADR-0010). The stale ADR-0010 reference is fixed. 5. Define a Configuration Module entry in CONTEXT.md as a Phase 2 deliverable, with explicit Interface contract for loadConfig, normalizeLegacyKeys, mergeDefaults, migrateOnDisk. 6. Split the Workstream Inventory Module into a pure Builder (generated, shared) and per-side Reader Adapters (hand-authored, sync vs async). Same pattern generalizes to other paired Modules. 7. Match enforcement to existing scripts. Per-Module freshness checks (precedent: check-command-aliases-fresh.mjs), per-Module drift lints (precedent: lint-shell-command-projection-drift.cjs), and one hand-sync pair lint that blocks the #3523 anti-pattern at PR time. PRD phases reordered: STATE.md Document Module ships first as a proof of pattern (two identical files become one source plus one generated artifact). Configuration Module ships second, closing the #3523 class. Workstream Inventory Builder split third. Project-Root Resolution fourth. Enforcement and retrospective fifth. * docs(3524): expand scope — CJS router delegates to SDK runtime bridge User flagged that the original "Out of scope" list was my unilateral scoping call, not theirs. After review, the CJS router consolidation (formerly out-of-scope item #1) is brought into scope. ADR additions: - CJS Command Router Adapter Module row added to canonical-owner table. Existing Module (per CONTEXT.md) is amended so the per-family `handlers` map delegates to `QueryRuntimeBridge.execute()` in-process. Per-side CJS handler files for canonical families (state.cjs, verify.cjs, init.cjs, phase.cjs, etc.) shrink to delegates or are deleted. - Per-side I/O Adapter consequence updated to clarify the bridge preserves the in-process model. No subprocess hop is added. - "Out of scope" stripped of router item; CJS-only seam migration and verify-Module-first work remain out of scope. PRD additions: - New Phase 5: CJS Command Router Adapter delegates to SDK runtime bridge, family-by-family, with golden parity matrix per family gating each PR. - Old Phase 5 (enforcement) renumbered to Phase 6, expanded to cover Phase 5's parity matrix and runtime-bridge CODEOWNERS. - Open question #4 added for the synchronous-bridging mechanism (`deasync` vs `Atomics.wait` vs sync-handler refactor) — resolved in the Phase 5 spike before any family migration begins. - Open question #5 added for family migration order (recommended: smallest read-only family first). - Risks table expanded with three Phase 5 rows: bridging-mechanism uncertainty, observable-output regression, startup-time impact. - Done-when updated for six phases and five enforcement layers. Non-goals updated: CJS-only Module migration and verify-Module deepening remain out of scope. CJS CLI removal explicitly stays off the table — the external `gsd-tools` contract is preserved. * docs(3524): address CodeRabbit review * docs(3524): fix PRD issue reference markdown |
||
|
|
8b679959cc |
docs: adopt issue#-prefix naming for ADRs/PRDs to eliminate parallel-developer collisions (#3487)
* docs: adopt issue#-prefix naming for ADRs/PRDs (#3485) The repo's sequential ADR/PRD numbering convention has produced recurring collisions when developers compute "next number" locally and ship in parallel — currently visible on disk as duplicate docs/adr/0010-*.md and triplicate docs/adr/0011-*.md, plus a stack of "resolve ADR conflict" commits in git history. Replace the local-compute convention with issue#-prefix slug naming: docs/adr/<issue#>-<slug>.md (new ADRs) docs/prd/<issue#>-<slug>.md (new PRDs — directory introduced) GitHub issue numbers are server-assigned and atomic, so the reservation step the CONTRIBUTING.md issue-first rule already enforces also produces the artifact ID. One issue = one ADR-or-PRD = one PR. Same shape as the existing changeset random-name pattern (#2975) for CHANGELOG.md fragments, applied to a different artifact class. Migration policy: legacy ADRs 0001-* through 0011-* are preserved as immutable historical record. The new convention applies only to ADRs/PRDs created on or after this merge. Files updated: - docs/adr/README.md — naming convention + legacy note + link - docs/prd/README.md (new) — seeds the new directory + same convention - CONTRIBUTING.md — new "Proposing an ADR or PRD" section - docs/contributor-standards.md — formalize as contributor requirement No code surface — docs-only. Closes #3485 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(changeset): add Changed fragment for ADR/PRD naming convention (#3487) Per CONTRIBUTING.md "When unsure whether a change is user-facing, add the fragment" — the contributor process IS user-facing for the contributor user class. Drop the no-changelog opt-out, surface the naming-convention change in the next CHANGELOG so contributors see it before they hit it as a PR rejection. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: address CodeRabbit findings on #3487 - CONTRIBUTING.md: rename heading to "Proposing an ADR or PRD" so its GitHub-anchor slug matches the #proposing-an-adr-or-prd link target used from docs/adr/README.md, docs/prd/README.md, and docs/contributor-standards.md (broken anchors) - docs/adr/README.md, docs/prd/README.md, docs/contributor-standards.md: add `text` language tag to the new naming-convention fenced blocks to satisfy markdownlint MD040 Pre-existing untyped fences elsewhere in the touched files are left alone per CONTRIBUTING.md "no drive-by formatting". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
1e091d2bcb |
refactor(shell-projection): remove deprecated wrappers + finalize ADRs (Phase 4, #3468) (#3484)
* refactor(shell-projection): remove deprecated wrappers + finalize ADRs (Phase 4, #3468) Final phase of the shell-command-projection expansion. Removes the legacy core.cjs wrappers (`atomicWriteFileSync`, `safeReadFile`, `normalizeMd`) now that every call site lives behind the seam, plus three Phase-3 stragglers (`graphify.cjs`, `template.cjs`, dead import in `profile-pipeline.cjs`). Documentation: - ADR-0009: addendum noting Phase 1–4 scope expansion (subprocess + file I/O ownership), supersession of "does not execute" constraint, and resolution of open Q4. - ADR-0010: status changed to Superseded by ADR-0009 with explanation. - CONTEXT.md "Shell Command Projection Module" entry already current from Phase 1 — no edit needed. Tests: - `tests/atomic-write.test.cjs` deleted — wrapper it tested is gone; `atomic-write-coverage.test.cjs` (Phase 3) covers platformWriteSync. - `tests/core.test.cjs::safeReadFile` + `::normalizeMd` describes deleted — wrappers are gone. - `tests/concurrency-safety.test.cjs` normalizeMd suite (behavioral / perf / snapshot) repointed via 2-line shim at the seam's `normalizeContent` — full regression coverage preserved. Test result: 9059/9041/18 — exact pre-Phase-4 baseline. All 18 failures are pre-existing path-with-spaces local-env issues. Closes #3468 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(shell-projection): migrate remaining raw fs.writeFileSync sites (Phase 4, #3468) Sweeps the 7 raw fs.writeFileSync call sites that bypassed the seam through Phase 3, folding them into platformWriteSync. Net -14 lines: deletes the local writeFileAtomicSync helper in installer-migrations.cjs and collapses surface.cjs's manual tmp+rename into a single seam call. Sites migrated: - drift.cjs (1) — frontmatter write - learnings.cjs (1) — learning record JSON write - install-profiles.cjs (1) — profile marker write (collapsed redundant mkdir) - gsd2-import.cjs (1) — imported file write (collapsed redundant mkdir) - surface.cjs (1) — surface state write (replaced manual tmp+rename block) - installer-migrations.cjs (3) — journal init/finalize + rewrite-json action; deleted private writeFileAtomicSync helper and its three call sites Two sites intentionally retained outside the seam: - planning-workspace.cjs:241 — workspace lock (wx-flag atomic-create; previously excluded by Phase 3) - installer-migrations.cjs:220 — install migration lock (fd write into wx-opened handle) - writeInstallState (installer-migrations.cjs) — strict atomic contract for install state; the seam's fallback-to-direct-write on rename failure would silently violate the invariant that install state must never be left half-written. Inline tmp+rename with rethrow keeps the original guarantee. Tests: 9059 / 9041 / 18 — exactly the pre-Phase-4 baseline; 18 failures are the pre-existing path-with-spaces local-env issues, identical files as before. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(installer-migrations): use strict atomic write for rollback install-state restore The rollback path was restoring INSTALL_STATE via platformWriteSync, which falls back to a direct write on rename failure and would silently violate the half-written invariant that the install-state contract guarantees elsewhere. Extracts the strict tmp+rename logic from writeInstallState into a shared atomicWriteInstallState(configDir, content) helper and routes both writeInstallState and rollbackAppliedMigrationResult through it. Preserves the existing null-handling (rmSync when previousInstallStateBytes === null) and existing failure-collection (failures.push on caught errors). Byte-faithful restore: previousInstallStateBytes is written as-is (no JSON parse round-trip), preserving the exact prior file contents on restore. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
ba625c0978 |
feat(shell-projection): add exec* dispatch and platform* file I/O seam (#3465) (#3470)
* feat(shell-projection): add exec* dispatch and platform* file I/O seam (Phase 1, #3465) Extends shell-command-projection.cjs with two new sections: Subprocess dispatch: - execGit(args, opts) → { exitCode, stdout, stderr } - execNpm(args, opts) → same; owns shell:true on Windows (npm.cmd) - execTool(program, args, opts) → same; ENOENT → exitCode 127, no throw - probeTty(opts) → string | null; returns null on Windows and non-tty Platform file I/O: - normalizeContent(filePath, content) → { content, encoding }; pure function; .md → full normalizeMd pass; other → CRLF→LF + trailing newline - platformWriteSync(filePath, content, opts) → ensureDir + normalizeContent + atomic write - platformReadSync(filePath, opts) → null on ENOENT; throws when required:true - platformEnsureDir(dirPath) → mkdirSync recursive, idempotent Absorbs normalizeMd fence-tracking logic from core.cjs (no circular dep). Existing rendering exports untouched. core.cjs compat exports unchanged until Phase 4. Updates CONTEXT.md with Shell Command Projection Module canonical definition. 31 new behavioral tests; full suite green. Closes #3465 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(context): record shell-projection expansion session learnings * chore(changeset): add entry for shell-projection I/O seam (#3465) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(adr): add ADR-0010 skill-surface budget module and ADR-0011 review default reviewers (Phase 1, #3465) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(context): record phase 1 rebase and PR session learnings (#3465) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(shell-projection): drop substring match on stderr — assert typed shape only The lint-no-source-grep rule prohibits substring matching on stderr (or any test-output text). The exitCode === 127 assertion already proves the ENOENT path; the stderr content was implementation-detail of the OS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(pr3470): address CodeRabbit findings and minimal-core drift * docs(adr0010): align profile interface with phase-1 scope * docs(adr): index newly added 0010/0011 ADR drafts in README enh-3271 invariant requires every file in docs/adr/ to be linked from the README. Adds entries for the three ADR drafts committed earlier in this PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
d0f916728b |
feat(skill-surface): install-time profiles + runtime /gsd:surface (#3408) (#3456)
* feat(skill-deps): add requires: frontmatter to all 51 skills with cross-skill references Mechanical migration from docs/research/data/2026-05-12-skill-audit.json. Every skill whose body references another GSD skill now declares those dependencies in `requires:` YAML frontmatter (flow-style array). Notable: discuss-phase, plan-phase, and execute-phase all reference `phase`, which confirms the latent gap in MINIMAL_SKILL_ALLOWLIST — `phase` is pulled by the core loop but was never in the allowlist. The profile closure model (ADR-0010 Phase 1) resolves this automatically. Closes part of #3408. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(skill-surface-budget): add PROFILES map, resolveProfile, loadSkillsManifest, staging, marker IO Implements the Skill Surface Budget Module core (ADR-0010, Phase 1): - PROFILES Object.freeze map: core (6 skills), standard (~13), full ('*') - loadSkillsManifest: parses requires: frontmatter from commands/gsd/*.md into a Map<stem, string[]> without external YAML dep - resolveProfile({modes, manifest}): computes transitive closure over the requires: graph; composable (modes=['core','audit'] unions closures) - stageSkillsForProfile / stageAgentsForProfile: filesystem staging with same exit-cleanup machinery as the legacy stageSkillsForMode - readActiveProfile / writeActiveProfile: .gsd-profile marker round-trip - Back-compat shims preserved: MINIMAL_SKILL_ALLOWLIST, isMinimalMode, shouldInstallSkill (overloaded), stageSkillsForMode — all legacy tests pass The phase latent bug is now resolved by closure: discuss-phase, plan-phase, and execute-phase all require phase, so any profile including any of them automatically includes phase via transitive closure. Tests: 22 manifest+resolve, 9 stage, 10 marker (41 new tests, all green). Back-compat anchor: 80/80 passing. Closes part of #3408. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(skill-surface-budget): add lint-skill-deps.cjs CI gate and fix 19 missed requires: entries Two lint checks (scripts/lint-skill-deps.cjs): a) Frontmatter-body consistency: skill body references must appear in requires: b) Profile closure: every requires: dep of any profile skill must be in closure Running the lint revealed 19 body references missed by the audit JSON (the audit used static analysis; some bodies have conditional references). Fixed: complete-milestone: +audit-milestone, discuss-phase, plan-phase, execute-phase, new-milestone fast: +quick health: +thread map-codebase: +new-project, plan-phase new-milestone, new-project, review, ultraplan-phase: +plan-phase ship: +verify-work sketch, spike: +new-project verify-work: +execute-phase workstreams: +new-milestone, resume-work Wired into package.json as lint:skill-deps and added to pretest. 8 fixture-based tests: all green. Closes part of #3408. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(skill-surface-budget): wire --profile= arg, profile marker write/read in bin/install.js - Add --profile=<name> / --profile=<n1>,<n2> arg parsing (composable). Mutually exclusive with --minimal / --core-only (aliases for --profile=core). Default (no flag): full. - Import readActiveProfile / writeActiveProfile from install-profiles.cjs. - After writeManifest: persist active profile to .gsd-profile marker. - gsd update path: if no --profile flag given, read existing .gsd-profile marker so non-full profiles are not silently re-expanded to full (ADR-0010). - Update --help block to document --profile= with per-tier token costs. New test: install-minimal-backcompat.test.cjs (6 tests): - PROFILES.core === MINIMAL_SKILL_ALLOWLIST (contract) - --minimal writes .gsd-profile marker "core" - --profile=core, --profile=standard write correct markers - default install writes marker "full" Closes part of #3408. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(changeset): add feat-3408-skill-profiles changelog fragment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(install-profiles): derive agents from skill body refs and wire into resolveProfile Deviation 1 of ADR-0010 phase 1b: tiered profiles (core, standard) now produce a non-empty agents Set instead of always returning empty. resolveProfile() scans each skill body for gsd-* agent name references (via new parseCallsAgents()), stores them in _calls_agents_<stem> manifest entries, and unions them across the resolved skill closure. stageAgentsForProfile() already checked resolvedProfile.agents — it now gets real data so tiered profiles install the correct subset of agents instead of zero. Closes #3408 (partial — Deviation 1 only) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(install): honor .gsd-profile marker on update, add resolveEffectiveProfile/mostRestrictiveProfile Deviation 2 of ADR-0010 phase 1b: the marker written during installation is now actually honored when re-running without explicit flags (e.g. gsd update). The dead-end logging block is replaced by resolveEffectiveProfile(), which picks the marker profile over 'full' when no explicit --profile= flag was given. The resolved profile is piped through to all 13 stageSkillsForMode dispatch sites (now _stageSkills) so updates install only the previously-chosen skill subset. --minimal retains its back-compat behavior (strict 6-skill allowlist, no closure) while writing 'core' to the marker. mostRestrictiveProfile() is exported for callers that need to reconcile disagreeing markers across runtimes (smallest skill set wins). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(surface): add CLUSTERS data + state IO module Add clusters.cjs with 10 named skill groups covering all 66 skills (verified by surface-clusters.test.cjs). Add surface.cjs with readSurface/ writeSurface atomic IO, resolveSurface, applySurface, and listSurface. Tests: 17 passing (11 state IO + 6 cluster integrity). Closes #3408 * docs(adr): add ADR-0011 Skill Surface Budget Module (Phase 1 accepted, Phase 2 amendment) Records the install-time profile staging decision (Phase 1, landed) and the runtime /gsd:surface cluster-toggle decision (Phase 2, in flight) as an amendment. Updates the ADR README index. Closes #3408 * docs(install-profiles): update module docblock for Phase 2 and ADR-0011 Corrects the ADR reference from 0010 to 0011, documents the three-profile model and back-compat aliases, adds resolveEffectiveProfile precedence rule, and notes the companion surface.cjs Phase 2 engine. * docs(context): add Skill Surface Budget Module canonical entry Adds the Domain terms entry for the Skill Surface Budget Module covering both Phase 1 (install-time profiles, .gsd-profile marker) and Phase 2 (runtime /gsd:surface cluster toggles, clusters.cjs, .gsd-surface.json), per ADR-0011 Consequences requirement. * feat(surface): add resolveSurface and applySurface engine + tests Tests cover: profile → surface equivalence, cluster disable/enable, explicitAdds transitive closure, applySurface file sync (add missing, remove superseded, preserve non-gsd files), listSurface token cost. 16 new tests passing. * docs(readme): document --profile= flag and /gsd:surface command Brief user-facing mention of install profiles (core/standard/full) and the /gsd:surface slash command in the Commands table. Points to ADR-0011 for details. * feat(surface): add /gsd:surface slash command runbook New skill: gsd:surface — runtime profile/cluster toggle without reinstall. Sub-commands: list, status, profile <name>, disable/enable <cluster>, reset. Persists state to .gsd-surface.json (independent of .gsd-profile). Description 96 chars (≤100 limit). lint:descriptions + lint:skill-deps: 0 violations. * feat(surface): add changeset fragment for /gsd:surface runtime toggle * feat(surface): add surface skill stem to utility cluster surface.md is a new skill; add it to the utility cluster so the surface-clusters.test.cjs coverage invariant stays satisfied. * docs(adr): fix ADR references to 0011 and record Phase 2 as shipped ADR-0010 number was already claimed by the file-operation-engine ADR; this ADR landed as 0011-skill-surface-budget-module.md. Update inline ADR references in clusters.cjs, surface.cjs, install-profiles.cjs, and the Phase 2 changeset to ADR-0011. Update the ADR Status section to record Phase 2 artifacts as shipped on this branch rather than "in progress". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(research): port skill-surface-budget memo and audit data ADR-0011 references docs/research/2026-05-12-skill-surface-budget.md and docs/research/data/2026-05-12-skill-audit.json, which only existed in the research worktree. Port both onto this branch so the ADR's References section resolves and reviewers can read the cluster taxonomy (§3.2), dependency topology (§3.1), and option grading (§4) that justify Phase 1 and Phase 2 decisions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(registration): register surface/clusters in INVENTORY, COMMANDS, and help.md - surface.md: convert allowed-tools from inline YAML array to block style (was parsed as a single tool name "[Read, Write, Bash]" by test harness) - docs/INVENTORY.md: add CLI module rows for clusters.cjs and surface.cjs; add Commands row for /gsd-surface; bump CLI Modules count 55→57, Commands 66→67 - docs/INVENTORY-MANIFEST.json: add entries for clusters.cjs, surface.cjs, and /gsd-surface (filename-based command key) - docs/COMMANDS.md: add ### `/gsd-surface` heading in Configuration Commands - get-shit-done/workflows/help.md: add /gsd:surface entry in Configuration section Fixes registration failures introduced by Phase 2 of #3408. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(surface,docs): scrub .claude leakage and escape hypothetical slash tokens Two PR regressions introduced earlier on this branch: 1. surface.cjs JSDoc comments contained the canonical paths (~/.claude/commands/gsd, ~/.claude/agents) as example values, which the cline-install leak regex (~\/\.claude\/(?:get-shit-done|commands|agents |hooks)) flagged as install-time path leaks. Reworded the docblocks to describe runtime-resolved paths without literal ~/.claude tokens. 2. The ported research memo proposed hypothetical Option C dispatchers using slash syntax (/gsd:milestone, /gsd:research). The docs-parity-live-registry test enforces that every slash-command token in docs/ resolves to a real command. Rewrote the Option C sketch without the slash prefix and added a clarifying note that the dispatchers are illustrative, not shipped. Targeted tests now pass: tests/cline-install.test.cjs and tests/docs-parity-live-registry.test.cjs both green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: remove raw output/source grep in lint tests * fix: close coderabbit profile and requires issues * test: align surface token-cost assertion wording * fix(install): align core profile alias and defer profile marker write --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
bf3c736029 |
feat(shell-projection): centralize managed hook command policy (#3450)
* feat(shell-projection): route persistent PATH hints through projection seam * refactor(shell-projection): unify managed hook command policy * fix(install): guard malformed settings hooks during uninstall * chore(changeset): add fragment for pr 3450 * fix(install): guard malformed settings hook entries |
||
|
|
7e91a861ee |
feat: deepen shell command projection seam (#3445)
* feat: deepen shell command projection seam * chore: add changeset for shell projection seam * feat: centralize local and portable hook path projection * docs: avoid prompt-scan false positive in installer migrations * docs(adr): fix path-style token punctuation |
||
|
|
c8efbe5382 | docs(adr): add shell command projection module ADR | ||
|
|
a1f00a8a0c | Feat(installer): add phase 5 migration guardrails | ||
|
|
3084ecc2a6 | Add first-time installer baseline migration | ||
|
|
3943146484 | feat: migrate legacy codex hooks cleanup | ||
|
|
6d33055756 | feat: add installer migration framework | ||
|
|
706ddb5ea5 |
docs(adr): add docs/adr/README.md index and structural ADR test (#3302)
* docs(adr): add docs/adr/README.md index and structural ADR test (#3271) - Add docs/adr/README.md as an indexed entry point linking all 7 ADRs - Add tests/enh-3271-sdk-adr-structure.test.cjs: structural assertions that ADR 0005 and 0006 exist, have required headings and Status/Date metadata, and that README links every ADR file by filename - Update CHANGELOG.md with Enhancement entry - Add .changeset/3271-sdk-adr-structure.md ADRs 0005 (SDK architecture seam-map) and 0006 (planning-path projection module) already landed on main. This PR completes issue #3271 by adding the README index and the structural test gate that enforces ADR completeness going forward. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: set changeset pr: 3302 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(test): exclude self-reference from ADR 0005 cross-ref count (#3271) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: drop redundant CHANGELOG.md edit (use .changeset/ fragment per CONTRIBUTING.md) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
8bc255c266 |
fix(workstream): normalize migration workstream names (#3269)
* fix(workstream): normalize migrate-name to valid slug * docs(context): record workstream migrate-name slug invariant * fix(catalog-cjs): balanced fallback for unknown profile (CR finding A) profiles[profile] could return undefined for any profile key absent from the catalog entry, causing downstream callers like formatAgentToModelMapAsTable to crash on .length. Add ?? profiles.balanced fallback to match the SDK adapter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(sdk): anchor path resolution on import.meta.url not cwd (CR finding B) resolve(process.cwd(), '..') breaks when Vitest is invoked from the repo root because cwd is already the repo root and '..' goes one level above. Replace with a file-relative path using fileURLToPath(new URL('../../../', import.meta.url)) anchored at the test file's location (sdk/src/query/). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: derive Group B runtime list from catalog (CR finding C) Hardcoded ['kilo', 'cline', ...] throws TypeError if a runtime name is removed from the catalog. Derive group B dynamically via Object.keys(catalog.runtimeTierDefaults).filter(r => !r.opus) so the test never goes stale and auto-covers future Group B additions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(workflow): add hermes to Step B runtime options (CR finding D) hermes appears in the Group A built-in defaults table but was missing from the AskUserQuestion options in Step B, forcing users to manually type it via 'Other (Group B or custom)'. Add explicit hermes entry for UI consistency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(config): refresh dynamic_routing tier table; fix stale L671 (findings E+F) Finding E: tier table was missing 6 heavy-tier agents and 15 standard/light agents added by this PR. Updated all three rows to match catalog routingTier assignments (33 agents total). Finding F: removed stale '18 of 31' claim and agent enumeration; replaced with accurate note that all 33 agents have explicit catalog entries. Updated authoritative source pointers to model-catalog.cjs / model-catalog.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(core): add profile-fallback unit tests for quality and budget (CR nitpick G) The PR introduced quality→opus and budget→haiku unknown-agent fallbacks but only balanced→sonnet and inherit→inherit were tested. Add two tests covering the remaining two branches to complete coverage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * adr: define planning workspace and worktree seam * refactor(worktree): extract worktree safety policy module * refactor(workstream): extract active workstream pointer store seam * test(worktree): cover policy branch paths and persist seam guardrails * refactor(worktree): centralize health inventory seam for W017 * fix(workspace): align SDK project path policy with CJS planningDir * refactor(query): unify SDK planning path projection seam * refactor(init): route workspace projection through planningPaths seam * docs(adr): add SDK architecture and planning path ADRs * refactor(worktree): deepen name, pointer, inventory, and config seams * docs(config): harmonize claude-opus-4-6 to 4-7 in resolve_model_ids example (CR finding 2) * fix(sdk): return undefined for model_profile='inherit' sentinel (CR finding 3) * docs(adr): renumber conflicting 0003-sdk-package-seam-module to 0007, update seam-map reference (CR finding 4) * fix(workstream): align CJS and SDK name validation to accept dots, guard path traversal via includes('..') (CR finding 5) * fix(sdk): guard writeActiveWorkstream against non-existent workstream directory, k014/k031 parity (CR finding 6) * chore(changeset): add #3269 changeset (CR finding 1 — proper changeset for this PR) * docs(inventory): register 3 new CLI modules in INVENTORY.md/MANIFEST (active-workstream-store, workstream-name-policy, worktree-safety) * fix(sdk): use relPlanningPath(workstream) in planningPaths, fix setActiveWorkstream/getActiveWorkstream name errors in workstream.ts * fix(sdk): validate GSD_WORKSTREAM in planningPaths before use (#3269 regression) planningPaths() called resolveWorkspaceContext() which returned GSD_WORKSTREAM raw (no validation). An invalid value like '../evil' was used as effectiveWorkstream, constructing a bad path; roadmapAnalyze() caught the ENOENT and returned a no-phase_count error object instead of the root ROADMAP result. Fix: validate envCtx.workstream with validateWorkstreamName() in planningPaths() before accepting it as effectiveWorkstream. Invalid env → null → root .planning/ fallback, preserving the bug-2791 contract: invalid GSD_WORKSTREAM is silently ignored and falls back to the root context (phase_count: 0 for empty root ROADMAP). The bug-2791 regression test now passes. No other call sites read GSD_WORKSTREAM without validation: query-runtime-context.ts already validates; cli.ts already validates; context-engine.ts takes a caller-validated workstream parameter. Closes #3268 (regression introduced by #3269 workstream-name-policy work). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
96806003c5 |
fix(#3229): shared model catalog source of truth for agent profiles + runtime tier defaults (#3230)
* docs(adr): add ADR-0003 model catalog module * fix(#3229): add shared model catalog as source of truth for agent profiles and runtime tier defaults Research / design (ADR-0003): - Existing drift came from 4 independent model truths: 1. CJS model-profiles.cjs 2. SDK config-query.ts stale copy (18 agents) 3. settings-advanced.md runtime tier table 4. session-runner Claude-only profile map - New design: one machine-readable Model Catalog Module in sdk/shared/ that both packages ship and consume. Implementation: - sdk/shared/model-catalog.json — canonical source of truth for: - full 33-agent registry - per-agent golden (quality) alias + balanced/budget aliases - adaptive derivation from routingTier - agent→phaseType map - agent→dynamic-routing default tier map - runtime tier defaults for all supported runtimes - get-shit-done/bin/lib/model-catalog.cjs — CJS adapter over the catalog - sdk/src/model-catalog.ts — SDK adapter over the same catalog - CJS model-profiles.cjs now re-exports derived data from model-catalog.cjs - SDK config-query.ts now re-exports MODEL_PROFILES/VALID_PROFILES from model-catalog.ts instead of maintaining its own list - sdk/src/query/helpers.ts runtime list now comes from the catalog (fixes hermes drift) - sdk/src/session-runner.ts Claude profile→model-id mapping now resolves via catalog - docs/CONFIGURATION.md + settings-advanced.md runtime tables updated to match catalog Behavior changes: - resolve-model now covers every shipped agent file on disk (33 agents) - unknown-agent fallback is profile-semantic, not hardcoded sonnet: quality→opus, budget→haiku, balanced/adaptive→sonnet, inherit→inherit - Group B runtimes remain known runtimes but do not get built-in tier defaults Tests (RED→GREEN): - root tests: shipped agent files must equal MODEL_PROFILES keys - sdk tests: shipped agent files must equal MODEL_PROFILES keys - direct fix assertion: gsd-code-reviewer resolves to opus under quality with no unknown_agent - runtime defaults parity test: settings-advanced.md + CONFIGURATION.md tables must match catalog - helper tests: hermes included in SUPPORTED_RUNTIMES and getRuntimeConfigDir() Closes #3229 * chore(changeset): update #3229 changeset pr field to 3230 * fix(ci): update inherit fallback expectations and inventory parity for model catalog |
||
|
|
397c34142a |
Deepen SDK package seam and converge runtime skills policy (#3238)
* Deepen SDK package seam and converge runtime skills policy * fix(sdk): unified install-root resolution for workflows and agents (CR finding 1) Use the already-resolved gsdInstallDir constant instead of calling resolveLegacyInstallDir() again when computing agentsDir, ensuring workflowsDir and agentsDir share the same install root. * fix(sdk): tilde shortening requires path-boundary match (CR finding 2) Both renderGlobalSkillsBaseDisplayPath and renderGlobalSkillDisplayPath used startsWith(home) which could incorrectly shorten unrelated paths sharing the same prefix. Now checks for home === base or base.startsWith(home + sep) to ensure a real directory boundary. * fix(sdk): validate loadConfig export before invocation (CR finding 3) After requiring core.cjs, check typeof mod.loadConfig === 'function' before calling it. Throws a classified GSDError with the module path if the export is missing, rather than a generic TypeError. * fix(test): guard root lookup before .path dereference (CR finding 4) Added assert.ok() guards for claudeRoot and codexRoot after the .find() calls so that a missing root produces an explicit assertion failure rather than a TypeError on .path dereference. * fix(ci): fail-safe on transient API errors in approval dismissal (CR finding 6) resolveRole() returns 'unknown' for non-404 errors (rate limits, 5xx, network blips). shouldDismissReviewer() now treats 'unknown' as unresolvable and skips dismissal, preventing legitimate approvals from being dismissed due to a transient API failure. Only 'none' (true 404) is treated as a confirmed non-collaborator. * changeset: pr=3238 SDK package seam and runtime skills convergence * fix(sdk): harden resolveGlobalSkillDir against path traversal (CR finding 1) Use resolve+relative to validate that skillName cannot escape the global skills base directory. Values like "../../foo" or absolute paths now return null instead of joining directly. All imports (resolve, relative, isAbsolute) were already present in helpers.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(sdk): split skill-dir-resolution and skill-not-found warnings (CR finding 2) After resolveGlobalSkillDir's hardening can return null for traversal attempts, the old single-branch warning "Global skill not found at ..." was misleading. Split into two distinct cases: - skillDir === null → "Could not resolve global skill directory for ..." - skillMd missing → "Global skill not found at ..." Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: lock skill path-traversal rejection in resolveGlobalSkillDir Regression test verifying that traversal segments (../../foo, ../escape), empty string, and absolute paths are all rejected (return null), while a legitimate skill name resolves correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(sdk): align display-path contract + traversal coverage for resolveGlobalSkillMarkdownPath (CR nitpicks) - renderGlobalSkillsBaseDisplayPath now returns a non-null string for unsupported runtimes (e.g. cline → "(cline does not use a skills directory)") matching the existing renderGlobalSkillDisplayPath contract; callers of both helpers no longer need null-checks for unsupported runtimes. - Remove now-redundant ! non-null assertion on renderGlobalSkillsBaseDisplayPath calls in skill-manifest.ts (return type is string, not string | null). - Extend the path-traversal test block to assert resolveGlobalSkillMarkdownPath also propagates null for ../../foo, ../escape, empty, and /abs/path inputs, locking the null-propagation contract against future refactors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
54b06e653e | docs(sdk): document runtime bridge seam, strict mode, and fallback policy | ||
|
|
a411e08e88 |
fix(coderabbit): resolve all 12 findings on PR #3152
MAJOR (security/correctness): - commands/gsd/debug.md: add Write to allowed-tools (session file creation requires it — workflow explicitly says 'use Write tool, never heredoc') - workflows/debug.md: add SLUG sanitization guard to steps 1b+1c (status/ continue subcommands used raw user input in file paths — path traversal) - workflows/thread.md: sanitize $ARGUMENTS in RESUME mode before file path construction (was bypassing the sanitization guard in CLOSE/STATUS modes) MINOR (consistency/correctness): - docs/INVENTORY-MANIFEST.json: remove stale top-level 'workflows' array (duplicate of families.workflows introduced in earlier update) - commands/gsd/resume-work.md: normalize process to 'Execute end-to-end.' - commands/gsd/settings.md: normalize process to 'Execute end-to-end.' - commands/gsd/update.md: normalize otherwise branch to 'execute end-to-end.' - docs/adr/0002: add Status: Accepted + Date header (ADR convention) - workflows/extract-learnings.md: rename step extract_learnings → extract-learnings - tests/extract-learnings.test.cjs: tighten step-name assertion to exact name ARCHITECTURE: - scripts/command-contract-helpers.cjs: extract CANONICAL_TOOLS, parseFrontmatter, executionContextRefs as shared module — single source of truth consumed by both lint script and test suite (prevents silent lint/test disagreement) - scripts/lint-command-contract.cjs: require() helpers instead of duplicating - tests/command-contract.test.cjs: require() helpers; move readFileSync calls inside test() callbacks (registration-time throws surface as named failures) |
||
|
|
695ad986c0 | docs(adr): add ADR-0002 command contract validation module | ||
|
|
5e21bf7567 |
Deepen query dispatch seam with Command Topology Module (#3078)
* Deepen query dispatch seam with command topology module * Stabilize SDK parity defaults and integration test gating * docs(architecture): record pre-project config policy and e2e gate * refactor(query): stop injecting native adapter in CLI dispatch path * fix(config): align workflow auto-chain typing and docs |
||
|
|
9c92c32f6e |
refactor(query): deepen runtime context/native adapter/output seams (#3076)
* refactor(query): deepen runtime context, native adapter, and cli output seams * chore(changeset): add fragment for query seam deepening continuation * refactor(query): converge internal command-resolution imports on canonical seam * refactor(query): remove dead seam wrappers and converge on canonical modules * docs(architecture): update context and adr for query seam completion * fix(query): preserve gsd-tools stderr in cli output and clarify static ws test scope * test(query): cover whitespace stderr and null exitCode fallback |
||
|
|
f104dab332 |
refactor(query): deepen dispatch policy seam with structured result contract (#3066)
* refactor(query): deepen dispatch policy seam with structured result contract Closes #3065. - unify query dispatch outcome as typed success/failure union - include error kind/details + final exit_code in failure path - align native and fallback paths under one dispatch policy seam - make CLI query path consume seam result (thin adapter) - add ADR + context term for Dispatch Policy Module * refactor(query): strengthen dispatch seam with shared error mapper and typed details - add query-dispatch-error-mapper module shared by native/fallback paths - remove ad-hoc inline mapping in dispatch/fallback executors - lock error-details schema in mapper + dispatch tests - document structured dispatch contract in QUERY-HANDLERS.md * fix(query): return structured fallback failure when path resolution throws - guard resolveGsdToolsPath in cjs dispatch path - map thrown resolution errors to fallback_failure result - add regression test for structured failure contract |