@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.
Files changed (56) hide show
  1. package/dist/chunks/branch.mjs +9 -7
  2. package/dist/chunks/checks.mjs +9 -7
  3. package/dist/chunks/claim-verify.mjs +10 -406
  4. package/dist/chunks/classify.mjs +1 -1
  5. package/dist/chunks/confidence.mjs +17 -11
  6. package/dist/chunks/hook.mjs +13 -10
  7. package/dist/chunks/init.mjs +315 -61
  8. package/dist/chunks/luca-gitignore.mjs +4 -4
  9. package/dist/chunks/muninn-mcp.mjs +13 -10
  10. package/dist/chunks/phase.mjs +13 -9
  11. package/dist/chunks/plan.mjs +49 -0
  12. package/dist/chunks/pr-review.mjs +13 -9
  13. package/dist/chunks/preferences.mjs +11 -8
  14. package/dist/chunks/repair.mjs +1 -1
  15. package/dist/chunks/repo.mjs +9 -7
  16. package/dist/chunks/retro.mjs +5 -5
  17. package/dist/chunks/roadmap.mjs +11 -8
  18. package/dist/chunks/rules.mjs +5 -5
  19. package/dist/chunks/state.mjs +15 -10
  20. package/dist/chunks/stray-local-install.mjs +4 -4
  21. package/dist/chunks/telemetry.mjs +1 -1
  22. package/dist/chunks/todo.mjs +52 -15
  23. package/dist/chunks/vault-init.mjs +7 -228
  24. package/dist/chunks/verification.mjs +9 -6
  25. package/dist/chunks/workflow.mjs +9 -7
  26. package/dist/claude/.claude/agents/architect.md +55 -9
  27. package/dist/claude/.claude/agents/execute.md +9 -2
  28. package/dist/claude/.claude/agents/executor.md +32 -1
  29. package/dist/claude/.claude/agents/finalize.md +34 -9
  30. package/dist/claude/.claude/agents/plan-reviewer.md +5 -0
  31. package/dist/claude/.claude/agents/review.md +19 -4
  32. package/dist/claude/.claude/agents/verifier.md +62 -7
  33. package/dist/claude/.claude/commands/phase-plan.md +5 -1
  34. package/dist/claude/.claude/commands/todo-check.md +2 -2
  35. package/dist/claude/skills/gh-issue-triage/SKILL.md +6 -6
  36. package/dist/claude/skills/phase-execute/SKILL.md +1 -1
  37. package/dist/claude/skills/phase-plan/SKILL.md +16 -2
  38. package/dist/claude/skills/quick/SKILL.md +1 -1
  39. package/dist/claude/skills/session-plan/SKILL.md +3 -2
  40. package/dist/claude/skills/todo-add/SKILL.md +0 -23
  41. package/dist/index.mjs +4 -1
  42. package/dist/shared/{luca.cizL1tYz.mjs → luca.1Es9-Gvz.mjs} +1 -1
  43. package/dist/shared/{luca.BHov6l1O.mjs → luca.41dcdyd6.mjs} +33 -19
  44. package/dist/shared/{luca.Xq97ytct.mjs → luca.BSiiWgBd.mjs} +3 -3
  45. package/dist/shared/{luca.BtwZ3m3l.mjs → luca.BYM-DeyF.mjs} +244 -83
  46. package/dist/shared/{luca.ChU85KSu.mjs → luca.BZc5veeE.mjs} +4 -0
  47. package/dist/shared/{luca.CI5IvdwC.mjs → luca.CGOV-hrW.mjs} +505 -5
  48. package/dist/shared/luca.CvcFKGbj.mjs +249 -0
  49. package/dist/shared/{luca.DbrDoFFH.mjs → luca.CzglpVsy.mjs} +1 -1
  50. package/dist/shared/{luca.DGgeB5U5.mjs → luca.D5Rk3yXn.mjs} +5 -5
  51. package/dist/shared/luca.DHbTnxmf.mjs +114 -0
  52. package/dist/shared/luca.DQSuoQwr.mjs +118 -0
  53. package/dist/shared/{luca.ig-qt2eC.mjs → luca.NNGS-NSE.mjs} +2 -59
  54. package/dist/shared/{luca.LySXBNNL.mjs → luca.juAH_s77.mjs} +2 -2
  55. package/package.json +1 -1
  56. package/dist/shared/luca.GSXJf0Tv.mjs +0 -57
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CI5IvdwC.mjs';
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 { r as runWriteHandler, u as lucaBranchGuardTool } from '../shared/luca.BtwZ3m3l.mjs';
12
- import '../shared/luca.ig-qt2eC.mjs';
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.GSXJf0Tv.mjs';
15
- import '../shared/luca.LySXBNNL.mjs';
16
- import '../shared/luca.DbrDoFFH.mjs';
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
  });
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CI5IvdwC.mjs';
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 { f as readJsonPayload, r as runWriteHandler, t as lucaChecksRunTool } from '../shared/luca.BtwZ3m3l.mjs';
12
- import '../shared/luca.ig-qt2eC.mjs';
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.GSXJf0Tv.mjs';
15
- import '../shared/luca.LySXBNNL.mjs';
16
- import '../shared/luca.DbrDoFFH.mjs';
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.CI5IvdwC.mjs';
4
- import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
3
+ import { v as verifyFile } from '../shared/luca.CGOV-hrW.mjs';
4
+ import 'node:fs';
5
5
  import 'node:fs/promises';
6
- import { join } from 'node:path';
6
+ import 'node:path';
7
7
  import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
- import { spawnSync } from 'node:child_process';
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;
@@ -1,5 +1,5 @@
1
1
  import { defineCommand } from 'citty';
2
- import { C as ClassifyComplexityInputSchema } from '../shared/luca.CI5IvdwC.mjs';
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.CI5IvdwC.mjs';
3
- import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.GSXJf0Tv.mjs';
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.LySXBNNL.mjs';
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 { f as readJsonPayload, r as runWriteHandler, w as lucaConfidenceLogTool } from '../shared/luca.BtwZ3m3l.mjs';
15
- import '../shared/luca.ig-qt2eC.mjs';
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.DbrDoFFH.mjs';
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(
@@ -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.CI5IvdwC.mjs';
3
- import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.GSXJf0Tv.mjs';
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 { l as lucaStateClaimOwnerTool, S as STEP_ARTIFACTS } from '../shared/luca.ig-qt2eC.mjs';
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") {