dotmd-cli 0.41.0 → 0.41.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/bin/dotmd.mjs +5 -18
- package/dotmd.config.example.mjs +0 -1
- package/package.json +1 -1
- package/src/commands.mjs +1 -1
- package/src/completions.mjs +1 -1
- package/src/lifecycle.mjs +5 -61
package/bin/dotmd.mjs
CHANGED
|
@@ -51,8 +51,7 @@ Lifecycle:
|
|
|
51
51
|
pickup <file> [--takeover] Pick up a plan (set in-session + print body)
|
|
52
52
|
release [<file>] [--to <s>] Release in-session lease (alias: unpickup)
|
|
53
53
|
runlist <hub> [next] Show or walk an ordered group of plans (see \`dotmd help runlist\`)
|
|
54
|
-
|
|
55
|
-
status <file> <status> Transition document status
|
|
54
|
+
status <file> <status> Transition document status (deprecated; prefer \`set\`)
|
|
56
55
|
set <status> [<file>] Unified transition: archive/release/transition in one verb
|
|
57
56
|
archive <file> Archive (status + move + update refs)
|
|
58
57
|
bulk archive <f1> <f2> ... Archive multiple files at once
|
|
@@ -139,10 +138,10 @@ plan statuses (each maps to a distinct unstuck-action)
|
|
|
139
138
|
|
|
140
139
|
Canonical transitions:
|
|
141
140
|
active → in-session \`dotmd pickup <file>\`
|
|
142
|
-
in-session → active \`dotmd
|
|
143
|
-
in-session → partial \`dotmd
|
|
144
|
-
in-session → awaiting \`dotmd
|
|
145
|
-
any → archived \`dotmd
|
|
141
|
+
in-session → active \`dotmd set active\` (auto-releases lease)
|
|
142
|
+
in-session → partial \`dotmd set partial\` (auto-releases lease)
|
|
143
|
+
in-session → awaiting \`dotmd set awaiting\` (auto-releases lease)
|
|
144
|
+
any → archived \`dotmd set archived <file>\` (or \`dotmd archive\`)
|
|
146
145
|
|
|
147
146
|
────────────────────────────────────────────────────────────────────
|
|
148
147
|
doc statuses
|
|
@@ -296,17 +295,6 @@ status. With no file, releases every lease owned by the current session.
|
|
|
296
295
|
Identical behavior to \`dotmd unpickup\`; both names route to the same
|
|
297
296
|
implementation. See \`dotmd unpickup --help\` for full option list.`,
|
|
298
297
|
|
|
299
|
-
finish: `dotmd finish <file> [done|active] — finish working on a plan
|
|
300
|
-
|
|
301
|
-
Sets the plan status to done (default) or back to active.
|
|
302
|
-
Only works on plans currently in-session.
|
|
303
|
-
|
|
304
|
-
Options:
|
|
305
|
-
--json Output as JSON
|
|
306
|
-
--dry-run, -n Preview without writing
|
|
307
|
-
|
|
308
|
-
If no file is given, prompts with a list of in-session plans.`,
|
|
309
|
-
|
|
310
298
|
set: `dotmd set <status> [<file>] — unified status-transition verb
|
|
311
299
|
|
|
312
300
|
Routes to the right plumbing based on the target status:
|
|
@@ -1160,7 +1148,6 @@ async function main() {
|
|
|
1160
1148
|
if (command === 'unpickup' || command === 'release') { const { runUnpickup } = await import('../src/lifecycle.mjs'); await runUnpickup(restArgs, config, { dryRun }); return; }
|
|
1161
1149
|
if (command === 'runlist') { const { runRunlist } = await import('../src/runlist.mjs'); await runRunlist(restArgs, config, { dryRun }); return; }
|
|
1162
1150
|
if (command === 'handoff') { die('`dotmd handoff` was removed in 0.31.0. Use `dotmd prompts new <name>` to create a saved prompt instead. The .dotmd/handoffs/ sidecar mechanism no longer exists; see CHANGELOG.'); }
|
|
1163
|
-
if (command === 'finish') { const { runFinish } = await import('../src/lifecycle.mjs'); await runFinish(restArgs, config, { dryRun }); return; }
|
|
1164
1151
|
if (command === 'status') { const { runStatus } = await import('../src/lifecycle.mjs'); await runStatus(restArgs, config, { dryRun }); return; }
|
|
1165
1152
|
if (command === 'set') { const { runSet } = await import('../src/lifecycle.mjs'); await runSet(restArgs, config, { dryRun }); return; }
|
|
1166
1153
|
if (command === 'archive') { const { runArchive } = await import('../src/lifecycle.mjs'); runArchive(restArgs, config, { dryRun }); return; }
|
package/dotmd.config.example.mjs
CHANGED
|
@@ -268,7 +268,6 @@ export const presets = {
|
|
|
268
268
|
// export function onRename({ oldPath, newPath, referencesUpdated }) {}
|
|
269
269
|
// export function onLint({ path, fixes }) {}
|
|
270
270
|
// export function onPickup({ path, oldStatus, newStatus }) {}
|
|
271
|
-
// export function onFinish({ path, oldStatus, newStatus }) {}
|
|
272
271
|
|
|
273
272
|
// AI hooks — override summarization (replaces local MLX model).
|
|
274
273
|
// export function summarizeDoc(body, meta) { return 'Custom summary'; }
|
package/package.json
CHANGED
package/src/commands.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// templates points at a real command.
|
|
5
5
|
export const KNOWN_COMMANDS = [
|
|
6
6
|
'list', 'json', 'check', 'coverage', 'stats', 'graph', 'deps', 'briefing', 'context', 'hud',
|
|
7
|
-
'focus', 'query', 'plans', 'prompts', 'stale', 'actionable', 'index', 'pickup', 'release', '
|
|
7
|
+
'focus', 'query', 'plans', 'prompts', 'stale', 'actionable', 'index', 'pickup', 'release', 'status', 'set', 'archive', 'bulk', 'bulk-tag', 'touch', 'doctor',
|
|
8
8
|
'unblocks', 'health', 'glossary', 'modules', 'module',
|
|
9
9
|
'fix-refs', 'lint', 'rename', 'migrate', 'notion', 'export', 'summary',
|
|
10
10
|
'watch', 'diff', 'new', 'init', 'completions', 'statuses', 'journal',
|
package/src/completions.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { die } from './util.mjs';
|
|
|
2
2
|
|
|
3
3
|
const COMMANDS = [
|
|
4
4
|
'list', 'json', 'check', 'coverage', 'stats', 'graph', 'deps', 'unblocks', 'health', 'glossary', 'briefing', 'context', 'focus', 'query',
|
|
5
|
-
'plans', 'stale', 'actionable', 'index', 'pickup', 'unpickup', '
|
|
5
|
+
'plans', 'stale', 'actionable', 'index', 'pickup', 'unpickup', 'status', 'set', 'archive', 'bulk', 'touch', 'doctor', 'lint', 'rename', 'migrate',
|
|
6
6
|
'fix-refs', 'notion', 'export', 'summary', 'watch', 'diff', 'init', 'new', 'completions', 'journal',
|
|
7
7
|
];
|
|
8
8
|
|
package/src/lifecycle.mjs
CHANGED
|
@@ -112,6 +112,10 @@ export async function runStatus(argv, config, opts = {}) {
|
|
|
112
112
|
const input = argv[0];
|
|
113
113
|
let newStatus = argv[1];
|
|
114
114
|
|
|
115
|
+
if (!opts.suppressDeprecation) {
|
|
116
|
+
process.stderr.write(dim('`dotmd status <file> <status>` is deprecated; prefer `dotmd set <status> [<file>]` (note: <status> first, <file> optional when a lease is held). Removed in a future major.\n'));
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
if (!input) { die('Usage: dotmd status <file> <new-status>'); }
|
|
116
120
|
|
|
117
121
|
const filePath = resolveDocPath(input, config);
|
|
@@ -519,66 +523,6 @@ export async function runUnpickup(argv, config, opts = {}) {
|
|
|
519
523
|
}
|
|
520
524
|
}
|
|
521
525
|
|
|
522
|
-
export async function runFinish(argv, config, opts = {}) {
|
|
523
|
-
const { dryRun } = opts;
|
|
524
|
-
const json = argv.includes('--json');
|
|
525
|
-
const positional = argv.filter(a => !a.startsWith('-'));
|
|
526
|
-
let input = positional[0];
|
|
527
|
-
const targetStatus = positional[1] ?? 'done';
|
|
528
|
-
|
|
529
|
-
if (!['done', 'active'].includes(targetStatus)) die(`Invalid finish status: ${targetStatus}. Use 'done' or 'active'.`);
|
|
530
|
-
|
|
531
|
-
// Interactive: pick from in-session plans
|
|
532
|
-
if (!input) {
|
|
533
|
-
if (!isInteractive()) die('Usage: dotmd finish <file> [done|active]');
|
|
534
|
-
const index = buildIndex(config);
|
|
535
|
-
const inSession = index.docs.filter(d => d.status === 'in-session');
|
|
536
|
-
if (inSession.length === 0) die('No plans currently in-session.');
|
|
537
|
-
if (inSession.length === 1) {
|
|
538
|
-
input = inSession[0].path;
|
|
539
|
-
process.stderr.write(`${dim(`Auto-selected: ${input}`)}\n`);
|
|
540
|
-
} else {
|
|
541
|
-
const choice = await promptChoice('Finish which plan:', inSession.map(d => `${d.title} — ${d.path}`));
|
|
542
|
-
if (!choice) die('No plan selected.');
|
|
543
|
-
const idx = inSession.findIndex((_, i) => choice === `${inSession[i].title} — ${inSession[i].path}`);
|
|
544
|
-
if (idx === -1) die('No plan selected.');
|
|
545
|
-
input = inSession[idx].path;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
const filePath = resolveDocPath(input, config);
|
|
550
|
-
if (!filePath) die(`File not found: ${input}`);
|
|
551
|
-
|
|
552
|
-
const raw = readFileSync(filePath, 'utf8');
|
|
553
|
-
const { frontmatter: fmRaw } = extractFrontmatter(raw);
|
|
554
|
-
const parsedFm = parseSimpleFrontmatter(fmRaw);
|
|
555
|
-
const oldStatus = asString(parsedFm.status);
|
|
556
|
-
const repoPath = toRepoPath(filePath, config.repoRoot);
|
|
557
|
-
|
|
558
|
-
if (oldStatus !== 'in-session') die(`Plan is not in-session (current: ${oldStatus}).\n ${repoPath}`);
|
|
559
|
-
|
|
560
|
-
const today = nowIso();
|
|
561
|
-
|
|
562
|
-
if (dryRun) {
|
|
563
|
-
process.stderr.write(`${dim('[dry-run]')} Would update: status: in-session → ${targetStatus}, updated: ${today}\n`);
|
|
564
|
-
} else {
|
|
565
|
-
updateFrontmatter(filePath, { status: targetStatus, updated: today });
|
|
566
|
-
regenIndex(config);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
if (json) {
|
|
570
|
-
process.stdout.write(JSON.stringify({ path: repoPath, oldStatus, newStatus: targetStatus }, null, 2) + '\n');
|
|
571
|
-
} else {
|
|
572
|
-
process.stdout.write(`${green('✓ Finished')}: ${repoPath} (in-session → ${targetStatus})\n`);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
if (!dryRun) {
|
|
576
|
-
try { releaseLease(config, repoPath, { force: true }); } catch (err) { warn(`Could not release lease for ${repoPath}: ${err.message}`); }
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
try { config.hooks.onFinish?.({ path: repoPath, oldStatus, newStatus: targetStatus }); } catch (err) { warn(`Hook 'onFinish' threw: ${err.message}`); }
|
|
580
|
-
}
|
|
581
|
-
|
|
582
526
|
export function runArchive(argv, config, opts = {}) {
|
|
583
527
|
const { dryRun, out = process.stdout } = opts;
|
|
584
528
|
const noIndex = argv.includes('--no-index') || opts.noIndex;
|
|
@@ -747,7 +691,7 @@ export async function runSet(argv, config, opts = {}) {
|
|
|
747
691
|
const statusArgs = [filePath, newStatus];
|
|
748
692
|
if (noIndex) statusArgs.push('--no-index');
|
|
749
693
|
if (showFiles) statusArgs.push('--show-files');
|
|
750
|
-
await runStatus(statusArgs, config, { dryRun });
|
|
694
|
+
await runStatus(statusArgs, config, { dryRun, suppressDeprecation: true });
|
|
751
695
|
|
|
752
696
|
if (oldStatus === 'in-session' && newStatus !== 'in-session' && !dryRun) {
|
|
753
697
|
const repoPath = toRepoPath(filePath, config.repoRoot);
|