memento-mori-jester 0.1.87 → 0.1.88
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 +6 -0
- package/README.md +6 -0
- package/ROADMAP.md +1 -0
- package/docs/GETTING_STARTED.md +1 -1
- package/docs/MAINTAINER_TRIAGE.md +2 -0
- package/docs/PRODUCTION_READINESS.md +3 -0
- package/docs/RELEASE.md +3 -1
- package/docs/RELEASE_NOTES_v0.1.88.md +62 -0
- package/examples/reports/README.md +25 -0
- package/examples/reports/report-gallery.json +47 -0
- package/package.json +3 -2
- package/scripts/check-production-readiness.mjs +15 -0
- package/scripts/check-report-gallery.mjs +245 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to Memento Mori Jester are tracked here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.1.88
|
|
8
|
+
|
|
9
|
+
- Added `examples/reports`, a small checked report gallery for fresh `doctor`, destructive-command `summary`, and full blocked-command review output.
|
|
10
|
+
- Added `npm run reports:check`, which installs the package into a temporary consumer project and verifies every gallery command against stable output fragments.
|
|
11
|
+
- Updated README, getting-started docs, maintainer triage docs, release docs, production-readiness docs, roadmap, and release notes for the report gallery.
|
|
12
|
+
|
|
7
13
|
## 0.1.87
|
|
8
14
|
|
|
9
15
|
- Fixed `npm run consumer:quickstart:check -- --package memento-mori-jester@latest` so registry package specs install through `npm install --save-dev <spec>` in the temporary consumer project.
|
package/README.md
CHANGED
|
@@ -72,6 +72,8 @@ For a first read-only CI smoke, copy [examples/ci/adoption-smoke.yml](examples/c
|
|
|
72
72
|
|
|
73
73
|
Maintainers can prove that fresh-project path with [examples/consumer-quickstart](examples/consumer-quickstart) and `npm run consumer:quickstart:check`, which installs the package into a temporary project and runs the same quickstart commands from there.
|
|
74
74
|
|
|
75
|
+
For trust-building output examples, see [examples/reports](examples/reports). `npm run reports:check` installs the package into a temporary project and proves the gallery's `doctor`, `summary`, and blocked-command reports stay current.
|
|
76
|
+
|
|
75
77
|
Expected vibe:
|
|
76
78
|
|
|
77
79
|
```text
|
|
@@ -442,6 +444,7 @@ More setup examples:
|
|
|
442
444
|
- [Framework CI Examples](examples/ci)
|
|
443
445
|
- [Adoption Smoke CI](examples/ci/adoption-smoke.yml)
|
|
444
446
|
- [Consumer Quickstart Smoke](examples/consumer-quickstart)
|
|
447
|
+
- [Real-World Report Gallery](examples/reports)
|
|
445
448
|
- [Security Policy](SECURITY.md)
|
|
446
449
|
- [Maintainer Triage](docs/MAINTAINER_TRIAGE.md)
|
|
447
450
|
- [Changelog](CHANGELOG.md)
|
|
@@ -461,6 +464,7 @@ Framework CI examples:
|
|
|
461
464
|
|
|
462
465
|
- [Adoption Smoke CI](examples/ci/adoption-smoke.yml)
|
|
463
466
|
- [Consumer Quickstart Smoke](examples/consumer-quickstart)
|
|
467
|
+
- [Real-World Report Gallery](examples/reports)
|
|
464
468
|
- [Next.js CI](examples/ci/nextjs.yml)
|
|
465
469
|
- [Vite React CI](examples/ci/vite-react.yml)
|
|
466
470
|
- [Express API CI](examples/ci/express-api.yml)
|
|
@@ -516,6 +520,7 @@ Use the false-positive template for noisy cautions or blocks. Include `jester su
|
|
|
516
520
|
Maintainers can use [docs/MAINTAINER_TRIAGE.md](docs/MAINTAINER_TRIAGE.md) to turn useful false-positive reports into redacted fixtures.
|
|
517
521
|
Run `npm run fixtures:check` before merging fixture changes; it catches duplicate IDs, missing rule metadata, weak descriptions, unsafe-looking content, and duplicate content.
|
|
518
522
|
Run `npm run fixtures:report` to see fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass boundaries, feasible pass-case gaps, and curation-next guidance before choosing the next fixture. Use `npm run fixtures:report -- --markdown` when you want a paste-ready summary for release notes or GitHub issues.
|
|
523
|
+
Run `npm run reports:check` after editing [examples/reports](examples/reports); it verifies the public report gallery against an installed package in a temporary consumer project.
|
|
519
524
|
Run `npm run promo:card` to regenerate the repo-local social preview card after changing its copy or design.
|
|
520
525
|
Run `npm run promo:check` after editing promo assets; it checks the current demo video, stills, docs, and fixture evidence numbers stay in sync.
|
|
521
526
|
Run `npm run site:check` after editing the repo-local landing page; it verifies the start command, demo links, social card, repo, release, and npm links.
|
|
@@ -529,6 +534,7 @@ Release checklist:
|
|
|
529
534
|
```powershell
|
|
530
535
|
npm.cmd test
|
|
531
536
|
npm.cmd run consumer:quickstart:check
|
|
537
|
+
npm.cmd run reports:check
|
|
532
538
|
npm.cmd run promo:check
|
|
533
539
|
npm.cmd run production:check
|
|
534
540
|
npm.cmd run pack:dry
|
package/ROADMAP.md
CHANGED
|
@@ -6,6 +6,7 @@ Memento Mori Jester is usable today as a CLI, MCP server, GitHub Action, and git
|
|
|
6
6
|
|
|
7
7
|
## Recently Shipped
|
|
8
8
|
|
|
9
|
+
- Checked report gallery in v0.1.88, proving fresh `doctor`, destructive-command `summary`, and blocked-command reports from an installed consumer project.
|
|
9
10
|
- Consumer quickstart registry-mode fix in v0.1.87, proving the same smoke against `memento-mori-jester@latest` after publish.
|
|
10
11
|
- Consumer quickstart smoke in v0.1.86, proving the first installed-project commands from a minimal repo before release.
|
|
11
12
|
- Adoption smoke CI example in v0.1.85, giving real repos a read-only workflow for `doctor`, `summary`, and packaged framework tuning checks.
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -106,7 +106,7 @@ npx -y memento-mori-jester@latest bootstrap --preset node
|
|
|
106
106
|
|
|
107
107
|
Then tell them to open `MEMENTO_MORI.md`.
|
|
108
108
|
|
|
109
|
-
For copy-paste agent and hook examples, see [examples](../examples). For stack-specific config examples, see [preset example packs](../examples/presets) for Next.js, Vite React, Express API, FastAPI, Terraform/Kubernetes, and AI MCP repos. For copy-paste CI workflows, see [framework CI examples](../examples/ci). For concrete pass, caution, and block cases, see [review fixtures](../examples/fixtures). For stack-shaped noisy-rule reports, see [framework tuning examples](FRAMEWORK_TUNING.md) and the checked [framework tuning cookbook](../examples/tuning).
|
|
109
|
+
For copy-paste agent and hook examples, see [examples](../examples). For stack-specific config examples, see [preset example packs](../examples/presets) for Next.js, Vite React, Express API, FastAPI, Terraform/Kubernetes, and AI MCP repos. For copy-paste CI workflows, see [framework CI examples](../examples/ci). For concrete pass, caution, and block cases, see [review fixtures](../examples/fixtures). For first trustworthy output examples, see the checked [report gallery](../examples/reports). For stack-shaped noisy-rule reports, see [framework tuning examples](FRAMEWORK_TUNING.md) and the checked [framework tuning cookbook](../examples/tuning).
|
|
110
110
|
|
|
111
111
|
## Need Help?
|
|
112
112
|
|
|
@@ -17,6 +17,8 @@ npx -y memento-mori-jester@latest summary --kind <command|plan|diff|final> "<min
|
|
|
17
17
|
npx -y memento-mori-jester@latest tune <rule-id> --json
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
For users who just need to understand what a healthy report looks like, point them at the checked [report gallery](../examples/reports). Maintainers can run `npm run reports:check` to prove those examples still match the current package output.
|
|
21
|
+
|
|
20
22
|
Do not ask users to paste secrets, private code, customer data, live credentials, complete CI logs, or unredacted SARIF. If the report involves credential exposure, command execution, unexpected network access, private code disclosure, package publishing, or MCP data exposure, route it through [SECURITY.md](../SECURITY.md).
|
|
21
23
|
|
|
22
24
|
## Triage Labels
|
|
@@ -46,6 +46,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
|
|
|
46
46
|
|
|
47
47
|
- `README.md` leads with a no-write first run, project bootstrap, agent setup, and optional hooks/CI.
|
|
48
48
|
- `docs/GETTING_STARTED.md`, `docs/CLI.md`, `docs/RELEASE.md`, and `docs/TRUSTED_PUBLISHING.md` cover the core adoption and release paths.
|
|
49
|
+
- `examples/reports` provides checked, public-safe report examples for fresh install diagnostics, summary output, and blocked command reviews.
|
|
49
50
|
- `site/index.html` gives maintainers a static one-page share surface that reuses the demo, social card, start command, and public links.
|
|
50
51
|
- Every public release has matching `CHANGELOG.md` notes and `docs/RELEASE_NOTES_vX.Y.Z.md`.
|
|
51
52
|
|
|
@@ -63,6 +64,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
|
|
|
63
64
|
- `npm run framework:tuning:check` keeps the framework tuning guide, cookbook JSON, cookbook README, and fixture IDs aligned.
|
|
64
65
|
- `npm run framework:tuning:doctor` runs the cookbook tune commands through the built CLI with temporary preset configs, so package consumers do not inherit stale recipes.
|
|
65
66
|
- `npm run consumer:quickstart:check` installs the package into a temporary minimal project and runs `doctor`, `summary`, and packaged framework tuning checks from that consumer side.
|
|
67
|
+
- `npm run reports:check` installs the package into a temporary minimal project and runs the report gallery's `doctor`, `summary`, and blocked-command examples through that consumer side.
|
|
66
68
|
- `npm run promo:card` regenerates the deterministic social preview card, and `npm run promo:check` verifies current repo-local promo assets against the current fixture evidence before maintainers post or refresh the demo.
|
|
67
69
|
- `npm run site:check` verifies the static landing page before maintainers post or host it.
|
|
68
70
|
- npm publish has a manual workflow fallback, but the normal release path is tag-driven trusted publishing.
|
|
@@ -84,6 +86,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
|
|
|
84
86
|
- framework tuning cookbook doctor checks are wired into `npm test`.
|
|
85
87
|
- CI adoption example checks are wired into `npm test`.
|
|
86
88
|
- consumer quickstart smoke checks are wired into `npm test`.
|
|
89
|
+
- report gallery checks are wired into `npm test`.
|
|
87
90
|
- promo freshness checks are wired into `npm test`.
|
|
88
91
|
- site checks are wired into `npm test`.
|
|
89
92
|
|
package/docs/RELEASE.md
CHANGED
|
@@ -16,6 +16,7 @@ npm.cmd run framework:tuning:check
|
|
|
16
16
|
npm.cmd run framework:tuning:doctor
|
|
17
17
|
npm.cmd run ci:adoption:check
|
|
18
18
|
npm.cmd run consumer:quickstart:check
|
|
19
|
+
npm.cmd run reports:check
|
|
19
20
|
npm.cmd run promo:card:check
|
|
20
21
|
npm.cmd run promo:check
|
|
21
22
|
npm.cmd run site:check
|
|
@@ -28,7 +29,7 @@ Move the current changelog bullets into a matching version section and add `docs
|
|
|
28
29
|
## 2. Tag And Push
|
|
29
30
|
|
|
30
31
|
```powershell
|
|
31
|
-
git add package.json package-lock.json CHANGELOG.md docs/RELEASE_NOTES_v0.1.x.md docs/PRODUCTION_READINESS.md docs/MAINTAINER_TRIAGE.md docs/FRAMEWORK_TUNING.md docs/GITHUB_ACTIONS.md examples/ci examples/consumer-quickstart examples/tuning scripts/check-ci-adoption.mjs scripts/check-consumer-quickstart.mjs scripts/check-framework-tuning.mjs scripts/doctor-framework-tuning.mjs SECURITY.md .github/ISSUE_TEMPLATE
|
|
32
|
+
git add package.json package-lock.json CHANGELOG.md docs/RELEASE_NOTES_v0.1.x.md docs/PRODUCTION_READINESS.md docs/MAINTAINER_TRIAGE.md docs/FRAMEWORK_TUNING.md docs/GITHUB_ACTIONS.md examples/ci examples/consumer-quickstart examples/reports examples/tuning scripts/check-ci-adoption.mjs scripts/check-consumer-quickstart.mjs scripts/check-report-gallery.mjs scripts/check-framework-tuning.mjs scripts/doctor-framework-tuning.mjs SECURITY.md .github/ISSUE_TEMPLATE
|
|
32
33
|
git commit -m "Release v0.1.x"
|
|
33
34
|
git tag -a v0.1.x -m "Memento Mori Jester v0.1.x"
|
|
34
35
|
git push origin main
|
|
@@ -85,6 +86,7 @@ npx.cmd -y memento-mori-jester@latest config validate --config jester-ai.config.
|
|
|
85
86
|
npx.cmd -y memento-mori-jester@latest config init --preset security --path jester-security.config.json
|
|
86
87
|
npx.cmd -y memento-mori-jester@latest config validate --config jester-security.config.json
|
|
87
88
|
npm.cmd run consumer:quickstart:check -- --package memento-mori-jester@latest
|
|
89
|
+
npm.cmd run reports:check -- --package memento-mori-jester@latest
|
|
88
90
|
```
|
|
89
91
|
|
|
90
92
|
## 4. MCP Copy-Paste
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Memento Mori Jester v0.1.88
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
This release adds a small checked report gallery. The goal is to make the project easier to trust from concrete public examples without changing rule behavior: a fresh `doctor` report, a destructive-command `summary`, and a full blocked command review.
|
|
6
|
+
|
|
7
|
+
## What Changed
|
|
8
|
+
|
|
9
|
+
- Added `examples/reports/report-gallery.json`.
|
|
10
|
+
- Added `examples/reports/README.md`.
|
|
11
|
+
- Added `scripts/check-report-gallery.mjs`.
|
|
12
|
+
- Added `npm run reports:check`.
|
|
13
|
+
- Wired the report gallery checker into `npm test` and production-readiness checks.
|
|
14
|
+
- Updated README, getting-started docs, maintainer triage docs, release docs, production-readiness docs, roadmap, and changelog.
|
|
15
|
+
|
|
16
|
+
## Public Interface
|
|
17
|
+
|
|
18
|
+
- No CLI command changes.
|
|
19
|
+
- No MCP tool changes.
|
|
20
|
+
- No config schema changes.
|
|
21
|
+
- No review rule, scoring, matching, or verdict behavior changes.
|
|
22
|
+
- No GitHub Action input changes.
|
|
23
|
+
- New maintainer/package script: `npm run reports:check`.
|
|
24
|
+
- New checked example gallery: `examples/reports`.
|
|
25
|
+
|
|
26
|
+
## Release Validation
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
npm.cmd test
|
|
30
|
+
npm.cmd run reports:check
|
|
31
|
+
npm.cmd run reports:check -- --package memento-mori-jester@latest
|
|
32
|
+
npm.cmd run demo:svg:check
|
|
33
|
+
npm.cmd run promo:card:check
|
|
34
|
+
npm.cmd run promo:check
|
|
35
|
+
npm.cmd run fixtures:report
|
|
36
|
+
npm.cmd run fixtures:report -- --json
|
|
37
|
+
npm.cmd run fixtures:report -- --markdown
|
|
38
|
+
npm.cmd run pack:dry
|
|
39
|
+
git diff --check
|
|
40
|
+
node .\dist\cli.js doctor
|
|
41
|
+
node .\dist\cli.js summary --kind command "git reset --hard"
|
|
42
|
+
node .\dist\cli.js command "git reset --hard"
|
|
43
|
+
git diff | node .\dist\cli.js diff --fail-on block --subject "v0.1.88 checked report gallery"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Expected:
|
|
47
|
+
|
|
48
|
+
- `reports:check` installs the package into a temporary minimal project,
|
|
49
|
+
- `fresh-install-doctor` passes against installed `jester doctor`,
|
|
50
|
+
- `destructive-command-summary` passes against installed `jester summary --kind command "git reset --hard"`,
|
|
51
|
+
- `blocked-command-review` passes against installed `jester command "git reset --hard"`,
|
|
52
|
+
- fixture report still shows `Fixtures: 222`,
|
|
53
|
+
- GitHub Release and npm Publish complete from the `v0.1.88` tag.
|
|
54
|
+
|
|
55
|
+
After publish:
|
|
56
|
+
|
|
57
|
+
```powershell
|
|
58
|
+
npm.cmd view memento-mori-jester version --silent
|
|
59
|
+
npx.cmd -y memento-mori-jester@latest doctor
|
|
60
|
+
npx.cmd -y memento-mori-jester@latest summary --kind command "git reset --hard"
|
|
61
|
+
npm.cmd run reports:check -- --package memento-mori-jester@latest
|
|
62
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Real-World Report Gallery
|
|
2
|
+
|
|
3
|
+
These small examples show the first reports people tend to trust when trying Memento Mori Jester in a fresh project. They are public, synthetic, and intentionally boring: no private code, no tokens, no customer data, and no full CI logs.
|
|
4
|
+
|
|
5
|
+
The machine-readable source is [report-gallery.json](report-gallery.json). It is checked by `npm run reports:check`, which installs Memento Mori Jester into a temporary consumer project and runs each command through that installed package.
|
|
6
|
+
|
|
7
|
+
| ID | Report | Command | What It Proves |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| `fresh-install-doctor` | Fresh install health check | `jester doctor` | The package, runtime, MCP file, review engine, config, hook, and workflow diagnostics are visible. |
|
|
10
|
+
| `destructive-command-summary` | Readable summary for a destructive command | `jester summary --kind command "git reset --hard"` | A compact report shows the block verdict, rule hit, and next tuning commands. |
|
|
11
|
+
| `blocked-command-review` | Full blocked command review | `jester command "git reset --hard"` | The full command review blocks the risky operation and explains the safer check. |
|
|
12
|
+
|
|
13
|
+
Run the checker from the repo root:
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
npm run reports:check
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
After publishing, verify the same gallery against the public package:
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
npm run reports:check -- --package memento-mori-jester@latest
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
When turning a real issue into a gallery entry, keep the example minimal and redacted. If the report needs private context, route it through [SECURITY.md](../../SECURITY.md) or keep it out of the public repo.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "fresh-install-doctor",
|
|
4
|
+
"title": "Fresh install health check",
|
|
5
|
+
"scenario": "A new repo wants to confirm the package, Node runtime, MCP server file, review engine, config discovery, hooks, and generated workflow checks are visible.",
|
|
6
|
+
"command": "jester doctor",
|
|
7
|
+
"args": ["doctor"],
|
|
8
|
+
"expected": {
|
|
9
|
+
"includes": [
|
|
10
|
+
"Memento Mori Jester doctor",
|
|
11
|
+
"PASS package-version",
|
|
12
|
+
"PASS review-engine: Dangerous git command is blocked.",
|
|
13
|
+
"The fool is fit for court."
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "destructive-command-summary",
|
|
19
|
+
"title": "Readable summary for a destructive command",
|
|
20
|
+
"scenario": "A team wants a compact CI-friendly report showing which rule fired before enabling stricter workflow failure behavior.",
|
|
21
|
+
"command": "jester summary --kind command \"git reset --hard\"",
|
|
22
|
+
"args": ["summary", "--kind", "command", "git reset --hard"],
|
|
23
|
+
"expected": {
|
|
24
|
+
"includes": [
|
|
25
|
+
"Memento Mori Jester summary",
|
|
26
|
+
"Verdict: BLOCK",
|
|
27
|
+
"destructive-git-history",
|
|
28
|
+
"Suggested next:"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "blocked-command-review",
|
|
34
|
+
"title": "Full blocked command review",
|
|
35
|
+
"scenario": "A developer or agent is about to run a destructive git command and needs the full review text before proceeding.",
|
|
36
|
+
"command": "jester command \"git reset --hard\"",
|
|
37
|
+
"args": ["command", "git reset --hard"],
|
|
38
|
+
"expected": {
|
|
39
|
+
"includes": [
|
|
40
|
+
"Jester verdict: BLOCK",
|
|
41
|
+
"Destructive git operation",
|
|
42
|
+
"git reset --hard",
|
|
43
|
+
"Inspect `git status`"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memento-mori-jester",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.88",
|
|
4
4
|
"description": "A local court-jester sidecar for AI coding agents: review plans, commands, diffs, and final claims before they get too pleased with themselves.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"build": "tsc -p tsconfig.json",
|
|
41
41
|
"start": "node dist/server.js",
|
|
42
42
|
"start:mcp": "node dist/server.js",
|
|
43
|
-
"test": "npm run build && node scripts/run-tests.mjs && npm run fixtures:check && npm run fixtures:report && npm run framework:tuning:check && npm run framework:tuning:doctor && npm run ci:adoption:check && npm run consumer:quickstart:check && npm run promo:check && npm run site:check && npm run production:check",
|
|
43
|
+
"test": "npm run build && node scripts/run-tests.mjs && npm run fixtures:check && npm run fixtures:report && npm run framework:tuning:check && npm run framework:tuning:doctor && npm run ci:adoption:check && npm run consumer:quickstart:check && npm run reports:check && npm run promo:check && npm run site:check && npm run production:check",
|
|
44
44
|
"doctor": "node dist/cli.js doctor",
|
|
45
45
|
"demo:svg": "node scripts/render-demo-svg.mjs",
|
|
46
46
|
"demo:svg:check": "node scripts/render-demo-svg.mjs --check",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"framework:tuning:doctor": "node scripts/doctor-framework-tuning.mjs",
|
|
51
51
|
"ci:adoption:check": "node scripts/check-ci-adoption.mjs",
|
|
52
52
|
"consumer:quickstart:check": "node scripts/check-consumer-quickstart.mjs",
|
|
53
|
+
"reports:check": "node scripts/check-report-gallery.mjs",
|
|
53
54
|
"promo:card": "node scripts/render-social-card.mjs",
|
|
54
55
|
"promo:card:check": "node scripts/render-social-card.mjs --check",
|
|
55
56
|
"promo:check": "node scripts/check-promo-freshness.mjs",
|
|
@@ -72,6 +72,7 @@ for (const path of [
|
|
|
72
72
|
"scripts/doctor-framework-tuning.mjs",
|
|
73
73
|
"scripts/check-ci-adoption.mjs",
|
|
74
74
|
"scripts/check-consumer-quickstart.mjs",
|
|
75
|
+
"scripts/check-report-gallery.mjs",
|
|
75
76
|
"scripts/check-fixtures.mjs",
|
|
76
77
|
"scripts/report-fixtures.mjs",
|
|
77
78
|
".github/ISSUE_TEMPLATE/bug_report.yml",
|
|
@@ -87,6 +88,8 @@ for (const path of [
|
|
|
87
88
|
"examples/ci/adoption-smoke.yml",
|
|
88
89
|
"examples/consumer-quickstart/README.md",
|
|
89
90
|
"examples/consumer-quickstart/package.json",
|
|
91
|
+
"examples/reports/README.md",
|
|
92
|
+
"examples/reports/report-gallery.json",
|
|
90
93
|
"examples/presets/README.md",
|
|
91
94
|
"examples/tuning/README.md",
|
|
92
95
|
"examples/tuning/framework-tuning-cookbook.json",
|
|
@@ -113,6 +116,7 @@ requireText("README.md", /FRAMEWORK_TUNING\.md/, "framework tuning guide link");
|
|
|
113
116
|
requireText("README.md", /examples\/tuning/, "framework tuning cookbook link");
|
|
114
117
|
requireText("README.md", /adoption-smoke\.yml/, "adoption smoke CI link");
|
|
115
118
|
requireText("README.md", /consumer-quickstart/, "consumer quickstart smoke link");
|
|
119
|
+
requireText("README.md", /examples\/reports/, "report gallery link");
|
|
116
120
|
requireText("README.md", /License: PolyForm Noncommercial/, "the noncommercial license badge");
|
|
117
121
|
requireText("docs/PRODUCTION_READINESS.md", /npm package/i, "npm package readiness");
|
|
118
122
|
requireText("docs/PRODUCTION_READINESS.md", /GitHub Action/i, "GitHub Action readiness");
|
|
@@ -130,6 +134,7 @@ requireText("docs/PRODUCTION_READINESS.md", /framework:tuning:check/, "framework
|
|
|
130
134
|
requireText("docs/PRODUCTION_READINESS.md", /framework:tuning:doctor/, "framework tuning cookbook doctor readiness");
|
|
131
135
|
requireText("docs/PRODUCTION_READINESS.md", /adoption-smoke\.yml/, "adoption smoke CI readiness");
|
|
132
136
|
requireText("docs/PRODUCTION_READINESS.md", /consumer:quickstart:check/, "consumer quickstart smoke readiness");
|
|
137
|
+
requireText("docs/PRODUCTION_READINESS.md", /reports:check/, "report gallery readiness");
|
|
133
138
|
requireText("docs/PRODUCTION_READINESS.md", /quiet-pass/, "quiet-pass fixture readiness");
|
|
134
139
|
requireText("docs/CLI.md", /jester doctor --json/, "doctor JSON CLI docs");
|
|
135
140
|
requireText("docs/CLI.md", /quiet-pass fixture/, "quiet-pass fixture CLI docs");
|
|
@@ -164,6 +169,11 @@ requireText("examples/ci/adoption-smoke.yml", /framework:tuning:doctor/, "adopti
|
|
|
164
169
|
requireText("examples/consumer-quickstart/README.md", /npm run consumer:quickstart:check/, "consumer quickstart check command");
|
|
165
170
|
requireText("examples/consumer-quickstart/package.json", /jester:summary/, "consumer quickstart summary script");
|
|
166
171
|
requireText("examples/consumer-quickstart/package.json", /framework:tuning:doctor/, "consumer quickstart tuning doctor script");
|
|
172
|
+
requireText("examples/reports/README.md", /report-gallery\.json/, "report gallery JSON link");
|
|
173
|
+
requireText("examples/reports/README.md", /npm run reports:check/, "report gallery check command");
|
|
174
|
+
requireText("examples/reports/report-gallery.json", /fresh-install-doctor/, "fresh install doctor report");
|
|
175
|
+
requireText("examples/reports/report-gallery.json", /destructive-command-summary/, "destructive command summary report");
|
|
176
|
+
requireText("examples/reports/report-gallery.json", /blocked-command-review/, "blocked command review report");
|
|
167
177
|
requireText("examples/tuning/README.md", /framework-tuning-cookbook\.json/, "framework tuning cookbook JSON link");
|
|
168
178
|
requireText("examples/tuning/README.md", /framework:tuning:doctor/, "framework tuning doctor guidance");
|
|
169
179
|
requireText("examples/tuning/README.md", /jester tune <rule-id> --json|jester tune [a-z0-9-]+ --json/, "framework tuning command guidance");
|
|
@@ -191,12 +201,16 @@ requireText("scripts/check-ci-adoption.mjs", /framework:tuning:doctor/, "adoptio
|
|
|
191
201
|
requireText("scripts/check-consumer-quickstart.mjs", /consumer-quickstart/, "consumer quickstart checker target");
|
|
192
202
|
requireText("scripts/check-consumer-quickstart.mjs", /memento-mori-jester@latest/, "consumer quickstart registry verification option");
|
|
193
203
|
requireText("scripts/check-consumer-quickstart.mjs", /framework:tuning:doctor/, "consumer quickstart tuning doctor guard");
|
|
204
|
+
requireText("scripts/check-report-gallery.mjs", /report-gallery\.json/, "report gallery checker target");
|
|
205
|
+
requireText("scripts/check-report-gallery.mjs", /memento-mori-jester@latest/, "report gallery registry verification option");
|
|
206
|
+
requireText("scripts/check-report-gallery.mjs", /destructive-command-summary/, "report gallery summary guard");
|
|
194
207
|
requireText("package.json", /"fixtures:check": "node scripts\/check-fixtures\.mjs"/, "fixture authoring check script");
|
|
195
208
|
requireText("package.json", /"fixtures:report": "node scripts\/report-fixtures\.mjs"/, "fixture coverage report script");
|
|
196
209
|
requireText("package.json", /"framework:tuning:check": "node scripts\/check-framework-tuning\.mjs"/, "framework tuning cookbook check script");
|
|
197
210
|
requireText("package.json", /"framework:tuning:doctor": "node scripts\/doctor-framework-tuning\.mjs"/, "framework tuning cookbook doctor script");
|
|
198
211
|
requireText("package.json", /"ci:adoption:check": "node scripts\/check-ci-adoption\.mjs"/, "CI adoption check script");
|
|
199
212
|
requireText("package.json", /"consumer:quickstart:check": "node scripts\/check-consumer-quickstart\.mjs"/, "consumer quickstart check script");
|
|
213
|
+
requireText("package.json", /"reports:check": "node scripts\/check-report-gallery\.mjs"/, "report gallery check script");
|
|
200
214
|
requireText("package.json", /"promo:card": "node scripts\/render-social-card\.mjs"/, "social card render script");
|
|
201
215
|
requireText("package.json", /"promo:card:check": "node scripts\/render-social-card\.mjs --check"/, "social card stale check script");
|
|
202
216
|
requireText("package.json", /"promo:check": "node scripts\/check-promo-freshness\.mjs"/, "promo freshness check script");
|
|
@@ -207,6 +221,7 @@ requireText("package.json", /npm run framework:tuning:check/, "framework tuning
|
|
|
207
221
|
requireText("package.json", /npm run framework:tuning:doctor/, "framework tuning cookbook doctor in npm test");
|
|
208
222
|
requireText("package.json", /npm run ci:adoption:check/, "CI adoption check in npm test");
|
|
209
223
|
requireText("package.json", /npm run consumer:quickstart:check/, "consumer quickstart check in npm test");
|
|
224
|
+
requireText("package.json", /npm run reports:check/, "report gallery check in npm test");
|
|
210
225
|
requireText("package.json", /npm run promo:check/, "promo freshness check in npm test");
|
|
211
226
|
requireText("package.json", /npm run site:check/, "site check in npm test");
|
|
212
227
|
requireText("scripts/check-promo-freshness.mjs", /--require-package-version/, "optional strict package-version promo check");
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const root = join(scriptDir, "..");
|
|
10
|
+
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
11
|
+
const npmExecPath = process.env.npm_execpath;
|
|
12
|
+
const galleryPath = join(root, "examples", "reports", "report-gallery.json");
|
|
13
|
+
const readmePath = join(root, "examples", "reports", "README.md");
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
|
|
16
|
+
process.on("uncaughtException", (error) => {
|
|
17
|
+
console.error("Report gallery check failed:");
|
|
18
|
+
console.error(`- ${error instanceof Error ? error.message : String(error)}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
let requestedPackageSpec = null;
|
|
23
|
+
let keepTemp = false;
|
|
24
|
+
|
|
25
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
26
|
+
const arg = args[index];
|
|
27
|
+
if (arg === "--package" || arg === "--package-spec") {
|
|
28
|
+
requestedPackageSpec = args[index + 1];
|
|
29
|
+
index += 1;
|
|
30
|
+
} else if (arg === "--registry-latest") {
|
|
31
|
+
requestedPackageSpec = "memento-mori-jester@latest";
|
|
32
|
+
} else if (arg === "--keep-temp") {
|
|
33
|
+
keepTemp = true;
|
|
34
|
+
} else {
|
|
35
|
+
fail(`Unknown option: ${arg}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (requestedPackageSpec === "") {
|
|
40
|
+
fail("--package requires a non-empty npm package spec.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const unsafeContentPatterns = [
|
|
44
|
+
{ name: "private key block", pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
|
|
45
|
+
{ name: "OpenAI-looking secret key", pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b/ },
|
|
46
|
+
{ name: "Anthropic-looking secret key", pattern: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/ },
|
|
47
|
+
{ name: "GitHub-looking token", pattern: /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/ },
|
|
48
|
+
{ name: "AWS access key id", pattern: /\bAKIA[0-9A-Z]{16}\b/ },
|
|
49
|
+
{ name: "Slack-looking token", pattern: /\bxox[baprs]-[A-Za-z0-9-]{20,}\b/ },
|
|
50
|
+
{ name: "absolute Unix home path", pattern: /(?:^|[\s"'`])\/(?:Users|home)\/[A-Za-z0-9._-]+/ },
|
|
51
|
+
{ name: "absolute Windows user path", pattern: /[A-Za-z]:\\Users\\[A-Za-z0-9._-]+\\/ }
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const gallery = readGallery();
|
|
55
|
+
checkReadme(gallery);
|
|
56
|
+
|
|
57
|
+
const tempRoot = mkdtempSync(join(tmpdir(), "jester-report-gallery-"));
|
|
58
|
+
let packageSpec = requestedPackageSpec;
|
|
59
|
+
const packageLabel = requestedPackageSpec ?? "local packed package";
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
if (!packageSpec) {
|
|
63
|
+
packageSpec = packLocalPackage(tempRoot);
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const consumerDir = join(tempRoot, "consumer-project");
|
|
72
|
+
prepareConsumerProject(consumerDir, packageSpec);
|
|
73
|
+
|
|
74
|
+
const results = [];
|
|
75
|
+
for (const report of gallery) {
|
|
76
|
+
const output = runNpm(["exec", "--", "jester", ...report.args], { cwd: consumerDir });
|
|
77
|
+
for (const expected of report.expected.includes) {
|
|
78
|
+
if (!output.includes(expected)) {
|
|
79
|
+
fail(`${report.id} output should include ${expected}. Output was:\n${output}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
results.push(report.id);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log("Report gallery check");
|
|
86
|
+
console.log(`PASS installed ${packageLabel}`);
|
|
87
|
+
for (const id of results) {
|
|
88
|
+
console.log(`PASS ${id}`);
|
|
89
|
+
}
|
|
90
|
+
} finally {
|
|
91
|
+
if (keepTemp) {
|
|
92
|
+
console.log(`Kept temp project at ${tempRoot}`);
|
|
93
|
+
} else {
|
|
94
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function readGallery() {
|
|
99
|
+
if (!existsSync(galleryPath)) {
|
|
100
|
+
fail("examples/reports/report-gallery.json is missing.");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!existsSync(readmePath)) {
|
|
104
|
+
fail("examples/reports/README.md is missing.");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const galleryRaw = readFileSync(galleryPath, "utf8");
|
|
108
|
+
const readme = readFileSync(readmePath, "utf8");
|
|
109
|
+
|
|
110
|
+
for (const [path, content] of [
|
|
111
|
+
["examples/reports/report-gallery.json", galleryRaw],
|
|
112
|
+
["examples/reports/README.md", readme]
|
|
113
|
+
]) {
|
|
114
|
+
for (const unsafe of unsafeContentPatterns) {
|
|
115
|
+
if (unsafe.pattern.test(content)) {
|
|
116
|
+
fail(`${path} appears to contain ${unsafe.name}; report examples should stay public and redacted.`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let parsed;
|
|
122
|
+
try {
|
|
123
|
+
parsed = JSON.parse(galleryRaw);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
fail(`examples/reports/report-gallery.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!Array.isArray(parsed) || parsed.length !== 3) {
|
|
129
|
+
fail("examples/reports/report-gallery.json should contain exactly three report examples.");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const expectedIds = ["fresh-install-doctor", "destructive-command-summary", "blocked-command-review"];
|
|
133
|
+
const seenIds = new Set();
|
|
134
|
+
|
|
135
|
+
for (const [index, report] of parsed.entries()) {
|
|
136
|
+
const expectedId = expectedIds[index];
|
|
137
|
+
if (report?.id !== expectedId) {
|
|
138
|
+
fail(`Report ${index + 1} should have id ${expectedId}.`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (seenIds.has(report.id)) {
|
|
142
|
+
fail(`Duplicate report id: ${report.id}.`);
|
|
143
|
+
}
|
|
144
|
+
seenIds.add(report.id);
|
|
145
|
+
|
|
146
|
+
for (const field of ["title", "scenario", "command"]) {
|
|
147
|
+
if (typeof report[field] !== "string" || report[field].trim().length < 10) {
|
|
148
|
+
fail(`${report.id}.${field} should be a useful string.`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!Array.isArray(report.args) || report.args.length === 0 || report.args.some((arg) => typeof arg !== "string")) {
|
|
153
|
+
fail(`${report.id}.args should be a non-empty string array.`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!Array.isArray(report.expected?.includes) || report.expected.includes.length < 3) {
|
|
157
|
+
fail(`${report.id}.expected.includes should contain at least three stable output fragments.`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return parsed;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function checkReadme(gallery) {
|
|
165
|
+
const readme = readFileSync(readmePath, "utf8");
|
|
166
|
+
|
|
167
|
+
for (const report of gallery) {
|
|
168
|
+
for (const expected of [report.id, report.command]) {
|
|
169
|
+
if (!readme.includes(expected)) {
|
|
170
|
+
fail(`examples/reports/README.md should include ${expected}.`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
for (const expected of [
|
|
176
|
+
"npm run reports:check",
|
|
177
|
+
"memento-mori-jester@latest",
|
|
178
|
+
"SECURITY.md"
|
|
179
|
+
]) {
|
|
180
|
+
if (!readme.includes(expected)) {
|
|
181
|
+
fail(`examples/reports/README.md should include ${expected}.`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function packLocalPackage(destination) {
|
|
187
|
+
const cliPath = join(root, "dist", "cli.js");
|
|
188
|
+
if (!existsSync(cliPath)) {
|
|
189
|
+
fail(`${cliPath} is missing. Run npm run build before npm run reports:check.`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const output = runNpm(["pack", "--ignore-scripts", "--pack-destination", destination, "--silent"], { cwd: root });
|
|
193
|
+
const filename = output.trim().split(/\r?\n/).filter(Boolean).at(-1);
|
|
194
|
+
if (!filename) {
|
|
195
|
+
fail("npm pack did not return a tarball filename.");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return isAbsolute(filename) ? filename : resolve(destination, filename);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function prepareConsumerProject(consumerDir, spec) {
|
|
202
|
+
rmSync(consumerDir, { recursive: true, force: true });
|
|
203
|
+
mkdirSync(consumerDir, { recursive: true });
|
|
204
|
+
writeFileSync(
|
|
205
|
+
join(consumerDir, "package.json"),
|
|
206
|
+
`${JSON.stringify({ name: "jester-report-gallery-consumer", version: "0.0.0", private: true }, null, 2)}\n`
|
|
207
|
+
);
|
|
208
|
+
runNpm(["install", "--save-dev", spec, "--ignore-scripts", "--no-audit", "--no-fund"], { cwd: consumerDir });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function runNpm(commandArgs, options = {}) {
|
|
212
|
+
if (npmExecPath) {
|
|
213
|
+
return run(process.execPath, [npmExecPath, ...commandArgs], options);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return run(npmCommand, commandArgs, options);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function run(command, commandArgs, options = {}) {
|
|
220
|
+
const result = spawnSync(command, commandArgs, {
|
|
221
|
+
cwd: options.cwd ?? root,
|
|
222
|
+
encoding: "utf8",
|
|
223
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
224
|
+
env: {
|
|
225
|
+
...process.env,
|
|
226
|
+
npm_config_audit: "false",
|
|
227
|
+
npm_config_fund: "false"
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
if (result.error) {
|
|
232
|
+
throw result.error;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (result.status !== 0) {
|
|
236
|
+
const detail = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
237
|
+
fail(`${command} ${commandArgs.join(" ")} failed${detail ? `:\n${detail}` : "."}`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return result.stdout;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function fail(message) {
|
|
244
|
+
throw new Error(message);
|
|
245
|
+
}
|