codex-plugin-doctor 1.76.0 → 1.78.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.
Files changed (38) hide show
  1. package/README.md +21 -2
  2. package/dist/core/init-ci.d.ts +1 -0
  3. package/dist/core/init-ci.js +16 -2
  4. package/dist/core/mcp-prompt-catalog.d.ts +36 -0
  5. package/dist/core/mcp-prompt-catalog.js +53 -0
  6. package/dist/core/mcp-prompt-definition.d.ts +24 -0
  7. package/dist/core/mcp-prompt-definition.js +107 -0
  8. package/dist/core/mcp-prompt-diff.d.ts +43 -0
  9. package/dist/core/mcp-prompt-diff.js +132 -0
  10. package/dist/core/mcp-prompt-file.d.ts +31 -0
  11. package/dist/core/mcp-prompt-file.js +118 -0
  12. package/dist/core/mcp-prompt-impact.d.ts +21 -0
  13. package/dist/core/mcp-prompt-impact.js +93 -0
  14. package/dist/core/mcp-stdio-tool-catalog.d.ts +9 -3
  15. package/dist/core/mcp-stdio-tool-catalog.js +74 -55
  16. package/dist/core/mcp-tool-catalog.d.ts +44 -5
  17. package/dist/core/mcp-tool-catalog.js +76 -31
  18. package/dist/core/mcp-tool-diff.d.ts +1 -0
  19. package/dist/core/mcp-tool-diff.js +1 -1
  20. package/dist/core/mcp-tool-file.d.ts +20 -0
  21. package/dist/core/mcp-tool-file.js +1 -1
  22. package/dist/core/mcp-tool-response-file.d.ts +6 -4
  23. package/dist/core/mcp-tool-response-file.js +8 -8
  24. package/dist/core/output-contract.js +177 -0
  25. package/dist/reporting/quote-server-text.d.ts +1 -0
  26. package/dist/reporting/quote-server-text.js +13 -0
  27. package/dist/reporting/render-mcp-prompt-catalog-report.d.ts +2 -0
  28. package/dist/reporting/render-mcp-prompt-catalog-report.js +31 -0
  29. package/dist/reporting/render-mcp-prompt-diff-markdown.d.ts +2 -0
  30. package/dist/reporting/render-mcp-prompt-diff-markdown.js +39 -0
  31. package/dist/reporting/render-mcp-prompt-diff-report.d.ts +2 -0
  32. package/dist/reporting/render-mcp-prompt-diff-report.js +48 -0
  33. package/dist/reporting/render-mcp-prompt-file-report.d.ts +5 -0
  34. package/dist/reporting/render-mcp-prompt-file-report.js +33 -0
  35. package/dist/reporting/render-mcp-tool-diff-markdown.js +3 -16
  36. package/dist/run-cli.d.ts +7 -0
  37. package/dist/run-cli.js +223 -150
  38. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ import type { McpPromptDiffReport } from "../core/mcp-prompt-diff.js";
2
+ export declare function renderMcpPromptDiffReport(report: McpPromptDiffReport): string;
@@ -0,0 +1,48 @@
1
+ import { describePromptLocation } from "./render-mcp-prompt-file-report.js";
2
+ import { quoteServerText } from "./quote-server-text.js";
3
+ export function renderMcpPromptDiffReport(report) {
4
+ const comparison = report.comparison;
5
+ return [
6
+ "Offline MCP Prompt 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
+ `Prompt retrieval: ${report.coverage.promptRetrieval}`,
23
+ `Impact classification: ${report.coverage.impactClassification}`,
24
+ "Only the supplied responses are compared. Impact labels are argument 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}; prompts checked: ${source.inspection.promptsChecked}; 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} ${describePromptLocation(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.beforePromptIndex === null ? [] : [`before prompt ${change.beforePromptIndex}`]),
40
+ ...(change.afterPromptIndex === null ? [] : [`after prompt ${change.afterPromptIndex}`])
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.argument === null ? "(prompt)" : `argument ${quoteServerText(location.argument)}`}: ${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 { PromptCatalogLocation } from "../core/mcp-prompt-definition.js";
2
+ import type { McpPromptFileReport } from "../core/mcp-prompt-file.js";
3
+ /** Describes a finding location by one-based positions only, such as "prompt 2, argument 1, related argument 3". */
4
+ export declare function describePromptLocation(location: PromptCatalogLocation): string;
5
+ export declare function renderMcpPromptFileReport(report: McpPromptFileReport): string;
@@ -0,0 +1,33 @@
1
+ /** Describes a finding location by one-based positions only, such as "prompt 2, argument 1, related argument 3". */
2
+ export function describePromptLocation(location) {
3
+ return [
4
+ `prompt ${location.promptIndex}`,
5
+ ...(location.argumentIndex === undefined ? [] : [`argument ${location.argumentIndex}`]),
6
+ ...(location.relatedPromptIndex === undefined ? [] : [`related prompt ${location.relatedPromptIndex}`]),
7
+ ...(location.relatedArgumentIndex === undefined ? [] : [`related argument ${location.relatedArgumentIndex}`])
8
+ ].join(", ");
9
+ }
10
+ export function renderMcpPromptFileReport(report) {
11
+ return [
12
+ "Offline MCP Prompt Definitions",
13
+ "==============================",
14
+ `Status: ${report.status}`,
15
+ `Scope: ${report.scope}`,
16
+ `Source: ${report.source.kind} (${report.source.format})`,
17
+ `Bytes read: ${report.source.bytesRead}`,
18
+ `Inspection complete: ${report.inspection.complete}`,
19
+ `Prompts checked: ${report.inspection.promptsChecked}`,
20
+ `More pages advertised: ${report.inspection.hasNextCursor ?? "unknown"}`,
21
+ ...(report.inspection.reason === null ? [] : [`Reason: ${report.inspection.reason}`]),
22
+ `Definition coverage: ${report.coverage.definitions}`,
23
+ `Discovery: ${report.coverage.discovery}`,
24
+ `Server catalog: ${report.coverage.serverCatalog}`,
25
+ `Prompt retrieval: ${report.coverage.promptRetrieval}`,
26
+ `Full conformance: ${report.coverage.fullConformance}`,
27
+ "Only the supplied file was inspected. Its provenance and server completeness are not established.",
28
+ ...report.findings.map((finding) => {
29
+ const locator = finding.location ? ` [${describePromptLocation(finding.location)}]` : "";
30
+ return `${finding.severity.toUpperCase()} ${finding.id}${locator}: ${finding.message}\n ${finding.suggestedFix}`;
31
+ })
32
+ ].join("\n");
33
+ }
@@ -1,23 +1,10 @@
1
- import { quoteServerText } from "./quote-server-text.js";
1
+ import { markdownCodeSpan } from "./quote-server-text.js";
2
2
  function count(value) {
3
3
  return value === null || value === undefined ? "not compared" : String(value);
4
4
  }
5
5
  function toolIndex(value) {
6
6
  return value === null ? "-" : String(value);
7
7
  }
8
- // Names and pointers come from the server, so they are quoted and put in a code span, where Markdown,
9
- // HTML, mentions, and links stay inert; the fence outgrows any backtick run, and pipes are escaped for the table.
10
- function code(text) {
11
- const quoted = quoteServerText(text);
12
- let run = 0;
13
- let longest = 0;
14
- for (const character of quoted) {
15
- run = character === "`" ? run + 1 : 0;
16
- longest = Math.max(longest, run);
17
- }
18
- const fence = "`".repeat(longest + 1);
19
- return `${fence}${quoted.replace(/\|/gu, "\\|")}${fence}`;
20
- }
21
8
  export function renderMcpToolDiffMarkdown(report) {
22
9
  const comparison = report.comparison;
23
10
  const named = report.changes.some((change) => change.name !== undefined);
@@ -31,9 +18,9 @@ export function renderMcpToolDiffMarkdown(report) {
31
18
  `| ${count(comparison.added)} | ${count(comparison.removed)} | ${count(comparison.changed)} | ${count(comparison.unchanged)} | ${count(comparison.breaking)} | ${count(comparison.unclassified)} |`
32
19
  ];
33
20
  if (report.changes.length > 0) {
34
- lines.push("", "### Changes", "", named ? "| Change | Tool | Before tool | After tool | Fields | Impact | Reasons |" : "| Change | Before tool | After tool | Fields | Impact | Reasons |", named ? "| --- | --- | --- | --- | --- | --- | --- |" : "| --- | --- | --- | --- | --- | --- |", ...report.changes.map((change) => `| ${change.kind}${named ? ` | ${change.name === undefined ? "-" : code(change.name)}` : ""} | ${toolIndex(change.beforeToolIndex)} | ${toolIndex(change.afterToolIndex)} | ${change.fields.map((field) => `\`${field}\``).join(", ") || "-"} | **${change.impact}** | ${change.reasons.map((reason) => `\`${reason}\``).join(", ") || "-"} |`));
21
+ lines.push("", "### Changes", "", named ? "| Change | Tool | Before tool | After tool | Fields | Impact | Reasons |" : "| Change | Before tool | After tool | Fields | Impact | Reasons |", named ? "| --- | --- | --- | --- | --- | --- | --- |" : "| --- | --- | --- | --- | --- | --- |", ...report.changes.map((change) => `| ${change.kind}${named ? ` | ${change.name === undefined ? "-" : markdownCodeSpan(change.name)}` : ""} | ${toolIndex(change.beforeToolIndex)} | ${toolIndex(change.afterToolIndex)} | ${change.fields.map((field) => `\`${field}\``).join(", ") || "-"} | **${change.impact}** | ${change.reasons.map((reason) => `\`${reason}\``).join(", ") || "-"} |`));
35
22
  }
36
- const located = report.changes.flatMap((change) => (change.locations ?? []).map((location) => `| ${change.name === undefined ? "-" : code(change.name)} | \`${location.reason}\` | ${location.pointer === "" ? "(tool)" : code(location.pointer)} |`));
23
+ const located = report.changes.flatMap((change) => (change.locations ?? []).map((location) => `| ${change.name === undefined ? "-" : markdownCodeSpan(change.name)} | \`${location.reason}\` | ${location.pointer === "" ? "(tool)" : markdownCodeSpan(location.pointer)} |`));
37
24
  if (located.length > 0) {
38
25
  lines.push("", "### Locations", "", "| Tool | Reason | Location |", "| --- | --- | --- |", ...located);
39
26
  }
package/dist/run-cli.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  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
+ import { captureMcpPromptCatalog, captureStdioMcpPromptCatalog } from "./core/mcp-prompt-catalog.js";
5
+ import { compareMcpPromptFiles } from "./core/mcp-prompt-diff.js";
6
+ import { inspectMcpPromptFile } from "./core/mcp-prompt-file.js";
4
7
  import { inspectMcpToolFile } from "./core/mcp-tool-file.js";
5
8
  import { compareMcpToolFiles } from "./core/mcp-tool-diff.js";
6
9
  import { buildCorpusQualityMetricsDiffReport, buildCorpusQualityMetricsReport } from "./core/corpus-quality-metrics.js";
@@ -23,6 +26,10 @@ export interface RunCliOptions {
23
26
  inspectMcpToolCatalogImpl?: typeof inspectMcpToolCatalog;
24
27
  captureMcpToolCatalogImpl?: typeof captureMcpToolCatalog;
25
28
  captureStdioMcpToolCatalogImpl?: typeof captureStdioMcpToolCatalog;
29
+ compareMcpPromptFilesImpl?: typeof compareMcpPromptFiles;
30
+ inspectMcpPromptFileImpl?: typeof inspectMcpPromptFile;
31
+ captureMcpPromptCatalogImpl?: typeof captureMcpPromptCatalog;
32
+ captureStdioMcpPromptCatalogImpl?: typeof captureStdioMcpPromptCatalog;
26
33
  discoverMcpServerImpl?: typeof discoverMcpServer;
27
34
  terminalContext?: CliTerminalContext;
28
35
  runCheckImpl?: typeof runCheck;