feat: Phase 2 caller migration — gsd-sdk query in workflows, agents, commands (#2179)

* feat: Phase 2 caller migration — gsd-sdk query in workflows (#2122)

Cherry-picked orchestration rewrites from feat/sdk-foundation (#2008, 4018fee) onto current main, resolving conflicts to keep upstream worktree guards and post-merge test gate. SDK stub registry omitted (out of Phase 2 scope per #2122).

Refs: #2122 #2008
Made-with: Cursor

* docs: add gsd-sdk query migration blurb

Made-with: Cursor

* docs(workflows): extend Phase 2 gsd-sdk query caller migration

- Swap node gsd-tools.cjs for gsd-sdk query in review, plan-phase, execute-plan,
  ship, extract_learnings, ai-integration-phase, eval-review, next, thread
- Document graphify CJS-only in gsd-planner; dual-path in CLI-TOOLS and ARCHITECTURE
- Update tests: workstreams gsd-sdk path, thread frontmatter.get, workspace init.*,
  CRLF-safe autonomous frontmatter parse
- CHANGELOG: Phase 2 caller migration scope

Made-with: Cursor

* docs(phase2): USER-GUIDE + remaining gsd-sdk query call sites

- USER-GUIDE: dual-path CLI section; state validate/sync use full CJS path
- Commands: debug (config-get+tdd), quick (security note), intel Task prompt
- Agent: gsd-debug-session-manager resolve-model via jq
- Workflows: milestone-summary, forensics, next, complete-milestone/verify-work
  (audit-open CJS notes), discuss-phase, progress, verify-phase, add/insert/remove
  phase, transition, manager, quick workflow; remove-phase commit without --files
- Test: quick-session-management accepts frontmatter.get
- CHANGELOG: Phase 2 follow-up bullet

Made-with: Cursor

* docs(phase2): align gsd-sdk query examples in commands and agents

- init.* query names; frontmatter.get uses positional field name
- state.* handlers use positional args; commit uses positional paths
- CJS-only notes for from-gsd2 and graphify; learnings.query wording
- CHANGELOG: Phase 2 orchestration doc pass

Made-with: Cursor

* docs(phase2): normalize gsd-sdk query commit to positional file paths

- Strip --files from commit examples in workflows, references, commands
- Keep commit-to-subrepo ... --files (separate handler)
- git-planning-commit.md: document positional args
- Tests: new-project commit line, state.record-session, gates CRLF, roadmap.analyze
- CHANGELOG [Unreleased]

Made-with: Cursor

* feat(sdk): gsd-sdk query parity with gsd-tools and PR 2179 registry fixes

- Route query via longest-prefix match and dotted single-token expansion; fall back
  to runGsdToolsQuery (same argv as node gsd-tools.cjs) for full CLI coverage.
- Parse gsd-sdk query permissively so gsd-tools flags (--json, --verify, etc.) are
  not rejected by strict parseArgs.
- resolveGsdToolsPath: honor GSD_TOOLS_PATH; prefer bundled get-shit-done copy
  over project .claude installs; export runGsdToolsQuery from the SDK.
- Fix gsd-tools audit-open (core.output; pass object for --json JSON).
- Register summary-extract as alias of summary.extract; fix audit-fix workflow to
  call audit-uat instead of invalid init.audit-uat (PR review).

Updates QUERY-HANDLERS.md and CHANGELOG [Unreleased].

Made-with: Cursor

* fix(sdk): Phase 2 scope — Trek-e review (#2179, #2122)

- Remove gsd-sdk query passthrough to gsd-tools.cjs; drop GSD_TOOLS_PATH
- Consolidate argv routing in resolveQueryArgv(); update USAGE and QUERY-HANDLERS
- Surface @file: read failures in GSDTools.parseOutput
- execute-plan: defer Task Commit Protocol to gsd-executor
- stale-colon-refs: skip .planning/ and root CLAUDE.md (gitignored overlays)
- CHANGELOG [Unreleased]: maintainer review and routing notes

Made-with: Cursor
This commit is contained in:
Rezolv
2026-04-15 22:46:31 -04:00
committed by GitHub
parent 762b8ed25b
commit d3a79917fa
120 changed files with 845 additions and 586 deletions

View File

@@ -2,8 +2,9 @@
* Query command registry — routes commands to native SDK handlers.
*
* The registry is a flat `Map<string, QueryHandler>` that maps command names
* to handler functions. Unknown commands throw GSDError — the gsd-tools.cjs
* fallback was removed in v3.0 when all commands were migrated to native handlers.
* to handler functions. Unknown keys passed to `dispatch()` throw `GSDError`.
* The `gsd-sdk query` CLI resolves argv with `resolveQueryArgv()` before dispatch;
* there is no automatic delegation to `gsd-tools.cjs`.
*
* Also exports `extractField` — a TypeScript port of the `--pick` field
* extraction logic from gsd-tools.cjs (lines 365-382).
@@ -59,9 +60,9 @@ export function extractField(obj: unknown, fieldPath: string): unknown {
/**
* Flat command registry that routes query commands to native handlers.
*
* Unknown commands throw `GSDError` from `dispatch()` — there is no fallback
* to gsd-tools.cjs (bridge removed in v3.0). All supported commands must be
* registered via `register()`.
* `dispatch()` throws `GSDError` for unknown command keys. The `gsd-sdk query`
* CLI uses `resolveQueryArgv()` to map argv to a registered handler; there is
* no passthrough to `gsd-tools.cjs` — CJS-only commands stay on the legacy CLI.
*/
export class QueryRegistry {
private handlers = new Map<string, QueryHandler>();
@@ -106,9 +107,6 @@ export class QueryRegistry {
/**
* Dispatch a command to its registered native handler.
*
* Throws GSDError for unknown commands — the gsd-tools.cjs fallback was
* removed in v3.0. All commands must be registered as native handlers (T-14-13).
*
* @param command - The command name to dispatch
* @param args - Arguments to pass to the handler
* @param projectDir - The project directory for context
@@ -126,3 +124,51 @@ export class QueryRegistry {
return handler(args, projectDir);
}
}
function expandSingleDottedToken(tokens: string[]): string[] {
if (tokens.length !== 1 || tokens[0].startsWith('--')) {
return tokens;
}
const t = tokens[0];
if (!t.includes('.')) {
return tokens;
}
return t.split('.');
}
function matchRegisteredPrefix(
tokens: string[],
registry: QueryRegistry,
): { cmd: string; args: string[] } | null {
for (let i = tokens.length; i >= 1; i--) {
const head = tokens.slice(0, i);
const dotted = head.join('.');
const spaced = head.join(' ');
if (registry.has(dotted)) {
return { cmd: dotted, args: tokens.slice(i) };
}
if (registry.has(spaced)) {
return { cmd: spaced, args: tokens.slice(i) };
}
}
return null;
}
/**
* Map argv after `gsd-sdk query` to a registered handler key and remaining args.
* Longest-prefix match on dotted (`a.b.c`) and spaced (`a b c`) keys; if no match,
* expands a single dotted token (`state.validate` → `state`, `validate`) and retries.
*/
export function resolveQueryArgv(
tokens: string[],
registry: QueryRegistry,
): { cmd: string; args: string[] } | null {
let matched = matchRegisteredPrefix(tokens, registry);
if (!matched) {
const expanded = expandSingleDottedToken(tokens);
if (expanded !== tokens) {
matched = matchRegisteredPrefix(expanded, registry);
}
}
return matched;
}