@codacy/verity-cli 0.28.1-experimental.99781f8 → 0.28.1-experimental.a72d2d9
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/bin/verity.js +151 -52
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -13591,6 +13591,70 @@ var import_node_fs10 = require("node:fs");
|
|
|
13591
13591
|
var import_node_crypto5 = require("node:crypto");
|
|
13592
13592
|
var import_node_path11 = require("node:path");
|
|
13593
13593
|
|
|
13594
|
+
// src/lib/skip-detection.ts
|
|
13595
|
+
function isBareAckPrompt(prompt) {
|
|
13596
|
+
if (typeof prompt !== "string") return false;
|
|
13597
|
+
const trimmed = prompt.trim();
|
|
13598
|
+
if (trimmed.length === 0) return false;
|
|
13599
|
+
if (trimmed.length > 20) return false;
|
|
13600
|
+
const bareAckPattern = /^(\d{1,2}|y|n|yes|no|yep|nope|ok(ay)?|sure|skip|cancel|stop|done|noted|got\s+it|sounds\s+good|thanks|thank\s+you|thx)[.!?]*$/i;
|
|
13601
|
+
return bareAckPattern.test(trimmed);
|
|
13602
|
+
}
|
|
13603
|
+
function isContinuationPrompt(prompt) {
|
|
13604
|
+
if (typeof prompt !== "string") return false;
|
|
13605
|
+
const trimmed = prompt.trim();
|
|
13606
|
+
if (trimmed.length === 0) return false;
|
|
13607
|
+
if (trimmed.length > 24) return false;
|
|
13608
|
+
const continuation = /^(let['’]?s\s+(go|do\s+it|start|continue)|go|go\s+ahead|go\s+on|proceed|continue|carry\s+on|keep\s+going|do\s+it|make\s+it\s+so|next|start|begin|ship\s+it|yes\s+please|please\s+continue|perfect|great|nice|excellent|agreed)[.!]*$/i;
|
|
13609
|
+
return continuation.test(trimmed) || isBareAckPrompt(trimmed);
|
|
13610
|
+
}
|
|
13611
|
+
function resolveGoalPrompt(prompts) {
|
|
13612
|
+
if (prompts.length === 0) return null;
|
|
13613
|
+
const latest = prompts[prompts.length - 1];
|
|
13614
|
+
if (!isContinuationPrompt(latest.prompt)) return { entry: latest, turnsBack: 0 };
|
|
13615
|
+
for (let i = prompts.length - 2; i >= 0; i--) {
|
|
13616
|
+
if (!isContinuationPrompt(prompts[i].prompt)) {
|
|
13617
|
+
return { entry: prompts[i], turnsBack: prompts.length - 1 - i };
|
|
13618
|
+
}
|
|
13619
|
+
}
|
|
13620
|
+
return { entry: latest, turnsBack: 0 };
|
|
13621
|
+
}
|
|
13622
|
+
function isReflectionQuestion(response) {
|
|
13623
|
+
if (!response || typeof response !== "string") return false;
|
|
13624
|
+
const markers = [
|
|
13625
|
+
/reflection\s+for\s+future\s+agents/i,
|
|
13626
|
+
/what(?:'s|\s+is)\s+one\s+thing\s+you\s+learned/i,
|
|
13627
|
+
/say\s+['"]?skip['"]?\s+to\s+skip/i,
|
|
13628
|
+
/quick\s+reflection\s+question/i,
|
|
13629
|
+
// Post-flip (VRT-21): the agent drafts the reflection itself and, when
|
|
13630
|
+
// interactive, asks the user to confirm/correct before recording. That
|
|
13631
|
+
// turn authors no code either, so it's still a reflection turn.
|
|
13632
|
+
/reflection\s+draft/i,
|
|
13633
|
+
/confirm,?\s+correct,?\s+or\s+add/i
|
|
13634
|
+
];
|
|
13635
|
+
return markers.some((m) => m.test(response));
|
|
13636
|
+
}
|
|
13637
|
+
function isMetaTaskLabel(label2) {
|
|
13638
|
+
if (label2 === null || label2 === void 0) return false;
|
|
13639
|
+
if (typeof label2 !== "string") return false;
|
|
13640
|
+
const trimmed = label2.trim();
|
|
13641
|
+
if (trimmed.length === 0) return true;
|
|
13642
|
+
const metaPatterns = [
|
|
13643
|
+
/^verity\s+[\w-]+\s+response$/i,
|
|
13644
|
+
// "Verity reflect response"
|
|
13645
|
+
/^simple user response$/i,
|
|
13646
|
+
/^verity\s+command$/i,
|
|
13647
|
+
// "Verity command"
|
|
13648
|
+
/^user\s+(question|reply|response|ack)$/i
|
|
13649
|
+
];
|
|
13650
|
+
return metaPatterns.some((p) => p.test(trimmed));
|
|
13651
|
+
}
|
|
13652
|
+
function shouldSkipForBareAck(input) {
|
|
13653
|
+
if (!isBareAckPrompt(input.prompt)) return false;
|
|
13654
|
+
if (input.turnAuthoredCode) return false;
|
|
13655
|
+
return input.canSeeTurnAuthorship;
|
|
13656
|
+
}
|
|
13657
|
+
|
|
13594
13658
|
// src/lib/dossier.ts
|
|
13595
13659
|
var import_node_fs9 = require("node:fs");
|
|
13596
13660
|
var import_node_crypto4 = require("node:crypto");
|
|
@@ -14695,7 +14759,19 @@ function sessionDossier(token, sessionId) {
|
|
|
14695
14759
|
const d = openDossier(identity);
|
|
14696
14760
|
return d ? { d, identity } : null;
|
|
14697
14761
|
}
|
|
14762
|
+
function hasActiveGoal(d) {
|
|
14763
|
+
try {
|
|
14764
|
+
if (!(0, import_node_fs10.existsSync)(d.eventsPath)) return false;
|
|
14765
|
+
return (0, import_node_fs10.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
|
|
14766
|
+
} catch {
|
|
14767
|
+
return false;
|
|
14768
|
+
}
|
|
14769
|
+
}
|
|
14698
14770
|
function recordGoal(d, prompt, source = "prompt") {
|
|
14771
|
+
if (source === "prompt" && isContinuationPrompt(prompt) && hasActiveGoal(d)) {
|
|
14772
|
+
appendEvent(d, { k: "goal_continue", text: prompt.slice(0, 64) });
|
|
14773
|
+
return;
|
|
14774
|
+
}
|
|
14699
14775
|
const text = prompt.slice(0, MAX_GOAL_CHARS);
|
|
14700
14776
|
appendEvent(d, {
|
|
14701
14777
|
k: "goal",
|
|
@@ -16625,7 +16701,7 @@ function resolveTaskContext(opts) {
|
|
|
16625
16701
|
// src/lib/cli-version.ts
|
|
16626
16702
|
function cliVersion() {
|
|
16627
16703
|
try {
|
|
16628
|
-
return true ? "0.28.1-experimental.
|
|
16704
|
+
return true ? "0.28.1-experimental.a72d2d9" : "dev";
|
|
16629
16705
|
} catch {
|
|
16630
16706
|
return "dev";
|
|
16631
16707
|
}
|
|
@@ -17222,6 +17298,33 @@ function describeCoverage(coverage, maxPaths = 5) {
|
|
|
17222
17298
|
${lines.join("\n")}
|
|
17223
17299
|
Treat those files as UNCHECKED, not as approved.`;
|
|
17224
17300
|
}
|
|
17301
|
+
function openBlockingElsewhere(statements, reviewedNow, lineShaAt) {
|
|
17302
|
+
const reviewed = new Set(reviewedNow);
|
|
17303
|
+
const out = [];
|
|
17304
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17305
|
+
for (const s of statements) {
|
|
17306
|
+
if (s.outcome !== "open") continue;
|
|
17307
|
+
if (s.register !== "BLOCK") continue;
|
|
17308
|
+
if (s.carried) continue;
|
|
17309
|
+
if (reviewed.has(s.file)) continue;
|
|
17310
|
+
if (!s.line_sha) continue;
|
|
17311
|
+
if (lineShaAt(s.file, s.line) !== s.line_sha) continue;
|
|
17312
|
+
const key = `${s.file}::${s.pattern_id}`;
|
|
17313
|
+
if (seen.has(key)) continue;
|
|
17314
|
+
seen.add(key);
|
|
17315
|
+
out.push({ file: s.file, line: s.line, pattern_id: s.pattern_id });
|
|
17316
|
+
}
|
|
17317
|
+
return out;
|
|
17318
|
+
}
|
|
17319
|
+
function describeOpenElsewhere(open) {
|
|
17320
|
+
if (open.length === 0) return null;
|
|
17321
|
+
const lines = open.slice(0, 5).map((o) => ` ${o.file}:${o.line} [${o.pattern_id}]`);
|
|
17322
|
+
const more = open.length > 5 ? `
|
|
17323
|
+
(+${open.length - 5} more)` : "";
|
|
17324
|
+
return `STILL OPEN ELSEWHERE. ${open.length} blocking finding(s) Verity raised earlier are still present in files this run did not review:
|
|
17325
|
+
${lines.join("\n")}${more}
|
|
17326
|
+
This verdict covers the current change only. The tree is not clean.`;
|
|
17327
|
+
}
|
|
17225
17328
|
|
|
17226
17329
|
// src/lib/channel.ts
|
|
17227
17330
|
var MAX_AGENT_CONTEXT_CHARS = 1500;
|
|
@@ -17316,8 +17419,10 @@ var NC2 = "\x1B[0m";
|
|
|
17316
17419
|
function emitVerdict(input) {
|
|
17317
17420
|
const exit = input.exit ?? ((code) => process.exit(code));
|
|
17318
17421
|
const { coverage, unaccounted } = reconcileCoverage(input.changed, input.coverage);
|
|
17319
|
-
|
|
17320
|
-
const
|
|
17422
|
+
let verdict = resolveVerdict(input.proposed, coverage);
|
|
17423
|
+
const openElsewhere = input.openElsewhere ?? [];
|
|
17424
|
+
if (verdict === "PASS" && openElsewhere.length > 0) verdict = "WARN";
|
|
17425
|
+
const note = [describeCoverage(coverage), describeOpenElsewhere(openElsewhere)].filter(Boolean).join("\n\n") || null;
|
|
17321
17426
|
if (unaccounted.length > 0) {
|
|
17322
17427
|
process.stderr.write(
|
|
17323
17428
|
`${YELLOW2}Verity: ${unaccounted.length} changed file(s) could not be attributed to any review stage \u2014 counted as unreviewed.${NC2}
|
|
@@ -17520,46 +17625,6 @@ function shouldWarmRetryAnalyze(result) {
|
|
|
17520
17625
|
return false;
|
|
17521
17626
|
}
|
|
17522
17627
|
|
|
17523
|
-
// src/lib/skip-detection.ts
|
|
17524
|
-
function isBareAckPrompt(prompt) {
|
|
17525
|
-
if (typeof prompt !== "string") return false;
|
|
17526
|
-
const trimmed = prompt.trim();
|
|
17527
|
-
if (trimmed.length === 0) return false;
|
|
17528
|
-
if (trimmed.length > 20) return false;
|
|
17529
|
-
const bareAckPattern = /^(\d{1,2}|y|n|yes|no|yep|nope|ok(ay)?|sure|skip|cancel|stop|done|noted|got\s+it|sounds\s+good|thanks|thank\s+you|thx)[.!?]*$/i;
|
|
17530
|
-
return bareAckPattern.test(trimmed);
|
|
17531
|
-
}
|
|
17532
|
-
function isReflectionQuestion(response) {
|
|
17533
|
-
if (!response || typeof response !== "string") return false;
|
|
17534
|
-
const markers = [
|
|
17535
|
-
/reflection\s+for\s+future\s+agents/i,
|
|
17536
|
-
/what(?:'s|\s+is)\s+one\s+thing\s+you\s+learned/i,
|
|
17537
|
-
/say\s+['"]?skip['"]?\s+to\s+skip/i,
|
|
17538
|
-
/quick\s+reflection\s+question/i,
|
|
17539
|
-
// Post-flip (VRT-21): the agent drafts the reflection itself and, when
|
|
17540
|
-
// interactive, asks the user to confirm/correct before recording. That
|
|
17541
|
-
// turn authors no code either, so it's still a reflection turn.
|
|
17542
|
-
/reflection\s+draft/i,
|
|
17543
|
-
/confirm,?\s+correct,?\s+or\s+add/i
|
|
17544
|
-
];
|
|
17545
|
-
return markers.some((m) => m.test(response));
|
|
17546
|
-
}
|
|
17547
|
-
function isMetaTaskLabel(label2) {
|
|
17548
|
-
if (label2 === null || label2 === void 0) return false;
|
|
17549
|
-
if (typeof label2 !== "string") return false;
|
|
17550
|
-
const trimmed = label2.trim();
|
|
17551
|
-
if (trimmed.length === 0) return true;
|
|
17552
|
-
const metaPatterns = [
|
|
17553
|
-
/^verity\s+[\w-]+\s+response$/i,
|
|
17554
|
-
// "Verity reflect response"
|
|
17555
|
-
/^simple user response$/i,
|
|
17556
|
-
/^verity\s+command$/i,
|
|
17557
|
-
// "Verity command"
|
|
17558
|
-
/^user\s+(question|reply|response|ack)$/i
|
|
17559
|
-
];
|
|
17560
|
-
return metaPatterns.some((p) => p.test(trimmed));
|
|
17561
|
-
}
|
|
17562
|
-
|
|
17563
17628
|
// src/lib/transcript.ts
|
|
17564
17629
|
var import_node_fs22 = require("node:fs");
|
|
17565
17630
|
var MAX_READ_BYTES = 256 * 1024;
|
|
@@ -18321,10 +18386,12 @@ async function runAnalyze(opts, globals) {
|
|
|
18321
18386
|
if (/^\s*\/verity-/i.test(latestPrompt)) {
|
|
18322
18387
|
await passAndExit("Verity command \u2014 skipping analysis", "verity-command");
|
|
18323
18388
|
}
|
|
18324
|
-
|
|
18389
|
+
const agentAuthoredCodeThisTurn = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0));
|
|
18390
|
+
const turnAuthoredCode = agentAuthoredCodeThisTurn || !!baseline && allForReview.some((f) => changedSinceBaseline(f, baseline));
|
|
18391
|
+
const canSeeTurnAuthorship = !!actionSummary || !!baseline;
|
|
18392
|
+
if (shouldSkipForBareAck({ prompt: latestPrompt, turnAuthoredCode, canSeeTurnAuthorship })) {
|
|
18325
18393
|
await passAndExit("Bare acknowledgment \u2014 skipping analysis", "bare-acknowledgment");
|
|
18326
18394
|
}
|
|
18327
|
-
const agentAuthoredCodeThisTurn = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0));
|
|
18328
18395
|
if (isReflectionQuestion(assistantResponse) && !agentAuthoredCodeThisTurn) {
|
|
18329
18396
|
await passAndExit("Reflection-prompt turn \u2014 skipping analysis", "reflection-prompt");
|
|
18330
18397
|
}
|
|
@@ -18767,7 +18834,20 @@ async function runAnalyze(opts, globals) {
|
|
|
18767
18834
|
const intentContext = {};
|
|
18768
18835
|
if (conversation && conversation.prompts.length > 0) {
|
|
18769
18836
|
const latest = conversation.prompts[conversation.prompts.length - 1];
|
|
18770
|
-
|
|
18837
|
+
const goalPrompt = resolveGoalPrompt(conversation.prompts) ?? { entry: latest, turnsBack: 0 };
|
|
18838
|
+
intentContext.user_prompt = goalPrompt.entry.prompt;
|
|
18839
|
+
if (isContinuationPrompt(intentContext.user_prompt)) {
|
|
18840
|
+
const carried = memory?.projection.goal?.text;
|
|
18841
|
+
if (carried && !isContinuationPrompt(carried)) {
|
|
18842
|
+
intentContext.continuation_prompt = latest.prompt;
|
|
18843
|
+
intentContext.user_prompt = carried;
|
|
18844
|
+
logEvent("goal_from_dossier", { chars: carried.length });
|
|
18845
|
+
}
|
|
18846
|
+
}
|
|
18847
|
+
if (goalPrompt.turnsBack > 0) {
|
|
18848
|
+
intentContext.continuation_prompt = latest.prompt;
|
|
18849
|
+
logEvent("goal_walked_back", { turns_back: goalPrompt.turnsBack });
|
|
18850
|
+
}
|
|
18771
18851
|
intentContext.session_id = latest.session_id || void 0;
|
|
18772
18852
|
intentContext.prompt_captured_at = latest.captured_at || void 0;
|
|
18773
18853
|
if (conversation.prompts.length > 1) {
|
|
@@ -18859,6 +18939,22 @@ async function runAnalyze(opts, globals) {
|
|
|
18859
18939
|
const response = result.data;
|
|
18860
18940
|
const decision = response.gate_decision ?? "(unrecognised)";
|
|
18861
18941
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
18942
|
+
let openElsewhere = [];
|
|
18943
|
+
if (memorySession) {
|
|
18944
|
+
try {
|
|
18945
|
+
const st = foldDossier(memorySession.d);
|
|
18946
|
+
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
18947
|
+
try {
|
|
18948
|
+
const src = (0, import_node_fs24.readFileSync)((0, import_node_path20.join)(repoRoot(), file), "utf8").split("\n");
|
|
18949
|
+
const at = src[line - 1];
|
|
18950
|
+
return at === void 0 ? null : lineSha(at);
|
|
18951
|
+
} catch {
|
|
18952
|
+
return null;
|
|
18953
|
+
}
|
|
18954
|
+
});
|
|
18955
|
+
} catch {
|
|
18956
|
+
}
|
|
18957
|
+
}
|
|
18862
18958
|
const reviewCoverage = {
|
|
18863
18959
|
reviewed: sentPaths,
|
|
18864
18960
|
// Declared drops from the stages that DO report themselves today. The other
|
|
@@ -19163,7 +19259,8 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
19163
19259
|
// so what the cut removes is the repeated commentary, never the defect.
|
|
19164
19260
|
agentContext: silenced ? null : agentContextFor(response, intentRepeatCount),
|
|
19165
19261
|
// The coverage note is silenced with it — half a channel is still a channel.
|
|
19166
|
-
silenced: !!silenced
|
|
19262
|
+
silenced: !!silenced,
|
|
19263
|
+
openElsewhere
|
|
19167
19264
|
});
|
|
19168
19265
|
break;
|
|
19169
19266
|
}
|
|
@@ -19183,7 +19280,8 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
19183
19280
|
userSummary,
|
|
19184
19281
|
agentContext: silenced ? null : agentContextFor(response, intentRepeatCount),
|
|
19185
19282
|
// The coverage note is silenced with it — half a channel is still a channel.
|
|
19186
|
-
silenced: !!silenced
|
|
19283
|
+
silenced: !!silenced,
|
|
19284
|
+
openElsewhere
|
|
19187
19285
|
});
|
|
19188
19286
|
break;
|
|
19189
19287
|
}
|
|
@@ -19202,7 +19300,8 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
19202
19300
|
userSummary,
|
|
19203
19301
|
agentContext: silenced ? null : agentContextFor(response, intentRepeatCount),
|
|
19204
19302
|
// The coverage note is silenced with it — half a channel is still a channel.
|
|
19205
|
-
silenced: !!silenced
|
|
19303
|
+
silenced: !!silenced,
|
|
19304
|
+
openElsewhere
|
|
19206
19305
|
});
|
|
19207
19306
|
break;
|
|
19208
19307
|
}
|
|
@@ -19316,8 +19415,8 @@ async function runReview(opts, globals) {
|
|
|
19316
19415
|
for (const p of specPaths) {
|
|
19317
19416
|
if (!(0, import_node_fs26.existsSync)(p)) continue;
|
|
19318
19417
|
try {
|
|
19319
|
-
const { readFileSync:
|
|
19320
|
-
const content =
|
|
19418
|
+
const { readFileSync: readFileSync16 } = await import("node:fs");
|
|
19419
|
+
const content = readFileSync16(p, "utf-8");
|
|
19321
19420
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
19322
19421
|
} catch {
|
|
19323
19422
|
}
|
|
@@ -21003,7 +21102,7 @@ function registerTelemetryCommands(program2) {
|
|
|
21003
21102
|
}
|
|
21004
21103
|
|
|
21005
21104
|
// src/cli.ts
|
|
21006
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.28.1-experimental.
|
|
21105
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.28.1-experimental.a72d2d9").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async () => {
|
|
21007
21106
|
try {
|
|
21008
21107
|
await foldLegacyLocalCredential();
|
|
21009
21108
|
} catch {
|