@alecsibilia/luca 13.0.0-alpha.10 → 13.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/branch.mjs +9 -7
- package/dist/chunks/checks.mjs +9 -7
- package/dist/chunks/claim-verify.mjs +10 -406
- package/dist/chunks/classify.mjs +1 -1
- package/dist/chunks/confidence.mjs +17 -11
- package/dist/chunks/hook.mjs +13 -10
- package/dist/chunks/init.mjs +315 -61
- package/dist/chunks/luca-gitignore.mjs +4 -4
- package/dist/chunks/muninn-mcp.mjs +13 -10
- package/dist/chunks/phase.mjs +13 -9
- package/dist/chunks/plan.mjs +49 -0
- package/dist/chunks/pr-review.mjs +13 -9
- package/dist/chunks/preferences.mjs +11 -8
- package/dist/chunks/repair.mjs +1 -1
- package/dist/chunks/repo.mjs +9 -7
- package/dist/chunks/retro.mjs +5 -5
- package/dist/chunks/roadmap.mjs +11 -8
- package/dist/chunks/rules.mjs +5 -5
- package/dist/chunks/state.mjs +15 -10
- package/dist/chunks/stray-local-install.mjs +4 -4
- package/dist/chunks/telemetry.mjs +1 -1
- package/dist/chunks/todo.mjs +52 -15
- package/dist/chunks/vault-init.mjs +7 -228
- package/dist/chunks/verification.mjs +9 -6
- package/dist/chunks/workflow.mjs +9 -7
- package/dist/claude/.claude/agents/architect.md +55 -9
- package/dist/claude/.claude/agents/execute.md +9 -2
- package/dist/claude/.claude/agents/executor.md +32 -1
- package/dist/claude/.claude/agents/finalize.md +34 -9
- package/dist/claude/.claude/agents/plan-reviewer.md +5 -0
- package/dist/claude/.claude/agents/review.md +19 -4
- package/dist/claude/.claude/agents/verifier.md +62 -7
- package/dist/claude/.claude/commands/phase-plan.md +5 -1
- package/dist/claude/.claude/commands/todo-check.md +2 -2
- package/dist/claude/skills/gh-issue-triage/SKILL.md +6 -6
- package/dist/claude/skills/phase-execute/SKILL.md +1 -1
- package/dist/claude/skills/phase-plan/SKILL.md +16 -2
- package/dist/claude/skills/quick/SKILL.md +1 -1
- package/dist/claude/skills/session-plan/SKILL.md +3 -2
- package/dist/claude/skills/todo-add/SKILL.md +0 -23
- package/dist/index.mjs +4 -1
- package/dist/shared/{luca.cizL1tYz.mjs → luca.1Es9-Gvz.mjs} +1 -1
- package/dist/shared/{luca.BHov6l1O.mjs → luca.41dcdyd6.mjs} +33 -19
- package/dist/shared/{luca.Xq97ytct.mjs → luca.BSiiWgBd.mjs} +3 -3
- package/dist/shared/{luca.BtwZ3m3l.mjs → luca.BYM-DeyF.mjs} +244 -83
- package/dist/shared/{luca.ChU85KSu.mjs → luca.BZc5veeE.mjs} +4 -0
- package/dist/shared/{luca.CI5IvdwC.mjs → luca.CGOV-hrW.mjs} +505 -5
- package/dist/shared/luca.CvcFKGbj.mjs +249 -0
- package/dist/shared/{luca.DbrDoFFH.mjs → luca.CzglpVsy.mjs} +1 -1
- package/dist/shared/{luca.DGgeB5U5.mjs → luca.D5Rk3yXn.mjs} +5 -5
- package/dist/shared/luca.DHbTnxmf.mjs +114 -0
- package/dist/shared/luca.DQSuoQwr.mjs +118 -0
- package/dist/shared/{luca.ig-qt2eC.mjs → luca.NNGS-NSE.mjs} +2 -59
- package/dist/shared/{luca.LySXBNNL.mjs → luca.juAH_s77.mjs} +2 -2
- package/package.json +1 -1
- package/dist/shared/luca.GSXJf0Tv.mjs +0 -57
package/dist/chunks/branch.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
2
|
import 'zod';
|
|
3
|
-
import '../shared/luca.
|
|
3
|
+
import '../shared/luca.CGOV-hrW.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:fs/promises';
|
|
6
6
|
import 'node:path';
|
|
@@ -8,12 +8,13 @@ import 'node:crypto';
|
|
|
8
8
|
import 'node:module';
|
|
9
9
|
import 'node:url';
|
|
10
10
|
import 'node:child_process';
|
|
11
|
-
import {
|
|
12
|
-
import '../shared/luca.
|
|
11
|
+
import { t as lucaBranchGuardTool } from '../shared/luca.BYM-DeyF.mjs';
|
|
12
|
+
import '../shared/luca.NNGS-NSE.mjs';
|
|
13
|
+
import { r as rejectUnknownFlags, a as runWriteHandler } from '../shared/luca.DHbTnxmf.mjs';
|
|
13
14
|
import 'node:os';
|
|
14
|
-
import '../shared/luca.
|
|
15
|
-
import '../shared/luca.
|
|
16
|
-
import '../shared/luca.
|
|
15
|
+
import '../shared/luca.DQSuoQwr.mjs';
|
|
16
|
+
import '../shared/luca.juAH_s77.mjs';
|
|
17
|
+
import '../shared/luca.CzglpVsy.mjs';
|
|
17
18
|
import '../shared/luca.CQ3g1xrD.mjs';
|
|
18
19
|
|
|
19
20
|
const guardCommand = defineCommand({
|
|
@@ -28,7 +29,8 @@ const guardCommand = defineCommand({
|
|
|
28
29
|
description: 'Branch name that must NOT equal the current branch (typically the repository default branch, default "main").'
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
|
-
async run({ args }) {
|
|
32
|
+
async run({ args, rawArgs, cmd }) {
|
|
33
|
+
rejectUnknownFlags("branch guard", cmd, rawArgs);
|
|
32
34
|
await runWriteHandler("branch guard", lucaBranchGuardTool, {
|
|
33
35
|
default_branch: args["default-branch"]
|
|
34
36
|
});
|
package/dist/chunks/checks.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
2
|
import 'zod';
|
|
3
|
-
import '../shared/luca.
|
|
3
|
+
import '../shared/luca.CGOV-hrW.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:fs/promises';
|
|
6
6
|
import 'node:path';
|
|
@@ -8,12 +8,13 @@ import 'node:crypto';
|
|
|
8
8
|
import 'node:module';
|
|
9
9
|
import 'node:url';
|
|
10
10
|
import 'node:child_process';
|
|
11
|
-
import {
|
|
12
|
-
import '../shared/luca.
|
|
11
|
+
import { s as lucaChecksRunTool } from '../shared/luca.BYM-DeyF.mjs';
|
|
12
|
+
import '../shared/luca.NNGS-NSE.mjs';
|
|
13
|
+
import { r as rejectUnknownFlags, b as readJsonPayload, a as runWriteHandler } from '../shared/luca.DHbTnxmf.mjs';
|
|
13
14
|
import 'node:os';
|
|
14
|
-
import '../shared/luca.
|
|
15
|
-
import '../shared/luca.
|
|
16
|
-
import '../shared/luca.
|
|
15
|
+
import '../shared/luca.DQSuoQwr.mjs';
|
|
16
|
+
import '../shared/luca.juAH_s77.mjs';
|
|
17
|
+
import '../shared/luca.CzglpVsy.mjs';
|
|
17
18
|
import '../shared/luca.CQ3g1xrD.mjs';
|
|
18
19
|
|
|
19
20
|
const runCommand = defineCommand({
|
|
@@ -32,7 +33,8 @@ const runCommand = defineCommand({
|
|
|
32
33
|
description: "Per-command timeout in milliseconds (range 100-600000, default 90000). On timeout the process is killed."
|
|
33
34
|
}
|
|
34
35
|
},
|
|
35
|
-
async run({ args }) {
|
|
36
|
+
async run({ args, rawArgs, cmd }) {
|
|
37
|
+
rejectUnknownFlags("checks run", cmd, rawArgs);
|
|
36
38
|
const commands = await readJsonPayload("checks run", args.file);
|
|
37
39
|
await runWriteHandler("checks run", lucaChecksRunTool, {
|
|
38
40
|
commands,
|
|
@@ -1,420 +1,18 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
2
|
import { resolve } from 'pathe';
|
|
3
|
-
import '../shared/luca.
|
|
4
|
-
import
|
|
3
|
+
import { v as verifyFile } from '../shared/luca.CGOV-hrW.mjs';
|
|
4
|
+
import 'node:fs';
|
|
5
5
|
import 'node:fs/promises';
|
|
6
|
-
import
|
|
6
|
+
import 'node:path';
|
|
7
7
|
import 'node:crypto';
|
|
8
8
|
import 'node:module';
|
|
9
9
|
import 'node:url';
|
|
10
|
-
import
|
|
10
|
+
import 'node:child_process';
|
|
11
11
|
import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
|
|
12
12
|
import 'zod';
|
|
13
13
|
import 'node:os';
|
|
14
14
|
import 'consola';
|
|
15
15
|
|
|
16
|
-
const SYMBOL_STOPWORDS = /* @__PURE__ */ new Set([
|
|
17
|
-
"true",
|
|
18
|
-
"false",
|
|
19
|
-
"null",
|
|
20
|
-
"undefined",
|
|
21
|
-
"void",
|
|
22
|
-
"any",
|
|
23
|
-
"unknown",
|
|
24
|
-
"never",
|
|
25
|
-
"string",
|
|
26
|
-
"number",
|
|
27
|
-
"boolean",
|
|
28
|
-
"object",
|
|
29
|
-
"array",
|
|
30
|
-
"bun",
|
|
31
|
-
"npm",
|
|
32
|
-
"pnpm",
|
|
33
|
-
"yarn",
|
|
34
|
-
"git",
|
|
35
|
-
"gh",
|
|
36
|
-
"pr",
|
|
37
|
-
"ci",
|
|
38
|
-
"cd",
|
|
39
|
-
"repo",
|
|
40
|
-
"main",
|
|
41
|
-
"master",
|
|
42
|
-
"dev",
|
|
43
|
-
"build",
|
|
44
|
-
"test",
|
|
45
|
-
"lint",
|
|
46
|
-
"tsc",
|
|
47
|
-
"eslint",
|
|
48
|
-
"todo",
|
|
49
|
-
"fixme",
|
|
50
|
-
"note",
|
|
51
|
-
"warn",
|
|
52
|
-
"info",
|
|
53
|
-
"log",
|
|
54
|
-
"http",
|
|
55
|
-
"https",
|
|
56
|
-
"json",
|
|
57
|
-
"yaml",
|
|
58
|
-
"toml",
|
|
59
|
-
"env",
|
|
60
|
-
"src",
|
|
61
|
-
"dist",
|
|
62
|
-
"lib",
|
|
63
|
-
"app",
|
|
64
|
-
"apps"
|
|
65
|
-
]);
|
|
66
|
-
const COUNTABLE_NOUNS = /* @__PURE__ */ new Set([
|
|
67
|
-
"file",
|
|
68
|
-
"files",
|
|
69
|
-
"test",
|
|
70
|
-
"tests",
|
|
71
|
-
"table",
|
|
72
|
-
"tables",
|
|
73
|
-
"index",
|
|
74
|
-
"indexes",
|
|
75
|
-
"indices",
|
|
76
|
-
"function",
|
|
77
|
-
"functions",
|
|
78
|
-
"endpoint",
|
|
79
|
-
"endpoints",
|
|
80
|
-
"route",
|
|
81
|
-
"routes",
|
|
82
|
-
"mutation",
|
|
83
|
-
"mutations",
|
|
84
|
-
"query",
|
|
85
|
-
"queries",
|
|
86
|
-
"action",
|
|
87
|
-
"actions",
|
|
88
|
-
"tool",
|
|
89
|
-
"tools",
|
|
90
|
-
"mode",
|
|
91
|
-
"modes",
|
|
92
|
-
"phase",
|
|
93
|
-
"phases",
|
|
94
|
-
"wave",
|
|
95
|
-
"waves",
|
|
96
|
-
"commit",
|
|
97
|
-
"commits",
|
|
98
|
-
"package",
|
|
99
|
-
"packages",
|
|
100
|
-
"module",
|
|
101
|
-
"modules",
|
|
102
|
-
"class",
|
|
103
|
-
"classes",
|
|
104
|
-
"method",
|
|
105
|
-
"methods",
|
|
106
|
-
"component",
|
|
107
|
-
"components",
|
|
108
|
-
"hook",
|
|
109
|
-
"hooks"
|
|
110
|
-
]);
|
|
111
|
-
function singularize(noun) {
|
|
112
|
-
const lower = noun.toLowerCase();
|
|
113
|
-
if (lower === "indices") return "index";
|
|
114
|
-
if (lower === "queries") return "query";
|
|
115
|
-
if (lower === "classes") return "class";
|
|
116
|
-
if (lower === "indexes") return "index";
|
|
117
|
-
if (lower.endsWith("ies") && lower.length > 3) {
|
|
118
|
-
return `${lower.slice(0, -3)}y`;
|
|
119
|
-
}
|
|
120
|
-
if (lower.endsWith("s") && !lower.endsWith("ss")) return lower.slice(0, -1);
|
|
121
|
-
return lower;
|
|
122
|
-
}
|
|
123
|
-
const BACKTICK_RE = /`([^`\n]+)`/g;
|
|
124
|
-
const FILE_PATH_RE = /(?:^|[\s(`'"])((?:packages|src|apps|lib|tests?|docs?|\.planning|\.luca|\.changeset|\.github)\/[\w./-]+\.[\w]+)(?=[\s)`'".,;!?]|$)/g;
|
|
125
|
-
const QUANTITATIVE_RE = /\b(\d+)\s+([a-zA-Z]+)\b/g;
|
|
126
|
-
const IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
127
|
-
function extractClaims(text) {
|
|
128
|
-
if (!text) return [];
|
|
129
|
-
const lines = text.split("\n");
|
|
130
|
-
const seen = /* @__PURE__ */ new Set();
|
|
131
|
-
const claims = [];
|
|
132
|
-
const pushIfNew = (key, claim) => {
|
|
133
|
-
if (seen.has(key)) return;
|
|
134
|
-
seen.add(key);
|
|
135
|
-
claims.push(claim);
|
|
136
|
-
};
|
|
137
|
-
for (let i = 0; i < lines.length; i++) {
|
|
138
|
-
const line = lines[i] ?? "";
|
|
139
|
-
const sourceLine = i + 1;
|
|
140
|
-
const sourceContext = line.trim().slice(0, 240);
|
|
141
|
-
for (const match of line.matchAll(BACKTICK_RE)) {
|
|
142
|
-
const inner = (match[1] ?? "").trim();
|
|
143
|
-
if (inner.includes("/") && /\.\w+(?:[#?:]|$)/.test(inner)) continue;
|
|
144
|
-
if (!IDENTIFIER_RE.test(inner)) continue;
|
|
145
|
-
if (inner.length < 3) continue;
|
|
146
|
-
if (SYMBOL_STOPWORDS.has(inner.toLowerCase())) continue;
|
|
147
|
-
pushIfNew(`symbol:${inner}`, {
|
|
148
|
-
type: "symbol",
|
|
149
|
-
text: match[0],
|
|
150
|
-
identifier: inner,
|
|
151
|
-
sourceLine,
|
|
152
|
-
sourceContext
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
for (const match of line.matchAll(FILE_PATH_RE)) {
|
|
156
|
-
const path = match[1];
|
|
157
|
-
if (!path) continue;
|
|
158
|
-
pushIfNew(`path:${path}`, {
|
|
159
|
-
type: "file-path",
|
|
160
|
-
text: path,
|
|
161
|
-
path,
|
|
162
|
-
sourceLine,
|
|
163
|
-
sourceContext
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
for (const match of line.matchAll(QUANTITATIVE_RE)) {
|
|
167
|
-
const numStr = match[1];
|
|
168
|
-
const noun = match[2];
|
|
169
|
-
if (!numStr || !noun) continue;
|
|
170
|
-
if (numStr.length === 4) {
|
|
171
|
-
const n = Number(numStr);
|
|
172
|
-
if (n >= 1900 && n <= 2200) continue;
|
|
173
|
-
}
|
|
174
|
-
const lowerNoun = noun.toLowerCase();
|
|
175
|
-
if (!COUNTABLE_NOUNS.has(lowerNoun)) continue;
|
|
176
|
-
const num = Number(numStr);
|
|
177
|
-
if (!Number.isFinite(num)) continue;
|
|
178
|
-
pushIfNew(`count:${num}:${lowerNoun}`, {
|
|
179
|
-
type: "quantitative",
|
|
180
|
-
text: `${numStr} ${noun}`,
|
|
181
|
-
number: num,
|
|
182
|
-
noun: singularize(lowerNoun),
|
|
183
|
-
sourceLine,
|
|
184
|
-
sourceContext
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return claims;
|
|
189
|
-
}
|
|
190
|
-
function gitAvailable(repoRoot) {
|
|
191
|
-
const r = spawnSync(
|
|
192
|
-
"git",
|
|
193
|
-
["-C", repoRoot, "rev-parse", "--is-inside-work-tree"],
|
|
194
|
-
{ encoding: "utf-8" }
|
|
195
|
-
);
|
|
196
|
-
return r.status === 0;
|
|
197
|
-
}
|
|
198
|
-
function gitGrepFiles(repoRoot, needle, timeoutMs) {
|
|
199
|
-
const r = spawnSync(
|
|
200
|
-
"git",
|
|
201
|
-
["-C", repoRoot, "grep", "--untracked", "-l", "--fixed-strings", needle],
|
|
202
|
-
{ encoding: "utf-8", timeout: timeoutMs }
|
|
203
|
-
);
|
|
204
|
-
if (r.signal === "SIGTERM" || r.error?.message?.includes("ETIMEDOUT")) {
|
|
205
|
-
return { ok: false, matchedFiles: [], timedOut: true };
|
|
206
|
-
}
|
|
207
|
-
if (r.status === 1) return { ok: true, matchedFiles: [], timedOut: false };
|
|
208
|
-
if (r.status !== 0) return { ok: false, matchedFiles: [], timedOut: false };
|
|
209
|
-
const matchedFiles = (r.stdout ?? "").split("\n").map((s) => s.trim()).filter(Boolean);
|
|
210
|
-
return { ok: true, matchedFiles, timedOut: false };
|
|
211
|
-
}
|
|
212
|
-
const FS_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
213
|
-
"node_modules",
|
|
214
|
-
".git",
|
|
215
|
-
"dist",
|
|
216
|
-
"build",
|
|
217
|
-
".next",
|
|
218
|
-
".turbo",
|
|
219
|
-
"coverage",
|
|
220
|
-
".cache"
|
|
221
|
-
]);
|
|
222
|
-
const FS_SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
223
|
-
".png",
|
|
224
|
-
".jpg",
|
|
225
|
-
".jpeg",
|
|
226
|
-
".gif",
|
|
227
|
-
".webp",
|
|
228
|
-
".ico",
|
|
229
|
-
".pdf",
|
|
230
|
-
".zip",
|
|
231
|
-
".tar",
|
|
232
|
-
".gz",
|
|
233
|
-
".lock",
|
|
234
|
-
".lockb"
|
|
235
|
-
]);
|
|
236
|
-
const FS_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
237
|
-
function fsGrepFiles(repoRoot, needle, timeoutMs) {
|
|
238
|
-
const start = Date.now();
|
|
239
|
-
const matchedFiles = [];
|
|
240
|
-
const stack = [repoRoot];
|
|
241
|
-
while (stack.length > 0) {
|
|
242
|
-
if (Date.now() - start > timeoutMs) {
|
|
243
|
-
return { ok: false, matchedFiles, timedOut: true };
|
|
244
|
-
}
|
|
245
|
-
const dir = stack.pop();
|
|
246
|
-
if (dir === void 0) break;
|
|
247
|
-
let entries;
|
|
248
|
-
try {
|
|
249
|
-
entries = readdirSync(dir);
|
|
250
|
-
} catch {
|
|
251
|
-
continue;
|
|
252
|
-
}
|
|
253
|
-
for (const name of entries) {
|
|
254
|
-
const full = join(dir, name);
|
|
255
|
-
let info;
|
|
256
|
-
try {
|
|
257
|
-
info = statSync(full);
|
|
258
|
-
} catch {
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
if (info.isDirectory()) {
|
|
262
|
-
if (FS_SKIP_DIRS.has(name)) continue;
|
|
263
|
-
stack.push(full);
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
if (!info.isFile()) continue;
|
|
267
|
-
const dotIdx = name.lastIndexOf(".");
|
|
268
|
-
if (dotIdx >= 0) {
|
|
269
|
-
const ext = name.slice(dotIdx).toLowerCase();
|
|
270
|
-
if (FS_SKIP_EXTENSIONS.has(ext)) continue;
|
|
271
|
-
}
|
|
272
|
-
if (info.size > FS_MAX_FILE_BYTES) continue;
|
|
273
|
-
try {
|
|
274
|
-
if (readFileSync(full).includes(needle)) {
|
|
275
|
-
matchedFiles.push(full);
|
|
276
|
-
}
|
|
277
|
-
} catch {
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
return { ok: true, matchedFiles, timedOut: false };
|
|
282
|
-
}
|
|
283
|
-
function searchFiles(repoRoot, needle, timeoutMs, useGit) {
|
|
284
|
-
return useGit ? gitGrepFiles(repoRoot, needle, timeoutMs) : fsGrepFiles(repoRoot, needle, timeoutMs);
|
|
285
|
-
}
|
|
286
|
-
function verifyClaims(claims, opts) {
|
|
287
|
-
const totalBudgetMs = opts.totalBudgetMs ?? 3e4;
|
|
288
|
-
const perClaimBudgetMs = opts.perClaimBudgetMs ?? 5e3;
|
|
289
|
-
const useGit = gitAvailable(opts.repoRoot);
|
|
290
|
-
const start = Date.now();
|
|
291
|
-
const failures = [];
|
|
292
|
-
let timedOut = false;
|
|
293
|
-
const breakdown = { symbols: 0, filePaths: 0, quantitative: 0 };
|
|
294
|
-
for (const claim of claims) {
|
|
295
|
-
if (claim.type === "symbol") breakdown.symbols++;
|
|
296
|
-
else if (claim.type === "file-path") breakdown.filePaths++;
|
|
297
|
-
else breakdown.quantitative++;
|
|
298
|
-
if (Date.now() - start > totalBudgetMs) {
|
|
299
|
-
timedOut = true;
|
|
300
|
-
failures.push({
|
|
301
|
-
claim,
|
|
302
|
-
reason: "timeout",
|
|
303
|
-
evidence: `Total budget ${totalBudgetMs}ms exhausted before this claim was checked.`
|
|
304
|
-
});
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
if (claim.type === "symbol" && claim.identifier) {
|
|
308
|
-
const r = searchFiles(
|
|
309
|
-
opts.repoRoot,
|
|
310
|
-
claim.identifier,
|
|
311
|
-
perClaimBudgetMs,
|
|
312
|
-
useGit
|
|
313
|
-
);
|
|
314
|
-
if (r.timedOut) {
|
|
315
|
-
timedOut = true;
|
|
316
|
-
failures.push({
|
|
317
|
-
claim,
|
|
318
|
-
reason: "timeout",
|
|
319
|
-
evidence: `Search for symbol "${claim.identifier}" exceeded ${perClaimBudgetMs}ms.`
|
|
320
|
-
});
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
if (!r.ok || r.matchedFiles.length === 0) {
|
|
324
|
-
failures.push({
|
|
325
|
-
claim,
|
|
326
|
-
reason: "symbol-not-found",
|
|
327
|
-
evidence: `git grep for "${claim.identifier}" returned 0 hits.`
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
continue;
|
|
331
|
-
}
|
|
332
|
-
if (claim.type === "file-path" && claim.path) {
|
|
333
|
-
const abs = join(opts.repoRoot, claim.path);
|
|
334
|
-
if (!existsSync(abs)) {
|
|
335
|
-
failures.push({
|
|
336
|
-
claim,
|
|
337
|
-
reason: "file-not-found",
|
|
338
|
-
evidence: `Path "${claim.path}" does not exist (resolved to ${abs}).`
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
if (claim.type === "quantitative" && claim.noun && typeof claim.number === "number") {
|
|
344
|
-
const r = searchFiles(
|
|
345
|
-
opts.repoRoot,
|
|
346
|
-
claim.noun,
|
|
347
|
-
perClaimBudgetMs,
|
|
348
|
-
useGit
|
|
349
|
-
);
|
|
350
|
-
if (r.timedOut) {
|
|
351
|
-
timedOut = true;
|
|
352
|
-
failures.push({
|
|
353
|
-
claim,
|
|
354
|
-
reason: "timeout",
|
|
355
|
-
evidence: `Search for noun "${claim.noun}" exceeded ${perClaimBudgetMs}ms.`
|
|
356
|
-
});
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
if (!r.ok) {
|
|
360
|
-
failures.push({
|
|
361
|
-
claim,
|
|
362
|
-
reason: "count-mismatch",
|
|
363
|
-
evidence: `grep for "${claim.noun}" failed; cannot verify "${claim.text}".`
|
|
364
|
-
});
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
const found = r.matchedFiles.length;
|
|
368
|
-
if (Math.abs(found - claim.number) > 1) {
|
|
369
|
-
failures.push({
|
|
370
|
-
claim,
|
|
371
|
-
reason: "count-mismatch",
|
|
372
|
-
evidence: `Claim says "${claim.text}", repo has ${found} file(s) mentioning "${claim.noun}" (tolerance \xB11).`
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
return {
|
|
379
|
-
passed: failures.length === 0,
|
|
380
|
-
totalClaims: claims.length,
|
|
381
|
-
failures,
|
|
382
|
-
extractedBreakdown: breakdown,
|
|
383
|
-
timedOut
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
function verifyTextArtifact(text, opts) {
|
|
387
|
-
return verifyClaims(extractClaims(text), opts);
|
|
388
|
-
}
|
|
389
|
-
function verifyFile(filePath, opts) {
|
|
390
|
-
let text;
|
|
391
|
-
try {
|
|
392
|
-
text = readFileSync(filePath, "utf-8");
|
|
393
|
-
} catch (err) {
|
|
394
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
395
|
-
return {
|
|
396
|
-
passed: false,
|
|
397
|
-
totalClaims: 0,
|
|
398
|
-
failures: [
|
|
399
|
-
{
|
|
400
|
-
claim: {
|
|
401
|
-
type: "file-path",
|
|
402
|
-
text: filePath,
|
|
403
|
-
path: filePath,
|
|
404
|
-
sourceLine: 0,
|
|
405
|
-
sourceContext: ""
|
|
406
|
-
},
|
|
407
|
-
reason: "artifact-unreadable",
|
|
408
|
-
evidence: `Could not read "${filePath}": ${msg}`
|
|
409
|
-
}
|
|
410
|
-
],
|
|
411
|
-
extractedBreakdown: { symbols: 0, filePaths: 0, quantitative: 0 },
|
|
412
|
-
timedOut: false
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
return verifyTextArtifact(text, opts);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
16
|
const claimVerifyCommand = defineCommand({
|
|
419
17
|
meta: {
|
|
420
18
|
name: "claim-verify",
|
|
@@ -450,6 +48,12 @@ const claimVerifyCommand = defineCommand({
|
|
|
450
48
|
${failure.evidence}`
|
|
451
49
|
);
|
|
452
50
|
}
|
|
51
|
+
for (const warning of report.forbiddenLanguage) {
|
|
52
|
+
logger.warn(
|
|
53
|
+
`forbidden-language: "${warning.phrase}" (line ${warning.sourceLine}) has no nearby probe evidence
|
|
54
|
+
${warning.sourceContext}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
453
57
|
if (report.passed) {
|
|
454
58
|
logger.success("All claims verified.");
|
|
455
59
|
process.exitCode = 0;
|
package/dist/chunks/classify.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
|
-
import { C as ClassifyComplexityInputSchema } from '../shared/luca.
|
|
2
|
+
import { C as ClassifyComplexityInputSchema } from '../shared/luca.CGOV-hrW.mjs';
|
|
3
3
|
import 'node:fs';
|
|
4
4
|
import 'node:fs/promises';
|
|
5
5
|
import 'node:path';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
|
-
import '../shared/luca.
|
|
3
|
-
import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.
|
|
2
|
+
import '../shared/luca.CGOV-hrW.mjs';
|
|
3
|
+
import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.DQSuoQwr.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:fs/promises';
|
|
6
6
|
import 'node:path';
|
|
@@ -8,13 +8,14 @@ import 'node:crypto';
|
|
|
8
8
|
import 'node:module';
|
|
9
9
|
import 'node:url';
|
|
10
10
|
import 'node:child_process';
|
|
11
|
-
import { r as readConfidenceJournal, b as renderConfidenceJournalMarkdown, g as getConfidenceSummary } from '../shared/luca.
|
|
11
|
+
import { r as readConfidenceJournal, b as renderConfidenceJournalMarkdown, g as getConfidenceSummary } from '../shared/luca.juAH_s77.mjs';
|
|
12
12
|
import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
|
|
13
13
|
import 'zod';
|
|
14
|
-
import {
|
|
15
|
-
import '../shared/luca.
|
|
14
|
+
import { v as lucaConfidenceLogTool } from '../shared/luca.BYM-DeyF.mjs';
|
|
15
|
+
import '../shared/luca.NNGS-NSE.mjs';
|
|
16
|
+
import { r as rejectUnknownFlags, b as readJsonPayload, a as runWriteHandler } from '../shared/luca.DHbTnxmf.mjs';
|
|
16
17
|
import 'node:os';
|
|
17
|
-
import '../shared/luca.
|
|
18
|
+
import '../shared/luca.CzglpVsy.mjs';
|
|
18
19
|
import 'consola';
|
|
19
20
|
import '../shared/luca.CQ3g1xrD.mjs';
|
|
20
21
|
|
|
@@ -128,7 +129,8 @@ const logCommand = defineCommand({
|
|
|
128
129
|
description: "Optional. Explicit gate routing override: auto | research | ask. Overrides confidence-derived bucketing when set."
|
|
129
130
|
}
|
|
130
131
|
},
|
|
131
|
-
async run({ args }) {
|
|
132
|
+
async run({ args, rawArgs, cmd }) {
|
|
133
|
+
rejectUnknownFlags("confidence log", cmd, rawArgs);
|
|
132
134
|
let payload;
|
|
133
135
|
if (args.file) {
|
|
134
136
|
const fromFile = await readJsonPayload("confidence log", args.file);
|
|
@@ -181,7 +183,8 @@ const readCommand = defineCommand({
|
|
|
181
183
|
description: "Phase slug to read (default: the active phase)."
|
|
182
184
|
}
|
|
183
185
|
},
|
|
184
|
-
async run({ args }) {
|
|
186
|
+
async run({ args, rawArgs, cmd }) {
|
|
187
|
+
rejectUnknownFlags("confidence read", cmd, rawArgs);
|
|
185
188
|
const cwd = process.cwd();
|
|
186
189
|
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
187
190
|
const entries = readConfidenceJournal({ cwd, slug });
|
|
@@ -200,7 +203,8 @@ const summaryCommand = defineCommand({
|
|
|
200
203
|
description: "Phase slug to summarize (default: the active phase)."
|
|
201
204
|
}
|
|
202
205
|
},
|
|
203
|
-
async run({ args }) {
|
|
206
|
+
async run({ args, rawArgs, cmd }) {
|
|
207
|
+
rejectUnknownFlags("confidence summary", cmd, rawArgs);
|
|
204
208
|
const cwd = process.cwd();
|
|
205
209
|
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
206
210
|
const summary = getConfidenceSummary(
|
|
@@ -221,7 +225,8 @@ const renderCommand = defineCommand({
|
|
|
221
225
|
description: "Phase slug to render (default: the active phase)."
|
|
222
226
|
}
|
|
223
227
|
},
|
|
224
|
-
async run({ args }) {
|
|
228
|
+
async run({ args, rawArgs, cmd }) {
|
|
229
|
+
rejectUnknownFlags("confidence render", cmd, rawArgs);
|
|
225
230
|
const cwd = process.cwd();
|
|
226
231
|
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
227
232
|
const md = renderConfidenceJournalMarkdown(
|
|
@@ -242,7 +247,8 @@ const gateCommand = defineCommand({
|
|
|
242
247
|
description: "Phase slug (defaults to active phase)."
|
|
243
248
|
}
|
|
244
249
|
},
|
|
245
|
-
async run({ args }) {
|
|
250
|
+
async run({ args, rawArgs, cmd }) {
|
|
251
|
+
rejectUnknownFlags("confidence gate", cmd, rawArgs);
|
|
246
252
|
const cwd = process.cwd();
|
|
247
253
|
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
248
254
|
const actions = selectConfidenceGateActions(
|
package/dist/chunks/hook.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
|
-
import { c as coarsePhaseOf, t as toLucaRelative, a as classifyWritePath, b as TMP_PATH_PATTERN, A as AUDIT_PATH_PATTERN, W as WAVE_FILE_RE } from '../shared/luca.
|
|
3
|
-
import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.
|
|
2
|
+
import { c as coarsePhaseOf, t as toLucaRelative, a as classifyWritePath, b as TMP_PATH_PATTERN, A as AUDIT_PATH_PATTERN, W as WAVE_FILE_RE } from '../shared/luca.CGOV-hrW.mjs';
|
|
3
|
+
import { l as loadCurrentState, S as STEP_ARTIFACTS, r as resolveActiveSlug } from '../shared/luca.DQSuoQwr.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:fs/promises';
|
|
6
6
|
import 'node:path';
|
|
7
|
-
import {
|
|
8
|
-
import { p as phasePathFor } from '../shared/luca.DbrDoFFH.mjs';
|
|
7
|
+
import { p as phasePathFor } from '../shared/luca.CzglpVsy.mjs';
|
|
9
8
|
import 'node:crypto';
|
|
10
9
|
import 'node:module';
|
|
11
10
|
import 'node:url';
|
|
12
11
|
import 'node:child_process';
|
|
13
12
|
import { parse } from 'shell-quote';
|
|
13
|
+
import { l as lucaStateClaimOwnerTool } from '../shared/luca.NNGS-NSE.mjs';
|
|
14
14
|
import 'zod';
|
|
15
15
|
import 'node:os';
|
|
16
16
|
|
|
@@ -234,7 +234,8 @@ const LUCA_READ_VERBS = /* @__PURE__ */ new Set([
|
|
|
234
234
|
"aggregate",
|
|
235
235
|
"filter-stale",
|
|
236
236
|
"detect-convergence",
|
|
237
|
-
"regression-check"
|
|
237
|
+
"regression-check",
|
|
238
|
+
"lint"
|
|
238
239
|
]);
|
|
239
240
|
const LUCA_NOUN_VERBS = {
|
|
240
241
|
state: /* @__PURE__ */ new Set(["read", "advance", "claim-owner", "set-current-phase"]),
|
|
@@ -253,7 +254,9 @@ const LUCA_NOUN_VERBS = {
|
|
|
253
254
|
workflow: /* @__PURE__ */ new Set(["reset"]),
|
|
254
255
|
confidence: /* @__PURE__ */ new Set(["log"]),
|
|
255
256
|
// Read-side surfaces over the per-phase verify.json files.
|
|
256
|
-
verification: /* @__PURE__ */ new Set(["read", "aggregate"])
|
|
257
|
+
verification: /* @__PURE__ */ new Set(["read", "aggregate"]),
|
|
258
|
+
// Read-only plan-quality linter over a plan.md file.
|
|
259
|
+
plan: /* @__PURE__ */ new Set(["lint"])
|
|
257
260
|
};
|
|
258
261
|
function classifyLucaCommand(rest) {
|
|
259
262
|
if (rest.some((t) => ["--help", "-h", "--version"].includes(t))) {
|
|
@@ -590,10 +593,10 @@ async function handleStageGateHook(opts) {
|
|
|
590
593
|
}
|
|
591
594
|
let category;
|
|
592
595
|
let pathBlockReason;
|
|
593
|
-
if (toolName === "Edit" || toolName === "Write" || toolName === "NotebookEdit") {
|
|
594
|
-
const targetPath = toolInput?.file_path;
|
|
596
|
+
if (toolName === "Edit" || toolName === "Write" || toolName === "NotebookEdit" || toolName === "replace" || toolName === "write_file") {
|
|
597
|
+
const targetPath = toolInput?.file_path ?? toolInput?.path;
|
|
595
598
|
if (!targetPath) {
|
|
596
|
-
log(`stage-gate: ${toolName} without file_path \u2014 allowing`);
|
|
599
|
+
log(`stage-gate: ${toolName} without file_path/path \u2014 allowing`);
|
|
597
600
|
return { exitCode: 0, toolName, toolInput, decision: "allow" };
|
|
598
601
|
}
|
|
599
602
|
const relTarget = toLucaRelative(targetPath, cwd);
|
|
@@ -620,7 +623,7 @@ async function handleStageGateHook(opts) {
|
|
|
620
623
|
} else {
|
|
621
624
|
category = pathClassToToolCategory(pc.class);
|
|
622
625
|
}
|
|
623
|
-
} else if (toolName === "Bash") {
|
|
626
|
+
} else if (toolName === "Bash" || toolName === "run_shell_command" || toolName === "run_command") {
|
|
624
627
|
const command = toolInput?.command ?? "";
|
|
625
628
|
const bashResult = classifyBashCommand(command);
|
|
626
629
|
if (bashResult.category === "denied") {
|