Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/commands/doctor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ function makeDoctorProgram(deps: DoctorDeps = {}): Command {
const program = new Command();
program.exitOverride();
program.option('--output <mode>', 'output', 'text');
program.option('--request-timeout <seconds>', 'per-request timeout in seconds');
program.addCommand(createDoctorCommand(deps));
return program;
}
Expand Down Expand Up @@ -470,6 +471,22 @@ describe('createDoctorCommand wiring', () => {
});
});

it('rejects an invalid --request-timeout with the SHARED validation message', async () => {
// Guards the drift this repo's shared helper exists to prevent: the doctor
// command once carried a private copy whose message differed from every
// other command's. Same flag, same bad input, one message.
const rejection = await makeDoctorProgram()
.parseAsync(['node', 'ts', '--request-timeout', 'abc', 'doctor'])
.catch((error: unknown) => error);
expect(rejection).toBeInstanceOf(ApiError);
expect(rejection).toMatchObject({
code: 'VALIDATION_ERROR',
exitCode: 5,
nextAction:
'Flag `--request-timeout` is invalid: "abc" is not valid — must be a positive number of seconds.',
});
});

it('accepts valid --output modes through command wiring', async () => {
writeProfile('default', { apiKey: 'sk-user-abc' }, { path: credentialsPath });
for (const mode of ['text', 'json'] as const) {
Expand Down
23 changes: 2 additions & 21 deletions src/commands/doctor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Command } from 'commander';
import {
assertValidEndpointUrl,
makeHttpClient,
parseRequestTimeoutFlag,
type CommonOptions as FactoryCommonOptions,
} from '../lib/client-factory.js';
import {
Expand All @@ -28,13 +29,7 @@ import {
normalizeEnvVar,
type Config,
} from '../lib/config.js';
import {
ApiError,
CLIError,
InterruptError,
RequestTimeoutError,
localValidationError,
} from '../lib/errors.js';
import { ApiError, CLIError, InterruptError, RequestTimeoutError } from '../lib/errors.js';
import type { FetchImpl } from '../lib/http.js';
import { globalShutdown } from '../lib/interrupt.js';
import type { CliOrgBinding, CliOrgSummary } from '../lib/org-render.js';
Expand Down Expand Up @@ -504,20 +499,6 @@ function resolveCommonOptions(command: Command, env?: NodeJS.ProcessEnv): Common
};
}

function parseRequestTimeoutFlag(raw: string | undefined): number | undefined {
if (raw === undefined) return undefined;
const seconds = Number(raw);
if (!Number.isFinite(seconds) || seconds <= 0) {
// Match the other commands: a malformed --request-timeout is a validation
// error, not a silently-ignored default.
throw localValidationError(
'request-timeout',
`must be a positive number of seconds (got "${raw}")`,
);
}
return Math.round(seconds * 1000);
}

function makeOutput(mode: OutputMode, deps: DoctorDeps): Output {
return new Output(mode, { stdout: deps.stdout, stderr: deps.stderr });
}
Loading