gennady 0.8.4-draft.2 → 0.8.4-draft.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/ai/directives/sdd-v2/root.directive.xml +36 -3
- package/ai/directives/sdd-v2/router.directive.xml +22 -1
- package/ai/kit/templates/sdd-v2/root.directive.hbs +11 -3
- package/ai/kit/templates/sdd-v2/router.directive.hbs +22 -1
- package/ai/skills/agent-inbox/SKILL.md +1 -1
- package/ai/skills/sdd/SKILL.md +5 -3
- package/ai/skills/sdd-audit/SKILL.md +5 -2
- package/ai/skills/sdd-check/SKILL.md +2 -2
- package/ai/skills/sdd-code-review/SKILL.md +4 -1
- package/ai/skills/sdd-critic/SKILL.md +5 -2
- package/ai/skills/sdd-execute/SKILL.md +5 -2
- package/ai/skills/sdd-reconcile/SKILL.md +5 -2
- package/ai/skills/sdd-scaffold/SKILL.md +5 -2
- package/dist/ai/directives/sdd-v2/root.directive.xml +36 -3
- package/dist/ai/directives/sdd-v2/router.directive.xml +22 -1
- package/dist/ai/kit/templates/sdd-v2/root.directive.hbs +11 -3
- package/dist/ai/kit/templates/sdd-v2/router.directive.hbs +22 -1
- package/dist/ai/skills/agent-inbox/SKILL.md +1 -1
- package/dist/ai/skills/sdd/SKILL.md +5 -3
- package/dist/ai/skills/sdd-audit/SKILL.md +5 -2
- package/dist/ai/skills/sdd-check/SKILL.md +2 -2
- package/dist/ai/skills/sdd-code-review/SKILL.md +4 -1
- package/dist/ai/skills/sdd-critic/SKILL.md +5 -2
- package/dist/ai/skills/sdd-execute/SKILL.md +5 -2
- package/dist/ai/skills/sdd-reconcile/SKILL.md +5 -2
- package/dist/ai/skills/sdd-scaffold/SKILL.md +5 -2
- package/dist/chunks/{classify-mr-stage.logic-BiCHTmPp.js → classify-mr-stage.logic-CazmQDwZ.js} +2 -2
- package/dist/chunks/{config-index-9VHWSDQD.js → config-index-DU8-FEjq.js} +1 -1
- package/dist/chunks/{devtools-b0DwO1x_.js → devtools-1JmXJjUG.js} +1 -1
- package/dist/chunks/{eval.cmd-CwNPaNJd.js → eval.cmd-CBANnOFG.js} +1 -1
- package/dist/chunks/{help-D5cXtdMI.js → help-DVloaFF5.js} +1 -1
- package/dist/chunks/{index-BVnJEutp.js → index-2xhpqJtd.js} +2 -2
- package/dist/chunks/{index-RR5OUxje.js → index-AxsLBUAx.js} +14 -14
- package/dist/chunks/{index-CUkeTGqM.js → index-B7sydB0W.js} +2 -2
- package/dist/chunks/{index-CMCn9ErF.js → index-BKxk4zOz.js} +2 -2
- package/dist/chunks/{index-Db13NlHh.js → index-BNMmX_Mv.js} +21 -21
- package/dist/chunks/{index-CmQO-RmM.js → index-BPzldG3a.js} +2 -2
- package/dist/chunks/{index-BOQl7F_Z.js → index-BQlFDvKW.js} +2 -2
- package/dist/chunks/{index-RzkvIfJQ.js → index-Baq7RL1L.js} +3 -3
- package/dist/chunks/index-BbPiwvY9.js +2 -0
- package/dist/chunks/{index-ClJLPEUB.js → index-BreGNLJ_.js} +1 -1
- package/dist/chunks/{index-DjSafAkN.js → index-BslPwGtM.js} +2 -2
- package/dist/chunks/{index-DiMFxS0z.js → index-BtCUN2fZ.js} +16 -16
- package/dist/chunks/{index-CS0VbiLD.js → index-C10-EOdB.js} +1 -1
- package/dist/chunks/{index-2BOEcJIa.js → index-C4JmZLaj.js} +2 -2
- package/dist/chunks/index-CA-JKLr4.js +2 -0
- package/dist/chunks/{index-43GiH--T.js → index-CG_jJZVu.js} +2 -2
- package/dist/chunks/{index-BdkFKsMm.js → index-CGyP2uDE.js} +3 -3
- package/dist/chunks/{index-BOKv0b01.js → index-CPl1s9XJ.js} +2 -2
- package/dist/chunks/{index-DIPrBH-4.js → index-CSxE4cEm.js} +9 -9
- package/dist/chunks/{index-Cm7U1-fU.js → index-CWR5EzXx.js} +2 -2
- package/dist/chunks/{index-BwN5llCR.js → index-Camql5kL.js} +2 -2
- package/dist/chunks/{index-Drh-J9O7.js → index-CdUiTipO.js} +7 -7
- package/dist/chunks/{index-Cn029KTN.js → index-Crg61pK5.js} +2 -2
- package/dist/chunks/{index-Dja2O-hV.js → index-Cv9ZYXso.js} +1 -1
- package/dist/chunks/{index-Ck8v_Gv7.js → index-D7ADMlG3.js} +1 -1
- package/dist/chunks/index-DNl2gC8l.js +158 -0
- package/dist/chunks/{index-BYIzl-Ut.js → index-DVJA0qVm.js} +36 -36
- package/dist/chunks/{index-BAEIZVx0.js → index-DcFJhkY1.js} +2 -2
- package/dist/chunks/{index-Dx5_CB2E.js → index-DdEd-L3x.js} +2 -2
- package/dist/chunks/{index-DVmqMmgb.js → index-DkGA1eW_.js} +32 -32
- package/dist/chunks/{index-3k7mPX1e.js → index-Dnwxlti3.js} +1 -1
- package/dist/chunks/{index-CrizvxOJ.js → index-DqdEJDi2.js} +2 -2
- package/dist/chunks/{index-BIPebtDl.js → index-DqiwmBt4.js} +1 -1
- package/dist/chunks/{index-DS4MhAw-.js → index-PfuqBWjY.js} +2 -2
- package/dist/chunks/{index-BmFT1Kx2.js → index-SVP6RfVl.js} +2 -2
- package/dist/chunks/{index-CDxV4b81.js → index-Y8wu48Q0.js} +1 -1
- package/dist/chunks/index-_ewSKppm.js +2 -0
- package/dist/chunks/{index-Ctcr_Qeu.js → index-aBVtCLIJ.js} +2 -2
- package/dist/chunks/index-dNdz9j6d.js +2 -0
- package/dist/chunks/{index-BFUkVkSo.js → index-gskOpu3H.js} +16 -16
- package/dist/chunks/{index-CXpkT25O.js → index-pBSLMn5Q.js} +3 -3
- package/dist/chunks/index-sqPhX5Io.js +2 -0
- package/dist/chunks/{index-BzmR4Es2.js → index-vfrjhUD1.js} +39 -39
- package/dist/chunks/{index-J2NvjjDV.js → index-xGF5XC_i.js} +2 -2
- package/dist/chunks/{run-review-command.logic-CA2Rjymb.js → run-review-command.logic-B9GoCxh-.js} +24 -24
- package/dist/chunks/{serve.cmd-RxYS6WoN.js → serve.cmd-UXkaeaPI.js} +2 -2
- package/dist/chunks/{services-Csd556Tv.js → services-BYCeGBlO.js} +4 -4
- package/dist/chunks/{shared-B5CTGvpG.js → shared-B3cXL2Np.js} +1178 -1117
- package/dist/chunks/{stats-index-BLztvK69.js → stats-index-AIAnnp9S.js} +2 -2
- package/dist/gennady.js +46 -46
- package/dist/index.js +4 -4
- package/dist/shared/sdd/ladder.d.ts +42 -0
- package/dist/shared/sdd/module-specs.d.ts +7 -0
- package/dist/shared/sdd/tracker.d.ts +9 -0
- package/package.json +1 -1
- package/dist/chunks/classify-mr-stage.logic-ClmhzQPQ.js +0 -53
- package/dist/chunks/config-index-RFeqlDWs.js +0 -104
- package/dist/chunks/devtools-p8tmPuLn.js +0 -79
- package/dist/chunks/eval.cmd-ewU5lcUY.js +0 -34
- package/dist/chunks/help-DzGnMNi2.js +0 -7
- package/dist/chunks/index--AXFi0ty.js +0 -89
- package/dist/chunks/index-64TSesTc.js +0 -186
- package/dist/chunks/index-9Gv5trS_.js +0 -125
- package/dist/chunks/index-B1DQIryA.js +0 -2
- package/dist/chunks/index-B1PiBeQ3.js +0 -2
- package/dist/chunks/index-B4rzuhkt.js +0 -183
- package/dist/chunks/index-B97HJjkg.js +0 -159
- package/dist/chunks/index-BF6qypm0.js +0 -131
- package/dist/chunks/index-BK84ZQsh.js +0 -128
- package/dist/chunks/index-BRVIirjj.js +0 -141
- package/dist/chunks/index-BXnryCGW.js +0 -96
- package/dist/chunks/index-BaZm7Otb.js +0 -2
- package/dist/chunks/index-Bhk746A2.js +0 -129
- package/dist/chunks/index-Bi-eY_dY.js +0 -164
- package/dist/chunks/index-BjumU69g.js +0 -2
- package/dist/chunks/index-BkWXcpXU.js +0 -16979
- package/dist/chunks/index-BlY4jQIA.js +0 -168
- package/dist/chunks/index-C0iy7GxD.js +0 -140
- package/dist/chunks/index-CCBTXczb.js +0 -56
- package/dist/chunks/index-CDAfkSrr.js +0 -2
- package/dist/chunks/index-CDHymWzC.js +0 -102
- package/dist/chunks/index-CNfXJAao.js +0 -2
- package/dist/chunks/index-CQsae1nq.js +0 -207
- package/dist/chunks/index-CVmd0prf.js +0 -2
- package/dist/chunks/index-CZuTNeNm.js +0 -2
- package/dist/chunks/index-CasNhhrL.js +0 -96
- package/dist/chunks/index-Ce7GWENF.js +0 -377
- package/dist/chunks/index-Cf-02TAg.js +0 -265
- package/dist/chunks/index-CfjQWSrh.js +0 -52
- package/dist/chunks/index-Chr7gBBz.js +0 -443
- package/dist/chunks/index-Ci875Zlg.js +0 -346
- package/dist/chunks/index-CwA6RzIB.js +0 -3793
- package/dist/chunks/index-D1dI63ej.js +0 -46
- package/dist/chunks/index-DCS32A2i.js +0 -663
- package/dist/chunks/index-DOFoNxvb.js +0 -131
- package/dist/chunks/index-DVkCEuws.js +0 -136
- package/dist/chunks/index-DkadaaXq.js +0 -658
- package/dist/chunks/index-Dn11CLtk.js +0 -7
- package/dist/chunks/index-Do3spFJT.js +0 -340
- package/dist/chunks/index-DrFRZ0Yg.js +0 -2
- package/dist/chunks/index-DvEQhXi2.js +0 -1054
- package/dist/chunks/index-GiS0x6jg.js +0 -90
- package/dist/chunks/index-NacvqeQ5.js +0 -69
- package/dist/chunks/index-RNJhFzdr.js +0 -227
- package/dist/chunks/index-R_vUB6CL.js +0 -2
- package/dist/chunks/index-TQft1s5H.js +0 -20
- package/dist/chunks/index-ZmQRP38W.js +0 -26969
- package/dist/chunks/index-jdOZ4AkD.js +0 -143
- package/dist/chunks/index-kNa21kUI.js +0 -279
- package/dist/chunks/index-v4AV9kAc.js +0 -108
- package/dist/chunks/run-review-command.logic-CU1Slmc_.js +0 -331
- package/dist/chunks/serve.cmd-dWu_k_G_.js +0 -162
- package/dist/chunks/services-CwvXl2MB.js +0 -46832
- package/dist/chunks/shared-DSZTUx5b.js +0 -4509
- package/dist/chunks/stats-index-H6ALcjxy.js +0 -66
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import { spawn as
|
|
2
|
-
import v, { mkdirSync as
|
|
3
|
-
import k, { resolve as y, dirname as w, join as h, basename as
|
|
4
|
-
import { platform as
|
|
5
|
-
import { fileURLToPath as
|
|
6
|
-
import { l as O, V as
|
|
7
|
-
import { promisify as
|
|
8
|
-
const
|
|
9
|
-
function
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
function
|
|
1
|
+
import { spawn as Ot, execSync as Ve, execFile as Tt, execFileSync as _t } from "node:child_process";
|
|
2
|
+
import v, { mkdirSync as je, readFileSync as C, existsSync as R, readdirSync as B, statSync as ie, writeFileSync as W, rmSync as Ie, renameSync as Nt } from "node:fs";
|
|
3
|
+
import k, { resolve as y, dirname as w, join as h, basename as V, relative as x, sep as b, extname as Ct, posix as F } from "node:path";
|
|
4
|
+
import { platform as Oe, homedir as ne } from "node:os";
|
|
5
|
+
import { fileURLToPath as me } from "node:url";
|
|
6
|
+
import { l as O, V as Dt, a as At } from "./services-BYCeGBlO.js";
|
|
7
|
+
import { promisify as yt } from "node:util";
|
|
8
|
+
const Rt = 864e5, kt = 3e3, vt = "update-check-worker.ts", wt = "update-check-cache.json";
|
|
9
|
+
function Pt(e) {
|
|
10
|
+
return Oe() === "win32" ? y(process.env.LOCALAPPDATA ?? y(ne(), "AppData", "Local"), "gennady") : Oe() === "darwin" ? y(ne(), "Library", "Caches", "gennady") : y(ne(), ".cache", "gennady");
|
|
11
|
+
}
|
|
12
|
+
function Lt(e) {
|
|
13
13
|
try {
|
|
14
|
-
const t =
|
|
14
|
+
const t = C(e, "utf-8"), s = JSON.parse(t);
|
|
15
15
|
return typeof s?.lastCheck != "string" || typeof s?.latestVersion != "string" ? null : s;
|
|
16
16
|
} catch {
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function bt(e, t) {
|
|
21
21
|
return Date.now() - new Date(e.lastCheck).getTime() < t;
|
|
22
22
|
}
|
|
23
|
-
function
|
|
24
|
-
const s = (
|
|
25
|
-
if (n.some(isNaN) ||
|
|
26
|
-
for (let
|
|
27
|
-
const i = n[
|
|
23
|
+
function Te(e, t) {
|
|
24
|
+
const s = (o) => o.split(".").map((i) => parseInt(i, 10)), n = s(e), r = s(t);
|
|
25
|
+
if (n.some(isNaN) || r.some(isNaN)) return !1;
|
|
26
|
+
for (let o = 0; o < Math.max(n.length, r.length); o++) {
|
|
27
|
+
const i = n[o] ?? 0, a = r[o] ?? 0;
|
|
28
28
|
if (a > i) return !0;
|
|
29
29
|
if (a < i) return !1;
|
|
30
30
|
}
|
|
31
31
|
return !1;
|
|
32
32
|
}
|
|
33
|
-
function
|
|
33
|
+
function _e(e, t) {
|
|
34
34
|
let s = !1;
|
|
35
35
|
process.on("beforeExit", () => {
|
|
36
36
|
s || (s = !0, process.stderr.write(`
|
|
@@ -40,7 +40,7 @@ Update available: ${e} → ${t}
|
|
|
40
40
|
`));
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
|
-
function
|
|
43
|
+
function ao(e, t) {
|
|
44
44
|
if (process.env.GENNADY_NO_UPDATE_CHECK === "1" || process.argv.includes("--no-update-check")) {
|
|
45
45
|
process.env.GENNADY_DEBUG === "1" && process.stderr.write(
|
|
46
46
|
`[update-check] skipped: opt-out (GENNADY_NO_UPDATE_CHECK or --no-update-check)
|
|
@@ -53,25 +53,25 @@ function oo(e, t) {
|
|
|
53
53
|
`);
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
const s = Number(process.env.GENNADY_UPDATE_CHECK_INTERVAL) ||
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
if (
|
|
60
|
-
|
|
56
|
+
const s = Number(process.env.GENNADY_UPDATE_CHECK_INTERVAL) || Rt, n = Pt(), r = y(n, wt);
|
|
57
|
+
je(n, { recursive: !0 });
|
|
58
|
+
const o = Lt(r);
|
|
59
|
+
if (o && bt(o, s)) {
|
|
60
|
+
o.latestVersion && Te(e.version, o.latestVersion) && (process.stderr.isTTY || t?.skipNotificationIfNoTty === !1) && _e(e.version, o.latestVersion);
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
-
const i = y(w(
|
|
64
|
-
|
|
63
|
+
const i = y(w(me(import.meta.url)), vt);
|
|
64
|
+
Ot(
|
|
65
65
|
process.execPath,
|
|
66
|
-
[i, e.name, e.version,
|
|
66
|
+
[i, e.name, e.version, r, String(kt)],
|
|
67
67
|
{
|
|
68
68
|
stdio: "ignore"
|
|
69
69
|
}
|
|
70
|
-
).unref(),
|
|
70
|
+
).unref(), o?.latestVersion && Te(e.version, o.latestVersion) && (process.stderr.isTTY || t?.skipNotificationIfNoTty === !1) && _e(e.version, o.latestVersion);
|
|
71
71
|
}
|
|
72
|
-
const
|
|
72
|
+
const Y = ["plain", "nocolor", "noColor", "no-color", "color=no", "color=never"].some(
|
|
73
73
|
(e) => process.argv.includes(`-${e}`) || process.argv.includes(`--${e}`)
|
|
74
|
-
),
|
|
74
|
+
), G = {
|
|
75
75
|
// Modifiers
|
|
76
76
|
reset: "\x1B[0m",
|
|
77
77
|
bold: "\x1B[1m",
|
|
@@ -117,27 +117,27 @@ const j = ["plain", "nocolor", "noColor", "no-color", "color=no", "color=never"]
|
|
|
117
117
|
bgCyanBright: "\x1B[106m",
|
|
118
118
|
bgWhiteBright: "\x1B[107m"
|
|
119
119
|
};
|
|
120
|
-
function
|
|
121
|
-
const t = (s) =>
|
|
120
|
+
function Ye(e = []) {
|
|
121
|
+
const t = (s) => Y ? s : e.join("") + s + G.reset;
|
|
122
122
|
return new Proxy(t, {
|
|
123
123
|
get(s, n) {
|
|
124
124
|
if (n === "toString")
|
|
125
|
-
return () =>
|
|
126
|
-
if (n in
|
|
127
|
-
const
|
|
128
|
-
return
|
|
125
|
+
return () => Y ? "%s" : e.join("") + "%s" + G.reset;
|
|
126
|
+
if (n in G) {
|
|
127
|
+
const r = G[n];
|
|
128
|
+
return Ye(Y ? [] : [...e, r].filter(Boolean));
|
|
129
129
|
}
|
|
130
130
|
},
|
|
131
|
-
apply(s, n,
|
|
132
|
-
const
|
|
133
|
-
return
|
|
131
|
+
apply(s, n, r) {
|
|
132
|
+
const o = r[0] ?? "";
|
|
133
|
+
return Y ? o : e.join("") + o + G.reset;
|
|
134
134
|
}
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
|
-
const
|
|
138
|
-
const n = { _: [] },
|
|
139
|
-
for (let
|
|
140
|
-
const i = o
|
|
137
|
+
const co = Ye(), lo = (e, t = {}, s = {}) => {
|
|
138
|
+
const n = { _: [] }, r = e.slice(2);
|
|
139
|
+
for (let o = 0; o < r.length; o++) {
|
|
140
|
+
const i = r[o];
|
|
141
141
|
if (i.startsWith("-")) {
|
|
142
142
|
const a = i.replace(/^-+/, ""), [c, l] = a.split("=");
|
|
143
143
|
let f = !1;
|
|
@@ -147,7 +147,7 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
147
147
|
f = !0;
|
|
148
148
|
const m = typeof u == "object" && !Array.isArray(u) ? u.takesValue === !0 : !1;
|
|
149
149
|
let E;
|
|
150
|
-
l !== void 0 ? E = l.replace(/^"|"$/g, "") : m &&
|
|
150
|
+
l !== void 0 ? E = l.replace(/^"|"$/g, "") : m && o + 1 < r.length && !r[o + 1].startsWith("-") ? (E = r[o + 1], o++) : E = !0, d in n ? (Array.isArray(n[d]) || (n[d] = [n[d]]), n[d].push(E)) : n[d] = E;
|
|
151
151
|
break;
|
|
152
152
|
}
|
|
153
153
|
}
|
|
@@ -157,7 +157,7 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
157
157
|
n._.push(i);
|
|
158
158
|
}
|
|
159
159
|
return n;
|
|
160
|
-
},
|
|
160
|
+
}, Mt = {
|
|
161
161
|
js: "JavaScript",
|
|
162
162
|
jsx: "JavaScript",
|
|
163
163
|
ts: "TypeScript",
|
|
@@ -183,16 +183,16 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
183
183
|
sass: "Sass",
|
|
184
184
|
md: "Markdown",
|
|
185
185
|
mdc: "Markdown"
|
|
186
|
-
},
|
|
186
|
+
}, Ne = (e) => Mt[e] ?? void 0, uo = () => {
|
|
187
187
|
try {
|
|
188
|
-
return
|
|
188
|
+
return Ve("osascript -e 'user locale of (get system info)'").toString().trim().toLowerCase().split("_").filter((s) => s !== "en" && s !== "us")[0] ?? "en";
|
|
189
189
|
} catch {
|
|
190
190
|
return "en";
|
|
191
191
|
}
|
|
192
|
-
},
|
|
192
|
+
}, Ce = (e) => {
|
|
193
193
|
const t = e.match(/[\p{L}\p{N}_]+|[^\s\p{L}\p{N}_]/gu);
|
|
194
194
|
return t ? t.length : 0;
|
|
195
|
-
},
|
|
195
|
+
}, $t = [
|
|
196
196
|
"^package\\.json",
|
|
197
197
|
"^tsconfig\\.json",
|
|
198
198
|
"^babel\\.config\\.json",
|
|
@@ -202,7 +202,7 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
202
202
|
"^\\.env(?:\\.[\\w]+)?",
|
|
203
203
|
"^\\..+",
|
|
204
204
|
".*\\.(?:yml|yaml|rc|ini|conf)"
|
|
205
|
-
],
|
|
205
|
+
], xt = [
|
|
206
206
|
"^package-lock\\.json",
|
|
207
207
|
"^npm-shrinkwrap\\.json",
|
|
208
208
|
"^yarn(?:-lock)?\\.(?:yaml|yml|toml)",
|
|
@@ -211,41 +211,41 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
211
211
|
"^podfile\\.lock",
|
|
212
212
|
"^go\\.sum",
|
|
213
213
|
"^gemfile\\.lock"
|
|
214
|
-
],
|
|
214
|
+
], Bt = {
|
|
215
215
|
doc: /\.(md|markdown|txt|rst)$/i,
|
|
216
|
-
cfg: new RegExp(
|
|
216
|
+
cfg: new RegExp($t.join("|"), "i"),
|
|
217
217
|
img: /\.(png|jpe?g|gif|svg|bmp|tiff|ico)$/i,
|
|
218
218
|
css: /\.(css|less|scss|sass|styl)$/i,
|
|
219
219
|
html: /\.(html?)$/i,
|
|
220
220
|
code: /\.(js|jsx|ts|tsx|java|py|c|cpp|cs|rb|php|go|swift|m|mm|kt|sh|bash)$/i,
|
|
221
221
|
bin: /^(exe|dll|so|bin)\b/i,
|
|
222
|
-
lock: new RegExp(
|
|
222
|
+
lock: new RegExp(xt.join("|"), "i"),
|
|
223
223
|
json: /\.json$/i
|
|
224
|
-
},
|
|
224
|
+
}, De = (e, t) => {
|
|
225
225
|
if (t?.extra && Array.isArray(t.extra)) {
|
|
226
226
|
for (const n of t.extra)
|
|
227
227
|
if (/^Binary files? /i.test(n) || /GIT binary patch/i.test(n))
|
|
228
228
|
return "bin";
|
|
229
229
|
}
|
|
230
|
-
return Object.entries(
|
|
231
|
-
},
|
|
230
|
+
return Object.entries(Bt).find(([, n]) => n.test(e))?.[0] ?? "other";
|
|
231
|
+
}, Ut = (e) => {
|
|
232
232
|
const t = e.split(`
|
|
233
233
|
`), s = [];
|
|
234
|
-
let n = null,
|
|
235
|
-
if (t.forEach((
|
|
236
|
-
if (
|
|
234
|
+
let n = null, r = null;
|
|
235
|
+
if (t.forEach((o) => {
|
|
236
|
+
if (o.startsWith("diff --git")) {
|
|
237
237
|
if (n) {
|
|
238
238
|
n.diff.tokens = n.diff.hunks.reduce(
|
|
239
239
|
(f, d) => f + d.tokens,
|
|
240
240
|
0
|
|
241
241
|
), n.tokens = n.diff.tokens;
|
|
242
242
|
const l = n.filename.match(/\.([^.]+)$/);
|
|
243
|
-
n.ext = l?.[1]?.toLowerCase() ?? "", n.category =
|
|
243
|
+
n.ext = l?.[1]?.toLowerCase() ?? "", n.category = De(
|
|
244
244
|
n.filename,
|
|
245
245
|
n.metadata
|
|
246
|
-
), n.programmingLanguage =
|
|
246
|
+
), n.programmingLanguage = Ne(n.ext), s.push(n);
|
|
247
247
|
}
|
|
248
|
-
const i =
|
|
248
|
+
const i = o.match(/^diff --git a\/(.+?) b\/(.+)$/), a = i?.[1] ?? null;
|
|
249
249
|
n = {
|
|
250
250
|
isNew: !1,
|
|
251
251
|
isDeleted: !1,
|
|
@@ -263,93 +263,93 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
263
263
|
ext: "",
|
|
264
264
|
category: "other",
|
|
265
265
|
programmingLanguage: void 0
|
|
266
|
-
},
|
|
267
|
-
} else if (n &&
|
|
268
|
-
const i =
|
|
266
|
+
}, r = null;
|
|
267
|
+
} else if (n && o.startsWith("new file mode")) {
|
|
268
|
+
const i = o.split(" ");
|
|
269
269
|
n.isNew = !0, n.newFileMode = i[3] ?? null, n.metadata.newFileMode = n.newFileMode;
|
|
270
|
-
} else if (n &&
|
|
271
|
-
const i =
|
|
270
|
+
} else if (n && o.startsWith("deleted file mode")) {
|
|
271
|
+
const i = o.split(" ");
|
|
272
272
|
n.isDeleted = !0, n.deletedFileMode = i[3] ?? null, n.metadata.deletedFileMode = n.deletedFileMode;
|
|
273
|
-
} else if (n &&
|
|
274
|
-
const i =
|
|
273
|
+
} else if (n && o.startsWith("old mode")) {
|
|
274
|
+
const i = o.split(" ");
|
|
275
275
|
n.metadata.oldMode = i[2] ?? null;
|
|
276
|
-
} else if (n &&
|
|
277
|
-
const i =
|
|
276
|
+
} else if (n && o.startsWith("new mode")) {
|
|
277
|
+
const i = o.split(" ");
|
|
278
278
|
n.metadata.newMode = i[2] ?? null;
|
|
279
|
-
} else if (n &&
|
|
280
|
-
const i =
|
|
279
|
+
} else if (n && o.startsWith("similarity index")) {
|
|
280
|
+
const i = o.split(" ");
|
|
281
281
|
n.metadata.similarityIndex = i[2] ?? null;
|
|
282
|
-
} else if (n &&
|
|
283
|
-
const i =
|
|
282
|
+
} else if (n && o.startsWith("rename from")) {
|
|
283
|
+
const i = o.substring(11).trim();
|
|
284
284
|
n.isRenamed = !0, n.oldFilename = i, n.metadata.renameFrom = i;
|
|
285
|
-
} else if (n &&
|
|
286
|
-
const i =
|
|
285
|
+
} else if (n && o.startsWith("rename to")) {
|
|
286
|
+
const i = o.substring(9).trim();
|
|
287
287
|
n.isRenamed = !0, n.filename = i, n.metadata.renameTo = i;
|
|
288
|
-
} else n &&
|
|
289
|
-
header:
|
|
290
|
-
changes: [
|
|
291
|
-
tokens:
|
|
292
|
-
}, n.diff.hunks.push(
|
|
288
|
+
} else n && o.startsWith("index") ? n.metadata.index = o.substring(5).trim() : n && (o.startsWith("--- ") || o.startsWith("+++ ")) ? o.startsWith("--- ") ? n.metadata.oldFileMarker = o : n.metadata.newFileMarker = o : n && o.startsWith("@@") ? (r = {
|
|
289
|
+
header: o,
|
|
290
|
+
changes: [o],
|
|
291
|
+
tokens: Ce(o)
|
|
292
|
+
}, n.diff.hunks.push(r)) : r && (o.startsWith("+") || o.startsWith("-") || o.startsWith(" ")) ? (r.changes.push(o), r.tokens += Ce(o)) : n && (Array.isArray(n.metadata.extra) || (n.metadata.extra = []), n.metadata.extra.push(o));
|
|
293
293
|
}), n) {
|
|
294
|
-
const
|
|
295
|
-
|
|
294
|
+
const o = n, i = o.filename.match(/\.([^.]+)$/);
|
|
295
|
+
o.diff.tokens = o.diff.hunks.reduce(
|
|
296
296
|
(a, c) => a + c.tokens,
|
|
297
297
|
0
|
|
298
|
-
),
|
|
298
|
+
), o.tokens = o.diff.tokens, o.ext = i?.[1]?.toLowerCase() ?? "", o.category = De(o.filename, o.metadata), o.programmingLanguage = Ne(o.ext), s.push(o);
|
|
299
299
|
}
|
|
300
300
|
return s;
|
|
301
301
|
}, P = (e, t) => {
|
|
302
302
|
try {
|
|
303
|
-
return
|
|
303
|
+
return Ve(e, { encoding: "utf-8" });
|
|
304
304
|
} catch (s) {
|
|
305
305
|
const n = s.status;
|
|
306
306
|
return n !== void 0 && (t?.expectedExitCodes ?? []).includes(n) || O.error("[execSyncSafe] [running → failed] Command failed", { cause: s }), "";
|
|
307
307
|
}
|
|
308
|
-
},
|
|
308
|
+
}, Ae = (e) => /\.(test|spec)s?\./.test(e), Ft = () => P("git branch --list 2>/dev/null")?.match(/\s*\*?\s*(master|main)$/m)?.[1] ?? "master", fo = () => P("git rev-parse --abbrev-ref HEAD 2>/dev/null").trim() || "HEAD", po = () => {
|
|
309
309
|
const t = (P("git config --get remote.origin.url 2>/dev/null").trim() || P("git remote get-url origin 2>/dev/null").trim() || "").trim();
|
|
310
310
|
if (!t) return null;
|
|
311
311
|
if (/^[a-z]+:\/\//i.test(t))
|
|
312
312
|
try {
|
|
313
|
-
const n = new URL(t),
|
|
314
|
-
return !
|
|
313
|
+
const n = new URL(t), r = (n.hostname || "").toLowerCase(), o = (n.protocol || "").replace(/:$/, "").toLowerCase(), i = (n.pathname || "").replace(/^\/+/, "").replace(/\.git$/i, "");
|
|
314
|
+
return !r || !i ? null : { host: r, project: i, scheme: o };
|
|
315
315
|
} catch (n) {
|
|
316
316
|
O.debug("[getGitRemote] [parsing → skip] URL parse failed", { cause: n });
|
|
317
317
|
}
|
|
318
318
|
const s = t.match(/^[\w.-]+@([^:\/]+)[:\/](.+)$/);
|
|
319
319
|
if (s) {
|
|
320
|
-
const n = (s[1] || "").toLowerCase(),
|
|
321
|
-
return !n || !
|
|
320
|
+
const n = (s[1] || "").toLowerCase(), r = (s[2] || "").replace(/^\/+/, "").replace(/\.git$/i, ""), o = "ssh";
|
|
321
|
+
return !n || !r ? null : { host: n, project: r, scheme: o };
|
|
322
322
|
}
|
|
323
323
|
return null;
|
|
324
|
-
},
|
|
324
|
+
}, Gt = () => {
|
|
325
325
|
try {
|
|
326
|
-
const e = P(`git rev-list --count HEAD ^${
|
|
326
|
+
const e = P(`git rev-list --count HEAD ^${Ft()} 2>/dev/null`);
|
|
327
327
|
return parseInt(e, 10) || 0;
|
|
328
328
|
} catch (e) {
|
|
329
329
|
return O.debug("[getGitCommitCount] [counting → fallback] Using 0", { cause: e }), 0;
|
|
330
330
|
}
|
|
331
|
-
},
|
|
332
|
-
const t =
|
|
333
|
-
(a) => !a.isDeleted && !a.isRenamed && !
|
|
331
|
+
}, Vt = (e) => P(e ? `git diff ${e}` : "git diff HEAD"), mo = (e) => {
|
|
332
|
+
const t = Vt(e), s = Ut(t).sort((a, c) => a.tokens - c.tokens), n = s.filter(
|
|
333
|
+
(a) => !a.isDeleted && !a.isRenamed && !Ae(a.filename) && (a.category === "config" || a.programmingLanguage)
|
|
334
334
|
);
|
|
335
335
|
n.length || n.push(
|
|
336
336
|
...s.filter(
|
|
337
|
-
(a) => !a.isDeleted && !a.isRenamed && (a.category === "doc" ||
|
|
337
|
+
(a) => !a.isDeleted && !a.isRenamed && (a.category === "doc" || Ae(a.filename))
|
|
338
338
|
)
|
|
339
339
|
);
|
|
340
|
-
const
|
|
340
|
+
const r = n.reduce((a, c) => a + c.tokens, 0), o = n.at(-1)?.tokens ?? 0, i = [
|
|
341
341
|
...new Set(n.map((a) => a.programmingLanguage).filter(Boolean))
|
|
342
342
|
];
|
|
343
343
|
return {
|
|
344
344
|
diff: t,
|
|
345
345
|
parsedDiff: s,
|
|
346
346
|
parsedCodeDiff: n,
|
|
347
|
-
parsedCodeTokens:
|
|
348
|
-
parsedCodeChunkMaxTokens:
|
|
347
|
+
parsedCodeTokens: r,
|
|
348
|
+
parsedCodeChunkMaxTokens: o,
|
|
349
349
|
programmingLanguages: i,
|
|
350
|
-
commitCount:
|
|
350
|
+
commitCount: Gt()
|
|
351
351
|
};
|
|
352
|
-
},
|
|
352
|
+
}, jt = (e) => {
|
|
353
353
|
if (Array.isArray(e) && e.length === 2) {
|
|
354
354
|
const t = e[1];
|
|
355
355
|
if (t === null)
|
|
@@ -360,11 +360,11 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
360
360
|
"[UNGUARD_ERROR_SYNTAX] Invalid input: not a valid [result, error] tuple.",
|
|
361
361
|
{ cause: e }
|
|
362
362
|
);
|
|
363
|
-
},
|
|
363
|
+
}, Eo = async (e) => {
|
|
364
364
|
const t = await e;
|
|
365
|
-
return
|
|
366
|
-
},
|
|
367
|
-
const t = String(e ?? "").split(
|
|
365
|
+
return jt(t);
|
|
366
|
+
}, ye = "</think>", ho = (e) => {
|
|
367
|
+
const t = String(e ?? "").split(ye).slice(-1).join(ye).trim();
|
|
368
368
|
return /^(Хорошо,|Okay,)/.test(t) ? t.split(`
|
|
369
369
|
|
|
370
370
|
|
|
@@ -373,7 +373,7 @@ const ro = Ve(), io = (e, t = {}, s = {}) => {
|
|
|
373
373
|
|
|
374
374
|
`).trim() : t;
|
|
375
375
|
};
|
|
376
|
-
class
|
|
376
|
+
class ae {
|
|
377
377
|
/** @purpose Default configuration filename. */
|
|
378
378
|
static DEFAULT_FILENAME = ".gennadyrc";
|
|
379
379
|
/**
|
|
@@ -382,7 +382,7 @@ class re {
|
|
|
382
382
|
* @sideEffect IO: file read at constructor.
|
|
383
383
|
*/
|
|
384
384
|
static getDefaults() {
|
|
385
|
-
return [process.cwd(), process.env.HOME].map((t) => new
|
|
385
|
+
return [process.cwd(), process.env.HOME].map((t) => new ae(t));
|
|
386
386
|
}
|
|
387
387
|
/** @purpose Full path to the loaded rc config file. */
|
|
388
388
|
_filename = "";
|
|
@@ -397,11 +397,11 @@ class re {
|
|
|
397
397
|
* @param [dir] Directory to look for the rc file in (defaults to cwd).
|
|
398
398
|
* @param [name] Config filename (defaults to .gennadyrc).
|
|
399
399
|
*/
|
|
400
|
-
constructor(t = process.cwd(), s =
|
|
400
|
+
constructor(t = process.cwd(), s = ae.DEFAULT_FILENAME) {
|
|
401
401
|
this._filename = h(t, s);
|
|
402
402
|
try {
|
|
403
403
|
if (R(this._filename)) {
|
|
404
|
-
const n = JSON.parse(
|
|
404
|
+
const n = JSON.parse(C(this._filename).toString());
|
|
405
405
|
Array.isArray(n) ? this._data.models = n : n && typeof n == "object" && Array.isArray(n.models) ? this._data = {
|
|
406
406
|
...this._data,
|
|
407
407
|
...n
|
|
@@ -438,7 +438,7 @@ class re {
|
|
|
438
438
|
return this._error;
|
|
439
439
|
}
|
|
440
440
|
}
|
|
441
|
-
const
|
|
441
|
+
const Yt = yt(Tt);
|
|
442
442
|
class A extends Error {
|
|
443
443
|
/**
|
|
444
444
|
* @purpose Create a VCS resolution error with an optional root cause.
|
|
@@ -449,36 +449,36 @@ class A extends Error {
|
|
|
449
449
|
super(t, { cause: s }), this.name = "VcsResolveError";
|
|
450
450
|
}
|
|
451
451
|
}
|
|
452
|
-
function
|
|
452
|
+
function Ht() {
|
|
453
453
|
return {
|
|
454
454
|
git: async (e) => {
|
|
455
|
-
const { stdout: t } = await
|
|
455
|
+
const { stdout: t } = await Yt("git", e, { encoding: "utf-8" });
|
|
456
456
|
return String(t ?? "").trim();
|
|
457
457
|
},
|
|
458
458
|
env: (e) => process.env[e]
|
|
459
459
|
};
|
|
460
460
|
}
|
|
461
|
-
function
|
|
461
|
+
function qt(e) {
|
|
462
462
|
const t = e.lastIndexOf("!");
|
|
463
463
|
if (t === -1) return null;
|
|
464
|
-
const s = e.slice(0, t), n = e.slice(t + 1),
|
|
465
|
-
return !s || !Number.isInteger(
|
|
464
|
+
const s = e.slice(0, t), n = e.slice(t + 1), r = Number(n);
|
|
465
|
+
return !s || !Number.isInteger(r) || r <= 0 ? null : { project: s, iid: r };
|
|
466
466
|
}
|
|
467
|
-
function
|
|
467
|
+
function Wt(e) {
|
|
468
468
|
const t = e.match(/^git@([^:]+):(.+)\.git$/);
|
|
469
469
|
if (t)
|
|
470
470
|
return { host: t[1], project: t[2] };
|
|
471
471
|
const s = e.match(/^https?:\/\/([^/]+)\/(.+)\.git$/);
|
|
472
472
|
return s ? { host: s[1], project: s[2] } : null;
|
|
473
473
|
}
|
|
474
|
-
function
|
|
474
|
+
function Kt(e) {
|
|
475
475
|
const t = e.match(/^https?:\/\/([^/]+)\/(.+)\/-\/merge_requests\/(\d+)\/?$/);
|
|
476
476
|
return t ? { host: t[1], project: t[2], iid: Number(t[3]) } : null;
|
|
477
477
|
}
|
|
478
|
-
async function
|
|
478
|
+
async function Xt(e, t = Ht()) {
|
|
479
479
|
if (O.debug("[resolveVcsContext] [idle → resolving]"), typeof e.url == "string") {
|
|
480
480
|
O.debug("[resolveVcsContext] [resolving → parsing-url]");
|
|
481
|
-
const d =
|
|
481
|
+
const d = Kt(e.url);
|
|
482
482
|
if (!d) {
|
|
483
483
|
const N = `[resolveVcsContext] Некорректный URL: ${e.url}`;
|
|
484
484
|
throw O.error(`[resolveVcsContext] [resolving → failed] ${N}`), new A(`Некорректный URL: ${e.url}`);
|
|
@@ -493,25 +493,25 @@ async function Wt(e, t = jt()) {
|
|
|
493
493
|
}
|
|
494
494
|
if (typeof e.ref == "string" && e.branch)
|
|
495
495
|
throw O.error("[resolveVcsContext] [resolving → failed] [resolveVcsContext] ref и branch не могут быть указаны одновременно"), new A("ref и branch не могут быть указаны одновременно");
|
|
496
|
-
const s = typeof e.ref == "string" ?
|
|
496
|
+
const s = typeof e.ref == "string" ? qt(e.ref) : null;
|
|
497
497
|
if (typeof e.ref == "string" && !s) {
|
|
498
498
|
const d = `[resolveVcsContext] Некорректный формат ref: ${e.ref}`;
|
|
499
499
|
throw O.error(`[resolveVcsContext] [resolving → failed] ${d}`), new A(`Некорректный формат ref: ${e.ref}`);
|
|
500
500
|
}
|
|
501
|
-
const n = s?.iid ?? e.iid,
|
|
502
|
-
let
|
|
503
|
-
if (!
|
|
501
|
+
const n = s?.iid ?? e.iid, r = s?.project ?? e.project;
|
|
502
|
+
let o = e.host, i = r;
|
|
503
|
+
if (!o || !i)
|
|
504
504
|
try {
|
|
505
505
|
O.debug("[resolveVcsContext] [resolving → fetching-remote]");
|
|
506
|
-
const d = await t.git(["config", "remote.origin.url"]), u =
|
|
506
|
+
const d = await t.git(["config", "remote.origin.url"]), u = Wt(d);
|
|
507
507
|
if (!u) {
|
|
508
508
|
const p = `[resolveVcsContext] Не удалось разобрать URL удалённого репозитория: ${d}`;
|
|
509
509
|
throw O.error(`[resolveVcsContext] [resolving → failed] ${p}`), new A(`Не удалось разобрать URL удалённого репозитория: ${d}`);
|
|
510
510
|
}
|
|
511
|
-
|
|
511
|
+
o ??= u.host, i ??= u.project;
|
|
512
512
|
} catch (d) {
|
|
513
513
|
if (d instanceof A) throw d;
|
|
514
|
-
if (!
|
|
514
|
+
if (!r) {
|
|
515
515
|
const u = "[resolveVcsContext] Не найден удалённый репозиторий origin", p = new A("Не найден удалённый репозиторий origin", d);
|
|
516
516
|
throw O.error(`[resolveVcsContext] [resolving → failed] ${u}`, { error: p }), p;
|
|
517
517
|
}
|
|
@@ -519,9 +519,9 @@ async function Wt(e, t = jt()) {
|
|
|
519
519
|
"[resolveVcsContext] [resolving → remote-unreachable] project explicit, skipping host auto-detect"
|
|
520
520
|
);
|
|
521
521
|
}
|
|
522
|
-
if (!
|
|
522
|
+
if (!o || !i)
|
|
523
523
|
throw O.error("[resolveVcsContext] [resolving → failed] [resolveVcsContext] Не удалось определить host и project"), new A("Не удалось определить host и project");
|
|
524
|
-
const a = /github/i.test(
|
|
524
|
+
const a = /github/i.test(o) ? "github" : "gitlab";
|
|
525
525
|
let c = e.branch;
|
|
526
526
|
if (!s && n === void 0)
|
|
527
527
|
try {
|
|
@@ -540,35 +540,35 @@ async function Wt(e, t = jt()) {
|
|
|
540
540
|
}
|
|
541
541
|
const f = {
|
|
542
542
|
provider: a,
|
|
543
|
-
host:
|
|
543
|
+
host: o,
|
|
544
544
|
project: i,
|
|
545
545
|
iid: n,
|
|
546
546
|
branch: c,
|
|
547
547
|
token: l
|
|
548
548
|
};
|
|
549
549
|
return O.info(
|
|
550
|
-
`[resolveVcsContext] [resolving → resolved] ${
|
|
550
|
+
`[resolveVcsContext] [resolving → resolved] ${o}/${i}${n ? `!${n}` : ""}`
|
|
551
551
|
), f;
|
|
552
552
|
}
|
|
553
|
-
const
|
|
553
|
+
const So = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
554
554
|
__proto__: null,
|
|
555
555
|
VcsResolveError: A,
|
|
556
|
-
resolveVcsContext:
|
|
556
|
+
resolveVcsContext: Xt
|
|
557
557
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
558
|
-
function
|
|
558
|
+
function go(e) {
|
|
559
559
|
const t = String(e).match(/<message[\s\S]*?>[\s\S]*?<\/message>/)?.[0];
|
|
560
560
|
if (!t)
|
|
561
561
|
return null;
|
|
562
|
-
const s = (a) => t.match(a)?.[1] ?? "", n = s(/type="([^"]+)"/),
|
|
562
|
+
const s = (a) => t.match(a)?.[1] ?? "", n = s(/type="([^"]+)"/), r = s(/icon="([^"]+)"/), o = s(/<subject>([\s\S]*?)<\/subject>/), i = s(/<description>([\s\S]*?)<\/description>/).replace(/\n\s+-/g, `
|
|
563
563
|
-`);
|
|
564
564
|
return {
|
|
565
565
|
type: n,
|
|
566
|
-
icon:
|
|
567
|
-
subject:
|
|
566
|
+
icon: r,
|
|
567
|
+
subject: o?.trim() || null,
|
|
568
568
|
description: i?.trim() || null
|
|
569
569
|
};
|
|
570
570
|
}
|
|
571
|
-
function
|
|
571
|
+
function oe(e) {
|
|
572
572
|
return e ? String(e).replace(/[<>&'"]/g, (t) => {
|
|
573
573
|
switch (t) {
|
|
574
574
|
case "<":
|
|
@@ -586,37 +586,37 @@ function se(e) {
|
|
|
586
586
|
}
|
|
587
587
|
}) : "";
|
|
588
588
|
}
|
|
589
|
-
function
|
|
590
|
-
const s = " ".repeat(t), { tag: n, attrs:
|
|
589
|
+
function Re(e, t = 0) {
|
|
590
|
+
const s = " ".repeat(t), { tag: n, attrs: r, children: o } = e;
|
|
591
591
|
let i = "";
|
|
592
|
-
if (
|
|
592
|
+
if (r && (i = Object.entries(r).filter(([, c]) => c != null).map(([c, l]) => ` ${c}="${oe(String(l))}"`).join("")), o == null)
|
|
593
593
|
return `${s}<${n}${i} />`;
|
|
594
|
-
if (Array.isArray(
|
|
594
|
+
if (Array.isArray(o) && o.length === 0)
|
|
595
595
|
return `${s}<${n}${i} />`;
|
|
596
596
|
let a = "";
|
|
597
|
-
return Array.isArray(
|
|
597
|
+
return Array.isArray(o) ? o.length > 0 && typeof o[0] == "string" ? a = o.map((l) => oe(l)).join(`
|
|
598
598
|
`) : a = `
|
|
599
|
-
` +
|
|
599
|
+
` + o.map((l) => Re(l, t + 1)).join(`
|
|
600
600
|
`) + `
|
|
601
|
-
` + s : typeof
|
|
602
|
-
` +
|
|
601
|
+
` + s : typeof o == "string" ? a = oe(o) : "cdata" in o ? a = `<![CDATA[${String(o.cdata).replaceAll("]]>", "]]]]><![CDATA[>")}]]>` : a = `
|
|
602
|
+
` + Re(o, t + 1) + `
|
|
603
603
|
` + s, `${s}<${n}${i}>${a}</${n}>`;
|
|
604
604
|
}
|
|
605
|
-
function
|
|
605
|
+
function Io(e) {
|
|
606
606
|
const t = [
|
|
607
607
|
"ai.knowledge.md",
|
|
608
608
|
"ai/ai.knowledge.md"
|
|
609
609
|
], s = [];
|
|
610
610
|
for (const n of t) {
|
|
611
|
-
const
|
|
611
|
+
const r = k.join(e, n);
|
|
612
612
|
try {
|
|
613
|
-
v.existsSync(
|
|
613
|
+
v.existsSync(r) && v.statSync(r).isFile() && s.push(n);
|
|
614
614
|
} catch {
|
|
615
615
|
}
|
|
616
616
|
}
|
|
617
617
|
return s.length === 0 ? "" : `**MUST READ PROJECT KNOWLEDGE FILES**: ${s.join(", ")}.`;
|
|
618
618
|
}
|
|
619
|
-
const
|
|
619
|
+
const Zt = [
|
|
620
620
|
{
|
|
621
621
|
kind: "marker",
|
|
622
622
|
relativePath: "go.mod",
|
|
@@ -655,7 +655,7 @@ const Kt = [
|
|
|
655
655
|
commands: ["cargo test", "cargo clippy"]
|
|
656
656
|
}
|
|
657
657
|
];
|
|
658
|
-
function
|
|
658
|
+
function zt(e, t) {
|
|
659
659
|
const s = k.join(e, t);
|
|
660
660
|
try {
|
|
661
661
|
return v.existsSync(s) && v.statSync(s).isFile();
|
|
@@ -663,28 +663,28 @@ function Xt(e, t) {
|
|
|
663
663
|
return !1;
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
|
-
function
|
|
666
|
+
function Qt(e, t) {
|
|
667
667
|
const s = e.toLowerCase(), n = t.toLowerCase();
|
|
668
668
|
return /(^|:|-)watch($|:|-)/i.test(s) ? !0 : [
|
|
669
669
|
/(^|\s)--watch(?:[=\s]|$)/i,
|
|
670
670
|
/(^|\s)--watchall(?:[=\s]|$)/i,
|
|
671
671
|
/(^|\s)watch(?:\s|$)/i,
|
|
672
672
|
/(^|\s)nodemon(?:\s|$)/i
|
|
673
|
-
].some((
|
|
673
|
+
].some((o) => o.test(n));
|
|
674
674
|
}
|
|
675
|
-
function
|
|
675
|
+
function Jt(e, t, s) {
|
|
676
676
|
const n = Object.entries(e).filter(
|
|
677
|
-
([
|
|
677
|
+
([r, o]) => !s.has(r) && !Qt(r, o)
|
|
678
678
|
);
|
|
679
|
-
for (const
|
|
680
|
-
if (n.some(([
|
|
681
|
-
return
|
|
682
|
-
for (const [
|
|
683
|
-
if (t.fallbackPatterns.some((
|
|
684
|
-
return
|
|
679
|
+
for (const r of t.preferredNames)
|
|
680
|
+
if (n.some(([o]) => o === r))
|
|
681
|
+
return r;
|
|
682
|
+
for (const [r] of n)
|
|
683
|
+
if (t.fallbackPatterns.some((o) => o.test(r)))
|
|
684
|
+
return r;
|
|
685
685
|
return null;
|
|
686
686
|
}
|
|
687
|
-
function
|
|
687
|
+
function es(e, t) {
|
|
688
688
|
const s = k.join(e, "package.json");
|
|
689
689
|
let n;
|
|
690
690
|
try {
|
|
@@ -694,61 +694,61 @@ function Qt(e, t) {
|
|
|
694
694
|
} catch {
|
|
695
695
|
return null;
|
|
696
696
|
}
|
|
697
|
-
let
|
|
697
|
+
let r;
|
|
698
698
|
try {
|
|
699
|
-
|
|
699
|
+
r = JSON.parse(n);
|
|
700
700
|
} catch {
|
|
701
701
|
return null;
|
|
702
702
|
}
|
|
703
|
-
const
|
|
704
|
-
if (!
|
|
703
|
+
const o = r.scripts;
|
|
704
|
+
if (!o || typeof o != "object")
|
|
705
705
|
return null;
|
|
706
706
|
const i = [], a = /* @__PURE__ */ new Set();
|
|
707
707
|
for (const c of t.scriptGroups) {
|
|
708
|
-
const l =
|
|
708
|
+
const l = Jt(o, c, a);
|
|
709
709
|
if (l && (i.push(`npm run ${l}`), a.add(l)), i.length >= t.maxCommands)
|
|
710
710
|
break;
|
|
711
711
|
}
|
|
712
712
|
return i.length === 0 ? null : i.slice(0, t.maxCommands);
|
|
713
713
|
}
|
|
714
|
-
function
|
|
715
|
-
for (const t of
|
|
714
|
+
function ts(e) {
|
|
715
|
+
for (const t of Zt) {
|
|
716
716
|
if (t.kind === "marker") {
|
|
717
|
-
if (
|
|
717
|
+
if (zt(e, t.relativePath))
|
|
718
718
|
return [...t.commands];
|
|
719
719
|
continue;
|
|
720
720
|
}
|
|
721
721
|
if (t.kind === "npm-package-json") {
|
|
722
|
-
const s =
|
|
722
|
+
const s = es(e, t);
|
|
723
723
|
if (s != null && s.length > 0)
|
|
724
724
|
return s;
|
|
725
725
|
}
|
|
726
726
|
}
|
|
727
727
|
return [];
|
|
728
728
|
}
|
|
729
|
-
function
|
|
729
|
+
function ss(e) {
|
|
730
730
|
return e.map((t) => `\`${t}\``).join(", ");
|
|
731
731
|
}
|
|
732
|
-
function
|
|
733
|
-
const t =
|
|
732
|
+
function Oo(e) {
|
|
733
|
+
const t = ts(e);
|
|
734
734
|
if (t.length === 0)
|
|
735
735
|
return {
|
|
736
736
|
axiomHint: "как в README или CI принято проверять код (тесты, линтер, типы). Не подменяй это тяжёлой production-сборкой или публикацией, если это явно не описано как проверка",
|
|
737
737
|
toolsExample: "команды из `package.json` → `scripts`, из Makefile или из CI-шагов, которые относятся к качеству кода; сначала прочитай README",
|
|
738
738
|
verifyStep: "Прочитай README и при наличии — конфиг CI: какие команды запускают тесты, линтер и проверку типов. Выполни их из корня репозитория. Не запускай `build`/`publish`/полный `ci`, если не уверен, что это нужно для проверки изменений; при сомнении спроси пользователя."
|
|
739
739
|
};
|
|
740
|
-
const s =
|
|
740
|
+
const s = ss(t);
|
|
741
741
|
return {
|
|
742
742
|
axiomHint: `\`${t[0]}\` или следующую команду из того же набора проверок`,
|
|
743
743
|
toolsExample: s,
|
|
744
744
|
verifyStep: `Из корня репозитория выполни: ${s}. Не добавляй \`build\`, полный \`ci\` или публикацию, если они не перечислены здесь и не описаны в README как обязательная проверка.`
|
|
745
745
|
};
|
|
746
746
|
}
|
|
747
|
-
const
|
|
748
|
-
function
|
|
747
|
+
const H = "ai/agents";
|
|
748
|
+
function ke(e) {
|
|
749
749
|
return v.existsSync(e) ? v.promises.readFile(e, "utf-8") : null;
|
|
750
750
|
}
|
|
751
|
-
function
|
|
751
|
+
function ns(e) {
|
|
752
752
|
let t = e;
|
|
753
753
|
for (; ; ) {
|
|
754
754
|
const s = k.join(t, "package.json");
|
|
@@ -760,27 +760,27 @@ function ts(e) {
|
|
|
760
760
|
t = n;
|
|
761
761
|
}
|
|
762
762
|
}
|
|
763
|
-
async function
|
|
764
|
-
const t = k.dirname(
|
|
763
|
+
async function To(e) {
|
|
764
|
+
const t = k.dirname(me(import.meta.url)), s = k.join(process.cwd(), H, e), n = ke(s);
|
|
765
765
|
if (n)
|
|
766
766
|
return n;
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
k.join(t, "../../../../../../dist",
|
|
767
|
+
const r = ns(t), o = [];
|
|
768
|
+
r ? (o.push(k.join(r, H, e)), o.push(k.join(r, "dist", H, e))) : o.push(
|
|
769
|
+
k.join(t, "../../../../../../dist", H, e)
|
|
770
770
|
);
|
|
771
|
-
for (const i of
|
|
772
|
-
const a =
|
|
771
|
+
for (const i of o) {
|
|
772
|
+
const a = ke(i);
|
|
773
773
|
if (a)
|
|
774
774
|
return a;
|
|
775
775
|
}
|
|
776
776
|
throw new Error(`Не найден файл шаблона ${e}.`, {
|
|
777
777
|
cause: {
|
|
778
778
|
projectOverridePath: s,
|
|
779
|
-
packageCandidates:
|
|
779
|
+
packageCandidates: o
|
|
780
780
|
}
|
|
781
781
|
});
|
|
782
782
|
}
|
|
783
|
-
const
|
|
783
|
+
const He = ["product", "library", "infrastructure", "interface"], J = "One-line human summary of how many decisions and what area; fold the full D-NNN entries under <details> per AX_SPEC_PROGRESSIVE_DISCLOSURE.", ee = 'One-line human summary of outstanding prerequisites; fold the full Requirement/Kind/Owner/Resolution table under <details>. Declare explicitly ("No external bootstrap required.") when the STEP_7 audit found none — do not leave the table silently empty.', j = "MANDATORY (AX_SPEC_MANDATORY_DIAGRAM): at least one fenced mermaid or ASCII diagram giving a reader the shape of this artifact at a glance, up top.", os = "List infra-*/api/design-system-* scopes this scope depends on, and any consumer scopes it provides to.", rs = `# <scope-name>: Scope Specification
|
|
784
784
|
|
|
785
785
|
<!--SECTION:SCOPE_TYPE-->
|
|
786
786
|
## scope-type
|
|
@@ -885,7 +885,7 @@ flowchart TD
|
|
|
885
885
|
|
|
886
886
|
<!-- Pivot Invalidation List — only in pivot mode -->
|
|
887
887
|
<!--/SECTION:HANDOFF-->
|
|
888
|
-
`,
|
|
888
|
+
`, is = [
|
|
889
889
|
{
|
|
890
890
|
name: "SCOPE_TYPE",
|
|
891
891
|
required: !0,
|
|
@@ -900,7 +900,7 @@ flowchart TD
|
|
|
900
900
|
fold: !1,
|
|
901
901
|
fill: "Vision & primary goal — what this product scope is for, in a sentence or two."
|
|
902
902
|
},
|
|
903
|
-
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill:
|
|
903
|
+
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill: j },
|
|
904
904
|
{
|
|
905
905
|
name: "PROJECT_TYPE",
|
|
906
906
|
required: !0,
|
|
@@ -920,7 +920,7 @@ flowchart TD
|
|
|
920
920
|
required: !0,
|
|
921
921
|
loadBearing: !1,
|
|
922
922
|
fold: !1,
|
|
923
|
-
fill:
|
|
923
|
+
fill: os
|
|
924
924
|
},
|
|
925
925
|
{
|
|
926
926
|
name: "REQUIREMENTS_AND_CONSTRAINTS",
|
|
@@ -943,13 +943,13 @@ flowchart TD
|
|
|
943
943
|
fold: !1,
|
|
944
944
|
fill: "Appended by module-decomposition; initially a placeholder pointing at that command."
|
|
945
945
|
},
|
|
946
|
-
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill:
|
|
946
|
+
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill: J },
|
|
947
947
|
{
|
|
948
948
|
name: "BOOTSTRAP_REQUIREMENTS",
|
|
949
949
|
required: !0,
|
|
950
950
|
loadBearing: !1,
|
|
951
951
|
fold: !0,
|
|
952
|
-
fill:
|
|
952
|
+
fill: ee
|
|
953
953
|
},
|
|
954
954
|
{
|
|
955
955
|
name: "HANDOFF",
|
|
@@ -958,7 +958,7 @@ flowchart TD
|
|
|
958
958
|
fold: !1,
|
|
959
959
|
fill: "Primary input path, areas requiring decomposition, named abstractions, bootstrap tickets, open risks."
|
|
960
960
|
}
|
|
961
|
-
],
|
|
961
|
+
], as = `# <scope-name>: Library Specification
|
|
962
962
|
|
|
963
963
|
<!--SECTION:SCOPE_TYPE-->
|
|
964
964
|
## scope-type
|
|
@@ -1054,7 +1054,7 @@ flowchart LR
|
|
|
1054
1054
|
|
|
1055
1055
|
<!-- Pivot Invalidation List — only in pivot mode -->
|
|
1056
1056
|
<!--/SECTION:HANDOFF-->
|
|
1057
|
-
`,
|
|
1057
|
+
`, cs = [
|
|
1058
1058
|
{
|
|
1059
1059
|
name: "SCOPE_TYPE",
|
|
1060
1060
|
required: !0,
|
|
@@ -1069,7 +1069,7 @@ flowchart LR
|
|
|
1069
1069
|
fold: !1,
|
|
1070
1070
|
fill: "What the library does and the main problem it solves."
|
|
1071
1071
|
},
|
|
1072
|
-
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill:
|
|
1072
|
+
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill: j },
|
|
1073
1073
|
{
|
|
1074
1074
|
name: "GOLDEN_DX",
|
|
1075
1075
|
required: !0,
|
|
@@ -1105,13 +1105,13 @@ flowchart LR
|
|
|
1105
1105
|
fold: !1,
|
|
1106
1106
|
fill: "Chosen design pattern, briefly, plus rejected alternatives."
|
|
1107
1107
|
},
|
|
1108
|
-
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill:
|
|
1108
|
+
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill: J },
|
|
1109
1109
|
{
|
|
1110
1110
|
name: "BOOTSTRAP_REQUIREMENTS",
|
|
1111
1111
|
required: !0,
|
|
1112
1112
|
loadBearing: !1,
|
|
1113
1113
|
fold: !0,
|
|
1114
|
-
fill:
|
|
1114
|
+
fill: ee
|
|
1115
1115
|
},
|
|
1116
1116
|
{
|
|
1117
1117
|
name: "HANDOFF",
|
|
@@ -1120,7 +1120,7 @@ flowchart LR
|
|
|
1120
1120
|
fold: !1,
|
|
1121
1121
|
fill: "Areas requiring decomposition, named abstractions, bootstrap tickets, open risks."
|
|
1122
1122
|
}
|
|
1123
|
-
],
|
|
1123
|
+
], ls = `# <scope-name>: Infrastructure Specification
|
|
1124
1124
|
|
|
1125
1125
|
<!--SECTION:SCOPE_TYPE-->
|
|
1126
1126
|
## scope-type
|
|
@@ -1235,7 +1235,7 @@ Include only command names for tools present in the chosen stack.
|
|
|
1235
1235
|
|
|
1236
1236
|
<!-- Pivot Invalidation List — only in pivot mode -->
|
|
1237
1237
|
<!--/SECTION:HANDOFF-->
|
|
1238
|
-
`,
|
|
1238
|
+
`, ds = [
|
|
1239
1239
|
{
|
|
1240
1240
|
name: "SCOPE_TYPE",
|
|
1241
1241
|
required: !0,
|
|
@@ -1250,7 +1250,7 @@ Include only command names for tools present in the chosen stack.
|
|
|
1250
1250
|
fold: !1,
|
|
1251
1251
|
fill: "What dev/ops experience this scope covers."
|
|
1252
1252
|
},
|
|
1253
|
-
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill:
|
|
1253
|
+
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill: j },
|
|
1254
1254
|
{
|
|
1255
1255
|
name: "SCOPE_DEPENDENCIES",
|
|
1256
1256
|
required: !0,
|
|
@@ -1293,13 +1293,13 @@ Include only command names for tools present in the chosen stack.
|
|
|
1293
1293
|
fold: !1,
|
|
1294
1294
|
fill: "Mandatory: Command Name/Invocation table for the active phases (typecheck/test/lint/format) plus the composed check-command alias."
|
|
1295
1295
|
},
|
|
1296
|
-
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill:
|
|
1296
|
+
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill: J },
|
|
1297
1297
|
{
|
|
1298
1298
|
name: "BOOTSTRAP_REQUIREMENTS",
|
|
1299
1299
|
required: !0,
|
|
1300
1300
|
loadBearing: !1,
|
|
1301
1301
|
fold: !0,
|
|
1302
|
-
fill:
|
|
1302
|
+
fill: ee
|
|
1303
1303
|
},
|
|
1304
1304
|
{
|
|
1305
1305
|
name: "HANDOFF",
|
|
@@ -1308,7 +1308,7 @@ Include only command names for tools present in the chosen stack.
|
|
|
1308
1308
|
fold: !1,
|
|
1309
1309
|
fill: "Setup tasks to scaffold, effective rules/verification commands/bootstrap tickets ready for cascade, open risks."
|
|
1310
1310
|
}
|
|
1311
|
-
],
|
|
1311
|
+
], us = `# <scope-name>: Interface Specification
|
|
1312
1312
|
|
|
1313
1313
|
<!--SECTION:SCOPE_TYPE-->
|
|
1314
1314
|
## scope-type
|
|
@@ -1395,7 +1395,7 @@ flowchart LR
|
|
|
1395
1395
|
- **Bootstrap tickets ready for cascade:** see Prerequisites
|
|
1396
1396
|
- **Open risks:** [versioning gaps, unconfirmed consumers]
|
|
1397
1397
|
<!--/SECTION:HANDOFF-->
|
|
1398
|
-
`,
|
|
1398
|
+
`, fs = [
|
|
1399
1399
|
{
|
|
1400
1400
|
name: "SCOPE_TYPE",
|
|
1401
1401
|
required: !0,
|
|
@@ -1410,7 +1410,7 @@ flowchart LR
|
|
|
1410
1410
|
fold: !1,
|
|
1411
1411
|
fill: "What the contract defines, and for whom."
|
|
1412
1412
|
},
|
|
1413
|
-
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill:
|
|
1413
|
+
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill: j },
|
|
1414
1414
|
{
|
|
1415
1415
|
name: "SCOPE_DEPENDENCIES",
|
|
1416
1416
|
required: !0,
|
|
@@ -1439,13 +1439,13 @@ flowchart LR
|
|
|
1439
1439
|
fold: !0,
|
|
1440
1440
|
fill: "One-line summary of consumer count / pending breaking changes; full Consumer/Min-version/Breaking-change-protocol matrix folds under <details>."
|
|
1441
1441
|
},
|
|
1442
|
-
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill:
|
|
1442
|
+
{ name: "DECISION_LOG", required: !0, loadBearing: !0, fold: !0, fill: J },
|
|
1443
1443
|
{
|
|
1444
1444
|
name: "BOOTSTRAP_REQUIREMENTS",
|
|
1445
1445
|
required: !0,
|
|
1446
1446
|
loadBearing: !1,
|
|
1447
1447
|
fold: !0,
|
|
1448
|
-
fill:
|
|
1448
|
+
fill: ee
|
|
1449
1449
|
},
|
|
1450
1450
|
{
|
|
1451
1451
|
name: "HANDOFF",
|
|
@@ -1454,7 +1454,7 @@ flowchart LR
|
|
|
1454
1454
|
fold: !1,
|
|
1455
1455
|
fill: "Contract files to scaffold (schemas, codegen configs), bootstrap tickets, open risks."
|
|
1456
1456
|
}
|
|
1457
|
-
],
|
|
1457
|
+
], ps = `# Module: <ModuleName>
|
|
1458
1458
|
|
|
1459
1459
|
<!--SECTION:MODULE_VISION-->
|
|
1460
1460
|
## Module Vision
|
|
@@ -1596,7 +1596,7 @@ graph TD
|
|
|
1596
1596
|
|
|
1597
1597
|
</details>
|
|
1598
1598
|
<!--/SECTION:IMPLEMENTATION_INSIGHTS-->
|
|
1599
|
-
`,
|
|
1599
|
+
`, ms = [
|
|
1600
1600
|
{
|
|
1601
1601
|
name: "MODULE_VISION",
|
|
1602
1602
|
required: !0,
|
|
@@ -1604,7 +1604,7 @@ graph TD
|
|
|
1604
1604
|
fold: !1,
|
|
1605
1605
|
fill: "What this module owns; link to the parent scope spec and to sibling/parent/child modules."
|
|
1606
1606
|
},
|
|
1607
|
-
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill:
|
|
1607
|
+
{ name: "OVERVIEW", required: !0, loadBearing: !1, fold: !1, fill: j },
|
|
1608
1608
|
{
|
|
1609
1609
|
name: "MODULE_USAGE_EXAMPLE",
|
|
1610
1610
|
required: !0,
|
|
@@ -1675,7 +1675,7 @@ graph TD
|
|
|
1675
1675
|
fold: !1,
|
|
1676
1676
|
fill: "Optional appendix — non-trivial post-implementation learnings (library wrap patterns, transaction subtleties, fake-runtime pitfalls), added after audit-cycle compaction."
|
|
1677
1677
|
}
|
|
1678
|
-
],
|
|
1678
|
+
], Es = `# Task: <ACRONYM>-<slug> — <Task Title>
|
|
1679
1679
|
|
|
1680
1680
|
<!--SECTION:META-->
|
|
1681
1681
|
## Meta
|
|
@@ -1783,7 +1783,7 @@ use-case → \`[<ACRONYM>-REQ-N]\` → vision chain the operator reviews at scaf
|
|
|
1783
1783
|
<!--/SECTION:DECISION_LOG-->
|
|
1784
1784
|
|
|
1785
1785
|
<!-- AUDIT_ROUNDS appended only after the first reopen-triggering audit (per the audit directive). -->
|
|
1786
|
-
`,
|
|
1786
|
+
`, hs = [
|
|
1787
1787
|
{
|
|
1788
1788
|
name: "META",
|
|
1789
1789
|
required: !0,
|
|
@@ -1840,7 +1840,7 @@ use-case → \`[<ACRONYM>-REQ-N]\` → vision chain the operator reviews at scaf
|
|
|
1840
1840
|
fold: !1,
|
|
1841
1841
|
fill: "Local ADR-compact decisions taken during execution; omit if none beyond the spec."
|
|
1842
1842
|
}
|
|
1843
|
-
],
|
|
1843
|
+
], Ss = `# <module> — Tasks
|
|
1844
1844
|
|
|
1845
1845
|
## Tracker Index
|
|
1846
1846
|
| Task-ID | Title | Dependencies | Status | Reopens |
|
|
@@ -1863,7 +1863,7 @@ graph TD
|
|
|
1863
1863
|
|
|
1864
1864
|
## Conventions
|
|
1865
1865
|
Project-wide conventions (Execution-Log token vocabulary, Baseline Completion Rule, post-task audit hook, file-header) are declared once in \`specs/3-tasks.md\` and inherited here — not repeated.
|
|
1866
|
-
`,
|
|
1866
|
+
`, gs = [
|
|
1867
1867
|
{
|
|
1868
1868
|
name: "TRACKER_INDEX",
|
|
1869
1869
|
required: !0,
|
|
@@ -1899,7 +1899,7 @@ Project-wide conventions (Execution-Log token vocabulary, Baseline Completion Ru
|
|
|
1899
1899
|
fold: !1,
|
|
1900
1900
|
fill: "Pointer to specs/3-tasks.md — project-wide conventions are declared once there, inherited here."
|
|
1901
1901
|
}
|
|
1902
|
-
],
|
|
1902
|
+
], Is = `# Tasks: <scope>
|
|
1903
1903
|
|
|
1904
1904
|
## Scope Spec
|
|
1905
1905
|
- [Scope spec](./<scope>.spec.md)
|
|
@@ -1925,7 +1925,7 @@ graph TD
|
|
|
1925
1925
|
|
|
1926
1926
|
## Decision Log (scope task level)
|
|
1927
1927
|
[D-NNN for scope-level decomposition / planning choices.]
|
|
1928
|
-
`,
|
|
1928
|
+
`, Os = [
|
|
1929
1929
|
{
|
|
1930
1930
|
name: "SCOPE_SPEC_LINK",
|
|
1931
1931
|
required: !0,
|
|
@@ -1961,7 +1961,7 @@ graph TD
|
|
|
1961
1961
|
fold: !1,
|
|
1962
1962
|
fill: "Scope-level decomposition/planning decisions, D-NNN, ADR-compact."
|
|
1963
1963
|
}
|
|
1964
|
-
],
|
|
1964
|
+
], Ts = "# Project Tasks\n\n## Entry Points\n- [Specs Portal](./README.md) — Scope Graph + all scope specs.\n- Tickets execute ONLY via the `/sdd-execute` flow (one ticket) or its batch form; the orchestrator dispatches phase-workers then audit — the operator does not invoke audit by hand.\n\n## Project-Wide Conventions (declared once, inherited)\n- **File-header:** owned by the coding rule (`@file` / `@consumers` / `@tasks`), enforced by `sdd-verify`.\n- **Baseline Completion Rule:** a Round cannot go `[x] DONE` until — every phase `[x]`; every BDD scenario mapped to a test or `Deferred Test Ownership`; verification commands run with exit recorded; every entity beyond the Inventory logged `intro …`; a Handoff line closes each phase.\n- **Execution-Log token vocabulary:** `intro <Entity> ← <reason>` · `decision <key>=<value> ← <reason>` · `tried <approach> → <result>` · `discovery <fact>` · `insight <observation> → <spec-section>` · `verified <tool>@<version> <summary>` · `ver <cmd> → pass|fail exit=<N>` · `BLOCKED <cause>` · `DONE`. A `[x]` line with an unreplaced `<…>` placeholder is fabricated (BLOCKER).\n- **Post-task hook:** after a Round closes the orchestrator runs audit; until PASS the round is closed-but-unverified and dependents are blocked.\n\n## Cross-Scope DAG\nCross-scope edges + integration tickets only; intra-scope edges live in each scope index. Order follows the Portal Scope Graph.\n```mermaid\ngraph TD\n backend --> infra-base\n web --> backend\n```\n\n## Scope Tracker\n| Scope | Type | Index | Tasks | Done |\n|---|---|---|---|---|\n| infra-base | infrastructure | [3-tasks](./infra-base/infra-base.3-tasks.md) | 6 | 0/6 |\n| backend | product | [3-tasks](./backend/backend.3-tasks.md) | 12 | 0/12 |\n\n## Decision Log (project task level)\n[D-NNN when the operator made non-default cross-scope choices.]\n", _s = [
|
|
1965
1965
|
{
|
|
1966
1966
|
name: "ENTRY_POINTS",
|
|
1967
1967
|
required: !0,
|
|
@@ -1997,7 +1997,7 @@ graph TD
|
|
|
1997
1997
|
fold: !1,
|
|
1998
1998
|
fill: "Cross-scope decomposition/planning decisions, D-NNN, ADR-compact."
|
|
1999
1999
|
}
|
|
2000
|
-
],
|
|
2000
|
+
], Ns = `# <project-name>
|
|
2001
2001
|
|
|
2002
2002
|
## Vision
|
|
2003
2003
|
<Одно предложение. Опускается для infrastructure-only проектов.>
|
|
@@ -2022,7 +2022,7 @@ graph TD
|
|
|
2022
2022
|
| [\`api\`](./api/api.spec.md) | interface | 🚧 | REST API v1 |
|
|
2023
2023
|
| [\`backend\`](./backend/backend.spec.md) | product | ✅ | Node.js IMAP-сервис |
|
|
2024
2024
|
| [\`web\`](./web/web.spec.md) | product | 🚧 | React SPA |
|
|
2025
|
-
`,
|
|
2025
|
+
`, Cs = [
|
|
2026
2026
|
{
|
|
2027
2027
|
name: "VISION",
|
|
2028
2028
|
required: !1,
|
|
@@ -2044,81 +2044,81 @@ graph TD
|
|
|
2044
2044
|
fold: !1,
|
|
2045
2045
|
fill: "Scope/Type/Spec-status/Description table — one row per scope, linking to its spec.md."
|
|
2046
2046
|
}
|
|
2047
|
-
],
|
|
2047
|
+
], Ee = {
|
|
2048
2048
|
product: {
|
|
2049
2049
|
kind: "product",
|
|
2050
|
-
skeleton:
|
|
2051
|
-
sections:
|
|
2050
|
+
skeleton: rs,
|
|
2051
|
+
sections: is,
|
|
2052
2052
|
pathPattern: "specs/<scope>/<scope>.spec.md"
|
|
2053
2053
|
},
|
|
2054
2054
|
library: {
|
|
2055
2055
|
kind: "library",
|
|
2056
|
-
skeleton:
|
|
2057
|
-
sections:
|
|
2056
|
+
skeleton: as,
|
|
2057
|
+
sections: cs,
|
|
2058
2058
|
pathPattern: "specs/<scope>/<scope>.spec.md"
|
|
2059
2059
|
},
|
|
2060
2060
|
infrastructure: {
|
|
2061
2061
|
kind: "infrastructure",
|
|
2062
|
-
skeleton:
|
|
2063
|
-
sections:
|
|
2062
|
+
skeleton: ls,
|
|
2063
|
+
sections: ds,
|
|
2064
2064
|
pathPattern: "specs/<scope>/<scope>.spec.md"
|
|
2065
2065
|
},
|
|
2066
2066
|
interface: {
|
|
2067
2067
|
kind: "interface",
|
|
2068
|
-
skeleton:
|
|
2069
|
-
sections:
|
|
2068
|
+
skeleton: us,
|
|
2069
|
+
sections: fs,
|
|
2070
2070
|
pathPattern: "specs/<scope>/<scope>.spec.md"
|
|
2071
2071
|
},
|
|
2072
2072
|
module: {
|
|
2073
2073
|
kind: "module",
|
|
2074
|
-
skeleton:
|
|
2075
|
-
sections:
|
|
2074
|
+
skeleton: ps,
|
|
2075
|
+
sections: ms,
|
|
2076
2076
|
pathPattern: "specs/<scope>/<module>/<module>.spec.md"
|
|
2077
2077
|
},
|
|
2078
2078
|
task: {
|
|
2079
2079
|
kind: "task",
|
|
2080
|
-
skeleton:
|
|
2081
|
-
sections:
|
|
2080
|
+
skeleton: Es,
|
|
2081
|
+
sections: hs,
|
|
2082
2082
|
pathPattern: "specs/<scope>/<module>/<module>.task.<ACR>-<slug>.md"
|
|
2083
2083
|
},
|
|
2084
2084
|
"module-index": {
|
|
2085
2085
|
kind: "module-index",
|
|
2086
|
-
skeleton:
|
|
2087
|
-
sections:
|
|
2086
|
+
skeleton: Ss,
|
|
2087
|
+
sections: gs,
|
|
2088
2088
|
pathPattern: "specs/<scope>/<module...>/<module>.3-tasks.md"
|
|
2089
2089
|
},
|
|
2090
2090
|
"scope-index": {
|
|
2091
2091
|
kind: "scope-index",
|
|
2092
|
-
skeleton:
|
|
2093
|
-
sections:
|
|
2092
|
+
skeleton: Is,
|
|
2093
|
+
sections: Os,
|
|
2094
2094
|
pathPattern: "specs/<scope>/<scope>.3-tasks.md"
|
|
2095
2095
|
},
|
|
2096
2096
|
"project-index": {
|
|
2097
2097
|
kind: "project-index",
|
|
2098
|
-
skeleton:
|
|
2099
|
-
sections:
|
|
2098
|
+
skeleton: Ts,
|
|
2099
|
+
sections: _s,
|
|
2100
2100
|
pathPattern: "specs/3-tasks.md"
|
|
2101
2101
|
},
|
|
2102
2102
|
portal: {
|
|
2103
2103
|
kind: "portal",
|
|
2104
|
-
skeleton:
|
|
2105
|
-
sections:
|
|
2104
|
+
skeleton: Ns,
|
|
2105
|
+
sections: Cs,
|
|
2106
2106
|
pathPattern: "specs/README.md"
|
|
2107
2107
|
}
|
|
2108
|
-
},
|
|
2109
|
-
function
|
|
2110
|
-
return
|
|
2108
|
+
}, _o = Object.keys(Ee);
|
|
2109
|
+
function qe(e) {
|
|
2110
|
+
return Ee[e].sections.filter((t) => t.loadBearing).map((t) => t.name);
|
|
2111
2111
|
}
|
|
2112
|
-
function
|
|
2113
|
-
return
|
|
2112
|
+
function Ds(e) {
|
|
2113
|
+
return Ee[e].sections.filter((t) => t.fold).map((t) => t.name);
|
|
2114
2114
|
}
|
|
2115
|
-
function
|
|
2116
|
-
return e.provider === "github" ? new
|
|
2115
|
+
function As(e) {
|
|
2116
|
+
return e.provider === "github" ? new Dt({ baseUrl: "https://api.github.com", token: e.token }) : new At({ baseUrl: `https://${e.host}/api/v4`, token: e.token });
|
|
2117
2117
|
}
|
|
2118
|
-
const
|
|
2118
|
+
const No = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2119
2119
|
__proto__: null,
|
|
2120
|
-
createVcsClient:
|
|
2121
|
-
}, Symbol.toStringTag, { value: "Module" })),
|
|
2120
|
+
createVcsClient: As
|
|
2121
|
+
}, Symbol.toStringTag, { value: "Module" })), We = "(?<!\\p{L})", ys = "(?!\\p{L})", L = (e) => new RegExp(`${We}${e}${ys}`, "iu"), T = (e) => new RegExp(`${We}${e}\\p{L}*`, "iu"), Rs = [
|
|
2122
2122
|
{ re: L("проз[аыуе]"), why: "книжное", use: "текст" },
|
|
2123
2123
|
{ re: L("новь[её]"), why: "сленг", use: "новое" },
|
|
2124
2124
|
{ re: T("докрут"), why: "сленг", use: "доработать" },
|
|
@@ -2149,20 +2149,20 @@ const Oo = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
2149
2149
|
{ re: T("блокер"), why: "сленг (blocker)", use: "блокирующий дефект" },
|
|
2150
2150
|
{ re: T("терминальн"), why: "калька (terminal)", use: "окончательный / конечный" }
|
|
2151
2151
|
];
|
|
2152
|
-
function
|
|
2152
|
+
function Co(e) {
|
|
2153
2153
|
const t = [], s = e.split(`
|
|
2154
|
-
`),
|
|
2154
|
+
`), r = e.replace(/<!--[\s\S]*?-->/g, (i) => i.replace(/[^\n]/g, " ")).split(`
|
|
2155
2155
|
`);
|
|
2156
|
-
let
|
|
2157
|
-
for (let i = 0; i <
|
|
2158
|
-
const a =
|
|
2156
|
+
let o = !1;
|
|
2157
|
+
for (let i = 0; i < r.length; i++) {
|
|
2158
|
+
const a = r[i];
|
|
2159
2159
|
if (a.trim().startsWith("```")) {
|
|
2160
|
-
|
|
2160
|
+
o = !o;
|
|
2161
2161
|
continue;
|
|
2162
2162
|
}
|
|
2163
|
-
if (
|
|
2163
|
+
if (o || s[i].includes("<!-- stop-ok")) continue;
|
|
2164
2164
|
const l = a.replace(/`[^`]*`/g, (f) => " ".repeat(f.length));
|
|
2165
|
-
for (const f of
|
|
2165
|
+
for (const f of Rs) {
|
|
2166
2166
|
const d = new RegExp(
|
|
2167
2167
|
f.re.source,
|
|
2168
2168
|
f.re.flags.includes("g") ? f.re.flags : f.re.flags + "g"
|
|
@@ -2174,25 +2174,25 @@ function To(e) {
|
|
|
2174
2174
|
}
|
|
2175
2175
|
return t;
|
|
2176
2176
|
}
|
|
2177
|
-
const
|
|
2178
|
-
function
|
|
2179
|
-
return
|
|
2177
|
+
const ks = /^[A-Z][A-Z0-9_]*$/;
|
|
2178
|
+
function Ke(e) {
|
|
2179
|
+
return ks.test(e);
|
|
2180
2180
|
}
|
|
2181
2181
|
function g(e, t) {
|
|
2182
|
-
if (!
|
|
2183
|
-
const s = `<!--SECTION:${t}-->`, n = `<!--/SECTION:${t}-->`,
|
|
2182
|
+
if (!Ke(t)) return { status: "invalid_name" };
|
|
2183
|
+
const s = `<!--SECTION:${t}-->`, n = `<!--/SECTION:${t}-->`, r = e.split(`
|
|
2184
2184
|
`);
|
|
2185
|
-
let
|
|
2186
|
-
for (const f of
|
|
2185
|
+
let o = 0, i = 0;
|
|
2186
|
+
for (const f of r) {
|
|
2187
2187
|
const d = f.trim();
|
|
2188
|
-
d === s ?
|
|
2188
|
+
d === s ? o++ : d === n && i++;
|
|
2189
2189
|
}
|
|
2190
|
-
if (
|
|
2191
|
-
if (
|
|
2192
|
-
if (
|
|
2190
|
+
if (o === 0 && i === 0) return { status: "not_found" };
|
|
2191
|
+
if (o !== i) return { status: "unbalanced", startCount: o, endCount: i };
|
|
2192
|
+
if (o > 1) return { status: "duplicated", count: o };
|
|
2193
2193
|
const a = [];
|
|
2194
2194
|
let c = !1;
|
|
2195
|
-
for (const f of
|
|
2195
|
+
for (const f of r) {
|
|
2196
2196
|
const d = f.trim();
|
|
2197
2197
|
if (d === s) {
|
|
2198
2198
|
c = !0;
|
|
@@ -2208,115 +2208,115 @@ function g(e, t) {
|
|
|
2208
2208
|
`);
|
|
2209
2209
|
return l.trim() === "" ? { status: "empty" } : { status: "ok", content: l };
|
|
2210
2210
|
}
|
|
2211
|
-
function
|
|
2212
|
-
if (!
|
|
2213
|
-
const s = `<!--SECTION:${t}-->`, n = `<!--/SECTION:${t}-->`,
|
|
2211
|
+
function Do(e, t) {
|
|
2212
|
+
if (!Ke(t)) return null;
|
|
2213
|
+
const s = `<!--SECTION:${t}-->`, n = `<!--/SECTION:${t}-->`, r = e.split(`
|
|
2214
2214
|
`);
|
|
2215
|
-
let
|
|
2216
|
-
return
|
|
2215
|
+
let o = -1, i = -1, a = 0, c = 0;
|
|
2216
|
+
return r.forEach((l, f) => {
|
|
2217
2217
|
const d = l.trim();
|
|
2218
|
-
d === s ? (a++,
|
|
2219
|
-
}), a !== 1 || c !== 1 || i <
|
|
2218
|
+
d === s ? (a++, o === -1 && (o = f)) : d === n && (c++, i = f);
|
|
2219
|
+
}), a !== 1 || c !== 1 || i < o ? null : { openLine: o, closeLine: i };
|
|
2220
2220
|
}
|
|
2221
|
-
function
|
|
2221
|
+
function Ao(e) {
|
|
2222
2222
|
const t = g(e, "ENTITY_INVENTORY");
|
|
2223
2223
|
return t.status !== "ok" ? [] : t.content.split(`
|
|
2224
2224
|
`).map((n) => n.trim()).filter((n) => n.startsWith("|") && !/^\|[\s:|-]+$/.test(n)).slice(1).map((n) => (n.split("|")[1] ?? "").replace(/`/g, "").trim()).filter(Boolean);
|
|
2225
2225
|
}
|
|
2226
|
-
function
|
|
2226
|
+
function vs(e, t) {
|
|
2227
2227
|
try {
|
|
2228
2228
|
const s = h(e, "package.json");
|
|
2229
|
-
if (!R(s) || JSON.parse(
|
|
2230
|
-
const
|
|
2231
|
-
return R(
|
|
2229
|
+
if (!R(s) || JSON.parse(C(s, "utf-8")).name !== "gennady") return null;
|
|
2230
|
+
const r = h(e, t);
|
|
2231
|
+
return R(r) ? r : null;
|
|
2232
2232
|
} catch {
|
|
2233
2233
|
return null;
|
|
2234
2234
|
}
|
|
2235
2235
|
}
|
|
2236
|
-
function
|
|
2236
|
+
function yo(e, t) {
|
|
2237
2237
|
try {
|
|
2238
2238
|
const n = h(e, "node_modules", "gennady", t);
|
|
2239
2239
|
if (R(n)) return n;
|
|
2240
2240
|
} catch {
|
|
2241
2241
|
}
|
|
2242
2242
|
try {
|
|
2243
|
-
const n = import.meta.resolve("gennady"),
|
|
2243
|
+
const n = import.meta.resolve("gennady"), o = me(n).replace(/[/\\]dist[/\\].*$/, ""), i = h(o, t);
|
|
2244
2244
|
if (R(i)) return i;
|
|
2245
2245
|
} catch {
|
|
2246
2246
|
}
|
|
2247
|
-
const s =
|
|
2247
|
+
const s = vs(e, t);
|
|
2248
2248
|
return s || null;
|
|
2249
2249
|
}
|
|
2250
|
-
function
|
|
2250
|
+
function Ro(e, t) {
|
|
2251
2251
|
return !Buffer.isBuffer(e) || !Buffer.isBuffer(t) ? !0 : Buffer.compare(e, t) !== 0;
|
|
2252
2252
|
}
|
|
2253
|
-
function
|
|
2253
|
+
function ko(e, t) {
|
|
2254
2254
|
let s = e;
|
|
2255
2255
|
for (const n of t)
|
|
2256
2256
|
s = s.replace(n.from, n.to);
|
|
2257
2257
|
return s;
|
|
2258
2258
|
}
|
|
2259
|
-
const
|
|
2259
|
+
const Xe = {
|
|
2260
2260
|
from: /npx\s+tsx\s+~\/Developer\/gennady\/cli\/gennady\.ts\b/g,
|
|
2261
2261
|
to: "npx gennady"
|
|
2262
|
-
},
|
|
2262
|
+
}, Ze = {
|
|
2263
2263
|
from: /npx tsx ~\/Developer\/gennady\/cli[ \t]+/g,
|
|
2264
2264
|
to: "npx gennady "
|
|
2265
|
-
},
|
|
2265
|
+
}, ze = {
|
|
2266
2266
|
from: /~\/Developer\/gennady\/cli\/gennady\.ts/g,
|
|
2267
2267
|
to: "npx gennady"
|
|
2268
|
-
},
|
|
2268
|
+
}, ws = {
|
|
2269
2269
|
from: /~\/Developer\/gennady\/ai\/skills\//g,
|
|
2270
2270
|
to: ".claude/skills/"
|
|
2271
|
-
},
|
|
2271
|
+
}, Qe = {
|
|
2272
2272
|
from: /~\/Developer\/gennady\/ai\/directives\//g,
|
|
2273
2273
|
to: "ai/directives/"
|
|
2274
|
-
},
|
|
2274
|
+
}, Je = {
|
|
2275
2275
|
from: /\/Users\/k\.lebedev\/Developer\/gennady\/ai\//g,
|
|
2276
2276
|
to: "ai/"
|
|
2277
|
-
},
|
|
2277
|
+
}, et = {
|
|
2278
2278
|
from: /\/Users\/k\.lebedev\/Developer\/gennady\/cli\/gennady\.ts/g,
|
|
2279
2279
|
to: "npx gennady"
|
|
2280
|
-
},
|
|
2280
|
+
}, tt = {
|
|
2281
2281
|
from: /\$HOME\/Developer\/gennady\/cli\/gennady\.ts\b/g,
|
|
2282
2282
|
to: "~/Developer/gennady/cli/gennady.ts"
|
|
2283
|
-
},
|
|
2284
|
-
We,
|
|
2285
|
-
Ke,
|
|
2283
|
+
}, vo = [
|
|
2286
2284
|
Xe,
|
|
2287
2285
|
Ze,
|
|
2288
2286
|
ze,
|
|
2289
2287
|
Qe,
|
|
2290
|
-
Je
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2288
|
+
Je,
|
|
2289
|
+
et,
|
|
2290
|
+
tt
|
|
2291
|
+
], wo = [
|
|
2294
2292
|
Xe,
|
|
2295
|
-
ks,
|
|
2296
2293
|
Ze,
|
|
2297
2294
|
ze,
|
|
2295
|
+
ws,
|
|
2298
2296
|
Qe,
|
|
2299
|
-
Je
|
|
2300
|
-
|
|
2301
|
-
|
|
2297
|
+
Je,
|
|
2298
|
+
et,
|
|
2299
|
+
tt
|
|
2300
|
+
], Ps = "+", Ls = "~", bs = "-", Ms = "=", $s = "(unchanged)", xs = "(would add)", Bs = "(would update)", Us = "(would delete)", Fs = "(unchanged, skip)";
|
|
2301
|
+
function Po(e, t = {}) {
|
|
2302
2302
|
const s = [];
|
|
2303
2303
|
for (const a of e) {
|
|
2304
2304
|
const { relativePath: c, status: l } = a;
|
|
2305
2305
|
let f, d;
|
|
2306
|
-
l === "added" ? (f =
|
|
2306
|
+
l === "added" ? (f = Ps, d = t.dryRun ? xs : "") : l === "updated" ? (f = Ls, d = t.dryRun ? Bs : "") : l === "deleted" ? (f = bs, d = t.dryRun ? Us : "") : (f = Ms, d = t.dryRun ? Fs : $s);
|
|
2307
2307
|
const u = c.padEnd(64);
|
|
2308
2308
|
d ? s.push(` ${f} ${u} ${d}`) : s.push(` ${f} ${c}`);
|
|
2309
2309
|
}
|
|
2310
|
-
const n = e.filter((a) => a.status === "added").length,
|
|
2310
|
+
const n = e.filter((a) => a.status === "added").length, r = e.filter((a) => a.status === "updated").length, o = e.filter((a) => a.status === "unchanged").length, i = e.filter((a) => a.status === "deleted").length;
|
|
2311
2311
|
if (t.dryRun)
|
|
2312
2312
|
s.push("Dry-run: no files written.");
|
|
2313
2313
|
else {
|
|
2314
|
-
let a = `Synced: ${n} added, ${
|
|
2314
|
+
let a = `Synced: ${n} added, ${r} updated, ${o} skipped (unchanged)`;
|
|
2315
2315
|
i > 0 && (a += `, ${i} deleted`), s.push(a);
|
|
2316
2316
|
}
|
|
2317
2317
|
return s;
|
|
2318
2318
|
}
|
|
2319
|
-
const
|
|
2319
|
+
const Gs = /[\u001B\u009B][[\]()#;?]*(?:(?:(?:[a-zA-Z\d]*(?:;[-a-zA-Z\d/#&.:=?%@~_]*)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-ntqry=><~]))/g, ve = [
|
|
2320
2320
|
/^\s*(✖|❌|⚠|🛑|× |✗ |FAIL |●|▶)/,
|
|
2321
2321
|
/:\d+:\d+:\s+(error|warning)/i,
|
|
2322
2322
|
/^\s+at\s+/,
|
|
@@ -2332,58 +2332,58 @@ const Us = /[\u001B\u009B][[\]()#;?]*(?:(?:(?:[a-zA-Z\d]*(?:;[-a-zA-Z\d/#&.:=?%@
|
|
|
2332
2332
|
/^TAP version/i,
|
|
2333
2333
|
/^\s*not\s+ok\s+\d+/i
|
|
2334
2334
|
];
|
|
2335
|
-
function
|
|
2336
|
-
const t = e.replace(
|
|
2335
|
+
function Lo(e) {
|
|
2336
|
+
const t = e.replace(Gs, ""), s = t.split(`
|
|
2337
2337
|
`).filter((n) => {
|
|
2338
|
-
const
|
|
2339
|
-
return !
|
|
2338
|
+
const r = n.trim();
|
|
2339
|
+
return !r || r.length > 200 && !/:\d+/.test(r) && !ve.some((o) => o.test(r)) ? !1 : ve.some((o) => o.test(r));
|
|
2340
2340
|
});
|
|
2341
2341
|
return s.length === 0 ? t.slice(0, 2e3) + `
|
|
2342
2342
|
... [no error lines]` : s.join(`
|
|
2343
2343
|
`);
|
|
2344
2344
|
}
|
|
2345
|
-
const
|
|
2346
|
-
function
|
|
2345
|
+
const Vs = ["typecheck", "test", "test:coverage", "lint", "format"];
|
|
2346
|
+
function js(e) {
|
|
2347
2347
|
const t = e.lint;
|
|
2348
2348
|
if (t === void 0) return !1;
|
|
2349
2349
|
const s = /* @__PURE__ */ new Set(), n = [t];
|
|
2350
2350
|
for (; n.length > 0; ) {
|
|
2351
|
-
const
|
|
2352
|
-
if (
|
|
2353
|
-
if (/\bgennady\b/.test(
|
|
2354
|
-
for (const
|
|
2355
|
-
const i =
|
|
2351
|
+
const r = n.shift();
|
|
2352
|
+
if (r !== void 0) {
|
|
2353
|
+
if (/\bgennady\b/.test(r)) return !0;
|
|
2354
|
+
for (const o of r.matchAll(/npm run ([A-Za-z0-9:_-]+)/g)) {
|
|
2355
|
+
const i = o[1];
|
|
2356
2356
|
i && !s.has(i) && e[i] !== void 0 && (s.add(i), n.push(e[i]));
|
|
2357
2357
|
}
|
|
2358
2358
|
}
|
|
2359
2359
|
}
|
|
2360
2360
|
return !1;
|
|
2361
2361
|
}
|
|
2362
|
-
function
|
|
2363
|
-
const { packageJsonPresent: t, scripts: s, gennadyAvailable: n } = e,
|
|
2362
|
+
function bo(e) {
|
|
2363
|
+
const { packageJsonPresent: t, scripts: s, gennadyAvailable: n } = e, r = Vs.map((c) => ({
|
|
2364
2364
|
name: c,
|
|
2365
2365
|
present: s[c] !== void 0
|
|
2366
|
-
})),
|
|
2367
|
-
t || i.push("package.json"), i.push(...
|
|
2368
|
-
const a = t &&
|
|
2369
|
-
return { packageJsonPresent: t, required:
|
|
2366
|
+
})), o = js(s), i = [];
|
|
2367
|
+
t || i.push("package.json"), i.push(...r.filter((c) => !c.present).map((c) => c.name)), s.lint !== void 0 && !o && i.push("lint→gennady"), n || i.push("gennady (not installed)");
|
|
2368
|
+
const a = t && r.every((c) => c.present) && o && n;
|
|
2369
|
+
return { packageJsonPresent: t, required: r, lintHasGennady: o, gennadyAvailable: n, ready: a, missing: i };
|
|
2370
2370
|
}
|
|
2371
|
-
function
|
|
2371
|
+
function Ys(e) {
|
|
2372
2372
|
return e.includes("✅") ? "done" : e.includes("🚧") ? "wip" : "unknown";
|
|
2373
2373
|
}
|
|
2374
|
-
function
|
|
2374
|
+
function Mo(e) {
|
|
2375
2375
|
const t = e.split(`
|
|
2376
2376
|
`);
|
|
2377
2377
|
let s = !1;
|
|
2378
2378
|
const n = [];
|
|
2379
|
-
for (const
|
|
2380
|
-
const
|
|
2381
|
-
if (/^#{1,6}\s/.test(
|
|
2382
|
-
s = /^#{1,6}\s+Scopes\s*$/.test(
|
|
2379
|
+
for (const r of t) {
|
|
2380
|
+
const o = r.trim();
|
|
2381
|
+
if (/^#{1,6}\s/.test(o)) {
|
|
2382
|
+
s = /^#{1,6}\s+Scopes\s*$/.test(o);
|
|
2383
2383
|
continue;
|
|
2384
2384
|
}
|
|
2385
|
-
if (!s || !
|
|
2386
|
-
const i =
|
|
2385
|
+
if (!s || !o.startsWith("|")) continue;
|
|
2386
|
+
const i = o.replace(/^\|/, "").replace(/\|$/, "").split("|").map((p) => p.trim());
|
|
2387
2387
|
if (i.length < 3) continue;
|
|
2388
2388
|
const [a, c, l, f] = i;
|
|
2389
2389
|
if (a === void 0 || c === void 0 || l === void 0) continue;
|
|
@@ -2393,25 +2393,25 @@ function Po(e) {
|
|
|
2393
2393
|
n.push({
|
|
2394
2394
|
name: d[1],
|
|
2395
2395
|
type: c,
|
|
2396
|
-
status:
|
|
2396
|
+
status: Ys(l),
|
|
2397
2397
|
description: f?.trim() ?? "",
|
|
2398
2398
|
specPath: u?.[1] ?? null
|
|
2399
2399
|
});
|
|
2400
2400
|
}
|
|
2401
2401
|
return n;
|
|
2402
2402
|
}
|
|
2403
|
-
function
|
|
2403
|
+
function Hs(e) {
|
|
2404
2404
|
const t = [], s = /([A-Za-z0-9_-]+)(?:\[[^\]]*\])?\s*-->(?:\s*\|[^|]*\|)?\s*([A-Za-z0-9_-]+)/;
|
|
2405
2405
|
for (const n of e.split(`
|
|
2406
2406
|
`)) {
|
|
2407
|
-
const
|
|
2408
|
-
if (!
|
|
2409
|
-
const
|
|
2410
|
-
|
|
2407
|
+
const r = n.trim();
|
|
2408
|
+
if (!r.includes("-->")) continue;
|
|
2409
|
+
const o = s.exec(r);
|
|
2410
|
+
o?.[1] && o[2] && t.push({ from: o[1], to: o[2] });
|
|
2411
2411
|
}
|
|
2412
2412
|
return t;
|
|
2413
2413
|
}
|
|
2414
|
-
const
|
|
2414
|
+
const qs = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", "coverage", ".next", "out"]), Ws = /\.(js|jsx|ts|tsx)$/, Ks = [
|
|
2415
2415
|
"tsconfig.json",
|
|
2416
2416
|
"eslint.config.js",
|
|
2417
2417
|
"eslint.config.mjs",
|
|
@@ -2431,29 +2431,29 @@ const Ys = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", "co
|
|
|
2431
2431
|
"jest.config.js",
|
|
2432
2432
|
"jest.config.ts"
|
|
2433
2433
|
];
|
|
2434
|
-
function
|
|
2434
|
+
function st(e, t, s) {
|
|
2435
2435
|
let n;
|
|
2436
2436
|
try {
|
|
2437
|
-
n =
|
|
2437
|
+
n = B(e, { withFileTypes: !0 });
|
|
2438
2438
|
} catch {
|
|
2439
2439
|
return;
|
|
2440
2440
|
}
|
|
2441
|
-
for (const
|
|
2442
|
-
const
|
|
2443
|
-
if (
|
|
2444
|
-
if (
|
|
2445
|
-
|
|
2446
|
-
} else if (
|
|
2441
|
+
for (const r of n) {
|
|
2442
|
+
const o = r.name;
|
|
2443
|
+
if (r.isDirectory()) {
|
|
2444
|
+
if (qs.has(o) || o.startsWith(".")) continue;
|
|
2445
|
+
st(h(e, o), t, s);
|
|
2446
|
+
} else if (Ws.test(o)) {
|
|
2447
2447
|
s.count++;
|
|
2448
|
-
const i = h(e,
|
|
2448
|
+
const i = h(e, o).slice(t.length + 1);
|
|
2449
2449
|
s.dirs.add(i.includes("/") ? i.slice(0, i.indexOf("/")) : ".");
|
|
2450
2450
|
}
|
|
2451
2451
|
}
|
|
2452
2452
|
}
|
|
2453
|
-
function
|
|
2453
|
+
function $o(e) {
|
|
2454
2454
|
const t = { count: 0, dirs: /* @__PURE__ */ new Set() };
|
|
2455
|
-
|
|
2456
|
-
const s =
|
|
2455
|
+
st(e, e, t);
|
|
2456
|
+
const s = Ks.filter((n) => R(h(e, n)));
|
|
2457
2457
|
return {
|
|
2458
2458
|
codePresent: t.count > 0,
|
|
2459
2459
|
codeFileCount: t.count,
|
|
@@ -2462,160 +2462,309 @@ function Lo(e) {
|
|
|
2462
2462
|
configFiles: s
|
|
2463
2463
|
};
|
|
2464
2464
|
}
|
|
2465
|
-
function
|
|
2465
|
+
function Xs(e) {
|
|
2466
2466
|
try {
|
|
2467
|
-
return
|
|
2467
|
+
return ie(h(e, "tasks")).isDirectory() ? "v1" : "v2";
|
|
2468
2468
|
} catch {
|
|
2469
2469
|
return "v2";
|
|
2470
2470
|
}
|
|
2471
2471
|
}
|
|
2472
|
-
function
|
|
2473
|
-
if (
|
|
2472
|
+
function xo(e, t) {
|
|
2473
|
+
if (Xs(e) === "v2") return "v2";
|
|
2474
2474
|
try {
|
|
2475
|
-
if (
|
|
2475
|
+
if (ie(h(e, "tasks", t)).isDirectory()) return "v1";
|
|
2476
2476
|
} catch {
|
|
2477
2477
|
}
|
|
2478
2478
|
try {
|
|
2479
|
-
return
|
|
2479
|
+
return ie(h(e, "specs", t, `${t}.3-tasks.md`)).isFile() ? "v2" : "v1";
|
|
2480
2480
|
} catch {
|
|
2481
2481
|
return "v1";
|
|
2482
2482
|
}
|
|
2483
2483
|
}
|
|
2484
|
-
|
|
2484
|
+
const Zs = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
2485
|
+
function Bo(e) {
|
|
2486
|
+
let t = 0;
|
|
2487
|
+
function s(n) {
|
|
2488
|
+
let r;
|
|
2489
|
+
try {
|
|
2490
|
+
r = B(n, { withFileTypes: !0 });
|
|
2491
|
+
} catch {
|
|
2492
|
+
return;
|
|
2493
|
+
}
|
|
2494
|
+
for (const o of r)
|
|
2495
|
+
if (o.isDirectory()) {
|
|
2496
|
+
if (Zs.has(o.name)) continue;
|
|
2497
|
+
s(h(n, o.name));
|
|
2498
|
+
} else if (o.name.endsWith(".spec.md"))
|
|
2499
|
+
try {
|
|
2500
|
+
C(h(n, o.name), "utf-8").includes("<!--SECTION:MODULE_VISION-->") && t++;
|
|
2501
|
+
} catch {
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
return s(e), t;
|
|
2505
|
+
}
|
|
2506
|
+
function nt(e) {
|
|
2507
|
+
const t = e.match(/\*{0,2}Task-ID:\*{0,2}\s*`?([A-Za-z0-9][A-Za-z0-9_-]*)`?/), s = e.match(/\*{0,2}Status:\*{0,2}\s*(\[.\]\s*[A-Z_]+)/);
|
|
2508
|
+
return {
|
|
2509
|
+
taskId: t?.[1] ?? null,
|
|
2510
|
+
status: s?.[1] ?? null
|
|
2511
|
+
};
|
|
2512
|
+
}
|
|
2513
|
+
function K(e) {
|
|
2514
|
+
return e.replace(/`/g, "").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").trim();
|
|
2515
|
+
}
|
|
2516
|
+
function U(e) {
|
|
2517
|
+
return e.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((t) => t.trim());
|
|
2518
|
+
}
|
|
2519
|
+
function Uo(e, t, s) {
|
|
2520
|
+
const n = e.split(`
|
|
2521
|
+
`), r = ot(n);
|
|
2522
|
+
if (!r) return { ok: !1, reason: "no_table" };
|
|
2523
|
+
const { headerIdx: o, idCol: i, statusCol: a } = r;
|
|
2524
|
+
for (let c = o + 1; c < n.length; c++) {
|
|
2525
|
+
const l = n[c];
|
|
2526
|
+
if (l === void 0 || !l.trimStart().startsWith("|")) break;
|
|
2527
|
+
const f = U(l);
|
|
2528
|
+
if (/^\|?\s*-+\s*\|/.test(l) || K(f[i] ?? "") !== t) continue;
|
|
2529
|
+
const d = l.split("|"), u = a + 1;
|
|
2530
|
+
if (d[u] === void 0) return { ok: !1, reason: "no_table" };
|
|
2531
|
+
const p = d[u];
|
|
2532
|
+
return d[u] = ` ${s} `, d[u] === p ? { ok: !0, text: e, changed: !1 } : (n[c] = d.join("|"), { ok: !0, text: n.join(`
|
|
2533
|
+
`), changed: !0 });
|
|
2534
|
+
}
|
|
2535
|
+
return { ok: !1, reason: "task_not_found" };
|
|
2536
|
+
}
|
|
2537
|
+
function ot(e) {
|
|
2538
|
+
for (let t = 0; t < e.length; t++) {
|
|
2539
|
+
const s = e[t];
|
|
2540
|
+
if (s === void 0 || !s.trimStart().startsWith("|")) continue;
|
|
2541
|
+
const n = U(s).map((i) => i.toLowerCase()), r = n.indexOf("task-id"), o = n.indexOf("status");
|
|
2542
|
+
if (r !== -1 && o !== -1) return { headerIdx: t, idCol: r, statusCol: o };
|
|
2543
|
+
}
|
|
2544
|
+
return null;
|
|
2545
|
+
}
|
|
2546
|
+
function Fo(e) {
|
|
2547
|
+
const t = e.split(`
|
|
2548
|
+
`), s = ot(t);
|
|
2549
|
+
if (!s) return [];
|
|
2550
|
+
const n = [];
|
|
2551
|
+
for (let r = s.headerIdx + 1; r < t.length; r++) {
|
|
2552
|
+
const o = t[r];
|
|
2553
|
+
if (o === void 0 || !o.trimStart().startsWith("|")) break;
|
|
2554
|
+
if (/^\|?\s*-+\s*\|/.test(o)) continue;
|
|
2555
|
+
const i = U(o), a = K(i[s.idCol] ?? "");
|
|
2556
|
+
a && n.push({ taskId: a, status: (i[s.statusCol] ?? "").trim() });
|
|
2557
|
+
}
|
|
2558
|
+
return n;
|
|
2559
|
+
}
|
|
2560
|
+
function zs(e) {
|
|
2561
|
+
return /^\[x\]/i.test(e.trim());
|
|
2562
|
+
}
|
|
2563
|
+
function rt(e) {
|
|
2564
|
+
for (let t = 0; t < e.length; t++) {
|
|
2565
|
+
const s = e[t];
|
|
2566
|
+
if (s === void 0 || !s.trimStart().startsWith("|")) continue;
|
|
2567
|
+
const n = U(s).map((a) => a.toLowerCase()), r = n.indexOf("index"), o = n.indexOf("tasks"), i = n.indexOf("done") !== -1 ? n.indexOf("done") : n.indexOf("progress");
|
|
2568
|
+
if (r !== -1 && o !== -1 && i !== -1)
|
|
2569
|
+
return { headerIdx: t, indexCol: r, tasksCol: o, doneCol: i };
|
|
2570
|
+
}
|
|
2571
|
+
return null;
|
|
2572
|
+
}
|
|
2573
|
+
function Qs(e) {
|
|
2574
|
+
return e.match(/\[[^\]]*\]\(([^)]+)\)/)?.[1] ?? null;
|
|
2575
|
+
}
|
|
2576
|
+
function Go(e, t) {
|
|
2577
|
+
const s = e.split(`
|
|
2578
|
+
`), n = rt(s);
|
|
2579
|
+
if (!n) return { text: e, updated: [] };
|
|
2580
|
+
const r = [];
|
|
2581
|
+
for (let o = n.headerIdx + 1; o < s.length; o++) {
|
|
2582
|
+
const i = s[o];
|
|
2583
|
+
if (i === void 0 || !i.trimStart().startsWith("|")) break;
|
|
2584
|
+
if (/^\|?\s*-+\s*\|/.test(i)) continue;
|
|
2585
|
+
const a = U(i), c = Qs(a[n.indexCol] ?? "");
|
|
2586
|
+
if (!c) continue;
|
|
2587
|
+
const l = t(c);
|
|
2588
|
+
if (!l) continue;
|
|
2589
|
+
const f = l.filter((_) => zs(_.status)).length, d = l.length, u = i.split("|"), p = n.tasksCol + 1, m = n.doneCol + 1;
|
|
2590
|
+
if (u[p] === void 0 || u[m] === void 0) continue;
|
|
2591
|
+
const E = ` ${d} `, S = ` ${f}/${d} `;
|
|
2592
|
+
u[p] === E && u[m] === S || (u[p] = E, u[m] = S, s[o] = u.join("|"), r.push(c));
|
|
2593
|
+
}
|
|
2594
|
+
return { text: s.join(`
|
|
2595
|
+
`), updated: r };
|
|
2596
|
+
}
|
|
2597
|
+
function Vo(e) {
|
|
2598
|
+
const t = e.split(`
|
|
2599
|
+
`), s = rt(t);
|
|
2600
|
+
if (!s) return null;
|
|
2601
|
+
let n = 0, r = 0;
|
|
2602
|
+
for (let o = s.headerIdx + 1; o < t.length; o++) {
|
|
2603
|
+
const i = t[o];
|
|
2604
|
+
if (i === void 0 || !i.trimStart().startsWith("|")) break;
|
|
2605
|
+
if (/^\|?\s*-+\s*\|/.test(i)) continue;
|
|
2606
|
+
const a = U(i), c = Number.parseInt(K(a[s.tasksCol] ?? ""), 10), l = K(a[s.doneCol] ?? "").match(/^(\d+)/);
|
|
2607
|
+
Number.isFinite(c) && (n += c), l?.[1] && (r += Number.parseInt(l[1], 10));
|
|
2608
|
+
}
|
|
2609
|
+
return { totalTasks: n, totalDone: r };
|
|
2610
|
+
}
|
|
2611
|
+
const Js = 17;
|
|
2612
|
+
function M(e) {
|
|
2613
|
+
return e ? "✅" : "⬜";
|
|
2614
|
+
}
|
|
2615
|
+
function jo(e) {
|
|
2616
|
+
const t = e.portalPresent, s = e.scopesTotal > 0 && e.scopesApproved === e.scopesTotal, n = e.moduleSpecCount > 0, r = e.packageJsonPresent && e.gates.typecheck && e.gates.test && e.gates.lint, o = e.tasksTotal !== null && e.tasksTotal > 0 && e.tasksDone !== null && e.tasksDone === e.tasksTotal, i = t ? `specs/README.md — скоупов в графе: ${e.scopesTotal}` : "specs/README.md — отсутствует", a = e.scopesTotal === 0 ? "нет ни одной" : `approved: ${e.scopesApproved} из ${e.scopesTotal}`, c = e.moduleSpecCount > 0 ? `модульных спек: ${e.moduleSpecCount}` : "—", l = e.packageJsonPresent ? `гейты: type-check ${M(e.gates.typecheck)} · test ${M(e.gates.test)} · lint ${M(e.gates.lint)}` : "не настроена", f = e.tasksTotal === null ? "tasks/ отсутствует" : `тикетов: ${e.tasksTotal} · done: ${e.tasksDone ?? 0}`, d = e.portalPresent && e.projectName ? e.projectName : "«пустой репозиторий»";
|
|
2617
|
+
let u;
|
|
2618
|
+
t ? s ? n ? r ? o ? u = "всё закрыто — следующий цикл /sdd-execute" : u = e.tasksTotal === null ? "разбить спеки на задачи — /sdd-scaffold" : "выполнить следующую задачу — /sdd-execute" : u = "настроить инфраструктуру (гейты) перед scaffold" : u = "разбить скоуп на модули — /sdd" : u = "написать и approve скоуп-спеку — /sdd" : u = "создать проект — /sdd";
|
|
2619
|
+
const p = (m) => m.padEnd(Js);
|
|
2620
|
+
return [
|
|
2621
|
+
`🏗 SDD · ${d}`,
|
|
2622
|
+
"",
|
|
2623
|
+
` ${M(t)} 1. ${p("Портал")}${i}`,
|
|
2624
|
+
` ${M(s)} 2. ${p("Скоупы")}${a}`,
|
|
2625
|
+
` ${M(n)} 3. ${p("Модули")}${c}`,
|
|
2626
|
+
` ${M(r)} 4. ${p("Инфраструктура")}${l}`,
|
|
2627
|
+
` ${M(o)} 5. ${p("Задачи")}${f}`,
|
|
2628
|
+
"",
|
|
2629
|
+
` 👉 Следующий шаг: ${u}`
|
|
2630
|
+
].join(`
|
|
2631
|
+
`);
|
|
2632
|
+
}
|
|
2633
|
+
function Yo(e) {
|
|
2485
2634
|
const t = P(`git -C ${JSON.stringify(e)} diff --name-only HEAD 2>/dev/null`), s = P(
|
|
2486
2635
|
`git -C ${JSON.stringify(e)} ls-files --others --exclude-standard 2>/dev/null`
|
|
2487
2636
|
);
|
|
2488
2637
|
return [...new Set(
|
|
2489
2638
|
[...t.split(`
|
|
2490
2639
|
`), ...s.split(`
|
|
2491
|
-
`)].map((
|
|
2640
|
+
`)].map((r) => r.trim()).filter(Boolean)
|
|
2492
2641
|
)].filter(
|
|
2493
|
-
(
|
|
2642
|
+
(r) => /\.(ts|tsx|js)$/.test(r) && !/\.(test|spec)\.[jt]sx?$/.test(r) && !r.includes("node_modules/")
|
|
2494
2643
|
);
|
|
2495
2644
|
}
|
|
2496
|
-
function
|
|
2645
|
+
function Ho(e, t) {
|
|
2497
2646
|
const s = P(
|
|
2498
2647
|
`git -C ${JSON.stringify(e)} show HEAD:${JSON.stringify(t)} 2>/dev/null`,
|
|
2499
2648
|
{ expectedExitCodes: [128] }
|
|
2500
2649
|
);
|
|
2501
2650
|
return s || null;
|
|
2502
2651
|
}
|
|
2503
|
-
function
|
|
2652
|
+
function $(e, t) {
|
|
2504
2653
|
const s = new RegExp(`\\*\\*${t}:\\*\\*\\s*(.+)`);
|
|
2505
2654
|
return e.match(s)?.[1]?.trim() ?? null;
|
|
2506
2655
|
}
|
|
2507
|
-
function
|
|
2656
|
+
function ce(e, t) {
|
|
2508
2657
|
const s = e.split(`
|
|
2509
2658
|
`), n = [];
|
|
2510
|
-
let
|
|
2511
|
-
for (const
|
|
2512
|
-
const i = /^\s*-?\s*\*\*([^:*]+):\*\*/.exec(
|
|
2659
|
+
let r = !1;
|
|
2660
|
+
for (const o of s) {
|
|
2661
|
+
const i = /^\s*-?\s*\*\*([^:*]+):\*\*/.exec(o);
|
|
2513
2662
|
if (i) {
|
|
2514
|
-
|
|
2663
|
+
r = i[1]?.trim().toLowerCase() === t.toLowerCase();
|
|
2515
2664
|
continue;
|
|
2516
2665
|
}
|
|
2517
|
-
if (
|
|
2518
|
-
if (/^\s*-\s+/.test(
|
|
2666
|
+
if (r && o.trim() !== "")
|
|
2667
|
+
if (/^\s*-\s+/.test(o)) n.push(o.trim().replace(/^-\s+/, "").trim());
|
|
2519
2668
|
else break;
|
|
2520
2669
|
}
|
|
2521
2670
|
return n;
|
|
2522
2671
|
}
|
|
2523
|
-
function
|
|
2672
|
+
function le(e) {
|
|
2524
2673
|
const t = e.match(/\[([^\]]+)\]\(([^)]+)\)/);
|
|
2525
2674
|
return t && t[1] && t[2] ? { name: t[1], anchor: t[2] } : { name: e.trim(), anchor: "" };
|
|
2526
2675
|
}
|
|
2527
|
-
function
|
|
2528
|
-
const t = e.match(/\*\*Task-ID:\*\*\s*`?([A-Za-z0-9][\w-]*)`?/)?.[1] ?? null, s = e.match(/\*\*Status:\*\*\s*(\[.\]\s*[A-Z_]+)/)?.[1] ?? null, n =
|
|
2529
|
-
const a = i.indexOf(":"), c = a !== -1 && a < i.indexOf("["), l = c ? i.slice(0, a).trim() : "", { name: f, anchor: d } =
|
|
2676
|
+
function he(e) {
|
|
2677
|
+
const t = e.match(/\*\*Task-ID:\*\*\s*`?([A-Za-z0-9][\w-]*)`?/)?.[1] ?? null, s = e.match(/\*\*Status:\*\*\s*(\[.\]\s*[A-Z_]+)/)?.[1] ?? null, n = $(e, "Dependencies"), r = !n || /^none$/i.test(n.trim()) ? [] : n.split(",").map((i) => i.trim()).filter(Boolean), o = ce(e, "Spec References").map((i) => {
|
|
2678
|
+
const a = i.indexOf(":"), c = a !== -1 && a < i.indexOf("["), l = c ? i.slice(0, a).trim() : "", { name: f, anchor: d } = le(c ? i.slice(a + 1) : i);
|
|
2530
2679
|
return { role: l, name: f, anchor: d };
|
|
2531
2680
|
});
|
|
2532
2681
|
return {
|
|
2533
2682
|
taskId: t,
|
|
2534
2683
|
status: s,
|
|
2535
|
-
purpose:
|
|
2536
|
-
scope:
|
|
2537
|
-
module:
|
|
2538
|
-
dependencies:
|
|
2539
|
-
specRefs:
|
|
2684
|
+
purpose: $(e, "Purpose"),
|
|
2685
|
+
scope: $(e, "Scope"),
|
|
2686
|
+
module: $(e, "Module"),
|
|
2687
|
+
dependencies: r,
|
|
2688
|
+
specRefs: o
|
|
2540
2689
|
};
|
|
2541
2690
|
}
|
|
2542
|
-
function
|
|
2691
|
+
function it(e) {
|
|
2543
2692
|
return e.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((t) => t.trim());
|
|
2544
2693
|
}
|
|
2545
|
-
function
|
|
2694
|
+
function at(e) {
|
|
2546
2695
|
return /^\|?\s*:?-{2,}/.test(e.trim());
|
|
2547
2696
|
}
|
|
2548
|
-
function
|
|
2697
|
+
function en(e) {
|
|
2549
2698
|
const t = [];
|
|
2550
2699
|
for (const s of e.split(`
|
|
2551
2700
|
`)) {
|
|
2552
|
-
if (!s.trimStart().startsWith("|") ||
|
|
2553
|
-
const n =
|
|
2701
|
+
if (!s.trimStart().startsWith("|") || at(s)) continue;
|
|
2702
|
+
const n = it(s);
|
|
2554
2703
|
if (n.length < 4 || n[0]?.toLowerCase() === "id") continue;
|
|
2555
|
-
const [
|
|
2556
|
-
|
|
2557
|
-
id:
|
|
2558
|
-
kind:
|
|
2704
|
+
const [r, o, i, a] = n;
|
|
2705
|
+
r && t.push({
|
|
2706
|
+
id: r,
|
|
2707
|
+
kind: o ?? "",
|
|
2559
2708
|
deps: !i || i === "—" ? [] : i.split(",").map((c) => c.trim()).filter(Boolean),
|
|
2560
2709
|
status: a ?? ""
|
|
2561
2710
|
});
|
|
2562
2711
|
}
|
|
2563
2712
|
return t;
|
|
2564
2713
|
}
|
|
2565
|
-
function
|
|
2714
|
+
function qo(e) {
|
|
2566
2715
|
return {
|
|
2567
|
-
objective:
|
|
2568
|
-
rules:
|
|
2569
|
-
targetFiles:
|
|
2570
|
-
inputs:
|
|
2571
|
-
exit:
|
|
2716
|
+
objective: $(e, "Objective"),
|
|
2717
|
+
rules: ce(e, "Rules").map((t) => le(t).anchor || le(t).name),
|
|
2718
|
+
targetFiles: ce(e, "Target Files").map((t) => t.replace(/[`*]/g, "").trim()),
|
|
2719
|
+
inputs: $(e, "Inputs"),
|
|
2720
|
+
exit: $(e, "Exit")
|
|
2572
2721
|
};
|
|
2573
2722
|
}
|
|
2574
|
-
function
|
|
2723
|
+
function Wo(e) {
|
|
2575
2724
|
const t = [];
|
|
2576
2725
|
for (const s of e.split(`
|
|
2577
2726
|
`)) {
|
|
2578
|
-
if (!s.trimStart().startsWith("|") ||
|
|
2579
|
-
const n =
|
|
2727
|
+
if (!s.trimStart().startsWith("|") || at(s)) continue;
|
|
2728
|
+
const n = it(s);
|
|
2580
2729
|
if (n.length < 2 || n[0]?.toLowerCase() === "command") continue;
|
|
2581
|
-
const [
|
|
2582
|
-
|
|
2583
|
-
command:
|
|
2584
|
-
requiredBy: (
|
|
2730
|
+
const [r, o] = n;
|
|
2731
|
+
r && t.push({
|
|
2732
|
+
command: r.replace(/`/g, "").trim(),
|
|
2733
|
+
requiredBy: (o ?? "").split(",").map((i) => i.trim()).filter(Boolean)
|
|
2585
2734
|
});
|
|
2586
2735
|
}
|
|
2587
2736
|
return t;
|
|
2588
2737
|
}
|
|
2589
|
-
function
|
|
2738
|
+
function tn(e, t) {
|
|
2590
2739
|
const s = t.trim(), n = /^P(\d+)(\b|_FIX\b)/i.exec(s);
|
|
2591
2740
|
if (e === 3 && n) return `PHASE_P${n[1]}${/_FIX/i.test(s) ? "_FIX" : ""}`;
|
|
2592
2741
|
if (e !== 2) return null;
|
|
2593
|
-
const
|
|
2594
|
-
return /\bmeta\b/.test(
|
|
2742
|
+
const r = s.toLowerCase();
|
|
2743
|
+
return /\bmeta\b/.test(r) ? "META" : /phases overview/.test(r) ? "PHASES_OVERVIEW" : /acceptance criteria|\bbdd\b/.test(r) ? "BDD" : /\bverification\b/.test(r) ? "VERIFICATION" : /test scenario coverage|test coverage/.test(r) ? "TEST_COVERAGE" : /execution log/.test(r) ? "EXECUTION_LOG" : /decision log/.test(r) ? "DECISION_LOG" : null;
|
|
2595
2744
|
}
|
|
2596
|
-
function
|
|
2745
|
+
function ct(e) {
|
|
2597
2746
|
const t = [];
|
|
2598
2747
|
return e.forEach((s, n) => {
|
|
2599
|
-
const
|
|
2600
|
-
|
|
2748
|
+
const r = /^(#{2,3})\s+(.+?)\s*$/.exec(s);
|
|
2749
|
+
r && r[1] && r[2] && t.push({ idx: n, level: r[1].length, name: tn(r[1].length, r[2]) });
|
|
2601
2750
|
}), t;
|
|
2602
2751
|
}
|
|
2603
|
-
function
|
|
2752
|
+
function X(e, t) {
|
|
2604
2753
|
const s = e.split(`
|
|
2605
|
-
`), n =
|
|
2606
|
-
if (!
|
|
2607
|
-
let
|
|
2754
|
+
`), n = ct(s), r = n.find((i) => i.name === t);
|
|
2755
|
+
if (!r) return null;
|
|
2756
|
+
let o = s.length;
|
|
2608
2757
|
for (const i of n)
|
|
2609
|
-
if (i.idx >
|
|
2610
|
-
|
|
2758
|
+
if (i.idx > r.idx && i.level <= r.level) {
|
|
2759
|
+
o = i.idx;
|
|
2611
2760
|
break;
|
|
2612
2761
|
}
|
|
2613
|
-
return s.slice(
|
|
2762
|
+
return s.slice(r.idx + 1, o).join(`
|
|
2614
2763
|
`);
|
|
2615
2764
|
}
|
|
2616
|
-
function
|
|
2765
|
+
function Ko(e) {
|
|
2617
2766
|
const t = e.split(`
|
|
2618
|
-
`), s =
|
|
2767
|
+
`), s = ct(t), n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), o = [];
|
|
2619
2768
|
for (let a = 0; a < s.length; a++) {
|
|
2620
2769
|
const c = s[a];
|
|
2621
2770
|
if (!c || c.name === null || e.includes(`<!--SECTION:${c.name}-->`)) continue;
|
|
@@ -2627,23 +2776,23 @@ function Uo(e) {
|
|
|
2627
2776
|
break;
|
|
2628
2777
|
}
|
|
2629
2778
|
}
|
|
2630
|
-
n.set(c.idx, c.name),
|
|
2779
|
+
n.set(c.idx, c.name), r.set(l, c.name), o.push(c.name);
|
|
2631
2780
|
}
|
|
2632
|
-
if (
|
|
2781
|
+
if (o.length === 0) return { text: e, injected: [] };
|
|
2633
2782
|
const i = [];
|
|
2634
2783
|
for (let a = 0; a <= t.length; a++) {
|
|
2635
|
-
const c =
|
|
2784
|
+
const c = r.get(a);
|
|
2636
2785
|
c && i.push(`<!--/SECTION:${c}-->`);
|
|
2637
2786
|
const l = n.get(a);
|
|
2638
2787
|
l && i.push(`<!--SECTION:${l}-->`), a < t.length && i.push(t[a]);
|
|
2639
2788
|
}
|
|
2640
2789
|
return { text: i.join(`
|
|
2641
|
-
`), injected:
|
|
2790
|
+
`), injected: o };
|
|
2642
2791
|
}
|
|
2643
|
-
function
|
|
2644
|
-
const s = e.includes("<!--SECTION:META-->") ||
|
|
2792
|
+
function Xo(e, t) {
|
|
2793
|
+
const s = e.includes("<!--SECTION:META-->") || X(e, "META") !== null, n = e.includes("<!--SECTION:EXECUTION_LOG-->");
|
|
2645
2794
|
if (!s || n) return { text: e, scaffolded: !1 };
|
|
2646
|
-
const
|
|
2795
|
+
const r = [
|
|
2647
2796
|
"",
|
|
2648
2797
|
"## Execution Log",
|
|
2649
2798
|
"<!--SECTION:EXECUTION_LOG-->",
|
|
@@ -2653,33 +2802,33 @@ function Go(e, t) {
|
|
|
2653
2802
|
`);
|
|
2654
2803
|
return { text: `${e.endsWith(`
|
|
2655
2804
|
`) ? e.slice(0, -1) : e}
|
|
2656
|
-
${
|
|
2805
|
+
${r}
|
|
2657
2806
|
`, scaffolded: !0 };
|
|
2658
2807
|
}
|
|
2659
|
-
const
|
|
2660
|
-
function
|
|
2808
|
+
const we = /<[A-Za-z…][^>\s]*>/, sn = /`[^`]*`/g;
|
|
2809
|
+
function Zo(e) {
|
|
2661
2810
|
return e.includes("<!--SECTION:META-->") && e.includes("<!--SECTION:EXECUTION_LOG-->");
|
|
2662
2811
|
}
|
|
2663
|
-
function
|
|
2664
|
-
return
|
|
2812
|
+
function zo(e) {
|
|
2813
|
+
return X(e, "META") !== null && X(e, "EXECUTION_LOG") !== null;
|
|
2665
2814
|
}
|
|
2666
|
-
function
|
|
2815
|
+
function lt(e) {
|
|
2667
2816
|
const t = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map();
|
|
2668
|
-
for (const
|
|
2817
|
+
for (const r of e.split(`
|
|
2669
2818
|
`)) {
|
|
2670
|
-
const
|
|
2819
|
+
const o = r.trim(), i = /^<!--SECTION:([A-Z][A-Z0-9_]*)-->$/.exec(o), a = /^<!--\/SECTION:([A-Z][A-Z0-9_]*)-->$/.exec(o);
|
|
2671
2820
|
i?.[1] && t.set(i[1], (t.get(i[1]) ?? 0) + 1), a?.[1] && s.set(a[1], (s.get(a[1]) ?? 0) + 1);
|
|
2672
2821
|
}
|
|
2673
|
-
return [.../* @__PURE__ */ new Set([...t.keys(), ...s.keys()])].filter((
|
|
2822
|
+
return [.../* @__PURE__ */ new Set([...t.keys(), ...s.keys()])].filter((r) => (t.get(r) ?? 0) !== (s.get(r) ?? 0));
|
|
2674
2823
|
}
|
|
2675
|
-
function
|
|
2824
|
+
function dt(e) {
|
|
2676
2825
|
const t = [], s = [];
|
|
2677
2826
|
for (const n of e.split(`
|
|
2678
2827
|
`)) {
|
|
2679
|
-
const
|
|
2680
|
-
if (
|
|
2828
|
+
const r = n.trim(), o = /^<!--SECTION:([A-Z][A-Z0-9_]*)-->$/.exec(r), i = /^<!--\/SECTION:([A-Z][A-Z0-9_]*)-->$/.exec(r);
|
|
2829
|
+
if (o?.[1]) {
|
|
2681
2830
|
const a = s[s.length - 1];
|
|
2682
|
-
a && t.push(`${
|
|
2831
|
+
a && t.push(`${o[1]} opens while ${a} is still open — sections must be flat, not nested`), s.push(o[1]);
|
|
2683
2832
|
} else if (i?.[1]) {
|
|
2684
2833
|
const a = s[s.length - 1];
|
|
2685
2834
|
if (a === i[1]) s.pop();
|
|
@@ -2693,56 +2842,56 @@ function rt(e) {
|
|
|
2693
2842
|
}
|
|
2694
2843
|
return t;
|
|
2695
2844
|
}
|
|
2696
|
-
function
|
|
2845
|
+
function nn(e) {
|
|
2697
2846
|
const t = e.split(`
|
|
2698
2847
|
`);
|
|
2699
2848
|
let s = -1, n = -1;
|
|
2700
|
-
return t.forEach((
|
|
2701
|
-
/🛑|BLOCKED/.test(
|
|
2849
|
+
return t.forEach((r, o) => {
|
|
2850
|
+
/🛑|BLOCKED/.test(r) && (s = o), /✅|RESOLVED/.test(r) && (n = o);
|
|
2702
2851
|
}), s !== -1 && s > n;
|
|
2703
2852
|
}
|
|
2704
|
-
function
|
|
2705
|
-
const s = [], n = (l, f) => void s.push({ severity: "error", code: l, file: e, message: f }),
|
|
2706
|
-
for (const l of
|
|
2853
|
+
function Qo(e, t) {
|
|
2854
|
+
const s = [], n = (l, f) => void s.push({ severity: "error", code: l, file: e, message: f }), r = (l, f) => void s.push({ severity: "warn", code: l, file: e, message: f });
|
|
2855
|
+
for (const l of lt(t))
|
|
2707
2856
|
n("SDD_ANCHOR_UNBALANCED", `Section ${l}: open/close markers do not balance.`);
|
|
2708
|
-
for (const l of
|
|
2857
|
+
for (const l of dt(t))
|
|
2709
2858
|
n("SDD_SECTION_OVERLAP", `${l}. sdd-extract pulls one flat section — fix the marker order.`);
|
|
2710
|
-
const
|
|
2711
|
-
|
|
2859
|
+
const o = g(t, "META"), i = g(t, "EXECUTION_LOG");
|
|
2860
|
+
o.status !== "ok" && n("SDD_MISSING_META", "No usable META section."), i.status !== "ok" && n("SDD_MISSING_EXECUTION_LOG", "No usable EXECUTION_LOG section.");
|
|
2712
2861
|
let a = !1;
|
|
2713
|
-
if (
|
|
2714
|
-
const l =
|
|
2715
|
-
l.taskId ||
|
|
2862
|
+
if (o.status === "ok") {
|
|
2863
|
+
const l = he(o.content);
|
|
2864
|
+
l.taskId || r("SDD_MISSING_TASK_ID", "Meta has no parseable Task-ID."), l.status || r("SDD_STATUS_UNPARSEABLE", "Meta Status is missing or not in `[x] STATE` form."), a = l.status?.includes("[x]") ?? !1;
|
|
2716
2865
|
}
|
|
2717
2866
|
if (i.status === "ok") {
|
|
2718
2867
|
const l = i.content.split(`
|
|
2719
2868
|
`);
|
|
2720
2869
|
for (const f of l) {
|
|
2721
|
-
const d = f.replace(
|
|
2722
|
-
/\[x\]/.test(d) &&
|
|
2870
|
+
const d = f.replace(sn, "");
|
|
2871
|
+
/\[x\]/.test(d) && we.test(f) && n(
|
|
2723
2872
|
"SDD_FABRICATED_DONE",
|
|
2724
2873
|
`Checked [x] line with an unreplaced placeholder: "${f.trim()}"`
|
|
2725
2874
|
);
|
|
2726
2875
|
}
|
|
2727
|
-
|
|
2876
|
+
nn(i.content) && (a ? n(
|
|
2728
2877
|
"SDD_DONE_WITH_ACTIVE_BLOCKER",
|
|
2729
2878
|
"Status is DONE but the Execution Log ends with an unresolved BLOCKED."
|
|
2730
|
-
) :
|
|
2879
|
+
) : r(
|
|
2731
2880
|
"SDD_BLOCKER_OPEN",
|
|
2732
2881
|
"Execution Log ends with an unresolved 🛑 BLOCKED — no later ✅ RESOLVED. Resolve or explicitly reopen before the orchestrator relies on this ticket."
|
|
2733
2882
|
));
|
|
2734
2883
|
}
|
|
2735
|
-
a &&
|
|
2884
|
+
a && we.test(t) && r(
|
|
2736
2885
|
"SDD_DONE_WITH_PLACEHOLDERS",
|
|
2737
2886
|
"Status is DONE but unreplaced <…> scaffold placeholders remain."
|
|
2738
2887
|
);
|
|
2739
2888
|
const c = g(t, "PHASES_OVERVIEW");
|
|
2740
2889
|
if (c.status === "ok") {
|
|
2741
|
-
const l =
|
|
2890
|
+
const l = en(c.content), f = new Set(l.map((u) => u.id));
|
|
2742
2891
|
for (const u of l)
|
|
2743
2892
|
for (const p of u.deps)
|
|
2744
2893
|
f.has(p) || n("SDD_PHASE_DEP_UNRESOLVED", `Phase ${u.id} depends on unknown phase ${p}.`);
|
|
2745
|
-
|
|
2894
|
+
te(l.flatMap((u) => u.deps.map((p) => ({ from: u.id, to: p })))) && n("SDD_PHASE_DAG_CYCLE", "Phase dependency graph has a cycle.");
|
|
2746
2895
|
const d = /* @__PURE__ */ new Set();
|
|
2747
2896
|
for (const u of t.matchAll(/<!--SECTION:PHASE_(P[0-9]+)-->/g))
|
|
2748
2897
|
d.add(u[1]);
|
|
@@ -2759,27 +2908,27 @@ function jo(e, t) {
|
|
|
2759
2908
|
}
|
|
2760
2909
|
return s;
|
|
2761
2910
|
}
|
|
2762
|
-
function
|
|
2911
|
+
function te(e) {
|
|
2763
2912
|
const t = /* @__PURE__ */ new Map();
|
|
2764
|
-
for (const
|
|
2765
|
-
const
|
|
2766
|
-
|
|
2913
|
+
for (const r of e) {
|
|
2914
|
+
const o = t.get(r.from);
|
|
2915
|
+
o ? o.push(r.to) : t.set(r.from, [r.to]);
|
|
2767
2916
|
}
|
|
2768
|
-
const s = /* @__PURE__ */ new Map(), n = (
|
|
2769
|
-
s.set(
|
|
2770
|
-
for (const
|
|
2771
|
-
const i = s.get(
|
|
2772
|
-
if (i === 1 || i === void 0 && n(
|
|
2917
|
+
const s = /* @__PURE__ */ new Map(), n = (r) => {
|
|
2918
|
+
s.set(r, 1);
|
|
2919
|
+
for (const o of t.get(r) ?? []) {
|
|
2920
|
+
const i = s.get(o);
|
|
2921
|
+
if (i === 1 || i === void 0 && n(o)) return !0;
|
|
2773
2922
|
}
|
|
2774
|
-
return s.set(
|
|
2923
|
+
return s.set(r, 2), !1;
|
|
2775
2924
|
};
|
|
2776
|
-
for (const
|
|
2777
|
-
if (s.get(
|
|
2925
|
+
for (const r of t.keys())
|
|
2926
|
+
if (s.get(r) === void 0 && n(r)) return !0;
|
|
2778
2927
|
return !1;
|
|
2779
2928
|
}
|
|
2780
|
-
function
|
|
2781
|
-
const { scopes: t, edges: s, specDirs: n } = e,
|
|
2782
|
-
|
|
2929
|
+
function Jo(e) {
|
|
2930
|
+
const { scopes: t, edges: s, specDirs: n } = e, r = "specs/README.md", o = [], i = (c, l) => void o.push({ severity: "error", code: c, file: r, message: l }), a = new Set(t.map((c) => c.name));
|
|
2931
|
+
te(s) && i("SDD_PORTAL_GRAPH_CYCLE", "Scope Graph has a dependency cycle.");
|
|
2783
2932
|
for (const c of s)
|
|
2784
2933
|
a.has(c.from) || i(
|
|
2785
2934
|
"SDD_PORTAL_DANGLING_DEP",
|
|
@@ -2792,29 +2941,29 @@ function Yo(e) {
|
|
|
2792
2941
|
a.has(c) || i("SDD_PORTAL_ORPHAN_SPEC", `Spec dir has no row in the portal Scopes table: specs/${c}/`);
|
|
2793
2942
|
for (const c of t)
|
|
2794
2943
|
c.status === "done" && !n.includes(c.name) && i("SDD_PORTAL_SPEC_MISSING", `Scope marked done has no spec on disk: ${c.name}`);
|
|
2795
|
-
return
|
|
2944
|
+
return o;
|
|
2796
2945
|
}
|
|
2797
|
-
function
|
|
2798
|
-
const n = g(t, "META"),
|
|
2946
|
+
function er(e, t, s) {
|
|
2947
|
+
const n = g(t, "META"), r = n.status === "ok" ? he(n.content) : null;
|
|
2799
2948
|
return {
|
|
2800
2949
|
file: e,
|
|
2801
|
-
taskId:
|
|
2802
|
-
status:
|
|
2803
|
-
dependencies:
|
|
2950
|
+
taskId: r?.taskId ?? null,
|
|
2951
|
+
status: r?.status ?? null,
|
|
2952
|
+
dependencies: r?.dependencies ?? [],
|
|
2804
2953
|
flowVersion: s
|
|
2805
2954
|
};
|
|
2806
2955
|
}
|
|
2807
|
-
function
|
|
2808
|
-
const n =
|
|
2956
|
+
function tr(e, t, s) {
|
|
2957
|
+
const n = X(t, "META"), r = n !== null ? he(n) : null;
|
|
2809
2958
|
return {
|
|
2810
2959
|
file: e,
|
|
2811
|
-
taskId:
|
|
2812
|
-
status:
|
|
2813
|
-
dependencies:
|
|
2960
|
+
taskId: r?.taskId ?? null,
|
|
2961
|
+
status: r?.status ?? null,
|
|
2962
|
+
dependencies: r?.dependencies ?? [],
|
|
2814
2963
|
flowVersion: s
|
|
2815
2964
|
};
|
|
2816
2965
|
}
|
|
2817
|
-
function
|
|
2966
|
+
function sr(e) {
|
|
2818
2967
|
return [
|
|
2819
2968
|
{
|
|
2820
2969
|
severity: "warn",
|
|
@@ -2824,49 +2973,49 @@ function Wo(e) {
|
|
|
2824
2973
|
}
|
|
2825
2974
|
];
|
|
2826
2975
|
}
|
|
2827
|
-
function
|
|
2976
|
+
function on(e) {
|
|
2828
2977
|
return e != null && /\bDONE\b/i.test(e);
|
|
2829
2978
|
}
|
|
2830
|
-
function
|
|
2979
|
+
function nr(e) {
|
|
2831
2980
|
const t = new Map(
|
|
2832
2981
|
e.filter((n) => n.taskId).map((n) => [n.taskId, n.status])
|
|
2833
|
-
), s = (n) => n.filter((
|
|
2982
|
+
), s = (n) => n.filter((r) => !/^(none|n\/a|[—-])\b/i.test(r.trim()));
|
|
2834
2983
|
return e.filter(
|
|
2835
|
-
(n) => n.taskId != null && /\bTODO\b/i.test(n.status ?? "") && s(n.dependencies).every((
|
|
2984
|
+
(n) => n.taskId != null && /\bTODO\b/i.test(n.status ?? "") && s(n.dependencies).every((r) => on(t.get(r)))
|
|
2836
2985
|
);
|
|
2837
2986
|
}
|
|
2838
|
-
function
|
|
2987
|
+
function or(e) {
|
|
2839
2988
|
const t = [], s = /* @__PURE__ */ new Map();
|
|
2840
|
-
for (const
|
|
2841
|
-
if (!
|
|
2842
|
-
const
|
|
2843
|
-
|
|
2989
|
+
for (const r of e) {
|
|
2990
|
+
if (!r.taskId) continue;
|
|
2991
|
+
const o = s.get(r.taskId);
|
|
2992
|
+
o ? o.push(r.file) : s.set(r.taskId, [r.file]);
|
|
2844
2993
|
}
|
|
2845
|
-
for (const [
|
|
2846
|
-
|
|
2994
|
+
for (const [r, o] of s)
|
|
2995
|
+
o.length > 1 && t.push({
|
|
2847
2996
|
severity: "error",
|
|
2848
2997
|
code: "SDD_TASK_ID_COLLISION",
|
|
2849
|
-
file:
|
|
2850
|
-
message: `Task-ID ${
|
|
2998
|
+
file: o[0],
|
|
2999
|
+
message: `Task-ID ${r} is used by ${o.length} tickets: ${o.join(", ")}.`
|
|
2851
3000
|
});
|
|
2852
|
-
for (const
|
|
2853
|
-
for (const
|
|
2854
|
-
s.has(
|
|
3001
|
+
for (const r of e)
|
|
3002
|
+
for (const o of r.dependencies)
|
|
3003
|
+
s.has(o) || t.push({
|
|
2855
3004
|
severity: "error",
|
|
2856
3005
|
code: "SDD_DEP_UNRESOLVED",
|
|
2857
|
-
file:
|
|
2858
|
-
message: `Dependency ${
|
|
3006
|
+
file: r.file,
|
|
3007
|
+
message: `Dependency ${o} resolves to no ticket in the tree.`
|
|
2859
3008
|
});
|
|
2860
|
-
const n = e.filter((
|
|
2861
|
-
return
|
|
3009
|
+
const n = e.filter((r) => r.taskId).flatMap((r) => r.dependencies.map((o) => ({ from: r.taskId, to: o })));
|
|
3010
|
+
return te(n) && t.push({
|
|
2862
3011
|
severity: "error",
|
|
2863
3012
|
code: "SDD_DAG_CYCLE",
|
|
2864
3013
|
file: "(task graph)",
|
|
2865
3014
|
message: "Task dependency graph has a cycle."
|
|
2866
3015
|
}), t;
|
|
2867
3016
|
}
|
|
2868
|
-
function
|
|
2869
|
-
const s = [], n = (a) => a.replace(/`/g, "").replace(/\s+/g, " ").trim(),
|
|
3017
|
+
function rr(e, t) {
|
|
3018
|
+
const s = [], n = (a) => a.replace(/`/g, "").replace(/\s+/g, " ").trim(), r = (a) => a === "v2" ? "error" : "warn", o = new Set(e.map((a) => a.taskId).filter((a) => a !== null)), i = /* @__PURE__ */ new Map();
|
|
2870
3019
|
for (const a of t) {
|
|
2871
3020
|
const c = i.get(a.taskId);
|
|
2872
3021
|
c ? c.push(a) : i.set(a.taskId, [a]);
|
|
@@ -2876,7 +3025,7 @@ function Zo(e, t) {
|
|
|
2876
3025
|
const c = i.get(a.taskId);
|
|
2877
3026
|
if (!c) {
|
|
2878
3027
|
s.push({
|
|
2879
|
-
severity:
|
|
3028
|
+
severity: r(a.flowVersion),
|
|
2880
3029
|
code: "SDD_TRACKER_MISSING_ROW",
|
|
2881
3030
|
file: a.file,
|
|
2882
3031
|
message: `Ticket ${a.taskId} has no row in any Tracker Index.`
|
|
@@ -2893,23 +3042,23 @@ function Zo(e, t) {
|
|
|
2893
3042
|
});
|
|
2894
3043
|
}
|
|
2895
3044
|
for (const a of t)
|
|
2896
|
-
|
|
2897
|
-
severity:
|
|
3045
|
+
o.has(a.taskId) || s.push({
|
|
3046
|
+
severity: r(a.flowVersion),
|
|
2898
3047
|
code: "SDD_TRACKER_ORPHAN_ROW",
|
|
2899
3048
|
file: a.file,
|
|
2900
3049
|
message: `Tracker row ${a.taskId} points to no ticket on disk.`
|
|
2901
3050
|
});
|
|
2902
3051
|
return s;
|
|
2903
3052
|
}
|
|
2904
|
-
const
|
|
2905
|
-
|
|
2906
|
-
),
|
|
2907
|
-
new Set([...
|
|
2908
|
-
),
|
|
2909
|
-
function
|
|
3053
|
+
const de = Object.fromEntries(
|
|
3054
|
+
He.map((e) => [e, qe(e)])
|
|
3055
|
+
), ut = qe("module"), ue = Array.from(
|
|
3056
|
+
new Set([...He, "module"].flatMap((e) => Ds(e)))
|
|
3057
|
+
), Pe = 120, Le = 120, be = 6, rn = /[.!?]\s+[A-ZА-ЯЁ]/;
|
|
3058
|
+
function an(e) {
|
|
2910
3059
|
return (e.match(/^```/gm) ?? []).length >= 2;
|
|
2911
3060
|
}
|
|
2912
|
-
const
|
|
3061
|
+
const cn = [
|
|
2913
3062
|
{ re: /аппрув[а-яё]*/giu, say: "подтверждение" },
|
|
2914
3063
|
{ re: /реифицир[а-яё]*/giu, say: "вынести в данные" },
|
|
2915
3064
|
{ re: /чек(ать|нуть|аем|ается)[а-яё]*/giu, say: "проверить" },
|
|
@@ -2927,7 +3076,7 @@ const tn = [
|
|
|
2927
3076
|
{ re: /подня[а-яё]*\s+сервис[а-яё]*/giu, say: "запустить сервис" },
|
|
2928
3077
|
{ re: /на\s+проводе/giu, say: "в ответе / запросе сервера" },
|
|
2929
3078
|
{ re: /разв(о|е)д[а-яё]*\s+провод[а-яё]*/giu, say: "явно связать зависимости" }
|
|
2930
|
-
],
|
|
3079
|
+
], ln = [
|
|
2931
3080
|
{
|
|
2932
3081
|
re: /осуществля[а-яё]*/giu,
|
|
2933
3082
|
say: "подставить подлежащее и обычный глагол, напр. «модуль делает X»"
|
|
@@ -2939,50 +3088,50 @@ const tn = [
|
|
|
2939
3088
|
},
|
|
2940
3089
|
{ re: /имеет\s+место\s+быть/giu, say: "есть / происходит" }
|
|
2941
3090
|
];
|
|
2942
|
-
function
|
|
3091
|
+
function ir(e, t) {
|
|
2943
3092
|
const s = [];
|
|
2944
|
-
for (const { re: n, say:
|
|
2945
|
-
const
|
|
2946
|
-
|
|
3093
|
+
for (const { re: n, say: r } of cn) {
|
|
3094
|
+
const o = [...t.matchAll(n)].map((i) => i[0]);
|
|
3095
|
+
o.length !== 0 && s.push({
|
|
2947
3096
|
severity: "warn",
|
|
2948
3097
|
code: "SDD_LANGUAGE_CALQUE",
|
|
2949
3098
|
file: e,
|
|
2950
|
-
message: `«${
|
|
3099
|
+
message: `«${o[0]}»${o.length > 1 ? ` (×${o.length})` : ""} — англицизм-калька; по-русски: ${r} (AX_OPERATOR_DIALOGUE_STYLE).`
|
|
2951
3100
|
});
|
|
2952
3101
|
}
|
|
2953
|
-
for (const { re: n, say:
|
|
2954
|
-
const
|
|
2955
|
-
|
|
3102
|
+
for (const { re: n, say: r } of ln) {
|
|
3103
|
+
const o = [...t.matchAll(n)].map((i) => i[0]);
|
|
3104
|
+
o.length !== 0 && s.push({
|
|
2956
3105
|
severity: "warn",
|
|
2957
3106
|
code: "SDD_LANGUAGE_CALQUE",
|
|
2958
3107
|
file: e,
|
|
2959
|
-
message: `«${
|
|
3108
|
+
message: `«${o[0]}»${o.length > 1 ? ` (×${o.length})` : ""} — канцелярит; по-русски: ${r} (AX_OPERATOR_DIALOGUE_STYLE).`
|
|
2960
3109
|
});
|
|
2961
3110
|
}
|
|
2962
3111
|
return s;
|
|
2963
3112
|
}
|
|
2964
|
-
const
|
|
2965
|
-
function
|
|
3113
|
+
const Me = 20, $e = 750;
|
|
3114
|
+
function dn(e) {
|
|
2966
3115
|
const t = e.split(`
|
|
2967
3116
|
`).map((s) => s.trim()).filter((s) => s.startsWith("|") && !/^\|[\s:|-]+$/.test(s));
|
|
2968
3117
|
return Math.max(0, t.length - 1);
|
|
2969
3118
|
}
|
|
2970
|
-
function
|
|
2971
|
-
const n =
|
|
3119
|
+
function ar(e, t, s = "v1") {
|
|
3120
|
+
const n = lt(t).map((a) => ({
|
|
2972
3121
|
severity: "error",
|
|
2973
3122
|
code: "SDD_ANCHOR_UNBALANCED",
|
|
2974
3123
|
file: e,
|
|
2975
3124
|
message: `Section ${a}: open/close markers do not balance.`
|
|
2976
3125
|
}));
|
|
2977
|
-
for (const a of
|
|
3126
|
+
for (const a of dt(t))
|
|
2978
3127
|
n.push({
|
|
2979
3128
|
severity: "error",
|
|
2980
3129
|
code: "SDD_SECTION_OVERLAP",
|
|
2981
3130
|
file: e,
|
|
2982
3131
|
message: `${a}. sdd-extract pulls one flat section — fix the marker order.`
|
|
2983
3132
|
});
|
|
2984
|
-
const
|
|
2985
|
-
if (
|
|
3133
|
+
const r = /<!--SECTION:MODULE_VISION-->/.test(t), o = /<!--SECTION:SCOPE_TYPE-->/.test(t) && !r;
|
|
3134
|
+
if (o)
|
|
2986
3135
|
for (const a of ["ENTITY_INVENTORY", "MODULE_CONTRACTS"])
|
|
2987
3136
|
new RegExp(`<!--SECTION:${a}-->`).test(t) && n.push({
|
|
2988
3137
|
severity: "warn",
|
|
@@ -2990,32 +3139,32 @@ function Qo(e, t, s = "v1") {
|
|
|
2990
3139
|
file: e,
|
|
2991
3140
|
message: `Scope spec carries module-level section ${a} — move that detail into a module spec; a scope stays a thin index of modules (AX_SCOPE_STAYS_THIN).`
|
|
2992
3141
|
});
|
|
2993
|
-
if (
|
|
2994
|
-
const a = g(t, "ENTITY_INVENTORY"), c = a.status === "ok" ?
|
|
2995
|
-
c >
|
|
3142
|
+
if (r) {
|
|
3143
|
+
const a = g(t, "ENTITY_INVENTORY"), c = a.status === "ok" ? dn(a.content) : 0;
|
|
3144
|
+
c > Me ? n.push({
|
|
2996
3145
|
severity: "warn",
|
|
2997
3146
|
code: "SDD_MODULE_OVERSIZED",
|
|
2998
3147
|
file: e,
|
|
2999
|
-
message: `Entity Inventory has ${c} entities (> ${
|
|
3148
|
+
message: `Entity Inventory has ${c} entities (> ${Me}) — decompose into sub-modules (AX_HIERARCHICAL_SPECS).`
|
|
3000
3149
|
}) : t.split(`
|
|
3001
|
-
`).length >
|
|
3150
|
+
`).length > $e && n.push({
|
|
3002
3151
|
severity: "warn",
|
|
3003
3152
|
code: "SDD_MODULE_SPEC_VERBOSE",
|
|
3004
3153
|
file: e,
|
|
3005
3154
|
message: `Module spec is ${t.split(`
|
|
3006
|
-
`).length} lines (> ${
|
|
3155
|
+
`).length} lines (> ${$e}) with a cohesive inventory — compress the spec (AX_HIERARCHICAL_SPECS).`
|
|
3007
3156
|
});
|
|
3008
3157
|
}
|
|
3009
3158
|
const i = g(t, "SCOPE_TYPE");
|
|
3010
|
-
if (i.status === "ok" && !
|
|
3011
|
-
const a = Object.keys(
|
|
3159
|
+
if (i.status === "ok" && !r) {
|
|
3160
|
+
const a = Object.keys(de).find(
|
|
3012
3161
|
(c) => new RegExp(`\\b${c}\\b`).test(i.content)
|
|
3013
3162
|
);
|
|
3014
3163
|
if (a) {
|
|
3015
3164
|
const c = new Set(
|
|
3016
3165
|
[...t.matchAll(/<!--SECTION:([A-Z_]+)-->/g)].map((l) => l[1])
|
|
3017
3166
|
);
|
|
3018
|
-
for (const l of
|
|
3167
|
+
for (const l of de[a])
|
|
3019
3168
|
c.has(l) || n.push({
|
|
3020
3169
|
severity: "error",
|
|
3021
3170
|
code: "SDD_SPEC_SECTION_MISSING",
|
|
@@ -3028,30 +3177,30 @@ function Qo(e, t, s = "v1") {
|
|
|
3028
3177
|
const a = new Set(
|
|
3029
3178
|
[...t.matchAll(/<!--SECTION:([A-Z_]+)-->/g)].map((c) => c[1])
|
|
3030
3179
|
);
|
|
3031
|
-
if (
|
|
3032
|
-
for (const c of
|
|
3180
|
+
if (r)
|
|
3181
|
+
for (const c of ut)
|
|
3033
3182
|
a.has(c) || n.push({
|
|
3034
3183
|
severity: "error",
|
|
3035
3184
|
code: "SDD_SPEC_SECTION_MISSING",
|
|
3036
3185
|
file: e,
|
|
3037
3186
|
message: `module spec is missing required section ${c}.`
|
|
3038
3187
|
});
|
|
3039
|
-
if (
|
|
3188
|
+
if (o || r) {
|
|
3040
3189
|
const c = g(t, "OVERVIEW");
|
|
3041
3190
|
c.status !== "ok" ? n.push({
|
|
3042
3191
|
severity: "error",
|
|
3043
3192
|
code: "SDD_NO_DIAGRAM_BLOCK",
|
|
3044
3193
|
file: e,
|
|
3045
3194
|
message: "Spec has no Overview section — every spec opens with an Overview carrying at least one diagram (AX_SPEC_MANDATORY_DIAGRAM)."
|
|
3046
|
-
}) :
|
|
3195
|
+
}) : an(c.content) || n.push({
|
|
3047
3196
|
severity: "error",
|
|
3048
3197
|
code: "SDD_DIAGRAM_BLOCK_EMPTY",
|
|
3049
3198
|
file: e,
|
|
3050
3199
|
message: "Overview section has no diagram — add at least one fenced mermaid or ASCII diagram (AX_SPEC_MANDATORY_DIAGRAM)."
|
|
3051
3200
|
});
|
|
3052
3201
|
}
|
|
3053
|
-
if (
|
|
3054
|
-
for (const c of
|
|
3202
|
+
if (r || o)
|
|
3203
|
+
for (const c of ue) {
|
|
3055
3204
|
const l = g(t, c);
|
|
3056
3205
|
l.status === "ok" && !/<details[\s>]/i.test(l.content) && n.push({
|
|
3057
3206
|
severity: "error",
|
|
@@ -3060,52 +3209,52 @@ function Qo(e, t, s = "v1") {
|
|
|
3060
3209
|
message: `Section ${c} does not fold its detail under \`<details>\` — collapse the contract body so the summary stays readable (AX_SPEC_PROGRESSIVE_DISCLOSURE).`
|
|
3061
3210
|
});
|
|
3062
3211
|
}
|
|
3063
|
-
if (
|
|
3212
|
+
if (r || o)
|
|
3064
3213
|
for (const c of a) {
|
|
3065
|
-
if (
|
|
3214
|
+
if (ue.includes(c)) continue;
|
|
3066
3215
|
const l = g(t, c);
|
|
3067
3216
|
if (l.status !== "ok") continue;
|
|
3068
3217
|
const f = l.content.split(`
|
|
3069
3218
|
`).length;
|
|
3070
|
-
f >
|
|
3219
|
+
f > Pe && n.push({
|
|
3071
3220
|
severity: "error",
|
|
3072
3221
|
code: "SDD_SECTION_TOO_LONG",
|
|
3073
3222
|
file: e,
|
|
3074
|
-
message: `Section ${c} is ${f} lines (> ${
|
|
3223
|
+
message: `Section ${c} is ${f} lines (> ${Pe}) — decompose (split into a module/sub-scope) or fold the reference detail into a foldable section (AX_SPEC_PROGRESSIVE_DISCLOSURE).`
|
|
3075
3224
|
});
|
|
3076
3225
|
}
|
|
3077
|
-
n.push(...
|
|
3226
|
+
n.push(...un(e, t));
|
|
3078
3227
|
}
|
|
3079
3228
|
return n;
|
|
3080
3229
|
}
|
|
3081
|
-
function
|
|
3230
|
+
function xe(e) {
|
|
3082
3231
|
return /^\|[\s:|-]+\|$/.test(e);
|
|
3083
3232
|
}
|
|
3084
|
-
function
|
|
3233
|
+
function Be(e) {
|
|
3085
3234
|
return e.slice(1, -1).split("|").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
3086
3235
|
}
|
|
3087
|
-
function
|
|
3236
|
+
function un(e, t) {
|
|
3088
3237
|
const s = [], n = t.split(`
|
|
3089
3238
|
`);
|
|
3090
|
-
let
|
|
3091
|
-
for (let
|
|
3092
|
-
const i = n[
|
|
3239
|
+
let r = !1;
|
|
3240
|
+
for (let o = 0; o < n.length; o++) {
|
|
3241
|
+
const i = n[o].trim();
|
|
3093
3242
|
if (i.startsWith("```")) {
|
|
3094
|
-
|
|
3243
|
+
r = !r;
|
|
3095
3244
|
continue;
|
|
3096
3245
|
}
|
|
3097
|
-
if (
|
|
3098
|
-
const a = (n[
|
|
3099
|
-
if (
|
|
3100
|
-
const c =
|
|
3101
|
-
c >
|
|
3246
|
+
if (r || !i.startsWith("|") || !i.endsWith("|") || xe(i)) continue;
|
|
3247
|
+
const a = (n[o + 1] ?? "").trim();
|
|
3248
|
+
if (xe(a)) {
|
|
3249
|
+
const c = Be(i).length;
|
|
3250
|
+
c > be && s.push({
|
|
3102
3251
|
severity: "error",
|
|
3103
3252
|
code: "SDD_TABLE_TOO_MANY_COLUMNS",
|
|
3104
3253
|
file: e,
|
|
3105
|
-
message: `Table header has ${c} columns (> ${
|
|
3254
|
+
message: `Table header has ${c} columns (> ${be}) — a table is an index; split it or move detail into a subsection (AX_SPEC_TABLE_IS_INDEX).`
|
|
3106
3255
|
});
|
|
3107
3256
|
}
|
|
3108
|
-
for (const c of
|
|
3257
|
+
for (const c of Be(i)) {
|
|
3109
3258
|
if (/<br/i.test(c)) {
|
|
3110
3259
|
s.push({
|
|
3111
3260
|
severity: "error",
|
|
@@ -3115,12 +3264,12 @@ function on(e, t) {
|
|
|
3115
3264
|
});
|
|
3116
3265
|
continue;
|
|
3117
3266
|
}
|
|
3118
|
-
c.length >
|
|
3267
|
+
c.length > Le ? s.push({
|
|
3119
3268
|
severity: "error",
|
|
3120
3269
|
code: "SDD_TABLE_CELL_TOO_LONG",
|
|
3121
3270
|
file: e,
|
|
3122
|
-
message: `Table cell is ${c.length} chars (> ${
|
|
3123
|
-
}) :
|
|
3271
|
+
message: `Table cell is ${c.length} chars (> ${Le}) — a cell is one short line; move the detail into a subsection below the table (AX_SPEC_TABLE_IS_INDEX): "${c.slice(0, 60)}..."`
|
|
3272
|
+
}) : rn.test(c) && s.push({
|
|
3124
3273
|
severity: "error",
|
|
3125
3274
|
code: "SDD_TABLE_CELL_MULTI_SENTENCE",
|
|
3126
3275
|
file: e,
|
|
@@ -3130,34 +3279,34 @@ function on(e, t) {
|
|
|
3130
3279
|
}
|
|
3131
3280
|
return s;
|
|
3132
3281
|
}
|
|
3133
|
-
function
|
|
3282
|
+
function cr(e) {
|
|
3134
3283
|
const t = g(e, "INTER_MODULE_DEPENDENCIES");
|
|
3135
|
-
return t.status === "ok" ?
|
|
3284
|
+
return t.status === "ok" ? Hs(t.content) : [];
|
|
3136
3285
|
}
|
|
3137
|
-
function
|
|
3286
|
+
function fn(e) {
|
|
3138
3287
|
const t = /\*\*Depends on:\*\*\s*(.*)/i.exec(e);
|
|
3139
3288
|
return t?.[1] ? [...t[1].matchAll(/[a-z][a-z0-9-]*\*?/gi)].map((s) => s[0]) : [];
|
|
3140
3289
|
}
|
|
3141
|
-
function
|
|
3290
|
+
function pn(e, t) {
|
|
3142
3291
|
return e.some((s) => s.endsWith("*") ? t.startsWith(s.slice(0, -1)) : s === t);
|
|
3143
3292
|
}
|
|
3144
|
-
function
|
|
3293
|
+
function lr(e, t, s) {
|
|
3145
3294
|
const n = g(t, "SCOPE_DEPENDENCIES");
|
|
3146
3295
|
if (n.status !== "ok") return [];
|
|
3147
|
-
const
|
|
3148
|
-
if (!
|
|
3149
|
-
const
|
|
3296
|
+
const r = /([^/\\]+)\.(?:spec|1-spec)\.md$/.exec(e)?.[1];
|
|
3297
|
+
if (!r) return [];
|
|
3298
|
+
const o = fn(n.content), i = [];
|
|
3150
3299
|
for (const a of s)
|
|
3151
|
-
a.from ===
|
|
3300
|
+
a.from === r && !pn(o, a.to) && i.push({
|
|
3152
3301
|
severity: "warn",
|
|
3153
3302
|
code: "SDD_SCOPE_DEP_UNDECLARED",
|
|
3154
3303
|
file: e,
|
|
3155
|
-
message: `Portal Scope Graph has \`${
|
|
3304
|
+
message: `Portal Scope Graph has \`${r} --> ${a.to}\` but the scope spec's Scope Dependencies does not list ${a.to} (AX_SCOPE_GRAPH_DISCIPLINE). Add it under "Depends on" (a name or a \`prefix-*\` wildcard), or fix the portal graph.`
|
|
3156
3305
|
});
|
|
3157
3306
|
return i;
|
|
3158
3307
|
}
|
|
3159
|
-
function
|
|
3160
|
-
return
|
|
3308
|
+
function dr(e, t, s) {
|
|
3309
|
+
return te(s) ? [
|
|
3161
3310
|
{
|
|
3162
3311
|
severity: "error",
|
|
3163
3312
|
code: "SDD_MODULE_DAG_CYCLE",
|
|
@@ -3166,47 +3315,47 @@ function tr(e, t, s) {
|
|
|
3166
3315
|
}
|
|
3167
3316
|
] : [];
|
|
3168
3317
|
}
|
|
3169
|
-
function
|
|
3318
|
+
function Ue(e) {
|
|
3170
3319
|
const t = /<!--SECTION:MODULE_VISION-->/.test(e), s = /<!--SECTION:SCOPE_TYPE-->/.test(e) && !t;
|
|
3171
3320
|
return t ? "module" : s ? "scope" : "other";
|
|
3172
3321
|
}
|
|
3173
|
-
function
|
|
3322
|
+
function mn(e, t) {
|
|
3174
3323
|
let s = w(w(e)), n = "";
|
|
3175
3324
|
for (; s !== n; ) {
|
|
3176
|
-
const
|
|
3177
|
-
if (
|
|
3325
|
+
const r = h(s, `${V(s)}.spec.md`);
|
|
3326
|
+
if (r !== e && t.has(r)) return r;
|
|
3178
3327
|
n = s, s = w(s);
|
|
3179
3328
|
}
|
|
3180
3329
|
return null;
|
|
3181
3330
|
}
|
|
3182
|
-
function
|
|
3331
|
+
function En(e, t, s) {
|
|
3183
3332
|
for (const n of e.matchAll(/\]\(([^)`#]+\.spec\.md)(?:#[^)]*)?\)/g)) {
|
|
3184
|
-
const
|
|
3185
|
-
if (
|
|
3333
|
+
const r = n[1];
|
|
3334
|
+
if (r && y(t, r) === y(s)) return !0;
|
|
3186
3335
|
}
|
|
3187
3336
|
return !1;
|
|
3188
3337
|
}
|
|
3189
|
-
function
|
|
3190
|
-
const t = [], s = new Map(e.map((a) => [a.file, a])), n = new Set(e.map((a) => a.file)),
|
|
3191
|
-
for (const a of
|
|
3192
|
-
const c =
|
|
3193
|
-
c &&
|
|
3338
|
+
function ur(e) {
|
|
3339
|
+
const t = [], s = new Map(e.map((a) => [a.file, a])), n = new Set(e.map((a) => a.file)), r = e.filter((a) => Ue(a.content) === "module"), o = /* @__PURE__ */ new Map();
|
|
3340
|
+
for (const a of r) {
|
|
3341
|
+
const c = mn(a.file, n);
|
|
3342
|
+
c && o.set(a.file, c);
|
|
3194
3343
|
}
|
|
3195
|
-
for (const a of
|
|
3196
|
-
const c =
|
|
3344
|
+
for (const a of r) {
|
|
3345
|
+
const c = o.get(a.file);
|
|
3197
3346
|
if (!c) continue;
|
|
3198
3347
|
const l = s.get(c);
|
|
3199
|
-
l && (
|
|
3348
|
+
l && (En(l.content, w(c), a.file) || t.push({
|
|
3200
3349
|
severity: a.flowVersion === "v2" ? "error" : "warn",
|
|
3201
3350
|
code: "SDD_MODULE_NOT_IN_INDEX",
|
|
3202
3351
|
file: c,
|
|
3203
3352
|
message: `Module spec ${a.file} is not linked from its parent index ${c} — every module must appear in the parent's Module Map / links (AX_HIERARCHICAL_SPECS).`
|
|
3204
3353
|
}));
|
|
3205
3354
|
}
|
|
3206
|
-
const i = new Set(
|
|
3355
|
+
const i = new Set(o.values());
|
|
3207
3356
|
for (const a of i) {
|
|
3208
3357
|
const c = s.get(a);
|
|
3209
|
-
if (!(!c ||
|
|
3358
|
+
if (!(!c || Ue(c.content) !== "module"))
|
|
3210
3359
|
for (const l of ["ENTITY_INVENTORY", "MODULE_CONTRACTS"])
|
|
3211
3360
|
new RegExp(`<!--SECTION:${l}-->`).test(c.content) && t.push({
|
|
3212
3361
|
severity: c.flowVersion === "v2" ? "error" : "warn",
|
|
@@ -3217,15 +3366,15 @@ function sr(e) {
|
|
|
3217
3366
|
}
|
|
3218
3367
|
return t;
|
|
3219
3368
|
}
|
|
3220
|
-
const
|
|
3221
|
-
function
|
|
3222
|
-
const s = [], n = g(t, "CHANGE_MANIFEST"),
|
|
3223
|
-
return
|
|
3369
|
+
const hn = /^[ \t]*✚ /m;
|
|
3370
|
+
function fr(e, t) {
|
|
3371
|
+
const s = [], n = g(t, "CHANGE_MANIFEST"), r = n.status === "ok";
|
|
3372
|
+
return hn.test(t) && !r && s.push({
|
|
3224
3373
|
severity: "error",
|
|
3225
3374
|
code: "SDD_REVIEW_INCONSISTENT",
|
|
3226
3375
|
file: e,
|
|
3227
3376
|
message: "Found a ✚ change-mark but no CHANGE_MANIFEST — review-state is malformed (compress half-ran, or marks added without entering review-state). Add the manifest (CHANGE_MANIFEST_FORMAT) or strip the marks. AX_SPEC_LIFECYCLE."
|
|
3228
|
-
}),
|
|
3377
|
+
}), r && (/ТИП ИЗМЕНЕНИЯ/.test(n.content) || s.push({
|
|
3229
3378
|
severity: "error",
|
|
3230
3379
|
code: "SDD_REVIEW_INCONSISTENT",
|
|
3231
3380
|
file: e,
|
|
@@ -3237,35 +3386,35 @@ function nr(e, t) {
|
|
|
3237
3386
|
message: "Spec is in review-state (CHANGE_MANIFEST present). Finalize it: once external review approves («no comments»), run compress — remove the manifest + ✚/~ marks; if the change was abandoned, remove the manifest. A spec must not linger in review-state. AX_SPEC_LIFECYCLE."
|
|
3238
3387
|
})), s;
|
|
3239
3388
|
}
|
|
3240
|
-
let
|
|
3241
|
-
async function
|
|
3242
|
-
if (
|
|
3389
|
+
let q = null;
|
|
3390
|
+
async function Sn() {
|
|
3391
|
+
if (q) return q;
|
|
3243
3392
|
const { JSDOM: e } = await import("jsdom"), t = new e("<!DOCTYPE html><html><body></body></html>"), s = globalThis;
|
|
3244
3393
|
s.window ??= t.window, s.document ??= t.window.document, s.navigator ??= t.window.navigator;
|
|
3245
3394
|
const n = (await import("mermaid")).default;
|
|
3246
|
-
return n.initialize({ startOnLoad: !1 }),
|
|
3395
|
+
return n.initialize({ startOnLoad: !1 }), q = (r) => n.parse(r), q;
|
|
3247
3396
|
}
|
|
3248
|
-
function
|
|
3397
|
+
function gn(e) {
|
|
3249
3398
|
const t = [], s = e.split(`
|
|
3250
3399
|
`);
|
|
3251
|
-
let n = !1,
|
|
3252
|
-
for (const
|
|
3253
|
-
const i =
|
|
3400
|
+
let n = !1, r = [];
|
|
3401
|
+
for (const o of s) {
|
|
3402
|
+
const i = o.trim();
|
|
3254
3403
|
if (!n && i.startsWith("```mermaid")) {
|
|
3255
|
-
n = !0,
|
|
3404
|
+
n = !0, r = [];
|
|
3256
3405
|
continue;
|
|
3257
3406
|
}
|
|
3258
3407
|
if (n && i === "```") {
|
|
3259
|
-
t.push(
|
|
3408
|
+
t.push(r.join(`
|
|
3260
3409
|
`)), n = !1;
|
|
3261
3410
|
continue;
|
|
3262
3411
|
}
|
|
3263
|
-
n &&
|
|
3412
|
+
n && r.push(o);
|
|
3264
3413
|
}
|
|
3265
3414
|
return t;
|
|
3266
3415
|
}
|
|
3267
|
-
async function
|
|
3268
|
-
const t = await
|
|
3416
|
+
async function In(e) {
|
|
3417
|
+
const t = await Sn();
|
|
3269
3418
|
try {
|
|
3270
3419
|
return await t(e), null;
|
|
3271
3420
|
} catch (s) {
|
|
@@ -3273,129 +3422,38 @@ async function pn(e) {
|
|
|
3273
3422
|
`)[0] ?? "invalid" : String(s);
|
|
3274
3423
|
}
|
|
3275
3424
|
}
|
|
3276
|
-
async function
|
|
3277
|
-
const s =
|
|
3425
|
+
async function pr(e, t) {
|
|
3426
|
+
const s = gn(t);
|
|
3278
3427
|
if (s.length === 0) return [];
|
|
3279
3428
|
const n = [];
|
|
3280
|
-
for (const
|
|
3281
|
-
const
|
|
3282
|
-
|
|
3429
|
+
for (const r of s) {
|
|
3430
|
+
const o = await In(r);
|
|
3431
|
+
o !== null && n.push({
|
|
3283
3432
|
severity: "error",
|
|
3284
3433
|
code: "SDD_DIAGRAM_INVALID",
|
|
3285
3434
|
file: e,
|
|
3286
|
-
message: `mermaid diagram does not parse: ${
|
|
3435
|
+
message: `mermaid diagram does not parse: ${o}`
|
|
3287
3436
|
});
|
|
3288
3437
|
}
|
|
3289
3438
|
return n;
|
|
3290
3439
|
}
|
|
3291
|
-
function
|
|
3292
|
-
const t = e.match(/\*{0,2}Task-ID:\*{0,2}\s*`?([A-Za-z0-9][A-Za-z0-9_-]*)`?/), s = e.match(/\*{0,2}Status:\*{0,2}\s*(\[.\]\s*[A-Z_]+)/);
|
|
3293
|
-
return {
|
|
3294
|
-
taskId: t?.[1] ?? null,
|
|
3295
|
-
status: s?.[1] ?? null
|
|
3296
|
-
};
|
|
3297
|
-
}
|
|
3298
|
-
function ct(e) {
|
|
3299
|
-
return e.replace(/`/g, "").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").trim();
|
|
3300
|
-
}
|
|
3301
|
-
function V(e) {
|
|
3302
|
-
return e.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((t) => t.trim());
|
|
3303
|
-
}
|
|
3304
|
-
function rr(e, t, s) {
|
|
3305
|
-
const n = e.split(`
|
|
3306
|
-
`), o = lt(n);
|
|
3307
|
-
if (!o) return { ok: !1, reason: "no_table" };
|
|
3308
|
-
const { headerIdx: r, idCol: i, statusCol: a } = o;
|
|
3309
|
-
for (let c = r + 1; c < n.length; c++) {
|
|
3310
|
-
const l = n[c];
|
|
3311
|
-
if (l === void 0 || !l.trimStart().startsWith("|")) break;
|
|
3312
|
-
const f = V(l);
|
|
3313
|
-
if (/^\|?\s*-+\s*\|/.test(l) || ct(f[i] ?? "") !== t) continue;
|
|
3314
|
-
const d = l.split("|"), u = a + 1;
|
|
3315
|
-
if (d[u] === void 0) return { ok: !1, reason: "no_table" };
|
|
3316
|
-
const p = d[u];
|
|
3317
|
-
return d[u] = ` ${s} `, d[u] === p ? { ok: !0, text: e, changed: !1 } : (n[c] = d.join("|"), { ok: !0, text: n.join(`
|
|
3318
|
-
`), changed: !0 });
|
|
3319
|
-
}
|
|
3320
|
-
return { ok: !1, reason: "task_not_found" };
|
|
3321
|
-
}
|
|
3322
|
-
function lt(e) {
|
|
3323
|
-
for (let t = 0; t < e.length; t++) {
|
|
3324
|
-
const s = e[t];
|
|
3325
|
-
if (s === void 0 || !s.trimStart().startsWith("|")) continue;
|
|
3326
|
-
const n = V(s).map((i) => i.toLowerCase()), o = n.indexOf("task-id"), r = n.indexOf("status");
|
|
3327
|
-
if (o !== -1 && r !== -1) return { headerIdx: t, idCol: o, statusCol: r };
|
|
3328
|
-
}
|
|
3329
|
-
return null;
|
|
3330
|
-
}
|
|
3331
|
-
function ir(e) {
|
|
3332
|
-
const t = e.split(`
|
|
3333
|
-
`), s = lt(t);
|
|
3334
|
-
if (!s) return [];
|
|
3335
|
-
const n = [];
|
|
3336
|
-
for (let o = s.headerIdx + 1; o < t.length; o++) {
|
|
3337
|
-
const r = t[o];
|
|
3338
|
-
if (r === void 0 || !r.trimStart().startsWith("|")) break;
|
|
3339
|
-
if (/^\|?\s*-+\s*\|/.test(r)) continue;
|
|
3340
|
-
const i = V(r), a = ct(i[s.idCol] ?? "");
|
|
3341
|
-
a && n.push({ taskId: a, status: (i[s.statusCol] ?? "").trim() });
|
|
3342
|
-
}
|
|
3343
|
-
return n;
|
|
3344
|
-
}
|
|
3345
|
-
function mn(e) {
|
|
3346
|
-
return /^\[x\]/i.test(e.trim());
|
|
3347
|
-
}
|
|
3348
|
-
function En(e) {
|
|
3349
|
-
for (let t = 0; t < e.length; t++) {
|
|
3350
|
-
const s = e[t];
|
|
3351
|
-
if (s === void 0 || !s.trimStart().startsWith("|")) continue;
|
|
3352
|
-
const n = V(s).map((a) => a.toLowerCase()), o = n.indexOf("index"), r = n.indexOf("tasks"), i = n.indexOf("done") !== -1 ? n.indexOf("done") : n.indexOf("progress");
|
|
3353
|
-
if (o !== -1 && r !== -1 && i !== -1)
|
|
3354
|
-
return { headerIdx: t, indexCol: o, tasksCol: r, doneCol: i };
|
|
3355
|
-
}
|
|
3356
|
-
return null;
|
|
3357
|
-
}
|
|
3358
|
-
function hn(e) {
|
|
3359
|
-
return e.match(/\[[^\]]*\]\(([^)]+)\)/)?.[1] ?? null;
|
|
3360
|
-
}
|
|
3361
|
-
function ar(e, t) {
|
|
3362
|
-
const s = e.split(`
|
|
3363
|
-
`), n = En(s);
|
|
3364
|
-
if (!n) return { text: e, updated: [] };
|
|
3365
|
-
const o = [];
|
|
3366
|
-
for (let r = n.headerIdx + 1; r < s.length; r++) {
|
|
3367
|
-
const i = s[r];
|
|
3368
|
-
if (i === void 0 || !i.trimStart().startsWith("|")) break;
|
|
3369
|
-
if (/^\|?\s*-+\s*\|/.test(i)) continue;
|
|
3370
|
-
const a = V(i), c = hn(a[n.indexCol] ?? "");
|
|
3371
|
-
if (!c) continue;
|
|
3372
|
-
const l = t(c);
|
|
3373
|
-
if (!l) continue;
|
|
3374
|
-
const f = l.filter((_) => mn(_.status)).length, d = l.length, u = i.split("|"), p = n.tasksCol + 1, m = n.doneCol + 1;
|
|
3375
|
-
if (u[p] === void 0 || u[m] === void 0) continue;
|
|
3376
|
-
const E = ` ${d} `, S = ` ${f}/${d} `;
|
|
3377
|
-
u[p] === E && u[m] === S || (u[p] = E, u[m] = S, s[r] = u.join("|"), o.push(c));
|
|
3378
|
-
}
|
|
3379
|
-
return { text: s.join(`
|
|
3380
|
-
`), updated: o };
|
|
3381
|
-
}
|
|
3382
|
-
function cr(e, t, s) {
|
|
3440
|
+
function mr(e, t, s) {
|
|
3383
3441
|
const n = y(w(y(e)), s);
|
|
3384
3442
|
return x(y(t), n).split(b).join("/");
|
|
3385
3443
|
}
|
|
3386
|
-
function
|
|
3444
|
+
function Er(e) {
|
|
3387
3445
|
const t = /<DependsOn>([\s\S]*?)<\/DependsOn>/.exec(e);
|
|
3388
3446
|
return t?.[1] ? [...t[1].matchAll(/^\s*-\s+(\S+)/gm)].map((s) => s[1]) : [];
|
|
3389
3447
|
}
|
|
3390
|
-
function
|
|
3448
|
+
function hr(e, t, s, n) {
|
|
3391
3449
|
if (s.length === 0) return [];
|
|
3392
|
-
const
|
|
3450
|
+
const r = new Set(s), o = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = [...s];
|
|
3393
3451
|
for (; a.length; ) {
|
|
3394
3452
|
const c = a.pop();
|
|
3395
|
-
if (!
|
|
3396
|
-
|
|
3453
|
+
if (!o.has(c)) {
|
|
3454
|
+
o.add(c);
|
|
3397
3455
|
for (const l of n.get(c) ?? [])
|
|
3398
|
-
|
|
3456
|
+
r.has(l) || i.add(l), o.has(l) || a.push(l);
|
|
3399
3457
|
}
|
|
3400
3458
|
}
|
|
3401
3459
|
return [...i].map((c) => ({
|
|
@@ -3405,87 +3463,87 @@ function dr(e, t, s, n) {
|
|
|
3405
3463
|
message: `Phase ${t}: rule dependency "${c}" is required transitively but is not in the phase's Rules: list — the closure over <DependsOn> is incomplete.`
|
|
3406
3464
|
}));
|
|
3407
3465
|
}
|
|
3408
|
-
function
|
|
3466
|
+
function Fe(e) {
|
|
3409
3467
|
const t = /@tasks:\s*(.+)/.exec(e);
|
|
3410
3468
|
return t?.[1] ? t[1].split(",").map((s) => s.trim()).filter((s) => s.length > 0 && !/^n\/a$/i.test(s)) : [];
|
|
3411
3469
|
}
|
|
3412
|
-
function
|
|
3470
|
+
function Sr(e, t, s) {
|
|
3413
3471
|
if (s === null) return [];
|
|
3414
|
-
const n =
|
|
3415
|
-
return
|
|
3472
|
+
const n = Fe(s), r = new Set(Fe(t)), o = n.filter((i) => !r.has(i));
|
|
3473
|
+
return o.length === 0 ? [] : [
|
|
3416
3474
|
{
|
|
3417
3475
|
severity: "error",
|
|
3418
3476
|
code: "SDD_TASKS_APPEND_ONLY_REGRESSION",
|
|
3419
3477
|
file: e,
|
|
3420
|
-
message: `@tasks: header dropped previously-declared id(s): ${
|
|
3478
|
+
message: `@tasks: header dropped previously-declared id(s): ${o.join(", ")} — the header is append-only, ids are never removed.`
|
|
3421
3479
|
}
|
|
3422
3480
|
];
|
|
3423
3481
|
}
|
|
3424
|
-
function
|
|
3482
|
+
function On(e) {
|
|
3425
3483
|
const t = [];
|
|
3426
3484
|
let s = 0, n = 0;
|
|
3427
|
-
for (let
|
|
3428
|
-
const
|
|
3429
|
-
|
|
3485
|
+
for (let r = 0; r < e.length; r++) {
|
|
3486
|
+
const o = e[r];
|
|
3487
|
+
o === "(" ? s++ : o === ")" ? s = Math.max(0, s - 1) : o === "," && s === 0 && (t.push(e.slice(n, r).trim()), n = r + 1);
|
|
3430
3488
|
}
|
|
3431
|
-
return t.push(e.slice(n).trim()), t.filter((
|
|
3489
|
+
return t.push(e.slice(n).trim()), t.filter((r) => r.length > 0);
|
|
3432
3490
|
}
|
|
3433
|
-
function
|
|
3491
|
+
function gr(e) {
|
|
3434
3492
|
const t = /@consumers:\s*(.+)/.exec(e);
|
|
3435
|
-
return t?.[1] ?
|
|
3493
|
+
return t?.[1] ? On(t[1]) : [];
|
|
3436
3494
|
}
|
|
3437
|
-
function
|
|
3495
|
+
function Ir(e) {
|
|
3438
3496
|
const t = e.trim(), s = t.replace(/\s*\([^)]*\)\s*$/, "").trim(), n = s.length === 0 || /\s/.test(s) || /\bexternal\b/i.test(t);
|
|
3439
3497
|
return { raw: t, name: s, external: n };
|
|
3440
3498
|
}
|
|
3441
|
-
function
|
|
3499
|
+
function Or(e, t, s) {
|
|
3442
3500
|
const n = [];
|
|
3443
|
-
for (const
|
|
3444
|
-
|
|
3501
|
+
for (const r of t)
|
|
3502
|
+
r.external || s.has(r.name) || n.push({
|
|
3445
3503
|
severity: "warn",
|
|
3446
3504
|
code: "SDD_CONSUMERS_UNRESOLVED",
|
|
3447
3505
|
file: e,
|
|
3448
|
-
message: `@consumers: entry "${
|
|
3506
|
+
message: `@consumers: entry "${r.name}" was not found referenced elsewhere in the codebase (text search) — mark it external in the description if it lives outside this repo, or fix the name.`
|
|
3449
3507
|
});
|
|
3450
3508
|
return n;
|
|
3451
3509
|
}
|
|
3452
|
-
function
|
|
3453
|
-
const t = /^-\s*Deferred Test Ownership:\s*(\S+)\s*(.*)$/.exec(e), s = t?.[1] ?? null, n = t ? t[2] ?? "" : e.replace(/^-\s*/, ""),
|
|
3454
|
-
if (!
|
|
3455
|
-
const
|
|
3456
|
-
return !i || a.length === 0 ? null : { scenario:
|
|
3510
|
+
function ft(e) {
|
|
3511
|
+
const t = /^-\s*Deferred Test Ownership:\s*(\S+)\s*(.*)$/.exec(e), s = t?.[1] ?? null, n = t ? t[2] ?? "" : e.replace(/^-\s*/, ""), r = /^(.+?)\s*→\s*`([^`]+)`\s*::\s*(.+?)\.?\s*$/.exec(n);
|
|
3512
|
+
if (!r) return null;
|
|
3513
|
+
const o = (r[1] ?? "").replace(/`\[[^\]]+\]`|\[[^\]]+\]/g, "").trim(), i = (r[2] ?? "").trim(), a = [...(r[3] ?? "").matchAll(/`([^`]+)`/g)].map((c) => c[1]);
|
|
3514
|
+
return !i || a.length === 0 ? null : { scenario: o, testFile: i, caseNames: a, deferred: s };
|
|
3457
3515
|
}
|
|
3458
|
-
function
|
|
3516
|
+
function Tr(e) {
|
|
3459
3517
|
const t = [];
|
|
3460
3518
|
for (const s of e.split(`
|
|
3461
3519
|
`)) {
|
|
3462
3520
|
const n = s.trim();
|
|
3463
3521
|
if (!n.startsWith("-")) continue;
|
|
3464
|
-
const
|
|
3465
|
-
|
|
3522
|
+
const r = ft(n);
|
|
3523
|
+
r && t.push(r);
|
|
3466
3524
|
}
|
|
3467
3525
|
return t;
|
|
3468
3526
|
}
|
|
3469
|
-
function
|
|
3527
|
+
function Tn(e) {
|
|
3470
3528
|
const t = [];
|
|
3471
3529
|
for (const s of e.split(`
|
|
3472
3530
|
`)) {
|
|
3473
3531
|
const n = s.trim();
|
|
3474
|
-
n.startsWith("-") && (
|
|
3532
|
+
n.startsWith("-") && (ft(n) || t.push(n));
|
|
3475
3533
|
}
|
|
3476
3534
|
return t;
|
|
3477
3535
|
}
|
|
3478
|
-
function
|
|
3536
|
+
function _r(e) {
|
|
3479
3537
|
const t = [], s = /\b(?:it|test)(?:\.\w+)?\s*\(\s*(['"`])((?:\\.|(?!\1).)*)\1/g;
|
|
3480
3538
|
for (const n of e.matchAll(s))
|
|
3481
3539
|
n[2] !== void 0 && t.push(n[2]);
|
|
3482
3540
|
return t;
|
|
3483
3541
|
}
|
|
3484
|
-
function
|
|
3542
|
+
function Nr(e, t) {
|
|
3485
3543
|
const s = t.replace(/\\/g, "/"), n = `/${s}`;
|
|
3486
|
-
return e.filter((
|
|
3544
|
+
return e.filter((r) => r === s || r.endsWith(n));
|
|
3487
3545
|
}
|
|
3488
|
-
function
|
|
3546
|
+
function Cr(e, t, s) {
|
|
3489
3547
|
return s.length <= 1 ? [] : [
|
|
3490
3548
|
{
|
|
3491
3549
|
severity: "warn",
|
|
@@ -3495,31 +3553,31 @@ function gr(e, t, s) {
|
|
|
3495
3553
|
}
|
|
3496
3554
|
];
|
|
3497
3555
|
}
|
|
3498
|
-
function
|
|
3499
|
-
const
|
|
3556
|
+
function Dr(e, t, s, n = "v1", r = null) {
|
|
3557
|
+
const o = [], i = n === "v2" ? "error" : "warn";
|
|
3500
3558
|
for (const a of t) {
|
|
3501
3559
|
if (a.deferred !== null) {
|
|
3502
|
-
|
|
3560
|
+
r !== null && a.deferred === r && o.push({
|
|
3503
3561
|
severity: "error",
|
|
3504
3562
|
code: "SDD_BDD_DEFERRED_TO_SELF",
|
|
3505
3563
|
file: e,
|
|
3506
|
-
message: `Scenario "${a.scenario}" defers test ownership to this ticket's own Task-ID (${
|
|
3564
|
+
message: `Scenario "${a.scenario}" defers test ownership to this ticket's own Task-ID (${r}) — that hides missing coverage instead of delegating it to another ticket.`
|
|
3507
3565
|
});
|
|
3508
3566
|
continue;
|
|
3509
3567
|
}
|
|
3510
3568
|
const c = s.get(a.testFile) ?? [];
|
|
3511
3569
|
for (const l of a.caseNames)
|
|
3512
|
-
c.includes(l) ||
|
|
3570
|
+
c.includes(l) || o.push({
|
|
3513
3571
|
severity: i,
|
|
3514
3572
|
code: "SDD_BDD_SCENARIO_UNTESTED",
|
|
3515
3573
|
file: e,
|
|
3516
3574
|
message: `Scenario "${a.scenario}" claims case "${l}" in ${a.testFile}, but no it()/test() with that exact name was found there.`
|
|
3517
3575
|
});
|
|
3518
3576
|
}
|
|
3519
|
-
return
|
|
3577
|
+
return o;
|
|
3520
3578
|
}
|
|
3521
|
-
function
|
|
3522
|
-
return
|
|
3579
|
+
function Ar(e, t) {
|
|
3580
|
+
return Tn(t).map(
|
|
3523
3581
|
(s) => ({
|
|
3524
3582
|
severity: "warn",
|
|
3525
3583
|
code: "SDD_BDD_COVERAGE_ROW_UNPARSED",
|
|
@@ -3528,7 +3586,7 @@ function Or(e, t) {
|
|
|
3528
3586
|
})
|
|
3529
3587
|
);
|
|
3530
3588
|
}
|
|
3531
|
-
const
|
|
3589
|
+
const Se = ["PLANNED", "MAPPED", "APPROVED", "DONE"], fe = ["keep", "rename", "merge", "split", "create", "drop"], Z = "UNMAPPED", _n = [
|
|
3532
3590
|
{ match: /^scope-type$/i, section: "SCOPE_TYPE" },
|
|
3533
3591
|
{ match: /^vision(\s*&\s*primary goal)?$/i, section: "VISION" },
|
|
3534
3592
|
{ match: /^module vision$/i, section: "MODULE_VISION" },
|
|
@@ -3559,27 +3617,27 @@ const Ee = ["PLANNED", "MAPPED", "APPROVED", "DONE"], de = ["keep", "rename", "m
|
|
|
3559
3617
|
{ match: /^module contracts(\s*\(.*\))?$/i, section: "MODULE_CONTRACTS" },
|
|
3560
3618
|
{ match: /^public options(\s*&\s*policies)?$/i, section: "PUBLIC_OPTIONS" }
|
|
3561
3619
|
];
|
|
3562
|
-
function
|
|
3620
|
+
function Nn(e) {
|
|
3563
3621
|
const t = e.replace(/^#{2,3}\s*/, "").replace(/^\d+(\.\d+)*\.?\s+/, "").trim();
|
|
3564
|
-
for (const s of
|
|
3622
|
+
for (const s of _n)
|
|
3565
3623
|
if (s.match.test(t)) return s.section;
|
|
3566
|
-
return
|
|
3624
|
+
return Z;
|
|
3567
3625
|
}
|
|
3568
|
-
const
|
|
3569
|
-
function
|
|
3626
|
+
const Cn = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", "out", "coverage"]);
|
|
3627
|
+
function pe(e, t, s) {
|
|
3570
3628
|
let n;
|
|
3571
3629
|
try {
|
|
3572
|
-
n =
|
|
3630
|
+
n = B(e, { withFileTypes: !0 });
|
|
3573
3631
|
} catch {
|
|
3574
3632
|
return;
|
|
3575
3633
|
}
|
|
3576
|
-
for (const
|
|
3577
|
-
if (
|
|
3578
|
-
const
|
|
3579
|
-
|
|
3634
|
+
for (const r of n) {
|
|
3635
|
+
if (r.name.startsWith(".") || Cn.has(r.name) || r.isSymbolicLink()) continue;
|
|
3636
|
+
const o = h(e, r.name);
|
|
3637
|
+
r.isDirectory() ? pe(o, t, s) : r.isFile() && t(r.name) && s.push(o);
|
|
3580
3638
|
}
|
|
3581
3639
|
}
|
|
3582
|
-
function
|
|
3640
|
+
function Dn(e) {
|
|
3583
3641
|
const t = [];
|
|
3584
3642
|
let s = !1;
|
|
3585
3643
|
for (const n of e.split(`
|
|
@@ -3592,42 +3650,42 @@ function _n(e) {
|
|
|
3592
3650
|
}
|
|
3593
3651
|
return t;
|
|
3594
3652
|
}
|
|
3595
|
-
function
|
|
3653
|
+
function An(e) {
|
|
3596
3654
|
const t = /* @__PURE__ */ new Set();
|
|
3597
3655
|
for (const s of e.matchAll(/<!--SECTION:([A-Z][A-Z0-9_]*)-->/g))
|
|
3598
3656
|
s[1] && t.add(s[1]);
|
|
3599
3657
|
return [...t];
|
|
3600
3658
|
}
|
|
3601
|
-
function
|
|
3659
|
+
function yn(e) {
|
|
3602
3660
|
const t = g(e, "SCOPE_TYPE");
|
|
3603
3661
|
return t.status !== "ok" ? null : /\b(product|library|infrastructure|interface)\b/.exec(t.content)?.[1] ?? null;
|
|
3604
3662
|
}
|
|
3605
|
-
function
|
|
3663
|
+
function Rn(e, t) {
|
|
3606
3664
|
let s = "";
|
|
3607
3665
|
try {
|
|
3608
|
-
s =
|
|
3666
|
+
s = C(t, "utf-8");
|
|
3609
3667
|
} catch {
|
|
3610
3668
|
}
|
|
3611
|
-
const n = g(s, "META"),
|
|
3669
|
+
const n = g(s, "META"), r = n.status === "ok" ? n.content : /##[^\n]*\bMeta\b[^\n]*\n([\s\S]*?)(?=\n## |$)/.exec(s)?.[1] ?? "", o = nt(r), i = /\*{0,2}Purpose:\*{0,2}\s*([^\n]+)/.exec(r)?.[1]?.trim() ?? null, a = /\*{0,2}Scope:\*{0,2}\s*`?([\w./-]+)`?/.exec(r)?.[1] ?? null, c = /\*{0,2}Module:\*{0,2}\s*`?([\w./-]+)`?/.exec(r)?.[1] ?? null;
|
|
3612
3670
|
return {
|
|
3613
3671
|
ticket: {
|
|
3614
3672
|
file: x(e, t),
|
|
3615
|
-
taskId:
|
|
3616
|
-
status:
|
|
3673
|
+
taskId: o.taskId,
|
|
3674
|
+
status: o.status,
|
|
3617
3675
|
purpose: i
|
|
3618
3676
|
},
|
|
3619
3677
|
scope: a,
|
|
3620
3678
|
module: c
|
|
3621
3679
|
};
|
|
3622
3680
|
}
|
|
3623
|
-
function
|
|
3681
|
+
function ge(e) {
|
|
3624
3682
|
const t = h(e, "specs"), s = [];
|
|
3625
|
-
|
|
3683
|
+
pe(t, (i) => i.endsWith(".spec.md") || i.endsWith(".1-spec.md"), s), s.sort();
|
|
3626
3684
|
const n = [];
|
|
3627
3685
|
for (const i of s) {
|
|
3628
3686
|
const a = x(e, i), c = a.split(b), l = c[1];
|
|
3629
3687
|
if (!l || c.length < 3) continue;
|
|
3630
|
-
const f = c.length >= 4 ? c[c.length - 2] ?? null : null, d =
|
|
3688
|
+
const f = c.length >= 4 ? c[c.length - 2] ?? null : null, d = C(i, "utf-8"), u = f !== null, p = yn(d), m = u ? ["MODULE_VISION", "OVERVIEW", ...ut.filter((E) => E !== "MODULE_VISION")] : ["OVERVIEW", ...p ? de[p] ?? [] : []];
|
|
3631
3689
|
n.push({
|
|
3632
3690
|
specFile: a,
|
|
3633
3691
|
scope: l,
|
|
@@ -3636,27 +3694,27 @@ function he(e) {
|
|
|
3636
3694
|
lines: d.split(`
|
|
3637
3695
|
`).length,
|
|
3638
3696
|
mermaidCount: (d.match(/^\s*```mermaid/gm) ?? []).length,
|
|
3639
|
-
anchors:
|
|
3640
|
-
headings:
|
|
3697
|
+
anchors: An(d),
|
|
3698
|
+
headings: Dn(d),
|
|
3641
3699
|
tickets: [],
|
|
3642
3700
|
targetSections: [...new Set(m)],
|
|
3643
|
-
foldSections: u ? [...
|
|
3701
|
+
foldSections: u ? [...ue] : []
|
|
3644
3702
|
});
|
|
3645
3703
|
}
|
|
3646
|
-
const o = [];
|
|
3647
|
-
ue(h(e, "tasks"), (i) => /\.task-[0-9]+\.md$/.test(i), o), o.sort();
|
|
3648
3704
|
const r = [];
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3705
|
+
pe(h(e, "tasks"), (i) => /\.task-[0-9]+\.md$/.test(i), r), r.sort();
|
|
3706
|
+
const o = [];
|
|
3707
|
+
for (const i of r) {
|
|
3708
|
+
const a = x(e, i), c = a.split(b)[1] ?? "", { ticket: l, scope: f, module: d } = Rn(e, i), u = a.split(b).length >= 4 ? a.split(b)[2] : null, p = n.filter((I) => I.scope === c), m = d ? p.find((I) => I.module === d) : void 0, E = u ? p.find((I) => I.module === u) : void 0, S = f ? p.find((I) => I.module === f) : void 0, _ = p.find((I) => I.module === null), N = m ?? E ?? S ?? _;
|
|
3709
|
+
N ? N.tickets.push(l) : o.push(l);
|
|
3652
3710
|
}
|
|
3653
|
-
return { units: n, orphanTickets:
|
|
3711
|
+
return { units: n, orphanTickets: o };
|
|
3654
3712
|
}
|
|
3655
|
-
function
|
|
3656
|
-
const t = w(e.specFile).split(b).slice(1).join(b), s =
|
|
3713
|
+
function se(e) {
|
|
3714
|
+
const t = w(e.specFile).split(b).slice(1).join(b), s = V(e.specFile).replace(/\.md$/, ".migration.md");
|
|
3657
3715
|
return h("migration", t, s);
|
|
3658
3716
|
}
|
|
3659
|
-
function
|
|
3717
|
+
function pt(e) {
|
|
3660
3718
|
const t = [
|
|
3661
3719
|
"## Inventory",
|
|
3662
3720
|
"",
|
|
@@ -3677,29 +3735,29 @@ function ut(e) {
|
|
|
3677
3735
|
return e.tickets.length === 0 && t.push(" - (нет)"), t.join(`
|
|
3678
3736
|
`);
|
|
3679
3737
|
}
|
|
3680
|
-
function
|
|
3738
|
+
function kn(e) {
|
|
3681
3739
|
const t = [
|
|
3682
3740
|
"## Section Map",
|
|
3683
3741
|
"",
|
|
3684
3742
|
"<!-- Предзаполнено `sdd-migrate plan` по курируемым правилам (mapHeadingToSection). Агент правит",
|
|
3685
3743
|
" только строки с целью UNMAPPED — остальные пересматривает лишь если правило ошиблось.",
|
|
3686
|
-
` Действия: ${
|
|
3744
|
+
` Действия: ${fe.join(" | ")}. Каждая обязательная целевая секция должна появиться в колонке «Цель».`,
|
|
3687
3745
|
" Полный целевой порядок секций — в format-файле структуры (ai/directives/sdd-v2/formats/*-spec-structure.xml). -->",
|
|
3688
3746
|
"",
|
|
3689
3747
|
"| Источник | Действие | Цель (SECTION) | Комментарий |",
|
|
3690
3748
|
"|---|---|---|---|"
|
|
3691
3749
|
], s = /* @__PURE__ */ new Set();
|
|
3692
3750
|
for (const n of e.headings) {
|
|
3693
|
-
const
|
|
3694
|
-
|
|
3751
|
+
const r = Nn(n);
|
|
3752
|
+
r === Z ? t.push(`| \`${n}\` | ? | ${Z} | не распознано правилом — решает агент |`) : (s.add(r), t.push(`| \`${n}\` | keep | ${r} | предзаполнено правилом |`));
|
|
3695
3753
|
}
|
|
3696
3754
|
for (const n of e.targetSections)
|
|
3697
3755
|
s.has(n) || t.push(`| — | create | ${n} | если не покрыта строками выше — создать |`);
|
|
3698
3756
|
return t.join(`
|
|
3699
3757
|
`);
|
|
3700
3758
|
}
|
|
3701
|
-
function
|
|
3702
|
-
const t =
|
|
3759
|
+
function vn(e) {
|
|
3760
|
+
const t = V(e.specFile).replace(/\.(1-spec|spec)\.md$/, ""), n = [
|
|
3703
3761
|
"## Ticket Map",
|
|
3704
3762
|
"",
|
|
3705
3763
|
"<!-- Новый ID: `<ACR>-<slug>` — kebab-case, слаг из Meta.Purpose, уникален в рамках всего репо.",
|
|
@@ -3708,11 +3766,11 @@ function yn(e) {
|
|
|
3708
3766
|
"| Файл | Task-ID | Новый ID | Назначение |",
|
|
3709
3767
|
"|---|---|---|---|"
|
|
3710
3768
|
];
|
|
3711
|
-
for (const
|
|
3769
|
+
for (const r of e.tickets) n.push(`| \`${r.file}\` | ${r.taskId ?? "—"} | ? | ? |`);
|
|
3712
3770
|
return e.tickets.length === 0 && n.push("| (нет тикетов) | — | — | — |"), n.join(`
|
|
3713
3771
|
`);
|
|
3714
3772
|
}
|
|
3715
|
-
function
|
|
3773
|
+
function wn(e) {
|
|
3716
3774
|
return [
|
|
3717
3775
|
"## Diagram Plan",
|
|
3718
3776
|
"",
|
|
@@ -3725,7 +3783,7 @@ function Rn(e) {
|
|
|
3725
3783
|
].join(`
|
|
3726
3784
|
`);
|
|
3727
3785
|
}
|
|
3728
|
-
function
|
|
3786
|
+
function Pn(e) {
|
|
3729
3787
|
return [
|
|
3730
3788
|
"## Steps",
|
|
3731
3789
|
"",
|
|
@@ -3742,37 +3800,37 @@ function kn(e) {
|
|
|
3742
3800
|
].join(`
|
|
3743
3801
|
`);
|
|
3744
3802
|
}
|
|
3745
|
-
function
|
|
3803
|
+
function yr(e) {
|
|
3746
3804
|
return [
|
|
3747
3805
|
`# План миграции: ${e.specFile}`,
|
|
3748
3806
|
"",
|
|
3749
|
-
`- **Status:** PLANNED <!-- ${
|
|
3807
|
+
`- **Status:** PLANNED <!-- ${Se.join(" → ")} -->`,
|
|
3750
3808
|
`- **Scope:** ${e.scope}${e.module ? ` | **Module:** ${e.module}` : ""}`,
|
|
3751
3809
|
"",
|
|
3752
3810
|
"<!--SECTION:INVENTORY-->",
|
|
3753
|
-
|
|
3811
|
+
pt(e),
|
|
3754
3812
|
"<!--/SECTION:INVENTORY-->",
|
|
3755
3813
|
"",
|
|
3756
3814
|
"<!--SECTION:SECTION_MAP-->",
|
|
3757
|
-
|
|
3815
|
+
kn(e),
|
|
3758
3816
|
"<!--/SECTION:SECTION_MAP-->",
|
|
3759
3817
|
"",
|
|
3760
3818
|
"<!--SECTION:TICKET_MAP-->",
|
|
3761
|
-
|
|
3819
|
+
vn(e),
|
|
3762
3820
|
"<!--/SECTION:TICKET_MAP-->",
|
|
3763
3821
|
"",
|
|
3764
3822
|
"<!--SECTION:DIAGRAM_PLAN-->",
|
|
3765
|
-
|
|
3823
|
+
wn(e),
|
|
3766
3824
|
"<!--/SECTION:DIAGRAM_PLAN-->",
|
|
3767
3825
|
"",
|
|
3768
3826
|
"<!--SECTION:STEPS-->",
|
|
3769
|
-
|
|
3827
|
+
Pn(e),
|
|
3770
3828
|
"<!--/SECTION:STEPS-->",
|
|
3771
3829
|
""
|
|
3772
3830
|
].join(`
|
|
3773
3831
|
`);
|
|
3774
3832
|
}
|
|
3775
|
-
function
|
|
3833
|
+
function Rr(e) {
|
|
3776
3834
|
const t = [
|
|
3777
3835
|
"# Миграция v1 → v2 — план",
|
|
3778
3836
|
"",
|
|
@@ -3796,7 +3854,7 @@ function _r(e) {
|
|
|
3796
3854
|
"|---|---|---|"
|
|
3797
3855
|
];
|
|
3798
3856
|
for (const s of e.units)
|
|
3799
|
-
t.push(`| \`${
|
|
3857
|
+
t.push(`| \`${se(s)}\` | \`${s.specFile}\` | ${s.tickets.length} |`);
|
|
3800
3858
|
if (e.orphanTickets.length > 0) {
|
|
3801
3859
|
t.push("", "## ⚠ Тикеты без юнита", ""), t.push("Их scope не имеет спеки — решить с оператором до старта:", "");
|
|
3802
3860
|
for (const s of e.orphanTickets) t.push(`- \`${s.file}\` (${s.taskId ?? "—"})`);
|
|
@@ -3804,14 +3862,14 @@ function _r(e) {
|
|
|
3804
3862
|
return t.push(""), t.join(`
|
|
3805
3863
|
`);
|
|
3806
3864
|
}
|
|
3807
|
-
function
|
|
3865
|
+
function Ln(e) {
|
|
3808
3866
|
const s = /\*\*Status:\*\*\s*([A-Z]+)/.exec(e)?.[1];
|
|
3809
|
-
return s &&
|
|
3867
|
+
return s && Se.includes(s) ? s : null;
|
|
3810
3868
|
}
|
|
3811
|
-
function
|
|
3869
|
+
function bn(e) {
|
|
3812
3870
|
return e.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((t) => t.trim());
|
|
3813
3871
|
}
|
|
3814
|
-
function
|
|
3872
|
+
function z(e) {
|
|
3815
3873
|
const t = [];
|
|
3816
3874
|
let s = !1;
|
|
3817
3875
|
for (const n of e.split(`
|
|
@@ -3821,67 +3879,67 @@ function X(e) {
|
|
|
3821
3879
|
s = !0;
|
|
3822
3880
|
continue;
|
|
3823
3881
|
}
|
|
3824
|
-
/^\|?\s*-+\s*\|/.test(n) || t.push(
|
|
3882
|
+
/^\|?\s*-+\s*\|/.test(n) || t.push(bn(n));
|
|
3825
3883
|
}
|
|
3826
3884
|
return t;
|
|
3827
3885
|
}
|
|
3828
|
-
function
|
|
3886
|
+
function D(e) {
|
|
3829
3887
|
return e.replace(/^`|`$/g, "").trim();
|
|
3830
3888
|
}
|
|
3831
|
-
const
|
|
3832
|
-
function
|
|
3889
|
+
const mt = /^[A-Z][A-Z0-9]*(-[a-z0-9]+)+$/;
|
|
3890
|
+
function Ge(e) {
|
|
3833
3891
|
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3834
3892
|
}
|
|
3835
|
-
function
|
|
3836
|
-
const n = [],
|
|
3893
|
+
function Mn(e, t, s) {
|
|
3894
|
+
const n = [], r = (d, u) => {
|
|
3837
3895
|
n.push({ severity: "error", code: d, file: e, message: u });
|
|
3838
|
-
},
|
|
3839
|
-
if (
|
|
3840
|
-
return
|
|
3896
|
+
}, o = Ln(t);
|
|
3897
|
+
if (o === null)
|
|
3898
|
+
return r(
|
|
3841
3899
|
"MIG_STATUS_INVALID",
|
|
3842
|
-
`Строка **Status:** отсутствует или несёт неизвестный токен — допустимо: ${
|
|
3900
|
+
`Строка **Status:** отсутствует или несёт неизвестный токен — допустимо: ${Se.join(" / ")}.`
|
|
3843
3901
|
), n;
|
|
3844
|
-
const i =
|
|
3845
|
-
a.status !== "ok" ?
|
|
3902
|
+
const i = o !== "PLANNED", a = g(t, "INVENTORY");
|
|
3903
|
+
a.status !== "ok" ? r("MIG_INVENTORY_MISSING", "Секция INVENTORY отсутствует или разбалансирована.") : a.content.trim() !== pt(s).trim() && r(
|
|
3846
3904
|
"MIG_INVENTORY_DRIFT",
|
|
3847
3905
|
"Inventory разошёлся с реальностью (спека или тикеты изменились после генерации плана) — перегенерируй юнит: sdd-migrate plan --all --write."
|
|
3848
3906
|
);
|
|
3849
3907
|
const c = g(t, "SECTION_MAP");
|
|
3850
3908
|
if (c.status !== "ok")
|
|
3851
|
-
|
|
3909
|
+
r("MIG_SECTION_MAP_MISSING", "Секция SECTION_MAP отсутствует или разбалансирована.");
|
|
3852
3910
|
else {
|
|
3853
|
-
const d =
|
|
3911
|
+
const d = z(c.content), p = d.filter((m) => D(m[0] ?? "") !== "—").map((m) => D(m[0] ?? ""));
|
|
3854
3912
|
for (const m of s.headings) {
|
|
3855
3913
|
const E = p.filter((S) => S === m).length;
|
|
3856
|
-
E === 0 &&
|
|
3914
|
+
E === 0 && r("MIG_SECTION_UNMAPPED", `Заголовок из Inventory без строки в Section Map: \`${m}\`.`), E > 1 && r(
|
|
3857
3915
|
"MIG_SECTION_DUPLICATED",
|
|
3858
3916
|
`Заголовок отображён ${E} раз(а): \`${m}\` — нужна ровно одна строка.`
|
|
3859
3917
|
);
|
|
3860
3918
|
}
|
|
3861
3919
|
for (const m of p)
|
|
3862
|
-
s.headings.includes(m) ||
|
|
3920
|
+
s.headings.includes(m) || r(
|
|
3863
3921
|
"MIG_SECTION_UNKNOWN",
|
|
3864
3922
|
`Строка Section Map ссылается на несуществующий заголовок: \`${m}\`.`
|
|
3865
3923
|
);
|
|
3866
3924
|
for (const m of d)
|
|
3867
|
-
|
|
3925
|
+
D(m[2] ?? "") === Z && r(
|
|
3868
3926
|
"MIG_SECTION_UNMAPPED_TARGET",
|
|
3869
|
-
`Заголовок «${
|
|
3927
|
+
`Заголовок «${D(m[0] ?? "")}» остался нераспознанным (UNMAPPED) — реши действие и цель вручную.`
|
|
3870
3928
|
);
|
|
3871
3929
|
for (const m of d) {
|
|
3872
3930
|
const E = (m[1] ?? "").trim();
|
|
3873
|
-
|
|
3931
|
+
fe.includes(E) || !i && E === "?" || r(
|
|
3874
3932
|
"MIG_BAD_ACTION",
|
|
3875
|
-
`Недопустимое действие «${E}» — словарь: ${
|
|
3876
|
-
), i && (m[2] ?? "").trim() === "?" &&
|
|
3933
|
+
`Недопустимое действие «${E}» — словарь: ${fe.join(" | ")}${i ? "" : " (или ? до заполнения)"}.`
|
|
3934
|
+
), i && (m[2] ?? "").trim() === "?" && r(
|
|
3877
3935
|
"MIG_TARGET_UNSET",
|
|
3878
|
-
`Цель не заполнена для строки «${
|
|
3936
|
+
`Цель не заполнена для строки «${D(m[0] ?? "")}» при Status ≥ MAPPED.`
|
|
3879
3937
|
);
|
|
3880
3938
|
}
|
|
3881
3939
|
if (i) {
|
|
3882
3940
|
const m = d.map((E) => (E[2] ?? "").trim());
|
|
3883
3941
|
for (const E of s.targetSections)
|
|
3884
|
-
m.includes(E) ||
|
|
3942
|
+
m.includes(E) || r(
|
|
3885
3943
|
"MIG_TARGET_MISSING",
|
|
3886
3944
|
`Обязательная целевая секция не производится ни одной строкой: \`${E}\`.`
|
|
3887
3945
|
);
|
|
@@ -3889,82 +3947,82 @@ function Pn(e, t, s) {
|
|
|
3889
3947
|
}
|
|
3890
3948
|
const l = g(t, "TICKET_MAP");
|
|
3891
3949
|
if (l.status !== "ok")
|
|
3892
|
-
|
|
3950
|
+
r("MIG_TICKET_MAP_MISSING", "Секция TICKET_MAP отсутствует или разбалансирована.");
|
|
3893
3951
|
else {
|
|
3894
|
-
const d =
|
|
3952
|
+
const d = z(l.content).filter((p) => D(p[0] ?? "") !== "(нет тикетов)"), u = d.map((p) => D(p[0] ?? ""));
|
|
3895
3953
|
for (const p of s.tickets)
|
|
3896
|
-
u.includes(p.file) ||
|
|
3954
|
+
u.includes(p.file) || r("MIG_TICKET_UNMAPPED", `Тикет из Inventory без строки в Ticket Map: \`${p.file}\`.`);
|
|
3897
3955
|
for (const p of d) {
|
|
3898
|
-
const m =
|
|
3956
|
+
const m = D(p[0] ?? "");
|
|
3899
3957
|
if (!s.tickets.find((I) => I.file === m)) {
|
|
3900
|
-
|
|
3958
|
+
r(
|
|
3901
3959
|
"MIG_TICKET_UNKNOWN",
|
|
3902
3960
|
`Строка Ticket Map ссылается на несуществующий тикет: \`${m}\`.`
|
|
3903
3961
|
);
|
|
3904
3962
|
continue;
|
|
3905
3963
|
}
|
|
3906
|
-
const S =
|
|
3907
|
-
(S === "" || S === "—") &&
|
|
3964
|
+
const S = D(p[1] ?? "");
|
|
3965
|
+
(S === "" || S === "—") && r(
|
|
3908
3966
|
"MIG_TICKET_ID_UNREADABLE",
|
|
3909
3967
|
`Старый Task-ID не прочитан из тикета \`${m}\` (parseMeta вернул null — проверь формат строки Task-ID в Meta) — заменять нечего, sdd-migrate ids промолчит.`
|
|
3910
3968
|
);
|
|
3911
|
-
const _ =
|
|
3912
|
-
i && (
|
|
3913
|
-
`^specs/${
|
|
3914
|
-
).test(N.split(b).join("/")) ||
|
|
3969
|
+
const _ = D(p[2] ?? ""), N = D(p[3] ?? "");
|
|
3970
|
+
i && (mt.test(_) ? new RegExp(
|
|
3971
|
+
`^specs/${Ge(s.scope)}/.*\\.task\\.${Ge(_)}\\.md$`
|
|
3972
|
+
).test(N.split(b).join("/")) || r(
|
|
3915
3973
|
"MIG_BAD_DESTINATION",
|
|
3916
3974
|
`Назначение «${N}» не подходит форме \`specs/${s.scope}/**/*.task.${_}.md\` — тикет \`${m}\`.`
|
|
3917
|
-
) :
|
|
3975
|
+
) : r(
|
|
3918
3976
|
"MIG_BAD_SLUG",
|
|
3919
3977
|
`Новый ID «${_}» не соответствует грамматике \`<ACR>-<slug>\` (ACR — верхний регистр, slug — kebab-case, ≥ 2 слова) — тикет \`${m}\`.`
|
|
3920
3978
|
));
|
|
3921
3979
|
}
|
|
3922
3980
|
}
|
|
3923
3981
|
const f = g(t, "DIAGRAM_PLAN");
|
|
3924
|
-
return f.status !== "ok" ?
|
|
3982
|
+
return f.status !== "ok" ? r("MIG_DIAGRAM_PLAN_MISSING", "Секция DIAGRAM_PLAN отсутствует или разбалансирована.") : i && /Overview-диаграмма:\s*\?/.test(f.content) && r(
|
|
3925
3983
|
"MIG_DIAGRAM_PLAN_EMPTY",
|
|
3926
3984
|
"Diagram Plan не заполнен (Overview-диаграмма: ?) при Status ≥ MAPPED."
|
|
3927
3985
|
), n;
|
|
3928
3986
|
}
|
|
3929
|
-
function
|
|
3930
|
-
const t = [], s =
|
|
3931
|
-
for (const
|
|
3932
|
-
const
|
|
3987
|
+
function kr(e) {
|
|
3988
|
+
const t = [], s = ge(e), n = /* @__PURE__ */ new Map();
|
|
3989
|
+
for (const r of s.units) {
|
|
3990
|
+
const o = se(r), i = h(e, o);
|
|
3933
3991
|
if (!R(i)) {
|
|
3934
3992
|
t.push({
|
|
3935
3993
|
severity: "error",
|
|
3936
3994
|
code: "MIG_UNIT_FILE_MISSING",
|
|
3937
|
-
file:
|
|
3938
|
-
message: `Нет файла плана для спеки \`${
|
|
3995
|
+
file: o,
|
|
3996
|
+
message: `Нет файла плана для спеки \`${r.specFile}\` — сгенерируй: sdd-migrate plan --all --write.`
|
|
3939
3997
|
});
|
|
3940
3998
|
continue;
|
|
3941
3999
|
}
|
|
3942
|
-
const a =
|
|
3943
|
-
t.push(...
|
|
4000
|
+
const a = C(i, "utf-8");
|
|
4001
|
+
t.push(...Mn(o, a, r));
|
|
3944
4002
|
const c = g(a, "TICKET_MAP");
|
|
3945
4003
|
if (c.status === "ok")
|
|
3946
|
-
for (const l of
|
|
3947
|
-
const f =
|
|
3948
|
-
if (!
|
|
4004
|
+
for (const l of z(c.content)) {
|
|
4005
|
+
const f = D(l[2] ?? "");
|
|
4006
|
+
if (!mt.test(f)) continue;
|
|
3949
4007
|
const d = n.get(f);
|
|
3950
|
-
d && d !==
|
|
4008
|
+
d && d !== o ? t.push({
|
|
3951
4009
|
severity: "error",
|
|
3952
4010
|
code: "MIG_SLUG_COLLISION",
|
|
3953
|
-
file:
|
|
4011
|
+
file: o,
|
|
3954
4012
|
message: `Новый ID «${f}» уже занят в \`${d}\` — слаг уникален в рамках репо.`
|
|
3955
|
-
}) : n.set(f,
|
|
4013
|
+
}) : n.set(f, o);
|
|
3956
4014
|
}
|
|
3957
4015
|
}
|
|
3958
|
-
for (const
|
|
4016
|
+
for (const r of s.orphanTickets)
|
|
3959
4017
|
t.push({
|
|
3960
4018
|
severity: "error",
|
|
3961
4019
|
code: "MIG_TICKET_ORPHAN",
|
|
3962
|
-
file:
|
|
4020
|
+
file: r.file,
|
|
3963
4021
|
message: "Тикет без юнита: его scope не имеет спеки — решить с оператором до миграции."
|
|
3964
4022
|
});
|
|
3965
4023
|
return t;
|
|
3966
4024
|
}
|
|
3967
|
-
const
|
|
4025
|
+
const Et = ["specs", "tasks", "cli", "shared", "services", "ai", "e2e"], $n = /* @__PURE__ */ new Set([
|
|
3968
4026
|
".md",
|
|
3969
4027
|
".ts",
|
|
3970
4028
|
".tsx",
|
|
@@ -3979,48 +4037,48 @@ const pt = ["specs", "tasks", "cli", "shared", "services", "ai", "e2e"], Ln = /*
|
|
|
3979
4037
|
".sh",
|
|
3980
4038
|
".hbs",
|
|
3981
4039
|
".txt"
|
|
3982
|
-
]),
|
|
3983
|
-
function
|
|
3984
|
-
const t = [], s = [], n = /* @__PURE__ */ new Set(),
|
|
4040
|
+
]), xn = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", "out", "coverage"]), Q = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
4041
|
+
function vr(e) {
|
|
4042
|
+
const t = [], s = [], n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set();
|
|
3985
4043
|
e.split(`
|
|
3986
|
-
`).forEach((
|
|
3987
|
-
const a =
|
|
4044
|
+
`).forEach((o, i) => {
|
|
4045
|
+
const a = o.trim();
|
|
3988
4046
|
if (a === "" || a.startsWith("#")) return;
|
|
3989
|
-
const c =
|
|
4047
|
+
const c = o.split(" ").map((d) => d.trim()), [l, f] = c;
|
|
3990
4048
|
if (c.length !== 2 || !l || !f) {
|
|
3991
4049
|
t.push(`строка ${i + 1}: ожидаю ровно две TAB-колонки \`<old>\\t<new>\``);
|
|
3992
4050
|
return;
|
|
3993
4051
|
}
|
|
3994
|
-
|
|
4052
|
+
Q.test(l) || t.push(`строка ${i + 1}: old «${l}» вне грамматики ID`), Q.test(f) || t.push(`строка ${i + 1}: new «${f}» вне грамматики ID`), l === f && t.push(`строка ${i + 1}: old и new совпадают («${l}»)`), n.has(l) && t.push(`строка ${i + 1}: old «${l}» встречается повторно`), r.has(f) && t.push(`строка ${i + 1}: new «${f}» встречается повторно`), n.add(l), r.add(f), s.push({ old: l, next: f });
|
|
3995
4053
|
});
|
|
3996
|
-
for (const
|
|
3997
|
-
n.has(
|
|
3998
|
-
`цепочка: new «${
|
|
4054
|
+
for (const o of s)
|
|
4055
|
+
n.has(o.next) && t.push(
|
|
4056
|
+
`цепочка: new «${o.next}» одновременно чей-то old — переименования нельзя упорядочить безопасно`
|
|
3999
4057
|
);
|
|
4000
4058
|
return t.length > 0 ? { ok: !1, errors: t } : { ok: !0, map: s };
|
|
4001
4059
|
}
|
|
4002
|
-
function
|
|
4060
|
+
function re(e) {
|
|
4003
4061
|
return (e ?? "").replace(/`/g, "").trim();
|
|
4004
4062
|
}
|
|
4005
|
-
function
|
|
4006
|
-
const t =
|
|
4007
|
-
for (const
|
|
4008
|
-
const i =
|
|
4063
|
+
function wr(e) {
|
|
4064
|
+
const t = ge(e), s = [], n = /* @__PURE__ */ new Set(), r = [];
|
|
4065
|
+
for (const o of t.units) {
|
|
4066
|
+
const i = se(o);
|
|
4009
4067
|
let a;
|
|
4010
4068
|
try {
|
|
4011
|
-
a =
|
|
4069
|
+
a = C(h(e, i), "utf-8");
|
|
4012
4070
|
} catch {
|
|
4013
4071
|
continue;
|
|
4014
4072
|
}
|
|
4015
4073
|
const c = g(a, "TICKET_MAP");
|
|
4016
4074
|
if (c.status === "ok")
|
|
4017
|
-
for (const l of
|
|
4018
|
-
const f =
|
|
4075
|
+
for (const l of z(c.content)) {
|
|
4076
|
+
const f = re(l[0]);
|
|
4019
4077
|
if (f === "(нет тикетов)") continue;
|
|
4020
|
-
const d =
|
|
4078
|
+
const d = re(l[1]), u = re(l[2]);
|
|
4021
4079
|
if (d === "?" || u === "?") continue;
|
|
4022
|
-
if (!
|
|
4023
|
-
|
|
4080
|
+
if (!Q.test(d) || !Q.test(u)) {
|
|
4081
|
+
r.push(
|
|
4024
4082
|
`${i}: строка Ticket Map тикета \`${f}\` невалидна — old=«${d}» new=«${u}» вне грамматики ID (не «?», значит не заглушка).`
|
|
4025
4083
|
);
|
|
4026
4084
|
continue;
|
|
@@ -4029,89 +4087,89 @@ function Dr(e) {
|
|
|
4029
4087
|
n.has(p) || (n.add(p), s.push(p));
|
|
4030
4088
|
}
|
|
4031
4089
|
}
|
|
4032
|
-
return
|
|
4090
|
+
return r.length > 0 ? { ok: !1, errors: r } : { ok: !0, tsv: s.sort().join(`
|
|
4033
4091
|
`) + (s.length > 0 ? `
|
|
4034
4092
|
` : "") };
|
|
4035
4093
|
}
|
|
4036
|
-
function
|
|
4094
|
+
function ht(e) {
|
|
4037
4095
|
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4038
4096
|
}
|
|
4039
|
-
function
|
|
4040
|
-
const s = [], n = (
|
|
4041
|
-
let
|
|
4097
|
+
function St(e, t) {
|
|
4098
|
+
const s = [], n = (r) => {
|
|
4099
|
+
let o;
|
|
4042
4100
|
try {
|
|
4043
|
-
|
|
4101
|
+
o = B(r, { withFileTypes: !0 });
|
|
4044
4102
|
} catch {
|
|
4045
4103
|
return;
|
|
4046
4104
|
}
|
|
4047
|
-
for (const i of
|
|
4048
|
-
if (i.name.startsWith(".") ||
|
|
4049
|
-
const a = h(
|
|
4050
|
-
i.isDirectory() ? n(a) : i.isFile() &&
|
|
4105
|
+
for (const i of o) {
|
|
4106
|
+
if (i.name.startsWith(".") || xn.has(i.name) || i.isSymbolicLink()) continue;
|
|
4107
|
+
const a = h(r, i.name);
|
|
4108
|
+
i.isDirectory() ? n(a) : i.isFile() && $n.has(Ct(i.name)) && s.push(a);
|
|
4051
4109
|
}
|
|
4052
4110
|
};
|
|
4053
|
-
for (const
|
|
4111
|
+
for (const r of t) n(h(e, r));
|
|
4054
4112
|
return s.sort();
|
|
4055
4113
|
}
|
|
4056
|
-
function
|
|
4057
|
-
const
|
|
4058
|
-
re: new RegExp(`\\b${
|
|
4114
|
+
function Pr(e, t, s, n = Et) {
|
|
4115
|
+
const r = [], o = t.map((i) => ({
|
|
4116
|
+
re: new RegExp(`\\b${ht(i.old)}\\b`, "g"),
|
|
4059
4117
|
next: i.next
|
|
4060
4118
|
}));
|
|
4061
|
-
for (const i of
|
|
4119
|
+
for (const i of St(e, n)) {
|
|
4062
4120
|
let a;
|
|
4063
4121
|
try {
|
|
4064
|
-
a =
|
|
4122
|
+
a = C(i, "utf-8");
|
|
4065
4123
|
} catch {
|
|
4066
4124
|
continue;
|
|
4067
4125
|
}
|
|
4068
4126
|
let c = a, l = 0;
|
|
4069
|
-
for (const { re: f, next: d } of
|
|
4127
|
+
for (const { re: f, next: d } of o)
|
|
4070
4128
|
c = c.replace(f, () => (l++, d));
|
|
4071
|
-
l > 0 && (s &&
|
|
4129
|
+
l > 0 && (s && W(i, c, "utf-8"), r.push({ file: x(e, i), count: l }));
|
|
4072
4130
|
}
|
|
4073
|
-
return
|
|
4131
|
+
return r;
|
|
4074
4132
|
}
|
|
4075
|
-
function
|
|
4076
|
-
const n = [],
|
|
4077
|
-
for (const
|
|
4133
|
+
function Lr(e, t, s = Et) {
|
|
4134
|
+
const n = [], r = t.map((o) => ({ re: new RegExp(`\\b${ht(o.old)}\\b`), id: o.old }));
|
|
4135
|
+
for (const o of St(e, s)) {
|
|
4078
4136
|
let i;
|
|
4079
4137
|
try {
|
|
4080
|
-
i =
|
|
4138
|
+
i = C(o, "utf-8");
|
|
4081
4139
|
} catch {
|
|
4082
4140
|
continue;
|
|
4083
4141
|
}
|
|
4084
|
-
for (const { re: a, id: c } of
|
|
4085
|
-
a.test(i) && n.push({ file: x(e,
|
|
4142
|
+
for (const { re: a, id: c } of r)
|
|
4143
|
+
a.test(i) && n.push({ file: x(e, o), id: c });
|
|
4086
4144
|
}
|
|
4087
4145
|
return n;
|
|
4088
4146
|
}
|
|
4089
|
-
function
|
|
4147
|
+
function Bn(e) {
|
|
4090
4148
|
const t = /\*\*Dependencies:\*\*\s*([^\n]+)/.exec(e);
|
|
4091
4149
|
return !t || !t[1] || /^\s*(none|—|-)\s*$/i.test(t[1]) ? [] : [...t[1].replace(/\([^)]*\)/g, " ").matchAll(/\b([A-Za-z][A-Za-z0-9]*(?:-[A-Za-z0-9]+)+)\b/g)].map(
|
|
4092
4150
|
(n) => n[1]
|
|
4093
4151
|
);
|
|
4094
4152
|
}
|
|
4095
|
-
function
|
|
4153
|
+
function Un(e) {
|
|
4096
4154
|
const t = /^#\s+Task:\s*([^\n]+)/m.exec(e);
|
|
4097
4155
|
if (!t || !t[1]) return "—";
|
|
4098
4156
|
const s = t[1].trim(), n = s.split("—");
|
|
4099
4157
|
return (n.length > 1 ? n.slice(1).join("—") : s).trim() || "—";
|
|
4100
4158
|
}
|
|
4101
|
-
function
|
|
4102
|
-
const s = [],
|
|
4103
|
-
if (
|
|
4159
|
+
function Fn(e, t) {
|
|
4160
|
+
const s = [], r = ge(e).units.filter((a) => a.scope === t);
|
|
4161
|
+
if (r.length === 0)
|
|
4104
4162
|
return { ok: !1, errors: [`scope «${t}» не найден среди юнитов миграции`] };
|
|
4105
|
-
const
|
|
4106
|
-
for (const a of
|
|
4107
|
-
const c =
|
|
4163
|
+
const o = [], i = [];
|
|
4164
|
+
for (const a of r) {
|
|
4165
|
+
const c = se(a), l = h(e, c);
|
|
4108
4166
|
if (!R(l)) {
|
|
4109
4167
|
a.tickets.length > 0 && s.push(
|
|
4110
4168
|
`нет файла плана ${c} — сгенерируй слой: sdd-migrate plan --all --write`
|
|
4111
4169
|
), i.push({ unit: a, tickets: [] });
|
|
4112
4170
|
continue;
|
|
4113
4171
|
}
|
|
4114
|
-
const f = g(
|
|
4172
|
+
const f = g(C(l, "utf-8"), "TICKET_MAP"), d = /* @__PURE__ */ new Map();
|
|
4115
4173
|
if (f.status === "ok")
|
|
4116
4174
|
for (const p of f.content.split(`
|
|
4117
4175
|
`)) {
|
|
@@ -4133,44 +4191,44 @@ function $n(e, t) {
|
|
|
4133
4191
|
);
|
|
4134
4192
|
continue;
|
|
4135
4193
|
}
|
|
4136
|
-
|
|
4137
|
-
const S =
|
|
4194
|
+
o.push({ from: p.file, to: m.dest, newId: m.newId });
|
|
4195
|
+
const S = C(E, "utf-8"), _ = g(S, "META"), N = _.status === "ok" ? _.content : S, I = nt(N);
|
|
4138
4196
|
u.push({
|
|
4139
4197
|
newId: m.newId,
|
|
4140
|
-
title:
|
|
4198
|
+
title: Un(S),
|
|
4141
4199
|
status: I.status ?? "[ ] TODO",
|
|
4142
|
-
deps:
|
|
4200
|
+
deps: Bn(N),
|
|
4143
4201
|
destDir: w(m.dest)
|
|
4144
4202
|
});
|
|
4145
4203
|
}
|
|
4146
4204
|
i.push({ unit: a, tickets: u });
|
|
4147
4205
|
}
|
|
4148
|
-
return s.length > 0 ? { ok: !1, errors: s } : { ok: !0, moves:
|
|
4206
|
+
return s.length > 0 ? { ok: !1, errors: s } : { ok: !0, moves: o, units: i };
|
|
4149
4207
|
}
|
|
4150
|
-
function
|
|
4151
|
-
const s = new Set(t.map((
|
|
4208
|
+
function Gn(e, t) {
|
|
4209
|
+
const s = new Set(t.map((o) => o.newId)), n = [
|
|
4152
4210
|
`# ${e} — Tasks`,
|
|
4153
4211
|
"",
|
|
4154
4212
|
"## Tracker Index",
|
|
4155
4213
|
"| Task-ID | Title | Dependencies | Status | Reopens |",
|
|
4156
4214
|
"|---------|-------|--------------|--------|---------|"
|
|
4157
4215
|
];
|
|
4158
|
-
for (const
|
|
4216
|
+
for (const o of t)
|
|
4159
4217
|
n.push(
|
|
4160
|
-
`| ${
|
|
4218
|
+
`| ${o.newId} | ${o.title} | ${o.deps.length > 0 ? o.deps.join(", ") : "—"} | ${o.status} | — |`
|
|
4161
4219
|
);
|
|
4162
4220
|
n.push("", "## Slug Registry"), n.push(
|
|
4163
4221
|
"<!-- один ID на строку; уникальность держится этим списком — одинаковый ID в двух ветках сталкивается здесь при merge. Только добавление. -->"
|
|
4164
4222
|
);
|
|
4165
|
-
for (const
|
|
4223
|
+
for (const o of t) n.push(`- ${o.newId}`);
|
|
4166
4224
|
n.push("", "## Intra-Module DAG", "```mermaid", "graph TD");
|
|
4167
|
-
let
|
|
4168
|
-
for (const
|
|
4169
|
-
for (const i of
|
|
4225
|
+
let r = 0;
|
|
4226
|
+
for (const o of t)
|
|
4227
|
+
for (const i of o.deps)
|
|
4170
4228
|
s.has(i) && (n.push(
|
|
4171
|
-
` ${
|
|
4172
|
-
),
|
|
4173
|
-
return
|
|
4229
|
+
` ${o.newId.replace(/[^A-Za-z0-9]/g, "_")}[${o.newId}] --> ${i.replace(/[^A-Za-z0-9]/g, "_")}[${i}]`
|
|
4230
|
+
), r++);
|
|
4231
|
+
return r === 0 && n.push(" %% зависимостей внутри модуля нет"), n.push(
|
|
4174
4232
|
"```",
|
|
4175
4233
|
"<!-- ребро A → B = «A зависит от B». Кросс-модульные рёбра живут уровнем выше. -->"
|
|
4176
4234
|
), n.push(
|
|
@@ -4185,11 +4243,11 @@ function Bn(e, t) {
|
|
|
4185
4243
|
), n.join(`
|
|
4186
4244
|
`);
|
|
4187
4245
|
}
|
|
4188
|
-
function
|
|
4189
|
-
const s = h("specs", e), n = (c) => c === s ? e :
|
|
4246
|
+
function Vn(e, t) {
|
|
4247
|
+
const s = h("specs", e), n = (c) => c === s ? e : V(c), r = /* @__PURE__ */ new Map(), o = [];
|
|
4190
4248
|
for (const c of t)
|
|
4191
4249
|
for (const l of c.tickets)
|
|
4192
|
-
|
|
4250
|
+
r.set(l.newId, n(l.destDir)), o.push(l);
|
|
4193
4251
|
const i = [
|
|
4194
4252
|
`# Tasks: ${e}`,
|
|
4195
4253
|
"",
|
|
@@ -4203,10 +4261,10 @@ function Un(e, t) {
|
|
|
4203
4261
|
"```mermaid",
|
|
4204
4262
|
"graph TD"
|
|
4205
4263
|
], a = /* @__PURE__ */ new Set();
|
|
4206
|
-
for (const c of
|
|
4264
|
+
for (const c of o) {
|
|
4207
4265
|
const l = n(c.destDir);
|
|
4208
4266
|
for (const f of c.deps) {
|
|
4209
|
-
const d =
|
|
4267
|
+
const d = r.get(f);
|
|
4210
4268
|
if (d && d !== l) {
|
|
4211
4269
|
const u = `${l}-->${d}`;
|
|
4212
4270
|
a.has(u) || (a.add(u), i.push(
|
|
@@ -4222,7 +4280,7 @@ function Un(e, t) {
|
|
|
4222
4280
|
"| Task-ID | Title | Module | Dependencies | Status | Reopens |",
|
|
4223
4281
|
"|---------|-------|--------|--------------|--------|---------|"
|
|
4224
4282
|
);
|
|
4225
|
-
for (const c of
|
|
4283
|
+
for (const c of o) {
|
|
4226
4284
|
const l = n(c.destDir);
|
|
4227
4285
|
i.push(
|
|
4228
4286
|
`| ${c.newId} | ${c.title} | ${l === e ? "—" : l} | ${c.deps.length > 0 ? c.deps.join(", ") : "—"} | ${c.status} | — |`
|
|
@@ -4236,85 +4294,85 @@ function Un(e, t) {
|
|
|
4236
4294
|
), i.join(`
|
|
4237
4295
|
`);
|
|
4238
4296
|
}
|
|
4239
|
-
const
|
|
4240
|
-
function
|
|
4297
|
+
const jn = ["specs", "tasks"];
|
|
4298
|
+
function Yn(e) {
|
|
4241
4299
|
const t = e.indexOf("#");
|
|
4242
4300
|
return t >= 0 ? { path: e.slice(0, t), fragment: e.slice(t) } : { path: e, fragment: "" };
|
|
4243
4301
|
}
|
|
4244
|
-
function
|
|
4302
|
+
function Hn(e, t, s, n) {
|
|
4245
4303
|
if (n.size === 0) return { text: e, count: 0 };
|
|
4246
|
-
const
|
|
4304
|
+
const r = F.dirname(t), o = F.dirname(s);
|
|
4247
4305
|
let i = 0;
|
|
4248
4306
|
return { text: e.replace(
|
|
4249
4307
|
/\]\(([^)\s]+)([^)]*)\)/g,
|
|
4250
4308
|
(c, l, f) => {
|
|
4251
4309
|
if (l === "" || /^[a-z][a-z0-9+.-]*:\/\//i.test(l)) return c;
|
|
4252
|
-
const { path: d, fragment: u } =
|
|
4310
|
+
const { path: d, fragment: u } = Yn(l);
|
|
4253
4311
|
if (d === "") return c;
|
|
4254
|
-
const p =
|
|
4312
|
+
const p = F.normalize(F.join(r, d)), m = n.get(p);
|
|
4255
4313
|
if (!m) return c;
|
|
4256
4314
|
i++;
|
|
4257
|
-
let E =
|
|
4315
|
+
let E = F.relative(o, m);
|
|
4258
4316
|
return E.startsWith(".") || (E = "./" + E), `](${E}${u}${f})`;
|
|
4259
4317
|
}
|
|
4260
4318
|
), count: i };
|
|
4261
4319
|
}
|
|
4262
|
-
function
|
|
4263
|
-
const s = [], n = (
|
|
4264
|
-
let
|
|
4320
|
+
function qn(e, t) {
|
|
4321
|
+
const s = [], n = (r) => {
|
|
4322
|
+
let o;
|
|
4265
4323
|
try {
|
|
4266
|
-
|
|
4324
|
+
o = B(r, { withFileTypes: !0 });
|
|
4267
4325
|
} catch {
|
|
4268
4326
|
return;
|
|
4269
4327
|
}
|
|
4270
|
-
for (const i of
|
|
4328
|
+
for (const i of o) {
|
|
4271
4329
|
if (i.name.startsWith(".") || i.isSymbolicLink()) continue;
|
|
4272
|
-
const a = h(
|
|
4330
|
+
const a = h(r, i.name);
|
|
4273
4331
|
i.isDirectory() ? n(a) : i.isFile() && i.name.endsWith(".md") && s.push(a);
|
|
4274
4332
|
}
|
|
4275
4333
|
};
|
|
4276
|
-
for (const
|
|
4334
|
+
for (const r of t) n(h(e, r));
|
|
4277
4335
|
return s.sort();
|
|
4278
4336
|
}
|
|
4279
|
-
function
|
|
4280
|
-
|
|
4337
|
+
function Wn(e, t, s) {
|
|
4338
|
+
je(w(h(e, s)), { recursive: !0 });
|
|
4281
4339
|
try {
|
|
4282
|
-
|
|
4340
|
+
_t("git", ["mv", t, s], { cwd: e, stdio: "pipe" });
|
|
4283
4341
|
} catch {
|
|
4284
|
-
|
|
4342
|
+
Nt(h(e, t), h(e, s));
|
|
4285
4343
|
}
|
|
4286
4344
|
}
|
|
4287
|
-
function
|
|
4345
|
+
function Kn(e) {
|
|
4288
4346
|
const t = [], s = (n) => {
|
|
4289
|
-
let
|
|
4347
|
+
let r;
|
|
4290
4348
|
try {
|
|
4291
|
-
|
|
4349
|
+
r = B(n, { withFileTypes: !0 });
|
|
4292
4350
|
} catch {
|
|
4293
4351
|
return;
|
|
4294
4352
|
}
|
|
4295
|
-
for (const
|
|
4296
|
-
const i = h(n,
|
|
4297
|
-
|
|
4353
|
+
for (const o of r) {
|
|
4354
|
+
const i = h(n, o.name);
|
|
4355
|
+
o.isDirectory() ? s(i) : /\.task-[0-9]+\.md$/.test(o.name) && t.push(i);
|
|
4298
4356
|
}
|
|
4299
4357
|
};
|
|
4300
4358
|
return s(e), t.length === 0;
|
|
4301
4359
|
}
|
|
4302
|
-
function
|
|
4303
|
-
const n =
|
|
4360
|
+
function br(e, t, s) {
|
|
4361
|
+
const n = Fn(e, t);
|
|
4304
4362
|
if (!n.ok) return n;
|
|
4305
|
-
const
|
|
4363
|
+
const r = s ? "" : "would ", o = [], i = new Map(n.moves.map((u) => [u.from, u.to]));
|
|
4306
4364
|
if (i.size > 0)
|
|
4307
|
-
for (const u of
|
|
4308
|
-
const p = x(e, u), m = i.get(p) ?? p, { text: E, count: S } =
|
|
4309
|
-
|
|
4365
|
+
for (const u of qn(e, jn)) {
|
|
4366
|
+
const p = x(e, u), m = i.get(p) ?? p, { text: E, count: S } = Hn(
|
|
4367
|
+
C(u, "utf-8"),
|
|
4310
4368
|
p,
|
|
4311
4369
|
m,
|
|
4312
4370
|
i
|
|
4313
4371
|
);
|
|
4314
|
-
S > 0 && (s &&
|
|
4372
|
+
S > 0 && (s && W(u, E, "utf-8"), o.push(` ${r}link ${p} — ${S} ссылк(и) на переезжающие тикеты`));
|
|
4315
4373
|
}
|
|
4316
4374
|
for (const u of n.moves)
|
|
4317
|
-
s &&
|
|
4375
|
+
s && Wn(e, u.from, u.to), o.push(` ${r}mv ${u.from} → ${u.to}`);
|
|
4318
4376
|
const a = h("specs", t), c = /* @__PURE__ */ new Map();
|
|
4319
4377
|
for (const u of n.units)
|
|
4320
4378
|
for (const p of u.tickets) {
|
|
@@ -4323,42 +4381,42 @@ function Rr(e, t, s) {
|
|
|
4323
4381
|
}
|
|
4324
4382
|
for (const u of [...c.keys()].sort()) {
|
|
4325
4383
|
if (u === a) continue;
|
|
4326
|
-
const p = c.get(u), m =
|
|
4327
|
-
s &&
|
|
4384
|
+
const p = c.get(u), m = V(u), E = h(u, `${m}.3-tasks.md`);
|
|
4385
|
+
s && W(h(e, E), Gn(m, p), "utf-8"), o.push(` ${r}index ${E} — ${p.length} тикет(ов)`);
|
|
4328
4386
|
}
|
|
4329
4387
|
const l = h("specs", t, `${t}.3-tasks.md`);
|
|
4330
|
-
s &&
|
|
4388
|
+
s && W(h(e, l), Vn(t, n.units), "utf-8"), o.push(` ${r}index ${l} — сводный трекер scope`);
|
|
4331
4389
|
const f = h(e, "tasks", t);
|
|
4332
|
-
R(f) && (s ?
|
|
4390
|
+
R(f) && (s ? Kn(f) ? (Ie(f, { recursive: !0, force: !0 }), o.push(` rm -r tasks/${t}/ — пусто, scope переключён на v2`)) : o.push(` ⚠ tasks/${t}/ НЕ удалён — там остались *.task-*.md вне плана`) : o.push(` would rm -r tasks/${t}/ (если не останется тикетов)`));
|
|
4333
4391
|
const d = h(e, "tasks");
|
|
4334
|
-
return R(d) &&
|
|
4392
|
+
return R(d) && B(d, { withFileTypes: !0 }).filter(
|
|
4335
4393
|
(p) => p.name !== "README.md"
|
|
4336
|
-
).length === 0 && (s ? (
|
|
4394
|
+
).length === 0 && (s ? (Ie(d, { recursive: !0, force: !0 }), o.push(
|
|
4337
4395
|
" rm -r tasks/ — последний scope мигрирован, репо переключён на v2 (FLOW_VERSION)"
|
|
4338
|
-
)) :
|
|
4396
|
+
)) : o.push(" would rm -r tasks/ (последний scope — репо переключится на v2)")), { ok: !0, report: o };
|
|
4339
4397
|
}
|
|
4340
|
-
const
|
|
4341
|
-
function
|
|
4398
|
+
const Xn = "ERR_CLI_YAGNI_UNDERUSED", Zn = "ERR_CLI_YAGNI_WAIVER_DECISION_MISSING", zn = 2;
|
|
4399
|
+
function Mr(e) {
|
|
4342
4400
|
return e.replace(/^[ \t]*export\s*(?:\*|\{[^}]*\})\s*from\s*['"][^'"]+['"];?[ \t]*$/gm, "");
|
|
4343
4401
|
}
|
|
4344
|
-
const
|
|
4345
|
-
function
|
|
4402
|
+
const Qn = ["MODULE_CONTRACTS", "ENTITY_SURFACES", "PUBLIC_API_SURFACE"];
|
|
4403
|
+
function Jn(e, t) {
|
|
4346
4404
|
const s = [];
|
|
4347
4405
|
for (const n of t) {
|
|
4348
|
-
const
|
|
4406
|
+
const r = new RegExp(
|
|
4349
4407
|
"<!--SECTION:" + n + "-->([\\s\\S]*?)<!--/SECTION:" + n + "-->",
|
|
4350
4408
|
"g"
|
|
4351
4409
|
);
|
|
4352
|
-
for (const
|
|
4353
|
-
s.push([
|
|
4410
|
+
for (const o of e.matchAll(r))
|
|
4411
|
+
s.push([o.index, o.index + o[0].length]);
|
|
4354
4412
|
}
|
|
4355
4413
|
return s;
|
|
4356
4414
|
}
|
|
4357
|
-
function
|
|
4358
|
-
const n = /<!--SECTION:[A-Z_]+-->/.test(e) ?
|
|
4415
|
+
function $r(e, t) {
|
|
4416
|
+
const n = /<!--SECTION:[A-Z_]+-->/.test(e) ? Jn(e, Qn) : null, r = (I) => !n || n.some(([gt, It]) => I >= gt && I < It), o = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), i = new RegExp("^(#{2,6})[ \\t]+.*`" + o + "`.*$", "gm");
|
|
4359
4417
|
let a, c = null;
|
|
4360
4418
|
for (; a = i.exec(e); )
|
|
4361
|
-
if (
|
|
4419
|
+
if (r(a.index)) {
|
|
4362
4420
|
c = a;
|
|
4363
4421
|
break;
|
|
4364
4422
|
}
|
|
@@ -4372,138 +4430,141 @@ function vr(e, t) {
|
|
|
4372
4430
|
const S = m[1]?.trim(), _ = m[2], N = _ ? { decision: _, reason: E } : { reason: E };
|
|
4373
4431
|
return S ? { ...N, external: S } : N;
|
|
4374
4432
|
}
|
|
4375
|
-
function
|
|
4433
|
+
function xr(e, t) {
|
|
4376
4434
|
const s = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4377
4435
|
return new RegExp("^###\\s*" + s + "\\b", "m").test(e);
|
|
4378
4436
|
}
|
|
4379
|
-
function
|
|
4380
|
-
const
|
|
4381
|
-
for (const
|
|
4382
|
-
const i = t.get(
|
|
4383
|
-
if (i >=
|
|
4384
|
-
const a = s.get(
|
|
4437
|
+
function Br(e, t, s, n) {
|
|
4438
|
+
const r = [];
|
|
4439
|
+
for (const o of e) {
|
|
4440
|
+
const i = t.get(o.name) ?? 0;
|
|
4441
|
+
if (i >= zn) continue;
|
|
4442
|
+
const a = s.get(o.name);
|
|
4385
4443
|
if (!a) {
|
|
4386
|
-
|
|
4444
|
+
r.push({
|
|
4387
4445
|
severity: "error",
|
|
4388
|
-
code:
|
|
4389
|
-
file:
|
|
4390
|
-
symbol:
|
|
4391
|
-
message: `\`${
|
|
4446
|
+
code: Xn,
|
|
4447
|
+
file: o.file,
|
|
4448
|
+
symbol: o.name,
|
|
4449
|
+
message: `\`${o.name}\` (${o.kind}) has ${i} usage(s) in production code (< 2) — YAGNI suspect. Fix: remove it, or — if genuinely needed — add \`- **Usage Waiver:** <reason>\` to its contract/surface entry (cite \`D-NNN — <reason>\` instead only when a Decision Log entry actually backs the reason, and then it must exist; for a public API named to an external consumer use the \`(external: <consumer>)\` variant) and log \`yagni ${o.name} ← <reason>\` in the Execution Log.`
|
|
4392
4450
|
});
|
|
4393
4451
|
continue;
|
|
4394
4452
|
}
|
|
4395
|
-
a.decision && !n.has(a.decision) &&
|
|
4453
|
+
a.decision && !n.has(a.decision) && r.push({
|
|
4396
4454
|
severity: "error",
|
|
4397
|
-
code:
|
|
4398
|
-
file:
|
|
4399
|
-
symbol:
|
|
4400
|
-
message: `\`${
|
|
4455
|
+
code: Zn,
|
|
4456
|
+
file: o.file,
|
|
4457
|
+
symbol: o.name,
|
|
4458
|
+
message: `\`${o.name}\` has a Usage Waiver citing ${a.decision}, but no Decision Log entry with that id was found anywhere in the repo — an unresolvable citation does not gate the finding. Fix: add the ${a.decision} entry to a Decision Log, correct the citation, or drop the citation if the reason does not need one.`
|
|
4401
4459
|
});
|
|
4402
4460
|
}
|
|
4403
|
-
return
|
|
4461
|
+
return r;
|
|
4404
4462
|
}
|
|
4405
4463
|
export {
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4464
|
+
he as $,
|
|
4465
|
+
_o as A,
|
|
4466
|
+
ar as B,
|
|
4467
|
+
fr as C,
|
|
4468
|
+
lr as D,
|
|
4469
|
+
cr as E,
|
|
4470
|
+
Fo as F,
|
|
4471
|
+
ae as G,
|
|
4472
|
+
Zo as H,
|
|
4473
|
+
er as I,
|
|
4474
|
+
zo as J,
|
|
4475
|
+
sr as K,
|
|
4476
|
+
tr as L,
|
|
4477
|
+
or as M,
|
|
4478
|
+
rr as N,
|
|
4479
|
+
ur as O,
|
|
4480
|
+
dr as P,
|
|
4481
|
+
g as Q,
|
|
4482
|
+
en as R,
|
|
4483
|
+
qo as S,
|
|
4484
|
+
Ee as T,
|
|
4485
|
+
mr as U,
|
|
4428
4486
|
A as V,
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
vr as
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
Eo as
|
|
4507
|
-
|
|
4508
|
-
|
|
4487
|
+
hr as W,
|
|
4488
|
+
Ar as X,
|
|
4489
|
+
Tr as Y,
|
|
4490
|
+
Nr as Z,
|
|
4491
|
+
Cr as _,
|
|
4492
|
+
ao as a,
|
|
4493
|
+
Dr as a0,
|
|
4494
|
+
xo as a1,
|
|
4495
|
+
gr as a2,
|
|
4496
|
+
Ir as a3,
|
|
4497
|
+
P as a4,
|
|
4498
|
+
Or as a5,
|
|
4499
|
+
_r as a6,
|
|
4500
|
+
Er as a7,
|
|
4501
|
+
ks as a8,
|
|
4502
|
+
Ke as a9,
|
|
4503
|
+
vo as aA,
|
|
4504
|
+
Po as aB,
|
|
4505
|
+
wo as aC,
|
|
4506
|
+
fo as aD,
|
|
4507
|
+
Re as aE,
|
|
4508
|
+
To as aF,
|
|
4509
|
+
Oo as aG,
|
|
4510
|
+
Io as aH,
|
|
4511
|
+
Ao as aI,
|
|
4512
|
+
ho as aJ,
|
|
4513
|
+
Ne as aK,
|
|
4514
|
+
uo as aL,
|
|
4515
|
+
Ut as aM,
|
|
4516
|
+
jt as aN,
|
|
4517
|
+
So as aO,
|
|
4518
|
+
No as aP,
|
|
4519
|
+
Do as aa,
|
|
4520
|
+
nt as ab,
|
|
4521
|
+
Uo as ac,
|
|
4522
|
+
Go as ad,
|
|
4523
|
+
Wo as ae,
|
|
4524
|
+
nr as af,
|
|
4525
|
+
br as ag,
|
|
4526
|
+
Ko as ah,
|
|
4527
|
+
Xo as ai,
|
|
4528
|
+
kr as aj,
|
|
4529
|
+
ge as ak,
|
|
4530
|
+
se as al,
|
|
4531
|
+
yr as am,
|
|
4532
|
+
Rr as an,
|
|
4533
|
+
wr as ao,
|
|
4534
|
+
vr as ap,
|
|
4535
|
+
Pr as aq,
|
|
4536
|
+
Lr as ar,
|
|
4537
|
+
Br as as,
|
|
4538
|
+
Ae as at,
|
|
4539
|
+
Mr as au,
|
|
4540
|
+
$r as av,
|
|
4541
|
+
xr as aw,
|
|
4542
|
+
ko as ax,
|
|
4543
|
+
Ro as ay,
|
|
4544
|
+
yo as az,
|
|
4545
|
+
po as b,
|
|
4546
|
+
As as c,
|
|
4547
|
+
Lo as d,
|
|
4548
|
+
Xs as e,
|
|
4549
|
+
Co as f,
|
|
4550
|
+
mo as g,
|
|
4551
|
+
Mo as h,
|
|
4552
|
+
bo as i,
|
|
4553
|
+
$o as j,
|
|
4554
|
+
Bo as k,
|
|
4555
|
+
Vo as l,
|
|
4556
|
+
jo as m,
|
|
4557
|
+
Qo as n,
|
|
4558
|
+
pr as o,
|
|
4559
|
+
lo as p,
|
|
4560
|
+
ir as q,
|
|
4561
|
+
Xt as r,
|
|
4562
|
+
co as s,
|
|
4563
|
+
Yo as t,
|
|
4564
|
+
Eo as u,
|
|
4565
|
+
Sr as v,
|
|
4566
|
+
Ho as w,
|
|
4567
|
+
go as x,
|
|
4568
|
+
Hs as y,
|
|
4569
|
+
Jo as z
|
|
4509
4570
|
};
|