@alecsibilia/luca 13.0.0-alpha.1 → 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 +88 -12
- package/dist/chunks/config-version-skew.mjs +97 -0
- package/dist/chunks/doctor.mjs +17 -1
- package/dist/chunks/hook.mjs +148 -17
- package/dist/chunks/init.mjs +396 -98
- package/dist/chunks/legacy-claude-artifacts.mjs +105 -0
- package/dist/chunks/legacy-package.mjs +47 -0
- package/dist/chunks/luca-gitignore.mjs +93 -0
- package/dist/chunks/muninn-mcp.mjs +81 -0
- package/dist/chunks/muninndb-health.mjs +1 -1
- package/dist/chunks/phase.mjs +33 -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/shared-tmp-payloads.mjs +72 -0
- package/dist/chunks/stale-global-symlinks.mjs +78 -0
- package/dist/chunks/state.mjs +54 -9
- package/dist/chunks/stray-local-install.mjs +17 -9
- package/dist/chunks/telemetry.mjs +1 -1
- package/dist/chunks/todo.mjs +52 -15
- package/dist/chunks/vault-config-location.mjs +96 -0
- package/dist/chunks/vault-init.mjs +15 -223
- package/dist/chunks/verification.mjs +9 -6
- package/dist/chunks/workflow.mjs +9 -7
- package/dist/claude/.claude/agents/architect.md +99 -10
- package/dist/claude/.claude/agents/debater.md +89 -0
- package/dist/claude/.claude/agents/discussion.md +14 -26
- package/dist/claude/.claude/agents/execute.md +24 -5
- package/dist/claude/.claude/agents/executor.md +42 -22
- package/dist/claude/.claude/agents/finalize.md +66 -42
- package/dist/claude/.claude/agents/learner.md +32 -71
- package/dist/claude/.claude/agents/plan-reviewer.md +11 -9
- package/dist/claude/.claude/agents/research.md +2 -2
- package/dist/claude/.claude/agents/researcher.md +6 -9
- package/dist/claude/.claude/agents/review.md +46 -21
- package/dist/claude/.claude/agents/reviewer.md +19 -15
- package/dist/claude/.claude/agents/shadow-scanner.md +25 -27
- package/dist/claude/.claude/agents/test-writer.md +90 -0
- package/dist/claude/.claude/agents/triage.md +6 -7
- package/dist/claude/.claude/agents/verifier.md +68 -12
- package/dist/claude/.claude/commands/gh-pr-address.md +10 -10
- package/dist/claude/.claude/commands/lu-review.md +1 -1
- package/dist/claude/.claude/commands/lu.md +38 -15
- package/dist/claude/.claude/commands/milestone-new.md +4 -4
- package/dist/claude/.claude/commands/phase-execute.md +1 -1
- package/dist/claude/.claude/commands/phase-plan.md +6 -2
- package/dist/claude/.claude/commands/repo-cleanup.md +10 -7
- package/dist/claude/.claude/commands/todo-check.md +2 -2
- package/dist/claude/.claude/hooks/context-refresher.ts +14046 -252
- package/dist/claude/.claude/hooks/continuation-messages.ts +14023 -190
- package/dist/claude/.claude/hooks/pipeline-guard.ts +14015 -162
- package/dist/claude/.claude/luca-statusline.ts +146 -0
- package/dist/claude/skills/caveman/SKILL.md +58 -0
- package/dist/claude/skills/gh-issue-triage/SKILL.md +6 -6
- package/dist/claude/skills/gh-pr-address/SKILL.md +10 -10
- package/dist/claude/skills/gh-prepare/SKILL.md +1 -1
- package/dist/claude/skills/lu/SKILL.md +70 -19
- package/dist/claude/skills/lu-review/SKILL.md +1 -1
- package/dist/claude/skills/luca-init/SKILL.md +2 -2
- package/dist/claude/skills/luca-write-surface/SKILL.md +19 -3
- package/dist/claude/skills/milestone-audit/SKILL.md +41 -61
- package/dist/claude/skills/milestone-complete/SKILL.md +10 -3
- package/dist/claude/skills/phase-discuss/SKILL.md +16 -6
- package/dist/claude/skills/phase-execute/SKILL.md +93 -86
- package/dist/claude/skills/phase-plan/SKILL.md +43 -19
- package/dist/claude/skills/phase-research/SKILL.md +9 -1
- package/dist/claude/skills/post-init-tour/SKILL.md +1 -1
- package/dist/claude/skills/project-new/SKILL.md +21 -79
- package/dist/claude/skills/quick/SKILL.md +10 -15
- package/dist/claude/skills/repo-audit/SKILL.md +5 -5
- package/dist/claude/skills/repo-cleanup/SKILL.md +10 -7
- package/dist/claude/skills/session-pause/SKILL.md +1 -1
- package/dist/claude/skills/session-plan/SKILL.md +12 -11
- package/dist/claude/skills/todo-add/SKILL.md +0 -23
- package/dist/claude/skills/workflow-save/SKILL.md +4 -4
- package/dist/index.mjs +4 -1
- package/dist/shared/luca.1Es9-Gvz.mjs +102 -0
- package/dist/shared/{luca.B3saVjJm.mjs → luca.41dcdyd6.mjs} +58 -24
- package/dist/shared/{luca.C4gMUoBd.mjs → luca.BSiiWgBd.mjs} +3 -3
- package/dist/shared/{luca.DjDTeDCi.mjs → luca.BYM-DeyF.mjs} +479 -142
- package/dist/shared/luca.BZc5veeE.mjs +36 -0
- package/dist/shared/{luca.BYdjkfnz.mjs → luca.BfjhRHhj.mjs} +1 -1
- package/dist/shared/{luca.CRmaAfXR.mjs → luca.CGOV-hrW.mjs} +595 -30
- package/dist/shared/luca.CvcFKGbj.mjs +249 -0
- package/dist/shared/{luca.TSMg1t7I.mjs → luca.CzglpVsy.mjs} +1 -1
- package/dist/shared/{luca.BmhNkYe2.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.NNGS-NSE.mjs +127 -0
- package/dist/shared/{luca.HZxBTBgD.mjs → luca.juAH_s77.mjs} +2 -2
- package/package.json +4 -4
- package/dist/claude/skills/autopilot/SKILL.md +0 -1299
- package/dist/shared/luca.B3Mimc0P.mjs +0 -52
- package/dist/shared/luca.CrXzXueR.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,13 +8,14 @@ import 'node:crypto';
|
|
|
8
8
|
import 'node:module';
|
|
9
9
|
import 'node:url';
|
|
10
10
|
import 'node:child_process';
|
|
11
|
-
import {
|
|
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';
|
|
12
14
|
import 'node:os';
|
|
13
|
-
import '../shared/luca.
|
|
14
|
-
import '../shared/luca.
|
|
15
|
-
import '../shared/luca.
|
|
15
|
+
import '../shared/luca.DQSuoQwr.mjs';
|
|
16
|
+
import '../shared/luca.juAH_s77.mjs';
|
|
17
|
+
import '../shared/luca.CzglpVsy.mjs';
|
|
16
18
|
import '../shared/luca.CQ3g1xrD.mjs';
|
|
17
|
-
import '../shared/luca.B3Mimc0P.mjs';
|
|
18
19
|
|
|
19
20
|
const guardCommand = defineCommand({
|
|
20
21
|
meta: {
|
|
@@ -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,13 +8,14 @@ import 'node:crypto';
|
|
|
8
8
|
import 'node:module';
|
|
9
9
|
import 'node:url';
|
|
10
10
|
import 'node:child_process';
|
|
11
|
-
import {
|
|
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';
|
|
12
14
|
import 'node:os';
|
|
13
|
-
import '../shared/luca.
|
|
14
|
-
import '../shared/luca.
|
|
15
|
-
import '../shared/luca.
|
|
15
|
+
import '../shared/luca.DQSuoQwr.mjs';
|
|
16
|
+
import '../shared/luca.juAH_s77.mjs';
|
|
17
|
+
import '../shared/luca.CzglpVsy.mjs';
|
|
16
18
|
import '../shared/luca.CQ3g1xrD.mjs';
|
|
17
|
-
import '../shared/luca.B3Mimc0P.mjs';
|
|
18
19
|
|
|
19
20
|
const runCommand = defineCommand({
|
|
20
21
|
meta: {
|
|
@@ -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,15 +8,47 @@ import 'node:crypto';
|
|
|
8
8
|
import 'node:module';
|
|
9
9
|
import 'node:url';
|
|
10
10
|
import 'node:child_process';
|
|
11
|
-
import {
|
|
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 {
|
|
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';
|
|
15
17
|
import 'node:os';
|
|
16
|
-
import '../shared/luca.
|
|
18
|
+
import '../shared/luca.CzglpVsy.mjs';
|
|
17
19
|
import 'consola';
|
|
18
20
|
import '../shared/luca.CQ3g1xrD.mjs';
|
|
19
|
-
|
|
21
|
+
|
|
22
|
+
function selectConfidenceGateActions(entries) {
|
|
23
|
+
const auto = [];
|
|
24
|
+
const research = [];
|
|
25
|
+
const ask = [];
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
if (entry.resolution) {
|
|
28
|
+
if (entry.resolution === "auto") auto.push(entry);
|
|
29
|
+
else if (entry.resolution === "research") research.push(entry);
|
|
30
|
+
else if (entry.resolution === "ask") ask.push(entry);
|
|
31
|
+
else {
|
|
32
|
+
entry.resolution;
|
|
33
|
+
ask.push(entry);
|
|
34
|
+
}
|
|
35
|
+
} else if (entry.confidence === "high") {
|
|
36
|
+
auto.push(entry);
|
|
37
|
+
} else if (entry.confidence === "medium") {
|
|
38
|
+
auto.push(entry);
|
|
39
|
+
} else if (entry.confidence === "low" && entry.researchable === true) {
|
|
40
|
+
research.push(entry);
|
|
41
|
+
} else {
|
|
42
|
+
ask.push(entry);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
auto,
|
|
47
|
+
research,
|
|
48
|
+
ask,
|
|
49
|
+
counts: { auto: auto.length, research: research.length, ask: ask.length }
|
|
50
|
+
};
|
|
51
|
+
}
|
|
20
52
|
|
|
21
53
|
async function resolveSlug(opts) {
|
|
22
54
|
if (opts.explicit) return opts.explicit;
|
|
@@ -87,9 +119,18 @@ const logCommand = defineCommand({
|
|
|
87
119
|
"review-hint": {
|
|
88
120
|
type: "string",
|
|
89
121
|
description: "Optional. Suggested focus area for a human reviewer."
|
|
122
|
+
},
|
|
123
|
+
researchable: {
|
|
124
|
+
type: "boolean",
|
|
125
|
+
description: "Optional. Set true when the ambiguity is factual and resolvable by automated research; absent/false means human judgment is required (gate routes to ask)."
|
|
126
|
+
},
|
|
127
|
+
resolution: {
|
|
128
|
+
type: "string",
|
|
129
|
+
description: "Optional. Explicit gate routing override: auto | research | ask. Overrides confidence-derived bucketing when set."
|
|
90
130
|
}
|
|
91
131
|
},
|
|
92
|
-
async run({ args }) {
|
|
132
|
+
async run({ args, rawArgs, cmd }) {
|
|
133
|
+
rejectUnknownFlags("confidence log", cmd, rawArgs);
|
|
93
134
|
let payload;
|
|
94
135
|
if (args.file) {
|
|
95
136
|
const fromFile = await readJsonPayload("confidence log", args.file);
|
|
@@ -101,6 +142,13 @@ const logCommand = defineCommand({
|
|
|
101
142
|
}
|
|
102
143
|
payload = fromFile;
|
|
103
144
|
} else {
|
|
145
|
+
const resolution = args.resolution;
|
|
146
|
+
if (resolution !== void 0 && resolution !== "auto" && resolution !== "research" && resolution !== "ask") {
|
|
147
|
+
logger.error(
|
|
148
|
+
`luca confidence log: --resolution must be one of: auto, research, ask (got "${resolution}"). Run \`luca confidence log --help\` for usage.`
|
|
149
|
+
);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
104
152
|
payload = {
|
|
105
153
|
phase: args.phase,
|
|
106
154
|
wave: args.wave !== void 0 ? Number(args.wave) : void 0,
|
|
@@ -112,7 +160,9 @@ const logCommand = defineCommand({
|
|
|
112
160
|
reasoning: args.reasoning,
|
|
113
161
|
risk: args.risk,
|
|
114
162
|
files: splitCsv(args.files),
|
|
115
|
-
...args["review-hint"] !== void 0 ? { reviewHint: args["review-hint"] } : {}
|
|
163
|
+
...args["review-hint"] !== void 0 ? { reviewHint: args["review-hint"] } : {},
|
|
164
|
+
...args.researchable !== void 0 ? { researchable: args.researchable } : {},
|
|
165
|
+
...resolution !== void 0 ? { resolution } : {}
|
|
116
166
|
};
|
|
117
167
|
}
|
|
118
168
|
await runWriteHandler(
|
|
@@ -133,7 +183,8 @@ const readCommand = defineCommand({
|
|
|
133
183
|
description: "Phase slug to read (default: the active phase)."
|
|
134
184
|
}
|
|
135
185
|
},
|
|
136
|
-
async run({ args }) {
|
|
186
|
+
async run({ args, rawArgs, cmd }) {
|
|
187
|
+
rejectUnknownFlags("confidence read", cmd, rawArgs);
|
|
137
188
|
const cwd = process.cwd();
|
|
138
189
|
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
139
190
|
const entries = readConfidenceJournal({ cwd, slug });
|
|
@@ -152,7 +203,8 @@ const summaryCommand = defineCommand({
|
|
|
152
203
|
description: "Phase slug to summarize (default: the active phase)."
|
|
153
204
|
}
|
|
154
205
|
},
|
|
155
|
-
async run({ args }) {
|
|
206
|
+
async run({ args, rawArgs, cmd }) {
|
|
207
|
+
rejectUnknownFlags("confidence summary", cmd, rawArgs);
|
|
156
208
|
const cwd = process.cwd();
|
|
157
209
|
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
158
210
|
const summary = getConfidenceSummary(
|
|
@@ -173,7 +225,8 @@ const renderCommand = defineCommand({
|
|
|
173
225
|
description: "Phase slug to render (default: the active phase)."
|
|
174
226
|
}
|
|
175
227
|
},
|
|
176
|
-
async run({ args }) {
|
|
228
|
+
async run({ args, rawArgs, cmd }) {
|
|
229
|
+
rejectUnknownFlags("confidence render", cmd, rawArgs);
|
|
177
230
|
const cwd = process.cwd();
|
|
178
231
|
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
179
232
|
const md = renderConfidenceJournalMarkdown(
|
|
@@ -183,6 +236,28 @@ const renderCommand = defineCommand({
|
|
|
183
236
|
`);
|
|
184
237
|
}
|
|
185
238
|
});
|
|
239
|
+
const gateCommand = defineCommand({
|
|
240
|
+
meta: {
|
|
241
|
+
name: "gate",
|
|
242
|
+
description: "Bucket a phase's confidence entries into gate actions and emit a JSON object shaped { auto: [...], research: [...], ask: [...], counts: { auto, research, ask } } to stdout. Each entry lands in exactly one bucket: explicit resolution overrides first, then high/medium \u2192 auto, low+researchable \u2192 research, otherwise \u2192 ask (fail-toward-human)."
|
|
243
|
+
},
|
|
244
|
+
args: {
|
|
245
|
+
slug: {
|
|
246
|
+
type: "string",
|
|
247
|
+
description: "Phase slug (defaults to active phase)."
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
async run({ args, rawArgs, cmd }) {
|
|
251
|
+
rejectUnknownFlags("confidence gate", cmd, rawArgs);
|
|
252
|
+
const cwd = process.cwd();
|
|
253
|
+
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
254
|
+
const actions = selectConfidenceGateActions(
|
|
255
|
+
readConfidenceJournal({ cwd, slug })
|
|
256
|
+
);
|
|
257
|
+
process.stdout.write(`${JSON.stringify(actions, null, 2)}
|
|
258
|
+
`);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
186
261
|
const confidenceCommand = defineCommand({
|
|
187
262
|
meta: {
|
|
188
263
|
name: "confidence",
|
|
@@ -192,7 +267,8 @@ const confidenceCommand = defineCommand({
|
|
|
192
267
|
log: logCommand,
|
|
193
268
|
read: readCommand,
|
|
194
269
|
summary: summaryCommand,
|
|
195
|
-
render: renderCommand
|
|
270
|
+
render: renderCommand,
|
|
271
|
+
gate: gateCommand
|
|
196
272
|
}
|
|
197
273
|
});
|
|
198
274
|
|