codex-plugin-doctor 1.73.0 → 1.74.1
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 +7 -3
- package/dist/core/init-ci.d.ts +6 -0
- package/dist/core/init-ci.js +75 -1
- package/dist/core/mcp-tool-impact.js +10 -4
- package/dist/run-cli.js +56 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -149,7 +149,11 @@ live list with `tools-capture-url` (and `tools-capture-token-env`) or, for a loc
|
|
|
149
149
|
stdio server with `runtime: "true"`, `tools-capture-server`, and skip the
|
|
150
150
|
plugin package check with `check: "false"` in repositories that only ship an MCP
|
|
151
151
|
server. With `tools-diff-comment: "true"` it also posts the comparison as one
|
|
152
|
-
pull request comment that later runs update.
|
|
152
|
+
pull request comment that later runs update. `tools-capture-sandbox: docker`
|
|
153
|
+
starts a stdio server in the Docker sandbox, and
|
|
154
|
+
`codex-plugin-doctor init-ci . --tools-diff-server <name> --sandbox docker`
|
|
155
|
+
writes a pull request workflow that captures in one job and compares and
|
|
156
|
+
comments in another.
|
|
153
157
|
|
|
154
158
|
Local stdio servers from a package's MCP configuration can be cataloged too.
|
|
155
159
|
`--runtime` is required because this starts package code; the server is stopped
|
|
@@ -585,9 +589,9 @@ jobs:
|
|
|
585
589
|
runs-on: ubuntu-latest
|
|
586
590
|
steps:
|
|
587
591
|
- uses: actions/checkout@v5
|
|
588
|
-
- uses: Esquetta/CodexPluginDoctor@v1.
|
|
592
|
+
- uses: Esquetta/CodexPluginDoctor@v1.74.1
|
|
589
593
|
with:
|
|
590
|
-
version: "1.
|
|
594
|
+
version: "1.74.1"
|
|
591
595
|
path: .
|
|
592
596
|
runtime: "true"
|
|
593
597
|
policy: codex-publish
|
package/dist/core/init-ci.d.ts
CHANGED
|
@@ -2,4 +2,10 @@ export interface InitCiResult {
|
|
|
2
2
|
rootPath: string;
|
|
3
3
|
workflowPath: string;
|
|
4
4
|
}
|
|
5
|
+
export interface ToolsDiffWorkflowOptions {
|
|
6
|
+
server: string;
|
|
7
|
+
baseline: string;
|
|
8
|
+
sandbox: "docker" | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function initToolsDiffWorkflow(targetPath: string, options: ToolsDiffWorkflowOptions): Promise<InitCiResult>;
|
|
5
11
|
export declare function initCiWorkflow(targetPath: string): Promise<InitCiResult>;
|
package/dist/core/init-ci.js
CHANGED
|
@@ -15,7 +15,7 @@ function buildWorkflow() {
|
|
|
15
15
|
" doctor:",
|
|
16
16
|
" runs-on: ubuntu-latest",
|
|
17
17
|
" steps:",
|
|
18
|
-
" - uses: actions/checkout@
|
|
18
|
+
" - uses: actions/checkout@v5",
|
|
19
19
|
` - uses: Esquetta/CodexPluginDoctor@v${packageVersion}`,
|
|
20
20
|
" with:",
|
|
21
21
|
` version: \"${packageVersion}\"`,
|
|
@@ -31,6 +31,80 @@ function buildWorkflow() {
|
|
|
31
31
|
""
|
|
32
32
|
].join("\n");
|
|
33
33
|
}
|
|
34
|
+
// JSON strings are valid YAML double-quoted scalars, so names and paths cannot break the document.
|
|
35
|
+
const yamlString = (value) => JSON.stringify(value);
|
|
36
|
+
/**
|
|
37
|
+
* A pull request workflow in two jobs: the first starts the stdio server and uploads its tool list,
|
|
38
|
+
* and the second compares it with the committed baseline and comments. Only the second job may write
|
|
39
|
+
* to pull requests, and it runs no package code.
|
|
40
|
+
*/
|
|
41
|
+
function buildToolsDiffWorkflow(options) {
|
|
42
|
+
return [
|
|
43
|
+
"name: MCP tool diff",
|
|
44
|
+
"",
|
|
45
|
+
"on:",
|
|
46
|
+
" pull_request:",
|
|
47
|
+
"",
|
|
48
|
+
"permissions:",
|
|
49
|
+
" contents: read",
|
|
50
|
+
"",
|
|
51
|
+
"jobs:",
|
|
52
|
+
" capture:",
|
|
53
|
+
" runs-on: ubuntu-latest",
|
|
54
|
+
" steps:",
|
|
55
|
+
" - uses: actions/checkout@v5",
|
|
56
|
+
" with:",
|
|
57
|
+
" persist-credentials: false",
|
|
58
|
+
" # Add install or build steps here if the server needs them; the Docker sandbox has no network.",
|
|
59
|
+
` - uses: Esquetta/CodexPluginDoctor@v${packageVersion}`,
|
|
60
|
+
" with:",
|
|
61
|
+
` version: \"${packageVersion}\"`,
|
|
62
|
+
" path: .",
|
|
63
|
+
" check: \"false\"",
|
|
64
|
+
" runtime: \"true\"",
|
|
65
|
+
` tools-capture-server: ${yamlString(options.server)}`,
|
|
66
|
+
...(options.sandbox === "docker" ? [" tools-capture-sandbox: docker"] : []),
|
|
67
|
+
" # Catalog findings do not fail this job; the compare job re-checks the saved list.",
|
|
68
|
+
" tools-capture-defer-findings: \"true\"",
|
|
69
|
+
" artifact-name: mcp-tools-capture",
|
|
70
|
+
"",
|
|
71
|
+
" compare:",
|
|
72
|
+
" needs: capture",
|
|
73
|
+
" runs-on: ubuntu-latest",
|
|
74
|
+
" permissions:",
|
|
75
|
+
" contents: read",
|
|
76
|
+
" pull-requests: write",
|
|
77
|
+
" steps:",
|
|
78
|
+
" - uses: actions/checkout@v5",
|
|
79
|
+
" with:",
|
|
80
|
+
" persist-credentials: false",
|
|
81
|
+
" # Outside the checkout, so files from the pull request cannot shadow the downloaded list.",
|
|
82
|
+
" - uses: actions/download-artifact@v5",
|
|
83
|
+
" with:",
|
|
84
|
+
" name: mcp-tools-capture",
|
|
85
|
+
" path: ${{ runner.temp }}/mcp-tools-capture",
|
|
86
|
+
` - uses: Esquetta/CodexPluginDoctor@v${packageVersion}`,
|
|
87
|
+
" with:",
|
|
88
|
+
` version: \"${packageVersion}\"`,
|
|
89
|
+
" check: \"false\"",
|
|
90
|
+
` tools-diff-before: ${yamlString(options.baseline)}`,
|
|
91
|
+
" tools-diff-after: ${{ runner.temp }}/mcp-tools-capture/mcp-tools-current.json",
|
|
92
|
+
" tools-diff-fail-on: breaking",
|
|
93
|
+
" tools-diff-comment: \"true\"",
|
|
94
|
+
" output-dir: ${{ runner.temp }}/codex-plugin-doctor-reports",
|
|
95
|
+
" artifact-name: mcp-tools-diff",
|
|
96
|
+
""
|
|
97
|
+
].join("\n");
|
|
98
|
+
}
|
|
99
|
+
export async function initToolsDiffWorkflow(targetPath, options) {
|
|
100
|
+
const rootPath = path.resolve(targetPath);
|
|
101
|
+
const workflowPath = path.join(rootPath, ".github", "workflows", "codex-plugin-doctor-tools.yml");
|
|
102
|
+
await mkdir(path.dirname(workflowPath), { recursive: true });
|
|
103
|
+
await writeFile(workflowPath, buildToolsDiffWorkflow(options), "utf8");
|
|
104
|
+
// doctor tools --save-response writes into an existing directory, so the baseline can be captured next.
|
|
105
|
+
await mkdir(path.dirname(path.resolve(rootPath, options.baseline)), { recursive: true });
|
|
106
|
+
return { rootPath, workflowPath };
|
|
107
|
+
}
|
|
34
108
|
export async function initCiWorkflow(targetPath) {
|
|
35
109
|
const rootPath = path.resolve(targetPath);
|
|
36
110
|
const workflowPath = path.join(rootPath, ".github", "workflows", "codex-plugin-doctor.yml");
|
|
@@ -181,10 +181,8 @@ function compareBounds(inner, outer, codes, reasons) {
|
|
|
181
181
|
*/
|
|
182
182
|
function numericBound(schema, inclusive, exclusive, lower) {
|
|
183
183
|
if (typeof schema[exclusive] === "boolean") {
|
|
184
|
-
// Draft-04 marks the inclusive keyword itself as exclusive.
|
|
184
|
+
// Draft-04 marks the inclusive keyword itself as exclusive; a boolean alone is invalid in every draft.
|
|
185
185
|
const value = schema[inclusive];
|
|
186
|
-
if (value === undefined)
|
|
187
|
-
return undefined;
|
|
188
186
|
return isFiniteNumber(value) ? { value, exclusive: schema[exclusive] } : null;
|
|
189
187
|
}
|
|
190
188
|
const candidates = [];
|
|
@@ -599,7 +597,15 @@ function compareSchema(before, after, direction, depth, equal, reasons, scope) {
|
|
|
599
597
|
const beforeComposed = isComposition(resolvedBefore.schema);
|
|
600
598
|
const afterComposed = isComposition(resolvedAfter.schema);
|
|
601
599
|
if (beforeComposed !== afterComposed) {
|
|
602
|
-
|
|
600
|
+
// The reference is kept only when an alternative can pair with it; otherwise its target compares
|
|
601
|
+
// with inline alternatives by type.
|
|
602
|
+
const composite = beforeComposed ? resolvedBefore.schema : resolvedAfter.schema;
|
|
603
|
+
const original = beforeComposed ? after : before;
|
|
604
|
+
const plainKey = alternativeKey(original);
|
|
605
|
+
const keepReference = (alternatives(composite) ?? [])
|
|
606
|
+
.some((alternative) => (plainKey !== null && alternativeKey(alternative) === plainKey) || sameMeaning(original, alternative, equal, scope));
|
|
607
|
+
const plain = keepReference ? original : (beforeComposed ? resolvedAfter.schema : resolvedBefore.schema);
|
|
608
|
+
compareComposition(beforeComposed ? composite : plain, beforeComposed ? plain : composite, direction, depth, equal, reasons, scope);
|
|
603
609
|
return;
|
|
604
610
|
}
|
|
605
611
|
if (resolvedBefore.ref !== undefined || resolvedAfter.ref !== undefined) {
|
package/dist/run-cli.js
CHANGED
|
@@ -49,7 +49,7 @@ import { buildDoctorInspectorReport, renderDoctorInspectorReport, renderDoctorIn
|
|
|
49
49
|
import { applyFixPlan, buildFixPlan, renderApplyFixResult, renderFixPlanJsonReport, renderFixPlan } from "./core/fix-plan.js";
|
|
50
50
|
import { renderClientDoctor, renderEnvironmentDoctor, renderEnvironmentDoctorJson } from "./core/environment-doctor.js";
|
|
51
51
|
import { buildDoctorSize, renderDoctorSize, renderDoctorSizeJson } from "./core/doctor-size.js";
|
|
52
|
-
import { initCiWorkflow } from "./core/init-ci.js";
|
|
52
|
+
import { initCiWorkflow, initToolsDiffWorkflow } from "./core/init-ci.js";
|
|
53
53
|
import { watchPlugin } from "./core/watch-plugin.js";
|
|
54
54
|
import { buildDepAudit, renderDepAudit, renderDepAuditJson, renderDepAuditSarif } from "./core/dep-audit.js";
|
|
55
55
|
import { initGitHooks, removeGitHooks } from "./core/init-git-hooks.js";
|
|
@@ -117,6 +117,40 @@ const toolsUsage = "Usage: codex-plugin-doctor doctor tools <url> --allow-networ
|
|
|
117
117
|
const discoveryUsage = "Usage: codex-plugin-doctor doctor discover <url> --allow-network [--allow-local-network] [--json] [--bearer-token-env <NAME>]";
|
|
118
118
|
const bearerTokenHelp = "--bearer-token-env reads a bearer token from the named environment variable and sends it only over HTTPS or to an approved loopback target; the token is never printed or saved.";
|
|
119
119
|
const ENVIRONMENT_VARIABLE_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
120
|
+
/** Reads init-ci --tools-diff-server, --baseline, and --sandbox; options is null when none is given. */
|
|
121
|
+
function parseToolsDiffWorkflowOptions(flags) {
|
|
122
|
+
const values = new Map();
|
|
123
|
+
for (let index = 0; index < flags.length; index += 1) {
|
|
124
|
+
if (!["--tools-diff-server", "--baseline", "--sandbox"].includes(flags[index]))
|
|
125
|
+
continue;
|
|
126
|
+
const value = flags[index + 1];
|
|
127
|
+
const present = value !== undefined && !value.startsWith("--");
|
|
128
|
+
values.set(flags[index], present ? value : undefined);
|
|
129
|
+
if (present)
|
|
130
|
+
index += 1;
|
|
131
|
+
}
|
|
132
|
+
if (values.size === 0)
|
|
133
|
+
return { options: null };
|
|
134
|
+
if (!values.has("--tools-diff-server"))
|
|
135
|
+
return { error: "--baseline and --sandbox require --tools-diff-server." };
|
|
136
|
+
// Control characters would break the generated workflow lines, GitHub evaluates "${{" in any
|
|
137
|
+
// workflow value, and the Action rejects values that start with "-".
|
|
138
|
+
const usable = (value) => value !== undefined && value.trim() !== "" && !value.startsWith("-") && !value.includes("${{")
|
|
139
|
+
&& !/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/u.test(value);
|
|
140
|
+
const server = values.get("--tools-diff-server");
|
|
141
|
+
if (!usable(server))
|
|
142
|
+
return { error: "--tools-diff-server requires a server name." };
|
|
143
|
+
// The workflow runs on Linux from the repository root, so the baseline is a relative POSIX path.
|
|
144
|
+
const baseline = (values.has("--baseline") ? values.get("--baseline") : "mcp/tools-baseline.json")?.replaceAll("\\", "/");
|
|
145
|
+
if (!usable(baseline) || path.posix.isAbsolute(baseline) || /^[A-Za-z]:/u.test(baseline)
|
|
146
|
+
|| path.posix.normalize(baseline).split("/").includes("..")) {
|
|
147
|
+
return { error: "--baseline requires a relative path inside the repository." };
|
|
148
|
+
}
|
|
149
|
+
const sandbox = values.get("--sandbox");
|
|
150
|
+
if (values.has("--sandbox") && sandbox !== "docker")
|
|
151
|
+
return { error: "--sandbox must be docker." };
|
|
152
|
+
return { options: { server, baseline, sandbox: sandbox === "docker" ? "docker" : null } };
|
|
153
|
+
}
|
|
120
154
|
const MAX_FORWARDED_ENVIRONMENT_VARIABLES = 32;
|
|
121
155
|
const forwardedEnvironmentHelp = "--env forwards the named host environment variable into the Docker sandbox by name; Doctor never prints its value, writes it to a report, or passes it as a command argument. Native servers already inherit Doctor's environment.";
|
|
122
156
|
function resolveBearerToken(name, env) {
|
|
@@ -340,7 +374,7 @@ function parseRemoteNetworkFlags(flags, runtime) {
|
|
|
340
374
|
return { allowNetwork, allowLocalNetwork, allowSessionLifecycle, requireRemoteReliability };
|
|
341
375
|
}
|
|
342
376
|
function printUsage(io) {
|
|
343
|
-
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 [--allow-network [--allow-local-network]]] [--sandbox docker] [--require-runtime-approval --runtime-approval-digest <digest>] [--verbose-runtime] [--explain] [--no-animations] [--ascii] [--changed-since <ref>] [--fail-on <rule-id>]\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> [--runtime [--allow-network [--allow-local-network]]] [--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>]|corpus metrics --manifest <corpus.json> [--json|--markdown] [--output <path>] [--min-precision <0..1>] [--min-recall <0..1>] [--max-false-positive-rate <0..1>]|runtime-plan <path> [--sandbox docker] [--json|--markdown] [--output <path>]|runtime-policy <path> [--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 [--allow-network [--allow-local-network]]] [--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 [--runtime [--allow-network [--allow-local-network]]] [--sandbox docker] [--allow-dirty] [--allow-untagged] [--require-runtime-approval --runtime-approval-digest <digest>] [--upload]|mcp <path> [--runtime [--allow-network [--allow-local-network]]]|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 [--allow-network [--allow-local-network]]] [--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");
|
|
377
|
+
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 [--allow-network [--allow-local-network]]] [--sandbox docker] [--require-runtime-approval --runtime-approval-digest <digest>] [--verbose-runtime] [--explain] [--no-animations] [--ascii] [--changed-since <ref>] [--fail-on <rule-id>]\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> [--runtime [--allow-network [--allow-local-network]]] [--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>]|corpus metrics --manifest <corpus.json> [--json|--markdown] [--output <path>] [--min-precision <0..1>] [--min-recall <0..1>] [--max-false-positive-rate <0..1>]|runtime-plan <path> [--sandbox docker] [--json|--markdown] [--output <path>]|runtime-policy <path> [--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 [--allow-network [--allow-local-network]]] [--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 [--runtime [--allow-network [--allow-local-network]]] [--sandbox docker] [--allow-dirty] [--allow-untagged] [--require-runtime-approval --runtime-approval-digest <digest>] [--upload]|mcp <path> [--runtime [--allow-network [--allow-local-network]]]|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] [--tools-diff-server <name> [--baseline <path>] [--sandbox docker]]\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 [--allow-network [--allow-local-network]]] [--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");
|
|
344
378
|
io.writeStderr(discoveryUsage);
|
|
345
379
|
io.writeStderr(toolsUsage);
|
|
346
380
|
io.writeStderr(toolsFileUsage);
|
|
@@ -1308,9 +1342,10 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1308
1342
|
(command === "doctor" &&
|
|
1309
1343
|
(["runtime-plan", "runtime-policy"].includes(maybePath ?? "") ||
|
|
1310
1344
|
(maybePath === "release-evidence" && remainingArgs[0] !== "verify") ||
|
|
1311
|
-
(maybePath === "tools" && remainingArgs.includes("--server"))))
|
|
1345
|
+
(maybePath === "tools" && remainingArgs.includes("--server")))) ||
|
|
1346
|
+
(command === "init-ci" && args.includes("--tools-diff-server"));
|
|
1312
1347
|
if (args.includes("--sandbox") && !runtimeSandboxSupported) {
|
|
1313
|
-
io.writeStderr("--sandbox is supported only by single-package check, release check, runtime-plan, runtime-policy, release-evidence,
|
|
1348
|
+
io.writeStderr("--sandbox is supported only by single-package check, release check, runtime-plan, runtime-policy, release-evidence, doctor tools --server, and init-ci --tools-diff-server.");
|
|
1314
1349
|
return 2;
|
|
1315
1350
|
}
|
|
1316
1351
|
if (command === "--version" || command === "-v" || command === "version") {
|
|
@@ -2771,6 +2806,23 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
2771
2806
|
}
|
|
2772
2807
|
if (command === "init-ci") {
|
|
2773
2808
|
const targetPath = maybePath && !maybePath.startsWith("--") ? maybePath : ".";
|
|
2809
|
+
const initFlags = maybePath && maybePath.startsWith("--") ? [maybePath, ...remainingArgs] : remainingArgs;
|
|
2810
|
+
const toolsDiff = parseToolsDiffWorkflowOptions(initFlags);
|
|
2811
|
+
if ("error" in toolsDiff) {
|
|
2812
|
+
io.writeStderr(toolsDiff.error);
|
|
2813
|
+
return 2;
|
|
2814
|
+
}
|
|
2815
|
+
if (toolsDiff.options !== null) {
|
|
2816
|
+
const { server, baseline, sandbox } = toolsDiff.options;
|
|
2817
|
+
const toolsResult = await initToolsDiffWorkflow(targetPath, toolsDiff.options);
|
|
2818
|
+
io.writeStdout([
|
|
2819
|
+
"Initialized Codex Plugin Doctor tool diff workflow",
|
|
2820
|
+
`Root: ${toolsResult.rootPath}`,
|
|
2821
|
+
`Workflow: ${toolsResult.workflowPath}`,
|
|
2822
|
+
`Capture and commit a baseline at ${baseline}, for example with: codex-plugin-doctor doctor tools ${JSON.stringify(targetPath)} --server ${JSON.stringify(server)} --runtime${sandbox === "docker" ? " --sandbox docker" : ""} --save-response ${JSON.stringify(path.join(targetPath, baseline))}`
|
|
2823
|
+
].join("\n"));
|
|
2824
|
+
return 0;
|
|
2825
|
+
}
|
|
2774
2826
|
const result = await initCiWorkflow(targetPath);
|
|
2775
2827
|
io.writeStdout([
|
|
2776
2828
|
"Initialized Codex Plugin Doctor workflow",
|
package/package.json
CHANGED