@codacy/verity-cli 0.31.1-experimental.02b82ff → 0.31.1-experimental.68fca47
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/CHANGELOG.md +81 -3
- package/README.md +28 -3
- package/bin/verity.js +2121 -458
- package/data/skills/verity-setup/SKILL.md +120 -278
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -10395,6 +10395,7 @@ var MAX_DELTA_BYTES = 194560;
|
|
|
10395
10395
|
var MAX_FILES = 40;
|
|
10396
10396
|
var MAX_FILE_BYTES = 51200;
|
|
10397
10397
|
var DEBOUNCE_SECONDS = 30;
|
|
10398
|
+
var MAX_ITERATIONS = 2;
|
|
10398
10399
|
var MAX_SPEC_FILES = 6;
|
|
10399
10400
|
var MAX_SPEC_FILE_BYTES = 512e3;
|
|
10400
10401
|
var MAX_TOTAL_SPEC_BYTES = 512e3;
|
|
@@ -10519,13 +10520,20 @@ var ADVISORY_EPISODE_FILE = `${VERITY_DIR}/.advisory-episode`;
|
|
|
10519
10520
|
var IGNORE_DECLARATION_FILE = `${VERITY_DIR}/.ignore-declaration`;
|
|
10520
10521
|
|
|
10521
10522
|
// src/lib/output.ts
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10528
|
-
var
|
|
10523
|
+
function colorEnabled() {
|
|
10524
|
+
if (process.env.FORCE_COLOR) return true;
|
|
10525
|
+
if (process.env.NO_COLOR !== void 0) return false;
|
|
10526
|
+
if (process.env.TERM === "dumb") return false;
|
|
10527
|
+
return !!process.stderr.isTTY;
|
|
10528
|
+
}
|
|
10529
|
+
var COLOR = colorEnabled();
|
|
10530
|
+
var RED = COLOR ? "\x1B[0;31m" : "";
|
|
10531
|
+
var YELLOW = COLOR ? "\x1B[1;33m" : "";
|
|
10532
|
+
var GREEN = COLOR ? "\x1B[0;32m" : "";
|
|
10533
|
+
var CYAN = COLOR ? "\x1B[0;36m" : "";
|
|
10534
|
+
var BOLD = COLOR ? "\x1B[1m" : "";
|
|
10535
|
+
var DIM = COLOR ? "\x1B[2m" : "";
|
|
10536
|
+
var NC = COLOR ? "\x1B[0m" : "";
|
|
10529
10537
|
function printJson(data) {
|
|
10530
10538
|
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
10531
10539
|
}
|
|
@@ -11252,7 +11260,7 @@ async function resolveServiceUrlDetailed(flagUrl, opts = {}) {
|
|
|
11252
11260
|
}
|
|
11253
11261
|
return {
|
|
11254
11262
|
ok: false,
|
|
11255
|
-
error: 'No Verity service URL found. Run "verity login" to get started, or
|
|
11263
|
+
error: 'No Verity service URL found. Run "verity login" to get started, or "verity init" to set up this project.'
|
|
11256
11264
|
};
|
|
11257
11265
|
}
|
|
11258
11266
|
async function resolveServiceUrlForAuth(flagUrl) {
|
|
@@ -11299,7 +11307,7 @@ async function resolveToken(flagToken) {
|
|
|
11299
11307
|
}
|
|
11300
11308
|
return {
|
|
11301
11309
|
ok: false,
|
|
11302
|
-
error: 'No Verity token found. Run "verity login" to sign in, or
|
|
11310
|
+
error: 'No Verity token found. Run "verity login" to sign in, or "verity init" to set up this project.'
|
|
11303
11311
|
};
|
|
11304
11312
|
}
|
|
11305
11313
|
async function whoami(token, serviceUrl, verbose) {
|
|
@@ -11393,6 +11401,91 @@ async function maybeHealServiceUrl(resolution, verbose) {
|
|
|
11393
11401
|
var readline = __toESM(require("node:readline/promises"));
|
|
11394
11402
|
var import_node_os = require("node:os");
|
|
11395
11403
|
|
|
11404
|
+
// src/lib/spinner.ts
|
|
11405
|
+
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
11406
|
+
var FRAME_MS = 80;
|
|
11407
|
+
var DIM2 = "\x1B[2m";
|
|
11408
|
+
var GREEN2 = "\x1B[0;32m";
|
|
11409
|
+
var YELLOW2 = "\x1B[1;33m";
|
|
11410
|
+
var RESET = "\x1B[0m";
|
|
11411
|
+
function secondsSince(start) {
|
|
11412
|
+
return `${Math.round((Date.now() - start) / 1e3)}s`;
|
|
11413
|
+
}
|
|
11414
|
+
function startSpinner(label2, opts = {}) {
|
|
11415
|
+
const stream = process.stderr;
|
|
11416
|
+
const color = colorEnabled();
|
|
11417
|
+
const animate = opts.animate ?? !!stream.isTTY;
|
|
11418
|
+
const showElapsed = opts.elapsed ?? true;
|
|
11419
|
+
const start = Date.now();
|
|
11420
|
+
let current = label2;
|
|
11421
|
+
let frame = 0;
|
|
11422
|
+
let timer = null;
|
|
11423
|
+
let done = false;
|
|
11424
|
+
const fit = (label3, clock, columns) => {
|
|
11425
|
+
const budget = columns - 5;
|
|
11426
|
+
if (budget <= 0) return { label: "", clock: "" };
|
|
11427
|
+
if (label3.length + clock.length <= budget) return { label: label3, clock };
|
|
11428
|
+
if (clock.length >= budget) return { label: "", clock: clock.slice(0, budget) };
|
|
11429
|
+
const room = budget - clock.length;
|
|
11430
|
+
return { label: room <= 1 ? label3.slice(0, room) : `${label3.slice(0, room - 1)}\u2026`, clock };
|
|
11431
|
+
};
|
|
11432
|
+
const paint = () => {
|
|
11433
|
+
const glyph = FRAMES[frame++ % FRAMES.length];
|
|
11434
|
+
const columns = stream.columns ?? 80;
|
|
11435
|
+
const { label: label3, clock } = fit(current, showElapsed ? ` ${secondsSince(start)}` : "", columns);
|
|
11436
|
+
const line = color ? ` ${GREEN2}${glyph}${RESET} ${label3}${DIM2}${clock}${RESET}` : ` ${glyph} ${label3}${clock}`;
|
|
11437
|
+
stream.write(`\r\x1B[2K${line}`);
|
|
11438
|
+
};
|
|
11439
|
+
const clearLine = () => {
|
|
11440
|
+
if (animate) stream.write("\r\x1B[2K");
|
|
11441
|
+
};
|
|
11442
|
+
if (animate) {
|
|
11443
|
+
paint();
|
|
11444
|
+
timer = setInterval(paint, FRAME_MS);
|
|
11445
|
+
timer.unref?.();
|
|
11446
|
+
} else {
|
|
11447
|
+
stream.write(` ${current}\u2026
|
|
11448
|
+
`);
|
|
11449
|
+
}
|
|
11450
|
+
const finish = (render2) => {
|
|
11451
|
+
if (done) return;
|
|
11452
|
+
done = true;
|
|
11453
|
+
if (timer) clearInterval(timer);
|
|
11454
|
+
clearLine();
|
|
11455
|
+
render2();
|
|
11456
|
+
};
|
|
11457
|
+
return {
|
|
11458
|
+
update(next) {
|
|
11459
|
+
current = next;
|
|
11460
|
+
if (animate) paint();
|
|
11461
|
+
else stream.write(` ${next}\u2026
|
|
11462
|
+
`);
|
|
11463
|
+
},
|
|
11464
|
+
succeed(message) {
|
|
11465
|
+
finish(() => {
|
|
11466
|
+
const text = message ?? current;
|
|
11467
|
+
const clock = showElapsed ? ` (${secondsSince(start)})` : "";
|
|
11468
|
+
stream.write(
|
|
11469
|
+
color ? ` ${GREEN2}\u2713${RESET} ${text}${DIM2}${clock}${RESET}
|
|
11470
|
+
` : ` \u2713 ${text}${clock}
|
|
11471
|
+
`
|
|
11472
|
+
);
|
|
11473
|
+
});
|
|
11474
|
+
},
|
|
11475
|
+
warn(message) {
|
|
11476
|
+
finish(() => {
|
|
11477
|
+
stream.write(color ? ` ${YELLOW2}\u26A0${RESET} ${message}
|
|
11478
|
+
` : ` \u26A0 ${message}
|
|
11479
|
+
`);
|
|
11480
|
+
});
|
|
11481
|
+
},
|
|
11482
|
+
stop() {
|
|
11483
|
+
finish(() => {
|
|
11484
|
+
});
|
|
11485
|
+
}
|
|
11486
|
+
};
|
|
11487
|
+
}
|
|
11488
|
+
|
|
11396
11489
|
// src/lib/provider-auth.ts
|
|
11397
11490
|
var sleep = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
11398
11491
|
var form = (fields) => new URLSearchParams(fields).toString();
|
|
@@ -11459,42 +11552,49 @@ async function githubDeviceFlow() {
|
|
|
11459
11552
|
printInfo("");
|
|
11460
11553
|
printInfo(`To authorize Verity, open: ${dc.verification_uri}`);
|
|
11461
11554
|
printInfo(`And enter the code: ${dc.user_code}`);
|
|
11462
|
-
|
|
11555
|
+
const spinner = startSpinner(`Waiting for you to approve in the browser \xB7 code ${dc.user_code}`);
|
|
11463
11556
|
const deadline = Date.now() + (dc.expires_in || 900) * 1e3;
|
|
11464
11557
|
let interval = dc.interval || 5;
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11558
|
+
try {
|
|
11559
|
+
while (Date.now() < deadline) {
|
|
11560
|
+
await sleep(interval * 1e3);
|
|
11561
|
+
let data;
|
|
11562
|
+
try {
|
|
11563
|
+
const res = await fetch(GITHUB_ACCESS_TOKEN_URL, {
|
|
11564
|
+
method: "POST",
|
|
11565
|
+
headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
|
|
11566
|
+
body: form({
|
|
11567
|
+
client_id: GITHUB_CLIENT_ID,
|
|
11568
|
+
device_code: dc.device_code,
|
|
11569
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
11570
|
+
})
|
|
11571
|
+
});
|
|
11572
|
+
data = await res.json().catch(() => ({}));
|
|
11573
|
+
} catch {
|
|
11574
|
+
continue;
|
|
11575
|
+
}
|
|
11576
|
+
if (data.access_token) {
|
|
11577
|
+
spinner.succeed("Authorized on GitHub");
|
|
11578
|
+
return { ok: true, data: data.access_token };
|
|
11579
|
+
}
|
|
11580
|
+
switch (data.error) {
|
|
11581
|
+
case "authorization_pending":
|
|
11582
|
+
break;
|
|
11583
|
+
case "slow_down":
|
|
11584
|
+
interval += 5;
|
|
11585
|
+
break;
|
|
11586
|
+
case "access_denied":
|
|
11587
|
+
return { ok: false, error: "Authorization was denied on GitHub." };
|
|
11588
|
+
case "expired_token":
|
|
11589
|
+
return { ok: false, error: "The authorization code expired. Re-run register." };
|
|
11590
|
+
default:
|
|
11591
|
+
if (data.error) return { ok: false, error: `GitHub auth error: ${data.error}` };
|
|
11592
|
+
}
|
|
11495
11593
|
}
|
|
11594
|
+
return { ok: false, error: "Timed out waiting for GitHub authorization." };
|
|
11595
|
+
} finally {
|
|
11596
|
+
spinner.stop();
|
|
11496
11597
|
}
|
|
11497
|
-
return { ok: false, error: "Timed out waiting for GitHub authorization." };
|
|
11498
11598
|
}
|
|
11499
11599
|
|
|
11500
11600
|
// src/lib/register.ts
|
|
@@ -12263,12 +12363,20 @@ var VERITY_STOP_RE = /(?:^|[\/\s"'])verity\s+analyze\b/;
|
|
|
12263
12363
|
var VERITY_INTENT_RE = /(?:^|[\/\s"'])verity\s+intent\s+capture\b/;
|
|
12264
12364
|
var VERITY_GUARD_RE = /(?:^|[\/\s"'])verity\s+guard\b/;
|
|
12265
12365
|
var VERITY_BASELINE_RE = /(?:^|[\/\s"'])verity\s+baseline\s+capture\b/;
|
|
12366
|
+
var VERITY_COMPACT_RE = /(?:^|[\/\s"'])verity\s+compact\b/;
|
|
12367
|
+
var VERITY_SESSION_END_RE = /(?:^|[\/\s"'])verity\s+session\s+end\b/;
|
|
12266
12368
|
function isVerityGuardHook(entry) {
|
|
12267
12369
|
return VERITY_GUARD_RE.test(entry.command ?? "");
|
|
12268
12370
|
}
|
|
12269
12371
|
function isVerityBaselineHook(entry) {
|
|
12270
12372
|
return VERITY_BASELINE_RE.test(entry.command ?? "");
|
|
12271
12373
|
}
|
|
12374
|
+
function isVerityCompactHook(entry) {
|
|
12375
|
+
return VERITY_COMPACT_RE.test(entry.command ?? "");
|
|
12376
|
+
}
|
|
12377
|
+
function isVeritySessionEndHook(entry) {
|
|
12378
|
+
return VERITY_SESSION_END_RE.test(entry.command ?? "");
|
|
12379
|
+
}
|
|
12272
12380
|
var LEGACY_STOP_RE = /(?:^|[\/\s"'])gate\s+analyze\b/;
|
|
12273
12381
|
var LEGACY_INTENT_RE = /(?:^|[\/\s"'])gate\s+intent\s+capture\b/;
|
|
12274
12382
|
function isVerityStopHook(entry) {
|
|
@@ -12280,7 +12388,7 @@ function isVerityIntentHook(entry) {
|
|
|
12280
12388
|
return VERITY_INTENT_RE.test(c) || LEGACY_INTENT_RE.test(c) || c.includes(".verity/hooks/capture-intent.sh") || c.includes(".gate/hooks/capture-intent.sh");
|
|
12281
12389
|
}
|
|
12282
12390
|
function isVerityHook(entry) {
|
|
12283
|
-
return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
|
|
12391
|
+
return isVerityStopHook(entry) || isVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry) || isVerityCompactHook(entry) || isVeritySessionEndHook(entry);
|
|
12284
12392
|
}
|
|
12285
12393
|
function isCurrentVerityStopHook(entry) {
|
|
12286
12394
|
const c = entry.command ?? "";
|
|
@@ -12291,7 +12399,7 @@ function isCurrentVerityIntentHook(entry) {
|
|
|
12291
12399
|
return VERITY_INTENT_RE.test(c) || c.includes(".verity/hooks/capture-intent.sh");
|
|
12292
12400
|
}
|
|
12293
12401
|
function isCurrentVerityHook(entry) {
|
|
12294
|
-
return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry);
|
|
12402
|
+
return isCurrentVerityStopHook(entry) || isCurrentVerityIntentHook(entry) || isVerityGuardHook(entry) || isVerityBaselineHook(entry) || isVerityCompactHook(entry) || isVeritySessionEndHook(entry);
|
|
12295
12403
|
}
|
|
12296
12404
|
function settingsHasLegacyHook(settings) {
|
|
12297
12405
|
for (const groups of Object.values(settings.hooks ?? {})) {
|
|
@@ -12353,6 +12461,8 @@ async function checkAllVerityHooks() {
|
|
|
12353
12461
|
async function checkExternalVerityHooks() {
|
|
12354
12462
|
let stop = false;
|
|
12355
12463
|
let intent = false;
|
|
12464
|
+
let compact = false;
|
|
12465
|
+
let sessionEnd = false;
|
|
12356
12466
|
let guardOn = [];
|
|
12357
12467
|
for (const f of [SETTINGS_LOCAL_FILE, globalSettingsFile()]) {
|
|
12358
12468
|
let settings;
|
|
@@ -12364,9 +12474,11 @@ async function checkExternalVerityHooks() {
|
|
|
12364
12474
|
const r = checkVerityHooks(settings);
|
|
12365
12475
|
stop = stop || r.stop;
|
|
12366
12476
|
intent = intent || r.intent;
|
|
12477
|
+
compact = compact || r.compact;
|
|
12478
|
+
sessionEnd = sessionEnd || r.sessionEnd;
|
|
12367
12479
|
if (r.guardOn.length > guardOn.length) guardOn = r.guardOn;
|
|
12368
12480
|
}
|
|
12369
|
-
return { stop, intent, guardOn };
|
|
12481
|
+
return { stop, intent, compact, sessionEnd, guardOn };
|
|
12370
12482
|
}
|
|
12371
12483
|
async function checkAllVerityHooksDetailed() {
|
|
12372
12484
|
let stop = false;
|
|
@@ -12446,11 +12558,11 @@ function checkVerityHooks(settings) {
|
|
|
12446
12558
|
}
|
|
12447
12559
|
const compactGroups = hooks["PostCompact"] ?? [];
|
|
12448
12560
|
const hasCompact = compactGroups.some(
|
|
12449
|
-
(g) => g.hooks?.some((h) => h
|
|
12561
|
+
(g) => g.hooks?.some((h) => isVerityCompactHook(h))
|
|
12450
12562
|
);
|
|
12451
12563
|
const endGroups = hooks["SessionEnd"] ?? [];
|
|
12452
12564
|
const hasSessionEnd = endGroups.some(
|
|
12453
|
-
(g) => g.hooks?.some((h) => h
|
|
12565
|
+
(g) => g.hooks?.some((h) => isVeritySessionEndHook(h))
|
|
12454
12566
|
);
|
|
12455
12567
|
return {
|
|
12456
12568
|
stop: hasStop,
|
|
@@ -12564,6 +12676,8 @@ function reconcileMomentHooks(settings, moments, externalPresent = {
|
|
|
12564
12676
|
};
|
|
12565
12677
|
if (!externalPresent.intent) push("UserPromptSubmit", { hooks: [VERITY_INTENT_HOOK] });
|
|
12566
12678
|
push("SessionStart", { hooks: [VERITY_BASELINE_HOOK] });
|
|
12679
|
+
if (!externalPresent.compact) push("PostCompact", { hooks: [VERITY_COMPACT_HOOK] });
|
|
12680
|
+
if (!externalPresent.sessionEnd) push("SessionEnd", { hooks: [VERITY_SESSION_END_HOOK] });
|
|
12567
12681
|
if (moments.includes("stop") && !externalPresent.stop) {
|
|
12568
12682
|
push("Stop", { hooks: [VERITY_STOP_HOOK] });
|
|
12569
12683
|
}
|
|
@@ -13540,6 +13654,74 @@ var LEGACY_MD_END = "<!-- gate-memory:end -->";
|
|
|
13540
13654
|
var LEGACY_PRESERVE_START = "<!-- gate-memory:preserve -->";
|
|
13541
13655
|
var LEGACY_PRESERVE_END = "<!-- /gate-memory:preserve -->";
|
|
13542
13656
|
var CLAUDE_MD_PROSE = [
|
|
13657
|
+
"## Project Memory",
|
|
13658
|
+
"",
|
|
13659
|
+
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
13660
|
+
"non-trivial work, scan `.verity/memory/index.md` for decisions, gotchas, and patterns",
|
|
13661
|
+
"that may apply to the change you are about to make. Open specific node files via",
|
|
13662
|
+
"the Read tool when the title or scope suggests relevance.",
|
|
13663
|
+
"",
|
|
13664
|
+
"The graph is auto-maintained by Verity. Files at `.verity/memory/_archive/` are",
|
|
13665
|
+
"superseded \u2014 ignore them unless investigating history.",
|
|
13666
|
+
"",
|
|
13667
|
+
"## Quality gate: accepted risks",
|
|
13668
|
+
"",
|
|
13669
|
+
"When the Verity pre-commit/pre-push gate FAILs, fix the findings \u2014 that is the",
|
|
13670
|
+
'default. Use `verity waive <pattern-id> --file <path> --reason "\u2026"` ONLY to relay',
|
|
13671
|
+
"a risk a human has explicitly accepted: a named code-review finding, an ADR, or",
|
|
13672
|
+
"the user saying so in this conversation. The --reason must cite that source.",
|
|
13673
|
+
"",
|
|
13674
|
+
"Never waive on your own judgment, to get past a block, or pre-emptively. A waive",
|
|
13675
|
+
"binds to the file's current bytes and voids automatically when the file changes,",
|
|
13676
|
+
"and every waive is recorded in the run ledger. For a pattern-level false positive",
|
|
13677
|
+
"use `verity feedback finding <run-id> <pattern-id> false_positive` instead.",
|
|
13678
|
+
"",
|
|
13679
|
+
"## Post-task reflection",
|
|
13680
|
+
"",
|
|
13681
|
+
`When a task is complete (you've created a PR, the user says "done" or "ship it",`,
|
|
13682
|
+
"or the work is clearly finished), **draft the reflection yourself first** \u2014 1\u20133",
|
|
13683
|
+
"concrete things worth remembering (a decision, a gotcha, or a pattern), each",
|
|
13684
|
+
"cited with the files / PR / commands / error-signatures it came from. Skip",
|
|
13685
|
+
"entirely if nothing non-obvious happened.",
|
|
13686
|
+
"",
|
|
13687
|
+
"Then, depending on how the session is running:",
|
|
13688
|
+
"",
|
|
13689
|
+
"- **Interactive** (a person is at the keyboard): show your draft and ask one",
|
|
13690
|
+
` question before recording \u2014 "Here's my reflection draft for the project`,
|
|
13691
|
+
" memory: <draft>. Anything to confirm, correct, or add before I record it?",
|
|
13692
|
+
` (Say 'skip' to drop it.)" Record the final text (with their corrections) via`,
|
|
13693
|
+
' `verity reflect --user-input "<final reflection>" --kind <kind>`. If they say',
|
|
13694
|
+
' "skip", do not record.',
|
|
13695
|
+
"- **Autonomous** (headless / CI / cron, or `VERITY_AUTONOMOUS=1`): record your",
|
|
13696
|
+
' draft directly, never blocking \u2014 `verity reflect --user-input "<your draft>"',
|
|
13697
|
+
" --kind <kind> --autonomous`.",
|
|
13698
|
+
"",
|
|
13699
|
+
"> Durable, hand-curated guidance goes in the preserve region below (it survives",
|
|
13700
|
+
"> regeneration) or anywhere OUTSIDE these markers. Everything else between the",
|
|
13701
|
+
"> markers is tool-owned and overwritten on each run.",
|
|
13702
|
+
"",
|
|
13703
|
+
"## Housekeeping Turns",
|
|
13704
|
+
"",
|
|
13705
|
+
"When a turn will be pure housekeeping \u2014 pulling, installing dependencies,",
|
|
13706
|
+
"rebasing, a formatting sweep you are not authoring \u2014 declare it BEFORE doing it:",
|
|
13707
|
+
"",
|
|
13708
|
+
"```bash",
|
|
13709
|
+
'verity ignore --turn --agent --reason "pulling latest before starting"',
|
|
13710
|
+
"```",
|
|
13711
|
+
"",
|
|
13712
|
+
"This skips the review for that turn, which saves the turn Verity would",
|
|
13713
|
+
"otherwise spend saying it had nothing to say. Use `--for 30m` instead of",
|
|
13714
|
+
"`--turn` when a single piece of housekeeping spans several turns.",
|
|
13715
|
+
"",
|
|
13716
|
+
"**It is a claim about the turn, not a way to silence review.** The declaration",
|
|
13717
|
+
"is checked against what the turn actually did: if anything is authored \u2014 by you,",
|
|
13718
|
+
"by a subagent, or by a shell command that can write files \u2014 it voids, the review",
|
|
13719
|
+
"runs anyway, and the broken declaration is reported. So declare housekeeping you",
|
|
13720
|
+
"are about to do, never work you have already done, and never as a way to get past",
|
|
13721
|
+
"a finding. Declarations are budgeted per session and every one is recorded with",
|
|
13722
|
+
"its reason."
|
|
13723
|
+
].join("\n");
|
|
13724
|
+
var CLAUDE_MD_PROSE_PRE_REFLECT = [
|
|
13543
13725
|
"## Project Memory",
|
|
13544
13726
|
"",
|
|
13545
13727
|
"This project has a knowledge graph maintained at `.verity/memory/`. Before starting",
|
|
@@ -13750,6 +13932,7 @@ function stripKnownProse(interior) {
|
|
|
13750
13932
|
const trimmed = interior.replace(/^\n+/, "");
|
|
13751
13933
|
for (const prose of [
|
|
13752
13934
|
CLAUDE_MD_PROSE,
|
|
13935
|
+
CLAUDE_MD_PROSE_PRE_REFLECT,
|
|
13753
13936
|
CLAUDE_MD_PROSE_PRE_WAIVE,
|
|
13754
13937
|
CLAUDE_MD_PROSE_PRE_IGNORE,
|
|
13755
13938
|
CLAUDE_MD_PROSE_LEGACY
|
|
@@ -15795,33 +15978,6 @@ ${addedLines}`,
|
|
|
15795
15978
|
}
|
|
15796
15979
|
return { diffs, has_snapshots: true };
|
|
15797
15980
|
}
|
|
15798
|
-
function ensureSnapshotGitignored() {
|
|
15799
|
-
let content = "";
|
|
15800
|
-
try {
|
|
15801
|
-
content = (0, import_node_fs16.readFileSync)(".gitignore", "utf-8");
|
|
15802
|
-
} catch {
|
|
15803
|
-
}
|
|
15804
|
-
let ignored = null;
|
|
15805
|
-
try {
|
|
15806
|
-
(0, import_node_child_process6.execSync)("git check-ignore -q -- .verity/.snapshot/__probe__", { stdio: "pipe" });
|
|
15807
|
-
ignored = true;
|
|
15808
|
-
} catch (err) {
|
|
15809
|
-
ignored = err.status === 1 ? false : null;
|
|
15810
|
-
}
|
|
15811
|
-
if (ignored === true) return "covered";
|
|
15812
|
-
if (ignored === null) {
|
|
15813
|
-
const lines = content.split("\n").map((l) => l.trim());
|
|
15814
|
-
const covering = [".verity/.snapshot/", ".verity/.snapshot", ".verity/", ".verity", ".verity/*"];
|
|
15815
|
-
if (lines.some((l) => covering.includes(l))) return "covered";
|
|
15816
|
-
}
|
|
15817
|
-
try {
|
|
15818
|
-
const block = "# Verity \u2014 snapshots of analyzed files (machine state, never commit)\n.verity/.snapshot/\n";
|
|
15819
|
-
(0, import_node_fs16.writeFileSync)(".gitignore", content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block);
|
|
15820
|
-
return "added";
|
|
15821
|
-
} catch {
|
|
15822
|
-
return "failed";
|
|
15823
|
-
}
|
|
15824
|
-
}
|
|
15825
15981
|
function saveSnapshots(files) {
|
|
15826
15982
|
const snapshotPaths = /* @__PURE__ */ new Set();
|
|
15827
15983
|
for (const file of files) {
|
|
@@ -16743,19 +16899,19 @@ function loc(f) {
|
|
|
16743
16899
|
if (!f.file) return "";
|
|
16744
16900
|
return f.line != null ? `${f.file}:${f.line}` : f.file;
|
|
16745
16901
|
}
|
|
16746
|
-
function formatRunDetail(
|
|
16902
|
+
function formatRunDetail(run2) {
|
|
16747
16903
|
const lines = [];
|
|
16748
|
-
const q =
|
|
16749
|
-
const s =
|
|
16904
|
+
const q = run2.assessment?.quality_score;
|
|
16905
|
+
const s = run2.assessment?.security_score;
|
|
16750
16906
|
const qStr = q != null ? `${q}` : "-";
|
|
16751
16907
|
const sStr = s != null ? `${s}` : "-";
|
|
16752
|
-
lines.push(`${
|
|
16908
|
+
lines.push(`${run2.run_id} ${run2.gate_decision} Q ${qStr}/10 S ${sStr}/10`);
|
|
16753
16909
|
const meta = [];
|
|
16754
|
-
if (
|
|
16755
|
-
if (
|
|
16756
|
-
if (
|
|
16910
|
+
if (run2.trigger) meta.push(`trigger: ${run2.trigger}`);
|
|
16911
|
+
if (run2.standard_version != null) meta.push(`standard v${run2.standard_version}`);
|
|
16912
|
+
if (run2.created_at) meta.push(run2.created_at.slice(0, 19).replace("T", " "));
|
|
16757
16913
|
if (meta.length > 0) lines.push(meta.join(" \xB7 "));
|
|
16758
|
-
const findings =
|
|
16914
|
+
const findings = run2.findings ?? [];
|
|
16759
16915
|
if (findings.length === 0) {
|
|
16760
16916
|
lines.push("");
|
|
16761
16917
|
lines.push("No findings \u2014 clean.");
|
|
@@ -16772,7 +16928,7 @@ function formatRunDetail(run) {
|
|
|
16772
16928
|
if (f.scope === "pre-existing") lines.push(" (pre-existing)");
|
|
16773
16929
|
}
|
|
16774
16930
|
}
|
|
16775
|
-
const pending =
|
|
16931
|
+
const pending = run2.pending_items ?? [];
|
|
16776
16932
|
if (pending.length > 0) {
|
|
16777
16933
|
lines.push("");
|
|
16778
16934
|
lines.push(`PENDING (${pending.length})`);
|
|
@@ -16780,9 +16936,9 @@ function formatRunDetail(run) {
|
|
|
16780
16936
|
lines.push(` [${(p.priority ?? "").toUpperCase()}] ${p.description}`);
|
|
16781
16937
|
}
|
|
16782
16938
|
}
|
|
16783
|
-
if (
|
|
16939
|
+
if (run2.assessment?.narrative) {
|
|
16784
16940
|
lines.push("");
|
|
16785
|
-
lines.push(
|
|
16941
|
+
lines.push(run2.assessment.narrative);
|
|
16786
16942
|
}
|
|
16787
16943
|
return lines;
|
|
16788
16944
|
}
|
|
@@ -17154,7 +17310,7 @@ function registerStatusCommand(program2) {
|
|
|
17154
17310
|
return;
|
|
17155
17311
|
}
|
|
17156
17312
|
if (mem?.configured === false) {
|
|
17157
|
-
printInfo(
|
|
17313
|
+
printInfo('Verity is not configured for this project. Run "verity init".');
|
|
17158
17314
|
return;
|
|
17159
17315
|
}
|
|
17160
17316
|
printInfo("=== Verity Status ===");
|
|
@@ -17186,7 +17342,7 @@ function registerStatusCommand(program2) {
|
|
|
17186
17342
|
if (hookStatus.stop) moments.push("stop");
|
|
17187
17343
|
if (hookStatus.guardOn.includes("commit")) moments.push("pre-commit");
|
|
17188
17344
|
if (hookStatus.guardOn.includes("push")) moments.push("pre-push/PR");
|
|
17189
|
-
printInfo(`Moments: ${moments.length > 0 ? moments.join(", ") :
|
|
17345
|
+
printInfo(`Moments: ${moments.length > 0 ? moments.join(", ") : 'none (run "verity init")'}`);
|
|
17190
17346
|
if (!mem) return;
|
|
17191
17347
|
if (mem.recent_runs) {
|
|
17192
17348
|
const r = mem.recent_runs;
|
|
@@ -17272,12 +17428,12 @@ function registerStatusCommand(program2) {
|
|
|
17272
17428
|
printInfo("");
|
|
17273
17429
|
printInfo("--- Recent Runs ---");
|
|
17274
17430
|
printInfo(`${"Run ID".padEnd(32)} ${"Decision".padEnd(10)}${"Q".padEnd(4)}${"S".padEnd(4)}${"Findings".padEnd(32)}Date`);
|
|
17275
|
-
for (const
|
|
17276
|
-
const q =
|
|
17277
|
-
const s =
|
|
17278
|
-
const findings = formatFindingsSummary(
|
|
17279
|
-
const date =
|
|
17280
|
-
printInfo(`${
|
|
17431
|
+
for (const run2 of runsResult.data.runs) {
|
|
17432
|
+
const q = run2.quality_score != null ? `${run2.quality_score}` : "-";
|
|
17433
|
+
const s = run2.security_score != null ? `${run2.security_score}` : "-";
|
|
17434
|
+
const findings = formatFindingsSummary(run2.findings_count);
|
|
17435
|
+
const date = run2.created_at.slice(0, 19).replace("T", " ");
|
|
17436
|
+
printInfo(`${run2.run_id.padEnd(32)} ${run2.gate_decision.padEnd(10)}${q.padEnd(4)}${s.padEnd(4)}${findings.padEnd(32)}${date}`);
|
|
17281
17437
|
}
|
|
17282
17438
|
}
|
|
17283
17439
|
}
|
|
@@ -17412,7 +17568,6 @@ function createRun(opts, globals) {
|
|
|
17412
17568
|
token: "",
|
|
17413
17569
|
modeDecision: null,
|
|
17414
17570
|
sessionIdForMemory: "",
|
|
17415
|
-
contextFilePaths: [],
|
|
17416
17571
|
analysisMode: "standard",
|
|
17417
17572
|
sessionAuthoredCode: false,
|
|
17418
17573
|
staticResults: {
|
|
@@ -17422,6 +17577,7 @@ function createRun(opts, globals) {
|
|
|
17422
17577
|
},
|
|
17423
17578
|
codeDelta: { files: [], total_lines: 0, total_files: 0, excluded: [] },
|
|
17424
17579
|
snapshotResult: { has_snapshots: false, diffs: [] },
|
|
17580
|
+
repoContext: null,
|
|
17425
17581
|
contentHash: null,
|
|
17426
17582
|
iteration: 1,
|
|
17427
17583
|
currentCommit: "",
|
|
@@ -17513,35 +17669,35 @@ function row(label2, value) {
|
|
|
17513
17669
|
return ` \u25B8 ${label2.padEnd(10)} ${value}
|
|
17514
17670
|
`;
|
|
17515
17671
|
}
|
|
17516
|
-
function formatRunEvidence(
|
|
17672
|
+
function formatRunEvidence(run2, startedAt) {
|
|
17517
17673
|
const ms = Date.now() - startedAt;
|
|
17518
|
-
const sent =
|
|
17519
|
-
const context =
|
|
17674
|
+
const sent = run2.codeDelta.files.filter((f) => f.role !== "context").map((f) => f.path);
|
|
17675
|
+
const context = run2.codeDelta.files.filter((f) => f.role === "context").map((f) => f.path);
|
|
17520
17676
|
let out = ` \u2500\u2500 what verity saw \u2500\u2500
|
|
17521
17677
|
`;
|
|
17522
|
-
out += row("turn", `${
|
|
17523
|
-
out += row("reached", `${
|
|
17524
|
-
if (
|
|
17525
|
-
const f =
|
|
17678
|
+
out += row("turn", `${run2.turnId || "(unminted)"}${run2.sessionId ? ` \xB7 session ${run2.sessionId}` : ""}`);
|
|
17679
|
+
out += row("reached", `${run2.phaseReached || "(none)"}${run2.skipReason ? ` \xB7 SKIPPED: ${run2.skipReason}` : ""} \xB7 ${ms}ms`);
|
|
17680
|
+
if (run2.treeFrame) {
|
|
17681
|
+
const f = run2.treeFrame;
|
|
17526
17682
|
out += row("tree", f.worktreeRoot ? `${f.worktreeRoot}${f.isLinkedWorktree ? " \xB7 linked worktree" : ""}${f.branch ? ` \xB7 branch ${f.branch}` : " \xB7 detached"}` : `(unresolved: ${f.refusal ?? "unknown"})`);
|
|
17527
17683
|
}
|
|
17528
|
-
out += row("changed", `${
|
|
17529
|
-
const done = (phase) =>
|
|
17684
|
+
out += row("changed", `${run2.changedUniverse.length} from git \xB7 analyzable ${run2.analyzable.length} \xB7 reviewable ${run2.reviewable.length} \xB7 security ${run2.securityFiles.length} \xB7 forReview ${run2.allForReview.length}`);
|
|
17685
|
+
const done = (phase) => run2.phasesCompleted.includes(phase);
|
|
17530
17686
|
const ifDone = (phase, value) => done(phase) ? value : "?";
|
|
17531
|
-
const md =
|
|
17687
|
+
const md = run2.modeDecision;
|
|
17532
17688
|
if (md) {
|
|
17533
17689
|
const how = md.forced ? "forced by --mode" : `predicted=${md.predicted ?? "none"} \u2192 ${md.resolved}`;
|
|
17534
17690
|
out += row("mode", `${md.resolved} \xB7 ${how}` + (md.flip ? ` (flipped to plan: no delta at ${md.flip})` : "") + ` \xB7 authored=${md.authored ? "yes" : "no"} \xB7 investigated=${md.investigated ? "yes" : "no"}`);
|
|
17535
17691
|
} else {
|
|
17536
|
-
out += row("mode", `? (this run stopped in ${
|
|
17692
|
+
out += row("mode", `? (this run stopped in ${run2.phaseReached || "no phase"}, before the mode was decided)`);
|
|
17537
17693
|
}
|
|
17538
|
-
out += row("signals", `baseline=${ifDone("bootstrap",
|
|
17694
|
+
out += row("signals", `baseline=${ifDone("bootstrap", run2.baseline ? "yes" : "no")} \xB7 authored=${ifDone("intentInputs", run2.turnAuthoredCode ? "yes" : "no")} \xB7 observable=${ifDone("intentInputs", run2.authorshipIsObservable ? "yes" : "no")}` + (run2.actionSummary?.transcript_windowed ? ` \xB7 window=${run2.actionSummary.transcript_windowed}` : ""));
|
|
17539
17695
|
if (!done("intentInputs")) {
|
|
17540
|
-
out += row("", `(\`?\` = the phase that determines it did not complete \u2014 this run stopped in ${
|
|
17696
|
+
out += row("", `(\`?\` = the phase that determines it did not complete \u2014 this run stopped in ${run2.phaseReached})`);
|
|
17541
17697
|
}
|
|
17542
17698
|
out += row("sent", `${sent.length} \xB7 ${list(sent)}`);
|
|
17543
17699
|
if (context.length > 0) out += row("context", `${context.length} \xB7 ${list(context)}`);
|
|
17544
|
-
const withheld =
|
|
17700
|
+
const withheld = run2.reviewCoverage.notReviewed;
|
|
17545
17701
|
if (withheld.length > 0) {
|
|
17546
17702
|
const byReason = /* @__PURE__ */ new Map();
|
|
17547
17703
|
for (const w of withheld) {
|
|
@@ -17554,18 +17710,18 @@ function formatRunEvidence(run, startedAt) {
|
|
|
17554
17710
|
first = false;
|
|
17555
17711
|
}
|
|
17556
17712
|
} else {
|
|
17557
|
-
const sentSet = new Set(
|
|
17558
|
-
const notSent =
|
|
17713
|
+
const sentSet = new Set(run2.codeDelta.files.map((f) => f.path));
|
|
17714
|
+
const notSent = run2.changedUniverse.filter((p) => !sentSet.has(p));
|
|
17559
17715
|
if (notSent.length > 0) {
|
|
17560
17716
|
out += row("not sent", `${list(notSent)}`);
|
|
17561
|
-
out += row("", `(stage unknown \u2014 the coverage ledger is built in phase 13, and this run reached ${
|
|
17562
|
-
} else if (
|
|
17717
|
+
out += row("", `(stage unknown \u2014 the coverage ledger is built in phase 13, and this run reached ${run2.phaseReached || "no phase"})`);
|
|
17718
|
+
} else if (run2.changedUniverse.length > 0) {
|
|
17563
17719
|
out += row("withheld", "(nothing \u2014 every changed file was reviewed)");
|
|
17564
17720
|
}
|
|
17565
17721
|
}
|
|
17566
|
-
const cov =
|
|
17722
|
+
const cov = run2.foldResult?.coverage;
|
|
17567
17723
|
if (cov) {
|
|
17568
|
-
const delegated =
|
|
17724
|
+
const delegated = run2.foldResult.authored.filter((a) => a.owner === "subagent").length;
|
|
17569
17725
|
if (cov.dispatched > 0 || cov.subagentFiles > 0 || cov.subagentSkipped > 0) {
|
|
17570
17726
|
out += row("delegated", `${cov.dispatched} dispatched \xB7 ${cov.subagentFiles} agent log(s) read \xB7 ${delegated} path(s) attributed to subagents`);
|
|
17571
17727
|
}
|
|
@@ -17579,54 +17735,740 @@ function formatRunEvidence(run, startedAt) {
|
|
|
17579
17735
|
out += row("", `${cov.outsideRepo} authored path(s) refused as outside the repo`);
|
|
17580
17736
|
}
|
|
17581
17737
|
}
|
|
17582
|
-
if (
|
|
17583
|
-
const shown =
|
|
17738
|
+
if (run2.foldResult?.tools?.length) {
|
|
17739
|
+
const shown = run2.foldResult.tools.slice(0, 6).map((t) => {
|
|
17584
17740
|
const outcome = t.failed > 0 ? `${t.failed} failed` : t.last_status === 0 ? "ok" : "?";
|
|
17585
17741
|
const where = t.targets.length > 0 ? ` \u2192 ${t.targets.slice(0, 2).join(", ")}` : "";
|
|
17586
17742
|
return `${t.runs}\xD7 ${t.name} (${outcome})${where}`;
|
|
17587
17743
|
});
|
|
17588
|
-
const more =
|
|
17744
|
+
const more = run2.foldResult.tools.length > 6 ? ` \u2026 +${run2.foldResult.tools.length - 6} more` : "";
|
|
17589
17745
|
out += row("tools", shown.join(" \xB7 ") + more);
|
|
17590
|
-
if (
|
|
17591
|
-
out += row("", `\u26A0 ${
|
|
17746
|
+
if (run2.foldResult.coverage.toolNamesDropped > 0) {
|
|
17747
|
+
out += row("", `\u26A0 ${run2.foldResult.coverage.toolNamesDropped} tool name(s) refused by the cap`);
|
|
17592
17748
|
}
|
|
17593
17749
|
}
|
|
17594
|
-
if (
|
|
17595
|
-
const t =
|
|
17750
|
+
if (run2.foldResult?.tasks?.length) {
|
|
17751
|
+
const t = run2.foldResult.tasks;
|
|
17596
17752
|
const done2 = t.filter((x) => x.status === "completed").length;
|
|
17597
17753
|
out += row("tasks", `${t.length} \xB7 ${done2} completed \xB7 ` + list(t.slice(0, 4).map((x) => `#${x.id} ${x.name} [${x.status}]`), 4));
|
|
17598
17754
|
}
|
|
17599
|
-
if (
|
|
17600
|
-
const readThisSession = new Set(
|
|
17601
|
-
const labelled =
|
|
17755
|
+
if (run2.specs?.length) {
|
|
17756
|
+
const readThisSession = new Set(run2.actionSummary?.files_read ?? []);
|
|
17757
|
+
const labelled = run2.specs.map(
|
|
17602
17758
|
(s) => `${s.path}${readThisSession.has(s.path) ? " (read)" : " (positional)"}`
|
|
17603
17759
|
);
|
|
17604
|
-
out += row("specs", `${
|
|
17760
|
+
out += row("specs", `${run2.specs.length} \xB7 ${list(labelled, 5)}`);
|
|
17605
17761
|
}
|
|
17606
|
-
if (
|
|
17607
|
-
out += row("static", `${
|
|
17762
|
+
if (run2.staticResults.findings.length > 0) {
|
|
17763
|
+
out += row("static", `${run2.staticResults.findings.length} finding(s) from ${run2.staticResults.summary.tools_run.join(", ") || "no tools"}`);
|
|
17608
17764
|
}
|
|
17609
|
-
if (
|
|
17610
|
-
out += row("verdict",
|
|
17765
|
+
if (run2.decision && run2.decision !== "(unrecognised)") {
|
|
17766
|
+
out += row("verdict", run2.decision + (run2.silenced ? ` \xB7 agent channel silenced (${run2.silenced})` : ""));
|
|
17611
17767
|
}
|
|
17612
17768
|
return out;
|
|
17613
17769
|
}
|
|
17614
|
-
function installRunEvidence(
|
|
17770
|
+
function installRunEvidence(run2) {
|
|
17615
17771
|
const startedAt = Date.now();
|
|
17616
17772
|
process.on("exit", () => {
|
|
17617
17773
|
try {
|
|
17618
|
-
logToFileOnly(formatRunEvidence(
|
|
17774
|
+
logToFileOnly(formatRunEvidence(run2, startedAt));
|
|
17619
17775
|
} catch {
|
|
17620
17776
|
}
|
|
17621
17777
|
});
|
|
17622
17778
|
}
|
|
17623
17779
|
|
|
17624
17780
|
// src/lib/git-frame.ts
|
|
17625
|
-
var
|
|
17781
|
+
var import_node_child_process8 = require("node:child_process");
|
|
17626
17782
|
var import_node_fs24 = require("node:fs");
|
|
17627
|
-
var
|
|
17783
|
+
var import_node_os4 = require("node:os");
|
|
17628
17784
|
var import_node_path18 = require("node:path");
|
|
17629
17785
|
var import_node_path19 = require("node:path");
|
|
17786
|
+
|
|
17787
|
+
// src/lib/repo-context.ts
|
|
17788
|
+
var import_node_child_process7 = require("node:child_process");
|
|
17789
|
+
var import_node_os3 = require("node:os");
|
|
17790
|
+
function rgInvocations(env = process.env) {
|
|
17791
|
+
const out = [{ cmd: "rg" }];
|
|
17792
|
+
if (env.CLAUDE_CODE_EXECPATH) out.push({ cmd: env.CLAUDE_CODE_EXECPATH, argv0: "rg" });
|
|
17793
|
+
out.push({ cmd: `${(0, import_node_os3.homedir)()}/.local/bin/claude`, argv0: "rg" });
|
|
17794
|
+
return out;
|
|
17795
|
+
}
|
|
17796
|
+
var MAX_SYMBOLS = 12;
|
|
17797
|
+
var MAX_SITES = 24;
|
|
17798
|
+
var MAX_SITES_PER_FILE = 3;
|
|
17799
|
+
var MAX_HITS_PER_SYMBOL = 50;
|
|
17800
|
+
var MAX_TEST_SLOTS = 8;
|
|
17801
|
+
var SITE_TEXT_MAX = 160;
|
|
17802
|
+
var ENCLOSING_SCAN_LINES = 200;
|
|
17803
|
+
var RG_TIMEOUT_MS = 1500;
|
|
17804
|
+
var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17805
|
+
var STOPLIST = /* @__PURE__ */ new Set([
|
|
17806
|
+
// keyword-shaped captures
|
|
17807
|
+
"if",
|
|
17808
|
+
"for",
|
|
17809
|
+
"while",
|
|
17810
|
+
"switch",
|
|
17811
|
+
"catch",
|
|
17812
|
+
"return",
|
|
17813
|
+
"function",
|
|
17814
|
+
"class",
|
|
17815
|
+
"const",
|
|
17816
|
+
"let",
|
|
17817
|
+
"var",
|
|
17818
|
+
"new",
|
|
17819
|
+
"else",
|
|
17820
|
+
"try",
|
|
17821
|
+
"finally",
|
|
17822
|
+
"throw",
|
|
17823
|
+
"await",
|
|
17824
|
+
"async",
|
|
17825
|
+
"yield",
|
|
17826
|
+
"delete",
|
|
17827
|
+
"typeof",
|
|
17828
|
+
"instanceof",
|
|
17829
|
+
"void",
|
|
17830
|
+
"this",
|
|
17831
|
+
"super",
|
|
17832
|
+
"import",
|
|
17833
|
+
"export",
|
|
17834
|
+
"default",
|
|
17835
|
+
"extends",
|
|
17836
|
+
"implements",
|
|
17837
|
+
"interface",
|
|
17838
|
+
"enum",
|
|
17839
|
+
"type",
|
|
17840
|
+
"public",
|
|
17841
|
+
"private",
|
|
17842
|
+
"protected",
|
|
17843
|
+
"static",
|
|
17844
|
+
"get",
|
|
17845
|
+
"set",
|
|
17846
|
+
"constructor",
|
|
17847
|
+
"def",
|
|
17848
|
+
"elif",
|
|
17849
|
+
"lambda",
|
|
17850
|
+
"with",
|
|
17851
|
+
"pass",
|
|
17852
|
+
"self",
|
|
17853
|
+
"cls",
|
|
17854
|
+
"not",
|
|
17855
|
+
"and",
|
|
17856
|
+
"or",
|
|
17857
|
+
"raise",
|
|
17858
|
+
"except",
|
|
17859
|
+
"func",
|
|
17860
|
+
"defer",
|
|
17861
|
+
"chan",
|
|
17862
|
+
"select",
|
|
17863
|
+
"range",
|
|
17864
|
+
"module",
|
|
17865
|
+
"struct",
|
|
17866
|
+
"trait",
|
|
17867
|
+
"impl",
|
|
17868
|
+
"using",
|
|
17869
|
+
"namespace",
|
|
17870
|
+
// universal noise
|
|
17871
|
+
"main",
|
|
17872
|
+
"init",
|
|
17873
|
+
"index",
|
|
17874
|
+
"data",
|
|
17875
|
+
"value",
|
|
17876
|
+
"result",
|
|
17877
|
+
"item",
|
|
17878
|
+
"name",
|
|
17879
|
+
"key",
|
|
17880
|
+
"run",
|
|
17881
|
+
"test",
|
|
17882
|
+
"setup",
|
|
17883
|
+
"update",
|
|
17884
|
+
"create",
|
|
17885
|
+
"handle",
|
|
17886
|
+
"check",
|
|
17887
|
+
"load",
|
|
17888
|
+
"save",
|
|
17889
|
+
"list",
|
|
17890
|
+
"map",
|
|
17891
|
+
"args",
|
|
17892
|
+
"params",
|
|
17893
|
+
"props",
|
|
17894
|
+
"state",
|
|
17895
|
+
"error",
|
|
17896
|
+
"err",
|
|
17897
|
+
"res",
|
|
17898
|
+
"req",
|
|
17899
|
+
"ctx",
|
|
17900
|
+
"config",
|
|
17901
|
+
"options",
|
|
17902
|
+
"util",
|
|
17903
|
+
"utils",
|
|
17904
|
+
"helper",
|
|
17905
|
+
"render",
|
|
17906
|
+
"build",
|
|
17907
|
+
"parse",
|
|
17908
|
+
"format",
|
|
17909
|
+
"apply",
|
|
17910
|
+
"process",
|
|
17911
|
+
"start",
|
|
17912
|
+
"stop"
|
|
17913
|
+
]);
|
|
17914
|
+
var TS_RULES = [
|
|
17915
|
+
/\b(?:function|class|interface|enum)\s+([A-Za-z_][A-Za-z0-9_]*)/,
|
|
17916
|
+
/\btype\s+([A-Za-z_][A-Za-z0-9_]*)\s*=/,
|
|
17917
|
+
// const foo = (…) => · const foo = x => · const foo = function.
|
|
17918
|
+
// ⚠ REQUIRES the arrow or `function` ON THE LINE. The first version accepted
|
|
17919
|
+
// any `= (` — and `const started = (rows?.[0] as Row)?.at` is a PARENTHESIZED
|
|
17920
|
+
// CAST, not a function. Replayed over 12 real commits, that one shape put
|
|
17921
|
+
// three local variables into the symbol set per commit. A multi-line arrow
|
|
17922
|
+
// is the accepted false negative; a cast is not an accepted false positive.
|
|
17923
|
+
/\b(?:const|let|var)\s+([A-Za-z_][A-Za-z0-9_]*)\s*(?::[^=\n]+)?=\s*(?:async\s+)?(?:function\b|\([^)]*\)(?:\s*:[^=\n]+)?\s*=>|[A-Za-z_$][\w$]*\s*=>)/,
|
|
17924
|
+
// method shape: name(…) { — keyword captures die at the stoplist
|
|
17925
|
+
/^\s*(?:(?:public|private|protected|static|readonly|async|override)\s+)*(?:\*\s*)?([A-Za-z_][A-Za-z0-9_]*)\s*\([^)]*\)\s*(?::[^{;\n]+)?\s*\{/
|
|
17926
|
+
];
|
|
17927
|
+
var PY_RULES = [
|
|
17928
|
+
/^\s*(?:async\s+)?def\s+([A-Za-z_]\w*)/,
|
|
17929
|
+
/^\s*class\s+([A-Za-z_]\w*)/
|
|
17930
|
+
];
|
|
17931
|
+
var GO_RULES = [
|
|
17932
|
+
/^func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)/,
|
|
17933
|
+
/^type\s+([A-Za-z_]\w*)/
|
|
17934
|
+
];
|
|
17935
|
+
var CLIKE_RULES = [
|
|
17936
|
+
/\b(?:class|interface|enum|record|struct)\s+([A-Za-z_]\w*)/,
|
|
17937
|
+
// access-modifier method shape: `public async Task<Foo> BarBaz(…`
|
|
17938
|
+
/(?:public|private|protected|internal|static|final|virtual|override|sealed|abstract)[\w<>[\],?\s]*?\s([A-Za-z_]\w*)\s*\(/
|
|
17939
|
+
];
|
|
17940
|
+
var RB_RULES = [
|
|
17941
|
+
/^\s*def\s+(?:self\.)?([A-Za-z_]\w*)/,
|
|
17942
|
+
/^\s*(?:class|module)\s+([A-Z]\w*)/
|
|
17943
|
+
];
|
|
17944
|
+
var RS_RULES = [
|
|
17945
|
+
/\bfn\s+([A-Za-z_]\w*)/,
|
|
17946
|
+
/\b(?:struct|enum|trait)\s+([A-Za-z_]\w*)/
|
|
17947
|
+
];
|
|
17948
|
+
var PHP_RULES = [
|
|
17949
|
+
/\bfunction\s+([A-Za-z_]\w*)/,
|
|
17950
|
+
/\bclass\s+([A-Za-z_]\w*)/
|
|
17951
|
+
];
|
|
17952
|
+
var C_RULES = [
|
|
17953
|
+
/^(?:static\s+|inline\s+|extern\s+|constexpr\s+)*(?:struct\s+|enum\s+|union\s+|unsigned\s+|const\s+)*[A-Za-z_]\w*(?:\s*[*&]+\s*|\s+)([A-Za-z_]\w*)\s*\([^;]*$/,
|
|
17954
|
+
/\b(?:struct|enum|union|class)\s+([A-Za-z_]\w*)/,
|
|
17955
|
+
/::\s*~?([A-Za-z_]\w*)\s*\([^;]*$/
|
|
17956
|
+
// out-of-line C++ method definition
|
|
17957
|
+
];
|
|
17958
|
+
var SH_RULES = [
|
|
17959
|
+
/^\s*(?:function\s+)?([A-Za-z_]\w*)\s*\(\)\s*\{/,
|
|
17960
|
+
/^function\s+([A-Za-z_]\w*)/
|
|
17961
|
+
];
|
|
17962
|
+
var SQL_RULES = [
|
|
17963
|
+
/\bcreate\s+(?:or\s+replace\s+)?(?:table|view|materialized\s+view|function|procedure|index|trigger|type|policy)\s+(?:if\s+not\s+exists\s+)?(?:[\w".]*\.)?"?([A-Za-z_]\w*)"?/i
|
|
17964
|
+
];
|
|
17965
|
+
var TF_RULES = [
|
|
17966
|
+
/^\s*(?:resource|data)\s+"[^"]+"\s+"([A-Za-z_]\w*)"/,
|
|
17967
|
+
/^\s*(?:module|variable|output)\s+"([A-Za-z_]\w*)"/
|
|
17968
|
+
];
|
|
17969
|
+
var SWIFT_RULES = [
|
|
17970
|
+
/\bfunc\s+([A-Za-z_]\w*)/,
|
|
17971
|
+
/\b(?:class|struct|enum|protocol|extension|actor)\s+([A-Za-z_]\w*)/
|
|
17972
|
+
];
|
|
17973
|
+
var DART_RULES = [
|
|
17974
|
+
/\b(?:class|enum|mixin|extension)\s+([A-Za-z_]\w*)/,
|
|
17975
|
+
/^\s*(?:static\s+)?(?:Future<[^>]*>|Stream<[^>]*>|void|int|double|bool|String|num|dynamic|[A-Z]\w*(?:<[^>]*>)?)\s+([a-z_]\w*)\s*\(/
|
|
17976
|
+
];
|
|
17977
|
+
var LUA_RULES = [
|
|
17978
|
+
/^\s*(?:local\s+)?function\s+(?:[\w.]+[.:])?([A-Za-z_]\w*)/
|
|
17979
|
+
];
|
|
17980
|
+
var EX_RULES = [
|
|
17981
|
+
/^\s*def(?:p|macro)?\s+([a-z_]\w*)/,
|
|
17982
|
+
/^\s*defmodule\s+(?:[\w.]*\.)?([A-Z]\w*)/
|
|
17983
|
+
];
|
|
17984
|
+
var PROTO_RULES = [
|
|
17985
|
+
/^\s*(?:message|service|enum)\s+([A-Za-z_]\w*)/,
|
|
17986
|
+
/^\s*rpc\s+([A-Za-z_]\w*)/
|
|
17987
|
+
];
|
|
17988
|
+
var GRAPHQL_RULES = [
|
|
17989
|
+
/^\s*(?:type|interface|enum|input|union|scalar)\s+([A-Za-z_]\w*)/
|
|
17990
|
+
];
|
|
17991
|
+
var RULES_BY_EXT = {
|
|
17992
|
+
ts: TS_RULES,
|
|
17993
|
+
tsx: TS_RULES,
|
|
17994
|
+
js: TS_RULES,
|
|
17995
|
+
jsx: TS_RULES,
|
|
17996
|
+
mjs: TS_RULES,
|
|
17997
|
+
cjs: TS_RULES,
|
|
17998
|
+
svelte: TS_RULES,
|
|
17999
|
+
vue: TS_RULES,
|
|
18000
|
+
// script blocks
|
|
18001
|
+
py: PY_RULES,
|
|
18002
|
+
go: GO_RULES,
|
|
18003
|
+
java: CLIKE_RULES,
|
|
18004
|
+
cs: CLIKE_RULES,
|
|
18005
|
+
kt: CLIKE_RULES,
|
|
18006
|
+
scala: CLIKE_RULES,
|
|
18007
|
+
rb: RB_RULES,
|
|
18008
|
+
rs: RS_RULES,
|
|
18009
|
+
php: PHP_RULES,
|
|
18010
|
+
c: C_RULES,
|
|
18011
|
+
cpp: C_RULES,
|
|
18012
|
+
cc: C_RULES,
|
|
18013
|
+
h: C_RULES,
|
|
18014
|
+
hpp: C_RULES,
|
|
18015
|
+
sh: SH_RULES,
|
|
18016
|
+
bash: SH_RULES,
|
|
18017
|
+
zsh: SH_RULES,
|
|
18018
|
+
sql: SQL_RULES,
|
|
18019
|
+
tf: TF_RULES,
|
|
18020
|
+
hcl: TF_RULES,
|
|
18021
|
+
swift: SWIFT_RULES,
|
|
18022
|
+
dart: DART_RULES,
|
|
18023
|
+
lua: LUA_RULES,
|
|
18024
|
+
ex: EX_RULES,
|
|
18025
|
+
exs: EX_RULES,
|
|
18026
|
+
proto: PROTO_RULES,
|
|
18027
|
+
graphql: GRAPHQL_RULES,
|
|
18028
|
+
gql: GRAPHQL_RULES
|
|
18029
|
+
};
|
|
18030
|
+
var HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
18031
|
+
function parseDiffSignals(diff) {
|
|
18032
|
+
const addedRanges = [];
|
|
18033
|
+
const touchPoints = [];
|
|
18034
|
+
const deletedLines = [];
|
|
18035
|
+
let newLine = 0;
|
|
18036
|
+
let oldRemaining = 0;
|
|
18037
|
+
let newRemaining = 0;
|
|
18038
|
+
let runStart = -1;
|
|
18039
|
+
let deletionRun = false;
|
|
18040
|
+
const closeAddedRun = () => {
|
|
18041
|
+
if (runStart >= 0) addedRanges.push([runStart, newLine - 1]);
|
|
18042
|
+
runStart = -1;
|
|
18043
|
+
};
|
|
18044
|
+
const closeDeletionRun = () => {
|
|
18045
|
+
if (deletionRun) touchPoints.push(Math.max(1, newLine));
|
|
18046
|
+
deletionRun = false;
|
|
18047
|
+
};
|
|
18048
|
+
for (const line of diff.split("\n")) {
|
|
18049
|
+
const inHunk = oldRemaining > 0 || newRemaining > 0;
|
|
18050
|
+
if (!inHunk) {
|
|
18051
|
+
closeAddedRun();
|
|
18052
|
+
closeDeletionRun();
|
|
18053
|
+
const header = HUNK_HEADER.exec(line);
|
|
18054
|
+
if (header) {
|
|
18055
|
+
newLine = parseInt(header[3], 10);
|
|
18056
|
+
oldRemaining = header[2] === void 0 ? 1 : parseInt(header[2], 10);
|
|
18057
|
+
newRemaining = header[4] === void 0 ? 1 : parseInt(header[4], 10);
|
|
18058
|
+
if (newRemaining === 0) newLine = Math.max(1, newLine);
|
|
18059
|
+
}
|
|
18060
|
+
continue;
|
|
18061
|
+
}
|
|
18062
|
+
if (line.startsWith("\\")) continue;
|
|
18063
|
+
if (line.startsWith("+") && newRemaining > 0) {
|
|
18064
|
+
deletionRun = false;
|
|
18065
|
+
if (runStart < 0) runStart = newLine;
|
|
18066
|
+
newLine++;
|
|
18067
|
+
newRemaining--;
|
|
18068
|
+
continue;
|
|
18069
|
+
}
|
|
18070
|
+
if (line.startsWith("-") && oldRemaining > 0) {
|
|
18071
|
+
closeAddedRun();
|
|
18072
|
+
deletionRun = true;
|
|
18073
|
+
deletedLines.push(line.slice(1));
|
|
18074
|
+
oldRemaining--;
|
|
18075
|
+
continue;
|
|
18076
|
+
}
|
|
18077
|
+
closeAddedRun();
|
|
18078
|
+
closeDeletionRun();
|
|
18079
|
+
newLine++;
|
|
18080
|
+
if (oldRemaining > 0) oldRemaining--;
|
|
18081
|
+
if (newRemaining > 0) newRemaining--;
|
|
18082
|
+
}
|
|
18083
|
+
closeAddedRun();
|
|
18084
|
+
closeDeletionRun();
|
|
18085
|
+
return { addedRanges, touchPoints, deletedLines };
|
|
18086
|
+
}
|
|
18087
|
+
function declNameOn(line, rules) {
|
|
18088
|
+
for (const r of rules) {
|
|
18089
|
+
const m = r.exec(line);
|
|
18090
|
+
if (m?.[1]) return m[1];
|
|
18091
|
+
}
|
|
18092
|
+
return null;
|
|
18093
|
+
}
|
|
18094
|
+
function acceptable(name) {
|
|
18095
|
+
if (!name || !IDENTIFIER.test(name) || STOPLIST.has(name.toLowerCase())) return false;
|
|
18096
|
+
if (name.length < 3) return false;
|
|
18097
|
+
if (name.length === 3 && name === name.toLowerCase() && !name.includes("_")) return false;
|
|
18098
|
+
return true;
|
|
18099
|
+
}
|
|
18100
|
+
function isMultiSegment(name) {
|
|
18101
|
+
return /[a-z][A-Z]/.test(name) || name.includes("_");
|
|
18102
|
+
}
|
|
18103
|
+
function extractFileSymbols(path, content, signals) {
|
|
18104
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18105
|
+
const rules = RULES_BY_EXT[ext];
|
|
18106
|
+
if (!rules) return [];
|
|
18107
|
+
if (signals.addedRanges.length === 0 && signals.touchPoints.length === 0 && signals.deletedLines.length === 0) return [];
|
|
18108
|
+
const lines = content.split("\n");
|
|
18109
|
+
const found = [];
|
|
18110
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18111
|
+
const add = (name) => {
|
|
18112
|
+
if (acceptable(name) && !seen.has(name)) {
|
|
18113
|
+
seen.add(name);
|
|
18114
|
+
found.push(name);
|
|
18115
|
+
}
|
|
18116
|
+
};
|
|
18117
|
+
for (const deleted of signals.deletedLines) {
|
|
18118
|
+
add(declNameOn(deleted, rules));
|
|
18119
|
+
}
|
|
18120
|
+
for (const [start, end] of signals.addedRanges) {
|
|
18121
|
+
for (let n = start; n <= Math.min(end, lines.length); n++) {
|
|
18122
|
+
add(declNameOn(lines[n - 1] ?? "", rules));
|
|
18123
|
+
}
|
|
18124
|
+
}
|
|
18125
|
+
const scanStarts = [
|
|
18126
|
+
...signals.addedRanges.map(([start]) => start),
|
|
18127
|
+
...signals.touchPoints
|
|
18128
|
+
];
|
|
18129
|
+
for (const start of scanStarts) {
|
|
18130
|
+
const floor = Math.max(1, start - ENCLOSING_SCAN_LINES);
|
|
18131
|
+
for (let n = Math.min(start, lines.length); n >= floor; n--) {
|
|
18132
|
+
const name = declNameOn(lines[n - 1] ?? "", rules);
|
|
18133
|
+
if (acceptable(name)) {
|
|
18134
|
+
add(name);
|
|
18135
|
+
break;
|
|
18136
|
+
}
|
|
18137
|
+
}
|
|
18138
|
+
}
|
|
18139
|
+
return found;
|
|
18140
|
+
}
|
|
18141
|
+
function rankSymbols(symbols) {
|
|
18142
|
+
return symbols.map((s, i) => ({ s, i })).sort((a, b) => {
|
|
18143
|
+
const seg = Number(isMultiSegment(b.s)) - Number(isMultiSegment(a.s));
|
|
18144
|
+
if (seg !== 0) return seg;
|
|
18145
|
+
if (b.s.length !== a.s.length) return b.s.length - a.s.length;
|
|
18146
|
+
return a.i - b.i;
|
|
18147
|
+
}).slice(0, MAX_SYMBOLS).map((x) => x.s);
|
|
18148
|
+
}
|
|
18149
|
+
var TEST_PATH = /(^|\/)(tests?|specs?|__tests__|e2e)(\/|$)/i;
|
|
18150
|
+
var TEST_FILE = /(\.(test|spec|e2e)\.[^./]+|_test\.[^./]+|_spec\.rb)$/i;
|
|
18151
|
+
var TEST_PY_PREFIX = /(^|\/)test_[^/]+\.py$/i;
|
|
18152
|
+
var IMPORT_LINE = /^\s*(import\s|from\s+\S+\s+import\s|const\s+.*=\s*require\s*\(|require\s*\(|using\s+[\w.]+;|#include|export\s+\{[^}]*\}\s+from|export\s+\*\s+from)/;
|
|
18153
|
+
var BARE_MEMBER_LINE = /^(type\s+)?[A-Za-z_$][\w$]*\s*,?$/;
|
|
18154
|
+
var GO_IMPORT_PATH_LINE = /^"[^"]+",?$/;
|
|
18155
|
+
var SITE_CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
18156
|
+
"ts",
|
|
18157
|
+
"tsx",
|
|
18158
|
+
"js",
|
|
18159
|
+
"jsx",
|
|
18160
|
+
"mjs",
|
|
18161
|
+
"cjs",
|
|
18162
|
+
"py",
|
|
18163
|
+
"go",
|
|
18164
|
+
"java",
|
|
18165
|
+
"kt",
|
|
18166
|
+
"rb",
|
|
18167
|
+
"rs",
|
|
18168
|
+
"scala",
|
|
18169
|
+
"c",
|
|
18170
|
+
"cpp",
|
|
18171
|
+
"cc",
|
|
18172
|
+
"h",
|
|
18173
|
+
"hpp",
|
|
18174
|
+
"cs",
|
|
18175
|
+
"php",
|
|
18176
|
+
"swift",
|
|
18177
|
+
"dart",
|
|
18178
|
+
"lua",
|
|
18179
|
+
"sh",
|
|
18180
|
+
"bash",
|
|
18181
|
+
"zsh",
|
|
18182
|
+
"svelte",
|
|
18183
|
+
"vue",
|
|
18184
|
+
"ex",
|
|
18185
|
+
"exs",
|
|
18186
|
+
// sql/tf carry REAL call sites (SELECT my_function(...), module.name) —
|
|
18187
|
+
// excluded in an earlier round because of migration-comment noise, which the
|
|
18188
|
+
// COMMENT_LINE filter now handles on its own.
|
|
18189
|
+
"sql",
|
|
18190
|
+
"tf",
|
|
18191
|
+
"hcl"
|
|
18192
|
+
]);
|
|
18193
|
+
var COMMENT_LINE = /^(\/\/|#(?!\[)|\*|\/\*|--\s|<!--)/;
|
|
18194
|
+
function isCodeSiteFile(path) {
|
|
18195
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18196
|
+
return SITE_CODE_EXTENSIONS.has(ext);
|
|
18197
|
+
}
|
|
18198
|
+
function isTestPath(path) {
|
|
18199
|
+
return TEST_PATH.test(path) || TEST_FILE.test(path) || TEST_PY_PREFIX.test(path);
|
|
18200
|
+
}
|
|
18201
|
+
function parseRgLine(line) {
|
|
18202
|
+
const first = line.indexOf(":");
|
|
18203
|
+
if (first <= 0) return null;
|
|
18204
|
+
const second = line.indexOf(":", first + 1);
|
|
18205
|
+
if (second < 0) return null;
|
|
18206
|
+
const n = parseInt(line.slice(first + 1, second), 10);
|
|
18207
|
+
if (!Number.isFinite(n) || n < 1) return null;
|
|
18208
|
+
return { file: line.slice(0, first), line: n, text: line.slice(second + 1) };
|
|
18209
|
+
}
|
|
18210
|
+
var isWordChar = (c) => c !== void 0 && /[A-Za-z0-9_]/.test(c);
|
|
18211
|
+
function wordHit(text, symbol) {
|
|
18212
|
+
let from = 0;
|
|
18213
|
+
for (; ; ) {
|
|
18214
|
+
const at = text.indexOf(symbol, from);
|
|
18215
|
+
if (at < 0) return false;
|
|
18216
|
+
const before = at === 0 ? void 0 : text[at - 1];
|
|
18217
|
+
const after = text[at + symbol.length];
|
|
18218
|
+
if (!isWordChar(before) && !isWordChar(after)) return true;
|
|
18219
|
+
from = at + 1;
|
|
18220
|
+
}
|
|
18221
|
+
}
|
|
18222
|
+
function isContractLine(text, symbol) {
|
|
18223
|
+
for (const kw of ["implements", "extends"]) {
|
|
18224
|
+
let from = 0;
|
|
18225
|
+
for (; ; ) {
|
|
18226
|
+
const at = text.indexOf(kw, from);
|
|
18227
|
+
if (at < 0) break;
|
|
18228
|
+
from = at + 1;
|
|
18229
|
+
const before = at === 0 ? void 0 : text[at - 1];
|
|
18230
|
+
const after = text[at + kw.length];
|
|
18231
|
+
if (isWordChar(before) || isWordChar(after)) continue;
|
|
18232
|
+
let clause = text.slice(at + kw.length);
|
|
18233
|
+
const stop = Math.min(
|
|
18234
|
+
...[clause.indexOf(";"), clause.indexOf("{")].filter((i) => i >= 0)
|
|
18235
|
+
);
|
|
18236
|
+
if (Number.isFinite(stop)) clause = clause.slice(0, stop);
|
|
18237
|
+
if (wordHit(clause, symbol)) return true;
|
|
18238
|
+
}
|
|
18239
|
+
}
|
|
18240
|
+
return false;
|
|
18241
|
+
}
|
|
18242
|
+
function partitionSites(rgLines, symbols, opts) {
|
|
18243
|
+
const hits = [];
|
|
18244
|
+
const hitCount = /* @__PURE__ */ new Map();
|
|
18245
|
+
for (const line of rgLines) {
|
|
18246
|
+
const hit = parseRgLine(line);
|
|
18247
|
+
if (!hit) continue;
|
|
18248
|
+
const matched = symbols.filter((s) => wordHit(hit.text, s));
|
|
18249
|
+
for (const s of matched) hitCount.set(s, (hitCount.get(s) ?? 0) + 1);
|
|
18250
|
+
if (matched.length === 0) continue;
|
|
18251
|
+
hits.push({ ...hit, symbol: matched[0] });
|
|
18252
|
+
}
|
|
18253
|
+
hits.sort((a, b) => a.file < b.file ? -1 : a.file > b.file ? 1 : a.line - b.line);
|
|
18254
|
+
const dropped = symbols.filter((s) => (hitCount.get(s) ?? 0) > MAX_HITS_PER_SYMBOL);
|
|
18255
|
+
const droppedSet = new Set(dropped);
|
|
18256
|
+
const perFile = /* @__PURE__ */ new Map();
|
|
18257
|
+
const callers = [];
|
|
18258
|
+
const tests = [];
|
|
18259
|
+
for (const h of hits) {
|
|
18260
|
+
if (droppedSet.has(h.symbol)) continue;
|
|
18261
|
+
if (opts.sentPaths.has(h.file)) continue;
|
|
18262
|
+
if (opts.isExcluded(h.file)) continue;
|
|
18263
|
+
if (!isCodeSiteFile(h.file)) continue;
|
|
18264
|
+
const text = h.text.trim();
|
|
18265
|
+
if (text.length === 0 || IMPORT_LINE.test(h.text)) continue;
|
|
18266
|
+
if (COMMENT_LINE.test(text)) continue;
|
|
18267
|
+
if (BARE_MEMBER_LINE.test(text) || GO_IMPORT_PATH_LINE.test(text)) continue;
|
|
18268
|
+
const n = perFile.get(h.file) ?? 0;
|
|
18269
|
+
if (n >= MAX_SITES_PER_FILE) continue;
|
|
18270
|
+
const site = {
|
|
18271
|
+
file: h.file,
|
|
18272
|
+
line: h.line,
|
|
18273
|
+
text: text.slice(0, SITE_TEXT_MAX),
|
|
18274
|
+
symbol: h.symbol,
|
|
18275
|
+
// R2 falls out of R1 for free: a word search for `Sym` already matches
|
|
18276
|
+
// `implements Sym` / `extends Sym` lines — classification is all R2 is.
|
|
18277
|
+
...isContractLine(text, h.symbol) ? { kind: "contract" } : {}
|
|
18278
|
+
};
|
|
18279
|
+
if (isTestPath(h.file)) {
|
|
18280
|
+
if (tests.length < MAX_TEST_SLOTS) {
|
|
18281
|
+
tests.push(site);
|
|
18282
|
+
perFile.set(h.file, n + 1);
|
|
18283
|
+
}
|
|
18284
|
+
} else if (callers.length + tests.length < MAX_SITES) {
|
|
18285
|
+
callers.push(site);
|
|
18286
|
+
perFile.set(h.file, n + 1);
|
|
18287
|
+
}
|
|
18288
|
+
}
|
|
18289
|
+
while (callers.length + tests.length > MAX_SITES) callers.pop();
|
|
18290
|
+
return { callers, tests, dropped };
|
|
18291
|
+
}
|
|
18292
|
+
function buildRepoContext(input) {
|
|
18293
|
+
const started = Date.now();
|
|
18294
|
+
let signalsByPath;
|
|
18295
|
+
if (input.signalsByPath) {
|
|
18296
|
+
if (input.signalsByPath.size === 0) return { state: "absent", reason: "no-diffs" };
|
|
18297
|
+
signalsByPath = input.signalsByPath;
|
|
18298
|
+
} else {
|
|
18299
|
+
if (input.diffs.length === 0) return { state: "absent", reason: "no-diffs" };
|
|
18300
|
+
signalsByPath = /* @__PURE__ */ new Map();
|
|
18301
|
+
for (const d of input.diffs) signalsByPath.set(d.path, parseDiffSignals(d.diff));
|
|
18302
|
+
}
|
|
18303
|
+
const collected = [];
|
|
18304
|
+
const unsupported = /* @__PURE__ */ new Set();
|
|
18305
|
+
const noteUnsupported = (path) => {
|
|
18306
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18307
|
+
if (ext && !RULES_BY_EXT[ext]) unsupported.add(ext);
|
|
18308
|
+
};
|
|
18309
|
+
const deltaPathSet = new Set(input.deltaFiles.map((f) => f.path));
|
|
18310
|
+
for (const f of input.deltaFiles) {
|
|
18311
|
+
const signals = signalsByPath.get(f.path);
|
|
18312
|
+
if (!signals) continue;
|
|
18313
|
+
noteUnsupported(f.path);
|
|
18314
|
+
collected.push(...extractFileSymbols(f.path, f.content, signals));
|
|
18315
|
+
}
|
|
18316
|
+
for (const [path, signals] of signalsByPath) {
|
|
18317
|
+
if (deltaPathSet.has(path)) continue;
|
|
18318
|
+
if (signals.deletedLines.length > 0) {
|
|
18319
|
+
noteUnsupported(path);
|
|
18320
|
+
collected.push(...extractFileSymbols(path, "", signals));
|
|
18321
|
+
}
|
|
18322
|
+
}
|
|
18323
|
+
const unsupportedExts = [...unsupported].sort().slice(0, 8);
|
|
18324
|
+
const audit = unsupportedExts.length > 0 ? { unsupported_exts: unsupportedExts } : {};
|
|
18325
|
+
const symbols = rankSymbols([...new Set(collected)]);
|
|
18326
|
+
if (symbols.length === 0) {
|
|
18327
|
+
const everySupportedFileFoundNothing = unsupportedExts.length > 0;
|
|
18328
|
+
return {
|
|
18329
|
+
state: "absent",
|
|
18330
|
+
reason: everySupportedFileFoundNothing ? "unsupported-language" : "no-symbols",
|
|
18331
|
+
...audit
|
|
18332
|
+
};
|
|
18333
|
+
}
|
|
18334
|
+
const args = [
|
|
18335
|
+
"-n",
|
|
18336
|
+
"-w",
|
|
18337
|
+
"-F",
|
|
18338
|
+
"--no-heading",
|
|
18339
|
+
"--color",
|
|
18340
|
+
"never",
|
|
18341
|
+
// ⚠ NO `--sort path` — it single-threads rg, and on a large worktree that
|
|
18342
|
+
// is the difference between 17ms and a timeout. Determinism is restored by
|
|
18343
|
+
// sorting the hits in partitionSites instead.
|
|
18344
|
+
//
|
|
18345
|
+
// `-m 8` bounds output PER FILE (shared across all patterns), so a noisy
|
|
18346
|
+
// repo cannot blow the 4MB read buffer and turn the whole feature into
|
|
18347
|
+
// `absent/error`. Cost, accepted: the frequency gate sees per-file-capped
|
|
18348
|
+
// counts, so a symbol concentrated in a handful of files can slip a gate
|
|
18349
|
+
// a full count would have tripped — but the ≤3-sites-per-file cap already
|
|
18350
|
+
// bounds exactly that shape's damage; the gate exists for the many-file
|
|
18351
|
+
// 'init' shape, which 8-per-file still trips (>6 files ⇒ >50).
|
|
18352
|
+
"-m",
|
|
18353
|
+
"8",
|
|
18354
|
+
"--max-columns",
|
|
18355
|
+
"300",
|
|
18356
|
+
"--max-columns-preview",
|
|
18357
|
+
...symbols.flatMap((s) => ["-e", s]),
|
|
18358
|
+
"-g",
|
|
18359
|
+
"!**/{dist,build,out,vendor,node_modules,.git,coverage,target,__pycache__}/**",
|
|
18360
|
+
"./"
|
|
18361
|
+
];
|
|
18362
|
+
let res = null;
|
|
18363
|
+
for (const inv of rgInvocations()) {
|
|
18364
|
+
res = (0, import_node_child_process7.spawnSync)(inv.cmd, args, {
|
|
18365
|
+
...inv.argv0 ? { argv0: inv.argv0 } : {},
|
|
18366
|
+
cwd: input.cwd ?? process.cwd(),
|
|
18367
|
+
timeout: input.timeoutMs ?? RG_TIMEOUT_MS,
|
|
18368
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
18369
|
+
encoding: "utf8"
|
|
18370
|
+
});
|
|
18371
|
+
if (res.error?.code !== "ENOENT") break;
|
|
18372
|
+
}
|
|
18373
|
+
if (!res || res.error?.code === "ENOENT") {
|
|
18374
|
+
return { state: "absent", reason: "no-tool", symbols, ...audit };
|
|
18375
|
+
}
|
|
18376
|
+
if (res.error) {
|
|
18377
|
+
const code = res.error.code;
|
|
18378
|
+
if (code === "ETIMEDOUT") return { state: "absent", reason: "timeout", symbols, ...audit };
|
|
18379
|
+
return { state: "absent", reason: "error", symbols, ...audit };
|
|
18380
|
+
}
|
|
18381
|
+
if (res.signal) return { state: "absent", reason: "timeout", symbols, ...audit };
|
|
18382
|
+
if (res.status !== 0 && res.status !== 1) return { state: "absent", reason: "error", symbols, ...audit };
|
|
18383
|
+
const lines = (res.stdout ?? "").split("\n").map((l) => l.replace(/^\.\//, "")).filter(Boolean);
|
|
18384
|
+
const { callers, tests, dropped } = partitionSites(lines, symbols, {
|
|
18385
|
+
sentPaths: input.sentPaths,
|
|
18386
|
+
isExcluded: input.isExcluded
|
|
18387
|
+
});
|
|
18388
|
+
if (callers.length === 0 && tests.length === 0) {
|
|
18389
|
+
return {
|
|
18390
|
+
state: "absent",
|
|
18391
|
+
reason: "no-sites",
|
|
18392
|
+
symbols,
|
|
18393
|
+
...dropped.length > 0 ? { dropped_symbols: dropped } : {},
|
|
18394
|
+
...audit,
|
|
18395
|
+
elapsed_ms: Date.now() - started
|
|
18396
|
+
};
|
|
18397
|
+
}
|
|
18398
|
+
return {
|
|
18399
|
+
state: "ok",
|
|
18400
|
+
symbols,
|
|
18401
|
+
...dropped.length > 0 ? { dropped_symbols: dropped } : {},
|
|
18402
|
+
...audit,
|
|
18403
|
+
callers,
|
|
18404
|
+
tests,
|
|
18405
|
+
elapsed_ms: Date.now() - started
|
|
18406
|
+
};
|
|
18407
|
+
}
|
|
18408
|
+
var MAX_EXCERPTS = 12;
|
|
18409
|
+
var MAX_EXCERPTS_PER_FILE = 2;
|
|
18410
|
+
var EXCERPT_MAX_LINES = 30;
|
|
18411
|
+
var EXCERPT_MAX_CHARS = 2400;
|
|
18412
|
+
var EXCERPT_TOTAL_BYTES = 24576;
|
|
18413
|
+
var EXCERPT_DECL_SCAN = 40;
|
|
18414
|
+
function extractEnclosingExcerpt(content, siteLine, path) {
|
|
18415
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
18416
|
+
const rules = RULES_BY_EXT[ext] ?? [];
|
|
18417
|
+
const lines = content.split("\n");
|
|
18418
|
+
if (siteLine < 1 || siteLine > lines.length) return null;
|
|
18419
|
+
let declStart = null;
|
|
18420
|
+
const floor = Math.max(1, siteLine - EXCERPT_DECL_SCAN);
|
|
18421
|
+
for (let n = siteLine; n >= floor; n--) {
|
|
18422
|
+
if (declNameOn(lines[n - 1] ?? "", rules) !== null) {
|
|
18423
|
+
declStart = n;
|
|
18424
|
+
break;
|
|
18425
|
+
}
|
|
18426
|
+
}
|
|
18427
|
+
let start;
|
|
18428
|
+
if (declStart !== null && siteLine - declStart < EXCERPT_MAX_LINES) {
|
|
18429
|
+
start = declStart;
|
|
18430
|
+
} else {
|
|
18431
|
+
start = Math.max(1, siteLine - (EXCERPT_MAX_LINES - 6));
|
|
18432
|
+
}
|
|
18433
|
+
const end = Math.min(lines.length, start + EXCERPT_MAX_LINES - 1);
|
|
18434
|
+
const text = lines.slice(start - 1, end).join("\n").slice(0, EXCERPT_MAX_CHARS);
|
|
18435
|
+
return { start_line: start, text };
|
|
18436
|
+
}
|
|
18437
|
+
function upgradeToExcerpts(rc, opts) {
|
|
18438
|
+
if (rc.state !== "ok") return;
|
|
18439
|
+
const ranked = [
|
|
18440
|
+
...(rc.callers ?? []).filter((s) => s.kind === "contract"),
|
|
18441
|
+
...rc.tests ?? [],
|
|
18442
|
+
...(rc.callers ?? []).filter((s) => s.kind !== "contract")
|
|
18443
|
+
];
|
|
18444
|
+
const perFile = /* @__PURE__ */ new Map();
|
|
18445
|
+
const contentCache = /* @__PURE__ */ new Map();
|
|
18446
|
+
const excerpts = [];
|
|
18447
|
+
let totalBytes = 0;
|
|
18448
|
+
for (const site of ranked) {
|
|
18449
|
+
if (excerpts.length >= MAX_EXCERPTS) break;
|
|
18450
|
+
const used = perFile.get(site.file) ?? 0;
|
|
18451
|
+
if (used >= MAX_EXCERPTS_PER_FILE) continue;
|
|
18452
|
+
if (!contentCache.has(site.file)) contentCache.set(site.file, opts.readFile(site.file));
|
|
18453
|
+
const content = contentCache.get(site.file);
|
|
18454
|
+
if (content === null || content === void 0) continue;
|
|
18455
|
+
const ex = extractEnclosingExcerpt(content, site.line, site.file);
|
|
18456
|
+
if (!ex) continue;
|
|
18457
|
+
if (totalBytes + ex.text.length > EXCERPT_TOTAL_BYTES) break;
|
|
18458
|
+
excerpts.push({
|
|
18459
|
+
file: site.file,
|
|
18460
|
+
start_line: ex.start_line,
|
|
18461
|
+
symbol: site.symbol,
|
|
18462
|
+
kind: site.kind === "contract" ? "contract" : isTestPath(site.file) ? "test" : "caller",
|
|
18463
|
+
text: ex.text
|
|
18464
|
+
});
|
|
18465
|
+
totalBytes += ex.text.length;
|
|
18466
|
+
perFile.set(site.file, used + 1);
|
|
18467
|
+
}
|
|
18468
|
+
if (excerpts.length > 0) rc.excerpts = excerpts;
|
|
18469
|
+
}
|
|
18470
|
+
|
|
18471
|
+
// src/lib/git-frame.ts
|
|
17630
18472
|
var VALUE_TOKEN = `(?:'[^']*'|"[^"]*"|\\S+)`;
|
|
17631
18473
|
var GIT_GLOBAL_OPTS = `(?:\\s+(?:-[Cc]\\s+${VALUE_TOKEN}|--?[\\w-]+(?:=\\S+)?))*`;
|
|
17632
18474
|
var COMMIT_HEAD = `git${GIT_GLOBAL_OPTS}\\s+commit(?![\\w-])`;
|
|
@@ -17672,14 +18514,14 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
17672
18514
|
if (!m) continue;
|
|
17673
18515
|
named = true;
|
|
17674
18516
|
if (m[1] === void 0) {
|
|
17675
|
-
dir = (0,
|
|
18517
|
+
dir = (0, import_node_os4.homedir)();
|
|
17676
18518
|
continue;
|
|
17677
18519
|
}
|
|
17678
18520
|
const raw = unquote(m[1]);
|
|
17679
18521
|
if (SHELL_DYNAMIC.test(raw) || raw === "-") {
|
|
17680
18522
|
return { dir: null, named: true, unresolvable: `cd target not statically resolvable: ${raw}` };
|
|
17681
18523
|
}
|
|
17682
|
-
const expanded = raw === "~" ? (0,
|
|
18524
|
+
const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
|
|
17683
18525
|
dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
|
|
17684
18526
|
}
|
|
17685
18527
|
const seg = segments[segmentIndex];
|
|
@@ -17698,7 +18540,7 @@ function extractCommandTarget(command, segmentIndex, baseDir) {
|
|
|
17698
18540
|
if (SHELL_DYNAMIC.test(raw)) {
|
|
17699
18541
|
return { dir: null, named: true, unresolvable: `-C target not statically resolvable: ${raw}` };
|
|
17700
18542
|
}
|
|
17701
|
-
const expanded = raw === "~" ? (0,
|
|
18543
|
+
const expanded = raw === "~" ? (0, import_node_os4.homedir)() : raw.startsWith("~/") ? (0, import_node_path19.join)((0, import_node_os4.homedir)(), raw.slice(2)) : raw;
|
|
17702
18544
|
dir = (0, import_node_path18.isAbsolute)(expanded) ? expanded : (0, import_node_path18.resolve)(dir, expanded);
|
|
17703
18545
|
}
|
|
17704
18546
|
}
|
|
@@ -17755,7 +18597,7 @@ function parsePushTarget(segment) {
|
|
|
17755
18597
|
}
|
|
17756
18598
|
function gitAt(dir, args) {
|
|
17757
18599
|
try {
|
|
17758
|
-
return (0,
|
|
18600
|
+
return (0, import_node_child_process8.execFileSync)("git", args, { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
17759
18601
|
} catch {
|
|
17760
18602
|
return "";
|
|
17761
18603
|
}
|
|
@@ -17894,18 +18736,52 @@ function rangeFiles(frame, range) {
|
|
|
17894
18736
|
}
|
|
17895
18737
|
return out.split("\n").filter((l) => l.length > 0).filter((f) => !isVerityOwnedPath(f));
|
|
17896
18738
|
}
|
|
17897
|
-
function
|
|
17898
|
-
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
|
|
17902
|
-
|
|
17903
|
-
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
18739
|
+
function rangeChangeSignals(frame, range, paths) {
|
|
18740
|
+
const out = /* @__PURE__ */ new Map();
|
|
18741
|
+
if (range.kind === "nothing" || paths.length === 0) return out;
|
|
18742
|
+
const args = range.kind === "staged" ? ["diff", "--cached", "--unified=0"] : ["diff", "--unified=0", range.base, range.head === "INDEX" ? "HEAD" : range.head];
|
|
18743
|
+
const diff = frameGit(frame, [...args, "--", ...paths]);
|
|
18744
|
+
let current = null;
|
|
18745
|
+
let oldSide = null;
|
|
18746
|
+
let buf = [];
|
|
18747
|
+
const flush = () => {
|
|
18748
|
+
if (current !== null && buf.length > 0) out.set(current, parseDiffSignals(buf.join("\n")));
|
|
18749
|
+
buf = [];
|
|
17907
18750
|
};
|
|
17908
|
-
|
|
18751
|
+
for (const line of diff.split("\n")) {
|
|
18752
|
+
if (line.startsWith("diff --git ")) {
|
|
18753
|
+
flush();
|
|
18754
|
+
current = null;
|
|
18755
|
+
oldSide = null;
|
|
18756
|
+
continue;
|
|
18757
|
+
}
|
|
18758
|
+
const minusM = /^--- (?:a\/)?(.+)$/.exec(line);
|
|
18759
|
+
if (minusM) {
|
|
18760
|
+
oldSide = minusM[1] === "/dev/null" ? null : minusM[1];
|
|
18761
|
+
continue;
|
|
18762
|
+
}
|
|
18763
|
+
const plusM = /^\+\+\+ (?:b\/)?(.+)$/.exec(line);
|
|
18764
|
+
if (plusM) {
|
|
18765
|
+
current = plusM[1] === "/dev/null" ? oldSide : plusM[1];
|
|
18766
|
+
continue;
|
|
18767
|
+
}
|
|
18768
|
+
if (current !== null) buf.push(line);
|
|
18769
|
+
}
|
|
18770
|
+
flush();
|
|
18771
|
+
return out;
|
|
18772
|
+
}
|
|
18773
|
+
function rangeMessages(frame, range) {
|
|
18774
|
+
if (range.kind === "staged" || range.kind === "nothing" || !range.base) return "";
|
|
18775
|
+
return frameGit(frame, ["log", `${range.base}..${range.head === "INDEX" ? "HEAD" : range.head}`, "--format=%B%x00"]).split("\0").map((s) => s.trim()).filter(Boolean).join("\n\n");
|
|
18776
|
+
}
|
|
18777
|
+
function frameTelemetry(frame, range, divergence) {
|
|
18778
|
+
const t = {
|
|
18779
|
+
anchor: frame.anchor,
|
|
18780
|
+
linked_worktree: frame.isLinkedWorktree,
|
|
18781
|
+
range_via: range?.via ?? null,
|
|
18782
|
+
refusal: frame.refusal
|
|
18783
|
+
};
|
|
18784
|
+
if (divergence) {
|
|
17909
18785
|
t.root_differs = !!frame.worktreeRoot && !!divergence.actualRoot && realpathOr(frame.worktreeRoot) !== realpathOr(divergence.actualRoot);
|
|
17910
18786
|
const a = [...divergence.actualFiles].sort().join("\n");
|
|
17911
18787
|
const b = [...divergence.frameFiles].sort().join("\n");
|
|
@@ -17953,6 +18829,7 @@ var MAX_COMMANDS = 10;
|
|
|
17953
18829
|
var MAX_COMMAND_CHARS = 80;
|
|
17954
18830
|
var MAX_TOOL_BLOCKS = 200;
|
|
17955
18831
|
var MAX_SUMMARY_BYTES = 4096;
|
|
18832
|
+
var MAX_SEARCHES_DETAIL = 10;
|
|
17956
18833
|
var HOME = process.env.HOME ?? "";
|
|
17957
18834
|
var BASH_INPUT_RE = /^\s*<bash-input>([\s\S]*?)<\/bash-input>/;
|
|
17958
18835
|
var BASH_ECHO_RE = /^\s*<bash-(?:stdout|stderr)>/;
|
|
@@ -18038,6 +18915,7 @@ function buildSummary(lines) {
|
|
|
18038
18915
|
let userCommandsTruncated = false;
|
|
18039
18916
|
let commandsTruncated = false;
|
|
18040
18917
|
let searches = 0;
|
|
18918
|
+
const searchesDetail = [];
|
|
18041
18919
|
let subagents = 0;
|
|
18042
18920
|
let webFetches = 0;
|
|
18043
18921
|
let totalToolCalls = 0;
|
|
@@ -18109,9 +18987,19 @@ function buildSummary(lines) {
|
|
|
18109
18987
|
break;
|
|
18110
18988
|
}
|
|
18111
18989
|
case "Grep":
|
|
18112
|
-
case "Glob":
|
|
18990
|
+
case "Glob": {
|
|
18113
18991
|
searches++;
|
|
18992
|
+
const pattern = typeof input.pattern === "string" ? input.pattern.slice(0, 120) : "";
|
|
18993
|
+
if (pattern && searchesDetail.length < MAX_SEARCHES_DETAIL) {
|
|
18994
|
+
const scopePath = typeof input.path === "string" ? input.path.slice(0, 200) : void 0;
|
|
18995
|
+
searchesDetail.push({
|
|
18996
|
+
tool: toolName,
|
|
18997
|
+
pattern,
|
|
18998
|
+
...scopePath ? { path: scopePath } : {}
|
|
18999
|
+
});
|
|
19000
|
+
}
|
|
18114
19001
|
break;
|
|
19002
|
+
}
|
|
18115
19003
|
case "Agent":
|
|
18116
19004
|
case "Task":
|
|
18117
19005
|
case "Workflow":
|
|
@@ -18146,6 +19034,7 @@ function buildSummary(lines) {
|
|
|
18146
19034
|
...cappedOut(filesCreated, MAX_CREATED_LIST)
|
|
18147
19035
|
],
|
|
18148
19036
|
searches,
|
|
19037
|
+
...searchesDetail.length > 0 ? { searches_detail: searchesDetail } : {},
|
|
18149
19038
|
commands,
|
|
18150
19039
|
...commandsTruncated ? { commands_truncated: true } : {},
|
|
18151
19040
|
user_commands: userCommands,
|
|
@@ -18156,6 +19045,9 @@ function buildSummary(lines) {
|
|
|
18156
19045
|
turn_messages: turnMessages,
|
|
18157
19046
|
turn_duration_ms: turnDurationMs
|
|
18158
19047
|
};
|
|
19048
|
+
if (JSON.stringify(summary).length > MAX_SUMMARY_BYTES) {
|
|
19049
|
+
delete summary.searches_detail;
|
|
19050
|
+
}
|
|
18159
19051
|
if (JSON.stringify(summary).length > MAX_SUMMARY_BYTES) {
|
|
18160
19052
|
summary.commands = [];
|
|
18161
19053
|
summary.commands_truncated = true;
|
|
@@ -18266,13 +19158,13 @@ async function readStopHookStdin() {
|
|
|
18266
19158
|
return empty;
|
|
18267
19159
|
}
|
|
18268
19160
|
}
|
|
18269
|
-
async function bootstrap(
|
|
18270
|
-
const { opts, globals } =
|
|
19161
|
+
async function bootstrap(run2) {
|
|
19162
|
+
const { opts, globals } = run2;
|
|
18271
19163
|
try {
|
|
18272
19164
|
process.chdir(repoRoot());
|
|
18273
19165
|
} catch {
|
|
18274
19166
|
}
|
|
18275
|
-
|
|
19167
|
+
run2.treeFrame = resolveFrame({ command: "", on: [], hookCwd: null }).frame;
|
|
18276
19168
|
const turnId = `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
18277
19169
|
let reachability = resolveReachability({
|
|
18278
19170
|
autonomousFlag: process.env.VERITY_AUTONOMOUS === "1" || opts.mode === "autonomous",
|
|
@@ -18286,7 +19178,7 @@ async function bootstrap(run) {
|
|
|
18286
19178
|
const rawSessionId = sessionId || process.env.CLAUDE_SESSION_ID || void 0;
|
|
18287
19179
|
const baselineSessionId = sessionScopeKey(scopeToken, rawSessionId);
|
|
18288
19180
|
if (tokenResult.ok) {
|
|
18289
|
-
|
|
19181
|
+
run2.beacon = {
|
|
18290
19182
|
resolveServiceUrl: async () => {
|
|
18291
19183
|
const u = await resolveServiceUrl(globals.serviceUrl);
|
|
18292
19184
|
return u.ok ? u.data : null;
|
|
@@ -18306,7 +19198,7 @@ async function bootstrap(run) {
|
|
|
18306
19198
|
age_ms: Date.now() - baseline.captured_at
|
|
18307
19199
|
});
|
|
18308
19200
|
}
|
|
18309
|
-
Object.assign(
|
|
19201
|
+
Object.assign(run2, { actionSummary, assistantResponse, baseline, baselineSessionId, reachability, sessionId, stopReason, tokenResult, transcriptPath, turnId });
|
|
18310
19202
|
}
|
|
18311
19203
|
|
|
18312
19204
|
// src/lib/self-scope.ts
|
|
@@ -18459,7 +19351,7 @@ function channelSilence(input) {
|
|
|
18459
19351
|
// src/lib/cli-version.ts
|
|
18460
19352
|
function cliVersion() {
|
|
18461
19353
|
try {
|
|
18462
|
-
return true ? "0.31.1-experimental.
|
|
19354
|
+
return true ? "0.31.1-experimental.68fca47" : "dev";
|
|
18463
19355
|
} catch {
|
|
18464
19356
|
return "dev";
|
|
18465
19357
|
}
|
|
@@ -18499,7 +19391,7 @@ async function sendSkipBeacon(ctx, reason) {
|
|
|
18499
19391
|
}
|
|
18500
19392
|
|
|
18501
19393
|
// src/lib/static-analysis.ts
|
|
18502
|
-
var
|
|
19394
|
+
var import_node_child_process9 = require("node:child_process");
|
|
18503
19395
|
var import_node_fs26 = require("node:fs");
|
|
18504
19396
|
var SEVERITY_ORDER = {
|
|
18505
19397
|
Error: 0,
|
|
@@ -18512,7 +19404,7 @@ var SEVERITY_ORDER = {
|
|
|
18512
19404
|
};
|
|
18513
19405
|
function isCodacyAvailable() {
|
|
18514
19406
|
try {
|
|
18515
|
-
(0,
|
|
19407
|
+
(0, import_node_child_process9.execSync)("which codacy-analysis", { stdio: "pipe" });
|
|
18516
19408
|
return true;
|
|
18517
19409
|
} catch {
|
|
18518
19410
|
return false;
|
|
@@ -18554,7 +19446,7 @@ function runCodacyAnalysis(files) {
|
|
|
18554
19446
|
}
|
|
18555
19447
|
});
|
|
18556
19448
|
if (existingFiles.length === 0) return empty;
|
|
18557
|
-
const proc = (0,
|
|
19449
|
+
const proc = (0, import_node_child_process9.spawnSync)("codacy-analysis", buildAnalyzerArgv(existingFiles), {
|
|
18558
19450
|
encoding: "utf-8",
|
|
18559
19451
|
maxBuffer: 10 * 1024 * 1024
|
|
18560
19452
|
});
|
|
@@ -18565,12 +19457,12 @@ function runCodacyAnalysis(files) {
|
|
|
18565
19457
|
spawnError: proc.error?.message
|
|
18566
19458
|
});
|
|
18567
19459
|
}
|
|
18568
|
-
function interpretAnalyzerRun(
|
|
18569
|
-
const output =
|
|
19460
|
+
function interpretAnalyzerRun(run2) {
|
|
19461
|
+
const output = run2.stdout ?? "";
|
|
18570
19462
|
if (!output.trim()) {
|
|
18571
19463
|
return withFailure(
|
|
18572
|
-
|
|
18573
|
-
|
|
19464
|
+
run2.spawnError ? "spawn_failed" : "no_output",
|
|
19465
|
+
run2.spawnError ?? run2.stderr ?? `exit ${run2.status}`
|
|
18574
19466
|
);
|
|
18575
19467
|
}
|
|
18576
19468
|
let parsed;
|
|
@@ -18711,7 +19603,7 @@ function describeOpenElsewhere(open) {
|
|
|
18711
19603
|
(+${open.length - 5} more)` : "";
|
|
18712
19604
|
return `STILL OPEN ELSEWHERE. ${open.length} finding(s) Verity raised earlier are still on disk in files this run did not review:
|
|
18713
19605
|
${lines.join("\n")}${more}
|
|
18714
|
-
They did not
|
|
19606
|
+
They did not fail this run \u2014 this verdict covers the current change only. The tree is not clean.
|
|
18715
19607
|
Fix them, or record a disposition: verity waive <pattern-id> --file <path> --reason "\u2026"`;
|
|
18716
19608
|
}
|
|
18717
19609
|
|
|
@@ -18737,9 +19629,9 @@ function localOnlyAndExit(staticResults) {
|
|
|
18737
19629
|
});
|
|
18738
19630
|
process.exit(0);
|
|
18739
19631
|
}
|
|
18740
|
-
async function passAndExit(
|
|
18741
|
-
|
|
18742
|
-
const sent = await sendSkipBeacon(
|
|
19632
|
+
async function passAndExit(run2, reason, skip, kindOverride) {
|
|
19633
|
+
run2.skipReason = skip;
|
|
19634
|
+
const sent = await sendSkipBeacon(run2.beacon, skip);
|
|
18743
19635
|
logEvent("skip", { reason: skip, beacon: sent });
|
|
18744
19636
|
const POLICY_SKIPS = /* @__PURE__ */ new Set([
|
|
18745
19637
|
"no-analyzable-files",
|
|
@@ -18754,7 +19646,7 @@ async function passAndExit(run, reason, skip, kindOverride) {
|
|
|
18754
19646
|
"no-delta-since-last-review"
|
|
18755
19647
|
]);
|
|
18756
19648
|
const skipKind = kindOverride ?? (POLICY_SKIPS.has(skip) ? "policy" : "capacity");
|
|
18757
|
-
const changed =
|
|
19649
|
+
const changed = run2.changedUniverse;
|
|
18758
19650
|
const { coverage, unaccounted } = reconcileCoverage(changed, {
|
|
18759
19651
|
reviewed: [],
|
|
18760
19652
|
notReviewed: changed.map((path) => ({ path, reason: skip, stage: "pre-flight", kind: skipKind }))
|
|
@@ -18782,10 +19674,10 @@ async function passAndExit(run, reason, skip, kindOverride) {
|
|
|
18782
19674
|
}
|
|
18783
19675
|
|
|
18784
19676
|
// src/commands/analyze/phases/02-scope.ts
|
|
18785
|
-
async function scope(
|
|
18786
|
-
const { assistantResponse } =
|
|
19677
|
+
async function scope(run2) {
|
|
19678
|
+
const { assistantResponse } = run2;
|
|
18787
19679
|
const { files: allChanged, hasRecentCommitFiles } = getChangedFiles();
|
|
18788
|
-
|
|
19680
|
+
run2.changedUniverse = allChanged;
|
|
18789
19681
|
const { kept: external } = partitionVerityOwned(allChanged);
|
|
18790
19682
|
const verityIgnore = loadVerityIgnore();
|
|
18791
19683
|
const ignored = partitionIgnored(external, verityIgnore);
|
|
@@ -18810,10 +19702,10 @@ async function scope(run) {
|
|
|
18810
19702
|
const securityFiles = filterSecurity(inScope);
|
|
18811
19703
|
const noFilesChanged = analyzable.length === 0 && reviewable.length === 0 && securityFiles.length === 0;
|
|
18812
19704
|
if (noFilesChanged && !assistantResponse) {
|
|
18813
|
-
await passAndExit(
|
|
19705
|
+
await passAndExit(run2, "No analyzable files changed", "no-analyzable-files");
|
|
18814
19706
|
}
|
|
18815
19707
|
const allForReview = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable]));
|
|
18816
|
-
Object.assign(
|
|
19708
|
+
Object.assign(run2, { allChanged, allForReview, analyzable, hasRecentCommitFiles, noFilesChanged, reviewable, securityFiles, verityIgnored: ignored });
|
|
18817
19709
|
}
|
|
18818
19710
|
|
|
18819
19711
|
// src/lib/specs.ts
|
|
@@ -18959,8 +19851,8 @@ function discoverGuardDocs(rangeFiles2) {
|
|
|
18959
19851
|
}
|
|
18960
19852
|
|
|
18961
19853
|
// src/commands/analyze/phases/03-intent-inputs.ts
|
|
18962
|
-
async function intentInputs(
|
|
18963
|
-
const { actionSummary, allForReview, assistantResponse, baseline, baselineSessionId } =
|
|
19854
|
+
async function intentInputs(run2) {
|
|
19855
|
+
const { actionSummary, allForReview, assistantResponse, baseline, baselineSessionId } = run2;
|
|
18964
19856
|
if (isCommandOnlyTurn({
|
|
18965
19857
|
userCommands: actionSummary?.user_commands,
|
|
18966
19858
|
userCommandsTruncated: actionSummary?.user_commands_truncated,
|
|
@@ -18968,11 +19860,11 @@ async function intentInputs(run) {
|
|
|
18968
19860
|
agentToolCalls: actionSummary?.total_tool_calls ?? 0,
|
|
18969
19861
|
authorshipIsObservable: !!actionSummary && actionSummary.transcript_windowed !== "orphaned"
|
|
18970
19862
|
})) {
|
|
18971
|
-
await passAndExit(
|
|
19863
|
+
await passAndExit(run2, "User command only \u2014 skipping analysis", "command-only-turn");
|
|
18972
19864
|
}
|
|
18973
19865
|
{
|
|
18974
19866
|
const ignoreKeys = ignoreStateKeys(
|
|
18975
|
-
|
|
19867
|
+
run2.tokenResult.ok ? run2.tokenResult.data.token : void 0,
|
|
18976
19868
|
null
|
|
18977
19869
|
);
|
|
18978
19870
|
const found = resolveIgnoreState([baselineSessionId, ...ignoreKeys]);
|
|
@@ -18996,7 +19888,7 @@ async function intentInputs(run) {
|
|
|
18996
19888
|
if (declaration.scope === "turn" && found) clearActiveDeclaration(found.key);
|
|
18997
19889
|
logEvent("ignore_honoured", { scope: declaration.scope, origin: declaration.origin });
|
|
18998
19890
|
await passAndExit(
|
|
18999
|
-
|
|
19891
|
+
run2,
|
|
19000
19892
|
`skipping this turn \u2014 declared housekeeping ("${declaration.reason}")`,
|
|
19001
19893
|
"declared-ignore"
|
|
19002
19894
|
);
|
|
@@ -19010,7 +19902,7 @@ async function intentInputs(run) {
|
|
|
19010
19902
|
const notice = `Verity: the ignore declared for this window ("${declaration.reason}") was voided \u2014 ${outcome.why}. Reviewing normally.`;
|
|
19011
19903
|
process.stderr.write(`${notice}
|
|
19012
19904
|
`);
|
|
19013
|
-
|
|
19905
|
+
run2.voidedIgnoreNotice = notice;
|
|
19014
19906
|
}
|
|
19015
19907
|
}
|
|
19016
19908
|
}
|
|
@@ -19032,34 +19924,33 @@ async function intentInputs(run) {
|
|
|
19032
19924
|
const adopted = absorbIntoBaseline(setupAuthored, baselineSessionId);
|
|
19033
19925
|
logEvent("baseline_absorbed", { skip: "verity-command", offered: setupAuthored.length, adopted });
|
|
19034
19926
|
}
|
|
19035
|
-
await passAndExit(
|
|
19927
|
+
await passAndExit(run2, "Verity command \u2014 skipping analysis", "verity-command");
|
|
19036
19928
|
}
|
|
19037
19929
|
if (shouldSkipForBareAck({ prompt: latestPrompt, turnAuthoredCode, canSeeTurnAuthorship })) {
|
|
19038
|
-
await passAndExit(
|
|
19930
|
+
await passAndExit(run2, "Bare acknowledgment \u2014 skipping analysis", "bare-acknowledgment");
|
|
19039
19931
|
}
|
|
19040
19932
|
if (isReflectionQuestion(assistantResponse) && !turnAuthoredCode && canSeeTurnAuthorship) {
|
|
19041
|
-
await passAndExit(
|
|
19933
|
+
await passAndExit(run2, "Reflection-prompt turn \u2014 skipping analysis", "reflection-prompt");
|
|
19042
19934
|
}
|
|
19043
|
-
Object.assign(
|
|
19935
|
+
Object.assign(run2, { authorshipIsObservable, conversation, earlyFold, plans, specs, turnAuthoredCode });
|
|
19044
19936
|
}
|
|
19045
19937
|
|
|
19046
19938
|
// src/commands/analyze/phases/04-connect.ts
|
|
19047
|
-
async function connect(
|
|
19048
|
-
const { opts, globals } =
|
|
19049
|
-
const { analyzable, baseline, securityFiles, tokenResult } =
|
|
19939
|
+
async function connect(run2) {
|
|
19940
|
+
const { opts, globals } = run2;
|
|
19941
|
+
const { analyzable, baseline, securityFiles, tokenResult } = run2;
|
|
19050
19942
|
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
19051
19943
|
if (!tokenResult.ok || !urlResult.ok) {
|
|
19052
19944
|
localOnlyAndExit(runLocalStatic(analyzable, securityFiles, baseline, !!opts.skipStatic));
|
|
19053
19945
|
}
|
|
19054
|
-
Object.assign(
|
|
19946
|
+
Object.assign(run2, { urlResult, serviceUrl: urlResult.data, token: tokenResult.data.token });
|
|
19055
19947
|
}
|
|
19056
19948
|
|
|
19057
19949
|
// src/commands/analyze/phases/05-mode.ts
|
|
19058
|
-
async function mode(
|
|
19059
|
-
const { opts, globals } =
|
|
19060
|
-
const { actionSummary, allForReview, assistantResponse, baseline, conversation, memory, noFilesChanged, serviceUrl, sessionId, token, turnAuthoredCode } =
|
|
19950
|
+
async function mode(run2) {
|
|
19951
|
+
const { opts, globals } = run2;
|
|
19952
|
+
const { actionSummary, allForReview, assistantResponse, baseline, conversation, memory, noFilesChanged, serviceUrl, sessionId, token, turnAuthoredCode } = run2;
|
|
19061
19953
|
const sessionIdForMemory = sessionId || process.env.CLAUDE_SESSION_ID || "";
|
|
19062
|
-
let contextFilePaths = [];
|
|
19063
19954
|
let predictedMode;
|
|
19064
19955
|
try {
|
|
19065
19956
|
const memoryPath2 = sessionIdForMemory ? `/memory?session_id=${encodeURIComponent(sessionIdForMemory)}` : "/memory";
|
|
@@ -19073,9 +19964,6 @@ async function mode(run) {
|
|
|
19073
19964
|
cmd: "analyze_context"
|
|
19074
19965
|
});
|
|
19075
19966
|
if (memoryResult.ok) {
|
|
19076
|
-
if (Array.isArray(memoryResult.data.context_files)) {
|
|
19077
|
-
contextFilePaths = memoryResult.data.context_files;
|
|
19078
|
-
}
|
|
19079
19967
|
const rawMode = memoryResult.data.predicted_mode;
|
|
19080
19968
|
if (rawMode && ["standard", "plan", "debug", "skip"].includes(rawMode)) {
|
|
19081
19969
|
predictedMode = rawMode;
|
|
@@ -19098,7 +19986,7 @@ async function mode(run) {
|
|
|
19098
19986
|
);
|
|
19099
19987
|
}
|
|
19100
19988
|
const investigated = didAgentInvestigate(actionSummary);
|
|
19101
|
-
|
|
19989
|
+
run2.modeDecision = {
|
|
19102
19990
|
predicted: predictedMode ?? null,
|
|
19103
19991
|
resolved: analysisMode,
|
|
19104
19992
|
authored: turnAuthoredCode,
|
|
@@ -19118,13 +20006,13 @@ async function mode(run) {
|
|
|
19118
20006
|
});
|
|
19119
20007
|
if (analysisMode === "skip") {
|
|
19120
20008
|
await passAndExit(
|
|
19121
|
-
|
|
20009
|
+
run2,
|
|
19122
20010
|
"Skip mode \u2014 no code work to analyze",
|
|
19123
20011
|
"skip-mode",
|
|
19124
20012
|
turnAuthoredCode ? "capacity" : void 0
|
|
19125
20013
|
);
|
|
19126
20014
|
}
|
|
19127
|
-
Object.assign(
|
|
20015
|
+
Object.assign(run2, { analysisMode, sessionAuthoredCode, sessionIdForMemory });
|
|
19128
20016
|
}
|
|
19129
20017
|
|
|
19130
20018
|
// src/lib/fold.ts
|
|
@@ -19584,12 +20472,12 @@ function checkConservation(changedFiles, result, repoRoot2) {
|
|
|
19584
20472
|
}
|
|
19585
20473
|
|
|
19586
20474
|
// src/commands/analyze/phases/06-evidence.ts
|
|
19587
|
-
async function evidence(
|
|
19588
|
-
const { opts } =
|
|
19589
|
-
const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath, turnAuthoredCode } =
|
|
19590
|
-
let { analysisMode, earlyFold } =
|
|
20475
|
+
async function evidence(run2) {
|
|
20476
|
+
const { opts } = run2;
|
|
20477
|
+
const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath, turnAuthoredCode } = run2;
|
|
20478
|
+
let { analysisMode, earlyFold } = run2;
|
|
19591
20479
|
const recordFlip = (stage) => {
|
|
19592
|
-
if (
|
|
20480
|
+
if (run2.modeDecision) run2.modeDecision = { ...run2.modeDecision, resolved: "plan", flip: stage };
|
|
19593
20481
|
logEvent("mode_flipped", { stage, to: "plan" });
|
|
19594
20482
|
};
|
|
19595
20483
|
const planWorthy = !!assistantResponse && !turnAuthoredCode;
|
|
@@ -19616,7 +20504,7 @@ async function evidence(run) {
|
|
|
19616
20504
|
analysisMode = "plan";
|
|
19617
20505
|
recordFlip("debounce");
|
|
19618
20506
|
} else {
|
|
19619
|
-
await passAndExit(
|
|
20507
|
+
await passAndExit(run2, debounceSkip, "debounce");
|
|
19620
20508
|
}
|
|
19621
20509
|
}
|
|
19622
20510
|
if (analysisMode !== "plan") {
|
|
@@ -19627,7 +20515,7 @@ async function evidence(run) {
|
|
|
19627
20515
|
analysisMode = "plan";
|
|
19628
20516
|
recordFlip("mtime");
|
|
19629
20517
|
} else {
|
|
19630
|
-
await passAndExit(
|
|
20518
|
+
await passAndExit(run2, mtimeSkip, "no-delta-since-last-review");
|
|
19631
20519
|
}
|
|
19632
20520
|
}
|
|
19633
20521
|
}
|
|
@@ -19640,7 +20528,7 @@ async function evidence(run) {
|
|
|
19640
20528
|
analysisMode = "plan";
|
|
19641
20529
|
recordFlip("content-hash");
|
|
19642
20530
|
} else {
|
|
19643
|
-
await passAndExit(
|
|
20531
|
+
await passAndExit(run2, hashResult.skip, "no-delta-since-last-review");
|
|
19644
20532
|
}
|
|
19645
20533
|
}
|
|
19646
20534
|
contentHash = hashResult.hash;
|
|
@@ -19648,7 +20536,7 @@ async function evidence(run) {
|
|
|
19648
20536
|
const scoped = scopeToAuthored(allForReview, actionSummary);
|
|
19649
20537
|
const canTrustNoneAuthored = scoped.signal === "none-authored" && authorshipIsObservable;
|
|
19650
20538
|
if (canTrustNoneAuthored && !hasNonEditAuthorship(actionSummary, sessionAuthoredCode)) {
|
|
19651
|
-
await passAndExit(
|
|
20539
|
+
await passAndExit(run2, "No agent-authored code this turn \u2014 working-tree changes were not authored by this session", "zero-increment");
|
|
19652
20540
|
}
|
|
19653
20541
|
if (scoped.signal === "none-authored" && !authorshipIsObservable) {
|
|
19654
20542
|
logEvent("none_authored_unverifiable", {
|
|
@@ -19705,7 +20593,7 @@ async function evidence(run) {
|
|
|
19705
20593
|
recordFlip("empty-after-scoping");
|
|
19706
20594
|
} else {
|
|
19707
20595
|
await passAndExit(
|
|
19708
|
-
|
|
20596
|
+
run2,
|
|
19709
20597
|
"No files within size limits to analyze",
|
|
19710
20598
|
"size-limit",
|
|
19711
20599
|
codeDelta.excluded.length > 0 ? "capacity" : "policy"
|
|
@@ -19730,7 +20618,7 @@ async function evidence(run) {
|
|
|
19730
20618
|
currentCommit = getCurrentCommit();
|
|
19731
20619
|
iteration = readIteration(currentCommit);
|
|
19732
20620
|
}
|
|
19733
|
-
Object.assign(
|
|
20621
|
+
Object.assign(run2, { analysisMode, codeDelta, contentHash, currentCommit, earlyFold, iteration, snapshotResult, staticResults });
|
|
19734
20622
|
}
|
|
19735
20623
|
|
|
19736
20624
|
// src/lib/cache-cleanup.ts
|
|
@@ -19762,15 +20650,52 @@ function pruneStaleCache() {
|
|
|
19762
20650
|
|
|
19763
20651
|
// src/lib/context-files.ts
|
|
19764
20652
|
var import_node_fs30 = require("node:fs");
|
|
20653
|
+
var import_node_os5 = require("node:os");
|
|
19765
20654
|
var MAX_CONTEXT_FILES = 10;
|
|
19766
20655
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
19767
|
-
var MAX_CONTEXT_TOTAL_BYTES =
|
|
19768
|
-
function
|
|
20656
|
+
var MAX_CONTEXT_TOTAL_BYTES = 24576;
|
|
20657
|
+
function readSetContextPaths(summary, deltaFiles) {
|
|
20658
|
+
const reads = summary?.files_read ?? [];
|
|
20659
|
+
if (reads.length === 0) return [];
|
|
20660
|
+
const root = process.cwd().replace(/\/+$/, "");
|
|
20661
|
+
const home = (0, import_node_os5.homedir)();
|
|
20662
|
+
const toRepoRelative2 = (p) => {
|
|
20663
|
+
if (!p) return null;
|
|
20664
|
+
let abs;
|
|
20665
|
+
if (p.startsWith("/")) {
|
|
20666
|
+
abs = p;
|
|
20667
|
+
} else {
|
|
20668
|
+
const rebuilt = `${home}/${p}`;
|
|
20669
|
+
abs = rebuilt.startsWith(`${root}/`) ? rebuilt : `${root}/${p}`;
|
|
20670
|
+
}
|
|
20671
|
+
if (!abs.startsWith(`${root}/`)) return null;
|
|
20672
|
+
return abs.slice(root.length + 1);
|
|
20673
|
+
};
|
|
20674
|
+
const authored = /* @__PURE__ */ new Set();
|
|
20675
|
+
for (const p of [...summary?.files_edited ?? [], ...summary?.files_created ?? []]) {
|
|
20676
|
+
const rel = toRepoRelative2(p);
|
|
20677
|
+
if (rel) authored.add(rel);
|
|
20678
|
+
}
|
|
20679
|
+
for (const f of deltaFiles) authored.add(f.path);
|
|
20680
|
+
const out = [];
|
|
20681
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20682
|
+
for (const p of reads) {
|
|
20683
|
+
const rel = toRepoRelative2(p);
|
|
20684
|
+
if (!rel || seen.has(rel) || authored.has(rel)) continue;
|
|
20685
|
+
seen.add(rel);
|
|
20686
|
+
const ext = rel.split(".").pop()?.toLowerCase() ?? "";
|
|
20687
|
+
if (!ANALYZABLE_EXTENSIONS.has(ext) && !REVIEWABLE_EXTENSIONS.has(ext)) continue;
|
|
20688
|
+
out.push(rel);
|
|
20689
|
+
}
|
|
20690
|
+
return out;
|
|
20691
|
+
}
|
|
20692
|
+
function gatherContextFiles(contextPaths, deltaFiles, opts) {
|
|
20693
|
+
const fileCap = Math.max(0, Math.min(MAX_CONTEXT_FILES, opts?.maxFiles ?? MAX_CONTEXT_FILES));
|
|
19769
20694
|
const deltaPaths = new Set(deltaFiles.map((f) => f.path));
|
|
19770
20695
|
const result = [];
|
|
19771
20696
|
let totalBytes = 0;
|
|
19772
20697
|
for (const filePath of contextPaths) {
|
|
19773
|
-
if (result.length >=
|
|
20698
|
+
if (result.length >= fileCap) break;
|
|
19774
20699
|
if (deltaPaths.has(filePath)) continue;
|
|
19775
20700
|
if (isVerityOwnedPath(filePath)) {
|
|
19776
20701
|
logEvent("context_file_skipped", { path: filePath, reason: "verity_owned" });
|
|
@@ -19827,10 +20752,15 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
19827
20752
|
}
|
|
19828
20753
|
|
|
19829
20754
|
// src/commands/analyze/phases/07-context-files.ts
|
|
19830
|
-
async function contextFiles(
|
|
19831
|
-
const { codeDelta
|
|
19832
|
-
const
|
|
19833
|
-
const
|
|
20755
|
+
async function contextFiles(run2) {
|
|
20756
|
+
const { codeDelta } = run2;
|
|
20757
|
+
const readSet = readSetContextPaths(run2.actionSummary, codeDelta.files);
|
|
20758
|
+
const { kept: externalContext } = partitionVerityOwned(readSet);
|
|
20759
|
+
const ig = loadVerityIgnore();
|
|
20760
|
+
const unfenced = run2.verityIgnored.suspended ? externalContext : externalContext.filter((p) => !isIgnored(ig, p));
|
|
20761
|
+
const contextFiles2 = gatherContextFiles(unfenced, codeDelta.files, {
|
|
20762
|
+
maxFiles: MAX_FILES - codeDelta.files.length
|
|
20763
|
+
});
|
|
19834
20764
|
for (const f of codeDelta.files) {
|
|
19835
20765
|
f.role = "delta";
|
|
19836
20766
|
}
|
|
@@ -19842,6 +20772,30 @@ async function contextFiles(run) {
|
|
|
19842
20772
|
});
|
|
19843
20773
|
}
|
|
19844
20774
|
|
|
20775
|
+
// src/commands/analyze/phases/07b-repo-context.ts
|
|
20776
|
+
async function repoContext(run2) {
|
|
20777
|
+
const { codeDelta, snapshotResult } = run2;
|
|
20778
|
+
const deltaFiles = codeDelta.files.filter((f) => f.role !== "context");
|
|
20779
|
+
const sentPaths = new Set(codeDelta.files.map((f) => f.path));
|
|
20780
|
+
const ig = loadVerityIgnore();
|
|
20781
|
+
const isExcluded = (p) => isVerityOwnedPath(p) || !run2.verityIgnored.suspended && isIgnored(ig, p);
|
|
20782
|
+
run2.repoContext = buildRepoContext({
|
|
20783
|
+
deltaFiles,
|
|
20784
|
+
diffs: snapshotResult.diffs,
|
|
20785
|
+
sentPaths,
|
|
20786
|
+
isExcluded
|
|
20787
|
+
});
|
|
20788
|
+
logEvent("repo_context", {
|
|
20789
|
+
state: run2.repoContext.state,
|
|
20790
|
+
reason: run2.repoContext.reason ?? null,
|
|
20791
|
+
symbols: run2.repoContext.symbols?.length ?? 0,
|
|
20792
|
+
dropped: run2.repoContext.dropped_symbols?.length ?? 0,
|
|
20793
|
+
callers: run2.repoContext.callers?.length ?? 0,
|
|
20794
|
+
tests: run2.repoContext.tests?.length ?? 0,
|
|
20795
|
+
elapsed_ms: run2.repoContext.elapsed_ms ?? null
|
|
20796
|
+
});
|
|
20797
|
+
}
|
|
20798
|
+
|
|
19845
20799
|
// src/lib/seed-runner.ts
|
|
19846
20800
|
var import_promises11 = require("node:fs/promises");
|
|
19847
20801
|
var import_node_fs31 = require("node:fs");
|
|
@@ -20185,9 +21139,9 @@ async function runSeed(opts) {
|
|
|
20185
21139
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
20186
21140
|
var import_node_fs32 = require("node:fs");
|
|
20187
21141
|
var import_node_path24 = require("node:path");
|
|
20188
|
-
async function memoryManifest(
|
|
20189
|
-
const { globals } =
|
|
20190
|
-
const { serviceUrl, token } =
|
|
21142
|
+
async function memoryManifest(run2) {
|
|
21143
|
+
const { globals } = run2;
|
|
21144
|
+
const { serviceUrl, token } = run2;
|
|
20191
21145
|
let memoryManifest2;
|
|
20192
21146
|
let deletedNodePaths = [];
|
|
20193
21147
|
let editedUploads = [];
|
|
@@ -20239,12 +21193,12 @@ async function memoryManifest(run) {
|
|
|
20239
21193
|
editedUploads = await computeEditedNodeUploads();
|
|
20240
21194
|
} catch {
|
|
20241
21195
|
}
|
|
20242
|
-
Object.assign(
|
|
21196
|
+
Object.assign(run2, { autoSeedNotice, deletedNodePaths, editedUploads, memoryManifest: memoryManifest2 });
|
|
20243
21197
|
}
|
|
20244
21198
|
|
|
20245
21199
|
// src/commands/analyze/phases/09-fold-transcript.ts
|
|
20246
|
-
async function foldTranscript(
|
|
20247
|
-
const { allForReview, earlyFold, transcriptPath } =
|
|
21200
|
+
async function foldTranscript(run2) {
|
|
21201
|
+
const { allForReview, earlyFold, transcriptPath } = run2;
|
|
20248
21202
|
let foldResult = null;
|
|
20249
21203
|
let foldConservation = null;
|
|
20250
21204
|
if (transcriptPath) {
|
|
@@ -20261,7 +21215,7 @@ async function foldTranscript(run) {
|
|
|
20261
21215
|
foldResult = null;
|
|
20262
21216
|
}
|
|
20263
21217
|
}
|
|
20264
|
-
Object.assign(
|
|
21218
|
+
Object.assign(run2, { foldConservation, foldResult });
|
|
20265
21219
|
}
|
|
20266
21220
|
|
|
20267
21221
|
// src/lib/increment.ts
|
|
@@ -20313,10 +21267,10 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
|
|
|
20313
21267
|
|
|
20314
21268
|
// src/commands/analyze/phases/10-working-memory.ts
|
|
20315
21269
|
var import_node_path25 = require("node:path");
|
|
20316
|
-
async function workingMemory(
|
|
20317
|
-
const { opts } =
|
|
20318
|
-
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } =
|
|
20319
|
-
let { reachability } =
|
|
21270
|
+
async function workingMemory(run2) {
|
|
21271
|
+
const { opts } = run2;
|
|
21272
|
+
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run2;
|
|
21273
|
+
let { reachability } = run2;
|
|
20320
21274
|
const memorySession = sessionDossier(token, sessionId ?? process.env.CLAUDE_SESSION_ID ?? null);
|
|
20321
21275
|
let memory = null;
|
|
20322
21276
|
let incrementReport = null;
|
|
@@ -20402,7 +21356,7 @@ async function workingMemory(run) {
|
|
|
20402
21356
|
hasUserPrompt: (conversation?.prompts?.length ?? 0) > 0,
|
|
20403
21357
|
isTTY: process.stdout.isTTY === true
|
|
20404
21358
|
});
|
|
20405
|
-
Object.assign(
|
|
21359
|
+
Object.assign(run2, { incrementReport, memory, memorySession, reachability });
|
|
20406
21360
|
}
|
|
20407
21361
|
|
|
20408
21362
|
// src/lib/note-budget.ts
|
|
@@ -20475,7 +21429,7 @@ function isExplicitlyAutonomous(env = process.env) {
|
|
|
20475
21429
|
}
|
|
20476
21430
|
|
|
20477
21431
|
// src/lib/task-context.ts
|
|
20478
|
-
var
|
|
21432
|
+
var import_node_child_process10 = require("node:child_process");
|
|
20479
21433
|
var CLOSING_RE = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\b[\s:]*#(\d+)/i;
|
|
20480
21434
|
var BRANCH_RE = /(?:^|[/_-])(?:issue|gh|fix)[-_/]?(\d+)\b/i;
|
|
20481
21435
|
function parseLinkedIssue(sources) {
|
|
@@ -20491,7 +21445,7 @@ function parseLinkedIssue(sources) {
|
|
|
20491
21445
|
}
|
|
20492
21446
|
function safeExec(cmd, timeout) {
|
|
20493
21447
|
try {
|
|
20494
|
-
return (0,
|
|
21448
|
+
return (0, import_node_child_process10.execSync)(cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout }).trim();
|
|
20495
21449
|
} catch {
|
|
20496
21450
|
return "";
|
|
20497
21451
|
}
|
|
@@ -20521,8 +21475,8 @@ function resolveTaskContext(opts) {
|
|
|
20521
21475
|
// src/commands/analyze/phases/11-build-request.ts
|
|
20522
21476
|
var MAX_ASSISTANT_RESPONSE_CHARS_PLAN = 32768;
|
|
20523
21477
|
var MAX_ASSISTANT_RESPONSE_CHARS_DEFAULT = 8e3;
|
|
20524
|
-
async function buildRequest(
|
|
20525
|
-
const { actionSummary, allChanged, allForReview, analysisMode, analyzable, assistantResponse, codeDelta, conversation, deletedNodePaths, editedUploads, foldConservation, foldResult, incrementReport, iteration, memory, memoryManifest: memoryManifest2, memorySession, plans, reachability, reviewable, securityFiles, sessionId, snapshotResult, specs, staticResults, stopReason, turnId } =
|
|
21478
|
+
async function buildRequest(run2) {
|
|
21479
|
+
const { actionSummary, allChanged, allForReview, analysisMode, analyzable, assistantResponse, codeDelta, conversation, deletedNodePaths, editedUploads, foldConservation, foldResult, incrementReport, iteration, memory, memoryManifest: memoryManifest2, memorySession, plans, reachability, reviewable, securityFiles, sessionId, snapshotResult, specs, staticResults, stopReason, turnId } = run2;
|
|
20526
21480
|
const excludedByReason = {};
|
|
20527
21481
|
for (const e of codeDelta.excluded ?? []) {
|
|
20528
21482
|
excludedByReason[e.reason] = (excludedByReason[e.reason] ?? 0) + 1;
|
|
@@ -20552,15 +21506,15 @@ async function buildRequest(run) {
|
|
|
20552
21506
|
// the state, so the number is one turn lagged by construction. The
|
|
20553
21507
|
// degenerate win for the budget is a dead channel that looks like clean
|
|
20554
21508
|
// code; this is what makes "did delivery rate collapse" a query.
|
|
20555
|
-
advisory_delivered_prior: readAdvisoryEpisode(
|
|
21509
|
+
advisory_delivered_prior: readAdvisoryEpisode(run2.baselineSessionId)?.delivered ?? 0,
|
|
20556
21510
|
// `.verityignore` — see CoverageTelemetry.verityignore for why the SHARE is
|
|
20557
21511
|
// the number that matters and why no paths travel with it.
|
|
20558
21512
|
verityignore: {
|
|
20559
|
-
rules:
|
|
20560
|
-
excluded:
|
|
20561
|
-
share: ignoreShare(
|
|
20562
|
-
security_excluded:
|
|
20563
|
-
suspended:
|
|
21513
|
+
rules: run2.verityIgnored.rules,
|
|
21514
|
+
excluded: run2.verityIgnored.ignored.length,
|
|
21515
|
+
share: ignoreShare(run2.verityIgnored.kept.length, run2.verityIgnored.ignored.length),
|
|
21516
|
+
security_excluded: run2.verityIgnored.securityExcluded.length,
|
|
21517
|
+
suspended: run2.verityIgnored.suspended
|
|
20564
21518
|
}
|
|
20565
21519
|
};
|
|
20566
21520
|
const requestBody = {
|
|
@@ -20698,6 +21652,9 @@ async function buildRequest(run) {
|
|
|
20698
21652
|
if (snapshotResult.has_snapshots && snapshotResult.diffs.length > 0) {
|
|
20699
21653
|
requestBody.snapshot_diffs = snapshotResult.diffs;
|
|
20700
21654
|
}
|
|
21655
|
+
if (run2.repoContext) {
|
|
21656
|
+
requestBody.repo_context = run2.repoContext;
|
|
21657
|
+
}
|
|
20701
21658
|
const noHumanPrompt = (conversation?.prompts?.length ?? 0) === 0;
|
|
20702
21659
|
const w4Task = noHumanPrompt && isExplicitlyAutonomous() ? resolveTaskContext() : null;
|
|
20703
21660
|
const planApprovalActive = foldResult?.planApproval?.activeSinceLastPrompt === true;
|
|
@@ -20755,7 +21712,7 @@ async function buildRequest(run) {
|
|
|
20755
21712
|
}
|
|
20756
21713
|
requestBody.intent_context = intentContext;
|
|
20757
21714
|
}
|
|
20758
|
-
Object.assign(
|
|
21715
|
+
Object.assign(run2, { requestBody });
|
|
20759
21716
|
}
|
|
20760
21717
|
|
|
20761
21718
|
// src/lib/offline.ts
|
|
@@ -20816,9 +21773,9 @@ function shouldWarmRetryAnalyze(result) {
|
|
|
20816
21773
|
}
|
|
20817
21774
|
|
|
20818
21775
|
// src/commands/analyze/phases/12-transmit.ts
|
|
20819
|
-
async function transmit(
|
|
20820
|
-
const { globals } =
|
|
20821
|
-
const { codeDelta, requestBody, serviceUrl, staticResults, token } =
|
|
21776
|
+
async function transmit(run2) {
|
|
21777
|
+
const { globals } = run2;
|
|
21778
|
+
const { codeDelta, requestBody, serviceUrl, staticResults, token } = run2;
|
|
20822
21779
|
const ANALYZE_TIMEOUT_MS = 1e5;
|
|
20823
21780
|
let result = await analyzeRequest({
|
|
20824
21781
|
serviceUrl,
|
|
@@ -20881,15 +21838,34 @@ async function transmit(run) {
|
|
|
20881
21838
|
}
|
|
20882
21839
|
const response = result.data;
|
|
20883
21840
|
const decision = response.gate_decision ?? "(unrecognised)";
|
|
20884
|
-
Object.assign(
|
|
21841
|
+
Object.assign(run2, { decision, response });
|
|
20885
21842
|
}
|
|
20886
21843
|
|
|
20887
21844
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
20888
21845
|
var import_node_fs35 = require("node:fs");
|
|
20889
21846
|
var import_node_path26 = require("node:path");
|
|
20890
|
-
async function reconcile(
|
|
20891
|
-
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } =
|
|
21847
|
+
async function reconcile(run2) {
|
|
21848
|
+
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run2;
|
|
20892
21849
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
21850
|
+
if (memorySession) {
|
|
21851
|
+
try {
|
|
21852
|
+
const settledSites = response.metadata?.settled_sites;
|
|
21853
|
+
if (Array.isArray(settledSites)) {
|
|
21854
|
+
for (const site of settledSites) {
|
|
21855
|
+
const siteRecord = site;
|
|
21856
|
+
const file = typeof siteRecord?.file === "string" ? siteRecord.file : null;
|
|
21857
|
+
const patternId = typeof siteRecord?.pattern_id === "string" ? siteRecord.pattern_id : null;
|
|
21858
|
+
if (!file || !patternId) continue;
|
|
21859
|
+
appendEvent(memorySession.d, {
|
|
21860
|
+
k: "outcome",
|
|
21861
|
+
anchor_key: statementAnchorKey(file, patternId),
|
|
21862
|
+
outcome: "answered"
|
|
21863
|
+
});
|
|
21864
|
+
}
|
|
21865
|
+
}
|
|
21866
|
+
} catch {
|
|
21867
|
+
}
|
|
21868
|
+
}
|
|
20893
21869
|
let openElsewhere = [];
|
|
20894
21870
|
if (memorySession) {
|
|
20895
21871
|
try {
|
|
@@ -20970,7 +21946,7 @@ async function reconcile(run) {
|
|
|
20970
21946
|
// below is the signal that replaces the noise.
|
|
20971
21947
|
//
|
|
20972
21948
|
// Taken from the run, not recomputed — see context.ts `verityIgnored`.
|
|
20973
|
-
...
|
|
21949
|
+
...run2.verityIgnored.ignored.map((path) => ({
|
|
20974
21950
|
path,
|
|
20975
21951
|
reason: "verityignore",
|
|
20976
21952
|
stage: "verityignore",
|
|
@@ -21050,20 +22026,6 @@ async function reconcile(run) {
|
|
|
21050
22026
|
})() : [];
|
|
21051
22027
|
if (memorySession) {
|
|
21052
22028
|
try {
|
|
21053
|
-
const settledSites = response.metadata?.settled_sites;
|
|
21054
|
-
if (Array.isArray(settledSites)) {
|
|
21055
|
-
for (const site of settledSites) {
|
|
21056
|
-
const s = site;
|
|
21057
|
-
const file = typeof s?.file === "string" ? s.file : null;
|
|
21058
|
-
const patternId = typeof s?.pattern_id === "string" ? s.pattern_id : null;
|
|
21059
|
-
if (!file || !patternId) continue;
|
|
21060
|
-
appendEvent(memorySession.d, {
|
|
21061
|
-
k: "outcome",
|
|
21062
|
-
anchor_key: statementAnchorKey(file, patternId),
|
|
21063
|
-
outcome: "answered"
|
|
21064
|
-
});
|
|
21065
|
-
}
|
|
21066
|
-
}
|
|
21067
22029
|
recordVerdict(memorySession.d, {
|
|
21068
22030
|
runId: response.run_id ?? turnId,
|
|
21069
22031
|
decision,
|
|
@@ -21104,11 +22066,11 @@ async function reconcile(run) {
|
|
|
21104
22066
|
`
|
|
21105
22067
|
);
|
|
21106
22068
|
}
|
|
21107
|
-
Object.assign(
|
|
22069
|
+
Object.assign(run2, { intentRepeatCount, openElsewhere, priorPendingFingerprints, reviewCoverage, sentPaths, silenced, watermarkHash, watermarkIsPartial });
|
|
21108
22070
|
}
|
|
21109
22071
|
|
|
21110
22072
|
// src/lib/emit.ts
|
|
21111
|
-
var
|
|
22073
|
+
var YELLOW3 = "\x1B[33m";
|
|
21112
22074
|
var NC2 = "\x1B[0m";
|
|
21113
22075
|
function emitVerdict(input) {
|
|
21114
22076
|
const exit = input.exit ?? ((code) => process.exit(code));
|
|
@@ -21119,7 +22081,7 @@ function emitVerdict(input) {
|
|
|
21119
22081
|
const note = [describeCoverage(coverage), describeOpenElsewhere(openElsewhere)].filter(Boolean).join("\n\n") || null;
|
|
21120
22082
|
if (unaccounted.length > 0) {
|
|
21121
22083
|
process.stderr.write(
|
|
21122
|
-
`${
|
|
22084
|
+
`${YELLOW3}Verity: ${unaccounted.length} changed file(s) could not be attributed to any review stage \u2014 counted as unreviewed.${NC2}
|
|
21123
22085
|
`
|
|
21124
22086
|
);
|
|
21125
22087
|
}
|
|
@@ -21131,7 +22093,7 @@ ${input.agentContext}
|
|
|
21131
22093
|
`);
|
|
21132
22094
|
}
|
|
21133
22095
|
if (note && !input.silenced) process.stderr.write(`
|
|
21134
|
-
${
|
|
22096
|
+
${YELLOW3}${note}${NC2}
|
|
21135
22097
|
`);
|
|
21136
22098
|
return exit(2);
|
|
21137
22099
|
}
|
|
@@ -21217,10 +22179,10 @@ function screenRemediation(fix, findingFile) {
|
|
|
21217
22179
|
function agentContextFor(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
21218
22180
|
return buildAgentContext(channelInputFrom(response, intentRepeat, priorPendingFingerprints));
|
|
21219
22181
|
}
|
|
21220
|
-
async function render(
|
|
21221
|
-
const { opts, globals } =
|
|
21222
|
-
const { actionSummary, assistantResponse, autoSeedNotice, voidedIgnoreNotice, baselineSessionId, codeDelta, contentHash, conversation, currentCommit, decision, intentRepeatCount, memory, openElsewhere, priorPendingFingerprints, response, reviewCoverage, serviceUrl, sessionIdForMemory, silenced, token, watermarkHash, watermarkIsPartial } =
|
|
21223
|
-
let { iteration } =
|
|
22182
|
+
async function render(run2) {
|
|
22183
|
+
const { opts, globals } = run2;
|
|
22184
|
+
const { actionSummary, assistantResponse, autoSeedNotice, voidedIgnoreNotice, baselineSessionId, codeDelta, contentHash, conversation, currentCommit, decision, intentRepeatCount, memory, openElsewhere, priorPendingFingerprints, response, reviewCoverage, serviceUrl, sessionIdForMemory, silenced, token, watermarkHash, watermarkIsPartial } = run2;
|
|
22185
|
+
let { iteration } = run2;
|
|
21224
22186
|
const metadata = response.metadata ?? {};
|
|
21225
22187
|
const intentAmbiguity = metadata.intent_ambiguity;
|
|
21226
22188
|
if (intentAmbiguity != null && intentAmbiguity > 5) {
|
|
@@ -21327,7 +22289,7 @@ async function render(run) {
|
|
|
21327
22289
|
const blocks = prior.blocks + 1;
|
|
21328
22290
|
const decisionNow = mayBlock({
|
|
21329
22291
|
reviewedFileCount: codeDelta.files.length,
|
|
21330
|
-
staticFindingCount:
|
|
22292
|
+
staticFindingCount: run2.staticResults?.findings?.length ?? 0,
|
|
21331
22293
|
cycleCutFired: silenced !== null,
|
|
21332
22294
|
attempts,
|
|
21333
22295
|
blocks,
|
|
@@ -21358,7 +22320,7 @@ async function render(run) {
|
|
|
21358
22320
|
});
|
|
21359
22321
|
emitVerdict({
|
|
21360
22322
|
proposed: "WARN",
|
|
21361
|
-
changed:
|
|
22323
|
+
changed: run2.changedUniverse,
|
|
21362
22324
|
coverage: reviewCoverage,
|
|
21363
22325
|
userSummary: lines.length > 0 ? `${summary}
|
|
21364
22326
|
${lines.join("\n")}` : summary,
|
|
@@ -21450,7 +22412,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
21450
22412
|
`);
|
|
21451
22413
|
emitVerdict({
|
|
21452
22414
|
proposed: "FAIL",
|
|
21453
|
-
changed:
|
|
22415
|
+
changed: run2.changedUniverse,
|
|
21454
22416
|
coverage: reviewCoverage,
|
|
21455
22417
|
userSummary: "",
|
|
21456
22418
|
// Subject to the SAME cycle cut as PASS/WARN. Suppressing here is safe:
|
|
@@ -21475,7 +22437,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
21475
22437
|
userSummary += loginNudge + grantNudge;
|
|
21476
22438
|
emitVerdict({
|
|
21477
22439
|
proposed: "PASS",
|
|
21478
|
-
changed:
|
|
22440
|
+
changed: run2.changedUniverse,
|
|
21479
22441
|
coverage: reviewCoverage,
|
|
21480
22442
|
userSummary,
|
|
21481
22443
|
agentContext: silenced ? null : agentContextFor(response, intentRepeatCount, priorPendingFingerprints),
|
|
@@ -21497,7 +22459,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
21497
22459
|
userSummary += loginNudge + grantNudge;
|
|
21498
22460
|
emitVerdict({
|
|
21499
22461
|
proposed: "WARN",
|
|
21500
|
-
changed:
|
|
22462
|
+
changed: run2.changedUniverse,
|
|
21501
22463
|
coverage: reviewCoverage,
|
|
21502
22464
|
userSummary,
|
|
21503
22465
|
agentContext: silenced ? null : agentContextFor(response, intentRepeatCount, priorPendingFingerprints),
|
|
@@ -21522,7 +22484,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
21522
22484
|
process.exit(0);
|
|
21523
22485
|
}
|
|
21524
22486
|
}
|
|
21525
|
-
Object.assign(
|
|
22487
|
+
Object.assign(run2, { iteration });
|
|
21526
22488
|
}
|
|
21527
22489
|
|
|
21528
22490
|
// src/commands/analyze/index.ts
|
|
@@ -21541,6 +22503,8 @@ var PIPELINE = [
|
|
|
21541
22503
|
// ← THE NARROWING. what gets sent, and why not the rest
|
|
21542
22504
|
["contextFiles", contextFiles],
|
|
21543
22505
|
// supporting files, merged INTO the delta array
|
|
22506
|
+
["repoContext", repoContext],
|
|
22507
|
+
// R1/R3 — call sites of changed symbols, one line each
|
|
21544
22508
|
["memoryManifest", memoryManifest],
|
|
21545
22509
|
// knowledge-graph manifest + one-time auto-seed
|
|
21546
22510
|
["foldTranscript", foldTranscript],
|
|
@@ -21557,7 +22521,7 @@ var PIPELINE = [
|
|
|
21557
22521
|
// say it — stderr, stdout, disk
|
|
21558
22522
|
];
|
|
21559
22523
|
function registerAnalyzeCommand(program2) {
|
|
21560
|
-
program2.command("analyze").description("Run Verity analysis on changed files (stop hook)").option("--debounce <seconds>", "Skip if last analysis was within N seconds",
|
|
22524
|
+
program2.command("analyze").description("Run Verity analysis on changed files (stop hook)").option("--debounce <seconds>", "Skip if last analysis was within N seconds", String(DEBOUNCE_SECONDS)).option("--max-iterations <n>", "Force PASS after N FAIL cycles", String(MAX_ITERATIONS)).option("--max-files <n>", "Max files to send for review", String(MAX_FILES)).option("--max-file-size <bytes>", "Skip files larger than N bytes", String(MAX_FILE_BYTES)).option("--max-total-size <bytes>", "Stop collecting files at N total bytes", String(MAX_DELTA_BYTES)).option("--skip-static", "Skip codacy-analysis").option("--mode <mode>", "Force analysis mode (standard|plan|debug|skip)").option("--json", "Output raw JSON response").action(async (opts) => {
|
|
21561
22525
|
const globals = program2.opts();
|
|
21562
22526
|
try {
|
|
21563
22527
|
await runAnalyze(opts, globals);
|
|
@@ -21572,18 +22536,18 @@ function registerAnalyzeCommand(program2) {
|
|
|
21572
22536
|
}
|
|
21573
22537
|
var tracing = () => process.env.VERITY_TRACE_PHASES === "1";
|
|
21574
22538
|
async function runAnalyze(opts, globals) {
|
|
21575
|
-
const
|
|
21576
|
-
installRunEvidence(
|
|
22539
|
+
const run2 = createRun(opts, globals);
|
|
22540
|
+
installRunEvidence(run2);
|
|
21577
22541
|
for (const [name, phase] of PIPELINE) {
|
|
21578
|
-
|
|
22542
|
+
run2.phaseReached = name;
|
|
21579
22543
|
if (!tracing()) {
|
|
21580
|
-
await phase(
|
|
21581
|
-
|
|
22544
|
+
await phase(run2);
|
|
22545
|
+
run2.phasesCompleted.push(name);
|
|
21582
22546
|
continue;
|
|
21583
22547
|
}
|
|
21584
22548
|
const started = Date.now();
|
|
21585
|
-
await phase(
|
|
21586
|
-
|
|
22549
|
+
await phase(run2);
|
|
22550
|
+
run2.phasesCompleted.push(name);
|
|
21587
22551
|
process.stderr.write(`verity\xB7phase ${name} ${Date.now() - started}ms
|
|
21588
22552
|
`);
|
|
21589
22553
|
}
|
|
@@ -21686,8 +22650,8 @@ async function runReview(opts, globals) {
|
|
|
21686
22650
|
for (const p of specPaths) {
|
|
21687
22651
|
if (!(0, import_node_fs37.existsSync)(p)) continue;
|
|
21688
22652
|
try {
|
|
21689
|
-
const { readFileSync:
|
|
21690
|
-
const content =
|
|
22653
|
+
const { readFileSync: readFileSync25 } = await import("node:fs");
|
|
22654
|
+
const content = readFileSync25(p, "utf-8");
|
|
21691
22655
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
21692
22656
|
} catch {
|
|
21693
22657
|
}
|
|
@@ -22022,6 +22986,39 @@ async function runGuard(opts, globals) {
|
|
|
22022
22986
|
statedIntent,
|
|
22023
22987
|
buildGuardCoverage(files, codeDelta, frame, range)
|
|
22024
22988
|
);
|
|
22989
|
+
try {
|
|
22990
|
+
const ig = loadVerityIgnore();
|
|
22991
|
+
const repoContext2 = buildRepoContext({
|
|
22992
|
+
deltaFiles: codeDelta.files,
|
|
22993
|
+
diffs: [],
|
|
22994
|
+
signalsByPath: rangeChangeSignals(frame, range, codeDelta.files.map((f) => f.path)),
|
|
22995
|
+
sentPaths: new Set(codeDelta.files.map((f) => f.path)),
|
|
22996
|
+
isExcluded: (p) => isVerityOwnedPath(p) || isIgnored(ig, p),
|
|
22997
|
+
cwd: frame.worktreeRoot ?? process.cwd()
|
|
22998
|
+
});
|
|
22999
|
+
upgradeToExcerpts(repoContext2, {
|
|
23000
|
+
readFile: (rel) => {
|
|
23001
|
+
try {
|
|
23002
|
+
return (0, import_node_fs38.readFileSync)((0, import_node_path27.join)(frame.worktreeRoot ?? process.cwd(), rel), "utf8");
|
|
23003
|
+
} catch {
|
|
23004
|
+
return null;
|
|
23005
|
+
}
|
|
23006
|
+
}
|
|
23007
|
+
});
|
|
23008
|
+
requestBody.repo_context = repoContext2;
|
|
23009
|
+
logEvent("repo_context", {
|
|
23010
|
+
moment,
|
|
23011
|
+
state: repoContext2.state,
|
|
23012
|
+
reason: repoContext2.reason ?? null,
|
|
23013
|
+
symbols: repoContext2.symbols?.length ?? 0,
|
|
23014
|
+
callers: repoContext2.callers?.length ?? 0,
|
|
23015
|
+
tests: repoContext2.tests?.length ?? 0,
|
|
23016
|
+
excerpts: repoContext2.excerpts?.length ?? 0,
|
|
23017
|
+
elapsed_ms: repoContext2.elapsed_ms ?? null
|
|
23018
|
+
});
|
|
23019
|
+
} catch (e) {
|
|
23020
|
+
logEvent("repo_context", { moment, state: "absent", reason: "exception", message: e.message });
|
|
23021
|
+
}
|
|
22025
23022
|
const coverage = {
|
|
22026
23023
|
moment,
|
|
22027
23024
|
root: frame.worktreeRoot,
|
|
@@ -22276,22 +23273,297 @@ function registerWaiveCommand(program2) {
|
|
|
22276
23273
|
}
|
|
22277
23274
|
|
|
22278
23275
|
// src/commands/init.ts
|
|
22279
|
-
var
|
|
22280
|
-
var
|
|
23276
|
+
var import_node_fs44 = require("node:fs");
|
|
23277
|
+
var import_promises14 = require("node:fs/promises");
|
|
22281
23278
|
var import_node_path29 = require("node:path");
|
|
23279
|
+
var import_node_child_process14 = require("node:child_process");
|
|
23280
|
+
|
|
23281
|
+
// src/lib/banner.ts
|
|
23282
|
+
var WORDMARK = [
|
|
23283
|
+
"\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
23284
|
+
"\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D",
|
|
23285
|
+
"\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D ",
|
|
23286
|
+
"\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D ",
|
|
23287
|
+
" \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 ",
|
|
23288
|
+
" \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D "
|
|
23289
|
+
];
|
|
23290
|
+
var WORDMARK_NARROW = [
|
|
23291
|
+
"\u2588 \u2588 \u2588\u2580\u2580\u2580\u2580 \u2588\u2580\u2580\u2580\u2584 \u2580\u2580\u2588\u2580\u2580 \u2580\u2580\u2588\u2580\u2580 \u2588 \u2588",
|
|
23292
|
+
"\u2588 \u2588 \u2588\u2580\u2580\u2580 \u2588\u2584\u2584\u2584\u2580 \u2588 \u2588 \u2580\u2584\u2580 ",
|
|
23293
|
+
" \u2580\u2584\u2580 \u2588\u2584\u2584\u2584\u2584 \u2588 \u2580\u2584 \u2584\u2584\u2588\u2584\u2584 \u2588 \u2588 "
|
|
23294
|
+
];
|
|
23295
|
+
var TAGLINE = "reviews every turn, remembers every lesson";
|
|
23296
|
+
var WORDMARK_COLOR = ["\x1B[0;32m"];
|
|
23297
|
+
var DIM3 = "\x1B[2m";
|
|
23298
|
+
var RESET2 = "\x1B[0m";
|
|
23299
|
+
var INDENT = " ";
|
|
23300
|
+
function artWidth(art) {
|
|
23301
|
+
return Math.max(...art.map((r) => r.length)) + INDENT.length;
|
|
23302
|
+
}
|
|
23303
|
+
function canRenderArt() {
|
|
23304
|
+
return !!process.stderr.isTTY;
|
|
23305
|
+
}
|
|
23306
|
+
function printBanner(opts) {
|
|
23307
|
+
if (!opts.interactive) return;
|
|
23308
|
+
const columns = opts.columns ?? process.stderr.columns ?? 80;
|
|
23309
|
+
const color = colorEnabled();
|
|
23310
|
+
const version = `v${cliVersion()}`;
|
|
23311
|
+
const art = [WORDMARK, WORDMARK_NARROW].find((a) => artWidth(a) <= columns) ?? null;
|
|
23312
|
+
const dim = (text) => color ? `${DIM3}${text}${RESET2}` : text;
|
|
23313
|
+
process.stderr.write("\n");
|
|
23314
|
+
if (!art) {
|
|
23315
|
+
const candidates = [`Verity ${version}`, "Verity"];
|
|
23316
|
+
const text = candidates.find((c) => c.length + INDENT.length <= columns);
|
|
23317
|
+
if (text) process.stderr.write(`${INDENT}${dim(text)}
|
|
23318
|
+
`);
|
|
23319
|
+
process.stderr.write("\n");
|
|
23320
|
+
return;
|
|
23321
|
+
}
|
|
23322
|
+
art.forEach((row2, i) => {
|
|
23323
|
+
const tint = color && WORDMARK_COLOR.length > 0 ? WORDMARK_COLOR[Math.min(i, WORDMARK_COLOR.length - 1)] : "";
|
|
23324
|
+
const reset = color && tint ? RESET2 : "";
|
|
23325
|
+
process.stderr.write(`${INDENT}${tint}${row2}${reset}
|
|
23326
|
+
`);
|
|
23327
|
+
});
|
|
23328
|
+
if (TAGLINE.length + INDENT.length <= columns) {
|
|
23329
|
+
process.stderr.write(`${INDENT}${dim(TAGLINE)}
|
|
23330
|
+
`);
|
|
23331
|
+
}
|
|
23332
|
+
if (version.length + INDENT.length <= columns) {
|
|
23333
|
+
process.stderr.write(`${INDENT}${dim(version)}
|
|
23334
|
+
`);
|
|
23335
|
+
}
|
|
23336
|
+
process.stderr.write("\n");
|
|
23337
|
+
}
|
|
23338
|
+
function printPhase(n, of, title, subtitle) {
|
|
23339
|
+
const color = colorEnabled();
|
|
23340
|
+
const columns = process.stderr.columns ?? 72;
|
|
23341
|
+
const width = Math.min(columns, 72);
|
|
23342
|
+
const label2 = `\u2500\u2500 Phase ${n} of ${of} \xB7 ${title} `;
|
|
23343
|
+
const rule = label2 + "\u2500".repeat(Math.max(0, width - label2.length - 2));
|
|
23344
|
+
process.stderr.write("\n");
|
|
23345
|
+
process.stderr.write(color ? ` ${DIM3}${rule}${RESET2}
|
|
23346
|
+
` : ` ${rule}
|
|
23347
|
+
`);
|
|
23348
|
+
if (subtitle && subtitle.length + INDENT.length <= columns) {
|
|
23349
|
+
process.stderr.write(color ? ` ${DIM3}${subtitle}${RESET2}
|
|
23350
|
+
` : ` ${subtitle}
|
|
23351
|
+
`);
|
|
23352
|
+
}
|
|
23353
|
+
process.stderr.write("\n");
|
|
23354
|
+
}
|
|
23355
|
+
|
|
23356
|
+
// src/commands/doctor.ts
|
|
23357
|
+
var import_node_fs42 = require("node:fs");
|
|
23358
|
+
|
|
23359
|
+
// src/lib/prereqs.ts
|
|
22282
23360
|
var import_node_child_process11 = require("node:child_process");
|
|
22283
|
-
var
|
|
23361
|
+
var MIN_NODE_MAJOR = 20;
|
|
23362
|
+
function which(bin) {
|
|
23363
|
+
try {
|
|
23364
|
+
const out = (0, import_node_child_process11.execSync)(`command -v ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
23365
|
+
return out || null;
|
|
23366
|
+
} catch {
|
|
23367
|
+
return null;
|
|
23368
|
+
}
|
|
23369
|
+
}
|
|
23370
|
+
function checkNode() {
|
|
23371
|
+
const version = process.version;
|
|
23372
|
+
const major = Number.parseInt(version.slice(1), 10);
|
|
23373
|
+
const ok = Number.isFinite(major) && major >= MIN_NODE_MAJOR;
|
|
23374
|
+
return {
|
|
23375
|
+
id: "node",
|
|
23376
|
+
label: "Node.js",
|
|
23377
|
+
status: ok ? "ok" : "missing",
|
|
23378
|
+
detail: version,
|
|
23379
|
+
remedy: ok ? void 0 : `Node.js ${MIN_NODE_MAJOR}+ required \u2014 update from https://nodejs.org`,
|
|
23380
|
+
required: true
|
|
23381
|
+
};
|
|
23382
|
+
}
|
|
23383
|
+
function checkGit() {
|
|
23384
|
+
let detail = "";
|
|
23385
|
+
try {
|
|
23386
|
+
detail = (0, import_node_child_process11.execSync)("git --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
23387
|
+
} catch {
|
|
23388
|
+
return {
|
|
23389
|
+
id: "git",
|
|
23390
|
+
label: "git",
|
|
23391
|
+
status: "missing",
|
|
23392
|
+
detail: "not found",
|
|
23393
|
+
remedy: "Install git from https://git-scm.com",
|
|
23394
|
+
required: true
|
|
23395
|
+
};
|
|
23396
|
+
}
|
|
23397
|
+
return { id: "git", label: "git", status: "ok", detail, required: true };
|
|
23398
|
+
}
|
|
23399
|
+
function checkClaude() {
|
|
23400
|
+
const path = which("claude");
|
|
23401
|
+
return {
|
|
23402
|
+
id: "claude",
|
|
23403
|
+
label: "Claude Code",
|
|
23404
|
+
status: path ? "ok" : "warn",
|
|
23405
|
+
detail: path ?? "not found",
|
|
23406
|
+
remedy: path ? void 0 : "Hooks are wired but need Claude Code to fire \u2014 https://claude.com/claude-code",
|
|
23407
|
+
required: false
|
|
23408
|
+
};
|
|
23409
|
+
}
|
|
23410
|
+
function checkAnalysisCli() {
|
|
23411
|
+
const path = which("codacy-analysis");
|
|
23412
|
+
return {
|
|
23413
|
+
id: "analysis-cli",
|
|
23414
|
+
label: "@codacy/analysis-cli",
|
|
23415
|
+
status: path ? "ok" : "warn",
|
|
23416
|
+
detail: path ?? "not found",
|
|
23417
|
+
remedy: path ? void 0 : "npm install -g @codacy/analysis-cli (static findings are unavailable until then)",
|
|
23418
|
+
required: false
|
|
23419
|
+
};
|
|
23420
|
+
}
|
|
23421
|
+
var INSTALL_TIMEOUT_MS = 12e4;
|
|
23422
|
+
function run(command, args, opts = {}) {
|
|
23423
|
+
return new Promise((resolve4) => {
|
|
23424
|
+
const child = (0, import_node_child_process11.spawn)(command, args, {
|
|
23425
|
+
stdio: opts.inherit ? "inherit" : "pipe",
|
|
23426
|
+
timeout: INSTALL_TIMEOUT_MS
|
|
23427
|
+
});
|
|
23428
|
+
child.on("error", () => resolve4(false));
|
|
23429
|
+
child.on("close", (code) => resolve4(code === 0));
|
|
23430
|
+
});
|
|
23431
|
+
}
|
|
23432
|
+
async function installAnalysisCli() {
|
|
23433
|
+
const spinner = startSpinner("Installing @codacy/analysis-cli");
|
|
23434
|
+
const ok = await run("npm", ["install", "-g", "@codacy/analysis-cli"]);
|
|
23435
|
+
if (ok) {
|
|
23436
|
+
const check = checkAnalysisCli();
|
|
23437
|
+
if (check.status === "ok") {
|
|
23438
|
+
spinner.succeed("@codacy/analysis-cli installed");
|
|
23439
|
+
return { ...check, justInstalled: true };
|
|
23440
|
+
}
|
|
23441
|
+
spinner.warn("npm reported success but codacy-analysis is not on PATH");
|
|
23442
|
+
return check;
|
|
23443
|
+
}
|
|
23444
|
+
spinner.stop();
|
|
23445
|
+
{
|
|
23446
|
+
const failed = {
|
|
23447
|
+
id: "analysis-cli",
|
|
23448
|
+
label: "@codacy/analysis-cli",
|
|
23449
|
+
status: "warn",
|
|
23450
|
+
detail: "install failed",
|
|
23451
|
+
remedy: "Install manually: npm install -g @codacy/analysis-cli",
|
|
23452
|
+
required: false
|
|
23453
|
+
};
|
|
23454
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return failed;
|
|
23455
|
+
process.stderr.write(" Retrying with sudo (you may be asked for your password)\u2026\n");
|
|
23456
|
+
const sudoOk = await run("sudo", ["npm", "install", "-g", "@codacy/analysis-cli"], { inherit: true });
|
|
23457
|
+
if (!sudoOk) return failed;
|
|
23458
|
+
const check = checkAnalysisCli();
|
|
23459
|
+
return check.status === "ok" ? { ...check, justInstalled: true } : check;
|
|
23460
|
+
}
|
|
23461
|
+
}
|
|
23462
|
+
async function checkPrereqs(opts = {}) {
|
|
23463
|
+
const checks = [checkNode(), checkGit(), checkClaude()];
|
|
23464
|
+
let analysis = checkAnalysisCli();
|
|
23465
|
+
if (analysis.status !== "ok" && opts.install) {
|
|
23466
|
+
analysis = await installAnalysisCli();
|
|
23467
|
+
}
|
|
23468
|
+
checks.push(analysis);
|
|
23469
|
+
return { checks, blocked: checks.some((c) => c.required && c.status !== "ok") };
|
|
23470
|
+
}
|
|
22284
23471
|
|
|
22285
|
-
// src/
|
|
23472
|
+
// src/lib/telemetry.ts
|
|
23473
|
+
var import_promises12 = require("node:fs/promises");
|
|
23474
|
+
|
|
23475
|
+
// src/lib/gitignore.ts
|
|
23476
|
+
var import_node_child_process12 = require("node:child_process");
|
|
22286
23477
|
var import_node_fs40 = require("node:fs");
|
|
22287
|
-
var
|
|
22288
|
-
var
|
|
23478
|
+
var VERITY_GITIGNORE_MARKER = "# Verity \u2014 machine-local state.";
|
|
23479
|
+
var SETTINGS_LOCAL_IGNORE_ENTRY = ".claude/settings.local.json";
|
|
23480
|
+
var VERITY_GITIGNORE_BLOCK = [
|
|
23481
|
+
"# Verity \u2014 machine-local state. Everything in .verity/ is ignored EXCEPT the",
|
|
23482
|
+
"# shared standard and the knowledge graph, which are meant to be committed.",
|
|
23483
|
+
".verity/*",
|
|
23484
|
+
"!.verity/standard.yaml",
|
|
23485
|
+
"!.verity/memory/",
|
|
23486
|
+
".verity/memory/log.md",
|
|
23487
|
+
SETTINGS_LOCAL_IGNORE_ENTRY,
|
|
23488
|
+
""
|
|
23489
|
+
].join("\n");
|
|
23490
|
+
var BREAKING_ENTRIES = /* @__PURE__ */ new Set([".verity/", ".verity"]);
|
|
23491
|
+
function isIgnored2(path) {
|
|
23492
|
+
try {
|
|
23493
|
+
(0, import_node_child_process12.execSync)(`git check-ignore -q -- "${path}"`, { stdio: "pipe" });
|
|
23494
|
+
return true;
|
|
23495
|
+
} catch (err) {
|
|
23496
|
+
return err.status === 1 ? false : null;
|
|
23497
|
+
}
|
|
23498
|
+
}
|
|
23499
|
+
function semanticsHold() {
|
|
23500
|
+
const snapshot = isIgnored2(".verity/.snapshot/__probe__");
|
|
23501
|
+
const standard = isIgnored2(".verity/standard.yaml");
|
|
23502
|
+
const node = isIgnored2(".verity/memory/domain/__probe__.md");
|
|
23503
|
+
const futureState = isIgnored2(".verity/.__probe-future-state__");
|
|
23504
|
+
if (snapshot === null || standard === null || node === null || futureState === null) return null;
|
|
23505
|
+
return snapshot === true && futureState === true && standard === false && node === false;
|
|
23506
|
+
}
|
|
23507
|
+
function ensureVerityGitignore() {
|
|
23508
|
+
let content = "";
|
|
23509
|
+
try {
|
|
23510
|
+
content = (0, import_node_fs40.readFileSync)(".gitignore", "utf-8");
|
|
23511
|
+
} catch {
|
|
23512
|
+
}
|
|
23513
|
+
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
23514
|
+
const lines = content.split("\n");
|
|
23515
|
+
const breakingCount = lines.filter((l) => BREAKING_ENTRIES.has(l.trim())).length;
|
|
23516
|
+
const needsRepair = breakingCount > 0;
|
|
23517
|
+
const verified = (result) => semanticsHold() === false ? "conflict" : result;
|
|
23518
|
+
if (hasMarker && !needsRepair) return verified("covered");
|
|
23519
|
+
if (!hasMarker && !needsRepair) {
|
|
23520
|
+
if (semanticsHold() === true) return "covered";
|
|
23521
|
+
}
|
|
23522
|
+
try {
|
|
23523
|
+
let next = content;
|
|
23524
|
+
if (needsRepair) {
|
|
23525
|
+
next = lines.map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l).join("\n");
|
|
23526
|
+
}
|
|
23527
|
+
if (!hasMarker) {
|
|
23528
|
+
const sep2 = next === "" ? "" : next.endsWith("\n") ? "\n" : "\n\n";
|
|
23529
|
+
next = next + sep2 + VERITY_GITIGNORE_BLOCK;
|
|
23530
|
+
}
|
|
23531
|
+
(0, import_node_fs40.writeFileSync)(".gitignore", next);
|
|
23532
|
+
return verified(needsRepair ? "repaired" : "added");
|
|
23533
|
+
} catch {
|
|
23534
|
+
return "failed";
|
|
23535
|
+
}
|
|
23536
|
+
}
|
|
23537
|
+
function committedVerityState() {
|
|
23538
|
+
let out = "";
|
|
23539
|
+
try {
|
|
23540
|
+
out = (0, import_node_child_process12.execSync)("git ls-files -z -- .verity", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
23541
|
+
} catch {
|
|
23542
|
+
return [];
|
|
23543
|
+
}
|
|
23544
|
+
return out.split("\0").filter(Boolean).filter((p) => p !== ".verity/standard.yaml" && !(p.startsWith(".verity/memory/") && p !== ".verity/memory/log.md"));
|
|
23545
|
+
}
|
|
23546
|
+
function untrackVerityState() {
|
|
23547
|
+
const tracked = committedVerityState();
|
|
23548
|
+
if (tracked.length === 0) return "none";
|
|
23549
|
+
try {
|
|
23550
|
+
(0, import_node_child_process12.execSync)("git rm -r --cached --quiet -- .verity", { stdio: "pipe" });
|
|
23551
|
+
for (const keep of [".verity/standard.yaml", ".verity/memory"]) {
|
|
23552
|
+
try {
|
|
23553
|
+
(0, import_node_child_process12.execSync)(`git add -- "${keep}"`, { stdio: "pipe" });
|
|
23554
|
+
} catch {
|
|
23555
|
+
}
|
|
23556
|
+
}
|
|
23557
|
+
return "untracked";
|
|
23558
|
+
} catch {
|
|
23559
|
+
return "failed";
|
|
23560
|
+
}
|
|
23561
|
+
}
|
|
22289
23562
|
|
|
22290
23563
|
// src/lib/telemetry.ts
|
|
22291
|
-
var import_promises12 = require("node:fs/promises");
|
|
22292
23564
|
var SETTINGS_LOCAL_FILE2 = ".claude/settings.local.json";
|
|
22293
23565
|
var GITIGNORE_FILE = ".gitignore";
|
|
22294
|
-
var GITIGNORE_ENTRY =
|
|
23566
|
+
var GITIGNORE_ENTRY = SETTINGS_LOCAL_IGNORE_ENTRY;
|
|
22295
23567
|
var OTEL_HEADERS_HELPER_CMD = "verity telemetry headers";
|
|
22296
23568
|
var LEGACY_TELEMETRY_ENV_KEYS = ["OTEL_EXPORTER_OTLP_HEADERS"];
|
|
22297
23569
|
function deriveOtlpEndpoint(serviceUrl) {
|
|
@@ -22377,14 +23649,119 @@ async function uninstallTelemetry() {
|
|
|
22377
23649
|
return { ok: true, data: { removed } };
|
|
22378
23650
|
}
|
|
22379
23651
|
|
|
23652
|
+
// src/lib/setup-state.ts
|
|
23653
|
+
var import_promises13 = require("node:fs/promises");
|
|
23654
|
+
var import_node_fs41 = require("node:fs");
|
|
23655
|
+
var SETUP_STATE_FILE = `${VERITY_DIR}/setup.json`;
|
|
23656
|
+
async function readSetupState() {
|
|
23657
|
+
const path = projectPath(SETUP_STATE_FILE);
|
|
23658
|
+
if (!(0, import_node_fs41.existsSync)(path)) return null;
|
|
23659
|
+
try {
|
|
23660
|
+
const parsed = JSON.parse(await (0, import_promises13.readFile)(path, "utf-8"));
|
|
23661
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
23662
|
+
} catch {
|
|
23663
|
+
return null;
|
|
23664
|
+
}
|
|
23665
|
+
}
|
|
23666
|
+
async function writeSetupState(patch) {
|
|
23667
|
+
const current = await readSetupState() ?? { version: 1 };
|
|
23668
|
+
const next = { ...current, ...patch, version: 1 };
|
|
23669
|
+
await writeJsonFilePreservingStyle(projectPath(SETUP_STATE_FILE), next);
|
|
23670
|
+
return next;
|
|
23671
|
+
}
|
|
23672
|
+
|
|
23673
|
+
// src/commands/doctor.ts
|
|
23674
|
+
async function buildReport() {
|
|
23675
|
+
const prereqs = await checkPrereqs({ install: false });
|
|
23676
|
+
const state = await readSetupState();
|
|
23677
|
+
const hooks = await checkAllVerityHooks();
|
|
23678
|
+
const telemetry = await checkTelemetry();
|
|
23679
|
+
const artifacts = {
|
|
23680
|
+
standard: (0, import_node_fs42.existsSync)(projectPath(STANDARD_FILE)),
|
|
23681
|
+
analysisConfig: (0, import_node_fs42.existsSync)(projectPath(CODACY_CONFIG_FILE)),
|
|
23682
|
+
verityMd: (0, import_node_fs42.existsSync)(projectPath(VERITY_MD_FILE))
|
|
23683
|
+
};
|
|
23684
|
+
const next = [];
|
|
23685
|
+
for (const c of prereqs.checks) {
|
|
23686
|
+
if (c.status !== "ok" && c.remedy) next.push(c.remedy);
|
|
23687
|
+
}
|
|
23688
|
+
if (!state?.init) next.push('Run "verity init" \u2014 the deterministic setup phase has not completed here.');
|
|
23689
|
+
if (!artifacts.standard || !artifacts.analysisConfig || !artifacts.verityMd) {
|
|
23690
|
+
next.push("Run /verity-setup in Claude Code \u2014 the Standard, analysis config, and VERITY.md are synthesized there.");
|
|
23691
|
+
}
|
|
23692
|
+
const noAnalysisMoment = !hooks.stop && hooks.guardOn.length === 0;
|
|
23693
|
+
if (noAnalysisMoment) {
|
|
23694
|
+
next.push('No analysis moment is active \u2014 run "verity hooks install --moments stop" or re-run "verity init".');
|
|
23695
|
+
}
|
|
23696
|
+
if (state?.telemetry === "deferred") {
|
|
23697
|
+
next.push('Telemetry was requested but needs a token \u2014 run "verity login", then "verity telemetry install".');
|
|
23698
|
+
}
|
|
23699
|
+
return {
|
|
23700
|
+
prerequisites: prereqs.checks,
|
|
23701
|
+
blocked: prereqs.blocked,
|
|
23702
|
+
phases: {
|
|
23703
|
+
init: { done: !!state?.init, ...state?.init ?? {} },
|
|
23704
|
+
setup: { done: artifacts.standard && artifacts.analysisConfig && artifacts.verityMd }
|
|
23705
|
+
},
|
|
23706
|
+
answers: {
|
|
23707
|
+
intensity: state?.intensity ?? null,
|
|
23708
|
+
moments: state?.moments ?? null,
|
|
23709
|
+
telemetry: state?.telemetry ?? null
|
|
23710
|
+
},
|
|
23711
|
+
hooks: { ...hooks, noAnalysisMoment },
|
|
23712
|
+
telemetry: { enabled: telemetry.enabled, endpoint: telemetry.endpoint },
|
|
23713
|
+
artifacts,
|
|
23714
|
+
next
|
|
23715
|
+
};
|
|
23716
|
+
}
|
|
23717
|
+
function registerDoctorCommand(program2) {
|
|
23718
|
+
program2.command("doctor").description("Report prerequisites, setup phase, hooks, and what is still missing").option("--json", "Output the full report as JSON (what /verity-setup reads)").action(async (opts) => {
|
|
23719
|
+
const report = await buildReport();
|
|
23720
|
+
if (opts.json) {
|
|
23721
|
+
printJson(report);
|
|
23722
|
+
if (report.blocked) process.exit(1);
|
|
23723
|
+
return;
|
|
23724
|
+
}
|
|
23725
|
+
printInfo("Prerequisites:");
|
|
23726
|
+
for (const c of report.prerequisites) {
|
|
23727
|
+
if (c.status === "ok") printInfo(` ${c.label} ${c.detail} \u2713`);
|
|
23728
|
+
else printWarn(` ${c.label}: ${c.detail}${c.remedy ? ` \u2014 ${c.remedy}` : ""}`);
|
|
23729
|
+
}
|
|
23730
|
+
printInfo("Setup:");
|
|
23731
|
+
printInfo(` verity init: ${report.phases.init.done ? `done ${report.phases.init.completed_at ?? ""}`.trim() : "NOT run here"}`);
|
|
23732
|
+
printInfo(` /verity-setup: ${report.phases.setup.done ? "done" : "not completed"}`);
|
|
23733
|
+
printInfo(` intensity: ${report.answers.intensity ?? "\u2014"} moments: ${report.answers.moments?.join(", ") ?? "\u2014"}`);
|
|
23734
|
+
printInfo("Hooks:");
|
|
23735
|
+
printInfo(` Stop (verity analyze): ${report.hooks.stop ? "on" : "off"}`);
|
|
23736
|
+
printInfo(` Git-moment gate: ${report.hooks.guardOn.length ? report.hooks.guardOn.join(", ") : "off"}`);
|
|
23737
|
+
printInfo(` Infra (intent/baseline/compact/session-end): ${[report.hooks.intent, report.hooks.baseline, report.hooks.compact, report.hooks.sessionEnd].filter(Boolean).length}/4`);
|
|
23738
|
+
printInfo(`Telemetry: ${report.telemetry.enabled ? `enabled \u2192 ${report.telemetry.endpoint}` : "disabled"}`);
|
|
23739
|
+
printInfo("Artifacts:");
|
|
23740
|
+
printInfo(` .verity/standard.yaml: ${report.artifacts.standard ? "\u2713" : "missing"}`);
|
|
23741
|
+
printInfo(` .codacy/codacy.config.json: ${report.artifacts.analysisConfig ? "\u2713" : "missing"}`);
|
|
23742
|
+
printInfo(` VERITY.md: ${report.artifacts.verityMd ? "\u2713" : "missing"}`);
|
|
23743
|
+
if (report.next.length > 0) {
|
|
23744
|
+
console.log("");
|
|
23745
|
+
printWarn("Next:");
|
|
23746
|
+
for (const n of report.next) printWarn(` - ${n}`);
|
|
23747
|
+
} else {
|
|
23748
|
+
printInfo("Setup is complete.");
|
|
23749
|
+
}
|
|
23750
|
+
if (report.blocked) process.exit(1);
|
|
23751
|
+
});
|
|
23752
|
+
}
|
|
23753
|
+
|
|
22380
23754
|
// src/commands/migrate.ts
|
|
23755
|
+
var import_node_fs43 = require("node:fs");
|
|
23756
|
+
var import_node_path28 = require("node:path");
|
|
23757
|
+
var import_node_child_process13 = require("node:child_process");
|
|
22381
23758
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
22382
23759
|
function defaultNpmRemover(pkg) {
|
|
22383
|
-
(0,
|
|
23760
|
+
(0, import_node_child_process13.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
|
|
22384
23761
|
}
|
|
22385
23762
|
function isGitTracked(cwd, relPath) {
|
|
22386
23763
|
try {
|
|
22387
|
-
(0,
|
|
23764
|
+
(0, import_node_child_process13.execSync)(`git ls-files --error-unmatch ${relPath}`, { cwd, stdio: "pipe" });
|
|
22388
23765
|
return true;
|
|
22389
23766
|
} catch {
|
|
22390
23767
|
return false;
|
|
@@ -22392,7 +23769,7 @@ function isGitTracked(cwd, relPath) {
|
|
|
22392
23769
|
}
|
|
22393
23770
|
function isGitRepo(cwd) {
|
|
22394
23771
|
try {
|
|
22395
|
-
(0,
|
|
23772
|
+
(0, import_node_child_process13.execSync)("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
|
|
22396
23773
|
return true;
|
|
22397
23774
|
} catch {
|
|
22398
23775
|
return false;
|
|
@@ -22415,10 +23792,10 @@ async function runMigration(opts = {}) {
|
|
|
22415
23792
|
function migrateProjectDir(root, actions) {
|
|
22416
23793
|
const gateDir = (0, import_node_path28.join)(root, ".gate");
|
|
22417
23794
|
const verityDir = (0, import_node_path28.join)(root, ".verity");
|
|
22418
|
-
if ((0,
|
|
23795
|
+
if ((0, import_node_fs43.existsSync)(gateDir) && !(0, import_node_fs43.existsSync)(verityDir)) {
|
|
22419
23796
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
22420
23797
|
}
|
|
22421
|
-
if ((0,
|
|
23798
|
+
if ((0, import_node_fs43.existsSync)(gateDir) && (0, import_node_fs43.existsSync)(verityDir)) {
|
|
22422
23799
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
22423
23800
|
}
|
|
22424
23801
|
return false;
|
|
@@ -22432,20 +23809,20 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
22432
23809
|
);
|
|
22433
23810
|
}
|
|
22434
23811
|
try {
|
|
22435
|
-
(0,
|
|
23812
|
+
(0, import_node_child_process13.execSync)("git mv .gate .verity", { cwd: root, stdio: "pipe" });
|
|
22436
23813
|
actions.push("Moved .gate/ \u2192 .verity/ (git mv, staged)");
|
|
22437
23814
|
moved = true;
|
|
22438
23815
|
} catch {
|
|
22439
23816
|
}
|
|
22440
23817
|
}
|
|
22441
23818
|
if (moved) {
|
|
22442
|
-
if ((0,
|
|
23819
|
+
if ((0, import_node_fs43.existsSync)(gateDir)) {
|
|
22443
23820
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
22444
23821
|
if (carried > 0) {
|
|
22445
23822
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
22446
23823
|
}
|
|
22447
23824
|
try {
|
|
22448
|
-
(0,
|
|
23825
|
+
(0, import_node_fs43.rmSync)(gateDir, { recursive: true, force: true });
|
|
22449
23826
|
} catch {
|
|
22450
23827
|
}
|
|
22451
23828
|
}
|
|
@@ -22461,7 +23838,7 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
22461
23838
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
22462
23839
|
}
|
|
22463
23840
|
try {
|
|
22464
|
-
(0,
|
|
23841
|
+
(0, import_node_fs43.rmSync)(gateDir, { recursive: true, force: true });
|
|
22465
23842
|
} catch {
|
|
22466
23843
|
}
|
|
22467
23844
|
return carried > 0;
|
|
@@ -22470,9 +23847,9 @@ function migrateGlobalCredentials(home, actions) {
|
|
|
22470
23847
|
if (!home) return;
|
|
22471
23848
|
const gateCreds = (0, import_node_path28.join)(home, ".gate", "credentials");
|
|
22472
23849
|
const verityCreds = (0, import_node_path28.join)(home, ".verity", "credentials");
|
|
22473
|
-
if (!(0,
|
|
22474
|
-
if (!(0,
|
|
22475
|
-
(0,
|
|
23850
|
+
if (!(0, import_node_fs43.existsSync)(gateCreds)) return;
|
|
23851
|
+
if (!(0, import_node_fs43.existsSync)(verityCreds)) {
|
|
23852
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path28.join)(home, ".verity"), { recursive: true });
|
|
22476
23853
|
moveFile(gateCreds, verityCreds);
|
|
22477
23854
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
22478
23855
|
return;
|
|
@@ -22495,7 +23872,7 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
22495
23872
|
}
|
|
22496
23873
|
async function migrateClaudeMd(root, actions) {
|
|
22497
23874
|
const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
|
|
22498
|
-
const hadLegacyBlock = (0,
|
|
23875
|
+
const hadLegacyBlock = (0, import_node_fs43.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
22499
23876
|
if (!hadLegacyBlock) return;
|
|
22500
23877
|
try {
|
|
22501
23878
|
await ensureClaudeMdPointer(root);
|
|
@@ -22507,11 +23884,11 @@ async function migrateClaudeMd(root, actions) {
|
|
|
22507
23884
|
function migrateStandardFile(root, actions) {
|
|
22508
23885
|
const gateMd = (0, import_node_path28.join)(root, "GATE.md");
|
|
22509
23886
|
const verityMd = (0, import_node_path28.join)(root, "VERITY.md");
|
|
22510
|
-
if (!(0,
|
|
23887
|
+
if (!(0, import_node_fs43.existsSync)(gateMd) || (0, import_node_fs43.existsSync)(verityMd)) return;
|
|
22511
23888
|
let moved = false;
|
|
22512
23889
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
22513
23890
|
try {
|
|
22514
|
-
(0,
|
|
23891
|
+
(0, import_node_child_process13.execSync)("git mv GATE.md VERITY.md", { cwd: root, stdio: "pipe" });
|
|
22515
23892
|
moved = true;
|
|
22516
23893
|
} catch {
|
|
22517
23894
|
}
|
|
@@ -22519,12 +23896,12 @@ function migrateStandardFile(root, actions) {
|
|
|
22519
23896
|
if (!moved) moveFile(gateMd, verityMd);
|
|
22520
23897
|
const content = readFileSyncSafe(verityMd);
|
|
22521
23898
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
22522
|
-
if (refreshed !== content) (0,
|
|
23899
|
+
if (refreshed !== content) (0, import_node_fs43.writeFileSync)(verityMd, refreshed);
|
|
22523
23900
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
22524
23901
|
}
|
|
22525
23902
|
async function migrateTelemetryHeaders(root, actions) {
|
|
22526
23903
|
const file = (0, import_node_path28.join)(root, ".claude", "settings.local.json");
|
|
22527
|
-
if (!(0,
|
|
23904
|
+
if (!(0, import_node_fs43.existsSync)(file)) return;
|
|
22528
23905
|
let settings;
|
|
22529
23906
|
try {
|
|
22530
23907
|
settings = JSON.parse(readFileSyncSafe(file) || "{}");
|
|
@@ -22572,21 +23949,21 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
22572
23949
|
}
|
|
22573
23950
|
if (toAppend.length > 0) {
|
|
22574
23951
|
const sep2 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
22575
|
-
(0,
|
|
23952
|
+
(0, import_node_fs43.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
|
|
22576
23953
|
}
|
|
22577
|
-
(0,
|
|
23954
|
+
(0, import_node_fs43.rmSync)(gateCreds, { force: true });
|
|
22578
23955
|
return toAppend.length;
|
|
22579
23956
|
}
|
|
22580
23957
|
function readFileSyncSafe(path) {
|
|
22581
23958
|
try {
|
|
22582
|
-
return (0,
|
|
23959
|
+
return (0, import_node_fs43.readFileSync)(path, "utf-8");
|
|
22583
23960
|
} catch {
|
|
22584
23961
|
return "";
|
|
22585
23962
|
}
|
|
22586
23963
|
}
|
|
22587
23964
|
function hasStagedChanges(root) {
|
|
22588
23965
|
try {
|
|
22589
|
-
(0,
|
|
23966
|
+
(0, import_node_child_process13.execSync)("git diff --cached --quiet", { cwd: root, stdio: "pipe" });
|
|
22590
23967
|
return false;
|
|
22591
23968
|
} catch {
|
|
22592
23969
|
return true;
|
|
@@ -22594,35 +23971,35 @@ function hasStagedChanges(root) {
|
|
|
22594
23971
|
}
|
|
22595
23972
|
function moveDir(from, to) {
|
|
22596
23973
|
try {
|
|
22597
|
-
(0,
|
|
23974
|
+
(0, import_node_fs43.renameSync)(from, to);
|
|
22598
23975
|
} catch (err) {
|
|
22599
23976
|
if (err.code !== "EXDEV") throw err;
|
|
22600
|
-
(0,
|
|
22601
|
-
(0,
|
|
23977
|
+
(0, import_node_fs43.cpSync)(from, to, { recursive: true });
|
|
23978
|
+
(0, import_node_fs43.rmSync)(from, { recursive: true, force: true });
|
|
22602
23979
|
}
|
|
22603
23980
|
}
|
|
22604
23981
|
function moveFile(from, to) {
|
|
22605
23982
|
try {
|
|
22606
|
-
(0,
|
|
23983
|
+
(0, import_node_fs43.renameSync)(from, to);
|
|
22607
23984
|
} catch (err) {
|
|
22608
23985
|
if (err.code !== "EXDEV") throw err;
|
|
22609
|
-
(0,
|
|
22610
|
-
(0,
|
|
23986
|
+
(0, import_node_fs43.cpSync)(from, to);
|
|
23987
|
+
(0, import_node_fs43.rmSync)(from, { force: true });
|
|
22611
23988
|
}
|
|
22612
23989
|
}
|
|
22613
23990
|
function carryLegacyContents(gateDir, verityDir) {
|
|
22614
23991
|
let copied = 0;
|
|
22615
23992
|
const walk = (relDir) => {
|
|
22616
23993
|
const srcDir = (0, import_node_path28.join)(gateDir, relDir);
|
|
22617
|
-
for (const entry of (0,
|
|
23994
|
+
for (const entry of (0, import_node_fs43.readdirSync)(srcDir)) {
|
|
22618
23995
|
const rel = relDir ? (0, import_node_path28.join)(relDir, entry) : entry;
|
|
22619
23996
|
const src = (0, import_node_path28.join)(gateDir, rel);
|
|
22620
23997
|
const dest = (0, import_node_path28.join)(verityDir, rel);
|
|
22621
|
-
if ((0,
|
|
23998
|
+
if ((0, import_node_fs43.statSync)(src).isDirectory()) {
|
|
22622
23999
|
walk(rel);
|
|
22623
|
-
} else if (!(0,
|
|
22624
|
-
(0,
|
|
22625
|
-
(0,
|
|
24000
|
+
} else if (!(0, import_node_fs43.existsSync)(dest)) {
|
|
24001
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path28.dirname)(dest), { recursive: true });
|
|
24002
|
+
(0, import_node_fs43.cpSync)(src, dest);
|
|
22626
24003
|
copied++;
|
|
22627
24004
|
}
|
|
22628
24005
|
}
|
|
@@ -22633,20 +24010,20 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
22633
24010
|
async function needsMigration(root = repoRoot()) {
|
|
22634
24011
|
const gateDir = (0, import_node_path28.join)(root, ".gate");
|
|
22635
24012
|
const verityDir = (0, import_node_path28.join)(root, ".verity");
|
|
22636
|
-
if ((0,
|
|
22637
|
-
if ((0,
|
|
22638
|
-
if ((0,
|
|
24013
|
+
if ((0, import_node_fs43.existsSync)(gateDir) && !(0, import_node_fs43.existsSync)(verityDir)) return true;
|
|
24014
|
+
if ((0, import_node_fs43.existsSync)(gateDir) && (0, import_node_fs43.existsSync)(verityDir)) {
|
|
24015
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path28.join)(gateDir, "credentials")) && !(0, import_node_fs43.existsSync)((0, import_node_path28.join)(verityDir, "credentials"))) {
|
|
22639
24016
|
return true;
|
|
22640
24017
|
}
|
|
22641
|
-
if ((0,
|
|
24018
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path28.join)(gateDir, "memory")) && !(0, import_node_fs43.existsSync)((0, import_node_path28.join)(verityDir, "memory"))) {
|
|
22642
24019
|
return true;
|
|
22643
24020
|
}
|
|
22644
24021
|
}
|
|
22645
24022
|
const claudeMd = (0, import_node_path28.join)(root, "CLAUDE.md");
|
|
22646
|
-
if ((0,
|
|
24023
|
+
if ((0, import_node_fs43.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
22647
24024
|
return true;
|
|
22648
24025
|
}
|
|
22649
|
-
if ((0,
|
|
24026
|
+
if ((0, import_node_fs43.existsSync)((0, import_node_path28.join)(root, "GATE.md")) && !(0, import_node_fs43.existsSync)((0, import_node_path28.join)(root, "VERITY.md"))) {
|
|
22650
24027
|
return true;
|
|
22651
24028
|
}
|
|
22652
24029
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -22671,17 +24048,96 @@ function registerMigrateCommand(program2) {
|
|
|
22671
24048
|
});
|
|
22672
24049
|
}
|
|
22673
24050
|
|
|
22674
|
-
// src/
|
|
22675
|
-
|
|
22676
|
-
|
|
22677
|
-
|
|
24051
|
+
// src/lib/prompt.ts
|
|
24052
|
+
var readline2 = __toESM(require("node:readline/promises"));
|
|
24053
|
+
function interactive() {
|
|
24054
|
+
return !!process.stdin.isTTY && !!process.stdout.isTTY;
|
|
24055
|
+
}
|
|
24056
|
+
async function askLine(question, io = {}) {
|
|
24057
|
+
const rl = readline2.createInterface({
|
|
24058
|
+
input: io.input ?? process.stdin,
|
|
24059
|
+
output: io.output ?? process.stdout
|
|
24060
|
+
});
|
|
22678
24061
|
try {
|
|
22679
|
-
|
|
22680
|
-
|
|
24062
|
+
return await new Promise((resolve4) => {
|
|
24063
|
+
rl.question(question).then((a) => resolve4(a.trim())).catch(() => resolve4(null));
|
|
24064
|
+
rl.once("close", () => setImmediate(() => resolve4(null)));
|
|
24065
|
+
});
|
|
22681
24066
|
} finally {
|
|
22682
24067
|
rl.close();
|
|
22683
24068
|
}
|
|
22684
24069
|
}
|
|
24070
|
+
var ask = (question) => askLine(question);
|
|
24071
|
+
function parseChoice(answer, choices, fallback) {
|
|
24072
|
+
const a = answer.trim().toLowerCase();
|
|
24073
|
+
if (a === "") return { id: fallback, recognized: true };
|
|
24074
|
+
const byNumber = Number.parseInt(a, 10);
|
|
24075
|
+
if (Number.isInteger(byNumber) && byNumber >= 1 && byNumber <= choices.length) {
|
|
24076
|
+
return { id: choices[byNumber - 1].id, recognized: true };
|
|
24077
|
+
}
|
|
24078
|
+
const byId = choices.find((c) => c.id.toLowerCase() === a || c.label.toLowerCase() === a);
|
|
24079
|
+
if (byId) return { id: byId.id, recognized: true };
|
|
24080
|
+
return { id: fallback, recognized: false };
|
|
24081
|
+
}
|
|
24082
|
+
function parseMultiSelect(answer, choices, fallback) {
|
|
24083
|
+
const a = answer.trim().toLowerCase();
|
|
24084
|
+
if (a === "") return { ids: [...fallback], recognized: true };
|
|
24085
|
+
const picked = /* @__PURE__ */ new Set();
|
|
24086
|
+
for (const part of a.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
24087
|
+
const n = Number.parseInt(part, 10);
|
|
24088
|
+
if (Number.isInteger(n) && n >= 1 && n <= choices.length) {
|
|
24089
|
+
picked.add(choices[n - 1].id);
|
|
24090
|
+
continue;
|
|
24091
|
+
}
|
|
24092
|
+
const byId = choices.find((c) => c.id.toLowerCase() === part || c.label.toLowerCase() === part);
|
|
24093
|
+
if (byId) picked.add(byId.id);
|
|
24094
|
+
}
|
|
24095
|
+
if (picked.size === 0) return { ids: [...fallback], recognized: false };
|
|
24096
|
+
return { ids: choices.filter((c) => picked.has(c.id)).map((c) => c.id), recognized: true };
|
|
24097
|
+
}
|
|
24098
|
+
async function promptYes(question, opts) {
|
|
24099
|
+
if (!interactive()) return opts.nonInteractive;
|
|
24100
|
+
const answer = await ask(question);
|
|
24101
|
+
if (answer === null) return opts.nonInteractive;
|
|
24102
|
+
const a = answer.toLowerCase();
|
|
24103
|
+
return a === "" || a === "y" || a === "yes";
|
|
24104
|
+
}
|
|
24105
|
+
function printOptions(question, choices) {
|
|
24106
|
+
console.log("");
|
|
24107
|
+
console.log(` ${question}`);
|
|
24108
|
+
choices.forEach((c, i) => {
|
|
24109
|
+
const tag = c.recommended ? " (recommended)" : "";
|
|
24110
|
+
console.log(` ${i + 1}. ${c.label}${tag}${c.hint ? ` \u2014 ${c.hint}` : ""}`);
|
|
24111
|
+
});
|
|
24112
|
+
}
|
|
24113
|
+
async function promptChoice(question, choices, fallback) {
|
|
24114
|
+
if (!interactive()) return fallback;
|
|
24115
|
+
printOptions(question, choices);
|
|
24116
|
+
const defaultIdx = choices.findIndex((c) => c.id === fallback);
|
|
24117
|
+
const answer = await ask(` Choose [${defaultIdx + 1}]: `);
|
|
24118
|
+
if (answer === null) {
|
|
24119
|
+
console.log(` (no answer \u2014 using ${fallback})`);
|
|
24120
|
+
return fallback;
|
|
24121
|
+
}
|
|
24122
|
+
const parsed = parseChoice(answer, choices, fallback);
|
|
24123
|
+
if (!parsed.recognized) console.log(` Unrecognized answer "${answer}" \u2014 using ${fallback}.`);
|
|
24124
|
+
return parsed.id;
|
|
24125
|
+
}
|
|
24126
|
+
async function promptMultiSelect(question, choices, fallback) {
|
|
24127
|
+
if (!interactive()) return [...fallback];
|
|
24128
|
+
printOptions(question, choices);
|
|
24129
|
+
const defaultLabel = choices.map((c, i) => fallback.includes(c.id) ? String(i + 1) : null).filter(Boolean).join(",");
|
|
24130
|
+
const answer = await ask(` Choose one or more, comma-separated [${defaultLabel}]: `);
|
|
24131
|
+
if (answer === null) {
|
|
24132
|
+
console.log(" (no answer \u2014 using the default)");
|
|
24133
|
+
return [...fallback];
|
|
24134
|
+
}
|
|
24135
|
+
const parsed = parseMultiSelect(answer, choices, fallback);
|
|
24136
|
+
if (!parsed.recognized) console.log(` Unrecognized answer "${answer}" \u2014 using the default.`);
|
|
24137
|
+
return parsed.ids;
|
|
24138
|
+
}
|
|
24139
|
+
|
|
24140
|
+
// src/commands/init.ts
|
|
22685
24141
|
async function confirmExistingLogin(serviceUrl, remote, opts) {
|
|
22686
24142
|
const existing = await resolveToken(opts.token);
|
|
22687
24143
|
if (!existing.ok) return "drive-login";
|
|
@@ -22739,7 +24195,7 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
22739
24195
|
}
|
|
22740
24196
|
let remote = "";
|
|
22741
24197
|
try {
|
|
22742
|
-
remote = (0,
|
|
24198
|
+
remote = (0, import_node_child_process14.execSync)("git remote get-url origin", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
22743
24199
|
} catch {
|
|
22744
24200
|
}
|
|
22745
24201
|
if (!healed) {
|
|
@@ -22750,7 +24206,7 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
22750
24206
|
printInfo("Verity runs in local-only mode: the gate still runs and shows static findings, but nothing uploads.");
|
|
22751
24207
|
printInfo(' Authenticate anytime: run "verity login" (one login covers every repo you can write to).');
|
|
22752
24208
|
};
|
|
22753
|
-
if (
|
|
24209
|
+
if (interactive() && !opts.yes) {
|
|
22754
24210
|
console.log("");
|
|
22755
24211
|
console.log(" Signing in is optional. What it does:");
|
|
22756
24212
|
console.log(" - Confirms which repositories you can write to. The GitHub token is");
|
|
@@ -22765,9 +24221,12 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
22765
24221
|
console.log(" findings, but nothing is uploaded.");
|
|
22766
24222
|
console.log("");
|
|
22767
24223
|
}
|
|
22768
|
-
const wantsAuth =
|
|
24224
|
+
const wantsAuth = opts.yes ? false : await promptYes(
|
|
24225
|
+
"Authenticate with GitHub now to upload results to Verity? [Y/skip] ",
|
|
24226
|
+
{ nonInteractive: false }
|
|
24227
|
+
);
|
|
22769
24228
|
if (!wantsAuth) {
|
|
22770
|
-
printInfo("Skipped authentication.");
|
|
24229
|
+
printInfo(opts.yes ? "Skipped authentication (unattended run)." : "Skipped authentication.");
|
|
22771
24230
|
localOnlyNote();
|
|
22772
24231
|
return;
|
|
22773
24232
|
}
|
|
@@ -22790,7 +24249,7 @@ function resolveDataDir() {
|
|
|
22790
24249
|
// local dev: running from repo root
|
|
22791
24250
|
];
|
|
22792
24251
|
for (const candidate of candidates) {
|
|
22793
|
-
if ((0,
|
|
24252
|
+
if ((0, import_node_fs44.existsSync)((0, import_node_path29.join)(candidate, "skills"))) {
|
|
22794
24253
|
return candidate;
|
|
22795
24254
|
}
|
|
22796
24255
|
}
|
|
@@ -22799,22 +24258,197 @@ function resolveDataDir() {
|
|
|
22799
24258
|
);
|
|
22800
24259
|
}
|
|
22801
24260
|
async function copyDir(src, dest) {
|
|
22802
|
-
await (0,
|
|
22803
|
-
await (0,
|
|
24261
|
+
await (0, import_promises14.mkdir)(dest, { recursive: true });
|
|
24262
|
+
await (0, import_promises14.cp)(src, dest, { recursive: true, force: true });
|
|
24263
|
+
}
|
|
24264
|
+
async function skillIsCurrent(src, dest) {
|
|
24265
|
+
const list2 = (dir) => {
|
|
24266
|
+
const out = [];
|
|
24267
|
+
const walk = (d, prefix) => {
|
|
24268
|
+
for (const e of (0, import_node_fs44.readdirSync)(d, { withFileTypes: true })) {
|
|
24269
|
+
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
24270
|
+
if (e.isDirectory()) walk((0, import_node_path29.join)(d, e.name), rel);
|
|
24271
|
+
else if (e.isFile()) out.push(rel);
|
|
24272
|
+
}
|
|
24273
|
+
};
|
|
24274
|
+
walk(dir, "");
|
|
24275
|
+
return out.sort();
|
|
24276
|
+
};
|
|
24277
|
+
try {
|
|
24278
|
+
const shipped = list2(src);
|
|
24279
|
+
if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
|
|
24280
|
+
for (const rel of shipped) {
|
|
24281
|
+
const a = await (0, import_promises14.readFile)((0, import_node_path29.join)(src, rel), "utf-8");
|
|
24282
|
+
const b = await (0, import_promises14.readFile)((0, import_node_path29.join)(dest, rel), "utf-8");
|
|
24283
|
+
if (a !== b) return false;
|
|
24284
|
+
}
|
|
24285
|
+
return true;
|
|
24286
|
+
} catch {
|
|
24287
|
+
return false;
|
|
24288
|
+
}
|
|
24289
|
+
}
|
|
24290
|
+
var SKILLS = [
|
|
24291
|
+
"verity-setup",
|
|
24292
|
+
"verity-analyze",
|
|
24293
|
+
"verity-status",
|
|
24294
|
+
"verity-feedback",
|
|
24295
|
+
"verity-learn",
|
|
24296
|
+
"verity-memory",
|
|
24297
|
+
"verity-insights",
|
|
24298
|
+
"verity-reflect"
|
|
24299
|
+
];
|
|
24300
|
+
var INTENSITY_CHOICES = [
|
|
24301
|
+
{ id: "lightweight", label: "lightweight", hint: "critical security only, fastest (~3s)" },
|
|
24302
|
+
{ id: "balanced", label: "balanced", hint: "security + quality (~8s)", recommended: true },
|
|
24303
|
+
{ id: "thorough", label: "thorough", hint: "all tools, all rules (~15s)" }
|
|
24304
|
+
];
|
|
24305
|
+
var MOMENT_CHOICES = [
|
|
24306
|
+
{ id: "stop", label: "On stop", hint: "after every agent turn \u2014 fast feedback while you work", recommended: true },
|
|
24307
|
+
{ id: "pre-commit", label: "Before commit", hint: "reviews the staged diff, blocks the commit on FAIL" },
|
|
24308
|
+
{ id: "pre-push", label: "Before push / PR", hint: "reviews the to-be-pushed commits, blocks on FAIL" }
|
|
24309
|
+
];
|
|
24310
|
+
var DEFAULT_MOMENTS = ["stop"];
|
|
24311
|
+
async function askSetupQuestions(defaultsOnly, previous) {
|
|
24312
|
+
const intensityDefault = previous?.intensity ?? "balanced";
|
|
24313
|
+
const momentsDefault = previous?.moments?.length ? previous.moments : DEFAULT_MOMENTS;
|
|
24314
|
+
if (defaultsOnly) {
|
|
24315
|
+
return { intensity: intensityDefault, moments: momentsDefault, telemetry: "not-asked" };
|
|
24316
|
+
}
|
|
24317
|
+
if (previous?.intensity || previous?.moments) {
|
|
24318
|
+
printInfo(`Current: ${intensityDefault} \xB7 ${momentsDefault.join(", ")} \u2014 press Enter to keep either.`);
|
|
24319
|
+
}
|
|
24320
|
+
const intensity = await promptChoice(
|
|
24321
|
+
"Analysis intensity \u2014 how deeply should Verity review?",
|
|
24322
|
+
INTENSITY_CHOICES,
|
|
24323
|
+
intensityDefault
|
|
24324
|
+
);
|
|
24325
|
+
const moments = await promptMultiSelect(
|
|
24326
|
+
"When should Verity review your code?",
|
|
24327
|
+
MOMENT_CHOICES,
|
|
24328
|
+
momentsDefault
|
|
24329
|
+
);
|
|
24330
|
+
const current = await checkTelemetry();
|
|
24331
|
+
if (current.enabled) {
|
|
24332
|
+
printInfo(`Cost & usage telemetry: already enabled \u2192 ${current.endpoint}`);
|
|
24333
|
+
printInfo(' (turn it off with "verity telemetry uninstall")');
|
|
24334
|
+
return { intensity, moments, telemetry: "already-on" };
|
|
24335
|
+
}
|
|
24336
|
+
console.log("");
|
|
24337
|
+
console.log(" Cost & usage telemetry (opt-in) \u2014 powers the /usage dashboard.");
|
|
24338
|
+
console.log(" Sends Claude Code's own OpenTelemetry metrics and traces only: model names,");
|
|
24339
|
+
console.log(" token counts, USD cost, agent types, session ids. NOT your prompts, code, or");
|
|
24340
|
+
console.log(" tool input/output. Without it, /usage stays empty.");
|
|
24341
|
+
const wants = await promptYes(" Enable cost & usage telemetry? [Y/n] ", { nonInteractive: false });
|
|
24342
|
+
return { intensity, moments, telemetry: wants ? "yes" : "no" };
|
|
24343
|
+
}
|
|
24344
|
+
function insideClaudeCode() {
|
|
24345
|
+
return !!process.env.CLAUDECODE || !!process.env.CLAUDE_SESSION_ID;
|
|
24346
|
+
}
|
|
24347
|
+
function resumeDeferredPending(previous) {
|
|
24348
|
+
return previous?.telemetry === "deferred";
|
|
24349
|
+
}
|
|
24350
|
+
var PHASE_TWO_ARTIFACTS = [
|
|
24351
|
+
{
|
|
24352
|
+
path: ".verity/standard.yaml",
|
|
24353
|
+
what: "the Standard, synthesized from your codebase",
|
|
24354
|
+
// The presence flag travels WITH the row. Read positionally from a parallel
|
|
24355
|
+
// array, a reorder of this list would silently move every ✓ onto the wrong
|
|
24356
|
+
// path — a report that is confidently wrong about what got created.
|
|
24357
|
+
present: (a) => a.standard
|
|
24358
|
+
},
|
|
24359
|
+
{
|
|
24360
|
+
path: ".codacy/codacy.config.json",
|
|
24361
|
+
what: "curated static-analysis patterns",
|
|
24362
|
+
present: (a) => a.analysisConfig
|
|
24363
|
+
},
|
|
24364
|
+
{
|
|
24365
|
+
path: "VERITY.md",
|
|
24366
|
+
what: "project quality overview",
|
|
24367
|
+
present: (a) => a.verityMd
|
|
24368
|
+
}
|
|
24369
|
+
];
|
|
24370
|
+
async function reportPhaseTwo(startedAt) {
|
|
24371
|
+
const elapsed = Math.round((Date.now() - startedAt) / 1e3);
|
|
24372
|
+
let report = null;
|
|
24373
|
+
try {
|
|
24374
|
+
report = await buildReport();
|
|
24375
|
+
} catch {
|
|
24376
|
+
}
|
|
24377
|
+
console.log("");
|
|
24378
|
+
if (!report) {
|
|
24379
|
+
printWarn('Could not verify what the setup session produced \u2014 run "verity doctor".');
|
|
24380
|
+
return;
|
|
24381
|
+
}
|
|
24382
|
+
const { artifacts } = report;
|
|
24383
|
+
const complete = PHASE_TWO_ARTIFACTS.every((a) => a.present(artifacts));
|
|
24384
|
+
printInfo(complete ? `Setup complete (${elapsed}s).` : `Setup session ended after ${elapsed}s.`);
|
|
24385
|
+
for (const { path, what, present } of PHASE_TWO_ARTIFACTS) {
|
|
24386
|
+
const ok = present(artifacts);
|
|
24387
|
+
console.log(` ${ok ? "\u2713" : "\xB7"} ${path.padEnd(30)} ${ok ? what : `${what} \u2014 NOT created`}`);
|
|
24388
|
+
}
|
|
24389
|
+
if (!complete) {
|
|
24390
|
+
console.log("");
|
|
24391
|
+
printWarn('Setup did not finish. Re-run "/verity-setup" in Claude Code to complete it \u2014');
|
|
24392
|
+
printWarn(" nothing is lost; it picks up from what is already on disk.");
|
|
24393
|
+
}
|
|
24394
|
+
}
|
|
24395
|
+
async function handoffToSetup(enabled, claudeInstalled) {
|
|
24396
|
+
const instruct = (why) => {
|
|
24397
|
+
console.log("");
|
|
24398
|
+
printInfo("Still to do \u2014 this is what /verity-setup does (it needs a model):");
|
|
24399
|
+
for (const { path, what } of PHASE_TWO_ARTIFACTS) {
|
|
24400
|
+
console.log(` ${path.padEnd(30)} ${what}`);
|
|
24401
|
+
}
|
|
24402
|
+
console.log("");
|
|
24403
|
+
printInfo("Next step: run /verity-setup in Claude Code.");
|
|
24404
|
+
printInfo(` (${why})`);
|
|
24405
|
+
};
|
|
24406
|
+
if (!enabled) return instruct("--no-setup was passed");
|
|
24407
|
+
if (insideClaudeCode()) return instruct("you are already in a Claude Code session \u2014 invoke the skill there");
|
|
24408
|
+
if (!interactive()) return instruct("no interactive terminal here");
|
|
24409
|
+
if (!claudeInstalled) return instruct("Claude Code is not installed on this machine yet");
|
|
24410
|
+
printPhase(2, 2, "your Standard", "reading the codebase \xB7 synthesizing the Standard \xB7 curating patterns");
|
|
24411
|
+
console.log(" Claude Code takes over the screen from here. It will:");
|
|
24412
|
+
console.log(" \xB7 read your codebase \u2014 languages, frameworks, architecture");
|
|
24413
|
+
console.log(" \xB7 synthesize .verity/standard.yaml and show it to you");
|
|
24414
|
+
console.log(" \xB7 write the analysis config, then VERITY.md");
|
|
24415
|
+
console.log(" Usually a minute or two. Quit any time \u2014 re-running /verity-setup resumes.");
|
|
24416
|
+
console.log("");
|
|
24417
|
+
const startedAt = Date.now();
|
|
24418
|
+
const run2 = (0, import_node_child_process14.spawnSync)("claude", ["/verity-setup"], { stdio: "inherit" });
|
|
24419
|
+
if (run2.error) {
|
|
24420
|
+
printWarn(`Could not start Claude Code: ${run2.error.message}`);
|
|
24421
|
+
return instruct("start it yourself and run the skill there");
|
|
24422
|
+
}
|
|
24423
|
+
await reportPhaseTwo(startedAt);
|
|
22804
24424
|
}
|
|
22805
24425
|
function registerInitCommand(program2) {
|
|
22806
|
-
program2.command("init").description("
|
|
24426
|
+
program2.command("init").alias("setup").description("Set up Verity in the current project (asks the setup questions, then hands off to /verity-setup)").option("--force", "Reinstall the skills even when they are already up to date (hooks are always reconciled)").option("-y, --yes", "Take the recommended answer for every question (no prompts)").option("--no-setup", "Skip the /verity-setup handoff at the end").action(async (opts) => {
|
|
22807
24427
|
const force = opts.force ?? false;
|
|
24428
|
+
const wantsHandoff = opts.setup !== false;
|
|
24429
|
+
const defaultsOnly = (opts.yes ?? false) || !interactive();
|
|
22808
24430
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
22809
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
24431
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs44.existsSync)(m));
|
|
22810
24432
|
if (!isProject) {
|
|
22811
24433
|
printError("No project detected in the current directory.");
|
|
22812
24434
|
printInfo('Run "verity init" from your project root.');
|
|
22813
24435
|
process.exit(1);
|
|
22814
24436
|
}
|
|
22815
|
-
|
|
22816
|
-
|
|
22817
|
-
|
|
24437
|
+
const showArt = canRenderArt() && !insideClaudeCode();
|
|
24438
|
+
printBanner({ interactive: showArt });
|
|
24439
|
+
if (!showArt) {
|
|
24440
|
+
console.log("");
|
|
24441
|
+
printInfo("Initializing Verity in this project...");
|
|
24442
|
+
console.log("");
|
|
24443
|
+
} else {
|
|
24444
|
+
printPhase(1, 2, "this machine", "prerequisites \xB7 skills \xB7 hooks \xB7 sign-in");
|
|
24445
|
+
}
|
|
24446
|
+
const TOTAL_STEPS = 8;
|
|
24447
|
+
let stepNo = 0;
|
|
24448
|
+
const step = (label2) => {
|
|
24449
|
+
stepNo++;
|
|
24450
|
+
printInfo(`${DIM}[${stepNo}/${TOTAL_STEPS}]${NC} ${label2}`);
|
|
24451
|
+
};
|
|
22818
24452
|
if (await needsMigration()) {
|
|
22819
24453
|
printInfo("Legacy GATE.md install detected \u2014 migrating to Verity...");
|
|
22820
24454
|
try {
|
|
@@ -22825,143 +24459,171 @@ function registerInitCommand(program2) {
|
|
|
22825
24459
|
}
|
|
22826
24460
|
console.log("");
|
|
22827
24461
|
}
|
|
22828
|
-
|
|
22829
|
-
const
|
|
22830
|
-
const
|
|
22831
|
-
|
|
22832
|
-
|
|
22833
|
-
|
|
24462
|
+
step("Checking prerequisites");
|
|
24463
|
+
const prereqs = await checkPrereqs({ install: true });
|
|
24464
|
+
for (const c of prereqs.checks) {
|
|
24465
|
+
if (c.status === "ok") {
|
|
24466
|
+
if (c.justInstalled) continue;
|
|
24467
|
+
printInfo(` ${c.label} ${c.detail} \u2713`);
|
|
24468
|
+
} else {
|
|
24469
|
+
printWarn(` ${c.label}: ${c.detail}`);
|
|
24470
|
+
if (c.remedy) printWarn(` ${c.remedy}`);
|
|
24471
|
+
}
|
|
22834
24472
|
}
|
|
22835
|
-
|
|
22836
|
-
|
|
22837
|
-
const gitVersion = (0, import_node_child_process11.execSync)("git --version", { encoding: "utf-8" }).trim();
|
|
22838
|
-
printInfo(` ${gitVersion} \u2713`);
|
|
22839
|
-
} catch {
|
|
22840
|
-
printError("git is required but not installed. Install from https://git-scm.com");
|
|
24473
|
+
if (prereqs.blocked) {
|
|
24474
|
+
printError("A required prerequisite is missing \u2014 cannot continue.");
|
|
22841
24475
|
process.exit(1);
|
|
22842
24476
|
}
|
|
22843
|
-
|
|
22844
|
-
(0, import_node_child_process11.execSync)("which claude", { encoding: "utf-8" });
|
|
22845
|
-
printInfo(" Claude Code \u2713");
|
|
22846
|
-
} catch {
|
|
22847
|
-
printWarn(" Claude Code not found \u2014 hooks will be configured but need Claude Code to run.");
|
|
22848
|
-
}
|
|
22849
|
-
try {
|
|
22850
|
-
(0, import_node_child_process11.execSync)("which codacy-analysis", { encoding: "utf-8", stdio: "pipe" });
|
|
22851
|
-
printInfo(" @codacy/analysis-cli \u2713");
|
|
22852
|
-
} catch {
|
|
22853
|
-
printInfo(" Installing @codacy/analysis-cli...");
|
|
22854
|
-
try {
|
|
22855
|
-
(0, import_node_child_process11.execSync)("npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "pipe", timeout: 12e4 });
|
|
22856
|
-
printInfo(" @codacy/analysis-cli installed \u2713");
|
|
22857
|
-
} catch {
|
|
22858
|
-
try {
|
|
22859
|
-
printWarn(" Retrying with sudo...");
|
|
22860
|
-
(0, import_node_child_process11.execSync)("sudo npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
|
|
22861
|
-
printInfo(" @codacy/analysis-cli installed \u2713");
|
|
22862
|
-
} catch {
|
|
22863
|
-
printWarn(" Could not install @codacy/analysis-cli automatically.");
|
|
22864
|
-
printWarn(" Install manually: npm install -g @codacy/analysis-cli");
|
|
22865
|
-
printWarn(" Static analysis will be unavailable until installed.");
|
|
22866
|
-
}
|
|
22867
|
-
}
|
|
22868
|
-
}
|
|
24477
|
+
const claudeInstalled = prereqs.checks.some((c) => c.id === "claude" && c.status === "ok");
|
|
22869
24478
|
console.log("");
|
|
22870
|
-
|
|
24479
|
+
step("Installing skills");
|
|
22871
24480
|
const dataDir = resolveDataDir();
|
|
22872
24481
|
const skillsSource = (0, import_node_path29.join)(dataDir, "skills");
|
|
22873
24482
|
const skillsDest = ".claude/skills";
|
|
22874
|
-
const skills = ["verity-setup", "verity-analyze", "verity-status", "verity-feedback", "verity-learn", "verity-memory", "verity-insights", "verity-reflect"];
|
|
22875
24483
|
let skillsInstalled = 0;
|
|
22876
|
-
for (const skill of
|
|
24484
|
+
for (const skill of SKILLS) {
|
|
22877
24485
|
const src = (0, import_node_path29.join)(skillsSource, skill);
|
|
22878
24486
|
const dest = (0, import_node_path29.join)(skillsDest, skill);
|
|
22879
|
-
if (!(0,
|
|
24487
|
+
if (!(0, import_node_fs44.existsSync)(src)) {
|
|
22880
24488
|
printWarn(` Skill data not found: ${skill}`);
|
|
22881
24489
|
continue;
|
|
22882
24490
|
}
|
|
22883
|
-
if ((0,
|
|
22884
|
-
|
|
22885
|
-
|
|
22886
|
-
if ((0, import_node_fs41.existsSync)(destSkill)) {
|
|
22887
|
-
try {
|
|
22888
|
-
const srcContent = await (0, import_promises13.readFile)(srcSkill, "utf-8");
|
|
22889
|
-
const destContent = await (0, import_promises13.readFile)(destSkill, "utf-8");
|
|
22890
|
-
if (srcContent === destContent) {
|
|
22891
|
-
skillsInstalled++;
|
|
22892
|
-
continue;
|
|
22893
|
-
}
|
|
22894
|
-
} catch {
|
|
22895
|
-
}
|
|
22896
|
-
}
|
|
24491
|
+
if ((0, import_node_fs44.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
|
|
24492
|
+
skillsInstalled++;
|
|
24493
|
+
continue;
|
|
22897
24494
|
}
|
|
22898
24495
|
await copyDir(src, dest);
|
|
22899
24496
|
skillsInstalled++;
|
|
22900
24497
|
}
|
|
22901
|
-
printInfo(` ${skillsInstalled}/${
|
|
22902
|
-
|
|
22903
|
-
const
|
|
22904
|
-
const
|
|
22905
|
-
const
|
|
22906
|
-
if (
|
|
22907
|
-
|
|
22908
|
-
printInfo(" Stop hook: verity analyze \u2713");
|
|
22909
|
-
printInfo(" Intent hook: verity intent capture \u2713");
|
|
22910
|
-
printInfo(" Baseline hook: verity baseline capture \u2713");
|
|
22911
|
-
} else {
|
|
22912
|
-
printWarn(` ${hookResult.error}`);
|
|
22913
|
-
printInfo(' Run "verity hooks install --force" to overwrite.');
|
|
24498
|
+
printInfo(` ${skillsInstalled}/${SKILLS.length} skills installed to .claude/skills/ \u2713`);
|
|
24499
|
+
step(defaultsOnly ? "Setup answers (defaults)" : "Your setup answers");
|
|
24500
|
+
const previous = await readSetupState();
|
|
24501
|
+
const answers = await askSetupQuestions(defaultsOnly, previous);
|
|
24502
|
+
const { intensity, moments } = answers;
|
|
24503
|
+
if (defaultsOnly) {
|
|
24504
|
+
printInfo(` intensity: ${intensity} \xB7 moments: ${moments.join(", ") || "none"} (no questions asked)`);
|
|
22914
24505
|
}
|
|
22915
|
-
|
|
24506
|
+
step("Knowledge base, .gitignore and CLAUDE.md");
|
|
24507
|
+
await (0, import_promises14.mkdir)(VERITY_DIR, { recursive: true });
|
|
22916
24508
|
await ensureMemoryDir();
|
|
22917
|
-
const ignoreResult =
|
|
24509
|
+
const ignoreResult = ensureVerityGitignore();
|
|
22918
24510
|
if (ignoreResult === "failed") {
|
|
22919
|
-
printWarn(" .gitignore: could not
|
|
24511
|
+
printWarn(" .gitignore: could not write the Verity block \u2014 add it manually");
|
|
24512
|
+
printWarn(" (.verity/ holds copies of analyzed files, including any secret the gate flagged)");
|
|
24513
|
+
} else if (ignoreResult === "conflict") {
|
|
24514
|
+
printWarn(" .gitignore: the Verity block is in place but git still ignores .verity/standard.yaml");
|
|
24515
|
+
printWarn(" Something outside this file covers it \u2014 a global (~/.gitignore) or nested");
|
|
24516
|
+
printWarn(" .gitignore, or a pattern we do not recognise. Check: git check-ignore -v .verity/standard.yaml");
|
|
24517
|
+
printWarn(" Until it is fixed, the Standard and the knowledge graph cannot be committed.");
|
|
24518
|
+
} else if (ignoreResult === "repaired") {
|
|
24519
|
+
printInfo(" .gitignore: rewrote `.verity/` to `.verity/*` so the standard stays committable \u2713");
|
|
22920
24520
|
} else {
|
|
22921
|
-
printInfo(` .gitignore:
|
|
24521
|
+
printInfo(` .gitignore: Verity block ${ignoreResult === "added" ? "added" : "already covered"} \u2713`);
|
|
24522
|
+
}
|
|
24523
|
+
const tracked = committedVerityState();
|
|
24524
|
+
if (tracked.length > 0) {
|
|
24525
|
+
printWarn(` ${tracked.length} Verity state file(s) are tracked in git (e.g. ${tracked[0]}).`);
|
|
24526
|
+
const untrack = defaultsOnly ? false : await promptYes(" Untrack them now (files stay on disk)? [Y/n] ", { nonInteractive: false });
|
|
24527
|
+
if (untrack) {
|
|
24528
|
+
const result = untrackVerityState();
|
|
24529
|
+
if (result === "untracked") printInfo(" Untracked (staged) \u2014 commit to finish \u2713");
|
|
24530
|
+
else if (result === "failed") printWarn(' Could not untrack \u2014 run "git rm -r --cached .verity" manually');
|
|
24531
|
+
} else {
|
|
24532
|
+
printWarn(" Left tracked. Fix with: git rm -r --cached .verity && git add .verity/standard.yaml .verity/memory");
|
|
24533
|
+
}
|
|
22922
24534
|
}
|
|
22923
24535
|
try {
|
|
22924
24536
|
await ensureClaudeMdPointer();
|
|
22925
|
-
printInfo(" CLAUDE.md
|
|
24537
|
+
printInfo(" CLAUDE.md instructions \u2713");
|
|
22926
24538
|
} catch (err) {
|
|
22927
24539
|
printWarn(` Could not update CLAUDE.md: ${err.message}`);
|
|
22928
24540
|
}
|
|
22929
24541
|
const globalVerityDir = (0, import_node_path29.join)(process.env.HOME ?? "", ".verity");
|
|
22930
|
-
await (0,
|
|
24542
|
+
await (0, import_promises14.mkdir)(globalVerityDir, { recursive: true });
|
|
22931
24543
|
console.log("");
|
|
24544
|
+
step("Wiring Claude Code hooks");
|
|
24545
|
+
await applyMomentSelection(moments);
|
|
24546
|
+
const hookStatus = await checkAllVerityHooks();
|
|
24547
|
+
printInfo(` Stop (verity analyze): ${hookStatus.stop ? "on" : "off"}`);
|
|
24548
|
+
printInfo(` Pre-commit gate: ${hookStatus.guardOn.includes("commit") ? "on" : "off"}`);
|
|
24549
|
+
printInfo(` Pre-push/PR gate: ${hookStatus.guardOn.includes("push") ? "on" : "off"}`);
|
|
24550
|
+
printInfo(` Intent + baseline + compact + session-end: always on \u2713`);
|
|
24551
|
+
if (!hookStatus.stop && hookStatus.guardOn.length === 0) {
|
|
24552
|
+
printWarn(" No analysis moment is active \u2014 code changes will NOT be reviewed.");
|
|
24553
|
+
printWarn(" Enable one: verity hooks install --moments stop");
|
|
24554
|
+
}
|
|
24555
|
+
console.log("");
|
|
24556
|
+
step("Sign in to Verity (optional)");
|
|
22932
24557
|
try {
|
|
22933
24558
|
const globals = program2.opts();
|
|
22934
24559
|
const resolution = await resolveServiceUrlForAuth(globals.serviceUrl);
|
|
22935
24560
|
await runOptionalAuth(resolution, {
|
|
22936
24561
|
token: globals.token,
|
|
22937
|
-
verbose: globals.verbose
|
|
24562
|
+
verbose: globals.verbose,
|
|
24563
|
+
yes: defaultsOnly
|
|
22938
24564
|
});
|
|
22939
24565
|
} catch (err) {
|
|
22940
24566
|
printWarn(`Authentication step skipped: ${err.message}`);
|
|
22941
24567
|
}
|
|
24568
|
+
const resumeDeferred = answers.telemetry === "not-asked" && resumeDeferredPending(previous);
|
|
24569
|
+
const wantsTelemetry = answers.telemetry === "yes" || resumeDeferred;
|
|
24570
|
+
step("Cost & usage telemetry");
|
|
24571
|
+
if (answers.telemetry === "not-asked" && !resumeDeferredPending(previous)) {
|
|
24572
|
+
printInfo(' not asked (unattended run) \u2014 enable later with "verity telemetry install"');
|
|
24573
|
+
} else if (answers.telemetry === "no") {
|
|
24574
|
+
printInfo(' declined \u2014 enable later with "verity telemetry install"');
|
|
24575
|
+
}
|
|
24576
|
+
let telemetryChoice = answers.telemetry === "already-on" ? "enabled" : answers.telemetry === "no" ? "declined" : wantsTelemetry ? "deferred" : void 0;
|
|
24577
|
+
if (wantsTelemetry) {
|
|
24578
|
+
const globals = program2.opts();
|
|
24579
|
+
const token = await resolveToken(globals.token);
|
|
24580
|
+
const url = await resolveServiceUrl(globals.serviceUrl);
|
|
24581
|
+
if (token.ok && url.ok) {
|
|
24582
|
+
const installed2 = await installTelemetry(url.data);
|
|
24583
|
+
if (installed2.ok) {
|
|
24584
|
+
telemetryChoice = "enabled";
|
|
24585
|
+
printInfo(`Telemetry enabled \u2192 ${installed2.data.endpoint}`);
|
|
24586
|
+
printInfo(" takes effect on your NEXT Claude Code session; view cost & usage at /usage");
|
|
24587
|
+
} else {
|
|
24588
|
+
printWarn(`Could not enable telemetry: ${installed2.error}`);
|
|
24589
|
+
}
|
|
24590
|
+
} else {
|
|
24591
|
+
printWarn('Telemetry needs a Verity token \u2014 run "verity login", then "verity telemetry install".');
|
|
24592
|
+
}
|
|
24593
|
+
}
|
|
24594
|
+
step("Recording your answers");
|
|
24595
|
+
try {
|
|
24596
|
+
await writeSetupState({
|
|
24597
|
+
intensity,
|
|
24598
|
+
moments,
|
|
24599
|
+
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
24600
|
+
init: {
|
|
24601
|
+
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24602
|
+
cli_version: true ? "0.31.1-experimental.68fca47" : "dev"
|
|
24603
|
+
}
|
|
24604
|
+
});
|
|
24605
|
+
} catch (err) {
|
|
24606
|
+
printWarn(`Could not record setup answers: ${err.message}`);
|
|
24607
|
+
}
|
|
22942
24608
|
console.log("");
|
|
22943
|
-
printInfo("
|
|
24609
|
+
printInfo("This machine is set up.");
|
|
22944
24610
|
console.log("");
|
|
22945
|
-
console.log("
|
|
22946
|
-
console.log("
|
|
22947
|
-
console.log(" .claude/
|
|
22948
|
-
console.log(" .
|
|
22949
|
-
console.log(" .
|
|
22950
|
-
console.log(" .
|
|
22951
|
-
console.log(" .
|
|
22952
|
-
console.log(" .claude/skills/verity-insights/ \u2014 quality metrics + evolution");
|
|
22953
|
-
console.log(" .claude/skills/verity-reflect/ \u2014 capture learnings");
|
|
22954
|
-
console.log(" .claude/settings.json \u2014 hooks (verity analyze + intent capture)");
|
|
22955
|
-
console.log(" .verity/memory/ \u2014 knowledge base (8 domains, commit to git)");
|
|
24611
|
+
console.log(" .claude/skills/verity-*/ 8 skills (setup, analyze, status, feedback,");
|
|
24612
|
+
console.log(" learn, memory, insights, reflect)");
|
|
24613
|
+
console.log(" .claude/settings.json hooks, reconciled to your chosen moments");
|
|
24614
|
+
console.log(" .verity/memory/ knowledge base (commit to git)");
|
|
24615
|
+
console.log(" .verity/setup.json your answers, read by /verity-setup");
|
|
24616
|
+
console.log(" .gitignore Verity block (whitelist form)");
|
|
24617
|
+
console.log(" CLAUDE.md memory pointer, waive policy, reflection");
|
|
22956
24618
|
console.log("");
|
|
22957
|
-
console.log(
|
|
22958
|
-
|
|
24619
|
+
console.log(` Intensity: ${intensity} Moments: ${moments.join(", ") || "none"}`);
|
|
24620
|
+
await handoffToSetup(wantsHandoff, claudeInstalled);
|
|
22959
24621
|
console.log("");
|
|
22960
24622
|
});
|
|
22961
24623
|
}
|
|
22962
24624
|
|
|
22963
24625
|
// src/commands/uninstall.ts
|
|
22964
|
-
var
|
|
24626
|
+
var import_node_fs45 = require("node:fs");
|
|
22965
24627
|
var import_node_path30 = require("node:path");
|
|
22966
24628
|
var SKILL_NAMES = [
|
|
22967
24629
|
"verity-setup",
|
|
@@ -22982,10 +24644,10 @@ function registerUninstallCommand(program2) {
|
|
|
22982
24644
|
const skillsRoot = projectPath(".claude/skills");
|
|
22983
24645
|
for (const name of SKILL_NAMES) {
|
|
22984
24646
|
const dir = (0, import_node_path30.join)(skillsRoot, name);
|
|
22985
|
-
if ((0,
|
|
24647
|
+
if ((0, import_node_fs45.existsSync)(dir)) {
|
|
22986
24648
|
actions.push({
|
|
22987
24649
|
label: `Remove .claude/skills/${name}/`,
|
|
22988
|
-
apply: () => (0,
|
|
24650
|
+
apply: () => (0, import_node_fs45.rmSync)(dir, { recursive: true, force: true })
|
|
22989
24651
|
});
|
|
22990
24652
|
}
|
|
22991
24653
|
}
|
|
@@ -22999,24 +24661,24 @@ function registerUninstallCommand(program2) {
|
|
|
22999
24661
|
});
|
|
23000
24662
|
}
|
|
23001
24663
|
const verityDir = projectPath(VERITY_DIR);
|
|
23002
|
-
if ((0,
|
|
24664
|
+
if ((0, import_node_fs45.existsSync)(verityDir)) {
|
|
23003
24665
|
actions.push({
|
|
23004
24666
|
label: `Remove ${VERITY_DIR}/`,
|
|
23005
|
-
apply: () => (0,
|
|
24667
|
+
apply: () => (0, import_node_fs45.rmSync)(verityDir, { recursive: true, force: true })
|
|
23006
24668
|
});
|
|
23007
24669
|
}
|
|
23008
24670
|
if (!keepVerityMd) {
|
|
23009
24671
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
23010
|
-
if ((0,
|
|
24672
|
+
if ((0, import_node_fs45.existsSync)(verityMd)) {
|
|
23011
24673
|
actions.push({
|
|
23012
24674
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
23013
|
-
apply: () => (0,
|
|
24675
|
+
apply: () => (0, import_node_fs45.rmSync)(verityMd, { force: true })
|
|
23014
24676
|
});
|
|
23015
24677
|
}
|
|
23016
24678
|
}
|
|
23017
24679
|
const cleanupEmptyDir = (path) => {
|
|
23018
|
-
if ((0,
|
|
23019
|
-
(0,
|
|
24680
|
+
if ((0, import_node_fs45.existsSync)(path) && (0, import_node_fs45.statSync)(path).isDirectory() && (0, import_node_fs45.readdirSync)(path).length === 0) {
|
|
24681
|
+
(0, import_node_fs45.rmdirSync)(path);
|
|
23020
24682
|
}
|
|
23021
24683
|
};
|
|
23022
24684
|
actions.push({
|
|
@@ -23028,10 +24690,10 @@ function registerUninstallCommand(program2) {
|
|
|
23028
24690
|
});
|
|
23029
24691
|
const home = process.env.HOME ?? "";
|
|
23030
24692
|
const globalVerityDir = (0, import_node_path30.join)(home, ".verity");
|
|
23031
|
-
if (purgeGlobal && (0,
|
|
24693
|
+
if (purgeGlobal && (0, import_node_fs45.existsSync)(globalVerityDir)) {
|
|
23032
24694
|
actions.push({
|
|
23033
24695
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
23034
|
-
apply: () => (0,
|
|
24696
|
+
apply: () => (0, import_node_fs45.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
23035
24697
|
});
|
|
23036
24698
|
}
|
|
23037
24699
|
if (actions.length === 0) {
|
|
@@ -23051,7 +24713,7 @@ function registerUninstallCommand(program2) {
|
|
|
23051
24713
|
if (!purgeGlobal) {
|
|
23052
24714
|
printInfo('Saved tokens at ~/.verity/credentials are preserved \u2014 re-run "verity init" to reconnect.');
|
|
23053
24715
|
} else {
|
|
23054
|
-
printWarn(
|
|
24716
|
+
printWarn('Global credentials wiped \u2014 run "verity login" (or "verity init") to reconnect.');
|
|
23055
24717
|
}
|
|
23056
24718
|
});
|
|
23057
24719
|
}
|
|
@@ -23225,7 +24887,7 @@ function registerTaskCommands(program2) {
|
|
|
23225
24887
|
}
|
|
23226
24888
|
|
|
23227
24889
|
// src/commands/reset.ts
|
|
23228
|
-
var
|
|
24890
|
+
var import_node_fs46 = require("node:fs");
|
|
23229
24891
|
var import_node_path31 = require("node:path");
|
|
23230
24892
|
function registerResetCommand(program2) {
|
|
23231
24893
|
program2.command("reset").description("Close the current task and clear transient state").option("--keep-task", "Only purge caches; leave the current task open").option("--all", "Also purge diagnostic logs (.verity/.logs/)").action(async (opts) => {
|
|
@@ -23263,11 +24925,11 @@ function registerResetCommand(program2) {
|
|
|
23263
24925
|
}
|
|
23264
24926
|
const cacheDir = projectPath(CACHE_DIR);
|
|
23265
24927
|
let purged = 0;
|
|
23266
|
-
if ((0,
|
|
23267
|
-
for (const entry of (0,
|
|
24928
|
+
if ((0, import_node_fs46.existsSync)(cacheDir)) {
|
|
24929
|
+
for (const entry of (0, import_node_fs46.readdirSync)(cacheDir)) {
|
|
23268
24930
|
if (entry.startsWith("pending-")) {
|
|
23269
24931
|
try {
|
|
23270
|
-
(0,
|
|
24932
|
+
(0, import_node_fs46.unlinkSync)((0, import_node_path31.join)(cacheDir, entry));
|
|
23271
24933
|
purged++;
|
|
23272
24934
|
} catch {
|
|
23273
24935
|
}
|
|
@@ -23282,19 +24944,19 @@ function registerResetCommand(program2) {
|
|
|
23282
24944
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
23283
24945
|
];
|
|
23284
24946
|
for (const file of filesToClear) {
|
|
23285
|
-
if ((0,
|
|
24947
|
+
if ((0, import_node_fs46.existsSync)(file)) {
|
|
23286
24948
|
try {
|
|
23287
|
-
(0,
|
|
24949
|
+
(0, import_node_fs46.writeFileSync)(file, "");
|
|
23288
24950
|
} catch {
|
|
23289
24951
|
}
|
|
23290
24952
|
}
|
|
23291
24953
|
}
|
|
23292
24954
|
if (opts.all) {
|
|
23293
24955
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
23294
|
-
if ((0,
|
|
23295
|
-
for (const entry of (0,
|
|
24956
|
+
if ((0, import_node_fs46.existsSync)(logsDir)) {
|
|
24957
|
+
for (const entry of (0, import_node_fs46.readdirSync)(logsDir)) {
|
|
23296
24958
|
try {
|
|
23297
|
-
(0,
|
|
24959
|
+
(0, import_node_fs46.unlinkSync)((0, import_node_path31.join)(logsDir, entry));
|
|
23298
24960
|
} catch {
|
|
23299
24961
|
}
|
|
23300
24962
|
}
|
|
@@ -23602,8 +25264,8 @@ function registerTelemetryCommands(program2) {
|
|
|
23602
25264
|
}
|
|
23603
25265
|
|
|
23604
25266
|
// src/cli.ts
|
|
23605
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.31.1-experimental.
|
|
23606
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.1-experimental.
|
|
25267
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.31.1-experimental.68fca47").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async (_thisCommand, actionCommand) => {
|
|
25268
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.1-experimental.68fca47");
|
|
23607
25269
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
23608
25270
|
try {
|
|
23609
25271
|
await foldLegacyLocalCredential();
|
|
@@ -23629,6 +25291,7 @@ registerGuardCommand(program);
|
|
|
23629
25291
|
registerIgnoreCommand(program);
|
|
23630
25292
|
registerWaiveCommand(program);
|
|
23631
25293
|
registerInitCommand(program);
|
|
25294
|
+
registerDoctorCommand(program);
|
|
23632
25295
|
registerUninstallCommand(program);
|
|
23633
25296
|
registerTaskCommands(program);
|
|
23634
25297
|
registerResetCommand(program);
|