dotmd-cli 0.76.2 → 0.76.3
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/section.mjs +34 -3
package/package.json
CHANGED
package/src/section.mjs
CHANGED
|
@@ -9,6 +9,7 @@ export function walkSections(body) {
|
|
|
9
9
|
const headingRe = /^(#{1,6})\s+(.+?)\s*$/;
|
|
10
10
|
const sections = [];
|
|
11
11
|
let fenceChar = null;
|
|
12
|
+
let h2Ancestor = null;
|
|
12
13
|
|
|
13
14
|
for (let i = 0; i < lines.length; i++) {
|
|
14
15
|
const line = lines[i];
|
|
@@ -22,13 +23,18 @@ export function walkSections(body) {
|
|
|
22
23
|
if (fenceChar !== null) continue;
|
|
23
24
|
const h = line.match(headingRe);
|
|
24
25
|
if (!h) continue;
|
|
26
|
+
const level = h[1].length;
|
|
27
|
+
const heading = h[2];
|
|
28
|
+
if (level === 1) h2Ancestor = null;
|
|
25
29
|
sections.push({
|
|
26
|
-
level
|
|
27
|
-
heading
|
|
30
|
+
level,
|
|
31
|
+
heading,
|
|
32
|
+
h2Ancestor: level > 2 ? h2Ancestor : null,
|
|
28
33
|
lineStart: i + 1, // 1-indexed
|
|
29
34
|
lineEnd: lines.length, // patched below
|
|
30
35
|
bodyLineStart: i + 2,
|
|
31
36
|
});
|
|
37
|
+
if (level === 2) h2Ancestor = heading;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -111,6 +117,7 @@ export function detectMarker(heading) {
|
|
|
111
117
|
// codepoint was. Reported by the owner, 2026-08-16.
|
|
112
118
|
const PHASE_DECORATION = String.raw`[\s>*_~\`#-]*(?:[✅🚧⬜🟡⏭☑✔✓◻☐⬛🔴🔄][︎️]?\s*)*`;
|
|
113
119
|
const PHASE_LEAD = new RegExp(`^${PHASE_DECORATION}phase\\b`, 'i');
|
|
120
|
+
const FILES_MANIFEST_ANCESTOR = new RegExp(`^${PHASE_DECORATION}files\\b`, 'i');
|
|
114
121
|
|
|
115
122
|
// "Phase 3 outcome" is commentary ABOUT a phase, not a phase. Counting it
|
|
116
123
|
// inflates the phase set, and because `findActivePhase` ranks blocked above
|
|
@@ -126,9 +133,33 @@ const PHASE_COMMENTARY = new RegExp(
|
|
|
126
133
|
'i',
|
|
127
134
|
);
|
|
128
135
|
|
|
136
|
+
// Compound commentary shapes proven against the full platform corpus. Keep
|
|
137
|
+
// these anchored immediately after the phase identifier: the individual nouns
|
|
138
|
+
// all collide with genuine work. In particular, do not add bare `status`,
|
|
139
|
+
// `audit`, `design`, `shape`, `plan`, `pre-plan`, or `gap-check`; the corpus has
|
|
140
|
+
// executable phases with each of those names. The dated gap-check form below is
|
|
141
|
+
// a status report, while `Phase N — gap-check fixes` remains a real phase.
|
|
142
|
+
const PHASE_COMPOUND_COMMENTARY = new RegExp(
|
|
143
|
+
`^${PHASE_DECORATION}phase\\s+\\S+\\s+(?:` +
|
|
144
|
+
`execution\\s+status|` +
|
|
145
|
+
`status\\s+snapshot|` +
|
|
146
|
+
`gap[- ]check\\s+\\d{4}-\\d{2}-\\d{2}|` +
|
|
147
|
+
`audit\\s+results?|` +
|
|
148
|
+
`inventory\\s+findings?|` +
|
|
149
|
+
`deviations\\s*(?:\\+|&|and)\\s*(?:open\\s+questions|notes?)|` +
|
|
150
|
+
`design\\s+[-—:]\\s*researched|` +
|
|
151
|
+
`shape\\s+[-—:]\\s*worked\\s+out|` +
|
|
152
|
+
`sub[- ]phases` +
|
|
153
|
+
`)\\b`,
|
|
154
|
+
'i',
|
|
155
|
+
);
|
|
156
|
+
|
|
129
157
|
export function isPhaseHeading(section) {
|
|
130
158
|
if (section.level !== 3) return false;
|
|
131
|
-
|
|
159
|
+
if (FILES_MANIFEST_ANCESTOR.test(section.h2Ancestor ?? '')) return false;
|
|
160
|
+
return PHASE_LEAD.test(section.heading)
|
|
161
|
+
&& !PHASE_COMMENTARY.test(section.heading)
|
|
162
|
+
&& !PHASE_COMPOUND_COMMENTARY.test(section.heading);
|
|
132
163
|
}
|
|
133
164
|
|
|
134
165
|
// A phase's OWN checklist — the boxes directly under its heading, stopping at
|