codex-plugin-doctor 0.1.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/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +9 -0
- package/dist/core/discover-package.d.ts +2 -0
- package/dist/core/discover-package.js +18 -0
- package/dist/core/runtime-probe.d.ts +5 -0
- package/dist/core/runtime-probe.js +917 -0
- package/dist/core/runtime-transcript.d.ts +5 -0
- package/dist/core/runtime-transcript.js +139 -0
- package/dist/core/validate-plugin.d.ts +2 -0
- package/dist/core/validate-plugin.js +341 -0
- package/dist/domain/types.d.ts +64 -0
- package/dist/domain/types.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/release/release-notes.d.ts +9 -0
- package/dist/release/release-notes.js +46 -0
- package/dist/reporting/render-json-report.d.ts +7 -0
- package/dist/reporting/render-json-report.js +26 -0
- package/dist/reporting/render-markdown-report.d.ts +4 -0
- package/dist/reporting/render-markdown-report.js +44 -0
- package/dist/reporting/render-text-report.d.ts +4 -0
- package/dist/reporting/render-text-report.js +77 -0
- package/dist/run-cli.d.ts +15 -0
- package/dist/run-cli.js +87 -0
- package/dist/terminal/live-status-renderer.d.ts +9 -0
- package/dist/terminal/live-status-renderer.js +38 -0
- package/dist/terminal/output-policy.d.ts +16 -0
- package/dist/terminal/output-policy.js +50 -0
- package/dist/terminal/spinner-registry.d.ts +8 -0
- package/dist/terminal/spinner-registry.js +30 -0
- package/package.json +61 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export function buildMarkdownReport(result, options) {
|
|
2
|
+
const failCount = result.findings.filter((finding) => finding.severity === "fail").length;
|
|
3
|
+
const warnCount = result.findings.filter((finding) => finding.severity === "warn").length;
|
|
4
|
+
const lines = [
|
|
5
|
+
"# Codex Plugin Doctor Report",
|
|
6
|
+
"",
|
|
7
|
+
"| Field | Value |",
|
|
8
|
+
"| --- | --- |",
|
|
9
|
+
`| Target | \`${result.targetPath}\` |`,
|
|
10
|
+
`| Status | ${result.status.toUpperCase()} |`,
|
|
11
|
+
`| Exit Code | ${result.exitCode} |`,
|
|
12
|
+
`| Runtime Probe | ${options.runtimeProbeEnabled ? "enabled" : "disabled"} |`,
|
|
13
|
+
`| Fail Findings | ${failCount} |`,
|
|
14
|
+
`| Warn Findings | ${warnCount} |`,
|
|
15
|
+
`| Total Findings | ${result.findings.length} |`
|
|
16
|
+
];
|
|
17
|
+
if (result.findings.length === 0) {
|
|
18
|
+
lines.push("", "No findings.");
|
|
19
|
+
return lines.join("\n");
|
|
20
|
+
}
|
|
21
|
+
if (result.runtimeScorecard) {
|
|
22
|
+
lines.push("", "## Runtime Scorecard", "");
|
|
23
|
+
lines.push("| Operation | Status |");
|
|
24
|
+
lines.push("| --- | --- |");
|
|
25
|
+
lines.push(`| initialize | ${result.runtimeScorecard.initialize.toUpperCase()} |`);
|
|
26
|
+
lines.push(`| tools/list | ${result.runtimeScorecard.toolsList.toUpperCase()} |`);
|
|
27
|
+
lines.push(`| tools/call | ${result.runtimeScorecard.toolsCall.toUpperCase()} |`);
|
|
28
|
+
lines.push(`| resources/list | ${result.runtimeScorecard.resourcesList.toUpperCase()} |`);
|
|
29
|
+
lines.push(`| resources/read | ${result.runtimeScorecard.resourceRead.toUpperCase()} |`);
|
|
30
|
+
lines.push(`| resources/templates/list | ${result.runtimeScorecard.resourceTemplatesList.toUpperCase()} |`);
|
|
31
|
+
lines.push(`| prompts/list | ${result.runtimeScorecard.promptsList.toUpperCase()} |`);
|
|
32
|
+
lines.push(`| prompts/get | ${result.runtimeScorecard.promptGet.toUpperCase()} |`);
|
|
33
|
+
}
|
|
34
|
+
lines.push("", "## Findings", "");
|
|
35
|
+
for (const finding of result.findings) {
|
|
36
|
+
lines.push(`### ${finding.severity.toUpperCase()} \`${finding.id}\``);
|
|
37
|
+
lines.push("");
|
|
38
|
+
lines.push(`- Message: ${finding.message}`);
|
|
39
|
+
lines.push(`- Impact: ${finding.impact}`);
|
|
40
|
+
lines.push(`- Suggested fix: ${finding.suggestedFix}`);
|
|
41
|
+
lines.push("");
|
|
42
|
+
}
|
|
43
|
+
return lines.join("\n");
|
|
44
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
function getCounts(result) {
|
|
2
|
+
const failCount = result.findings.filter((finding) => finding.severity === "fail").length;
|
|
3
|
+
const warnCount = result.findings.filter((finding) => finding.severity === "warn").length;
|
|
4
|
+
return {
|
|
5
|
+
failCount,
|
|
6
|
+
warnCount,
|
|
7
|
+
totalCount: result.findings.length
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function getGlyphs(ascii) {
|
|
11
|
+
return ascii
|
|
12
|
+
? {
|
|
13
|
+
fail: "x",
|
|
14
|
+
warn: "!",
|
|
15
|
+
ok: "ok"
|
|
16
|
+
}
|
|
17
|
+
: {
|
|
18
|
+
fail: "✖",
|
|
19
|
+
warn: "!",
|
|
20
|
+
ok: "✔"
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function renderTextReport(result, options = {}) {
|
|
24
|
+
const ascii = options.ascii ?? false;
|
|
25
|
+
const glyphs = getGlyphs(ascii);
|
|
26
|
+
const { failCount, warnCount, totalCount } = getCounts(result);
|
|
27
|
+
const lines = [
|
|
28
|
+
"Codex Plugin Doctor",
|
|
29
|
+
"===================",
|
|
30
|
+
`Status: ${result.status.toUpperCase()}`,
|
|
31
|
+
`Target: ${result.targetPath}`,
|
|
32
|
+
`Summary: ${failCount} fail, ${warnCount} warn, ${totalCount} total`
|
|
33
|
+
];
|
|
34
|
+
if (result.findings.length === 0) {
|
|
35
|
+
if (result.runtimeScorecard) {
|
|
36
|
+
lines.push("", "Runtime Scorecard", "----------------");
|
|
37
|
+
lines.push(`initialize: ${result.runtimeScorecard.initialize}`);
|
|
38
|
+
lines.push(`tools/list: ${result.runtimeScorecard.toolsList}`);
|
|
39
|
+
lines.push(`tools/call: ${result.runtimeScorecard.toolsCall}`);
|
|
40
|
+
lines.push(`resources/list: ${result.runtimeScorecard.resourcesList}`);
|
|
41
|
+
lines.push(`resources/read: ${result.runtimeScorecard.resourceRead}`);
|
|
42
|
+
lines.push(`resources/templates/list: ${result.runtimeScorecard.resourceTemplatesList}`);
|
|
43
|
+
lines.push(`prompts/list: ${result.runtimeScorecard.promptsList}`);
|
|
44
|
+
lines.push(`prompts/get: ${result.runtimeScorecard.promptGet}`);
|
|
45
|
+
}
|
|
46
|
+
lines.push("", "No findings.");
|
|
47
|
+
return lines.join("\n");
|
|
48
|
+
}
|
|
49
|
+
const failures = result.findings.filter((finding) => finding.severity === "fail");
|
|
50
|
+
const warnings = result.findings.filter((finding) => finding.severity === "warn");
|
|
51
|
+
const appendSection = (title, items, marker) => {
|
|
52
|
+
if (items.length === 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
lines.push("", title, "--------");
|
|
56
|
+
for (const finding of items) {
|
|
57
|
+
lines.push(`${marker} ${finding.id}`);
|
|
58
|
+
lines.push(` Message: ${finding.message}`);
|
|
59
|
+
lines.push(` Impact: ${finding.impact}`);
|
|
60
|
+
lines.push(` Suggested fix: ${finding.suggestedFix}`);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
appendSection("Failures", failures, glyphs.fail);
|
|
64
|
+
appendSection("Warnings", warnings, glyphs.warn);
|
|
65
|
+
if (result.runtimeScorecard) {
|
|
66
|
+
lines.push("", "Runtime Scorecard", "----------------");
|
|
67
|
+
lines.push(`initialize: ${result.runtimeScorecard.initialize}`);
|
|
68
|
+
lines.push(`tools/list: ${result.runtimeScorecard.toolsList}`);
|
|
69
|
+
lines.push(`tools/call: ${result.runtimeScorecard.toolsCall}`);
|
|
70
|
+
lines.push(`resources/list: ${result.runtimeScorecard.resourcesList}`);
|
|
71
|
+
lines.push(`resources/read: ${result.runtimeScorecard.resourceRead}`);
|
|
72
|
+
lines.push(`resources/templates/list: ${result.runtimeScorecard.resourceTemplatesList}`);
|
|
73
|
+
lines.push(`prompts/list: ${result.runtimeScorecard.promptsList}`);
|
|
74
|
+
lines.push(`prompts/get: ${result.runtimeScorecard.promptGet}`);
|
|
75
|
+
}
|
|
76
|
+
return lines.join("\n");
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { runCheck } from "./index.js";
|
|
2
|
+
export interface CliIo {
|
|
3
|
+
writeStdout(message: string): void;
|
|
4
|
+
writeStderr(message: string): void;
|
|
5
|
+
}
|
|
6
|
+
export interface CliTerminalContext {
|
|
7
|
+
stdoutIsTTY: boolean;
|
|
8
|
+
stderrIsTTY: boolean;
|
|
9
|
+
env: Record<string, string | undefined>;
|
|
10
|
+
}
|
|
11
|
+
export interface RunCliOptions {
|
|
12
|
+
terminalContext?: CliTerminalContext;
|
|
13
|
+
runCheckImpl?: typeof runCheck;
|
|
14
|
+
}
|
|
15
|
+
export declare function runCli(args: string[], io?: CliIo, options?: RunCliOptions): Promise<number>;
|
package/dist/run-cli.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { runCheck } from "./index.js";
|
|
3
|
+
import { renderJsonReport } from "./reporting/render-json-report.js";
|
|
4
|
+
import { buildMarkdownReport } from "./reporting/render-markdown-report.js";
|
|
5
|
+
import { renderTextReport } from "./reporting/render-text-report.js";
|
|
6
|
+
import { createLiveStatusRenderer } from "./terminal/live-status-renderer.js";
|
|
7
|
+
import { determineOutputPolicy } from "./terminal/output-policy.js";
|
|
8
|
+
import { getSpinner } from "./terminal/spinner-registry.js";
|
|
9
|
+
const defaultIo = {
|
|
10
|
+
writeStdout(message) {
|
|
11
|
+
process.stdout.write(`${message}\n`);
|
|
12
|
+
},
|
|
13
|
+
writeStderr(message) {
|
|
14
|
+
process.stderr.write(`${message}\n`);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function printUsage(io) {
|
|
18
|
+
io.writeStderr("Usage: codex-plugin-doctor check <path> [--json|--markdown] [--output <path>] [--runtime] [--verbose-runtime] [--no-animations] [--ascii]");
|
|
19
|
+
}
|
|
20
|
+
export async function runCli(args, io = defaultIo, options = {}) {
|
|
21
|
+
const [command, maybePath, ...remainingArgs] = args;
|
|
22
|
+
if (command !== "check") {
|
|
23
|
+
printUsage(io);
|
|
24
|
+
return 2;
|
|
25
|
+
}
|
|
26
|
+
const targetPath = maybePath && !maybePath.startsWith("--") ? maybePath : ".";
|
|
27
|
+
const normalizedFlags = maybePath && maybePath.startsWith("--")
|
|
28
|
+
? [maybePath, ...remainingArgs]
|
|
29
|
+
: remainingArgs;
|
|
30
|
+
const jsonOutput = normalizedFlags.includes("--json");
|
|
31
|
+
const markdownOutput = normalizedFlags.includes("--markdown");
|
|
32
|
+
const runtimeProbeEnabled = normalizedFlags.includes("--runtime");
|
|
33
|
+
const verboseRuntime = normalizedFlags.includes("--verbose-runtime");
|
|
34
|
+
const noAnimations = normalizedFlags.includes("--no-animations");
|
|
35
|
+
const asciiMode = normalizedFlags.includes("--ascii");
|
|
36
|
+
const outputIndex = normalizedFlags.indexOf("--output");
|
|
37
|
+
const outputPath = outputIndex === -1 ? null : normalizedFlags[outputIndex + 1];
|
|
38
|
+
if (outputIndex !== -1 && (!outputPath || outputPath.startsWith("--"))) {
|
|
39
|
+
io.writeStderr("Missing path after --output.");
|
|
40
|
+
return 2;
|
|
41
|
+
}
|
|
42
|
+
const terminalContext = options.terminalContext ?? {
|
|
43
|
+
stdoutIsTTY: Boolean(process.stdout.isTTY),
|
|
44
|
+
stderrIsTTY: Boolean(process.stderr.isTTY),
|
|
45
|
+
env: process.env
|
|
46
|
+
};
|
|
47
|
+
const outputPolicy = determineOutputPolicy({
|
|
48
|
+
jsonOutput,
|
|
49
|
+
markdownOutput,
|
|
50
|
+
outputPath,
|
|
51
|
+
noAnimations,
|
|
52
|
+
asciiMode,
|
|
53
|
+
stdoutIsTTY: terminalContext.stdoutIsTTY,
|
|
54
|
+
stderrIsTTY: terminalContext.stderrIsTTY,
|
|
55
|
+
env: terminalContext.env
|
|
56
|
+
});
|
|
57
|
+
const runCheckImpl = options.runCheckImpl ?? runCheck;
|
|
58
|
+
const renderer = outputPolicy.interactive
|
|
59
|
+
&& !verboseRuntime
|
|
60
|
+
? createLiveStatusRenderer(io, getSpinner(outputPolicy.style === "ascii" ? "ascii" : "doctor"))
|
|
61
|
+
: null;
|
|
62
|
+
renderer?.start("Validating package");
|
|
63
|
+
const result = await runCheckImpl(targetPath, {
|
|
64
|
+
runtime: runtimeProbeEnabled,
|
|
65
|
+
runtimeTranscript: runtimeProbeEnabled && verboseRuntime
|
|
66
|
+
? (line) => io.writeStderr(line)
|
|
67
|
+
: undefined
|
|
68
|
+
});
|
|
69
|
+
if (renderer) {
|
|
70
|
+
if (result.status === "fail") {
|
|
71
|
+
renderer.stopFailure("Validation failed");
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
renderer.stopSuccess("Validation complete");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const report = markdownOutput
|
|
78
|
+
? buildMarkdownReport(result, { runtimeProbeEnabled })
|
|
79
|
+
: jsonOutput
|
|
80
|
+
? renderJsonReport(result, { runtimeProbeEnabled })
|
|
81
|
+
: renderTextReport(result, { ascii: outputPolicy.style === "ascii" });
|
|
82
|
+
if (outputPath) {
|
|
83
|
+
await writeFile(outputPath, report, "utf8");
|
|
84
|
+
}
|
|
85
|
+
io.writeStdout(report);
|
|
86
|
+
return result.exitCode;
|
|
87
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CliIo } from "../run-cli.js";
|
|
2
|
+
import type { SpinnerDefinition } from "./spinner-registry.js";
|
|
3
|
+
export interface LiveStatusRenderer {
|
|
4
|
+
start(label: string): void;
|
|
5
|
+
update(label: string): void;
|
|
6
|
+
stopSuccess(label: string): void;
|
|
7
|
+
stopFailure(label: string): void;
|
|
8
|
+
}
|
|
9
|
+
export declare function createLiveStatusRenderer(io: Pick<CliIo, "writeStderr">, spinner: SpinnerDefinition): LiveStatusRenderer;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function clearLine() {
|
|
2
|
+
return "\r\x1B[2K";
|
|
3
|
+
}
|
|
4
|
+
export function createLiveStatusRenderer(io, spinner) {
|
|
5
|
+
let frameIndex = 0;
|
|
6
|
+
let currentLabel = "";
|
|
7
|
+
let timer = null;
|
|
8
|
+
const renderFrame = () => {
|
|
9
|
+
const frame = spinner.frames[frameIndex % spinner.frames.length];
|
|
10
|
+
frameIndex += 1;
|
|
11
|
+
io.writeStderr(`${clearLine()}${frame} ${currentLabel}`);
|
|
12
|
+
};
|
|
13
|
+
const stopTimer = () => {
|
|
14
|
+
if (timer) {
|
|
15
|
+
clearInterval(timer);
|
|
16
|
+
timer = null;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
start(label) {
|
|
21
|
+
currentLabel = label;
|
|
22
|
+
renderFrame();
|
|
23
|
+
timer = setInterval(renderFrame, spinner.intervalMs);
|
|
24
|
+
},
|
|
25
|
+
update(label) {
|
|
26
|
+
currentLabel = label;
|
|
27
|
+
renderFrame();
|
|
28
|
+
},
|
|
29
|
+
stopSuccess(label) {
|
|
30
|
+
stopTimer();
|
|
31
|
+
io.writeStderr(`${clearLine()}✔ ${label}\n`);
|
|
32
|
+
},
|
|
33
|
+
stopFailure(label) {
|
|
34
|
+
stopTimer();
|
|
35
|
+
io.writeStderr(`${clearLine()}✖ ${label}\n`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface OutputPolicyInput {
|
|
2
|
+
jsonOutput: boolean;
|
|
3
|
+
markdownOutput: boolean;
|
|
4
|
+
outputPath: string | null;
|
|
5
|
+
noAnimations: boolean;
|
|
6
|
+
asciiMode: boolean;
|
|
7
|
+
stdoutIsTTY: boolean;
|
|
8
|
+
stderrIsTTY: boolean;
|
|
9
|
+
env: Record<string, string | undefined>;
|
|
10
|
+
}
|
|
11
|
+
export interface OutputPolicy {
|
|
12
|
+
interactive: boolean;
|
|
13
|
+
style: "unicode" | "ascii";
|
|
14
|
+
reason: "tty" | "machine_output" | "redirected_output" | "ci" | "dumb_terminal" | "non_tty" | "disabled_by_flag";
|
|
15
|
+
}
|
|
16
|
+
export declare function determineOutputPolicy(input: OutputPolicyInput): OutputPolicy;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export function determineOutputPolicy(input) {
|
|
2
|
+
const style = input.asciiMode ? "ascii" : "unicode";
|
|
3
|
+
if (input.jsonOutput || input.markdownOutput) {
|
|
4
|
+
return {
|
|
5
|
+
interactive: false,
|
|
6
|
+
style,
|
|
7
|
+
reason: "machine_output"
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
if (input.outputPath) {
|
|
11
|
+
return {
|
|
12
|
+
interactive: false,
|
|
13
|
+
style,
|
|
14
|
+
reason: "redirected_output"
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (input.env.CI) {
|
|
18
|
+
return {
|
|
19
|
+
interactive: false,
|
|
20
|
+
style,
|
|
21
|
+
reason: "ci"
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (input.env.TERM === "dumb") {
|
|
25
|
+
return {
|
|
26
|
+
interactive: false,
|
|
27
|
+
style: "ascii",
|
|
28
|
+
reason: "dumb_terminal"
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (!input.stdoutIsTTY || !input.stderrIsTTY) {
|
|
32
|
+
return {
|
|
33
|
+
interactive: false,
|
|
34
|
+
style,
|
|
35
|
+
reason: "non_tty"
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (input.noAnimations) {
|
|
39
|
+
return {
|
|
40
|
+
interactive: false,
|
|
41
|
+
style,
|
|
42
|
+
reason: "disabled_by_flag"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
interactive: true,
|
|
47
|
+
style,
|
|
48
|
+
reason: "tty"
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const spinners = {
|
|
2
|
+
braille: {
|
|
3
|
+
name: "braille",
|
|
4
|
+
frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
|
|
5
|
+
intervalMs: 80
|
|
6
|
+
},
|
|
7
|
+
doctor: {
|
|
8
|
+
name: "doctor",
|
|
9
|
+
frames: ["⠑", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐"],
|
|
10
|
+
intervalMs: 75
|
|
11
|
+
},
|
|
12
|
+
dots: {
|
|
13
|
+
name: "dots",
|
|
14
|
+
frames: ["⠁", "⠂", "⠄", "⠂"],
|
|
15
|
+
intervalMs: 90
|
|
16
|
+
},
|
|
17
|
+
scan: {
|
|
18
|
+
name: "scan",
|
|
19
|
+
frames: ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▂"],
|
|
20
|
+
intervalMs: 70
|
|
21
|
+
},
|
|
22
|
+
ascii: {
|
|
23
|
+
name: "ascii",
|
|
24
|
+
frames: ["-", "\\", "|", "/"],
|
|
25
|
+
intervalMs: 90
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export function getSpinner(name) {
|
|
29
|
+
return spinners[name];
|
|
30
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codex-plugin-doctor",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "CLI-first validator for Codex plugins, skills, and MCP package surfaces with runtime MCP protocol validation.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"codex-plugin-doctor": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
23
|
+
"build": "npm run clean && tsc -p tsconfig.json",
|
|
24
|
+
"dev": "tsx src/cli.ts",
|
|
25
|
+
"generate-validation-artifacts": "node scripts/generate-validation-artifacts.mjs",
|
|
26
|
+
"prepare-rc": "tsx scripts/prepare-release-candidate.ts",
|
|
27
|
+
"prepare-release": "npm test && npm run build && npm pack --dry-run",
|
|
28
|
+
"prepublishOnly": "npm test && npm run build",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest"
|
|
31
|
+
},
|
|
32
|
+
"packageManager": "npm@11.11.1",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=22"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"codex",
|
|
38
|
+
"mcp",
|
|
39
|
+
"plugin",
|
|
40
|
+
"skills",
|
|
41
|
+
"validation"
|
|
42
|
+
],
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/Esquetta/CodexPluginDoctor.git"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/Esquetta/CodexPluginDoctor/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/Esquetta/CodexPluginDoctor#readme",
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^24.2.1",
|
|
57
|
+
"tsx": "^4.20.4",
|
|
58
|
+
"typescript": "^5.9.2",
|
|
59
|
+
"vitest": "^3.2.4"
|
|
60
|
+
}
|
|
61
|
+
}
|