dotmd-cli 0.14.3 → 0.14.4
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 +60 -9
- package/dotmd.config.example.mjs +46 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -430,27 +430,78 @@ When `dotmd init` runs in a directory with existing `.md` files, it scans them a
|
|
|
430
430
|
|
|
431
431
|
## Configuration
|
|
432
432
|
|
|
433
|
-
Create `dotmd.config.mjs` at your project root (or run `dotmd init`)
|
|
433
|
+
Create `dotmd.config.mjs` at your project root (or run `dotmd init`).
|
|
434
|
+
|
|
435
|
+
### Rich status definitions (recommended)
|
|
436
|
+
|
|
437
|
+
Define each status as an object that co-locates all behavioral properties. Adding a new status is one line in one place — no need to update separate `lifecycle`, `staleDays`, `context`, or `taxonomy` sections.
|
|
438
|
+
|
|
439
|
+
```js
|
|
440
|
+
export const root = 'docs/plans';
|
|
441
|
+
export const archiveDir = 'archived';
|
|
442
|
+
|
|
443
|
+
export const types = {
|
|
444
|
+
plan: {
|
|
445
|
+
statuses: {
|
|
446
|
+
'active': { context: 'expanded', staleDays: 14, requiresModule: true },
|
|
447
|
+
'planned': { context: 'listed', staleDays: 30, requiresModule: true },
|
|
448
|
+
'blocked': { context: 'listed', staleDays: 30, skipStale: true },
|
|
449
|
+
'archived': { context: 'counted', archive: true, terminal: true, skipStale: true, skipWarnings: true },
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Status properties:**
|
|
456
|
+
|
|
457
|
+
| Property | Type | Default | Effect |
|
|
458
|
+
|---|---|---|---|
|
|
459
|
+
| `context` | `'expanded'` \| `'listed'` \| `'counted'` | `'counted'` | Display mode in `dotmd context` |
|
|
460
|
+
| `staleDays` | `number` \| `null` | `null` | Days before doc is stale (`null` = never) |
|
|
461
|
+
| `requiresModule` | `boolean` | `false` | Require `module` in frontmatter |
|
|
462
|
+
| `terminal` | `boolean` | `false` | Skip `current_state`/`next_step` warnings |
|
|
463
|
+
| `archive` | `boolean` | `false` | Auto-move to `archiveDir` on transition |
|
|
464
|
+
| `skipStale` | `boolean` | `false` | Exempt from stale checks |
|
|
465
|
+
| `skipWarnings` | `boolean` | `false` | Exempt from validation warnings |
|
|
466
|
+
|
|
467
|
+
Object key order determines display order. The config resolver derives `statuses.order`, `lifecycle.*`, `taxonomy.moduleRequiredFor`, and `context.*` from these definitions. Explicit global sections still win when provided.
|
|
468
|
+
|
|
469
|
+
### Array form (also supported)
|
|
470
|
+
|
|
471
|
+
The traditional array form remains fully backwards compatible:
|
|
434
472
|
|
|
435
473
|
```js
|
|
436
|
-
export const
|
|
437
|
-
|
|
474
|
+
export const types = {
|
|
475
|
+
plan: {
|
|
476
|
+
statuses: ['active', 'planned', 'blocked', 'archived'],
|
|
477
|
+
context: { expanded: ['active'], listed: ['planned', 'blocked'], counted: ['archived'] },
|
|
478
|
+
staleDays: { active: 14, planned: 30, blocked: 30 },
|
|
479
|
+
},
|
|
480
|
+
};
|
|
438
481
|
|
|
482
|
+
// When using array form, define behavior in separate sections:
|
|
439
483
|
export const statuses = {
|
|
440
|
-
order: ['
|
|
441
|
-
staleDays: {
|
|
484
|
+
order: ['active', 'planned', 'blocked', 'archived'],
|
|
485
|
+
staleDays: { active: 14, planned: 30, blocked: 30 },
|
|
442
486
|
};
|
|
443
487
|
|
|
444
488
|
export const lifecycle = {
|
|
445
|
-
archiveStatuses: ['archived'],
|
|
489
|
+
archiveStatuses: ['archived'],
|
|
446
490
|
skipStaleFor: ['archived'],
|
|
447
491
|
skipWarningsFor: ['archived'],
|
|
448
|
-
terminalStatuses: ['archived'
|
|
492
|
+
terminalStatuses: ['archived'],
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
export const taxonomy = {
|
|
496
|
+
moduleRequiredFor: ['active', 'planned', 'blocked'],
|
|
449
497
|
};
|
|
498
|
+
```
|
|
450
499
|
|
|
500
|
+
### Other config
|
|
501
|
+
|
|
502
|
+
```js
|
|
451
503
|
export const taxonomy = {
|
|
452
504
|
surfaces: ['web', 'ios', 'backend', 'api', 'platform'],
|
|
453
|
-
moduleRequiredFor: ['active', 'ready', 'planned', 'blocked'],
|
|
454
505
|
};
|
|
455
506
|
|
|
456
507
|
export const referenceFields = {
|
|
@@ -465,7 +516,7 @@ export const index = {
|
|
|
465
516
|
};
|
|
466
517
|
```
|
|
467
518
|
|
|
468
|
-
All exports are optional. Additional options: `
|
|
519
|
+
All exports are optional. Additional options: `context`, `display`, `presets`, `templates`, `excludeDirs`, `notion`. See [`dotmd.config.example.mjs`](dotmd.config.example.mjs) for the full reference.
|
|
469
520
|
|
|
470
521
|
Config discovery walks up from cwd looking for `dotmd.config.mjs` or `.dotmd.config.mjs`.
|
|
471
522
|
|
package/dotmd.config.example.mjs
CHANGED
|
@@ -13,27 +13,58 @@ export const archiveDir = 'archived';
|
|
|
13
13
|
// Directories to skip when scanning
|
|
14
14
|
export const excludeDirs = ['evidence'];
|
|
15
15
|
|
|
16
|
-
// Document types — each type has its own status vocabulary and context layout
|
|
16
|
+
// Document types — each type has its own status vocabulary and context layout.
|
|
17
17
|
// Defaults: plan, doc, research. Override to customize statuses per type.
|
|
18
|
+
//
|
|
19
|
+
// Statuses can be defined as an array (names only) or as an object (rich form).
|
|
20
|
+
// The object form co-locates all behavioral properties with each status,
|
|
21
|
+
// eliminating the need for separate lifecycle, staleDays, context, and taxonomy sections.
|
|
22
|
+
|
|
23
|
+
// ─── Rich status definitions (recommended) ──────────────────────────────────
|
|
24
|
+
// Each status is an object with optional properties:
|
|
25
|
+
// context: 'expanded' | 'listed' | 'counted' (default: 'counted')
|
|
26
|
+
// staleDays: number | null — stale threshold (default: null = never stale)
|
|
27
|
+
// requiresModule: boolean — require `module` frontmatter (default: false)
|
|
28
|
+
// terminal: boolean — skip current_state/next_step warnings (default: false)
|
|
29
|
+
// archive: boolean — auto-move to archiveDir on transition (default: false)
|
|
30
|
+
// skipStale: boolean — exempt from stale checks (default: false)
|
|
31
|
+
// skipWarnings: boolean — exempt from validation warnings (default: false)
|
|
32
|
+
//
|
|
18
33
|
// export const types = {
|
|
19
34
|
// plan: {
|
|
20
|
-
// statuses:
|
|
21
|
-
//
|
|
22
|
-
//
|
|
35
|
+
// statuses: {
|
|
36
|
+
// 'in-session': { context: 'expanded', staleDays: 1, requiresModule: true },
|
|
37
|
+
// 'active': { context: 'expanded', staleDays: 14, requiresModule: true },
|
|
38
|
+
// 'planned': { context: 'listed', staleDays: 30, requiresModule: true },
|
|
39
|
+
// 'blocked': { context: 'listed', staleDays: 30, requiresModule: true, skipStale: true },
|
|
40
|
+
// 'done': { context: 'counted', terminal: true, skipStale: true, skipWarnings: true },
|
|
41
|
+
// 'archived': { context: 'counted', archive: true, terminal: true, skipStale: true, skipWarnings: true },
|
|
42
|
+
// },
|
|
23
43
|
// },
|
|
24
44
|
// doc: {
|
|
25
|
-
// statuses:
|
|
26
|
-
//
|
|
27
|
-
//
|
|
45
|
+
// statuses: {
|
|
46
|
+
// 'draft': { context: 'listed', staleDays: 30 },
|
|
47
|
+
// 'active': { context: 'expanded', staleDays: 14 },
|
|
48
|
+
// 'review': { context: 'listed', staleDays: 14 },
|
|
49
|
+
// 'reference': { context: 'counted', skipStale: true },
|
|
50
|
+
// 'deprecated': { context: 'counted', terminal: true, skipStale: true },
|
|
51
|
+
// 'archived': { context: 'counted', archive: true, terminal: true, skipStale: true, skipWarnings: true },
|
|
52
|
+
// },
|
|
28
53
|
// },
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
//
|
|
54
|
+
// };
|
|
55
|
+
|
|
56
|
+
// ─── Array form (also supported) ────────────────────────────────────────────
|
|
57
|
+
// When using array form, define behavior in separate statuses/lifecycle/taxonomy sections.
|
|
58
|
+
// export const types = {
|
|
59
|
+
// plan: {
|
|
60
|
+
// statuses: ['in-session', 'active', 'planned', 'blocked', 'done', 'archived'],
|
|
61
|
+
// context: { expanded: ['in-session', 'active'], listed: ['planned', 'blocked'], counted: ['done', 'archived'] },
|
|
62
|
+
// staleDays: { 'in-session': 1, active: 14, planned: 30, blocked: 30 },
|
|
33
63
|
// },
|
|
34
64
|
// };
|
|
35
65
|
|
|
36
66
|
// Status workflow — fallback for docs without a type field. Order determines display grouping.
|
|
67
|
+
// When using rich status definitions, statuses.order and staleDays are derived automatically.
|
|
37
68
|
export const statuses = {
|
|
38
69
|
order: ['active', 'ready', 'planned', 'research', 'blocked', 'reference', 'archived'],
|
|
39
70
|
// Additional statuses valid only in specific roots (merged with order)
|
|
@@ -52,7 +83,8 @@ export const statuses = {
|
|
|
52
83
|
},
|
|
53
84
|
};
|
|
54
85
|
|
|
55
|
-
// Lifecycle behavior — which statuses trigger special handling
|
|
86
|
+
// Lifecycle behavior — which statuses trigger special handling.
|
|
87
|
+
// When using rich status definitions, these are derived from per-status flags.
|
|
56
88
|
export const lifecycle = {
|
|
57
89
|
archiveStatuses: ['archived'], // auto-move to archiveDir on transition
|
|
58
90
|
skipStaleFor: ['archived'], // skip staleness checks
|
|
@@ -60,7 +92,8 @@ export const lifecycle = {
|
|
|
60
92
|
terminalStatuses: ['archived', 'deprecated', 'reference', 'done'], // skip current_state/next_step warnings, exclude from stats scope
|
|
61
93
|
};
|
|
62
94
|
|
|
63
|
-
// Taxonomy validation — set fields to null to skip validation
|
|
95
|
+
// Taxonomy validation — set fields to null to skip validation.
|
|
96
|
+
// moduleRequiredFor is derived from requiresModule when using rich status definitions.
|
|
64
97
|
export const taxonomy = {
|
|
65
98
|
surfaces: ['web', 'ios', 'android', 'mobile', 'full-stack', 'frontend', 'backend', 'api', 'docs', 'ops', 'platform', 'infra', 'design'],
|
|
66
99
|
moduleRequiredFor: ['active', 'ready', 'planned', 'blocked'],
|
package/package.json
CHANGED