dotmd-cli 0.13.0 → 0.13.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 +35 -45
- package/package.json +1 -1
- package/src/git.mjs +18 -0
- package/src/lifecycle.mjs +3 -2
- package/src/query.mjs +3 -2
- package/src/validate.mjs +3 -2
package/bin/dotmd.mjs
CHANGED
|
@@ -4,29 +4,6 @@ import { readFileSync } from 'node:fs';
|
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { resolveConfig } from '../src/config.mjs';
|
|
7
|
-
import { buildIndex } from '../src/index.mjs';
|
|
8
|
-
import { renderCompactList, renderVerboseList, renderContext, renderBriefing, renderCheck, renderCoverage, buildCoverage } from '../src/render.mjs';
|
|
9
|
-
import { renderIndexFile, writeIndex } from '../src/index-file.mjs';
|
|
10
|
-
import { runFocus, runQuery } from '../src/query.mjs';
|
|
11
|
-
import { runStatus, runArchive, runTouch, runBulkArchive, runPickup, runFinish } from '../src/lifecycle.mjs';
|
|
12
|
-
import { runInit } from '../src/init.mjs';
|
|
13
|
-
import { runNew } from '../src/new.mjs';
|
|
14
|
-
import { runCompletions } from '../src/completions.mjs';
|
|
15
|
-
import { runWatch } from '../src/watch.mjs';
|
|
16
|
-
import { runDiff } from '../src/diff.mjs';
|
|
17
|
-
import { runLint } from '../src/lint.mjs';
|
|
18
|
-
import { runRename } from '../src/rename.mjs';
|
|
19
|
-
import { runMigrate } from '../src/migrate.mjs';
|
|
20
|
-
import { runFixRefs, fixBrokenRefs } from '../src/fix-refs.mjs';
|
|
21
|
-
import { buildGraph, renderGraphText, renderGraphDot, renderGraphJson } from '../src/graph.mjs';
|
|
22
|
-
import { runDoctor } from '../src/doctor.mjs';
|
|
23
|
-
import { buildStats, renderStats, renderStatsJson } from '../src/stats.mjs';
|
|
24
|
-
import { runSummary } from '../src/summary.mjs';
|
|
25
|
-
import { runDeps, runUnblocks } from '../src/deps.mjs';
|
|
26
|
-
import { runHealth } from '../src/health.mjs';
|
|
27
|
-
import { runGlossary } from '../src/glossary.mjs';
|
|
28
|
-
import { runExport } from '../src/export.mjs';
|
|
29
|
-
import { runNotion } from '../src/notion.mjs';
|
|
30
7
|
import { die, warn, levenshtein } from '../src/util.mjs';
|
|
31
8
|
|
|
32
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -427,6 +404,7 @@ async function main() {
|
|
|
427
404
|
}
|
|
428
405
|
|
|
429
406
|
if (command === 'completions') {
|
|
407
|
+
const { runCompletions } = await import('../src/completions.mjs');
|
|
430
408
|
runCompletions(args.slice(1));
|
|
431
409
|
return;
|
|
432
410
|
}
|
|
@@ -447,12 +425,13 @@ async function main() {
|
|
|
447
425
|
|
|
448
426
|
// Init — now has access to config for Claude command generation
|
|
449
427
|
if (command === 'init') {
|
|
428
|
+
const { runInit } = await import('../src/init.mjs');
|
|
450
429
|
runInit(process.cwd(), config.configFound ? config : null);
|
|
451
430
|
return;
|
|
452
431
|
}
|
|
453
432
|
|
|
454
433
|
// Watch is a pure proxy — pass raw args so the child process gets all flags
|
|
455
|
-
if (command === 'watch') { runWatch(args.slice(1), config); return; }
|
|
434
|
+
if (command === 'watch') { const { runWatch } = await import('../src/watch.mjs'); runWatch(args.slice(1), config); return; }
|
|
456
435
|
|
|
457
436
|
// Strip global flags from restArgs so commands don't have to filter them
|
|
458
437
|
const restArgs = [];
|
|
@@ -485,35 +464,41 @@ async function main() {
|
|
|
485
464
|
|
|
486
465
|
// Preset aliases
|
|
487
466
|
if (config.presets[command]) {
|
|
467
|
+
const { buildIndex } = await import('../src/index.mjs');
|
|
468
|
+
const { runQuery } = await import('../src/query.mjs');
|
|
488
469
|
const index = buildIndex(config);
|
|
489
470
|
runQuery(index, [...config.presets[command], ...restArgs], config);
|
|
490
471
|
return;
|
|
491
472
|
}
|
|
492
473
|
|
|
493
474
|
// Commands that handle their own index building
|
|
494
|
-
if (command === 'diff') { runDiff(restArgs, config); return; }
|
|
495
|
-
if (command === 'summary') { runSummary(restArgs, config); return; }
|
|
496
|
-
if (command === 'deps') { runDeps(restArgs, config); return; }
|
|
497
|
-
if (command === 'unblocks') { runUnblocks(restArgs, config); return; }
|
|
498
|
-
if (command === 'health') { runHealth(restArgs, config); return; }
|
|
499
|
-
if (command === 'glossary') { runGlossary(restArgs, config); return; }
|
|
500
|
-
if (command === 'export') { runExport(restArgs, config, { dryRun, root: rootArg, type: typeArg }); return; }
|
|
501
|
-
if (command === 'notion') { await runNotion(restArgs, config, { dryRun }); return; }
|
|
475
|
+
if (command === 'diff') { const { runDiff } = await import('../src/diff.mjs'); runDiff(restArgs, config); return; }
|
|
476
|
+
if (command === 'summary') { const { runSummary } = await import('../src/summary.mjs'); runSummary(restArgs, config); return; }
|
|
477
|
+
if (command === 'deps') { const { runDeps } = await import('../src/deps.mjs'); runDeps(restArgs, config); return; }
|
|
478
|
+
if (command === 'unblocks') { const { runUnblocks } = await import('../src/deps.mjs'); runUnblocks(restArgs, config); return; }
|
|
479
|
+
if (command === 'health') { const { runHealth } = await import('../src/health.mjs'); runHealth(restArgs, config); return; }
|
|
480
|
+
if (command === 'glossary') { const { runGlossary } = await import('../src/glossary.mjs'); runGlossary(restArgs, config); return; }
|
|
481
|
+
if (command === 'export') { const { runExport } = await import('../src/export.mjs'); runExport(restArgs, config, { dryRun, root: rootArg, type: typeArg }); return; }
|
|
482
|
+
if (command === 'notion') { const { runNotion } = await import('../src/notion.mjs'); await runNotion(restArgs, config, { dryRun }); return; }
|
|
502
483
|
|
|
503
484
|
// Lifecycle commands
|
|
504
|
-
if (command === 'pickup') { await runPickup(restArgs, config, { dryRun }); return; }
|
|
505
|
-
if (command === 'finish') { await runFinish(restArgs, config, { dryRun }); return; }
|
|
506
|
-
if (command === 'status') { await runStatus(restArgs, config, { dryRun }); return; }
|
|
507
|
-
if (command === 'archive') { runArchive(restArgs, config, { dryRun }); return; }
|
|
508
|
-
if (command === 'bulk' && restArgs[0] === 'archive') { runBulkArchive(restArgs.slice(1), config, { dryRun }); return; }
|
|
509
|
-
if (command === 'touch') { runTouch(restArgs, config, { dryRun }); return; }
|
|
510
|
-
if (command === 'new') { await runNew(restArgs, config, { dryRun, root: rootArg }); return; }
|
|
511
|
-
if (command === 'lint') { runLint(restArgs, config, { dryRun }); return; }
|
|
512
|
-
if (command === 'rename') { await runRename(restArgs, config, { dryRun }); return; }
|
|
513
|
-
if (command === 'migrate') { runMigrate(restArgs, config, { dryRun }); return; }
|
|
514
|
-
if (command === 'fix-refs') { runFixRefs(restArgs, config, { dryRun }); return; }
|
|
515
|
-
if (command === 'doctor') { runDoctor(restArgs, config, { dryRun }); return; }
|
|
516
|
-
|
|
485
|
+
if (command === 'pickup') { const { runPickup } = await import('../src/lifecycle.mjs'); await runPickup(restArgs, config, { dryRun }); return; }
|
|
486
|
+
if (command === 'finish') { const { runFinish } = await import('../src/lifecycle.mjs'); await runFinish(restArgs, config, { dryRun }); return; }
|
|
487
|
+
if (command === 'status') { const { runStatus } = await import('../src/lifecycle.mjs'); await runStatus(restArgs, config, { dryRun }); return; }
|
|
488
|
+
if (command === 'archive') { const { runArchive } = await import('../src/lifecycle.mjs'); runArchive(restArgs, config, { dryRun }); return; }
|
|
489
|
+
if (command === 'bulk' && restArgs[0] === 'archive') { const { runBulkArchive } = await import('../src/lifecycle.mjs'); runBulkArchive(restArgs.slice(1), config, { dryRun }); return; }
|
|
490
|
+
if (command === 'touch') { const { runTouch } = await import('../src/lifecycle.mjs'); runTouch(restArgs, config, { dryRun }); return; }
|
|
491
|
+
if (command === 'new') { const { runNew } = await import('../src/new.mjs'); await runNew(restArgs, config, { dryRun, root: rootArg }); return; }
|
|
492
|
+
if (command === 'lint') { const { runLint } = await import('../src/lint.mjs'); runLint(restArgs, config, { dryRun }); return; }
|
|
493
|
+
if (command === 'rename') { const { runRename } = await import('../src/rename.mjs'); await runRename(restArgs, config, { dryRun }); return; }
|
|
494
|
+
if (command === 'migrate') { const { runMigrate } = await import('../src/migrate.mjs'); runMigrate(restArgs, config, { dryRun }); return; }
|
|
495
|
+
if (command === 'fix-refs') { const { runFixRefs } = await import('../src/fix-refs.mjs'); runFixRefs(restArgs, config, { dryRun }); return; }
|
|
496
|
+
if (command === 'doctor') { const { runDoctor } = await import('../src/doctor.mjs'); runDoctor(restArgs, config, { dryRun }); return; }
|
|
497
|
+
|
|
498
|
+
// All remaining commands need the index + render modules
|
|
499
|
+
const { buildIndex } = await import('../src/index.mjs');
|
|
500
|
+
const { renderCompactList, renderVerboseList, renderContext, renderBriefing, renderCheck, renderCoverage, buildCoverage } = await import('../src/render.mjs');
|
|
501
|
+
const { runFocus, runQuery } = await import('../src/query.mjs');
|
|
517
502
|
const index = buildIndex(config);
|
|
518
503
|
|
|
519
504
|
// Apply --root and --type filters
|
|
@@ -570,6 +555,8 @@ async function main() {
|
|
|
570
555
|
|
|
571
556
|
if (fix) {
|
|
572
557
|
// Auto-fix: broken refs, then lint, then rebuild index
|
|
558
|
+
const { fixBrokenRefs } = await import('../src/fix-refs.mjs');
|
|
559
|
+
const { runLint } = await import('../src/lint.mjs');
|
|
573
560
|
fixBrokenRefs(config, { dryRun, quiet: false });
|
|
574
561
|
runLint(['--fix'], config, { dryRun });
|
|
575
562
|
if (config.indexPath) {
|
|
@@ -629,6 +616,7 @@ async function main() {
|
|
|
629
616
|
}
|
|
630
617
|
|
|
631
618
|
if (command === 'stats') {
|
|
619
|
+
const { buildStats, renderStats, renderStatsJson } = await import('../src/stats.mjs');
|
|
632
620
|
const stats = buildStats(index, config);
|
|
633
621
|
if (args.includes('--json')) {
|
|
634
622
|
process.stdout.write(renderStatsJson(stats));
|
|
@@ -643,6 +631,7 @@ async function main() {
|
|
|
643
631
|
die('Index generation is not configured. Add an `index` section to your dotmd.config.mjs.');
|
|
644
632
|
}
|
|
645
633
|
const write = args.includes('--write');
|
|
634
|
+
const { renderIndexFile, writeIndex } = await import('../src/index-file.mjs');
|
|
646
635
|
const rendered = renderIndexFile(index, config);
|
|
647
636
|
if (write && !dryRun) {
|
|
648
637
|
writeIndex(rendered, config);
|
|
@@ -730,6 +719,7 @@ async function main() {
|
|
|
730
719
|
}
|
|
731
720
|
|
|
732
721
|
if (command === 'graph') {
|
|
722
|
+
const { buildGraph, renderGraphText, renderGraphDot, renderGraphJson } = await import('../src/graph.mjs');
|
|
733
723
|
const statusFilter = (() => { const i = args.indexOf('--status'); return i !== -1 && args[i + 1] ? args[i + 1] : null; })();
|
|
734
724
|
const moduleFilter = (() => { const i = args.indexOf('--module'); return i !== -1 && args[i + 1] ? args[i + 1] : null; })();
|
|
735
725
|
const surfaceFilter = (() => { const i = args.indexOf('--surface'); return i !== -1 && args[i + 1] ? args[i + 1] : null; })();
|
package/package.json
CHANGED
package/src/git.mjs
CHANGED
|
@@ -19,6 +19,24 @@ export function getGitLastModified(relPath, repoRoot) {
|
|
|
19
19
|
return result.stdout.trim();
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
export function getGitLastModifiedBatch(repoRoot) {
|
|
23
|
+
const result = spawnSync('git', [
|
|
24
|
+
'log', '--format=commit %aI', '--name-only', '--diff-filter=ACDMR', 'HEAD',
|
|
25
|
+
], { cwd: repoRoot, encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
|
|
26
|
+
if (result.error || result.status !== 0) return new Map();
|
|
27
|
+
|
|
28
|
+
const map = new Map();
|
|
29
|
+
let currentDate = null;
|
|
30
|
+
for (const line of result.stdout.split('\n')) {
|
|
31
|
+
if (line.startsWith('commit ')) {
|
|
32
|
+
currentDate = line.slice(7).trim();
|
|
33
|
+
} else if (line && currentDate && !map.has(line)) {
|
|
34
|
+
map.set(line, currentDate);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return map;
|
|
38
|
+
}
|
|
39
|
+
|
|
22
40
|
export function gitMv(source, target, repoRoot) {
|
|
23
41
|
ensureGit();
|
|
24
42
|
const result = spawnSync('git', ['mv', source, target], {
|
package/src/lifecycle.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { extractFrontmatter, parseSimpleFrontmatter, replaceFrontmatter } from './frontmatter.mjs';
|
|
4
4
|
import { asString, toRepoPath, die, warn, resolveDocPath, escapeRegex } from './util.mjs';
|
|
5
|
-
import { gitMv, getGitLastModified } from './git.mjs';
|
|
5
|
+
import { gitMv, getGitLastModified, getGitLastModifiedBatch } from './git.mjs';
|
|
6
6
|
import { buildIndex, collectDocFiles } from './index.mjs';
|
|
7
7
|
import { renderIndexFile, writeIndex } from './index-file.mjs';
|
|
8
8
|
import { green, dim, yellow } from './color.mjs';
|
|
@@ -356,6 +356,7 @@ export function runTouch(argv, config, opts = {}) {
|
|
|
356
356
|
|
|
357
357
|
const prefix = dryRun ? dim('[dry-run] ') : '';
|
|
358
358
|
let synced = 0;
|
|
359
|
+
const gitDates = getGitLastModifiedBatch(config.repoRoot);
|
|
359
360
|
|
|
360
361
|
for (const filePath of allFiles) {
|
|
361
362
|
const repoPath = toRepoPath(filePath, config.repoRoot);
|
|
@@ -368,7 +369,7 @@ export function runTouch(argv, config, opts = {}) {
|
|
|
368
369
|
if (config.lifecycle.skipStaleFor.has(status)) continue;
|
|
369
370
|
|
|
370
371
|
const fmUpdated = asString(parsed.updated);
|
|
371
|
-
const gitDate =
|
|
372
|
+
const gitDate = gitDates.get(repoPath) ?? null;
|
|
372
373
|
if (!gitDate) continue;
|
|
373
374
|
|
|
374
375
|
const gitDay = gitDate.slice(0, 10);
|
package/src/query.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { capitalize, toSlug, warn } from './util.mjs';
|
|
4
4
|
import { renderProgressBar } from './render.mjs';
|
|
5
5
|
import { computeDaysSinceUpdate, computeIsStale } from './validate.mjs';
|
|
6
|
-
import {
|
|
6
|
+
import { getGitLastModifiedBatch } from './git.mjs';
|
|
7
7
|
import { extractFrontmatter } from './frontmatter.mjs';
|
|
8
8
|
import { summarizeDocBody } from './ai.mjs';
|
|
9
9
|
import { dim } from './color.mjs';
|
|
@@ -128,8 +128,9 @@ export function filterDocs(docs, filters, config) {
|
|
|
128
128
|
if (filters.updatedSince) result = result.filter(d => d.updated && d.updated >= filters.updatedSince);
|
|
129
129
|
|
|
130
130
|
if (filters.git) {
|
|
131
|
+
const gitDates = getGitLastModifiedBatch(config.repoRoot);
|
|
131
132
|
for (const doc of result) {
|
|
132
|
-
const gitDate =
|
|
133
|
+
const gitDate = gitDates.get(doc.path) ?? null;
|
|
133
134
|
if (gitDate) {
|
|
134
135
|
doc.daysSinceUpdate = computeDaysSinceUpdate(gitDate);
|
|
135
136
|
doc.isStale = computeIsStale(doc.status, gitDate, config);
|
package/src/validate.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { asString } from './util.mjs';
|
|
4
|
-
import { getGitLastModified } from './git.mjs';
|
|
4
|
+
import { getGitLastModified, getGitLastModifiedBatch } from './git.mjs';
|
|
5
5
|
import { toRepoPath } from './util.mjs';
|
|
6
6
|
|
|
7
7
|
const NOW = new Date();
|
|
@@ -150,11 +150,12 @@ export function checkBidirectionalReferences(docs, config) {
|
|
|
150
150
|
|
|
151
151
|
export function checkGitStaleness(docs, config) {
|
|
152
152
|
const warnings = [];
|
|
153
|
+
const gitDates = getGitLastModifiedBatch(config.repoRoot);
|
|
153
154
|
for (const doc of docs) {
|
|
154
155
|
if (config.lifecycle.skipStaleFor.has(doc.status)) continue;
|
|
155
156
|
if (!doc.updated) continue;
|
|
156
157
|
|
|
157
|
-
const gitDate =
|
|
158
|
+
const gitDate = gitDates.get(doc.path) ?? null;
|
|
158
159
|
if (!gitDate) continue;
|
|
159
160
|
|
|
160
161
|
const gitDay = gitDate.slice(0, 10);
|