dotmd-cli 0.64.0 → 0.64.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/README.md +26 -0
- package/bin/dotmd.mjs +15 -0
- package/package.json +1 -1
- package/src/init.mjs +8 -2
- package/src/new.mjs +98 -9
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Index, query, validate, and lifecycle-manage any collection of `.md` files — p
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install -g dotmd-cli # global — use `dotmd` anywhere
|
|
11
11
|
npm install -D dotmd-cli # project devDep — use via npm scripts
|
|
12
|
+
npx dotmd-cli init # try it without installing — scaffold a repo first
|
|
12
13
|
# requires Node.js >= 20
|
|
13
14
|
```
|
|
14
15
|
|
|
@@ -27,6 +28,19 @@ The plugin bundles the hooks (`SessionStart`/`SubagentStart` priming, a `PreTool
|
|
|
27
28
|
|
|
28
29
|
> **Upgrading to 0.57.0+:** per-repo `.claude/commands/{plans,docs,baton}.md` scaffolding is retired — that guidance now ships via the plugin's workflow skill and `/plans`, `/docs`, `/prompts`, `/baton` commands. On the next `dotmd hud` (SessionStart), dotmd removes those generated files (only banner-stamped `<!-- dotmd-generated -->` ones — your hand-authored command files are never touched). If you'd committed them, you'll see deletions to commit — that's expected. Run `claude plugin update dotmd@dotmd` to pick up `/baton`.
|
|
29
30
|
|
|
31
|
+
### Updating
|
|
32
|
+
|
|
33
|
+
The CLI and the Claude Code plugin are versioned in lockstep but ship as separate artifacts, so upgrading one can leave the other behind. `dotmd update` keeps them aligned:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
dotmd update # update both: npm CLI + the plugin
|
|
37
|
+
dotmd update --check # report CLI vs plugin versions, change nothing (no network)
|
|
38
|
+
dotmd update --cli-only # just the npm CLI
|
|
39
|
+
dotmd update --plugin-only # just the plugin (what to run after a plain npm upgrade)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`--plugin-only` is the usual fixup: after `npm i -g dotmd-cli@latest` the CLI is fresh but the plugin is stale, so run `dotmd update --plugin-only`, then restart the session (or `/reload-plugins`).
|
|
43
|
+
|
|
30
44
|
## Quick Start
|
|
31
45
|
|
|
32
46
|
```bash
|
|
@@ -338,6 +352,18 @@ Each built-in type has a template baked in:
|
|
|
338
352
|
| `doc` | `docs/<slug>.md` | Overview → Version History → Related (build-up shape lite) |
|
|
339
353
|
| `prompt` | `docs/prompts/<slug>.md` | Body is required (see [Saved Prompts](#saved-prompts)) |
|
|
340
354
|
|
|
355
|
+
**Plan body variants (plans only).** The default `plan` template is the full build-up shape. For a smaller plan, or the recurring audit shape, pass one body-variant flag:
|
|
356
|
+
|
|
357
|
+
- `--lite` / `--minimal` — Problem → Phases → Version History (drops Goals / Non-Goals / What Exists Today / Constraints / Decisions / Deferred / Closeout).
|
|
358
|
+
- `--audit` / `--findings` — Problem → Findings (ranked) → Suggested order → Open Questions, for "I investigated X, here's what I found" plans.
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
dotmd new plan quick-fix --lite
|
|
362
|
+
dotmd new plan perf-audit --audit
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
To scaffold an ordered sprint or a coordination map instead, see [Runlists](#runlists-ordered-groups-of-plans) (`--runlist a,b,c` / `--coordination`). The body variants and the hub flags are all mutually exclusive — a plan has exactly one body shape.
|
|
366
|
+
|
|
341
367
|
Add custom types via `templates` in your config:
|
|
342
368
|
|
|
343
369
|
```js
|
package/bin/dotmd.mjs
CHANGED
|
@@ -255,6 +255,7 @@ Create & Export:
|
|
|
255
255
|
|
|
256
256
|
Setup:
|
|
257
257
|
init Create starter config + docs directory
|
|
258
|
+
update [--check|--cli-only|--plugin-only] Update the CLI + Claude Code plugin (--check reports skew, no network)
|
|
258
259
|
statuses [list|add|set|remove|migrate] Manage per-project status taxonomy
|
|
259
260
|
help statuses Full status vocabulary + unstuck-actions + transitions
|
|
260
261
|
watch [command] Re-run a command on file changes
|
|
@@ -857,6 +858,20 @@ Scaffolding runlists (plans only):
|
|
|
857
858
|
dotmd new plan auth-revamp --runlist extract,rewrite,cleanup
|
|
858
859
|
dotmd new plan platform --coordination
|
|
859
860
|
|
|
861
|
+
Plan body variants (plans only — pick one body shape):
|
|
862
|
+
--lite / --minimal Trimmed plan: Problem → Phases → Version History. Drops
|
|
863
|
+
the full build-up scaffold (Goals / Non-Goals / What
|
|
864
|
+
Exists Today / Constraints / Decisions / Deferred /
|
|
865
|
+
Closeout) for a quick plan that doesn't need it.
|
|
866
|
+
--audit / --findings Audit plan: Problem → Findings (ranked) → Suggested order
|
|
867
|
+
→ Open Questions. The "investigated X, here's what I
|
|
868
|
+
found" shape, instead of build-up phases.
|
|
869
|
+
(The body variants and \`--runlist\`/\`--coordination\` are all mutually
|
|
870
|
+
exclusive — a plan has exactly one body shape.)
|
|
871
|
+
|
|
872
|
+
dotmd new plan quick-fix --lite
|
|
873
|
+
dotmd new plan perf-audit --audit
|
|
874
|
+
|
|
860
875
|
Other options:
|
|
861
876
|
--status <s> Set initial status (defaults to first valid status for the type)
|
|
862
877
|
--title <t> Override the auto-derived title
|
package/package.json
CHANGED
package/src/init.mjs
CHANGED
|
@@ -190,9 +190,15 @@ function generateDetectedConfig(scan, rootPath) {
|
|
|
190
190
|
lines.push('');
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
if (scan.surfaces.size > 0) {
|
|
193
|
+
if (scan.surfaces.size > 0 || scan.modules.size > 0) {
|
|
194
194
|
lines.push('export const taxonomy = {');
|
|
195
|
-
|
|
195
|
+
// Emit the full detected set so every existing doc passes — taxonomy
|
|
196
|
+
// enforcement only flags values outside the list, and the scan collected
|
|
197
|
+
// all of them. New surfaces/modules added later warn until appended here.
|
|
198
|
+
if (scan.surfaces.size > 0)
|
|
199
|
+
lines.push(` surfaces: [${[...scan.surfaces].sort().map(s => `'${s}'`).join(', ')}],`);
|
|
200
|
+
if (scan.modules.size > 0)
|
|
201
|
+
lines.push(` modules: [${[...scan.modules].sort().map(m => `'${m}'`).join(', ')}],`);
|
|
196
202
|
lines.push('};');
|
|
197
203
|
lines.push('');
|
|
198
204
|
}
|
package/src/new.mjs
CHANGED
|
@@ -350,6 +350,73 @@ graph pick it up. -->
|
|
|
350
350
|
`;
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
+
// Body for a `--lite` plan: the full build-up scaffold (Goals / Non-Goals /
|
|
354
|
+
// What Exists Today / Constraints / Decisions / Open Questions / Deferred /
|
|
355
|
+
// Closeout) is stripped down to the essentials — Problem → Phases → Version
|
|
356
|
+
// History — for a quick plan that doesn't need the full ceremony.
|
|
357
|
+
function litePlanBody(title, bodyInput, today) {
|
|
358
|
+
return `
|
|
359
|
+
# ${title}
|
|
360
|
+
|
|
361
|
+
> One-paragraph problem statement: what this plan is for, why now.
|
|
362
|
+
|
|
363
|
+
## Problem
|
|
364
|
+
|
|
365
|
+
${bodyInput?.trim() ?? ''}
|
|
366
|
+
|
|
367
|
+
## Phases
|
|
368
|
+
|
|
369
|
+
<!-- Status markers in heading text: ⬜ not started · 🟡 in progress (pickup
|
|
370
|
+
targets this) · ✅ shipped · ⏭ skipped · 🚧 blocked. -->
|
|
371
|
+
|
|
372
|
+
### Phase 1 — <title> ⬜
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
## Version History
|
|
377
|
+
|
|
378
|
+
- **${today}** Created.
|
|
379
|
+
`;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Body for an `--audit` plan: the recurring "investigated X, here's what I
|
|
383
|
+
// found" shape — ranked findings with impact tags, a suggested order to act on
|
|
384
|
+
// them, and open questions. The build-up phases scaffold doesn't fit audits
|
|
385
|
+
// (e.g. the onboarding audit), which is why this shape recurs by hand.
|
|
386
|
+
function auditPlanBody(title, bodyInput, today) {
|
|
387
|
+
return `
|
|
388
|
+
# ${title}
|
|
389
|
+
|
|
390
|
+
> One-paragraph: what was audited, and the headline finding.
|
|
391
|
+
|
|
392
|
+
## Problem
|
|
393
|
+
|
|
394
|
+
${bodyInput?.trim() ?? ''}
|
|
395
|
+
|
|
396
|
+
## Findings (ranked)
|
|
397
|
+
|
|
398
|
+
### 1. <finding> [impact]
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
### 2. <finding> [impact]
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
## Suggested order
|
|
407
|
+
|
|
408
|
+
1. <which finding to act on first, and why>
|
|
409
|
+
|
|
410
|
+
## Open Questions
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
## Version History
|
|
415
|
+
|
|
416
|
+
- **${today}** Created (audit).
|
|
417
|
+
`;
|
|
418
|
+
}
|
|
419
|
+
|
|
353
420
|
// Minimal child plan stub for a scaffolded runlist child. parent_plan points
|
|
354
421
|
// back at the hub (same dir) so \`dotmd doctor\` is satisfied and the reverse
|
|
355
422
|
// link/graph work; status starts `planned` (queued behind the hub).
|
|
@@ -402,11 +469,15 @@ export async function runNew(argv, config, opts = {}) {
|
|
|
402
469
|
let showFiles = opts.showFiles ?? false;
|
|
403
470
|
let runlistArg = null; // --runlist a,b,c → sprint hub + child stubs
|
|
404
471
|
let coordination = false; // --coordination → coordination hub skeleton
|
|
472
|
+
let lite = false; // --lite/--minimal → trimmed plan body
|
|
473
|
+
let audit = false; // --audit/--findings → ranked-findings plan body
|
|
405
474
|
for (let i = 0; i < argv.length; i++) {
|
|
406
475
|
if (argv[i] === '--status' && argv[i + 1]) { status = argv[++i]; continue; }
|
|
407
476
|
if (argv[i] === '--title' && argv[i + 1]) { title = argv[++i]; continue; }
|
|
408
477
|
if (argv[i] === '--runlist' && argv[i + 1]) { runlistArg = argv[++i]; continue; }
|
|
409
478
|
if (argv[i] === '--coordination') { coordination = true; continue; }
|
|
479
|
+
if (argv[i] === '--lite' || argv[i] === '--minimal') { lite = true; continue; }
|
|
480
|
+
if (argv[i] === '--audit' || argv[i] === '--findings') { audit = true; continue; }
|
|
410
481
|
// --body is the canonical flag; --message is a back-compat alias.
|
|
411
482
|
if ((argv[i] === '--body' || argv[i] === '--message') && argv[i + 1]) {
|
|
412
483
|
bodyFlagName = argv[i];
|
|
@@ -474,16 +545,28 @@ export async function runNew(argv, config, opts = {}) {
|
|
|
474
545
|
die(`Invalid status \`${status}\` for type \`${typeName}\`\nValid: ${[...effective].join(', ')}`);
|
|
475
546
|
}
|
|
476
547
|
|
|
477
|
-
// Runlist/coordination hubs
|
|
478
|
-
//
|
|
479
|
-
//
|
|
548
|
+
// Runlist/coordination hubs and the --lite/--audit variants are all plan
|
|
549
|
+
// *body shapes*, not separate types. Guard them to type plan and reject any
|
|
550
|
+
// combination — a plan has exactly one body shape (a sprint `runlist:` array,
|
|
551
|
+
// a prose-first coordination map, a trimmed lite plan, or a ranked-findings
|
|
552
|
+
// audit are mutually exclusive).
|
|
480
553
|
const isRunlistHub = runlistArg !== null;
|
|
481
554
|
const isCoordinationHub = coordination;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
555
|
+
const isLite = lite;
|
|
556
|
+
const isAudit = audit;
|
|
557
|
+
const planShapes = [
|
|
558
|
+
['--runlist', isRunlistHub],
|
|
559
|
+
['--coordination', isCoordinationHub],
|
|
560
|
+
['--lite', isLite],
|
|
561
|
+
['--audit', isAudit],
|
|
562
|
+
].filter(([, on]) => on);
|
|
563
|
+
if (planShapes.length > 0 && typeName !== 'plan') {
|
|
564
|
+
const flag = planShapes[0][0];
|
|
565
|
+
const usage = flag === '--runlist' ? '--runlist a,b,c' : flag;
|
|
566
|
+
die(`${flag} only applies to plans. Use: dotmd new plan <name> ${usage}`);
|
|
567
|
+
}
|
|
568
|
+
if (planShapes.length > 1) {
|
|
569
|
+
die(`${planShapes.map(([f]) => f).join(' and ')} are mutually exclusive — a plan has one body shape. Pick one.`);
|
|
487
570
|
}
|
|
488
571
|
const runlistTokens = isRunlistHub
|
|
489
572
|
? runlistArg.split(',').map(s => s.trim()).filter(Boolean)
|
|
@@ -652,6 +735,8 @@ export async function runNew(argv, config, opts = {}) {
|
|
|
652
735
|
let body;
|
|
653
736
|
if (isRunlistHub) body = runlistHubBody(docTitle, slug, runlistChildren, bodyInput, today);
|
|
654
737
|
else if (isCoordinationHub) body = coordinationHubBody(docTitle, bodyInput, today);
|
|
738
|
+
else if (isLite) body = litePlanBody(docTitle, bodyInput, today);
|
|
739
|
+
else if (isAudit) body = auditPlanBody(docTitle, bodyInput, today);
|
|
655
740
|
else body = template.body(docTitle, tmplCtx);
|
|
656
741
|
content = `---\n${fm}\n---\n${body}`;
|
|
657
742
|
}
|
|
@@ -669,7 +754,11 @@ export async function runNew(argv, config, opts = {}) {
|
|
|
669
754
|
rootHint = `Root: ${chosenLabel} (others: ${others.join(', ')} — pass --root <name> to change)\n`;
|
|
670
755
|
}
|
|
671
756
|
|
|
672
|
-
const hubKind = isRunlistHub ? ' (runlist hub)'
|
|
757
|
+
const hubKind = isRunlistHub ? ' (runlist hub)'
|
|
758
|
+
: isCoordinationHub ? ' (coordination hub)'
|
|
759
|
+
: isLite ? ' (lite plan)'
|
|
760
|
+
: isAudit ? ' (audit plan)'
|
|
761
|
+
: '';
|
|
673
762
|
|
|
674
763
|
if (dryRun) {
|
|
675
764
|
process.stdout.write(`${dim('[dry-run]')} Would create: ${repoPath}\n`);
|