diff --git a/integ-tests/status.test.ts b/integ-tests/status.test.ts
index 55890847f..5381ce5cd 100644
--- a/integ-tests/status.test.ts
+++ b/integ-tests/status.test.ts
@@ -69,7 +69,7 @@ describe('status command', () => {
it('emits failure telemetry for invalid --type', async () => {
const result = await runCLI(['status', '--type', 'bogus'], projectDir, { env: telemetry.env });
- expect(result.exitCode).toBe(0);
+ expect(result.exitCode).toBe(1);
telemetry.assertMetricEmitted({
command: 'status',
exit_reason: 'failure',
@@ -80,7 +80,7 @@ describe('status command', () => {
it('emits failure telemetry for invalid --state', async () => {
const result = await runCLI(['status', '--state', 'bogus'], projectDir, { env: telemetry.env });
- expect(result.exitCode).toBe(0);
+ expect(result.exitCode).toBe(1);
telemetry.assertMetricEmitted({
command: 'status',
exit_reason: 'failure',
diff --git a/src/cli/commands/status/__tests__/command.test.ts b/src/cli/commands/status/__tests__/command.test.ts
new file mode 100644
index 000000000..55521cc56
--- /dev/null
+++ b/src/cli/commands/status/__tests__/command.test.ts
@@ -0,0 +1,77 @@
+import { handleProjectStatus, loadStatusConfig } from '../action.js';
+import { registerStatus } from '../command.js';
+import { Command } from '@commander-js/extra-typings';
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+
+const { mockRender } = vi.hoisted(() => ({
+ mockRender: vi.fn(),
+}));
+
+vi.mock('../../../tui/guards', () => ({
+ requireProject: vi.fn(),
+}));
+
+vi.mock('../../../telemetry/cli-command-run.js', () => ({
+ withCommandRunTelemetry: vi.fn((_command, _attrs, run) => run()),
+}));
+
+vi.mock('../../../operations/dataset', () => ({
+ getDatasetStatus: vi.fn(),
+}));
+
+vi.mock('../action.js', () => ({
+ handleProjectStatus: vi.fn(),
+ handleRuntimeLookup: vi.fn(),
+ loadStatusConfig: vi.fn(),
+}));
+
+vi.mock('../../../feature-flags', () => ({
+ isPreviewEnabled: () => false,
+}));
+
+vi.mock('ink', () => ({
+ Box: ({ children }: { children?: unknown }) => children,
+ Text: ({ children }: { children?: unknown }) => children,
+ render: mockRender,
+}));
+
+describe('status command validation', () => {
+ let program: Command;
+ let originalExitCode: typeof process.exitCode;
+
+ beforeEach(() => {
+ originalExitCode = process.exitCode;
+ process.exitCode = undefined;
+ program = new Command();
+ program.exitOverride();
+ registerStatus(program);
+ });
+
+ afterEach(() => {
+ process.exitCode = originalExitCode;
+ vi.clearAllMocks();
+ });
+
+ it('sets a non-zero exit code for invalid resource type', async () => {
+ await program.parseAsync(['status', '--type', 'bogus'], { from: 'user' });
+
+ expect(process.exitCode).toBe(1);
+ expect(mockRender).toHaveBeenCalled();
+ });
+
+ it('sets a non-zero exit code for invalid state', async () => {
+ await program.parseAsync(['status', '--state', 'bogus'], { from: 'user' });
+
+ expect(process.exitCode).toBe(1);
+ expect(mockRender).toHaveBeenCalled();
+ });
+
+ it('leaves exit code unset for a valid filter', async () => {
+ vi.mocked(loadStatusConfig).mockResolvedValue({} as never);
+ vi.mocked(handleProjectStatus).mockResolvedValue({ success: true, resources: [] } as never);
+
+ await program.parseAsync(['status', '--type', 'agent'], { from: 'user' });
+
+ expect(process.exitCode).toBeUndefined();
+ });
+});
diff --git a/src/cli/commands/status/command.tsx b/src/cli/commands/status/command.tsx
index dda4e226f..bafccb023 100644
--- a/src/cli/commands/status/command.tsx
+++ b/src/cli/commands/status/command.tsx
@@ -96,6 +96,7 @@ export const registerStatus = (program: Command) => {
error: new ValidationError(msg),
}));
render({msg});
+ process.exitCode = 1;
return;
}
@@ -107,6 +108,7 @@ export const registerStatus = (program: Command) => {
error: new ValidationError(msg),
}));
render({msg});
+ process.exitCode = 1;
return;
}