dotmd-cli 0.78.0 → 0.79.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.
Files changed (54) hide show
  1. package/README.md +66 -63
  2. package/assets/opencode/plugin.js +11 -6
  3. package/bin/dotmd.mjs +272 -285
  4. package/package.json +2 -2
  5. package/scripts/postinstall.mjs +4 -4
  6. package/src/atomic-mutation.mjs +1 -1
  7. package/src/baton.mjs +7 -7
  8. package/src/check-collapse.mjs +5 -5
  9. package/src/claude-commands.mjs +6 -2
  10. package/src/commands.mjs +4 -4
  11. package/src/config.mjs +2 -2
  12. package/src/deps.mjs +1 -1
  13. package/src/doctor.mjs +17 -17
  14. package/src/fix-membership.mjs +4 -2
  15. package/src/frontmatter-fix.mjs +1 -1
  16. package/src/git.mjs +1 -1
  17. package/src/glossary.mjs +3 -3
  18. package/src/graph.mjs +1 -1
  19. package/src/guard.mjs +8 -8
  20. package/src/health.mjs +2 -2
  21. package/src/hints.mjs +7 -7
  22. package/src/host-integration.mjs +41 -22
  23. package/src/hub-membership.mjs +1 -1
  24. package/src/hud.mjs +14 -14
  25. package/src/index-file.mjs +2 -2
  26. package/src/init.mjs +24 -24
  27. package/src/install.mjs +4 -4
  28. package/src/journal.mjs +40 -7
  29. package/src/lifecycle.mjs +17 -17
  30. package/src/lint.mjs +1 -1
  31. package/src/migrate-prompts.mjs +1 -1
  32. package/src/migrate-template.mjs +2 -2
  33. package/src/migrate.mjs +1 -1
  34. package/src/misuse-read.mjs +4 -5
  35. package/src/modules.mjs +3 -3
  36. package/src/new.mjs +11 -11
  37. package/src/output-identity.mjs +7 -2
  38. package/src/pickup-card.mjs +2 -2
  39. package/src/pickup.mjs +2 -2
  40. package/src/prompts.mjs +12 -12
  41. package/src/query.mjs +9 -9
  42. package/src/rename.mjs +2 -2
  43. package/src/render.mjs +20 -20
  44. package/src/roadmap.mjs +5 -5
  45. package/src/runlist.mjs +11 -11
  46. package/src/ship.mjs +2 -2
  47. package/src/skill-drift.mjs +19 -6
  48. package/src/statuses.mjs +16 -16
  49. package/src/summary.mjs +1 -1
  50. package/src/surfaces.mjs +1 -1
  51. package/src/sync-status.mjs +4 -4
  52. package/src/update.mjs +11 -11
  53. package/src/validate.mjs +9 -9
  54. package/src/watch.mjs +1 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # dotmd
1
+ # runlist
2
2
 
3
3
  CLI for managing Markdown documents with YAML frontmatter.
4
4
 
5
- dotmd indexes, queries, validates, graphs, exports, and lifecycle-manages plans,
5
+ runlist (formerly dotmd) indexes, queries, validates, graphs, exports, and lifecycle-manages plans,
6
6
  ADRs, RFCs, design docs, and other structured Markdown. It is built for
7
7
  AI-assisted development workflows where documents need to remain current and
8
8
  safe to mutate.
@@ -22,7 +22,9 @@ npx dotmd-cli init # try it without installing
22
22
 
23
23
  `runlist` is the canonical executable, `rl` is its short convenience alias, and
24
24
  `dotmd` remains supported during the compatibility window. All three invoke the
25
- same CLI; examples below retain `dotmd` while the public package identity does.
25
+ same CLI. The package is still published as `dotmd-cli`, and the Claude Code
26
+ plugin is still `dotmd@dotmd`; those names change in a later release. Legacy
27
+ `dotmd.config.*` files, `DOTMD_*` variables and `.dotmd/` state keep working.
26
28
 
27
29
  Maintainer release automation is POSIX-only because it uses Bash and POSIX
28
30
  command-line tools. The published Node.js CLI remains cross-platform.
@@ -33,19 +35,19 @@ The CLI alone gives an agent no orientation and no session identity. Install the
33
35
  integration for whichever host you run:
34
36
 
35
37
  ```bash
36
- dotmd install # what's installed for each host
37
- dotmd install claude # Claude Code plugin (marketplace + plugin)
38
- dotmd install opencode # OpenCode plugin (one auto-discovered file)
39
- dotmd doctor --session # what identity dotmd sees here, and from where
38
+ runlist install # what's installed for each host
39
+ runlist install claude # Claude Code plugin (marketplace + plugin)
40
+ runlist install opencode # OpenCode plugin (one auto-discovered file)
41
+ runlist doctor --session # what identity runlist sees here, and from where
40
42
  ```
41
43
 
42
- Both are one-time and global; `dotmd update` keeps them in step with the CLI.
44
+ Both are one-time and global; `runlist update` keeps them in step with the CLI.
43
45
  Codex needs no install for identity: it exports `CODEX_THREAD_ID` to every tool
44
- shell, and dotmd reads it as a per-session identity automatically.
46
+ shell, and runlist reads it as a per-session identity automatically.
45
47
 
46
48
  ### Claude Code Plugin
47
49
 
48
- `dotmd install claude` runs the two steps below for you. From inside a session:
50
+ `runlist install claude` runs the two steps below for you. From inside a session:
49
51
 
50
52
  ```text
51
53
  /plugin marketplace add reowens/dotmd
@@ -58,32 +60,33 @@ guard, the canonical workflow skill, and `/plans`, `/docs`, `/prompts`, and
58
60
 
59
61
  ### OpenCode Plugin
60
62
 
61
- `dotmd install opencode` writes one plugin file into OpenCode's global config
63
+ `runlist install opencode` writes one plugin file into OpenCode's global config
62
64
  directory, where OpenCode auto-discovers it — no `opencode.json` edit. It
63
65
  supplies the two things the CLI cannot get on its own:
64
66
 
65
67
  - **Per-session plan ownership.** OpenCode exports no session id to a tool
66
- shell. Without the plugin, dotmd falls back to `OPENCODE_PID`, which names the
68
+ shell. Without the plugin, runlist falls back to `OPENCODE_PID`, which names the
67
69
  OpenCode *process* — so every session in one OpenCode instance shares an
68
70
  identity and can release the others' in-session plans.
69
71
  - **A session-start briefing**, the equivalent of Claude Code's SessionStart
70
72
  hook. OpenCode's Claude Code compatibility covers skills and the system
71
- prompt, not hooks, so nothing else runs `dotmd hud`.
73
+ prompt, not hooks, so nothing else runs `runlist hud`.
72
74
 
73
- Restart OpenCode after installing. The file is version-stamped; a `dotmd.js`
74
- without that stamp is treated as hand-authored and is never overwritten.
75
+ Restart OpenCode after installing. The file is version-stamped (`runlist-generated:`, or
76
+ `dotmd-generated:` from older releases); a `dotmd.js` without either stamp is
77
+ treated as hand-authored and is never overwritten.
75
78
 
76
- The plugin requires a global CLI install because its hooks resolve `dotmd` from
79
+ The plugin requires a global CLI install because its hooks resolve `runlist` (or `dotmd`) from
77
80
  `PATH`. A project devDependency is useful for npm scripts but does not put the
78
81
  CLI on the hook's `PATH`.
79
82
 
80
83
  Keep the CLI and plugin aligned with:
81
84
 
82
85
  ```bash
83
- dotmd update
84
- dotmd update --check
85
- dotmd update --cli-only
86
- dotmd update --plugin-only
86
+ runlist update
87
+ runlist update --check
88
+ runlist update --cli-only
89
+ runlist update --plugin-only
87
90
  ```
88
91
 
89
92
  Restart Claude Code, or run `/reload-plugins`, after a plugin update.
@@ -91,29 +94,29 @@ Restart Claude Code, or run `/reload-plugins`, after a plugin update.
91
94
  ## Quick Start
92
95
 
93
96
  ```bash
94
- dotmd init # create config, docs/, and the generated index
95
- dotmd new plan auth-refresh # scaffold a typed document
96
- dotmd briefing # compact active-work orientation
97
- dotmd plans # live plan dashboard
98
- dotmd check # validate schema, references, and lifecycle shape
99
- dotmd doctor # preview repairs; add --apply to write
97
+ runlist init # create config, docs/, and the generated index
98
+ runlist new plan auth-refresh # scaffold a typed document
99
+ runlist briefing # compact active-work orientation
100
+ runlist plans # live plan dashboard
101
+ runlist check # validate schema, references, and lifecycle shape
102
+ runlist doctor # preview repairs; add --apply to write
100
103
  ```
101
104
 
102
- `dotmd briefing` is the compact orientation view. `dotmd context` is the fuller
103
- human/LLM briefing, while `dotmd agent-context` emits bounded structured JSON for
105
+ `runlist briefing` is the compact orientation view. `runlist context` is the fuller
106
+ human/LLM briefing, while `runlist agent-context` emits bounded structured JSON for
104
107
  agent integrations.
105
108
 
106
109
  ## Core Workflow
107
110
 
108
111
  ```bash
109
- dotmd briefing
110
- dotmd use docs/plans/auth-refresh.md
111
- dotmd set awaiting docs/plans/auth-refresh.md --note "Need API owner decision"
112
- dotmd set active docs/plans/auth-refresh.md --note "Decision received"
113
- dotmd archive docs/plans/auth-refresh.md --note "Shipped and verified"
112
+ runlist briefing
113
+ runlist use docs/plans/auth-refresh.md
114
+ runlist set awaiting docs/plans/auth-refresh.md --note "Need API owner decision"
115
+ runlist set active docs/plans/auth-refresh.md --note "Decision received"
116
+ runlist archive docs/plans/auth-refresh.md --note "Shipped and verified"
114
117
  ```
115
118
 
116
- Use `dotmd set <status> [<file>]` for lifecycle changes rather than editing a
119
+ Use `runlist set <status> [<file>]` for lifecycle changes rather than editing a
117
120
  `status:` line. It validates the status for the document type, updates history,
118
121
  runs lifecycle hooks, repairs references after moves, and synchronizes the
119
122
  index.
@@ -122,18 +125,18 @@ For unfinished session work, save the handoff and release the owned plan in one
122
125
  operation:
123
126
 
124
127
  ```bash
125
- dotmd baton @/tmp/resume.md
128
+ runlist baton @/tmp/resume.md
126
129
  ```
127
130
 
128
131
  Baton refuses when a handoff for the same work is already pending, so one piece
129
132
  of work never has two resume prompts.
130
133
 
131
- Saved prompts are local session state. Consume them with `dotmd use`; inspect
132
- without consuming via `dotmd prompts show`. Consuming a baton prompt also claims
133
- its plan; `dotmd use --no-claim` reads and archives it without starting the plan.
134
+ Saved prompts are local session state. Consume them with `runlist use`; inspect
135
+ without consuming via `runlist prompts show`. Consuming a baton prompt also claims
136
+ its plan; `runlist use --no-claim` reads and archives it without starting the plan.
134
137
 
135
- New plans are created `planned`; `dotmd use` starts one, and
136
- `dotmd new plan <name> --status <status>` sets a different starting status.
138
+ New plans are created `planned`; `runlist use` starts one, and
139
+ `runlist new plan <name> --status <status>` sets a different starting status.
137
140
 
138
141
  ## Document Format
139
142
 
@@ -160,11 +163,11 @@ related_docs:
160
163
 
161
164
  `status` is the only universally required field. A `type` enables type-specific
162
165
  statuses, validation, templates, and briefing behavior. Explicit frontmatter
163
- wins, but dotmd can also derive titles, summaries, state, next steps, checklist
166
+ wins, but runlist can also derive titles, summaries, state, next steps, checklist
164
167
  progress, and Markdown links from the body.
165
168
 
166
169
  Use plural `modules:` and `surfaces:` arrays. The old singular keys remain
167
- readable for compatibility and can be migrated with `dotmd lint --fix`.
170
+ readable for compatibility and can be migrated with `runlist lint --fix`.
168
171
 
169
172
  ### Built-In Types
170
173
 
@@ -183,19 +186,19 @@ A sprint runlist is an ordered `runlist:` array on a hub plan. Scaffold a hub
183
186
  and children together:
184
187
 
185
188
  ```bash
186
- dotmd new plan auth-revamp --runlist extract,rewrite,cleanup
187
- dotmd runlist auth-revamp
188
- dotmd runlist next auth-revamp
189
+ runlist new plan auth-revamp --runlist extract,rewrite,cleanup
190
+ runlist runlist auth-revamp
191
+ runlist runlist next auth-revamp
189
192
  ```
190
193
 
191
194
  Mutate the structure through the CLI so the array, child `parent_plan` refs, and
192
195
  body order list remain synchronized:
193
196
 
194
197
  ```bash
195
- dotmd runlist add auth-revamp docs/plans/existing-plan.md
196
- dotmd runlist add auth-revamp follow-up
197
- dotmd runlist reorder auth-revamp follow-up --before cleanup
198
- dotmd runlist remove auth-revamp extract --clear-parent
198
+ runlist runlist add auth-revamp docs/plans/existing-plan.md
199
+ runlist runlist add auth-revamp follow-up
200
+ runlist runlist reorder auth-revamp follow-up --before cleanup
201
+ runlist runlist remove auth-revamp extract --clear-parent
199
202
  ```
200
203
 
201
204
  Archived children count as complete. Parked children (`blocked`, `partial`,
@@ -205,16 +208,16 @@ pickup but do not count as done.
205
208
  For a larger prose-first domain map, create a coordination runlist:
206
209
 
207
210
  ```bash
208
- dotmd new plan platform-work --coordination
209
- dotmd runlists
211
+ runlist new plan platform-work --coordination
212
+ runlist runlists
210
213
  ```
211
214
 
212
215
  For progress across several runlists, create a roadmap:
213
216
 
214
217
  ```bash
215
- dotmd new plan platform-roadmap --roadmap
216
- dotmd roadmap platform-roadmap
217
- dotmd roadmap platform-roadmap next
218
+ runlist new plan platform-roadmap --roadmap
219
+ runlist roadmap platform-roadmap
220
+ runlist roadmap platform-roadmap next
218
221
  ```
219
222
 
220
223
  Roadmaps roll up progress recursively and choose the first startable plan across
@@ -236,17 +239,17 @@ counts so dashboards do not double-count their children.
236
239
  The CLI is the source of truth for command syntax and options:
237
240
 
238
241
  ```bash
239
- dotmd --help
240
- dotmd help all
241
- dotmd help statuses
242
- dotmd <command> --help
242
+ runlist --help
243
+ runlist help all
244
+ runlist help statuses
245
+ runlist <command> --help
243
246
  ```
244
247
 
245
248
  Shell completion is generated from the same command registry:
246
249
 
247
250
  ```bash
248
- eval "$(dotmd completions bash)"
249
- eval "$(dotmd completions zsh)"
251
+ eval "$(runlist completions bash)"
252
+ eval "$(runlist completions zsh)"
250
253
  ```
251
254
 
252
255
  This README intentionally documents onboarding and concepts instead of
@@ -254,7 +257,7 @@ duplicating the complete command catalog.
254
257
 
255
258
  ## Configuration
256
259
 
257
- Run `dotmd init` to create `dotmd.config.mjs`. A minimal typed configuration:
260
+ Run `runlist init` to create `runlist.config.mjs` (a legacy `dotmd.config.mjs` is still read). A minimal typed configuration:
258
261
 
259
262
  ```js
260
263
  export const root = 'docs';
@@ -280,12 +283,12 @@ export const types = {
280
283
 
281
284
  Configuration supports multiple roots, custom types and templates, taxonomy,
282
285
  reference fields, presets, rendering, lifecycle hooks, validation hooks, and
283
- AI summarization hooks. See [`dotmd.config.example.mjs`](dotmd.config.example.mjs)
286
+ AI summarization hooks. See [`runlist.config.example.mjs`](runlist.config.example.mjs)
284
287
  for the complete annotated reference.
285
288
 
286
289
  ## Hooks
287
290
 
288
- Functions exported from `dotmd.config.mjs` are detected as hooks. They can add
291
+ Functions exported from `runlist.config.mjs` are detected as hooks. They can add
289
292
  validation, customize rendering and summaries, or react to lifecycle events.
290
293
  Hooks receive the resolved config and command context; mutation hooks participate
291
294
  in the command's dry-run and failure contracts.
@@ -1,4 +1,4 @@
1
- // dotmd's OpenCode integration. Installed by `dotmd install opencode`, which
1
+ // runlist's OpenCode integration. Installed by `runlist install opencode`, which
2
2
  // copies this file (with a version banner prepended) to the OpenCode plugin
3
3
  // directory, where OpenCode auto-discovers it — it globs
4
4
  // `{plugin,plugins}/*.{ts,js}` under `.opencode/` and the global config dir, so
@@ -13,7 +13,7 @@
13
13
  //
14
14
  // 2. NO HOOK MAY THROW. OpenCode awaits hook callbacks inside the request it
15
15
  // is serving; a rejected promise fails the user's chat turn. Every hook
16
- // body is wrapped, and a failure degrades to "dotmd does nothing here"
16
+ // body is wrapped, and a failure degrades to "runlist does nothing here"
17
17
  // rather than to a broken session.
18
18
  //
19
19
  // Runs under Bun inside the OpenCode process. Node builtins only, no deps.
@@ -46,6 +46,10 @@ function runCli(directory, args, input = null) {
46
46
  cwd: directory,
47
47
  timeout: PRIMER_TIMEOUT_MS,
48
48
  windowsHide: true,
49
+ // Node refuses to execFile a `.cmd` without a shell (EINVAL since the
50
+ // 2024 batch-file fix), and npm installs the CLI on Windows as one.
51
+ // The arguments are fixed strings, never user input.
52
+ shell: process.platform === 'win32',
49
53
  env: { ...process.env, NO_COLOR: '1' },
50
54
  }, (error, stdout) => {
51
55
  if (error?.code === 'ENOENT') attempt(index + 1);
@@ -60,7 +64,7 @@ function runCli(directory, args, input = null) {
60
64
  });
61
65
  }
62
66
 
63
- // OpenCode runs no Claude Code hooks, so `dotmd guard` never sees its tool
67
+ // OpenCode runs no Claude Code hooks, so `runlist guard` never sees its tool
64
68
  // calls, and sessions opened pending prompts with the read tool, which prints a
65
69
  // prompt without archiving it. The guard's answer for a prompt read is a
66
70
  // warning, not a block, so it is applied after the call: the teaching text is
@@ -98,7 +102,7 @@ export default async function dotmdOpencodePlugin({ directory }) {
98
102
 
99
103
  return {
100
104
  // Ownership identity. OpenCode sets no session-id variable of its own, and
101
- // `OPENCODE_PID` — what dotmd falls back to without this plugin — names the
105
+ // `OPENCODE_PID` — what runlist falls back to without this plugin — names the
102
106
  // OpenCode *process*, so every session in one TUI shares it and can release
103
107
  // the others' plans. This is the only place the real session id is
104
108
  // available to a tool shell.
@@ -106,11 +110,12 @@ export default async function dotmdOpencodePlugin({ directory }) {
106
110
  try {
107
111
  if (input?.sessionID) {
108
112
  output.env.RUNLIST_SESSION_ID = `opencode:${input.sessionID}`;
113
+ // Legacy name, kept for an older CLI (before 0.77.0) still on PATH.
109
114
  output.env.DOTMD_SESSION_ID = `opencode:${input.sessionID}`;
110
115
  }
111
116
  // The OpenCode server process hosts the session and outlives every tool
112
117
  // shell, so it is the process whose liveness answers "is this claim's
113
- // owner still there?" — `dotmd doctor --claims` probes exactly this.
118
+ // owner still there?" — `runlist doctor --claims` probes exactly this.
114
119
  output.env.RUNLIST_SESSION_PID = String(process.pid);
115
120
  output.env.DOTMD_SESSION_PID = String(process.pid);
116
121
  } catch { /* never break a shell over this */ }
@@ -130,7 +135,7 @@ export default async function dotmdOpencodePlugin({ directory }) {
130
135
  },
131
136
 
132
137
  // Session priming — the equivalent of the SessionStart hook that runs
133
- // `dotmd hud` under Claude Code. Silent outside a dotmd repo (hud prints
138
+ // `runlist hud` under Claude Code. Silent outside a runlist repo (hud prints
134
139
  // nothing and exits 0), so this is inert in unrelated projects.
135
140
  'experimental.chat.system.transform': async (input, output) => {
136
141
  try {