codex-plugin-doctor 1.77.0 → 1.79.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 +18 -2
- package/dist/core/init-ci.d.ts +1 -0
- package/dist/core/init-ci.js +16 -2
- package/dist/core/mcp-prompt-catalog.js +2 -0
- package/dist/core/mcp-resource-template-catalog.d.ts +36 -0
- package/dist/core/mcp-resource-template-catalog.js +55 -0
- package/dist/core/mcp-resource-template-definition.d.ts +28 -0
- package/dist/core/mcp-resource-template-definition.js +116 -0
- package/dist/core/mcp-resource-template-diff.d.ts +43 -0
- package/dist/core/mcp-resource-template-diff.js +136 -0
- package/dist/core/mcp-resource-template-file.d.ts +31 -0
- package/dist/core/mcp-resource-template-file.js +118 -0
- package/dist/core/mcp-resource-template-impact.d.ts +21 -0
- package/dist/core/mcp-resource-template-impact.js +74 -0
- package/dist/core/mcp-stdio-tool-catalog.d.ts +1 -1
- package/dist/core/mcp-stdio-tool-catalog.js +6 -6
- package/dist/core/mcp-tool-catalog.d.ts +8 -6
- package/dist/core/mcp-tool-catalog.js +7 -5
- package/dist/core/mcp-tool-response-file.d.ts +1 -1
- package/dist/core/mcp-tool-response-file.js +3 -2
- package/dist/core/output-contract.js +172 -1
- package/dist/reporting/render-mcp-resource-template-catalog-report.d.ts +2 -0
- package/dist/reporting/render-mcp-resource-template-catalog-report.js +33 -0
- package/dist/reporting/render-mcp-resource-template-diff-markdown.d.ts +2 -0
- package/dist/reporting/render-mcp-resource-template-diff-markdown.js +39 -0
- package/dist/reporting/render-mcp-resource-template-diff-report.d.ts +2 -0
- package/dist/reporting/render-mcp-resource-template-diff-report.js +48 -0
- package/dist/reporting/render-mcp-resource-template-file-report.d.ts +5 -0
- package/dist/reporting/render-mcp-resource-template-file-report.js +31 -0
- package/dist/run-cli.d.ts +7 -0
- package/dist/run-cli.js +80 -16
- package/package.json +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { markdownCodeSpan } from "./quote-server-text.js";
|
|
2
|
+
import { describeResourceTemplateLocation } from "./render-mcp-resource-template-file-report.js";
|
|
3
|
+
function count(value) {
|
|
4
|
+
return value === null || value === undefined ? "not compared" : String(value);
|
|
5
|
+
}
|
|
6
|
+
function templateIndex(value) {
|
|
7
|
+
return value === null ? "-" : String(value);
|
|
8
|
+
}
|
|
9
|
+
export function renderMcpResourceTemplateDiffMarkdown(report) {
|
|
10
|
+
const comparison = report.comparison;
|
|
11
|
+
const named = report.changes.some((change) => change.name !== undefined);
|
|
12
|
+
const lines = [
|
|
13
|
+
"## MCP Resource Template Definition Diff",
|
|
14
|
+
"",
|
|
15
|
+
`**Status:** \`${report.status}\` · **Comparison complete:** ${comparison.complete ? "yes" : "no"}${comparison.reason === null ? "" : ` · **Reason:** \`${comparison.reason}\``}`,
|
|
16
|
+
"",
|
|
17
|
+
"| Added | Removed | Changed | Unchanged | Breaking | Unclassified |",
|
|
18
|
+
"| --- | --- | --- | --- | --- | --- |",
|
|
19
|
+
`| ${count(comparison.added)} | ${count(comparison.removed)} | ${count(comparison.changed)} | ${count(comparison.unchanged)} | ${count(comparison.breaking)} | ${count(comparison.unclassified)} |`
|
|
20
|
+
];
|
|
21
|
+
if (report.changes.length > 0) {
|
|
22
|
+
lines.push("", "### Changes", "", named ? "| Change | Template | Before template | After template | Fields | Impact | Reasons |" : "| Change | Before template | After template | Fields | Impact | Reasons |", named ? "| --- | --- | --- | --- | --- | --- | --- |" : "| --- | --- | --- | --- | --- | --- |", ...report.changes.map((change) => `| ${change.kind}${named ? ` | ${change.name === undefined ? "-" : markdownCodeSpan(change.name)}` : ""} | ${templateIndex(change.beforeTemplateIndex)} | ${templateIndex(change.afterTemplateIndex)} | ${change.fields.map((field) => `\`${field}\``).join(", ") || "-"} | **${change.impact}** | ${change.reasons.map((reason) => `\`${reason}\``).join(", ") || "-"} |`));
|
|
23
|
+
}
|
|
24
|
+
const located = report.changes.flatMap((change) => (change.locations ?? []).map((location) => `| ${change.name === undefined ? "-" : markdownCodeSpan(change.name)} | \`${location.reason}\` | ${location.variable === null ? "-" : markdownCodeSpan(location.variable)} |`));
|
|
25
|
+
if (located.length > 0) {
|
|
26
|
+
lines.push("", "### Locations", "", "| Template | Reason | Variable |", "| --- | --- | --- |", ...located);
|
|
27
|
+
}
|
|
28
|
+
const findings = ["before", "after"].flatMap((side) => report[side].findings.map((finding) => {
|
|
29
|
+
const locator = finding.location ? `${side} ${describeResourceTemplateLocation(finding.location)}` : side;
|
|
30
|
+
return `| ${finding.severity} | \`${finding.id}\` | ${locator} | ${finding.message} |`;
|
|
31
|
+
}));
|
|
32
|
+
if (findings.length > 0) {
|
|
33
|
+
lines.push("", "### Input Findings", "", "| Severity | Finding | Location | Message |", "| --- | --- | --- | --- |", ...findings);
|
|
34
|
+
}
|
|
35
|
+
lines.push("", named
|
|
36
|
+
? `Template and variable names are shown because --show-names was used; URI templates, descriptions, and other values are not reported. Impact labels are ${report.coverage.impactClassification} URI template checks, not proof of compatibility.`
|
|
37
|
+
: `Template numbers are one-based positions in the before and after files; names, URI templates, and descriptions are not reported. Impact labels are ${report.coverage.impactClassification} URI template checks, not proof of compatibility.`);
|
|
38
|
+
return lines.join("\n");
|
|
39
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describeResourceTemplateLocation } from "./render-mcp-resource-template-file-report.js";
|
|
2
|
+
import { quoteServerText } from "./quote-server-text.js";
|
|
3
|
+
export function renderMcpResourceTemplateDiffReport(report) {
|
|
4
|
+
const comparison = report.comparison;
|
|
5
|
+
return [
|
|
6
|
+
"Offline MCP Resource Template Diff",
|
|
7
|
+
"==================================",
|
|
8
|
+
`Status: ${report.status}`,
|
|
9
|
+
`Scope: ${report.scope}`,
|
|
10
|
+
`Comparison complete: ${comparison.complete}`,
|
|
11
|
+
...(comparison.reason === null ? [] : [`Reason: ${comparison.reason}`]),
|
|
12
|
+
`Added: ${comparison.added ?? "not compared"}`,
|
|
13
|
+
`Removed: ${comparison.removed ?? "not compared"}`,
|
|
14
|
+
`Changed: ${comparison.changed ?? "not compared"}`,
|
|
15
|
+
`Unchanged: ${comparison.unchanged ?? "not compared"}`,
|
|
16
|
+
`Breaking: ${comparison.breaking ?? "not compared"}`,
|
|
17
|
+
`Unclassified: ${comparison.unclassified ?? "not compared"}`,
|
|
18
|
+
`Comparison coverage: ${report.coverage.comparison}`,
|
|
19
|
+
`Definition coverage: ${report.coverage.definitions}`,
|
|
20
|
+
`Compatibility: ${report.coverage.compatibility}`,
|
|
21
|
+
`Server catalog: ${report.coverage.serverCatalog}`,
|
|
22
|
+
`Resource read: ${report.coverage.resourceRead}`,
|
|
23
|
+
`Impact classification: ${report.coverage.impactClassification}`,
|
|
24
|
+
"Only the supplied responses are compared. Impact labels are URI template heuristics: a compatible label or an unchanged result does not establish compatibility.",
|
|
25
|
+
...["before", "after"].flatMap((side) => {
|
|
26
|
+
const source = report[side];
|
|
27
|
+
const label = side === "before" ? "Before" : "After";
|
|
28
|
+
return [
|
|
29
|
+
`${label} input: ${source.status}; templates checked: ${source.inspection.templatesChecked}; bytes read: ${source.source.bytesRead}`,
|
|
30
|
+
...(source.inspection.reason === null ? [] : [`${label} reason: ${source.inspection.reason}`]),
|
|
31
|
+
...source.findings.map((finding) => {
|
|
32
|
+
const locator = finding.location ? ` [${side} ${describeResourceTemplateLocation(finding.location)}]` : "";
|
|
33
|
+
return `${label} ${finding.severity.toUpperCase()} ${finding.id}${locator}: ${finding.message}\n ${finding.suggestedFix}`;
|
|
34
|
+
})
|
|
35
|
+
];
|
|
36
|
+
}),
|
|
37
|
+
...report.changes.map((change) => {
|
|
38
|
+
const locations = [
|
|
39
|
+
...(change.beforeTemplateIndex === null ? [] : [`before template ${change.beforeTemplateIndex}`]),
|
|
40
|
+
...(change.afterTemplateIndex === null ? [] : [`after template ${change.afterTemplateIndex}`])
|
|
41
|
+
];
|
|
42
|
+
const impact = `${change.impact}${change.reasons.length ? ` (${change.reasons.join(", ")})` : ""}`;
|
|
43
|
+
const name = change.name === undefined ? "" : ` ${quoteServerText(change.name)}`;
|
|
44
|
+
const at = (change.locations ?? []).map((location) => `\n At ${location.variable === null ? "(template)" : `variable ${quoteServerText(location.variable)}`}: ${location.reason}`).join("");
|
|
45
|
+
return `${change.kind.toUpperCase()}${name} [${locations.join(" -> ")}]${change.fields.length ? `: ${change.fields.join(", ")}` : ""}\n Impact: ${impact}${at}`;
|
|
46
|
+
})
|
|
47
|
+
].join("\n");
|
|
48
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ResourceTemplateCatalogLocation } from "../core/mcp-resource-template-definition.js";
|
|
2
|
+
import type { McpResourceTemplateFileReport } from "../core/mcp-resource-template-file.js";
|
|
3
|
+
/** Describes a finding location by one-based positions only, such as "template 2, related template 1". */
|
|
4
|
+
export declare function describeResourceTemplateLocation(location: ResourceTemplateCatalogLocation): string;
|
|
5
|
+
export declare function renderMcpResourceTemplateFileReport(report: McpResourceTemplateFileReport): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Describes a finding location by one-based positions only, such as "template 2, related template 1". */
|
|
2
|
+
export function describeResourceTemplateLocation(location) {
|
|
3
|
+
return [
|
|
4
|
+
`template ${location.templateIndex}`,
|
|
5
|
+
...(location.relatedTemplateIndex === undefined ? [] : [`related template ${location.relatedTemplateIndex}`])
|
|
6
|
+
].join(", ");
|
|
7
|
+
}
|
|
8
|
+
export function renderMcpResourceTemplateFileReport(report) {
|
|
9
|
+
return [
|
|
10
|
+
"Offline MCP Resource Template Definitions",
|
|
11
|
+
"=========================================",
|
|
12
|
+
`Status: ${report.status}`,
|
|
13
|
+
`Scope: ${report.scope}`,
|
|
14
|
+
`Source: ${report.source.kind} (${report.source.format})`,
|
|
15
|
+
`Bytes read: ${report.source.bytesRead}`,
|
|
16
|
+
`Inspection complete: ${report.inspection.complete}`,
|
|
17
|
+
`Templates checked: ${report.inspection.templatesChecked}`,
|
|
18
|
+
`More pages advertised: ${report.inspection.hasNextCursor ?? "unknown"}`,
|
|
19
|
+
...(report.inspection.reason === null ? [] : [`Reason: ${report.inspection.reason}`]),
|
|
20
|
+
`Definition coverage: ${report.coverage.definitions}`,
|
|
21
|
+
`Discovery: ${report.coverage.discovery}`,
|
|
22
|
+
`Server catalog: ${report.coverage.serverCatalog}`,
|
|
23
|
+
`Resource read: ${report.coverage.resourceRead}`,
|
|
24
|
+
`Full conformance: ${report.coverage.fullConformance}`,
|
|
25
|
+
"Only the supplied file was inspected. Its provenance and server completeness are not established.",
|
|
26
|
+
...report.findings.map((finding) => {
|
|
27
|
+
const locator = finding.location ? ` [${describeResourceTemplateLocation(finding.location)}]` : "";
|
|
28
|
+
return `${finding.severity.toUpperCase()} ${finding.id}${locator}: ${finding.message}\n ${finding.suggestedFix}`;
|
|
29
|
+
})
|
|
30
|
+
].join("\n");
|
|
31
|
+
}
|
package/dist/run-cli.d.ts
CHANGED
|
@@ -2,8 +2,11 @@ import { discoverMcpServer } from "./core/mcp-discovery.js";
|
|
|
2
2
|
import { captureMcpToolCatalog, inspectMcpToolCatalog } from "./core/mcp-tool-catalog.js";
|
|
3
3
|
import { captureStdioMcpToolCatalog } from "./core/mcp-stdio-tool-catalog.js";
|
|
4
4
|
import { captureMcpPromptCatalog, captureStdioMcpPromptCatalog } from "./core/mcp-prompt-catalog.js";
|
|
5
|
+
import { captureMcpResourceTemplateCatalog, captureStdioMcpResourceTemplateCatalog } from "./core/mcp-resource-template-catalog.js";
|
|
5
6
|
import { compareMcpPromptFiles } from "./core/mcp-prompt-diff.js";
|
|
6
7
|
import { inspectMcpPromptFile } from "./core/mcp-prompt-file.js";
|
|
8
|
+
import { compareMcpResourceTemplateFiles } from "./core/mcp-resource-template-diff.js";
|
|
9
|
+
import { inspectMcpResourceTemplateFile } from "./core/mcp-resource-template-file.js";
|
|
7
10
|
import { inspectMcpToolFile } from "./core/mcp-tool-file.js";
|
|
8
11
|
import { compareMcpToolFiles } from "./core/mcp-tool-diff.js";
|
|
9
12
|
import { buildCorpusQualityMetricsDiffReport, buildCorpusQualityMetricsReport } from "./core/corpus-quality-metrics.js";
|
|
@@ -27,9 +30,13 @@ export interface RunCliOptions {
|
|
|
27
30
|
captureMcpToolCatalogImpl?: typeof captureMcpToolCatalog;
|
|
28
31
|
captureStdioMcpToolCatalogImpl?: typeof captureStdioMcpToolCatalog;
|
|
29
32
|
compareMcpPromptFilesImpl?: typeof compareMcpPromptFiles;
|
|
33
|
+
compareMcpResourceTemplateFilesImpl?: typeof compareMcpResourceTemplateFiles;
|
|
34
|
+
inspectMcpResourceTemplateFileImpl?: typeof inspectMcpResourceTemplateFile;
|
|
30
35
|
inspectMcpPromptFileImpl?: typeof inspectMcpPromptFile;
|
|
31
36
|
captureMcpPromptCatalogImpl?: typeof captureMcpPromptCatalog;
|
|
32
37
|
captureStdioMcpPromptCatalogImpl?: typeof captureStdioMcpPromptCatalog;
|
|
38
|
+
captureMcpResourceTemplateCatalogImpl?: typeof captureMcpResourceTemplateCatalog;
|
|
39
|
+
captureStdioMcpResourceTemplateCatalogImpl?: typeof captureStdioMcpResourceTemplateCatalog;
|
|
33
40
|
discoverMcpServerImpl?: typeof discoverMcpServer;
|
|
34
41
|
terminalContext?: CliTerminalContext;
|
|
35
42
|
runCheckImpl?: typeof runCheck;
|
package/dist/run-cli.js
CHANGED
|
@@ -26,8 +26,11 @@ import { discoverMcpServer } from "./core/mcp-discovery.js";
|
|
|
26
26
|
import { captureMcpToolCatalog, inspectMcpToolCatalog } from "./core/mcp-tool-catalog.js";
|
|
27
27
|
import { captureStdioMcpToolCatalog, resolveMcpStdioServer } from "./core/mcp-stdio-tool-catalog.js";
|
|
28
28
|
import { captureMcpPromptCatalog, captureStdioMcpPromptCatalog } from "./core/mcp-prompt-catalog.js";
|
|
29
|
+
import { captureMcpResourceTemplateCatalog, captureStdioMcpResourceTemplateCatalog } from "./core/mcp-resource-template-catalog.js";
|
|
29
30
|
import { compareMcpPromptFiles } from "./core/mcp-prompt-diff.js";
|
|
30
31
|
import { inspectMcpPromptFile } from "./core/mcp-prompt-file.js";
|
|
32
|
+
import { compareMcpResourceTemplateFiles } from "./core/mcp-resource-template-diff.js";
|
|
33
|
+
import { inspectMcpResourceTemplateFile } from "./core/mcp-resource-template-file.js";
|
|
31
34
|
import { inspectMcpToolFile, isBlockedOfflinePath } from "./core/mcp-tool-file.js";
|
|
32
35
|
import { saveMcpListResponse } from "./core/mcp-tool-response-file.js";
|
|
33
36
|
import { compareMcpToolFiles } from "./core/mcp-tool-diff.js";
|
|
@@ -36,9 +39,13 @@ import { renderMcpToolDiffReport } from "./reporting/render-mcp-tool-diff-report
|
|
|
36
39
|
import { renderMcpToolFileReport } from "./reporting/render-mcp-tool-file-report.js";
|
|
37
40
|
import { renderMcpToolCatalogReport } from "./reporting/render-mcp-tool-catalog-report.js";
|
|
38
41
|
import { renderMcpPromptCatalogReport } from "./reporting/render-mcp-prompt-catalog-report.js";
|
|
42
|
+
import { renderMcpResourceTemplateCatalogReport } from "./reporting/render-mcp-resource-template-catalog-report.js";
|
|
39
43
|
import { renderMcpPromptDiffMarkdown } from "./reporting/render-mcp-prompt-diff-markdown.js";
|
|
40
44
|
import { renderMcpPromptDiffReport } from "./reporting/render-mcp-prompt-diff-report.js";
|
|
41
45
|
import { renderMcpPromptFileReport } from "./reporting/render-mcp-prompt-file-report.js";
|
|
46
|
+
import { renderMcpResourceTemplateDiffMarkdown } from "./reporting/render-mcp-resource-template-diff-markdown.js";
|
|
47
|
+
import { renderMcpResourceTemplateDiffReport } from "./reporting/render-mcp-resource-template-diff-report.js";
|
|
48
|
+
import { renderMcpResourceTemplateFileReport } from "./reporting/render-mcp-resource-template-file-report.js";
|
|
42
49
|
import { renderMcpDiscoveryReport } from "./reporting/render-mcp-discovery-report.js";
|
|
43
50
|
import { buildDoctorValidationCorpusReport, renderDoctorValidationCorpusJson, renderDoctorValidationCorpusReport } from "./core/validation-corpus.js";
|
|
44
51
|
import { buildExternalValidationCorpusReport, ExternalCorpusManifestError } from "./core/external-validation-corpus.js";
|
|
@@ -122,18 +129,25 @@ const toolsDiffUsage = "Usage: codex-plugin-doctor doctor tools-diff --before <p
|
|
|
122
129
|
const toolsFileUsage = "Usage: codex-plugin-doctor doctor tools-file <path> [--json]";
|
|
123
130
|
const promptsDiffUsage = "Usage: codex-plugin-doctor doctor prompts-diff --before <path> --after <path> [--json|--markdown] [--fail-on any|breaking] [--show-names]";
|
|
124
131
|
const promptsFileUsage = "Usage: codex-plugin-doctor doctor prompts-file <path> [--json]";
|
|
132
|
+
const resourceTemplatesDiffUsage = "Usage: codex-plugin-doctor doctor resource-templates-diff --before <path> --after <path> [--json|--markdown] [--fail-on any|breaking] [--show-names]";
|
|
133
|
+
const resourceTemplatesFileUsage = "Usage: codex-plugin-doctor doctor resource-templates-file <path> [--json]";
|
|
125
134
|
const toolsUsage = "Usage: codex-plugin-doctor doctor tools <url> --allow-network [--allow-local-network] [--json] [--save-response <path>] [--bearer-token-env <NAME>]\n codex-plugin-doctor doctor tools <path> --server <name> --runtime [--sandbox docker [--env <NAME>]...] [--require-runtime-approval [--runtime-approval-digest <digest>]] [--json] [--save-response <path>]";
|
|
135
|
+
const resourceTemplatesUsage = "Usage: codex-plugin-doctor doctor resource-templates <url> --allow-network [--allow-local-network] [--json] [--save-response <path>] [--bearer-token-env <NAME>]\n codex-plugin-doctor doctor resource-templates <path> --server <name> --runtime [--sandbox docker [--env <NAME>]...] [--require-runtime-approval [--runtime-approval-digest <digest>]] [--json] [--save-response <path>]";
|
|
126
136
|
const promptsUsage = "Usage: codex-plugin-doctor doctor prompts <url> --allow-network [--allow-local-network] [--json] [--save-response <path>] [--bearer-token-env <NAME>]\n codex-plugin-doctor doctor prompts <path> --server <name> --runtime [--sandbox docker [--env <NAME>]...] [--require-runtime-approval [--runtime-approval-digest <digest>]] [--json] [--save-response <path>]";
|
|
127
|
-
const TOOL_CATALOG_COMMAND = { name: "tools", noun: "Tool", method: "tools/list", usage: toolsUsage };
|
|
128
|
-
const PROMPT_CATALOG_COMMAND = { name: "prompts", noun: "Prompt", method: "prompts/list", usage: promptsUsage };
|
|
137
|
+
const TOOL_CATALOG_COMMAND = { name: "tools", noun: "Tool", plural: "tools", method: "tools/list", resultKey: "tools", usage: toolsUsage };
|
|
138
|
+
const PROMPT_CATALOG_COMMAND = { name: "prompts", noun: "Prompt", plural: "prompts", method: "prompts/list", resultKey: "prompts", usage: promptsUsage };
|
|
139
|
+
const RESOURCE_TEMPLATE_CATALOG_COMMAND = {
|
|
140
|
+
name: "resource-templates", noun: "Resource template", plural: "resource templates",
|
|
141
|
+
method: "resources/templates/list", resultKey: "resourceTemplates", usage: resourceTemplatesUsage
|
|
142
|
+
};
|
|
129
143
|
const discoveryUsage = "Usage: codex-plugin-doctor doctor discover <url> --allow-network [--allow-local-network] [--json] [--bearer-token-env <NAME>]";
|
|
130
144
|
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.";
|
|
131
145
|
const ENVIRONMENT_VARIABLE_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
132
|
-
/** Reads init-ci --tools-diff-server, --baseline, and --sandbox; options is null when none is given. */
|
|
146
|
+
/** Reads init-ci --tools-diff-server, --baseline, --prompts-baseline, and --sandbox; options is null when none is given. */
|
|
133
147
|
function parseToolsDiffWorkflowOptions(flags) {
|
|
134
148
|
const values = new Map();
|
|
135
149
|
for (let index = 0; index < flags.length; index += 1) {
|
|
136
|
-
if (!["--tools-diff-server", "--baseline", "--sandbox"].includes(flags[index]))
|
|
150
|
+
if (!["--tools-diff-server", "--baseline", "--prompts-baseline", "--sandbox"].includes(flags[index]))
|
|
137
151
|
continue;
|
|
138
152
|
const value = flags[index + 1];
|
|
139
153
|
const present = value !== undefined && !value.startsWith("--");
|
|
@@ -144,7 +158,7 @@ function parseToolsDiffWorkflowOptions(flags) {
|
|
|
144
158
|
if (values.size === 0)
|
|
145
159
|
return { options: null };
|
|
146
160
|
if (!values.has("--tools-diff-server"))
|
|
147
|
-
return { error: "--baseline and --sandbox require --tools-diff-server." };
|
|
161
|
+
return { error: "--baseline, --prompts-baseline, and --sandbox require --tools-diff-server." };
|
|
148
162
|
// Control characters would break the generated workflow lines, GitHub evaluates "${{" in any
|
|
149
163
|
// workflow value, and the Action rejects values that start with "-".
|
|
150
164
|
const usable = (value) => value !== undefined && value.trim() !== "" && !value.startsWith("-") && !value.includes("${{")
|
|
@@ -152,16 +166,23 @@ function parseToolsDiffWorkflowOptions(flags) {
|
|
|
152
166
|
const server = values.get("--tools-diff-server");
|
|
153
167
|
if (!usable(server))
|
|
154
168
|
return { error: "--tools-diff-server requires a server name." };
|
|
155
|
-
// The workflow runs on Linux from the repository root, so
|
|
169
|
+
// The workflow runs on Linux from the repository root, so baselines are relative POSIX paths.
|
|
170
|
+
const relative = (value) => usable(value) && !path.posix.isAbsolute(value)
|
|
171
|
+
&& !/^[A-Za-z]:/u.test(value) && !path.posix.normalize(value).split("/").includes("..");
|
|
156
172
|
const baseline = (values.has("--baseline") ? values.get("--baseline") : "mcp/tools-baseline.json")?.replaceAll("\\", "/");
|
|
157
|
-
if (!
|
|
158
|
-
|| path.posix.normalize(baseline).split("/").includes("..")) {
|
|
173
|
+
if (!relative(baseline))
|
|
159
174
|
return { error: "--baseline requires a relative path inside the repository." };
|
|
175
|
+
const promptsBaseline = values.has("--prompts-baseline") ? values.get("--prompts-baseline")?.replaceAll("\\", "/") : null;
|
|
176
|
+
if (promptsBaseline !== null && !relative(promptsBaseline)) {
|
|
177
|
+
return { error: "--prompts-baseline requires a relative path inside the repository." };
|
|
178
|
+
}
|
|
179
|
+
if (promptsBaseline !== null && path.posix.normalize(promptsBaseline) === path.posix.normalize(baseline)) {
|
|
180
|
+
return { error: "--prompts-baseline must differ from --baseline." };
|
|
160
181
|
}
|
|
161
182
|
const sandbox = values.get("--sandbox");
|
|
162
183
|
if (values.has("--sandbox") && sandbox !== "docker")
|
|
163
184
|
return { error: "--sandbox must be docker." };
|
|
164
|
-
return { options: { server, baseline, sandbox: sandbox === "docker" ? "docker" : null } };
|
|
185
|
+
return { options: { server, baseline, sandbox: sandbox === "docker" ? "docker" : null, promptsBaseline } };
|
|
165
186
|
}
|
|
166
187
|
const MAX_FORWARDED_ENVIRONMENT_VARIABLES = 32;
|
|
167
188
|
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.";
|
|
@@ -188,7 +209,7 @@ async function finishCatalogCommand(io, kind, status, output, items, cache, save
|
|
|
188
209
|
io.writeStderr(`${kind.noun} catalog response was not saved because enumeration did not complete.`);
|
|
189
210
|
return 2;
|
|
190
211
|
}
|
|
191
|
-
const saved = await saveMcpListResponse(savePath, kind.
|
|
212
|
+
const saved = await saveMcpListResponse(savePath, kind.resultKey, items, cache);
|
|
192
213
|
if (saved.kind !== "saved") {
|
|
193
214
|
io.writeStderr({
|
|
194
215
|
"path-blocked": `${kind.noun} catalog response was not saved because the path is not a local file path.`,
|
|
@@ -198,7 +219,7 @@ async function finishCatalogCommand(io, kind, status, output, items, cache, save
|
|
|
198
219
|
}[saved.kind]);
|
|
199
220
|
return 2;
|
|
200
221
|
}
|
|
201
|
-
io.writeStderr(`Saved a complete ${kind.method} response with ${saved.count} ${kind.
|
|
222
|
+
io.writeStderr(`Saved a complete ${kind.method} response with ${saved.count} ${kind.plural} (${saved.bytes} bytes).`);
|
|
202
223
|
return exitCode;
|
|
203
224
|
}
|
|
204
225
|
function finishToolCatalogCommand(io, snapshot, json, savePath) {
|
|
@@ -209,6 +230,10 @@ function finishPromptCatalogCommand(io, snapshot, json, savePath) {
|
|
|
209
230
|
const report = snapshot.report;
|
|
210
231
|
return finishCatalogCommand(io, PROMPT_CATALOG_COMMAND, report.status, json ? JSON.stringify(report, null, 2) : renderMcpPromptCatalogReport(report), snapshot.prompts, snapshot.cache, savePath);
|
|
211
232
|
}
|
|
233
|
+
function finishResourceTemplateCatalogCommand(io, snapshot, json, savePath) {
|
|
234
|
+
const report = snapshot.report;
|
|
235
|
+
return finishCatalogCommand(io, RESOURCE_TEMPLATE_CATALOG_COMMAND, report.status, json ? JSON.stringify(report, null, 2) : renderMcpResourceTemplateCatalogReport(report), snapshot.templates, snapshot.cache, savePath);
|
|
236
|
+
}
|
|
212
237
|
async function runHttpCatalogCommand(url, flags, io, env, kind, run) {
|
|
213
238
|
const allowedFlags = new Set(["--allow-network", "--allow-local-network", "--json"]);
|
|
214
239
|
const switches = [];
|
|
@@ -509,14 +534,17 @@ function parseRemoteNetworkFlags(flags, runtime) {
|
|
|
509
534
|
return { allowNetwork, allowLocalNetwork, allowSessionLifecycle, requireRemoteReliability };
|
|
510
535
|
}
|
|
511
536
|
function printUsage(io) {
|
|
512
|
-
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");
|
|
537
|
+
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>] [--prompts-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");
|
|
513
538
|
io.writeStderr(discoveryUsage);
|
|
514
539
|
io.writeStderr(toolsUsage);
|
|
515
540
|
io.writeStderr(promptsUsage);
|
|
541
|
+
io.writeStderr(resourceTemplatesUsage);
|
|
516
542
|
io.writeStderr(toolsFileUsage);
|
|
517
543
|
io.writeStderr(toolsDiffUsage);
|
|
518
544
|
io.writeStderr(promptsFileUsage);
|
|
519
545
|
io.writeStderr(promptsDiffUsage);
|
|
546
|
+
io.writeStderr(resourceTemplatesFileUsage);
|
|
547
|
+
io.writeStderr(resourceTemplatesDiffUsage);
|
|
520
548
|
io.writeStderr("Registry readiness: codex-plugin-doctor registry check <server.json|directory> [--json] [--output <path>] [--require-registry-readiness]\n"
|
|
521
549
|
+ " codex-plugin-doctor registry inspect <server-name> --allow-network [--json] [--output <path>] [--require-registry-readiness]\n"
|
|
522
550
|
+ "Registry publication preflight: codex-plugin-doctor registry preflight <server.json|directory> [--allow-network] [--json] [--output <path>] [--require-publish-ready]");
|
|
@@ -1480,10 +1508,10 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1480
1508
|
(command === "doctor" &&
|
|
1481
1509
|
(["runtime-plan", "runtime-policy"].includes(maybePath ?? "") ||
|
|
1482
1510
|
(maybePath === "release-evidence" && remainingArgs[0] !== "verify") ||
|
|
1483
|
-
(
|
|
1511
|
+
(["tools", "prompts", "resource-templates"].includes(maybePath ?? "") && remainingArgs.includes("--server")))) ||
|
|
1484
1512
|
(command === "init-ci" && args.includes("--tools-diff-server"));
|
|
1485
1513
|
if (args.includes("--sandbox") && !runtimeSandboxSupported) {
|
|
1486
|
-
io.writeStderr("--sandbox is supported only by single-package check, release check, runtime-plan, runtime-policy, release-evidence, doctor tools --server, doctor prompts --server, and init-ci --tools-diff-server.");
|
|
1514
|
+
io.writeStderr("--sandbox is supported only by single-package check, release check, runtime-plan, runtime-policy, release-evidence, doctor tools --server, doctor prompts --server, doctor resource-templates --server, and init-ci --tools-diff-server.");
|
|
1487
1515
|
return 2;
|
|
1488
1516
|
}
|
|
1489
1517
|
if (command === "--version" || command === "-v" || command === "version") {
|
|
@@ -1565,6 +1593,24 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1565
1593
|
}
|
|
1566
1594
|
return runOfflineFileCommand(remainingArgs, io, promptsFileUsage, options.inspectMcpPromptFileImpl ?? inspectMcpPromptFile, renderMcpPromptFileReport);
|
|
1567
1595
|
}
|
|
1596
|
+
if (maybePath === "resource-templates-diff") {
|
|
1597
|
+
if (remainingArgs.length === 1 && remainingArgs[0] === "--help") {
|
|
1598
|
+
io.writeStdout(`${resourceTemplatesDiffUsage}\nCompares two saved MCP resources/templates/list responses offline. Changes are classified heuristically as breaking, compatible, or unclassified; no resource is read and compatibility is not tested.\n--fail-on breaking exits 1 only for breaking or unclassified changes (default: any change or input warning).
|
|
1599
|
+
--show-names adds template names and the variable behind each reason; reports omit both, and never include URI templates, so keep the flag out of public output such as pull request comments.`);
|
|
1600
|
+
return 0;
|
|
1601
|
+
}
|
|
1602
|
+
return runOfflineDiffCommand(remainingArgs, io, resourceTemplatesDiffUsage, (beforePath, afterPath, showNames) => {
|
|
1603
|
+
const compare = options.compareMcpResourceTemplateFilesImpl ?? compareMcpResourceTemplateFiles;
|
|
1604
|
+
return showNames ? compare(beforePath, afterPath, { showNames: true }) : compare(beforePath, afterPath);
|
|
1605
|
+
}, (report, markdown) => markdown ? renderMcpResourceTemplateDiffMarkdown(report) : renderMcpResourceTemplateDiffReport(report));
|
|
1606
|
+
}
|
|
1607
|
+
if (maybePath === "resource-templates-file") {
|
|
1608
|
+
if (remainingArgs.length === 1 && remainingArgs[0] === "--help") {
|
|
1609
|
+
io.writeStdout(`${resourceTemplatesFileUsage}\nInspects one saved UTF-8 MCP resources/templates/list response. No server connection or resource read.`);
|
|
1610
|
+
return 0;
|
|
1611
|
+
}
|
|
1612
|
+
return runOfflineFileCommand(remainingArgs, io, resourceTemplatesFileUsage, options.inspectMcpResourceTemplateFileImpl ?? inspectMcpResourceTemplateFile, renderMcpResourceTemplateFileReport);
|
|
1613
|
+
}
|
|
1568
1614
|
if (maybePath === "tools") {
|
|
1569
1615
|
if (remainingArgs.length === 1 && remainingArgs[0] === "--help") {
|
|
1570
1616
|
io.writeStdout(`${toolsUsage}\nTool catalog structure only; tools are not executed.\n--server starts the named stdio server from the package MCP configuration after explicit --runtime consent and stops it after reading the tool list.\n${forwardedEnvironmentHelp}\n--save-response writes a complete enumeration as one tools/list response for doctor tools-file and tools-diff; nothing is written when enumeration is incomplete.\n${bearerTokenHelp}`);
|
|
@@ -1600,6 +1646,21 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1600
1646
|
}
|
|
1601
1647
|
return runHttpCatalogCommand(target, flags, io, terminalContext.env, PROMPT_CATALOG_COMMAND, async (url, catalogOptions, json, savePath) => finishPromptCatalogCommand(io, await (options.captureMcpPromptCatalogImpl ?? captureMcpPromptCatalog)(url, catalogOptions), json, savePath));
|
|
1602
1648
|
}
|
|
1649
|
+
if (maybePath === "resource-templates") {
|
|
1650
|
+
if (remainingArgs.length === 1 && remainingArgs[0] === "--help") {
|
|
1651
|
+
io.writeStdout(`${resourceTemplatesUsage}\nResource template catalog structure only; no resource is read.\n--server starts the named stdio server from the package MCP configuration after explicit --runtime consent and stops it after reading the resource template list.\n${forwardedEnvironmentHelp}\n--save-response writes a complete enumeration as one resources/templates/list response for doctor resource-templates-file and resource-templates-diff; nothing is written when enumeration is incomplete.\n${bearerTokenHelp}`);
|
|
1652
|
+
return 0;
|
|
1653
|
+
}
|
|
1654
|
+
const [target, ...flags] = remainingArgs;
|
|
1655
|
+
if (!target || target.startsWith("-")) {
|
|
1656
|
+
io.writeStderr(resourceTemplatesUsage);
|
|
1657
|
+
return 2;
|
|
1658
|
+
}
|
|
1659
|
+
if (flags.includes("--server")) {
|
|
1660
|
+
return runStdioCatalogCommand(target, flags, io, terminalContext.env, RESOURCE_TEMPLATE_CATALOG_COMMAND, async (server, captureOptions, json, savePath) => finishResourceTemplateCatalogCommand(io, await (options.captureStdioMcpResourceTemplateCatalogImpl ?? captureStdioMcpResourceTemplateCatalog)(server, captureOptions), json, savePath));
|
|
1661
|
+
}
|
|
1662
|
+
return runHttpCatalogCommand(target, flags, io, terminalContext.env, RESOURCE_TEMPLATE_CATALOG_COMMAND, async (url, catalogOptions, json, savePath) => finishResourceTemplateCatalogCommand(io, await (options.captureMcpResourceTemplateCatalogImpl ?? captureMcpResourceTemplateCatalog)(url, catalogOptions), json, savePath));
|
|
1663
|
+
}
|
|
1603
1664
|
if (maybePath === "discover") {
|
|
1604
1665
|
if (remainingArgs.length === 1 && remainingArgs[0] === "--help") {
|
|
1605
1666
|
io.writeStdout(`${discoveryUsage}\nHTTP discovery only; runtime behavior is not tested.\n${bearerTokenHelp}`);
|
|
@@ -2882,13 +2943,16 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
2882
2943
|
return 2;
|
|
2883
2944
|
}
|
|
2884
2945
|
if (toolsDiff.options !== null) {
|
|
2885
|
-
const { server, baseline, sandbox } = toolsDiff.options;
|
|
2946
|
+
const { server, baseline, sandbox, promptsBaseline } = toolsDiff.options;
|
|
2886
2947
|
const toolsResult = await initToolsDiffWorkflow(targetPath, toolsDiff.options);
|
|
2887
2948
|
io.writeStdout([
|
|
2888
2949
|
"Initialized Codex Plugin Doctor tool diff workflow",
|
|
2889
2950
|
`Root: ${toolsResult.rootPath}`,
|
|
2890
2951
|
`Workflow: ${toolsResult.workflowPath}`,
|
|
2891
|
-
`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))}
|
|
2952
|
+
`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))}`,
|
|
2953
|
+
...(promptsBaseline === null ? [] : [
|
|
2954
|
+
`Capture and commit a prompt baseline at ${promptsBaseline}, for example with: codex-plugin-doctor doctor prompts ${JSON.stringify(targetPath)} --server ${JSON.stringify(server)} --runtime${sandbox === "docker" ? " --sandbox docker" : ""} --save-response ${JSON.stringify(path.join(targetPath, promptsBaseline))}`
|
|
2955
|
+
])
|
|
2892
2956
|
].join("\n"));
|
|
2893
2957
|
return 0;
|
|
2894
2958
|
}
|
package/package.json
CHANGED