dotmd-cli 0.39.7 → 0.39.9

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/bin/dotmd.mjs CHANGED
@@ -581,10 +581,16 @@ Types and their default destinations:
581
581
  \`<name>\` is slugified for the filename.
582
582
 
583
583
  Body input (all built-in types — required for prompt, optional for plan/doc):
584
- <text> Inline body as 3rd positional
585
- --message "<text>" Explicit inline body
584
+ @path Read body from a file (preferred for multi-line bodies)
586
585
  - Read body from stdin (heredoc-friendly for agents)
587
- @path Read body from a file
586
+ --message "<text>" Explicit inline body
587
+ <text> Inline body as 3rd positional
588
+
589
+ Tip for agents: prefer \`@path\` or \`-\` for multi-line bodies. Inline bodies
590
+ put the entire content on the bash command line, which (a) breaks under shell
591
+ quoting for backticks/dollar-signs and (b) trips PreToolUse hooks that scan
592
+ command strings for forbidden literals (destructive-git patterns, etc.).
593
+ \`@/tmp/foo.md\` sidesteps both.
588
594
 
589
595
  For plan/doc, a single-section body lands under the type's first scaffolded
590
596
  section (e.g. \`## Problem\` for plans). If the body already authors
@@ -594,19 +600,19 @@ the title + your body is emitted — no duplicated empty outline below
594
600
 
595
601
  Examples:
596
602
  dotmd new plan auth-revamp
597
- dotmd new plan auth-revamp "Investigation findings before scoping…"
603
+ dotmd new prompt resume-foo @/tmp/draft.md
604
+ dotmd new prompt resume-foo - <<'EOF'
605
+ multi-line
606
+ prompt body
607
+ EOF
608
+ dotmd new prompt cleanup-tomorrow "look at remaining lint warnings"
598
609
  dotmd new plan full-spec - <<'EOF'
599
610
  ## Problem
600
611
 
601
612
  ## Phases
602
613
 
603
614
  EOF
604
- dotmd new prompt cleanup-tomorrow "look at remaining lint warnings"
605
- dotmd new prompt resume-foo - <<'EOF'
606
- multi-line
607
- prompt body
608
- EOF
609
- dotmd new prompt from-file @/tmp/draft.md
615
+ dotmd new plan auth-revamp "Investigation findings before scoping…"
610
616
 
611
617
  Other options:
612
618
  --status <s> Set initial status (defaults to first valid status for the type)
@@ -754,12 +760,17 @@ Prompts are documents with \`type: prompt\`, typically saved under
754
760
  docs/prompts/. They seed future Claude sessions; consuming a prompt
755
761
  prints its body to stdout and atomically archives it (one-shot).
756
762
 
763
+ \`dotmd prompt\` (singular) is an alias for \`dotmd prompts\` — every
764
+ subcommand below works under either spelling.
765
+
757
766
  Subcommands:
758
767
  list List pending prompts (default)
759
768
  next Consume the oldest pending prompt:
760
769
  print body to stdout, flip status to archived
761
770
  use <file-or-slug> Consume a specific prompt (same as next, but
762
771
  targets the named prompt instead of picking oldest)
772
+ resume <file-or-slug> Alias for \`use\` — same behavior, easier name
773
+ when continuing a session
763
774
  archive <file-or-slug> Archive a prompt without printing its body
764
775
  shelve <file-or-slug> Park a prompt (status → shelved): kept in list,
765
776
  hidden from hud/briefing pending surfaces, skipped
@@ -786,6 +797,8 @@ Examples:
786
797
  claude "$(dotmd prompts next)" # consume oldest pending + run claude
787
798
  claude "$(dotmd prompts use resume-foo)" # by slug
788
799
  claude "$(dotmd prompts use docs/prompts/foo.md)" # by path
800
+ claude "$(dotmd prompts resume resume-foo)" # \`resume\` is an alias for \`use\`
801
+ dotmd prompt list # singular alias for \`dotmd prompts list\`
789
802
 
790
803
  dotmd prompts next --dry-run # preview without consuming
791
804
  dotmd prompts archive old-thing
@@ -958,7 +971,7 @@ the whole docs tree is scanned.`,
958
971
 
959
972
  async function main() {
960
973
  const args = process.argv.slice(2);
961
- const command = args[0] ?? 'list';
974
+ let command = args[0] ?? 'list';
962
975
 
963
976
  // Pre-config flags
964
977
  if (args.includes('--version') || args.includes('-v')) {
@@ -979,6 +992,14 @@ async function main() {
979
992
  return;
980
993
  }
981
994
 
995
+ // Singular-form alias for the prompts subcommand namespace. Trivial
996
+ // no-collision collapse — `prompt` was previously "unknown command", now
997
+ // routes everywhere `prompts` does (incl. per-command --help below, and the
998
+ // subcommand dispatch at the `prompts` branch in the chain). The other
999
+ // singular/plural pairs (`plan`/`plans`, `module`/`modules`,
1000
+ // `status`/`statuses`) are deliberately kept distinct — see F20 plan.
1001
+ if (command === 'prompt') command = 'prompts';
1002
+
982
1003
  // Per-command help
983
1004
  if (args.includes('--help') || args.includes('-h')) {
984
1005
  process.stdout.write(`${HELP[command] ?? HELP._main}\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotmd-cli",
3
- "version": "0.39.7",
3
+ "version": "0.39.9",
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
@@ -76,10 +76,13 @@ export function buildHud(config) {
76
76
  // Validation error count — hud's "silent when clean" contract should treat
77
77
  // `check` errors as not-clean. Without this, a SessionStart hook firing hud
78
78
  // can leave the agent with no visible signal that a check is failing.
79
- // buildIndex wraps the same scan every other read command does; cost is fine.
79
+ // `errorsOnly: true` skips warning-only cross-doc passes (git staleness,
80
+ // bidirectional refs, claude-commands) that hud never reads — ~6× faster on
81
+ // SessionStart for platform-scale corpora. Per-file validation + checkIndex
82
+ // still run, so the error count matches `dotmd check`'s.
80
83
  let errors = 0;
81
84
  try {
82
- const index = buildIndex(config);
85
+ const index = buildIndex(config, { errorsOnly: true });
83
86
  errors = index.errors.length;
84
87
  } catch { /* swallow — bad config shouldn't break the SessionStart hook */ }
85
88
 
package/src/index.mjs CHANGED
@@ -7,14 +7,22 @@ import { validateDoc, validatePlanShape, validateDocShape, checkBidirectionalRef
7
7
  import { checkIndex } from './index-file.mjs';
8
8
  import { checkClaudeCommands } from './claude-commands.mjs';
9
9
 
10
- // `fast: true` skips every pass that only produces warnings/errors — the
11
- // rendered index file consumes only status/title/snapshot/etc., not the
12
- // validation output. Use it from `regenIndex` (post-mutation index refresh)
13
- // where validation has already run elsewhere (or will, next time the user
14
- // runs `dotmd check`). Saves the full-repo `git log` scan in
15
- // `checkGitStaleness` plus the bidirectional ref walk + claude-commands check.
10
+ // `fast: true` skips every pass that produces warnings/errors — the rendered
11
+ // index file consumes only status/title/snapshot/etc., not the validation
12
+ // output. Use it from `regenIndex` (post-mutation index refresh) where
13
+ // validation has already run elsewhere (or will, next time the user runs
14
+ // `dotmd check`). Saves the full-repo `git log` scan in `checkGitStaleness`
15
+ // plus the bidirectional ref walk + claude-commands check.
16
+ //
17
+ // `errorsOnly: true` runs every error-producing pass (per-file `validateDoc`,
18
+ // `checkIndex`, the `validate` hook) but skips the warning-only cross-doc
19
+ // passes (bidirectional refs, runlist back-pointers, git staleness, claude
20
+ // commands). Use it from `dotmd hud` — the SessionStart hook only renders the
21
+ // error COUNT, so the warning-only passes are pure overhead there. Preserves
22
+ // the invariant that hud's "✗ N validation errors" line matches `dotmd check`.
16
23
  export function buildIndex(config, opts = {}) {
17
- const { fast = false } = opts;
24
+ const { fast = false, errorsOnly = false } = opts;
25
+ const skipWarningOnlyChecks = fast || errorsOnly;
18
26
  const docs = collectDocFiles(config).map(f => parseDocFile(f, config, { fast }));
19
27
  if (!fast) {
20
28
  // Per-file validation (validateDoc) ran during parse without sibling
@@ -86,13 +94,13 @@ export function buildIndex(config, opts = {}) {
86
94
  countsByType[type][doc.status] = (countsByType[type][doc.status] ?? 0) + 1;
87
95
  }
88
96
 
89
- if (!fast) {
90
- if (config.indexPath) {
91
- const indexCheck = checkIndex(transformedDocs, config);
92
- warnings.push(...indexCheck.warnings);
93
- errors.push(...indexCheck.errors);
94
- }
97
+ if (!fast && config.indexPath) {
98
+ const indexCheck = checkIndex(transformedDocs, config);
99
+ warnings.push(...indexCheck.warnings);
100
+ errors.push(...indexCheck.errors);
101
+ }
95
102
 
103
+ if (!skipWarningOnlyChecks) {
96
104
  const refCheck = checkBidirectionalReferences(transformedDocs, config);
97
105
  warnings.push(...refCheck.warnings);
98
106
 
package/src/prompts.mjs CHANGED
@@ -8,7 +8,10 @@ import { runArchive, runStatus } from './lifecycle.mjs';
8
8
  import { runNew } from './new.mjs';
9
9
  import { green, dim } from './color.mjs';
10
10
 
11
- const SUBCOMMANDS = new Set(['list', 'next', 'use', 'archive', 'new', 'shelve', 'unshelve']);
11
+ // `resume` is an alias for `use` agents reach for "resume" when continuing a
12
+ // session; `use` reads as internal mechanics. Both names stay valid; the
13
+ // canonical output ("Consumed: …") is unchanged.
14
+ const SUBCOMMANDS = new Set(['list', 'next', 'use', 'resume', 'archive', 'new', 'shelve', 'unshelve']);
12
15
 
13
16
  export async function runPrompts(argv, config, opts = {}) {
14
17
  const sub = argv[0];
@@ -22,6 +25,7 @@ export async function runPrompts(argv, config, opts = {}) {
22
25
  case 'list': return runPromptsList(rest, config, opts);
23
26
  case 'next': return runPromptsNext(rest, config, opts);
24
27
  case 'use': return runPromptsUse(rest, config, opts);
28
+ case 'resume': return runPromptsUse(rest, config, opts);
25
29
  case 'archive': return runPromptsArchive(rest, config, opts);
26
30
  case 'new': return runPromptsNew(rest, config, opts);
27
31
  case 'shelve': return runPromptsShelve(rest, config, opts);