@natjswenson/devlog 0.4.0 → 0.4.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/package.json +1 -1
- package/CHANGELOG.md +0 -164
- package/LICENSE +0 -21
- package/README.md +0 -240
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@natjswenson/devlog",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Release dev log generator \u2014 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",
|
package/CHANGELOG.md
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to `@natjswenson/devlog` are documented here.
|
|
4
|
-
|
|
5
|
-
## 0.4.0 (2026-06-28) — researched, end-to-end implementation-guide posts
|
|
6
|
-
|
|
7
|
-
**Changed**
|
|
8
|
-
- `/devlog` now writes each release entry as a researched, cited, end-to-end
|
|
9
|
-
implementation guide rather than a narrative summary of what shipped. Step 6
|
|
10
|
-
derives the engineering topic(s) the work touched, researches them against
|
|
11
|
-
reputable outside sources (cited inline and in a `## Sources` section), and
|
|
12
|
-
writes a setup → build → use → verify walkthrough with multiple
|
|
13
|
-
copy-paste-reusable, language-tagged code blocks that together form a complete,
|
|
14
|
-
runnable whole (right-sized: roughly 3-6 essential blocks for a substantive
|
|
15
|
-
feature, fewer for a small change, never padded). A short `## Shipped` hook
|
|
16
|
-
still opens the post and `## Changelog` still closes it. Updated the skill
|
|
17
|
-
description and the Step 6 / 6a-6c guidance accordingly.
|
|
18
|
-
|
|
19
|
-
**Added**
|
|
20
|
-
- `deepDive` config block: `topicDomains` (default: AI, DevOps/SRE, software
|
|
21
|
-
engineering) and `minSources` (default 2) to steer topic selection and the
|
|
22
|
-
citation floor. Repo-agnostic; user-supplied values live in `config.json`.
|
|
23
|
-
|
|
24
|
-
## 0.3.1 (2026-06-20) — fetch tags before discovering releases
|
|
25
|
-
|
|
26
|
-
**Fixed**
|
|
27
|
-
- `/devlog` now runs a best-effort `git fetch --tags --quiet` per project at the
|
|
28
|
-
start of release discovery (Step 3), before listing tags. Releases are
|
|
29
|
-
commonly cut by CI on the remote (a version-driven GitHub Release on green
|
|
30
|
-
`main`/`master`), so the tag is born on the remote; a local clone that hadn't
|
|
31
|
-
fetched would list only stale local tags and silently report "no new release"
|
|
32
|
-
for a release that was already live. The fetch is best-effort: on failure
|
|
33
|
-
(offline, no remote, auth prompt) it notes the failure and proceeds on local
|
|
34
|
-
tags rather than aborting. `--tags` takes no untrusted input and `project.path`
|
|
35
|
-
is validated + single-quoted per Step 0.5.
|
|
36
|
-
|
|
37
|
-
## 0.3.0 (2026-06-18) — release-focused entries, written in your voice
|
|
38
|
-
|
|
39
|
-
**Changed (behavior)**
|
|
40
|
-
- `/devlog` now generates one entry **per version release** (a semver git tag) instead of
|
|
41
|
-
one entry per day. An entry summarizes the commits in a release's tag range
|
|
42
|
-
(`<prevTag>..<thisTag>`), scoped by `pathFilter` when present. The run is **idempotent**:
|
|
43
|
-
a release's entry is written once and never overwritten, and re-running produces nothing
|
|
44
|
-
until a new tag is cut. The per-day "Update — HH:MM" append mode is removed.
|
|
45
|
-
- Entries are keyed by version: `<project-key>/<version>.md` (e.g. `v0.2.0.md`), with a
|
|
46
|
-
`version` field added to the frontmatter and to each `manifest.json` entry. Entry sections
|
|
47
|
-
are now **What Shipped / What's Next / Commits**. The entry `date` is the tag's commit date.
|
|
48
|
-
|
|
49
|
-
**Added**
|
|
50
|
-
- **Voice-driven publishing.** Entries are written in the user's voice using a voice profile
|
|
51
|
-
resolved in this order: `config.voicePath` → `~/.claude/skills/ghostwriter/voice` (if
|
|
52
|
-
installed) → a bundled fallback at `~/.claude/skills/devlog/voice/`. devlog reads
|
|
53
|
-
`voice-profile.md` and `voice-notes.md` (overrides) — and never `algorithm.md`, since
|
|
54
|
-
LinkedIn reach tuning does not apply to a dev log.
|
|
55
|
-
- `voicePath` (top-level, optional) and `projects[].tagPrefix` (optional, default `v`) config
|
|
56
|
-
fields, with security validation in both `bin/devlog.js` and SKILL.md. `tagPrefix` lets each
|
|
57
|
-
project in a monorepo detect its own releases (e.g. `devlog-v`, `ghostwriter-v`).
|
|
58
|
-
- `init` prompts for the voice directory and release tag prefix, and installs the bundled
|
|
59
|
-
voice template. `config` shows the voice path and each project's tag pattern.
|
|
60
|
-
- The React example carries the optional `version` field through frontmatter parsing and
|
|
61
|
-
manifest validation.
|
|
62
|
-
|
|
63
|
-
**Migration note:** existing per-day `YYYY-MM-DD.md` entries are left untouched; new entries
|
|
64
|
-
are per-release. To detect a monorepo project's releases, set its `tagPrefix`.
|
|
65
|
-
|
|
66
|
-
## 0.2.0 (2026-06-08) — monorepo subdirectory filtering
|
|
67
|
-
|
|
68
|
-
**Added**
|
|
69
|
-
- `projects[].pathFilter` config field: scope a project's commits to a repo-relative
|
|
70
|
-
subdirectory (e.g. `skills/devlog`). Lets several logical projects share one monorepo
|
|
71
|
-
`path`/`remote` while each collects only its own subtree's commits. `git log` gains a
|
|
72
|
-
`-- <pathFilter>` pathspec; commit links still resolve to `<remote>/commit/<hash>`.
|
|
73
|
-
- SKILL.md documents the field, its security validation (no leading `-`/`/`, no `..`,
|
|
74
|
-
single-quoted), and the multi-skill monorepo workflow.
|
|
75
|
-
- `bin/devlog.js` validates `pathFilter` and shows it as `scope:` in `devlog config`.
|
|
76
|
-
|
|
77
|
-
## 0.1.9 (2026-06-05) — accessibility fix
|
|
78
|
-
|
|
79
|
-
**Accessibility**
|
|
80
|
-
- 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.
|
|
81
|
-
- The header carries `role="button"`, `tabIndex={0}`, `aria-expanded`, and `aria-controls` for screen-reader toggle semantics.
|
|
82
|
-
- `Enter`/`Space` toggle the focused entry (`preventDefault` on Space stops page scroll).
|
|
83
|
-
- `:focus-visible` outline makes keyboard focus visible.
|
|
84
|
-
- 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.
|
|
85
|
-
- Visuals are unchanged: padding/hover/cursor moved from `.devlog-entry` to `.devlog-header`, with the redundant content padding zeroed so spacing matches.
|
|
86
|
-
|
|
87
|
-
## 0.1.8 (2026-05-01) — final hardening pass
|
|
88
|
-
|
|
89
|
-
Closes the four Low-Hardening findings from the second adversarial verification:
|
|
90
|
-
|
|
91
|
-
- **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.
|
|
92
|
-
- **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.
|
|
93
|
-
- **L-3:** `atomicWriteJSON` tmp filename now also includes `Date.now()` for additional uniqueness across rapid sequential calls.
|
|
94
|
-
- **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.
|
|
95
|
-
|
|
96
|
-
Verification: a second 6-perspective adversarial agent against HEAD reports zero Critical/High/Medium-Active vulnerabilities remain.
|
|
97
|
-
|
|
98
|
-
## 0.1.7 (2026-05-01) — security hardening + UX improvements
|
|
99
|
-
|
|
100
|
-
**Security**
|
|
101
|
-
- Tightened `SHELL_METACHARS` to additionally reject whitespace, single-quote, square brackets, equals, and percent
|
|
102
|
-
- Project paths now cannot start with `-` (would be parsed as flag)
|
|
103
|
-
- Added strict validation of the `branch` field (no leading dash, no `..` as a path component)
|
|
104
|
-
- Atomic `config.json` writes (write-to-tmp + rename)
|
|
105
|
-
- CLI no longer forwards arbitrary `VITE_*` env vars to the spawned vite — only `VITE_DEVLOG_*` plus `PATH`/`HOME`/etc.
|
|
106
|
-
- Added `Content-Security-Policy` meta tag to the preview app
|
|
107
|
-
- Explicit `urlTransform` in `react-markdown` rejects `data:`, `blob:`, `javascript:`, `vbscript:`, `file:`, and any non-http(s)/mailto scheme
|
|
108
|
-
- `react-markdown` invoked with `skipHtml` for explicit defense-in-depth
|
|
109
|
-
- `SKILL.md` instructs the LLM to single-quote every interpolated config value (defense-in-depth on top of validation)
|
|
110
|
-
- Production preview builds without env vars show a clear "Setup required" screen instead of attempting demo fetches that would 404
|
|
111
|
-
- `config.json` written with mode `0600`, `~/.claude/skills/devlog/` created with mode `0700`
|
|
112
|
-
- Pinned all dependencies to exact versions (no `^` ranges) to eliminate resolution drift
|
|
113
|
-
|
|
114
|
-
**UX**
|
|
115
|
-
- `init` now loops to register multiple projects in a single setup
|
|
116
|
-
- New `add-project` subcommand: `npx @natjswenson/devlog add-project` — register a project without editing config.json by hand
|
|
117
|
-
- New `config` subcommand: `npx @natjswenson/devlog config` — view current config with validation status
|
|
118
|
-
- Init detects when `gh` is authenticated as a different user than `githubUser` and warns
|
|
119
|
-
- Better next-step messaging after init (color, concrete commands)
|
|
120
|
-
- All error messages now include actionable hints (`log.hint`)
|
|
121
|
-
|
|
122
|
-
**Docs**
|
|
123
|
-
- New `SECURITY.md` — threat model, audit history, ruled-out attack scenarios, vulnerability reporting flow
|
|
124
|
-
- New `CHANGELOG.md` (this file)
|
|
125
|
-
- README updated with new subcommands and security guarantees section
|
|
126
|
-
|
|
127
|
-
## 0.1.6 (2026-05-01) — initial security audit fixes
|
|
128
|
-
|
|
129
|
-
Addressed 1 Critical + 3 High findings from the first round of the 6-agent siege:
|
|
130
|
-
- SKILL.md now requires runtime allowlist validation of every config value before shell interpolation
|
|
131
|
-
- CLI switched from `execSync` with template strings to `spawnSync` with argv arrays for any user-input-bearing call
|
|
132
|
-
- `gh repo create` regex hardened against leading-dash flag injection
|
|
133
|
-
- `gitAuthor` validator now rejects shell metachars
|
|
134
|
-
- Schema validation added for `manifest.json`, `VITE_DEVLOG_PROJECTS`, frontmatter (allowlist + `Object.create(null)`)
|
|
135
|
-
- `optimizeDeps` includes for vite to fix react-markdown / react-dom CJS interop in npx layouts
|
|
136
|
-
- Preview vite server bound to localhost only, CORS disabled
|
|
137
|
-
|
|
138
|
-
## 0.1.5 (2026-05-01)
|
|
139
|
-
|
|
140
|
-
- Corrected live-site URL in README (`natejswenson.com` not `.io`)
|
|
141
|
-
|
|
142
|
-
## 0.1.4 (2026-05-01)
|
|
143
|
-
|
|
144
|
-
- README troubleshooting section, npm + license badges
|
|
145
|
-
- SKILL.md uses `<config.branch || 'main'>` consistently in push/URL output
|
|
146
|
-
|
|
147
|
-
## 0.1.3 (2026-05-01)
|
|
148
|
-
|
|
149
|
-
- Expanded `optimizeDeps.include` to cover react/react-dom for npx-installed layouts
|
|
150
|
-
|
|
151
|
-
## 0.1.2 (2026-05-01)
|
|
152
|
-
|
|
153
|
-
- First `optimizeDeps` fix for `style-to-js` CJS/ESM interop (react-markdown rendering)
|
|
154
|
-
|
|
155
|
-
## 0.1.1 (2026-05-01)
|
|
156
|
-
|
|
157
|
-
- `projects[].label` and `branch` config fields (optional, with safe defaults)
|
|
158
|
-
|
|
159
|
-
## 0.1.0 (2026-05-01)
|
|
160
|
-
|
|
161
|
-
- Initial release
|
|
162
|
-
- CLI: `init`, `preview`
|
|
163
|
-
- React drop-in components: `DevLogPage`, `useDevLogEntries`
|
|
164
|
-
- Standalone deployable Vite preview app with snarky demo mode
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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.
|
package/README.md
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
# devlog
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@natjswenson/devlog)
|
|
4
|
-
[](./LICENSE)
|
|
5
|
-
[](./SECURITY.md)
|
|
6
|
-
[](#security)
|
|
7
|
-
|
|
8
|
-
A Claude Code skill that turns each version release (a git tag) into a published dev log entry, written in your own voice — and a React example for displaying it on your site.
|
|
9
|
-
|
|
10
|
-
> **Build in public, by release.** Tag a release like you always do. Run `/devlog`. Each new version shows up on your site as a narrative entry — in your voice — not raw commit messages.
|
|
11
|
-
|
|
12
|
-
## Live example
|
|
13
|
-
|
|
14
|
-
The skill is in production at [natejswenson.com/devlog](https://natejswenson.com/devlog), publishing to [github.com/natejswenson/daily-dev-log](https://github.com/natejswenson/daily-dev-log). What you see on that page is exactly what `npx @natjswenson/devlog preview` renders for you locally.
|
|
15
|
-
|
|
16
|
-
## How it works
|
|
17
|
-
|
|
18
|
-
1. **You ship a release** — tag it (e.g. `git tag v0.3.0`), like you already do.
|
|
19
|
-
2. **Run `/devlog` in Claude Code.** The skill finds tags that don't yet have an entry, summarizes each release's changes into a narrative markdown entry written in your voice, and pushes it to your dev-log GitHub repo. It's idempotent — re-running does nothing until you cut a new release.
|
|
20
|
-
3. **Your site fetches it.** Static `manifest.json` + per-release markdown files served from `raw.githubusercontent.com` — no backend needed.
|
|
21
|
-
|
|
22
|
-
**In your voice.** Entries are written using a voice profile, resolved in this order: your `config.voicePath` → [ghostwriter](../ghostwriter)'s `voice/` dir if installed → a bundled default. devlog reads `voice-profile.md` (and `voice-notes.md` overrides) — never ghostwriter's `algorithm.md`, since LinkedIn reach tuning doesn't apply to a dev log.
|
|
23
|
-
|
|
24
|
-
## Quick start
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
npx @natjswenson/devlog init
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
That command:
|
|
31
|
-
- Creates `<your-username>/daily-dev-log` on GitHub (or uses an existing one)
|
|
32
|
-
- Installs the skill at `~/.claude/skills/devlog/`
|
|
33
|
-
- Writes `~/.claude/skills/devlog/config.json` with your answers
|
|
34
|
-
- Lets you register one or more projects in a single run
|
|
35
|
-
|
|
36
|
-
Then:
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
npx @natjswenson/devlog preview
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
to see your dev log rendered locally at `http://localhost:5173`.
|
|
43
|
-
|
|
44
|
-
## Prerequisites
|
|
45
|
-
|
|
46
|
-
- **Node 18+** — for the CLI and preview app
|
|
47
|
-
- **GitHub CLI** (`gh`), authenticated with `gh auth login` — used to create your dev-log repo and push entries
|
|
48
|
-
- **Claude Code** — to run the `/devlog` skill
|
|
49
|
-
|
|
50
|
-
## Commands
|
|
51
|
-
|
|
52
|
-
| Command | What it does |
|
|
53
|
-
|---|---|
|
|
54
|
-
| `npx @natjswenson/devlog init` | One-time setup: create dev-log repo, install skill, write config |
|
|
55
|
-
| `npx @natjswenson/devlog add-project` | Register an additional project without editing config.json by hand |
|
|
56
|
-
| `npx @natjswenson/devlog config` | Show your current config with validation status |
|
|
57
|
-
| `npx @natjswenson/devlog preview` | Run a local preview at `http://localhost:5173` |
|
|
58
|
-
| `npx @natjswenson/devlog --help` | Usage |
|
|
59
|
-
| `npx @natjswenson/devlog --version` | Version |
|
|
60
|
-
|
|
61
|
-
> **Tip:** run from any directory *outside* a clone of this repo. Running inside the repo causes a `package.json` name collision and `npx` fails with `command not found`.
|
|
62
|
-
|
|
63
|
-
## What you end up with
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
~/.claude/skills/devlog/
|
|
67
|
-
├── SKILL.md # The /devlog slash-command instructions
|
|
68
|
-
├── config.json # Your settings (mode 0600)
|
|
69
|
-
└── voice/ # Bundled fallback voice profile (last resort)
|
|
70
|
-
├── voice-profile.md
|
|
71
|
-
└── voice-notes.md
|
|
72
|
-
|
|
73
|
-
github.com/<you>/daily-dev-log/ # Created by init, populated by /devlog
|
|
74
|
-
├── myproject/
|
|
75
|
-
│ ├── manifest.json
|
|
76
|
-
│ ├── v0.3.0.md
|
|
77
|
-
│ ├── v0.2.0.md
|
|
78
|
-
│ └── ...
|
|
79
|
-
└── ...
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Manual setup (if you prefer)
|
|
83
|
-
|
|
84
|
-
```sh
|
|
85
|
-
gh repo create <you>/daily-dev-log --public --add-readme
|
|
86
|
-
mkdir -p ~/.claude/skills/devlog/voice
|
|
87
|
-
curl -o ~/.claude/skills/devlog/SKILL.md https://raw.githubusercontent.com/natejswenson/devlog/main/SKILL.md
|
|
88
|
-
# Optional fallback voice profile (used when voicePath and ghostwriter are both absent):
|
|
89
|
-
curl -o ~/.claude/skills/devlog/voice/voice-profile.md https://raw.githubusercontent.com/natejswenson/devlog/main/voice/voice-profile.example.md
|
|
90
|
-
curl -o ~/.claude/skills/devlog/voice/voice-notes.md https://raw.githubusercontent.com/natejswenson/devlog/main/voice/voice-notes.example.md
|
|
91
|
-
# Then copy config.example.json → ~/.claude/skills/devlog/config.json and fill it in
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Add to your site
|
|
95
|
-
|
|
96
|
-
### React (drop-in)
|
|
97
|
-
|
|
98
|
-
```sh
|
|
99
|
-
cp -r examples/react/ your-site/src/devlog/
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Edit `your-site/src/devlog/devlog-config.js` to point at your repo, then:
|
|
103
|
-
|
|
104
|
-
```jsx
|
|
105
|
-
import DevLogPage from './devlog/DevLogPage.jsx';
|
|
106
|
-
|
|
107
|
-
<DevLogPage project="myproject" />
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Full instructions: [`examples/react/README.md`](./examples/react/README.md).
|
|
111
|
-
|
|
112
|
-
### No site yet?
|
|
113
|
-
|
|
114
|
-
The `preview/` directory is a complete deployable Vite app. Set `VITE_DEVLOG_OWNER` / `VITE_DEVLOG_REPO` / `VITE_DEVLOG_PROJECTS` env vars on Vercel, Netlify, or Cloudflare Pages, build with `vite build`, deploy `dist/`. See [`preview/README.md`](./preview/README.md).
|
|
115
|
-
|
|
116
|
-
### Other stacks (Next, Astro, plain HTML)
|
|
117
|
-
|
|
118
|
-
It's static JSON and Markdown on GitHub. Build whatever UI you want — see the **Data contract** below.
|
|
119
|
-
|
|
120
|
-
## Data contract
|
|
121
|
-
|
|
122
|
-
The dev-log repo has this layout, all served as raw files from `https://raw.githubusercontent.com/<owner>/<repo>/<branch>/`:
|
|
123
|
-
|
|
124
|
-
```
|
|
125
|
-
<repo>/
|
|
126
|
-
└── <project-key>/
|
|
127
|
-
├── manifest.json # Index of all entries (newest first)
|
|
128
|
-
├── v0.3.0.md # One entry per release (named by version)
|
|
129
|
-
├── v0.2.0.md
|
|
130
|
-
└── ...
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
**`manifest.json`:**
|
|
134
|
-
```json
|
|
135
|
-
{
|
|
136
|
-
"entries": [
|
|
137
|
-
{ "date": "2026-06-08", "file": "v0.2.0.md", "title": "...", "summary": "...", "version": "v0.2.0" }
|
|
138
|
-
]
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Strict validation rules (entries that don't match are silently dropped by the React example):
|
|
143
|
-
- `date` matches `YYYY-MM-DD` (the release/tag date)
|
|
144
|
-
- `file` matches `^[a-zA-Z0-9._-]+\.md$`
|
|
145
|
-
- `title` and `summary` are non-empty strings
|
|
146
|
-
- `version` (optional) matches `^[a-zA-Z0-9._-]+$`
|
|
147
|
-
|
|
148
|
-
**Entry markdown:**
|
|
149
|
-
|
|
150
|
-
```markdown
|
|
151
|
-
---
|
|
152
|
-
title: "Concise release summary"
|
|
153
|
-
date: 2026-06-08
|
|
154
|
-
project: myproject
|
|
155
|
-
version: v0.2.0
|
|
156
|
-
summary: "1-2 sentence summary"
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## What Shipped
|
|
160
|
-
Narrative paragraphs, written in your voice.
|
|
161
|
-
|
|
162
|
-
## What's Next
|
|
163
|
-
Forward-looking note.
|
|
164
|
-
|
|
165
|
-
## Commits
|
|
166
|
-
- commit message ([abc1234](https://github.com/.../commit/abc1234567...))
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
That's the entire contract.
|
|
170
|
-
|
|
171
|
-
## Configuration reference
|
|
172
|
-
|
|
173
|
-
`~/.claude/skills/devlog/config.json`:
|
|
174
|
-
|
|
175
|
-
| Field | Type | Description |
|
|
176
|
-
|---|---|---|
|
|
177
|
-
| `targetRepo` | `"<owner>/<repo>"` | Repo where dev log entries are published. Must match `^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$`. |
|
|
178
|
-
| `branch` | string (optional) | Branch in the dev-log repo. Defaults to `main`. Must not contain `..` or start with `-`. |
|
|
179
|
-
| `gitAuthor` | string | Your name. Retained for backward compatibility; it is **not** currently rendered on entries (the author filter was removed, and release notes summarize all commits in a tag range). Still **required** by config validation — it must be present and non-empty (don't drop it). Whitespace OK; no shell metacharacters. |
|
|
180
|
-
| `githubUser` | string | Your GitHub username. |
|
|
181
|
-
| `voicePath` | string (optional) | Directory holding `voice-profile.md` (and optionally `voice-notes.md`) used to write entries in your voice. A leading `~` is expanded. If unset, devlog uses ghostwriter's `voice/` if installed, else the bundled default. Read only — never shell-interpolated. |
|
|
182
|
-
| `projects` | array | One entry per project you want dev logs for. |
|
|
183
|
-
| `projects[].key` | string | Subdirectory name in the dev-log repo. Strict token: `^[a-z0-9][a-z0-9._-]*$`, no `..`. |
|
|
184
|
-
| `projects[].label` | string (optional) | Display name for the tab. Defaults to `key`. |
|
|
185
|
-
| `projects[].path` | string | Local filesystem path to the project. Whitespace OK. |
|
|
186
|
-
| `projects[].remote` | `"<owner>/<repo>"` | The project's GitHub remote. Used to mark public commits and link them. |
|
|
187
|
-
| `projects[].pathFilter` | string (optional) | Repo-relative subdir scoping this project's commits in a monorepo (e.g. `skills/devlog`). |
|
|
188
|
-
| `projects[].tagPrefix` | string (optional) | Prefix of the git tags that mark this project's releases (e.g. `devlog-v`). Defaults to `v`. Used in `git tag --list '<tagPrefix>*'`. |
|
|
189
|
-
|
|
190
|
-
See [`config.example.json`](./config.example.json) for a complete template, or run `npx @natjswenson/devlog config` to inspect your current config with validation.
|
|
191
|
-
|
|
192
|
-
## Security
|
|
193
|
-
|
|
194
|
-
The package is designed to be safe to install on a developer's machine and have ambient gh/git credentials. See [SECURITY.md](./SECURITY.md) for the full threat model and audit history.
|
|
195
|
-
|
|
196
|
-
**At a glance:**
|
|
197
|
-
- ✓ All shell calls in the CLI use `spawnSync` with argv arrays (no shell, no injection surface)
|
|
198
|
-
- ✓ The skill validates every config field against an allowlist before interpolating into shell commands; instructs the LLM to single-quote interpolated values
|
|
199
|
-
- ✓ Markdown rendering uses `react-markdown` with `skipHtml` and an allowlist `urlTransform` (only http(s)/mailto allowed; data:, javascript:, vbscript:, file:, blob: all neutralized)
|
|
200
|
-
- ✓ Frontmatter parser uses `Object.create(null)` + key allowlist (no prototype pollution)
|
|
201
|
-
- ✓ All external JSON is schema-validated before use (manifest, env-var projects array)
|
|
202
|
-
- ✓ Vite dev server bound to `localhost`, CORS off
|
|
203
|
-
- ✓ Demo-mode `window.fetch` override gated to dev builds only
|
|
204
|
-
- ✓ `config.json` written atomically (tmp + rename), mode 0600
|
|
205
|
-
- ✓ All dependencies pinned to exact versions
|
|
206
|
-
- ✓ `npm audit`: 0 known vulnerabilities
|
|
207
|
-
|
|
208
|
-
**To report a vulnerability:** open a [GitHub security advisory](https://github.com/natejswenson/devlog/security/advisories/new). Do not open a public issue.
|
|
209
|
-
|
|
210
|
-
## Customization
|
|
211
|
-
|
|
212
|
-
- **Tweak the entry template:** edit `~/.claude/skills/devlog/SKILL.md` (Step 6 — generate the entry).
|
|
213
|
-
- **Tweak your voice:** edit the `voice-profile.md` / `voice-notes.md` in your `voicePath` (or `~/.claude/skills/devlog/voice/`).
|
|
214
|
-
- **Tweak the UI:** override the `--devlog-*` CSS variables in `examples/react/DevLogPage.css` to match your theme.
|
|
215
|
-
- **Add more projects:** `npx @natjswenson/devlog add-project` (no manual JSON editing required).
|
|
216
|
-
|
|
217
|
-
## Troubleshooting
|
|
218
|
-
|
|
219
|
-
**`sh: devlog: command not found` when running `npx`:** you're inside a checkout of this repo. The local `package.json` name collides with the published one. Run `npx` from somewhere else, e.g. `cd ~ && npx @natjswenson/devlog ...`.
|
|
220
|
-
|
|
221
|
-
**Init prompts show `78` after placeholder text:** that's an artifact of how some output capture tools render `\x1b7`/`\x1b8` (cursor save/restore) escape sequences. In a real interactive terminal, you won't see it.
|
|
222
|
-
|
|
223
|
-
**Preview is blank / no tabs / no entries:** check the browser console. If you see CJS interop errors related to `react-dom/client`, `style-to-js`, or `react-markdown`, you're on a pre-0.1.6 release — upgrade with `npm cache clean --force && rm -rf ~/.npm/_npx && npx --yes @natjswenson/devlog@latest preview`.
|
|
224
|
-
|
|
225
|
-
**Init can't find `gh`:** install via [cli.github.com](https://cli.github.com/) and run `gh auth login`.
|
|
226
|
-
|
|
227
|
-
**`Config validation failed: ...`** — the validator rejected something in your `config.json`. Run `npx @natjswenson/devlog config` for a detailed diagnosis. Common causes:
|
|
228
|
-
- A field has shell metacharacters (`;` `&` `|` `` ` `` `$` etc) — see SKILL.md for the full list
|
|
229
|
-
- A project key contains `..` or `/`
|
|
230
|
-
- A path doesn't exist on disk
|
|
231
|
-
|
|
232
|
-
**Preview shows "Setup required":** you deployed the preview app standalone but didn't set the env vars. Set `VITE_DEVLOG_OWNER`, `VITE_DEVLOG_REPO`, `VITE_DEVLOG_PROJECTS` (JSON-stringified array) in your hosting environment.
|
|
233
|
-
|
|
234
|
-
## Versioning
|
|
235
|
-
|
|
236
|
-
Releases are documented in [CHANGELOG.md](./CHANGELOG.md). The package follows semver — bug fixes/security patches in patch releases (0.1.x), behavior changes in minor (0.x.0).
|
|
237
|
-
|
|
238
|
-
## License
|
|
239
|
-
|
|
240
|
-
MIT
|