codex-plugin-doctor 1.58.0 → 1.60.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 +22 -3
- package/dist/core/output-contract.js +138 -0
- package/dist/core/shell-completion.js +52 -0
- package/dist/core/submission-archive-preflight.d.ts +24 -0
- package/dist/core/submission-archive-preflight.js +259 -0
- package/dist/core/submission-archive-reader.d.ts +21 -0
- package/dist/core/submission-archive-reader.js +624 -0
- package/dist/core/submission-archive-ruleset.d.ts +58 -0
- package/dist/core/submission-archive-ruleset.js +61 -0
- package/dist/core/submission-assets.d.ts +8 -0
- package/dist/core/submission-assets.js +451 -0
- package/dist/core/submission-package-reader.d.ts +15 -0
- package/dist/core/submission-package-reader.js +274 -0
- package/dist/core/submission-preflight.d.ts +36 -0
- package/dist/core/submission-preflight.js +289 -0
- package/dist/core/submission-ruleset.d.ts +56 -0
- package/dist/core/submission-ruleset.js +38 -0
- package/dist/core/submission-skill-metadata.d.ts +11 -0
- package/dist/core/submission-skill-metadata.js +282 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/reporting/render-submission-archive-report.d.ts +4 -0
- package/dist/reporting/render-submission-archive-report.js +52 -0
- package/dist/reporting/render-submission-report.d.ts +5 -0
- package/dist/reporting/render-submission-report.js +68 -0
- package/dist/run-cli.js +202 -0
- package/package.json +8 -1
package/dist/run-cli.js
CHANGED
|
@@ -19,6 +19,8 @@ import { buildDoctorRecommendations, renderDoctorRecommendations, renderDoctorRe
|
|
|
19
19
|
import { buildDoctorExportBundle, renderDoctorExportBundle, renderDoctorExportBundleJson } from "./core/doctor-export-bundle.js";
|
|
20
20
|
import { buildDoctorAttestation, renderDoctorAttestation, renderDoctorAttestationJson, renderDoctorAttestationVerification, renderDoctorAttestationVerificationJson, verifyDoctorAttestation } from "./core/attestation.js";
|
|
21
21
|
import { buildDoctorOutputContract, renderDoctorOutputContract, renderDoctorOutputContractJson } from "./core/output-contract.js";
|
|
22
|
+
import { buildSubmissionArchivePreflight, submissionArchiveExitCode } from "./core/submission-archive-preflight.js";
|
|
23
|
+
import { buildSubmissionPreflight } from "./core/submission-preflight.js";
|
|
22
24
|
import { buildDoctorValidationCorpusReport, renderDoctorValidationCorpusJson, renderDoctorValidationCorpusReport } from "./core/validation-corpus.js";
|
|
23
25
|
import { buildExternalValidationCorpusReport, ExternalCorpusManifestError } from "./core/external-validation-corpus.js";
|
|
24
26
|
import { buildCorpusQualityMetricsDiffReport, buildCorpusQualityMetricsReport, CorpusMetricsDiffError, CorpusMetricsManifestError, renderCorpusQualityMetricsDiffJson, renderCorpusQualityMetricsDiffMarkdown, renderCorpusQualityMetricsDiffText, renderCorpusQualityMetricsJson, renderCorpusQualityMetricsMarkdown, renderCorpusQualityMetricsText } from "./core/corpus-quality-metrics.js";
|
|
@@ -57,6 +59,8 @@ import { renderSuppressionList, renderSuppressionListJson, renderSuppressionMuta
|
|
|
57
59
|
import { renderRuleExplanation } from "./reporting/render-rule-explanation.js";
|
|
58
60
|
import { renderSarifReport } from "./reporting/render-sarif-report.js";
|
|
59
61
|
import { renderTextReport } from "./reporting/render-text-report.js";
|
|
62
|
+
import { renderSubmissionArchiveJson, renderSubmissionArchiveMarkdown, renderSubmissionArchiveText } from "./reporting/render-submission-archive-report.js";
|
|
63
|
+
import { renderSubmissionPreflightJson, renderSubmissionPreflightMarkdown, renderSubmissionPreflightText, submissionPreflightExitCode } from "./reporting/render-submission-report.js";
|
|
60
64
|
import { applyPolicyToDepAudit, applyPolicyToDoctorConfig, applyPolicyToSecurityAudit, parsePolicyPack, policyEnablesRuntime, policyFailsOnWarnings, policyPackNames } from "./policy/policy-packs.js";
|
|
61
65
|
import { findRuleDefinition } from "./rules/rule-catalog.js";
|
|
62
66
|
import { buildSecurityAudit, renderSecurityAuditJson, renderSecurityScorecard } from "./security/security-audit.js";
|
|
@@ -86,6 +90,13 @@ const defaultIo = {
|
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
92
|
};
|
|
93
|
+
function writeExactStdout(io, message) {
|
|
94
|
+
if (io === defaultIo) {
|
|
95
|
+
process.stdout.write(message);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
io.writeStdout(message);
|
|
99
|
+
}
|
|
89
100
|
class CliUsageError extends Error {
|
|
90
101
|
}
|
|
91
102
|
function parseRuntimeSandbox(flags, options = { requireRuntime: true }) {
|
|
@@ -177,6 +188,8 @@ function printUsage(io) {
|
|
|
177
188
|
io.writeStderr("Suppression governance: codex-plugin-doctor suppress list <path> [--fail-on-expired] [--fail-on-invalid] [--warn-expiring-within-days <days>]\n codex-plugin-doctor suppress prune <path> [--apply] [--json]");
|
|
178
189
|
io.writeStderr("Baseline gating: codex-plugin-doctor baseline create <path> --output <path> [--runtime]\n codex-plugin-doctor check <path> --baseline <path>");
|
|
179
190
|
io.writeStderr("Remote MCP runtime flags (check, mcp, release check, and doctor release-evidence): --runtime --allow-network [--allow-local-network] [--allow-session-lifecycle] [--require-remote-reliability]\n --allow-session-lifecycle requires --runtime --allow-network and can terminate a remote session.\n --require-remote-reliability requires --runtime --allow-network, blocks non-pass reliability, and does not grant network consent.");
|
|
191
|
+
io.writeStderr(" codex-plugin-doctor doctor submission <path> [--json|--markdown] [--output <path>] [--require-ready]"
|
|
192
|
+
+ "\n codex-plugin-doctor doctor submission archive <zip> [--json|--markdown] [--output <path>] [--require-ready]");
|
|
180
193
|
}
|
|
181
194
|
const suppressUsageText = [
|
|
182
195
|
"Usage:",
|
|
@@ -970,6 +983,158 @@ function parseSelectedFixActionIndexes(answer, actionCount) {
|
|
|
970
983
|
? actionIndexes
|
|
971
984
|
: null;
|
|
972
985
|
}
|
|
986
|
+
function parseSubmissionCommandArgs(args) {
|
|
987
|
+
let targetPath = null;
|
|
988
|
+
let jsonOutput = false;
|
|
989
|
+
let markdownOutput = false;
|
|
990
|
+
let outputPath = null;
|
|
991
|
+
let requireReady = false;
|
|
992
|
+
let optionsEnded = false;
|
|
993
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
994
|
+
const argument = args[index];
|
|
995
|
+
if (argument === "--" && !optionsEnded) {
|
|
996
|
+
optionsEnded = true;
|
|
997
|
+
}
|
|
998
|
+
else if (optionsEnded) {
|
|
999
|
+
if (targetPath === null) {
|
|
1000
|
+
targetPath = argument;
|
|
1001
|
+
}
|
|
1002
|
+
else {
|
|
1003
|
+
return new CliUsageError(`Unexpected submission argument: ${argument}.`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
else if (argument === "--json") {
|
|
1007
|
+
if (jsonOutput)
|
|
1008
|
+
return new CliUsageError("Duplicate submission flag: --json.");
|
|
1009
|
+
jsonOutput = true;
|
|
1010
|
+
}
|
|
1011
|
+
else if (argument === "--markdown") {
|
|
1012
|
+
if (markdownOutput)
|
|
1013
|
+
return new CliUsageError("Duplicate submission flag: --markdown.");
|
|
1014
|
+
markdownOutput = true;
|
|
1015
|
+
}
|
|
1016
|
+
else if (argument === "--require-ready") {
|
|
1017
|
+
if (requireReady)
|
|
1018
|
+
return new CliUsageError("Duplicate submission flag: --require-ready.");
|
|
1019
|
+
requireReady = true;
|
|
1020
|
+
}
|
|
1021
|
+
else if (argument === "--output") {
|
|
1022
|
+
if (outputPath !== null)
|
|
1023
|
+
return new CliUsageError("Duplicate submission flag: --output.");
|
|
1024
|
+
const value = args[index + 1];
|
|
1025
|
+
if (!value || value.startsWith("--"))
|
|
1026
|
+
return new CliUsageError("Missing path after --output.");
|
|
1027
|
+
outputPath = value;
|
|
1028
|
+
index += 1;
|
|
1029
|
+
}
|
|
1030
|
+
else if (argument.startsWith("--output=")) {
|
|
1031
|
+
if (outputPath !== null)
|
|
1032
|
+
return new CliUsageError("Duplicate submission flag: --output.");
|
|
1033
|
+
const value = argument.slice("--output=".length);
|
|
1034
|
+
if (!value)
|
|
1035
|
+
return new CliUsageError("Missing path after --output.");
|
|
1036
|
+
outputPath = value;
|
|
1037
|
+
}
|
|
1038
|
+
else if (argument.startsWith("--")) {
|
|
1039
|
+
return new CliUsageError(`Unknown submission flag: ${argument}.`);
|
|
1040
|
+
}
|
|
1041
|
+
else if (targetPath === null) {
|
|
1042
|
+
targetPath = argument;
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
return new CliUsageError(`Unexpected submission argument: ${argument}.`);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
if (targetPath === null)
|
|
1049
|
+
return new CliUsageError("Missing target path for submission.");
|
|
1050
|
+
if (jsonOutput && markdownOutput)
|
|
1051
|
+
return new CliUsageError("Use either --json or --markdown, not both.");
|
|
1052
|
+
return { targetPath, jsonOutput, markdownOutput, outputPath, requireReady };
|
|
1053
|
+
}
|
|
1054
|
+
function parseSubmissionArchiveCommandArgs(args) {
|
|
1055
|
+
let targetPath = null;
|
|
1056
|
+
let jsonOutput = false;
|
|
1057
|
+
let markdownOutput = false;
|
|
1058
|
+
let outputPath = null;
|
|
1059
|
+
let requireReady = false;
|
|
1060
|
+
let optionsEnded = false;
|
|
1061
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1062
|
+
const argument = args[index];
|
|
1063
|
+
if (argument === "--" && !optionsEnded)
|
|
1064
|
+
optionsEnded = true;
|
|
1065
|
+
else if (optionsEnded) {
|
|
1066
|
+
if (targetPath === null)
|
|
1067
|
+
targetPath = argument;
|
|
1068
|
+
else
|
|
1069
|
+
return new CliUsageError(`Unexpected submission archive argument: ${argument}.`);
|
|
1070
|
+
}
|
|
1071
|
+
else if (argument === "--json") {
|
|
1072
|
+
if (jsonOutput)
|
|
1073
|
+
return new CliUsageError("Duplicate submission archive flag: --json.");
|
|
1074
|
+
jsonOutput = true;
|
|
1075
|
+
}
|
|
1076
|
+
else if (argument === "--markdown") {
|
|
1077
|
+
if (markdownOutput)
|
|
1078
|
+
return new CliUsageError("Duplicate submission archive flag: --markdown.");
|
|
1079
|
+
markdownOutput = true;
|
|
1080
|
+
}
|
|
1081
|
+
else if (argument === "--require-ready") {
|
|
1082
|
+
if (requireReady)
|
|
1083
|
+
return new CliUsageError("Duplicate submission archive flag: --require-ready.");
|
|
1084
|
+
requireReady = true;
|
|
1085
|
+
}
|
|
1086
|
+
else if (argument === "--output" || argument.startsWith("--output=")) {
|
|
1087
|
+
if (outputPath !== null)
|
|
1088
|
+
return new CliUsageError("Duplicate submission archive flag: --output.");
|
|
1089
|
+
const value = argument === "--output" ? args[index + 1] : argument.slice("--output=".length);
|
|
1090
|
+
if (!value || (argument === "--output" && value.startsWith("--")))
|
|
1091
|
+
return new CliUsageError("Missing path after --output.");
|
|
1092
|
+
outputPath = value;
|
|
1093
|
+
if (argument === "--output")
|
|
1094
|
+
index += 1;
|
|
1095
|
+
}
|
|
1096
|
+
else if (argument.startsWith("--"))
|
|
1097
|
+
return new CliUsageError(`Unknown submission archive flag: ${argument}.`);
|
|
1098
|
+
else if (targetPath === null)
|
|
1099
|
+
targetPath = argument;
|
|
1100
|
+
else
|
|
1101
|
+
return new CliUsageError(`Unexpected submission archive argument: ${argument}.`);
|
|
1102
|
+
}
|
|
1103
|
+
if (targetPath === null)
|
|
1104
|
+
return new CliUsageError("Missing archive path for submission.");
|
|
1105
|
+
if (jsonOutput && markdownOutput)
|
|
1106
|
+
return new CliUsageError("Use either --json or --markdown, not both.");
|
|
1107
|
+
return { targetPath, jsonOutput, markdownOutput, outputPath, requireReady };
|
|
1108
|
+
}
|
|
1109
|
+
function hasArchiveSubcommandTarget(args) {
|
|
1110
|
+
let optionsEnded = false;
|
|
1111
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1112
|
+
const argument = args[index];
|
|
1113
|
+
if (optionsEnded)
|
|
1114
|
+
return true;
|
|
1115
|
+
if (argument === "--") {
|
|
1116
|
+
optionsEnded = true;
|
|
1117
|
+
}
|
|
1118
|
+
else if (argument === "--output") {
|
|
1119
|
+
index += 1;
|
|
1120
|
+
}
|
|
1121
|
+
else if (!argument.startsWith("--")) {
|
|
1122
|
+
return true;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
return false;
|
|
1126
|
+
}
|
|
1127
|
+
async function submissionTargetExists(targetPath) {
|
|
1128
|
+
try {
|
|
1129
|
+
const { stat } = await import("node:fs/promises");
|
|
1130
|
+
await stat(targetPath);
|
|
1131
|
+
return true;
|
|
1132
|
+
}
|
|
1133
|
+
catch (error) {
|
|
1134
|
+
return !(typeof error === "object" && error !== null && "code" in error
|
|
1135
|
+
&& error.code === "ENOENT");
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
973
1138
|
export async function runCli(args, io = defaultIo, options = {}) {
|
|
974
1139
|
const [command, maybePath, ...remainingArgs] = args;
|
|
975
1140
|
const runtimeSandboxSupported = (command === "check" &&
|
|
@@ -1079,6 +1244,43 @@ export async function runCli(args, io = defaultIo, options = {}) {
|
|
|
1079
1244
|
: renderDoctorOutputContract(contract, { outputPath }));
|
|
1080
1245
|
return 0;
|
|
1081
1246
|
}
|
|
1247
|
+
if (maybePath === "submission") {
|
|
1248
|
+
if (remainingArgs[0] === "archive") {
|
|
1249
|
+
const useLegacyDirectoryTarget = !hasArchiveSubcommandTarget(remainingArgs.slice(1))
|
|
1250
|
+
&& await submissionTargetExists("archive");
|
|
1251
|
+
if (!useLegacyDirectoryTarget) {
|
|
1252
|
+
const parsedArchiveArgs = parseSubmissionArchiveCommandArgs(remainingArgs.slice(1));
|
|
1253
|
+
if (parsedArchiveArgs instanceof CliUsageError) {
|
|
1254
|
+
io.writeStderr(parsedArchiveArgs.message);
|
|
1255
|
+
return 2;
|
|
1256
|
+
}
|
|
1257
|
+
const report = await buildSubmissionArchivePreflight(parsedArchiveArgs.targetPath);
|
|
1258
|
+
const renderedReport = parsedArchiveArgs.jsonOutput
|
|
1259
|
+
? renderSubmissionArchiveJson(report)
|
|
1260
|
+
: parsedArchiveArgs.markdownOutput ? renderSubmissionArchiveMarkdown(report) : renderSubmissionArchiveText(report);
|
|
1261
|
+
if (parsedArchiveArgs.outputPath)
|
|
1262
|
+
await writeFile(parsedArchiveArgs.outputPath, renderedReport, "utf8");
|
|
1263
|
+
writeExactStdout(io, renderedReport);
|
|
1264
|
+
return submissionArchiveExitCode(report, parsedArchiveArgs.requireReady);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
const parsedSubmissionArgs = parseSubmissionCommandArgs(remainingArgs);
|
|
1268
|
+
if (parsedSubmissionArgs instanceof CliUsageError) {
|
|
1269
|
+
io.writeStderr(parsedSubmissionArgs.message);
|
|
1270
|
+
return 2;
|
|
1271
|
+
}
|
|
1272
|
+
const report = await buildSubmissionPreflight(parsedSubmissionArgs.targetPath);
|
|
1273
|
+
const renderedReport = parsedSubmissionArgs.jsonOutput
|
|
1274
|
+
? renderSubmissionPreflightJson(report)
|
|
1275
|
+
: parsedSubmissionArgs.markdownOutput
|
|
1276
|
+
? renderSubmissionPreflightMarkdown(report)
|
|
1277
|
+
: renderSubmissionPreflightText(report);
|
|
1278
|
+
if (parsedSubmissionArgs.outputPath) {
|
|
1279
|
+
await writeFile(parsedSubmissionArgs.outputPath, renderedReport, "utf8");
|
|
1280
|
+
}
|
|
1281
|
+
writeExactStdout(io, renderedReport);
|
|
1282
|
+
return submissionPreflightExitCode(report, parsedSubmissionArgs.requireReady);
|
|
1283
|
+
}
|
|
1082
1284
|
if (maybePath === "mcp") {
|
|
1083
1285
|
const targetPath = remainingArgs[0] && !remainingArgs[0].startsWith("--")
|
|
1084
1286
|
? remainingArgs[0]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-plugin-doctor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.60.0",
|
|
4
4
|
"description": "CLI-first validator for Codex plugins, skills, and MCP package surfaces with runtime MCP protocol validation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -57,8 +57,15 @@
|
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/node": "^24.2.1",
|
|
60
|
+
"@types/yauzl": "^3.4.0",
|
|
60
61
|
"tsx": "^4.20.4",
|
|
61
62
|
"typescript": "^5.9.2",
|
|
62
63
|
"vitest": "^3.2.4"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"fast-xml-parser": "^5.11.0",
|
|
67
|
+
"iconv-lite": "^0.7.3",
|
|
68
|
+
"yaml": "^2.9.0",
|
|
69
|
+
"yauzl": "^3.4.0"
|
|
63
70
|
}
|
|
64
71
|
}
|