dotmd-cli 0.28.2 → 0.29.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotmd-cli",
3
- "version": "0.28.2",
3
+ "version": "0.29.0",
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/hud.mjs CHANGED
@@ -16,9 +16,23 @@ function previewList(items, max = MAX_PREVIEW) {
16
16
  return slugs.join(', ') + more;
17
17
  }
18
18
 
19
- function findPendingPrompts(config) {
19
+ // Statuses that count as "actionable" for a prompt are derived from config:
20
+ // types.prompt.context.expanded (the statuses the user wants prominently shown).
21
+ // Falls back to ['pending'] when no prompt type is configured (defensive default
22
+ // for stripped-down configs). This means a user who customizes
23
+ // types.prompt.statuses to add e.g. `urgent: { context: 'expanded' }` gets that
24
+ // status surfaced too, without needing a code change.
25
+ export function actionablePromptStatuses(config) {
26
+ const promptCtx = config.typeContextConfig?.get('prompt');
27
+ const expanded = promptCtx?.expanded;
28
+ if (Array.isArray(expanded) && expanded.length > 0) return new Set(expanded);
29
+ return new Set(['pending']);
30
+ }
31
+
32
+ function findActionablePrompts(config) {
20
33
  const roots = config.docsRoots || (config.docsRoot ? [config.docsRoot] : []);
21
34
  const archiveDir = config.archiveDir || 'archived';
35
+ const actionable = actionablePromptStatuses(config);
22
36
  const found = [];
23
37
  const seen = new Set();
24
38
 
@@ -43,7 +57,7 @@ function findPendingPrompts(config) {
43
57
  if (!frontmatter) continue;
44
58
  const fm = parseSimpleFrontmatter(frontmatter);
45
59
  if (asString(fm.type) !== 'prompt') continue;
46
- if (asString(fm.status) !== 'pending') continue;
60
+ if (!actionable.has(asString(fm.status))) continue;
47
61
  found.push(toRepoPath(filePath, config.repoRoot));
48
62
  }
49
63
  }
@@ -57,7 +71,7 @@ export function buildHud(config) {
57
71
  const owned = Object.values(leases).filter(l => l.session === session).map(l => l.path);
58
72
  const queued = listQueuedHandoffs(config).map(h => h.repoPath);
59
73
  const stale = findStaleLeases(config).map(l => l.path);
60
- const prompts = findPendingPrompts(config);
74
+ const prompts = findActionablePrompts(config);
61
75
 
62
76
  return { owned, queued, stale, prompts };
63
77
  }
package/src/validate.mjs CHANGED
@@ -6,10 +6,13 @@ import { toRepoPath } from './util.mjs';
6
6
  const NOW = new Date();
7
7
 
8
8
  function isValidStatus(status, root, config, type) {
9
- // Union type-specific + root-specific statuses (a doc can satisfy either)
9
+ // When a doc declares a known type, that type's status set is authoritative.
10
+ // Falling through to the global union (across all types) would allow a
11
+ // `type: prompt` doc to carry `status: active` just because `active` is valid
12
+ // for plans — defeating the purpose of type-scoped vocabularies.
10
13
  if (type) {
11
14
  const typeSet = config.typeStatuses?.get(type);
12
- if (typeSet && typeSet.has(status)) return true;
15
+ if (typeSet) return typeSet.has(status);
13
16
  }
14
17
  const rootSet = config.rootValidStatuses?.get(root);
15
18
  if (rootSet) return rootSet.has(status);
@@ -27,8 +30,11 @@ export function validateDoc(doc, frontmatter, headingTitle, config) {
27
30
  } else if (!isValidStatus(doc.status, doc.root, config, doc.type)) {
28
31
  const typeSet = doc.type && config.typeStatuses?.get(doc.type);
29
32
  const rootSet = config.rootValidStatuses?.get(doc.root);
30
- const combined = new Set([...(typeSet ?? []), ...(rootSet ?? config.validStatuses)]);
31
- const hint = `valid: ${[...combined].join(', ')}`;
33
+ // When the doc has a known type, scope the error hint to that type's vocab.
34
+ // Otherwise fall back to root-specific or global validStatuses.
35
+ const hint = typeSet
36
+ ? `valid for type \`${doc.type}\`: ${[...typeSet].join(', ')}`
37
+ : `valid: ${[...(rootSet ?? config.validStatuses)].join(', ')}`;
32
38
  doc.errors.push({ path: doc.path, level: 'error', message: `Unknown status \`${doc.status}\`; ${hint}.` });
33
39
  }
34
40