dotmd-cli 0.36.1 → 0.36.2
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 +1 -1
- package/src/config.mjs +10 -0
- package/src/glossary.mjs +13 -6
- package/src/query.mjs +14 -7
- package/src/render.mjs +7 -1
package/package.json
CHANGED
package/src/config.mjs
CHANGED
|
@@ -158,6 +158,16 @@ function normalizeRichStatuses(config, userConfig) {
|
|
|
158
158
|
const quietImpliesSkipStale = p.quiet && p.skipStale !== false;
|
|
159
159
|
const quietImpliesSkipWarnings = p.quiet && p.skipWarnings !== false;
|
|
160
160
|
|
|
161
|
+
// Contradiction diagnostics — emit at load so dead config doesn't fail silently.
|
|
162
|
+
const skipStaleEffective = p.skipStale === true || quietImpliesSkipStale;
|
|
163
|
+
const skipWarningsEffective = p.skipWarnings === true || quietImpliesSkipWarnings;
|
|
164
|
+
if (skipStaleEffective && p.staleDays != null) {
|
|
165
|
+
warn(`dotmd config: status "${typeName}.${name}" has skipStale: true and staleDays: ${p.staleDays} — staleDays is ignored. Drop one to silence this warning.`);
|
|
166
|
+
}
|
|
167
|
+
if (skipWarningsEffective && p.requiresModule) {
|
|
168
|
+
warn(`dotmd config: status "${typeName}.${name}" has skipWarnings: true and requiresModule: true — the module requirement can never fire. Drop one to silence this warning.`);
|
|
169
|
+
}
|
|
170
|
+
|
|
161
171
|
if (p.archive && !derived.archiveStatuses.includes(name)) derived.archiveStatuses.push(name);
|
|
162
172
|
if ((p.skipStale || quietImpliesSkipStale) && !derived.skipStaleFor.includes(name)) derived.skipStaleFor.push(name);
|
|
163
173
|
if ((p.skipWarnings || quietImpliesSkipWarnings) && !derived.skipWarningsFor.includes(name)) derived.skipWarningsFor.push(name);
|
package/src/glossary.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { bold, dim, green, yellow } from './color.mjs';
|
|
|
7
7
|
function parseGlossaryTable(content, sectionHeading) {
|
|
8
8
|
const headingRegex = new RegExp(`^##\\s+${sectionHeading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`, 'm');
|
|
9
9
|
const match = content.match(headingRegex);
|
|
10
|
-
if (!match) return [];
|
|
10
|
+
if (!match) return { found: false, entries: [] };
|
|
11
11
|
|
|
12
12
|
const sectionStart = match.index + match[0].length;
|
|
13
13
|
const nextHeading = content.indexOf('\n## ', sectionStart);
|
|
@@ -47,7 +47,7 @@ function parseGlossaryTable(content, sectionHeading) {
|
|
|
47
47
|
entries.push({ term: m[1], meaning: `UI label: "${m[2]}"${m[3] ? ` (${m[3]})` : ''}`, tiers: 'schema→UI' });
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
return entries;
|
|
50
|
+
return { found: true, entries };
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function loadGlossary(config) {
|
|
@@ -62,7 +62,8 @@ function loadGlossary(config) {
|
|
|
62
62
|
|
|
63
63
|
const content = readFileSync(filePath, 'utf8');
|
|
64
64
|
const section = glossaryConfig.section ?? 'Terminology';
|
|
65
|
-
|
|
65
|
+
const result = parseGlossaryTable(content, section);
|
|
66
|
+
return { ...result, path: glossaryConfig.path, section };
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
function matchTerm(query, entries) {
|
|
@@ -177,9 +178,15 @@ export function runGlossary(argv, config) {
|
|
|
177
178
|
const listAll = argv.includes('--list');
|
|
178
179
|
const term = argv.find(a => !a.startsWith('-'));
|
|
179
180
|
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
182
|
-
if (
|
|
181
|
+
const result = loadGlossary(config);
|
|
182
|
+
if (!result) die('No glossary configured. Add glossary: { path, section } to your dotmd config.');
|
|
183
|
+
if (!result.found) {
|
|
184
|
+
die(`Glossary section "## ${result.section}" not found in ${result.path}. Add the section, or update glossary.section in dotmd.config.mjs.`);
|
|
185
|
+
}
|
|
186
|
+
if (result.entries.length === 0) {
|
|
187
|
+
die(`Glossary section "## ${result.section}" found in ${result.path} but contains no recognizable entries (expected markdown table or schema→UI bullets).`);
|
|
188
|
+
}
|
|
189
|
+
const entries = result.entries;
|
|
183
190
|
|
|
184
191
|
if (json && listAll) {
|
|
185
192
|
const index = buildIndex(config);
|
package/src/query.mjs
CHANGED
|
@@ -251,7 +251,13 @@ function getDocSummary(doc, config) {
|
|
|
251
251
|
|
|
252
252
|
function renderQueryResults(docs, filters, config) {
|
|
253
253
|
process.stdout.write('Query\n\n');
|
|
254
|
-
|
|
254
|
+
const total = filters._totalBeforeLimit ?? docs.length;
|
|
255
|
+
const truncated = !filters.all && total > docs.length;
|
|
256
|
+
if (truncated) {
|
|
257
|
+
process.stdout.write(`- results: ${docs.length} of ${total} ${dim('(use --all to see all)')}\n`);
|
|
258
|
+
} else {
|
|
259
|
+
process.stdout.write(`- results: ${docs.length}\n`);
|
|
260
|
+
}
|
|
255
261
|
if (filters.types?.length) process.stdout.write(`- type: ${filters.types.join(', ')}\n`);
|
|
256
262
|
if (filters.statuses?.length) process.stdout.write(`- status: ${filters.statuses.join(', ')}\n`);
|
|
257
263
|
if (filters.keyword) process.stdout.write(`- keyword: ${filters.keyword}\n`);
|
|
@@ -381,12 +387,13 @@ function renderPlansOutput(docs, filters, config, opts = {}) {
|
|
|
381
387
|
// Triage view: flat, sorted by recency, tag on right.
|
|
382
388
|
process.stdout.write('\n');
|
|
383
389
|
renderPlanRows(docs, filters, maxWidth, { showTag: true });
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Footer when the result was capped — emit for every view shape.
|
|
393
|
+
const hidden = totalAll - totalShown;
|
|
394
|
+
if (hidden > 0) {
|
|
395
|
+
process.stdout.write('\n');
|
|
396
|
+
process.stdout.write(dim(` ${hidden} more ${noun} · dotmd ${noun} --all · dotmd ${noun} status\n`));
|
|
390
397
|
}
|
|
391
398
|
|
|
392
399
|
process.stdout.write('\n');
|
package/src/render.mjs
CHANGED
|
@@ -275,7 +275,13 @@ function _renderContext(index, config, opts = {}) {
|
|
|
275
275
|
|
|
276
276
|
const stale = index.docs.filter(d => d.isStale && !config.lifecycle.skipStaleFor.has(d.status));
|
|
277
277
|
if (stale.length) {
|
|
278
|
-
|
|
278
|
+
const cap = config.context?.staleTailLimit ?? 8;
|
|
279
|
+
const shown = stale.slice(0, cap).map(d => `${toSlug(d)} (${d.daysSinceUpdate}d)`).join(', ');
|
|
280
|
+
const overflow = stale.length - cap;
|
|
281
|
+
const tail = overflow > 0
|
|
282
|
+
? `${shown}, …and ${overflow} more (run \`dotmd stale\` for the full list)`
|
|
283
|
+
: shown;
|
|
284
|
+
lines.push(`Stale: ${tail}`);
|
|
279
285
|
} else {
|
|
280
286
|
lines.push('Stale: none');
|
|
281
287
|
}
|