@mcptoolshop/mcpt-publishing 0.2.0 → 0.3.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/CHANGELOG.md +27 -0
- package/README.md +89 -33
- package/package.json +8 -1
- package/schemas/assets-receipt.schema.json +53 -0
- package/schemas/fix-receipt.schema.json +113 -0
- package/scripts/lib/providers/npm.mjs +10 -0
- package/src/audit/run-audit.mjs +108 -0
- package/src/cli/exit-codes.mjs +2 -0
- package/src/cli/help.mjs +15 -8
- package/src/cli/router.mjs +3 -0
- package/src/commands/assets.mjs +169 -0
- package/src/commands/audit.mjs +4 -84
- package/src/commands/fix.mjs +333 -0
- package/src/commands/init.mjs +27 -12
- package/src/commands/plan.mjs +17 -15
- package/src/commands/verify-receipt.mjs +58 -0
- package/src/commands/weekly.mjs +143 -0
- package/src/fixers/fixer.mjs +79 -0
- package/src/fixers/fixers/_npm-helpers.mjs +75 -0
- package/src/fixers/fixers/github-about.mjs +100 -0
- package/src/fixers/fixers/npm-bugs.mjs +67 -0
- package/src/fixers/fixers/npm-homepage.mjs +67 -0
- package/src/fixers/fixers/npm-keywords.mjs +77 -0
- package/src/fixers/fixers/npm-repository.mjs +80 -0
- package/src/fixers/fixers/nuget-csproj.mjs +200 -0
- package/src/fixers/fixers/readme-header.mjs +136 -0
- package/src/fixers/registry.mjs +71 -0
- package/src/plugins/loader.mjs +48 -0
- package/src/receipts/fix-receipt.mjs +49 -0
- package/src/receipts/index-writer.mjs +21 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.3.0] - 2026-02-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **fix command**: `mcpt-publishing fix` — allowlisted metadata fixes with local, `--remote`, and `--pr` modes
|
|
9
|
+
- **7 fixers**: npm-repository, npm-homepage, npm-bugs, npm-keywords, readme-header, github-about, nuget-csproj
|
|
10
|
+
- **Fixer plugin system**: Base `Fixer` class with auto-discovery registry, matching `canFix()` to audit findings
|
|
11
|
+
- **weekly command**: `mcpt-publishing weekly` — orchestrates audit → fix → optionally publish in one shot
|
|
12
|
+
- **assets command**: `mcpt-publishing assets` — bridges to optional `@mcptoolshop/mcpt-publishing-assets` plugin
|
|
13
|
+
- **Assets plugin**: `@mcptoolshop/mcpt-publishing-assets` — logo/icon generation via `sharp` (doctor, logo, wire)
|
|
14
|
+
- **Fix receipts**: Immutable JSON receipts for fix operations with schema validation
|
|
15
|
+
- **Assets receipts**: Receipt type for asset generation operations
|
|
16
|
+
- **CI prepublish gate**: Tarball verification, install smoke test, CLI smoke tests in GitHub Actions
|
|
17
|
+
- **Plugin loader**: Auto-discovers optional plugins with install hints
|
|
18
|
+
- **Shared audit loop**: Extracted `runAudit()` for reuse by both audit and fix commands
|
|
19
|
+
- Exit code 6 (`FIX_FAILURE`) for failed fixes
|
|
20
|
+
- `init --dry-run` support
|
|
21
|
+
- npm workspace support (`packages/` directory)
|
|
22
|
+
- 2 new npm audit findings: `missing-bugs-url`, `missing-keywords`
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Version bumped from 0.2.0 to 0.3.0
|
|
26
|
+
- Global help rewritten with Golden Path workflow
|
|
27
|
+
- README rewritten with fix command, weekly, assets plugin documentation
|
|
28
|
+
- CI workflow renamed from `audit-weekly.yml` to `ci.yml` with prepublish gate
|
|
29
|
+
- `plan` command deprecated (replaced by `fix --dry-run`)
|
|
30
|
+
- Test suite expanded from 42 to 93 tests
|
|
31
|
+
|
|
5
32
|
## [0.2.0] - 2026-02-17
|
|
6
33
|
|
|
7
34
|
### Added
|
package/README.md
CHANGED
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
|
|
20
20
|
## What it is
|
|
21
21
|
|
|
22
|
-
**mcpt-publishing** is a portable
|
|
22
|
+
**mcpt-publishing** is a portable publishing layer that sits between your repos and public registries.
|
|
23
23
|
|
|
24
|
-
It answers the
|
|
24
|
+
It answers the questions humans actually have:
|
|
25
25
|
|
|
26
26
|
- *Are my registry pages stale or embarrassing?*
|
|
27
27
|
- *Do tags/releases match what's published?*
|
|
@@ -38,7 +38,7 @@ Every run produces **receipts**: immutable JSON artifacts with SHA-256 hashes, c
|
|
|
38
38
|
|
|
39
39
|
- You publish to **npm and/or NuGet** and your pages drift over time (they do).
|
|
40
40
|
- You want a single place to enforce "registry truth" (versions, tags, URLs, READMEs, icons).
|
|
41
|
-
- You want automation that's safe: **
|
|
41
|
+
- You want automation that's safe: **audit, fix, receipts**, and no surprise pushes.
|
|
42
42
|
|
|
43
43
|
**Not for you if...**
|
|
44
44
|
|
|
@@ -67,17 +67,31 @@ This scaffolds:
|
|
|
67
67
|
- `profiles/` (where repos/packages are declared)
|
|
68
68
|
- `reports/` and `receipts/` output folders
|
|
69
69
|
|
|
70
|
-
###
|
|
70
|
+
### The golden path
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
+
# 1. Discover drift
|
|
73
74
|
npx mcpt-publishing audit
|
|
75
|
+
|
|
76
|
+
# 2. Preview fixes
|
|
77
|
+
npx mcpt-publishing fix --dry-run
|
|
78
|
+
|
|
79
|
+
# 3. Apply fixes locally
|
|
80
|
+
npx mcpt-publishing fix
|
|
81
|
+
|
|
82
|
+
# 4. Publish with receipts
|
|
83
|
+
npx mcpt-publishing publish --target npm
|
|
84
|
+
|
|
85
|
+
# 5. Verify the receipt
|
|
86
|
+
npx mcpt-publishing verify-receipt receipts/publish/...json
|
|
74
87
|
```
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
Or do it all at once:
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
91
|
+
```bash
|
|
92
|
+
npx mcpt-publishing weekly --dry-run # preview everything
|
|
93
|
+
npx mcpt-publishing weekly --publish # the full pipeline
|
|
94
|
+
```
|
|
81
95
|
|
|
82
96
|
---
|
|
83
97
|
|
|
@@ -92,34 +106,55 @@ npx mcpt-publishing audit
|
|
|
92
106
|
npx mcpt-publishing audit --json
|
|
93
107
|
```
|
|
94
108
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
Generates a safe plan to fix drift (no network writes). *(coming soon)*
|
|
109
|
+
Outputs:
|
|
98
110
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
```
|
|
111
|
+
- `reports/latest.md` (human-readable)
|
|
112
|
+
- `reports/latest.json` (machine-readable)
|
|
113
|
+
- a receipt under `receipts/`
|
|
103
114
|
|
|
104
|
-
### `mcpt-publishing
|
|
115
|
+
### `mcpt-publishing fix`
|
|
105
116
|
|
|
106
|
-
Applies
|
|
117
|
+
Applies allowlisted metadata fixes to bring your registry pages into shape.
|
|
107
118
|
|
|
108
119
|
```bash
|
|
109
|
-
npx mcpt-publishing
|
|
110
|
-
npx mcpt-publishing apply
|
|
120
|
+
npx mcpt-publishing fix --dry-run # preview all fixes
|
|
121
|
+
npx mcpt-publishing fix # apply locally
|
|
122
|
+
npx mcpt-publishing fix --remote # apply via GitHub API (no checkout)
|
|
123
|
+
npx mcpt-publishing fix --pr # apply locally + open a PR
|
|
124
|
+
npx mcpt-publishing fix --repo mcp-tool-shop-org/mcpt # fix one repo only
|
|
111
125
|
```
|
|
112
126
|
|
|
127
|
+
Supported fixes:
|
|
128
|
+
|
|
129
|
+
| Fix | What it does |
|
|
130
|
+
|-----|-------------|
|
|
131
|
+
| `npm-repository` | Sets `repository` in package.json |
|
|
132
|
+
| `npm-homepage` | Sets `homepage` in package.json |
|
|
133
|
+
| `npm-bugs` | Sets `bugs.url` in package.json |
|
|
134
|
+
| `npm-keywords` | Adds starter keywords to package.json |
|
|
135
|
+
| `readme-header` | Adds logo + links to README.md |
|
|
136
|
+
| `github-about` | Sets homepage/description via GitHub API |
|
|
137
|
+
| `nuget-csproj` | Adds PackageProjectUrl/RepositoryUrl to .csproj |
|
|
138
|
+
|
|
113
139
|
### `mcpt-publishing publish`
|
|
114
140
|
|
|
115
141
|
Publishes packages to registries and generates immutable receipts.
|
|
116
142
|
|
|
117
143
|
```bash
|
|
118
144
|
npx mcpt-publishing publish --repo mcp-tool-shop-org/mcpt --target npm
|
|
119
|
-
npx mcpt-publishing publish --repo mcp-tool-shop-org/soundboard-maui --target nuget --cwd /path/to/repo
|
|
120
145
|
npx mcpt-publishing publish --target npm --dry-run
|
|
121
146
|
```
|
|
122
147
|
|
|
148
|
+
### `mcpt-publishing weekly`
|
|
149
|
+
|
|
150
|
+
Orchestrates the full golden path: audit, fix, and optionally publish.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npx mcpt-publishing weekly --dry-run # audit + fix preview
|
|
154
|
+
npx mcpt-publishing weekly --pr # audit + fix as PR
|
|
155
|
+
npx mcpt-publishing weekly --publish # audit + fix + publish
|
|
156
|
+
```
|
|
157
|
+
|
|
123
158
|
### `mcpt-publishing providers`
|
|
124
159
|
|
|
125
160
|
Shows enabled providers and required env vars.
|
|
@@ -134,22 +169,44 @@ Validates receipt files against schema and computes integrity hashes.
|
|
|
134
169
|
|
|
135
170
|
```bash
|
|
136
171
|
npx mcpt-publishing verify-receipt receipts/audit/2026-02-17.json
|
|
137
|
-
npx mcpt-publishing verify-receipt receipts/
|
|
172
|
+
npx mcpt-publishing verify-receipt receipts/fix/2026-02-17-fleet.json --json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### `mcpt-publishing init`
|
|
176
|
+
|
|
177
|
+
Scaffolds a new project. Supports `--dry-run` to preview without writing files.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npx mcpt-publishing init
|
|
181
|
+
npx mcpt-publishing init --dry-run
|
|
138
182
|
```
|
|
139
183
|
|
|
140
184
|
---
|
|
141
185
|
|
|
142
|
-
## Optional: assets plugin
|
|
186
|
+
## Optional: assets plugin
|
|
143
187
|
|
|
144
|
-
Core is zero-dependency. Visual updates (logos, icons
|
|
188
|
+
Core is zero-dependency. Visual updates (logos, icons) are handled by an optional plugin:
|
|
145
189
|
|
|
146
190
|
```bash
|
|
147
191
|
npm i -D @mcptoolshop/mcpt-publishing-assets
|
|
148
|
-
npx mcpt-publishing assets doctor
|
|
149
|
-
npx mcpt-publishing assets logo --repo mcp-tool-shop-org/mcpt
|
|
150
192
|
```
|
|
151
193
|
|
|
152
|
-
|
|
194
|
+
Once installed, `mcpt-publishing` auto-detects it:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
npx mcpt-publishing assets doctor # check sharp is working
|
|
198
|
+
npx mcpt-publishing assets logo --input src.png # generate icon + logo
|
|
199
|
+
npx mcpt-publishing assets wire --repo owner/name # wire into project files
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The plugin depends on `sharp` and is kept separate so core installs remain fast and reliable.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Upgrading from 0.2.x
|
|
207
|
+
|
|
208
|
+
- `mcpt-publishing plan` is deprecated — use `mcpt-publishing fix --dry-run` instead.
|
|
209
|
+
- Install the assets plugin for logo/icon generation: `npm i -D @mcptoolshop/mcpt-publishing-assets`
|
|
153
210
|
|
|
154
211
|
---
|
|
155
212
|
|
|
@@ -172,6 +229,8 @@ Schemas live in:
|
|
|
172
229
|
|
|
173
230
|
- `schemas/profile.schema.json`
|
|
174
231
|
- `schemas/receipt.schema.json`
|
|
232
|
+
- `schemas/fix-receipt.schema.json`
|
|
233
|
+
- `schemas/assets-receipt.schema.json`
|
|
175
234
|
|
|
176
235
|
Contract + phases: `docs/CONTRACT.md`
|
|
177
236
|
|
|
@@ -199,6 +258,7 @@ These are only needed when you publish or call APIs that require auth.
|
|
|
199
258
|
| `3` | Configuration or schema error |
|
|
200
259
|
| `4` | Missing credentials for a requested operation |
|
|
201
260
|
| `5` | One or more publishes failed |
|
|
261
|
+
| `6` | One or more fixes failed |
|
|
202
262
|
|
|
203
263
|
---
|
|
204
264
|
|
|
@@ -213,6 +273,8 @@ They include:
|
|
|
213
273
|
- URLs
|
|
214
274
|
- SHA-256 hashes of key artifacts
|
|
215
275
|
|
|
276
|
+
Types: `audit`, `publish`, `fix`, `assets`
|
|
277
|
+
|
|
216
278
|
If you like receipts, you can plug this into the receipt factory as the "publishing plugin."
|
|
217
279
|
|
|
218
280
|
---
|
|
@@ -221,13 +283,7 @@ If you like receipts, you can plug this into the receipt factory as the "publish
|
|
|
221
283
|
|
|
222
284
|
```bash
|
|
223
285
|
npm test
|
|
224
|
-
node
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
Smoke tests:
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
node scripts/test-providers.mjs
|
|
286
|
+
node bin/mcpt-publishing.mjs audit
|
|
231
287
|
```
|
|
232
288
|
|
|
233
289
|
---
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcptoolshop/mcpt-publishing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Publishing health auditor and receipt factory plugin for MCP Tool Shop packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mcpt-publishing": "./bin/mcpt-publishing.mjs"
|
|
8
8
|
},
|
|
9
|
+
"workspaces": [
|
|
10
|
+
"packages/*"
|
|
11
|
+
],
|
|
9
12
|
"files": [
|
|
10
13
|
"bin/",
|
|
11
14
|
"src/",
|
|
@@ -22,6 +25,10 @@
|
|
|
22
25
|
"scripts": {
|
|
23
26
|
"audit": "node bin/mcpt-publishing.mjs audit",
|
|
24
27
|
"audit:json": "node bin/mcpt-publishing.mjs audit --json",
|
|
28
|
+
"fix": "node bin/mcpt-publishing.mjs fix",
|
|
29
|
+
"fix:dry": "node bin/mcpt-publishing.mjs fix --dry-run",
|
|
30
|
+
"weekly": "node bin/mcpt-publishing.mjs weekly",
|
|
31
|
+
"weekly:dry": "node bin/mcpt-publishing.mjs weekly --dry-run",
|
|
25
32
|
"test": "node scripts/test-providers.mjs"
|
|
26
33
|
},
|
|
27
34
|
"engines": {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Assets Receipt",
|
|
4
|
+
"description": "Receipt for asset generation operations (logo, icon, wire).",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schemaVersion", "type", "timestamp", "repo", "artifacts"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"const": "1.0.0"
|
|
11
|
+
},
|
|
12
|
+
"type": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"const": "assets"
|
|
15
|
+
},
|
|
16
|
+
"timestamp": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"format": "date-time"
|
|
19
|
+
},
|
|
20
|
+
"repo": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"required": ["owner", "name"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"owner": { "type": "string" },
|
|
25
|
+
"name": { "type": "string" }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"artifacts": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"required": ["name", "sha256", "size"],
|
|
33
|
+
"properties": {
|
|
34
|
+
"name": { "type": "string" },
|
|
35
|
+
"sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
|
|
36
|
+
"size": { "type": "integer", "minimum": 0 }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"wireChanges": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": {
|
|
45
|
+
"file": { "type": "string" },
|
|
46
|
+
"field": { "type": "string" },
|
|
47
|
+
"before": { "type": "string" },
|
|
48
|
+
"after": { "type": "string" }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/mcp-tool-shop/mcpt-publishing/schemas/fix-receipt.schema.json",
|
|
4
|
+
"title": "Fix Receipt",
|
|
5
|
+
"description": "Record of a publishing metadata fix run.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schemaVersion", "type", "timestamp", "repo", "mode", "changes"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"const": "1.0.0"
|
|
13
|
+
},
|
|
14
|
+
"type": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"const": "fix"
|
|
17
|
+
},
|
|
18
|
+
"timestamp": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"format": "date-time",
|
|
21
|
+
"description": "When the fix ran"
|
|
22
|
+
},
|
|
23
|
+
"repo": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Repo slug (owner/name) or '*' for fleet-wide"
|
|
26
|
+
},
|
|
27
|
+
"mode": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"enum": ["local", "remote", "pr", "dry-run"],
|
|
30
|
+
"description": "How fixes were applied"
|
|
31
|
+
},
|
|
32
|
+
"dryRun": {
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
35
|
+
"prUrl": {
|
|
36
|
+
"type": ["string", "null"],
|
|
37
|
+
"description": "URL of the PR created (--pr mode only)"
|
|
38
|
+
},
|
|
39
|
+
"branchName": {
|
|
40
|
+
"type": ["string", "null"],
|
|
41
|
+
"description": "Branch name used for --pr mode"
|
|
42
|
+
},
|
|
43
|
+
"changes": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"required": ["fixerCode", "target", "field", "before", "after"],
|
|
48
|
+
"additionalProperties": false,
|
|
49
|
+
"properties": {
|
|
50
|
+
"fixerCode": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"description": "Machine-readable fixer identifier (e.g. npm-repository)"
|
|
53
|
+
},
|
|
54
|
+
"target": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"description": "Ecosystem (npm, nuget, readme, github)"
|
|
57
|
+
},
|
|
58
|
+
"packageName": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"description": "Package name affected"
|
|
61
|
+
},
|
|
62
|
+
"field": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"description": "Field that was changed (e.g. repository.url)"
|
|
65
|
+
},
|
|
66
|
+
"before": {
|
|
67
|
+
"description": "Value before the fix (null if missing)"
|
|
68
|
+
},
|
|
69
|
+
"after": {
|
|
70
|
+
"description": "Value after the fix"
|
|
71
|
+
},
|
|
72
|
+
"file": {
|
|
73
|
+
"type": ["string", "null"],
|
|
74
|
+
"description": "Relative path of the file changed"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"auditBefore": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"description": "Finding counts before fix",
|
|
82
|
+
"properties": {
|
|
83
|
+
"RED": { "type": "integer", "minimum": 0 },
|
|
84
|
+
"YELLOW": { "type": "integer", "minimum": 0 },
|
|
85
|
+
"GRAY": { "type": "integer", "minimum": 0 },
|
|
86
|
+
"INFO": { "type": "integer", "minimum": 0 }
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"auditAfter": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"description": "Finding counts after fix (if re-audited)",
|
|
92
|
+
"properties": {
|
|
93
|
+
"RED": { "type": "integer", "minimum": 0 },
|
|
94
|
+
"YELLOW": { "type": "integer", "minimum": 0 },
|
|
95
|
+
"GRAY": { "type": "integer", "minimum": 0 },
|
|
96
|
+
"INFO": { "type": "integer", "minimum": 0 }
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"commitSha": {
|
|
100
|
+
"type": ["string", "null"],
|
|
101
|
+
"pattern": "^[0-9a-f]{40}$",
|
|
102
|
+
"description": "Commit SHA at time of fix (null in dry-run)"
|
|
103
|
+
},
|
|
104
|
+
"fileHashes": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"description": "SHA-256 hashes of files modified",
|
|
107
|
+
"additionalProperties": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -159,6 +159,16 @@ export default class NpmProvider extends Provider {
|
|
|
159
159
|
findings.push({ severity: "GRAY", code: "missing-homepage", msg: `${pkg.name} has no homepage` });
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
// Bugs URL
|
|
163
|
+
if (!meta.bugs?.url) {
|
|
164
|
+
findings.push({ severity: "GRAY", code: "missing-bugs-url", msg: `${pkg.name} has no bugs URL` });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Keywords
|
|
168
|
+
if (!meta.keywords?.length) {
|
|
169
|
+
findings.push({ severity: "GRAY", code: "missing-keywords", msg: `${pkg.name} has no keywords` });
|
|
170
|
+
}
|
|
171
|
+
|
|
162
172
|
return findings;
|
|
163
173
|
}
|
|
164
174
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared audit loop — runs publishing health audit and returns structured results.
|
|
3
|
+
*
|
|
4
|
+
* Used by both `audit` (to generate reports) and `fix` (to discover fixable drift).
|
|
5
|
+
* Does NOT write reports or emit receipts — callers handle that.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
10
|
+
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Run the audit loop across all manifest entries.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} config - Resolved config (from loader.mjs)
|
|
17
|
+
* @param {object} manifest - Parsed manifest ({ npm: [...], nuget: [...], ... })
|
|
18
|
+
* @returns {Promise<{ results: object, allFindings: Array, counts: object }>}
|
|
19
|
+
*/
|
|
20
|
+
export async function runAudit(config, manifest) {
|
|
21
|
+
// Import provider registry (reuse existing working code in scripts/lib/)
|
|
22
|
+
const registryPath = join(__dirname, "..", "..", "scripts", "lib", "registry.mjs");
|
|
23
|
+
const registryUrl = pathToFileURL(registryPath).href;
|
|
24
|
+
const { loadProviders, matchProviders } = await import(registryUrl);
|
|
25
|
+
|
|
26
|
+
const providers = await loadProviders();
|
|
27
|
+
|
|
28
|
+
// Optional: filter by enabledProviders config
|
|
29
|
+
const enabled = config.enabledProviders ?? [];
|
|
30
|
+
const activeProviders = enabled.length > 0
|
|
31
|
+
? providers.filter(p => enabled.includes(p.name))
|
|
32
|
+
: providers;
|
|
33
|
+
|
|
34
|
+
// Shared context for tag/release caching
|
|
35
|
+
const ctx = {
|
|
36
|
+
tags: new Map(),
|
|
37
|
+
releases: new Map(),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Find the GitHub provider (context loader) — must run before ecosystem providers
|
|
41
|
+
const ghProvider = activeProviders.find(p => p.name === "github");
|
|
42
|
+
|
|
43
|
+
// Build results object with an array per ecosystem key present in the manifest
|
|
44
|
+
const results = {};
|
|
45
|
+
for (const key of Object.keys(manifest)) {
|
|
46
|
+
if (Array.isArray(manifest[key])) results[key] = [];
|
|
47
|
+
}
|
|
48
|
+
results.generated = new Date().toISOString();
|
|
49
|
+
|
|
50
|
+
const allFindings = [];
|
|
51
|
+
|
|
52
|
+
// Process each ecosystem section from the manifest
|
|
53
|
+
for (const [ecosystem, packages] of Object.entries(manifest)) {
|
|
54
|
+
if (!Array.isArray(packages)) continue;
|
|
55
|
+
process.stderr.write(`Auditing ${packages.length} ${ecosystem} packages...\n`);
|
|
56
|
+
|
|
57
|
+
for (const pkg of packages) {
|
|
58
|
+
const entry = { ...pkg, ecosystem };
|
|
59
|
+
|
|
60
|
+
// Ensure GitHub context (tags + releases) is loaded for this repo
|
|
61
|
+
if (ghProvider && ghProvider.detect(entry)) {
|
|
62
|
+
await ghProvider.audit(entry, ctx);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Find the ecosystem-specific provider(s)
|
|
66
|
+
const ecosystemProviders = matchProviders(activeProviders, entry).filter(p => p.name !== "github");
|
|
67
|
+
|
|
68
|
+
let version = "?";
|
|
69
|
+
const findings = [];
|
|
70
|
+
|
|
71
|
+
for (const provider of ecosystemProviders) {
|
|
72
|
+
const result = await provider.audit(entry, ctx);
|
|
73
|
+
if (result.version && result.version !== "?") version = result.version;
|
|
74
|
+
findings.push(...result.findings);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const resultEntry = {
|
|
78
|
+
name: pkg.name,
|
|
79
|
+
version,
|
|
80
|
+
repo: pkg.repo,
|
|
81
|
+
audience: pkg.audience,
|
|
82
|
+
findings,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (results[ecosystem]) {
|
|
86
|
+
results[ecosystem].push(resultEntry);
|
|
87
|
+
}
|
|
88
|
+
allFindings.push(...findings.map(f => ({ ...f, pkg: pkg.name, ecosystem })));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Counts
|
|
93
|
+
const red = allFindings.filter(f => f.severity === "RED");
|
|
94
|
+
const yellow = allFindings.filter(f => f.severity === "YELLOW");
|
|
95
|
+
const gray = allFindings.filter(f => f.severity === "GRAY");
|
|
96
|
+
const info = allFindings.filter(f => f.severity === "INFO");
|
|
97
|
+
const counts = { RED: red.length, YELLOW: yellow.length, GRAY: gray.length, INFO: info.length };
|
|
98
|
+
results.counts = counts;
|
|
99
|
+
|
|
100
|
+
// Count total packages
|
|
101
|
+
let totalPackages = 0;
|
|
102
|
+
for (const [, val] of Object.entries(results)) {
|
|
103
|
+
if (Array.isArray(val)) totalPackages += val.length;
|
|
104
|
+
}
|
|
105
|
+
results.totalPackages = totalPackages;
|
|
106
|
+
|
|
107
|
+
return { results, allFindings, counts };
|
|
108
|
+
}
|
package/src/cli/exit-codes.mjs
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 3 — config or schema error
|
|
8
8
|
* 4 — missing credentials for a requested operation
|
|
9
9
|
* 5 — one or more publishes failed
|
|
10
|
+
* 6 — one or more fixes failed to apply
|
|
10
11
|
*/
|
|
11
12
|
export const EXIT = {
|
|
12
13
|
SUCCESS: 0,
|
|
@@ -14,4 +15,5 @@ export const EXIT = {
|
|
|
14
15
|
CONFIG_ERROR: 3,
|
|
15
16
|
MISSING_CREDENTIALS: 4,
|
|
16
17
|
PUBLISH_FAILURE: 5,
|
|
18
|
+
FIX_FAILURE: 6,
|
|
17
19
|
};
|
package/src/cli/help.mjs
CHANGED
|
@@ -10,23 +10,30 @@ Usage:
|
|
|
10
10
|
|
|
11
11
|
Commands:
|
|
12
12
|
audit Run publishing health audit across all registries
|
|
13
|
-
|
|
13
|
+
fix Apply allowlisted metadata fixes (local, --remote, --pr)
|
|
14
14
|
publish Publish packages to registries with receipts
|
|
15
|
+
weekly Audit + fix + optionally publish (one command)
|
|
16
|
+
assets Logo/icon generation and wiring [plugin]
|
|
15
17
|
providers List registered providers and their status
|
|
16
18
|
verify-receipt Validate a receipt file (schema + integrity)
|
|
17
|
-
|
|
19
|
+
init Scaffold publishing.config.json and starter manifest
|
|
20
|
+
plan [deprecated — use fix --dry-run]
|
|
18
21
|
|
|
19
22
|
Global flags:
|
|
20
23
|
--help Show help for a command
|
|
21
24
|
--version Show version
|
|
22
25
|
--json Machine-readable output (supported by all commands)
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
mcpt-publishing audit
|
|
26
|
-
mcpt-publishing
|
|
27
|
-
mcpt-publishing
|
|
28
|
-
mcpt-publishing
|
|
29
|
-
mcpt-publishing
|
|
27
|
+
Golden path:
|
|
28
|
+
mcpt-publishing audit # 1. discover drift
|
|
29
|
+
mcpt-publishing fix --dry-run # 2. preview fixes
|
|
30
|
+
mcpt-publishing fix # 3. apply fixes locally
|
|
31
|
+
mcpt-publishing publish --target npm --dry-run # 4. preview publish
|
|
32
|
+
mcpt-publishing publish --target npm # 5. publish with receipts
|
|
33
|
+
|
|
34
|
+
# Or do it all at once:
|
|
35
|
+
mcpt-publishing weekly --dry-run # preview everything
|
|
36
|
+
mcpt-publishing weekly --publish # the full pipeline
|
|
30
37
|
|
|
31
38
|
Environment:
|
|
32
39
|
PUBLISHING_CONFIG Path to publishing.config.json (overrides walk-up discovery)
|
package/src/cli/router.mjs
CHANGED
|
@@ -12,10 +12,13 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
12
12
|
/** Lazy-loaded command map. Keys are subcommand names. */
|
|
13
13
|
const COMMANDS = {
|
|
14
14
|
audit: () => import("../commands/audit.mjs"),
|
|
15
|
+
fix: () => import("../commands/fix.mjs"),
|
|
15
16
|
init: () => import("../commands/init.mjs"),
|
|
16
17
|
plan: () => import("../commands/plan.mjs"),
|
|
17
18
|
publish: () => import("../commands/publish.mjs"),
|
|
18
19
|
providers: () => import("../commands/providers.mjs"),
|
|
20
|
+
weekly: () => import("../commands/weekly.mjs"),
|
|
21
|
+
assets: () => import("../commands/assets.mjs"),
|
|
19
22
|
"verify-receipt": () => import("../commands/verify-receipt.mjs"),
|
|
20
23
|
};
|
|
21
24
|
|