codex-plugin-doctor 1.29.0 → 1.31.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 CHANGED
@@ -400,9 +400,9 @@ jobs:
400
400
  runs-on: ubuntu-latest
401
401
  steps:
402
402
  - uses: actions/checkout@v5
403
- - uses: Esquetta/CodexPluginDoctor@v1.29.0
403
+ - uses: Esquetta/CodexPluginDoctor@v1.31.0
404
404
  with:
405
- version: "1.29.0"
405
+ version: "1.31.0"
406
406
  path: .
407
407
  runtime: "true"
408
408
  policy: codex-publish
@@ -3,6 +3,12 @@ export interface InitGitHooksResult {
3
3
  hookPaths: string[];
4
4
  preExisting: string[];
5
5
  }
6
+ export interface RemoveGitHooksResult {
7
+ rootPath: string;
8
+ removed: string[];
9
+ skipped: string[];
10
+ }
11
+ export declare function removeGitHooks(targetPath: string): Promise<RemoveGitHooksResult>;
6
12
  export declare function initGitHooks(targetPath: string, options?: {
7
13
  force?: boolean;
8
14
  }): Promise<InitGitHooksResult>;
@@ -54,6 +54,27 @@ async function writeHook(hookPath, content, force) {
54
54
  }
55
55
  return exists;
56
56
  }
57
+ export async function removeGitHooks(targetPath) {
58
+ const rootPath = path.resolve(targetPath);
59
+ const hooksDir = path.join(rootPath, ".git", "hooks");
60
+ const hookNames = ["pre-commit", "pre-push"];
61
+ const removed = [];
62
+ const skipped = [];
63
+ for (const name of hookNames) {
64
+ const hookPath = path.join(hooksDir, name);
65
+ if (await fileExists(hookPath)) {
66
+ const content = await import("node:fs/promises").then((m) => m.readFile(hookPath, "utf8"));
67
+ if (content.includes("Generated by codex-plugin-doctor init git-hooks")) {
68
+ await import("node:fs/promises").then((m) => m.rm(hookPath));
69
+ removed.push(hookPath);
70
+ }
71
+ else {
72
+ skipped.push(hookPath);
73
+ }
74
+ }
75
+ }
76
+ return { rootPath, removed, skipped };
77
+ }
57
78
  export async function initGitHooks(targetPath, options = {}) {
58
79
  const rootPath = path.resolve(targetPath);
59
80
  const hooksDir = path.join(rootPath, ".git", "hooks");
package/dist/index.d.ts CHANGED
@@ -26,5 +26,5 @@ export { applyPolicyToDoctorConfig, applyPolicyToSecurityAudit, parsePolicyPack,
26
26
  export { buildGenericMcpDoctor, renderGenericMcpDoctor, renderGenericMcpDoctorJson, type GenericMcpDoctorReport } from "./mcp/generic-mcp-doctor.js";
27
27
  export { watchPlugin, type WatchPluginOptions, type WatchPluginResult } from "./core/watch-plugin.js";
28
28
  export { buildDepAudit, renderDepAudit, renderDepAuditJson, type DepAuditReport, type DepAuditVulnerability } from "./core/dep-audit.js";
29
- export { initGitHooks, type InitGitHooksResult } from "./core/init-git-hooks.js";
29
+ export { initGitHooks, removeGitHooks, type InitGitHooksResult, type RemoveGitHooksResult } from "./core/init-git-hooks.js";
30
30
  export declare function runCheck(targetPath: string, options?: CheckOptions): Promise<CheckResult>;
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ export { applyPolicyToDoctorConfig, applyPolicyToSecurityAudit, parsePolicyPack,
26
26
  export { buildGenericMcpDoctor, renderGenericMcpDoctor, renderGenericMcpDoctorJson } from "./mcp/generic-mcp-doctor.js";
27
27
  export { watchPlugin } from "./core/watch-plugin.js";
28
28
  export { buildDepAudit, renderDepAudit, renderDepAuditJson } from "./core/dep-audit.js";
29
- export { initGitHooks } from "./core/init-git-hooks.js";
29
+ export { initGitHooks, removeGitHooks } from "./core/init-git-hooks.js";
30
30
  export async function runCheck(targetPath, options = {}) {
31
31
  return validatePlugin(targetPath, options);
32
32
  }
package/dist/run-cli.js CHANGED
@@ -32,7 +32,7 @@ import { renderClientDoctor, renderEnvironmentDoctor, renderEnvironmentDoctorJso
32
32
  import { initCiWorkflow } from "./core/init-ci.js";
33
33
  import { watchPlugin } from "./core/watch-plugin.js";
34
34
  import { buildDepAudit, renderDepAudit, renderDepAuditJson } from "./core/dep-audit.js";
35
- import { initGitHooks } from "./core/init-git-hooks.js";
35
+ import { initGitHooks, removeGitHooks } from "./core/init-git-hooks.js";
36
36
  import { initPluginPackage, initPluginTemplates, isInitPluginTemplate } from "./core/init-plugin.js";
37
37
  import { runCheck } from "./index.js";
38
38
  import { buildGenericMcpDoctor, renderGenericMcpDoctor, renderGenericMcpDoctorJson } from "./mcp/generic-mcp-doctor.js";
@@ -78,7 +78,7 @@ const defaultIo = {
78
78
  }
79
79
  };
80
80
  function printUsage(io) {
81
- 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] [--require-runtime-approval --runtime-approval-digest <digest>] [--verbose-runtime] [--explain] [--no-animations] [--ascii]\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> [--json] [--output <path>]\n codex-plugin-doctor mcp <path> [--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>]\n codex-plugin-doctor doctor [npm <package>|contract|corpus|runtime-plan <path> [--json|--markdown] [--output <path>]|runtime-policy <path> [--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 [--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 [--upload]|mcp <path>|inspector <path>|diff --before <path> --after <path>|recommend <path>|trust <path>|perf <path> [--max-total-ms <ms>] [--max-stage-ms stage=ms]|export --bundle <path>|snapshot|clients|--json|--update-check]\n codex-plugin-doctor init [path] [--template skill-only|mcp-stdio|mcp-http|full-runtime]\n codex-plugin-doctor init-ci [path]\n codex-plugin-doctor init-git-hooks [path] [--force] [--json]\n codex-plugin-doctor 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");
81
+ 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] [--require-runtime-approval --runtime-approval-digest <digest>] [--verbose-runtime] [--explain] [--no-animations] [--ascii]\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> [--json] [--output <path>]\n codex-plugin-doctor mcp <path> [--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>]\n codex-plugin-doctor doctor [npm <package>|contract|corpus|runtime-plan <path> [--json|--markdown] [--output <path>]|runtime-policy <path> [--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 [--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 [--upload]|mcp <path>|inspector <path>|diff --before <path> --after <path>|recommend <path>|trust <path>|perf <path> [--max-total-ms <ms>] [--max-stage-ms stage=ms]|export --bundle <path>|snapshot|clients|--json|--update-check]\n codex-plugin-doctor init [path] [--template skill-only|mcp-stdio|mcp-http|full-runtime]\n codex-plugin-doctor init-ci [path]\n codex-plugin-doctor init-git-hooks [path] [--force] [--json]\n codex-plugin-doctor init-git-hooks [path] --remove [--json]\n codex-plugin-doctor 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");
82
82
  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]");
83
83
  }
84
84
  const suppressUsageText = [
@@ -1754,8 +1754,38 @@ export async function runCli(args, io = defaultIo, options = {}) {
1754
1754
  const initFlags = maybePath && maybePath.startsWith("--")
1755
1755
  ? [maybePath, ...remainingArgs]
1756
1756
  : remainingArgs;
1757
+ const remove = initFlags.includes("--remove");
1757
1758
  const force = initFlags.includes("--force");
1758
1759
  const jsonOutput = initFlags.includes("--json");
1760
+ if (remove) {
1761
+ const removeResult = await removeGitHooks(targetPath);
1762
+ if (jsonOutput) {
1763
+ io.writeStdout(JSON.stringify({
1764
+ schemaVersion: "1.0.0",
1765
+ kind: "doctor.git.hooks.remove",
1766
+ rootPath: removeResult.rootPath,
1767
+ removed: removeResult.removed,
1768
+ skipped: removeResult.skipped
1769
+ }, null, 2));
1770
+ return 0;
1771
+ }
1772
+ const lines = ["Removed Codex Plugin Doctor git hooks", `Root: ${removeResult.rootPath}`];
1773
+ if (removeResult.removed.length > 0) {
1774
+ lines.push(`Removed: ${removeResult.removed.join(", ")}`);
1775
+ }
1776
+ if (removeResult.skipped.length > 0) {
1777
+ lines.push(`Skipped (not generated by doctor): ${removeResult.skipped.join(", ")}`);
1778
+ }
1779
+ if (removeResult.removed.length === 0 && removeResult.skipped.length === 0) {
1780
+ lines.push("No doctor-generated hooks found.");
1781
+ }
1782
+ io.writeStdout(lines.join("\n"));
1783
+ return 0;
1784
+ }
1785
+ if (force && remove) {
1786
+ io.writeStderr("Use either --force or --remove, not both.");
1787
+ return 2;
1788
+ }
1759
1789
  const result = await initGitHooks(targetPath, { force });
1760
1790
  if (jsonOutput) {
1761
1791
  io.writeStdout(JSON.stringify({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-plugin-doctor",
3
- "version": "1.29.0",
3
+ "version": "1.31.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",