diff --git a/.changeset/proud-elks-snooze.md b/.changeset/proud-elks-snooze.md new file mode 100644 index 000000000..6acaa7f1b --- /dev/null +++ b/.changeset/proud-elks-snooze.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 13 +--- +**`gsd-sdk query --pick` now emits raw string scalars (CJS parity restored)** — the SDK dispatch formatter previously JSON-stringified picked values, which wrapped string outputs in literal quotes and broke shell capture/path composition. The pick formatter now returns raw string scalars with newline while preserving JSON output for non-string picks. (#13) diff --git a/sdk/src/query/query-dispatch.test.ts b/sdk/src/query/query-dispatch.test.ts index 68cbff17f..e78395b3d 100644 --- a/sdk/src/query/query-dispatch.test.ts +++ b/sdk/src/query/query-dispatch.test.ts @@ -178,6 +178,12 @@ describe('stage: formatting', () => { expect(formatSuccess({ nested: { value: 3 } }, 'json', 'nested.value')).toBe('3\n'); }); + it('formatSuccess emits raw scalar for picked string fields', () => { + expect(formatSuccess({ slug: 'cli-agent-transcript-persistence' }, 'json', 'slug')).toBe( + 'cli-agent-transcript-persistence\n', + ); + }); + it('formatPick returns input unchanged when no pickField provided', () => { const input = { ok: true }; expect(formatPick(input)).toBe(input); @@ -362,6 +368,23 @@ describe('end-to-end IR contract', () => { expect(out.exit_code).toBe(0); }); + it('applies --pick to native json string output without quote wrapping', async () => { + const registry = createRegistry(); + const out = await runQueryDispatch({ + registry, + projectDir: tmpDir, + cjsFallbackEnabled: true, + resolveGsdToolsPath: () => '', + dispatchNative: async () => ({ data: { slug: 'cli-agent-transcript-persistence' } }), + topology: createCommandTopology(registry), + }, ['generate-slug', 'CLI agent transcript persistence', '--pick', 'slug']); + + expect(out.ok).toBe(true); + if (!out.ok) throw new Error('expected success'); + expect(out.stdout).toBe('cli-agent-transcript-persistence\n'); + expect(out.exit_code).toBe(0); + }); + it('returns structured error for unknown command when fallback disabled', async () => { const registry = createRegistry(); const out = await runQueryDispatch({ diff --git a/sdk/src/query/query-dispatch.ts b/sdk/src/query/query-dispatch.ts index 42d7a0384..b58889285 100644 --- a/sdk/src/query/query-dispatch.ts +++ b/sdk/src/query/query-dispatch.ts @@ -86,6 +86,9 @@ export function formatSuccess(data: unknown, format: DispatchSuccessFormat, pick return data.endsWith('\n') ? data : `${data}\n`; } const output = formatPick(data, pickField); + if (pickField && typeof output === 'string') { + return output.endsWith('\n') ? output : `${output}\n`; + } return `${JSON.stringify(output === undefined ? null : output, null, 2)}\n`; }