memento-mori-jester 0.1.79 → 0.1.80

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 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.80
8
+
9
+ - Added a deterministic `promo/share-kit/social-card.svg` for GitHub, X, and project-update link previews.
10
+ - Added `npm run promo:card` and `npm run promo:card:check` to regenerate or verify the social card.
11
+ - Extended promo freshness checks and docs so the social card stays part of the maintainer release flow.
12
+
7
13
  ## 0.1.79
8
14
 
9
15
  - Added `npm run promo:check` to verify the current repo-local promo video, stills, docs, and fixture evidence numbers stay aligned.
package/README.md CHANGED
@@ -503,6 +503,7 @@ Use the false-positive template for noisy cautions or blocks. Include `jester su
503
503
  Maintainers can use [docs/MAINTAINER_TRIAGE.md](docs/MAINTAINER_TRIAGE.md) to turn useful false-positive reports into redacted fixtures.
504
504
  Run `npm run fixtures:check` before merging fixture changes; it catches duplicate IDs, missing rule metadata, weak descriptions, unsafe-looking content, and duplicate content.
505
505
  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.
506
+ Run `npm run promo:card` to regenerate the repo-local social preview card after changing its copy or design.
506
507
  Run `npm run promo:check` after editing promo assets; it checks the current demo video, stills, docs, and fixture evidence numbers stay in sync.
507
508
 
508
509
  For vulnerabilities, private code exposure, or credential-handling concerns, follow [SECURITY.md](SECURITY.md) instead of opening a public issue with sensitive details.
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
+ - Social preview card in v0.1.80, adding a deterministic 1200x630 promo card plus generation and freshness checks.
9
10
  - Promo freshness check in v0.1.79, verifying the current demo video, share-kit stills, docs, and fixture evidence numbers before public posting.
10
11
  - Fresh demo render in v0.1.78, updating the repo-local X video and share-kit stills to current version and fixture totals.
11
12
  - Promo/share kit in v0.1.77, adding X post copy, a short demo script, a posting checklist, and still images from the existing demo video.
@@ -70,7 +71,7 @@ Memento Mori Jester is usable today as a CLI, MCP server, GitHub Action, and git
70
71
 
71
72
  - Collect real-world reports for the next lowest-count preset slices now highlighted by `fixtures:report`.
72
73
  - Add more framework-specific false-positive examples from real reports so tuning guidance keeps getting sharper.
73
- - Add a lightweight social preview card or landing-page still for GitHub and X link previews.
74
+ - Add a small web landing page that reuses the existing demo, social card, and start command.
74
75
 
75
76
  ## Quality And Safety
76
77
 
@@ -9,7 +9,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
9
9
  - GitHub Releases and npm publishing are automated from annotated `v*` tags through GitHub Actions trusted publishing.
10
10
  - CI runs tests and a package dry run on every push to `main` and pull request.
11
11
  - The local playground, GitHub Action, MCP setup snippets, preset examples, fixtures, and release notes ship in the npm package.
12
- - Repo-local promo assets stay outside the npm package, but `npm run promo:check` keeps the current demo video, stills, docs, and fixture evidence numbers aligned.
12
+ - Repo-local promo assets stay outside the npm package, but `npm run promo:check` keeps the current demo video, stills, social card, docs, and fixture evidence numbers aligned.
13
13
 
14
14
  ## npm Package
15
15
 
@@ -55,7 +55,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
55
55
  - `docs/MAINTAINER_TRIAGE.md` explains how to turn useful false-positive reports into fixture coverage before changing rule logic.
56
56
  - `npm run fixtures:check` validates fixture IDs, metadata, unsafe-looking content, duplicate content, and explicit expected/absent rule intent.
57
57
  - `npm run fixtures:report` shows fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass rule boundaries, and feasible pass-case gaps so maintainers can pick the next fixture target; `npm run fixtures:report -- --markdown` produces a paste-ready maintainer snapshot.
58
- - `npm run promo:check` verifies current repo-local promo assets against the current fixture evidence before maintainers post or refresh the demo.
58
+ - `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.
59
59
  - npm publish has a manual workflow fallback, but the normal release path is tag-driven trusted publishing.
60
60
 
61
61
  ## Static Guard
package/docs/RELEASE.md CHANGED
@@ -12,6 +12,7 @@ npm.cmd run fixtures:check
12
12
  npm.cmd run fixtures:report
13
13
  npm.cmd run fixtures:report -- --json
14
14
  npm.cmd run fixtures:report -- --markdown
15
+ npm.cmd run promo:card:check
15
16
  npm.cmd run promo:check
16
17
  npm.cmd run pack:dry
17
18
  git diff --check
@@ -0,0 +1,40 @@
1
+ # Memento Mori Jester v0.1.80
2
+
3
+ ## Summary
4
+
5
+ This release adds a deterministic social preview card for GitHub, X, and project-update links. It keeps the promo work local and reviewable while making shared links look intentional.
6
+
7
+ ## What Changed
8
+
9
+ - Added `promo/share-kit/social-card.svg`.
10
+ - Added `scripts/render-social-card.mjs`.
11
+ - Added `npm run promo:card` and `npm run promo:card:check`.
12
+ - Extended `npm run promo:check` to verify the social card exists, has 1200x630 dimensions, includes the product name, and includes the `npx` start command.
13
+ - Updated promo docs, release docs, production-readiness docs, roadmap, changelog, and release notes.
14
+
15
+ ## Public Interface
16
+
17
+ - No CLI command changes.
18
+ - No MCP tool changes.
19
+ - No config schema changes.
20
+ - No review rule, scoring, or verdict behavior changes.
21
+ - No GitHub Action behavior changes.
22
+ - `promo/` remains outside the npm package `files` list.
23
+
24
+ ## Release Validation
25
+
26
+ ```powershell
27
+ npm.cmd test
28
+ npm.cmd run demo:svg:check
29
+ npm.cmd run promo:card:check
30
+ npm.cmd run promo:check
31
+ npm.cmd run pack:dry
32
+ git diff --check
33
+ git diff | node .\dist\cli.js diff --fail-on block --subject "v0.1.80 social preview card"
34
+ ```
35
+
36
+ Expected:
37
+
38
+ - `promo/share-kit/social-card.svg` is deterministic and current,
39
+ - default `promo:check` includes social-card validation,
40
+ - GitHub Release and npm Publish complete from the `v0.1.80` tag.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memento-mori-jester",
3
- "version": "0.1.79",
3
+ "version": "0.1.80",
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": {
@@ -46,6 +46,8 @@
46
46
  "demo:svg:check": "node scripts/render-demo-svg.mjs --check",
47
47
  "fixtures:check": "node scripts/check-fixtures.mjs",
48
48
  "fixtures:report": "node scripts/report-fixtures.mjs",
49
+ "promo:card": "node scripts/render-social-card.mjs",
50
+ "promo:card:check": "node scripts/render-social-card.mjs --check",
49
51
  "promo:check": "node scripts/check-promo-freshness.mjs",
50
52
  "production:check": "node scripts/check-production-readiness.mjs",
51
53
  "pack:dry": "npm pack --dry-run",
@@ -65,6 +65,7 @@ for (const path of [
65
65
  `docs/RELEASE_NOTES_${tag}.md`,
66
66
  "action.yml",
67
67
  "scripts/check-promo-freshness.mjs",
68
+ "scripts/render-social-card.mjs",
68
69
  "scripts/check-fixtures.mjs",
69
70
  "scripts/report-fixtures.mjs",
70
71
  ".github/ISSUE_TEMPLATE/bug_report.yml",
@@ -133,11 +134,14 @@ requireText("scripts/report-fixtures.mjs", /--markdown/, "Markdown fixture repor
133
134
  forbidText("scripts/report-fixtures.mjs", /src\/config\.ts|src\/types\.ts/, "source-only fixture report dependencies");
134
135
  requireText("package.json", /"fixtures:check": "node scripts\/check-fixtures\.mjs"/, "fixture authoring check script");
135
136
  requireText("package.json", /"fixtures:report": "node scripts\/report-fixtures\.mjs"/, "fixture coverage report script");
137
+ requireText("package.json", /"promo:card": "node scripts\/render-social-card\.mjs"/, "social card render script");
138
+ requireText("package.json", /"promo:card:check": "node scripts\/render-social-card\.mjs --check"/, "social card stale check script");
136
139
  requireText("package.json", /"promo:check": "node scripts\/check-promo-freshness\.mjs"/, "promo freshness check script");
137
140
  requireText("package.json", /npm run fixtures:check/, "fixture authoring check in npm test");
138
141
  requireText("package.json", /npm run fixtures:report/, "fixture coverage report in npm test");
139
142
  requireText("package.json", /npm run promo:check/, "promo freshness check in npm test");
140
143
  requireText("scripts/check-promo-freshness.mjs", /--require-package-version/, "optional strict package-version promo check");
144
+ requireText("scripts/check-promo-freshness.mjs", /social-card\.svg/, "social-card freshness check");
141
145
  requireText("SECURITY.md", /doctor --json/, "doctor JSON redaction guidance");
142
146
  requireText("SECURITY.md", /security\/advisories\/new/, "private vulnerability report link");
143
147
  requireText(".github/ISSUE_TEMPLATE/bug_report.yml", /doctor --json/, "doctor JSON support prompt");
@@ -117,6 +117,7 @@ const demoDir = `promo/${demoId}`;
117
117
  const demoVideoPath = linkedTarget ? `promo/${linkedTarget}` : "";
118
118
  const fixtureTotal = Array.isArray(fixtures) ? fixtures.length : 0;
119
119
  const riskyEvidence = loadRiskyDomainEvidence();
120
+ const socialCardPath = "promo/share-kit/social-card.svg";
120
121
 
121
122
  if (requirePackageVersion && packageJson.version !== promoVersion) {
122
123
  failures.push(`Current promo version v${promoVersion} should match package.json ${packageJson.version} when --require-package-version is used.`);
@@ -133,6 +134,11 @@ if (promoVersion !== "unknown") {
133
134
  for (const still of ["01-opener.jpg", "02-command-block.jpg", "03-tuning-evidence.jpg", "04-try-it.jpg"]) {
134
135
  requireFile(`promo/share-kit/stills/${still}`, `share-kit still ${still}`, 50_000);
135
136
  }
137
+ requireFile(socialCardPath, "social preview card", 2_000);
138
+ requireText(socialCardPath, /width="1200" height="630"/, "1200x630 social-card dimensions");
139
+ requireText(socialCardPath, /Memento Mori Jester/, "product name");
140
+ requireText(socialCardPath, /npx -y memento-mori-jester@latest start/, "start command");
141
+ requireText("promo/share-kit/README.md", /social-card\.svg/, "social-card asset row");
136
142
 
137
143
  try {
138
144
  const demoPackage = readJson(`${demoDir}/package.json`);
@@ -0,0 +1,105 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
6
+ const targetPath = resolve(root, "promo/share-kit/social-card.svg");
7
+ const mode = process.argv.includes("--check") ? "check" : "write";
8
+
9
+ const width = 1200;
10
+ const height = 630;
11
+
12
+ const copy = {
13
+ title: "Memento Mori Jester",
14
+ eyebrow: "For AI agents with ambition",
15
+ headline: ["A local court jester", "for AI coding agents."],
16
+ detail: ["Reviews commands, plans, diffs, and final answers", "before the agent gets too pleased with itself."],
17
+ command: "npx -y memento-mori-jester@latest start",
18
+ footer: "Codex | Claude Code | MCP | hooks | CI"
19
+ };
20
+
21
+ function escapeXml(value) {
22
+ return value
23
+ .replaceAll("&", "&")
24
+ .replaceAll("<", "&lt;")
25
+ .replaceAll(">", "&gt;")
26
+ .replaceAll("\"", "&quot;");
27
+ }
28
+
29
+ function text(value) {
30
+ return escapeXml(value);
31
+ }
32
+
33
+ function renderSvg() {
34
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-labelledby="title desc">
35
+ <title id="title">${text(copy.title)} social preview card</title>
36
+ <desc id="desc">${text(copy.detail.join(" "))}</desc>
37
+ <defs>
38
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
39
+ <stop offset="0%" stop-color="#11100e"/>
40
+ <stop offset="58%" stop-color="#171410"/>
41
+ <stop offset="100%" stop-color="#211b14"/>
42
+ </linearGradient>
43
+ <radialGradient id="heat" cx="78%" cy="16%" r="70%">
44
+ <stop offset="0%" stop-color="#d7a642" stop-opacity="0.36"/>
45
+ <stop offset="42%" stop-color="#d64b3f" stop-opacity="0.12"/>
46
+ <stop offset="100%" stop-color="#11100e" stop-opacity="0"/>
47
+ </radialGradient>
48
+ <filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
49
+ <feDropShadow dx="0" dy="24" stdDeviation="24" flood-color="#050403" flood-opacity="0.38"/>
50
+ </filter>
51
+ </defs>
52
+ <rect width="${width}" height="${height}" fill="url(#bg)"/>
53
+ <rect width="${width}" height="${height}" fill="url(#heat)"/>
54
+ <g opacity="0.09">
55
+ <path d="M0 90H1200M0 180H1200M0 270H1200M0 360H1200M0 450H1200M0 540H1200" stroke="#f2eadc" stroke-width="1"/>
56
+ <path d="M100 0V630M200 0V630M300 0V630M400 0V630M500 0V630M600 0V630M700 0V630M800 0V630M900 0V630M1000 0V630M1100 0V630" stroke="#f2eadc" stroke-width="1"/>
57
+ </g>
58
+ <g transform="translate(875 74)" opacity="0.55">
59
+ <circle cx="150" cy="150" r="145" fill="none" stroke="#d7a642" stroke-width="3" opacity="0.55"/>
60
+ <circle cx="150" cy="150" r="95" fill="none" stroke="#d64b3f" stroke-width="3" opacity="0.36"/>
61
+ <circle cx="150" cy="150" r="48" fill="none" stroke="#f2eadc" stroke-width="3" opacity="0.28"/>
62
+ </g>
63
+ <text x="-36" y="612" fill="#f2eadc" opacity="0.055" font-family="Georgia, serif" font-size="132" font-weight="900">remember you are shipping code</text>
64
+ <g transform="translate(74 66)">
65
+ <g transform="translate(0 0)">
66
+ <circle cx="27" cy="27" r="27" fill="#f2eadc"/>
67
+ <path d="M27 0A27 27 0 0 1 54 27H27Z" fill="#d64b3f"/>
68
+ <path d="M27 27H54A27 27 0 0 1 13 50Z" fill="#d7a642"/>
69
+ <path d="M27 0V27H0A27 27 0 0 1 27 0Z" fill="#f2eadc"/>
70
+ </g>
71
+ <text x="76" y="36" fill="#f2eadc" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="25" font-weight="800" letter-spacing="4">${text(copy.title.toUpperCase())}</text>
72
+ </g>
73
+ <g transform="translate(76 166)">
74
+ <text x="0" y="0" fill="#d7a642" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="22" font-weight="700" letter-spacing="3">${text(copy.eyebrow.toUpperCase())}</text>
75
+ <text x="0" y="76" fill="#f2eadc" font-family="Georgia, serif" font-size="72" font-weight="900">${text(copy.headline[0])}</text>
76
+ <text x="0" y="146" fill="#f2eadc" font-family="Georgia, serif" font-size="72" font-weight="900">${text(copy.headline[1])}</text>
77
+ <text x="0" y="202" fill="#d8cbb5" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="25">${text(copy.detail[0])}</text>
78
+ <text x="0" y="238" fill="#d8cbb5" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="25">${text(copy.detail[1])}</text>
79
+ </g>
80
+ <g transform="translate(76 432)" filter="url(#soft-shadow)">
81
+ <rect x="0" y="0" width="812" height="88" rx="18" fill="#1b1814" stroke="#d7a642" stroke-opacity="0.48" stroke-width="2"/>
82
+ <text x="32" y="55" fill="#d7a642" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="28">$</text>
83
+ <text x="64" y="55" fill="#f2eadc" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="28" font-weight="700">${text(copy.command)}</text>
84
+ </g>
85
+ <g transform="translate(76 546)">
86
+ <rect x="0" y="-28" width="650" height="48" rx="24" fill="#d64b3f"/>
87
+ <text x="28" y="3" fill="#fff3eb" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="18" font-weight="800" letter-spacing="1.5">${text(copy.footer.toUpperCase())}</text>
88
+ </g>
89
+ </svg>
90
+ `;
91
+ }
92
+
93
+ const svg = renderSvg();
94
+
95
+ if (mode === "check") {
96
+ const existing = await readFile(targetPath, "utf8");
97
+ if (existing !== svg) {
98
+ process.stderr.write("promo/share-kit/social-card.svg is stale. Run `npm run promo:card`.\n");
99
+ process.exitCode = 1;
100
+ }
101
+ } else {
102
+ await mkdir(dirname(targetPath), { recursive: true });
103
+ await writeFile(targetPath, svg, "utf8");
104
+ process.stdout.write(`Wrote ${targetPath}\n`);
105
+ }