@natjswenson/devlog 0.11.0 → 0.11.2
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 +495 -0
- package/LICENSE +21 -0
- package/README.md +272 -0
- package/evals/baseline/published/devlog-v0.10.0.md +129 -0
- package/evals/baseline/published/devlog-v0.11.0.md +139 -0
- package/evals/baseline/published/devlog-v0.8.1.md +97 -0
- package/evals/baseline/published/devlog-v0.9.0.md +193 -0
- package/evals/baseline/published/ghostwriter-v0.11.0.md +211 -0
- package/evals/baseline/published/ghostwriter-v0.8.1.md +221 -0
- package/evals/baseline/published/local-fitness-v0.25.0.md +233 -0
- package/evals/baseline/published/resume-v1.0.1.md +129 -0
- package/package.json +4 -2
- package/skill-invariants.json +26 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@natjswenson/devlog` are documented here.
|
|
4
|
+
|
|
5
|
+
## 0.11.2 (2026-07-28) — actually render the README on npmjs.com
|
|
6
|
+
|
|
7
|
+
- **Fixed: the npm page still showed "No README data found" after 0.11.1.** That
|
|
8
|
+
release put README.md, LICENSE and CHANGELOG.md into the tarball (verified by
|
|
9
|
+
downloading it), which fixed what `npm install` delivers — but not the website.
|
|
10
|
+
npm reads README.md to populate the registry manifest's `readme` field when it
|
|
11
|
+
builds the publish manifest, which happens BEFORE the package's own `prepack`
|
|
12
|
+
hook runs. So the tarball had the file and the registry record did not.
|
|
13
|
+
Worse than merely empty: the stored value was the literal string
|
|
14
|
+
`ERROR: No README data found!`, and npmjs.com falls back to reading the
|
|
15
|
+
tarball only when that field is *absent* (compare `zod`, which renders fine
|
|
16
|
+
with no packument readme at all), so the error string kept winning.
|
|
17
|
+
The release workflow now stages the three files into the package directory
|
|
18
|
+
before `npm publish` is invoked at all, rather than relying on `prepack`.
|
|
19
|
+
Code unchanged.
|
|
20
|
+
|
|
21
|
+
## 0.11.1 (2026-07-28) — publish the README, LICENSE and CHANGELOG to npm
|
|
22
|
+
|
|
23
|
+
- **Fixed: the npm package shipped with no README, LICENSE or CHANGELOG.**
|
|
24
|
+
`package.json`'s `files` listed all three, but they live at the plugin root
|
|
25
|
+
(beside `.claude-plugin/`), one level above the package directory — and npm only
|
|
26
|
+
includes files from inside the package directory, so the entries silently matched
|
|
27
|
+
nothing. Every release published a tarball without them, and
|
|
28
|
+
`npm view @natjswenson/devlog readme` returned *"No README data found"*, leaving
|
|
29
|
+
the npm page blank. A `prepack` script now stages the three files into the package
|
|
30
|
+
directory before the tarball is built, and `postpack` removes them again so the
|
|
31
|
+
working tree stays clean; they are gitignored at that path so an interrupted pack
|
|
32
|
+
cannot leave committable strays. Code unchanged.
|
|
33
|
+
|
|
34
|
+
## 0.11.0 (2026-07-19) — everything the six-run audit found
|
|
35
|
+
|
|
36
|
+
A three-way audit of the first six real `/devlog` runs (content graded against git
|
|
37
|
+
ground truth, run archaeology in both target repos, session-transcript mining) drove
|
|
38
|
+
this release end to end.
|
|
39
|
+
|
|
40
|
+
**Added**
|
|
41
|
+
- **Tombstones — entry identity is now project+version in the manifest, not a file
|
|
42
|
+
path.** `devlog tombstone --clone <root> --project <key> --version <v> --reason <why>`
|
|
43
|
+
marks an editorially moved/consolidated/deleted entry's identity as retired
|
|
44
|
+
(`removed: true` row; a dead row's frozen `no` is kept so numbers are never reused).
|
|
45
|
+
`scan` now fetches each project's `manifest.json` (directory-listing fallback for
|
|
46
|
+
legacy dirs) and reports retired versions as `entry-tombstoned`; `publish-entry`
|
|
47
|
+
refuses them. This kills the failure class that re-armed three deleted entries across
|
|
48
|
+
the first six runs (ghostwriter v0.8.1 twice, market-research v0.1.0 — the latter was
|
|
49
|
+
live-armed at audit time: the entry had been hand-moved to `personal/2026-07-17` and
|
|
50
|
+
the next run would have republished it).
|
|
51
|
+
- **`devlog sync-entry`** — the legitimate post-publish edit path: resyncs a manifest
|
|
52
|
+
row's title/summary/date/tags from the published entry's frontmatter (never `no`/
|
|
53
|
+
`version`/`file`/`cover`) and reports `coverStale`. The v0.8.1 reframe left the
|
|
54
|
+
manifest stale for six hours while four "rebuild" commits chased a phantom CDN issue;
|
|
55
|
+
this is the command that should have existed.
|
|
56
|
+
- **`devlog assemble-post <draft> --out <dir>`** — extracts a draft's fenced code blocks,
|
|
57
|
+
in order, as numbered files (`text` fences are expected output, listed but not
|
|
58
|
+
written). SKILL.md Step 4's assemble-and-run check is now mechanical; the audit proved
|
|
59
|
+
the honor-system version was skipped exactly when it mattered (two posts shipped
|
|
60
|
+
claiming "real output" over code that could not run).
|
|
61
|
+
- **Ground-truth gate in SKILL.md Step 4**: every claim about the author's own repo must
|
|
62
|
+
be re-verified with a git command run in-session; a specific number is publishable
|
|
63
|
+
only if it appears in a commit/diff/source; output may be labeled real only if the
|
|
64
|
+
command ran this session. One audited post had published a provably false premise.
|
|
65
|
+
- **`lint-post --voice`** — opt-in deterministic voice rules: `voice-em-dash` (prose em
|
|
66
|
+
dashes; `## Sources`/`## Changelog`/fenced code exempt per the existing carve-outs)
|
|
67
|
+
and `voice-banned-phrase` (the explicit bans from voice-notes.md). Replaces the ad-hoc
|
|
68
|
+
grep pass every run hand-rolled.
|
|
69
|
+
- **Cross-entry Changelog collision refusal**: `publish-entry` refuses a draft whose
|
|
70
|
+
`## Changelog` lists a commit an existing entry already lists (monorepo twin releases
|
|
71
|
+
had shipped identical Changelogs). Hashes are matched by 7-char short form across link
|
|
72
|
+
text and `/commit/` URLs.
|
|
73
|
+
- **`scan --summary`** — the plan-table view: `commitCount` instead of commit lists and
|
|
74
|
+
diffstats, per-reason `skippedTags` tallies. Full detail stays one
|
|
75
|
+
`scan --project <key>` away.
|
|
76
|
+
- `scan` output now includes `cliVersion` (stale-npx tripwire — three real runs hit a
|
|
77
|
+
stale cached install) and per-project `publishedEntries` (`version`/`title`/`tags` of
|
|
78
|
+
every live entry — the catalog-level topic-dedup input; two near-duplicate guides had
|
|
79
|
+
shipped one day apart).
|
|
80
|
+
|
|
81
|
+
**Changed**
|
|
82
|
+
- **`render-cover` re-renders whenever the HTML file is present**, overwriting a stale
|
|
83
|
+
PNG, and **no longer deletes the HTML on success**. The old PNG-exists short-circuit
|
|
84
|
+
silently ignored freshly edited HTML (both real retry loops burned ~6 tool calls
|
|
85
|
+
diagnosing it, including a guessed-at `--force` that didn't exist), and the
|
|
86
|
+
post-success delete broke every later Edit attempt. The no-op path now only applies
|
|
87
|
+
when the HTML is gone and a valid PNG exists.
|
|
88
|
+
- All agent-facing commands now report unknown/malformed flags as
|
|
89
|
+
`{"error": "bad-flag"}` JSON (exit 2) instead of dying with a raw
|
|
90
|
+
`ERR_PARSE_ARGS_UNKNOWN_OPTION` stack trace.
|
|
91
|
+
- SKILL.md: every CLI invocation pins `@latest`; Step 1 leads with `scan --summary`;
|
|
92
|
+
Step 3b dedupes topics against the whole published catalog and forbids inventing a
|
|
93
|
+
second angle for a twin release the history doesn't support; Step 3c disqualifies
|
|
94
|
+
content-farm sources from `minSources`; Step 5 writes a `run-state.json` for
|
|
95
|
+
mid-run-compaction recovery, reads at most one reference cover image, and documents
|
|
96
|
+
the re-render recipe; new edge cases cover `entry-tombstoned`, hand-moved entries
|
|
97
|
+
(tombstone them), and hand-edited entries (sync-entry).
|
|
98
|
+
- `mergeManifestEntries`/`backfill-covers`/the preview manifest validator skip
|
|
99
|
+
`removed: true` rows.
|
|
100
|
+
- Four new prose invariants in `skill-invariants.json` (ground-truth-gate,
|
|
101
|
+
no-unrun-output, tombstone-never-republish, one-commit-one-changelog).
|
|
102
|
+
|
|
103
|
+
## 0.10.0 (2026-07-19) — publish into a subdirectory of the target repo
|
|
104
|
+
|
|
105
|
+
**Added**
|
|
106
|
+
- Optional `targetDir` config field (`devlog set targetDir content/devlog`, clear with
|
|
107
|
+
`set targetDir ''`): the subdirectory of `targetRepo` that holds the devlog content
|
|
108
|
+
tree. Lets the devlog publish directly into a site repo (e.g.
|
|
109
|
+
`natejswenson.io/content/devlog`) so the publish push itself triggers the site's
|
|
110
|
+
deploy — no separate rebuild commit, no second repo. Validated as a relative,
|
|
111
|
+
traversal-free path since it's interpolated into the publish clone path and the
|
|
112
|
+
`gh api` contents path.
|
|
113
|
+
- `scan` threads `targetDir` through the existence check
|
|
114
|
+
(`repos/<targetRepo>/contents/<targetDir>/<key>`) and echoes it in its JSON output,
|
|
115
|
+
so already-published entries are still filtered correctly when content lives in a
|
|
116
|
+
subfolder. Unset behaves exactly as before (repo root).
|
|
117
|
+
- `SKILL.md`: publish step now targets `<content-root>` (`<clone>/<targetDir>` when
|
|
118
|
+
set); the confirm message notes that a push to an auto-deploying site repo IS the
|
|
119
|
+
rebuild trigger.
|
|
120
|
+
|
|
121
|
+
**Fixed**
|
|
122
|
+
- `image-style/icons.md` still described the pre-PRESS dark palette for accent icons
|
|
123
|
+
(`#ededed` / accent yellow `#fff503`); corrected to PRESS ink/dim, never orange —
|
|
124
|
+
matching the style guide's accent law.
|
|
125
|
+
|
|
126
|
+
## 0.9.0 (2026-07-17) — cover images: icon catalog + geometry-enforced hero zone
|
|
127
|
+
|
|
128
|
+
**Added**
|
|
129
|
+
- `image-style/icons.md`: a 20-icon catalog (agents/LLM, testing, CI/CD, git,
|
|
130
|
+
accessibility, debugging, CLI, config, deploy, database, API, search, auth,
|
|
131
|
+
monitoring, cover/image tooling, performance, parsing, caching, UI, networking) —
|
|
132
|
+
real inline SVG, stroke-only, for the optional kicker-area accent glyph only. Never
|
|
133
|
+
the hero illustration itself. Installed by `devlog init` alongside the existing
|
|
134
|
+
style guide/font.
|
|
135
|
+
- A fixed hero-zone bounding box (`x:150 y:425 width:1300 height:400`) and 25px
|
|
136
|
+
coordinate grid, documented in `image-style/style-guide.example.md`, with two named
|
|
137
|
+
composition slots: single centered hero, and two-node before/after.
|
|
138
|
+
- `lib/render_cover.mjs` now mechanically enforces the hero zone via a new
|
|
139
|
+
`checkHeroZoneOverlap()` check, run immediately before the screenshot: throws if
|
|
140
|
+
`#hero-zone` is missing, duplicated, positioned/sized outside a 2px tolerance of the
|
|
141
|
+
fixed box, or if any catalog icon's rendered rect overlaps it. This replaces a
|
|
142
|
+
prose-only safeguard (a regex checking one sentence still exists in `SKILL.md`) with
|
|
143
|
+
a real pixel-geometry check against actual rendered layout — a sibling investigation
|
|
144
|
+
found the prose-only check could never catch an agent composing two catalog icons
|
|
145
|
+
connected by a line and calling that the hero. `renderCoverImage()`'s documented
|
|
146
|
+
throw contract widens from three failure modes to four accordingly.
|
|
147
|
+
- `devlog backfill-covers list` gains an `--all` flag: lists every manifest entry
|
|
148
|
+
regardless of cover status (the default stays missing-cover-only). Needed because
|
|
149
|
+
the ~51 real entries in a typical `daily-dev-log` already have covers from a prior
|
|
150
|
+
batch — without `--all`, there is nothing to iterate over for a cover-quality
|
|
151
|
+
backfill.
|
|
152
|
+
- `cover-context`'s underlying `loadStyleGuide()` now also returns the icon catalog
|
|
153
|
+
content (`iconCatalog`, `null` if `icons.md` isn't installed) alongside the style
|
|
154
|
+
guide text — no new CLI flag, just a widened response.
|
|
155
|
+
|
|
156
|
+
**Changed**
|
|
157
|
+
- `skill-invariants.json` gains a `code` array (alongside the existing `prose` array)
|
|
158
|
+
for guardrails checked against arbitrary source files, not just `SKILL.md` — first
|
|
159
|
+
entry: `cover-catalog-hero-overlap-guard`, asserting the new geometry check stays
|
|
160
|
+
wired into `render_cover.mjs`.
|
|
161
|
+
|
|
162
|
+
## 0.8.1 (2026-07-16) — cover images: illustration over typography
|
|
163
|
+
|
|
164
|
+
**Changed**
|
|
165
|
+
- Rewrote the bundled cover style guide (`image-style/style-guide.example.md`) after the
|
|
166
|
+
first real batch of covers shipped bland and repetitive: a shared text-heavy layout
|
|
167
|
+
with a rotating stock shape (circle/square/slash). The guide now mandates ONE custom
|
|
168
|
+
inline-SVG illustration per post depicting the specific mechanism the release is about
|
|
169
|
+
— sized as the dominant visual element — with the title demoted to a secondary line.
|
|
170
|
+
Explicitly forbids reusing the same shape family/motif across posts and falling back to
|
|
171
|
+
a generic circle/square/checkmark when stuck.
|
|
172
|
+
- `SKILL.md` Step 5's compose sub-step now states this mandate inline (not just "compose
|
|
173
|
+
using the style guide") so the failure mode can't silently regress even if the
|
|
174
|
+
installed style guide is later replaced with something weaker.
|
|
175
|
+
- New `skill-invariants.json` entry (`cover-custom-illustration`) guards the "cover that
|
|
176
|
+
just re-renders the title in large text is a failure" line in `SKILL.md`.
|
|
177
|
+
|
|
178
|
+
## 0.8.0 (2026-07-16) — cover images
|
|
179
|
+
|
|
180
|
+
**Added**
|
|
181
|
+
- Every post now gets an auto-generated 1600x900 cover image. Claude composes a
|
|
182
|
+
self-contained HTML/CSS (or inline SVG) document from the post's title/tags/summary/
|
|
183
|
+
`## Shipped` text plus an installed style guide and up to 3 reference images of
|
|
184
|
+
recently published covers — then `devlog render-cover` rasterizes it locally via
|
|
185
|
+
headless Chromium (`playwright`), embeds a bundled font, and quantizes the PNG. No
|
|
186
|
+
external API, no credentials, nothing ever leaves the machine.
|
|
187
|
+
- New `SKILL.md` Step 5 sub-steps: `devlog cover-context` (style guide + references) →
|
|
188
|
+
Claude composes the markup → `devlog render-cover` → `publish-entry --cover`. A cover
|
|
189
|
+
render failure (timeout, Chromium not installed, missing font) never blocks publish —
|
|
190
|
+
the post ships with no cover, the same graceful degradation as any other failure.
|
|
191
|
+
- New commands for backfilling covers onto already-published posts: `devlog
|
|
192
|
+
backfill-covers list` (deterministic, cross-project, oldest-first, extracts only
|
|
193
|
+
`## Shipped`) drives an agent loop of `cover-context` + compose + `render-cover` into a
|
|
194
|
+
project-namespaced staging directory, reviewed via a contact sheet, then `devlog
|
|
195
|
+
commit-covers` publishes the approved set (with `--force` for re-covering).
|
|
196
|
+
- `devlog init` now installs the bundled style guide + font (`image-style/`) and checks
|
|
197
|
+
Chromium/font reachability, mirroring its existing SKILL.md/voice-profile install
|
|
198
|
+
pattern.
|
|
199
|
+
- `publishEntry()` gains an optional `coverImageBuffer` param; new
|
|
200
|
+
`addCoverToExistingEntry()` in `lib/publish_entry.mjs` for the backfill path.
|
|
201
|
+
|
|
202
|
+
## 0.7.0 (2026-07-15) — private projects
|
|
203
|
+
|
|
204
|
+
**Added**
|
|
205
|
+
- New `private` project flag (`add-project --private`, or the interactive "Is this repo
|
|
206
|
+
private?" prompt). A private project's `remote` becomes optional, and `scanProject`'s
|
|
207
|
+
`isPublic` check now short-circuits to `false` unconditionally for it — regardless of
|
|
208
|
+
whether `remote` matches `origin` and the commit is on the published branch. Previously
|
|
209
|
+
those two checks alone decided "public," which is a proxy for "the commit is reachable
|
|
210
|
+
from a correctly-configured remote," not "the GitHub repo is public." A project with a
|
|
211
|
+
real, correctly configured `remote` that happens to live in a private GitHub repo would
|
|
212
|
+
have scanned every commit as public and generated dead `github.com/.../commit/...` links
|
|
213
|
+
in the post. `private` is a declared type, not auto-detected via the GitHub API — no
|
|
214
|
+
extra network call per run, and it stays correct even for a project with no push target
|
|
215
|
+
at all.
|
|
216
|
+
- `config`'s project listing shows `(private — no commit links)` instead of a broken
|
|
217
|
+
`remote: github.com/undefined` line for a private project with no `remote` set.
|
|
218
|
+
|
|
219
|
+
**Fixed**
|
|
220
|
+
- `validateConfig` previously required every project to have a valid `remote`
|
|
221
|
+
unconditionally; a private project can now omit it (still validated for shape if
|
|
222
|
+
supplied anyway).
|
|
223
|
+
|
|
224
|
+
## 0.6.0 (2026-07-12) — lessons from rewriting the whole back-catalog
|
|
225
|
+
|
|
226
|
+
Every pre-0.5 entry (38 posts across devlog, ghostwriter, resume, local-fitness) was
|
|
227
|
+
rewritten against the 0.5.0 how-to contract, and each rewrite's friction fed a skill
|
|
228
|
+
refinement. What changed:
|
|
229
|
+
|
|
230
|
+
**Added (lint)**
|
|
231
|
+
- New `sources-inline` rule: every URL in `## Sources` must also be cited inline in the
|
|
232
|
+
body — the contract required it, nothing enforced it, and it was the easiest step to
|
|
233
|
+
silently skip. The finding suggests drop-the-source as an alternative fix so the rule
|
|
234
|
+
can't push citation stuffing. Fixtures updated to comply.
|
|
235
|
+
|
|
236
|
+
**Changed (SKILL.md writing contract)**
|
|
237
|
+
- Topics must pass a usability test: prefer the transferable technique a reader could
|
|
238
|
+
apply to their own project, with a tie-break rule for releases spanning several
|
|
239
|
+
topics; cross-project (monorepo) commits belong to one post's story only.
|
|
240
|
+
- New contract point 8, **fun to follow**: early runnable win, momentum between steps,
|
|
241
|
+
payoff visible at each stage — never forced jokes or hype.
|
|
242
|
+
- Reader-side verification must be REAL when cheap: run the blocks, paste actual output
|
|
243
|
+
(trim/normalize only with disclosure); new **assemble-and-run** self-check step
|
|
244
|
+
executes the post's own code blocks in order, catching phantom symbols and ordering
|
|
245
|
+
traps mechanically. Revised functions must be shown as complete redefinitions.
|
|
246
|
+
- Facts anchor at the tag (`git show '<tag>:<file>'`), teaching code may generalize;
|
|
247
|
+
when a commit message and its diff disagree, the diff wins.
|
|
248
|
+
- Gotcha mining follows the release's code FORWARD in history — a later fix to code
|
|
249
|
+
this release introduced is prime material when dated honestly.
|
|
250
|
+
- Research: quotes require verbatim re-verification (fetch tools can return
|
|
251
|
+
quote-shaped summaries that aren't on the page).
|
|
252
|
+
- Punctuation scope settled: voice rules govern prose; the Sources template separator
|
|
253
|
+
and verbatim commit subjects keep their punctuation. Titles are sentence case.
|
|
254
|
+
- Template flexibility: only Shipped/Gotchas/Sources are mandatory sections; output
|
|
255
|
+
blocks fence as `text`; the 900-1600 word target counts prose only.
|
|
256
|
+
|
|
257
|
+
## 0.5.2 (2026-07-11) — fix: same-date manifest entries buried the newest post
|
|
258
|
+
|
|
259
|
+
**Fixed**
|
|
260
|
+
- `publish-entry` sorted the manifest by date only; several releases cut on the same
|
|
261
|
+
day kept insertion order, so the feed rendered them oldest-version-on-top and the
|
|
262
|
+
newest post landed at the bottom of the day's group (hit live with
|
|
263
|
+
v0.4.2/v0.5.0/v0.5.1, all dated 2026-07-11). Same-date ties now break by version,
|
|
264
|
+
highest first, with numeric component comparison (v0.10.0 > v0.9.0). Date still wins
|
|
265
|
+
overall so a backported tag sorts by its release date. Legacy rows without a
|
|
266
|
+
`version` keep their relative order.
|
|
267
|
+
|
|
268
|
+
## 0.5.1 (2026-07-11) — fix: npx invocations were a silent no-op
|
|
269
|
+
|
|
270
|
+
**Fixed**
|
|
271
|
+
- Every `npx @natjswenson/devlog <cmd>` invocation exited 0 with no output (present
|
|
272
|
+
since the import-side-effect guard was added, so ≤0.5.0). npm/npx expose the binary
|
|
273
|
+
as a `node_modules/.bin/devlog` **symlink**; `process.argv[1]` is the symlink while
|
|
274
|
+
`import.meta.url` resolves to the real file, so the naive `===` in the `isMain` guard
|
|
275
|
+
never matched and the dispatcher never ran. Both sides are now `realpathSync`'d. A
|
|
276
|
+
regression test invokes the CLI through a symlink exactly like npx does. Running
|
|
277
|
+
`node bin/devlog.js` directly was always unaffected — which is why the test suite
|
|
278
|
+
and local verification missed it.
|
|
279
|
+
|
|
280
|
+
## 0.5.0 (2026-07-11) — how-to posts with gotchas, deterministic core, agent-native config
|
|
281
|
+
|
|
282
|
+
**Changed (posts)**
|
|
283
|
+
- Every post is now held to an explicit **how-to contract**: the stranger test (a reader
|
|
284
|
+
without the author's repo can build the technique from the post alone), complete code
|
|
285
|
+
(no phantom fixtures — every referenced symbol is defined or explicitly stubbed),
|
|
286
|
+
reader-side verification (commands the reader runs, with expected output), a required
|
|
287
|
+
`## Gotchas` section (trap → symptom → escape, mined from real history: fix-after-feat
|
|
288
|
+
commits, reverts, CHANGELOG "Fixed" entries — never invented), honest scope, and no
|
|
289
|
+
leaked repo-specific artifacts. Generate mode runs a mandatory self-check (lint +
|
|
290
|
+
rubric review, max 2 revision passes) before publishing autonomously.
|
|
291
|
+
- `deepDive.minSources` default raised 2 → 3, and sources must be **distinct** URLs.
|
|
292
|
+
|
|
293
|
+
**Changed (architecture)**
|
|
294
|
+
- Release discovery, post linting, entry publication, and manifest updates moved from
|
|
295
|
+
~20 hand-rolled SKILL.md bash steps into tested CLI subcommands (`scan`, `lint-post`,
|
|
296
|
+
`publish-entry`) backed by new `lib/` modules. Tag names and semver/range logic no
|
|
297
|
+
longer pass through the LLM's shell at all (spawnSync argv only), entry existence is
|
|
298
|
+
one GitHub API call per project instead of one per tag, and the
|
|
299
|
+
never-overwrite-a-published-entry guard is now code-enforced in `publish-entry`.
|
|
300
|
+
- SKILL.md restructured around three modes — Configure / Status / Generate — and the
|
|
301
|
+
generate flow prints the release plan up front before any research starts.
|
|
302
|
+
|
|
303
|
+
**Added**
|
|
304
|
+
- Agent-native configuration: `add-project --yes` (non-interactive, auto-detects
|
|
305
|
+
key/remote), `remove-project <key> --yes`, `set <field> <value>` (targetRepo, branch,
|
|
306
|
+
gitAuthor, githubUser, voicePath, deepDive.minSources, deepDive.topicDomains), and
|
|
307
|
+
`config --json`. `/devlog` now handles "add this repo", "stop tracking X", "set min
|
|
308
|
+
sources to 4", and `/devlog status` conversationally.
|
|
309
|
+
- `deepDive` config validation (minSources integer 1-10, topicDomains non-empty strings).
|
|
310
|
+
- Deterministic test suites for the new core (fixture git repos for scan; manifest
|
|
311
|
+
ordering incl. backported tags; overwrite refusal; config ops) plus a skill-contract
|
|
312
|
+
suite (`skill-invariants.json`) that pins SKILL.md's prose guardrails, its CLI surface,
|
|
313
|
+
and package.json↔CHANGELOG version agreement.
|
|
314
|
+
- Cost-capped eval harness under `evals/` for the non-deterministic half: a $0
|
|
315
|
+
deterministic layer (lint-post) plus an LLM judge scoring reproducibility, code
|
|
316
|
+
completeness, gotcha quality, citations, voice, and scope honesty against golden
|
|
317
|
+
fixtures. Mock mode runs in CI for free; live runs are hard-capped (default $0.50) and
|
|
318
|
+
refuse to start over budget.
|
|
319
|
+
|
|
320
|
+
## 0.4.2 (2026-07-10) — ghostwriter voice-fallback path fix
|
|
321
|
+
|
|
322
|
+
**Fixed**
|
|
323
|
+
- The ghostwriter voice-fallback path (`GHOSTWRITER_VOICE_DIR` / Step 2 of voice resolution) now
|
|
324
|
+
points at `~/.claude/ghostwriter/voice`, matching ghostwriter's new shared home-directory
|
|
325
|
+
location (previously `~/.claude/skills/ghostwriter/voice`, which was never ghostwriter's real
|
|
326
|
+
install path). devlog's own config location (`~/.claude/skills/devlog/config.json`) is
|
|
327
|
+
unchanged.
|
|
328
|
+
|
|
329
|
+
## 0.4.1 (2026-07-11) — plugin marketplace discovery fix
|
|
330
|
+
|
|
331
|
+
**Fixed**
|
|
332
|
+
- The skill was not discoverable when installed via the Claude Code plugin marketplace
|
|
333
|
+
(Claude Desktop's plugin UI showed no skills). `SKILL.md` now lives at the plugin's
|
|
334
|
+
documented `skills/devlog/SKILL.md` auto-discovery path instead of the plugin root.
|
|
335
|
+
|
|
336
|
+
## 0.4.0 (2026-06-28) — researched, end-to-end implementation-guide posts
|
|
337
|
+
|
|
338
|
+
**Changed**
|
|
339
|
+
- `/devlog` now writes each release entry as a researched, cited, end-to-end
|
|
340
|
+
implementation guide rather than a narrative summary of what shipped. Step 6
|
|
341
|
+
derives the engineering topic(s) the work touched, researches them against
|
|
342
|
+
reputable outside sources (cited inline and in a `## Sources` section), and
|
|
343
|
+
writes a setup → build → use → verify walkthrough with multiple
|
|
344
|
+
copy-paste-reusable, language-tagged code blocks that together form a complete,
|
|
345
|
+
runnable whole (right-sized: roughly 3-6 essential blocks for a substantive
|
|
346
|
+
feature, fewer for a small change, never padded). A short `## Shipped` hook
|
|
347
|
+
still opens the post and `## Changelog` still closes it. Updated the skill
|
|
348
|
+
description and the Step 6 / 6a-6c guidance accordingly.
|
|
349
|
+
|
|
350
|
+
**Added**
|
|
351
|
+
- `deepDive` config block: `topicDomains` (default: AI, DevOps/SRE, software
|
|
352
|
+
engineering) and `minSources` (default 2) to steer topic selection and the
|
|
353
|
+
citation floor. Repo-agnostic; user-supplied values live in `config.json`.
|
|
354
|
+
|
|
355
|
+
## 0.3.1 (2026-06-20) — fetch tags before discovering releases
|
|
356
|
+
|
|
357
|
+
**Fixed**
|
|
358
|
+
- `/devlog` now runs a best-effort `git fetch --tags --quiet` per project at the
|
|
359
|
+
start of release discovery (Step 3), before listing tags. Releases are
|
|
360
|
+
commonly cut by CI on the remote (a version-driven GitHub Release on green
|
|
361
|
+
`main`/`master`), so the tag is born on the remote; a local clone that hadn't
|
|
362
|
+
fetched would list only stale local tags and silently report "no new release"
|
|
363
|
+
for a release that was already live. The fetch is best-effort: on failure
|
|
364
|
+
(offline, no remote, auth prompt) it notes the failure and proceeds on local
|
|
365
|
+
tags rather than aborting. `--tags` takes no untrusted input and `project.path`
|
|
366
|
+
is validated + single-quoted per Step 0.5.
|
|
367
|
+
|
|
368
|
+
## 0.3.0 (2026-06-18) — release-focused entries, written in your voice
|
|
369
|
+
|
|
370
|
+
**Changed (behavior)**
|
|
371
|
+
- `/devlog` now generates one entry **per version release** (a semver git tag) instead of
|
|
372
|
+
one entry per day. An entry summarizes the commits in a release's tag range
|
|
373
|
+
(`<prevTag>..<thisTag>`), scoped by `pathFilter` when present. The run is **idempotent**:
|
|
374
|
+
a release's entry is written once and never overwritten, and re-running produces nothing
|
|
375
|
+
until a new tag is cut. The per-day "Update — HH:MM" append mode is removed.
|
|
376
|
+
- Entries are keyed by version: `<project-key>/<version>.md` (e.g. `v0.2.0.md`), with a
|
|
377
|
+
`version` field added to the frontmatter and to each `manifest.json` entry. Entry sections
|
|
378
|
+
are now **What Shipped / What's Next / Commits**. The entry `date` is the tag's commit date.
|
|
379
|
+
|
|
380
|
+
**Added**
|
|
381
|
+
- **Voice-driven publishing.** Entries are written in the user's voice using a voice profile
|
|
382
|
+
resolved in this order: `config.voicePath` → `~/.claude/skills/ghostwriter/voice` (if
|
|
383
|
+
installed) → a bundled fallback at `~/.claude/skills/devlog/voice/`. devlog reads
|
|
384
|
+
`voice-profile.md` and `voice-notes.md` (overrides) — and never `algorithm.md`, since
|
|
385
|
+
LinkedIn reach tuning does not apply to a dev log.
|
|
386
|
+
- `voicePath` (top-level, optional) and `projects[].tagPrefix` (optional, default `v`) config
|
|
387
|
+
fields, with security validation in both `bin/devlog.js` and SKILL.md. `tagPrefix` lets each
|
|
388
|
+
project in a monorepo detect its own releases (e.g. `devlog-v`, `ghostwriter-v`).
|
|
389
|
+
- `init` prompts for the voice directory and release tag prefix, and installs the bundled
|
|
390
|
+
voice template. `config` shows the voice path and each project's tag pattern.
|
|
391
|
+
- The React example carries the optional `version` field through frontmatter parsing and
|
|
392
|
+
manifest validation.
|
|
393
|
+
|
|
394
|
+
**Migration note:** existing per-day `YYYY-MM-DD.md` entries are left untouched; new entries
|
|
395
|
+
are per-release. To detect a monorepo project's releases, set its `tagPrefix`.
|
|
396
|
+
|
|
397
|
+
## 0.2.0 (2026-06-08) — monorepo subdirectory filtering
|
|
398
|
+
|
|
399
|
+
**Added**
|
|
400
|
+
- `projects[].pathFilter` config field: scope a project's commits to a repo-relative
|
|
401
|
+
subdirectory (e.g. `skills/devlog`). Lets several logical projects share one monorepo
|
|
402
|
+
`path`/`remote` while each collects only its own subtree's commits. `git log` gains a
|
|
403
|
+
`-- <pathFilter>` pathspec; commit links still resolve to `<remote>/commit/<hash>`.
|
|
404
|
+
- SKILL.md documents the field, its security validation (no leading `-`/`/`, no `..`,
|
|
405
|
+
single-quoted), and the multi-skill monorepo workflow.
|
|
406
|
+
- `bin/devlog.js` validates `pathFilter` and shows it as `scope:` in `devlog config`.
|
|
407
|
+
|
|
408
|
+
## 0.1.9 (2026-06-05) — accessibility fix
|
|
409
|
+
|
|
410
|
+
**Accessibility**
|
|
411
|
+
- The drop-in React component (`examples/react/DevLogPage.jsx`) now exposes the expand/collapse entries as a proper disclosure control. Previously they were mouse-only — a bare `onClick` on `<article>` with no `role`, `tabIndex`, `aria-expanded`, or keyboard handler, so keyboard and screen-reader users could not operate the feed.
|
|
412
|
+
- The header carries `role="button"`, `tabIndex={0}`, `aria-expanded`, and `aria-controls` for screen-reader toggle semantics.
|
|
413
|
+
- `Enter`/`Space` toggle the focused entry (`preventDefault` on Space stops page scroll).
|
|
414
|
+
- `:focus-visible` outline makes keyboard focus visible.
|
|
415
|
+
- The toggle moved from the whole card to the header, so links inside an expanded entry are no longer nested in an interactive ancestor and text selection in the body works normally.
|
|
416
|
+
- Visuals are unchanged: padding/hover/cursor moved from `.devlog-entry` to `.devlog-header`, with the redundant content padding zeroed so spacing matches.
|
|
417
|
+
|
|
418
|
+
## 0.1.8 (2026-05-01) — final hardening pass
|
|
419
|
+
|
|
420
|
+
Closes the four Low-Hardening findings from the second adversarial verification:
|
|
421
|
+
|
|
422
|
+
- **L-1:** `validateConfig` now bounds `projects[].label` length (≤200 chars) and rejects control characters. Label apostrophes/quotes/etc are intentionally allowed since label is React text content only — never shell-interpolated. The validator includes an explicit invariant comment to keep this guarantee load-bearing.
|
|
423
|
+
- **L-2:** `atomicWriteJSON` uses `wx` (exclusive create) flag, preventing symlink-attack scenarios on shared filesystems where another local user could pre-create the tmp file.
|
|
424
|
+
- **L-3:** `atomicWriteJSON` tmp filename now also includes `Date.now()` for additional uniqueness across rapid sequential calls.
|
|
425
|
+
- **L-4:** SKILL.md Step 5 explicitly instructs the LLM to treat fetched dev-log content as data, not instructions — defense against indirect prompt injection from hostile dev-log markdown.
|
|
426
|
+
|
|
427
|
+
Verification: a second 6-perspective adversarial agent against HEAD reports zero Critical/High/Medium-Active vulnerabilities remain.
|
|
428
|
+
|
|
429
|
+
## 0.1.7 (2026-05-01) — security hardening + UX improvements
|
|
430
|
+
|
|
431
|
+
**Security**
|
|
432
|
+
- Tightened `SHELL_METACHARS` to additionally reject whitespace, single-quote, square brackets, equals, and percent
|
|
433
|
+
- Project paths now cannot start with `-` (would be parsed as flag)
|
|
434
|
+
- Added strict validation of the `branch` field (no leading dash, no `..` as a path component)
|
|
435
|
+
- Atomic `config.json` writes (write-to-tmp + rename)
|
|
436
|
+
- CLI no longer forwards arbitrary `VITE_*` env vars to the spawned vite — only `VITE_DEVLOG_*` plus `PATH`/`HOME`/etc.
|
|
437
|
+
- Added `Content-Security-Policy` meta tag to the preview app
|
|
438
|
+
- Explicit `urlTransform` in `react-markdown` rejects `data:`, `blob:`, `javascript:`, `vbscript:`, `file:`, and any non-http(s)/mailto scheme
|
|
439
|
+
- `react-markdown` invoked with `skipHtml` for explicit defense-in-depth
|
|
440
|
+
- `SKILL.md` instructs the LLM to single-quote every interpolated config value (defense-in-depth on top of validation)
|
|
441
|
+
- Production preview builds without env vars show a clear "Setup required" screen instead of attempting demo fetches that would 404
|
|
442
|
+
- `config.json` written with mode `0600`, `~/.claude/skills/devlog/` created with mode `0700`
|
|
443
|
+
- Pinned all dependencies to exact versions (no `^` ranges) to eliminate resolution drift
|
|
444
|
+
|
|
445
|
+
**UX**
|
|
446
|
+
- `init` now loops to register multiple projects in a single setup
|
|
447
|
+
- New `add-project` subcommand: `npx @natjswenson/devlog add-project` — register a project without editing config.json by hand
|
|
448
|
+
- New `config` subcommand: `npx @natjswenson/devlog config` — view current config with validation status
|
|
449
|
+
- Init detects when `gh` is authenticated as a different user than `githubUser` and warns
|
|
450
|
+
- Better next-step messaging after init (color, concrete commands)
|
|
451
|
+
- All error messages now include actionable hints (`log.hint`)
|
|
452
|
+
|
|
453
|
+
**Docs**
|
|
454
|
+
- New `SECURITY.md` — threat model, audit history, ruled-out attack scenarios, vulnerability reporting flow
|
|
455
|
+
- New `CHANGELOG.md` (this file)
|
|
456
|
+
- README updated with new subcommands and security guarantees section
|
|
457
|
+
|
|
458
|
+
## 0.1.6 (2026-05-01) — initial security audit fixes
|
|
459
|
+
|
|
460
|
+
Addressed 1 Critical + 3 High findings from the first round of the 6-agent siege:
|
|
461
|
+
- SKILL.md now requires runtime allowlist validation of every config value before shell interpolation
|
|
462
|
+
- CLI switched from `execSync` with template strings to `spawnSync` with argv arrays for any user-input-bearing call
|
|
463
|
+
- `gh repo create` regex hardened against leading-dash flag injection
|
|
464
|
+
- `gitAuthor` validator now rejects shell metachars
|
|
465
|
+
- Schema validation added for `manifest.json`, `VITE_DEVLOG_PROJECTS`, frontmatter (allowlist + `Object.create(null)`)
|
|
466
|
+
- `optimizeDeps` includes for vite to fix react-markdown / react-dom CJS interop in npx layouts
|
|
467
|
+
- Preview vite server bound to localhost only, CORS disabled
|
|
468
|
+
|
|
469
|
+
## 0.1.5 (2026-05-01)
|
|
470
|
+
|
|
471
|
+
- Corrected live-site URL in README (`natejswenson.com` not `.io`)
|
|
472
|
+
|
|
473
|
+
## 0.1.4 (2026-05-01)
|
|
474
|
+
|
|
475
|
+
- README troubleshooting section, npm + license badges
|
|
476
|
+
- SKILL.md uses `<config.branch || 'main'>` consistently in push/URL output
|
|
477
|
+
|
|
478
|
+
## 0.1.3 (2026-05-01)
|
|
479
|
+
|
|
480
|
+
- Expanded `optimizeDeps.include` to cover react/react-dom for npx-installed layouts
|
|
481
|
+
|
|
482
|
+
## 0.1.2 (2026-05-01)
|
|
483
|
+
|
|
484
|
+
- First `optimizeDeps` fix for `style-to-js` CJS/ESM interop (react-markdown rendering)
|
|
485
|
+
|
|
486
|
+
## 0.1.1 (2026-05-01)
|
|
487
|
+
|
|
488
|
+
- `projects[].label` and `branch` config fields (optional, with safe defaults)
|
|
489
|
+
|
|
490
|
+
## 0.1.0 (2026-05-01)
|
|
491
|
+
|
|
492
|
+
- Initial release
|
|
493
|
+
- CLI: `init`, `preview`
|
|
494
|
+
- React drop-in components: `DevLogPage`, `useDevLogEntries`
|
|
495
|
+
- Standalone deployable Vite preview app with snarky demo mode
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nate Swenson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|