From 543a8569e45645ca6ec10155d334e098f0304120 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 11 May 2026 15:27:32 -0400 Subject: [PATCH] Fix(workflow): normalize SDK init phase flags (#3389) * fix: normalize sdk init phase flags * chore: add changeset for sdk init phase flags * test: cover sdk phase equals flag variants --- .changeset/sdk-init-phase-flags.md | 5 +++ sdk/src/query/init.test.ts | 56 ++++++++++++++++++++++++++++++ sdk/src/query/init.ts | 25 ++++++++++--- 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 .changeset/sdk-init-phase-flags.md diff --git a/.changeset/sdk-init-phase-flags.md b/.changeset/sdk-init-phase-flags.md new file mode 100644 index 000000000..bfce4cfbe --- /dev/null +++ b/.changeset/sdk-init-phase-flags.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 3389 +--- +**`gsd-sdk query init.*` phase-scoped handlers now accept `--phase ` and `--phase=N`** - flag-style init queries no longer search for a phase literally named `--phase`. diff --git a/sdk/src/query/init.test.ts b/sdk/src/query/init.test.ts index 94bdb5738..7343854cb 100644 --- a/sdk/src/query/init.test.ts +++ b/sdk/src/query/init.test.ts @@ -325,6 +325,20 @@ describe('initExecutePhase', () => { expect(data.milestone_version).toBeDefined(); }); + it('accepts --phase flag form for existing phase (#3387)', async () => { + const result = await initExecutePhase(['--phase', '9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); + + it('accepts --phase=value flag form for existing phase (#3387)', async () => { + const result = await initExecutePhase(['--phase=9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); + it('returns error when phase arg missing', async () => { const result = await initExecutePhase([], tmpDir); const data = result.data as Record; @@ -360,6 +374,20 @@ describe('initPlanPhase', () => { expect(data.project_root).toBe(tmpDir); }); + it('accepts --phase flag form for existing phase (#3387)', async () => { + const result = await initPlanPhase(['--phase', '9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); + + it('accepts --phase=value flag form for existing phase (#3387)', async () => { + const result = await initPlanPhase(['--phase=9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); + it('returns error when phase arg missing', async () => { const result = await initPlanPhase([], tmpDir); const data = result.data as Record; @@ -448,6 +476,20 @@ describe('initVerifyWork', () => { expect(data.project_root).toBe(tmpDir); }); + it('accepts --phase flag form for existing phase (#3387)', async () => { + const result = await initVerifyWork(['--phase', '9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); + + it('accepts --phase=value flag form for existing phase (#3387)', async () => { + const result = await initVerifyWork(['--phase=9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); + it('resolves workstream-scoped phases when workstream is provided', async () => { const wsDir = join(tmpDir, '.planning', 'workstreams', 'delivery'); await mkdir(join(wsDir, 'phases', '32-shipment-creation-tracking-numbers-print-forms'), { recursive: true }); @@ -490,6 +532,20 @@ describe('initPhaseOp', () => { expect(data.plan_count).toBeGreaterThanOrEqual(1); expect(data.project_root).toBe(tmpDir); }); + + it('accepts --phase flag form for existing phase (#3387)', async () => { + const result = await initPhaseOp(['--phase', '9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); + + it('accepts --phase=value flag form for existing phase (#3387)', async () => { + const result = await initPhaseOp(['--phase=9'], tmpDir); + const data = result.data as Record; + expect(data.phase_found).toBe(true); + expect(data.phase_number).toBe('09'); + }); }); describe('initTodos', () => { diff --git a/sdk/src/query/init.ts b/sdk/src/query/init.ts index c89bdd81d..5c7e29959 100644 --- a/sdk/src/query/init.ts +++ b/sdk/src/query/init.ts @@ -54,6 +54,23 @@ function generateSlugInternal(text: string): string { .substring(0, 60); } +function extractPhaseArg(args: string[]): string | undefined { + const equalsArg = args.find((arg) => arg.startsWith('--phase=')); + if (equalsArg) { + const value = equalsArg.slice('--phase='.length).trim(); + return value || undefined; + } + + const flagIndex = args.indexOf('--phase'); + if (flagIndex !== -1) { + const value = args[flagIndex + 1]; + return value && !value.startsWith('--') ? value : undefined; + } + + const first = args[0]; + return first && !first.startsWith('--') ? first : undefined; +} + /** * Check if a path exists on disk. */ @@ -293,7 +310,7 @@ export function withProjectRoot( * Port of cmdInitExecutePhase from init.cjs lines 50-171. */ export const initExecutePhase: QueryHandler = async (args, projectDir, workstream) => { - const phase = args[0]; + const phase = extractPhaseArg(args); if (!phase) { return { data: { error: 'phase required for init execute-phase' } }; } @@ -376,7 +393,7 @@ export const initExecutePhase: QueryHandler = async (args, projectDir, workstrea * Port of cmdInitPlanPhase from init.cjs lines 173-293. */ export const initPlanPhase: QueryHandler = async (args, projectDir, workstream) => { - const phase = args[0]; + const phase = extractPhaseArg(args); if (!phase) { return { data: { error: 'phase required for init plan-phase' } }; } @@ -623,7 +640,7 @@ export const initResume: QueryHandler = async (_args, projectDir) => { * Port of cmdInitVerifyWork from init.cjs lines 538-586. */ export const initVerifyWork: QueryHandler = async (args, projectDir, workstream) => { - const phase = args[0]; + const phase = extractPhaseArg(args); if (!phase) { return { data: { error: 'phase required for init verify-work' } }; } @@ -660,7 +677,7 @@ export const initVerifyWork: QueryHandler = async (args, projectDir, workstream) * Port of cmdInitPhaseOp from init.cjs lines 588-697. */ export const initPhaseOp: QueryHandler = async (args, projectDir, workstream) => { - const phase = args[0]; + const phase = extractPhaseArg(args); if (!phase) { return { data: { error: 'phase required for init phase-op' } }; }