dotmd-cli 0.15.1 → 0.16.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 +30 -2
- package/bin/dotmd.mjs +50 -1
- package/dotmd.config.example.mjs +15 -8
- package/package.json +1 -1
- package/src/config-edit.mjs +603 -0
- package/src/config.mjs +3 -3
- package/src/statuses.mjs +736 -0
package/README.md
CHANGED
|
@@ -117,12 +117,12 @@ The default plan vocabulary is shaped around the **unstuck-action test**: every
|
|
|
117
117
|
| `planned` | Wait for trigger | Queued; not yet ready to execute. |
|
|
118
118
|
| `blocked` | **Monitor** | External arrival on its own schedule (hardware, vendor, third-party rollout). You can't speed it up. |
|
|
119
119
|
| `partial` | **Spawn successors** | Shipped most of the plan; tail deferred. Body should reference successor plans tracking the tail. Visible but quiet (no nagging). |
|
|
120
|
-
| `paused` | **Re-evaluate** |
|
|
120
|
+
| `paused` | **Re-evaluate** | Started but stopped mid-work; needs near-term review. NOT quiet — short (3-day) stale threshold so resume-decisions don't decay. |
|
|
121
121
|
| `awaiting` | **Ask** | Needs a human decision or input. NOT quiet — pings get forgotten, so this status generates stale pressure to chase the answer. |
|
|
122
122
|
| `queued-after` | **Check predecessor** | Sequenced behind another plan; can start once that one ships. Quiet. |
|
|
123
123
|
| `archived` | — | No longer relevant; auto-moved to the archive directory on transition. |
|
|
124
124
|
|
|
125
|
-
Each *quiet* status (`partial`, `
|
|
125
|
+
Each *quiet* status (`partial`, `queued-after`, `archived`) is exempt from stale-warning pressure but still appears in active scope and metrics — quietness is a presentation flag, not a closure flag. `awaiting` and `paused` deliberately stay loud so unanswered questions and stalled mid-flight work don't decay into invisible backlog.
|
|
126
126
|
|
|
127
127
|
> **Heads-up:** versions before 0.15 included a `done` plan status in the defaults. It saw effectively zero real-world use (plans went `in-session`/`active` → `archived` directly), so it was dropped from the built-in vocabulary. To finish a plan, run `dotmd archive <plan-file>` — or, if you preferred the previous behavior, add `done` back via the `types.plan.statuses` key in your config.
|
|
128
128
|
|
|
@@ -423,6 +423,34 @@ dotmd lint # report issues
|
|
|
423
423
|
dotmd lint --fix # fix all issues
|
|
424
424
|
```
|
|
425
425
|
|
|
426
|
+
### Manage Statuses
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
dotmd statuses # table view, all types
|
|
430
|
+
dotmd statuses --type plan # one type
|
|
431
|
+
dotmd statuses --json # machine-readable
|
|
432
|
+
|
|
433
|
+
dotmd statuses add paused --type plan --like blocked --quiet # clone blocked, then quiet
|
|
434
|
+
dotmd statuses set archived --type plan --no-quiet # tweak a flag
|
|
435
|
+
dotmd statuses remove obsolete --type plan # refuses if any docs use it
|
|
436
|
+
|
|
437
|
+
dotmd statuses migrate plan # array-form → rich-form
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
`--like <existing>` is the affordance for "kinda like X but…" — clones every
|
|
441
|
+
flag from another status, then user flags override. Write commands print a flag
|
|
442
|
+
diff and prompt for confirmation; pass `--yes` to skip the prompt or
|
|
443
|
+
`--dry-run` to preview without writing. Edits are atomic: the rewrite lands in
|
|
444
|
+
a sibling temp file, is validated by re-importing it and running
|
|
445
|
+
`resolveConfig`, then renamed into place — a syntax error or new warning
|
|
446
|
+
leaves the original untouched.
|
|
447
|
+
|
|
448
|
+
**Lifecycle-override gotcha.** If your config has both rich-form `types` and an
|
|
449
|
+
explicit `export const lifecycle = {...}`, the explicit lifecycle silently
|
|
450
|
+
overrides per-status flags at runtime. `dotmd statuses` write commands refuse
|
|
451
|
+
to write into that state and recommend deleting the explicit `lifecycle` block;
|
|
452
|
+
pass `--ignore-lifecycle-override` to write anyway.
|
|
453
|
+
|
|
426
454
|
### Rename
|
|
427
455
|
|
|
428
456
|
```bash
|
package/bin/dotmd.mjs
CHANGED
|
@@ -59,6 +59,7 @@ Create & Export:
|
|
|
59
59
|
|
|
60
60
|
Setup:
|
|
61
61
|
init Create starter config + docs directory
|
|
62
|
+
statuses [list|add|set|remove|migrate] Manage per-project status taxonomy
|
|
62
63
|
watch [command] Re-run a command on file changes
|
|
63
64
|
completions <shell> Shell completion script (bash, zsh)
|
|
64
65
|
|
|
@@ -449,6 +450,53 @@ Options:
|
|
|
449
450
|
--list List all glossary terms
|
|
450
451
|
--json Output as JSON`,
|
|
451
452
|
|
|
453
|
+
statuses: `dotmd statuses — manage per-project status taxonomy
|
|
454
|
+
|
|
455
|
+
Subcommands:
|
|
456
|
+
list [--type <t>] [--json] Default. Table view of every status × type with all flags.
|
|
457
|
+
--type accepts comma-separated types.
|
|
458
|
+
add <name> --type <t> [--like <e>] [flags...]
|
|
459
|
+
Add a new status. --like <existing> clones every flag from
|
|
460
|
+
another status; user flags override. Inserts before the
|
|
461
|
+
first terminal/archive status. Refuses if name already
|
|
462
|
+
exists or is invalid.
|
|
463
|
+
set <name> --type <t> <flags...> Edit flags on an existing status. Refuses if status doesn't
|
|
464
|
+
exist. Flags overwrite individually.
|
|
465
|
+
remove <name> --type <t> Delete a status entry. Refuses if any docs use the status
|
|
466
|
+
(lists offenders, suggests \`dotmd migrate\`). Warns if an
|
|
467
|
+
explicit lifecycle export references the name.
|
|
468
|
+
migrate <type> One-shot conversion of array-form types.<t>.statuses to
|
|
469
|
+
rich form, pulling in peer staleDays/context and per-status
|
|
470
|
+
requiresModule from taxonomy.moduleRequiredFor.
|
|
471
|
+
|
|
472
|
+
Flags accepted by add/set:
|
|
473
|
+
--context <expanded|listed|counted> Briefing layout bucket
|
|
474
|
+
--staleDays <n|null> Stale threshold; null = never stale
|
|
475
|
+
--requiresModule / --no-requiresModule
|
|
476
|
+
--terminal / --no-terminal Closure state — excluded from active-work scope
|
|
477
|
+
--archive / --no-archive Auto-move to archive dir on transition
|
|
478
|
+
--skipStale / --no-skipStale
|
|
479
|
+
--skipWarnings / --no-skipWarnings
|
|
480
|
+
--quiet / --no-quiet Sugar for skipStale + skipWarnings (explicit overrides win)
|
|
481
|
+
|
|
482
|
+
Workflow flags:
|
|
483
|
+
--yes Skip the confirmation prompt
|
|
484
|
+
--dry-run, -n Show the diff without writing
|
|
485
|
+
--ignore-lifecycle-override Write even when an explicit \`lifecycle\` export
|
|
486
|
+
would silently mask the per-status flags
|
|
487
|
+
|
|
488
|
+
Examples:
|
|
489
|
+
dotmd statuses # list everything
|
|
490
|
+
dotmd statuses add paused --type plan --like blocked --quiet
|
|
491
|
+
dotmd statuses set archived --type plan --no-quiet
|
|
492
|
+
dotmd statuses remove obsolete --type plan
|
|
493
|
+
dotmd statuses migrate plan # array → rich
|
|
494
|
+
|
|
495
|
+
Lifecycle-override gotcha: if your config has both rich-form types and an explicit
|
|
496
|
+
\`export const lifecycle\`, the runtime ignores per-status flags. The CLI refuses
|
|
497
|
+
to write in that case unless you pass --ignore-lifecycle-override; the recommended
|
|
498
|
+
fix is to delete the explicit \`lifecycle\` block so flags take effect.`,
|
|
499
|
+
|
|
452
500
|
bulk: `dotmd bulk archive <f1> <f2> ... — archive multiple files at once
|
|
453
501
|
|
|
454
502
|
Archives each file: sets status to archived, moves to archive
|
|
@@ -569,6 +617,7 @@ async function main() {
|
|
|
569
617
|
if (command === 'migrate') { const { runMigrate } = await import('../src/migrate.mjs'); runMigrate(restArgs, config, { dryRun }); return; }
|
|
570
618
|
if (command === 'fix-refs') { const { runFixRefs } = await import('../src/fix-refs.mjs'); runFixRefs(restArgs, config, { dryRun }); return; }
|
|
571
619
|
if (command === 'doctor') { const { runDoctor } = await import('../src/doctor.mjs'); runDoctor(restArgs, config, { dryRun }); return; }
|
|
620
|
+
if (command === 'statuses') { const { runStatuses } = await import('../src/statuses.mjs'); await runStatuses(restArgs, config, { dryRun, type: typeArg }); return; }
|
|
572
621
|
|
|
573
622
|
// All remaining commands need the index + render modules
|
|
574
623
|
const { buildIndex } = await import('../src/index.mjs');
|
|
@@ -819,7 +868,7 @@ async function main() {
|
|
|
819
868
|
'focus', 'query', 'plans', 'stale', 'actionable', 'index', 'pickup', 'finish', 'status', 'archive', 'bulk', 'touch', 'doctor',
|
|
820
869
|
'unblocks', 'health', 'glossary',
|
|
821
870
|
'fix-refs', 'lint', 'rename', 'migrate', 'notion', 'export', 'summary',
|
|
822
|
-
'watch', 'diff', 'new', 'init', 'completions',
|
|
871
|
+
'watch', 'diff', 'new', 'init', 'completions', 'statuses',
|
|
823
872
|
];
|
|
824
873
|
const matches = allCommands
|
|
825
874
|
.map(c => ({ cmd: c, dist: levenshtein(command, c) }))
|
package/dotmd.config.example.mjs
CHANGED
|
@@ -50,7 +50,7 @@ export const excludeDirs = ['evidence'];
|
|
|
50
50
|
// 'planned': { context: 'listed', staleDays: 30, requiresModule: true },
|
|
51
51
|
// 'blocked': { context: 'listed', staleDays: 30, requiresModule: true },
|
|
52
52
|
// 'partial': { context: 'expanded', requiresModule: true, quiet: true }, // shipped + deferred tail; visible, no nagging
|
|
53
|
-
// 'paused': { context: 'listed',
|
|
53
|
+
// 'paused': { context: 'listed', staleDays: 3, requiresModule: true }, // stopped mid-work, near-term review — loud (short stale threshold)
|
|
54
54
|
// 'awaiting': { context: 'listed', staleDays: 14, requiresModule: true }, // human input/decision wait — NOT quiet (pings get forgotten)
|
|
55
55
|
// 'queued-after': { context: 'counted', requiresModule: true, quiet: true }, // sequenced behind another plan
|
|
56
56
|
// 'archived': { context: 'counted', archive: true, terminal: true, quiet: true },
|
|
@@ -103,13 +103,20 @@ export const statuses = {
|
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
// Lifecycle behavior — which statuses trigger special handling.
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
//
|
|
107
|
+
// IMPORTANT: only enable this block if you're using ARRAY-form types (above) or
|
|
108
|
+
// no `types` definition. With rich-form types, the runtime derives these from
|
|
109
|
+
// per-status `terminal` / `archive` / `skipStale` / `skipWarnings` / `quiet`
|
|
110
|
+
// flags. An explicit `lifecycle` export sitting alongside rich-form types will
|
|
111
|
+
// SILENTLY OVERRIDE the per-status flags — `dotmd statuses` will warn you
|
|
112
|
+
// before writing into a config in that state.
|
|
113
|
+
//
|
|
114
|
+
// export const lifecycle = {
|
|
115
|
+
// archiveStatuses: ['archived'], // auto-move to archiveDir on transition
|
|
116
|
+
// skipStaleFor: ['archived'], // skip staleness checks
|
|
117
|
+
// skipWarningsFor: ['archived'], // skip validation warnings (summary, etc.)
|
|
118
|
+
// terminalStatuses: ['archived', 'deprecated', 'reference'], // skip current_state/next_step warnings, exclude from stats scope
|
|
119
|
+
// };
|
|
113
120
|
|
|
114
121
|
// Taxonomy validation — set fields to null to skip validation.
|
|
115
122
|
// moduleRequiredFor is derived from requiresModule when using rich status definitions.
|
package/package.json
CHANGED