@sentropic/track 0.96.2 → 0.97.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/dist/cli/desync.d.ts +6 -5
- package/dist/cli/desync.d.ts.map +1 -1
- package/dist/cli/desync.js +59 -9
- package/dist/cli/desync.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/desync.d.ts
CHANGED
|
@@ -7,11 +7,12 @@ export interface DesyncFinding {
|
|
|
7
7
|
hint: string;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* SPEC §4 round-trip / desync rule: when an Item's `body`
|
|
11
|
-
*
|
|
12
|
-
* file or a title mismatch is a desync finding (MVP reports; it never auto-repairs).
|
|
13
|
-
* bodies (the common case, incl. BRANCH-imported items) are not file
|
|
14
|
-
* Each finding carries a `hint` — a suggested fix the human/agent may
|
|
10
|
+
* SPEC §4 round-trip / desync rule: when an Item's `body` is a markdown file reference (see
|
|
11
|
+
* {@link resolveMarkdownRef}), that file MUST exist and its H1 title MUST match the Item title. A
|
|
12
|
+
* missing file or a title mismatch is a desync finding (MVP reports; it never auto-repairs).
|
|
13
|
+
* Inline-prose bodies (the common case, incl. BRANCH-imported items and spec citations) are not file
|
|
14
|
+
* references and are skipped. Each finding carries a `hint` — a suggested fix the human/agent may
|
|
15
|
+
* apply (track never does).
|
|
15
16
|
*/
|
|
16
17
|
export declare function desyncFindings(state: State, cwd: string): DesyncFinding[];
|
|
17
18
|
//# sourceMappingURL=desync.d.ts.map
|
package/dist/cli/desync.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"desync.d.ts","sourceRoot":"","sources":["../../src/cli/desync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,kGAAkG;IAClG,IAAI,EAAE,MAAM,CAAA;CACb;
|
|
1
|
+
{"version":3,"file":"desync.d.ts","sourceRoot":"","sources":["../../src/cli/desync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,kGAAkG;IAClG,IAAI,EAAE,MAAM,CAAA;CACb;AA6CD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,CAmCzE"}
|
package/dist/cli/desync.js
CHANGED
|
@@ -1,20 +1,70 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { isAbsolute, join } from 'node:path';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* path
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Decide whether an item `body` is a markdown *file reference* (SPEC §4 round-trip). Returns the
|
|
5
|
+
* resolved path plus whether it exists on disk, or `null` for everything that is NOT a reference —
|
|
6
|
+
* prose, a `.md`-suffixed domain/email, or any body that is not unambiguously a single path.
|
|
7
|
+
*
|
|
8
|
+
* The round-trip rule must also fire on a *missing* file, so existence alone cannot be the gate: for
|
|
9
|
+
* an absent file we still need a syntactic decision "did the author mean a path?". That decision is
|
|
10
|
+
* deliberately CONSERVATIVE — precision over recall — because the reported defect was prose being
|
|
11
|
+
* mistaken for a path, and a `.md`-suffix is a false signal (`.md` is also Moldova's ccTLD, and any
|
|
12
|
+
* sentence can end in a "…foo.md" citation). The gate is:
|
|
13
|
+
*
|
|
14
|
+
* 1. If the resolved path EXISTS on disk, it is a reference (ground truth — bare or nested, with
|
|
15
|
+
* spaces or not). This is what validates a real spec file's H1 against the item title.
|
|
16
|
+
* 2. Otherwise it is a reference only when the body is a single, unambiguous path *token*:
|
|
17
|
+
* - it contains a directory separator `/` (a nested path such as `docs/specs/foo.md`); a
|
|
18
|
+
* bare word / domain / email like `service.md` or `contact@service.md` is NOT a reference
|
|
19
|
+
* unless it actually exists (rule 1), so `.md` TLDs never desync;
|
|
20
|
+
* - it contains NO whitespace — prose that merely cites a spec ("… Spec: docs/x.md") has
|
|
21
|
+
* interior whitespace and is not a path token;
|
|
22
|
+
* - it contains no `:` — a glued prose label ("Ref:docs/x.md", "See:docs/x.md") is prose,
|
|
23
|
+
* not a clean path (`:` is not used in this repo's paths).
|
|
24
|
+
*
|
|
25
|
+
* POLICY — ESCALATED to the conductor (two intentional, reversible defaults):
|
|
26
|
+
* (a) A MISSING path that contains whitespace (e.g. `docs/Getting Started.md`) is skipped as
|
|
27
|
+
* prose. This is IRREDUCIBLE: a spaced path is character-for-character indistinguishable from
|
|
28
|
+
* a spaced prose body that ends in a "…/foo.md" citation (both have whitespace + `/` + `.md`),
|
|
29
|
+
* so flagging the former necessarily re-flags the latter — i.e. re-opens the reported bug. The
|
|
30
|
+
* repo's spec-file convention uses hyphenated, space-free names, so precision-first is safe
|
|
31
|
+
* here today. If spaced spec filenames are ever adopted, relax the `\s` rule below (one line)
|
|
32
|
+
* and accept that prose citations will desync again.
|
|
33
|
+
* (b) A MISSING bare name (no `/`) is not validated, so `.md` domains/emails never desync. A bare
|
|
34
|
+
* spec is validated only once it exists (rule 1).
|
|
35
|
+
*/
|
|
36
|
+
function resolveMarkdownRef(body, cwd) {
|
|
37
|
+
if (!body.endsWith('.md'))
|
|
38
|
+
return null;
|
|
39
|
+
const path = isAbsolute(body) ? body : join(cwd, body);
|
|
40
|
+
if (existsSync(path))
|
|
41
|
+
return { path, exists: true };
|
|
42
|
+
if (/\s/.test(body))
|
|
43
|
+
return null; // prose / spaced citation — not a single path token
|
|
44
|
+
if (!body.includes('/'))
|
|
45
|
+
return null; // bare word / domain / email that does not exist
|
|
46
|
+
if (body.includes(':'))
|
|
47
|
+
return null; // glued prose label (Ref:/See:/Spec:) — not a clean path
|
|
48
|
+
return { path, exists: false }; // a clean, nested, missing path: a genuine desync
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* SPEC §4 round-trip / desync rule: when an Item's `body` is a markdown file reference (see
|
|
52
|
+
* {@link resolveMarkdownRef}), that file MUST exist and its H1 title MUST match the Item title. A
|
|
53
|
+
* missing file or a title mismatch is a desync finding (MVP reports; it never auto-repairs).
|
|
54
|
+
* Inline-prose bodies (the common case, incl. BRANCH-imported items and spec citations) are not file
|
|
55
|
+
* references and are skipped. Each finding carries a `hint` — a suggested fix the human/agent may
|
|
56
|
+
* apply (track never does).
|
|
9
57
|
*/
|
|
10
58
|
export function desyncFindings(state, cwd) {
|
|
11
59
|
const findings = [];
|
|
12
60
|
for (const item of state.items.values()) {
|
|
13
61
|
const ref = item.body?.trim();
|
|
14
|
-
if (ref === undefined
|
|
62
|
+
if (ref === undefined)
|
|
63
|
+
continue;
|
|
64
|
+
const resolved = resolveMarkdownRef(ref, cwd);
|
|
65
|
+
if (resolved === null)
|
|
15
66
|
continue;
|
|
16
|
-
|
|
17
|
-
if (!existsSync(path)) {
|
|
67
|
+
if (!resolved.exists) {
|
|
18
68
|
findings.push({
|
|
19
69
|
kind: 'desync',
|
|
20
70
|
itemId: item.id,
|
|
@@ -23,7 +73,7 @@ export function desyncFindings(state, cwd) {
|
|
|
23
73
|
});
|
|
24
74
|
continue;
|
|
25
75
|
}
|
|
26
|
-
const h1 = /^#\s+(.+?)\s*$/m.exec(readFileSync(path, 'utf8'))?.[1];
|
|
76
|
+
const h1 = /^#\s+(.+?)\s*$/m.exec(readFileSync(resolved.path, 'utf8'))?.[1];
|
|
27
77
|
if (h1 === undefined) {
|
|
28
78
|
// SPEC §4 requires the H1 to MATCH the title; a file with no H1 cannot match.
|
|
29
79
|
findings.push({
|
package/dist/cli/desync.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"desync.js","sourceRoot":"","sources":["../../src/cli/desync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAY5C
|
|
1
|
+
{"version":3,"file":"desync.js","sourceRoot":"","sources":["../../src/cli/desync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAY5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,SAAS,kBAAkB,CAAC,IAAY,EAAE,GAAW;IACnD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACtC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACtD,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IACnD,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA,CAAC,oDAAoD;IACrF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA,CAAC,iDAAiD;IACtF,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA,CAAC,yDAAyD;IAC7F,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA,CAAC,kDAAkD;AACnF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,KAAY,EAAE,GAAW;IACtD,MAAM,QAAQ,GAAoB,EAAE,CAAA;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAA;QAC7B,IAAI,GAAG,KAAK,SAAS;YAAE,SAAQ;QAC/B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QAC7C,IAAI,QAAQ,KAAK,IAAI;YAAE,SAAQ;QAC/B,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,MAAM,EAAE,gCAAgC,GAAG,EAAE;gBAC7C,IAAI,EAAE,WAAW,GAAG,mBAAmB,IAAI,CAAC,KAAK,qCAAqC;aACvF,CAAC,CAAA;YACF,SAAQ;QACV,CAAC;QACD,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC3E,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,8EAA8E;YAC9E,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,MAAM,EAAE,kCAAkC,GAAG,EAAE;gBAC/C,IAAI,EAAE,0BAA0B,IAAI,CAAC,KAAK,SAAS,GAAG,GAAG;aAC1D,CAAC,CAAA;QACJ,CAAC;aAAM,IAAI,EAAE,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,MAAM,EAAE,OAAO,EAAE,oBAAoB,IAAI,CAAC,KAAK,MAAM,GAAG,GAAG;gBAC3D,IAAI,EAAE,sCAAsC,EAAE,oBAAoB,GAAG,WAAW,IAAI,CAAC,KAAK,GAAG;aAC9F,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
package/package.json
CHANGED