@natjswenson/devlog 0.14.0 → 0.14.1

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
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to `@natjswenson/devlog` are documented here.
4
4
 
5
+ ## 0.14.1 (2026-09-10) — native branded cover generation
6
+
7
+ - Require Codex covers to use native generated raster artwork in the established
8
+ monochrome technical-engraving PRESS style; reject wireframes and SVG substitutes.
9
+ - Require copyable agent handoffs and validated covers before publication.
10
+ - Fix cover backfills when the target repository stores entries below `targetDir`.
11
+
5
12
  ## 0.14.0 (2026-09-09) — verified concept guides and AI cover composition
6
13
 
7
14
  - Add an explicit concept-guide draft workflow: select one transferable reader
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # devlog
2
2
 
3
- <!-- >>> press:masthead v0.9.0 sha256:4b48a8031589 GENERATED by @natjswenson/press, do not edit -->
4
- **NS** · NATE SWENSON · CLAUDE CODE + CODEX SKILL · PRESS v0.9.0 · linkedin.com/in/natejswenson
3
+ <!-- >>> press:masthead v0.10.0 sha256:b950ecf78f98 GENERATED by @natjswenson/press, do not edit -->
4
+ **NS** · NATE SWENSON · CLAUDE CODE + CODEX SKILL · PRESS v0.10.0 · linkedin.com/in/natejswenson
5
5
 
6
6
  ---
7
7
  <!-- <<< press:masthead -->
package/SKILL.md CHANGED
@@ -19,6 +19,10 @@ apps by capability rather than assuming Claude MCP tool names exist.
19
19
 
20
20
  # /devlog — Release How-To Generator
21
21
 
22
+ <!-- press:runtime -->
23
+ In Claude Code, load `/press`; in Codex, load `$press`; then follow the shared PRESS terminal/UI contract from `brand/agent-ui.md`. Do not copy or override that contract here.
24
+ <!-- press:runtime -->
25
+
22
26
  In the default Generate mode, you turn each **new version release** (a semver git tag) in the user's projects into a
23
27
  published blog post, written in **the user's own voice**, and pushed to the GitHub repo
24
28
  configured in `~/.claude/skills/devlog/config.json`.
@@ -392,9 +396,12 @@ The `--clone` flag always points at the CONTENT ROOT: `<abs-tmp>/<repo-name>` wh
392
396
  `targetDir` is empty, `<abs-tmp>/<repo-name>/<targetDir>` when it's set. Git commands
393
397
  always run against the clone root `<abs-tmp>/<repo-name>` regardless.
394
398
 
395
- In this legacy Generate path, each release also gets a cover image, composed inline in this same loop right before that
396
- release's own `publish-entry` call a self-contained HTML/CSS (or inline SVG) document,
397
- rasterized locally, never sent to any external service:
399
+ In this Generate path, each release also gets a cover image, created inline in this same loop right before that
400
+ release's own `publish-entry` call. In Codex, the dominant artwork MUST come from the native
401
+ image-generation tool as a persisted raster source; wireframes, hand-authored SVG, CSS drawings,
402
+ and title-only placeholders are not covers. The deterministic compositor may add PRESS typography
403
+ around that generated artwork, but it must never substitute for native image generation.
404
+ The cover must carry a custom illustration or other meaningful visual material; a cover that just re-renders the title in large text is a failure.
398
405
 
399
406
  ```bash
400
407
  mktemp -d # → record the absolute path, e.g. /var/folders/.../tmp.abc
@@ -415,24 +422,17 @@ Per release:
415
422
  returns the style guide, icon catalog, and up to 3 reference cover paths. **Read
416
423
  only the single most recent reference image** (image reads are the expensive part;
417
424
  open another only if you're genuinely unsure the new cover is distinct). On
418
- `{"error": "style-guide-missing"}`: skip cover composition for this release entirely
419
- and proceed straight to publish-entry with no `--cover` flag.
420
- Never block publish on a missing style guide.
421
- 2. **Compose** using ONLY this release's title/tags/summary/`## Shipped` text
422
- (never the raw draft file, never `## Changelog`) plus the style guide and icon catalog. A
423
- cover that just re-renders the title in large text is a failure — find the one
424
- concrete mechanism this release is actually about (not the project name, not "a bug
425
- fix") and draw ONE custom inline-SVG illustration of it as the dominant visual
426
- element; title/kicker stay secondary; two releases should never produce visually
427
- similar covers. Follow the style guide's hero-zone grid contract: the illustration
428
- lives in a `#hero-zone` container at exactly `x:150 y:425 width:1300 height:400`
429
- (render-cover mechanically enforces this), one of two slots (single centered hero,
430
- or two-node before/after), interior points snapped to a 25px grid; catalog icons
431
- never go inside `#hero-zone` (optional small accent glyph near the kicker only,
432
- bottom edge above y:400). Write the document with the Write tool to
433
- `'<abs-scratch>/<key>/<version>.html'` — full `<!DOCTYPE html>` document, sized
434
- `html, body { margin:0; width:1600px; height:900px; }`, font referenced only as
435
- `font-family: 'DevlogCoverFont', sans-serif`.
425
+ `{"error": "style-guide-missing"}`: stop this release and report that publication is
426
+ blocked. A release entry is not publishable without a cover and agent handoff.
427
+ 2. **Generate and compose.** Use ONLY this release's title/tags/summary/`## Shipped` text
428
+ (never the raw draft file, never `## Changelog`) plus the style guide and icon catalog to
429
+ brief the native image-generation tool. Request artwork only: one concrete mechanism,
430
+ no lettering, labels, numbers, logos, fake code, UI, wireframe, gradients, or watermark.
431
+ Persist and inspect the exact returned raster, then use `compose-art-cover` to add local
432
+ PRESS typography. Do not draw the dominant art as inline SVG or CSS. A cover that just
433
+ re-renders the title in large text is a failure. Match the established backfill look:
434
+ flat cream paper, monochrome technical engraving, black/gray ink, restrained crosshatching,
435
+ a quiet left field for the headline, and at most one small orange accent.
436
436
  3. **Rasterize.**
437
437
  `npx -y @natjswenson/devlog@latest render-cover '<abs-scratch>/<key>/<version>.html' --project '<key>' --slug '<version>' --out '<abs-scratch>'`
438
438
  The HTML is the source of truth and **survives the render**: to fix a visual
package/bin/devlog.js CHANGED
@@ -1126,15 +1126,18 @@ async function cmdCommitCovers(rest) {
1126
1126
  // routinely runs well after the backfill/review session that produced the staging dir,
1127
1127
  // and reusing an hours-or-days-old clone would risk mutating a manifest that's since
1128
1128
  // moved on.
1129
- const cloneDir = mkdtempSync(join(tmpdir(), 'devlog-commit-covers-'));
1129
+ const repoDir = mkdtempSync(join(tmpdir(), 'devlog-commit-covers-'));
1130
1130
  const branch = config.branch || 'main';
1131
1131
  const cloneUrl = `https://github.com/${config.targetRepo}.git`;
1132
- const cloneResult = spawnSync('git', ['clone', '--depth=1', '--branch', branch, cloneUrl, cloneDir], { encoding: 'utf8' });
1132
+ const cloneResult = spawnSync('git', ['clone', '--depth=1', '--branch', branch, cloneUrl, repoDir], { encoding: 'utf8' });
1133
1133
  if (cloneResult.status !== 0) {
1134
- rmSync(cloneDir, { recursive: true, force: true });
1134
+ rmSync(repoDir, { recursive: true, force: true });
1135
1135
  emitJSON({ error: 'clone-failed', message: cloneResult.stderr || 'git clone failed' }, 1);
1136
1136
  return;
1137
1137
  }
1138
+ // Manifests live under the configured content root; git operations still run
1139
+ // from the repository root.
1140
+ const cloneDir = join(repoDir, config.targetDir || '');
1138
1141
 
1139
1142
  const summary = { written: [], skipped: [], failed: [], missingManifest: [] };
1140
1143
  let bulkForceOverwriteCount = 0;
@@ -1199,20 +1202,20 @@ async function cmdCommitCovers(rest) {
1199
1202
  ['commit', '-m', `chore(devlog): add ${summary.written.length} cover image(s)`],
1200
1203
  ];
1201
1204
  for (const args of steps) {
1202
- const r = spawnSync('git', ['-C', cloneDir, ...args], { encoding: 'utf8' });
1205
+ const r = spawnSync('git', ['-C', repoDir, ...args], { encoding: 'utf8' });
1203
1206
  if (r.status !== 0) {
1204
1207
  emitJSON({ ok: false, ...summary, bulkForceOverwriteCount, error: 'git-commit-failed', message: r.stderr }, 1);
1205
1208
  return;
1206
1209
  }
1207
1210
  }
1208
- const push = spawnSync('git', ['-C', cloneDir, 'push', '--no-tags', 'origin', branch], { encoding: 'utf8' });
1211
+ const push = spawnSync('git', ['-C', repoDir, 'push', '--no-tags', 'origin', branch], { encoding: 'utf8' });
1209
1212
  if (push.status !== 0) {
1210
1213
  emitJSON({ ok: false, ...summary, bulkForceOverwriteCount, error: 'git-push-failed', message: push.stderr }, 1);
1211
1214
  return;
1212
1215
  }
1213
1216
  }
1214
1217
 
1215
- rmSync(cloneDir, { recursive: true, force: true });
1218
+ rmSync(repoDir, { recursive: true, force: true });
1216
1219
  emitJSON({ ok: summary.failed.length === 0, ...summary, bulkForceOverwriteCount });
1217
1220
  }
1218
1221
 
@@ -11,8 +11,9 @@ are how a from-scratch visual language stays consistent from post to post.
11
11
 
12
12
  ## What you're composing
13
13
 
14
- A single self-contained HTML document (inline `<style>`, inline SVG for any artwork) that
15
- renders, at exactly 1600×900px, as a cover image for one dev log entry. Compose from these
14
+ A single PRESS editorial cover that renders, at exactly 1600×900px, as a cover image for
15
+ one dev log entry. In Codex, the dominant image is a native generated raster illustration;
16
+ the local compositor adds the typography and layout. Compose from these
16
17
  fields only — never open the post's raw markdown file, never reference any section other
17
18
  than `## Shipped` (no `## Changelog`, no gotchas, no sources):
18
19
  - `title`
@@ -34,11 +35,11 @@ Before writing any HTML, do this thinking step explicitly:
34
35
  key that doesn't fit, a git tag being distrusted like any other user input, one broken
35
36
  link in a chain, a filter separating signal from noise, a clock catching a stale
36
37
  timestamp, two paths diverging and one being cut off.
37
- 3. Design ONE illustration built from inline SVG shapes (lines, arcs, polygons,
38
- simple geometric forms) that depicts that concept. Not a photo, not a stock icon,
39
- not a screenshot: a small original line-art scene, **editorial line art in ink with
40
- sparing orange**, in the spirit of a newspaper diagram or a technical schematic, using
41
- only the palette below.
38
+ 3. Design ONE native raster illustration that depicts that concept. Not a photo, stock
39
+ icon, screenshot, UI, wireframe, or geometric placeholder: a detailed original
40
+ **monochrome technical engraving in black and warm gray ink on flat cream paper**, in
41
+ the spirit of a historical engineering plate or newspaper field illustration, with at
42
+ most one small vermilion/orange focal accent. The art must look printed, not painterly.
42
43
  4. That illustration is the dominant visual element of the cover — roughly half the
43
44
  canvas, not a thumbnail in the corner. Title, kicker, and summary text support it;
44
45
  they do not replace it.
@@ -151,10 +152,10 @@ For the two-node slot specifically: the accent icon's presence must not be read
151
152
  `DevlogCoverFont` finishes loading. That's resolving a name the browser already has, not
152
153
  embedding or fetching a file — no different in kind from the fallback this rule already
153
154
  requires.
154
- - No external resources of any kind no `<link>`, no `@import`, no remote `<img src>`,
155
- no web fonts, no raster images. All artwork is inline SVG built from basic shapes
156
- (`<path>`, `<circle>`, `<rect>`, `<line>`, `<polygon>`, `<polyline>`) everything must
157
- be inline HTML/CSS/SVG, hand-composed, not fetched or embedded from anywhere.
155
+ - The final cover must be self-contained and offline-renderable. Native raster artwork is
156
+ persisted locally and embedded by `compose-art-cover`; no remote images or web fonts.
157
+ Typography is rendered locally and the generated artwork is never replaced by inline
158
+ SVG, CSS shapes, a wireframe, or a title-only placeholder.
158
159
 
159
160
  ## Visual direction
160
161
 
@@ -165,7 +166,7 @@ site, not a marketing graphic and not a repeated template.
165
166
 
166
167
  ### Palette
167
168
 
168
- <!-- >>> press:palette v0.9.0 sha256:5904c52d4168 GENERATED by @natjswenson/press, do not edit -->
169
+ <!-- >>> press:palette v0.10.0 sha256:5904c52d4168 GENERATED by @natjswenson/press, do not edit -->
169
170
  - **Paper** `#F5F0E6` — Warm cream. Flat — never gradiented, never textured.
170
171
  - **Ink** `#181510` — Near-black. Text, headlines, and every structural rule.
171
172
  - **Dim** `#6E675C` — Muted secondary text; the serif commentary voice's color.
@@ -176,9 +177,10 @@ site, not a marketing graphic and not a repeated template.
176
177
  survives, and only inside a terminal element. Never on paper.
177
178
  <!-- <<< press:palette -->
178
179
 
179
- Prefer flat, limited color and solid/line fills over gradients or smooth shading — the
180
- render is compressed with lossy PNG palette quantization afterward, and gradients band
181
- visibly under that compression while flat fills don't.
180
+ Prefer flat, limited color and solid/line fills over gradients or smooth shading. Native
181
+ art should be predominantly cream paper plus black/gray engraving lines, with no broad
182
+ color wash, no saturated palette, and no painterly digital lighting. The only bright color
183
+ is the single small orange accent permitted by the accent law below.
182
184
 
183
185
  ### The accent law, carried to covers
184
186
 
@@ -304,7 +306,8 @@ summary as on-image text.
304
306
  cursor, no bare `_` suffix, no stray `$` prompt as decoration. The dark palette now
305
307
  belongs to exactly one place, the `.term` panel, and only when it's real code.
306
308
  - Don't embed a photograph, stock image, or anything requiring an external fetch — the
307
- illustration is drawn from inline SVG primitives, not sourced from anywhere.
309
+ illustration is native-generated raster artwork persisted locally and embedded by the
310
+ compositor, never a hand-authored SVG substitute.
308
311
  - Don't reference any font file other than the bundled `'DevlogCoverFont'` — the serif
309
312
  and display voices lean on this rendering host's own system fonts, never a file you
310
313
  fetch or embed yourself.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@natjswenson/devlog",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "Release dev log generator — Claude Code skill + preview app for publishing version-release dev logs, written in your voice, to your site",
5
5
  "license": "MIT",
6
6
  "author": "Nate Swenson",
@@ -72,9 +72,9 @@
72
72
  "rationale": "Cover composition must draw only from title/tags/summary/## Shipped \u2014 never the raw draft or Changelog \u2014 losing this line reopens off-scope content leaking into an auto-composed image."
73
73
  },
74
74
  {
75
- "id": "cover-never-blocks-publish",
76
- "pattern": "[Nn]ever block[\\s\\S]{0,10}publish on a missing style guide",
77
- "rationale": "A missing/uninstalled style guide must degrade gracefully (no cover this run), never abort the whole publish."
75
+ "id": "cover-required-before-publish",
76
+ "pattern": "publication is[\\s\\S]{0,5}blocked",
77
+ "rationale": "A missing/uninstalled style guide must stop the release so Generate mode cannot publish an entry without its required cover."
78
78
  },
79
79
  {
80
80
  "id": "cover-review-gate",