@codacy/verity-cli 0.31.2 → 0.31.3
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 +20 -0
- package/bin/verity.js +340 -307
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -107,6 +107,26 @@ with one entry point.
|
|
|
107
107
|
terminal (Ctrl+D, a pty that ends) falls back to the default instead of
|
|
108
108
|
crashing init between copying the skills and wiring the hooks.
|
|
109
109
|
|
|
110
|
+
## [0.31.3] — 2026-09-03
|
|
111
|
+
|
|
112
|
+
**After a rebase, Verity reviewed the wrong code.** When a branch was rebased
|
|
113
|
+
onto an updated main, the gate could treat all of the upstream changes as the
|
|
114
|
+
session's own work and block the push on findings in code the session never
|
|
115
|
+
touched. The cause was that the review baseline was trusted by whether its commit
|
|
116
|
+
still existed rather than whether it was still part of the current history, so a
|
|
117
|
+
rewritten baseline kept anchoring every diff.
|
|
118
|
+
|
|
119
|
+
- **The push gate reviews exactly what the push publishes** — the commits the
|
|
120
|
+
remote does not yet have — so a rebase, a force-push, a first push, or
|
|
121
|
+
re-pushing an already-published commit each review only their real new work.
|
|
122
|
+
- **The stop-hook baseline is trusted only while it is an ancestor of HEAD.** A
|
|
123
|
+
rewritten baseline is discarded and re-derived from the commits actually made
|
|
124
|
+
since, so upstream changes are never attributed to the session.
|
|
125
|
+
- **A commit made during a merge reviews only the files you resolved**, not the
|
|
126
|
+
whole incoming branch.
|
|
127
|
+
- **A slash command such as `/login` is no longer treated as a task or a goal**,
|
|
128
|
+
so the review is graded against what you were actually working on.
|
|
129
|
+
|
|
110
130
|
## [0.31.1] — 2026-08-27
|
|
111
131
|
|
|
112
132
|
**Verity stops repeating itself.** A finding it had already closed could keep
|
package/bin/verity.js
CHANGED
|
@@ -10833,16 +10833,9 @@ function splitLines(s) {
|
|
|
10833
10833
|
}
|
|
10834
10834
|
var SHA_RE = /^[0-9a-f]{40}$/;
|
|
10835
10835
|
function readBaselineSha() {
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
sha = (0, import_node_fs3.readFileSync)(BASELINE_SHA_FILE, "utf-8").trim();
|
|
10840
|
-
} catch {
|
|
10841
|
-
return null;
|
|
10842
|
-
}
|
|
10843
|
-
if (!SHA_RE.test(sha)) return null;
|
|
10844
|
-
const reachable = execGit(`git cat-file -e ${sha}^{commit} 2>/dev/null && echo ok`) === "ok";
|
|
10845
|
-
if (!reachable) {
|
|
10836
|
+
const sha = readRawBaselineSha();
|
|
10837
|
+
if (sha === null) return null;
|
|
10838
|
+
if (!commitResolves(sha)) {
|
|
10846
10839
|
try {
|
|
10847
10840
|
(0, import_node_fs3.unlinkSync)(BASELINE_SHA_FILE);
|
|
10848
10841
|
} catch {
|
|
@@ -10851,6 +10844,16 @@ function readBaselineSha() {
|
|
|
10851
10844
|
}
|
|
10852
10845
|
return sha;
|
|
10853
10846
|
}
|
|
10847
|
+
function readRawBaselineSha() {
|
|
10848
|
+
if (!(0, import_node_fs3.existsSync)(BASELINE_SHA_FILE)) return null;
|
|
10849
|
+
let sha;
|
|
10850
|
+
try {
|
|
10851
|
+
sha = (0, import_node_fs3.readFileSync)(BASELINE_SHA_FILE, "utf-8").trim();
|
|
10852
|
+
} catch {
|
|
10853
|
+
return null;
|
|
10854
|
+
}
|
|
10855
|
+
return SHA_RE.test(sha) ? sha : null;
|
|
10856
|
+
}
|
|
10854
10857
|
function writeBaselineSha(sha) {
|
|
10855
10858
|
if (!SHA_RE.test(sha)) return;
|
|
10856
10859
|
try {
|
|
@@ -10859,6 +10862,25 @@ function writeBaselineSha(sha) {
|
|
|
10859
10862
|
} catch {
|
|
10860
10863
|
}
|
|
10861
10864
|
}
|
|
10865
|
+
function commitObjectExists(sha) {
|
|
10866
|
+
if (!SHA_RE.test(sha)) return false;
|
|
10867
|
+
return execGit(`git cat-file -e ${sha}^{commit} 2>/dev/null && echo ok`) === "ok";
|
|
10868
|
+
}
|
|
10869
|
+
function committedSinceRewrite(oldSha) {
|
|
10870
|
+
if (!SHA_RE.test(oldSha)) return [];
|
|
10871
|
+
const newLocal = new Set(splitLines(execGit(`git rev-list HEAD --not ${oldSha} --remotes`)));
|
|
10872
|
+
if (newLocal.size === 0) return [];
|
|
10873
|
+
const files = /* @__PURE__ */ new Set();
|
|
10874
|
+
for (const line of splitLines(execGit(`git cherry ${oldSha} HEAD`))) {
|
|
10875
|
+
const sp = line.indexOf(" ");
|
|
10876
|
+
if (sp < 0) continue;
|
|
10877
|
+
const mark = line.slice(0, sp);
|
|
10878
|
+
const sha = line.slice(sp + 1).trim();
|
|
10879
|
+
if (mark !== "+" || !newLocal.has(sha)) continue;
|
|
10880
|
+
for (const f of splitLines(execGit(`git diff-tree --no-commit-id --name-only -r ${sha}`))) files.add(f);
|
|
10881
|
+
}
|
|
10882
|
+
return [...files].filter((f) => !isVerityOwnedPath(f));
|
|
10883
|
+
}
|
|
10862
10884
|
var VERITY_OWNED_PREFIXES = [".verity/", ".gate/", ".codacy/"];
|
|
10863
10885
|
var VERITY_OWNED_FILES = ["VERITY.md"];
|
|
10864
10886
|
function isVerityOwnedPath(file) {
|
|
@@ -10871,6 +10893,7 @@ function getChangedFiles() {
|
|
|
10871
10893
|
for (const f of splitLines(execGit("git diff --name-only HEAD"))) sets.add(f);
|
|
10872
10894
|
for (const f of splitLines(execGit("git diff --name-only --cached"))) sets.add(f);
|
|
10873
10895
|
for (const f of splitLines(execGit("git ls-files --others --exclude-standard"))) sets.add(f);
|
|
10896
|
+
const rawBaseline = readRawBaselineSha();
|
|
10874
10897
|
const baseline = readBaselineSha();
|
|
10875
10898
|
if (baseline) {
|
|
10876
10899
|
const committed = splitLines(execGit(`git diff --name-only ${baseline}..HEAD`));
|
|
@@ -10878,6 +10901,13 @@ function getChangedFiles() {
|
|
|
10878
10901
|
hasRecentCommitFiles = true;
|
|
10879
10902
|
for (const f of committed) sets.add(f);
|
|
10880
10903
|
}
|
|
10904
|
+
} else if (rawBaseline && commitObjectExists(rawBaseline)) {
|
|
10905
|
+
const committed = committedSinceRewrite(rawBaseline);
|
|
10906
|
+
logEvent("baseline_rewritten", { recovered: committed.length });
|
|
10907
|
+
if (committed.length > 0) {
|
|
10908
|
+
hasRecentCommitFiles = true;
|
|
10909
|
+
for (const f of committed) sets.add(f);
|
|
10910
|
+
}
|
|
10881
10911
|
} else {
|
|
10882
10912
|
const headTimestamp = parseInt(execGit("git log -1 --format=%ct HEAD"), 10) || 0;
|
|
10883
10913
|
const commitAge = Math.floor(Date.now() / 1e3) - headTimestamp;
|
|
@@ -13083,6 +13113,242 @@ function getRecentCommitMessages() {
|
|
|
13083
13113
|
}
|
|
13084
13114
|
}
|
|
13085
13115
|
|
|
13116
|
+
// src/lib/analysis-mode.ts
|
|
13117
|
+
var DEBUG_PHRASES = [
|
|
13118
|
+
"not working",
|
|
13119
|
+
"doesn't work",
|
|
13120
|
+
"doesn't work",
|
|
13121
|
+
"does not work",
|
|
13122
|
+
"isn't working",
|
|
13123
|
+
"is not working",
|
|
13124
|
+
"can't figure out",
|
|
13125
|
+
"stack trace"
|
|
13126
|
+
];
|
|
13127
|
+
var DEBUG_WORDS = [
|
|
13128
|
+
"fix",
|
|
13129
|
+
"bug",
|
|
13130
|
+
"broken",
|
|
13131
|
+
"crash",
|
|
13132
|
+
"crashing",
|
|
13133
|
+
"failing",
|
|
13134
|
+
"debug",
|
|
13135
|
+
"debugging",
|
|
13136
|
+
"investigate",
|
|
13137
|
+
"troubleshoot",
|
|
13138
|
+
"regression",
|
|
13139
|
+
"wrong"
|
|
13140
|
+
];
|
|
13141
|
+
var DEBUG_PATTERN = new RegExp(
|
|
13142
|
+
[
|
|
13143
|
+
...DEBUG_PHRASES.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")),
|
|
13144
|
+
...DEBUG_WORDS.map((w) => `\\b${w}\\b`)
|
|
13145
|
+
].join("|"),
|
|
13146
|
+
"i"
|
|
13147
|
+
);
|
|
13148
|
+
var FALSE_POSITIVE_PATTERNS = [
|
|
13149
|
+
/\b(?:add|create|implement|write|build|design|set\s*up)\b.{0,20}\berror\b/i,
|
|
13150
|
+
/\berror\s+handling\b/i,
|
|
13151
|
+
/\berror\s+boundar(?:y|ies)\b/i,
|
|
13152
|
+
/\berror\s+(?:type|class|page|component|message|code|enum)\b/i,
|
|
13153
|
+
/\b(?:add|create|implement|write|build)\b.{0,20}\b(?:fix|debug|issue)\b/i
|
|
13154
|
+
];
|
|
13155
|
+
function hasDebugIntent(prompt) {
|
|
13156
|
+
if (!DEBUG_PATTERN.test(prompt)) return false;
|
|
13157
|
+
for (const fp of FALSE_POSITIVE_PATTERNS) {
|
|
13158
|
+
if (fp.test(prompt)) return false;
|
|
13159
|
+
}
|
|
13160
|
+
return true;
|
|
13161
|
+
}
|
|
13162
|
+
var GIT_ONLY_PATTERN = /\b(commit|push|deploy|merge|rebase|tag|release|publish|ship)\b/i;
|
|
13163
|
+
var CODE_AUTHORING_PATTERN = /\b(add|create|implement|build|write|fix|update|change|refactor|modify|remove|delete|move|rename)\b.*\b(function|component|feature|endpoint|test|file|module|class|type|interface|hook|page|route|style|migration|code|bug|error|issue)\b/i;
|
|
13164
|
+
function isGitOnlyPrompt(prompt) {
|
|
13165
|
+
if (!GIT_ONLY_PATTERN.test(prompt)) return false;
|
|
13166
|
+
if (CODE_AUTHORING_PATTERN.test(prompt)) return false;
|
|
13167
|
+
return true;
|
|
13168
|
+
}
|
|
13169
|
+
function reconcileAnalysisMode(predictedMode, signals) {
|
|
13170
|
+
const mode2 = resolveAnalysisMode(predictedMode, signals);
|
|
13171
|
+
if (mode2 !== "skip") return mode2;
|
|
13172
|
+
const windowIsOrphaned = signals.actionSummary?.transcript_windowed === "orphaned";
|
|
13173
|
+
if (windowIsOrphaned && !signals.sessionAuthoredCode) return "standard";
|
|
13174
|
+
return mode2;
|
|
13175
|
+
}
|
|
13176
|
+
function resolveAnalysisMode(predictedMode, signals) {
|
|
13177
|
+
if (!predictedMode || !isValidMode(predictedMode)) {
|
|
13178
|
+
return detectAnalysisMode(
|
|
13179
|
+
signals.noFilesChanged,
|
|
13180
|
+
signals.assistantResponse,
|
|
13181
|
+
signals.conversationPrompts,
|
|
13182
|
+
signals.actionSummary,
|
|
13183
|
+
signals.sessionAuthoredCode
|
|
13184
|
+
);
|
|
13185
|
+
}
|
|
13186
|
+
const agentAuthoredCode = !!(signals.actionSummary && (signals.actionSummary.files_edited.length > 0 || signals.actionSummary.files_created.length > 0)) || !!signals.sessionAuthoredCode;
|
|
13187
|
+
const agentInvestigated = didAgentInvestigate(signals.actionSummary);
|
|
13188
|
+
switch (predictedMode) {
|
|
13189
|
+
case "skip":
|
|
13190
|
+
if (agentAuthoredCode) return "standard";
|
|
13191
|
+
return "skip";
|
|
13192
|
+
case "plan":
|
|
13193
|
+
if (agentAuthoredCode) return "standard";
|
|
13194
|
+
return "plan";
|
|
13195
|
+
case "debug":
|
|
13196
|
+
return "debug";
|
|
13197
|
+
case "standard":
|
|
13198
|
+
if (!!signals.actionSummary && !agentAuthoredCode && !!signals.assistantResponse) {
|
|
13199
|
+
return agentInvestigated ? "plan" : "skip";
|
|
13200
|
+
}
|
|
13201
|
+
return "standard";
|
|
13202
|
+
}
|
|
13203
|
+
}
|
|
13204
|
+
function didAgentInvestigate(summary) {
|
|
13205
|
+
if (!summary) return false;
|
|
13206
|
+
return summary.files_read.length > 0 || summary.searches > 0 || summary.commands.length > 0 || summary.subagents > 0 || summary.web_fetches > 0;
|
|
13207
|
+
}
|
|
13208
|
+
function isValidMode(mode2) {
|
|
13209
|
+
return mode2 === "standard" || mode2 === "plan" || mode2 === "debug" || mode2 === "skip";
|
|
13210
|
+
}
|
|
13211
|
+
function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPrompts, actionSummary, sessionAuthoredCode) {
|
|
13212
|
+
const agentAuthoredCode = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0)) || !!sessionAuthoredCode;
|
|
13213
|
+
if (conversationPrompts.length > 0 && conversationPrompts.every(isGitOnlyPrompt)) {
|
|
13214
|
+
if (!agentAuthoredCode) return "skip";
|
|
13215
|
+
}
|
|
13216
|
+
if (noFilesChanged && !!assistantResponse && !agentAuthoredCode) {
|
|
13217
|
+
return "plan";
|
|
13218
|
+
}
|
|
13219
|
+
if (!!actionSummary && !agentAuthoredCode && !!assistantResponse) {
|
|
13220
|
+
return didAgentInvestigate(actionSummary) ? "plan" : "skip";
|
|
13221
|
+
}
|
|
13222
|
+
for (const prompt of conversationPrompts) {
|
|
13223
|
+
if (hasDebugIntent(prompt)) {
|
|
13224
|
+
return "debug";
|
|
13225
|
+
}
|
|
13226
|
+
}
|
|
13227
|
+
return "standard";
|
|
13228
|
+
}
|
|
13229
|
+
var FILE_MUTATE_RE = /(?:^|[\s|&;(`])(?:sed\s+-i|perl\s+-i|awk\b|tee\b|dd\b|cp\b|mv\b|ln\b|install\b|touch\b|patch\b|git\s+(?:apply|am)\b|cargo\s+build|go\s+generate|make\b|--write\b|--fix\b|--in-place\b)|>>?(?![&>])/i;
|
|
13230
|
+
var GIT_PLUMBING_RE = /^\s*git\s+(?:merge|rebase|stash|cherry-pick|revert|pull|fetch|checkout|switch|reset|restore|clean)\b/i;
|
|
13231
|
+
var READ_ONLY_RE = /^\s*(?:git\s+(?:status|diff|log|show|branch|remote|config|rev-parse|ls-files|blame|describe)|ls|cat|head|tail|less|grep|rg|find|pwd|echo|printf|wc|which|type|tree|stat|file|env|printenv|date|whoami)\b/i;
|
|
13232
|
+
var CHAIN_RE = /&&|\||;|\$\(|\x60/;
|
|
13233
|
+
function isNonAuthoringCommand(cmd) {
|
|
13234
|
+
if (typeof cmd !== "string" || cmd.trim().length === 0) return false;
|
|
13235
|
+
if (FILE_MUTATE_RE.test(cmd)) return false;
|
|
13236
|
+
if (CHAIN_RE.test(cmd)) return false;
|
|
13237
|
+
return GIT_PLUMBING_RE.test(cmd) || READ_ONLY_RE.test(cmd);
|
|
13238
|
+
}
|
|
13239
|
+
function hasNonEditAuthorship(actionSummary, sessionAuthoredCode) {
|
|
13240
|
+
if (!actionSummary) return sessionAuthoredCode;
|
|
13241
|
+
if ((actionSummary.subagents ?? 0) > 0) return true;
|
|
13242
|
+
if (Object.keys(actionSummary.tool_counts ?? {}).some((t) => t.startsWith("mcp__"))) return true;
|
|
13243
|
+
const commands = actionSummary.commands ?? [];
|
|
13244
|
+
if (commands.some((c) => FILE_MUTATE_RE.test(c))) return true;
|
|
13245
|
+
if (sessionAuthoredCode) {
|
|
13246
|
+
const allSafe = commands.length > 0 && commands.every(isNonAuthoringCommand);
|
|
13247
|
+
if (!allSafe) return true;
|
|
13248
|
+
}
|
|
13249
|
+
return false;
|
|
13250
|
+
}
|
|
13251
|
+
function scopeToAuthored(files, actionSummary) {
|
|
13252
|
+
if (!actionSummary) return { files, signal: "no-transcript" };
|
|
13253
|
+
const touched = [...actionSummary.files_edited ?? [], ...actionSummary.files_created ?? []];
|
|
13254
|
+
if (touched.length === 0) return { files: [], signal: "none-authored" };
|
|
13255
|
+
return { files: narrowToAgentAuthored(files, actionSummary), signal: "authored" };
|
|
13256
|
+
}
|
|
13257
|
+
function chooseReviewScope(input) {
|
|
13258
|
+
if (input.narrowingIsTrustworthy) return input.scopedFiles;
|
|
13259
|
+
if (input.recoveredScope.length > 0) return input.recoveredScope;
|
|
13260
|
+
return input.authorshipWasObservable ? [] : input.allForReview;
|
|
13261
|
+
}
|
|
13262
|
+
function narrowToAgentAuthored(files, actionSummary) {
|
|
13263
|
+
if (!actionSummary) return files;
|
|
13264
|
+
const touched = [
|
|
13265
|
+
...actionSummary.files_edited,
|
|
13266
|
+
...actionSummary.files_created
|
|
13267
|
+
];
|
|
13268
|
+
if (touched.length === 0) return files;
|
|
13269
|
+
return files.filter((f) => {
|
|
13270
|
+
const suffix = "/" + f;
|
|
13271
|
+
return touched.some((t) => t === f || t.endsWith(suffix));
|
|
13272
|
+
});
|
|
13273
|
+
}
|
|
13274
|
+
|
|
13275
|
+
// src/lib/skip-detection.ts
|
|
13276
|
+
function isBareAckPrompt(prompt) {
|
|
13277
|
+
if (typeof prompt !== "string") return false;
|
|
13278
|
+
const trimmed = prompt.trim();
|
|
13279
|
+
if (trimmed.length === 0) return false;
|
|
13280
|
+
if (trimmed.length > 20) return false;
|
|
13281
|
+
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;
|
|
13282
|
+
return bareAckPattern.test(trimmed);
|
|
13283
|
+
}
|
|
13284
|
+
function isContinuationPrompt(prompt) {
|
|
13285
|
+
if (typeof prompt !== "string") return false;
|
|
13286
|
+
const trimmed = prompt.trim();
|
|
13287
|
+
if (trimmed.length === 0) return false;
|
|
13288
|
+
if (trimmed.length > 24) return false;
|
|
13289
|
+
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;
|
|
13290
|
+
return continuation.test(trimmed) || isBareAckPrompt(trimmed);
|
|
13291
|
+
}
|
|
13292
|
+
function isSlashCommand(prompt) {
|
|
13293
|
+
if (typeof prompt !== "string") return false;
|
|
13294
|
+
return /^\s*\/[A-Za-z][\w-]*(\s|$)/.test(prompt);
|
|
13295
|
+
}
|
|
13296
|
+
function resolveGoalPrompt(prompts) {
|
|
13297
|
+
if (prompts.length === 0) return null;
|
|
13298
|
+
const latest = prompts[prompts.length - 1];
|
|
13299
|
+
if (!isContinuationPrompt(latest.prompt)) return { entry: latest, turnsBack: 0 };
|
|
13300
|
+
for (let i = prompts.length - 2; i >= 0; i--) {
|
|
13301
|
+
if (!isContinuationPrompt(prompts[i].prompt)) {
|
|
13302
|
+
return { entry: prompts[i], turnsBack: prompts.length - 1 - i };
|
|
13303
|
+
}
|
|
13304
|
+
}
|
|
13305
|
+
return { entry: latest, turnsBack: 0 };
|
|
13306
|
+
}
|
|
13307
|
+
function isReflectionQuestion(response) {
|
|
13308
|
+
if (!response || typeof response !== "string") return false;
|
|
13309
|
+
const markers = [
|
|
13310
|
+
/reflection\s+for\s+future\s+agents/i,
|
|
13311
|
+
/what(?:'s|\s+is)\s+one\s+thing\s+you\s+learned/i,
|
|
13312
|
+
/say\s+['"]?skip['"]?\s+to\s+skip/i,
|
|
13313
|
+
/quick\s+reflection\s+question/i,
|
|
13314
|
+
// Post-flip (VRT-21): the agent drafts the reflection itself and, when
|
|
13315
|
+
// interactive, asks the user to confirm/correct before recording. That
|
|
13316
|
+
// turn authors no code either, so it's still a reflection turn.
|
|
13317
|
+
/reflection\s+draft/i,
|
|
13318
|
+
/confirm,?\s+correct,?\s+or\s+add/i
|
|
13319
|
+
];
|
|
13320
|
+
return markers.some((m) => m.test(response));
|
|
13321
|
+
}
|
|
13322
|
+
function isMetaTaskLabel(label2) {
|
|
13323
|
+
if (label2 === null || label2 === void 0) return false;
|
|
13324
|
+
if (typeof label2 !== "string") return false;
|
|
13325
|
+
const trimmed = label2.trim();
|
|
13326
|
+
if (trimmed.length === 0) return true;
|
|
13327
|
+
const metaPatterns = [
|
|
13328
|
+
/^verity\s+[\w-]+\s+response$/i,
|
|
13329
|
+
// "Verity reflect response"
|
|
13330
|
+
/^simple user response$/i,
|
|
13331
|
+
/^verity\s+command$/i,
|
|
13332
|
+
// "Verity command"
|
|
13333
|
+
/^user\s+(question|reply|response|ack)$/i
|
|
13334
|
+
];
|
|
13335
|
+
return metaPatterns.some((p) => p.test(trimmed));
|
|
13336
|
+
}
|
|
13337
|
+
function shouldSkipForBareAck(input) {
|
|
13338
|
+
if (!isBareAckPrompt(input.prompt)) return false;
|
|
13339
|
+
if (input.turnAuthoredCode) return false;
|
|
13340
|
+
return input.canSeeTurnAuthorship;
|
|
13341
|
+
}
|
|
13342
|
+
function isCommandOnlyTurn(input) {
|
|
13343
|
+
if (!input.authorshipIsObservable) return false;
|
|
13344
|
+
if (input.userCommandsTruncated) return false;
|
|
13345
|
+
const commands = input.userCommands ?? [];
|
|
13346
|
+
if (commands.length === 0) return false;
|
|
13347
|
+
if (input.agentAuthoredFiles > 0) return false;
|
|
13348
|
+
if (input.agentToolCalls > 0) return false;
|
|
13349
|
+
return commands.every(isNonAuthoringCommand);
|
|
13350
|
+
}
|
|
13351
|
+
|
|
13086
13352
|
// src/lib/context-identity.ts
|
|
13087
13353
|
var import_node_crypto2 = require("node:crypto");
|
|
13088
13354
|
var import_node_fs8 = require("node:fs");
|
|
@@ -14177,233 +14443,6 @@ var import_node_fs17 = require("node:fs");
|
|
|
14177
14443
|
var import_node_crypto7 = require("node:crypto");
|
|
14178
14444
|
var import_node_path13 = require("node:path");
|
|
14179
14445
|
|
|
14180
|
-
// src/lib/analysis-mode.ts
|
|
14181
|
-
var DEBUG_PHRASES = [
|
|
14182
|
-
"not working",
|
|
14183
|
-
"doesn't work",
|
|
14184
|
-
"doesn't work",
|
|
14185
|
-
"does not work",
|
|
14186
|
-
"isn't working",
|
|
14187
|
-
"is not working",
|
|
14188
|
-
"can't figure out",
|
|
14189
|
-
"stack trace"
|
|
14190
|
-
];
|
|
14191
|
-
var DEBUG_WORDS = [
|
|
14192
|
-
"fix",
|
|
14193
|
-
"bug",
|
|
14194
|
-
"broken",
|
|
14195
|
-
"crash",
|
|
14196
|
-
"crashing",
|
|
14197
|
-
"failing",
|
|
14198
|
-
"debug",
|
|
14199
|
-
"debugging",
|
|
14200
|
-
"investigate",
|
|
14201
|
-
"troubleshoot",
|
|
14202
|
-
"regression",
|
|
14203
|
-
"wrong"
|
|
14204
|
-
];
|
|
14205
|
-
var DEBUG_PATTERN = new RegExp(
|
|
14206
|
-
[
|
|
14207
|
-
...DEBUG_PHRASES.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")),
|
|
14208
|
-
...DEBUG_WORDS.map((w) => `\\b${w}\\b`)
|
|
14209
|
-
].join("|"),
|
|
14210
|
-
"i"
|
|
14211
|
-
);
|
|
14212
|
-
var FALSE_POSITIVE_PATTERNS = [
|
|
14213
|
-
/\b(?:add|create|implement|write|build|design|set\s*up)\b.{0,20}\berror\b/i,
|
|
14214
|
-
/\berror\s+handling\b/i,
|
|
14215
|
-
/\berror\s+boundar(?:y|ies)\b/i,
|
|
14216
|
-
/\berror\s+(?:type|class|page|component|message|code|enum)\b/i,
|
|
14217
|
-
/\b(?:add|create|implement|write|build)\b.{0,20}\b(?:fix|debug|issue)\b/i
|
|
14218
|
-
];
|
|
14219
|
-
function hasDebugIntent(prompt) {
|
|
14220
|
-
if (!DEBUG_PATTERN.test(prompt)) return false;
|
|
14221
|
-
for (const fp of FALSE_POSITIVE_PATTERNS) {
|
|
14222
|
-
if (fp.test(prompt)) return false;
|
|
14223
|
-
}
|
|
14224
|
-
return true;
|
|
14225
|
-
}
|
|
14226
|
-
var GIT_ONLY_PATTERN = /\b(commit|push|deploy|merge|rebase|tag|release|publish|ship)\b/i;
|
|
14227
|
-
var CODE_AUTHORING_PATTERN = /\b(add|create|implement|build|write|fix|update|change|refactor|modify|remove|delete|move|rename)\b.*\b(function|component|feature|endpoint|test|file|module|class|type|interface|hook|page|route|style|migration|code|bug|error|issue)\b/i;
|
|
14228
|
-
function isGitOnlyPrompt(prompt) {
|
|
14229
|
-
if (!GIT_ONLY_PATTERN.test(prompt)) return false;
|
|
14230
|
-
if (CODE_AUTHORING_PATTERN.test(prompt)) return false;
|
|
14231
|
-
return true;
|
|
14232
|
-
}
|
|
14233
|
-
function reconcileAnalysisMode(predictedMode, signals) {
|
|
14234
|
-
const mode2 = resolveAnalysisMode(predictedMode, signals);
|
|
14235
|
-
if (mode2 !== "skip") return mode2;
|
|
14236
|
-
const windowIsOrphaned = signals.actionSummary?.transcript_windowed === "orphaned";
|
|
14237
|
-
if (windowIsOrphaned && !signals.sessionAuthoredCode) return "standard";
|
|
14238
|
-
return mode2;
|
|
14239
|
-
}
|
|
14240
|
-
function resolveAnalysisMode(predictedMode, signals) {
|
|
14241
|
-
if (!predictedMode || !isValidMode(predictedMode)) {
|
|
14242
|
-
return detectAnalysisMode(
|
|
14243
|
-
signals.noFilesChanged,
|
|
14244
|
-
signals.assistantResponse,
|
|
14245
|
-
signals.conversationPrompts,
|
|
14246
|
-
signals.actionSummary,
|
|
14247
|
-
signals.sessionAuthoredCode
|
|
14248
|
-
);
|
|
14249
|
-
}
|
|
14250
|
-
const agentAuthoredCode = !!(signals.actionSummary && (signals.actionSummary.files_edited.length > 0 || signals.actionSummary.files_created.length > 0)) || !!signals.sessionAuthoredCode;
|
|
14251
|
-
const agentInvestigated = didAgentInvestigate(signals.actionSummary);
|
|
14252
|
-
switch (predictedMode) {
|
|
14253
|
-
case "skip":
|
|
14254
|
-
if (agentAuthoredCode) return "standard";
|
|
14255
|
-
return "skip";
|
|
14256
|
-
case "plan":
|
|
14257
|
-
if (agentAuthoredCode) return "standard";
|
|
14258
|
-
return "plan";
|
|
14259
|
-
case "debug":
|
|
14260
|
-
return "debug";
|
|
14261
|
-
case "standard":
|
|
14262
|
-
if (!!signals.actionSummary && !agentAuthoredCode && !!signals.assistantResponse) {
|
|
14263
|
-
return agentInvestigated ? "plan" : "skip";
|
|
14264
|
-
}
|
|
14265
|
-
return "standard";
|
|
14266
|
-
}
|
|
14267
|
-
}
|
|
14268
|
-
function didAgentInvestigate(summary) {
|
|
14269
|
-
if (!summary) return false;
|
|
14270
|
-
return summary.files_read.length > 0 || summary.searches > 0 || summary.commands.length > 0 || summary.subagents > 0 || summary.web_fetches > 0;
|
|
14271
|
-
}
|
|
14272
|
-
function isValidMode(mode2) {
|
|
14273
|
-
return mode2 === "standard" || mode2 === "plan" || mode2 === "debug" || mode2 === "skip";
|
|
14274
|
-
}
|
|
14275
|
-
function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPrompts, actionSummary, sessionAuthoredCode) {
|
|
14276
|
-
const agentAuthoredCode = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0)) || !!sessionAuthoredCode;
|
|
14277
|
-
if (conversationPrompts.length > 0 && conversationPrompts.every(isGitOnlyPrompt)) {
|
|
14278
|
-
if (!agentAuthoredCode) return "skip";
|
|
14279
|
-
}
|
|
14280
|
-
if (noFilesChanged && !!assistantResponse && !agentAuthoredCode) {
|
|
14281
|
-
return "plan";
|
|
14282
|
-
}
|
|
14283
|
-
if (!!actionSummary && !agentAuthoredCode && !!assistantResponse) {
|
|
14284
|
-
return didAgentInvestigate(actionSummary) ? "plan" : "skip";
|
|
14285
|
-
}
|
|
14286
|
-
for (const prompt of conversationPrompts) {
|
|
14287
|
-
if (hasDebugIntent(prompt)) {
|
|
14288
|
-
return "debug";
|
|
14289
|
-
}
|
|
14290
|
-
}
|
|
14291
|
-
return "standard";
|
|
14292
|
-
}
|
|
14293
|
-
var FILE_MUTATE_RE = /(?:^|[\s|&;(`])(?:sed\s+-i|perl\s+-i|awk\b|tee\b|dd\b|cp\b|mv\b|ln\b|install\b|touch\b|patch\b|git\s+(?:apply|am)\b|cargo\s+build|go\s+generate|make\b|--write\b|--fix\b|--in-place\b)|>>?(?![&>])/i;
|
|
14294
|
-
var GIT_PLUMBING_RE = /^\s*git\s+(?:merge|rebase|stash|cherry-pick|revert|pull|fetch|checkout|switch|reset|restore|clean)\b/i;
|
|
14295
|
-
var READ_ONLY_RE = /^\s*(?:git\s+(?:status|diff|log|show|branch|remote|config|rev-parse|ls-files|blame|describe)|ls|cat|head|tail|less|grep|rg|find|pwd|echo|printf|wc|which|type|tree|stat|file|env|printenv|date|whoami)\b/i;
|
|
14296
|
-
var CHAIN_RE = /&&|\||;|\$\(|\x60/;
|
|
14297
|
-
function isNonAuthoringCommand(cmd) {
|
|
14298
|
-
if (typeof cmd !== "string" || cmd.trim().length === 0) return false;
|
|
14299
|
-
if (FILE_MUTATE_RE.test(cmd)) return false;
|
|
14300
|
-
if (CHAIN_RE.test(cmd)) return false;
|
|
14301
|
-
return GIT_PLUMBING_RE.test(cmd) || READ_ONLY_RE.test(cmd);
|
|
14302
|
-
}
|
|
14303
|
-
function hasNonEditAuthorship(actionSummary, sessionAuthoredCode) {
|
|
14304
|
-
if (!actionSummary) return sessionAuthoredCode;
|
|
14305
|
-
if ((actionSummary.subagents ?? 0) > 0) return true;
|
|
14306
|
-
if (Object.keys(actionSummary.tool_counts ?? {}).some((t) => t.startsWith("mcp__"))) return true;
|
|
14307
|
-
const commands = actionSummary.commands ?? [];
|
|
14308
|
-
if (commands.some((c) => FILE_MUTATE_RE.test(c))) return true;
|
|
14309
|
-
if (sessionAuthoredCode) {
|
|
14310
|
-
const allSafe = commands.length > 0 && commands.every(isNonAuthoringCommand);
|
|
14311
|
-
if (!allSafe) return true;
|
|
14312
|
-
}
|
|
14313
|
-
return false;
|
|
14314
|
-
}
|
|
14315
|
-
function scopeToAuthored(files, actionSummary) {
|
|
14316
|
-
if (!actionSummary) return { files, signal: "no-transcript" };
|
|
14317
|
-
const touched = [...actionSummary.files_edited ?? [], ...actionSummary.files_created ?? []];
|
|
14318
|
-
if (touched.length === 0) return { files: [], signal: "none-authored" };
|
|
14319
|
-
return { files: narrowToAgentAuthored(files, actionSummary), signal: "authored" };
|
|
14320
|
-
}
|
|
14321
|
-
function narrowToAgentAuthored(files, actionSummary) {
|
|
14322
|
-
if (!actionSummary) return files;
|
|
14323
|
-
const touched = [
|
|
14324
|
-
...actionSummary.files_edited,
|
|
14325
|
-
...actionSummary.files_created
|
|
14326
|
-
];
|
|
14327
|
-
if (touched.length === 0) return files;
|
|
14328
|
-
return files.filter((f) => {
|
|
14329
|
-
const suffix = "/" + f;
|
|
14330
|
-
return touched.some((t) => t === f || t.endsWith(suffix));
|
|
14331
|
-
});
|
|
14332
|
-
}
|
|
14333
|
-
|
|
14334
|
-
// src/lib/skip-detection.ts
|
|
14335
|
-
function isBareAckPrompt(prompt) {
|
|
14336
|
-
if (typeof prompt !== "string") return false;
|
|
14337
|
-
const trimmed = prompt.trim();
|
|
14338
|
-
if (trimmed.length === 0) return false;
|
|
14339
|
-
if (trimmed.length > 20) return false;
|
|
14340
|
-
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;
|
|
14341
|
-
return bareAckPattern.test(trimmed);
|
|
14342
|
-
}
|
|
14343
|
-
function isContinuationPrompt(prompt) {
|
|
14344
|
-
if (typeof prompt !== "string") return false;
|
|
14345
|
-
const trimmed = prompt.trim();
|
|
14346
|
-
if (trimmed.length === 0) return false;
|
|
14347
|
-
if (trimmed.length > 24) return false;
|
|
14348
|
-
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;
|
|
14349
|
-
return continuation.test(trimmed) || isBareAckPrompt(trimmed);
|
|
14350
|
-
}
|
|
14351
|
-
function resolveGoalPrompt(prompts) {
|
|
14352
|
-
if (prompts.length === 0) return null;
|
|
14353
|
-
const latest = prompts[prompts.length - 1];
|
|
14354
|
-
if (!isContinuationPrompt(latest.prompt)) return { entry: latest, turnsBack: 0 };
|
|
14355
|
-
for (let i = prompts.length - 2; i >= 0; i--) {
|
|
14356
|
-
if (!isContinuationPrompt(prompts[i].prompt)) {
|
|
14357
|
-
return { entry: prompts[i], turnsBack: prompts.length - 1 - i };
|
|
14358
|
-
}
|
|
14359
|
-
}
|
|
14360
|
-
return { entry: latest, turnsBack: 0 };
|
|
14361
|
-
}
|
|
14362
|
-
function isReflectionQuestion(response) {
|
|
14363
|
-
if (!response || typeof response !== "string") return false;
|
|
14364
|
-
const markers = [
|
|
14365
|
-
/reflection\s+for\s+future\s+agents/i,
|
|
14366
|
-
/what(?:'s|\s+is)\s+one\s+thing\s+you\s+learned/i,
|
|
14367
|
-
/say\s+['"]?skip['"]?\s+to\s+skip/i,
|
|
14368
|
-
/quick\s+reflection\s+question/i,
|
|
14369
|
-
// Post-flip (VRT-21): the agent drafts the reflection itself and, when
|
|
14370
|
-
// interactive, asks the user to confirm/correct before recording. That
|
|
14371
|
-
// turn authors no code either, so it's still a reflection turn.
|
|
14372
|
-
/reflection\s+draft/i,
|
|
14373
|
-
/confirm,?\s+correct,?\s+or\s+add/i
|
|
14374
|
-
];
|
|
14375
|
-
return markers.some((m) => m.test(response));
|
|
14376
|
-
}
|
|
14377
|
-
function isMetaTaskLabel(label2) {
|
|
14378
|
-
if (label2 === null || label2 === void 0) return false;
|
|
14379
|
-
if (typeof label2 !== "string") return false;
|
|
14380
|
-
const trimmed = label2.trim();
|
|
14381
|
-
if (trimmed.length === 0) return true;
|
|
14382
|
-
const metaPatterns = [
|
|
14383
|
-
/^verity\s+[\w-]+\s+response$/i,
|
|
14384
|
-
// "Verity reflect response"
|
|
14385
|
-
/^simple user response$/i,
|
|
14386
|
-
/^verity\s+command$/i,
|
|
14387
|
-
// "Verity command"
|
|
14388
|
-
/^user\s+(question|reply|response|ack)$/i
|
|
14389
|
-
];
|
|
14390
|
-
return metaPatterns.some((p) => p.test(trimmed));
|
|
14391
|
-
}
|
|
14392
|
-
function shouldSkipForBareAck(input) {
|
|
14393
|
-
if (!isBareAckPrompt(input.prompt)) return false;
|
|
14394
|
-
if (input.turnAuthoredCode) return false;
|
|
14395
|
-
return input.canSeeTurnAuthorship;
|
|
14396
|
-
}
|
|
14397
|
-
function isCommandOnlyTurn(input) {
|
|
14398
|
-
if (!input.authorshipIsObservable) return false;
|
|
14399
|
-
if (input.userCommandsTruncated) return false;
|
|
14400
|
-
const commands = input.userCommands ?? [];
|
|
14401
|
-
if (commands.length === 0) return false;
|
|
14402
|
-
if (input.agentAuthoredFiles > 0) return false;
|
|
14403
|
-
if (input.agentToolCalls > 0) return false;
|
|
14404
|
-
return commands.every(isNonAuthoringCommand);
|
|
14405
|
-
}
|
|
14406
|
-
|
|
14407
14446
|
// src/lib/pending-repeat.ts
|
|
14408
14447
|
var STOP = /* @__PURE__ */ new Set([
|
|
14409
14448
|
"the",
|
|
@@ -15863,15 +15902,18 @@ function registerIntentCommands(program2) {
|
|
|
15863
15902
|
if (deferredToPlugin("intent capture", event.session_id ?? process.env.CLAUDE_SESSION_ID ?? null)) {
|
|
15864
15903
|
process.exit(0);
|
|
15865
15904
|
}
|
|
15905
|
+
const isPrimitive = isSlashCommand(prompt);
|
|
15866
15906
|
const authForScope = await resolveToken(program2.opts().token);
|
|
15867
15907
|
const scopeToken = authForScope.ok ? authForScope.data.token : void 0;
|
|
15868
15908
|
const scopeSession = event.session_id || process.env.CLAUDE_SESSION_ID || "";
|
|
15869
|
-
await appendToConversationBuffer(prompt, sessionScopeKey(scopeToken, scopeSession));
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15909
|
+
if (!isPrimitive) await appendToConversationBuffer(prompt, sessionScopeKey(scopeToken, scopeSession));
|
|
15910
|
+
if (!isPrimitive) {
|
|
15911
|
+
try {
|
|
15912
|
+
const tok = await resolveToken(globals.token);
|
|
15913
|
+
const session = sessionDossier(tok.ok ? tok.data.token : null, event.session_id ?? null);
|
|
15914
|
+
if (session) recordGoal(session.d, prompt);
|
|
15915
|
+
} catch {
|
|
15916
|
+
}
|
|
15875
15917
|
}
|
|
15876
15918
|
try {
|
|
15877
15919
|
await ensureMemoryDir();
|
|
@@ -18831,21 +18873,19 @@ function refResolves(frame, ref) {
|
|
|
18831
18873
|
return frameGit(frame, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]) !== "";
|
|
18832
18874
|
}
|
|
18833
18875
|
var SHA_RE2 = /^[0-9a-f]{40}$/;
|
|
18834
|
-
function
|
|
18835
|
-
if (!frame.worktreeRoot) return null;
|
|
18836
|
-
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
return
|
|
18876
|
+
function stagedRange(frame) {
|
|
18877
|
+
if (!frame.worktreeRoot) return { kind: "nothing", base: null, head: "INDEX", via: "refused" };
|
|
18878
|
+
const mergeHead = frame.gitDir ? (0, import_node_path19.join)(frame.gitDir, "MERGE_HEAD") : null;
|
|
18879
|
+
if (mergeHead && (0, import_node_fs26.existsSync)(mergeHead)) {
|
|
18880
|
+
const vsHead = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "HEAD"]).split("\n").filter(Boolean));
|
|
18881
|
+
const vsMerge = new Set(frameGit(frame, ["diff", "--cached", "--name-only", "MERGE_HEAD"]).split("\n").filter(Boolean));
|
|
18882
|
+
const resolutions = [...vsHead].filter((f) => vsMerge.has(f) && !isVerityOwnedPath(f));
|
|
18883
|
+
return { kind: "merge", base: "HEAD", head: "INDEX", via: "merge-resolutions", files: resolutions };
|
|
18842
18884
|
}
|
|
18843
|
-
}
|
|
18844
|
-
function stagedRange() {
|
|
18845
18885
|
return { kind: "staged", base: "HEAD", head: "INDEX", via: "index" };
|
|
18846
18886
|
}
|
|
18847
18887
|
function resolvePushRange(frame, command, on) {
|
|
18848
|
-
const nothing = (
|
|
18888
|
+
const nothing = (via2) => ({ kind: "nothing", base: null, head: "HEAD", via: via2 });
|
|
18849
18889
|
if (!frame.worktreeRoot) return nothing("refused");
|
|
18850
18890
|
const found = findMomentSegment(command, on);
|
|
18851
18891
|
const segment = found ? splitSegments(command)[found.segmentIndex] : "";
|
|
@@ -18853,54 +18893,32 @@ function resolvePushRange(frame, command, on) {
|
|
|
18853
18893
|
if (target.isDelete) return nothing("deletion");
|
|
18854
18894
|
const head = target.srcRef ?? "HEAD";
|
|
18855
18895
|
if (!refResolves(frame, head)) return nothing(`src-unresolvable:${head}`);
|
|
18856
|
-
const
|
|
18857
|
-
const
|
|
18858
|
-
const
|
|
18859
|
-
if (
|
|
18860
|
-
|
|
18861
|
-
|
|
18862
|
-
|
|
18863
|
-
|
|
18864
|
-
|
|
18865
|
-
|
|
18866
|
-
|
|
18867
|
-
candidates.push({ ref: srcName ? `${srcName}@{upstream}` : "@{upstream}", via: "@{upstream}" });
|
|
18868
|
-
if (branchForRemote) {
|
|
18869
|
-
candidates.push({
|
|
18870
|
-
ref: `refs/remotes/origin/${branchForRemote.replace(/^refs\/heads\//, "")}`,
|
|
18871
|
-
via: `origin/${branchForRemote.replace(/^refs\/heads\//, "")}`
|
|
18872
|
-
});
|
|
18873
|
-
}
|
|
18874
|
-
for (const c of candidates) {
|
|
18875
|
-
if (!refResolves(frame, c.ref)) continue;
|
|
18876
|
-
const mergeBase = frameGit(frame, ["merge-base", c.ref, head]);
|
|
18877
|
-
if (SHA_RE2.test(mergeBase)) return { kind: "push", base: mergeBase, head, via: c.via };
|
|
18896
|
+
const remotePattern = target.remote ? `--remotes=${target.remote}` : "--remotes";
|
|
18897
|
+
const via = target.remote ? `publication:${target.remote}` : "publication";
|
|
18898
|
+
const commits = frameGit(frame, ["rev-list", head, "--not", remotePattern]).split("\n").filter(Boolean);
|
|
18899
|
+
if (commits.length === 0) return { kind: "nothing", base: null, head, via: "already-published" };
|
|
18900
|
+
const boundary = frameGit(frame, ["rev-list", head, "--not", remotePattern, "--boundary"]).split("\n").filter((l) => l.startsWith("-")).map((l) => l.slice(1));
|
|
18901
|
+
const base = boundary.find((s) => SHA_RE2.test(s)) ?? null;
|
|
18902
|
+
const files = /* @__PURE__ */ new Set();
|
|
18903
|
+
for (const sha of commits) {
|
|
18904
|
+
for (const f of frameGit(frame, ["diff-tree", "--no-commit-id", "--name-only", "-r", sha]).split("\n")) {
|
|
18905
|
+
if (f && !isVerityOwnedPath(f)) files.add(f);
|
|
18906
|
+
}
|
|
18878
18907
|
}
|
|
18879
|
-
|
|
18880
|
-
if (baseline) return { kind: "baseline", base: baseline, head, via: "review-baseline" };
|
|
18881
|
-
if (refResolves(frame, `${head}~1`)) return { kind: "last-commit", base: `${head}~1`, head, via: `${head}~1` };
|
|
18882
|
-
return nothing("no-parent");
|
|
18908
|
+
return { kind: "push", base, head, via, files: [...files], commits };
|
|
18883
18909
|
}
|
|
18884
18910
|
function rangeFiles(frame, range) {
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
out = frameGit(frame, ["diff", "--cached", "--name-only"]);
|
|
18889
|
-
break;
|
|
18890
|
-
case "push":
|
|
18891
|
-
case "baseline":
|
|
18892
|
-
case "last-commit":
|
|
18893
|
-
out = frameGit(frame, ["diff", "--name-only", range.base, range.head === "INDEX" ? "HEAD" : range.head]);
|
|
18894
|
-
break;
|
|
18895
|
-
case "nothing":
|
|
18896
|
-
return [];
|
|
18911
|
+
if (range.files) return range.files.filter((f) => !isVerityOwnedPath(f));
|
|
18912
|
+
if (range.kind === "staged") {
|
|
18913
|
+
return frameGit(frame, ["diff", "--cached", "--name-only"]).split("\n").filter((l) => l.length > 0).filter((f) => !isVerityOwnedPath(f));
|
|
18897
18914
|
}
|
|
18898
|
-
return
|
|
18915
|
+
return [];
|
|
18899
18916
|
}
|
|
18900
18917
|
function rangeChangeSignals(frame, range, paths) {
|
|
18901
18918
|
const out = /* @__PURE__ */ new Map();
|
|
18902
18919
|
if (range.kind === "nothing" || paths.length === 0) return out;
|
|
18903
|
-
|
|
18920
|
+
if (range.kind === "push" && !range.base) return out;
|
|
18921
|
+
const args = range.kind === "staged" || range.kind === "merge" ? ["diff", "--cached", "--unified=0"] : ["diff", "--unified=0", range.base, range.head === "INDEX" ? "HEAD" : range.head];
|
|
18904
18922
|
const diff = frameGit(frame, [...args, "--", ...paths]);
|
|
18905
18923
|
let current = null;
|
|
18906
18924
|
let oldSide = null;
|
|
@@ -18932,8 +18950,9 @@ function rangeChangeSignals(frame, range, paths) {
|
|
|
18932
18950
|
return out;
|
|
18933
18951
|
}
|
|
18934
18952
|
function rangeMessages(frame, range) {
|
|
18935
|
-
if (range.kind
|
|
18936
|
-
|
|
18953
|
+
if (range.kind !== "push" || !range.commits || range.commits.length === 0) return "";
|
|
18954
|
+
const commits = range.commits.slice(0, 100);
|
|
18955
|
+
return frameGit(frame, ["show", "-s", "--format=%B%x00", ...commits]).split("\0").map((s) => s.trim()).filter(Boolean).join("\n\n");
|
|
18937
18956
|
}
|
|
18938
18957
|
function frameTelemetry(frame, range, divergence) {
|
|
18939
18958
|
const t = {
|
|
@@ -19515,7 +19534,7 @@ function channelSilence(input) {
|
|
|
19515
19534
|
// src/lib/cli-version.ts
|
|
19516
19535
|
function cliVersion() {
|
|
19517
19536
|
try {
|
|
19518
|
-
return true ? "0.31.
|
|
19537
|
+
return true ? "0.31.3" : "dev";
|
|
19519
19538
|
} catch {
|
|
19520
19539
|
return "dev";
|
|
19521
19540
|
}
|
|
@@ -20734,7 +20753,20 @@ async function evidence(run2) {
|
|
|
20734
20753
|
widened_to: allForReview.length
|
|
20735
20754
|
});
|
|
20736
20755
|
}
|
|
20737
|
-
const
|
|
20756
|
+
const authorshipWasObservable = scoped.signal === "authored" && actionSummary?.transcript_windowed !== "orphaned";
|
|
20757
|
+
if (!narrowingIsTrustworthy && recoveredScope.length === 0 && authorshipWasObservable) {
|
|
20758
|
+
logEvent("authored_nothing_reviewable", {
|
|
20759
|
+
touched: (actionSummary?.files_edited?.length ?? 0) + (actionSummary?.files_created?.length ?? 0),
|
|
20760
|
+
candidates: allForReview.length
|
|
20761
|
+
});
|
|
20762
|
+
}
|
|
20763
|
+
const baseForReview = chooseReviewScope({
|
|
20764
|
+
narrowingIsTrustworthy,
|
|
20765
|
+
scopedFiles: scoped.files,
|
|
20766
|
+
recoveredScope,
|
|
20767
|
+
allForReview,
|
|
20768
|
+
authorshipWasObservable
|
|
20769
|
+
});
|
|
20738
20770
|
const recentForReview = narrowToRecent(baseForReview, baselineSessionId);
|
|
20739
20771
|
if (!opts.skipStatic && isCodacyAvailable()) {
|
|
20740
20772
|
let allScannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles]));
|
|
@@ -22817,8 +22849,8 @@ async function runReview(opts, globals) {
|
|
|
22817
22849
|
for (const p of specPaths) {
|
|
22818
22850
|
if (!(0, import_node_fs39.existsSync)(p)) continue;
|
|
22819
22851
|
try {
|
|
22820
|
-
const { readFileSync:
|
|
22821
|
-
const content =
|
|
22852
|
+
const { readFileSync: readFileSync26 } = await import("node:fs");
|
|
22853
|
+
const content = readFileSync26(p, "utf-8");
|
|
22822
22854
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
22823
22855
|
} catch {
|
|
22824
22856
|
}
|
|
@@ -22975,13 +23007,14 @@ function registerGuardCommand(program2) {
|
|
|
22975
23007
|
});
|
|
22976
23008
|
}
|
|
22977
23009
|
function resolveMomentRange(moment, frame, command, on) {
|
|
22978
|
-
return moment === "pre-commit" ? stagedRange() : resolvePushRange(frame, command, on);
|
|
23010
|
+
return moment === "pre-commit" ? stagedRange(frame) : resolvePushRange(frame, command, on);
|
|
22979
23011
|
}
|
|
22980
23012
|
function describeRange(range) {
|
|
22981
23013
|
if (range.kind === "staged") return "staged";
|
|
22982
|
-
if (range.kind === "
|
|
22983
|
-
|
|
22984
|
-
|
|
23014
|
+
if (range.kind === "merge") return `merge (${range.via})`;
|
|
23015
|
+
if (range.kind === "nothing") return range.via === "already-published" ? "already published" : null;
|
|
23016
|
+
const base = range.base && /^[0-9a-f]{40}$/.test(range.base) ? range.base.slice(0, 7) : range.base;
|
|
23017
|
+
return base ? `${base}..${range.head} via ${range.via}` : `via ${range.via}`;
|
|
22985
23018
|
}
|
|
22986
23019
|
function matchFlagValue(command, flags) {
|
|
22987
23020
|
const re = new RegExp(`(?<![\\w-])(?:${flags})(?:=|\\s+)('((?:[^'\\\\]|\\\\.)*)'|"((?:[^"\\\\]|\\\\.)*)"|([^\\s'"-][^\\s]*))`);
|
|
@@ -24811,7 +24844,7 @@ function registerInitCommand(program2) {
|
|
|
24811
24844
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
24812
24845
|
init: {
|
|
24813
24846
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24814
|
-
cli_version: true ? "0.31.
|
|
24847
|
+
cli_version: true ? "0.31.3" : "dev"
|
|
24815
24848
|
}
|
|
24816
24849
|
});
|
|
24817
24850
|
} catch (err) {
|
|
@@ -25480,8 +25513,8 @@ function registerTelemetryCommands(program2) {
|
|
|
25480
25513
|
}
|
|
25481
25514
|
|
|
25482
25515
|
// src/cli.ts
|
|
25483
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.31.
|
|
25484
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.
|
|
25516
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.31.3").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) => {
|
|
25517
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.31.3");
|
|
25485
25518
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
25486
25519
|
try {
|
|
25487
25520
|
await foldLegacyLocalCredential();
|