dotmd-cli 0.64.0 → 0.64.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/README.md CHANGED
@@ -338,6 +338,18 @@ Each built-in type has a template baked in:
338
338
  | `doc` | `docs/<slug>.md` | Overview → Version History → Related (build-up shape lite) |
339
339
  | `prompt` | `docs/prompts/<slug>.md` | Body is required (see [Saved Prompts](#saved-prompts)) |
340
340
 
341
+ **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:
342
+
343
+ - `--lite` / `--minimal` — Problem → Phases → Version History (drops Goals / Non-Goals / What Exists Today / Constraints / Decisions / Deferred / Closeout).
344
+ - `--audit` / `--findings` — Problem → Findings (ranked) → Suggested order → Open Questions, for "I investigated X, here's what I found" plans.
345
+
346
+ ```bash
347
+ dotmd new plan quick-fix --lite
348
+ dotmd new plan perf-audit --audit
349
+ ```
350
+
351
+ 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.
352
+
341
353
  Add custom types via `templates` in your config:
342
354
 
343
355
  ```js
package/bin/dotmd.mjs CHANGED
@@ -857,6 +857,20 @@ Scaffolding runlists (plans only):
857
857
  dotmd new plan auth-revamp --runlist extract,rewrite,cleanup
858
858
  dotmd new plan platform --coordination
859
859
 
860
+ Plan body variants (plans only — pick one body shape):
861
+ --lite / --minimal Trimmed plan: Problem → Phases → Version History. Drops
862
+ the full build-up scaffold (Goals / Non-Goals / What
863
+ Exists Today / Constraints / Decisions / Deferred /
864
+ Closeout) for a quick plan that doesn't need it.
865
+ --audit / --findings Audit plan: Problem → Findings (ranked) → Suggested order
866
+ → Open Questions. The "investigated X, here's what I
867
+ found" shape, instead of build-up phases.
868
+ (The body variants and \`--runlist\`/\`--coordination\` are all mutually
869
+ exclusive — a plan has exactly one body shape.)
870
+
871
+ dotmd new plan quick-fix --lite
872
+ dotmd new plan perf-audit --audit
873
+
860
874
  Other options:
861
875
  --status <s> Set initial status (defaults to first valid status for the type)
862
876
  --title <t> Override the auto-derived title
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotmd-cli",
3
- "version": "0.64.0",
3
+ "version": "0.64.1",
4
4
  "description": "CLI for managing markdown documents with YAML frontmatter — index, query, validate, graph, export, Notion sync, AI summaries.",
5
5
  "type": "module",
6
6
  "license": "MIT",
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 are a plan shape, not a separate type. Guard the
478
- // flags to type plan and reject the contradictory combination (a sprint
479
- // `runlist:` array vs a prose-first coordination map are different shapes).
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
- if ((isRunlistHub || isCoordinationHub) && typeName !== 'plan') {
483
- die(`--${isRunlistHub ? 'runlist' : 'coordination'} only applies to plans. Use: dotmd new plan <name> --${isRunlistHub ? 'runlist a,b,c' : 'coordination'}`);
484
- }
485
- if (isRunlistHub && isCoordinationHub) {
486
- die('--runlist and --coordination are mutually exclusive: a sprint runlist hub carries an ordered `runlist:` array; a coordination hub is a prose-first map (`execution_mode: coordination`). Pick one.');
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)' : isCoordinationHub ? ' (coordination 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`);