codex-plugin-doctor 0.4.0 → 0.5.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
@@ -1,308 +1,316 @@
1
- # Codex Plugin Doctor
2
-
3
- [![CI](https://github.com/Esquetta/CodexPluginDoctor/actions/workflows/ci.yml/badge.svg)](https://github.com/Esquetta/CodexPluginDoctor/actions/workflows/ci.yml)
4
- [![npm version](https://img.shields.io/npm/v/codex-plugin-doctor.svg)](https://www.npmjs.com/package/codex-plugin-doctor)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
6
- [![GitHub release](https://img.shields.io/github/v/release/Esquetta/CodexPluginDoctor)](https://github.com/Esquetta/CodexPluginDoctor/releases)
7
-
8
- Codex Plugin Doctor is a local CLI validator for Codex plugin packages, skills, and MCP server bundles.
9
-
10
- It catches packaging, metadata, security, and runtime protocol problems before a plugin reaches users, teammates, or release workflows.
11
-
12
- ## Status
13
-
14
- Codex Plugin Doctor is an early public CLI release.
15
-
16
- - Primary surface: GitHub repository and npm package
17
- - Distribution today: `npm install -g`, local source install, `npm link`, `npm pack`, GitHub Releases
18
- - Public npm package: `codex-plugin-doctor`
19
- - License: [MIT](./LICENSE)
20
-
21
- ## Why This Exists
22
-
23
- Codex plugin packages can fail in several places:
24
-
25
- - the package manifest is missing or points outside the package root
26
- - skills exist but do not expose valid `SKILL.md` metadata
27
- - `.mcp.json` is malformed or references unsafe secrets
28
- - an MCP server starts but does not complete the protocol handshake
29
- - tools, resources, or prompts list successfully but fail deeper runtime checks
30
- - verbose metadata creates noisy matching and unnecessary context cost
31
-
32
- This tool gives plugin authors a repeatable preflight check before distribution.
33
-
34
- ## What It Checks
35
-
36
- Static validation:
37
-
38
- - required `.codex-plugin/plugin.json`
39
- - manifest fields: `name`, `version`, `description`
40
- - skill directory wiring
41
- - `SKILL.md` presence and frontmatter fields
42
- - YAML single-line and block-scalar skill descriptions
43
- - `.mcp.json` structure
44
- - path traversal risks
45
- - hard-coded secret-like env values
46
- - description quality heuristics tuned against real plugin packages
47
-
48
- Runtime MCP validation with `--runtime`:
49
-
50
- - `initialize`
51
- - `notifications/initialized`
52
- - `tools/list`
53
- - `tools/call`
54
- - `resources/list`
55
- - `resources/read`
56
- - `resources/templates/list`
57
- - `prompts/list`
58
- - `prompts/get`
59
- - paginated list responses
60
- - runtime capability scorecard
61
- - redacted verbose transcript with `--verbose-runtime`
62
-
63
- Output formats:
64
-
65
- - human text output
66
- - JSON reports
67
- - Markdown reports
68
- - `--output` file writing
69
- - CI summary and artifact generation
70
-
71
- ## Quick Start
72
-
73
- Global install from npm:
74
-
75
- ```bash
76
- npm install -g codex-plugin-doctor
77
- codex-plugin-doctor --version
78
- codex-plugin-doctor self-test
79
- codex-plugin-doctor check path/to/plugin-package
80
- ```
81
-
82
- Run `codex-plugin-doctor check .` from the root of a Codex plugin package that contains `.codex-plugin/plugin.json`. The Codex Plugin Doctor source repository is not itself a plugin package.
83
-
84
- If you already have Codex installed locally and do not know plugin paths, discover the installed plugin cache:
85
-
86
- ```bash
87
- codex-plugin-doctor list --installed
88
- codex-plugin-doctor check --installed
89
- codex-plugin-doctor check --installed --all-summary
90
- codex-plugin-doctor check --installed github
91
- codex-plugin-doctor explain plugin.manifest.missing
92
- ```
93
-
94
- Run from source:
95
-
96
- ```bash
97
- npm install
98
- npm run build
99
- node dist/cli.js check examples/codex-doctor-runtime --runtime
100
- ```
101
-
102
- For local global usage:
103
-
104
- ```bash
105
- npm link
106
- codex-plugin-doctor check examples/codex-doctor-runtime --runtime
107
- ```
108
-
109
- Generate validation artifacts locally:
110
-
111
- ```bash
112
- npm run generate-validation-artifacts -- --target examples/codex-doctor-runtime --runtime-target examples/codex-doctor-runtime --out-dir validation-artifacts-local
113
- ```
114
-
115
- ## Example Output
116
-
117
- Passing runtime package:
118
-
119
- ```text
120
- Codex Plugin Doctor
121
- ===================
122
- Status: PASS
123
- Target: <repo>\examples\codex-doctor-runtime
124
- Summary: 0 fail, 0 warn, 0 total
125
-
126
- Runtime Scorecard
127
- ----------------
128
- initialize: pass
129
- tools/list: pass
130
- tools/call: pass
131
- resources/list: pass
132
- resources/read: pass
133
- resources/templates/list: pass
134
- prompts/list: pass
135
- prompts/get: pass
136
-
137
- No findings.
138
- ```
139
-
140
- Risky package:
141
-
142
- ```text
143
- Codex Plugin Doctor
144
- ===================
145
- Status: FAIL
146
- Target: <repo>\examples\codex-doctor-risky
147
- Summary: 1 fail, 0 warn, 1 total
148
-
149
- Failures
150
- --------
151
- x plugin.security.hard_coded_secret
152
- Message: The MCP server `dangerServer` contains a hard-coded secret-like env value for `OPENAI_API_KEY`.
153
- Impact: Hard-coded credentials inside plugin bundles increase leakage risk and make secure rotation difficult.
154
- Suggested fix: Replace the literal value for `OPENAI_API_KEY` with an environment reference or injected secret outside the package.
155
- ```
156
-
157
- ## Useful Commands
158
-
159
- Run these from a Codex plugin package root:
160
-
161
- ```bash
162
- codex-plugin-doctor --version
163
- codex-plugin-doctor self-test
164
- codex-plugin-doctor init my-plugin
165
- codex-plugin-doctor compat .
166
- codex-plugin-doctor compat . --client codex
167
- codex-plugin-doctor compat . --client generic-mcp
168
- codex-plugin-doctor compat . --client claude-desktop
169
- codex-plugin-doctor compat . --client claude-desktop --install-preview
170
- codex-plugin-doctor compat . --client claude-desktop --apply --backup
171
- codex-plugin-doctor compat . --client cursor
172
- codex-plugin-doctor compat . --client cursor --install-preview
173
- codex-plugin-doctor compat . --client cursor --apply --backup
174
- codex-plugin-doctor compat . --scorecard
175
- codex-plugin-doctor compat . --json
176
- codex-plugin-doctor compat . --json --output compatibility.json
177
- codex-plugin-doctor check .
178
- codex-plugin-doctor check . --json
179
- codex-plugin-doctor check . --json --output report.json
180
- codex-plugin-doctor check . --markdown --output report.md
181
- codex-plugin-doctor check . --sarif --output results.sarif
182
- codex-plugin-doctor check . --ascii
183
- codex-plugin-doctor check . --no-animations
184
- codex-plugin-doctor check . --runtime
185
- codex-plugin-doctor check . --config .codex-doctor.json
186
- codex-plugin-doctor check . --json --runtime --verbose-runtime
187
- ```
188
-
189
- `self-test` runs the bundled runtime-complete sample through static validation, runtime MCP probes, and the compatibility scorecard. It is the fastest post-install check after `npm install -g codex-plugin-doctor`.
190
-
191
- `compat --client claude-desktop` checks whether the MCP package can be added to the local Claude Desktop setup. On Windows it looks for `%APPDATA%\Claude\claude_desktop_config.json`; on macOS it looks for `~/Library/Application Support/Claude/claude_desktop_config.json`. A valid existing config returns `PASS`, a missing Claude Desktop install returns `WARN`, and a malformed local config returns `FAIL` so you do not add new servers into a broken config file. If the package server name already exists in Claude Desktop, the command returns `WARN` with the duplicate server name. Add `--install-preview` to print the JSON snippet that should be merged into `claude_desktop_config.json`; it does not modify files. Use `--apply --backup` only when you want the CLI to create a timestamped backup and merge the server config. Apply mode refuses to overwrite duplicate server names.
192
-
193
- `compat --client cursor` checks whether the MCP package can be added to Cursor. It prefers a project-level `.cursor/mcp.json` when one already exists in the target package, then falls back to the global `~/.cursor/mcp.json` path. A valid existing config returns `PASS`, a missing Cursor config returns `WARN`, malformed JSON returns `FAIL`, and duplicate MCP server names return `WARN`. Add `--install-preview` to print the JSON snippet that should be merged into Cursor's `mcp.json`; it does not modify files. Use `--apply --backup` only when you want the CLI to create a timestamped backup and merge the server config. Apply mode refuses to overwrite duplicate server names.
194
-
195
- `compat --scorecard` turns the compatibility matrix into a compact score summary. `PASS` maps to `100`, `WARN` maps to `70`, and `FAIL` or `SKIPPED` maps to `0`.
196
-
197
- Optional local policy file:
198
-
199
- ```json
200
- {
201
- "ignoreRules": ["plugin.heuristic.description.too_long"],
202
- "failOnWarnings": true
203
- }
204
- ```
205
-
206
- Run these when you want Codex Plugin Doctor to find plugins from the local Codex installation:
207
-
208
- ```bash
209
- codex-plugin-doctor list --installed
210
- codex-plugin-doctor check --installed
211
- codex-plugin-doctor check --installed --all-summary
212
- codex-plugin-doctor check --installed github
213
- codex-plugin-doctor check --installed github --runtime --no-animations
214
- codex-plugin-doctor explain plugin.security.hard_coded_secret
215
- ```
216
-
217
- ## GitHub Action
218
-
219
- ```yaml
220
- name: Validate Codex plugin
221
-
222
- on:
223
- pull_request:
224
-
225
- jobs:
226
- doctor:
227
- runs-on: ubuntu-latest
228
- steps:
229
- - uses: actions/checkout@v4
230
- - uses: Esquetta/CodexPluginDoctor@v0.2.0
231
- with:
232
- path: .
233
- runtime: "false"
234
- ```
235
-
236
- To self-test this repository after cloning it:
237
-
238
- ```bash
239
- codex-plugin-doctor check examples/codex-doctor-runtime --runtime --no-animations
240
- ```
241
-
242
- ## Repository Layout
243
-
244
- ```text
245
- docs/ Product, engineering, security, and release docs
246
- examples/ Manual plugin packs for local CLI testing
247
- src/ CLI, validation logic, runtime probing, reports
248
- tests/ Fixture-based regression tests
249
- validation-sessions/ Real-world validation waves and tuning notes
250
- ```
251
-
252
- ## Validation Evidence
253
-
254
- The validator is tuned against local fixtures and real marketplace-style plugin packages. See:
255
-
256
- - [Real-World Validation Workflow](./docs/engineering/real-world-validation-workflow.md)
257
- - [Validation Sessions](./validation-sessions/README.md)
258
- - [Examples](./examples/README.md)
259
- - [Rule Catalog](./docs/rules/catalog.md)
260
-
261
- Recent validation waves covered:
262
-
263
- - curated Codex plugin cache packages
264
- - marketplace-style plugin snapshots
265
- - YAML block-scalar skill metadata
266
- - media and visual workflow metadata
267
-
268
- ## Release Readiness
269
-
270
- Release preparation is reproducible from the repository:
271
-
272
- ```bash
273
- npm run prepare-release
274
- ```
275
-
276
- This runs tests, builds the TypeScript output, and performs `npm pack --dry-run`.
277
-
278
- Related docs:
279
-
280
- - [Changelog](./CHANGELOG.md)
281
- - [Contributing](./CONTRIBUTING.md)
282
- - [Security Policy](./SECURITY.md)
283
- - [Code of Conduct](./CODE_OF_CONDUCT.md)
284
- - [NPM Release Checklist](./docs/engineering/npm-release-checklist.md)
285
- - [Release Candidate Workflow](./docs/engineering/release-candidate-workflow.md)
286
- - [v0.1.0 Release Notes](./docs/engineering/v0.1.0-final-release-notes.md)
287
-
288
- ## Contributing
289
-
290
- Contributions are welcome once the repository is public. Start with:
291
-
292
- - [Contributing](./CONTRIBUTING.md)
293
- - [Security Policy](./SECURITY.md)
294
- - [Validation tuning issue template](./.github/ISSUE_TEMPLATE/validation_tuning.yml)
295
-
296
- ## Support
297
-
298
- If this tool saves you time, GitHub stars and sponsorship help signal that the project is worth continuing.
299
-
300
- - Star the repository on GitHub.
301
- - Use GitHub Sponsors through the repository funding link.
302
- - Open validation tuning issues for false positives or false negatives.
303
-
304
- ## Product Direction
305
-
306
- Codex Plugin Doctor starts as a Codex-specific validator and can grow into a broader MCP Doctor over time.
307
-
308
- The immediate goal is not a marketplace, dashboard, or hosted website. The immediate goal is a trustworthy local preflight check for Codex-compatible plugin bundles.
1
+ # Codex Plugin Doctor
2
+
3
+ [![CI](https://github.com/Esquetta/CodexPluginDoctor/actions/workflows/ci.yml/badge.svg)](https://github.com/Esquetta/CodexPluginDoctor/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/codex-plugin-doctor.svg)](https://www.npmjs.com/package/codex-plugin-doctor)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
6
+ [![GitHub release](https://img.shields.io/github/v/release/Esquetta/CodexPluginDoctor)](https://github.com/Esquetta/CodexPluginDoctor/releases)
7
+
8
+ Codex Plugin Doctor is a local CLI validator for Codex plugin packages, skills, and MCP server bundles.
9
+
10
+ It catches packaging, metadata, security, and runtime protocol problems before a plugin reaches users, teammates, or release workflows.
11
+
12
+ ## Status
13
+
14
+ Codex Plugin Doctor is an early public CLI release.
15
+
16
+ - Primary surface: GitHub repository and npm package
17
+ - Distribution today: `npm install -g`, local source install, `npm link`, `npm pack`, GitHub Releases
18
+ - Public npm package: `codex-plugin-doctor`
19
+ - License: [MIT](./LICENSE)
20
+
21
+ ## Why This Exists
22
+
23
+ Codex plugin packages can fail in several places:
24
+
25
+ - the package manifest is missing or points outside the package root
26
+ - skills exist but do not expose valid `SKILL.md` metadata
27
+ - `.mcp.json` is malformed or references unsafe secrets
28
+ - an MCP server starts but does not complete the protocol handshake
29
+ - tools, resources, or prompts list successfully but fail deeper runtime checks
30
+ - verbose metadata creates noisy matching and unnecessary context cost
31
+
32
+ This tool gives plugin authors a repeatable preflight check before distribution.
33
+
34
+ ## What It Checks
35
+
36
+ Static validation:
37
+
38
+ - required `.codex-plugin/plugin.json`
39
+ - manifest fields: `name`, `version`, `description`
40
+ - skill directory wiring
41
+ - `SKILL.md` presence and frontmatter fields
42
+ - YAML single-line and block-scalar skill descriptions
43
+ - `.mcp.json` structure
44
+ - path traversal risks
45
+ - hard-coded secret-like env values
46
+ - description quality heuristics tuned against real plugin packages
47
+
48
+ Runtime MCP validation with `--runtime`:
49
+
50
+ - `initialize`
51
+ - `notifications/initialized`
52
+ - `tools/list`
53
+ - `tools/call`
54
+ - `resources/list`
55
+ - `resources/read`
56
+ - `resources/templates/list`
57
+ - `prompts/list`
58
+ - `prompts/get`
59
+ - paginated list responses
60
+ - runtime capability scorecard
61
+ - redacted verbose transcript with `--verbose-runtime`
62
+
63
+ Output formats:
64
+
65
+ - human text output
66
+ - JSON reports
67
+ - Markdown reports
68
+ - Shields-compatible badge JSON and static badge Markdown
69
+ - `--output` file writing
70
+ - CI summary and artifact generation
71
+
72
+ ## Quick Start
73
+
74
+ Global install from npm:
75
+
76
+ ```bash
77
+ npm install -g codex-plugin-doctor
78
+ codex-plugin-doctor --version
79
+ codex-plugin-doctor self-test
80
+ codex-plugin-doctor check path/to/plugin-package
81
+ ```
82
+
83
+ Run `codex-plugin-doctor check .` from the root of a Codex plugin package that contains `.codex-plugin/plugin.json`. The Codex Plugin Doctor source repository is not itself a plugin package.
84
+
85
+ If you already have Codex installed locally and do not know plugin paths, discover the installed plugin cache:
86
+
87
+ ```bash
88
+ codex-plugin-doctor list --installed
89
+ codex-plugin-doctor check --installed
90
+ codex-plugin-doctor check --installed --all-summary
91
+ codex-plugin-doctor check --installed github
92
+ codex-plugin-doctor explain plugin.manifest.missing
93
+ ```
94
+
95
+ Run from source:
96
+
97
+ ```bash
98
+ npm install
99
+ npm run build
100
+ node dist/cli.js check examples/codex-doctor-runtime --runtime
101
+ ```
102
+
103
+ For local global usage:
104
+
105
+ ```bash
106
+ npm link
107
+ codex-plugin-doctor check examples/codex-doctor-runtime --runtime
108
+ ```
109
+
110
+ Generate validation artifacts locally:
111
+
112
+ ```bash
113
+ npm run generate-validation-artifacts -- --target examples/codex-doctor-runtime --runtime-target examples/codex-doctor-runtime --out-dir validation-artifacts-local
114
+ ```
115
+
116
+ ## Example Output
117
+
118
+ Passing runtime package:
119
+
120
+ ```text
121
+ Codex Plugin Doctor
122
+ ===================
123
+ Status: PASS
124
+ Target: <repo>\examples\codex-doctor-runtime
125
+ Summary: 0 fail, 0 warn, 0 total
126
+
127
+ Runtime Scorecard
128
+ ----------------
129
+ initialize: pass
130
+ tools/list: pass
131
+ tools/call: pass
132
+ resources/list: pass
133
+ resources/read: pass
134
+ resources/templates/list: pass
135
+ prompts/list: pass
136
+ prompts/get: pass
137
+
138
+ No findings.
139
+ ```
140
+
141
+ Risky package:
142
+
143
+ ```text
144
+ Codex Plugin Doctor
145
+ ===================
146
+ Status: FAIL
147
+ Target: <repo>\examples\codex-doctor-risky
148
+ Summary: 1 fail, 0 warn, 1 total
149
+
150
+ Failures
151
+ --------
152
+ x plugin.security.hard_coded_secret
153
+ Message: The MCP server `dangerServer` contains a hard-coded secret-like env value for `OPENAI_API_KEY`.
154
+ Impact: Hard-coded credentials inside plugin bundles increase leakage risk and make secure rotation difficult.
155
+ Suggested fix: Replace the literal value for `OPENAI_API_KEY` with an environment reference or injected secret outside the package.
156
+ ```
157
+
158
+ ## Useful Commands
159
+
160
+ Run these from a Codex plugin package root:
161
+
162
+ ```bash
163
+ codex-plugin-doctor --version
164
+ codex-plugin-doctor self-test
165
+ codex-plugin-doctor init my-plugin
166
+ codex-plugin-doctor compat .
167
+ codex-plugin-doctor compat . --client codex
168
+ codex-plugin-doctor compat . --client generic-mcp
169
+ codex-plugin-doctor compat . --client claude-desktop
170
+ codex-plugin-doctor compat . --client claude-desktop --install-preview
171
+ codex-plugin-doctor compat . --client claude-desktop --apply --backup
172
+ codex-plugin-doctor compat . --client cursor
173
+ codex-plugin-doctor compat . --client cursor --install-preview
174
+ codex-plugin-doctor compat . --client cursor --apply --backup
175
+ codex-plugin-doctor compat . --scorecard
176
+ codex-plugin-doctor compat . --json
177
+ codex-plugin-doctor compat . --json --output compatibility.json
178
+ codex-plugin-doctor check .
179
+ codex-plugin-doctor check . --json
180
+ codex-plugin-doctor check . --json --output report.json
181
+ codex-plugin-doctor check . --markdown --output report.md
182
+ codex-plugin-doctor check . --badge-json --output doctor-badge.json
183
+ codex-plugin-doctor check . --badge-markdown
184
+ codex-plugin-doctor check . --sarif --output results.sarif
185
+ codex-plugin-doctor check . --ascii
186
+ codex-plugin-doctor check . --no-animations
187
+ codex-plugin-doctor check . --runtime
188
+ codex-plugin-doctor check . --config .codex-doctor.json
189
+ codex-plugin-doctor check . --json --runtime --verbose-runtime
190
+ ```
191
+
192
+ `self-test` runs the bundled runtime-complete sample through static validation, runtime MCP probes, and the compatibility scorecard. It is the fastest post-install check after `npm install -g codex-plugin-doctor`.
193
+
194
+ `compat --client claude-desktop` checks whether the MCP package can be added to the local Claude Desktop setup. On Windows it looks for `%APPDATA%\Claude\claude_desktop_config.json`; on macOS it looks for `~/Library/Application Support/Claude/claude_desktop_config.json`. A valid existing config returns `PASS`, a missing Claude Desktop install returns `WARN`, and a malformed local config returns `FAIL` so you do not add new servers into a broken config file. If the package server name already exists in Claude Desktop, the command returns `WARN` with the duplicate server name. Add `--install-preview` to print the JSON snippet that should be merged into `claude_desktop_config.json`; it does not modify files. Use `--apply --backup` only when you want the CLI to create a timestamped backup and merge the server config. Apply mode refuses to overwrite duplicate server names.
195
+
196
+ `compat --client cursor` checks whether the MCP package can be added to Cursor. It prefers a project-level `.cursor/mcp.json` when one already exists in the target package, then falls back to the global `~/.cursor/mcp.json` path. A valid existing config returns `PASS`, a missing Cursor config returns `WARN`, malformed JSON returns `FAIL`, and duplicate MCP server names return `WARN`. Add `--install-preview` to print the JSON snippet that should be merged into Cursor's `mcp.json`; it does not modify files. Use `--apply --backup` only when you want the CLI to create a timestamped backup and merge the server config. Apply mode refuses to overwrite duplicate server names.
197
+
198
+ `compat --scorecard` turns the compatibility matrix into a compact score summary. `PASS` maps to `100`, `WARN` maps to `70`, and `FAIL` or `SKIPPED` maps to `0`.
199
+
200
+ `check --badge-json` emits Shields endpoint-compatible JSON such as `{"schemaVersion":1,"label":"doctor","message":"PASS","color":"brightgreen"}`. `check --badge-markdown` emits a static shields.io Markdown badge for README or release notes. Badge output is intentionally limited to single package checks, not `check --installed`.
201
+
202
+ Optional local policy file:
203
+
204
+ ```json
205
+ {
206
+ "ignoreRules": ["plugin.heuristic.description.too_long"],
207
+ "failOnWarnings": true
208
+ }
209
+ ```
210
+
211
+ Run these when you want Codex Plugin Doctor to find plugins from the local Codex installation:
212
+
213
+ ```bash
214
+ codex-plugin-doctor list --installed
215
+ codex-plugin-doctor check --installed
216
+ codex-plugin-doctor check --installed --all-summary
217
+ codex-plugin-doctor check --installed github
218
+ codex-plugin-doctor check --installed github --runtime --no-animations
219
+ codex-plugin-doctor explain plugin.security.hard_coded_secret
220
+ ```
221
+
222
+ ## GitHub Action
223
+
224
+ ```yaml
225
+ name: Validate Codex plugin
226
+
227
+ on:
228
+ pull_request:
229
+
230
+ jobs:
231
+ doctor:
232
+ runs-on: ubuntu-latest
233
+ steps:
234
+ - uses: actions/checkout@v4
235
+ - uses: Esquetta/CodexPluginDoctor@v0.5.0
236
+ with:
237
+ version: "0.5.0"
238
+ path: .
239
+ runtime: "false"
240
+ ```
241
+
242
+ For runtime probing, SARIF output, installed plugin cache checks, and pinned release examples, see [GitHub Action Usage](./docs/engineering/github-action-usage.md).
243
+
244
+ To self-test this repository after cloning it:
245
+
246
+ ```bash
247
+ codex-plugin-doctor check examples/codex-doctor-runtime --runtime --no-animations
248
+ ```
249
+
250
+ ## Repository Layout
251
+
252
+ ```text
253
+ docs/ Product, engineering, security, and release docs
254
+ examples/ Manual plugin packs for local CLI testing
255
+ src/ CLI, validation logic, runtime probing, reports
256
+ tests/ Fixture-based regression tests
257
+ validation-sessions/ Real-world validation waves and tuning notes
258
+ ```
259
+
260
+ ## Validation Evidence
261
+
262
+ The validator is tuned against local fixtures and real marketplace-style plugin packages. See:
263
+
264
+ - [Real-World Validation Workflow](./docs/engineering/real-world-validation-workflow.md)
265
+ - [Validation Sessions](./validation-sessions/README.md)
266
+ - [Examples](./examples/README.md)
267
+ - [Rule Catalog](./docs/rules/catalog.md)
268
+
269
+ Recent validation waves covered:
270
+
271
+ - curated Codex plugin cache packages
272
+ - marketplace-style plugin snapshots
273
+ - YAML block-scalar skill metadata
274
+ - media and visual workflow metadata
275
+
276
+ ## Release Readiness
277
+
278
+ Release preparation is reproducible from the repository:
279
+
280
+ ```bash
281
+ npm run prepare-release
282
+ ```
283
+
284
+ This runs tests, builds the TypeScript output, and performs `npm pack --dry-run`.
285
+
286
+ Related docs:
287
+
288
+ - [Changelog](./CHANGELOG.md)
289
+ - [Contributing](./CONTRIBUTING.md)
290
+ - [Security Policy](./SECURITY.md)
291
+ - [Code of Conduct](./CODE_OF_CONDUCT.md)
292
+ - [NPM Release Checklist](./docs/engineering/npm-release-checklist.md)
293
+ - [Release Candidate Workflow](./docs/engineering/release-candidate-workflow.md)
294
+ - [v0.1.0 Release Notes](./docs/engineering/v0.1.0-final-release-notes.md)
295
+
296
+ ## Contributing
297
+
298
+ Contributions are welcome once the repository is public. Start with:
299
+
300
+ - [Contributing](./CONTRIBUTING.md)
301
+ - [Security Policy](./SECURITY.md)
302
+ - [Validation tuning issue template](./.github/ISSUE_TEMPLATE/validation_tuning.yml)
303
+
304
+ ## Support
305
+
306
+ If this tool saves you time, GitHub stars and sponsorship help signal that the project is worth continuing.
307
+
308
+ - Star the repository on GitHub.
309
+ - Use GitHub Sponsors through the repository funding link.
310
+ - Open validation tuning issues for false positives or false negatives.
311
+
312
+ ## Product Direction
313
+
314
+ Codex Plugin Doctor starts as a Codex-specific validator and can grow into a broader MCP Doctor over time.
315
+
316
+ The immediate goal is not a marketplace, dashboard, or hosted website. The immediate goal is a trustworthy local preflight check for Codex-compatible plugin bundles.
@@ -0,0 +1,10 @@
1
+ import type { CheckResult } from "../domain/types.js";
2
+ export interface BadgeReport {
3
+ schemaVersion: 1;
4
+ label: "doctor";
5
+ message: "PASS" | "WARN" | "FAIL";
6
+ color: "brightgreen" | "yellow" | "red";
7
+ }
8
+ export declare function buildBadgeReport(result: CheckResult): BadgeReport;
9
+ export declare function renderBadgeJson(result: CheckResult): string;
10
+ export declare function renderBadgeMarkdown(result: CheckResult): string;
@@ -0,0 +1,32 @@
1
+ function badgeForStatus(status) {
2
+ if (status === "pass") {
3
+ return {
4
+ message: "PASS",
5
+ color: "brightgreen"
6
+ };
7
+ }
8
+ if (status === "warn") {
9
+ return {
10
+ message: "WARN",
11
+ color: "yellow"
12
+ };
13
+ }
14
+ return {
15
+ message: "FAIL",
16
+ color: "red"
17
+ };
18
+ }
19
+ export function buildBadgeReport(result) {
20
+ return {
21
+ schemaVersion: 1,
22
+ label: "doctor",
23
+ ...badgeForStatus(result.status)
24
+ };
25
+ }
26
+ export function renderBadgeJson(result) {
27
+ return JSON.stringify(buildBadgeReport(result), null, 2);
28
+ }
29
+ export function renderBadgeMarkdown(result) {
30
+ const badge = buildBadgeReport(result);
31
+ return `![Codex Plugin Doctor](https://img.shields.io/badge/${badge.label}-${badge.message}-${badge.color})`;
32
+ }
package/dist/run-cli.d.ts CHANGED
@@ -7,6 +7,7 @@ export interface CliTerminalContext {
7
7
  stdoutIsTTY: boolean;
8
8
  stderrIsTTY: boolean;
9
9
  env: Record<string, string | undefined>;
10
+ platform?: NodeJS.Platform;
10
11
  }
11
12
  export interface RunCliOptions {
12
13
  terminalContext?: CliTerminalContext;
package/dist/run-cli.js CHANGED
@@ -10,6 +10,7 @@ import { applyDoctorConfig, loadDoctorConfig } from "./core/doctor-config.js";
10
10
  import { initPluginPackage } from "./core/init-plugin.js";
11
11
  import { runCheck } from "./index.js";
12
12
  import { renderInstalledSummary } from "./reporting/render-installed-summary.js";
13
+ import { renderBadgeJson, renderBadgeMarkdown } from "./reporting/render-badge-report.js";
13
14
  import { renderCompatibilityScorecard } from "./reporting/render-compatibility-scorecard.js";
14
15
  import { renderCompatibilityReport } from "./reporting/render-compatibility-report.js";
15
16
  import { renderJsonReport } from "./reporting/render-json-report.js";
@@ -31,7 +32,7 @@ const defaultIo = {
31
32
  }
32
33
  };
33
34
  function printUsage(io) {
34
- io.writeStderr("Usage: codex-plugin-doctor check <path|--installed> [filter] [--json|--markdown] [--output <path>] [--runtime] [--verbose-runtime] [--no-animations] [--ascii]\n codex-plugin-doctor compat <path> [--client <client>] [--json] [--scorecard] [--output <path>] [--install-preview|--apply --backup]\n codex-plugin-doctor self-test\n codex-plugin-doctor list --installed\n codex-plugin-doctor explain <finding-id>\n codex-plugin-doctor --version");
35
+ io.writeStderr("Usage: codex-plugin-doctor check <path|--installed> [filter] [--json|--markdown|--badge-json|--badge-markdown] [--output <path>] [--runtime] [--verbose-runtime] [--no-animations] [--ascii]\n codex-plugin-doctor compat <path> [--client <client>] [--json] [--scorecard] [--output <path>] [--install-preview|--apply --backup]\n codex-plugin-doctor self-test\n codex-plugin-doctor list --installed\n codex-plugin-doctor explain <finding-id>\n codex-plugin-doctor --version");
35
36
  }
36
37
  function renderInstalledPlugins(plugins) {
37
38
  const lines = [
@@ -94,7 +95,8 @@ export async function runCli(args, io = defaultIo, options = {}) {
94
95
  const terminalContext = options.terminalContext ?? {
95
96
  stdoutIsTTY: Boolean(process.stdout.isTTY),
96
97
  stderrIsTTY: Boolean(process.stderr.isTTY),
97
- env: process.env
98
+ env: process.env,
99
+ platform: process.platform
98
100
  };
99
101
  if (command === "list" && maybePath === "--installed") {
100
102
  const installedPlugins = await discoverInstalledPlugins({
@@ -121,7 +123,8 @@ export async function runCli(args, io = defaultIo, options = {}) {
121
123
  const runCheckImpl = options.runCheckImpl ?? runCheck;
122
124
  const result = applyDoctorConfig(await runCheckImpl(targetPath, { runtime: true }), await loadDoctorConfig(targetPath));
123
125
  const compatibilityMatrix = await buildCompatibilityMatrix(targetPath, {
124
- env: terminalContext.env
126
+ env: terminalContext.env,
127
+ platform: terminalContext.platform
125
128
  });
126
129
  io.writeStdout(renderSelfTestReport(targetPath, result.status, result.findings.length, compatibilityMatrix));
127
130
  return result.exitCode === 1 || matrixExitCode(compatibilityMatrix) === 1 ? 1 : 0;
@@ -179,10 +182,12 @@ export async function runCli(args, io = defaultIo, options = {}) {
179
182
  try {
180
183
  const preview = clientFilter?.toLowerCase() === "cursor"
181
184
  ? await buildCursorInstallPreview(targetPath, {
182
- env: terminalContext.env
185
+ env: terminalContext.env,
186
+ platform: terminalContext.platform
183
187
  })
184
188
  : await buildClaudeDesktopInstallPreview(targetPath, {
185
- env: terminalContext.env
189
+ env: terminalContext.env,
190
+ platform: terminalContext.platform
186
191
  });
187
192
  const report = applyInstall
188
193
  ? renderApplyInstallResult(await applyInstallPreview(clientFilter?.toLowerCase() === "cursor" ? "Cursor" : "Claude Desktop", preview))
@@ -202,7 +207,8 @@ export async function runCli(args, io = defaultIo, options = {}) {
202
207
  }
203
208
  }
204
209
  let matrix = await buildCompatibilityMatrix(targetPath, {
205
- env: terminalContext.env
210
+ env: terminalContext.env,
211
+ platform: terminalContext.platform
206
212
  });
207
213
  if (clientFilter) {
208
214
  const filteredMatrix = filterCompatibilityMatrix(matrix, clientFilter);
@@ -242,6 +248,8 @@ export async function runCli(args, io = defaultIo, options = {}) {
242
248
  : remainingArgs;
243
249
  const jsonOutput = normalizedFlags.includes("--json");
244
250
  const markdownOutput = normalizedFlags.includes("--markdown");
251
+ const badgeJsonOutput = normalizedFlags.includes("--badge-json");
252
+ const badgeMarkdownOutput = normalizedFlags.includes("--badge-markdown");
245
253
  const sarifOutput = normalizedFlags.includes("--sarif");
246
254
  const runtimeProbeEnabled = normalizedFlags.includes("--runtime");
247
255
  const verboseRuntime = normalizedFlags.includes("--verbose-runtime");
@@ -260,9 +268,13 @@ export async function runCli(args, io = defaultIo, options = {}) {
260
268
  io.writeStderr("Missing path after --config.");
261
269
  return 2;
262
270
  }
271
+ if (checkInstalled && (badgeJsonOutput || badgeMarkdownOutput)) {
272
+ io.writeStderr("Badge output requires a single package target.");
273
+ return 2;
274
+ }
263
275
  const outputPolicy = determineOutputPolicy({
264
- jsonOutput,
265
- markdownOutput,
276
+ jsonOutput: jsonOutput || badgeJsonOutput,
277
+ markdownOutput: markdownOutput || badgeMarkdownOutput,
266
278
  outputPath,
267
279
  noAnimations,
268
280
  asciiMode,
@@ -334,7 +346,11 @@ export async function runCli(args, io = defaultIo, options = {}) {
334
346
  ? renderSarifReport(result)
335
347
  : jsonOutput
336
348
  ? renderJsonReport(result, { runtimeProbeEnabled })
337
- : renderTextReport(result, { ascii: outputPolicy.style === "ascii" });
349
+ : badgeJsonOutput
350
+ ? renderBadgeJson(result)
351
+ : badgeMarkdownOutput
352
+ ? renderBadgeMarkdown(result)
353
+ : renderTextReport(result, { ascii: outputPolicy.style === "ascii" });
338
354
  if (outputPath) {
339
355
  await writeFile(outputPath, report, "utf8");
340
356
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-plugin-doctor",
3
- "version": "0.4.0",
3
+ "version": "0.5.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",