@codacy/verity-cli 0.29.4-experimental.5fcba03 → 0.29.4-experimental.7126d67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/verity.js +179 -24
  2. package/package.json +1 -1
package/bin/verity.js CHANGED
@@ -10390,11 +10390,11 @@ var MAX_DELTA_BYTES = 194560;
10390
10390
  var MAX_FILES = 40;
10391
10391
  var MAX_FILE_BYTES = 51200;
10392
10392
  var DEBOUNCE_SECONDS = 30;
10393
- var MAX_SPEC_FILES = 10;
10394
- var MAX_SPEC_FILE_BYTES = 10240;
10395
- var MAX_TOTAL_SPEC_BYTES = 30720;
10393
+ var MAX_SPEC_FILES = 6;
10394
+ var MAX_SPEC_FILE_BYTES = 512e3;
10395
+ var MAX_TOTAL_SPEC_BYTES = 512e3;
10396
10396
  var MAX_PLAN_FILES = 3;
10397
- var MAX_PLAN_FILE_BYTES = 10240;
10397
+ var MAX_PLAN_FILE_BYTES = 512e3;
10398
10398
  var MAX_INTENT_CHARS = 2e3;
10399
10399
  var SNAPSHOT_DIR = `${VERITY_DIR}/.snapshot`;
10400
10400
  var BASELINE_DIR = `${VERITY_DIR}/.baseline`;
@@ -15060,8 +15060,10 @@ function recordVerdict(d, v) {
15060
15060
  if (summary) appendEvent(d, { k: "goal_delivered", summary });
15061
15061
  }
15062
15062
  const lines = /* @__PURE__ */ new Map();
15063
+ const sent = new Set(v.sentPaths);
15063
15064
  for (const f of v.findings) {
15064
15065
  if (!f.file || typeof f.line !== "number" || !f.pattern_id) continue;
15066
+ if (!sent.has(f.file)) continue;
15065
15067
  if (!lines.has(f.file)) {
15066
15068
  try {
15067
15069
  const abs = (0, import_node_path12.join)(root, f.file);
@@ -16717,7 +16719,7 @@ function formatRunEvidence(run, startedAt) {
16717
16719
  const md = run.modeDecision;
16718
16720
  if (md) {
16719
16721
  const how = md.forced ? "forced by --mode" : `predicted=${md.predicted ?? "none"} \u2192 ${md.resolved}`;
16720
- out += row("mode", `${md.resolved} \xB7 ${how} \xB7 authored=${md.authored ? "yes" : "no"} \xB7 investigated=${md.investigated ? "yes" : "no"}`);
16722
+ 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"}`);
16721
16723
  } else {
16722
16724
  out += row("mode", `? (this run stopped in ${run.phaseReached || "no phase"}, before the mode was decided)`);
16723
16725
  }
@@ -16765,6 +16767,30 @@ function formatRunEvidence(run, startedAt) {
16765
16767
  out += row("", `${cov.outsideRepo} authored path(s) refused as outside the repo`);
16766
16768
  }
16767
16769
  }
16770
+ if (run.foldResult?.tools?.length) {
16771
+ const shown = run.foldResult.tools.slice(0, 6).map((t) => {
16772
+ const outcome = t.failed > 0 ? `${t.failed} failed` : t.last_status === 0 ? "ok" : "?";
16773
+ const where = t.targets.length > 0 ? ` \u2192 ${t.targets.slice(0, 2).join(", ")}` : "";
16774
+ return `${t.runs}\xD7 ${t.name} (${outcome})${where}`;
16775
+ });
16776
+ const more = run.foldResult.tools.length > 6 ? ` \u2026 +${run.foldResult.tools.length - 6} more` : "";
16777
+ out += row("tools", shown.join(" \xB7 ") + more);
16778
+ if (run.foldResult.coverage.toolNamesDropped > 0) {
16779
+ out += row("", `\u26A0 ${run.foldResult.coverage.toolNamesDropped} tool name(s) refused by the cap`);
16780
+ }
16781
+ }
16782
+ if (run.foldResult?.tasks?.length) {
16783
+ const t = run.foldResult.tasks;
16784
+ const done2 = t.filter((x) => x.status === "completed").length;
16785
+ out += row("tasks", `${t.length} \xB7 ${done2} completed \xB7 ` + list(t.slice(0, 4).map((x) => `#${x.id} ${x.name} [${x.status}]`), 4));
16786
+ }
16787
+ if (run.specs?.length) {
16788
+ const readThisSession = new Set(run.actionSummary?.files_read ?? []);
16789
+ const labelled = run.specs.map(
16790
+ (s) => `${s.path}${readThisSession.has(s.path) ? " (read)" : " (positional)"}`
16791
+ );
16792
+ out += row("specs", `${run.specs.length} \xB7 ${list(labelled, 5)}`);
16793
+ }
16768
16794
  if (run.staticResults.findings.length > 0) {
16769
16795
  out += row("static", `${run.staticResults.findings.length} finding(s) from ${run.staticResults.summary.tools_run.join(", ") || "no tools"}`);
16770
16796
  }
@@ -17216,7 +17242,7 @@ function channelSilence(input) {
17216
17242
  // src/lib/cli-version.ts
17217
17243
  function cliVersion() {
17218
17244
  try {
17219
- return true ? "0.29.4-experimental.5fcba03" : "dev";
17245
+ return true ? "0.29.4-experimental.7126d67" : "dev";
17220
17246
  } catch {
17221
17247
  return "dev";
17222
17248
  }
@@ -17567,18 +17593,26 @@ var SPEC_CANDIDATES = [
17567
17593
  "docs/API.md",
17568
17594
  "spec/ARCHITECTURE.md"
17569
17595
  ];
17570
- function discoverSpecs() {
17596
+ var DOC_EXT = /\.(md|mdx|ya?ml|txt|rst|adoc)$/i;
17597
+ var UNCONSULTED_FILE_BYTES = 10240;
17598
+ var UNCONSULTED_TOTAL_BYTES = 30720;
17599
+ function discoverSpecs(consulted = []) {
17571
17600
  const result = [];
17572
17601
  const seen = /* @__PURE__ */ new Set();
17573
17602
  let totalBytes = 0;
17574
- const addSpec = (specPath) => {
17603
+ const consultedDocs = new Set(
17604
+ consulted.filter((p) => DOC_EXT.test(p) && !p.startsWith("/") && !p.includes(".."))
17605
+ );
17606
+ const addSpec = (specPath, relevant = false) => {
17575
17607
  if (result.length >= MAX_SPEC_FILES) return false;
17576
- if (totalBytes >= MAX_TOTAL_SPEC_BYTES) return false;
17608
+ const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
17609
+ if (totalBytes >= totalCap) return false;
17577
17610
  if (seen.has(specPath)) return true;
17578
17611
  if (!(0, import_node_fs21.existsSync)(specPath)) return true;
17579
17612
  seen.add(specPath);
17580
- const remaining = MAX_TOTAL_SPEC_BYTES - totalBytes;
17581
- const readBytes = Math.min(MAX_SPEC_FILE_BYTES, remaining);
17613
+ const remaining = totalCap - totalBytes;
17614
+ const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
17615
+ const readBytes = Math.min(fileCap, remaining);
17582
17616
  try {
17583
17617
  const buf = Buffer.alloc(readBytes);
17584
17618
  const fd = (0, import_node_fs21.openSync)(specPath, "r");
@@ -17592,6 +17626,9 @@ function discoverSpecs() {
17592
17626
  }
17593
17627
  return true;
17594
17628
  };
17629
+ for (const doc of consultedDocs) {
17630
+ if (!addSpec(doc, true)) break;
17631
+ }
17595
17632
  for (const candidate of SPEC_CANDIDATES) {
17596
17633
  if (!addSpec(candidate)) break;
17597
17634
  }
@@ -17662,7 +17699,7 @@ function discoverPlans() {
17662
17699
  async function intentInputs(run) {
17663
17700
  const { actionSummary, allForReview, assistantResponse, baseline, baselineSessionId } = run;
17664
17701
  const conversation = await readAndClearConversationBuffer(baselineSessionId);
17665
- const specs = discoverSpecs();
17702
+ const specs = discoverSpecs(actionSummary?.files_read ?? []);
17666
17703
  const plans = discoverPlans();
17667
17704
  const agentAuthoredCodeThisTurn = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0));
17668
17705
  const turnAuthoredCode = agentAuthoredCodeThisTurn || !!baseline && allForReview.some((f) => changedSinceBaseline(f, baseline));
@@ -18178,6 +18215,18 @@ function commandShape(cmd) {
18178
18215
  return out.join(" ").slice(0, COMMAND_HEAD_CHARS);
18179
18216
  }
18180
18217
  var COMMAND_HEAD_CHARS = 80;
18218
+ var MAX_TOOL_NAMES = 64;
18219
+ var MAX_TOOL_TARGETS = 3;
18220
+ var MAX_TASKS = 64;
18221
+ var TASK_NAME_CHARS = 120;
18222
+ function toolTarget(name, input) {
18223
+ if (name === "Bash") return null;
18224
+ for (const key of ["file_path", "notebook_path", "path", "filePath"]) {
18225
+ const v = input[key];
18226
+ if (typeof v === "string" && v) return v.slice(0, 120);
18227
+ }
18228
+ return null;
18229
+ }
18181
18230
  var rootCandidateCache = /* @__PURE__ */ new Map();
18182
18231
  function candidateRoots(repoRoot2) {
18183
18232
  const cached2 = rootCandidateCache.get(repoRoot2);
@@ -18208,15 +18257,20 @@ function toRepoRelative(path, repoRoot2) {
18208
18257
  }
18209
18258
  function isInsideRepo(path, repoRoot2) {
18210
18259
  const p = path.replace(/\\/g, "/");
18211
- if (!p.startsWith("/")) return true;
18260
+ if (!isAbsolutePath(p)) return true;
18212
18261
  if (!repoRoot2) return true;
18213
18262
  return candidateRoots(repoRoot2).some((root) => p === root || p.startsWith(root + "/"));
18214
18263
  }
18264
+ function isAbsolutePath(p) {
18265
+ return p.startsWith("/") || /^[A-Za-z]:\//.test(p);
18266
+ }
18215
18267
  function fold(transcriptPath, opts = {}) {
18216
18268
  const result = {
18217
18269
  authored: [],
18218
18270
  unobserved: [],
18219
18271
  commands: [],
18272
+ tools: [],
18273
+ tasks: [],
18220
18274
  unknownTypes: [],
18221
18275
  coverage: {
18222
18276
  recordCounts: {},
@@ -18224,16 +18278,23 @@ function fold(transcriptPath, opts = {}) {
18224
18278
  malformed: 0,
18225
18279
  subagentFiles: 0,
18226
18280
  outsideRepo: 0,
18281
+ toolNamesDropped: 0,
18227
18282
  dispatched: 0,
18228
18283
  userMessages: 0,
18229
18284
  subagentSkipped: 0,
18230
18285
  compactions: 0,
18231
18286
  complete: false
18232
- }
18287
+ },
18288
+ planApproval: { approvals: 0, activeSinceLastPrompt: false }
18233
18289
  };
18290
+ const flow = { seq: 0, lastPrompt: -1, lastApproval: -1, approvals: 0 };
18234
18291
  const byPath = /* @__PURE__ */ new Map();
18235
18292
  const commandStats = /* @__PURE__ */ new Map();
18236
18293
  const pendingByToolUse = /* @__PURE__ */ new Map();
18294
+ const toolStats = /* @__PURE__ */ new Map();
18295
+ const pendingToolName = /* @__PURE__ */ new Map();
18296
+ const taskById = /* @__PURE__ */ new Map();
18297
+ const pendingTaskName = /* @__PURE__ */ new Map();
18237
18298
  const unknown = /* @__PURE__ */ new Set();
18238
18299
  const ingest = (raw, owner) => {
18239
18300
  for (const line of raw.split("\n")) {
@@ -18252,8 +18313,12 @@ function fold(transcriptPath, opts = {}) {
18252
18313
  if (type === "system" && record.subtype === "compact_boundary") {
18253
18314
  result.coverage.compactions++;
18254
18315
  }
18255
- if (type === "user" && hasUserText(record)) result.coverage.userMessages++;
18256
- collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, opts.repoRoot, result.coverage);
18316
+ if (type === "user" && hasUserText(record)) {
18317
+ result.coverage.userMessages++;
18318
+ if (owner === "agent") flow.lastPrompt = flow.seq;
18319
+ }
18320
+ if (owner === "agent") flow.seq++;
18321
+ collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, toolStats, pendingToolName, taskById, pendingTaskName, opts.repoRoot, result.coverage, flow);
18257
18322
  }
18258
18323
  };
18259
18324
  try {
@@ -18311,12 +18376,24 @@ function fold(transcriptPath, opts = {}) {
18311
18376
  result.authored = [...byPath.values()].sort((a, b) => a.p.localeCompare(b.p));
18312
18377
  result.unknownTypes = [...unknown].sort();
18313
18378
  result.commands = [...commandStats.entries()].map(([cls, s]) => ({ class: cls, ...s })).sort((a, b) => a.class.localeCompare(b.class));
18379
+ result.tools = [...toolStats.entries()].map(([name, s]) => ({
18380
+ name,
18381
+ runs: s.runs,
18382
+ failed: s.failed,
18383
+ last_status: s.last_status,
18384
+ targets: [...s.targets].map((t) => toRepoRelative(t, opts.repoRoot)).sort()
18385
+ })).sort((a, b) => b.runs - a.runs || a.name.localeCompare(b.name));
18386
+ result.tasks = [...taskById.entries()].map(([id, t]) => ({ id, name: t.name, status: t.status })).sort((a, b) => (Number(a.id) || 0) - (Number(b.id) || 0));
18314
18387
  const authoredPaths = new Set(result.authored.map((a) => a.p));
18315
18388
  for (const raw of opts.changedFiles ?? []) {
18316
18389
  const p = toRepoRelative(raw, opts.repoRoot);
18317
18390
  if (!p || authoredPaths.has(p)) continue;
18318
18391
  result.unobserved.push({ p, cause: classifyUnobserved(raw) });
18319
18392
  }
18393
+ result.planApproval = {
18394
+ approvals: flow.approvals,
18395
+ activeSinceLastPrompt: flow.lastApproval >= 0 && flow.lastApproval > flow.lastPrompt
18396
+ };
18320
18397
  return result;
18321
18398
  }
18322
18399
  function classifyUnobserved(path) {
@@ -18329,7 +18406,7 @@ function classifyUnobserved(path) {
18329
18406
  if (/\.(png|jpg|jpeg|gif|pdf|zip|woff2?|ico|mp4)$/i.test(path)) return "binary";
18330
18407
  return "no_edit_record";
18331
18408
  }
18332
- function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, repoRoot2, tally) {
18409
+ function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, toolStats, pendingToolName, taskById, pendingTaskName, repoRoot2, tally, flow) {
18333
18410
  const message = record.message;
18334
18411
  const content = message?.content ?? record.content;
18335
18412
  const blocks = Array.isArray(content) ? content : content && typeof content === "object" ? [content] : [];
@@ -18338,6 +18415,32 @@ function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse
18338
18415
  if (blockType === "tool_use") {
18339
18416
  const name = String(block.name ?? "");
18340
18417
  const input = block.input ?? {};
18418
+ if (name && toolStats.size < MAX_TOOL_NAMES) {
18419
+ const prev = toolStats.get(name) ?? { runs: 0, failed: 0, last_status: null, targets: /* @__PURE__ */ new Set() };
18420
+ prev.targets = prev.targets ?? /* @__PURE__ */ new Set();
18421
+ if (prev.targets.size < MAX_TOOL_TARGETS) {
18422
+ const target = toolTarget(name, input);
18423
+ if (target) prev.targets.add(target);
18424
+ }
18425
+ toolStats.set(name, { runs: prev.runs + 1, failed: prev.failed, last_status: null, targets: prev.targets });
18426
+ const toolId = typeof block.id === "string" ? block.id : null;
18427
+ if (toolId) pendingToolName.set(toolId, name);
18428
+ } else if (name && tally) {
18429
+ tally.toolNamesDropped += 1;
18430
+ }
18431
+ if (name === "TaskCreate") {
18432
+ const subject = typeof input.subject === "string" ? input.subject : "";
18433
+ const taskId = typeof block.id === "string" ? block.id : null;
18434
+ if (subject && taskId) pendingTaskName.set(taskId, subject.slice(0, TASK_NAME_CHARS));
18435
+ }
18436
+ if (name === "TaskUpdate") {
18437
+ const id = typeof input.taskId === "string" ? input.taskId : "";
18438
+ const status = typeof input.status === "string" ? input.status : "";
18439
+ if (id && status) {
18440
+ const entry = taskById.get(id);
18441
+ taskById.set(id, { name: entry?.name ?? `#${id}`, status });
18442
+ }
18443
+ }
18341
18444
  if (EDIT_TOOLS.has(name)) {
18342
18445
  const rawPath = typeof input.notebook_path === "string" ? input.notebook_path : typeof input.file_path === "string" ? input.file_path : null;
18343
18446
  if (rawPath && !isInsideRepo(rawPath, repoRoot2)) {
@@ -18377,6 +18480,38 @@ function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse
18377
18480
  }
18378
18481
  if (blockType === "tool_result") {
18379
18482
  const id = typeof block.tool_use_id === "string" ? block.tool_use_id : null;
18483
+ const taskName = id ? pendingTaskName.get(id) : void 0;
18484
+ if (taskName) {
18485
+ pendingTaskName.delete(id);
18486
+ const body = typeof block.content === "string" ? block.content : "";
18487
+ const created = /Task #(\d+)/.exec(body);
18488
+ if (created && taskById.size < MAX_TASKS) {
18489
+ taskById.set(created[1], { name: taskName, status: taskById.get(created[1])?.status ?? "created" });
18490
+ }
18491
+ }
18492
+ const toolName = id ? pendingToolName.get(id) : void 0;
18493
+ if (toolName === "ExitPlanMode" && flow && block.is_error !== true) {
18494
+ const body = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => typeof c.text === "string" ? c.text : "").join(" ") : "";
18495
+ if (/approved your plan/i.test(body)) {
18496
+ flow.lastApproval = flow.seq;
18497
+ flow.approvals += 1;
18498
+ }
18499
+ }
18500
+ if (toolName) {
18501
+ pendingToolName.delete(id);
18502
+ const prevTool = toolStats.get(toolName);
18503
+ if (prevTool) {
18504
+ const failed = block.is_error === true;
18505
+ toolStats.set(toolName, {
18506
+ runs: prevTool.runs,
18507
+ failed: prevTool.failed + (failed ? 1 : 0),
18508
+ last_status: block.is_error === true ? 1 : block.is_error === false ? 0 : null,
18509
+ // Carried, not rebuilt: the targets were collected on the `tool_use`
18510
+ // side and dropping them here would empty the ledger on every result.
18511
+ targets: prevTool.targets
18512
+ });
18513
+ }
18514
+ }
18380
18515
  const cls = id ? pendingByToolUse.get(id) : void 0;
18381
18516
  if (!cls) continue;
18382
18517
  pendingByToolUse.delete(id);
@@ -18419,8 +18554,13 @@ function checkConservation(changedFiles, result, repoRoot2) {
18419
18554
  // src/commands/analyze/phases/06-evidence.ts
18420
18555
  async function evidence(run) {
18421
18556
  const { opts } = run;
18422
- const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath } = run;
18557
+ const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath, turnAuthoredCode } = run;
18423
18558
  let { analysisMode, earlyFold } = run;
18559
+ const recordFlip = (stage) => {
18560
+ if (run.modeDecision) run.modeDecision = { ...run.modeDecision, resolved: "plan", flip: stage };
18561
+ logEvent("mode_flipped", { stage, to: "plan" });
18562
+ };
18563
+ const planWorthy = !!assistantResponse && !turnAuthoredCode;
18424
18564
  let staticResults = {
18425
18565
  tool: "@codacy/analysis-cli",
18426
18566
  findings: [],
@@ -18440,8 +18580,9 @@ async function evidence(run) {
18440
18580
  const debounceSeconds = parseInt(opts.debounce, 10);
18441
18581
  const debounceSkip = checkDebounce(debounceSeconds, baselineSessionId);
18442
18582
  if (debounceSkip) {
18443
- if (assistantResponse) {
18583
+ if (planWorthy) {
18444
18584
  analysisMode = "plan";
18585
+ recordFlip("debounce");
18445
18586
  } else {
18446
18587
  await passAndExit(run, debounceSkip, "debounce");
18447
18588
  }
@@ -18450,8 +18591,9 @@ async function evidence(run) {
18450
18591
  const allCheckable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable, ...securityFiles]));
18451
18592
  const mtimeSkip = checkMtime(allCheckable, hasRecentCommitFiles, baselineSessionId);
18452
18593
  if (mtimeSkip) {
18453
- if (assistantResponse) {
18594
+ if (planWorthy) {
18454
18595
  analysisMode = "plan";
18596
+ recordFlip("mtime");
18455
18597
  } else {
18456
18598
  await passAndExit(run, mtimeSkip, "no-delta-since-last-review");
18457
18599
  }
@@ -18462,8 +18604,9 @@ async function evidence(run) {
18462
18604
  const allCheckable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable, ...securityFiles]));
18463
18605
  const hashResult = checkContentHash(allCheckable, baselineSessionId);
18464
18606
  if (hashResult.skip) {
18465
- if (assistantResponse) {
18607
+ if (planWorthy) {
18466
18608
  analysisMode = "plan";
18609
+ recordFlip("content-hash");
18467
18610
  } else {
18468
18611
  await passAndExit(run, hashResult.skip, "no-delta-since-last-review");
18469
18612
  }
@@ -18525,8 +18668,9 @@ async function evidence(run) {
18525
18668
  maxTotalBytes: parseInt(opts.maxTotalSize, 10)
18526
18669
  });
18527
18670
  if (codeDelta.files.length === 0 && staticResults.findings.length === 0) {
18528
- if (assistantResponse) {
18671
+ if (planWorthy) {
18529
18672
  analysisMode = "plan";
18673
+ recordFlip("empty-after-scoping");
18530
18674
  } else {
18531
18675
  await passAndExit(
18532
18676
  run,
@@ -19370,6 +19514,8 @@ async function buildRequest(run) {
19370
19514
  authored_since_verdict: memorySession ? foldDossier(memorySession.d).authored_all.filter((a) => a.hash_now !== a.hash_at_last_verdict).map((a) => a.path) : [],
19371
19515
  unobserved: foldResult?.unobserved ?? [],
19372
19516
  commands: foldResult?.commands ?? [],
19517
+ tools: foldResult?.tools ?? [],
19518
+ tasks: foldResult?.tasks ?? [],
19373
19519
  unknown_types: foldResult?.unknownTypes ?? [],
19374
19520
  coverage: foldResult?.coverage ?? { recordCounts: {}, totalRecords: 0, malformed: 0, subagentFiles: 0, subagentSkipped: 0, complete: false },
19375
19521
  // INV-19, computed client-side and sent so a conservation failure is
@@ -19480,6 +19626,10 @@ async function buildRequest(run) {
19480
19626
  intentContext.user_prompt = w4Task.goal;
19481
19627
  logEvent("w4_issue_anchor", { issue: w4Task.number, via: w4Task.via });
19482
19628
  }
19629
+ if (foldResult?.planApproval?.activeSinceLastPrompt && intentContext.user_prompt) {
19630
+ intentContext.plan_approved = true;
19631
+ logEvent("plan_approval_carried", { approvals: foldResult.planApproval.approvals });
19632
+ }
19483
19633
  if (assistantResponse) {
19484
19634
  const cap = analysisMode === "plan" ? MAX_ASSISTANT_RESPONSE_CHARS_PLAN : MAX_ASSISTANT_RESPONSE_CHARS_DEFAULT;
19485
19635
  intentContext.assistant_response = assistantResponse.length > cap ? assistantResponse.slice(0, cap) : assistantResponse;
@@ -19743,6 +19893,11 @@ async function reconcile(run) {
19743
19893
  decision,
19744
19894
  branch: getCurrentBranch(),
19745
19895
  watermarkSha: watermarkIsPartial ? null : watermarkHash,
19896
+ // The byte witness — the same "only honest definition of reviewed" the
19897
+ // coverage column uses. A finding on a path outside this set records no
19898
+ // statement (plan-mode prose anchored to unsent files must not become
19899
+ // "STILL OPEN … the tree is not clean").
19900
+ sentPaths,
19746
19901
  findings: response.findings?.map((f) => ({
19747
19902
  file: f.file,
19748
19903
  line: f.line,
@@ -21996,8 +22151,8 @@ function registerTelemetryCommands(program2) {
21996
22151
  }
21997
22152
 
21998
22153
  // src/cli.ts
21999
- program.name("verity").description("CLI for Verity quality gate service").version("0.29.4-experimental.5fcba03").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) => {
22000
- installStderrLog(actionCommand.name(), process.argv.slice(2), "0.29.4-experimental.5fcba03");
22154
+ program.name("verity").description("CLI for Verity quality gate service").version("0.29.4-experimental.7126d67").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) => {
22155
+ installStderrLog(actionCommand.name(), process.argv.slice(2), "0.29.4-experimental.7126d67");
22001
22156
  setUserNamedServiceUrl(program.opts().serviceUrl);
22002
22157
  try {
22003
22158
  await foldLegacyLocalCredential();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/verity-cli",
3
- "version": "0.29.4-experimental.5fcba03",
3
+ "version": "0.29.4-experimental.7126d67",
4
4
  "description": "CLI for Verity quality gate service",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://verity.md",