@codacy/verity-cli 0.29.4-experimental.6726d0f → 0.29.4-experimental.694bcef
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 +1053 -518
- package/data/skills/verity-setup/SKILL.md +21 -8
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -6974,10 +6974,10 @@ var require_resolve_block_map = __commonJS({
|
|
|
6974
6974
|
let offset = bm.offset;
|
|
6975
6975
|
let commentEnd = null;
|
|
6976
6976
|
for (const collItem of bm.items) {
|
|
6977
|
-
const { start, key, sep, value } = collItem;
|
|
6977
|
+
const { start, key, sep: sep2, value } = collItem;
|
|
6978
6978
|
const keyProps = resolveProps.resolveProps(start, {
|
|
6979
6979
|
indicator: "explicit-key-ind",
|
|
6980
|
-
next: key ??
|
|
6980
|
+
next: key ?? sep2?.[0],
|
|
6981
6981
|
offset,
|
|
6982
6982
|
onError,
|
|
6983
6983
|
parentIndent: bm.indent,
|
|
@@ -6991,7 +6991,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
6991
6991
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
6992
6992
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
6993
6993
|
}
|
|
6994
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
6994
|
+
if (!keyProps.anchor && !keyProps.tag && !sep2) {
|
|
6995
6995
|
commentEnd = keyProps.end;
|
|
6996
6996
|
if (keyProps.comment) {
|
|
6997
6997
|
if (map.comment)
|
|
@@ -7015,7 +7015,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
7015
7015
|
ctx.atKey = false;
|
|
7016
7016
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
7017
7017
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
7018
|
-
const valueProps = resolveProps.resolveProps(
|
|
7018
|
+
const valueProps = resolveProps.resolveProps(sep2 ?? [], {
|
|
7019
7019
|
indicator: "map-value-ind",
|
|
7020
7020
|
next: value,
|
|
7021
7021
|
offset: keyNode.range[2],
|
|
@@ -7031,7 +7031,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
7031
7031
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
7032
7032
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
7033
7033
|
}
|
|
7034
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
7034
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep2, null, valueProps, onError);
|
|
7035
7035
|
if (ctx.schema.compat)
|
|
7036
7036
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
7037
7037
|
offset = valueNode.range[2];
|
|
@@ -7122,7 +7122,7 @@ var require_resolve_end = __commonJS({
|
|
|
7122
7122
|
let comment = "";
|
|
7123
7123
|
if (end) {
|
|
7124
7124
|
let hasSpace = false;
|
|
7125
|
-
let
|
|
7125
|
+
let sep2 = "";
|
|
7126
7126
|
for (const token of end) {
|
|
7127
7127
|
const { source, type } = token;
|
|
7128
7128
|
switch (type) {
|
|
@@ -7136,13 +7136,13 @@ var require_resolve_end = __commonJS({
|
|
|
7136
7136
|
if (!comment)
|
|
7137
7137
|
comment = cb;
|
|
7138
7138
|
else
|
|
7139
|
-
comment +=
|
|
7140
|
-
|
|
7139
|
+
comment += sep2 + cb;
|
|
7140
|
+
sep2 = "";
|
|
7141
7141
|
break;
|
|
7142
7142
|
}
|
|
7143
7143
|
case "newline":
|
|
7144
7144
|
if (comment)
|
|
7145
|
-
|
|
7145
|
+
sep2 += source;
|
|
7146
7146
|
hasSpace = true;
|
|
7147
7147
|
break;
|
|
7148
7148
|
default:
|
|
@@ -7185,18 +7185,18 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7185
7185
|
let offset = fc.offset + fc.start.source.length;
|
|
7186
7186
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
7187
7187
|
const collItem = fc.items[i];
|
|
7188
|
-
const { start, key, sep, value } = collItem;
|
|
7188
|
+
const { start, key, sep: sep2, value } = collItem;
|
|
7189
7189
|
const props = resolveProps.resolveProps(start, {
|
|
7190
7190
|
flow: fcName,
|
|
7191
7191
|
indicator: "explicit-key-ind",
|
|
7192
|
-
next: key ??
|
|
7192
|
+
next: key ?? sep2?.[0],
|
|
7193
7193
|
offset,
|
|
7194
7194
|
onError,
|
|
7195
7195
|
parentIndent: fc.indent,
|
|
7196
7196
|
startOnNewline: false
|
|
7197
7197
|
});
|
|
7198
7198
|
if (!props.found) {
|
|
7199
|
-
if (!props.anchor && !props.tag && !
|
|
7199
|
+
if (!props.anchor && !props.tag && !sep2 && !value) {
|
|
7200
7200
|
if (i === 0 && props.comma)
|
|
7201
7201
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
7202
7202
|
else if (i < fc.items.length - 1)
|
|
@@ -7250,8 +7250,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7250
7250
|
}
|
|
7251
7251
|
}
|
|
7252
7252
|
}
|
|
7253
|
-
if (!isMap && !
|
|
7254
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
7253
|
+
if (!isMap && !sep2 && !props.found) {
|
|
7254
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep2, null, props, onError);
|
|
7255
7255
|
coll.items.push(valueNode);
|
|
7256
7256
|
offset = valueNode.range[2];
|
|
7257
7257
|
if (isBlock(value))
|
|
@@ -7263,7 +7263,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7263
7263
|
if (isBlock(key))
|
|
7264
7264
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
7265
7265
|
ctx.atKey = false;
|
|
7266
|
-
const valueProps = resolveProps.resolveProps(
|
|
7266
|
+
const valueProps = resolveProps.resolveProps(sep2 ?? [], {
|
|
7267
7267
|
flow: fcName,
|
|
7268
7268
|
indicator: "map-value-ind",
|
|
7269
7269
|
next: value,
|
|
@@ -7274,8 +7274,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7274
7274
|
});
|
|
7275
7275
|
if (valueProps.found) {
|
|
7276
7276
|
if (!isMap && !props.found && ctx.options.strict) {
|
|
7277
|
-
if (
|
|
7278
|
-
for (const st of
|
|
7277
|
+
if (sep2)
|
|
7278
|
+
for (const st of sep2) {
|
|
7279
7279
|
if (st === valueProps.found)
|
|
7280
7280
|
break;
|
|
7281
7281
|
if (st.type === "newline") {
|
|
@@ -7292,7 +7292,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
7292
7292
|
else
|
|
7293
7293
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
7294
7294
|
}
|
|
7295
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
7295
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep2, null, valueProps, onError) : null;
|
|
7296
7296
|
if (valueNode) {
|
|
7297
7297
|
if (isBlock(value))
|
|
7298
7298
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -7472,7 +7472,7 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
7472
7472
|
chompStart = i + 1;
|
|
7473
7473
|
}
|
|
7474
7474
|
let value = "";
|
|
7475
|
-
let
|
|
7475
|
+
let sep2 = "";
|
|
7476
7476
|
let prevMoreIndented = false;
|
|
7477
7477
|
for (let i = 0; i < contentStart; ++i)
|
|
7478
7478
|
value += lines[i][0].slice(trimIndent) + "\n";
|
|
@@ -7489,24 +7489,24 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
7489
7489
|
indent = "";
|
|
7490
7490
|
}
|
|
7491
7491
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
7492
|
-
value +=
|
|
7493
|
-
|
|
7492
|
+
value += sep2 + indent.slice(trimIndent) + content;
|
|
7493
|
+
sep2 = "\n";
|
|
7494
7494
|
} else if (indent.length > trimIndent || content[0] === " ") {
|
|
7495
|
-
if (
|
|
7496
|
-
|
|
7497
|
-
else if (!prevMoreIndented &&
|
|
7498
|
-
|
|
7499
|
-
value +=
|
|
7500
|
-
|
|
7495
|
+
if (sep2 === " ")
|
|
7496
|
+
sep2 = "\n";
|
|
7497
|
+
else if (!prevMoreIndented && sep2 === "\n")
|
|
7498
|
+
sep2 = "\n\n";
|
|
7499
|
+
value += sep2 + indent.slice(trimIndent) + content;
|
|
7500
|
+
sep2 = "\n";
|
|
7501
7501
|
prevMoreIndented = true;
|
|
7502
7502
|
} else if (content === "") {
|
|
7503
|
-
if (
|
|
7503
|
+
if (sep2 === "\n")
|
|
7504
7504
|
value += "\n";
|
|
7505
7505
|
else
|
|
7506
|
-
|
|
7506
|
+
sep2 = "\n";
|
|
7507
7507
|
} else {
|
|
7508
|
-
value +=
|
|
7509
|
-
|
|
7508
|
+
value += sep2 + content;
|
|
7509
|
+
sep2 = " ";
|
|
7510
7510
|
prevMoreIndented = false;
|
|
7511
7511
|
}
|
|
7512
7512
|
}
|
|
@@ -7684,25 +7684,25 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
7684
7684
|
if (!match)
|
|
7685
7685
|
return source;
|
|
7686
7686
|
let res = match[1];
|
|
7687
|
-
let
|
|
7687
|
+
let sep2 = " ";
|
|
7688
7688
|
let pos = first.lastIndex;
|
|
7689
7689
|
line.lastIndex = pos;
|
|
7690
7690
|
while (match = line.exec(source)) {
|
|
7691
7691
|
if (match[1] === "") {
|
|
7692
|
-
if (
|
|
7693
|
-
res +=
|
|
7692
|
+
if (sep2 === "\n")
|
|
7693
|
+
res += sep2;
|
|
7694
7694
|
else
|
|
7695
|
-
|
|
7695
|
+
sep2 = "\n";
|
|
7696
7696
|
} else {
|
|
7697
|
-
res +=
|
|
7698
|
-
|
|
7697
|
+
res += sep2 + match[1];
|
|
7698
|
+
sep2 = " ";
|
|
7699
7699
|
}
|
|
7700
7700
|
pos = line.lastIndex;
|
|
7701
7701
|
}
|
|
7702
7702
|
const last = /[ \t]*(.*)/sy;
|
|
7703
7703
|
last.lastIndex = pos;
|
|
7704
7704
|
match = last.exec(source);
|
|
7705
|
-
return res +
|
|
7705
|
+
return res + sep2 + (match?.[1] ?? "");
|
|
7706
7706
|
}
|
|
7707
7707
|
function doubleQuotedValue(source, onError) {
|
|
7708
7708
|
let res = "";
|
|
@@ -8509,14 +8509,14 @@ var require_cst_stringify = __commonJS({
|
|
|
8509
8509
|
}
|
|
8510
8510
|
}
|
|
8511
8511
|
}
|
|
8512
|
-
function stringifyItem({ start, key, sep, value }) {
|
|
8512
|
+
function stringifyItem({ start, key, sep: sep2, value }) {
|
|
8513
8513
|
let res = "";
|
|
8514
8514
|
for (const st of start)
|
|
8515
8515
|
res += st.source;
|
|
8516
8516
|
if (key)
|
|
8517
8517
|
res += stringifyToken(key);
|
|
8518
|
-
if (
|
|
8519
|
-
for (const st of
|
|
8518
|
+
if (sep2)
|
|
8519
|
+
for (const st of sep2)
|
|
8520
8520
|
res += st.source;
|
|
8521
8521
|
if (value)
|
|
8522
8522
|
res += stringifyToken(value);
|
|
@@ -9659,18 +9659,18 @@ var require_parser = __commonJS({
|
|
|
9659
9659
|
if (this.type === "map-value-ind") {
|
|
9660
9660
|
const prev = getPrevProps(this.peek(2));
|
|
9661
9661
|
const start = getFirstKeyStartProps(prev);
|
|
9662
|
-
let
|
|
9662
|
+
let sep2;
|
|
9663
9663
|
if (scalar.end) {
|
|
9664
|
-
|
|
9665
|
-
|
|
9664
|
+
sep2 = scalar.end;
|
|
9665
|
+
sep2.push(this.sourceToken);
|
|
9666
9666
|
delete scalar.end;
|
|
9667
9667
|
} else
|
|
9668
|
-
|
|
9668
|
+
sep2 = [this.sourceToken];
|
|
9669
9669
|
const map = {
|
|
9670
9670
|
type: "block-map",
|
|
9671
9671
|
offset: scalar.offset,
|
|
9672
9672
|
indent: scalar.indent,
|
|
9673
|
-
items: [{ start, key: scalar, sep }]
|
|
9673
|
+
items: [{ start, key: scalar, sep: sep2 }]
|
|
9674
9674
|
};
|
|
9675
9675
|
this.onKeyLine = true;
|
|
9676
9676
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -9822,15 +9822,15 @@ var require_parser = __commonJS({
|
|
|
9822
9822
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
9823
9823
|
const start2 = getFirstKeyStartProps(it.start);
|
|
9824
9824
|
const key = it.key;
|
|
9825
|
-
const
|
|
9826
|
-
|
|
9825
|
+
const sep2 = it.sep;
|
|
9826
|
+
sep2.push(this.sourceToken);
|
|
9827
9827
|
delete it.key;
|
|
9828
9828
|
delete it.sep;
|
|
9829
9829
|
this.stack.push({
|
|
9830
9830
|
type: "block-map",
|
|
9831
9831
|
offset: this.offset,
|
|
9832
9832
|
indent: this.indent,
|
|
9833
|
-
items: [{ start: start2, key, sep }]
|
|
9833
|
+
items: [{ start: start2, key, sep: sep2 }]
|
|
9834
9834
|
});
|
|
9835
9835
|
} else if (start.length > 0) {
|
|
9836
9836
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -10024,13 +10024,13 @@ var require_parser = __commonJS({
|
|
|
10024
10024
|
const prev = getPrevProps(parent);
|
|
10025
10025
|
const start = getFirstKeyStartProps(prev);
|
|
10026
10026
|
fixFlowSeqItems(fc);
|
|
10027
|
-
const
|
|
10028
|
-
|
|
10027
|
+
const sep2 = fc.end.splice(1, fc.end.length);
|
|
10028
|
+
sep2.push(this.sourceToken);
|
|
10029
10029
|
const map = {
|
|
10030
10030
|
type: "block-map",
|
|
10031
10031
|
offset: fc.offset,
|
|
10032
10032
|
indent: fc.indent,
|
|
10033
|
-
items: [{ start, key: fc, sep }]
|
|
10033
|
+
items: [{ start, key: fc, sep: sep2 }]
|
|
10034
10034
|
};
|
|
10035
10035
|
this.onKeyLine = true;
|
|
10036
10036
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -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 =
|
|
10394
|
-
var MAX_SPEC_FILE_BYTES =
|
|
10395
|
-
var MAX_TOTAL_SPEC_BYTES =
|
|
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 =
|
|
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`;
|
|
@@ -10502,6 +10502,7 @@ var GITHUB_APP_INSTALL_URL = `https://github.com/apps/${GITHUB_APP_SLUG}/install
|
|
|
10502
10502
|
function githubAppInstallUrl(accountId) {
|
|
10503
10503
|
return accountId != null ? `https://github.com/apps/${GITHUB_APP_SLUG}/installations/new/permissions?target_id=${accountId}` : GITHUB_APP_INSTALL_URL;
|
|
10504
10504
|
}
|
|
10505
|
+
var ADVISORY_EPISODE_FILE = `${VERITY_DIR}/.advisory-episode`;
|
|
10505
10506
|
|
|
10506
10507
|
// src/lib/output.ts
|
|
10507
10508
|
var RED = "\x1B[0;31m";
|
|
@@ -10775,7 +10776,7 @@ async function foldLegacyLocalCredential(remoteArg) {
|
|
|
10775
10776
|
const existing = await readGlobalCredential(remote);
|
|
10776
10777
|
const merged = {
|
|
10777
10778
|
token: existing?.token ?? local.token,
|
|
10778
|
-
serviceUrl: existing?.serviceUrl
|
|
10779
|
+
serviceUrl: existing?.serviceUrl,
|
|
10779
10780
|
userId: existing?.userId ?? local.userId,
|
|
10780
10781
|
email: existing?.email ?? local.email
|
|
10781
10782
|
};
|
|
@@ -10803,6 +10804,13 @@ function execGit(cmd) {
|
|
|
10803
10804
|
return "";
|
|
10804
10805
|
}
|
|
10805
10806
|
}
|
|
10807
|
+
function execGitArgs(args) {
|
|
10808
|
+
try {
|
|
10809
|
+
return (0, import_node_child_process3.execFileSync)("git", args, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
10810
|
+
} catch {
|
|
10811
|
+
return "";
|
|
10812
|
+
}
|
|
10813
|
+
}
|
|
10806
10814
|
function splitLines(s) {
|
|
10807
10815
|
return s.split("\n").filter((l) => l.length > 0);
|
|
10808
10816
|
}
|
|
@@ -10893,17 +10901,17 @@ function showContentAtRef(ref, repoRelPath) {
|
|
|
10893
10901
|
}
|
|
10894
10902
|
}
|
|
10895
10903
|
function getPushRangeFiles() {
|
|
10896
|
-
const diff = (range) => splitLines(
|
|
10904
|
+
const diff = (range) => splitLines(execGitArgs(["diff", "--name-only", range])).filter((f) => !f.startsWith(".verity/") && !f.startsWith(".verity\\"));
|
|
10897
10905
|
const resolvers = [
|
|
10898
|
-
() =>
|
|
10899
|
-
() =>
|
|
10906
|
+
() => execGitArgs(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{push}"]) ? "@{push}..HEAD" : null,
|
|
10907
|
+
() => execGitArgs(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"]) ? "@{upstream}..HEAD" : null,
|
|
10900
10908
|
() => {
|
|
10901
|
-
const branch =
|
|
10902
|
-
return branch && branch !== "HEAD" &&
|
|
10909
|
+
const branch = execGitArgs(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
10910
|
+
return branch && branch !== "HEAD" && execGitArgs(["rev-parse", "--verify", "-q", `origin/${branch}`]) ? `origin/${branch}..HEAD` : null;
|
|
10903
10911
|
}
|
|
10904
10912
|
];
|
|
10905
|
-
for (const
|
|
10906
|
-
const range =
|
|
10913
|
+
for (const resolve3 of resolvers) {
|
|
10914
|
+
const range = resolve3();
|
|
10907
10915
|
if (range) return { files: diff(range), range };
|
|
10908
10916
|
}
|
|
10909
10917
|
const baseline = readBaselineSha();
|
|
@@ -10917,7 +10925,7 @@ function getPushRangeFiles() {
|
|
|
10917
10925
|
function getPushRangeMessages() {
|
|
10918
10926
|
const { range } = getPushRangeFiles();
|
|
10919
10927
|
if (!range) return "";
|
|
10920
|
-
return
|
|
10928
|
+
return execGitArgs(["log", range, "--format=%B%x00"]).split("\0").map((s) => s.trim()).filter(Boolean).join("\n\n");
|
|
10921
10929
|
}
|
|
10922
10930
|
function filterAnalyzable(files) {
|
|
10923
10931
|
return files.filter((f) => {
|
|
@@ -10951,7 +10959,7 @@ function getCurrentBranch() {
|
|
|
10951
10959
|
function commitResolves(sha) {
|
|
10952
10960
|
if (!sha) return false;
|
|
10953
10961
|
try {
|
|
10954
|
-
(0, import_node_child_process3.
|
|
10962
|
+
(0, import_node_child_process3.execFileSync)("git", ["merge-base", "--is-ancestor", sha, "HEAD"], {
|
|
10955
10963
|
stdio: ["pipe", "pipe", "pipe"]
|
|
10956
10964
|
});
|
|
10957
10965
|
return true;
|
|
@@ -10962,8 +10970,9 @@ function commitResolves(sha) {
|
|
|
10962
10970
|
function commitsSincePaths(sha, paths) {
|
|
10963
10971
|
if (!sha) return null;
|
|
10964
10972
|
try {
|
|
10965
|
-
const
|
|
10966
|
-
|
|
10973
|
+
const args = ["rev-list", "--count", `${sha}..HEAD`];
|
|
10974
|
+
if (paths.length > 0) args.push("--", ...paths.slice(0, 50));
|
|
10975
|
+
const out = (0, import_node_child_process3.execFileSync)("git", args, {
|
|
10967
10976
|
encoding: "utf-8",
|
|
10968
10977
|
stdio: ["pipe", "pipe", "pipe"]
|
|
10969
10978
|
}).trim();
|
|
@@ -11245,7 +11254,8 @@ async function serviceUrlFromVerityMd() {
|
|
|
11245
11254
|
}
|
|
11246
11255
|
return null;
|
|
11247
11256
|
}
|
|
11248
|
-
async function resolveServiceUrlDetailed(flagUrl) {
|
|
11257
|
+
async function resolveServiceUrlDetailed(flagUrl, opts = {}) {
|
|
11258
|
+
const allowVerityMd = opts.allowVerityMd ?? true;
|
|
11249
11259
|
if (flagUrl) {
|
|
11250
11260
|
return { ok: true, data: { url: flagUrl, source: "flag" } };
|
|
11251
11261
|
}
|
|
@@ -11257,9 +11267,11 @@ async function resolveServiceUrlDetailed(flagUrl) {
|
|
|
11257
11267
|
if (credsUrl) {
|
|
11258
11268
|
return { ok: true, data: { url: credsUrl, source: "credentials" } };
|
|
11259
11269
|
}
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11270
|
+
if (allowVerityMd) {
|
|
11271
|
+
const mdUrl = await serviceUrlFromVerityMd();
|
|
11272
|
+
if (mdUrl) {
|
|
11273
|
+
return { ok: true, data: { url: mdUrl, source: "verity_md" } };
|
|
11274
|
+
}
|
|
11263
11275
|
}
|
|
11264
11276
|
return {
|
|
11265
11277
|
ok: false,
|
|
@@ -11267,7 +11279,7 @@ async function resolveServiceUrlDetailed(flagUrl) {
|
|
|
11267
11279
|
};
|
|
11268
11280
|
}
|
|
11269
11281
|
async function resolveServiceUrlForAuth(flagUrl) {
|
|
11270
|
-
const strict = await resolveServiceUrlDetailed(flagUrl);
|
|
11282
|
+
const strict = await resolveServiceUrlDetailed(flagUrl, { allowVerityMd: false });
|
|
11271
11283
|
if (strict.ok) return strict.data;
|
|
11272
11284
|
return { url: DEFAULT_SERVICE_URL, source: "default" };
|
|
11273
11285
|
}
|
|
@@ -11405,7 +11417,7 @@ var readline = __toESM(require("node:readline/promises"));
|
|
|
11405
11417
|
var import_node_os = require("node:os");
|
|
11406
11418
|
|
|
11407
11419
|
// src/lib/provider-auth.ts
|
|
11408
|
-
var sleep = (ms) => new Promise((
|
|
11420
|
+
var sleep = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
11409
11421
|
var form = (fields) => new URLSearchParams(fields).toString();
|
|
11410
11422
|
async function githubAccountId(owner) {
|
|
11411
11423
|
try {
|
|
@@ -13161,9 +13173,38 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
13161
13173
|
|
|
13162
13174
|
// src/lib/memory-sync.ts
|
|
13163
13175
|
var import_promises8 = require("node:fs/promises");
|
|
13176
|
+
var import_node_fs9 = require("node:fs");
|
|
13177
|
+
var import_node_path10 = require("node:path");
|
|
13178
|
+
var import_node_crypto3 = require("node:crypto");
|
|
13179
|
+
|
|
13180
|
+
// src/lib/safe-path.ts
|
|
13164
13181
|
var import_node_fs8 = require("node:fs");
|
|
13165
13182
|
var import_node_path9 = require("node:path");
|
|
13166
|
-
|
|
13183
|
+
function resolveInside(baseDir, candidate) {
|
|
13184
|
+
if (typeof candidate !== "string" || candidate.length === 0) return null;
|
|
13185
|
+
if ((0, import_node_path9.isAbsolute)(candidate)) return null;
|
|
13186
|
+
const baseAbs = (0, import_node_path9.resolve)(baseDir);
|
|
13187
|
+
const full = (0, import_node_path9.resolve)(baseAbs, candidate);
|
|
13188
|
+
const baseSep = baseAbs.endsWith(import_node_path9.sep) ? baseAbs : baseAbs + import_node_path9.sep;
|
|
13189
|
+
if (full !== baseAbs && !full.startsWith(baseSep)) return null;
|
|
13190
|
+
try {
|
|
13191
|
+
if ((0, import_node_fs8.existsSync)(baseAbs)) {
|
|
13192
|
+
const realBase = (0, import_node_fs8.realpathSync)(baseAbs);
|
|
13193
|
+
const realBaseSep = realBase.endsWith(import_node_path9.sep) ? realBase : realBase + import_node_path9.sep;
|
|
13194
|
+
let probe = full;
|
|
13195
|
+
while (!(0, import_node_fs8.existsSync)(probe)) {
|
|
13196
|
+
const parent = (0, import_node_path9.dirname)(probe);
|
|
13197
|
+
if (parent === probe) break;
|
|
13198
|
+
probe = parent;
|
|
13199
|
+
}
|
|
13200
|
+
const realProbe = (0, import_node_fs8.realpathSync)(probe);
|
|
13201
|
+
if (realProbe !== realBase && !realProbe.startsWith(realBaseSep)) return null;
|
|
13202
|
+
}
|
|
13203
|
+
} catch {
|
|
13204
|
+
return null;
|
|
13205
|
+
}
|
|
13206
|
+
return full;
|
|
13207
|
+
}
|
|
13167
13208
|
|
|
13168
13209
|
// src/lib/glob-match.ts
|
|
13169
13210
|
function globToRegex(glob) {
|
|
@@ -13233,32 +13274,32 @@ var syncStateFile = () => projectPath(`${VERITY_DIR}/.memory-sync-state.json`);
|
|
|
13233
13274
|
async function ensureMemoryDir() {
|
|
13234
13275
|
await (0, import_promises8.mkdir)(memoryDir2(), { recursive: true });
|
|
13235
13276
|
for (const domain of DOMAINS2) {
|
|
13236
|
-
await (0, import_promises8.mkdir)((0,
|
|
13277
|
+
await (0, import_promises8.mkdir)((0, import_node_path10.join)(memoryDir2(), domain), { recursive: true });
|
|
13237
13278
|
}
|
|
13238
|
-
if (!(0,
|
|
13239
|
-
await (0, import_promises8.writeFile)((0,
|
|
13279
|
+
if (!(0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"))) {
|
|
13280
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "SCHEMA.md"), SCHEMA_TEMPLATE);
|
|
13240
13281
|
}
|
|
13241
|
-
if (!(0,
|
|
13242
|
-
await (0, import_promises8.writeFile)((0,
|
|
13282
|
+
if (!(0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "index.md"))) {
|
|
13283
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "index.md"), "# Project Memory Index\n\nNo nodes yet. Run an analysis to start building the knowledge graph.\n");
|
|
13243
13284
|
}
|
|
13244
|
-
if (!(0,
|
|
13245
|
-
await (0, import_promises8.writeFile)((0,
|
|
13285
|
+
if (!(0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md"))) {
|
|
13286
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "# Memory Log\n\n");
|
|
13246
13287
|
}
|
|
13247
13288
|
}
|
|
13248
13289
|
async function buildManifest() {
|
|
13249
|
-
if (!(0,
|
|
13290
|
+
if (!(0, import_node_fs9.existsSync)(memoryDir2())) {
|
|
13250
13291
|
return { schema_version: 1, nodes: [], index_hash: null, log_length: 0 };
|
|
13251
13292
|
}
|
|
13252
13293
|
const nodes = [];
|
|
13253
13294
|
for (const domain of DOMAINS2) {
|
|
13254
|
-
const domainDir = (0,
|
|
13255
|
-
if (!(0,
|
|
13295
|
+
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13296
|
+
if (!(0, import_node_fs9.existsSync)(domainDir)) continue;
|
|
13256
13297
|
try {
|
|
13257
13298
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13258
13299
|
for (const file of files) {
|
|
13259
13300
|
if (!file.endsWith(".md")) continue;
|
|
13260
13301
|
const filePath = `${domain}/${file}`;
|
|
13261
|
-
const fullPath = (0,
|
|
13302
|
+
const fullPath = (0, import_node_path10.join)(memoryDir2(), filePath);
|
|
13262
13303
|
try {
|
|
13263
13304
|
const content = await (0, import_promises8.readFile)(fullPath, "utf-8");
|
|
13264
13305
|
const hash = (0, import_node_crypto3.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
@@ -13271,13 +13312,13 @@ async function buildManifest() {
|
|
|
13271
13312
|
}
|
|
13272
13313
|
let indexHash = null;
|
|
13273
13314
|
try {
|
|
13274
|
-
const indexContent = await (0, import_promises8.readFile)((0,
|
|
13315
|
+
const indexContent = await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "index.md"), "utf-8");
|
|
13275
13316
|
indexHash = `sha256:${(0, import_node_crypto3.createHash)("sha256").update(indexContent).digest("hex").slice(0, 16)}`;
|
|
13276
13317
|
} catch {
|
|
13277
13318
|
}
|
|
13278
13319
|
let logLength = 0;
|
|
13279
13320
|
try {
|
|
13280
|
-
const logContent = await (0, import_promises8.readFile)((0,
|
|
13321
|
+
const logContent = await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "utf-8");
|
|
13281
13322
|
logLength = logContent.split("\n").length;
|
|
13282
13323
|
} catch {
|
|
13283
13324
|
}
|
|
@@ -13288,15 +13329,15 @@ function hashContent(content) {
|
|
|
13288
13329
|
}
|
|
13289
13330
|
async function readOnDiskNodes() {
|
|
13290
13331
|
const out = /* @__PURE__ */ new Map();
|
|
13291
|
-
if (!(0,
|
|
13332
|
+
if (!(0, import_node_fs9.existsSync)(memoryDir2())) return out;
|
|
13292
13333
|
for (const domain of DOMAINS2) {
|
|
13293
|
-
const domainDir = (0,
|
|
13294
|
-
if (!(0,
|
|
13334
|
+
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13335
|
+
if (!(0, import_node_fs9.existsSync)(domainDir)) continue;
|
|
13295
13336
|
try {
|
|
13296
13337
|
for (const file of await (0, import_promises8.readdir)(domainDir)) {
|
|
13297
13338
|
if (!file.endsWith(".md")) continue;
|
|
13298
13339
|
try {
|
|
13299
|
-
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0,
|
|
13340
|
+
out.set(`${domain}/${file}`, hashContent(await (0, import_promises8.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8")));
|
|
13300
13341
|
} catch {
|
|
13301
13342
|
}
|
|
13302
13343
|
}
|
|
@@ -13342,8 +13383,8 @@ async function computeEditedNodeUploads() {
|
|
|
13342
13383
|
const uploads = [];
|
|
13343
13384
|
for (const [path, prevHash] of prev) {
|
|
13344
13385
|
if (prevHash == null) continue;
|
|
13345
|
-
const full = (0,
|
|
13346
|
-
if (!(0,
|
|
13386
|
+
const full = (0, import_node_path10.join)(memoryDir2(), path);
|
|
13387
|
+
if (!(0, import_node_fs9.existsSync)(full)) continue;
|
|
13347
13388
|
let content;
|
|
13348
13389
|
try {
|
|
13349
13390
|
content = await (0, import_promises8.readFile)(full, "utf-8");
|
|
@@ -13379,16 +13420,19 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
13379
13420
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
13380
13421
|
for (const n of notes) logLines.push(` - ${n}`);
|
|
13381
13422
|
try {
|
|
13382
|
-
const existing = (0,
|
|
13383
|
-
await (0, import_promises8.writeFile)((0,
|
|
13423
|
+
const existing = (0, import_node_fs9.existsSync)((0, import_node_path10.join)(memoryDir2(), "log.md")) ? await (0, import_promises8.readFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
|
|
13424
|
+
await (0, import_promises8.writeFile)((0, import_node_path10.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
13384
13425
|
} catch {
|
|
13385
13426
|
}
|
|
13386
13427
|
await recordSyncedNodePaths();
|
|
13387
13428
|
return count;
|
|
13388
13429
|
}
|
|
13389
13430
|
async function applyOneWrite(write, treePaths) {
|
|
13390
|
-
const fullPath = (
|
|
13431
|
+
const fullPath = resolveInside(memoryDir2(), write.path);
|
|
13391
13432
|
const notes = [];
|
|
13433
|
+
if (!fullPath) {
|
|
13434
|
+
return { written: false, notes: [`${String(write.path)}: rejected \u2014 path escapes the memory directory`] };
|
|
13435
|
+
}
|
|
13392
13436
|
let content = write.content;
|
|
13393
13437
|
if (treePaths && treePaths.length > 0) {
|
|
13394
13438
|
const grounded = groundFileGlobs(content, treePaths);
|
|
@@ -13397,7 +13441,7 @@ async function applyOneWrite(write, treePaths) {
|
|
|
13397
13441
|
notes.push(`${write.path}: dropped unmatched file_globs [${grounded.dropped.join(", ")}]`);
|
|
13398
13442
|
}
|
|
13399
13443
|
}
|
|
13400
|
-
if ((0,
|
|
13444
|
+
if ((0, import_node_fs9.existsSync)(fullPath)) {
|
|
13401
13445
|
let existing = "";
|
|
13402
13446
|
try {
|
|
13403
13447
|
existing = await (0, import_promises8.readFile)(fullPath, "utf-8");
|
|
@@ -13409,7 +13453,7 @@ async function applyOneWrite(write, treePaths) {
|
|
|
13409
13453
|
return { written: false, notes };
|
|
13410
13454
|
}
|
|
13411
13455
|
}
|
|
13412
|
-
await (0, import_promises8.mkdir)((0,
|
|
13456
|
+
await (0, import_promises8.mkdir)((0, import_node_path10.dirname)(fullPath), { recursive: true });
|
|
13413
13457
|
await (0, import_promises8.writeFile)(fullPath, content);
|
|
13414
13458
|
return { written: true, notes };
|
|
13415
13459
|
}
|
|
@@ -13450,8 +13494,8 @@ async function regenerateIndex() {
|
|
|
13450
13494
|
];
|
|
13451
13495
|
let totalNodes = 0;
|
|
13452
13496
|
for (const domain of DOMAINS2.filter((d) => d !== "_archive")) {
|
|
13453
|
-
const domainDir = (0,
|
|
13454
|
-
if (!(0,
|
|
13497
|
+
const domainDir = (0, import_node_path10.join)(memoryDir2(), domain);
|
|
13498
|
+
if (!(0, import_node_fs9.existsSync)(domainDir)) continue;
|
|
13455
13499
|
try {
|
|
13456
13500
|
const files = await (0, import_promises8.readdir)(domainDir);
|
|
13457
13501
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
@@ -13461,7 +13505,7 @@ async function regenerateIndex() {
|
|
|
13461
13505
|
for (const file of mdFiles.sort()) {
|
|
13462
13506
|
const slug = file.replace(/\.md$/, "");
|
|
13463
13507
|
try {
|
|
13464
|
-
const content = await (0, import_promises8.readFile)((0,
|
|
13508
|
+
const content = await (0, import_promises8.readFile)((0, import_node_path10.join)(domainDir, file), "utf-8");
|
|
13465
13509
|
const title = pickFrontmatter(content, "title") ?? slug;
|
|
13466
13510
|
const kind = pickFrontmatter(content, "kind") ?? "-";
|
|
13467
13511
|
const confidence = pickFrontmatter(content, "confidence");
|
|
@@ -13485,7 +13529,7 @@ async function regenerateIndex() {
|
|
|
13485
13529
|
lines.push("No nodes yet. Run an analysis to start building the knowledge graph.");
|
|
13486
13530
|
}
|
|
13487
13531
|
const next = lines.join("\n") + "\n";
|
|
13488
|
-
const indexPath = (0,
|
|
13532
|
+
const indexPath = (0, import_node_path10.join)(memoryDir2(), "index.md");
|
|
13489
13533
|
let existing = null;
|
|
13490
13534
|
try {
|
|
13491
13535
|
existing = await (0, import_promises8.readFile)(indexPath, "utf-8");
|
|
@@ -13567,9 +13611,9 @@ function hasLegacyMemoryBlock(text) {
|
|
|
13567
13611
|
return findMarker(text, LEGACY_MD_START) !== -1;
|
|
13568
13612
|
}
|
|
13569
13613
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
13570
|
-
const claudeMdPath = (0,
|
|
13614
|
+
const claudeMdPath = (0, import_node_path10.join)(cwd, "CLAUDE.md");
|
|
13571
13615
|
let existing = "";
|
|
13572
|
-
if ((0,
|
|
13616
|
+
if ((0, import_node_fs9.existsSync)(claudeMdPath)) {
|
|
13573
13617
|
existing = await (0, import_promises8.readFile)(claudeMdPath, "utf-8");
|
|
13574
13618
|
}
|
|
13575
13619
|
let startTag = CLAUDE_MD_START;
|
|
@@ -13699,9 +13743,9 @@ Body content (\u22648KB). Use [[node-id]] wikilinks for cross-references.
|
|
|
13699
13743
|
`;
|
|
13700
13744
|
|
|
13701
13745
|
// src/lib/dossier-session.ts
|
|
13702
|
-
var
|
|
13746
|
+
var import_node_fs14 = require("node:fs");
|
|
13703
13747
|
var import_node_crypto7 = require("node:crypto");
|
|
13704
|
-
var
|
|
13748
|
+
var import_node_path13 = require("node:path");
|
|
13705
13749
|
|
|
13706
13750
|
// src/lib/skip-detection.ts
|
|
13707
13751
|
function isBareAckPrompt(prompt) {
|
|
@@ -13865,8 +13909,8 @@ var DEFAULT_MEMORY_BUDGET_BYTES = 4096;
|
|
|
13865
13909
|
|
|
13866
13910
|
// src/lib/dossier/log.ts
|
|
13867
13911
|
var import_node_crypto4 = require("node:crypto");
|
|
13868
|
-
var
|
|
13869
|
-
var
|
|
13912
|
+
var import_node_fs10 = require("node:fs");
|
|
13913
|
+
var import_node_path11 = require("node:path");
|
|
13870
13914
|
var CRC_TABLE = (() => {
|
|
13871
13915
|
const t = new Int32Array(256);
|
|
13872
13916
|
for (let i = 0; i < 256; i++) {
|
|
@@ -13885,13 +13929,13 @@ function crc32(s) {
|
|
|
13885
13929
|
function openDossier(identity) {
|
|
13886
13930
|
try {
|
|
13887
13931
|
const dir = dossierDir(identity);
|
|
13888
|
-
(0,
|
|
13932
|
+
(0, import_node_fs10.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
13889
13933
|
return {
|
|
13890
13934
|
dir,
|
|
13891
13935
|
identity,
|
|
13892
|
-
eventsPath: (0,
|
|
13893
|
-
foldPath: (0,
|
|
13894
|
-
rotatedDir: (0,
|
|
13936
|
+
eventsPath: (0, import_node_path11.join)(dir, "events.jsonl"),
|
|
13937
|
+
foldPath: (0, import_node_path11.join)(dir, "fold.json"),
|
|
13938
|
+
rotatedDir: (0, import_node_path11.join)(dir, "rotated")
|
|
13895
13939
|
};
|
|
13896
13940
|
} catch {
|
|
13897
13941
|
return null;
|
|
@@ -13953,7 +13997,7 @@ function appendEvent(d, ev) {
|
|
|
13953
13997
|
at: ev.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
13954
13998
|
...ev
|
|
13955
13999
|
});
|
|
13956
|
-
(0,
|
|
14000
|
+
(0, import_node_fs10.appendFileSync)(d.eventsPath, line, { mode: 384 });
|
|
13957
14001
|
return true;
|
|
13958
14002
|
} catch {
|
|
13959
14003
|
return false;
|
|
@@ -13961,14 +14005,14 @@ function appendEvent(d, ev) {
|
|
|
13961
14005
|
}
|
|
13962
14006
|
function rotateIfNeeded2(d) {
|
|
13963
14007
|
try {
|
|
13964
|
-
if (!(0,
|
|
13965
|
-
if ((0,
|
|
13966
|
-
(0,
|
|
13967
|
-
(0,
|
|
13968
|
-
const kept = (0,
|
|
14008
|
+
if (!(0, import_node_fs10.existsSync)(d.eventsPath)) return;
|
|
14009
|
+
if ((0, import_node_fs10.statSync)(d.eventsPath).size < ROTATE_BYTES) return;
|
|
14010
|
+
(0, import_node_fs10.mkdirSync)(d.rotatedDir, { recursive: true, mode: 448 });
|
|
14011
|
+
(0, import_node_fs10.renameSync)(d.eventsPath, (0, import_node_path11.join)(d.rotatedDir, `events.${Date.now()}.jsonl`));
|
|
14012
|
+
const kept = (0, import_node_fs10.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
13969
14013
|
for (const stale of kept.slice(0, Math.max(0, kept.length - ROTATE_KEEP))) {
|
|
13970
14014
|
try {
|
|
13971
|
-
(0,
|
|
14015
|
+
(0, import_node_fs10.renameSync)((0, import_node_path11.join)(d.rotatedDir, stale), (0, import_node_path11.join)(d.rotatedDir, `${stale}.pruned`));
|
|
13972
14016
|
} catch {
|
|
13973
14017
|
}
|
|
13974
14018
|
}
|
|
@@ -13978,8 +14022,8 @@ function rotateIfNeeded2(d) {
|
|
|
13978
14022
|
|
|
13979
14023
|
// src/lib/dossier/fold-dossier.ts
|
|
13980
14024
|
var import_node_crypto5 = require("node:crypto");
|
|
13981
|
-
var
|
|
13982
|
-
var
|
|
14025
|
+
var import_node_fs11 = require("node:fs");
|
|
14026
|
+
var import_node_path12 = require("node:path");
|
|
13983
14027
|
var EMPTY_CAPABILITIES = () => ({
|
|
13984
14028
|
human_reachable: { value: "unknown", tier: "unknown" },
|
|
13985
14029
|
authorship_observability: { value: "unknown", tier: "unknown" },
|
|
@@ -14030,12 +14074,12 @@ function foldDossier(d, opts = {}) {
|
|
|
14030
14074
|
}
|
|
14031
14075
|
};
|
|
14032
14076
|
try {
|
|
14033
|
-
if ((0,
|
|
14034
|
-
const files = (0,
|
|
14077
|
+
if ((0, import_node_fs11.existsSync)(d.rotatedDir)) {
|
|
14078
|
+
const files = (0, import_node_fs11.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
14035
14079
|
state.meta.rotations = files.length;
|
|
14036
14080
|
for (const f of files) {
|
|
14037
14081
|
try {
|
|
14038
|
-
ingest((0,
|
|
14082
|
+
ingest((0, import_node_fs11.readFileSync)((0, import_node_path12.join)(d.rotatedDir, f), "utf8"));
|
|
14039
14083
|
} catch {
|
|
14040
14084
|
state.meta.dropped_lines++;
|
|
14041
14085
|
}
|
|
@@ -14044,9 +14088,9 @@ function foldDossier(d, opts = {}) {
|
|
|
14044
14088
|
} catch {
|
|
14045
14089
|
}
|
|
14046
14090
|
try {
|
|
14047
|
-
if ((0,
|
|
14048
|
-
state.meta.upto_offset = (0,
|
|
14049
|
-
ingest((0,
|
|
14091
|
+
if ((0, import_node_fs11.existsSync)(d.eventsPath)) {
|
|
14092
|
+
state.meta.upto_offset = (0, import_node_fs11.statSync)(d.eventsPath).size;
|
|
14093
|
+
ingest((0, import_node_fs11.readFileSync)(d.eventsPath, "utf8"));
|
|
14050
14094
|
}
|
|
14051
14095
|
} catch {
|
|
14052
14096
|
}
|
|
@@ -14316,7 +14360,7 @@ function applyBounds(state, input) {
|
|
|
14316
14360
|
}
|
|
14317
14361
|
|
|
14318
14362
|
// src/lib/dossier/cache.ts
|
|
14319
|
-
var
|
|
14363
|
+
var import_node_fs12 = require("node:fs");
|
|
14320
14364
|
function compactState(s) {
|
|
14321
14365
|
const ms = (iso) => Date.parse(iso) || 0;
|
|
14322
14366
|
return {
|
|
@@ -14445,20 +14489,20 @@ function encodeState(s) {
|
|
|
14445
14489
|
function writeFoldCache(d, state) {
|
|
14446
14490
|
try {
|
|
14447
14491
|
const tmp = `${d.foldPath}.${process.pid}.tmp`;
|
|
14448
|
-
(0,
|
|
14449
|
-
(0,
|
|
14492
|
+
(0, import_node_fs12.writeFileSync)(tmp, encodeState(state), { mode: 384 });
|
|
14493
|
+
(0, import_node_fs12.renameSync)(tmp, d.foldPath);
|
|
14450
14494
|
} catch {
|
|
14451
14495
|
}
|
|
14452
14496
|
}
|
|
14453
14497
|
function readFoldCache(d) {
|
|
14454
14498
|
try {
|
|
14455
|
-
if (!(0,
|
|
14456
|
-
const raw = JSON.parse((0,
|
|
14499
|
+
if (!(0, import_node_fs12.existsSync)(d.foldPath)) return null;
|
|
14500
|
+
const raw = JSON.parse((0, import_node_fs12.readFileSync)(d.foldPath, "utf8"));
|
|
14457
14501
|
if (raw?.v !== 1) return null;
|
|
14458
14502
|
const cached2 = expandState(raw);
|
|
14459
14503
|
if (!cached2?.meta) return null;
|
|
14460
|
-
const size = (0,
|
|
14461
|
-
const rotations = (0,
|
|
14504
|
+
const size = (0, import_node_fs12.existsSync)(d.eventsPath) ? (0, import_node_fs12.statSync)(d.eventsPath).size : 0;
|
|
14505
|
+
const rotations = (0, import_node_fs12.existsSync)(d.rotatedDir) ? (0, import_node_fs12.readdirSync)(d.rotatedDir).filter((f) => f.endsWith(".jsonl")).length : 0;
|
|
14462
14506
|
if (cached2.meta.upto_offset !== size || cached2.meta.rotations !== rotations) return null;
|
|
14463
14507
|
return cached2;
|
|
14464
14508
|
} catch {
|
|
@@ -14509,13 +14553,13 @@ function assessContinuity(i) {
|
|
|
14509
14553
|
|
|
14510
14554
|
// src/lib/dossier/reanchor.ts
|
|
14511
14555
|
var import_node_crypto6 = require("node:crypto");
|
|
14512
|
-
var
|
|
14556
|
+
var import_node_fs13 = require("node:fs");
|
|
14513
14557
|
function lineSha(text) {
|
|
14514
14558
|
return (0, import_node_crypto6.createHash)("sha256").update(text.trim()).digest("hex").slice(0, HASH_WIDTH);
|
|
14515
14559
|
}
|
|
14516
14560
|
function fileHash(path) {
|
|
14517
14561
|
try {
|
|
14518
|
-
return (0, import_node_crypto6.createHash)("sha256").update((0,
|
|
14562
|
+
return (0, import_node_crypto6.createHash)("sha256").update((0, import_node_fs13.readFileSync)(path)).digest("hex").slice(0, HASH_WIDTH);
|
|
14519
14563
|
} catch {
|
|
14520
14564
|
return null;
|
|
14521
14565
|
}
|
|
@@ -14887,20 +14931,20 @@ function foreignAuthoredPaths(identity, opts = {}) {
|
|
|
14887
14931
|
let sessions = 0;
|
|
14888
14932
|
try {
|
|
14889
14933
|
const dir = treeDir(identity);
|
|
14890
|
-
if (!(0,
|
|
14891
|
-
for (const entry of (0,
|
|
14934
|
+
if (!(0, import_node_fs14.existsSync)(dir)) return { paths: [], sessions: 0 };
|
|
14935
|
+
for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
|
|
14892
14936
|
if (!entry.isDirectory()) continue;
|
|
14893
14937
|
if (entry.name === identity.sessionKey) continue;
|
|
14894
|
-
const log = (0,
|
|
14938
|
+
const log = (0, import_node_path13.join)(dir, entry.name, "events.jsonl");
|
|
14895
14939
|
try {
|
|
14896
|
-
if (!(0,
|
|
14897
|
-
if (now - (0,
|
|
14940
|
+
if (!(0, import_node_fs14.existsSync)(log)) continue;
|
|
14941
|
+
if (now - (0, import_node_fs14.statSync)(log).mtimeMs > windowMs) continue;
|
|
14898
14942
|
const sib = {
|
|
14899
|
-
dir: (0,
|
|
14943
|
+
dir: (0, import_node_path13.join)(dir, entry.name),
|
|
14900
14944
|
identity,
|
|
14901
14945
|
eventsPath: log,
|
|
14902
|
-
foldPath: (0,
|
|
14903
|
-
rotatedDir: (0,
|
|
14946
|
+
foldPath: (0, import_node_path13.join)(dir, entry.name, "fold.json"),
|
|
14947
|
+
rotatedDir: (0, import_node_path13.join)(dir, entry.name, "rotated")
|
|
14904
14948
|
};
|
|
14905
14949
|
const state = readFoldCache(sib) ?? foldDossier(sib);
|
|
14906
14950
|
sessions++;
|
|
@@ -14928,25 +14972,25 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
14928
14972
|
let removed = 0;
|
|
14929
14973
|
try {
|
|
14930
14974
|
const mine = dossierDir(identity);
|
|
14931
|
-
const userDir = (0,
|
|
14932
|
-
if (!(0,
|
|
14975
|
+
const userDir = (0, import_node_path13.dirname)((0, import_node_path13.dirname)(mine));
|
|
14976
|
+
if (!(0, import_node_fs14.existsSync)(userDir)) return 0;
|
|
14933
14977
|
const cutoff = Date.now() - maxAgeMs;
|
|
14934
|
-
for (const tree of (0,
|
|
14978
|
+
for (const tree of (0, import_node_fs14.readdirSync)(userDir, { withFileTypes: true })) {
|
|
14935
14979
|
if (!tree.isDirectory()) continue;
|
|
14936
|
-
const treePath = (0,
|
|
14980
|
+
const treePath = (0, import_node_path13.join)(userDir, tree.name);
|
|
14937
14981
|
let live = 0;
|
|
14938
|
-
for (const entry of (0,
|
|
14982
|
+
for (const entry of (0, import_node_fs14.readdirSync)(treePath, { withFileTypes: true })) {
|
|
14939
14983
|
if (!entry.isDirectory()) continue;
|
|
14940
|
-
const dir = (0,
|
|
14984
|
+
const dir = (0, import_node_path13.join)(treePath, entry.name);
|
|
14941
14985
|
if (dir === mine) {
|
|
14942
14986
|
live++;
|
|
14943
14987
|
continue;
|
|
14944
14988
|
}
|
|
14945
14989
|
try {
|
|
14946
|
-
const log = (0,
|
|
14947
|
-
const at = (0,
|
|
14990
|
+
const log = (0, import_node_path13.join)(dir, "events.jsonl");
|
|
14991
|
+
const at = (0, import_node_fs14.existsSync)(log) ? (0, import_node_fs14.statSync)(log).mtimeMs : (0, import_node_fs14.statSync)(dir).mtimeMs;
|
|
14948
14992
|
if (at < cutoff) {
|
|
14949
|
-
(0,
|
|
14993
|
+
(0, import_node_fs14.rmSync)(dir, { recursive: true, force: true });
|
|
14950
14994
|
removed++;
|
|
14951
14995
|
} else {
|
|
14952
14996
|
live++;
|
|
@@ -14956,7 +15000,7 @@ function pruneOldDossiers(identity, maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
|
|
|
14956
15000
|
}
|
|
14957
15001
|
if (live === 0) {
|
|
14958
15002
|
try {
|
|
14959
|
-
(0,
|
|
15003
|
+
(0, import_node_fs14.rmSync)(treePath, { recursive: false, force: false });
|
|
14960
15004
|
} catch {
|
|
14961
15005
|
}
|
|
14962
15006
|
}
|
|
@@ -14973,8 +15017,8 @@ function sessionDossier(token, sessionId) {
|
|
|
14973
15017
|
}
|
|
14974
15018
|
function hasActiveGoal(d) {
|
|
14975
15019
|
try {
|
|
14976
|
-
if (!(0,
|
|
14977
|
-
return (0,
|
|
15020
|
+
if (!(0, import_node_fs14.existsSync)(d.eventsPath)) return false;
|
|
15021
|
+
return (0, import_node_fs14.readFileSync)(d.eventsPath, "utf8").includes('"k":"goal"');
|
|
14978
15022
|
} catch {
|
|
14979
15023
|
return false;
|
|
14980
15024
|
}
|
|
@@ -14998,7 +15042,7 @@ function recordTurn(d, t) {
|
|
|
14998
15042
|
for (const a of t.authored) {
|
|
14999
15043
|
const origin = a.owner === "subagent" ? "subagent" : "edit_tool";
|
|
15000
15044
|
const prior = t.known?.authored?.get(a.p);
|
|
15001
|
-
const hash = fileHash((0,
|
|
15045
|
+
const hash = fileHash((0, import_node_path13.join)(root, a.p));
|
|
15002
15046
|
const hunks = Math.max(0, a.h - (prior?.hunks ?? 0));
|
|
15003
15047
|
const adds = Math.max(0, a.a - (prior?.adds ?? 0));
|
|
15004
15048
|
const dels = Math.max(0, a.d - (prior?.dels ?? 0));
|
|
@@ -15031,7 +15075,7 @@ function recordTurn(d, t) {
|
|
|
15031
15075
|
}
|
|
15032
15076
|
const seenDivergence = t.known?.divergence ?? /* @__PURE__ */ new Set();
|
|
15033
15077
|
for (const u of t.unobserved) {
|
|
15034
|
-
const hash = fileHash((0,
|
|
15078
|
+
const hash = fileHash((0, import_node_path13.join)(root, u.p));
|
|
15035
15079
|
if (seenDivergence.has(divergenceKey(u.p, hash))) continue;
|
|
15036
15080
|
appendEvent(d, { k: "divergence", kind: "external_mutation", path: u.p, hash });
|
|
15037
15081
|
}
|
|
@@ -15060,12 +15104,14 @@ function recordVerdict(d, v) {
|
|
|
15060
15104
|
if (summary) appendEvent(d, { k: "goal_delivered", summary });
|
|
15061
15105
|
}
|
|
15062
15106
|
const lines = /* @__PURE__ */ new Map();
|
|
15107
|
+
const sent = new Set(v.sentPaths);
|
|
15063
15108
|
for (const f of v.findings) {
|
|
15064
15109
|
if (!f.file || typeof f.line !== "number" || !f.pattern_id) continue;
|
|
15110
|
+
if (!sent.has(f.file)) continue;
|
|
15065
15111
|
if (!lines.has(f.file)) {
|
|
15066
15112
|
try {
|
|
15067
|
-
const abs = (0,
|
|
15068
|
-
lines.set(f.file, (0,
|
|
15113
|
+
const abs = (0, import_node_path13.join)(root, f.file);
|
|
15114
|
+
lines.set(f.file, (0, import_node_fs14.existsSync)(abs) ? (0, import_node_fs14.readFileSync)(abs, "utf8").split("\n") : null);
|
|
15069
15115
|
} catch {
|
|
15070
15116
|
lines.set(f.file, null);
|
|
15071
15117
|
}
|
|
@@ -15165,8 +15211,8 @@ function recallMemory(d, identity, opts) {
|
|
|
15165
15211
|
budgetBytes: opts.budgetBytes,
|
|
15166
15212
|
readFileLines: (file) => {
|
|
15167
15213
|
try {
|
|
15168
|
-
const abs = (0,
|
|
15169
|
-
return (0,
|
|
15214
|
+
const abs = (0, import_node_path13.join)(root, file);
|
|
15215
|
+
return (0, import_node_fs14.existsSync)(abs) ? (0, import_node_fs14.readFileSync)(abs, "utf8").split("\n") : null;
|
|
15170
15216
|
} catch {
|
|
15171
15217
|
return null;
|
|
15172
15218
|
}
|
|
@@ -15304,22 +15350,22 @@ async function fireClassify(prompt, sessionId, globals) {
|
|
|
15304
15350
|
}
|
|
15305
15351
|
|
|
15306
15352
|
// src/commands/lifecycle.ts
|
|
15307
|
-
var
|
|
15308
|
-
var
|
|
15353
|
+
var import_node_fs18 = require("node:fs");
|
|
15354
|
+
var import_node_path17 = require("node:path");
|
|
15309
15355
|
|
|
15310
15356
|
// src/lib/baseline.ts
|
|
15311
|
-
var
|
|
15312
|
-
var
|
|
15357
|
+
var import_node_fs17 = require("node:fs");
|
|
15358
|
+
var import_node_path16 = require("node:path");
|
|
15313
15359
|
var import_node_crypto9 = require("node:crypto");
|
|
15314
15360
|
|
|
15315
15361
|
// src/lib/snapshot.ts
|
|
15316
|
-
var
|
|
15317
|
-
var
|
|
15362
|
+
var import_node_fs16 = require("node:fs");
|
|
15363
|
+
var import_node_path15 = require("node:path");
|
|
15318
15364
|
var import_node_child_process6 = require("node:child_process");
|
|
15319
15365
|
|
|
15320
15366
|
// src/lib/files.ts
|
|
15321
|
-
var
|
|
15322
|
-
var
|
|
15367
|
+
var import_node_fs15 = require("node:fs");
|
|
15368
|
+
var import_node_path14 = require("node:path");
|
|
15323
15369
|
var LANG_MAP = {
|
|
15324
15370
|
// Analyzable (static analysis + Gemini)
|
|
15325
15371
|
ts: "typescript",
|
|
@@ -15387,7 +15433,7 @@ var LANG_MAP = {
|
|
|
15387
15433
|
mk: "make"
|
|
15388
15434
|
};
|
|
15389
15435
|
function detectLanguage(filepath) {
|
|
15390
|
-
const ext = (0,
|
|
15436
|
+
const ext = (0, import_node_path14.extname)(filepath).slice(1);
|
|
15391
15437
|
return LANG_MAP[ext] ?? ext;
|
|
15392
15438
|
}
|
|
15393
15439
|
function sortByMtime(files) {
|
|
@@ -15395,7 +15441,7 @@ function sortByMtime(files) {
|
|
|
15395
15441
|
const resolved = resolveFile(f);
|
|
15396
15442
|
if (!resolved) return null;
|
|
15397
15443
|
try {
|
|
15398
|
-
const stat3 = (0,
|
|
15444
|
+
const stat3 = (0, import_node_fs15.statSync)(resolved);
|
|
15399
15445
|
return { path: f, resolved, mtime: stat3.mtimeMs };
|
|
15400
15446
|
} catch {
|
|
15401
15447
|
return null;
|
|
@@ -15428,7 +15474,7 @@ function collectCodeDelta(files, opts) {
|
|
|
15428
15474
|
}
|
|
15429
15475
|
let size;
|
|
15430
15476
|
try {
|
|
15431
|
-
size = (0,
|
|
15477
|
+
size = (0, import_node_fs15.statSync)(resolved).size;
|
|
15432
15478
|
} catch {
|
|
15433
15479
|
exclude(filepath, "not-stattable");
|
|
15434
15480
|
continue;
|
|
@@ -15445,7 +15491,7 @@ function collectCodeDelta(files, opts) {
|
|
|
15445
15491
|
}
|
|
15446
15492
|
let content;
|
|
15447
15493
|
try {
|
|
15448
|
-
content = (0,
|
|
15494
|
+
content = (0, import_node_fs15.readFileSync)(resolved, "utf-8");
|
|
15449
15495
|
} catch {
|
|
15450
15496
|
exclude(filepath, "not-readable");
|
|
15451
15497
|
continue;
|
|
@@ -15484,15 +15530,16 @@ function collectCodeDelta(files, opts) {
|
|
|
15484
15530
|
|
|
15485
15531
|
// src/lib/snapshot.ts
|
|
15486
15532
|
function generateSnapshotDiffs(files) {
|
|
15487
|
-
if (!(0,
|
|
15533
|
+
if (!(0, import_node_fs16.existsSync)(SNAPSHOT_DIR)) {
|
|
15488
15534
|
return { diffs: [], has_snapshots: false };
|
|
15489
15535
|
}
|
|
15490
15536
|
const diffs = [];
|
|
15491
15537
|
for (const file of files) {
|
|
15492
|
-
|
|
15538
|
+
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
15539
|
+
const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
|
|
15493
15540
|
const language = file.language ?? detectLanguage(file.path);
|
|
15494
|
-
if ((0,
|
|
15495
|
-
const oldContent = (0,
|
|
15541
|
+
if ((0, import_node_fs16.existsSync)(snapshotPath)) {
|
|
15542
|
+
const oldContent = (0, import_node_fs16.readFileSync)(snapshotPath, "utf-8");
|
|
15496
15543
|
if (oldContent === file.content) continue;
|
|
15497
15544
|
const diff = computeDiff(oldContent, file.content, file.path);
|
|
15498
15545
|
if (diff) {
|
|
@@ -15513,23 +15560,51 @@ ${addedLines}`,
|
|
|
15513
15560
|
}
|
|
15514
15561
|
return { diffs, has_snapshots: true };
|
|
15515
15562
|
}
|
|
15563
|
+
function ensureSnapshotGitignored() {
|
|
15564
|
+
let content = "";
|
|
15565
|
+
try {
|
|
15566
|
+
content = (0, import_node_fs16.readFileSync)(".gitignore", "utf-8");
|
|
15567
|
+
} catch {
|
|
15568
|
+
}
|
|
15569
|
+
let ignored = null;
|
|
15570
|
+
try {
|
|
15571
|
+
(0, import_node_child_process6.execSync)("git check-ignore -q -- .verity/.snapshot/__probe__", { stdio: "pipe" });
|
|
15572
|
+
ignored = true;
|
|
15573
|
+
} catch (err) {
|
|
15574
|
+
ignored = err.status === 1 ? false : null;
|
|
15575
|
+
}
|
|
15576
|
+
if (ignored === true) return "covered";
|
|
15577
|
+
if (ignored === null) {
|
|
15578
|
+
const lines = content.split("\n").map((l) => l.trim());
|
|
15579
|
+
const covering = [".verity/.snapshot/", ".verity/.snapshot", ".verity/", ".verity", ".verity/*"];
|
|
15580
|
+
if (lines.some((l) => covering.includes(l))) return "covered";
|
|
15581
|
+
}
|
|
15582
|
+
try {
|
|
15583
|
+
const block = "# Verity \u2014 snapshots of analyzed files (machine state, never commit)\n.verity/.snapshot/\n";
|
|
15584
|
+
(0, import_node_fs16.writeFileSync)(".gitignore", content ? content + (content.endsWith("\n") ? "" : "\n") + "\n" + block : block);
|
|
15585
|
+
return "added";
|
|
15586
|
+
} catch {
|
|
15587
|
+
return "failed";
|
|
15588
|
+
}
|
|
15589
|
+
}
|
|
15516
15590
|
function saveSnapshots(files) {
|
|
15517
15591
|
const snapshotPaths = /* @__PURE__ */ new Set();
|
|
15518
15592
|
for (const file of files) {
|
|
15519
|
-
|
|
15593
|
+
if (!resolveInside(SNAPSHOT_DIR, file.path)) continue;
|
|
15594
|
+
const snapshotPath = (0, import_node_path15.join)(SNAPSHOT_DIR, file.path);
|
|
15520
15595
|
snapshotPaths.add(snapshotPath);
|
|
15521
|
-
(0,
|
|
15522
|
-
(0,
|
|
15596
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path15.dirname)(snapshotPath), { recursive: true });
|
|
15597
|
+
(0, import_node_fs16.writeFileSync)(snapshotPath, file.content);
|
|
15523
15598
|
}
|
|
15524
15599
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
15525
15600
|
}
|
|
15526
15601
|
function computeDiff(oldContent, newContent, filePath) {
|
|
15527
|
-
const tmpOld = (0,
|
|
15528
|
-
const tmpNew = (0,
|
|
15602
|
+
const tmpOld = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
15603
|
+
const tmpNew = (0, import_node_path15.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
15529
15604
|
try {
|
|
15530
|
-
(0,
|
|
15531
|
-
(0,
|
|
15532
|
-
(0,
|
|
15605
|
+
(0, import_node_fs16.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
15606
|
+
(0, import_node_fs16.writeFileSync)(tmpOld, oldContent);
|
|
15607
|
+
(0, import_node_fs16.writeFileSync)(tmpNew, newContent);
|
|
15533
15608
|
const result = (0, import_node_child_process6.execSync)(
|
|
15534
15609
|
`git diff --no-index --unified=10 -- "${tmpOld}" "${tmpNew}"`,
|
|
15535
15610
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -15543,32 +15618,32 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
15543
15618
|
return null;
|
|
15544
15619
|
} finally {
|
|
15545
15620
|
try {
|
|
15546
|
-
(0,
|
|
15621
|
+
(0, import_node_fs16.unlinkSync)(tmpOld);
|
|
15547
15622
|
} catch {
|
|
15548
15623
|
}
|
|
15549
15624
|
try {
|
|
15550
|
-
(0,
|
|
15625
|
+
(0, import_node_fs16.unlinkSync)(tmpNew);
|
|
15551
15626
|
} catch {
|
|
15552
15627
|
}
|
|
15553
15628
|
}
|
|
15554
15629
|
}
|
|
15555
15630
|
function cleanStaleSnapshots(dir, keepSet) {
|
|
15556
|
-
if (!(0,
|
|
15631
|
+
if (!(0, import_node_fs16.existsSync)(dir)) return;
|
|
15557
15632
|
try {
|
|
15558
|
-
const entries = (0,
|
|
15633
|
+
const entries = (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true });
|
|
15559
15634
|
for (const entry of entries) {
|
|
15560
|
-
if (entry.name.
|
|
15561
|
-
const fullPath = (0,
|
|
15635
|
+
if (dir === SNAPSHOT_DIR && (entry.name === ".diff-old.tmp" || entry.name === ".diff-new.tmp")) continue;
|
|
15636
|
+
const fullPath = (0, import_node_path15.join)(dir, entry.name);
|
|
15562
15637
|
if (entry.isDirectory()) {
|
|
15563
15638
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
15564
15639
|
try {
|
|
15565
|
-
const remaining = (0,
|
|
15566
|
-
if (remaining.length === 0) (0,
|
|
15640
|
+
const remaining = (0, import_node_fs16.readdirSync)(fullPath);
|
|
15641
|
+
if (remaining.length === 0) (0, import_node_fs16.rmdirSync)(fullPath);
|
|
15567
15642
|
} catch {
|
|
15568
15643
|
}
|
|
15569
15644
|
} else if (!keepSet.has(fullPath)) {
|
|
15570
15645
|
try {
|
|
15571
|
-
(0,
|
|
15646
|
+
(0, import_node_fs16.unlinkSync)(fullPath);
|
|
15572
15647
|
} catch {
|
|
15573
15648
|
}
|
|
15574
15649
|
}
|
|
@@ -15587,20 +15662,20 @@ function sessionKey(sessionId) {
|
|
|
15587
15662
|
return (0, import_node_crypto9.createHash)("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
15588
15663
|
}
|
|
15589
15664
|
function sessionDir(key) {
|
|
15590
|
-
return (0,
|
|
15665
|
+
return (0, import_node_path16.join)(projectPath(BASELINE_DIR), key);
|
|
15591
15666
|
}
|
|
15592
15667
|
function manifestPath(dir) {
|
|
15593
|
-
return (0,
|
|
15668
|
+
return (0, import_node_path16.join)(dir, "manifest.json");
|
|
15594
15669
|
}
|
|
15595
15670
|
function mirrorPath(dir, repoRelPath) {
|
|
15596
|
-
return (0,
|
|
15671
|
+
return (0, import_node_path16.join)(dir, "files", repoRelPath);
|
|
15597
15672
|
}
|
|
15598
15673
|
var CARRY_FILE = `${BASELINE_DIR}/.carry`;
|
|
15599
15674
|
var CARRY_WINDOW_MS = 12e4;
|
|
15600
15675
|
function writeCarry(sessionId, headSha) {
|
|
15601
15676
|
try {
|
|
15602
|
-
(0,
|
|
15603
|
-
(0,
|
|
15677
|
+
(0, import_node_fs17.mkdirSync)(projectPath(BASELINE_DIR), { recursive: true });
|
|
15678
|
+
(0, import_node_fs17.writeFileSync)(
|
|
15604
15679
|
projectPath(CARRY_FILE),
|
|
15605
15680
|
JSON.stringify({ from_key: sessionKey(sessionId), head_sha: headSha, ts: Date.now() })
|
|
15606
15681
|
);
|
|
@@ -15610,10 +15685,10 @@ function writeCarry(sessionId, headSha) {
|
|
|
15610
15685
|
function claimCarry(newKey) {
|
|
15611
15686
|
const carryPath = projectPath(CARRY_FILE);
|
|
15612
15687
|
try {
|
|
15613
|
-
if (!(0,
|
|
15614
|
-
const carry = JSON.parse((0,
|
|
15688
|
+
if (!(0, import_node_fs17.existsSync)(carryPath)) return null;
|
|
15689
|
+
const carry = JSON.parse((0, import_node_fs17.readFileSync)(carryPath, "utf-8"));
|
|
15615
15690
|
try {
|
|
15616
|
-
(0,
|
|
15691
|
+
(0, import_node_fs17.rmSync)(carryPath, { force: true });
|
|
15617
15692
|
} catch {
|
|
15618
15693
|
}
|
|
15619
15694
|
if (!carry?.from_key || typeof carry.ts !== "number") return null;
|
|
@@ -15624,11 +15699,11 @@ function claimCarry(newKey) {
|
|
|
15624
15699
|
if (!prior) return null;
|
|
15625
15700
|
const toDir = sessionDir(newKey);
|
|
15626
15701
|
try {
|
|
15627
|
-
(0,
|
|
15702
|
+
(0, import_node_fs17.rmSync)(toDir, { recursive: true, force: true });
|
|
15628
15703
|
} catch {
|
|
15629
15704
|
}
|
|
15630
|
-
(0,
|
|
15631
|
-
(0,
|
|
15705
|
+
(0, import_node_fs17.renameSync)(fromDir, toDir);
|
|
15706
|
+
(0, import_node_fs17.writeFileSync)(manifestPath(toDir), JSON.stringify({ ...prior, session_id: newKey }) + "\n");
|
|
15632
15707
|
return readManifest(toDir);
|
|
15633
15708
|
} catch {
|
|
15634
15709
|
return null;
|
|
@@ -15652,21 +15727,21 @@ function captureBaseline(opts = {}) {
|
|
|
15652
15727
|
const head_sha = getCurrentCommit();
|
|
15653
15728
|
const dirty = getDirtyFiles();
|
|
15654
15729
|
try {
|
|
15655
|
-
(0,
|
|
15730
|
+
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
15656
15731
|
} catch {
|
|
15657
15732
|
}
|
|
15658
|
-
const filesDir = (0,
|
|
15733
|
+
const filesDir = (0, import_node_path16.join)(dir, "files");
|
|
15659
15734
|
const mirrored = [];
|
|
15660
15735
|
try {
|
|
15661
|
-
(0,
|
|
15736
|
+
(0, import_node_fs17.mkdirSync)(filesDir, { recursive: true });
|
|
15662
15737
|
for (const p of dirty) {
|
|
15663
15738
|
if (p.includes("..")) continue;
|
|
15664
15739
|
const content = safeReadForMirror(projectPath(p));
|
|
15665
15740
|
if (content === null) continue;
|
|
15666
15741
|
const dest = mirrorPath(dir, p);
|
|
15667
15742
|
try {
|
|
15668
|
-
(0,
|
|
15669
|
-
(0,
|
|
15743
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
15744
|
+
(0, import_node_fs17.writeFileSync)(dest, content);
|
|
15670
15745
|
mirrored.push(p);
|
|
15671
15746
|
} catch {
|
|
15672
15747
|
}
|
|
@@ -15681,8 +15756,8 @@ function captureBaseline(opts = {}) {
|
|
|
15681
15756
|
version: BASELINE_VERSION
|
|
15682
15757
|
};
|
|
15683
15758
|
try {
|
|
15684
|
-
(0,
|
|
15685
|
-
(0,
|
|
15759
|
+
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
15760
|
+
(0, import_node_fs17.writeFileSync)(manifestPath(dir), JSON.stringify(baseline));
|
|
15686
15761
|
} catch {
|
|
15687
15762
|
}
|
|
15688
15763
|
pruneOldBaselines();
|
|
@@ -15693,9 +15768,9 @@ function readBaseline(sessionId) {
|
|
|
15693
15768
|
}
|
|
15694
15769
|
function readManifest(dir) {
|
|
15695
15770
|
const mp = manifestPath(dir);
|
|
15696
|
-
if (!(0,
|
|
15771
|
+
if (!(0, import_node_fs17.existsSync)(mp)) return null;
|
|
15697
15772
|
try {
|
|
15698
|
-
const parsed = JSON.parse((0,
|
|
15773
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(mp, "utf-8"));
|
|
15699
15774
|
if (typeof parsed.head_sha !== "string" || typeof parsed.captured_at !== "number" || !Array.isArray(parsed.dirty_paths) || parsed.version !== BASELINE_VERSION) {
|
|
15700
15775
|
return null;
|
|
15701
15776
|
}
|
|
@@ -15726,9 +15801,9 @@ function preImage(repoRelPath, baseline) {
|
|
|
15726
15801
|
function resolvePreImage(repoRelPath, baseline) {
|
|
15727
15802
|
if (baseline.dirty_paths.includes(repoRelPath)) {
|
|
15728
15803
|
const mp = mirrorPath(sessionDir(sessionKey(baseline.session_id)), repoRelPath);
|
|
15729
|
-
if ((0,
|
|
15804
|
+
if ((0, import_node_fs17.existsSync)(mp)) {
|
|
15730
15805
|
try {
|
|
15731
|
-
return { content: (0,
|
|
15806
|
+
return { content: (0, import_node_fs17.readFileSync)(mp, "utf-8"), existed: true };
|
|
15732
15807
|
} catch {
|
|
15733
15808
|
}
|
|
15734
15809
|
}
|
|
@@ -15773,8 +15848,8 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
15773
15848
|
const content = safeReadForMirror(projectPath(p));
|
|
15774
15849
|
if (content === null) continue;
|
|
15775
15850
|
const dest = mirrorPath(dir, p);
|
|
15776
|
-
(0,
|
|
15777
|
-
(0,
|
|
15851
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
15852
|
+
(0, import_node_fs17.writeFileSync)(dest, content);
|
|
15778
15853
|
dirty.add(p);
|
|
15779
15854
|
adopted++;
|
|
15780
15855
|
} catch {
|
|
@@ -15783,7 +15858,7 @@ function absorbIntoBaseline(paths, sessionId) {
|
|
|
15783
15858
|
if (adopted === 0) return 0;
|
|
15784
15859
|
try {
|
|
15785
15860
|
const updated = { ...baseline, dirty_paths: [...dirty] };
|
|
15786
|
-
(0,
|
|
15861
|
+
(0, import_node_fs17.writeFileSync)(manifestPath(dir), JSON.stringify(updated));
|
|
15787
15862
|
preImageCache.delete(baseline);
|
|
15788
15863
|
} catch {
|
|
15789
15864
|
return 0;
|
|
@@ -15794,7 +15869,7 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
15794
15869
|
const pre = preImage(repoRelPath, baseline);
|
|
15795
15870
|
let current;
|
|
15796
15871
|
try {
|
|
15797
|
-
current = (0,
|
|
15872
|
+
current = (0, import_node_fs17.readFileSync)(projectPath(repoRelPath), "utf-8");
|
|
15798
15873
|
} catch {
|
|
15799
15874
|
return pre.existed;
|
|
15800
15875
|
}
|
|
@@ -15803,8 +15878,8 @@ function changedSinceBaseline(repoRelPath, baseline) {
|
|
|
15803
15878
|
}
|
|
15804
15879
|
function safeReadForMirror(absPath) {
|
|
15805
15880
|
try {
|
|
15806
|
-
if ((0,
|
|
15807
|
-
const buf = (0,
|
|
15881
|
+
if ((0, import_node_fs17.statSync)(absPath).size > MIRROR_MAX_BYTES) return null;
|
|
15882
|
+
const buf = (0, import_node_fs17.readFileSync)(absPath);
|
|
15808
15883
|
if (buf.includes(0)) return null;
|
|
15809
15884
|
return buf.toString("utf-8");
|
|
15810
15885
|
} catch {
|
|
@@ -15815,18 +15890,18 @@ function pruneOldBaselines() {
|
|
|
15815
15890
|
const root = projectPath(BASELINE_DIR);
|
|
15816
15891
|
let entries;
|
|
15817
15892
|
try {
|
|
15818
|
-
entries = (0,
|
|
15893
|
+
entries = (0, import_node_fs17.readdirSync)(root);
|
|
15819
15894
|
} catch {
|
|
15820
15895
|
return;
|
|
15821
15896
|
}
|
|
15822
15897
|
const now = Date.now();
|
|
15823
15898
|
for (const name of entries) {
|
|
15824
|
-
const dir = (0,
|
|
15899
|
+
const dir = (0, import_node_path16.join)(root, name);
|
|
15825
15900
|
const manifest = readManifest(dir);
|
|
15826
15901
|
if (!manifest) {
|
|
15827
15902
|
try {
|
|
15828
|
-
if (now - (0,
|
|
15829
|
-
(0,
|
|
15903
|
+
if (now - (0, import_node_fs17.statSync)(dir).mtimeMs > BASELINE_TTL_MS) {
|
|
15904
|
+
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
15830
15905
|
}
|
|
15831
15906
|
} catch {
|
|
15832
15907
|
}
|
|
@@ -15834,7 +15909,7 @@ function pruneOldBaselines() {
|
|
|
15834
15909
|
}
|
|
15835
15910
|
if (now - manifest.captured_at <= BASELINE_TTL_MS) continue;
|
|
15836
15911
|
try {
|
|
15837
|
-
(0,
|
|
15912
|
+
(0, import_node_fs17.rmSync)(dir, { recursive: true, force: true });
|
|
15838
15913
|
} catch {
|
|
15839
15914
|
}
|
|
15840
15915
|
}
|
|
@@ -16007,8 +16082,8 @@ function buildCompactionContext(session) {
|
|
|
16007
16082
|
commitsSince: commitsSincePaths(watermark, (state.authored ?? []).map((a) => a.path)),
|
|
16008
16083
|
readFileLines: (file) => {
|
|
16009
16084
|
try {
|
|
16010
|
-
const abs = (0,
|
|
16011
|
-
return (0,
|
|
16085
|
+
const abs = (0, import_node_path17.join)(root, file);
|
|
16086
|
+
return (0, import_node_fs18.existsSync)(abs) ? (0, import_node_fs18.readFileSync)(abs, "utf8").split("\n") : null;
|
|
16012
16087
|
} catch {
|
|
16013
16088
|
return null;
|
|
16014
16089
|
}
|
|
@@ -16044,17 +16119,17 @@ async function readHookStdin() {
|
|
|
16044
16119
|
try {
|
|
16045
16120
|
if (process.stdin.isTTY) return {};
|
|
16046
16121
|
const chunks = [];
|
|
16047
|
-
const timeout = new Promise((
|
|
16048
|
-
const read = new Promise((
|
|
16122
|
+
const timeout = new Promise((resolve3) => setTimeout(() => resolve3({}), 500));
|
|
16123
|
+
const read = new Promise((resolve3) => {
|
|
16049
16124
|
process.stdin.on("data", (c) => chunks.push(c));
|
|
16050
16125
|
process.stdin.on("end", () => {
|
|
16051
16126
|
try {
|
|
16052
|
-
|
|
16127
|
+
resolve3(JSON.parse(Buffer.concat(chunks).toString("utf-8").trim() || "{}"));
|
|
16053
16128
|
} catch {
|
|
16054
|
-
|
|
16129
|
+
resolve3({});
|
|
16055
16130
|
}
|
|
16056
16131
|
});
|
|
16057
|
-
process.stdin.on("error", () =>
|
|
16132
|
+
process.stdin.on("error", () => resolve3({}));
|
|
16058
16133
|
process.stdin.resume();
|
|
16059
16134
|
});
|
|
16060
16135
|
return await Promise.race([read, timeout]);
|
|
@@ -16601,6 +16676,7 @@ function createRun(opts, globals) {
|
|
|
16601
16676
|
urlResult: { ok: false, error: "unresolved" },
|
|
16602
16677
|
serviceUrl: "",
|
|
16603
16678
|
token: "",
|
|
16679
|
+
modeDecision: null,
|
|
16604
16680
|
sessionIdForMemory: "",
|
|
16605
16681
|
contextFilePaths: [],
|
|
16606
16682
|
analysisMode: "standard",
|
|
@@ -16639,7 +16715,7 @@ function createRun(opts, globals) {
|
|
|
16639
16715
|
}
|
|
16640
16716
|
|
|
16641
16717
|
// src/lib/stderr-log.ts
|
|
16642
|
-
var
|
|
16718
|
+
var import_node_fs19 = require("node:fs");
|
|
16643
16719
|
var TOKEN_RE2 = /verity_[0-9a-f]{16,}/g;
|
|
16644
16720
|
var ANSI_RE = /\u001b\[[0-?]*[ -/]*[@-~]/g;
|
|
16645
16721
|
function scrub(s) {
|
|
@@ -16652,9 +16728,9 @@ function append(text) {
|
|
|
16652
16728
|
try {
|
|
16653
16729
|
const dir = projectPath(DEBUG_LOG_DIR);
|
|
16654
16730
|
const file = projectPath(STDERR_LOG_FILE);
|
|
16655
|
-
(0,
|
|
16731
|
+
(0, import_node_fs19.mkdirSync)(dir, { recursive: true });
|
|
16656
16732
|
rotateIfNeeded(file);
|
|
16657
|
-
(0,
|
|
16733
|
+
(0, import_node_fs19.appendFileSync)(file, text);
|
|
16658
16734
|
} catch {
|
|
16659
16735
|
}
|
|
16660
16736
|
}
|
|
@@ -16713,8 +16789,15 @@ function formatRunEvidence(run, startedAt) {
|
|
|
16713
16789
|
out += row("changed", `${run.changedUniverse.length} from git \xB7 analyzable ${run.analyzable.length} \xB7 reviewable ${run.reviewable.length} \xB7 security ${run.securityFiles.length} \xB7 forReview ${run.allForReview.length}`);
|
|
16714
16790
|
const done = (phase) => run.phasesCompleted.includes(phase);
|
|
16715
16791
|
const ifDone = (phase, value) => done(phase) ? value : "?";
|
|
16716
|
-
|
|
16717
|
-
if (
|
|
16792
|
+
const md = run.modeDecision;
|
|
16793
|
+
if (md) {
|
|
16794
|
+
const how = md.forced ? "forced by --mode" : `predicted=${md.predicted ?? "none"} \u2192 ${md.resolved}`;
|
|
16795
|
+
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"}`);
|
|
16796
|
+
} else {
|
|
16797
|
+
out += row("mode", `? (this run stopped in ${run.phaseReached || "no phase"}, before the mode was decided)`);
|
|
16798
|
+
}
|
|
16799
|
+
out += row("signals", `baseline=${ifDone("bootstrap", run.baseline ? "yes" : "no")} \xB7 authored=${ifDone("intentInputs", run.turnAuthoredCode ? "yes" : "no")} \xB7 observable=${ifDone("intentInputs", run.authorshipIsObservable ? "yes" : "no")}` + (run.actionSummary?.transcript_windowed ? ` \xB7 window=${run.actionSummary.transcript_windowed}` : ""));
|
|
16800
|
+
if (!done("intentInputs")) {
|
|
16718
16801
|
out += row("", `(\`?\` = the phase that determines it did not complete \u2014 this run stopped in ${run.phaseReached})`);
|
|
16719
16802
|
}
|
|
16720
16803
|
out += row("sent", `${sent.length} \xB7 ${list(sent)}`);
|
|
@@ -16741,6 +16824,46 @@ function formatRunEvidence(run, startedAt) {
|
|
|
16741
16824
|
out += row("withheld", "(nothing \u2014 every changed file was reviewed)");
|
|
16742
16825
|
}
|
|
16743
16826
|
}
|
|
16827
|
+
const cov = run.foldResult?.coverage;
|
|
16828
|
+
if (cov) {
|
|
16829
|
+
const delegated = run.foldResult.authored.filter((a) => a.owner === "subagent").length;
|
|
16830
|
+
if (cov.dispatched > 0 || cov.subagentFiles > 0 || cov.subagentSkipped > 0) {
|
|
16831
|
+
out += row("delegated", `${cov.dispatched} dispatched \xB7 ${cov.subagentFiles} agent log(s) read \xB7 ${delegated} path(s) attributed to subagents`);
|
|
16832
|
+
}
|
|
16833
|
+
if (cov.subagentSkipped > 0) {
|
|
16834
|
+
out += row("", `\u26A0 ${cov.subagentSkipped} agent log(s) REFUSED by the byte budget \u2014 the authored set above is PARTIAL`);
|
|
16835
|
+
}
|
|
16836
|
+
if (cov.dispatched > 0 && cov.subagentFiles === 0) {
|
|
16837
|
+
out += row("", `\u26A0 this turn dispatched ${cov.dispatched} agent(s) but no agent log was found \u2014 delegated work is unattributed (has the transcript layout moved?)`);
|
|
16838
|
+
}
|
|
16839
|
+
if (cov.outsideRepo > 0) {
|
|
16840
|
+
out += row("", `${cov.outsideRepo} authored path(s) refused as outside the repo`);
|
|
16841
|
+
}
|
|
16842
|
+
}
|
|
16843
|
+
if (run.foldResult?.tools?.length) {
|
|
16844
|
+
const shown = run.foldResult.tools.slice(0, 6).map((t) => {
|
|
16845
|
+
const outcome = t.failed > 0 ? `${t.failed} failed` : t.last_status === 0 ? "ok" : "?";
|
|
16846
|
+
const where = t.targets.length > 0 ? ` \u2192 ${t.targets.slice(0, 2).join(", ")}` : "";
|
|
16847
|
+
return `${t.runs}\xD7 ${t.name} (${outcome})${where}`;
|
|
16848
|
+
});
|
|
16849
|
+
const more = run.foldResult.tools.length > 6 ? ` \u2026 +${run.foldResult.tools.length - 6} more` : "";
|
|
16850
|
+
out += row("tools", shown.join(" \xB7 ") + more);
|
|
16851
|
+
if (run.foldResult.coverage.toolNamesDropped > 0) {
|
|
16852
|
+
out += row("", `\u26A0 ${run.foldResult.coverage.toolNamesDropped} tool name(s) refused by the cap`);
|
|
16853
|
+
}
|
|
16854
|
+
}
|
|
16855
|
+
if (run.foldResult?.tasks?.length) {
|
|
16856
|
+
const t = run.foldResult.tasks;
|
|
16857
|
+
const done2 = t.filter((x) => x.status === "completed").length;
|
|
16858
|
+
out += row("tasks", `${t.length} \xB7 ${done2} completed \xB7 ` + list(t.slice(0, 4).map((x) => `#${x.id} ${x.name} [${x.status}]`), 4));
|
|
16859
|
+
}
|
|
16860
|
+
if (run.specs?.length) {
|
|
16861
|
+
const readThisSession = new Set(run.actionSummary?.files_read ?? []);
|
|
16862
|
+
const labelled = run.specs.map(
|
|
16863
|
+
(s) => `${s.path}${readThisSession.has(s.path) ? " (read)" : " (positional)"}`
|
|
16864
|
+
);
|
|
16865
|
+
out += row("specs", `${run.specs.length} \xB7 ${list(labelled, 5)}`);
|
|
16866
|
+
}
|
|
16744
16867
|
if (run.staticResults.findings.length > 0) {
|
|
16745
16868
|
out += row("static", `${run.staticResults.findings.length} finding(s) from ${run.staticResults.summary.tools_run.join(", ") || "no tools"}`);
|
|
16746
16869
|
}
|
|
@@ -16787,7 +16910,7 @@ function truthy(v) {
|
|
|
16787
16910
|
}
|
|
16788
16911
|
|
|
16789
16912
|
// src/lib/transcript.ts
|
|
16790
|
-
var
|
|
16913
|
+
var import_node_fs20 = require("node:fs");
|
|
16791
16914
|
var MAX_READ_BYTES = 256 * 1024;
|
|
16792
16915
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
16793
16916
|
var MAX_FILES_LIST = 20;
|
|
@@ -16811,7 +16934,7 @@ async function extractActionSummary(transcriptPath) {
|
|
|
16811
16934
|
function readTurnLines(transcriptPath) {
|
|
16812
16935
|
let size;
|
|
16813
16936
|
try {
|
|
16814
|
-
size = (0,
|
|
16937
|
+
size = (0, import_node_fs20.statSync)(transcriptPath).size;
|
|
16815
16938
|
} catch {
|
|
16816
16939
|
return null;
|
|
16817
16940
|
}
|
|
@@ -16819,7 +16942,7 @@ function readTurnLines(transcriptPath) {
|
|
|
16819
16942
|
let raw;
|
|
16820
16943
|
let windowed = false;
|
|
16821
16944
|
if (size <= SMALL_FILE_BYTES) {
|
|
16822
|
-
raw = (0,
|
|
16945
|
+
raw = (0, import_node_fs20.readFileSync)(transcriptPath, "utf-8");
|
|
16823
16946
|
} else {
|
|
16824
16947
|
windowed = true;
|
|
16825
16948
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
@@ -16936,6 +17059,8 @@ function buildSummary(lines) {
|
|
|
16936
17059
|
break;
|
|
16937
17060
|
case "Agent":
|
|
16938
17061
|
case "Task":
|
|
17062
|
+
case "Workflow":
|
|
17063
|
+
case "SendMessage":
|
|
16939
17064
|
subagents++;
|
|
16940
17065
|
break;
|
|
16941
17066
|
case "WebFetch":
|
|
@@ -16997,11 +17122,11 @@ function sanitizeCommand(rawCmd) {
|
|
|
16997
17122
|
let cmd = rawCmd.split("\n")[0];
|
|
16998
17123
|
let cut = -1;
|
|
16999
17124
|
let marker = "";
|
|
17000
|
-
for (const
|
|
17001
|
-
const idx = cmd.indexOf(
|
|
17125
|
+
for (const sep2 of [" | ", " > ", " >> ", " 2>", " && ", " ; "]) {
|
|
17126
|
+
const idx = cmd.indexOf(sep2);
|
|
17002
17127
|
if (idx > 0 && (cut === -1 || idx < cut)) {
|
|
17003
17128
|
cut = idx;
|
|
17004
|
-
marker =
|
|
17129
|
+
marker = sep2.trim();
|
|
17005
17130
|
}
|
|
17006
17131
|
}
|
|
17007
17132
|
if (cut > -1) cmd = cmd.slice(0, cut);
|
|
@@ -17025,28 +17150,28 @@ async function readStopHookStdin() {
|
|
|
17025
17150
|
try {
|
|
17026
17151
|
if (process.stdin.isTTY) return empty;
|
|
17027
17152
|
const chunks = [];
|
|
17028
|
-
const timeout = new Promise((
|
|
17029
|
-
const read = new Promise((
|
|
17153
|
+
const timeout = new Promise((resolve3) => setTimeout(() => resolve3(empty), 500));
|
|
17154
|
+
const read = new Promise((resolve3) => {
|
|
17030
17155
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
17031
17156
|
process.stdin.on("end", () => {
|
|
17032
17157
|
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
17033
17158
|
if (!raw) {
|
|
17034
|
-
|
|
17159
|
+
resolve3(empty);
|
|
17035
17160
|
return;
|
|
17036
17161
|
}
|
|
17037
17162
|
try {
|
|
17038
17163
|
const data = JSON.parse(raw);
|
|
17039
|
-
|
|
17164
|
+
resolve3({
|
|
17040
17165
|
assistantMessage: typeof data.last_assistant_message === "string" ? data.last_assistant_message : null,
|
|
17041
17166
|
stopReason: typeof data.stop_reason === "string" ? data.stop_reason : null,
|
|
17042
17167
|
transcriptPath: typeof data.transcript_path === "string" ? data.transcript_path : null,
|
|
17043
17168
|
sessionId: typeof data.session_id === "string" ? data.session_id : null
|
|
17044
17169
|
});
|
|
17045
17170
|
} catch {
|
|
17046
|
-
|
|
17171
|
+
resolve3(empty);
|
|
17047
17172
|
}
|
|
17048
17173
|
});
|
|
17049
|
-
process.stdin.on("error", () =>
|
|
17174
|
+
process.stdin.on("error", () => resolve3(empty));
|
|
17050
17175
|
process.stdin.resume();
|
|
17051
17176
|
});
|
|
17052
17177
|
return await Promise.race([read, timeout]);
|
|
@@ -17096,6 +17221,39 @@ async function bootstrap(run) {
|
|
|
17096
17221
|
Object.assign(run, { actionSummary, assistantResponse, baseline, baselineSessionId, reachability, sessionId, stopReason, tokenResult, transcriptPath, turnId });
|
|
17097
17222
|
}
|
|
17098
17223
|
|
|
17224
|
+
// src/lib/self-scope.ts
|
|
17225
|
+
var LEGACY_GATE_SKILLS = /* @__PURE__ */ new Set([
|
|
17226
|
+
"gate-setup",
|
|
17227
|
+
"gate-analyze",
|
|
17228
|
+
"gate-review",
|
|
17229
|
+
"gate-status",
|
|
17230
|
+
"gate-feedback",
|
|
17231
|
+
"gate-insights",
|
|
17232
|
+
"gate-learn",
|
|
17233
|
+
"gate-memory",
|
|
17234
|
+
"gate-reflect"
|
|
17235
|
+
]);
|
|
17236
|
+
function isVerityOwned(path) {
|
|
17237
|
+
const segments = path.replace(/\\/g, "/").split("/");
|
|
17238
|
+
for (let i = 0; i < segments.length; i++) {
|
|
17239
|
+
const seg = segments[i];
|
|
17240
|
+
if (seg === ".verity" || seg === ".codacy") return true;
|
|
17241
|
+
if (i === segments.length - 1 && (seg === "VERITY.md" || seg === "GATE.md")) return true;
|
|
17242
|
+
if (seg === ".claude" && segments[i + 1] === "skills" && typeof segments[i + 2] === "string") {
|
|
17243
|
+
const skill = segments[i + 2];
|
|
17244
|
+
if (skill.startsWith("verity-") || LEGACY_GATE_SKILLS.has(skill)) return true;
|
|
17245
|
+
}
|
|
17246
|
+
if (seg === ".claude" && segments[i + 1] === "settings.json") return true;
|
|
17247
|
+
}
|
|
17248
|
+
return false;
|
|
17249
|
+
}
|
|
17250
|
+
function partitionVerityOwned(paths) {
|
|
17251
|
+
const kept = [];
|
|
17252
|
+
const owned = [];
|
|
17253
|
+
for (const p of paths) (isVerityOwned(p) ? owned : kept).push(p);
|
|
17254
|
+
return { kept, owned };
|
|
17255
|
+
}
|
|
17256
|
+
|
|
17099
17257
|
// src/lib/channel.ts
|
|
17100
17258
|
var MAX_AGENT_CONTEXT_CHARS = 1500;
|
|
17101
17259
|
var MAX_AGENT_ITEMS = 5;
|
|
@@ -17105,6 +17263,29 @@ function renderItem(label2, text, patternId, file, line) {
|
|
|
17105
17263
|
const id = patternId ? ` [${patternId}]` : "";
|
|
17106
17264
|
return `- ${label2}${text}${where}${id}`;
|
|
17107
17265
|
}
|
|
17266
|
+
function channelInputFrom(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
17267
|
+
const metadata = response.metadata ?? {};
|
|
17268
|
+
const intent = response.intent_alignment ?? {};
|
|
17269
|
+
return {
|
|
17270
|
+
intentRepeat,
|
|
17271
|
+
priorPendingFingerprints,
|
|
17272
|
+
gateDecision: String(response.gate_decision ?? ""),
|
|
17273
|
+
findings: response.findings ?? [],
|
|
17274
|
+
pendingItems: response.pending_items ?? [],
|
|
17275
|
+
reviewStatus: metadata.review_status,
|
|
17276
|
+
coverage: metadata.coverage,
|
|
17277
|
+
intentVerdict: intent.verdict,
|
|
17278
|
+
intentGaps: intent.gaps
|
|
17279
|
+
};
|
|
17280
|
+
}
|
|
17281
|
+
function classifyChannelContent(input) {
|
|
17282
|
+
const refusal = input.reviewStatus === "not_reviewed" || input.reviewStatus === "no_authorship_evidence";
|
|
17283
|
+
const intentFlag = input.intentVerdict === "misaligned" || input.intentVerdict === "partial";
|
|
17284
|
+
const advisory = (input.findings ?? []).some((f) => f.scope !== "pre-existing") || (input.pendingItems ?? []).some(
|
|
17285
|
+
(p) => p.pattern_id !== "intent-misalignment" && !!(p.description ?? p.title ?? p.reason)
|
|
17286
|
+
);
|
|
17287
|
+
return { refusal, intentFlag, advisory };
|
|
17288
|
+
}
|
|
17108
17289
|
function buildAgentContext(input) {
|
|
17109
17290
|
const lines = [];
|
|
17110
17291
|
if (input.reviewStatus === "not_reviewed") {
|
|
@@ -17190,7 +17371,7 @@ function channelSilence(input) {
|
|
|
17190
17371
|
// src/lib/cli-version.ts
|
|
17191
17372
|
function cliVersion() {
|
|
17192
17373
|
try {
|
|
17193
|
-
return true ? "0.29.4-experimental.
|
|
17374
|
+
return true ? "0.29.4-experimental.694bcef" : "dev";
|
|
17194
17375
|
} catch {
|
|
17195
17376
|
return "dev";
|
|
17196
17377
|
}
|
|
@@ -17231,7 +17412,7 @@ async function sendSkipBeacon(ctx, reason) {
|
|
|
17231
17412
|
|
|
17232
17413
|
// src/lib/static-analysis.ts
|
|
17233
17414
|
var import_node_child_process7 = require("node:child_process");
|
|
17234
|
-
var
|
|
17415
|
+
var import_node_fs21 = require("node:fs");
|
|
17235
17416
|
var SEVERITY_ORDER = {
|
|
17236
17417
|
Error: 0,
|
|
17237
17418
|
Critical: 0,
|
|
@@ -17279,7 +17460,7 @@ function runCodacyAnalysis(files) {
|
|
|
17279
17460
|
if (files.length === 0) return empty;
|
|
17280
17461
|
const existingFiles = files.filter((f) => {
|
|
17281
17462
|
try {
|
|
17282
|
-
return (0,
|
|
17463
|
+
return (0, import_node_fs21.existsSync)(f);
|
|
17283
17464
|
} catch {
|
|
17284
17465
|
return false;
|
|
17285
17466
|
}
|
|
@@ -17512,9 +17693,10 @@ async function scope(run) {
|
|
|
17512
17693
|
const { assistantResponse } = run;
|
|
17513
17694
|
const { files: allChanged, hasRecentCommitFiles } = getChangedFiles();
|
|
17514
17695
|
run.changedUniverse = allChanged;
|
|
17515
|
-
const
|
|
17516
|
-
const
|
|
17517
|
-
const
|
|
17696
|
+
const { kept: external } = partitionVerityOwned(allChanged);
|
|
17697
|
+
const analyzable = filterAnalyzable(external);
|
|
17698
|
+
const reviewable = filterReviewable(external);
|
|
17699
|
+
const securityFiles = filterSecurity(external);
|
|
17518
17700
|
const noFilesChanged = analyzable.length === 0 && reviewable.length === 0 && securityFiles.length === 0;
|
|
17519
17701
|
if (noFilesChanged && !assistantResponse) {
|
|
17520
17702
|
await passAndExit(run, "No analyzable files changed", "no-analyzable-files");
|
|
@@ -17524,8 +17706,8 @@ async function scope(run) {
|
|
|
17524
17706
|
}
|
|
17525
17707
|
|
|
17526
17708
|
// src/lib/specs.ts
|
|
17527
|
-
var
|
|
17528
|
-
var
|
|
17709
|
+
var import_node_fs22 = require("node:fs");
|
|
17710
|
+
var import_node_path18 = require("node:path");
|
|
17529
17711
|
var SPEC_CANDIDATES = [
|
|
17530
17712
|
"CLAUDE.md",
|
|
17531
17713
|
"AGENTS.md",
|
|
@@ -17541,23 +17723,31 @@ var SPEC_CANDIDATES = [
|
|
|
17541
17723
|
"docs/API.md",
|
|
17542
17724
|
"spec/ARCHITECTURE.md"
|
|
17543
17725
|
];
|
|
17544
|
-
|
|
17726
|
+
var DOC_EXT = /\.(md|mdx|ya?ml|txt|rst|adoc)$/i;
|
|
17727
|
+
var UNCONSULTED_FILE_BYTES = 10240;
|
|
17728
|
+
var UNCONSULTED_TOTAL_BYTES = 30720;
|
|
17729
|
+
function discoverSpecs(consulted = []) {
|
|
17545
17730
|
const result = [];
|
|
17546
17731
|
const seen = /* @__PURE__ */ new Set();
|
|
17547
17732
|
let totalBytes = 0;
|
|
17548
|
-
const
|
|
17733
|
+
const consultedDocs = new Set(
|
|
17734
|
+
consulted.filter((p) => DOC_EXT.test(p) && !p.startsWith("/") && !p.includes(".."))
|
|
17735
|
+
);
|
|
17736
|
+
const addSpec = (specPath, relevant = false) => {
|
|
17549
17737
|
if (result.length >= MAX_SPEC_FILES) return false;
|
|
17550
|
-
|
|
17738
|
+
const totalCap = relevant ? MAX_TOTAL_SPEC_BYTES : UNCONSULTED_TOTAL_BYTES;
|
|
17739
|
+
if (totalBytes >= totalCap) return false;
|
|
17551
17740
|
if (seen.has(specPath)) return true;
|
|
17552
|
-
if (!(0,
|
|
17741
|
+
if (!(0, import_node_fs22.existsSync)(specPath)) return true;
|
|
17553
17742
|
seen.add(specPath);
|
|
17554
|
-
const remaining =
|
|
17555
|
-
const
|
|
17743
|
+
const remaining = totalCap - totalBytes;
|
|
17744
|
+
const fileCap = relevant ? MAX_SPEC_FILE_BYTES : UNCONSULTED_FILE_BYTES;
|
|
17745
|
+
const readBytes = Math.min(fileCap, remaining);
|
|
17556
17746
|
try {
|
|
17557
17747
|
const buf = Buffer.alloc(readBytes);
|
|
17558
|
-
const fd = (0,
|
|
17559
|
-
const bytesRead = (0,
|
|
17560
|
-
(0,
|
|
17748
|
+
const fd = (0, import_node_fs22.openSync)(specPath, "r");
|
|
17749
|
+
const bytesRead = (0, import_node_fs22.readSync)(fd, buf, 0, readBytes, 0);
|
|
17750
|
+
(0, import_node_fs22.closeSync)(fd);
|
|
17561
17751
|
const content = buf.slice(0, bytesRead).toString("utf-8");
|
|
17562
17752
|
if (!content) return true;
|
|
17563
17753
|
result.push({ path: specPath, content });
|
|
@@ -17566,11 +17756,14 @@ function discoverSpecs() {
|
|
|
17566
17756
|
}
|
|
17567
17757
|
return true;
|
|
17568
17758
|
};
|
|
17759
|
+
for (const doc of consultedDocs) {
|
|
17760
|
+
if (!addSpec(doc, true)) break;
|
|
17761
|
+
}
|
|
17569
17762
|
for (const candidate of SPEC_CANDIDATES) {
|
|
17570
17763
|
if (!addSpec(candidate)) break;
|
|
17571
17764
|
}
|
|
17572
17765
|
for (const dir of ["spec", "docs"]) {
|
|
17573
|
-
if (!(0,
|
|
17766
|
+
if (!(0, import_node_fs22.existsSync)(dir)) continue;
|
|
17574
17767
|
try {
|
|
17575
17768
|
const mdFiles = findMdFiles(dir, 2).sort();
|
|
17576
17769
|
for (const mdFile of mdFiles) {
|
|
@@ -17585,9 +17778,9 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
17585
17778
|
if (depth >= maxDepth) return [];
|
|
17586
17779
|
const result = [];
|
|
17587
17780
|
try {
|
|
17588
|
-
const entries = (0,
|
|
17781
|
+
const entries = (0, import_node_fs22.readdirSync)(dir, { withFileTypes: true });
|
|
17589
17782
|
for (const entry of entries) {
|
|
17590
|
-
const fullPath = (0,
|
|
17783
|
+
const fullPath = (0, import_node_path18.join)(dir, entry.name);
|
|
17591
17784
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
17592
17785
|
result.push(fullPath);
|
|
17593
17786
|
} else if (entry.isDirectory() && depth < maxDepth - 1) {
|
|
@@ -17599,19 +17792,19 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
17599
17792
|
return result;
|
|
17600
17793
|
}
|
|
17601
17794
|
function discoverPlans() {
|
|
17602
|
-
const homePlansDir = (0,
|
|
17795
|
+
const homePlansDir = (0, import_node_path18.join)(process.env.HOME ?? "", ".claude", "plans");
|
|
17603
17796
|
const localPlansDir = ".claude/plans";
|
|
17604
17797
|
const candidates = [];
|
|
17605
17798
|
const seen = /* @__PURE__ */ new Set();
|
|
17606
17799
|
for (const plansDir of [localPlansDir, homePlansDir]) {
|
|
17607
|
-
if (!(0,
|
|
17800
|
+
if (!(0, import_node_fs22.existsSync)(plansDir)) continue;
|
|
17608
17801
|
try {
|
|
17609
|
-
for (const f of (0,
|
|
17802
|
+
for (const f of (0, import_node_fs22.readdirSync)(plansDir)) {
|
|
17610
17803
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
17611
17804
|
seen.add(f);
|
|
17612
|
-
const fullPath = (0,
|
|
17805
|
+
const fullPath = (0, import_node_path18.join)(plansDir, f);
|
|
17613
17806
|
try {
|
|
17614
|
-
const stat3 = (0,
|
|
17807
|
+
const stat3 = (0, import_node_fs22.statSync)(fullPath);
|
|
17615
17808
|
candidates.push({ name: f, path: fullPath, mtime: stat3.mtimeMs, size: stat3.size });
|
|
17616
17809
|
} catch {
|
|
17617
17810
|
}
|
|
@@ -17624,7 +17817,7 @@ function discoverPlans() {
|
|
|
17624
17817
|
for (const entry of candidates.slice(0, MAX_PLAN_FILES)) {
|
|
17625
17818
|
if (entry.size > MAX_PLAN_FILE_BYTES) continue;
|
|
17626
17819
|
try {
|
|
17627
|
-
const content = (0,
|
|
17820
|
+
const content = (0, import_node_fs22.readFileSync)(entry.path, "utf-8");
|
|
17628
17821
|
result.push({ name: entry.name, content });
|
|
17629
17822
|
} catch {
|
|
17630
17823
|
}
|
|
@@ -17636,7 +17829,7 @@ function discoverPlans() {
|
|
|
17636
17829
|
async function intentInputs(run) {
|
|
17637
17830
|
const { actionSummary, allForReview, assistantResponse, baseline, baselineSessionId } = run;
|
|
17638
17831
|
const conversation = await readAndClearConversationBuffer(baselineSessionId);
|
|
17639
|
-
const specs = discoverSpecs();
|
|
17832
|
+
const specs = discoverSpecs(actionSummary?.files_read ?? []);
|
|
17640
17833
|
const plans = discoverPlans();
|
|
17641
17834
|
const agentAuthoredCodeThisTurn = !!(actionSummary && (actionSummary.files_edited.length > 0 || actionSummary.files_created.length > 0));
|
|
17642
17835
|
const turnAuthoredCode = agentAuthoredCodeThisTurn || !!baseline && allForReview.some((f) => changedSinceBaseline(f, baseline));
|
|
@@ -17859,7 +18052,8 @@ async function mode(run) {
|
|
|
17859
18052
|
let analysisMode;
|
|
17860
18053
|
const sessionAuthoredCode = !!baseline && allForReview.some((f) => changedSinceBaseline(f, baseline));
|
|
17861
18054
|
const modeOverride = opts.mode;
|
|
17862
|
-
|
|
18055
|
+
const forced = !!modeOverride && ["standard", "plan", "debug", "skip"].includes(modeOverride);
|
|
18056
|
+
if (forced) {
|
|
17863
18057
|
analysisMode = modeOverride;
|
|
17864
18058
|
} else {
|
|
17865
18059
|
analysisMode = reconcileAnalysisMode(
|
|
@@ -17867,6 +18061,25 @@ async function mode(run) {
|
|
|
17867
18061
|
{ noFilesChanged, assistantResponse, actionSummary, conversationPrompts, sessionAuthoredCode }
|
|
17868
18062
|
);
|
|
17869
18063
|
}
|
|
18064
|
+
const investigated = didAgentInvestigate(actionSummary);
|
|
18065
|
+
run.modeDecision = {
|
|
18066
|
+
predicted: predictedMode ?? null,
|
|
18067
|
+
resolved: analysisMode,
|
|
18068
|
+
authored: turnAuthoredCode,
|
|
18069
|
+
investigated,
|
|
18070
|
+
forced
|
|
18071
|
+
};
|
|
18072
|
+
logEvent("mode_resolved", {
|
|
18073
|
+
predicted: predictedMode ?? null,
|
|
18074
|
+
resolved: analysisMode,
|
|
18075
|
+
forced,
|
|
18076
|
+
authored: turnAuthoredCode,
|
|
18077
|
+
investigated,
|
|
18078
|
+
// The two counters that decide `investigated`, so a false reading is
|
|
18079
|
+
// traceable to the tool that was not recognised.
|
|
18080
|
+
subagents: actionSummary?.subagents ?? null,
|
|
18081
|
+
files_read: actionSummary?.files_read.length ?? null
|
|
18082
|
+
});
|
|
17870
18083
|
if (analysisMode === "skip") {
|
|
17871
18084
|
await passAndExit(
|
|
17872
18085
|
run,
|
|
@@ -17879,7 +18092,7 @@ async function mode(run) {
|
|
|
17879
18092
|
}
|
|
17880
18093
|
|
|
17881
18094
|
// src/lib/debounce.ts
|
|
17882
|
-
var
|
|
18095
|
+
var import_node_fs23 = require("node:fs");
|
|
17883
18096
|
var import_node_crypto10 = require("node:crypto");
|
|
17884
18097
|
function scopedFile(base, sessionId) {
|
|
17885
18098
|
if (!sessionId) return base;
|
|
@@ -17887,9 +18100,9 @@ function scopedFile(base, sessionId) {
|
|
|
17887
18100
|
}
|
|
17888
18101
|
function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
17889
18102
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
17890
|
-
if (!(0,
|
|
18103
|
+
if (!(0, import_node_fs23.existsSync)(file)) return null;
|
|
17891
18104
|
try {
|
|
17892
|
-
const lastTs = parseInt((0,
|
|
18105
|
+
const lastTs = parseInt((0, import_node_fs23.readFileSync)(file, "utf-8").trim(), 10);
|
|
17893
18106
|
const nowTs = Math.floor(Date.now() / 1e3);
|
|
17894
18107
|
const elapsed = nowTs - lastTs;
|
|
17895
18108
|
if (elapsed < debounceSeconds) {
|
|
@@ -17902,10 +18115,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS, sessionId) {
|
|
|
17902
18115
|
function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
17903
18116
|
if (bypassForRecentCommits) return null;
|
|
17904
18117
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
17905
|
-
if (!(0,
|
|
18118
|
+
if (!(0, import_node_fs23.existsSync)(file)) return null;
|
|
17906
18119
|
let debounceTime;
|
|
17907
18120
|
try {
|
|
17908
|
-
debounceTime = (0,
|
|
18121
|
+
debounceTime = (0, import_node_fs23.statSync)(file).mtimeMs;
|
|
17909
18122
|
} catch {
|
|
17910
18123
|
return null;
|
|
17911
18124
|
}
|
|
@@ -17913,7 +18126,7 @@ function checkMtime(files, bypassForRecentCommits, sessionId) {
|
|
|
17913
18126
|
const resolved = resolveFile(f);
|
|
17914
18127
|
if (!resolved) continue;
|
|
17915
18128
|
try {
|
|
17916
|
-
const stat3 = (0,
|
|
18129
|
+
const stat3 = (0, import_node_fs23.statSync)(resolved);
|
|
17917
18130
|
if (stat3.mtimeMs > debounceTime) {
|
|
17918
18131
|
return null;
|
|
17919
18132
|
}
|
|
@@ -17929,8 +18142,8 @@ function computeContentHash(files) {
|
|
|
17929
18142
|
for (const f of sorted) {
|
|
17930
18143
|
const resolved = resolveFile(f) ?? f;
|
|
17931
18144
|
try {
|
|
17932
|
-
if ((0,
|
|
17933
|
-
hash.update((0,
|
|
18145
|
+
if ((0, import_node_fs23.existsSync)(resolved)) {
|
|
18146
|
+
hash.update((0, import_node_fs23.readFileSync)(resolved));
|
|
17934
18147
|
}
|
|
17935
18148
|
} catch {
|
|
17936
18149
|
}
|
|
@@ -17940,9 +18153,9 @@ function computeContentHash(files) {
|
|
|
17940
18153
|
function checkContentHash(files, sessionId) {
|
|
17941
18154
|
const hash = computeContentHash(files);
|
|
17942
18155
|
const file = scopedFile(HASH_FILE, sessionId);
|
|
17943
|
-
if ((0,
|
|
18156
|
+
if ((0, import_node_fs23.existsSync)(file)) {
|
|
17944
18157
|
try {
|
|
17945
|
-
const storedHash = (0,
|
|
18158
|
+
const storedHash = (0, import_node_fs23.readFileSync)(file, "utf-8").trim();
|
|
17946
18159
|
if (hash === storedHash) {
|
|
17947
18160
|
return { skip: "No source changes since last analysis", hash };
|
|
17948
18161
|
}
|
|
@@ -17952,50 +18165,74 @@ function checkContentHash(files, sessionId) {
|
|
|
17952
18165
|
return { skip: null, hash };
|
|
17953
18166
|
}
|
|
17954
18167
|
function recordAnalysisStart(sessionId) {
|
|
17955
|
-
(0,
|
|
17956
|
-
(0,
|
|
18168
|
+
(0, import_node_fs23.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
18169
|
+
(0, import_node_fs23.writeFileSync)(scopedFile(DEBOUNCE_FILE, sessionId), String(Math.floor(Date.now() / 1e3)));
|
|
17957
18170
|
}
|
|
17958
18171
|
function recordPassHash(hash, sessionId) {
|
|
17959
|
-
(0,
|
|
18172
|
+
(0, import_node_fs23.writeFileSync)(scopedFile(HASH_FILE, sessionId), hash);
|
|
17960
18173
|
}
|
|
17961
18174
|
function narrowToRecent(files, sessionId) {
|
|
17962
18175
|
const file = scopedFile(DEBOUNCE_FILE, sessionId);
|
|
17963
|
-
if (!(0,
|
|
18176
|
+
if (!(0, import_node_fs23.existsSync)(file)) return files;
|
|
17964
18177
|
let debounceTime;
|
|
17965
18178
|
try {
|
|
17966
|
-
debounceTime = (0,
|
|
18179
|
+
debounceTime = (0, import_node_fs23.statSync)(file).mtimeMs;
|
|
17967
18180
|
} catch {
|
|
17968
18181
|
return files;
|
|
17969
18182
|
}
|
|
17970
18183
|
const recent = files.filter((f) => {
|
|
17971
18184
|
try {
|
|
17972
|
-
return (0,
|
|
18185
|
+
return (0, import_node_fs23.existsSync)(f) && (0, import_node_fs23.statSync)(f).mtimeMs > debounceTime;
|
|
17973
18186
|
} catch {
|
|
17974
18187
|
return false;
|
|
17975
18188
|
}
|
|
17976
18189
|
});
|
|
17977
18190
|
return recent.length > 0 ? recent : files;
|
|
17978
18191
|
}
|
|
17979
|
-
function
|
|
17980
|
-
|
|
18192
|
+
function readIteration(currentCommit, _contentHash) {
|
|
18193
|
+
return Math.max(1, readBlockState(currentCommit).attempts);
|
|
18194
|
+
}
|
|
18195
|
+
var NO_BLOCKS = { attempts: 0, blocks: 0, fingerprint: null };
|
|
18196
|
+
function readBlockState(currentCommit, opts) {
|
|
18197
|
+
if (opts?.newUserPrompt) return NO_BLOCKS;
|
|
18198
|
+
if (!(0, import_node_fs23.existsSync)(ITERATION_FILE)) return NO_BLOCKS;
|
|
17981
18199
|
try {
|
|
17982
|
-
const stored = (0,
|
|
17983
|
-
const
|
|
17984
|
-
|
|
17985
|
-
|
|
17986
|
-
|
|
17987
|
-
|
|
17988
|
-
if (isNaN(iter)) return { iteration: 1, fingerprint: null };
|
|
17989
|
-
if (storedCommit !== currentCommit) return { iteration: 1, fingerprint: null };
|
|
17990
|
-
if (storedTimestamp > 0) {
|
|
17991
|
-
const elapsed = Math.floor(Date.now() / 1e3) - storedTimestamp;
|
|
17992
|
-
if (elapsed > 600) return { iteration: 1, fingerprint: null };
|
|
17993
|
-
}
|
|
17994
|
-
return { iteration: iter, fingerprint };
|
|
18200
|
+
const stored = (0, import_node_fs23.readFileSync)(ITERATION_FILE, "utf-8").trim();
|
|
18201
|
+
const parsed = stored.startsWith("{") ? parseJsonState(stored) : parseLegacyState(stored);
|
|
18202
|
+
if (!parsed) return NO_BLOCKS;
|
|
18203
|
+
if (parsed.commit !== currentCommit) return NO_BLOCKS;
|
|
18204
|
+
if (parsed.ts > 0 && Math.floor(Date.now() / 1e3) - parsed.ts > 600) return NO_BLOCKS;
|
|
18205
|
+
return { attempts: parsed.attempts, blocks: parsed.blocks, fingerprint: parsed.fingerprint };
|
|
17995
18206
|
} catch {
|
|
17996
|
-
return
|
|
18207
|
+
return NO_BLOCKS;
|
|
17997
18208
|
}
|
|
17998
18209
|
}
|
|
18210
|
+
function parseJsonState(raw) {
|
|
18211
|
+
const o = JSON.parse(raw);
|
|
18212
|
+
const attempts = typeof o.attempts === "number" ? o.attempts : NaN;
|
|
18213
|
+
if (isNaN(attempts)) return null;
|
|
18214
|
+
return {
|
|
18215
|
+
attempts,
|
|
18216
|
+
blocks: typeof o.blocks === "number" ? o.blocks : attempts,
|
|
18217
|
+
fingerprint: typeof o.fingerprint === "string" && o.fingerprint ? o.fingerprint : null,
|
|
18218
|
+
commit: typeof o.commit === "string" ? o.commit : "",
|
|
18219
|
+
ts: typeof o.ts === "number" ? o.ts : 0
|
|
18220
|
+
};
|
|
18221
|
+
}
|
|
18222
|
+
function parseLegacyState(raw) {
|
|
18223
|
+
const parts = raw.split(":");
|
|
18224
|
+
const n = parseInt(parts[0], 10);
|
|
18225
|
+
if (isNaN(n)) return null;
|
|
18226
|
+
return {
|
|
18227
|
+
attempts: n,
|
|
18228
|
+
// The old file has no separate block count; the old counter is the closest
|
|
18229
|
+
// honest answer, and it errs toward releasing sooner rather than later.
|
|
18230
|
+
blocks: n,
|
|
18231
|
+
fingerprint: parts.slice(3).join(":") || null,
|
|
18232
|
+
commit: parts[1] ?? "",
|
|
18233
|
+
ts: parseInt(parts[2] ?? "0", 10)
|
|
18234
|
+
};
|
|
18235
|
+
}
|
|
17999
18236
|
function findingsFingerprint(findings) {
|
|
18000
18237
|
const keys = findings.map((f) => `${String(f.pattern_id ?? "?")}|${String(f.file ?? "?")}`).filter((k) => k !== "?|?");
|
|
18001
18238
|
return [...new Set(keys)].sort().join(",");
|
|
@@ -18005,16 +18242,27 @@ function isSameProblem(previous, current) {
|
|
|
18005
18242
|
const prev = new Set(previous.split(","));
|
|
18006
18243
|
return current.split(",").some((k) => prev.has(k));
|
|
18007
18244
|
}
|
|
18008
|
-
function
|
|
18009
|
-
(0,
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18245
|
+
function writeBlockState(commit, state) {
|
|
18246
|
+
(0, import_node_fs23.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
18247
|
+
(0, import_node_fs23.writeFileSync)(
|
|
18248
|
+
ITERATION_FILE,
|
|
18249
|
+
JSON.stringify({
|
|
18250
|
+
v: 2,
|
|
18251
|
+
attempts: state.attempts,
|
|
18252
|
+
blocks: state.blocks,
|
|
18253
|
+
commit,
|
|
18254
|
+
ts: Math.floor(Date.now() / 1e3),
|
|
18255
|
+
fingerprint: state.fingerprint ?? void 0
|
|
18256
|
+
})
|
|
18257
|
+
);
|
|
18258
|
+
}
|
|
18259
|
+
function resetBlockState(commit) {
|
|
18260
|
+
writeBlockState(commit, { attempts: 0, blocks: 0, fingerprint: null });
|
|
18013
18261
|
}
|
|
18014
18262
|
|
|
18015
18263
|
// src/lib/fold.ts
|
|
18016
|
-
var
|
|
18017
|
-
var
|
|
18264
|
+
var import_node_fs24 = require("node:fs");
|
|
18265
|
+
var import_node_path19 = require("node:path");
|
|
18018
18266
|
var KNOWN_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
18019
18267
|
"user",
|
|
18020
18268
|
"assistant",
|
|
@@ -18132,6 +18380,18 @@ function commandShape(cmd) {
|
|
|
18132
18380
|
return out.join(" ").slice(0, COMMAND_HEAD_CHARS);
|
|
18133
18381
|
}
|
|
18134
18382
|
var COMMAND_HEAD_CHARS = 80;
|
|
18383
|
+
var MAX_TOOL_NAMES = 64;
|
|
18384
|
+
var MAX_TOOL_TARGETS = 3;
|
|
18385
|
+
var MAX_TASKS = 64;
|
|
18386
|
+
var TASK_NAME_CHARS = 120;
|
|
18387
|
+
function toolTarget(name, input) {
|
|
18388
|
+
if (name === "Bash") return null;
|
|
18389
|
+
for (const key of ["file_path", "notebook_path", "path", "filePath"]) {
|
|
18390
|
+
const v = input[key];
|
|
18391
|
+
if (typeof v === "string" && v) return v.slice(0, 120);
|
|
18392
|
+
}
|
|
18393
|
+
return null;
|
|
18394
|
+
}
|
|
18135
18395
|
var rootCandidateCache = /* @__PURE__ */ new Map();
|
|
18136
18396
|
function candidateRoots(repoRoot2) {
|
|
18137
18397
|
const cached2 = rootCandidateCache.get(repoRoot2);
|
|
@@ -18139,7 +18399,7 @@ function candidateRoots(repoRoot2) {
|
|
|
18139
18399
|
const norm = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
18140
18400
|
const out = [norm];
|
|
18141
18401
|
try {
|
|
18142
|
-
const real =
|
|
18402
|
+
const real = import_node_fs24.realpathSync.native(norm).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
18143
18403
|
if (real !== norm) out.push(real);
|
|
18144
18404
|
} catch {
|
|
18145
18405
|
}
|
|
@@ -18160,27 +18420,46 @@ function toRepoRelative(path, repoRoot2) {
|
|
|
18160
18420
|
}
|
|
18161
18421
|
return p.replace(/^\/+/, "");
|
|
18162
18422
|
}
|
|
18423
|
+
function isInsideRepo(path, repoRoot2) {
|
|
18424
|
+
const p = path.replace(/\\/g, "/");
|
|
18425
|
+
if (!isAbsolutePath(p)) return true;
|
|
18426
|
+
if (!repoRoot2) return true;
|
|
18427
|
+
return candidateRoots(repoRoot2).some((root) => p === root || p.startsWith(root + "/"));
|
|
18428
|
+
}
|
|
18429
|
+
function isAbsolutePath(p) {
|
|
18430
|
+
return p.startsWith("/") || /^[A-Za-z]:\//.test(p);
|
|
18431
|
+
}
|
|
18163
18432
|
function fold(transcriptPath, opts = {}) {
|
|
18164
18433
|
const result = {
|
|
18165
18434
|
authored: [],
|
|
18166
18435
|
unobserved: [],
|
|
18167
18436
|
commands: [],
|
|
18437
|
+
tools: [],
|
|
18438
|
+
tasks: [],
|
|
18168
18439
|
unknownTypes: [],
|
|
18169
18440
|
coverage: {
|
|
18170
18441
|
recordCounts: {},
|
|
18171
18442
|
totalRecords: 0,
|
|
18172
18443
|
malformed: 0,
|
|
18173
18444
|
subagentFiles: 0,
|
|
18445
|
+
outsideRepo: 0,
|
|
18446
|
+
toolNamesDropped: 0,
|
|
18174
18447
|
dispatched: 0,
|
|
18175
18448
|
userMessages: 0,
|
|
18176
18449
|
subagentSkipped: 0,
|
|
18177
18450
|
compactions: 0,
|
|
18178
18451
|
complete: false
|
|
18179
|
-
}
|
|
18452
|
+
},
|
|
18453
|
+
planApproval: { approvals: 0, activeSinceLastPrompt: false }
|
|
18180
18454
|
};
|
|
18455
|
+
const flow = { seq: 0, lastPrompt: -1, lastApproval: -1, approvals: 0 };
|
|
18181
18456
|
const byPath = /* @__PURE__ */ new Map();
|
|
18182
18457
|
const commandStats = /* @__PURE__ */ new Map();
|
|
18183
18458
|
const pendingByToolUse = /* @__PURE__ */ new Map();
|
|
18459
|
+
const toolStats = /* @__PURE__ */ new Map();
|
|
18460
|
+
const pendingToolName = /* @__PURE__ */ new Map();
|
|
18461
|
+
const taskById = /* @__PURE__ */ new Map();
|
|
18462
|
+
const pendingTaskName = /* @__PURE__ */ new Map();
|
|
18184
18463
|
const unknown = /* @__PURE__ */ new Set();
|
|
18185
18464
|
const ingest = (raw, owner) => {
|
|
18186
18465
|
for (const line of raw.split("\n")) {
|
|
@@ -18199,32 +18478,40 @@ function fold(transcriptPath, opts = {}) {
|
|
|
18199
18478
|
if (type === "system" && record.subtype === "compact_boundary") {
|
|
18200
18479
|
result.coverage.compactions++;
|
|
18201
18480
|
}
|
|
18202
|
-
if (type === "user" && hasUserText(record))
|
|
18203
|
-
|
|
18481
|
+
if (type === "user" && hasUserText(record)) {
|
|
18482
|
+
result.coverage.userMessages++;
|
|
18483
|
+
if (owner === "agent") flow.lastPrompt = flow.seq;
|
|
18484
|
+
}
|
|
18485
|
+
if (owner === "agent") flow.seq++;
|
|
18486
|
+
collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, toolStats, pendingToolName, taskById, pendingTaskName, opts.repoRoot, result.coverage, flow);
|
|
18204
18487
|
}
|
|
18205
18488
|
};
|
|
18206
18489
|
try {
|
|
18207
|
-
if (!(0,
|
|
18208
|
-
ingest((0,
|
|
18490
|
+
if (!(0, import_node_fs24.existsSync)(transcriptPath)) return result;
|
|
18491
|
+
ingest((0, import_node_fs24.readFileSync)(transcriptPath, "utf8"), "agent");
|
|
18209
18492
|
result.coverage.complete = true;
|
|
18210
18493
|
} catch {
|
|
18211
18494
|
return result;
|
|
18212
18495
|
}
|
|
18213
18496
|
try {
|
|
18214
|
-
const sidecarDir = (0,
|
|
18215
|
-
|
|
18497
|
+
const sidecarDir = (0, import_node_path19.join)(
|
|
18498
|
+
(0, import_node_path19.dirname)(transcriptPath),
|
|
18499
|
+
(0, import_node_path19.basename)(transcriptPath).replace(/\.jsonl$/, ""),
|
|
18500
|
+
"subagents"
|
|
18501
|
+
);
|
|
18502
|
+
if ((0, import_node_fs24.existsSync)(sidecarDir)) {
|
|
18216
18503
|
const maxFiles = opts.maxSidecars ?? 200;
|
|
18217
18504
|
const maxBytes = opts.maxSidecarBytes ?? 16 * 1024 * 1024;
|
|
18218
18505
|
const found = [];
|
|
18219
18506
|
const walk = (d, depth) => {
|
|
18220
18507
|
if (depth > 4) return;
|
|
18221
|
-
for (const e of (0,
|
|
18222
|
-
const p = (0,
|
|
18508
|
+
for (const e of (0, import_node_fs24.readdirSync)(d, { withFileTypes: true })) {
|
|
18509
|
+
const p = (0, import_node_path19.join)(d, e.name);
|
|
18223
18510
|
if (e.isDirectory()) {
|
|
18224
18511
|
walk(p, depth + 1);
|
|
18225
18512
|
} else if (e.name.startsWith("agent-") && e.name.endsWith(".jsonl")) {
|
|
18226
18513
|
try {
|
|
18227
|
-
const st = (0,
|
|
18514
|
+
const st = (0, import_node_fs24.statSync)(p);
|
|
18228
18515
|
found.push({ path: p, size: st.size, mtimeMs: st.mtimeMs });
|
|
18229
18516
|
} catch {
|
|
18230
18517
|
result.coverage.malformed++;
|
|
@@ -18241,7 +18528,7 @@ function fold(transcriptPath, opts = {}) {
|
|
|
18241
18528
|
continue;
|
|
18242
18529
|
}
|
|
18243
18530
|
try {
|
|
18244
|
-
ingest((0,
|
|
18531
|
+
ingest((0, import_node_fs24.readFileSync)(f.path, "utf8"), "subagent");
|
|
18245
18532
|
bytes += f.size;
|
|
18246
18533
|
result.coverage.subagentFiles++;
|
|
18247
18534
|
} catch {
|
|
@@ -18254,17 +18541,29 @@ function fold(transcriptPath, opts = {}) {
|
|
|
18254
18541
|
result.authored = [...byPath.values()].sort((a, b) => a.p.localeCompare(b.p));
|
|
18255
18542
|
result.unknownTypes = [...unknown].sort();
|
|
18256
18543
|
result.commands = [...commandStats.entries()].map(([cls, s]) => ({ class: cls, ...s })).sort((a, b) => a.class.localeCompare(b.class));
|
|
18544
|
+
result.tools = [...toolStats.entries()].map(([name, s]) => ({
|
|
18545
|
+
name,
|
|
18546
|
+
runs: s.runs,
|
|
18547
|
+
failed: s.failed,
|
|
18548
|
+
last_status: s.last_status,
|
|
18549
|
+
targets: [...s.targets].map((t) => toRepoRelative(t, opts.repoRoot)).sort()
|
|
18550
|
+
})).sort((a, b) => b.runs - a.runs || a.name.localeCompare(b.name));
|
|
18551
|
+
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));
|
|
18257
18552
|
const authoredPaths = new Set(result.authored.map((a) => a.p));
|
|
18258
18553
|
for (const raw of opts.changedFiles ?? []) {
|
|
18259
18554
|
const p = toRepoRelative(raw, opts.repoRoot);
|
|
18260
18555
|
if (!p || authoredPaths.has(p)) continue;
|
|
18261
18556
|
result.unobserved.push({ p, cause: classifyUnobserved(raw) });
|
|
18262
18557
|
}
|
|
18558
|
+
result.planApproval = {
|
|
18559
|
+
approvals: flow.approvals,
|
|
18560
|
+
activeSinceLastPrompt: flow.lastApproval >= 0 && flow.lastApproval > flow.lastPrompt
|
|
18561
|
+
};
|
|
18263
18562
|
return result;
|
|
18264
18563
|
}
|
|
18265
18564
|
function classifyUnobserved(path) {
|
|
18266
18565
|
try {
|
|
18267
|
-
const st = (0,
|
|
18566
|
+
const st = (0, import_node_fs24.statSync)(path);
|
|
18268
18567
|
if (!st.isFile()) return "unreadable";
|
|
18269
18568
|
} catch {
|
|
18270
18569
|
return "unreadable";
|
|
@@ -18272,7 +18571,7 @@ function classifyUnobserved(path) {
|
|
|
18272
18571
|
if (/\.(png|jpg|jpeg|gif|pdf|zip|woff2?|ico|mp4)$/i.test(path)) return "binary";
|
|
18273
18572
|
return "no_edit_record";
|
|
18274
18573
|
}
|
|
18275
|
-
function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, repoRoot2, tally) {
|
|
18574
|
+
function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse, toolStats, pendingToolName, taskById, pendingTaskName, repoRoot2, tally, flow) {
|
|
18276
18575
|
const message = record.message;
|
|
18277
18576
|
const content = message?.content ?? record.content;
|
|
18278
18577
|
const blocks = Array.isArray(content) ? content : content && typeof content === "object" ? [content] : [];
|
|
@@ -18281,8 +18580,38 @@ function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse
|
|
|
18281
18580
|
if (blockType === "tool_use") {
|
|
18282
18581
|
const name = String(block.name ?? "");
|
|
18283
18582
|
const input = block.input ?? {};
|
|
18583
|
+
if (name && toolStats.size < MAX_TOOL_NAMES) {
|
|
18584
|
+
const prev = toolStats.get(name) ?? { runs: 0, failed: 0, last_status: null, targets: /* @__PURE__ */ new Set() };
|
|
18585
|
+
prev.targets = prev.targets ?? /* @__PURE__ */ new Set();
|
|
18586
|
+
if (prev.targets.size < MAX_TOOL_TARGETS) {
|
|
18587
|
+
const target = toolTarget(name, input);
|
|
18588
|
+
if (target) prev.targets.add(target);
|
|
18589
|
+
}
|
|
18590
|
+
toolStats.set(name, { runs: prev.runs + 1, failed: prev.failed, last_status: null, targets: prev.targets });
|
|
18591
|
+
const toolId = typeof block.id === "string" ? block.id : null;
|
|
18592
|
+
if (toolId) pendingToolName.set(toolId, name);
|
|
18593
|
+
} else if (name && tally) {
|
|
18594
|
+
tally.toolNamesDropped += 1;
|
|
18595
|
+
}
|
|
18596
|
+
if (name === "TaskCreate") {
|
|
18597
|
+
const subject = typeof input.subject === "string" ? input.subject : "";
|
|
18598
|
+
const taskId = typeof block.id === "string" ? block.id : null;
|
|
18599
|
+
if (subject && taskId) pendingTaskName.set(taskId, subject.slice(0, TASK_NAME_CHARS));
|
|
18600
|
+
}
|
|
18601
|
+
if (name === "TaskUpdate") {
|
|
18602
|
+
const id = typeof input.taskId === "string" ? input.taskId : "";
|
|
18603
|
+
const status = typeof input.status === "string" ? input.status : "";
|
|
18604
|
+
if (id && status) {
|
|
18605
|
+
const entry = taskById.get(id);
|
|
18606
|
+
taskById.set(id, { name: entry?.name ?? `#${id}`, status });
|
|
18607
|
+
}
|
|
18608
|
+
}
|
|
18284
18609
|
if (EDIT_TOOLS.has(name)) {
|
|
18285
18610
|
const rawPath = typeof input.notebook_path === "string" ? input.notebook_path : typeof input.file_path === "string" ? input.file_path : null;
|
|
18611
|
+
if (rawPath && !isInsideRepo(rawPath, repoRoot2)) {
|
|
18612
|
+
if (tally) tally.outsideRepo += 1;
|
|
18613
|
+
continue;
|
|
18614
|
+
}
|
|
18286
18615
|
const path = rawPath ? toRepoRelative(rawPath, repoRoot2) : null;
|
|
18287
18616
|
if (path) {
|
|
18288
18617
|
const entry = byPath.get(path) ?? { p: path, h: 0, a: 0, d: 0, owner };
|
|
@@ -18316,6 +18645,38 @@ function collectFromRecord(record, owner, byPath, commandStats, pendingByToolUse
|
|
|
18316
18645
|
}
|
|
18317
18646
|
if (blockType === "tool_result") {
|
|
18318
18647
|
const id = typeof block.tool_use_id === "string" ? block.tool_use_id : null;
|
|
18648
|
+
const taskName = id ? pendingTaskName.get(id) : void 0;
|
|
18649
|
+
if (taskName) {
|
|
18650
|
+
pendingTaskName.delete(id);
|
|
18651
|
+
const body = typeof block.content === "string" ? block.content : "";
|
|
18652
|
+
const created = /Task #(\d+)/.exec(body);
|
|
18653
|
+
if (created && taskById.size < MAX_TASKS) {
|
|
18654
|
+
taskById.set(created[1], { name: taskName, status: taskById.get(created[1])?.status ?? "created" });
|
|
18655
|
+
}
|
|
18656
|
+
}
|
|
18657
|
+
const toolName = id ? pendingToolName.get(id) : void 0;
|
|
18658
|
+
if (toolName === "ExitPlanMode" && flow && block.is_error !== true) {
|
|
18659
|
+
const body = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => typeof c.text === "string" ? c.text : "").join(" ") : "";
|
|
18660
|
+
if (/approved your plan/i.test(body)) {
|
|
18661
|
+
flow.lastApproval = flow.seq;
|
|
18662
|
+
flow.approvals += 1;
|
|
18663
|
+
}
|
|
18664
|
+
}
|
|
18665
|
+
if (toolName) {
|
|
18666
|
+
pendingToolName.delete(id);
|
|
18667
|
+
const prevTool = toolStats.get(toolName);
|
|
18668
|
+
if (prevTool) {
|
|
18669
|
+
const failed = block.is_error === true;
|
|
18670
|
+
toolStats.set(toolName, {
|
|
18671
|
+
runs: prevTool.runs,
|
|
18672
|
+
failed: prevTool.failed + (failed ? 1 : 0),
|
|
18673
|
+
last_status: block.is_error === true ? 1 : block.is_error === false ? 0 : null,
|
|
18674
|
+
// Carried, not rebuilt: the targets were collected on the `tool_use`
|
|
18675
|
+
// side and dropping them here would empty the ledger on every result.
|
|
18676
|
+
targets: prevTool.targets
|
|
18677
|
+
});
|
|
18678
|
+
}
|
|
18679
|
+
}
|
|
18319
18680
|
const cls = id ? pendingByToolUse.get(id) : void 0;
|
|
18320
18681
|
if (!cls) continue;
|
|
18321
18682
|
pendingByToolUse.delete(id);
|
|
@@ -18358,8 +18719,13 @@ function checkConservation(changedFiles, result, repoRoot2) {
|
|
|
18358
18719
|
// src/commands/analyze/phases/06-evidence.ts
|
|
18359
18720
|
async function evidence(run) {
|
|
18360
18721
|
const { opts } = run;
|
|
18361
|
-
const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath } = run;
|
|
18722
|
+
const { actionSummary, allForReview, analyzable, assistantResponse, authorshipIsObservable, baseline, baselineSessionId, hasRecentCommitFiles, reviewable, securityFiles, sessionAuthoredCode, transcriptPath, turnAuthoredCode } = run;
|
|
18362
18723
|
let { analysisMode, earlyFold } = run;
|
|
18724
|
+
const recordFlip = (stage) => {
|
|
18725
|
+
if (run.modeDecision) run.modeDecision = { ...run.modeDecision, resolved: "plan", flip: stage };
|
|
18726
|
+
logEvent("mode_flipped", { stage, to: "plan" });
|
|
18727
|
+
};
|
|
18728
|
+
const planWorthy = !!assistantResponse && !turnAuthoredCode;
|
|
18363
18729
|
let staticResults = {
|
|
18364
18730
|
tool: "@codacy/analysis-cli",
|
|
18365
18731
|
findings: [],
|
|
@@ -18379,8 +18745,9 @@ async function evidence(run) {
|
|
|
18379
18745
|
const debounceSeconds = parseInt(opts.debounce, 10);
|
|
18380
18746
|
const debounceSkip = checkDebounce(debounceSeconds, baselineSessionId);
|
|
18381
18747
|
if (debounceSkip) {
|
|
18382
|
-
if (
|
|
18748
|
+
if (planWorthy) {
|
|
18383
18749
|
analysisMode = "plan";
|
|
18750
|
+
recordFlip("debounce");
|
|
18384
18751
|
} else {
|
|
18385
18752
|
await passAndExit(run, debounceSkip, "debounce");
|
|
18386
18753
|
}
|
|
@@ -18389,8 +18756,9 @@ async function evidence(run) {
|
|
|
18389
18756
|
const allCheckable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable, ...securityFiles]));
|
|
18390
18757
|
const mtimeSkip = checkMtime(allCheckable, hasRecentCommitFiles, baselineSessionId);
|
|
18391
18758
|
if (mtimeSkip) {
|
|
18392
|
-
if (
|
|
18759
|
+
if (planWorthy) {
|
|
18393
18760
|
analysisMode = "plan";
|
|
18761
|
+
recordFlip("mtime");
|
|
18394
18762
|
} else {
|
|
18395
18763
|
await passAndExit(run, mtimeSkip, "no-delta-since-last-review");
|
|
18396
18764
|
}
|
|
@@ -18401,8 +18769,9 @@ async function evidence(run) {
|
|
|
18401
18769
|
const allCheckable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...reviewable, ...securityFiles]));
|
|
18402
18770
|
const hashResult = checkContentHash(allCheckable, baselineSessionId);
|
|
18403
18771
|
if (hashResult.skip) {
|
|
18404
|
-
if (
|
|
18772
|
+
if (planWorthy) {
|
|
18405
18773
|
analysisMode = "plan";
|
|
18774
|
+
recordFlip("content-hash");
|
|
18406
18775
|
} else {
|
|
18407
18776
|
await passAndExit(run, hashResult.skip, "no-delta-since-last-review");
|
|
18408
18777
|
}
|
|
@@ -18464,8 +18833,9 @@ async function evidence(run) {
|
|
|
18464
18833
|
maxTotalBytes: parseInt(opts.maxTotalSize, 10)
|
|
18465
18834
|
});
|
|
18466
18835
|
if (codeDelta.files.length === 0 && staticResults.findings.length === 0) {
|
|
18467
|
-
if (
|
|
18836
|
+
if (planWorthy) {
|
|
18468
18837
|
analysisMode = "plan";
|
|
18838
|
+
recordFlip("empty-after-scoping");
|
|
18469
18839
|
} else {
|
|
18470
18840
|
await passAndExit(
|
|
18471
18841
|
run,
|
|
@@ -18485,32 +18855,32 @@ async function evidence(run) {
|
|
|
18485
18855
|
snapshotResult = generateSnapshotDiffs(codeDelta.files);
|
|
18486
18856
|
}
|
|
18487
18857
|
currentCommit = getCurrentCommit();
|
|
18488
|
-
iteration =
|
|
18858
|
+
iteration = readIteration(currentCommit);
|
|
18489
18859
|
}
|
|
18490
18860
|
}
|
|
18491
18861
|
if (analysisMode === "plan") {
|
|
18492
18862
|
recordAnalysisStart();
|
|
18493
18863
|
currentCommit = getCurrentCommit();
|
|
18494
|
-
iteration =
|
|
18864
|
+
iteration = readIteration(currentCommit);
|
|
18495
18865
|
}
|
|
18496
18866
|
Object.assign(run, { analysisMode, codeDelta, contentHash, currentCommit, earlyFold, iteration, snapshotResult, staticResults });
|
|
18497
18867
|
}
|
|
18498
18868
|
|
|
18499
18869
|
// src/lib/cache-cleanup.ts
|
|
18500
|
-
var
|
|
18501
|
-
var
|
|
18870
|
+
var import_node_fs25 = require("node:fs");
|
|
18871
|
+
var import_node_path20 = require("node:path");
|
|
18502
18872
|
var CACHE_TTL_DAYS = 7;
|
|
18503
18873
|
function pruneStaleCache() {
|
|
18504
18874
|
try {
|
|
18505
18875
|
const dir = projectPath(CACHE_DIR);
|
|
18506
18876
|
const cutoff = Date.now() - CACHE_TTL_DAYS * 24 * 3600 * 1e3;
|
|
18507
|
-
for (const entry of (0,
|
|
18877
|
+
for (const entry of (0, import_node_fs25.readdirSync)(dir)) {
|
|
18508
18878
|
if (!entry.startsWith("pending-")) continue;
|
|
18509
|
-
const path = (0,
|
|
18879
|
+
const path = (0, import_node_path20.join)(dir, entry);
|
|
18510
18880
|
try {
|
|
18511
|
-
const stat3 = (0,
|
|
18881
|
+
const stat3 = (0, import_node_fs25.statSync)(path);
|
|
18512
18882
|
if (stat3.mtimeMs < cutoff) {
|
|
18513
|
-
(0,
|
|
18883
|
+
(0, import_node_fs25.unlinkSync)(path);
|
|
18514
18884
|
logEvent("cache_entry_pruned", {
|
|
18515
18885
|
path: entry,
|
|
18516
18886
|
age_days: Math.round((Date.now() - stat3.mtimeMs) / 864e5)
|
|
@@ -18524,7 +18894,7 @@ function pruneStaleCache() {
|
|
|
18524
18894
|
}
|
|
18525
18895
|
|
|
18526
18896
|
// src/lib/context-files.ts
|
|
18527
|
-
var
|
|
18897
|
+
var import_node_fs26 = require("node:fs");
|
|
18528
18898
|
var MAX_CONTEXT_FILES = 10;
|
|
18529
18899
|
var MAX_CONTEXT_FILE_BYTES = 10240;
|
|
18530
18900
|
var MAX_CONTEXT_TOTAL_BYTES = 51200;
|
|
@@ -18539,8 +18909,13 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
18539
18909
|
logEvent("context_file_skipped", { path: filePath, reason: "verity_owned" });
|
|
18540
18910
|
continue;
|
|
18541
18911
|
}
|
|
18912
|
+
const safePath = resolveInside(process.cwd(), filePath);
|
|
18913
|
+
if (!safePath) {
|
|
18914
|
+
logEvent("context_file_skipped", { path: filePath, reason: "outside_repo" });
|
|
18915
|
+
continue;
|
|
18916
|
+
}
|
|
18542
18917
|
try {
|
|
18543
|
-
const content = (0,
|
|
18918
|
+
const content = (0, import_node_fs26.readFileSync)(safePath, "utf8");
|
|
18544
18919
|
const bytes = Buffer.byteLength(content);
|
|
18545
18920
|
if (bytes > MAX_CONTEXT_FILE_BYTES) {
|
|
18546
18921
|
logEvent("context_file_skipped", { path: filePath, reason: "too_large", bytes });
|
|
@@ -18587,7 +18962,8 @@ function gatherContextFiles(contextPaths, deltaFiles) {
|
|
|
18587
18962
|
// src/commands/analyze/phases/07-context-files.ts
|
|
18588
18963
|
async function contextFiles(run) {
|
|
18589
18964
|
const { codeDelta, contextFilePaths } = run;
|
|
18590
|
-
const
|
|
18965
|
+
const { kept: externalContext } = partitionVerityOwned(contextFilePaths ?? []);
|
|
18966
|
+
const contextFiles2 = gatherContextFiles(externalContext, codeDelta.files);
|
|
18591
18967
|
for (const f of codeDelta.files) {
|
|
18592
18968
|
f.role = "delta";
|
|
18593
18969
|
}
|
|
@@ -18601,8 +18977,8 @@ async function contextFiles(run) {
|
|
|
18601
18977
|
|
|
18602
18978
|
// src/lib/seed-runner.ts
|
|
18603
18979
|
var import_promises11 = require("node:fs/promises");
|
|
18604
|
-
var
|
|
18605
|
-
var
|
|
18980
|
+
var import_node_fs27 = require("node:fs");
|
|
18981
|
+
var import_node_path21 = require("node:path");
|
|
18606
18982
|
var import_yaml2 = __toESM(require_dist());
|
|
18607
18983
|
|
|
18608
18984
|
// src/lib/seed.ts
|
|
@@ -18841,7 +19217,7 @@ function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
|
18841
19217
|
return fm;
|
|
18842
19218
|
}
|
|
18843
19219
|
async function runSeed(opts) {
|
|
18844
|
-
if (!(0,
|
|
19220
|
+
if (!(0, import_node_fs27.existsSync)(STANDARD_FILE)) {
|
|
18845
19221
|
return { created: 0, failed: 0, skipped: "no_standard", candidates: [] };
|
|
18846
19222
|
}
|
|
18847
19223
|
let standardDoc;
|
|
@@ -18853,7 +19229,7 @@ async function runSeed(opts) {
|
|
|
18853
19229
|
}
|
|
18854
19230
|
const knowledgeSpec = standardDoc.knowledge_spec ?? {};
|
|
18855
19231
|
let readmeContent;
|
|
18856
|
-
if ((0,
|
|
19232
|
+
if ((0, import_node_fs27.existsSync)("README.md")) {
|
|
18857
19233
|
try {
|
|
18858
19234
|
readmeContent = await (0, import_promises11.readFile)("README.md", "utf-8");
|
|
18859
19235
|
} catch {
|
|
@@ -18861,7 +19237,7 @@ async function runSeed(opts) {
|
|
|
18861
19237
|
}
|
|
18862
19238
|
let claudeMdContent;
|
|
18863
19239
|
for (const p of ["CLAUDE.md", ".claude/CLAUDE.md"]) {
|
|
18864
|
-
if ((0,
|
|
19240
|
+
if ((0, import_node_fs27.existsSync)(p)) {
|
|
18865
19241
|
try {
|
|
18866
19242
|
claudeMdContent = await (0, import_promises11.readFile)(p, "utf-8");
|
|
18867
19243
|
break;
|
|
@@ -18884,8 +19260,8 @@ async function runSeed(opts) {
|
|
|
18884
19260
|
if (candidates.length === 0) {
|
|
18885
19261
|
return { created: 0, failed: 0, skipped: "no_candidates", candidates: [] };
|
|
18886
19262
|
}
|
|
18887
|
-
const overviewPath = (0,
|
|
18888
|
-
if ((0,
|
|
19263
|
+
const overviewPath = (0, import_node_path21.join)(MEMORY_DIR, "domain", "project-overview.md");
|
|
19264
|
+
if ((0, import_node_fs27.existsSync)(overviewPath) && !opts.force) {
|
|
18889
19265
|
return { created: 0, failed: 0, skipped: "already_seeded", candidates };
|
|
18890
19266
|
}
|
|
18891
19267
|
if (opts.dryRun) {
|
|
@@ -18920,9 +19296,14 @@ async function runSeed(opts) {
|
|
|
18920
19296
|
}
|
|
18921
19297
|
const nodeId = res.data.node_id;
|
|
18922
19298
|
const filePathRel = res.data.file_path;
|
|
18923
|
-
const targetPath = (
|
|
19299
|
+
const targetPath = resolveInside(MEMORY_DIR, filePathRel);
|
|
19300
|
+
if (!targetPath) {
|
|
19301
|
+
opts.onFailed?.(c, `Server returned an out-of-bounds file_path (${String(filePathRel)}); refusing to write outside the memory directory.`);
|
|
19302
|
+
failed++;
|
|
19303
|
+
continue;
|
|
19304
|
+
}
|
|
18924
19305
|
try {
|
|
18925
|
-
await (0, import_promises11.mkdir)((0,
|
|
19306
|
+
await (0, import_promises11.mkdir)((0, import_node_path21.dirname)(targetPath), { recursive: true });
|
|
18926
19307
|
await (0, import_promises11.writeFile)(targetPath, renderNodeMarkdown(c, nodeId, createdAt));
|
|
18927
19308
|
created++;
|
|
18928
19309
|
opts.onCreated?.(nodeId, filePathRel, c);
|
|
@@ -18935,8 +19316,8 @@ async function runSeed(opts) {
|
|
|
18935
19316
|
}
|
|
18936
19317
|
|
|
18937
19318
|
// src/commands/analyze/phases/08-memory-manifest.ts
|
|
18938
|
-
var
|
|
18939
|
-
var
|
|
19319
|
+
var import_node_fs28 = require("node:fs");
|
|
19320
|
+
var import_node_path22 = require("node:path");
|
|
18940
19321
|
async function memoryManifest(run) {
|
|
18941
19322
|
const { globals } = run;
|
|
18942
19323
|
const { serviceUrl, token } = run;
|
|
@@ -18946,9 +19327,9 @@ async function memoryManifest(run) {
|
|
|
18946
19327
|
let autoSeedNotice = null;
|
|
18947
19328
|
try {
|
|
18948
19329
|
await ensureMemoryDir();
|
|
18949
|
-
const seedMarker = (0,
|
|
18950
|
-
const hasStandard = (0,
|
|
18951
|
-
const alreadyTried = (0,
|
|
19330
|
+
const seedMarker = (0, import_node_path22.join)(VERITY_DIR, ".seeded");
|
|
19331
|
+
const hasStandard = (0, import_node_fs28.existsSync)(STANDARD_FILE);
|
|
19332
|
+
const alreadyTried = (0, import_node_fs28.existsSync)(seedMarker);
|
|
18952
19333
|
if (hasStandard && !alreadyTried) {
|
|
18953
19334
|
const preManifest = await buildManifest();
|
|
18954
19335
|
if (preManifest.nodes.length === 0) {
|
|
@@ -18961,7 +19342,7 @@ async function memoryManifest(run) {
|
|
|
18961
19342
|
dryRun: false
|
|
18962
19343
|
});
|
|
18963
19344
|
if (seedResult.created > 0) {
|
|
18964
|
-
(0,
|
|
19345
|
+
(0, import_node_fs28.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} created=${seedResult.created}
|
|
18965
19346
|
`);
|
|
18966
19347
|
autoSeedNotice = `Seeded ${seedResult.created} knowledge node(s) from your existing Standard (one-time).`;
|
|
18967
19348
|
logEvent("auto_seed_ran", {
|
|
@@ -18969,7 +19350,7 @@ async function memoryManifest(run) {
|
|
|
18969
19350
|
failed: seedResult.failed
|
|
18970
19351
|
});
|
|
18971
19352
|
} else if (seedResult.skipped === "already_seeded") {
|
|
18972
|
-
(0,
|
|
19353
|
+
(0, import_node_fs28.writeFileSync)(seedMarker, `${(/* @__PURE__ */ new Date()).toISOString()} skipped=already_seeded
|
|
18973
19354
|
`);
|
|
18974
19355
|
} else {
|
|
18975
19356
|
logEvent("auto_seed_noop", {
|
|
@@ -19064,7 +19445,7 @@ function computeIncrement(reviewedPaths, hashOf, priorAuthored) {
|
|
|
19064
19445
|
}
|
|
19065
19446
|
|
|
19066
19447
|
// src/commands/analyze/phases/10-working-memory.ts
|
|
19067
|
-
var
|
|
19448
|
+
var import_node_path23 = require("node:path");
|
|
19068
19449
|
async function workingMemory(run) {
|
|
19069
19450
|
const { opts } = run;
|
|
19070
19451
|
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run;
|
|
@@ -19076,7 +19457,7 @@ async function workingMemory(run) {
|
|
|
19076
19457
|
const priorState = foldForMarks(memorySession.d);
|
|
19077
19458
|
incrementReport = computeIncrement(
|
|
19078
19459
|
allForReview,
|
|
19079
|
-
(p) => fileHash((0,
|
|
19460
|
+
(p) => fileHash((0, import_node_path23.join)(repoRoot(), p)),
|
|
19080
19461
|
priorState.authored_all.map((a) => ({
|
|
19081
19462
|
path: a.path,
|
|
19082
19463
|
hash_at_last_verdict: a.hash_at_last_verdict
|
|
@@ -19157,6 +19538,54 @@ async function workingMemory(run) {
|
|
|
19157
19538
|
Object.assign(run, { incrementReport, memory, memorySession, reachability });
|
|
19158
19539
|
}
|
|
19159
19540
|
|
|
19541
|
+
// src/lib/note-budget.ts
|
|
19542
|
+
var import_node_fs29 = require("node:fs");
|
|
19543
|
+
var ADVISORY_BUDGET = { PASS: 1, WARN: 2 };
|
|
19544
|
+
var EPISODE_STALE_SECONDS = 30 * 60;
|
|
19545
|
+
var FRESH = { delivered: 0, tasksCompleted: 0, ts: 0 };
|
|
19546
|
+
function resolveEpisode(prev, signals) {
|
|
19547
|
+
if (!prev) return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19548
|
+
if (signals.humanSpoke) return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19549
|
+
if (signals.rawFail) return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19550
|
+
if (prev.tasksCompleted !== signals.tasksCompleted) {
|
|
19551
|
+
return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19552
|
+
}
|
|
19553
|
+
if (prev.ts > 0 && signals.now - prev.ts > EPISODE_STALE_SECONDS) {
|
|
19554
|
+
return { ...FRESH, tasksCompleted: signals.tasksCompleted, ts: signals.now };
|
|
19555
|
+
}
|
|
19556
|
+
return prev;
|
|
19557
|
+
}
|
|
19558
|
+
function advisoryBudgetSpent(episode, rawDecision) {
|
|
19559
|
+
const budget = ADVISORY_BUDGET[rawDecision] ?? ADVISORY_BUDGET.WARN;
|
|
19560
|
+
return episode.delivered >= budget;
|
|
19561
|
+
}
|
|
19562
|
+
function readAdvisoryEpisode(sessionId) {
|
|
19563
|
+
const file = scopedFile(ADVISORY_EPISODE_FILE, sessionId);
|
|
19564
|
+
if (!(0, import_node_fs29.existsSync)(file)) return null;
|
|
19565
|
+
try {
|
|
19566
|
+
const o = JSON.parse((0, import_node_fs29.readFileSync)(file, "utf-8")) ?? {};
|
|
19567
|
+
const delivered = typeof o.delivered === "number" ? o.delivered : NaN;
|
|
19568
|
+
if (isNaN(delivered)) return null;
|
|
19569
|
+
return {
|
|
19570
|
+
delivered,
|
|
19571
|
+
tasksCompleted: typeof o.tasksCompleted === "number" ? o.tasksCompleted : 0,
|
|
19572
|
+
ts: typeof o.ts === "number" ? o.ts : 0
|
|
19573
|
+
};
|
|
19574
|
+
} catch {
|
|
19575
|
+
return null;
|
|
19576
|
+
}
|
|
19577
|
+
}
|
|
19578
|
+
function writeAdvisoryEpisode(episode, sessionId) {
|
|
19579
|
+
try {
|
|
19580
|
+
(0, import_node_fs29.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
19581
|
+
(0, import_node_fs29.writeFileSync)(
|
|
19582
|
+
scopedFile(ADVISORY_EPISODE_FILE, sessionId),
|
|
19583
|
+
JSON.stringify({ v: 1, ...episode })
|
|
19584
|
+
);
|
|
19585
|
+
} catch {
|
|
19586
|
+
}
|
|
19587
|
+
}
|
|
19588
|
+
|
|
19160
19589
|
// src/lib/run-mode.ts
|
|
19161
19590
|
function parseAutonomousEnv(raw) {
|
|
19162
19591
|
if (raw === void 0) return void 0;
|
|
@@ -19250,7 +19679,13 @@ async function buildRequest(run) {
|
|
|
19250
19679
|
excluded_by_reason: excludedByReason,
|
|
19251
19680
|
// was the transcript itself truncated? The 256 KB window means "this turn"
|
|
19252
19681
|
// can quietly mean "the last 256 KB of it".
|
|
19253
|
-
transcript_windowed: actionSummary?.transcript_windowed ?? null
|
|
19682
|
+
transcript_windowed: actionSummary?.transcript_windowed ?? null,
|
|
19683
|
+
// The advisory budget's fleet counter-metric (note-budget.ts): deliveries in
|
|
19684
|
+
// the episode as of the PREVIOUS turn — this runs before phase 13 updates
|
|
19685
|
+
// the state, so the number is one turn lagged by construction. The
|
|
19686
|
+
// degenerate win for the budget is a dead channel that looks like clean
|
|
19687
|
+
// code; this is what makes "did delivery rate collapse" a query.
|
|
19688
|
+
advisory_delivered_prior: readAdvisoryEpisode(run.baselineSessionId)?.delivered ?? 0
|
|
19254
19689
|
};
|
|
19255
19690
|
const requestBody = {
|
|
19256
19691
|
coverage_telemetry: coverageTelemetry,
|
|
@@ -19309,6 +19744,8 @@ async function buildRequest(run) {
|
|
|
19309
19744
|
authored_since_verdict: memorySession ? foldDossier(memorySession.d).authored_all.filter((a) => a.hash_now !== a.hash_at_last_verdict).map((a) => a.path) : [],
|
|
19310
19745
|
unobserved: foldResult?.unobserved ?? [],
|
|
19311
19746
|
commands: foldResult?.commands ?? [],
|
|
19747
|
+
tools: foldResult?.tools ?? [],
|
|
19748
|
+
tasks: foldResult?.tasks ?? [],
|
|
19312
19749
|
unknown_types: foldResult?.unknownTypes ?? [],
|
|
19313
19750
|
coverage: foldResult?.coverage ?? { recordCounts: {}, totalRecords: 0, malformed: 0, subagentFiles: 0, subagentSkipped: 0, complete: false },
|
|
19314
19751
|
// INV-19, computed client-side and sent so a conservation failure is
|
|
@@ -19387,7 +19824,8 @@ async function buildRequest(run) {
|
|
|
19387
19824
|
}
|
|
19388
19825
|
const noHumanPrompt = (conversation?.prompts?.length ?? 0) === 0;
|
|
19389
19826
|
const w4Task = noHumanPrompt && isExplicitlyAutonomous() ? resolveTaskContext() : null;
|
|
19390
|
-
const
|
|
19827
|
+
const planApprovalActive = foldResult?.planApproval?.activeSinceLastPrompt === true;
|
|
19828
|
+
const hasIntent = (conversation?.prompts?.length ?? 0) > 0 || specs.length > 0 || plans.length > 0 || !!assistantResponse || !!w4Task || planApprovalActive;
|
|
19391
19829
|
if (hasIntent) {
|
|
19392
19830
|
const intentContext = {};
|
|
19393
19831
|
if (conversation && conversation.prompts.length > 0) {
|
|
@@ -19419,6 +19857,10 @@ async function buildRequest(run) {
|
|
|
19419
19857
|
intentContext.user_prompt = w4Task.goal;
|
|
19420
19858
|
logEvent("w4_issue_anchor", { issue: w4Task.number, via: w4Task.via });
|
|
19421
19859
|
}
|
|
19860
|
+
if (planApprovalActive) {
|
|
19861
|
+
intentContext.plan_approved = true;
|
|
19862
|
+
logEvent("plan_approval_carried", { approvals: foldResult.planApproval.approvals });
|
|
19863
|
+
}
|
|
19422
19864
|
if (assistantResponse) {
|
|
19423
19865
|
const cap = analysisMode === "plan" ? MAX_ASSISTANT_RESPONSE_CHARS_PLAN : MAX_ASSISTANT_RESPONSE_CHARS_DEFAULT;
|
|
19424
19866
|
intentContext.assistant_response = assistantResponse.length > cap ? assistantResponse.slice(0, cap) : assistantResponse;
|
|
@@ -19438,14 +19880,14 @@ async function buildRequest(run) {
|
|
|
19438
19880
|
}
|
|
19439
19881
|
|
|
19440
19882
|
// src/lib/offline.ts
|
|
19441
|
-
var
|
|
19883
|
+
var import_node_fs30 = require("node:fs");
|
|
19442
19884
|
var import_node_crypto11 = require("node:crypto");
|
|
19443
19885
|
function cacheRequest(body) {
|
|
19444
19886
|
try {
|
|
19445
|
-
(0,
|
|
19887
|
+
(0, import_node_fs30.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
19446
19888
|
const suffix = (0, import_node_crypto11.randomBytes)(4).toString("hex");
|
|
19447
19889
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
19448
|
-
(0,
|
|
19890
|
+
(0, import_node_fs30.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(redactRequest(body)));
|
|
19449
19891
|
} catch {
|
|
19450
19892
|
}
|
|
19451
19893
|
}
|
|
@@ -19564,10 +20006,10 @@ async function transmit(run) {
|
|
|
19564
20006
|
}
|
|
19565
20007
|
|
|
19566
20008
|
// src/commands/analyze/phases/13-reconcile.ts
|
|
19567
|
-
var
|
|
19568
|
-
var
|
|
20009
|
+
var import_node_fs31 = require("node:fs");
|
|
20010
|
+
var import_node_path24 = require("node:path");
|
|
19569
20011
|
async function reconcile(run) {
|
|
19570
|
-
const { actionSummary, allChanged, analyzable, baseline, codeDelta, contentHash, conversation, decision, memory, memorySession, response, reviewable, securityFiles, turnId } = run;
|
|
20012
|
+
const { actionSummary, allChanged, analyzable, baseline, baselineSessionId, codeDelta, contentHash, conversation, decision, foldResult, memory, memorySession, response, reviewable, securityFiles, turnId } = run;
|
|
19571
20013
|
const sentPaths = codeDelta.files.map((f) => f.path);
|
|
19572
20014
|
let openElsewhere = [];
|
|
19573
20015
|
if (memorySession) {
|
|
@@ -19575,7 +20017,7 @@ async function reconcile(run) {
|
|
|
19575
20017
|
const st = foldDossier(memorySession.d);
|
|
19576
20018
|
openElsewhere = openBlockingElsewhere(st.statements, sentPaths, (file, line) => {
|
|
19577
20019
|
try {
|
|
19578
|
-
const src = (0,
|
|
20020
|
+
const src = (0, import_node_fs31.readFileSync)((0, import_node_path24.join)(repoRoot(), file), "utf8").split("\n");
|
|
19579
20021
|
const at = src[line - 1];
|
|
19580
20022
|
return at === void 0 ? null : lineSha(at);
|
|
19581
20023
|
} catch {
|
|
@@ -19585,6 +20027,7 @@ async function reconcile(run) {
|
|
|
19585
20027
|
} catch {
|
|
19586
20028
|
}
|
|
19587
20029
|
}
|
|
20030
|
+
const { kept: externalChanged, owned: verityOwned } = partitionVerityOwned(allChanged);
|
|
19588
20031
|
const reviewCoverage = {
|
|
19589
20032
|
reviewed: sentPaths,
|
|
19590
20033
|
// Declared drops from the stages that DO report themselves today. The other
|
|
@@ -19626,11 +20069,20 @@ async function reconcile(run) {
|
|
|
19626
20069
|
stage: "baseline-scoping",
|
|
19627
20070
|
kind: "policy"
|
|
19628
20071
|
})),
|
|
20072
|
+
// ⚠ VERITY'S OWN FILES, named as such — not laundered into the
|
|
20073
|
+
// extension bucket below, where "we do not review our own installer's
|
|
20074
|
+
// dirt" would read as "a changed README". See self-scope.ts.
|
|
20075
|
+
...verityOwned.map((path) => ({
|
|
20076
|
+
path,
|
|
20077
|
+
reason: "verity-owned",
|
|
20078
|
+
stage: "self-scope",
|
|
20079
|
+
kind: "policy"
|
|
20080
|
+
})),
|
|
19629
20081
|
// The extension allowlist. POLICY: a changed README was never going to be
|
|
19630
20082
|
// reviewed, and calling that a coverage gap would downgrade nearly every
|
|
19631
20083
|
// PASS to WARN until WARN meant nothing. Recorded so the ledger balances and
|
|
19632
20084
|
// so "what did Verity ignore entirely" is answerable.
|
|
19633
|
-
...
|
|
20085
|
+
...externalChanged.filter((p) => !analyzable.includes(p) && !reviewable.includes(p) && !securityFiles.includes(p)).map((path) => ({
|
|
19634
20086
|
path,
|
|
19635
20087
|
reason: "not-a-reviewed-file-type",
|
|
19636
20088
|
stage: "extension-allowlist",
|
|
@@ -19667,6 +20119,29 @@ async function reconcile(run) {
|
|
|
19667
20119
|
decision
|
|
19668
20120
|
});
|
|
19669
20121
|
}
|
|
20122
|
+
const episodeSignals = {
|
|
20123
|
+
humanSpoke: (conversation?.prompts?.length ?? 0) > 0,
|
|
20124
|
+
rawFail: decision === "FAIL",
|
|
20125
|
+
tasksCompleted: (foldResult?.tasks ?? []).filter((t) => t.status === "completed").length,
|
|
20126
|
+
now: Math.floor(Date.now() / 1e3)
|
|
20127
|
+
};
|
|
20128
|
+
let episode = resolveEpisode(readAdvisoryEpisode(baselineSessionId), episodeSignals);
|
|
20129
|
+
const contentClass = classifyChannelContent(channelInputFrom(response));
|
|
20130
|
+
const wouldCarryAdvisory = contentClass.advisory || openElsewhere.length > 0;
|
|
20131
|
+
if (decision !== "FAIL" && !silenced && wouldCarryAdvisory && !contentClass.refusal && !contentClass.intentFlag && advisoryBudgetSpent(episode, decision)) {
|
|
20132
|
+
silenced = "note-budget";
|
|
20133
|
+
logEvent("channel_silenced", {
|
|
20134
|
+
reason: silenced,
|
|
20135
|
+
run_id: response.run_id ?? turnId,
|
|
20136
|
+
decision,
|
|
20137
|
+
episode_delivered: episode.delivered
|
|
20138
|
+
});
|
|
20139
|
+
}
|
|
20140
|
+
const deliveringAdvisory = decision !== "FAIL" && !silenced && wouldCarryAdvisory;
|
|
20141
|
+
writeAdvisoryEpisode(
|
|
20142
|
+
{ ...episode, delivered: episode.delivered + (deliveringAdvisory ? 1 : 0), ts: episodeSignals.now },
|
|
20143
|
+
baselineSessionId
|
|
20144
|
+
);
|
|
19670
20145
|
let intentRepeatCount = 0;
|
|
19671
20146
|
const priorPendingFingerprints = memorySession ? (() => {
|
|
19672
20147
|
try {
|
|
@@ -19682,6 +20157,11 @@ async function reconcile(run) {
|
|
|
19682
20157
|
decision,
|
|
19683
20158
|
branch: getCurrentBranch(),
|
|
19684
20159
|
watermarkSha: watermarkIsPartial ? null : watermarkHash,
|
|
20160
|
+
// The byte witness — the same "only honest definition of reviewed" the
|
|
20161
|
+
// coverage column uses. A finding on a path outside this set records no
|
|
20162
|
+
// statement (plan-mode prose anchored to unsent files must not become
|
|
20163
|
+
// "STILL OPEN … the tree is not clean").
|
|
20164
|
+
sentPaths,
|
|
19685
20165
|
findings: response.findings?.map((f) => ({
|
|
19686
20166
|
file: f.file,
|
|
19687
20167
|
line: f.line,
|
|
@@ -19748,6 +20228,39 @@ ${YELLOW2}${note}${NC2}
|
|
|
19748
20228
|
return exit(0);
|
|
19749
20229
|
}
|
|
19750
20230
|
|
|
20231
|
+
// src/lib/may-block.ts
|
|
20232
|
+
var HARD_BLOCK_CEILING = 5;
|
|
20233
|
+
function mayBlock(input) {
|
|
20234
|
+
const ceiling = input.ceiling ?? HARD_BLOCK_CEILING;
|
|
20235
|
+
if (input.reviewedFileCount === 0 && input.staticFindingCount === 0) {
|
|
20236
|
+
return { block: false, release: "no-code-reviewed" };
|
|
20237
|
+
}
|
|
20238
|
+
if (input.cycleCutFired) {
|
|
20239
|
+
return { block: false, release: "nothing-moved" };
|
|
20240
|
+
}
|
|
20241
|
+
if (input.attempts > input.maxIterations) {
|
|
20242
|
+
return { block: false, release: "same-problem-cap" };
|
|
20243
|
+
}
|
|
20244
|
+
if (input.blocks > ceiling) {
|
|
20245
|
+
return { block: false, release: "block-ceiling" };
|
|
20246
|
+
}
|
|
20247
|
+
return { block: true, release: null };
|
|
20248
|
+
}
|
|
20249
|
+
function describeRelease(release, input) {
|
|
20250
|
+
const ceiling = input.ceiling ?? HARD_BLOCK_CEILING;
|
|
20251
|
+
const open = input.findingCount > 0 ? `${input.findingCount} finding(s) remain OPEN and were NOT fixed. Human review required before deploying.` : "Human review required before deploying.";
|
|
20252
|
+
switch (release) {
|
|
20253
|
+
case "no-code-reviewed":
|
|
20254
|
+
return `Verity: WARN \u2014 NOT BLOCKING: no code was reviewed on this turn, so there is nothing here to fix. Reported as advice instead. ${open}`;
|
|
20255
|
+
case "nothing-moved":
|
|
20256
|
+
return `Verity: WARN \u2014 NOT BLOCKING: nothing has changed since the last verdict, so re-raising it cannot move anything forward. ${open}`;
|
|
20257
|
+
case "same-problem-cap":
|
|
20258
|
+
return `Verity: WARN \u2014 self-healing limit (${input.maxIterations}) reached on the same finding. NO LONGER BLOCKING, but ${open}`;
|
|
20259
|
+
case "block-ceiling":
|
|
20260
|
+
return `Verity: WARN \u2014 ${ceiling} consecutive blocking verdicts reached; releasing the block so this cannot loop. ${open}`;
|
|
20261
|
+
}
|
|
20262
|
+
}
|
|
20263
|
+
|
|
19751
20264
|
// src/lib/remediation-guard.ts
|
|
19752
20265
|
var TOOL_CONFIG_PATTERNS = [
|
|
19753
20266
|
/(^|\/)\.codacy\//,
|
|
@@ -19790,19 +20303,7 @@ function screenRemediation(fix, findingFile) {
|
|
|
19790
20303
|
|
|
19791
20304
|
// src/commands/analyze/phases/14-render.ts
|
|
19792
20305
|
function agentContextFor(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
19793
|
-
|
|
19794
|
-
const intent = response.intent_alignment ?? {};
|
|
19795
|
-
return buildAgentContext({
|
|
19796
|
-
intentRepeat,
|
|
19797
|
-
priorPendingFingerprints,
|
|
19798
|
-
gateDecision: String(response.gate_decision ?? ""),
|
|
19799
|
-
findings: response.findings ?? [],
|
|
19800
|
-
pendingItems: response.pending_items ?? [],
|
|
19801
|
-
reviewStatus: metadata.review_status,
|
|
19802
|
-
coverage: metadata.coverage,
|
|
19803
|
-
intentVerdict: intent.verdict,
|
|
19804
|
-
intentGaps: intent.gaps
|
|
19805
|
-
});
|
|
20306
|
+
return buildAgentContext(channelInputFrom(response, intentRepeat, priorPendingFingerprints));
|
|
19806
20307
|
}
|
|
19807
20308
|
async function render(run) {
|
|
19808
20309
|
const { opts, globals } = run;
|
|
@@ -19896,38 +20397,63 @@ async function render(run) {
|
|
|
19896
20397
|
reverify_by: response.reverify_by
|
|
19897
20398
|
});
|
|
19898
20399
|
const grantNudge = grantWarning ? ` \u26A0\uFE0F ${grantWarning}` : "";
|
|
19899
|
-
let
|
|
20400
|
+
let release = null;
|
|
19900
20401
|
let effectiveDecision = decision;
|
|
19901
20402
|
if (decision === "FAIL") {
|
|
19902
|
-
const
|
|
20403
|
+
const findings = response.findings ?? [];
|
|
20404
|
+
const blocking = findings.filter((f) => {
|
|
19903
20405
|
const sev = String(f.severity ?? "").toLowerCase();
|
|
19904
20406
|
return sev === "critical" || sev === "high";
|
|
19905
20407
|
});
|
|
19906
20408
|
const fingerprint = findingsFingerprint(blocking);
|
|
19907
|
-
const prior =
|
|
20409
|
+
const prior = readBlockState(currentCommit, {
|
|
20410
|
+
newUserPrompt: (conversation?.prompts?.length ?? 0) > 0
|
|
20411
|
+
});
|
|
19908
20412
|
const sameProblem = isSameProblem(prior.fingerprint, fingerprint);
|
|
19909
|
-
const nextIteration = sameProblem ? prior.iteration + 1 : 1;
|
|
19910
20413
|
const maxIterations = parseInt(opts.maxIterations, 10);
|
|
19911
|
-
|
|
19912
|
-
|
|
19913
|
-
|
|
19914
|
-
|
|
20414
|
+
const attempts = sameProblem ? prior.attempts + 1 : 1;
|
|
20415
|
+
const blocks = prior.blocks + 1;
|
|
20416
|
+
const decisionNow = mayBlock({
|
|
20417
|
+
reviewedFileCount: codeDelta.files.length,
|
|
20418
|
+
staticFindingCount: run.staticResults?.findings?.length ?? 0,
|
|
20419
|
+
cycleCutFired: silenced !== null,
|
|
20420
|
+
attempts,
|
|
20421
|
+
blocks,
|
|
20422
|
+
maxIterations
|
|
20423
|
+
});
|
|
20424
|
+
if (decisionNow.block) {
|
|
20425
|
+
writeBlockState(currentCommit, { attempts, blocks, fingerprint });
|
|
20426
|
+
iteration = attempts;
|
|
20427
|
+
} else {
|
|
20428
|
+
release = decisionNow.release;
|
|
19915
20429
|
effectiveDecision = "WARN";
|
|
19916
|
-
logEvent("
|
|
20430
|
+
logEvent("block_released", {
|
|
20431
|
+
reason: release,
|
|
20432
|
+
attempts,
|
|
20433
|
+
blocks,
|
|
20434
|
+
reviewed_files: codeDelta.files.length,
|
|
20435
|
+
cycle_cut: silenced,
|
|
20436
|
+
fingerprint
|
|
20437
|
+
});
|
|
19917
20438
|
}
|
|
19918
20439
|
}
|
|
19919
|
-
if (
|
|
20440
|
+
if (release) {
|
|
19920
20441
|
const findings = response.findings ?? [];
|
|
19921
20442
|
const lines = findings.slice(0, 5).map((f) => ` [${String(f.severity ?? "?").toUpperCase()}] ${String(f.title ?? f.message ?? "")} (${String(f.file ?? "?")}:${String(f.line ?? "?")})`);
|
|
20443
|
+
const summary = describeRelease(release, {
|
|
20444
|
+
findingCount: findings.length,
|
|
20445
|
+
maxIterations: parseInt(opts.maxIterations, 10)
|
|
20446
|
+
});
|
|
19922
20447
|
emitVerdict({
|
|
19923
20448
|
proposed: "WARN",
|
|
19924
20449
|
changed: run.changedUniverse,
|
|
19925
20450
|
coverage: reviewCoverage,
|
|
19926
|
-
userSummary:
|
|
19927
|
-
${lines.join("\n")}
|
|
20451
|
+
userSummary: lines.length > 0 ? `${summary}
|
|
20452
|
+
${lines.join("\n")}` : summary,
|
|
19928
20453
|
agentContext: null,
|
|
19929
20454
|
silenced: true
|
|
19930
20455
|
});
|
|
20456
|
+
return;
|
|
19931
20457
|
}
|
|
19932
20458
|
switch (effectiveDecision) {
|
|
19933
20459
|
case "FAIL": {
|
|
@@ -20026,7 +20552,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
20026
20552
|
break;
|
|
20027
20553
|
}
|
|
20028
20554
|
case "PASS": {
|
|
20029
|
-
|
|
20555
|
+
resetBlockState(currentCommit);
|
|
20030
20556
|
if (watermarkHash) recordPassHash(watermarkHash, baselineSessionId);
|
|
20031
20557
|
if (!watermarkIsPartial && currentCommit && currentCommit !== "no-git") writeBaselineSha(currentCommit);
|
|
20032
20558
|
let userSummary = response.user_summary ?? "Verity: PASS";
|
|
@@ -20047,6 +20573,7 @@ ${YELLOW}${grantNudge.trim()}${NC}
|
|
|
20047
20573
|
break;
|
|
20048
20574
|
}
|
|
20049
20575
|
case "WARN": {
|
|
20576
|
+
if (decision !== "FAIL") resetBlockState(currentCommit);
|
|
20050
20577
|
if (watermarkHash) recordPassHash(watermarkHash, baselineSessionId);
|
|
20051
20578
|
if (!watermarkIsPartial && currentCommit && currentCommit !== "no-git") writeBaselineSha(currentCommit);
|
|
20052
20579
|
let userSummary = response.user_summary ?? "Verity: WARN";
|
|
@@ -20145,7 +20672,7 @@ async function runAnalyze(opts, globals) {
|
|
|
20145
20672
|
}
|
|
20146
20673
|
|
|
20147
20674
|
// src/commands/baseline.ts
|
|
20148
|
-
var
|
|
20675
|
+
var import_node_fs32 = require("node:fs");
|
|
20149
20676
|
function registerBaselineCommands(program2) {
|
|
20150
20677
|
const baseline = program2.command("baseline").description("Manage the task-start working-tree baseline");
|
|
20151
20678
|
baseline.command("capture").description("Snapshot the working tree at task start (used by SessionStart hook)").option("--session-id <id>", "Session id (overrides any value from stdin)").option("--source <source>", "Lifecycle hint: startup|resume|clear|compact").action(async (opts) => {
|
|
@@ -20154,7 +20681,7 @@ function registerBaselineCommands(program2) {
|
|
|
20154
20681
|
process.chdir(repoRoot());
|
|
20155
20682
|
} catch {
|
|
20156
20683
|
}
|
|
20157
|
-
if (!(0,
|
|
20684
|
+
if (!(0, import_node_fs32.existsSync)(VERITY_DIR)) {
|
|
20158
20685
|
process.exit(0);
|
|
20159
20686
|
}
|
|
20160
20687
|
let sessionId = opts.sessionId;
|
|
@@ -20194,7 +20721,7 @@ async function readStdin() {
|
|
|
20194
20721
|
}
|
|
20195
20722
|
|
|
20196
20723
|
// src/commands/review.ts
|
|
20197
|
-
var
|
|
20724
|
+
var import_node_fs33 = require("node:fs");
|
|
20198
20725
|
function registerReviewCommand(program2) {
|
|
20199
20726
|
program2.command("review").description("Run on-demand Verity analysis (advisory, never blocks)").requiredOption("--files <paths>", "Comma-separated file list").option("--changed <paths>", "Subset of --files that were modified").option("--intent <text>", "User intent description (max 2000 chars)").option("--specs <paths>", "Comma-separated spec file paths").option("--json", "Output raw JSON response").action(async (opts) => {
|
|
20200
20727
|
const globals = program2.opts();
|
|
@@ -20213,7 +20740,7 @@ async function runReview(opts, globals) {
|
|
|
20213
20740
|
const securityFiles = filterSecurity(allFiles);
|
|
20214
20741
|
let staticResults;
|
|
20215
20742
|
if (isCodacyAvailable()) {
|
|
20216
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
20743
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs33.existsSync)(f) || resolveFile(f) !== null);
|
|
20217
20744
|
staticResults = runCodacyAnalysis(scannable);
|
|
20218
20745
|
} else {
|
|
20219
20746
|
staticResults = {
|
|
@@ -20239,10 +20766,10 @@ async function runReview(opts, globals) {
|
|
|
20239
20766
|
const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
|
|
20240
20767
|
specs = [];
|
|
20241
20768
|
for (const p of specPaths) {
|
|
20242
|
-
if (!(0,
|
|
20769
|
+
if (!(0, import_node_fs33.existsSync)(p)) continue;
|
|
20243
20770
|
try {
|
|
20244
|
-
const { readFileSync:
|
|
20245
|
-
const content =
|
|
20771
|
+
const { readFileSync: readFileSync19 } = await import("node:fs");
|
|
20772
|
+
const content = readFileSync19(p, "utf-8");
|
|
20246
20773
|
specs.push({ path: p, content: content.slice(0, 10240) });
|
|
20247
20774
|
} catch {
|
|
20248
20775
|
}
|
|
@@ -20299,15 +20826,15 @@ async function runReview(opts, globals) {
|
|
|
20299
20826
|
}
|
|
20300
20827
|
|
|
20301
20828
|
// src/commands/guard.ts
|
|
20302
|
-
var
|
|
20303
|
-
var
|
|
20829
|
+
var import_node_fs34 = require("node:fs");
|
|
20830
|
+
var import_node_path25 = require("node:path");
|
|
20304
20831
|
var GUARD_BLOCK_CAP = 2;
|
|
20305
|
-
var GUARD_ITER_FILE = (0,
|
|
20832
|
+
var GUARD_ITER_FILE = (0, import_node_path25.join)(VERITY_DIR, ".guard-iteration");
|
|
20306
20833
|
function readPreToolUseStdin() {
|
|
20307
20834
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
20308
|
-
return new Promise((
|
|
20835
|
+
return new Promise((resolve3) => {
|
|
20309
20836
|
try {
|
|
20310
|
-
if (process.stdin.isTTY) return
|
|
20837
|
+
if (process.stdin.isTTY) return resolve3(empty);
|
|
20311
20838
|
const chunks = [];
|
|
20312
20839
|
let timer;
|
|
20313
20840
|
let settled = false;
|
|
@@ -20320,7 +20847,7 @@ function readPreToolUseStdin() {
|
|
|
20320
20847
|
process.stdin.removeListener("end", onEnd);
|
|
20321
20848
|
process.stdin.removeListener("error", onError);
|
|
20322
20849
|
process.stdin.pause();
|
|
20323
|
-
|
|
20850
|
+
resolve3(value);
|
|
20324
20851
|
};
|
|
20325
20852
|
const onEnd = () => {
|
|
20326
20853
|
try {
|
|
@@ -20341,7 +20868,7 @@ function readPreToolUseStdin() {
|
|
|
20341
20868
|
process.stdin.on("error", onError);
|
|
20342
20869
|
process.stdin.resume();
|
|
20343
20870
|
} catch {
|
|
20344
|
-
|
|
20871
|
+
resolve3(empty);
|
|
20345
20872
|
}
|
|
20346
20873
|
});
|
|
20347
20874
|
}
|
|
@@ -20366,7 +20893,7 @@ function classifyCommand2(command, on) {
|
|
|
20366
20893
|
}
|
|
20367
20894
|
function readIterMap() {
|
|
20368
20895
|
try {
|
|
20369
|
-
const raw = JSON.parse((0,
|
|
20896
|
+
const raw = JSON.parse((0, import_node_fs34.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
20370
20897
|
if (raw && typeof raw === "object") {
|
|
20371
20898
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
20372
20899
|
return { [raw.moment]: raw.count };
|
|
@@ -20386,10 +20913,10 @@ function readIter(moment) {
|
|
|
20386
20913
|
}
|
|
20387
20914
|
function writeIter(moment, count) {
|
|
20388
20915
|
try {
|
|
20389
|
-
(0,
|
|
20916
|
+
(0, import_node_fs34.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
20390
20917
|
const map = readIterMap();
|
|
20391
20918
|
map[moment] = count;
|
|
20392
|
-
(0,
|
|
20919
|
+
(0, import_node_fs34.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
20393
20920
|
} catch {
|
|
20394
20921
|
}
|
|
20395
20922
|
}
|
|
@@ -20399,10 +20926,10 @@ function resetIter(moment) {
|
|
|
20399
20926
|
if (!(moment in map)) return;
|
|
20400
20927
|
delete map[moment];
|
|
20401
20928
|
if (Object.keys(map).length === 0) {
|
|
20402
|
-
if ((0,
|
|
20929
|
+
if ((0, import_node_fs34.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs34.unlinkSync)(GUARD_ITER_FILE);
|
|
20403
20930
|
} else {
|
|
20404
|
-
(0,
|
|
20405
|
-
(0,
|
|
20931
|
+
(0, import_node_fs34.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
20932
|
+
(0, import_node_fs34.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
20406
20933
|
}
|
|
20407
20934
|
} catch {
|
|
20408
20935
|
}
|
|
@@ -20466,7 +20993,7 @@ function buildGuardRequest(moment, files, iter, sessionId, command) {
|
|
|
20466
20993
|
const securityFiles = filterSecurity(files);
|
|
20467
20994
|
let staticResults;
|
|
20468
20995
|
if (isCodacyAvailable()) {
|
|
20469
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
20996
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs34.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
20470
20997
|
staticResults = runCodacyAnalysis(scannable);
|
|
20471
20998
|
} else {
|
|
20472
20999
|
staticResults = { tool: "@codacy/analysis-cli", findings: [], summary: { total_findings: 0, by_severity: {}, tools_run: [] } };
|
|
@@ -20511,7 +21038,7 @@ function emitAllowNotice(userMsg, agentMsg) {
|
|
|
20511
21038
|
async function runGuard(opts, globals) {
|
|
20512
21039
|
const on = opts.on.split(",").map((s) => s.trim()).filter((s) => s === "commit" || s === "push");
|
|
20513
21040
|
const { command, cwd, sessionId } = await readPreToolUseStdin();
|
|
20514
|
-
if (cwd && (0,
|
|
21041
|
+
if (cwd && (0, import_node_fs34.existsSync)(cwd)) {
|
|
20515
21042
|
try {
|
|
20516
21043
|
process.chdir(cwd);
|
|
20517
21044
|
} catch {
|
|
@@ -20617,15 +21144,15 @@ function writeBlockMessage(moment, response) {
|
|
|
20617
21144
|
}
|
|
20618
21145
|
|
|
20619
21146
|
// src/commands/init.ts
|
|
20620
|
-
var
|
|
21147
|
+
var import_node_fs36 = require("node:fs");
|
|
20621
21148
|
var import_promises13 = require("node:fs/promises");
|
|
20622
|
-
var
|
|
21149
|
+
var import_node_path27 = require("node:path");
|
|
20623
21150
|
var import_node_child_process10 = require("node:child_process");
|
|
20624
21151
|
var readline2 = __toESM(require("node:readline/promises"));
|
|
20625
21152
|
|
|
20626
21153
|
// src/commands/migrate.ts
|
|
20627
|
-
var
|
|
20628
|
-
var
|
|
21154
|
+
var import_node_fs35 = require("node:fs");
|
|
21155
|
+
var import_node_path26 = require("node:path");
|
|
20629
21156
|
var import_node_child_process9 = require("node:child_process");
|
|
20630
21157
|
|
|
20631
21158
|
// src/lib/telemetry.ts
|
|
@@ -20754,12 +21281,12 @@ async function runMigration(opts = {}) {
|
|
|
20754
21281
|
return { actions, migrated: actions.length > 0 };
|
|
20755
21282
|
}
|
|
20756
21283
|
function migrateProjectDir(root, actions) {
|
|
20757
|
-
const gateDir = (0,
|
|
20758
|
-
const verityDir = (0,
|
|
20759
|
-
if ((0,
|
|
21284
|
+
const gateDir = (0, import_node_path26.join)(root, ".gate");
|
|
21285
|
+
const verityDir = (0, import_node_path26.join)(root, ".verity");
|
|
21286
|
+
if ((0, import_node_fs35.existsSync)(gateDir) && !(0, import_node_fs35.existsSync)(verityDir)) {
|
|
20760
21287
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
20761
21288
|
}
|
|
20762
|
-
if ((0,
|
|
21289
|
+
if ((0, import_node_fs35.existsSync)(gateDir) && (0, import_node_fs35.existsSync)(verityDir)) {
|
|
20763
21290
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
20764
21291
|
}
|
|
20765
21292
|
return false;
|
|
@@ -20780,13 +21307,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
20780
21307
|
}
|
|
20781
21308
|
}
|
|
20782
21309
|
if (moved) {
|
|
20783
|
-
if ((0,
|
|
21310
|
+
if ((0, import_node_fs35.existsSync)(gateDir)) {
|
|
20784
21311
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
20785
21312
|
if (carried > 0) {
|
|
20786
21313
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
20787
21314
|
}
|
|
20788
21315
|
try {
|
|
20789
|
-
(0,
|
|
21316
|
+
(0, import_node_fs35.rmSync)(gateDir, { recursive: true, force: true });
|
|
20790
21317
|
} catch {
|
|
20791
21318
|
}
|
|
20792
21319
|
}
|
|
@@ -20802,18 +21329,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
20802
21329
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
20803
21330
|
}
|
|
20804
21331
|
try {
|
|
20805
|
-
(0,
|
|
21332
|
+
(0, import_node_fs35.rmSync)(gateDir, { recursive: true, force: true });
|
|
20806
21333
|
} catch {
|
|
20807
21334
|
}
|
|
20808
21335
|
return carried > 0;
|
|
20809
21336
|
}
|
|
20810
21337
|
function migrateGlobalCredentials(home, actions) {
|
|
20811
21338
|
if (!home) return;
|
|
20812
|
-
const gateCreds = (0,
|
|
20813
|
-
const verityCreds = (0,
|
|
20814
|
-
if (!(0,
|
|
20815
|
-
if (!(0,
|
|
20816
|
-
(0,
|
|
21339
|
+
const gateCreds = (0, import_node_path26.join)(home, ".gate", "credentials");
|
|
21340
|
+
const verityCreds = (0, import_node_path26.join)(home, ".verity", "credentials");
|
|
21341
|
+
if (!(0, import_node_fs35.existsSync)(gateCreds)) return;
|
|
21342
|
+
if (!(0, import_node_fs35.existsSync)(verityCreds)) {
|
|
21343
|
+
(0, import_node_fs35.mkdirSync)((0, import_node_path26.join)(home, ".verity"), { recursive: true });
|
|
20817
21344
|
moveFile(gateCreds, verityCreds);
|
|
20818
21345
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
20819
21346
|
return;
|
|
@@ -20835,8 +21362,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
20835
21362
|
}
|
|
20836
21363
|
}
|
|
20837
21364
|
async function migrateClaudeMd(root, actions) {
|
|
20838
|
-
const claudeMd = (0,
|
|
20839
|
-
const hadLegacyBlock = (0,
|
|
21365
|
+
const claudeMd = (0, import_node_path26.join)(root, "CLAUDE.md");
|
|
21366
|
+
const hadLegacyBlock = (0, import_node_fs35.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
20840
21367
|
if (!hadLegacyBlock) return;
|
|
20841
21368
|
try {
|
|
20842
21369
|
await ensureClaudeMdPointer(root);
|
|
@@ -20846,9 +21373,9 @@ async function migrateClaudeMd(root, actions) {
|
|
|
20846
21373
|
}
|
|
20847
21374
|
}
|
|
20848
21375
|
function migrateStandardFile(root, actions) {
|
|
20849
|
-
const gateMd = (0,
|
|
20850
|
-
const verityMd = (0,
|
|
20851
|
-
if (!(0,
|
|
21376
|
+
const gateMd = (0, import_node_path26.join)(root, "GATE.md");
|
|
21377
|
+
const verityMd = (0, import_node_path26.join)(root, "VERITY.md");
|
|
21378
|
+
if (!(0, import_node_fs35.existsSync)(gateMd) || (0, import_node_fs35.existsSync)(verityMd)) return;
|
|
20852
21379
|
let moved = false;
|
|
20853
21380
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
20854
21381
|
try {
|
|
@@ -20860,12 +21387,12 @@ function migrateStandardFile(root, actions) {
|
|
|
20860
21387
|
if (!moved) moveFile(gateMd, verityMd);
|
|
20861
21388
|
const content = readFileSyncSafe(verityMd);
|
|
20862
21389
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
20863
|
-
if (refreshed !== content) (0,
|
|
21390
|
+
if (refreshed !== content) (0, import_node_fs35.writeFileSync)(verityMd, refreshed);
|
|
20864
21391
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
20865
21392
|
}
|
|
20866
21393
|
async function migrateTelemetryHeaders(root, actions) {
|
|
20867
|
-
const file = (0,
|
|
20868
|
-
if (!(0,
|
|
21394
|
+
const file = (0, import_node_path26.join)(root, ".claude", "settings.local.json");
|
|
21395
|
+
if (!(0, import_node_fs35.existsSync)(file)) return;
|
|
20869
21396
|
let settings;
|
|
20870
21397
|
try {
|
|
20871
21398
|
settings = JSON.parse(readFileSyncSafe(file) || "{}");
|
|
@@ -20912,15 +21439,15 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
20912
21439
|
toAppend.push(line.replace(/\r$/, ""));
|
|
20913
21440
|
}
|
|
20914
21441
|
if (toAppend.length > 0) {
|
|
20915
|
-
const
|
|
20916
|
-
(0,
|
|
21442
|
+
const sep2 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
21443
|
+
(0, import_node_fs35.writeFileSync)(verityCreds, verityContent + sep2 + toAppend.join("\n") + "\n");
|
|
20917
21444
|
}
|
|
20918
|
-
(0,
|
|
21445
|
+
(0, import_node_fs35.rmSync)(gateCreds, { force: true });
|
|
20919
21446
|
return toAppend.length;
|
|
20920
21447
|
}
|
|
20921
21448
|
function readFileSyncSafe(path) {
|
|
20922
21449
|
try {
|
|
20923
|
-
return (0,
|
|
21450
|
+
return (0, import_node_fs35.readFileSync)(path, "utf-8");
|
|
20924
21451
|
} catch {
|
|
20925
21452
|
return "";
|
|
20926
21453
|
}
|
|
@@ -20935,35 +21462,35 @@ function hasStagedChanges(root) {
|
|
|
20935
21462
|
}
|
|
20936
21463
|
function moveDir(from, to) {
|
|
20937
21464
|
try {
|
|
20938
|
-
(0,
|
|
21465
|
+
(0, import_node_fs35.renameSync)(from, to);
|
|
20939
21466
|
} catch (err) {
|
|
20940
21467
|
if (err.code !== "EXDEV") throw err;
|
|
20941
|
-
(0,
|
|
20942
|
-
(0,
|
|
21468
|
+
(0, import_node_fs35.cpSync)(from, to, { recursive: true });
|
|
21469
|
+
(0, import_node_fs35.rmSync)(from, { recursive: true, force: true });
|
|
20943
21470
|
}
|
|
20944
21471
|
}
|
|
20945
21472
|
function moveFile(from, to) {
|
|
20946
21473
|
try {
|
|
20947
|
-
(0,
|
|
21474
|
+
(0, import_node_fs35.renameSync)(from, to);
|
|
20948
21475
|
} catch (err) {
|
|
20949
21476
|
if (err.code !== "EXDEV") throw err;
|
|
20950
|
-
(0,
|
|
20951
|
-
(0,
|
|
21477
|
+
(0, import_node_fs35.cpSync)(from, to);
|
|
21478
|
+
(0, import_node_fs35.rmSync)(from, { force: true });
|
|
20952
21479
|
}
|
|
20953
21480
|
}
|
|
20954
21481
|
function carryLegacyContents(gateDir, verityDir) {
|
|
20955
21482
|
let copied = 0;
|
|
20956
21483
|
const walk = (relDir) => {
|
|
20957
|
-
const srcDir = (0,
|
|
20958
|
-
for (const entry of (0,
|
|
20959
|
-
const rel = relDir ? (0,
|
|
20960
|
-
const src = (0,
|
|
20961
|
-
const dest = (0,
|
|
20962
|
-
if ((0,
|
|
21484
|
+
const srcDir = (0, import_node_path26.join)(gateDir, relDir);
|
|
21485
|
+
for (const entry of (0, import_node_fs35.readdirSync)(srcDir)) {
|
|
21486
|
+
const rel = relDir ? (0, import_node_path26.join)(relDir, entry) : entry;
|
|
21487
|
+
const src = (0, import_node_path26.join)(gateDir, rel);
|
|
21488
|
+
const dest = (0, import_node_path26.join)(verityDir, rel);
|
|
21489
|
+
if ((0, import_node_fs35.statSync)(src).isDirectory()) {
|
|
20963
21490
|
walk(rel);
|
|
20964
|
-
} else if (!(0,
|
|
20965
|
-
(0,
|
|
20966
|
-
(0,
|
|
21491
|
+
} else if (!(0, import_node_fs35.existsSync)(dest)) {
|
|
21492
|
+
(0, import_node_fs35.mkdirSync)((0, import_node_path26.dirname)(dest), { recursive: true });
|
|
21493
|
+
(0, import_node_fs35.cpSync)(src, dest);
|
|
20967
21494
|
copied++;
|
|
20968
21495
|
}
|
|
20969
21496
|
}
|
|
@@ -20972,22 +21499,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
20972
21499
|
return copied;
|
|
20973
21500
|
}
|
|
20974
21501
|
async function needsMigration(root = repoRoot()) {
|
|
20975
|
-
const gateDir = (0,
|
|
20976
|
-
const verityDir = (0,
|
|
20977
|
-
if ((0,
|
|
20978
|
-
if ((0,
|
|
20979
|
-
if ((0,
|
|
21502
|
+
const gateDir = (0, import_node_path26.join)(root, ".gate");
|
|
21503
|
+
const verityDir = (0, import_node_path26.join)(root, ".verity");
|
|
21504
|
+
if ((0, import_node_fs35.existsSync)(gateDir) && !(0, import_node_fs35.existsSync)(verityDir)) return true;
|
|
21505
|
+
if ((0, import_node_fs35.existsSync)(gateDir) && (0, import_node_fs35.existsSync)(verityDir)) {
|
|
21506
|
+
if ((0, import_node_fs35.existsSync)((0, import_node_path26.join)(gateDir, "credentials")) && !(0, import_node_fs35.existsSync)((0, import_node_path26.join)(verityDir, "credentials"))) {
|
|
20980
21507
|
return true;
|
|
20981
21508
|
}
|
|
20982
|
-
if ((0,
|
|
21509
|
+
if ((0, import_node_fs35.existsSync)((0, import_node_path26.join)(gateDir, "memory")) && !(0, import_node_fs35.existsSync)((0, import_node_path26.join)(verityDir, "memory"))) {
|
|
20983
21510
|
return true;
|
|
20984
21511
|
}
|
|
20985
21512
|
}
|
|
20986
|
-
const claudeMd = (0,
|
|
20987
|
-
if ((0,
|
|
21513
|
+
const claudeMd = (0, import_node_path26.join)(root, "CLAUDE.md");
|
|
21514
|
+
if ((0, import_node_fs35.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
20988
21515
|
return true;
|
|
20989
21516
|
}
|
|
20990
|
-
if ((0,
|
|
21517
|
+
if ((0, import_node_fs35.existsSync)((0, import_node_path26.join)(root, "GATE.md")) && !(0, import_node_fs35.existsSync)((0, import_node_path26.join)(root, "VERITY.md"))) {
|
|
20991
21518
|
return true;
|
|
20992
21519
|
}
|
|
20993
21520
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -21069,6 +21596,8 @@ async function confirmExistingLogin(serviceUrl, remote, opts) {
|
|
|
21069
21596
|
async function runOptionalAuth(resolution, opts = {}) {
|
|
21070
21597
|
if (resolution.source === "default") {
|
|
21071
21598
|
printInfo(`No Verity service configured on this machine \u2014 using the default: ${resolution.url}`);
|
|
21599
|
+
} else {
|
|
21600
|
+
printInfo(`Authenticating against ${resolution.url} (source: ${resolution.source}).`);
|
|
21072
21601
|
}
|
|
21073
21602
|
const heal = await maybeHealServiceUrl(resolution, opts.verbose);
|
|
21074
21603
|
const serviceUrl = heal.serviceUrl;
|
|
@@ -21121,15 +21650,15 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
21121
21650
|
}
|
|
21122
21651
|
function resolveDataDir() {
|
|
21123
21652
|
const candidates = [
|
|
21124
|
-
(0,
|
|
21653
|
+
(0, import_node_path27.join)(__dirname, "..", "data"),
|
|
21125
21654
|
// installed: node_modules/@codacy/verity-cli/data
|
|
21126
|
-
(0,
|
|
21655
|
+
(0, import_node_path27.join)(__dirname, "..", "..", "data"),
|
|
21127
21656
|
// edge case: nested resolution
|
|
21128
|
-
(0,
|
|
21657
|
+
(0, import_node_path27.join)(process.cwd(), "cli", "data")
|
|
21129
21658
|
// local dev: running from repo root
|
|
21130
21659
|
];
|
|
21131
21660
|
for (const candidate of candidates) {
|
|
21132
|
-
if ((0,
|
|
21661
|
+
if ((0, import_node_fs36.existsSync)((0, import_node_path27.join)(candidate, "skills"))) {
|
|
21133
21662
|
return candidate;
|
|
21134
21663
|
}
|
|
21135
21664
|
}
|
|
@@ -21145,7 +21674,7 @@ function registerInitCommand(program2) {
|
|
|
21145
21674
|
program2.command("init").description("Initialize Verity in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
|
|
21146
21675
|
const force = opts.force ?? false;
|
|
21147
21676
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
21148
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
21677
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs36.existsSync)(m));
|
|
21149
21678
|
if (!isProject) {
|
|
21150
21679
|
printError("No project detected in the current directory.");
|
|
21151
21680
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -21208,21 +21737,21 @@ function registerInitCommand(program2) {
|
|
|
21208
21737
|
console.log("");
|
|
21209
21738
|
printInfo("Installing skills...");
|
|
21210
21739
|
const dataDir = resolveDataDir();
|
|
21211
|
-
const skillsSource = (0,
|
|
21740
|
+
const skillsSource = (0, import_node_path27.join)(dataDir, "skills");
|
|
21212
21741
|
const skillsDest = ".claude/skills";
|
|
21213
21742
|
const skills = ["verity-setup", "verity-analyze", "verity-status", "verity-feedback", "verity-learn", "verity-memory", "verity-insights", "verity-reflect"];
|
|
21214
21743
|
let skillsInstalled = 0;
|
|
21215
21744
|
for (const skill of skills) {
|
|
21216
|
-
const src = (0,
|
|
21217
|
-
const dest = (0,
|
|
21218
|
-
if (!(0,
|
|
21745
|
+
const src = (0, import_node_path27.join)(skillsSource, skill);
|
|
21746
|
+
const dest = (0, import_node_path27.join)(skillsDest, skill);
|
|
21747
|
+
if (!(0, import_node_fs36.existsSync)(src)) {
|
|
21219
21748
|
printWarn(` Skill data not found: ${skill}`);
|
|
21220
21749
|
continue;
|
|
21221
21750
|
}
|
|
21222
|
-
if ((0,
|
|
21223
|
-
const srcSkill = (0,
|
|
21224
|
-
const destSkill = (0,
|
|
21225
|
-
if ((0,
|
|
21751
|
+
if ((0, import_node_fs36.existsSync)(dest) && !force) {
|
|
21752
|
+
const srcSkill = (0, import_node_path27.join)(src, "SKILL.md");
|
|
21753
|
+
const destSkill = (0, import_node_path27.join)(dest, "SKILL.md");
|
|
21754
|
+
if ((0, import_node_fs36.existsSync)(destSkill)) {
|
|
21226
21755
|
try {
|
|
21227
21756
|
const srcContent = await (0, import_promises13.readFile)(srcSkill, "utf-8");
|
|
21228
21757
|
const destContent = await (0, import_promises13.readFile)(destSkill, "utf-8");
|
|
@@ -21253,13 +21782,19 @@ function registerInitCommand(program2) {
|
|
|
21253
21782
|
}
|
|
21254
21783
|
await (0, import_promises13.mkdir)(VERITY_DIR, { recursive: true });
|
|
21255
21784
|
await ensureMemoryDir();
|
|
21785
|
+
const ignoreResult = ensureSnapshotGitignored();
|
|
21786
|
+
if (ignoreResult === "failed") {
|
|
21787
|
+
printWarn(" .gitignore: could not add .verity/.snapshot/ \u2014 add it manually (it holds copies of analyzed files)");
|
|
21788
|
+
} else {
|
|
21789
|
+
printInfo(` .gitignore: .verity/.snapshot/ ${ignoreResult === "added" ? "added" : "already covered"} \u2713`);
|
|
21790
|
+
}
|
|
21256
21791
|
try {
|
|
21257
21792
|
await ensureClaudeMdPointer();
|
|
21258
21793
|
printInfo(" CLAUDE.md memory pointer \u2713");
|
|
21259
21794
|
} catch (err) {
|
|
21260
21795
|
printWarn(` Could not update CLAUDE.md: ${err.message}`);
|
|
21261
21796
|
}
|
|
21262
|
-
const globalVerityDir = (0,
|
|
21797
|
+
const globalVerityDir = (0, import_node_path27.join)(process.env.HOME ?? "", ".verity");
|
|
21263
21798
|
await (0, import_promises13.mkdir)(globalVerityDir, { recursive: true });
|
|
21264
21799
|
console.log("");
|
|
21265
21800
|
try {
|
|
@@ -21294,8 +21829,8 @@ function registerInitCommand(program2) {
|
|
|
21294
21829
|
}
|
|
21295
21830
|
|
|
21296
21831
|
// src/commands/uninstall.ts
|
|
21297
|
-
var
|
|
21298
|
-
var
|
|
21832
|
+
var import_node_fs37 = require("node:fs");
|
|
21833
|
+
var import_node_path28 = require("node:path");
|
|
21299
21834
|
var SKILL_NAMES = [
|
|
21300
21835
|
"verity-setup",
|
|
21301
21836
|
"verity-analyze",
|
|
@@ -21314,11 +21849,11 @@ function registerUninstallCommand(program2) {
|
|
|
21314
21849
|
const actions = [];
|
|
21315
21850
|
const skillsRoot = projectPath(".claude/skills");
|
|
21316
21851
|
for (const name of SKILL_NAMES) {
|
|
21317
|
-
const dir = (0,
|
|
21318
|
-
if ((0,
|
|
21852
|
+
const dir = (0, import_node_path28.join)(skillsRoot, name);
|
|
21853
|
+
if ((0, import_node_fs37.existsSync)(dir)) {
|
|
21319
21854
|
actions.push({
|
|
21320
21855
|
label: `Remove .claude/skills/${name}/`,
|
|
21321
|
-
apply: () => (0,
|
|
21856
|
+
apply: () => (0, import_node_fs37.rmSync)(dir, { recursive: true, force: true })
|
|
21322
21857
|
});
|
|
21323
21858
|
}
|
|
21324
21859
|
}
|
|
@@ -21332,24 +21867,24 @@ function registerUninstallCommand(program2) {
|
|
|
21332
21867
|
});
|
|
21333
21868
|
}
|
|
21334
21869
|
const verityDir = projectPath(VERITY_DIR);
|
|
21335
|
-
if ((0,
|
|
21870
|
+
if ((0, import_node_fs37.existsSync)(verityDir)) {
|
|
21336
21871
|
actions.push({
|
|
21337
21872
|
label: `Remove ${VERITY_DIR}/`,
|
|
21338
|
-
apply: () => (0,
|
|
21873
|
+
apply: () => (0, import_node_fs37.rmSync)(verityDir, { recursive: true, force: true })
|
|
21339
21874
|
});
|
|
21340
21875
|
}
|
|
21341
21876
|
if (!keepVerityMd) {
|
|
21342
21877
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
21343
|
-
if ((0,
|
|
21878
|
+
if ((0, import_node_fs37.existsSync)(verityMd)) {
|
|
21344
21879
|
actions.push({
|
|
21345
21880
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
21346
|
-
apply: () => (0,
|
|
21881
|
+
apply: () => (0, import_node_fs37.rmSync)(verityMd, { force: true })
|
|
21347
21882
|
});
|
|
21348
21883
|
}
|
|
21349
21884
|
}
|
|
21350
21885
|
const cleanupEmptyDir = (path) => {
|
|
21351
|
-
if ((0,
|
|
21352
|
-
(0,
|
|
21886
|
+
if ((0, import_node_fs37.existsSync)(path) && (0, import_node_fs37.statSync)(path).isDirectory() && (0, import_node_fs37.readdirSync)(path).length === 0) {
|
|
21887
|
+
(0, import_node_fs37.rmdirSync)(path);
|
|
21353
21888
|
}
|
|
21354
21889
|
};
|
|
21355
21890
|
actions.push({
|
|
@@ -21360,11 +21895,11 @@ function registerUninstallCommand(program2) {
|
|
|
21360
21895
|
}
|
|
21361
21896
|
});
|
|
21362
21897
|
const home = process.env.HOME ?? "";
|
|
21363
|
-
const globalVerityDir = (0,
|
|
21364
|
-
if (purgeGlobal && (0,
|
|
21898
|
+
const globalVerityDir = (0, import_node_path28.join)(home, ".verity");
|
|
21899
|
+
if (purgeGlobal && (0, import_node_fs37.existsSync)(globalVerityDir)) {
|
|
21365
21900
|
actions.push({
|
|
21366
21901
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
21367
|
-
apply: () => (0,
|
|
21902
|
+
apply: () => (0, import_node_fs37.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
21368
21903
|
});
|
|
21369
21904
|
}
|
|
21370
21905
|
if (actions.length === 0) {
|
|
@@ -21558,8 +22093,8 @@ function registerTaskCommands(program2) {
|
|
|
21558
22093
|
}
|
|
21559
22094
|
|
|
21560
22095
|
// src/commands/reset.ts
|
|
21561
|
-
var
|
|
21562
|
-
var
|
|
22096
|
+
var import_node_fs38 = require("node:fs");
|
|
22097
|
+
var import_node_path29 = require("node:path");
|
|
21563
22098
|
function registerResetCommand(program2) {
|
|
21564
22099
|
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) => {
|
|
21565
22100
|
const globals = program2.opts();
|
|
@@ -21596,11 +22131,11 @@ function registerResetCommand(program2) {
|
|
|
21596
22131
|
}
|
|
21597
22132
|
const cacheDir = projectPath(CACHE_DIR);
|
|
21598
22133
|
let purged = 0;
|
|
21599
|
-
if ((0,
|
|
21600
|
-
for (const entry of (0,
|
|
22134
|
+
if ((0, import_node_fs38.existsSync)(cacheDir)) {
|
|
22135
|
+
for (const entry of (0, import_node_fs38.readdirSync)(cacheDir)) {
|
|
21601
22136
|
if (entry.startsWith("pending-")) {
|
|
21602
22137
|
try {
|
|
21603
|
-
(0,
|
|
22138
|
+
(0, import_node_fs38.unlinkSync)((0, import_node_path29.join)(cacheDir, entry));
|
|
21604
22139
|
purged++;
|
|
21605
22140
|
} catch {
|
|
21606
22141
|
}
|
|
@@ -21615,19 +22150,19 @@ function registerResetCommand(program2) {
|
|
|
21615
22150
|
projectPath(`${VERITY_DIR}/.last-analysis`)
|
|
21616
22151
|
];
|
|
21617
22152
|
for (const file of filesToClear) {
|
|
21618
|
-
if ((0,
|
|
22153
|
+
if ((0, import_node_fs38.existsSync)(file)) {
|
|
21619
22154
|
try {
|
|
21620
|
-
(0,
|
|
22155
|
+
(0, import_node_fs38.writeFileSync)(file, "");
|
|
21621
22156
|
} catch {
|
|
21622
22157
|
}
|
|
21623
22158
|
}
|
|
21624
22159
|
}
|
|
21625
22160
|
if (opts.all) {
|
|
21626
22161
|
const logsDir = projectPath(`${VERITY_DIR}/.logs`);
|
|
21627
|
-
if ((0,
|
|
21628
|
-
for (const entry of (0,
|
|
22162
|
+
if ((0, import_node_fs38.existsSync)(logsDir)) {
|
|
22163
|
+
for (const entry of (0, import_node_fs38.readdirSync)(logsDir)) {
|
|
21629
22164
|
try {
|
|
21630
|
-
(0,
|
|
22165
|
+
(0, import_node_fs38.unlinkSync)((0, import_node_path29.join)(logsDir, entry));
|
|
21631
22166
|
} catch {
|
|
21632
22167
|
}
|
|
21633
22168
|
}
|
|
@@ -21935,8 +22470,8 @@ function registerTelemetryCommands(program2) {
|
|
|
21935
22470
|
}
|
|
21936
22471
|
|
|
21937
22472
|
// src/cli.ts
|
|
21938
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.29.4-experimental.
|
|
21939
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.29.4-experimental.
|
|
22473
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.29.4-experimental.694bcef").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) => {
|
|
22474
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.29.4-experimental.694bcef");
|
|
21940
22475
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
21941
22476
|
try {
|
|
21942
22477
|
await foldLegacyLocalCredential();
|