diff --git a/packages/sim-cli/src/embed.test.ts b/packages/sim-cli/src/embed.test.ts index a81c9549909..3234b73c57d 100644 --- a/packages/sim-cli/src/embed.test.ts +++ b/packages/sim-cli/src/embed.test.ts @@ -97,6 +97,35 @@ describe('runEmbeddedCli', () => { expect(JSON.parse(a.stdout).data[0].id).toBe(wsA) expect(JSON.parse(b.stdout).data[0].id).toBe(wsB) }) + + it('reports a thrown error with its own exit code, as the installed CLI does', async () => { + const receipt = { + operationId: 'op-1', + requestId: 'req-1', + workspaceId: IDENTITY.workspaceId, + kind: 'workflow_import', + applied: true, + status: 'processing', + issues: [], + } + // The clock moves only when a status is served, so the wait can time out + // only after it has a receipt to print, however slow the runner is. + let now = Date.now() + vi.spyOn(Date, 'now').mockImplementation(() => now) + const result = await runEmbeddedCli( + ['--output', 'json', 'workspaces', 'operations', 'wait', 'op-1', '--wait-timeout', '60'], + { + ...IDENTITY, + transport: async () => { + now += 61_000 + return jsonResponse({ data: receipt }) + }, + } + ) + expect(result.exitCode).toBe(4) + expect(JSON.parse(result.stdout)).toMatchObject({ operationId: 'op-1', status: 'processing' }) + expect(result.stderr).toContain('OPERATION_WAIT_TIMEOUT') + }) }) describe('embedded artifact destinations', () => { diff --git a/packages/sim-cli/src/embed.ts b/packages/sim-cli/src/embed.ts index b517aa06f8b..7c8d8335abb 100644 --- a/packages/sim-cli/src/embed.ts +++ b/packages/sim-cli/src/embed.ts @@ -70,8 +70,8 @@ export function createEmbeddedClient(identity: EmbeddedCliIdentity): SimClient { /** * Runs one CLI invocation in-process. `argv` is the token list exactly as the * terminal would receive it (no leading node/binary tokens). Errors the - * installed CLI would print-and-exit-1 on come back the same way: rendered to - * stderr, exitCode 1 — never thrown. + * installed CLI would print-and-exit on come back the same way: rendered to + * stderr with the same exit code — never thrown. */ export async function runEmbeddedCli( argv: string[], @@ -191,7 +191,7 @@ function renderEmbeddedError(ctx: EmbedContext, error: unknown): number { if (error.details !== undefined) { for (const line of formatApiErrorDetails(error.details)) ctx.stderr.diagnostic(sanitize(line)) } - return 1 + return error.exitCode } ctx.stderr.diagnostic( // utils-lint-allow: this published standalone CLI cannot import the private @sim/utils package.