codex-plugin-doctor 1.46.0 → 1.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -5
- package/dist/core/attestation.d.ts +1 -0
- package/dist/core/attestation.js +1 -1
- package/dist/core/external-validation-corpus.d.ts +88 -0
- package/dist/core/external-validation-corpus.js +271 -0
- package/dist/core/init-git-hooks.js +43 -4
- package/dist/core/output-contract.js +8 -2
- package/dist/core/release-check.d.ts +18 -2
- package/dist/core/release-check.js +90 -3
- package/dist/core/release-evidence.d.ts +5 -2
- package/dist/core/release-evidence.js +12 -2
- package/dist/core/runtime-plan.d.ts +5 -1
- package/dist/core/runtime-plan.js +13 -1
- package/dist/core/runtime-policy.d.ts +5 -1
- package/dist/core/runtime-policy.js +3 -2
- package/dist/core/runtime-probe.d.ts +2 -1
- package/dist/core/runtime-probe.js +100 -18
- package/dist/core/runtime-sandbox.d.ts +21 -0
- package/dist/core/runtime-sandbox.js +68 -0
- package/dist/core/validate-plugin.js +19 -8
- package/dist/core/validation-corpus.d.ts +4 -2
- package/dist/core/validation-corpus.js +12 -1
- package/dist/domain/types.d.ts +11 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/reporting/render-json-report.js +3 -0
- package/dist/reporting/render-markdown-report.js +3 -0
- package/dist/reporting/render-text-report.js +3 -0
- package/dist/run-cli.js +151 -20
- package/package.json +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export class RuntimeSandboxError extends Error {
|
|
3
|
+
}
|
|
4
|
+
export const DOCKER_RUNTIME_STARTUP_TIMEOUT_MS = 60_000;
|
|
5
|
+
export const DOCKER_RUNTIME_IMAGE = "node:22-bookworm-slim@sha256:6c74791e557ce11fc957704f6d4fe134a7bc8d6f5ca4403205b2966bd488f6b3";
|
|
6
|
+
export function buildRuntimeLaunch(input) {
|
|
7
|
+
if (input.sandbox !== "docker") {
|
|
8
|
+
throw new RuntimeSandboxError("Unsupported sandbox mode.");
|
|
9
|
+
}
|
|
10
|
+
if (!/^(node|node\.exe)$/i.test(path.basename(input.command))) {
|
|
11
|
+
throw new RuntimeSandboxError("Docker sandbox supports Node.js stdio commands only.");
|
|
12
|
+
}
|
|
13
|
+
const relativeCwd = path.relative(input.packageRoot, input.cwd);
|
|
14
|
+
if (relativeCwd === ".." ||
|
|
15
|
+
relativeCwd.startsWith(`..${path.sep}`) ||
|
|
16
|
+
path.isAbsolute(relativeCwd)) {
|
|
17
|
+
throw new RuntimeSandboxError("Runtime cwd escapes the package root.");
|
|
18
|
+
}
|
|
19
|
+
if (input.packageRoot.includes(",")) {
|
|
20
|
+
throw new RuntimeSandboxError("Docker sandbox does not support commas in package paths.");
|
|
21
|
+
}
|
|
22
|
+
const workdir = relativeCwd
|
|
23
|
+
? `/workspace/${relativeCwd.split(path.sep).join("/")}`
|
|
24
|
+
: "/workspace";
|
|
25
|
+
return {
|
|
26
|
+
command: "docker",
|
|
27
|
+
args: [
|
|
28
|
+
"run",
|
|
29
|
+
"--rm",
|
|
30
|
+
"-i",
|
|
31
|
+
"--init",
|
|
32
|
+
"--name",
|
|
33
|
+
input.containerName,
|
|
34
|
+
"--network",
|
|
35
|
+
"none",
|
|
36
|
+
"--read-only",
|
|
37
|
+
"--cap-drop",
|
|
38
|
+
"ALL",
|
|
39
|
+
"--security-opt",
|
|
40
|
+
"no-new-privileges",
|
|
41
|
+
"--user",
|
|
42
|
+
"65532:65532",
|
|
43
|
+
"--pids-limit",
|
|
44
|
+
"64",
|
|
45
|
+
"--memory",
|
|
46
|
+
"256m",
|
|
47
|
+
"--cpus",
|
|
48
|
+
"1",
|
|
49
|
+
"--tmpfs",
|
|
50
|
+
"/tmp:rw,noexec,nosuid,size=16m",
|
|
51
|
+
"--mount",
|
|
52
|
+
`type=bind,source=${input.packageRoot},target=/workspace,readonly`,
|
|
53
|
+
"--workdir",
|
|
54
|
+
workdir,
|
|
55
|
+
DOCKER_RUNTIME_IMAGE,
|
|
56
|
+
"node",
|
|
57
|
+
...input.args
|
|
58
|
+
],
|
|
59
|
+
cwd: input.packageRoot,
|
|
60
|
+
containerName: input.containerName,
|
|
61
|
+
evidence: {
|
|
62
|
+
backend: "docker",
|
|
63
|
+
image: DOCKER_RUNTIME_IMAGE,
|
|
64
|
+
network: "none",
|
|
65
|
+
packageMount: "read_only"
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -404,18 +404,23 @@ export async function validatePlugin(targetPath, options = {}) {
|
|
|
404
404
|
findings: withFindingFingerprints([await buildMissingManifestFailure(rootPath)], rootPath)
|
|
405
405
|
};
|
|
406
406
|
}
|
|
407
|
-
const
|
|
407
|
+
const staticFindings = [
|
|
408
|
+
...validateRequiredManifestFields(discoveredPackage),
|
|
409
|
+
...(await validateSkillsDirectory(discoveredPackage)),
|
|
410
|
+
...(await validateSkillDefinitions(discoveredPackage)),
|
|
411
|
+
...(await validateMcpConfig(discoveredPackage))
|
|
412
|
+
];
|
|
413
|
+
const staticFailed = staticFindings.some((finding) => finding.severity === "fail");
|
|
414
|
+
const runtimeResult = options.runtime && !staticFailed
|
|
408
415
|
? await probeRuntime(discoveredPackage, {
|
|
409
416
|
startupTimeoutMs: options.runtimeStartupTimeoutMs,
|
|
417
|
+
sandbox: options.runtimeSandbox,
|
|
410
418
|
transcript: options.runtimeTranscript
|
|
411
419
|
})
|
|
412
420
|
: null;
|
|
413
421
|
const findings = [
|
|
414
|
-
...
|
|
415
|
-
...(
|
|
416
|
-
...(await validateSkillDefinitions(discoveredPackage)),
|
|
417
|
-
...(await validateMcpConfig(discoveredPackage)),
|
|
418
|
-
...(runtimeResult ? runtimeResult.findings : [])
|
|
422
|
+
...staticFindings,
|
|
423
|
+
...(runtimeResult?.findings ?? [])
|
|
419
424
|
];
|
|
420
425
|
const fingerprintedFindings = withFindingFingerprints(findings, discoveredPackage.rootPath);
|
|
421
426
|
const hasFailures = fingerprintedFindings.some((finding) => finding.severity === "fail");
|
|
@@ -426,7 +431,10 @@ export async function validatePlugin(targetPath, options = {}) {
|
|
|
426
431
|
status: "pass",
|
|
427
432
|
exitCode: 0,
|
|
428
433
|
findings: [],
|
|
429
|
-
...(runtimeResult ? { runtimeScorecard: runtimeResult.scorecard } : {})
|
|
434
|
+
...(runtimeResult ? { runtimeScorecard: runtimeResult.scorecard } : {}),
|
|
435
|
+
...(runtimeResult?.execution
|
|
436
|
+
? { runtimeExecution: runtimeResult.execution }
|
|
437
|
+
: {})
|
|
430
438
|
};
|
|
431
439
|
}
|
|
432
440
|
return {
|
|
@@ -434,6 +442,9 @@ export async function validatePlugin(targetPath, options = {}) {
|
|
|
434
442
|
status: hasFailures ? "fail" : "warn",
|
|
435
443
|
exitCode: hasFailures ? 1 : 0,
|
|
436
444
|
findings: fingerprintedFindings,
|
|
437
|
-
...(runtimeResult ? { runtimeScorecard: runtimeResult.scorecard } : {})
|
|
445
|
+
...(runtimeResult ? { runtimeScorecard: runtimeResult.scorecard } : {}),
|
|
446
|
+
...(runtimeResult?.execution
|
|
447
|
+
? { runtimeExecution: runtimeResult.execution }
|
|
448
|
+
: {})
|
|
438
449
|
};
|
|
439
450
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type PackageAnalysisOptions } from "./package-analysis.js";
|
|
2
|
+
import type { ExternalValidationCorpusReport } from "./external-validation-corpus.js";
|
|
2
3
|
type ValidationStatus = "pass" | "warn" | "fail";
|
|
3
4
|
export interface ValidationCorpusCaseDefinition {
|
|
4
5
|
id: string;
|
|
@@ -36,6 +37,7 @@ export interface ValidationCorpusCaseResult {
|
|
|
36
37
|
export interface DoctorValidationCorpusReport {
|
|
37
38
|
schemaVersion: "1.0.0";
|
|
38
39
|
kind: "doctor.validation.corpus";
|
|
40
|
+
corpusType?: "bundled";
|
|
39
41
|
generatedAt: string;
|
|
40
42
|
version: string;
|
|
41
43
|
summary: {
|
|
@@ -51,8 +53,8 @@ export interface BuildDoctorValidationCorpusOptions {
|
|
|
51
53
|
environment?: PackageAnalysisOptions["environment"];
|
|
52
54
|
}
|
|
53
55
|
export declare function buildDoctorValidationCorpusReport(options?: BuildDoctorValidationCorpusOptions): Promise<DoctorValidationCorpusReport>;
|
|
54
|
-
export declare function renderDoctorValidationCorpusJson(report: DoctorValidationCorpusReport): string;
|
|
55
|
-
export declare function renderDoctorValidationCorpusReport(report: DoctorValidationCorpusReport, options?: {
|
|
56
|
+
export declare function renderDoctorValidationCorpusJson(report: DoctorValidationCorpusReport | ExternalValidationCorpusReport): string;
|
|
57
|
+
export declare function renderDoctorValidationCorpusReport(report: DoctorValidationCorpusReport | ExternalValidationCorpusReport, options?: {
|
|
56
58
|
outputPath?: string | null;
|
|
57
59
|
}): string;
|
|
58
60
|
export {};
|
|
@@ -163,8 +163,19 @@ export function renderDoctorValidationCorpusReport(report, options = {}) {
|
|
|
163
163
|
}
|
|
164
164
|
lines.push("", "Cases", "-----");
|
|
165
165
|
for (const caseResult of report.cases) {
|
|
166
|
+
const actual = caseResult.actual;
|
|
167
|
+
let status;
|
|
168
|
+
let findingCount;
|
|
169
|
+
if ("status" in actual) {
|
|
170
|
+
status = actual.status;
|
|
171
|
+
findingCount = actual.findings.length;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
status = actual.validationStatus;
|
|
175
|
+
findingCount = actual.findingIds.length;
|
|
176
|
+
}
|
|
166
177
|
lines.push(`${caseResult.id}: ${caseResult.expectationMatched ? "PASS" : "FAIL"} ` +
|
|
167
|
-
`(${
|
|
178
|
+
`(${status.toUpperCase()}, ${findingCount} findings)`);
|
|
168
179
|
}
|
|
169
180
|
return lines.join("\n");
|
|
170
181
|
}
|
package/dist/domain/types.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export interface CheckResult {
|
|
|
30
30
|
suppressedFindings?: SuppressedFinding[];
|
|
31
31
|
suppressionSummary?: SuppressionSummary;
|
|
32
32
|
runtimeScorecard?: RuntimeScorecard;
|
|
33
|
+
runtimeExecution?: RuntimeExecutionEvidence;
|
|
33
34
|
baselinedFindings?: Finding[];
|
|
34
35
|
baselineSummary?: BaselineSummary;
|
|
35
36
|
}
|
|
@@ -42,6 +43,7 @@ export interface CheckOptions {
|
|
|
42
43
|
runtime?: boolean;
|
|
43
44
|
runtimeTranscript?: (line: string) => void;
|
|
44
45
|
runtimeStartupTimeoutMs?: number;
|
|
46
|
+
runtimeSandbox?: RuntimeSandboxMode;
|
|
45
47
|
}
|
|
46
48
|
export interface PluginManifest {
|
|
47
49
|
name?: string;
|
|
@@ -61,6 +63,7 @@ export interface JsonReportSummary {
|
|
|
61
63
|
exitCode: 0 | 1;
|
|
62
64
|
runtimeProbeEnabled: boolean;
|
|
63
65
|
runtimeScorecard?: RuntimeScorecard;
|
|
66
|
+
runtimeExecution?: RuntimeExecutionEvidence;
|
|
64
67
|
findingCounts: {
|
|
65
68
|
fail: number;
|
|
66
69
|
warn: number;
|
|
@@ -91,4 +94,12 @@ export interface RuntimeScorecard {
|
|
|
91
94
|
export interface RuntimeProbeResult {
|
|
92
95
|
findings: Finding[];
|
|
93
96
|
scorecard: RuntimeScorecard;
|
|
97
|
+
execution?: RuntimeExecutionEvidence;
|
|
98
|
+
}
|
|
99
|
+
export type RuntimeSandboxMode = "docker";
|
|
100
|
+
export interface RuntimeExecutionEvidence {
|
|
101
|
+
backend: "native" | "docker";
|
|
102
|
+
image: string | null;
|
|
103
|
+
network: "host" | "none";
|
|
104
|
+
packageMount: "host" | "read_only";
|
|
94
105
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { buildDoctorSnapshot, renderDoctorSnapshot, renderDoctorSnapshotJson, ty
|
|
|
10
10
|
export { buildDoctorRecommendations, renderDoctorRecommendations, renderDoctorRecommendationsJson, type DoctorRecommendationAction, type DoctorRecommendationsReport } from "./core/doctor-recommendations.js";
|
|
11
11
|
export { buildDoctorExportBundle, renderDoctorExportBundle, renderDoctorExportBundleJson, type DoctorExportBundle } from "./core/doctor-export-bundle.js";
|
|
12
12
|
export { buildDoctorAttestation, renderDoctorAttestation, renderDoctorAttestationJson, renderDoctorAttestationVerification, renderDoctorAttestationVerificationJson, verifyDoctorAttestation, type DoctorAttestation, type DoctorAttestationVerificationCheck, type DoctorAttestationVerificationReport, type Digest, type PackageFingerprint } from "./core/attestation.js";
|
|
13
|
+
export { buildExternalValidationCorpusReport, ExternalCorpusManifestError, loadExternalCorpusManifest, type BuildExternalValidationCorpusOptions, type ExternalCorpusCaseResult, type ExternalCorpusClassificationCounts, type ExternalCorpusFindingReview, type ExternalCorpusManifest, type ExternalCorpusMode, type ExternalCorpusProfile, type ExternalCorpusSourceType, type ExternalValidationCorpusReport, type FindingReviewClassification } from "./core/external-validation-corpus.js";
|
|
13
14
|
export { buildDoctorOutputContract, renderDoctorOutputContract, renderDoctorOutputContractJson, type DoctorOutputContract, type OutputContractRule, type OutputContractSchema } from "./core/output-contract.js";
|
|
14
15
|
export { buildDoctorValidationCorpusReport, renderDoctorValidationCorpusJson, renderDoctorValidationCorpusReport, type BuildDoctorValidationCorpusOptions, type DoctorValidationCorpusReport, type ValidationCorpusCaseDefinition, type ValidationCorpusCaseResult } from "./core/validation-corpus.js";
|
|
15
16
|
export { buildDoctorExportBundleFromAnalysis, buildDoctorRecommendationsFromAnalysis, buildPackageAnalysis, type PackageAnalysis, type PackageAnalysisOptions, type PackageAnalysisStage, type PackageAnalysisTiming } from "./core/package-analysis.js";
|
|
@@ -29,5 +30,5 @@ export { buildDepAudit, buildDepAuditRecommendations, renderDepAudit, renderDepA
|
|
|
29
30
|
export { initGitHooks, removeGitHooks, type InitGitHooksResult, type RemoveGitHooksResult } from "./core/init-git-hooks.js";
|
|
30
31
|
export { generateCompletion, type CompletionShell } from "./core/shell-completion.js";
|
|
31
32
|
export { validateConfigFile, renderConfigValidation, renderConfigValidationJson, type ConfigValidationFinding, type ConfigValidationReport } from "./core/config-validate.js";
|
|
32
|
-
export { buildReleaseCheck, renderReleaseCheck, renderReleaseCheckJson, type ReleaseCheckReport } from "./core/release-check.js";
|
|
33
|
+
export { assertReleaseMetadataSync, buildReleaseCheck, buildReleaseMetadataCheck, renderReleaseCheck, renderReleaseCheckJson, type BuildReleaseCheckOptions, type ReleaseMetadataCheck, type ReleaseCheckReport } from "./core/release-check.js";
|
|
33
34
|
export declare function runCheck(targetPath: string, options?: CheckOptions): Promise<CheckResult>;
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { buildDoctorSnapshot, renderDoctorSnapshot, renderDoctorSnapshotJson } f
|
|
|
10
10
|
export { buildDoctorRecommendations, renderDoctorRecommendations, renderDoctorRecommendationsJson } from "./core/doctor-recommendations.js";
|
|
11
11
|
export { buildDoctorExportBundle, renderDoctorExportBundle, renderDoctorExportBundleJson } from "./core/doctor-export-bundle.js";
|
|
12
12
|
export { buildDoctorAttestation, renderDoctorAttestation, renderDoctorAttestationJson, renderDoctorAttestationVerification, renderDoctorAttestationVerificationJson, verifyDoctorAttestation } from "./core/attestation.js";
|
|
13
|
+
export { buildExternalValidationCorpusReport, ExternalCorpusManifestError, loadExternalCorpusManifest } from "./core/external-validation-corpus.js";
|
|
13
14
|
export { buildDoctorOutputContract, renderDoctorOutputContract, renderDoctorOutputContractJson } from "./core/output-contract.js";
|
|
14
15
|
export { buildDoctorValidationCorpusReport, renderDoctorValidationCorpusJson, renderDoctorValidationCorpusReport } from "./core/validation-corpus.js";
|
|
15
16
|
export { buildDoctorExportBundleFromAnalysis, buildDoctorRecommendationsFromAnalysis, buildPackageAnalysis } from "./core/package-analysis.js";
|
|
@@ -29,7 +30,7 @@ export { buildDepAudit, buildDepAuditRecommendations, renderDepAudit, renderDepA
|
|
|
29
30
|
export { initGitHooks, removeGitHooks } from "./core/init-git-hooks.js";
|
|
30
31
|
export { generateCompletion } from "./core/shell-completion.js";
|
|
31
32
|
export { validateConfigFile, renderConfigValidation, renderConfigValidationJson } from "./core/config-validate.js";
|
|
32
|
-
export { buildReleaseCheck, renderReleaseCheck, renderReleaseCheckJson } from "./core/release-check.js";
|
|
33
|
+
export { assertReleaseMetadataSync, buildReleaseCheck, buildReleaseMetadataCheck, renderReleaseCheck, renderReleaseCheckJson } from "./core/release-check.js";
|
|
33
34
|
export async function runCheck(targetPath, options = {}) {
|
|
34
35
|
return validatePlugin(targetPath, options);
|
|
35
36
|
}
|
|
@@ -12,6 +12,9 @@ export function buildJsonReport(result, options) {
|
|
|
12
12
|
...(result.runtimeScorecard
|
|
13
13
|
? { runtimeScorecard: result.runtimeScorecard }
|
|
14
14
|
: {}),
|
|
15
|
+
...(result.runtimeExecution
|
|
16
|
+
? { runtimeExecution: result.runtimeExecution }
|
|
17
|
+
: {}),
|
|
15
18
|
findingCounts: {
|
|
16
19
|
fail: failCount,
|
|
17
20
|
warn: warnCount,
|
|
@@ -23,6 +23,9 @@ export function buildMarkdownReport(result, options) {
|
|
|
23
23
|
if (result.baselineSummary) {
|
|
24
24
|
lines.push(`| Baseline New | ${result.baselineSummary.new} |`, `| Baseline Matched | ${result.baselineSummary.matched} |`, `| Baseline Resolved | ${result.baselineSummary.resolved} |`);
|
|
25
25
|
}
|
|
26
|
+
if (result.runtimeExecution) {
|
|
27
|
+
lines.push("", `Runtime backend: ${result.runtimeExecution.backend.toUpperCase()}`, `Runtime isolation: network=${result.runtimeExecution.network}, package=${result.runtimeExecution.packageMount}`);
|
|
28
|
+
}
|
|
26
29
|
if (result.findings.length === 0 && !result.suppressedFindings?.length) {
|
|
27
30
|
lines.push("", result.baselineSummary ? "No new findings." : "No findings.");
|
|
28
31
|
return lines.join("\n");
|
|
@@ -42,6 +42,9 @@ export function renderTextReport(result, options = {}) {
|
|
|
42
42
|
if (result.baselineSummary) {
|
|
43
43
|
lines.push(`Baseline: ${result.baselineSummary.new} new, ${result.baselineSummary.matched} matched, ${result.baselineSummary.resolved} resolved`);
|
|
44
44
|
}
|
|
45
|
+
if (result.runtimeExecution) {
|
|
46
|
+
lines.push(`Runtime backend: ${result.runtimeExecution.backend.toUpperCase()}`, `Runtime isolation: network=${result.runtimeExecution.network}, package=${result.runtimeExecution.packageMount}`);
|
|
47
|
+
}
|
|
45
48
|
if (result.findings.length === 0 && !result.suppressedFindings?.length) {
|
|
46
49
|
if (result.runtimeScorecard) {
|
|
47
50
|
lines.push("", "Runtime Scorecard", "----------------");
|
package/dist/run-cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { buildDoctorExportBundle, renderDoctorExportBundle, renderDoctorExportBu
|
|
|
20
20
|
import { buildDoctorAttestation, renderDoctorAttestation, renderDoctorAttestationJson, renderDoctorAttestationVerification, renderDoctorAttestationVerificationJson, verifyDoctorAttestation } from "./core/attestation.js";
|
|
21
21
|
import { buildDoctorOutputContract, renderDoctorOutputContract, renderDoctorOutputContractJson } from "./core/output-contract.js";
|
|
22
22
|
import { buildDoctorValidationCorpusReport, renderDoctorValidationCorpusJson, renderDoctorValidationCorpusReport } from "./core/validation-corpus.js";
|
|
23
|
+
import { buildExternalValidationCorpusReport, ExternalCorpusManifestError } from "./core/external-validation-corpus.js";
|
|
23
24
|
import { buildDoctorPerformanceReport, renderDoctorPerformanceReport, renderDoctorPerformanceReportJson } from "./core/performance-report.js";
|
|
24
25
|
import { buildDoctorRuntimePlan, evaluateRuntimeApproval, renderDoctorRuntimePlan, renderDoctorRuntimePlanMarkdown, renderDoctorRuntimePlanJson, runtimeApprovalPassed } from "./core/runtime-plan.js";
|
|
25
26
|
import { buildDoctorRuntimePolicyReport, renderDoctorRuntimePolicy, renderDoctorRuntimePolicyJson } from "./core/runtime-policy.js";
|
|
@@ -81,8 +82,24 @@ const defaultIo = {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
};
|
|
85
|
+
class CliUsageError extends Error {
|
|
86
|
+
}
|
|
87
|
+
function parseRuntimeSandbox(flags, options = { requireRuntime: true }) {
|
|
88
|
+
const index = flags.indexOf("--sandbox");
|
|
89
|
+
if (index === -1) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const value = flags[index + 1];
|
|
93
|
+
if (value !== "docker") {
|
|
94
|
+
throw new CliUsageError("Expected --sandbox docker.");
|
|
95
|
+
}
|
|
96
|
+
if (options.requireRuntime !== false && !flags.includes("--runtime")) {
|
|
97
|
+
throw new CliUsageError("--sandbox docker requires --runtime.");
|
|
98
|
+
}
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
84
101
|
function printUsage(io) {
|
|
85
|
-
io.writeStderr("Usage: codex-plugin-doctor check <path|--installed> [filter] [--policy codex-publish|mcp-strict|security] [--compat] [--json|--markdown|--badge-json|--badge-markdown] [--output <path>] [--history <path>] [--runtime] [--require-runtime-approval --runtime-approval-digest <digest>] [--verbose-runtime] [--explain] [--no-animations] [--ascii] [--changed-since <ref>]\n codex-plugin-doctor audit --installed [filter] [--policy codex-publish|mcp-strict|security] [--security] [--compat] [--json] [--output <path>] [--cache] [--changed]\n codex-plugin-doctor audit deps <path> [--policy codex-publish|mcp-strict|security] [--recommend] [--json|--sarif] [--output <path>]\n codex-plugin-doctor mcp <path> [--json] [--output <path>]\n codex-plugin-doctor security <path> [--policy security] [--json|--scorecard]\n codex-plugin-doctor compat <path> [--all|--client <client>] [--json] [--scorecard] [--output <path>] [--install-preview|--apply --backup]\n codex-plugin-doctor suppress add <path> [--fingerprint <sha256> --reason <text> --expires-at YYYY-MM-DD] [--config <path>] [--json]\n codex-plugin-doctor suppress list <path> [--config <path>] [--json]\n codex-plugin-doctor suppress remove <path> [--fingerprint <sha256>|--index <n>] [--config <path>] [--json]\n codex-plugin-doctor fix <path> (--dry-run|--interactive --backup|--apply --backup)\n codex-plugin-doctor history <history.jsonl> [--json] [--fail-on-regression]\n codex-plugin-doctor watch <path> [--runtime] [--json] [--output <path>] [--debounce-ms <ms>] [--max-iterations <n>] [--fail-fast] [--accumulate-json <path>]\n codex-plugin-doctor doctor [npm <package>|contract|corpus|runtime-plan <path> [--json|--markdown] [--output <path>]|runtime-policy <path> [--json] [--output <path>]|review-bundle <path> --output <dir> --sign-key-env NAME [--json] [--allow-dirty] [--allow-untagged]|review-bundle verify <bundle-dir> --target <path> --sign-key-env NAME [--json] [--output <path>] [--failures-only]|review-bundle diff --before <dir> --after <dir> [--json]|attest <path> [--sign-key-env NAME]|attest verify <attestation.json> --target <path> --sign-key-env NAME|release-evidence <path> --sign-key-env NAME [--allow-dirty] [--allow-untagged] [--require-runtime-approval --runtime-approval-digest <digest>]|release-evidence verify <evidence.json> --target <path> --sign-key-env NAME|release-evidence asset <path> --tag <tag> --output <evidence.json> --sign-key-env NAME [--upload]|mcp <path>|inspector <path>|diff --before <path> --after <path>|recommend <path>|trust <path>|perf <path> [--max-total-ms <ms>] [--max-stage-ms stage=ms]|export --bundle <path>|snapshot|clients|--json|--update-check]\n codex-plugin-doctor init [path] [--template skill-only|mcp-stdio|mcp-http|full-runtime]\n codex-plugin-doctor init-ci [path]\n codex-plugin-doctor init-git-hooks [path] [--force] [--json]\n codex-plugin-doctor init-git-hooks [path] --remove [--json]\n codex-plugin-doctor completion bash|zsh|fish\n codex-plugin-doctor config validate <path> [--json]\n codex-plugin-doctor release check <path> [--json]\n codex-plugin-doctor self-test\n codex-plugin-doctor list --installed\n codex-plugin-doctor explain <finding-id>\n codex-plugin-doctor --version\n\nFirst run:\n codex-plugin-doctor doctor\n codex-plugin-doctor self-test\n codex-plugin-doctor init my-plugin\n codex-plugin-doctor check . --runtime --explain");
|
|
102
|
+
io.writeStderr("Usage: codex-plugin-doctor check <path|--installed> [filter] [--policy codex-publish|mcp-strict|security] [--compat] [--json|--markdown|--badge-json|--badge-markdown] [--output <path>] [--history <path>] [--runtime] [--sandbox docker] [--require-runtime-approval --runtime-approval-digest <digest>] [--verbose-runtime] [--explain] [--no-animations] [--ascii] [--changed-since <ref>]\n codex-plugin-doctor audit --installed [filter] [--policy codex-publish|mcp-strict|security] [--security] [--compat] [--json] [--output <path>] [--cache] [--changed]\n codex-plugin-doctor audit deps <path> [--policy codex-publish|mcp-strict|security] [--recommend] [--json|--sarif] [--output <path>]\n codex-plugin-doctor mcp <path> [--json] [--output <path>]\n codex-plugin-doctor security <path> [--policy security] [--json|--scorecard]\n codex-plugin-doctor compat <path> [--all|--client <client>] [--json] [--scorecard] [--output <path>] [--install-preview|--apply --backup]\n codex-plugin-doctor suppress add <path> [--fingerprint <sha256> --reason <text> --expires-at YYYY-MM-DD] [--config <path>] [--json]\n codex-plugin-doctor suppress list <path> [--config <path>] [--json]\n codex-plugin-doctor suppress remove <path> [--fingerprint <sha256>|--index <n>] [--config <path>] [--json]\n codex-plugin-doctor fix <path> (--dry-run|--interactive --backup|--apply --backup)\n codex-plugin-doctor history <history.jsonl> [--json] [--fail-on-regression]\n codex-plugin-doctor watch <path> [--runtime] [--json] [--output <path>] [--debounce-ms <ms>] [--max-iterations <n>] [--fail-fast] [--accumulate-json <path>]\n codex-plugin-doctor doctor [npm <package>|contract|corpus [--manifest <corpus.json>] [--json] [--output <path>]|runtime-plan <path> [--runtime --sandbox docker] [--json|--markdown] [--output <path>]|runtime-policy <path> [--runtime --sandbox docker] [--json] [--output <path>]|review-bundle <path> --output <dir> --sign-key-env NAME [--json] [--allow-dirty] [--allow-untagged]|review-bundle verify <bundle-dir> --target <path> --sign-key-env NAME [--json] [--output <path>] [--failures-only]|review-bundle diff --before <dir> --after <dir> [--json]|attest <path> [--sign-key-env NAME]|attest verify <attestation.json> --target <path> --sign-key-env NAME|release-evidence <path> --sign-key-env NAME [--runtime --sandbox docker] [--allow-dirty] [--allow-untagged] [--require-runtime-approval --runtime-approval-digest <digest>]|release-evidence verify <evidence.json> --target <path> --sign-key-env NAME|release-evidence asset <path> --tag <tag> --output <evidence.json> --sign-key-env NAME [--upload]|mcp <path>|inspector <path>|diff --before <path> --after <path>|recommend <path>|trust <path>|perf <path> [--max-total-ms <ms>] [--max-stage-ms stage=ms]|export --bundle <path>|snapshot|clients|--json|--update-check]\n codex-plugin-doctor init [path] [--template skill-only|mcp-stdio|mcp-http|full-runtime]\n codex-plugin-doctor init-ci [path]\n codex-plugin-doctor init-git-hooks [path] [--force] [--json]\n codex-plugin-doctor init-git-hooks [path] --remove [--json]\n codex-plugin-doctor completion bash|zsh|fish\n codex-plugin-doctor config validate <path> [--json]\n codex-plugin-doctor release check <path> [--json] [--runtime --sandbox docker]\n codex-plugin-doctor self-test\n codex-plugin-doctor list --installed\n codex-plugin-doctor explain <finding-id>\n codex-plugin-doctor --version\n\nFirst run:\n codex-plugin-doctor doctor\n codex-plugin-doctor self-test\n codex-plugin-doctor init my-plugin\n codex-plugin-doctor check . --runtime --explain");
|
|
86
103
|
io.writeStderr("Suppression governance: codex-plugin-doctor suppress list <path> [--fail-on-expired] [--fail-on-invalid] [--warn-expiring-within-days <days>]\n codex-plugin-doctor suppress prune <path> [--apply] [--json]");
|
|
87
104
|
io.writeStderr("Baseline gating: codex-plugin-doctor baseline create <path> --output <path> [--runtime]\n codex-plugin-doctor check <path> --baseline <path>");
|
|
88
105
|
}
|
|
@@ -805,6 +822,17 @@ function parseSelectedFixActionIndexes(answer, actionCount) {
|
|
|
805
822
|
}
|
|
806
823
|
export async function runCli(args, io = defaultIo, options = {}) {
|
|
807
824
|
const [command, maybePath, ...remainingArgs] = args;
|
|
825
|
+
const runtimeSandboxSupported = (command === "check" &&
|
|
826
|
+
!args.includes("--installed") &&
|
|
827
|
+
!args.includes("--changed-since")) ||
|
|
828
|
+
(command === "release" && maybePath === "check") ||
|
|
829
|
+
(command === "doctor" &&
|
|
830
|
+
(["runtime-plan", "runtime-policy"].includes(maybePath ?? "") ||
|
|
831
|
+
(maybePath === "release-evidence" && remainingArgs[0] !== "verify")));
|
|
832
|
+
if (args.includes("--sandbox") && !runtimeSandboxSupported) {
|
|
833
|
+
io.writeStderr("--sandbox is supported only by single-package check, release check, runtime-plan, runtime-policy, and release-evidence.");
|
|
834
|
+
return 2;
|
|
835
|
+
}
|
|
808
836
|
if (command === "--version" || command === "-v" || command === "version") {
|
|
809
837
|
io.writeStdout(packageVersion);
|
|
810
838
|
return 0;
|
|
@@ -933,6 +961,14 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
933
961
|
const markdownOutput = runtimePlanFlags.includes("--markdown");
|
|
934
962
|
const outputIndex = runtimePlanFlags.indexOf("--output");
|
|
935
963
|
const outputPath = outputIndex === -1 ? null : runtimePlanFlags[outputIndex + 1];
|
|
964
|
+
let runtimeSandbox;
|
|
965
|
+
try {
|
|
966
|
+
runtimeSandbox = parseRuntimeSandbox(runtimePlanFlags, { requireRuntime: false });
|
|
967
|
+
}
|
|
968
|
+
catch (error) {
|
|
969
|
+
io.writeStderr(error.message);
|
|
970
|
+
return 2;
|
|
971
|
+
}
|
|
936
972
|
if (!targetPath) {
|
|
937
973
|
io.writeStderr("Missing target path for runtime plan.");
|
|
938
974
|
return 2;
|
|
@@ -945,7 +981,7 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
945
981
|
io.writeStderr("Use either --json or --markdown, not both.");
|
|
946
982
|
return 2;
|
|
947
983
|
}
|
|
948
|
-
const plan = await buildDoctorRuntimePlan(targetPath);
|
|
984
|
+
const plan = await buildDoctorRuntimePlan(targetPath, new Date().toISOString(), runtimeSandbox ? { sandbox: runtimeSandbox } : {});
|
|
949
985
|
const renderedPlan = jsonOutput
|
|
950
986
|
? renderDoctorRuntimePlanJson(plan)
|
|
951
987
|
: markdownOutput
|
|
@@ -965,6 +1001,14 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
965
1001
|
const jsonOutput = runtimePolicyFlags.includes("--json");
|
|
966
1002
|
const outputIndex = runtimePolicyFlags.indexOf("--output");
|
|
967
1003
|
const outputPath = outputIndex === -1 ? null : runtimePolicyFlags[outputIndex + 1];
|
|
1004
|
+
let runtimeSandbox;
|
|
1005
|
+
try {
|
|
1006
|
+
runtimeSandbox = parseRuntimeSandbox(runtimePolicyFlags, { requireRuntime: false });
|
|
1007
|
+
}
|
|
1008
|
+
catch (error) {
|
|
1009
|
+
io.writeStderr(error.message);
|
|
1010
|
+
return 2;
|
|
1011
|
+
}
|
|
968
1012
|
if (!targetPath) {
|
|
969
1013
|
io.writeStderr("Missing target path for runtime policy.");
|
|
970
1014
|
return 2;
|
|
@@ -973,7 +1017,7 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
973
1017
|
io.writeStderr("Missing path after --output.");
|
|
974
1018
|
return 2;
|
|
975
1019
|
}
|
|
976
|
-
const report = await buildDoctorRuntimePolicyReport(targetPath);
|
|
1020
|
+
const report = await buildDoctorRuntimePolicyReport(targetPath, new Date().toISOString(), runtimeSandbox ? { sandbox: runtimeSandbox } : {});
|
|
977
1021
|
const renderedReport = jsonOutput
|
|
978
1022
|
? renderDoctorRuntimePolicyJson(report)
|
|
979
1023
|
: renderDoctorRuntimePolicy(report);
|
|
@@ -1138,6 +1182,15 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1138
1182
|
const runtimeApprovalDigest = runtimeApprovalDigestIndex === -1
|
|
1139
1183
|
? null
|
|
1140
1184
|
: assetFlags[runtimeApprovalDigestIndex + 1];
|
|
1185
|
+
const runtime = assetFlags.includes("--runtime");
|
|
1186
|
+
let runtimeSandbox;
|
|
1187
|
+
try {
|
|
1188
|
+
runtimeSandbox = parseRuntimeSandbox(assetFlags);
|
|
1189
|
+
}
|
|
1190
|
+
catch (error) {
|
|
1191
|
+
io.writeStderr(error.message);
|
|
1192
|
+
return 2;
|
|
1193
|
+
}
|
|
1141
1194
|
if (!targetPath) {
|
|
1142
1195
|
io.writeStderr("Missing target path for release evidence asset.");
|
|
1143
1196
|
return 2;
|
|
@@ -1193,13 +1246,13 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1193
1246
|
allowUntagged,
|
|
1194
1247
|
requireRuntimeApproval,
|
|
1195
1248
|
runtimeApprovalDigest,
|
|
1249
|
+
runtime,
|
|
1250
|
+
...(runtimeSandbox ? { sandbox: runtimeSandbox } : {}),
|
|
1196
1251
|
environment: {
|
|
1197
1252
|
env: terminalContext.env,
|
|
1198
1253
|
platform: terminalContext.platform
|
|
1199
1254
|
},
|
|
1200
|
-
runCheck: options.runCheckImpl
|
|
1201
|
-
? (pathToCheck) => options.runCheckImpl(pathToCheck)
|
|
1202
|
-
: undefined,
|
|
1255
|
+
runCheck: options.runCheckImpl ?? runCheck,
|
|
1203
1256
|
performanceThresholds: parsedThresholds.thresholds
|
|
1204
1257
|
});
|
|
1205
1258
|
await writeFile(resolvedOutputPath, renderDoctorReleaseEvidenceJson(evidence), "utf8");
|
|
@@ -1298,6 +1351,15 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1298
1351
|
const runtimeApprovalDigest = runtimeApprovalDigestIndex === -1
|
|
1299
1352
|
? null
|
|
1300
1353
|
: evidenceFlags[runtimeApprovalDigestIndex + 1];
|
|
1354
|
+
const runtime = evidenceFlags.includes("--runtime");
|
|
1355
|
+
let runtimeSandbox;
|
|
1356
|
+
try {
|
|
1357
|
+
runtimeSandbox = parseRuntimeSandbox(evidenceFlags);
|
|
1358
|
+
}
|
|
1359
|
+
catch (error) {
|
|
1360
|
+
io.writeStderr(error.message);
|
|
1361
|
+
return 2;
|
|
1362
|
+
}
|
|
1301
1363
|
if (outputIndex !== -1 && (!outputPath || outputPath.startsWith("--"))) {
|
|
1302
1364
|
io.writeStderr("Missing path after --output.");
|
|
1303
1365
|
return 2;
|
|
@@ -1336,13 +1398,13 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1336
1398
|
allowUntagged,
|
|
1337
1399
|
requireRuntimeApproval,
|
|
1338
1400
|
runtimeApprovalDigest,
|
|
1401
|
+
runtime,
|
|
1402
|
+
...(runtimeSandbox ? { sandbox: runtimeSandbox } : {}),
|
|
1339
1403
|
environment: {
|
|
1340
1404
|
env: terminalContext.env,
|
|
1341
1405
|
platform: terminalContext.platform
|
|
1342
1406
|
},
|
|
1343
|
-
runCheck: options.runCheckImpl
|
|
1344
|
-
? (pathToCheck) => options.runCheckImpl(pathToCheck)
|
|
1345
|
-
: undefined,
|
|
1407
|
+
runCheck: options.runCheckImpl ?? runCheck,
|
|
1346
1408
|
performanceThresholds: parsedThresholds.thresholds
|
|
1347
1409
|
});
|
|
1348
1410
|
const reportJson = renderDoctorReleaseEvidenceJson(report);
|
|
@@ -1357,16 +1419,39 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1357
1419
|
const jsonOutput = remainingArgs.includes("--json");
|
|
1358
1420
|
const outputIndex = remainingArgs.indexOf("--output");
|
|
1359
1421
|
const outputPath = outputIndex === -1 ? null : remainingArgs[outputIndex + 1];
|
|
1422
|
+
const manifestIndex = remainingArgs.indexOf("--manifest");
|
|
1423
|
+
const manifestPath = manifestIndex === -1 ? null : remainingArgs[manifestIndex + 1];
|
|
1360
1424
|
if (outputIndex !== -1 && (!outputPath || outputPath.startsWith("--"))) {
|
|
1361
1425
|
io.writeStderr("Missing path after --output.");
|
|
1362
1426
|
return 2;
|
|
1363
1427
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1428
|
+
if (manifestIndex !== -1 && (!manifestPath || manifestPath.startsWith("--"))) {
|
|
1429
|
+
io.writeStderr("Missing path after --manifest.");
|
|
1430
|
+
return 2;
|
|
1431
|
+
}
|
|
1432
|
+
let report;
|
|
1433
|
+
try {
|
|
1434
|
+
report = manifestPath
|
|
1435
|
+
? await buildExternalValidationCorpusReport(manifestPath, {
|
|
1436
|
+
environment: {
|
|
1437
|
+
env: terminalContext.env,
|
|
1438
|
+
platform: terminalContext.platform
|
|
1439
|
+
}
|
|
1440
|
+
})
|
|
1441
|
+
: await buildDoctorValidationCorpusReport({
|
|
1442
|
+
environment: {
|
|
1443
|
+
env: terminalContext.env,
|
|
1444
|
+
platform: terminalContext.platform
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
catch (error) {
|
|
1449
|
+
if (error instanceof ExternalCorpusManifestError) {
|
|
1450
|
+
io.writeStderr(error.message);
|
|
1451
|
+
return 2;
|
|
1368
1452
|
}
|
|
1369
|
-
|
|
1453
|
+
throw error;
|
|
1454
|
+
}
|
|
1370
1455
|
const reportJson = renderDoctorValidationCorpusJson(report);
|
|
1371
1456
|
if (outputPath) {
|
|
1372
1457
|
await writeFile(outputPath, reportJson, "utf8");
|
|
@@ -2253,7 +2338,7 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
2253
2338
|
if (command === "release") {
|
|
2254
2339
|
const subCommand = maybePath;
|
|
2255
2340
|
if (subCommand !== "check") {
|
|
2256
|
-
io.writeStderr("Usage: codex-plugin-doctor release check <path> [--json]");
|
|
2341
|
+
io.writeStderr("Usage: codex-plugin-doctor release check <path> [--json] [--runtime] [--require-runtime-approval --runtime-approval-digest <digest>]");
|
|
2257
2342
|
return 2;
|
|
2258
2343
|
}
|
|
2259
2344
|
const targetPath = remainingArgs[0] && !remainingArgs[0].startsWith("--") ? remainingArgs[0] : ".";
|
|
@@ -2261,9 +2346,46 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
2261
2346
|
? remainingArgs
|
|
2262
2347
|
: remainingArgs.slice(1);
|
|
2263
2348
|
const jsonOutput = releaseFlags.includes("--json");
|
|
2349
|
+
const runtimeProbeEnabled = releaseFlags.includes("--runtime");
|
|
2350
|
+
let runtimeSandbox;
|
|
2351
|
+
try {
|
|
2352
|
+
runtimeSandbox = parseRuntimeSandbox(releaseFlags);
|
|
2353
|
+
}
|
|
2354
|
+
catch (error) {
|
|
2355
|
+
io.writeStderr(error.message);
|
|
2356
|
+
return 2;
|
|
2357
|
+
}
|
|
2358
|
+
const requireRuntimeApproval = releaseFlags.includes("--require-runtime-approval");
|
|
2359
|
+
const runtimeApprovalDigestIndex = releaseFlags.indexOf("--runtime-approval-digest");
|
|
2360
|
+
const runtimeApprovalDigest = runtimeApprovalDigestIndex === -1
|
|
2361
|
+
? null
|
|
2362
|
+
: releaseFlags[runtimeApprovalDigestIndex + 1];
|
|
2363
|
+
if (requireRuntimeApproval && !runtimeProbeEnabled) {
|
|
2364
|
+
io.writeStderr("Runtime approval requires --runtime.");
|
|
2365
|
+
return 2;
|
|
2366
|
+
}
|
|
2367
|
+
if (runtimeApprovalDigestIndex !== -1 &&
|
|
2368
|
+
(!runtimeApprovalDigest || runtimeApprovalDigest.startsWith("--"))) {
|
|
2369
|
+
io.writeStderr("Missing digest after --runtime-approval-digest.");
|
|
2370
|
+
return 2;
|
|
2371
|
+
}
|
|
2372
|
+
if (requireRuntimeApproval) {
|
|
2373
|
+
const runtimePlan = await buildDoctorRuntimePlan(targetPath, new Date().toISOString(), runtimeSandbox ? { sandbox: runtimeSandbox } : {});
|
|
2374
|
+
const approval = evaluateRuntimeApproval(runtimePlan, {
|
|
2375
|
+
required: true,
|
|
2376
|
+
approvedDigest: runtimeApprovalDigest
|
|
2377
|
+
});
|
|
2378
|
+
if (!runtimeApprovalPassed(approval)) {
|
|
2379
|
+
io.writeStderr(`${approval.message}\nCurrent runtime plan digest: ${runtimePlan.digest}`);
|
|
2380
|
+
return 1;
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2264
2383
|
const report = await buildReleaseCheck(targetPath, {
|
|
2265
2384
|
env: terminalContext.env,
|
|
2266
|
-
platform: terminalContext.platform
|
|
2385
|
+
platform: terminalContext.platform,
|
|
2386
|
+
runtime: runtimeProbeEnabled,
|
|
2387
|
+
...(runtimeSandbox ? { runtimeSandbox } : {}),
|
|
2388
|
+
runCheck: options.runCheckImpl
|
|
2267
2389
|
});
|
|
2268
2390
|
const output = jsonOutput
|
|
2269
2391
|
? renderReleaseCheckJson(report)
|
|
@@ -2303,6 +2425,14 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
2303
2425
|
: maybePath && maybePath.startsWith("--")
|
|
2304
2426
|
? [maybePath, ...remainingArgs]
|
|
2305
2427
|
: remainingArgs;
|
|
2428
|
+
let runtimeSandbox;
|
|
2429
|
+
try {
|
|
2430
|
+
runtimeSandbox = parseRuntimeSandbox(normalizedFlags);
|
|
2431
|
+
}
|
|
2432
|
+
catch (error) {
|
|
2433
|
+
io.writeStderr(error.message);
|
|
2434
|
+
return 2;
|
|
2435
|
+
}
|
|
2306
2436
|
const jsonOutput = normalizedFlags.includes("--json");
|
|
2307
2437
|
const markdownOutput = normalizedFlags.includes("--markdown");
|
|
2308
2438
|
const badgeJsonOutput = normalizedFlags.includes("--badge-json");
|
|
@@ -2430,7 +2560,7 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
2430
2560
|
});
|
|
2431
2561
|
const runCheckImpl = options.runCheckImpl ?? runCheck;
|
|
2432
2562
|
if (!checkInstalled && effectiveRuntimeProbeEnabled && requireRuntimeApproval) {
|
|
2433
|
-
const runtimePlan = await buildDoctorRuntimePlan(targetPath);
|
|
2563
|
+
const runtimePlan = await buildDoctorRuntimePlan(targetPath, new Date().toISOString(), runtimeSandbox ? { sandbox: runtimeSandbox } : {});
|
|
2434
2564
|
const approval = evaluateRuntimeApproval(runtimePlan, {
|
|
2435
2565
|
required: true,
|
|
2436
2566
|
approvedDigest: runtimeApprovalDigest
|
|
@@ -2552,9 +2682,10 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
2552
2682
|
const doctorConfig = applyPolicyToDoctorConfig(applyCheckProfile(await loadDoctorConfig(targetPath, configPath), checkProfile), policy);
|
|
2553
2683
|
const configuredResult = applyDoctorConfig(await runCheckImpl(targetPath, {
|
|
2554
2684
|
runtime: effectiveRuntimeProbeEnabled,
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
:
|
|
2685
|
+
...(runtimeSandbox ? { runtimeSandbox } : {}),
|
|
2686
|
+
...(effectiveRuntimeProbeEnabled && verboseRuntime
|
|
2687
|
+
? { runtimeTranscript: (line) => io.writeStderr(line) }
|
|
2688
|
+
: {})
|
|
2558
2689
|
}), doctorConfig);
|
|
2559
2690
|
const result = baseline
|
|
2560
2691
|
? applyValidationBaseline(configuredResult, baseline, {
|
package/package.json
CHANGED