@codacy/verity-cli 0.34.1 → 0.34.2-experimental.2cad220
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +38 -0
- package/bin/verity.js +1295 -722
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -2928,7 +2928,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2928
2928
|
* @param {(string | Function)} text - string to add, or a function returning a string
|
|
2929
2929
|
* @return {Command} `this` command for chaining
|
|
2930
2930
|
*/
|
|
2931
|
-
addHelpText(position,
|
|
2931
|
+
addHelpText(position, text2) {
|
|
2932
2932
|
const allowedValues = ["beforeAll", "before", "after", "afterAll"];
|
|
2933
2933
|
if (!allowedValues.includes(position)) {
|
|
2934
2934
|
throw new Error(`Unexpected value for position to addHelpText.
|
|
@@ -2937,10 +2937,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2937
2937
|
const helpEvent = `${position}Help`;
|
|
2938
2938
|
this.on(helpEvent, (context) => {
|
|
2939
2939
|
let helpStr;
|
|
2940
|
-
if (typeof
|
|
2941
|
-
helpStr =
|
|
2940
|
+
if (typeof text2 === "function") {
|
|
2941
|
+
helpStr = text2({ error: context.error, command: context.command });
|
|
2942
2942
|
} else {
|
|
2943
|
-
helpStr =
|
|
2943
|
+
helpStr = text2;
|
|
2944
2944
|
}
|
|
2945
2945
|
if (helpStr) {
|
|
2946
2946
|
context.write(`${helpStr}
|
|
@@ -3982,14 +3982,14 @@ var require_foldFlowLines = __commonJS2({
|
|
|
3982
3982
|
var FOLD_FLOW = "flow";
|
|
3983
3983
|
var FOLD_BLOCK = "block";
|
|
3984
3984
|
var FOLD_QUOTED = "quoted";
|
|
3985
|
-
function foldFlowLines(
|
|
3985
|
+
function foldFlowLines(text2, indent, mode2 = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
|
|
3986
3986
|
if (!lineWidth || lineWidth < 0)
|
|
3987
|
-
return
|
|
3987
|
+
return text2;
|
|
3988
3988
|
if (lineWidth < minContentWidth)
|
|
3989
3989
|
minContentWidth = 0;
|
|
3990
3990
|
const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
|
|
3991
|
-
if (
|
|
3992
|
-
return
|
|
3991
|
+
if (text2.length <= endStep)
|
|
3992
|
+
return text2;
|
|
3993
3993
|
const folds = [];
|
|
3994
3994
|
const escapedFolds = {};
|
|
3995
3995
|
let end = lineWidth - indent.length;
|
|
@@ -4006,14 +4006,14 @@ var require_foldFlowLines = __commonJS2({
|
|
|
4006
4006
|
let escStart = -1;
|
|
4007
4007
|
let escEnd = -1;
|
|
4008
4008
|
if (mode2 === FOLD_BLOCK) {
|
|
4009
|
-
i2 = consumeMoreIndentedLines(
|
|
4009
|
+
i2 = consumeMoreIndentedLines(text2, i2, indent.length);
|
|
4010
4010
|
if (i2 !== -1)
|
|
4011
4011
|
end = i2 + endStep;
|
|
4012
4012
|
}
|
|
4013
|
-
for (let ch; ch =
|
|
4013
|
+
for (let ch; ch = text2[i2 += 1]; ) {
|
|
4014
4014
|
if (mode2 === FOLD_QUOTED && ch === "\\") {
|
|
4015
4015
|
escStart = i2;
|
|
4016
|
-
switch (
|
|
4016
|
+
switch (text2[i2 + 1]) {
|
|
4017
4017
|
case "x":
|
|
4018
4018
|
i2 += 3;
|
|
4019
4019
|
break;
|
|
@@ -4030,12 +4030,12 @@ var require_foldFlowLines = __commonJS2({
|
|
|
4030
4030
|
}
|
|
4031
4031
|
if (ch === "\n") {
|
|
4032
4032
|
if (mode2 === FOLD_BLOCK)
|
|
4033
|
-
i2 = consumeMoreIndentedLines(
|
|
4033
|
+
i2 = consumeMoreIndentedLines(text2, i2, indent.length);
|
|
4034
4034
|
end = i2 + indent.length + endStep;
|
|
4035
4035
|
split = void 0;
|
|
4036
4036
|
} else {
|
|
4037
4037
|
if (ch === " " && prev && prev !== " " && prev !== "\n" && prev !== " ") {
|
|
4038
|
-
const next =
|
|
4038
|
+
const next = text2[i2 + 1];
|
|
4039
4039
|
if (next && next !== " " && next !== "\n" && next !== " ")
|
|
4040
4040
|
split = i2;
|
|
4041
4041
|
}
|
|
@@ -4047,12 +4047,12 @@ var require_foldFlowLines = __commonJS2({
|
|
|
4047
4047
|
} else if (mode2 === FOLD_QUOTED) {
|
|
4048
4048
|
while (prev === " " || prev === " ") {
|
|
4049
4049
|
prev = ch;
|
|
4050
|
-
ch =
|
|
4050
|
+
ch = text2[i2 += 1];
|
|
4051
4051
|
overflow = true;
|
|
4052
4052
|
}
|
|
4053
4053
|
const j = i2 > escEnd + 1 ? i2 - 2 : escStart - 1;
|
|
4054
4054
|
if (escapedFolds[j])
|
|
4055
|
-
return
|
|
4055
|
+
return text2;
|
|
4056
4056
|
folds.push(j);
|
|
4057
4057
|
escapedFolds[j] = true;
|
|
4058
4058
|
end = j + endStep;
|
|
@@ -4067,39 +4067,39 @@ var require_foldFlowLines = __commonJS2({
|
|
|
4067
4067
|
if (overflow && onOverflow)
|
|
4068
4068
|
onOverflow();
|
|
4069
4069
|
if (folds.length === 0)
|
|
4070
|
-
return
|
|
4070
|
+
return text2;
|
|
4071
4071
|
if (onFold)
|
|
4072
4072
|
onFold();
|
|
4073
|
-
let res =
|
|
4073
|
+
let res = text2.slice(0, folds[0]);
|
|
4074
4074
|
for (let i3 = 0; i3 < folds.length; ++i3) {
|
|
4075
4075
|
const fold2 = folds[i3];
|
|
4076
|
-
const end2 = folds[i3 + 1] ||
|
|
4076
|
+
const end2 = folds[i3 + 1] || text2.length;
|
|
4077
4077
|
if (fold2 === 0)
|
|
4078
4078
|
res = `
|
|
4079
|
-
${indent}${
|
|
4079
|
+
${indent}${text2.slice(0, end2)}`;
|
|
4080
4080
|
else {
|
|
4081
4081
|
if (mode2 === FOLD_QUOTED && escapedFolds[fold2])
|
|
4082
|
-
res += `${
|
|
4082
|
+
res += `${text2[fold2]}\\`;
|
|
4083
4083
|
res += `
|
|
4084
|
-
${indent}${
|
|
4084
|
+
${indent}${text2.slice(fold2 + 1, end2)}`;
|
|
4085
4085
|
}
|
|
4086
4086
|
}
|
|
4087
4087
|
return res;
|
|
4088
4088
|
}
|
|
4089
|
-
function consumeMoreIndentedLines(
|
|
4089
|
+
function consumeMoreIndentedLines(text2, i2, indent) {
|
|
4090
4090
|
let end = i2;
|
|
4091
4091
|
let start2 = i2 + 1;
|
|
4092
|
-
let ch =
|
|
4092
|
+
let ch = text2[start2];
|
|
4093
4093
|
while (ch === " " || ch === " ") {
|
|
4094
4094
|
if (i2 < start2 + indent) {
|
|
4095
|
-
ch =
|
|
4095
|
+
ch = text2[++i2];
|
|
4096
4096
|
} else {
|
|
4097
4097
|
do {
|
|
4098
|
-
ch =
|
|
4098
|
+
ch = text2[++i2];
|
|
4099
4099
|
} while (ch && ch !== "\n");
|
|
4100
4100
|
end = i2;
|
|
4101
4101
|
start2 = i2 + 1;
|
|
4102
|
-
ch =
|
|
4102
|
+
ch = text2[start2];
|
|
4103
4103
|
}
|
|
4104
4104
|
}
|
|
4105
4105
|
return end;
|
|
@@ -6975,10 +6975,10 @@ var require_resolve_block_map = __commonJS2({
|
|
|
6975
6975
|
let offset = bm.offset;
|
|
6976
6976
|
let commentEnd = null;
|
|
6977
6977
|
for (const collItem of bm.items) {
|
|
6978
|
-
const { start: start2, key, sep:
|
|
6978
|
+
const { start: start2, key, sep: sep7, value } = collItem;
|
|
6979
6979
|
const keyProps = resolveProps.resolveProps(start2, {
|
|
6980
6980
|
indicator: "explicit-key-ind",
|
|
6981
|
-
next: key ??
|
|
6981
|
+
next: key ?? sep7?.[0],
|
|
6982
6982
|
offset,
|
|
6983
6983
|
onError,
|
|
6984
6984
|
parentIndent: bm.indent,
|
|
@@ -6992,7 +6992,7 @@ var require_resolve_block_map = __commonJS2({
|
|
|
6992
6992
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
6993
6993
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
6994
6994
|
}
|
|
6995
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
6995
|
+
if (!keyProps.anchor && !keyProps.tag && !sep7) {
|
|
6996
6996
|
commentEnd = keyProps.end;
|
|
6997
6997
|
if (keyProps.comment) {
|
|
6998
6998
|
if (map.comment)
|
|
@@ -7016,7 +7016,7 @@ var require_resolve_block_map = __commonJS2({
|
|
|
7016
7016
|
ctx.atKey = false;
|
|
7017
7017
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
7018
7018
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
7019
|
-
const valueProps = resolveProps.resolveProps(
|
|
7019
|
+
const valueProps = resolveProps.resolveProps(sep7 ?? [], {
|
|
7020
7020
|
indicator: "map-value-ind",
|
|
7021
7021
|
next: value,
|
|
7022
7022
|
offset: keyNode.range[2],
|
|
@@ -7032,7 +7032,7 @@ var require_resolve_block_map = __commonJS2({
|
|
|
7032
7032
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
7033
7033
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
7034
7034
|
}
|
|
7035
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
7035
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep7, null, valueProps, onError);
|
|
7036
7036
|
if (ctx.schema.compat)
|
|
7037
7037
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
7038
7038
|
offset = valueNode.range[2];
|
|
@@ -7123,7 +7123,7 @@ var require_resolve_end = __commonJS2({
|
|
|
7123
7123
|
let comment = "";
|
|
7124
7124
|
if (end) {
|
|
7125
7125
|
let hasSpace = false;
|
|
7126
|
-
let
|
|
7126
|
+
let sep7 = "";
|
|
7127
7127
|
for (const token of end) {
|
|
7128
7128
|
const { source: source2, type } = token;
|
|
7129
7129
|
switch (type) {
|
|
@@ -7137,13 +7137,13 @@ var require_resolve_end = __commonJS2({
|
|
|
7137
7137
|
if (!comment)
|
|
7138
7138
|
comment = cb;
|
|
7139
7139
|
else
|
|
7140
|
-
comment +=
|
|
7141
|
-
|
|
7140
|
+
comment += sep7 + cb;
|
|
7141
|
+
sep7 = "";
|
|
7142
7142
|
break;
|
|
7143
7143
|
}
|
|
7144
7144
|
case "newline":
|
|
7145
7145
|
if (comment)
|
|
7146
|
-
|
|
7146
|
+
sep7 += source2;
|
|
7147
7147
|
hasSpace = true;
|
|
7148
7148
|
break;
|
|
7149
7149
|
default:
|
|
@@ -7186,18 +7186,18 @@ var require_resolve_flow_collection = __commonJS2({
|
|
|
7186
7186
|
let offset = fc.offset + fc.start.source.length;
|
|
7187
7187
|
for (let i2 = 0; i2 < fc.items.length; ++i2) {
|
|
7188
7188
|
const collItem = fc.items[i2];
|
|
7189
|
-
const { start: start2, key, sep:
|
|
7189
|
+
const { start: start2, key, sep: sep7, value } = collItem;
|
|
7190
7190
|
const props = resolveProps.resolveProps(start2, {
|
|
7191
7191
|
flow: fcName,
|
|
7192
7192
|
indicator: "explicit-key-ind",
|
|
7193
|
-
next: key ??
|
|
7193
|
+
next: key ?? sep7?.[0],
|
|
7194
7194
|
offset,
|
|
7195
7195
|
onError,
|
|
7196
7196
|
parentIndent: fc.indent,
|
|
7197
7197
|
startOnNewline: false
|
|
7198
7198
|
});
|
|
7199
7199
|
if (!props.found) {
|
|
7200
|
-
if (!props.anchor && !props.tag && !
|
|
7200
|
+
if (!props.anchor && !props.tag && !sep7 && !value) {
|
|
7201
7201
|
if (i2 === 0 && props.comma)
|
|
7202
7202
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
7203
7203
|
else if (i2 < fc.items.length - 1)
|
|
@@ -7251,8 +7251,8 @@ var require_resolve_flow_collection = __commonJS2({
|
|
|
7251
7251
|
}
|
|
7252
7252
|
}
|
|
7253
7253
|
}
|
|
7254
|
-
if (!isMap && !
|
|
7255
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
7254
|
+
if (!isMap && !sep7 && !props.found) {
|
|
7255
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep7, null, props, onError);
|
|
7256
7256
|
coll.items.push(valueNode);
|
|
7257
7257
|
offset = valueNode.range[2];
|
|
7258
7258
|
if (isBlock(value))
|
|
@@ -7264,7 +7264,7 @@ var require_resolve_flow_collection = __commonJS2({
|
|
|
7264
7264
|
if (isBlock(key))
|
|
7265
7265
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
7266
7266
|
ctx.atKey = false;
|
|
7267
|
-
const valueProps = resolveProps.resolveProps(
|
|
7267
|
+
const valueProps = resolveProps.resolveProps(sep7 ?? [], {
|
|
7268
7268
|
flow: fcName,
|
|
7269
7269
|
indicator: "map-value-ind",
|
|
7270
7270
|
next: value,
|
|
@@ -7275,8 +7275,8 @@ var require_resolve_flow_collection = __commonJS2({
|
|
|
7275
7275
|
});
|
|
7276
7276
|
if (valueProps.found) {
|
|
7277
7277
|
if (!isMap && !props.found && ctx.options.strict) {
|
|
7278
|
-
if (
|
|
7279
|
-
for (const st of
|
|
7278
|
+
if (sep7)
|
|
7279
|
+
for (const st of sep7) {
|
|
7280
7280
|
if (st === valueProps.found)
|
|
7281
7281
|
break;
|
|
7282
7282
|
if (st.type === "newline") {
|
|
@@ -7293,7 +7293,7 @@ var require_resolve_flow_collection = __commonJS2({
|
|
|
7293
7293
|
else
|
|
7294
7294
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
7295
7295
|
}
|
|
7296
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
7296
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep7, null, valueProps, onError) : null;
|
|
7297
7297
|
if (valueNode) {
|
|
7298
7298
|
if (isBlock(value))
|
|
7299
7299
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -7473,7 +7473,7 @@ var require_resolve_block_scalar = __commonJS2({
|
|
|
7473
7473
|
chompStart = i2 + 1;
|
|
7474
7474
|
}
|
|
7475
7475
|
let value = "";
|
|
7476
|
-
let
|
|
7476
|
+
let sep7 = "";
|
|
7477
7477
|
let prevMoreIndented = false;
|
|
7478
7478
|
for (let i2 = 0; i2 < contentStart; ++i2)
|
|
7479
7479
|
value += lines[i2][0].slice(trimIndent) + "\n";
|
|
@@ -7490,24 +7490,24 @@ var require_resolve_block_scalar = __commonJS2({
|
|
|
7490
7490
|
indent = "";
|
|
7491
7491
|
}
|
|
7492
7492
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
7493
|
-
value +=
|
|
7494
|
-
|
|
7493
|
+
value += sep7 + indent.slice(trimIndent) + content;
|
|
7494
|
+
sep7 = "\n";
|
|
7495
7495
|
} else if (indent.length > trimIndent || content[0] === " ") {
|
|
7496
|
-
if (
|
|
7497
|
-
|
|
7498
|
-
else if (!prevMoreIndented &&
|
|
7499
|
-
|
|
7500
|
-
value +=
|
|
7501
|
-
|
|
7496
|
+
if (sep7 === " ")
|
|
7497
|
+
sep7 = "\n";
|
|
7498
|
+
else if (!prevMoreIndented && sep7 === "\n")
|
|
7499
|
+
sep7 = "\n\n";
|
|
7500
|
+
value += sep7 + indent.slice(trimIndent) + content;
|
|
7501
|
+
sep7 = "\n";
|
|
7502
7502
|
prevMoreIndented = true;
|
|
7503
7503
|
} else if (content === "") {
|
|
7504
|
-
if (
|
|
7504
|
+
if (sep7 === "\n")
|
|
7505
7505
|
value += "\n";
|
|
7506
7506
|
else
|
|
7507
|
-
|
|
7507
|
+
sep7 = "\n";
|
|
7508
7508
|
} else {
|
|
7509
|
-
value +=
|
|
7510
|
-
|
|
7509
|
+
value += sep7 + content;
|
|
7510
|
+
sep7 = " ";
|
|
7511
7511
|
prevMoreIndented = false;
|
|
7512
7512
|
}
|
|
7513
7513
|
}
|
|
@@ -7689,25 +7689,25 @@ var require_resolve_flow_scalar = __commonJS2({
|
|
|
7689
7689
|
if (!match)
|
|
7690
7690
|
return source2;
|
|
7691
7691
|
let res = match[1];
|
|
7692
|
-
let
|
|
7692
|
+
let sep7 = " ";
|
|
7693
7693
|
let pos = first.lastIndex;
|
|
7694
7694
|
line2.lastIndex = pos;
|
|
7695
7695
|
while (match = line2.exec(source2)) {
|
|
7696
7696
|
if (match[1] === "") {
|
|
7697
|
-
if (
|
|
7698
|
-
res +=
|
|
7697
|
+
if (sep7 === "\n")
|
|
7698
|
+
res += sep7;
|
|
7699
7699
|
else
|
|
7700
|
-
|
|
7700
|
+
sep7 = "\n";
|
|
7701
7701
|
} else {
|
|
7702
|
-
res +=
|
|
7703
|
-
|
|
7702
|
+
res += sep7 + match[1];
|
|
7703
|
+
sep7 = " ";
|
|
7704
7704
|
}
|
|
7705
7705
|
pos = line2.lastIndex;
|
|
7706
7706
|
}
|
|
7707
7707
|
const last = /[ \t]*(.*)/sy;
|
|
7708
7708
|
last.lastIndex = pos;
|
|
7709
7709
|
match = last.exec(source2);
|
|
7710
|
-
return res +
|
|
7710
|
+
return res + sep7 + (match?.[1] ?? "");
|
|
7711
7711
|
}
|
|
7712
7712
|
function doubleQuotedValue(source2, onError) {
|
|
7713
7713
|
let res = "";
|
|
@@ -8514,14 +8514,14 @@ var require_cst_stringify = __commonJS2({
|
|
|
8514
8514
|
}
|
|
8515
8515
|
}
|
|
8516
8516
|
}
|
|
8517
|
-
function stringifyItem({ start: start2, key, sep:
|
|
8517
|
+
function stringifyItem({ start: start2, key, sep: sep7, value }) {
|
|
8518
8518
|
let res = "";
|
|
8519
8519
|
for (const st of start2)
|
|
8520
8520
|
res += st.source;
|
|
8521
8521
|
if (key)
|
|
8522
8522
|
res += stringifyToken(key);
|
|
8523
|
-
if (
|
|
8524
|
-
for (const st of
|
|
8523
|
+
if (sep7)
|
|
8524
|
+
for (const st of sep7)
|
|
8525
8525
|
res += st.source;
|
|
8526
8526
|
if (value)
|
|
8527
8527
|
res += stringifyToken(value);
|
|
@@ -9671,18 +9671,18 @@ var require_parser = __commonJS2({
|
|
|
9671
9671
|
if (this.type === "map-value-ind") {
|
|
9672
9672
|
const prev = getPrevProps(this.peek(2));
|
|
9673
9673
|
const start2 = getFirstKeyStartProps(prev);
|
|
9674
|
-
let
|
|
9674
|
+
let sep7;
|
|
9675
9675
|
if (scalar.end) {
|
|
9676
|
-
|
|
9677
|
-
|
|
9676
|
+
sep7 = scalar.end;
|
|
9677
|
+
sep7.push(this.sourceToken);
|
|
9678
9678
|
delete scalar.end;
|
|
9679
9679
|
} else
|
|
9680
|
-
|
|
9680
|
+
sep7 = [this.sourceToken];
|
|
9681
9681
|
const map = {
|
|
9682
9682
|
type: "block-map",
|
|
9683
9683
|
offset: scalar.offset,
|
|
9684
9684
|
indent: scalar.indent,
|
|
9685
|
-
items: [{ start: start2, key: scalar, sep:
|
|
9685
|
+
items: [{ start: start2, key: scalar, sep: sep7 }]
|
|
9686
9686
|
};
|
|
9687
9687
|
this.onKeyLine = true;
|
|
9688
9688
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -9835,15 +9835,15 @@ var require_parser = __commonJS2({
|
|
|
9835
9835
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
9836
9836
|
const start3 = getFirstKeyStartProps(it.start);
|
|
9837
9837
|
const key = it.key;
|
|
9838
|
-
const
|
|
9839
|
-
|
|
9838
|
+
const sep7 = it.sep;
|
|
9839
|
+
sep7.push(this.sourceToken);
|
|
9840
9840
|
delete it.key;
|
|
9841
9841
|
delete it.sep;
|
|
9842
9842
|
this.stack.push({
|
|
9843
9843
|
type: "block-map",
|
|
9844
9844
|
offset: this.offset,
|
|
9845
9845
|
indent: this.indent,
|
|
9846
|
-
items: [{ start: start3, key, sep:
|
|
9846
|
+
items: [{ start: start3, key, sep: sep7 }]
|
|
9847
9847
|
});
|
|
9848
9848
|
} else if (start2.length > 0) {
|
|
9849
9849
|
it.sep = it.sep.concat(start2, this.sourceToken);
|
|
@@ -10037,13 +10037,13 @@ var require_parser = __commonJS2({
|
|
|
10037
10037
|
const prev = getPrevProps(parent);
|
|
10038
10038
|
const start2 = getFirstKeyStartProps(prev);
|
|
10039
10039
|
fixFlowSeqItems(fc);
|
|
10040
|
-
const
|
|
10041
|
-
|
|
10040
|
+
const sep7 = fc.end.splice(1, fc.end.length);
|
|
10041
|
+
sep7.push(this.sourceToken);
|
|
10042
10042
|
const map = {
|
|
10043
10043
|
type: "block-map",
|
|
10044
10044
|
offset: fc.offset,
|
|
10045
10045
|
indent: fc.indent,
|
|
10046
|
-
items: [{ start: start2, key: fc, sep:
|
|
10046
|
+
items: [{ start: start2, key: fc, sep: sep7 }]
|
|
10047
10047
|
};
|
|
10048
10048
|
this.onKeyLine = true;
|
|
10049
10049
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -13782,9 +13782,9 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
13782
13782
|
PatternStructure: 5
|
|
13783
13783
|
};
|
|
13784
13784
|
var QueryError = class _QueryError extends Error {
|
|
13785
|
-
constructor(
|
|
13786
|
-
super(_QueryError.formatMessage(
|
|
13787
|
-
this.kind =
|
|
13785
|
+
constructor(kind2, info2, index, length) {
|
|
13786
|
+
super(_QueryError.formatMessage(kind2, info2));
|
|
13787
|
+
this.kind = kind2;
|
|
13788
13788
|
this.info = info2;
|
|
13789
13789
|
this.index = index;
|
|
13790
13790
|
this.length = length;
|
|
@@ -13798,8 +13798,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
13798
13798
|
__name(this, "QueryError");
|
|
13799
13799
|
}
|
|
13800
13800
|
/** Formats an error message based on the error kind and info */
|
|
13801
|
-
static formatMessage(
|
|
13802
|
-
switch (
|
|
13801
|
+
static formatMessage(kind2, info2) {
|
|
13802
|
+
switch (kind2) {
|
|
13803
13803
|
case QueryErrorKind.NodeName:
|
|
13804
13804
|
return `Bad node name '${info2.word}'`;
|
|
13805
13805
|
case QueryErrorKind.FieldName:
|
|
@@ -13882,11 +13882,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
13882
13882
|
for (const c of captures) {
|
|
13883
13883
|
if (c.name === captureName) nodes.push(c.node.text);
|
|
13884
13884
|
}
|
|
13885
|
-
const test = /* @__PURE__ */ __name((
|
|
13886
|
-
return positive ? regex.test(
|
|
13885
|
+
const test = /* @__PURE__ */ __name((text2, positive) => {
|
|
13886
|
+
return positive ? regex.test(text2) : !regex.test(text2);
|
|
13887
13887
|
}, "test");
|
|
13888
13888
|
if (nodes.length === 0) return !isPositive;
|
|
13889
|
-
return matchAll2 ? nodes.every((
|
|
13889
|
+
return matchAll2 ? nodes.every((text2) => test(text2, isPositive)) : nodes.some((text2) => test(text2, isPositive));
|
|
13890
13890
|
});
|
|
13891
13891
|
}
|
|
13892
13892
|
__name(parseMatchPredicate, "parseMatchPredicate");
|
|
@@ -13916,7 +13916,7 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
13916
13916
|
if (c.name === captureName) nodes.push(c.node.text);
|
|
13917
13917
|
}
|
|
13918
13918
|
if (nodes.length === 0) return !isPositive;
|
|
13919
|
-
return nodes.every((
|
|
13919
|
+
return nodes.every((text2) => values.includes(text2)) === isPositive;
|
|
13920
13920
|
});
|
|
13921
13921
|
}
|
|
13922
13922
|
__name(parseAnyOfPredicate, "parseAnyOfPredicate");
|
|
@@ -14726,7 +14726,7 @@ var SECURITY_PATTERNS = [
|
|
|
14726
14726
|
/Dockerfile/
|
|
14727
14727
|
];
|
|
14728
14728
|
var PROD_SERVICE_URL = "https://ofcamwrjwrkazqvdchko.supabase.co/functions/v1";
|
|
14729
|
-
var DEFAULT_SERVICE_URL = "".length > 0 ? "" : PROD_SERVICE_URL;
|
|
14729
|
+
var DEFAULT_SERVICE_URL = "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1".length > 0 ? "https://wukeddyzpijoegyajtnc.supabase.co/functions/v1" : PROD_SERVICE_URL;
|
|
14730
14730
|
var GITHUB_CLIENT_ID = "Iv23li88HxAi3ZrbYzWh";
|
|
14731
14731
|
var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
14732
14732
|
var GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
@@ -15172,8 +15172,8 @@ function filterReviewable(files) {
|
|
|
15172
15172
|
const ext = (0, import_node_path4.extname)(f).slice(1);
|
|
15173
15173
|
if (ANALYZABLE_EXTENSIONS.has(ext)) return false;
|
|
15174
15174
|
if (REVIEWABLE_EXTENSIONS.has(ext)) return true;
|
|
15175
|
-
const
|
|
15176
|
-
if (REVIEWABLE_FILENAMES.has(
|
|
15175
|
+
const basename11 = f.split("/").pop() ?? "";
|
|
15176
|
+
if (REVIEWABLE_FILENAMES.has(basename11)) return true;
|
|
15177
15177
|
if (REVIEWABLE_PATH_PATTERNS.some((p) => p.test(f))) return true;
|
|
15178
15178
|
return false;
|
|
15179
15179
|
});
|
|
@@ -15712,11 +15712,11 @@ function startSpinner(label2, opts = {}) {
|
|
|
15712
15712
|
},
|
|
15713
15713
|
succeed(message) {
|
|
15714
15714
|
finish(() => {
|
|
15715
|
-
const
|
|
15715
|
+
const text2 = message ?? current;
|
|
15716
15716
|
const clock = showElapsed ? ` (${secondsSince(start2)})` : "";
|
|
15717
15717
|
stream.write(
|
|
15718
|
-
color ? ` ${GREEN2}\u2713${RESET} ${
|
|
15719
|
-
` : ` \u2713 ${
|
|
15718
|
+
color ? ` ${GREEN2}\u2713${RESET} ${text2}${DIM2}${clock}${RESET}
|
|
15719
|
+
` : ` \u2713 ${text2}${clock}
|
|
15720
15720
|
`
|
|
15721
15721
|
);
|
|
15722
15722
|
});
|
|
@@ -16278,8 +16278,8 @@ async function reportLoginOutcome(out2, opts = {}) {
|
|
|
16278
16278
|
printWarn(" repository will report that account. Remove its line from ~/.verity/credentials");
|
|
16279
16279
|
printWarn(" only if you want this repository on the login you just completed.");
|
|
16280
16280
|
} else {
|
|
16281
|
-
const
|
|
16282
|
-
printWarn(` Note: this repository has a ${
|
|
16281
|
+
const kind2 = rec.userId != null ? "superseded per-repository" : "anonymous project-specific";
|
|
16282
|
+
printWarn(` Note: this repository has a ${kind2} credential that takes`);
|
|
16283
16283
|
printWarn(" precedence here. Remove its line from ~/.verity/credentials to use your login.");
|
|
16284
16284
|
printWarn(' Until then, "verity login" in this repository re-runs the full GitHub flow');
|
|
16285
16285
|
printWarn(" every time.");
|
|
@@ -16287,6 +16287,15 @@ async function reportLoginOutcome(out2, opts = {}) {
|
|
|
16287
16287
|
}
|
|
16288
16288
|
}
|
|
16289
16289
|
|
|
16290
|
+
// src/lib/session-env.ts
|
|
16291
|
+
function envSessionId(env = process.env) {
|
|
16292
|
+
for (const name2 of ["CLAUDE_SESSION_ID", "CLAUDE_CODE_SESSION_ID"]) {
|
|
16293
|
+
const value = env[name2];
|
|
16294
|
+
if (value) return value;
|
|
16295
|
+
}
|
|
16296
|
+
return void 0;
|
|
16297
|
+
}
|
|
16298
|
+
|
|
16290
16299
|
// src/commands/login.ts
|
|
16291
16300
|
function registerLoginCommand(program2) {
|
|
16292
16301
|
program2.command("login").description("Log in to Verity (one GitHub login grants access to all your repositories)").option("--force", "Re-authenticate even if already logged in").option("--start", "Show the GitHub code and return at once (finish with --finish); prints JSON").option("--finish", "Wait for approval of the code --start showed, then log in; prints JSON").option("--wait <seconds>", "With --finish: how long to wait for approval before returning", "100").option("--cancel", "Discard a code --start showed that will not be approved").action(async (opts) => {
|
|
@@ -16303,7 +16312,7 @@ function registerLoginCommand(program2) {
|
|
|
16303
16312
|
return;
|
|
16304
16313
|
}
|
|
16305
16314
|
const split = !!(opts.start || opts.finish);
|
|
16306
|
-
if (!split && !process.stdin.isTTY && (process.env.CLAUDECODE ||
|
|
16315
|
+
if (!split && !process.stdin.isTTY && (process.env.CLAUDECODE || envSessionId())) {
|
|
16307
16316
|
printWarn("Inside a Claude Code session the code below may not be visible until this command ends.");
|
|
16308
16317
|
printWarn(' Use "verity login --start", then "verity login --finish" once it is approved.');
|
|
16309
16318
|
}
|
|
@@ -16851,6 +16860,7 @@ var VERITY_SESSION_END_HOOK = {
|
|
|
16851
16860
|
command: "verity session end"
|
|
16852
16861
|
};
|
|
16853
16862
|
var GUARD_TIMEOUT = 300;
|
|
16863
|
+
var GUARD_TIMEOUT_MS = GUARD_TIMEOUT * 1e3;
|
|
16854
16864
|
function buildGuardHook(on) {
|
|
16855
16865
|
return {
|
|
16856
16866
|
type: "command",
|
|
@@ -17434,13 +17444,13 @@ function scrub(s) {
|
|
|
17434
17444
|
var installed = false;
|
|
17435
17445
|
var wroteBanner = false;
|
|
17436
17446
|
var banner = "";
|
|
17437
|
-
function append(
|
|
17447
|
+
function append(text2) {
|
|
17438
17448
|
try {
|
|
17439
17449
|
const dir = projectPath(DEBUG_LOG_DIR);
|
|
17440
17450
|
const file = projectPath(STDERR_LOG_FILE);
|
|
17441
17451
|
(0, import_node_fs9.mkdirSync)(dir, { recursive: true });
|
|
17442
17452
|
rotateIfNeeded(file);
|
|
17443
|
-
(0, import_node_fs9.appendFileSync)(file,
|
|
17453
|
+
(0, import_node_fs9.appendFileSync)(file, text2);
|
|
17444
17454
|
} catch {
|
|
17445
17455
|
}
|
|
17446
17456
|
}
|
|
@@ -17462,19 +17472,19 @@ function installStderrLog(cmd, argv, version) {
|
|
|
17462
17472
|
const result = original(...args2);
|
|
17463
17473
|
try {
|
|
17464
17474
|
const chunk = args2[0];
|
|
17465
|
-
const
|
|
17475
|
+
const text2 = typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf-8") : String(chunk);
|
|
17466
17476
|
ensureBanner();
|
|
17467
|
-
append(scrub(
|
|
17477
|
+
append(scrub(text2));
|
|
17468
17478
|
} catch {
|
|
17469
17479
|
}
|
|
17470
17480
|
return result;
|
|
17471
17481
|
};
|
|
17472
17482
|
process.stderr.write = tee;
|
|
17473
17483
|
}
|
|
17474
|
-
function logToFileOnly(
|
|
17484
|
+
function logToFileOnly(text2) {
|
|
17475
17485
|
if (!installed) return;
|
|
17476
17486
|
ensureBanner();
|
|
17477
|
-
append(
|
|
17487
|
+
append(text2.endsWith("\n") ? text2 : `${text2}
|
|
17478
17488
|
`);
|
|
17479
17489
|
}
|
|
17480
17490
|
|
|
@@ -17606,9 +17616,9 @@ function pointsAtVerity(src) {
|
|
|
17606
17616
|
}
|
|
17607
17617
|
function describeSource(src) {
|
|
17608
17618
|
if (!src || typeof src !== "object") return "an unrecognised source";
|
|
17609
|
-
const
|
|
17619
|
+
const kind2 = typeof src.source === "string" ? src.source : "unknown";
|
|
17610
17620
|
const target = typeof src.repo === "string" && src.repo || typeof src.url === "string" && src.url || typeof src.path === "string" && src.path || "";
|
|
17611
|
-
return target ? `${
|
|
17621
|
+
return target ? `${kind2} \u2192 ${target}` : kind2;
|
|
17612
17622
|
}
|
|
17613
17623
|
function legacyMarketplaceInstall() {
|
|
17614
17624
|
const plugins = readJsonFile((0, import_node_path11.join)(claudeConfigDir(), "plugins", "installed_plugins.json"))?.plugins;
|
|
@@ -18045,8 +18055,8 @@ var import_promises5 = require("node:fs/promises");
|
|
|
18045
18055
|
var import_node_fs12 = require("node:fs");
|
|
18046
18056
|
var import_node_child_process6 = require("node:child_process");
|
|
18047
18057
|
var import_node_crypto2 = require("node:crypto");
|
|
18048
|
-
function stripImageReferences(
|
|
18049
|
-
return
|
|
18058
|
+
function stripImageReferences(text2) {
|
|
18059
|
+
return text2.replace(/\[Image #\d+\]/g, "[screenshot \u2014 not available for review]");
|
|
18050
18060
|
}
|
|
18051
18061
|
function bufferTmpPath() {
|
|
18052
18062
|
return `${CONVERSATION_BUFFER_FILE}.${process.pid}.${(0, import_node_crypto2.randomBytes)(4).toString("hex")}.tmp`;
|
|
@@ -18532,8 +18542,8 @@ function slugify(s) {
|
|
|
18532
18542
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
18533
18543
|
}
|
|
18534
18544
|
function orgNodePath(node) {
|
|
18535
|
-
const
|
|
18536
|
-
return `${
|
|
18545
|
+
const kind2 = ORG_KINDS.includes(node.kind) ? node.kind : "domain";
|
|
18546
|
+
return `${kind2}/${slugify(node.title) || "claim"}-${node.tag_id.replace(/-/g, "").slice(0, 8)}.md`;
|
|
18537
18547
|
}
|
|
18538
18548
|
function renderOrgNode(node, orgName) {
|
|
18539
18549
|
const fm = [
|
|
@@ -18622,10 +18632,10 @@ function renderIndex(orgName, nodes) {
|
|
|
18622
18632
|
];
|
|
18623
18633
|
const byKind = /* @__PURE__ */ new Map();
|
|
18624
18634
|
for (const n of nodes) byKind.set(n.kind, [...byKind.get(n.kind) ?? [], n]);
|
|
18625
|
-
for (const
|
|
18626
|
-
const list2 = byKind.get(
|
|
18635
|
+
for (const kind2 of ORG_KINDS) {
|
|
18636
|
+
const list2 = byKind.get(kind2);
|
|
18627
18637
|
if (!list2?.length) continue;
|
|
18628
|
-
lines.push(`## ${
|
|
18638
|
+
lines.push(`## ${kind2}/ (${list2.length})`);
|
|
18629
18639
|
for (const n of list2) lines.push(`- [[${orgNodePath(n).split("/")[1].replace(/\.md$/, "")}]] \u2014 ${n.title} \xB7 ${n.origin}`);
|
|
18630
18640
|
lines.push("");
|
|
18631
18641
|
}
|
|
@@ -18684,8 +18694,8 @@ async function readOrgMirror(remote = requestRemote()) {
|
|
|
18684
18694
|
const dir = orgMirrorDir(remote);
|
|
18685
18695
|
if (!dir || !(0, import_node_fs14.existsSync)(dir)) return [];
|
|
18686
18696
|
const out2 = [];
|
|
18687
|
-
for (const
|
|
18688
|
-
const kindDir = (0, import_node_path14.join)(dir,
|
|
18697
|
+
for (const kind2 of ORG_KINDS) {
|
|
18698
|
+
const kindDir = (0, import_node_path14.join)(dir, kind2);
|
|
18689
18699
|
if (!(0, import_node_fs14.existsSync)(kindDir)) continue;
|
|
18690
18700
|
let files;
|
|
18691
18701
|
try {
|
|
@@ -18912,9 +18922,9 @@ var STOPWORDS = /* @__PURE__ */ new Set([
|
|
|
18912
18922
|
"within",
|
|
18913
18923
|
"without"
|
|
18914
18924
|
]);
|
|
18915
|
-
function tokenize(
|
|
18925
|
+
function tokenize(text2) {
|
|
18916
18926
|
return new Set(
|
|
18917
|
-
|
|
18927
|
+
text2.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w))
|
|
18918
18928
|
);
|
|
18919
18929
|
}
|
|
18920
18930
|
function jaccardKeywords(a, b) {
|
|
@@ -18953,16 +18963,16 @@ function relevance(node, ctx) {
|
|
|
18953
18963
|
return { score, via: { glob: globHit, tag: tagScore, text: textScore } };
|
|
18954
18964
|
}
|
|
18955
18965
|
var KIND_POOL_STRENGTH = 20;
|
|
18956
|
-
function priorFor(
|
|
18957
|
-
const base = KIND_PRIOR_MEAN[
|
|
18966
|
+
function priorFor(kind2, pooled) {
|
|
18967
|
+
const base = KIND_PRIOR_MEAN[kind2] ?? DEFAULT_PRIOR_MEAN;
|
|
18958
18968
|
const a = pooled ? Math.max(0, pooled.alpha) : 0;
|
|
18959
18969
|
const b = pooled ? Math.max(0, pooled.beta) : 0;
|
|
18960
|
-
const mean = pooled &&
|
|
18970
|
+
const mean = pooled && kind2 !== "integration" ? (KIND_POOL_STRENGTH * base + a) / (KIND_POOL_STRENGTH + a + b) : base;
|
|
18961
18971
|
return { alpha: mean * PRIOR_STRENGTH, beta: (1 - mean) * PRIOR_STRENGTH };
|
|
18962
18972
|
}
|
|
18963
|
-
function posteriorFor(
|
|
18964
|
-
const p = priorFor(
|
|
18965
|
-
if (!own ||
|
|
18973
|
+
function posteriorFor(kind2, own, pooled) {
|
|
18974
|
+
const p = priorFor(kind2, pooled);
|
|
18975
|
+
if (!own || kind2 === "integration") return p;
|
|
18966
18976
|
return { alpha: p.alpha + Math.max(0, own.alpha), beta: p.beta + Math.max(0, own.beta) };
|
|
18967
18977
|
}
|
|
18968
18978
|
function posteriorMean(p) {
|
|
@@ -18991,9 +19001,9 @@ var MAX_BUDGET_TOKENS = 4e3;
|
|
|
18991
19001
|
var MAX_NODE_FILE_BYTES = 64 * 1024;
|
|
18992
19002
|
var MIN_SCORE = RELEVANCE_FLOOR * 0.5;
|
|
18993
19003
|
var ORG_MIN_SHARED_TERMS = 2;
|
|
18994
|
-
function orgTerms(
|
|
19004
|
+
function orgTerms(text2) {
|
|
18995
19005
|
return new Set(
|
|
18996
|
-
|
|
19006
|
+
text2.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2)
|
|
18997
19007
|
);
|
|
18998
19008
|
}
|
|
18999
19009
|
function sharedTerms(a, b) {
|
|
@@ -19276,15 +19286,15 @@ function runHook(hooks) {
|
|
|
19276
19286
|
return false;
|
|
19277
19287
|
}
|
|
19278
19288
|
}
|
|
19279
|
-
function appendInRoot(root, name2,
|
|
19289
|
+
function appendInRoot(root, name2, text2, hooks = {}) {
|
|
19280
19290
|
return writeVerified(root, name2, hooks, true, (fd) => {
|
|
19281
|
-
(0, import_node_fs17.writeSync)(fd,
|
|
19291
|
+
(0, import_node_fs17.writeSync)(fd, text2);
|
|
19282
19292
|
});
|
|
19283
19293
|
}
|
|
19284
|
-
function replaceInRoot(root, name2,
|
|
19294
|
+
function replaceInRoot(root, name2, text2, hooks = {}) {
|
|
19285
19295
|
return writeVerified(root, name2, hooks, false, (fd) => {
|
|
19286
19296
|
(0, import_node_fs17.ftruncateSync)(fd, 0);
|
|
19287
|
-
(0, import_node_fs17.writeSync)(fd,
|
|
19297
|
+
(0, import_node_fs17.writeSync)(fd, text2, 0);
|
|
19288
19298
|
});
|
|
19289
19299
|
}
|
|
19290
19300
|
|
|
@@ -19474,12 +19484,12 @@ function ensureVerityGitignore() {
|
|
|
19474
19484
|
if (hasSupersededMemory && !memoryIsCommitted) {
|
|
19475
19485
|
next = fenceMemoryLines(next);
|
|
19476
19486
|
}
|
|
19477
|
-
let
|
|
19487
|
+
let text2 = next.join("\n");
|
|
19478
19488
|
if (!hasMarker) {
|
|
19479
|
-
const
|
|
19480
|
-
|
|
19489
|
+
const sep7 = text2 === "" ? "" : text2.endsWith("\n") ? "\n" : "\n\n";
|
|
19490
|
+
text2 = text2 + sep7 + VERITY_GITIGNORE_BLOCK;
|
|
19481
19491
|
}
|
|
19482
|
-
if (
|
|
19492
|
+
if (text2 !== content) (0, import_node_fs19.writeFileSync)(".gitignore", text2);
|
|
19483
19493
|
return verified(
|
|
19484
19494
|
memoryIsCommitted ? "memory-tracked" : hasSupersededMemory ? "memory-fenced" : needsRepair ? "repaired" : "added"
|
|
19485
19495
|
);
|
|
@@ -19505,13 +19515,13 @@ function writeFencedBlock() {
|
|
|
19505
19515
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
19506
19516
|
let lines = content.split("\n").map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l);
|
|
19507
19517
|
lines = fenceMemoryLines(lines);
|
|
19508
|
-
let
|
|
19518
|
+
let text2 = lines.join("\n");
|
|
19509
19519
|
if (!hasMarker) {
|
|
19510
|
-
const
|
|
19511
|
-
|
|
19520
|
+
const sep7 = text2 === "" ? "" : text2.endsWith("\n") ? "\n" : "\n\n";
|
|
19521
|
+
text2 = text2 + sep7 + VERITY_GITIGNORE_BLOCK;
|
|
19512
19522
|
}
|
|
19513
19523
|
try {
|
|
19514
|
-
(0, import_node_fs19.writeFileSync)(".gitignore",
|
|
19524
|
+
(0, import_node_fs19.writeFileSync)(".gitignore", text2);
|
|
19515
19525
|
return true;
|
|
19516
19526
|
} catch {
|
|
19517
19527
|
return false;
|
|
@@ -19558,8 +19568,8 @@ function keepMemoryTracked() {
|
|
|
19558
19568
|
}
|
|
19559
19569
|
if (content.includes(MEMORY_OPT_OUT_MARKER)) return "already";
|
|
19560
19570
|
try {
|
|
19561
|
-
const
|
|
19562
|
-
(0, import_node_fs19.writeFileSync)(".gitignore", content +
|
|
19571
|
+
const sep7 = content === "" ? "" : content.endsWith("\n") ? "\n" : "\n\n";
|
|
19572
|
+
(0, import_node_fs19.writeFileSync)(".gitignore", content + sep7 + MEMORY_OPT_OUT_STANZA);
|
|
19563
19573
|
} catch {
|
|
19564
19574
|
return "failed";
|
|
19565
19575
|
}
|
|
@@ -20002,7 +20012,7 @@ async function regenerateIndex() {
|
|
|
20002
20012
|
try {
|
|
20003
20013
|
const content = await (0, import_promises9.readFile)((0, import_node_path19.join)(domainDir, file), "utf-8");
|
|
20004
20014
|
const title = pickFrontmatter(content, "title") ?? slug;
|
|
20005
|
-
const
|
|
20015
|
+
const kind2 = pickFrontmatter(content, "kind") ?? "-";
|
|
20006
20016
|
const confidence = pickFrontmatter(content, "confidence");
|
|
20007
20017
|
const globs = pickFrontmatterArray(content, "file_globs");
|
|
20008
20018
|
const status = pickFrontmatter(content, "status") ?? "active";
|
|
@@ -20010,7 +20020,7 @@ async function regenerateIndex() {
|
|
|
20010
20020
|
const globPart = globs.length > 0 ? ` \xB7 scope: \`${globs.slice(0, 3).join("`, `")}\`` : "";
|
|
20011
20021
|
const statusPart = status !== "active" ? ` \xB7 *${status}*` : "";
|
|
20012
20022
|
lines.push(`- [[${slug}]] \u2014 **${title}**`);
|
|
20013
|
-
lines.push(` *${
|
|
20023
|
+
lines.push(` *${kind2}*${confPart}${globPart}${statusPart}`);
|
|
20014
20024
|
} catch {
|
|
20015
20025
|
lines.push(`- [[${slug}]]`);
|
|
20016
20026
|
}
|
|
@@ -20490,26 +20500,26 @@ var CLAUDE_MD_PROSE_LEGACY = [
|
|
|
20490
20500
|
"superseded \u2014 ignore them unless investigating history."
|
|
20491
20501
|
].join("\n");
|
|
20492
20502
|
var PRESERVE_PLACEHOLDER = "<!-- Add binding, hand-curated guidance here; it survives Verity regeneration. -->";
|
|
20493
|
-
function* scanLines(
|
|
20503
|
+
function* scanLines(text2) {
|
|
20494
20504
|
let offset = 0;
|
|
20495
20505
|
let inFence = false;
|
|
20496
|
-
for (const line2 of
|
|
20506
|
+
for (const line2 of text2.split("\n")) {
|
|
20497
20507
|
const isFence = /^(`{3,}|~{3,})/.test(line2.trim());
|
|
20498
20508
|
if (isFence) inFence = !inFence;
|
|
20499
20509
|
yield { line: line2, start: offset, inFence: inFence || isFence };
|
|
20500
20510
|
offset += line2.length + 1;
|
|
20501
20511
|
}
|
|
20502
20512
|
}
|
|
20503
|
-
function findMarker(
|
|
20504
|
-
for (const { line: line2, start: start2, inFence } of scanLines(
|
|
20513
|
+
function findMarker(text2, marker, from = 0) {
|
|
20514
|
+
for (const { line: line2, start: start2, inFence } of scanLines(text2)) {
|
|
20505
20515
|
if (!inFence && start2 >= from && line2.startsWith(marker)) {
|
|
20506
20516
|
return start2;
|
|
20507
20517
|
}
|
|
20508
20518
|
}
|
|
20509
20519
|
return -1;
|
|
20510
20520
|
}
|
|
20511
|
-
function hasLegacyMemoryBlock(
|
|
20512
|
-
return findMarker(
|
|
20521
|
+
function hasLegacyMemoryBlock(text2) {
|
|
20522
|
+
return findMarker(text2, LEGACY_MD_START) !== -1;
|
|
20513
20523
|
}
|
|
20514
20524
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
20515
20525
|
const claudeMdPath = (0, import_node_path19.join)(cwd, "CLAUDE.md");
|
|
@@ -20709,10 +20719,10 @@ var STOP = /* @__PURE__ */ new Set([
|
|
|
20709
20719
|
"verify",
|
|
20710
20720
|
"check"
|
|
20711
20721
|
]);
|
|
20712
|
-
function pendingTokens(
|
|
20713
|
-
if (!
|
|
20722
|
+
function pendingTokens(text2) {
|
|
20723
|
+
if (!text2 || typeof text2 !== "string") return [];
|
|
20714
20724
|
const out2 = /* @__PURE__ */ new Set();
|
|
20715
|
-
for (const raw of
|
|
20725
|
+
for (const raw of text2.toLowerCase().split(/[^a-z0-9]+/)) {
|
|
20716
20726
|
if (raw.length <= 3) continue;
|
|
20717
20727
|
if (STOP.has(raw)) continue;
|
|
20718
20728
|
out2.add(raw);
|
|
@@ -20727,8 +20737,8 @@ function overlapCoefficient(a, b) {
|
|
|
20727
20737
|
for (const t of a) if (setB.has(t)) shared++;
|
|
20728
20738
|
return shared / Math.min(a.length, b.length);
|
|
20729
20739
|
}
|
|
20730
|
-
function isRepeatOfAny(
|
|
20731
|
-
const tokens = pendingTokens(
|
|
20740
|
+
function isRepeatOfAny(text2, priorFingerprints, threshold = REPEAT_THRESHOLD) {
|
|
20741
|
+
const tokens = pendingTokens(text2);
|
|
20732
20742
|
if (tokens.length === 0) return false;
|
|
20733
20743
|
return priorFingerprints.some((prior) => overlapCoefficient(tokens, prior) >= threshold);
|
|
20734
20744
|
}
|
|
@@ -21418,8 +21428,8 @@ function assessContinuity(i2) {
|
|
|
21418
21428
|
// src/lib/dossier/reanchor.ts
|
|
21419
21429
|
var import_node_crypto8 = require("node:crypto");
|
|
21420
21430
|
var import_node_fs25 = require("node:fs");
|
|
21421
|
-
function lineSha(
|
|
21422
|
-
return (0, import_node_crypto8.createHash)("sha256").update(
|
|
21431
|
+
function lineSha(text2) {
|
|
21432
|
+
return (0, import_node_crypto8.createHash)("sha256").update(text2.trim()).digest("hex").slice(0, HASH_WIDTH);
|
|
21423
21433
|
}
|
|
21424
21434
|
function fileHash(path) {
|
|
21425
21435
|
try {
|
|
@@ -21892,10 +21902,10 @@ function recordGoal(d, prompt, source2 = "prompt") {
|
|
|
21892
21902
|
appendEvent(d, { k: "goal_continue", text: prompt.slice(0, 64) });
|
|
21893
21903
|
return;
|
|
21894
21904
|
}
|
|
21895
|
-
const
|
|
21905
|
+
const text2 = prompt.slice(0, MAX_GOAL_CHARS);
|
|
21896
21906
|
appendEvent(d, {
|
|
21897
21907
|
k: "goal",
|
|
21898
|
-
text,
|
|
21908
|
+
text: text2,
|
|
21899
21909
|
text_len: prompt.length,
|
|
21900
21910
|
source: source2,
|
|
21901
21911
|
...prompt.length > MAX_GOAL_CHARS && { truncated: true }
|
|
@@ -22053,8 +22063,8 @@ function toRegister(severity) {
|
|
|
22053
22063
|
return "NOTE";
|
|
22054
22064
|
}
|
|
22055
22065
|
}
|
|
22056
|
-
function recordMark(d,
|
|
22057
|
-
appendEvent(d, { k: "mark", kind, from: from ?? null, to: to ?? null });
|
|
22066
|
+
function recordMark(d, kind2, from, to) {
|
|
22067
|
+
appendEvent(d, { k: "mark", kind: kind2, from: from ?? null, to: to ?? null });
|
|
22058
22068
|
}
|
|
22059
22069
|
function recordCapabilities(d, c, known) {
|
|
22060
22070
|
const put = (field, value, tier) => {
|
|
@@ -22149,13 +22159,13 @@ function registerIntentCommands(program2) {
|
|
|
22149
22159
|
if (!prompt) {
|
|
22150
22160
|
process.exit(0);
|
|
22151
22161
|
}
|
|
22152
|
-
if (deferredToPlugin("intent capture", event.session_id ??
|
|
22162
|
+
if (deferredToPlugin("intent capture", event.session_id ?? envSessionId() ?? null)) {
|
|
22153
22163
|
process.exit(0);
|
|
22154
22164
|
}
|
|
22155
22165
|
const isPrimitive = isSlashCommand(prompt);
|
|
22156
22166
|
const authForScope = await resolveToken(program2.opts().token);
|
|
22157
22167
|
const scopeToken = authForScope.ok ? authForScope.data.token : void 0;
|
|
22158
|
-
const scopeSession = event.session_id ||
|
|
22168
|
+
const scopeSession = event.session_id || envSessionId() || "";
|
|
22159
22169
|
if (!isPrimitive) await appendToConversationBuffer(prompt, sessionScopeKey(scopeToken, scopeSession));
|
|
22160
22170
|
if (!isPrimitive) {
|
|
22161
22171
|
try {
|
|
@@ -22875,7 +22885,12 @@ function registerLifecycleCommands(program2) {
|
|
|
22875
22885
|
}
|
|
22876
22886
|
if (!verityConfigured()) process.exit(0);
|
|
22877
22887
|
const event = await readHookStdin();
|
|
22878
|
-
const
|
|
22888
|
+
const resolved = resolveHookSession(opts.sessionId, event, envSessionId());
|
|
22889
|
+
if (!resolved.ok) {
|
|
22890
|
+
logEvent("lifecycle_session_flag_refused", { command: "compact" });
|
|
22891
|
+
process.exit(0);
|
|
22892
|
+
}
|
|
22893
|
+
const sessionId = resolved.sessionId;
|
|
22879
22894
|
if (deferredToPlugin("compact", sessionId)) process.exit(0);
|
|
22880
22895
|
const globals = program2.opts();
|
|
22881
22896
|
const tok = await resolveToken(globals.token);
|
|
@@ -22904,9 +22919,14 @@ function registerLifecycleCommands(program2) {
|
|
|
22904
22919
|
}
|
|
22905
22920
|
if (!verityConfigured()) process.exit(0);
|
|
22906
22921
|
const event = await readHookStdin();
|
|
22907
|
-
const
|
|
22922
|
+
const resolved = resolveHookSession(opts.sessionId, event, envSessionId());
|
|
22923
|
+
if (!resolved.ok) {
|
|
22924
|
+
logEvent("lifecycle_session_flag_refused", { command: "session end" });
|
|
22925
|
+
process.exit(0);
|
|
22926
|
+
}
|
|
22927
|
+
const sessionId = resolved.sessionId;
|
|
22908
22928
|
if (deferredToPlugin("session end", sessionId)) process.exit(0);
|
|
22909
|
-
const reason = opts.reason ?? event.session_end_reason ?? event.reason ?? "other";
|
|
22929
|
+
const reason = hookWord(opts.reason) ?? event.session_end_reason ?? event.reason ?? "other";
|
|
22910
22930
|
if (reason === "clear") {
|
|
22911
22931
|
writeCarry(sessionId ?? void 0, getCurrentCommit());
|
|
22912
22932
|
}
|
|
@@ -22985,25 +23005,61 @@ function buildCompactionContext(session) {
|
|
|
22985
23005
|
`${r.projection.fold.refused} earlier finding(s) were dropped because the code they pointed at no longer matches. They are resolved; do not revisit them.`
|
|
22986
23006
|
);
|
|
22987
23007
|
}
|
|
22988
|
-
const
|
|
22989
|
-
if (
|
|
23008
|
+
const text2 = lines.join("\n");
|
|
23009
|
+
if (text2.length <= MAX_CHARS) return text2;
|
|
22990
23010
|
const trimmed = [...lines.slice(0, 5), ...lines.slice(5, 5 + 2)].join("\n");
|
|
22991
23011
|
return trimmed.length <= MAX_CHARS ? trimmed : null;
|
|
22992
23012
|
}
|
|
23013
|
+
var MAX_HOOK_EVENT_BYTES = 64 * 1024;
|
|
23014
|
+
var SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
23015
|
+
var HOOK_WORD = /^[a-z][a-z_]{0,63}$/;
|
|
23016
|
+
function isHookSessionId(value) {
|
|
23017
|
+
return typeof value === "string" && SESSION_ID.test(value);
|
|
23018
|
+
}
|
|
23019
|
+
function hookWord(value) {
|
|
23020
|
+
return typeof value === "string" && HOOK_WORD.test(value) ? value : void 0;
|
|
23021
|
+
}
|
|
23022
|
+
function resolveHookSession(flag, event, env) {
|
|
23023
|
+
if (flag !== void 0) return isHookSessionId(flag) ? { ok: true, sessionId: flag } : { ok: false };
|
|
23024
|
+
if (event.session_id) return { ok: true, sessionId: event.session_id };
|
|
23025
|
+
return { ok: true, sessionId: isHookSessionId(env) ? env : null };
|
|
23026
|
+
}
|
|
23027
|
+
function parseHookEvent(raw) {
|
|
23028
|
+
let data;
|
|
23029
|
+
try {
|
|
23030
|
+
data = JSON.parse(raw.trim() || "{}");
|
|
23031
|
+
} catch {
|
|
23032
|
+
return {};
|
|
23033
|
+
}
|
|
23034
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return {};
|
|
23035
|
+
const o = data;
|
|
23036
|
+
const event = {};
|
|
23037
|
+
if (isHookSessionId(o.session_id)) event.session_id = o.session_id;
|
|
23038
|
+
const compaction = hookWord(o.compaction_type);
|
|
23039
|
+
if (compaction) event.compaction_type = compaction;
|
|
23040
|
+
const endReason = hookWord(o.session_end_reason);
|
|
23041
|
+
if (endReason) event.session_end_reason = endReason;
|
|
23042
|
+
const reason = hookWord(o.reason);
|
|
23043
|
+
if (reason) event.reason = reason;
|
|
23044
|
+
return event;
|
|
23045
|
+
}
|
|
22993
23046
|
async function readHookStdin() {
|
|
22994
23047
|
try {
|
|
22995
23048
|
if (process.stdin.isTTY) return {};
|
|
22996
23049
|
const chunks = [];
|
|
23050
|
+
let size = 0;
|
|
22997
23051
|
const timeout = new Promise((resolve9) => setTimeout(() => resolve9({}), 500));
|
|
22998
23052
|
const read2 = new Promise((resolve9) => {
|
|
22999
|
-
process.stdin.on("data", (c) =>
|
|
23000
|
-
|
|
23001
|
-
|
|
23002
|
-
|
|
23003
|
-
} catch {
|
|
23053
|
+
process.stdin.on("data", (c) => {
|
|
23054
|
+
size += c.length;
|
|
23055
|
+
if (size > MAX_HOOK_EVENT_BYTES) {
|
|
23056
|
+
process.stdin.destroy();
|
|
23004
23057
|
resolve9({});
|
|
23058
|
+
return;
|
|
23005
23059
|
}
|
|
23060
|
+
chunks.push(c);
|
|
23006
23061
|
});
|
|
23062
|
+
process.stdin.on("end", () => resolve9(parseHookEvent(Buffer.concat(chunks).toString("utf-8"))));
|
|
23007
23063
|
process.stdin.on("error", () => resolve9({}));
|
|
23008
23064
|
process.stdin.resume();
|
|
23009
23065
|
});
|
|
@@ -23268,9 +23324,9 @@ function declaredDependencies(root, files) {
|
|
|
23268
23324
|
for (const path of pythonManifests) {
|
|
23269
23325
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
23270
23326
|
try {
|
|
23271
|
-
const
|
|
23272
|
-
for (const m of
|
|
23273
|
-
for (const line2 of
|
|
23327
|
+
const text2 = (0, import_node_fs31.readFileSync)(path, "utf-8");
|
|
23328
|
+
for (const m of text2.matchAll(/^\s*["']?([A-Za-z][A-Za-z0-9._-]+)/gm)) names2.push(m[1]);
|
|
23329
|
+
for (const line2 of text2.split("\n")) {
|
|
23274
23330
|
if (!/dependencies\s*=/.test(line2)) continue;
|
|
23275
23331
|
for (const m of line2.matchAll(/["']([A-Za-z][A-Za-z0-9._-]+)/g)) names2.push(m[1]);
|
|
23276
23332
|
}
|
|
@@ -23284,8 +23340,8 @@ function declaredDependencies(root, files) {
|
|
|
23284
23340
|
for (const path of goMods) {
|
|
23285
23341
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
23286
23342
|
try {
|
|
23287
|
-
const
|
|
23288
|
-
for (const m of
|
|
23343
|
+
const text2 = (0, import_node_fs31.readFileSync)(path, "utf-8");
|
|
23344
|
+
for (const m of text2.matchAll(/^\s+([\w.-]+\/[\w./-]+)\s+v/gm)) {
|
|
23289
23345
|
names2.push(m[1].replace(/^github\.com\//, ""));
|
|
23290
23346
|
}
|
|
23291
23347
|
} catch {
|
|
@@ -23295,8 +23351,8 @@ function declaredDependencies(root, files) {
|
|
|
23295
23351
|
const path = (0, import_node_path28.join)(root, file);
|
|
23296
23352
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
23297
23353
|
try {
|
|
23298
|
-
const
|
|
23299
|
-
for (const m of
|
|
23354
|
+
const text2 = (0, import_node_fs31.readFileSync)(path, "utf-8");
|
|
23355
|
+
for (const m of text2.matchAll(/["'<]([A-Za-z][A-Za-z0-9._-]{2,})["'>]/g)) names2.push(m[1]);
|
|
23300
23356
|
} catch {
|
|
23301
23357
|
}
|
|
23302
23358
|
}
|
|
@@ -23827,8 +23883,8 @@ async function correctVerityMdVersion(opts) {
|
|
|
23827
23883
|
origin: { kind: "synthesized", tools: opts.tools }
|
|
23828
23884
|
}));
|
|
23829
23885
|
}
|
|
23830
|
-
async function writeFileTo(
|
|
23831
|
-
const target = projectPath(
|
|
23886
|
+
async function writeFileTo(relative7, body2) {
|
|
23887
|
+
const target = projectPath(relative7);
|
|
23832
23888
|
await (0, import_promises10.mkdir)((0, import_node_path29.dirname)(target), { recursive: true });
|
|
23833
23889
|
await (0, import_promises10.writeFile)(target, body2);
|
|
23834
23890
|
}
|
|
@@ -24907,7 +24963,7 @@ function registerStatusCommand(program2) {
|
|
|
24907
24963
|
{
|
|
24908
24964
|
const tokenForScope = tokenResult.data.token;
|
|
24909
24965
|
const found = resolveIgnoreState(
|
|
24910
|
-
ignoreStateKeys(tokenForScope,
|
|
24966
|
+
ignoreStateKeys(tokenForScope, envSessionId())
|
|
24911
24967
|
);
|
|
24912
24968
|
const now = Math.floor(Date.now() / 1e3);
|
|
24913
24969
|
const active = resolveActive(found?.state ?? null, now);
|
|
@@ -25004,9 +25060,9 @@ function readTextInput(value, flag, readStdin2 = () => (0, import_node_fs39.read
|
|
|
25004
25060
|
if (raw.length > MAX_STDIN_BYTES) {
|
|
25005
25061
|
return { ok: false, error: `${flag} from stdin is ${raw.length} bytes; the limit is ${MAX_STDIN_BYTES}.` };
|
|
25006
25062
|
}
|
|
25007
|
-
const
|
|
25008
|
-
if (!
|
|
25009
|
-
return { ok: true, text };
|
|
25063
|
+
const text2 = raw.toString("utf8").replace(/\r?\n$/, "");
|
|
25064
|
+
if (!text2.trim()) return { ok: false, error: `${flag} from stdin is empty.` };
|
|
25065
|
+
return { ok: true, text: text2 };
|
|
25010
25066
|
}
|
|
25011
25067
|
|
|
25012
25068
|
// src/lib/terminal-text.ts
|
|
@@ -25024,8 +25080,8 @@ function terminalUrl(value) {
|
|
|
25024
25080
|
// src/commands/feedback.ts
|
|
25025
25081
|
function registerFeedbackCommand(program2) {
|
|
25026
25082
|
const feedbackCmd = program2.command("feedback").description("Send feedback to the Verity team");
|
|
25027
|
-
feedbackCmd.command("message <text>").description("Send general feedback (- reads the message from stdin, so the words never pass through shell quoting)").option("--session-id <id>", "Session identifier").option("--model <name>", "Agent model name").action(async (
|
|
25028
|
-
await sendMessageArg(
|
|
25083
|
+
feedbackCmd.command("message <text>").description("Send general feedback (- reads the message from stdin, so the words never pass through shell quoting)").option("--session-id <id>", "Session identifier").option("--model <name>", "Agent model name").action(async (text2, opts) => {
|
|
25084
|
+
await sendMessageArg(text2, opts, program2.opts());
|
|
25029
25085
|
});
|
|
25030
25086
|
feedbackCmd.command("finding <run-id> <pattern-id> <action> [note]").description("Submit per-finding feedback (false_positive, acknowledged, useful, etc.); a note of - is read from stdin").option("--file <path>", "File path the finding applies to").option("--line <n>", "Line number", parseInt).action(async (runId, patternId, action, inlineNote, opts) => {
|
|
25031
25087
|
const globals = program2.opts();
|
|
@@ -25100,7 +25156,7 @@ async function sendGeneralFeedback(message, opts, globals) {
|
|
|
25100
25156
|
process.exit(1);
|
|
25101
25157
|
}
|
|
25102
25158
|
const body2 = { message };
|
|
25103
|
-
const sessionId = opts.sessionId ??
|
|
25159
|
+
const sessionId = opts.sessionId ?? envSessionId();
|
|
25104
25160
|
const model = opts.model ?? process.env.CLAUDE_MODEL ?? "unknown";
|
|
25105
25161
|
if (sessionId) body2.session_id = sessionId;
|
|
25106
25162
|
if (model) body2.agent_model = model;
|
|
@@ -25630,28 +25686,28 @@ function parseRgLine(line2) {
|
|
|
25630
25686
|
return { file: line2.slice(0, first), line: n, text: line2.slice(second + 1) };
|
|
25631
25687
|
}
|
|
25632
25688
|
var isWordChar = (c) => c !== void 0 && /[A-Za-z0-9_]/.test(c);
|
|
25633
|
-
function wordHit(
|
|
25689
|
+
function wordHit(text2, symbol) {
|
|
25634
25690
|
let from = 0;
|
|
25635
25691
|
for (; ; ) {
|
|
25636
|
-
const at =
|
|
25692
|
+
const at = text2.indexOf(symbol, from);
|
|
25637
25693
|
if (at < 0) return false;
|
|
25638
|
-
const before = at === 0 ? void 0 :
|
|
25639
|
-
const after =
|
|
25694
|
+
const before = at === 0 ? void 0 : text2[at - 1];
|
|
25695
|
+
const after = text2[at + symbol.length];
|
|
25640
25696
|
if (!isWordChar(before) && !isWordChar(after)) return true;
|
|
25641
25697
|
from = at + 1;
|
|
25642
25698
|
}
|
|
25643
25699
|
}
|
|
25644
|
-
function isContractLine(
|
|
25700
|
+
function isContractLine(text2, symbol) {
|
|
25645
25701
|
for (const kw of ["implements", "extends"]) {
|
|
25646
25702
|
let from = 0;
|
|
25647
25703
|
for (; ; ) {
|
|
25648
|
-
const at =
|
|
25704
|
+
const at = text2.indexOf(kw, from);
|
|
25649
25705
|
if (at < 0) break;
|
|
25650
25706
|
from = at + 1;
|
|
25651
|
-
const before = at === 0 ? void 0 :
|
|
25652
|
-
const after =
|
|
25707
|
+
const before = at === 0 ? void 0 : text2[at - 1];
|
|
25708
|
+
const after = text2[at + kw.length];
|
|
25653
25709
|
if (isWordChar(before) || isWordChar(after)) continue;
|
|
25654
|
-
let clause =
|
|
25710
|
+
let clause = text2.slice(at + kw.length);
|
|
25655
25711
|
const stop2 = Math.min(
|
|
25656
25712
|
...[clause.indexOf(";"), clause.indexOf("{")].filter((i2) => i2 >= 0)
|
|
25657
25713
|
);
|
|
@@ -25683,20 +25739,20 @@ function partitionSites(rgLines, symbols, opts) {
|
|
|
25683
25739
|
if (opts.sentPaths.has(h.file)) continue;
|
|
25684
25740
|
if (opts.isExcluded(h.file)) continue;
|
|
25685
25741
|
if (!isCodeSiteFile(h.file)) continue;
|
|
25686
|
-
const
|
|
25687
|
-
if (
|
|
25688
|
-
if (COMMENT_LINE.test(
|
|
25689
|
-
if (BARE_MEMBER_LINE.test(
|
|
25742
|
+
const text2 = h.text.trim();
|
|
25743
|
+
if (text2.length === 0 || IMPORT_LINE.test(h.text)) continue;
|
|
25744
|
+
if (COMMENT_LINE.test(text2)) continue;
|
|
25745
|
+
if (BARE_MEMBER_LINE.test(text2) || GO_IMPORT_PATH_LINE.test(text2)) continue;
|
|
25690
25746
|
const n = perFile.get(h.file) ?? 0;
|
|
25691
25747
|
if (n >= MAX_SITES_PER_FILE) continue;
|
|
25692
25748
|
const site = {
|
|
25693
25749
|
file: h.file,
|
|
25694
25750
|
line: h.line,
|
|
25695
|
-
text:
|
|
25751
|
+
text: text2.slice(0, SITE_TEXT_MAX),
|
|
25696
25752
|
symbol: h.symbol,
|
|
25697
25753
|
// R2 falls out of R1 for free: a word search for `Sym` already matches
|
|
25698
25754
|
// `implements Sym` / `extends Sym` lines — classification is all R2 is.
|
|
25699
|
-
...isContractLine(
|
|
25755
|
+
...isContractLine(text2, h.symbol) ? { kind: "contract" } : {}
|
|
25700
25756
|
};
|
|
25701
25757
|
if (isTestPath(h.file)) {
|
|
25702
25758
|
if (tests.length < MAX_TEST_SLOTS) {
|
|
@@ -25716,8 +25772,8 @@ var MAX_IMPORTERS_PER_FILE = 2;
|
|
|
25716
25772
|
function moduleKey(path) {
|
|
25717
25773
|
return path.replace(/\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/i, "").replace(/\/index$/, "");
|
|
25718
25774
|
}
|
|
25719
|
-
function importSpecifier(
|
|
25720
|
-
const m = /(?:\bfrom|\brequire\s*\(|\bimport\s*\(|^\s*import)\s*['"]([^'"\n]+)['"]/.exec(
|
|
25775
|
+
function importSpecifier(text2) {
|
|
25776
|
+
const m = /(?:\bfrom|\brequire\s*\(|\bimport\s*\(|^\s*import)\s*['"]([^'"\n]+)['"]/.exec(text2);
|
|
25721
25777
|
return m?.[1] ?? null;
|
|
25722
25778
|
}
|
|
25723
25779
|
function resolveSpecifier(fromFile, spec) {
|
|
@@ -25987,8 +26043,8 @@ function extractEnclosingExcerpt(content, siteLine, path) {
|
|
|
25987
26043
|
start2 = Math.max(1, siteLine - (EXCERPT_MAX_LINES - 6));
|
|
25988
26044
|
}
|
|
25989
26045
|
const end = Math.min(lines.length, start2 + EXCERPT_MAX_LINES - 1);
|
|
25990
|
-
const
|
|
25991
|
-
return { start_line: start2, text };
|
|
26046
|
+
const text2 = lines.slice(start2 - 1, end).join("\n").slice(0, EXCERPT_MAX_CHARS);
|
|
26047
|
+
return { start_line: start2, text: text2 };
|
|
25992
26048
|
}
|
|
25993
26049
|
function upgradeToExcerpts(rc, opts) {
|
|
25994
26050
|
if (rc.state !== "ok") return;
|
|
@@ -26344,7 +26400,7 @@ function resolveFrame(input) {
|
|
|
26344
26400
|
const hookDirUsable = !!input.hookCwd && (0, import_node_fs40.existsSync)(input.hookCwd);
|
|
26345
26401
|
const baseDir = hookDirUsable ? input.hookCwd : process.cwd();
|
|
26346
26402
|
let anchor = hookDirUsable ? "hook-cwd" : "process-cwd";
|
|
26347
|
-
const
|
|
26403
|
+
const refuse2 = (refusal) => ({
|
|
26348
26404
|
moment: found?.moment ?? null,
|
|
26349
26405
|
frame: { worktreeRoot: null, gitDir: null, commonDir: null, isLinkedWorktree: false, branch: null, anchor, refusal }
|
|
26350
26406
|
});
|
|
@@ -26358,19 +26414,19 @@ function resolveFrame(input) {
|
|
|
26358
26414
|
if (!kindRes.some((re) => re.test(segments[i2]))) continue;
|
|
26359
26415
|
const target = extractCommandTarget(input.command, i2, baseDir);
|
|
26360
26416
|
if (target.named) anchor = "command-target";
|
|
26361
|
-
if (target.unresolvable) return
|
|
26417
|
+
if (target.unresolvable) return refuse2(`target:${target.unresolvable}`);
|
|
26362
26418
|
dirs.add(target.dir ?? baseDir);
|
|
26363
26419
|
}
|
|
26364
|
-
if (dirs.size > 1) return
|
|
26420
|
+
if (dirs.size > 1) return refuse2(`target:multiple ${found.moment} targets in one command`);
|
|
26365
26421
|
const targetDir = dirs.size === 1 ? [...dirs][0] : baseDir;
|
|
26366
26422
|
if (targetDir !== baseDir) {
|
|
26367
|
-
if (!(0, import_node_fs40.existsSync)(targetDir)) return
|
|
26423
|
+
if (!(0, import_node_fs40.existsSync)(targetDir)) return refuse2(`target:directory does not exist: ${targetDir}`);
|
|
26368
26424
|
dir = targetDir;
|
|
26369
26425
|
}
|
|
26370
26426
|
}
|
|
26371
26427
|
const toplevel = gitAt(dir, ["rev-parse", "--show-toplevel"]);
|
|
26372
26428
|
if (!toplevel) {
|
|
26373
|
-
return
|
|
26429
|
+
return refuse2(anchor === "command-target" ? `target:not a git repository: ${dir}` : `anchor:not a git repository: ${dir}`);
|
|
26374
26430
|
}
|
|
26375
26431
|
const gitDirRaw = gitAt(dir, ["rev-parse", "--absolute-git-dir"]);
|
|
26376
26432
|
const commonRaw = gitAt(dir, ["rev-parse", "--git-common-dir"]);
|
|
@@ -26966,7 +27022,7 @@ function sanitizeCommandWithLoss(rawCmd) {
|
|
|
26966
27022
|
const lost = lines.slice(1).some((l) => l.trim().length > 0);
|
|
26967
27023
|
const first = lines[0];
|
|
26968
27024
|
const cmd = sanitizeCommand(first);
|
|
26969
|
-
const hadSeparator = SEPARATORS.some((
|
|
27025
|
+
const hadSeparator = SEPARATORS.some((sep7) => first.indexOf(sep7) > 0);
|
|
26970
27026
|
return { cmd, lost: lost || !hadSeparator && first.length > MAX_COMMAND_CHARS };
|
|
26971
27027
|
}
|
|
26972
27028
|
var SEPARATORS = [" | ", " > ", " >> ", " 2>", " && ", " ; "];
|
|
@@ -26975,11 +27031,11 @@ function sanitizeCommand(rawCmd) {
|
|
|
26975
27031
|
let cmd = rawCmd.split("\n")[0];
|
|
26976
27032
|
let cut = -1;
|
|
26977
27033
|
let marker = "";
|
|
26978
|
-
for (const
|
|
26979
|
-
const idx = cmd.indexOf(
|
|
27034
|
+
for (const sep7 of SEPARATORS) {
|
|
27035
|
+
const idx = cmd.indexOf(sep7);
|
|
26980
27036
|
if (idx > 0 && (cut === -1 || idx < cut)) {
|
|
26981
27037
|
cut = idx;
|
|
26982
|
-
marker =
|
|
27038
|
+
marker = sep7.trim();
|
|
26983
27039
|
}
|
|
26984
27040
|
}
|
|
26985
27041
|
if (cut > -1) cmd = cmd.slice(0, cut);
|
|
@@ -27046,13 +27102,13 @@ async function bootstrap(run4) {
|
|
|
27046
27102
|
isTTY: process.stdout.isTTY === true
|
|
27047
27103
|
});
|
|
27048
27104
|
const { assistantMessage: assistantResponse, stopReason, transcriptPath, sessionId } = await readStopHookStdin();
|
|
27049
|
-
if (deferredToPlugin("analyze", sessionId ??
|
|
27105
|
+
if (deferredToPlugin("analyze", sessionId ?? envSessionId() ?? null)) {
|
|
27050
27106
|
process.exit(0);
|
|
27051
27107
|
}
|
|
27052
27108
|
const actionSummary = transcriptPath ? await extractActionSummary(transcriptPath) : null;
|
|
27053
27109
|
const tokenResult = await resolveToken(globals.token);
|
|
27054
27110
|
const scopeToken = tokenResult.ok ? tokenResult.data.token : void 0;
|
|
27055
|
-
const rawSessionId = sessionId ||
|
|
27111
|
+
const rawSessionId = sessionId || envSessionId();
|
|
27056
27112
|
const baselineSessionId = sessionScopeKey(scopeToken, rawSessionId);
|
|
27057
27113
|
if (tokenResult.ok) {
|
|
27058
27114
|
run4.beacon = {
|
|
@@ -27085,12 +27141,12 @@ function parseKnowledgeNote(raw) {
|
|
|
27085
27141
|
if (!raw || typeof raw !== "object") return null;
|
|
27086
27142
|
const o = raw;
|
|
27087
27143
|
const node_id = typeof o.node_id === "string" ? o.node_id.trim() : "";
|
|
27088
|
-
const
|
|
27089
|
-
if (!node_id || !
|
|
27090
|
-
if (
|
|
27144
|
+
const text2 = typeof o.text === "string" ? o.text.trim() : "";
|
|
27145
|
+
if (!node_id || !text2) return null;
|
|
27146
|
+
if (text2.length > 1e3) return null;
|
|
27091
27147
|
return {
|
|
27092
27148
|
node_id,
|
|
27093
|
-
text,
|
|
27149
|
+
text: text2,
|
|
27094
27150
|
file: typeof o.file === "string" && o.file ? o.file : null,
|
|
27095
27151
|
line: typeof o.line === "number" && Number.isFinite(o.line) && o.line > 0 ? Math.floor(o.line) : null
|
|
27096
27152
|
};
|
|
@@ -27128,10 +27184,10 @@ function episodeForWire(e, humanSpoke) {
|
|
|
27128
27184
|
var MAX_AGENT_CONTEXT_CHARS = 1500;
|
|
27129
27185
|
var MAX_AGENT_ITEMS = 5;
|
|
27130
27186
|
var REPORT_PREFIX = "Verity review (a report on the code just written \u2014 relay what matters to the user; it is not an instruction to you):";
|
|
27131
|
-
function renderItem(label2,
|
|
27187
|
+
function renderItem(label2, text2, patternId, file, line2) {
|
|
27132
27188
|
const where2 = file ? ` (${file}${line2 !== void 0 && line2 !== "" ? `:${line2}` : ""})` : "";
|
|
27133
27189
|
const id = patternId ? ` [${patternId}]` : "";
|
|
27134
|
-
return `- ${label2}${
|
|
27190
|
+
return `- ${label2}${text2}${where2}${id}`;
|
|
27135
27191
|
}
|
|
27136
27192
|
function channelInputFrom(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
27137
27193
|
const metadata2 = response.metadata ?? {};
|
|
@@ -27213,11 +27269,11 @@ function buildAgentContext(input) {
|
|
|
27213
27269
|
for (const p of input.pendingItems ?? []) {
|
|
27214
27270
|
if (lines.length >= MAX_AGENT_ITEMS) break;
|
|
27215
27271
|
if (p.pattern_id === "intent-misalignment") continue;
|
|
27216
|
-
const
|
|
27217
|
-
if (!
|
|
27218
|
-
const seenBefore = isRepeatOfAny(
|
|
27272
|
+
const text2 = p.description ?? p.title ?? p.reason;
|
|
27273
|
+
if (!text2) continue;
|
|
27274
|
+
const seenBefore = isRepeatOfAny(text2, input.priorPendingFingerprints ?? []);
|
|
27219
27275
|
lines.push(
|
|
27220
|
-
renderItem("",
|
|
27276
|
+
renderItem("", text2, p.pattern_id, p.file, p.line) + (seenBefore ? "\n (raised earlier this session and still open \u2014 do not re-explain it; act on it or carry on)" : "")
|
|
27221
27277
|
);
|
|
27222
27278
|
}
|
|
27223
27279
|
if (lines.length === 0) return null;
|
|
@@ -27225,11 +27281,11 @@ function buildAgentContext(input) {
|
|
|
27225
27281
|
${lines.slice(0, MAX_AGENT_ITEMS).join("\n")}`;
|
|
27226
27282
|
return truncateToCap(body2);
|
|
27227
27283
|
}
|
|
27228
|
-
function truncateToCap(
|
|
27229
|
-
if (
|
|
27284
|
+
function truncateToCap(text2) {
|
|
27285
|
+
if (text2.length <= MAX_AGENT_CONTEXT_CHARS) return text2;
|
|
27230
27286
|
const marker = "\n- (truncated)";
|
|
27231
27287
|
const budget = MAX_AGENT_CONTEXT_CHARS - marker.length;
|
|
27232
|
-
const lines =
|
|
27288
|
+
const lines = text2.slice(0, budget).split("\n");
|
|
27233
27289
|
lines.pop();
|
|
27234
27290
|
return `${lines.join("\n")}${marker}`;
|
|
27235
27291
|
}
|
|
@@ -27257,7 +27313,7 @@ function channelSilence(input) {
|
|
|
27257
27313
|
// src/lib/cli-version.ts
|
|
27258
27314
|
function cliVersion() {
|
|
27259
27315
|
try {
|
|
27260
|
-
return true ? "0.34.
|
|
27316
|
+
return true ? "0.34.2-experimental.2cad220" : "dev";
|
|
27261
27317
|
} catch {
|
|
27262
27318
|
return "dev";
|
|
27263
27319
|
}
|
|
@@ -27497,10 +27553,10 @@ var EMPTY_RESULT = {
|
|
|
27497
27553
|
findings: [],
|
|
27498
27554
|
summary: { total_findings: 0, by_severity: {}, tools_run: [] }
|
|
27499
27555
|
};
|
|
27500
|
-
function withFailure(
|
|
27556
|
+
function withFailure(kind2, detail) {
|
|
27501
27557
|
return {
|
|
27502
27558
|
...EMPTY_RESULT,
|
|
27503
|
-
summary: { ...EMPTY_RESULT.summary, failure: { kind, detail: detail.slice(0, 300) } }
|
|
27559
|
+
summary: { ...EMPTY_RESULT.summary, failure: { kind: kind2, detail: detail.slice(0, 300) } }
|
|
27504
27560
|
};
|
|
27505
27561
|
}
|
|
27506
27562
|
function runCodacyAnalysisIfAvailable(files) {
|
|
@@ -28058,7 +28114,7 @@ async function connect(run4) {
|
|
|
28058
28114
|
async function mode(run4) {
|
|
28059
28115
|
const { opts, globals } = run4;
|
|
28060
28116
|
const { actionSummary, allForReview, assistantResponse, baseline, conversation, memory: memory2, noFilesChanged, serviceUrl, sessionId, token, turnAuthoredCode } = run4;
|
|
28061
|
-
const sessionIdForMemory = sessionId ||
|
|
28117
|
+
const sessionIdForMemory = sessionId || envSessionId() || "";
|
|
28062
28118
|
let predictedMode;
|
|
28063
28119
|
try {
|
|
28064
28120
|
const memoryPath2 = sessionIdForMemory ? `/memory?session_id=${encodeURIComponent(sessionIdForMemory)}` : "/memory";
|
|
@@ -28259,11 +28315,11 @@ var rootCandidateCache = /* @__PURE__ */ new Map();
|
|
|
28259
28315
|
function candidateRoots(repoRoot2) {
|
|
28260
28316
|
const cached2 = rootCandidateCache.get(repoRoot2);
|
|
28261
28317
|
if (cached2) return cached2;
|
|
28262
|
-
const
|
|
28263
|
-
const out2 = [
|
|
28318
|
+
const norm3 = repoRoot2.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
28319
|
+
const out2 = [norm3];
|
|
28264
28320
|
try {
|
|
28265
|
-
const real = import_node_fs44.realpathSync.native(
|
|
28266
|
-
if (real !==
|
|
28321
|
+
const real = import_node_fs44.realpathSync.native(norm3).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
28322
|
+
if (real !== norm3) out2.push(real);
|
|
28267
28323
|
} catch {
|
|
28268
28324
|
}
|
|
28269
28325
|
for (const r of [...out2]) {
|
|
@@ -29114,39 +29170,39 @@ function extentOf(node) {
|
|
|
29114
29170
|
}
|
|
29115
29171
|
function definitionsIn(root, spec) {
|
|
29116
29172
|
const out2 = [];
|
|
29117
|
-
const add = (name2,
|
|
29173
|
+
const add = (name2, kind2, extent, fn, owner, last = extent) => {
|
|
29118
29174
|
const q = qualifierOf(owner, spec);
|
|
29119
|
-
out2.push({ name: name2, qualified: q ? `${q}.${name2}` : name2, kind, extent, last, fn });
|
|
29175
|
+
out2.push({ name: name2, qualified: q ? `${q}.${name2}` : name2, kind: kind2, extent, last, fn });
|
|
29120
29176
|
};
|
|
29121
29177
|
const visit = (n) => {
|
|
29122
|
-
const
|
|
29123
|
-
if (
|
|
29178
|
+
const kind2 = spec.definitions[n.type];
|
|
29179
|
+
if (kind2 && n.childForFieldName("body")) {
|
|
29124
29180
|
const nameNode = n.childForFieldName("name");
|
|
29125
29181
|
if (nameNode && nameNode.type !== "computed_property_name") {
|
|
29126
29182
|
const inClass = qualifierOf(n, spec) !== null;
|
|
29127
|
-
const k = spec.id === "python" ? inClass ? "method" : "function" :
|
|
29183
|
+
const k = spec.id === "python" ? inClass ? "method" : "function" : kind2;
|
|
29128
29184
|
add(nameNode.text, k, extentOf(n), n, n, n.parent?.type === "decorated_definition" ? n.parent : n);
|
|
29129
29185
|
}
|
|
29130
29186
|
} else if (spec.functionValues.has(n.type) && n.parent) {
|
|
29131
29187
|
const p = n.parent;
|
|
29132
|
-
const
|
|
29188
|
+
const kind3 = n.type === "arrow_function" ? "arrow" : n.type === "lambda" || n.type === "lambda_expression" ? "lambda" : "function";
|
|
29133
29189
|
const bound = p.childForFieldName("value")?.id === n.id;
|
|
29134
29190
|
if (bound && p.type === "variable_declarator" && p.childForFieldName("name")?.type === "identifier") {
|
|
29135
29191
|
const decl = p.parent && p.parent.namedChildren.filter((c) => c.type === "variable_declarator").length === 1 ? p.parent : p;
|
|
29136
|
-
add(p.childForFieldName("name").text,
|
|
29192
|
+
add(p.childForFieldName("name").text, kind3, decl, n, p);
|
|
29137
29193
|
} else if (bound && (p.type === "public_field_definition" || p.type === "field_definition")) {
|
|
29138
29194
|
const nameNode = p.childForFieldName("name") ?? p.childForFieldName("property");
|
|
29139
|
-
if (nameNode && nameNode.type !== "computed_property_name") add(nameNode.text,
|
|
29195
|
+
if (nameNode && nameNode.type !== "computed_property_name") add(nameNode.text, kind3, extentOf(p), n, p, p);
|
|
29140
29196
|
} else if (bound && p.type === "pair") {
|
|
29141
29197
|
const key = p.childForFieldName("key");
|
|
29142
|
-
if (key && (key.type === "property_identifier" || key.type === "identifier")) add(key.text,
|
|
29198
|
+
if (key && (key.type === "property_identifier" || key.type === "identifier")) add(key.text, kind3, p, n, p);
|
|
29143
29199
|
} else if (p.type === "arguments" && moduleCall(p.parent)) {
|
|
29144
29200
|
const call = p.parent;
|
|
29145
29201
|
const route = p.namedChildren[0];
|
|
29146
29202
|
const quoted = route && route.id !== n.id && route.type === "string" ? unquote2(route.text) : null;
|
|
29147
29203
|
const path = quoted && /^[\w/:.{}*-]{1,60}$/.test(quoted) ? quoted : null;
|
|
29148
29204
|
const callee = call.childForFieldName("function").text;
|
|
29149
|
-
add(path ? `${callee} ${path}` : callee,
|
|
29205
|
+
add(path ? `${callee} ${path}` : callee, kind3, call.parent, n, call);
|
|
29150
29206
|
}
|
|
29151
29207
|
}
|
|
29152
29208
|
for (const c of n.namedChildren) visit(c);
|
|
@@ -29423,18 +29479,18 @@ var STABLE_EXPRESSION = (t) => {
|
|
|
29423
29479
|
const root = t.split(".")[0];
|
|
29424
29480
|
return root === "this" || root === "self" || /^[A-Z]/.test(root);
|
|
29425
29481
|
};
|
|
29426
|
-
function argResource(
|
|
29427
|
-
if (!arg) return { kind, name: null, confidence: "unknown" };
|
|
29482
|
+
function argResource(kind2, arg) {
|
|
29483
|
+
if (!arg) return { kind: kind2, name: null, confidence: "unknown" };
|
|
29428
29484
|
if (arg.literal !== null) {
|
|
29429
29485
|
const n = literalName(arg.literal);
|
|
29430
|
-
return n ? { kind, name: n.name, confidence: n.confidence } : { kind, name: null, confidence: "unknown" };
|
|
29486
|
+
return n ? { kind: kind2, name: n.name, confidence: n.confidence } : { kind: kind2, name: null, confidence: "unknown" };
|
|
29431
29487
|
}
|
|
29432
|
-
if (SIMPLE_EXPRESSION.test(arg.text) && STABLE_EXPRESSION(arg.text)) return { kind, name: arg.text, confidence: "expression" };
|
|
29488
|
+
if (SIMPLE_EXPRESSION.test(arg.text) && STABLE_EXPRESSION(arg.text)) return { kind: kind2, name: arg.text, confidence: "expression" };
|
|
29433
29489
|
const keyed = keyedCall(arg.text);
|
|
29434
|
-
return keyed ? { kind, name: keyed, confidence: "expression" } : { kind, name: null, confidence: "unknown" };
|
|
29490
|
+
return keyed ? { kind: kind2, name: keyed, confidence: "expression" } : { kind: kind2, name: null, confidence: "unknown" };
|
|
29435
29491
|
}
|
|
29436
|
-
function keyedCall(
|
|
29437
|
-
const t =
|
|
29492
|
+
function keyedCall(text2) {
|
|
29493
|
+
const t = text2.trim();
|
|
29438
29494
|
const open = t.indexOf("(");
|
|
29439
29495
|
if (open <= 0 || !t.endsWith(")")) return null;
|
|
29440
29496
|
const callee = t.slice(0, open);
|
|
@@ -29468,16 +29524,16 @@ var SQL_TABLE = [
|
|
|
29468
29524
|
[/\bfrom\s+[`"[]?([\w.]+)/i, "read"]
|
|
29469
29525
|
];
|
|
29470
29526
|
function sqlLiteral(c) {
|
|
29471
|
-
const
|
|
29472
|
-
if (!
|
|
29527
|
+
const text2 = c.args.find((a) => a.literal !== null && SQL.test(a.literal))?.literal;
|
|
29528
|
+
if (!text2) return null;
|
|
29473
29529
|
for (const [re, op] of SQL_TABLE) {
|
|
29474
|
-
const m = re.exec(
|
|
29530
|
+
const m = re.exec(text2);
|
|
29475
29531
|
if (m) {
|
|
29476
29532
|
const name2 = m[1].split(".").pop();
|
|
29477
|
-
return { op, resource: table(name2), rule: "sql.literal", lock: op === "read" && /\bfor\s+(?:no\s+key\s+)?update\b/i.test(
|
|
29533
|
+
return { op, resource: table(name2), rule: "sql.literal", lock: op === "read" && /\bfor\s+(?:no\s+key\s+)?update\b/i.test(text2) };
|
|
29478
29534
|
}
|
|
29479
29535
|
}
|
|
29480
|
-
return { op: /^\s*select\b/i.test(
|
|
29536
|
+
return { op: /^\s*select\b/i.test(text2) ? "read" : "write", resource: { kind: "table", name: null, confidence: "unknown" }, rule: "sql.literal" };
|
|
29481
29537
|
}
|
|
29482
29538
|
var SB_WRITE = /* @__PURE__ */ new Set(["insert", "update", "upsert", "delete"]);
|
|
29483
29539
|
var SB_FROM = /\bfrom\(\s*(['"`])([\w.-]+)\1\s*\)\s*$/;
|
|
@@ -29873,28 +29929,28 @@ var ALIAS_OF = "alias-of:";
|
|
|
29873
29929
|
var FIELD_OF = "field-of:";
|
|
29874
29930
|
var IDENT_CHAR = /[\w$]/;
|
|
29875
29931
|
var isIdent = (s) => /^[A-Za-z_$][\w$]*$/.test(s);
|
|
29876
|
-
function wordAt(
|
|
29932
|
+
function wordAt(text2, word) {
|
|
29877
29933
|
const out2 = [];
|
|
29878
|
-
for (let i2 =
|
|
29879
|
-
if (IDENT_CHAR.test(
|
|
29934
|
+
for (let i2 = text2.indexOf(word); i2 >= 0; i2 = text2.indexOf(word, i2 + 1)) {
|
|
29935
|
+
if (IDENT_CHAR.test(text2[i2 - 1] ?? "") || IDENT_CHAR.test(text2[i2 + word.length] ?? "")) continue;
|
|
29880
29936
|
out2.push(i2);
|
|
29881
29937
|
}
|
|
29882
29938
|
return out2;
|
|
29883
29939
|
}
|
|
29884
29940
|
var GO_NOT_TYPES = /* @__PURE__ */ new Set(["int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "float32", "float64", "complex64", "complex128", "string", "bool", "byte", "rune", "error", "any", "func", "chan", "map", "struct", "interface", "range", "make", "new", "nil", "true", "false"]);
|
|
29885
|
-
function typeAt(
|
|
29941
|
+
function typeAt(text2, i2, lang) {
|
|
29886
29942
|
let j = i2;
|
|
29887
29943
|
const skip = () => {
|
|
29888
|
-
while (j <
|
|
29944
|
+
while (j < text2.length && /[\s?*&]/.test(text2[j])) j++;
|
|
29889
29945
|
};
|
|
29890
29946
|
skip();
|
|
29891
|
-
for (const kw of ["new ", "readonly ", "await "]) if (
|
|
29947
|
+
for (const kw of ["new ", "readonly ", "await "]) if (text2.startsWith(kw, j)) {
|
|
29892
29948
|
j += kw.length;
|
|
29893
29949
|
skip();
|
|
29894
29950
|
}
|
|
29895
29951
|
let k = j;
|
|
29896
|
-
while (k <
|
|
29897
|
-
const name2 =
|
|
29952
|
+
while (k < text2.length && /[\w$.]/.test(text2[k])) k++;
|
|
29953
|
+
const name2 = text2.slice(j, k).split(".").pop() ?? "";
|
|
29898
29954
|
if (lang === "go") return /^[A-Za-z_]\w*$/.test(name2) && !GO_NOT_TYPES.has(name2) ? name2 : null;
|
|
29899
29955
|
return /^[A-Z][\w$]*$/.test(name2) ? name2 : null;
|
|
29900
29956
|
}
|
|
@@ -30044,10 +30100,10 @@ function boundInGo(fnText, name2) {
|
|
|
30044
30100
|
const brace = fnText.indexOf("{");
|
|
30045
30101
|
return wordAt(brace < 0 ? fnText : fnText.slice(0, brace), name2).length > 0;
|
|
30046
30102
|
}
|
|
30047
|
-
function rebindsInGo(
|
|
30048
|
-
for (const i2 of wordAt(
|
|
30049
|
-
const lineEnd =
|
|
30050
|
-
const rest =
|
|
30103
|
+
function rebindsInGo(text2, name2) {
|
|
30104
|
+
for (const i2 of wordAt(text2, name2)) {
|
|
30105
|
+
const lineEnd = text2.indexOf("\n", i2);
|
|
30106
|
+
const rest = text2.slice(i2 + name2.length, lineEnd < 0 ? void 0 : lineEnd);
|
|
30051
30107
|
const decl = rest.indexOf(":=");
|
|
30052
30108
|
if (decl >= 0 && /^[\s\w,]*$/.test(rest.slice(0, decl))) return true;
|
|
30053
30109
|
}
|
|
@@ -30273,15 +30329,15 @@ function importOf(content, lang, name2, receiver) {
|
|
|
30273
30329
|
return null;
|
|
30274
30330
|
}
|
|
30275
30331
|
var TS_EXTS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
30276
|
-
function parseJsonc(
|
|
30332
|
+
function parseJsonc(text2) {
|
|
30277
30333
|
let out2 = "";
|
|
30278
30334
|
let inString = false;
|
|
30279
|
-
for (let i2 = 0; i2 <
|
|
30280
|
-
const c =
|
|
30335
|
+
for (let i2 = 0; i2 < text2.length; i2++) {
|
|
30336
|
+
const c = text2[i2];
|
|
30281
30337
|
if (inString) {
|
|
30282
30338
|
out2 += c;
|
|
30283
30339
|
if (c === "\\") {
|
|
30284
|
-
out2 +=
|
|
30340
|
+
out2 += text2[++i2] ?? "";
|
|
30285
30341
|
continue;
|
|
30286
30342
|
}
|
|
30287
30343
|
if (c === '"') inString = false;
|
|
@@ -30292,14 +30348,14 @@ function parseJsonc(text) {
|
|
|
30292
30348
|
out2 += c;
|
|
30293
30349
|
continue;
|
|
30294
30350
|
}
|
|
30295
|
-
if (c === "/" &&
|
|
30296
|
-
while (i2 <
|
|
30351
|
+
if (c === "/" && text2[i2 + 1] === "/") {
|
|
30352
|
+
while (i2 < text2.length && text2[i2] !== "\n") i2++;
|
|
30297
30353
|
out2 += "\n";
|
|
30298
30354
|
continue;
|
|
30299
30355
|
}
|
|
30300
|
-
if (c === "/" &&
|
|
30356
|
+
if (c === "/" && text2[i2 + 1] === "*") {
|
|
30301
30357
|
i2 += 2;
|
|
30302
|
-
while (i2 <
|
|
30358
|
+
while (i2 < text2.length && !(text2[i2] === "*" && text2[i2 + 1] === "/")) i2++;
|
|
30303
30359
|
i2++;
|
|
30304
30360
|
continue;
|
|
30305
30361
|
}
|
|
@@ -30508,36 +30564,36 @@ function definitionOf(input) {
|
|
|
30508
30564
|
}
|
|
30509
30565
|
var MAX_CALLER_SCAN_FILES = 60;
|
|
30510
30566
|
var isWordChar2 = (c) => c !== void 0 && /[\w$]/.test(c);
|
|
30511
|
-
function callStarts(
|
|
30567
|
+
function callStarts(text2, name2) {
|
|
30512
30568
|
const out2 = [];
|
|
30513
|
-
for (let i2 =
|
|
30569
|
+
for (let i2 = text2.indexOf(name2); i2 >= 0; i2 = text2.indexOf(name2, i2 + 1)) {
|
|
30514
30570
|
let j = i2 + name2.length;
|
|
30515
|
-
if (
|
|
30571
|
+
if (text2[j] === "<") {
|
|
30516
30572
|
let depth = 0;
|
|
30517
|
-
for (; j <
|
|
30518
|
-
if (
|
|
30519
|
-
else if (
|
|
30573
|
+
for (; j < text2.length; j++) {
|
|
30574
|
+
if (text2[j] === "<") depth++;
|
|
30575
|
+
else if (text2[j] === ">" && --depth === 0) break;
|
|
30520
30576
|
}
|
|
30521
30577
|
j++;
|
|
30522
30578
|
}
|
|
30523
|
-
if (
|
|
30579
|
+
if (text2[j] === "(") out2.push({ index: i2, open: j });
|
|
30524
30580
|
}
|
|
30525
30581
|
return out2;
|
|
30526
30582
|
}
|
|
30527
|
-
function callsName(
|
|
30528
|
-
const t =
|
|
30583
|
+
function callsName(text2, name2) {
|
|
30584
|
+
const t = text2.trim();
|
|
30529
30585
|
if (t.startsWith("//") || t.startsWith("*") || t.startsWith("/*") || t.startsWith("#")) return false;
|
|
30530
|
-
for (const at of callStarts(
|
|
30586
|
+
for (const at of callStarts(text2, name2)) {
|
|
30531
30587
|
const i2 = at.index;
|
|
30532
|
-
const spread =
|
|
30533
|
-
if (isWordChar2(
|
|
30588
|
+
const spread = text2.slice(Math.max(0, i2 - 3), i2) === "...";
|
|
30589
|
+
if (isWordChar2(text2[i2 - 1]) || text2[i2 - 1] === "." && !spread) continue;
|
|
30534
30590
|
let depth = 0;
|
|
30535
30591
|
let j = at.open;
|
|
30536
|
-
for (; j <
|
|
30537
|
-
if (
|
|
30538
|
-
else if (
|
|
30592
|
+
for (; j < text2.length; j++) {
|
|
30593
|
+
if (text2[j] === "(") depth++;
|
|
30594
|
+
else if (text2[j] === ")" && --depth === 0) break;
|
|
30539
30595
|
}
|
|
30540
|
-
const after =
|
|
30596
|
+
const after = text2.slice(j + 1).trimStart();
|
|
30541
30597
|
if (after.startsWith(":") || after.startsWith("{")) continue;
|
|
30542
30598
|
return true;
|
|
30543
30599
|
}
|
|
@@ -30627,11 +30683,11 @@ function callersOf(input) {
|
|
|
30627
30683
|
if (seen.has(line2) || declared.has(line2)) continue;
|
|
30628
30684
|
const inside2 = r.value.some((f) => f.start.line <= line2 && line2 <= f.end.line && f.calls.some((c) => c.line === line2 && c.name === name2));
|
|
30629
30685
|
if (inside2) continue;
|
|
30630
|
-
const
|
|
30631
|
-
if (!callsName(
|
|
30686
|
+
const text2 = lines[line2 - 1] ?? "";
|
|
30687
|
+
if (!callsName(text2, name2) || /^\s*(?:export\s+)?(?:async\s+)?(?:function|def|func)\b/.test(text2)) continue;
|
|
30632
30688
|
const enclosing = r.value.filter((f) => f.start.line <= line2 && line2 <= f.end.line).sort((a, b) => a.end.line - a.start.line - (b.end.line - b.start.line))[0];
|
|
30633
30689
|
seen.add(line2);
|
|
30634
|
-
callers.push({ path: p, caller: enclosing ? enclosing.qualified : null, line: line2, text:
|
|
30690
|
+
callers.push({ path: p, caller: enclosing ? enclosing.qualified : null, line: line2, text: text2.trim().slice(0, 200), provenance: fileTie });
|
|
30635
30691
|
}
|
|
30636
30692
|
}
|
|
30637
30693
|
}
|
|
@@ -30938,16 +30994,16 @@ ${m.accessors.map((x) => ` ${x.fn.path}:${x.fn.start.line} ${x.fn.qualified} \u
|
|
|
30938
30994
|
return { ok: true, value: lines.join("\n") };
|
|
30939
30995
|
};
|
|
30940
30996
|
var KINDS = ["table", "cache", "file", "http", "queue", "service", "memory"];
|
|
30941
|
-
function parseResource(
|
|
30942
|
-
const colon =
|
|
30943
|
-
const
|
|
30944
|
-
if (KINDS.includes(
|
|
30945
|
-
return { kinds: KINDS, name:
|
|
30997
|
+
function parseResource(text2) {
|
|
30998
|
+
const colon = text2.indexOf(":");
|
|
30999
|
+
const kind2 = colon > 0 ? text2.slice(0, colon) : "";
|
|
31000
|
+
if (KINDS.includes(kind2)) return { kinds: [kind2], name: text2.slice(colon + 1) };
|
|
31001
|
+
return { kinds: KINDS, name: text2 };
|
|
30946
31002
|
}
|
|
30947
31003
|
var writersOfTool = async (ctx, args2) => {
|
|
30948
|
-
const
|
|
30949
|
-
if (!
|
|
30950
|
-
const { kinds, name: name2 } = parseResource(
|
|
31004
|
+
const text2 = str(args2.resource, 300, "resource");
|
|
31005
|
+
if (!text2.ok) return text2;
|
|
31006
|
+
const { kinds, name: name2 } = parseResource(text2.value);
|
|
30951
31007
|
if (name2.length < 2) return { ok: false, error: "resource name too short to search for" };
|
|
30952
31008
|
const deadline = Date.now() + TOOL_MS;
|
|
30953
31009
|
const src = source(ctx);
|
|
@@ -30986,7 +31042,7 @@ var writersOfTool = async (ctx, args2) => {
|
|
|
30986
31042
|
if (files.size > 25) truncated = true;
|
|
30987
31043
|
const list2 = (xs) => xs.length ? xs.slice(0, MAX_LIST).map((x) => ` ${x}`).join("\n") + (xs.length > MAX_LIST ? `
|
|
30988
31044
|
\u2026 ${xs.length - MAX_LIST} more` : "") : " none found";
|
|
30989
|
-
return { ok: true, value: `${
|
|
31045
|
+
return { ok: true, value: `${text2.value} (${where(ctx)}), heuristic${truncated ? ", search cut short" : ""}
|
|
30990
31046
|
writers:
|
|
30991
31047
|
${list2(writers)}
|
|
30992
31048
|
readers:
|
|
@@ -31044,9 +31100,9 @@ function validateRepoPath(value, { allowRoot = false } = {}) {
|
|
|
31044
31100
|
function lineNumber(value, fallback) {
|
|
31045
31101
|
return typeof value === "number" && Number.isInteger(value) && value >= 1 ? value : fallback;
|
|
31046
31102
|
}
|
|
31047
|
-
function capOutput(
|
|
31048
|
-
return
|
|
31049
|
-
[truncated at ${TOOL_LIMITS.outputChars} characters]` :
|
|
31103
|
+
function capOutput(text2) {
|
|
31104
|
+
return text2.length > TOOL_LIMITS.outputChars ? `${text2.slice(0, TOOL_LIMITS.outputChars)}
|
|
31105
|
+
[truncated at ${TOOL_LIMITS.outputChars} characters]` : text2;
|
|
31050
31106
|
}
|
|
31051
31107
|
function git(ctx, args2, opts = {}) {
|
|
31052
31108
|
return runGit(ctx.root, args2, { timeoutMs: opts.timeoutMs ?? TOOL_LIMITS.gitTimeoutMs, maxBuffer: opts.maxBuffer ?? TOOL_LIMITS.fileBytes });
|
|
@@ -31180,8 +31236,8 @@ var listFilesTool = async (ctx, args2) => {
|
|
|
31180
31236
|
\u2026 ${more} more` : ""}` : "no matching files" };
|
|
31181
31237
|
};
|
|
31182
31238
|
var searchTool = async (ctx, args2) => {
|
|
31183
|
-
const
|
|
31184
|
-
if (typeof
|
|
31239
|
+
const text2 = args2.text;
|
|
31240
|
+
if (typeof text2 !== "string" || text2.length === 0 || text2.length > TOOL_LIMITS.textChars || /[\n\r]/.test(text2)) {
|
|
31185
31241
|
return { ok: false, error: `text must be 1-${TOOL_LIMITS.textChars} characters on one line` };
|
|
31186
31242
|
}
|
|
31187
31243
|
const glob = typeof args2.path_glob === "string" && args2.path_glob.length > 0 ? args2.path_glob : null;
|
|
@@ -31190,7 +31246,7 @@ var searchTool = async (ctx, args2) => {
|
|
|
31190
31246
|
}
|
|
31191
31247
|
const pathspec = glob ? [`:(glob)${glob}`] : [];
|
|
31192
31248
|
const revision = ctx.range.kind === "push" ? [ctx.range.head] : ["--cached"];
|
|
31193
|
-
const res = await git(ctx, ["grep", "-n", "-I", "-F", "--no-color", ...revision.filter((r) => r === "--cached"), "-e",
|
|
31249
|
+
const res = await git(ctx, ["grep", "-n", "-I", "-F", "--no-color", ...revision.filter((r) => r === "--cached"), "-e", text2, ...revision.filter((r) => r !== "--cached"), "--", ...pathspec]);
|
|
31194
31250
|
if (!res.ok) {
|
|
31195
31251
|
if (res.error === "failed" && res.stderr.trim() === "") return { ok: true, value: "no matches" };
|
|
31196
31252
|
return { ok: false, error: gitFailure(res, "search") };
|
|
@@ -31324,10 +31380,10 @@ function writerExcerpts(codeMap, writers, read2, maxLines, maxChars, budget) {
|
|
|
31324
31380
|
if (content === null) continue;
|
|
31325
31381
|
const win = functionWindow(codeMap, w.file, content, w.line, maxLines);
|
|
31326
31382
|
if (!win) continue;
|
|
31327
|
-
const
|
|
31328
|
-
if (used +
|
|
31329
|
-
used +=
|
|
31330
|
-
out2.push({ file: w.file, start_line: win.start_line, symbol: `${w.symbol} (writes ${w.resource}, like ${w.changed})`, kind: "writer", text });
|
|
31383
|
+
const text2 = content.split("\n").slice(win.start_line - 1, win.end_line).join("\n").slice(0, maxChars);
|
|
31384
|
+
if (used + text2.length > budget) break;
|
|
31385
|
+
used += text2.length;
|
|
31386
|
+
out2.push({ file: w.file, start_line: win.start_line, symbol: `${w.symbol} (writes ${w.resource}, like ${w.changed})`, kind: "writer", text: text2 });
|
|
31331
31387
|
}
|
|
31332
31388
|
return out2;
|
|
31333
31389
|
}
|
|
@@ -31951,7 +32007,7 @@ async function workingMemory(run4) {
|
|
|
31951
32007
|
const { opts } = run4;
|
|
31952
32008
|
const { allForReview, baseline, conversation, foldResult, sessionId, token, transcriptPath } = run4;
|
|
31953
32009
|
let { reachability } = run4;
|
|
31954
|
-
const memorySession = sessionDossier(token, sessionId ??
|
|
32010
|
+
const memorySession = sessionDossier(token, sessionId ?? envSessionId() ?? null);
|
|
31955
32011
|
let memory2 = null;
|
|
31956
32012
|
let incrementReport = null;
|
|
31957
32013
|
if (memorySession) {
|
|
@@ -32224,7 +32280,7 @@ async function buildRequest(run4) {
|
|
|
32224
32280
|
context: {
|
|
32225
32281
|
agent_model: process.env.CLAUDE_MODEL ?? "unknown",
|
|
32226
32282
|
agent_harness: "claude-code",
|
|
32227
|
-
session_id: sessionId ||
|
|
32283
|
+
session_id: sessionId || envSessionId() || "unknown",
|
|
32228
32284
|
iteration,
|
|
32229
32285
|
// Makes fleet composition falsifiable — without it, no adoption-gated
|
|
32230
32286
|
// rollout decision can be checked against anything.
|
|
@@ -33434,12 +33490,41 @@ async function runAnalyze(opts, globals) {
|
|
|
33434
33490
|
}
|
|
33435
33491
|
|
|
33436
33492
|
// src/commands/baseline.ts
|
|
33437
|
-
var
|
|
33438
|
-
var
|
|
33493
|
+
var import_node_fs56 = require("node:fs");
|
|
33494
|
+
var import_node_path43 = require("node:path");
|
|
33439
33495
|
|
|
33440
|
-
// src/lib/
|
|
33496
|
+
// src/lib/skew-notice.ts
|
|
33441
33497
|
var import_node_fs54 = require("node:fs");
|
|
33442
33498
|
var import_node_path41 = require("node:path");
|
|
33499
|
+
var MARKER = ".skew-notice.json";
|
|
33500
|
+
function markerPath2() {
|
|
33501
|
+
return (0, import_node_path41.join)(verityHome(), MARKER);
|
|
33502
|
+
}
|
|
33503
|
+
function today(now) {
|
|
33504
|
+
const y = now.getFullYear();
|
|
33505
|
+
const m = String(now.getMonth() + 1).padStart(2, "0");
|
|
33506
|
+
const d = String(now.getDate()).padStart(2, "0");
|
|
33507
|
+
return `${y}-${m}-${d}`;
|
|
33508
|
+
}
|
|
33509
|
+
function skewNoticeDue(skew, now = /* @__PURE__ */ new Date()) {
|
|
33510
|
+
try {
|
|
33511
|
+
const seen = JSON.parse((0, import_node_fs54.readFileSync)(markerPath2(), "utf-8"));
|
|
33512
|
+
return !(seen.global === skew.global && seen.hooks === skew.hooks && seen.day === today(now));
|
|
33513
|
+
} catch {
|
|
33514
|
+
return true;
|
|
33515
|
+
}
|
|
33516
|
+
}
|
|
33517
|
+
function recordSkewNotice(skew, now = /* @__PURE__ */ new Date()) {
|
|
33518
|
+
try {
|
|
33519
|
+
(0, import_node_fs54.mkdirSync)(verityHome(), { recursive: true, mode: 448 });
|
|
33520
|
+
(0, import_node_fs54.writeFileSync)(markerPath2(), JSON.stringify({ global: skew.global, hooks: skew.hooks, day: today(now) }) + "\n");
|
|
33521
|
+
} catch {
|
|
33522
|
+
}
|
|
33523
|
+
}
|
|
33524
|
+
|
|
33525
|
+
// src/lib/project-skills.ts
|
|
33526
|
+
var import_node_fs55 = require("node:fs");
|
|
33527
|
+
var import_node_path42 = require("node:path");
|
|
33443
33528
|
var PROJECT_SKILL_NAMES = [
|
|
33444
33529
|
"verity-setup",
|
|
33445
33530
|
"verity-analyze",
|
|
@@ -33465,14 +33550,14 @@ var LEGACY_SKILL_NAMES = [
|
|
|
33465
33550
|
var ALL = [...PROJECT_SKILL_NAMES, ...LEGACY_SKILL_NAMES];
|
|
33466
33551
|
function staleProjectSkills() {
|
|
33467
33552
|
const root = projectPath(".claude/skills");
|
|
33468
|
-
if (!(0,
|
|
33469
|
-
return ALL.filter((name2) => (0,
|
|
33553
|
+
if (!(0, import_node_fs55.existsSync)(root)) return [];
|
|
33554
|
+
return ALL.filter((name2) => (0, import_node_fs55.existsSync)((0, import_node_path42.join)(root, name2)));
|
|
33470
33555
|
}
|
|
33471
33556
|
function removeProjectSkills() {
|
|
33472
33557
|
const root = projectPath(".claude/skills");
|
|
33473
33558
|
const removed = [];
|
|
33474
33559
|
for (const name2 of staleProjectSkills()) {
|
|
33475
|
-
(0,
|
|
33560
|
+
(0, import_node_fs55.rmSync)((0, import_node_path42.join)(root, name2), { recursive: true, force: true });
|
|
33476
33561
|
removed.push(name2);
|
|
33477
33562
|
}
|
|
33478
33563
|
return removed;
|
|
@@ -33492,20 +33577,22 @@ function registerBaselineCommands(program2) {
|
|
|
33492
33577
|
if (!process.stdin.isTTY) {
|
|
33493
33578
|
const input = (await readStdin()).trim();
|
|
33494
33579
|
if (input) {
|
|
33495
|
-
const event =
|
|
33580
|
+
const event = parseHookEvent2(input);
|
|
33496
33581
|
if (opts.sessionId === void 0) sessionId = event.sessionId;
|
|
33497
33582
|
if (opts.source === void 0) source2 = event.source;
|
|
33498
33583
|
}
|
|
33499
33584
|
}
|
|
33500
|
-
const session = sessionId ?? validSessionId(
|
|
33585
|
+
const session = sessionId ?? validSessionId(envSessionId());
|
|
33501
33586
|
const cli = pluginCliInvocation();
|
|
33502
33587
|
const skew = cliVersionSkew();
|
|
33503
33588
|
const why = skew ? `the \`verity\` on PATH is ${skew.global} but the hooks run ${skew.hooks}, so it is not the CLI they use` : verityOnPath() ? "the `verity` on PATH is a separate install whose version could not be read" : "this machine has no `verity` on PATH \u2014 the plugin carries its own copy";
|
|
33504
33589
|
const cliLine = cli ? `Verity CLI: ${why}. When a Verity skill tells you to run \`verity <args>\`, run \`${cli} <args>\` instead. Everything else about the command is identical.` : null;
|
|
33505
|
-
const
|
|
33506
|
-
const
|
|
33590
|
+
const skewLoud = !!skew && skewNoticeDue(skew);
|
|
33591
|
+
const skewMsg = skew && skewLoud ? `Verity: your global \`verity\` CLI is ${skew.global} but the hooks run ${skew.hooks}. Fix it before using \`verity\` in a terminal: ${skew.remedy}` : null;
|
|
33592
|
+
const loginWarning = "Until they have, do not send them to run `verity login` in a terminal: that runs the global one, which can sign this machine in to a different server.";
|
|
33593
|
+
const skewNote = !skew ? null : skewLoud ? `Before anything else, including /verity:init's questions, tell the user their global \`verity\` is ${skew.global}, the hooks run ${skew.hooks}, and \`${skew.remedy}\` fixes it. ${loginWarning}` : `The user's global \`verity\` is ${skew.global} and the hooks run ${skew.hooks}; \`${skew.remedy}\` fixes it. They were already told today, so do not repeat it unprompted \u2014 mention it only where it matters, such as before suggesting a \`verity\` command for their terminal. ${loginWarning}`;
|
|
33507
33594
|
if (!verityConfigured()) {
|
|
33508
|
-
if (isMachineStore((0,
|
|
33595
|
+
if (isMachineStore((0, import_node_path43.join)(repoRoot(), VERITY_DIR))) process.exit(0);
|
|
33509
33596
|
const how = isPluginInvocation() ? "Tell the user to run /verity:init \u2014 they type it; you cannot invoke it." : "Tell the user to run `verity init` in their terminal.";
|
|
33510
33597
|
const lines = [
|
|
33511
33598
|
`Verity is installed but this project is not set up yet, so the quality gate will not review anything here. ${how}`
|
|
@@ -33532,19 +33619,20 @@ function registerBaselineCommands(program2) {
|
|
|
33532
33619
|
}
|
|
33533
33620
|
}) + "\n"
|
|
33534
33621
|
);
|
|
33622
|
+
if (skew && skewMsg) recordSkewNotice(skew);
|
|
33535
33623
|
process.exit(0);
|
|
33536
33624
|
}
|
|
33537
33625
|
const realStart = source2 === void 0 || source2 === "startup" || source2 === "clear";
|
|
33538
33626
|
let memoryMsg = null;
|
|
33539
33627
|
let memoryAgentLine = null;
|
|
33540
33628
|
const memoryNotice = projectPath(`${VERITY_DIR}/.memory-fence-notice`);
|
|
33541
|
-
if (realStart && !(0,
|
|
33629
|
+
if (realStart && !(0, import_node_fs56.existsSync)(memoryNotice)) {
|
|
33542
33630
|
const trackedGraph = memoryOptOut() ? 0 : committedMemoryFiles().length;
|
|
33543
33631
|
if (trackedGraph > 0) {
|
|
33544
33632
|
memoryMsg = `Verity: this project commits its knowledge base (${trackedGraph} files under .verity/memory/), so Verity's generated notes show up in every diff and pull request. Run \`verity memory untrack\` to keep them on disk but out of git, or \`verity memory track\` to keep committing them on purpose.`;
|
|
33545
33633
|
memoryAgentLine = `This project has ${trackedGraph} knowledge-graph files tracked in git under .verity/memory/. As of Verity 0.32.6 the graph is machine-local by default \u2014 it is rebuilt from the service, and committing it puts generated notes in every pull request. If the user wants that stopped, run \`verity memory untrack\` for them: it keeps every file on disk and stages their removal from the index, so they only need to commit \u2014 and their teammates' working copies will vanish on the next pull and re-sync from the service, which is expected. If they would rather keep committing it, \`verity memory track\` records that and nothing will offer again.`;
|
|
33546
33634
|
try {
|
|
33547
|
-
(0,
|
|
33635
|
+
(0, import_node_fs56.writeFileSync)(memoryNotice, (/* @__PURE__ */ new Date()).toISOString() + "\n");
|
|
33548
33636
|
} catch {
|
|
33549
33637
|
}
|
|
33550
33638
|
}
|
|
@@ -33572,7 +33660,7 @@ function registerBaselineCommands(program2) {
|
|
|
33572
33660
|
}
|
|
33573
33661
|
}
|
|
33574
33662
|
if (memoryAgentLine) notices.push(memoryAgentLine);
|
|
33575
|
-
if (notices.length > 0) {
|
|
33663
|
+
if (notices.length > 0 || skewMsg) {
|
|
33576
33664
|
process.stdout.write(
|
|
33577
33665
|
JSON.stringify({
|
|
33578
33666
|
...userMsg || skewMsg || memoryMsg ? { systemMessage: [skewMsg, userMsg, memoryMsg].filter(Boolean).join("\n") } : {},
|
|
@@ -33582,6 +33670,7 @@ function registerBaselineCommands(program2) {
|
|
|
33582
33670
|
}
|
|
33583
33671
|
}) + "\n"
|
|
33584
33672
|
);
|
|
33673
|
+
if (skew && skewMsg) recordSkewNotice(skew);
|
|
33585
33674
|
}
|
|
33586
33675
|
} else if (memoryMsg) {
|
|
33587
33676
|
process.stdout.write(
|
|
@@ -33613,7 +33702,7 @@ function registerBaselineCommands(program2) {
|
|
|
33613
33702
|
process.exit(0);
|
|
33614
33703
|
});
|
|
33615
33704
|
}
|
|
33616
|
-
var
|
|
33705
|
+
var MAX_HOOK_EVENT_BYTES2 = 64 * 1024;
|
|
33617
33706
|
var HOOK_SOURCES = /* @__PURE__ */ new Set(["startup", "resume", "clear", "compact"]);
|
|
33618
33707
|
var SESSION_ID_RE2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
33619
33708
|
async function readStdin() {
|
|
@@ -33621,11 +33710,11 @@ async function readStdin() {
|
|
|
33621
33710
|
let size = 0;
|
|
33622
33711
|
for await (const chunk of process.stdin) {
|
|
33623
33712
|
size += chunk.length;
|
|
33624
|
-
if (size <=
|
|
33713
|
+
if (size <= MAX_HOOK_EVENT_BYTES2) chunks.push(chunk);
|
|
33625
33714
|
}
|
|
33626
|
-
return size >
|
|
33715
|
+
return size > MAX_HOOK_EVENT_BYTES2 ? "" : Buffer.concat(chunks).toString("utf-8");
|
|
33627
33716
|
}
|
|
33628
|
-
function
|
|
33717
|
+
function parseHookEvent2(input) {
|
|
33629
33718
|
let event;
|
|
33630
33719
|
try {
|
|
33631
33720
|
event = JSON.parse(input);
|
|
@@ -33645,7 +33734,35 @@ function hookSource(value) {
|
|
|
33645
33734
|
}
|
|
33646
33735
|
|
|
33647
33736
|
// src/commands/review.ts
|
|
33648
|
-
var
|
|
33737
|
+
var import_node_fs57 = require("node:fs");
|
|
33738
|
+
var import_node_path44 = require("node:path");
|
|
33739
|
+
function containReviewPaths(paths, base) {
|
|
33740
|
+
const kept = [];
|
|
33741
|
+
const refused2 = [];
|
|
33742
|
+
for (const raw of paths) {
|
|
33743
|
+
const candidate = (0, import_node_path44.isAbsolute)(raw) ? relativeForm(base, raw) : raw;
|
|
33744
|
+
if (candidate === "" || resolveInside(base, candidate) === null) refused2.push(raw);
|
|
33745
|
+
else kept.push(candidate);
|
|
33746
|
+
}
|
|
33747
|
+
return { kept, refused: refused2 };
|
|
33748
|
+
}
|
|
33749
|
+
function relativeForm(base, abs) {
|
|
33750
|
+
const lexical = (0, import_node_path44.relative)(base, abs);
|
|
33751
|
+
if (!(lexical === ".." || lexical.startsWith(`..${import_node_path44.sep}`) || (0, import_node_path44.isAbsolute)(lexical))) return lexical;
|
|
33752
|
+
try {
|
|
33753
|
+
let dir = (0, import_node_path44.dirname)(abs);
|
|
33754
|
+
let rest = (0, import_node_path44.basename)(abs);
|
|
33755
|
+
while (!(0, import_node_fs57.existsSync)(dir)) {
|
|
33756
|
+
const up = (0, import_node_path44.dirname)(dir);
|
|
33757
|
+
if (up === dir) return lexical;
|
|
33758
|
+
rest = (0, import_node_path44.join)((0, import_node_path44.basename)(dir), rest);
|
|
33759
|
+
dir = up;
|
|
33760
|
+
}
|
|
33761
|
+
return (0, import_node_path44.relative)((0, import_node_fs57.realpathSync)(base), (0, import_node_path44.join)((0, import_node_fs57.realpathSync)(dir), rest));
|
|
33762
|
+
} catch {
|
|
33763
|
+
return lexical;
|
|
33764
|
+
}
|
|
33765
|
+
}
|
|
33649
33766
|
function registerReviewCommand(program2) {
|
|
33650
33767
|
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); - reads it from stdin, so the words never pass through shell quoting").option("--specs <paths>", "Comma-separated spec file paths").option("--json", "Output raw JSON response").action(async (opts) => {
|
|
33651
33768
|
const globals = program2.opts();
|
|
@@ -33664,11 +33781,23 @@ function registerReviewCommand(program2) {
|
|
|
33664
33781
|
});
|
|
33665
33782
|
}
|
|
33666
33783
|
async function runReview(opts, globals) {
|
|
33667
|
-
const
|
|
33668
|
-
const
|
|
33784
|
+
const base = process.cwd();
|
|
33785
|
+
const files = containReviewPaths(opts.files.split(",").map((f) => f.trim()).filter(Boolean), base);
|
|
33786
|
+
const changed = opts.changed ? containReviewPaths(opts.changed.split(",").map((f) => f.trim()).filter(Boolean), base) : files;
|
|
33787
|
+
const refused2 = Array.from(/* @__PURE__ */ new Set([...files.refused, ...changed.refused]));
|
|
33788
|
+
if (refused2.length > 0) {
|
|
33789
|
+
printJsonCompact({
|
|
33790
|
+
gate_decision: "WARN",
|
|
33791
|
+
systemMessage: `Verity: refused ${refused2.length} path(s) outside this repository \u2014 nothing was reviewed. Pass paths inside the repository you run \`verity review\` from.`,
|
|
33792
|
+
refused_paths: refused2
|
|
33793
|
+
});
|
|
33794
|
+
process.exit(0);
|
|
33795
|
+
}
|
|
33796
|
+
const allFiles = files.kept;
|
|
33797
|
+
const changedFiles = changed.kept;
|
|
33669
33798
|
const analyzable = filterAnalyzable(allFiles);
|
|
33670
33799
|
const securityFiles = filterSecurity(allFiles);
|
|
33671
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
33800
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs57.existsSync)(f) || resolveFile(f) !== null);
|
|
33672
33801
|
const staticResults = runCodacyAnalysisIfAvailable(scannable);
|
|
33673
33802
|
const codeDelta = collectCodeDelta(allFiles);
|
|
33674
33803
|
const tokenResult = await resolveToken(globals.token);
|
|
@@ -33693,7 +33822,7 @@ async function runReview(opts, globals) {
|
|
|
33693
33822
|
context: {
|
|
33694
33823
|
agent_model: process.env.CLAUDE_MODEL ?? "unknown",
|
|
33695
33824
|
agent_harness: "claude-code",
|
|
33696
|
-
session_id:
|
|
33825
|
+
session_id: envSessionId() ?? "unknown",
|
|
33697
33826
|
trigger: "review",
|
|
33698
33827
|
iteration: 1
|
|
33699
33828
|
}
|
|
@@ -33734,12 +33863,12 @@ async function runReview(opts, globals) {
|
|
|
33734
33863
|
}
|
|
33735
33864
|
|
|
33736
33865
|
// src/commands/guard.ts
|
|
33737
|
-
var
|
|
33738
|
-
var
|
|
33866
|
+
var import_node_fs63 = require("node:fs");
|
|
33867
|
+
var import_node_path51 = require("node:path");
|
|
33739
33868
|
|
|
33740
33869
|
// src/lib/vendored.ts
|
|
33741
|
-
var
|
|
33742
|
-
var
|
|
33870
|
+
var import_node_fs58 = require("node:fs");
|
|
33871
|
+
var import_node_path45 = require("node:path");
|
|
33743
33872
|
var INSTALLED_SKILL = /^\.claude\/skills\/(verity-[a-z0-9-]+)\/(.+)$/;
|
|
33744
33873
|
function dataDirOrNull() {
|
|
33745
33874
|
try {
|
|
@@ -33754,7 +33883,7 @@ function shippedSkillFile(path, dataDir = dataDirOrNull()) {
|
|
|
33754
33883
|
const [, skill, rel] = m;
|
|
33755
33884
|
if (rel.split("/").some((seg) => seg === ".." || seg === ".")) return null;
|
|
33756
33885
|
try {
|
|
33757
|
-
return (0,
|
|
33886
|
+
return (0, import_node_fs58.readFileSync)((0, import_node_path45.join)(dataDir, "skills", skill, rel), "utf8");
|
|
33758
33887
|
} catch {
|
|
33759
33888
|
return null;
|
|
33760
33889
|
}
|
|
@@ -33863,8 +33992,33 @@ async function runAgentReview(options) {
|
|
|
33863
33992
|
return { kind: "finished", response: finished.data };
|
|
33864
33993
|
}
|
|
33865
33994
|
|
|
33995
|
+
// src/lib/effort.ts
|
|
33996
|
+
var import_node_fs59 = require("node:fs");
|
|
33997
|
+
var import_node_path46 = require("node:path");
|
|
33998
|
+
var import_yaml5 = __toESM2(require_dist());
|
|
33999
|
+
var EFFORT_PROFILES = {
|
|
34000
|
+
default: { pushDeadlineMs: 18e4, formal: { tier: "fast", maxRounds: 2, minScore: 0.7, costCapUsd: 1, maxTargets: 1, relaxedGates: false, dailyModels: 5, dailyCostUsd: 5 } },
|
|
34001
|
+
high: { pushDeadlineMs: 22e4, formal: { tier: "deep", maxRounds: 2, minScore: 0.6, costCapUsd: 2, maxTargets: 2, relaxedGates: false, dailyModels: 15, dailyCostUsd: 15 } },
|
|
34002
|
+
max: { pushDeadlineMs: 27e4, formal: { tier: "deep", maxRounds: 3, minScore: 0.5, costCapUsd: 4, maxTargets: 3, relaxedGates: true, dailyModels: 30, dailyCostUsd: 30 } }
|
|
34003
|
+
};
|
|
34004
|
+
function asEffort(value) {
|
|
34005
|
+
return value === "high" || value === "max" ? value : "default";
|
|
34006
|
+
}
|
|
34007
|
+
function resolveEffort(root, env = process.env) {
|
|
34008
|
+
if (env.VERITY_EFFORT) return asEffort(env.VERITY_EFFORT);
|
|
34009
|
+
try {
|
|
34010
|
+
const standard = (0, import_yaml5.parse)((0, import_node_fs59.readFileSync)((0, import_node_path46.join)(root, STANDARD_FILE), "utf8"));
|
|
34011
|
+
return asEffort(standard?.process_constraints?.git_moment_effort);
|
|
34012
|
+
} catch {
|
|
34013
|
+
return "default";
|
|
34014
|
+
}
|
|
34015
|
+
}
|
|
34016
|
+
function effortProfile(root, env = process.env) {
|
|
34017
|
+
return EFFORT_PROFILES[resolveEffort(root, env)];
|
|
34018
|
+
}
|
|
34019
|
+
|
|
33866
34020
|
// src/lib/prove/auto.ts
|
|
33867
|
-
var
|
|
34021
|
+
var import_node_path50 = require("node:path");
|
|
33868
34022
|
var import_node_crypto19 = require("node:crypto");
|
|
33869
34023
|
|
|
33870
34024
|
// src/lib/prove/signals.ts
|
|
@@ -33927,14 +34081,14 @@ function trackedSourceFiles(root, opts = {}) {
|
|
|
33927
34081
|
return files.slice(0, opts.maxFiles ?? 5e3);
|
|
33928
34082
|
}
|
|
33929
34083
|
var EFFECT_LINE = /\bawait\b|\basync\s+with\b|\.then\(|\bsetTimeout\(|\bsetInterval\(|\bwith\s+\w[\w.]*\.(?:lock|acquire)\b|\bLock\(\)/;
|
|
33930
|
-
function countEffects(
|
|
34084
|
+
function countEffects(text2) {
|
|
33931
34085
|
let n = 0;
|
|
33932
|
-
for (const line2 of
|
|
34086
|
+
for (const line2 of text2.split("\n")) if (EFFECT_LINE.test(line2)) n++;
|
|
33933
34087
|
return n;
|
|
33934
34088
|
}
|
|
33935
|
-
function scanRisk(
|
|
34089
|
+
function scanRisk(text2) {
|
|
33936
34090
|
const counts = Object.fromEntries(RISK_PATTERNS.map(([c]) => [c, 0]));
|
|
33937
|
-
for (const line2 of
|
|
34091
|
+
for (const line2 of text2.split("\n")) {
|
|
33938
34092
|
for (const [category, re] of RISK_PATTERNS) {
|
|
33939
34093
|
if (re.test(line2)) counts[category]++;
|
|
33940
34094
|
}
|
|
@@ -34228,13 +34382,13 @@ var lunaRanker = {
|
|
|
34228
34382
|
signal: controller.signal
|
|
34229
34383
|
});
|
|
34230
34384
|
if (!res.ok) {
|
|
34231
|
-
const
|
|
34232
|
-
return { ok: false, ranker: "luna", error: `OpenAI ${res.status}: ${
|
|
34385
|
+
const text3 = await res.text().catch(() => "");
|
|
34386
|
+
return { ok: false, ranker: "luna", error: `OpenAI ${res.status}: ${text3.slice(0, 200)}`, ranked: fallback };
|
|
34233
34387
|
}
|
|
34234
34388
|
const data = await res.json();
|
|
34235
|
-
const
|
|
34236
|
-
if (!
|
|
34237
|
-
const parsed = JSON.parse(
|
|
34389
|
+
const text2 = (data.output ?? []).flatMap((o) => o.content ?? []).find((c) => c.type === "output_text")?.text;
|
|
34390
|
+
if (!text2) return { ok: false, ranker: "luna", error: "no output_text in response", ranked: fallback };
|
|
34391
|
+
const parsed = JSON.parse(text2);
|
|
34238
34392
|
const items = parsed.items.map((i2) => {
|
|
34239
34393
|
const legacy = i2.critical === void 0 && i2.hazard === void 0 && i2.error_prone === void 0;
|
|
34240
34394
|
const criteria = legacy ? { critical: Number(i2.score) || 0, hazard: Number(i2.score) || 0, error_prone: Number(i2.score) || 0 } : { critical: Number(i2.critical) || 0, hazard: Number(i2.hazard) || 0, error_prone: Number(i2.error_prone) || 0 };
|
|
@@ -34869,19 +35023,19 @@ var PURE_METHODS2 = /* @__PURE__ */ new Set([
|
|
|
34869
35023
|
"test",
|
|
34870
35024
|
"match"
|
|
34871
35025
|
]);
|
|
34872
|
-
function callsOn(
|
|
35026
|
+
function callsOn(text2, name2) {
|
|
34873
35027
|
const needle = `${name2}.`;
|
|
34874
|
-
for (let i2 =
|
|
34875
|
-
if (i2 > 0 && IDENT_CHAR2.test(
|
|
34876
|
-
const call = CALL_AFTER_DOT.exec(
|
|
35028
|
+
for (let i2 = text2.indexOf(needle); i2 >= 0; i2 = text2.indexOf(needle, i2 + 1)) {
|
|
35029
|
+
if (i2 > 0 && IDENT_CHAR2.test(text2[i2 - 1])) continue;
|
|
35030
|
+
const call = CALL_AFTER_DOT.exec(text2.slice(i2 + needle.length));
|
|
34877
35031
|
if (call && !PURE_METHODS2.has(call[1])) return true;
|
|
34878
35032
|
}
|
|
34879
35033
|
return false;
|
|
34880
35034
|
}
|
|
34881
|
-
function callsDirect(
|
|
35035
|
+
function callsDirect(text2, name2) {
|
|
34882
35036
|
const needle = `${name2}(`;
|
|
34883
|
-
for (let i2 =
|
|
34884
|
-
if (i2 > 0 && IDENT_CHAR2.test(
|
|
35037
|
+
for (let i2 = text2.indexOf(needle); i2 >= 0; i2 = text2.indexOf(needle, i2 + 1)) {
|
|
35038
|
+
if (i2 > 0 && IDENT_CHAR2.test(text2[i2 - 1])) continue;
|
|
34885
35039
|
return true;
|
|
34886
35040
|
}
|
|
34887
35041
|
return false;
|
|
@@ -34906,9 +35060,9 @@ function effectSites(numbered2) {
|
|
|
34906
35060
|
const t = r.text.trim();
|
|
34907
35061
|
if (!t || t.startsWith("//") || t.startsWith("#") || t.startsWith("*")) continue;
|
|
34908
35062
|
const onParam = [...params].some((p) => callsOn(t, p) || callsDirect(t, p));
|
|
34909
|
-
const
|
|
34910
|
-
if (!
|
|
34911
|
-
out2.push(`L${r.n} [${
|
|
35063
|
+
const kind2 = EFFECT_LINE2.test(t) || onParam ? "effect" : CONTROL_LINE.test(t) ? "control" : null;
|
|
35064
|
+
if (!kind2) continue;
|
|
35065
|
+
out2.push(`L${r.n} [${kind2}] ${t.length > 160 ? t.slice(0, 157) + "\u2026" : t}`);
|
|
34912
35066
|
if (out2.length >= MAX_EFFECT_SITES) break;
|
|
34913
35067
|
}
|
|
34914
35068
|
return out2;
|
|
@@ -35037,11 +35191,11 @@ async function generateModel(target, opts) {
|
|
|
35037
35191
|
return { ok: false, error: name2 === "TimeoutError" || name2 === "AbortError" ? "timed out" : err2.message };
|
|
35038
35192
|
}
|
|
35039
35193
|
const usage = data.usage ? { inputTokens: Number(data.usage.input_tokens ?? 0), outputTokens: Number(data.usage.output_tokens ?? 0) } : null;
|
|
35040
|
-
const
|
|
35041
|
-
if (!
|
|
35194
|
+
const text2 = (data.output ?? []).flatMap((o) => o.content ?? []).find((c) => c.type === "output_text")?.text;
|
|
35195
|
+
if (!text2) return { ok: false, error: "no output_text in response", usage };
|
|
35042
35196
|
let parsed;
|
|
35043
35197
|
try {
|
|
35044
|
-
parsed = JSON.parse(
|
|
35198
|
+
parsed = JSON.parse(text2);
|
|
35045
35199
|
} catch {
|
|
35046
35200
|
return { ok: false, error: "answer was not JSON", usage };
|
|
35047
35201
|
}
|
|
@@ -35051,8 +35205,8 @@ async function generateModel(target, opts) {
|
|
|
35051
35205
|
// src/lib/prove/replay.ts
|
|
35052
35206
|
var MAX_SOURCE_BYTES = 96 * 1024;
|
|
35053
35207
|
var MAX_MODEL_BYTES = 32 * 1024;
|
|
35054
|
-
function numberLines(
|
|
35055
|
-
return
|
|
35208
|
+
function numberLines(text2, from = 1) {
|
|
35209
|
+
return text2.split("\n").map((l, i2) => `${String(i2 + from).padStart(5)}| ${l}`).join("\n");
|
|
35056
35210
|
}
|
|
35057
35211
|
var PY_DECL = /^\s*(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(/;
|
|
35058
35212
|
var TS_DECLS = [
|
|
@@ -35126,9 +35280,9 @@ function extractSymbolBody(source2, symbol, file, range) {
|
|
|
35126
35280
|
}
|
|
35127
35281
|
return null;
|
|
35128
35282
|
}
|
|
35129
|
-
function significantLines(
|
|
35283
|
+
function significantLines(text2) {
|
|
35130
35284
|
const out2 = [];
|
|
35131
|
-
for (const raw of
|
|
35285
|
+
for (const raw of text2.split("\n")) {
|
|
35132
35286
|
const l = raw.trim();
|
|
35133
35287
|
if (l.length < 12) continue;
|
|
35134
35288
|
if (/^(\/\/|\/\*|\*|#)/.test(l)) continue;
|
|
@@ -35153,14 +35307,14 @@ function isTrackedInRoot(root, file) {
|
|
|
35153
35307
|
function buildReplayBrief(root, report, property, modelSource, readSource) {
|
|
35154
35308
|
const sources = (report.header?.abstracts ?? []).map((a) => {
|
|
35155
35309
|
const read2 = readSource ? readSource(a.file, MAX_SOURCE_BYTES) : isTrackedInRoot(root, a.file) ? readRegularFileInRoot(root, a.file, MAX_SOURCE_BYTES) : { ok: false, reason: "not tracked by git \u2014 models may only abstract tracked source" };
|
|
35156
|
-
const
|
|
35310
|
+
const text2 = read2.ok ? read2.content : "";
|
|
35157
35311
|
return {
|
|
35158
35312
|
file: a.file,
|
|
35159
35313
|
symbol: a.symbol,
|
|
35160
|
-
numbered:
|
|
35161
|
-
symbolBody:
|
|
35314
|
+
numbered: text2 ? numberLines(text2) : `(could not read ${a.file}: ${read2.ok ? "" : read2.reason})`,
|
|
35315
|
+
symbolBody: text2 ? extractSymbolBody(text2, a.symbol, a.file, a.lines) : null,
|
|
35162
35316
|
lines: a.lines,
|
|
35163
|
-
content:
|
|
35317
|
+
content: text2
|
|
35164
35318
|
};
|
|
35165
35319
|
});
|
|
35166
35320
|
return { model: report.model, property, modelSource: modelSource.slice(0, MAX_MODEL_BYTES), sources };
|
|
@@ -35242,7 +35396,7 @@ function parseReplayOutput(output) {
|
|
|
35242
35396
|
let executedCalls = 0;
|
|
35243
35397
|
const shellTexts = [];
|
|
35244
35398
|
const outputTexts = [];
|
|
35245
|
-
let
|
|
35399
|
+
let text2 = null;
|
|
35246
35400
|
for (const item of output) {
|
|
35247
35401
|
if (item.type === "shell_call") {
|
|
35248
35402
|
shellCalls++;
|
|
@@ -35258,13 +35412,13 @@ function parseReplayOutput(output) {
|
|
|
35258
35412
|
}
|
|
35259
35413
|
} else if (item.type === "message" && Array.isArray(item.content)) {
|
|
35260
35414
|
const t = item.content.find((c) => c.type === "output_text")?.text;
|
|
35261
|
-
if (typeof t === "string")
|
|
35415
|
+
if (typeof t === "string") text2 = t;
|
|
35262
35416
|
}
|
|
35263
35417
|
}
|
|
35264
35418
|
let claim = null;
|
|
35265
|
-
if (
|
|
35419
|
+
if (text2) {
|
|
35266
35420
|
try {
|
|
35267
|
-
const o = JSON.parse(
|
|
35421
|
+
const o = JSON.parse(text2);
|
|
35268
35422
|
const verdict = o.verdict;
|
|
35269
35423
|
if (verdict === "reproduced" || verdict === "diverged" || verdict === "unreplayable") {
|
|
35270
35424
|
claim = {
|
|
@@ -35551,9 +35705,9 @@ async function runReplay(brief, opts) {
|
|
|
35551
35705
|
if (opts.auth) return runReplayViaServer(brief, opts.auth, opts.timeoutMs);
|
|
35552
35706
|
const env = opts.env ?? process.env;
|
|
35553
35707
|
const none = { covered: 0, total: 0, ratio: 0, basis: "none" };
|
|
35554
|
-
const
|
|
35555
|
-
if (env.VERITY_PROVE_DIRECT !== "1") return
|
|
35556
|
-
if (!opts.apiKey) return
|
|
35708
|
+
const refuse2 = (error) => ({ claimed: null, verdict: "unverified", reason: "", downgrade: error, executedCalls: 0, shellCalls: 0, verbatim: none, executedOutput: "", harnessFiles: [], usage: null, durationMs: 0, containerId: null, error });
|
|
35709
|
+
if (env.VERITY_PROVE_DIRECT !== "1") return refuse2("not logged in (run `verity login`); replays run on the Verity service");
|
|
35710
|
+
if (!opts.apiKey) return refuse2("OPENAI_API_KEY is not set");
|
|
35557
35711
|
return runReplayInContainer(brief, { apiKey: opts.apiKey, model: opts.model, timeoutMs: opts.timeoutMs, maxRounds: opts.maxRounds, fetchImpl: opts.fetchImpl });
|
|
35558
35712
|
}
|
|
35559
35713
|
function renderReplay(model, property, r) {
|
|
@@ -35591,18 +35745,18 @@ function renderReplay(model, property, r) {
|
|
|
35591
35745
|
// src/lib/prove/runner.ts
|
|
35592
35746
|
var import_node_child_process15 = require("node:child_process");
|
|
35593
35747
|
var import_node_os8 = require("node:os");
|
|
35594
|
-
var
|
|
35748
|
+
var import_node_fs62 = require("node:fs");
|
|
35595
35749
|
var import_node_os9 = require("node:os");
|
|
35596
|
-
var
|
|
35750
|
+
var import_node_path49 = require("node:path");
|
|
35597
35751
|
|
|
35598
35752
|
// src/lib/prove/scaffold.ts
|
|
35599
|
-
var
|
|
35600
|
-
var
|
|
35753
|
+
var import_node_fs61 = require("node:fs");
|
|
35754
|
+
var import_node_path48 = require("node:path");
|
|
35601
35755
|
|
|
35602
35756
|
// src/lib/prove/safe-write.ts
|
|
35603
|
-
var
|
|
35757
|
+
var import_node_fs60 = require("node:fs");
|
|
35604
35758
|
var import_node_crypto15 = require("node:crypto");
|
|
35605
|
-
var
|
|
35759
|
+
var import_node_path47 = require("node:path");
|
|
35606
35760
|
var SafeWriteError = class extends Error {
|
|
35607
35761
|
constructor(reason, path) {
|
|
35608
35762
|
super(`refusing to write ${path}: ${reason}`);
|
|
@@ -35611,10 +35765,10 @@ var SafeWriteError = class extends Error {
|
|
|
35611
35765
|
this.name = "SafeWriteError";
|
|
35612
35766
|
}
|
|
35613
35767
|
};
|
|
35614
|
-
var FLAGS3 =
|
|
35768
|
+
var FLAGS3 = import_node_fs60.constants;
|
|
35615
35769
|
var NOFOLLOW2 = FLAGS3.O_NOFOLLOW ?? 0;
|
|
35616
35770
|
function assertPlainRelative(rel) {
|
|
35617
|
-
if (!rel || (0,
|
|
35771
|
+
if (!rel || (0, import_node_path47.isAbsolute)(rel)) throw new SafeWriteError("bad-path", rel);
|
|
35618
35772
|
for (const part of rel.split(/[\\/]/)) {
|
|
35619
35773
|
if (part === ".." || part === "" || part === ".") throw new SafeWriteError("bad-path", rel);
|
|
35620
35774
|
}
|
|
@@ -35623,34 +35777,34 @@ function ensureDirsNoFollow(root, rel) {
|
|
|
35623
35777
|
const parts2 = rel.split(/[\\/]/);
|
|
35624
35778
|
let cur = root;
|
|
35625
35779
|
for (const part of parts2.slice(0, -1)) {
|
|
35626
|
-
cur = (0,
|
|
35780
|
+
cur = (0, import_node_path47.join)(cur, part);
|
|
35627
35781
|
let st;
|
|
35628
35782
|
try {
|
|
35629
|
-
st = (0,
|
|
35783
|
+
st = (0, import_node_fs60.lstatSync)(cur);
|
|
35630
35784
|
} catch {
|
|
35631
|
-
(0,
|
|
35785
|
+
(0, import_node_fs60.mkdirSync)(cur);
|
|
35632
35786
|
continue;
|
|
35633
35787
|
}
|
|
35634
35788
|
if (st.isSymbolicLink()) throw new SafeWriteError("symlink", cur);
|
|
35635
35789
|
if (!st.isDirectory()) throw new SafeWriteError("not-regular", cur);
|
|
35636
35790
|
}
|
|
35637
|
-
return (0,
|
|
35791
|
+
return (0, import_node_path47.join)(root, rel);
|
|
35638
35792
|
}
|
|
35639
35793
|
function insideRoot(realRoot, realPath) {
|
|
35640
|
-
return realPath === realRoot || realPath.startsWith(realRoot.endsWith(
|
|
35794
|
+
return realPath === realRoot || realPath.startsWith(realRoot.endsWith(import_node_path47.sep) ? realRoot : realRoot + import_node_path47.sep);
|
|
35641
35795
|
}
|
|
35642
35796
|
function removeQuietly(path) {
|
|
35643
35797
|
try {
|
|
35644
|
-
(0,
|
|
35798
|
+
(0, import_node_fs60.unlinkSync)(path);
|
|
35645
35799
|
} catch {
|
|
35646
35800
|
}
|
|
35647
35801
|
}
|
|
35648
35802
|
function writeFileInRootNoFollow(root, rel, content) {
|
|
35649
35803
|
assertPlainRelative(rel);
|
|
35650
35804
|
const dest = ensureDirsNoFollow(root, rel);
|
|
35651
|
-
const dir = (0,
|
|
35805
|
+
const dir = (0, import_node_path47.dirname)(dest);
|
|
35652
35806
|
try {
|
|
35653
|
-
const st = (0,
|
|
35807
|
+
const st = (0, import_node_fs60.lstatSync)(dest);
|
|
35654
35808
|
if (st.isSymbolicLink()) throw new SafeWriteError("symlink", dest);
|
|
35655
35809
|
if (!st.isFile()) throw new SafeWriteError("not-regular", dest);
|
|
35656
35810
|
} catch (err2) {
|
|
@@ -35658,41 +35812,41 @@ function writeFileInRootNoFollow(root, rel, content) {
|
|
|
35658
35812
|
}
|
|
35659
35813
|
let realRoot;
|
|
35660
35814
|
try {
|
|
35661
|
-
realRoot = (0,
|
|
35815
|
+
realRoot = (0, import_node_fs60.realpathSync)(root);
|
|
35662
35816
|
} catch {
|
|
35663
35817
|
throw new SafeWriteError("unwritable", root);
|
|
35664
35818
|
}
|
|
35665
|
-
const tmp = (0,
|
|
35819
|
+
const tmp = (0, import_node_path47.join)(dir, `.${(0, import_node_path47.basename)(dest)}.${(0, import_node_crypto15.randomBytes)(6).toString("hex")}.tmp`);
|
|
35666
35820
|
let fd;
|
|
35667
35821
|
try {
|
|
35668
|
-
fd = (0,
|
|
35822
|
+
fd = (0, import_node_fs60.openSync)(tmp, import_node_fs60.constants.O_WRONLY | import_node_fs60.constants.O_CREAT | import_node_fs60.constants.O_EXCL | NOFOLLOW2, 420);
|
|
35669
35823
|
} catch {
|
|
35670
35824
|
throw new SafeWriteError("unwritable", tmp);
|
|
35671
35825
|
}
|
|
35672
35826
|
try {
|
|
35673
|
-
const opened = (0,
|
|
35827
|
+
const opened = (0, import_node_fs60.fstatSync)(fd, { bigint: true });
|
|
35674
35828
|
let realTmp;
|
|
35675
35829
|
try {
|
|
35676
|
-
realTmp = (0,
|
|
35830
|
+
realTmp = (0, import_node_fs60.realpathSync)(tmp);
|
|
35677
35831
|
} catch {
|
|
35678
35832
|
throw new SafeWriteError("escaped", tmp);
|
|
35679
35833
|
}
|
|
35680
|
-
const there = (0,
|
|
35834
|
+
const there = (0, import_node_fs60.lstatSync)(realTmp, { bigint: true });
|
|
35681
35835
|
if (!opened.isFile() || there.ino !== opened.ino || there.dev !== opened.dev || !insideRoot(realRoot, realTmp)) {
|
|
35682
35836
|
throw new SafeWriteError("escaped", tmp);
|
|
35683
35837
|
}
|
|
35684
35838
|
const buf = Buffer.from(content, "utf-8");
|
|
35685
35839
|
let off = 0;
|
|
35686
|
-
while (off < buf.length) off += (0,
|
|
35840
|
+
while (off < buf.length) off += (0, import_node_fs60.writeSync)(fd, buf, off, buf.length - off);
|
|
35687
35841
|
} catch (err2) {
|
|
35688
|
-
(0,
|
|
35842
|
+
(0, import_node_fs60.closeSync)(fd);
|
|
35689
35843
|
removeQuietly(tmp);
|
|
35690
35844
|
throw err2 instanceof SafeWriteError ? err2 : new SafeWriteError("unwritable", tmp);
|
|
35691
35845
|
}
|
|
35692
|
-
(0,
|
|
35846
|
+
(0, import_node_fs60.closeSync)(fd);
|
|
35693
35847
|
try {
|
|
35694
|
-
if (!insideRoot(realRoot, (0,
|
|
35695
|
-
(0,
|
|
35848
|
+
if (!insideRoot(realRoot, (0, import_node_fs60.realpathSync)(dir)) || (0, import_node_fs60.lstatSync)(dir).isSymbolicLink()) throw new SafeWriteError("escaped", dir);
|
|
35849
|
+
(0, import_node_fs60.renameSync)(tmp, dest);
|
|
35696
35850
|
} catch (err2) {
|
|
35697
35851
|
removeQuietly(tmp);
|
|
35698
35852
|
throw err2 instanceof SafeWriteError ? err2 : new SafeWriteError("unwritable", dest);
|
|
@@ -35706,9 +35860,9 @@ function pathHasNoLink(root, rel) {
|
|
|
35706
35860
|
}
|
|
35707
35861
|
let cur = root;
|
|
35708
35862
|
for (const part of rel.split(/[\\/]/)) {
|
|
35709
|
-
cur = cur +
|
|
35863
|
+
cur = cur + import_node_path47.sep + part;
|
|
35710
35864
|
try {
|
|
35711
|
-
if ((0,
|
|
35865
|
+
if ((0, import_node_fs60.lstatSync)(cur).isSymbolicLink()) return false;
|
|
35712
35866
|
} catch {
|
|
35713
35867
|
return true;
|
|
35714
35868
|
}
|
|
@@ -36018,20 +36172,20 @@ This directory is machine-local and gitignored (see ../.gitignore). Models are
|
|
|
36018
36172
|
never committed; what reaches the team is the bug report and the fix.
|
|
36019
36173
|
`;
|
|
36020
36174
|
function scaffoldProofs(root) {
|
|
36021
|
-
const proofsDir = (0,
|
|
36175
|
+
const proofsDir = (0, import_node_path48.join)(root, PROOFS_DIR);
|
|
36022
36176
|
const written = [];
|
|
36023
36177
|
const kept = [];
|
|
36024
36178
|
for (const stray of ["lakefile.lean"]) {
|
|
36025
36179
|
const rel = `${PROOFS_DIR}/${stray}`;
|
|
36026
|
-
if (!pathHasNoLink(root, rel)) throw new SafeWriteError("symlink", (0,
|
|
36180
|
+
if (!pathHasNoLink(root, rel)) throw new SafeWriteError("symlink", (0, import_node_path48.join)(root, rel));
|
|
36027
36181
|
try {
|
|
36028
|
-
(0,
|
|
36182
|
+
(0, import_node_fs61.rmSync)((0, import_node_path48.join)(root, rel), { force: true });
|
|
36029
36183
|
} catch {
|
|
36030
36184
|
}
|
|
36031
36185
|
}
|
|
36032
36186
|
for (const f of PROOFS_TEMPLATE_FILES) {
|
|
36033
36187
|
const rel = `${PROOFS_DIR}/${f.path}`;
|
|
36034
|
-
if (!pathHasNoLink(root, rel)) throw new SafeWriteError("symlink", (0,
|
|
36188
|
+
if (!pathHasNoLink(root, rel)) throw new SafeWriteError("symlink", (0, import_node_path48.join)(root, rel));
|
|
36035
36189
|
const current = readRegularFileInRoot(root, rel, 4 * 1024 * 1024);
|
|
36036
36190
|
if (current.ok && current.content === f.content) {
|
|
36037
36191
|
kept.push(rel);
|
|
@@ -36044,8 +36198,8 @@ function scaffoldProofs(root) {
|
|
|
36044
36198
|
[`${PROOFS_DIR}/.gitignore`, LOCAL_GITIGNORE],
|
|
36045
36199
|
[`${MODELS_DIR}/README.md`, MODELS_README]
|
|
36046
36200
|
]) {
|
|
36047
|
-
if (!pathHasNoLink(root, rel)) throw new SafeWriteError("symlink", (0,
|
|
36048
|
-
if (existsNoFollow((0,
|
|
36201
|
+
if (!pathHasNoLink(root, rel)) throw new SafeWriteError("symlink", (0, import_node_path48.join)(root, rel));
|
|
36202
|
+
if (existsNoFollow((0, import_node_path48.join)(root, rel))) {
|
|
36049
36203
|
kept.push(rel);
|
|
36050
36204
|
continue;
|
|
36051
36205
|
}
|
|
@@ -36056,7 +36210,7 @@ function scaffoldProofs(root) {
|
|
|
36056
36210
|
}
|
|
36057
36211
|
function existsNoFollow(abs) {
|
|
36058
36212
|
try {
|
|
36059
|
-
(0,
|
|
36213
|
+
(0, import_node_fs61.lstatSync)(abs);
|
|
36060
36214
|
return true;
|
|
36061
36215
|
} catch {
|
|
36062
36216
|
return false;
|
|
@@ -36135,12 +36289,12 @@ function parseHeader(obj) {
|
|
|
36135
36289
|
function parseProperty(obj) {
|
|
36136
36290
|
const model = ident(obj.model);
|
|
36137
36291
|
const id = ident(obj.id);
|
|
36138
|
-
const
|
|
36292
|
+
const kind2 = typeof obj.kind === "string" && KINDS2.has(obj.kind) ? obj.kind : null;
|
|
36139
36293
|
const result = typeof obj.result === "string" && RESULTS.has(obj.result) ? obj.result : null;
|
|
36140
36294
|
const source2 = obj.source === void 0 ? "" : str2(obj.source, LIMITS.text);
|
|
36141
36295
|
const desc = obj.desc === void 0 ? "" : str2(obj.desc, LIMITS.text);
|
|
36142
|
-
if (!model || !id || !
|
|
36143
|
-
const p = { model, id, kind, source: source2, desc, result };
|
|
36296
|
+
if (!model || !id || !kind2 || !result || source2 === null || desc === null) return null;
|
|
36297
|
+
const p = { model, id, kind: kind2, source: source2, desc, result };
|
|
36144
36298
|
if (obj.bound !== void 0) {
|
|
36145
36299
|
const n = nat(obj.bound);
|
|
36146
36300
|
if (n === null) return null;
|
|
@@ -36314,17 +36468,17 @@ function renderReport(r) {
|
|
|
36314
36468
|
|
|
36315
36469
|
// src/lib/prove/runner.ts
|
|
36316
36470
|
function verityLeanHome(env = process.env) {
|
|
36317
|
-
return env.VERITY_LEAN_HOME ?? (0,
|
|
36471
|
+
return env.VERITY_LEAN_HOME ?? (0, import_node_path49.join)(env.HOME ?? (0, import_node_os9.homedir)(), ".verity", "lean");
|
|
36318
36472
|
}
|
|
36319
36473
|
function findToolchain(env = process.env) {
|
|
36320
|
-
const managedBin = (0,
|
|
36321
|
-
const elanBin = (0,
|
|
36322
|
-
const elanHas = (0,
|
|
36323
|
-
const userPath = (env.PATH ?? "").split(
|
|
36324
|
-
const path = [managedBin, ...elanHas ? [elanBin] : [], ...userPath].join(
|
|
36474
|
+
const managedBin = (0, import_node_path49.join)(verityLeanHome(env), LEAN_TOOLCHAIN.replace(/^leanprover\/lean4:/, ""), "bin");
|
|
36475
|
+
const elanBin = (0, import_node_path49.join)(env.HOME ?? (0, import_node_os9.homedir)(), ".elan", "bin");
|
|
36476
|
+
const elanHas = (0, import_node_fs62.existsSync)((0, import_node_path49.join)(env.HOME ?? (0, import_node_os9.homedir)(), ".elan", "toolchains", LEAN_TOOLCHAIN.replace("/", "--").replace(":", "---")));
|
|
36477
|
+
const userPath = (env.PATH ?? "").split(import_node_path49.delimiter).filter((d) => d && (elanHas || (0, import_node_path49.resolve)(d) !== (0, import_node_path49.resolve)(elanBin)));
|
|
36478
|
+
const path = [managedBin, ...elanHas ? [elanBin] : [], ...userPath].join(import_node_path49.delimiter);
|
|
36325
36479
|
const merged = { ...env, PATH: path, ELAN_TOOLCHAIN: env.ELAN_TOOLCHAIN ?? LEAN_TOOLCHAIN };
|
|
36326
36480
|
const exe = process.platform === "win32" ? "lake.exe" : "lake";
|
|
36327
|
-
const candidates2 = [(0,
|
|
36481
|
+
const candidates2 = [(0, import_node_path49.join)(managedBin, exe), ...elanHas ? [(0, import_node_path49.join)(elanBin, exe)] : [], exe];
|
|
36328
36482
|
for (const candidate of candidates2) {
|
|
36329
36483
|
try {
|
|
36330
36484
|
(0, import_node_child_process15.execFileSync)(candidate, ["--version"], { env: merged, stdio: ["ignore", "pipe", "pipe"], timeout: 1e4 });
|
|
@@ -36403,7 +36557,7 @@ function proofsWorkspaceProblem(root) {
|
|
|
36403
36557
|
for (const rel of [".verity", PROOFS_DIR, `${PROOFS_DIR}/.lake`]) {
|
|
36404
36558
|
let st;
|
|
36405
36559
|
try {
|
|
36406
|
-
st = (0,
|
|
36560
|
+
st = (0, import_node_fs62.lstatSync)((0, import_node_path49.join)(root, rel));
|
|
36407
36561
|
} catch {
|
|
36408
36562
|
break;
|
|
36409
36563
|
}
|
|
@@ -36423,44 +36577,44 @@ function refused(problem) {
|
|
|
36423
36577
|
function buildLibrary(tc, root, timeoutMs = DEFAULT_BUILD_TIMEOUT_MS) {
|
|
36424
36578
|
const problem = proofsWorkspaceProblem(root);
|
|
36425
36579
|
if (problem) return refused(problem);
|
|
36426
|
-
return run2(tc, (0,
|
|
36580
|
+
return run2(tc, (0, import_node_path49.join)(root, PROOFS_DIR), ["build"], timeoutMs);
|
|
36427
36581
|
}
|
|
36428
36582
|
async function buildLibraryAsync(tc, root, timeoutMs = DEFAULT_BUILD_TIMEOUT_MS) {
|
|
36429
36583
|
const problem = proofsWorkspaceProblem(root);
|
|
36430
36584
|
if (problem) return refused(problem);
|
|
36431
|
-
return runAsync(tc, (0,
|
|
36585
|
+
return runAsync(tc, (0, import_node_path49.join)(root, PROOFS_DIR), ["build"], timeoutMs);
|
|
36432
36586
|
}
|
|
36433
36587
|
function isModelInRoot(modelsAbs, rel) {
|
|
36434
|
-
if (!rel.endsWith(".lean") || (0,
|
|
36588
|
+
if (!rel.endsWith(".lean") || (0, import_node_path49.isAbsolute)(rel) || rel.startsWith("..")) return false;
|
|
36435
36589
|
return statRegularInRoot(modelsAbs, rel).ok;
|
|
36436
36590
|
}
|
|
36437
36591
|
function resolveModelFile(root, arg) {
|
|
36438
|
-
const modelsAbs = (0,
|
|
36439
|
-
const asPath = (0,
|
|
36592
|
+
const modelsAbs = (0, import_node_path49.join)(root, MODELS_DIR);
|
|
36593
|
+
const asPath = (0, import_node_path49.relative)(modelsAbs, (0, import_node_path49.isAbsolute)(arg) ? arg : (0, import_node_path49.resolve)(root, arg));
|
|
36440
36594
|
const candidates2 = arg.includes("/") || arg.includes("\\") ? [asPath] : [arg, `${arg}.lean`];
|
|
36441
36595
|
for (const rel of candidates2) {
|
|
36442
|
-
if (isModelInRoot(modelsAbs, rel)) return (0,
|
|
36596
|
+
if (isModelInRoot(modelsAbs, rel)) return (0, import_node_path49.join)(modelsAbs, rel);
|
|
36443
36597
|
}
|
|
36444
36598
|
return null;
|
|
36445
36599
|
}
|
|
36446
36600
|
function listModelFiles(root) {
|
|
36447
|
-
const modelsAbs = (0,
|
|
36448
|
-
if (!(0,
|
|
36449
|
-
return (0,
|
|
36601
|
+
const modelsAbs = (0, import_node_path49.join)(root, MODELS_DIR);
|
|
36602
|
+
if (!(0, import_node_fs62.existsSync)(modelsAbs)) return [];
|
|
36603
|
+
return (0, import_node_fs62.readdirSync)(modelsAbs).filter((f) => isModelInRoot(modelsAbs, f)).sort().map((f) => (0, import_node_path49.join)(modelsAbs, f));
|
|
36450
36604
|
}
|
|
36451
|
-
function trimDiagnostics(
|
|
36452
|
-
return
|
|
36605
|
+
function trimDiagnostics(text2) {
|
|
36606
|
+
return text2.split("\n").filter((l) => !l.startsWith("trace:")).join("\n").trim().slice(0, 4e3);
|
|
36453
36607
|
}
|
|
36454
36608
|
function checkModel(tc, root, modelFile, opts = {}) {
|
|
36455
|
-
const proofsAbs = (0,
|
|
36456
|
-
const rel = (0,
|
|
36609
|
+
const proofsAbs = (0, import_node_path49.join)(root, PROOFS_DIR);
|
|
36610
|
+
const rel = (0, import_node_path49.relative)(proofsAbs, modelFile);
|
|
36457
36611
|
const problem = proofsWorkspaceProblem(root);
|
|
36458
36612
|
const res = problem ? refused(problem) : run2(tc, proofsAbs, ["env", "lean", rel], opts.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS);
|
|
36459
36613
|
return toReport(res, root, modelFile, opts.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS);
|
|
36460
36614
|
}
|
|
36461
36615
|
async function checkModelAsync(tc, root, modelFile, opts = {}) {
|
|
36462
|
-
const proofsAbs = (0,
|
|
36463
|
-
const rel = (0,
|
|
36616
|
+
const proofsAbs = (0, import_node_path49.join)(root, PROOFS_DIR);
|
|
36617
|
+
const rel = (0, import_node_path49.relative)(proofsAbs, modelFile);
|
|
36464
36618
|
const problem = proofsWorkspaceProblem(root);
|
|
36465
36619
|
const res = problem ? refused(problem) : await runAsync(tc, proofsAbs, ["env", "lean", rel], opts.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS);
|
|
36466
36620
|
return toReport(res, root, modelFile, opts.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS);
|
|
@@ -36469,10 +36623,10 @@ function toReport(res, root, modelFile, timeoutMs) {
|
|
|
36469
36623
|
const parsed = parseVerityLines(res.stdout);
|
|
36470
36624
|
const combined = `${res.stdout}
|
|
36471
36625
|
${res.stderr}`;
|
|
36472
|
-
const name2 = parsed.header?.model ?? (0,
|
|
36626
|
+
const name2 = parsed.header?.model ?? (0, import_node_path49.basename)(modelFile, ".lean");
|
|
36473
36627
|
const report = {
|
|
36474
36628
|
model: name2,
|
|
36475
|
-
file: (0,
|
|
36629
|
+
file: (0, import_node_path49.relative)(root, modelFile),
|
|
36476
36630
|
ok: res.ok,
|
|
36477
36631
|
header: parsed.header,
|
|
36478
36632
|
properties: parsed.properties,
|
|
@@ -36517,33 +36671,70 @@ function writeResult(root, report) {
|
|
|
36517
36671
|
function isCrashTrace(trace) {
|
|
36518
36672
|
return trace.some((s) => /\b(crash\w*|kill\w*|restart\w*|interrupt\w*|power|abort\w*|process (dies|exit\w*)|lost (reply|response))\b/i.test(s));
|
|
36519
36673
|
}
|
|
36674
|
+
function formalDisposition(f) {
|
|
36675
|
+
if (f.verdict !== "reproduced" || f.waived) return "none";
|
|
36676
|
+
const c = f.check;
|
|
36677
|
+
if (!c || c.outcome !== "answered") return "block";
|
|
36678
|
+
switch (c.verdict) {
|
|
36679
|
+
case "REAL":
|
|
36680
|
+
return c.introduced === "no" ? "report" : "block";
|
|
36681
|
+
case "REAL-LOW":
|
|
36682
|
+
return "report";
|
|
36683
|
+
case "PREVENTED":
|
|
36684
|
+
case "ARTIFACT":
|
|
36685
|
+
return "checked";
|
|
36686
|
+
default:
|
|
36687
|
+
return "block";
|
|
36688
|
+
}
|
|
36689
|
+
}
|
|
36690
|
+
var CAUTION = { block: 3, report: 2, checked: 1, none: 0 };
|
|
36691
|
+
function cautiousCheck(f, checks) {
|
|
36692
|
+
if (checks.length === 0) return void 0;
|
|
36693
|
+
let chosen = checks[0];
|
|
36694
|
+
for (const c of checks.slice(1)) if (CAUTION[formalDisposition({ ...f, check: c })] > CAUTION[formalDisposition({ ...f, check: chosen })]) chosen = c;
|
|
36695
|
+
return { ...chosen, votes: checks.map((c) => c.outcome === "answered" && c.verdict ? c.verdict : c.outcome), costUsd: checks.reduce((n, c) => n + c.costUsd, 0), unpriced: checks.reduce((n, c) => n + c.unpriced, 0) };
|
|
36696
|
+
}
|
|
36697
|
+
function checkLine(f) {
|
|
36698
|
+
const c = f.check;
|
|
36699
|
+
if (!c || c.outcome !== "answered" || !c.verdict) return "";
|
|
36700
|
+
const why = c.verdict === "PREVENTED" ? c.preventedBy || c.reason : c.reason;
|
|
36701
|
+
const from = c.trigger ? ` Reached from: ${c.trigger}.` : "";
|
|
36702
|
+
const pre = c.introduced === "no" ? " Already possible before this change." : "";
|
|
36703
|
+
const votes = c.votes && c.votes.length > 1 ? ` (${c.votes.length} checks: ${c.votes.join(", ")})` : "";
|
|
36704
|
+
return `Checked: ${c.verdict}${votes}.${from}${pre} ${why ?? ""}`.trim();
|
|
36705
|
+
}
|
|
36520
36706
|
function mergeFormalFindings(response, outcome, pushedFiles) {
|
|
36521
|
-
if (!outcome) return { blocking: 0 };
|
|
36522
|
-
const
|
|
36523
|
-
const pushed = new Set(pushedFiles.map(
|
|
36524
|
-
const
|
|
36525
|
-
|
|
36707
|
+
if (!outcome) return { blocking: 0, reported: 0 };
|
|
36708
|
+
const norm3 = (p) => p.replace(/\\/g, "/");
|
|
36709
|
+
const pushed = new Set(pushedFiles.map(norm3));
|
|
36710
|
+
const onPush = outcome.findings.filter((f) => pushed.has(norm3(f.file)));
|
|
36711
|
+
const blocking = onPush.filter((f) => formalDisposition(f) === "block");
|
|
36712
|
+
const reported = onPush.filter((f) => formalDisposition(f) === "report");
|
|
36713
|
+
if (blocking.length === 0 && reported.length === 0) return { blocking: 0, reported: 0 };
|
|
36526
36714
|
const existing = Array.isArray(response.findings) ? response.findings : [];
|
|
36527
|
-
|
|
36528
|
-
|
|
36529
|
-
|
|
36715
|
+
const asFinding = (f, blocks) => {
|
|
36716
|
+
const checked = checkLine(f);
|
|
36717
|
+
return {
|
|
36530
36718
|
pattern_id: "formal-counterexample",
|
|
36531
|
-
severity: "high",
|
|
36532
|
-
|
|
36719
|
+
severity: blocks ? "high" : "medium",
|
|
36720
|
+
// A bug this change did not introduce is filed the way the gate files everything it will not block on.
|
|
36721
|
+
scope: f.check?.introduced === "no" && !blocks ? "pre-existing" : "change",
|
|
36533
36722
|
file: f.file,
|
|
36534
36723
|
line: outcome.target?.lines?.from ?? null,
|
|
36535
36724
|
// Worded as the VIOLATION: the property text is what should hold, and
|
|
36536
36725
|
// as a title it read backwards (e2e, 2026-09-26). A trace that needs a
|
|
36537
36726
|
// crash between two writes is labelled: reproducing it means injecting
|
|
36538
36727
|
// the crash, so it is a crash-consistency finding, not a race.
|
|
36539
|
-
title: `Formal: ${terminalText(f.symbol, 128)} breaks "${terminalText(f.desc, 280)}"${isCrashTrace(f.trace) ? " after a crash (crash consistency)" : ""} \u2014 reproduced on the real code`,
|
|
36540
|
-
description: terminalText(f.reason ?? "", 2e3),
|
|
36728
|
+
title: `Formal: ${terminalText(f.symbol, 128)} breaks "${terminalText(f.desc, 280)}"${isCrashTrace(f.trace) ? " after a crash (crash consistency)" : ""} \u2014 reproduced on the real code${f.check?.outcome === "answered" ? `, checked ${f.check.verdict}` : ""}`,
|
|
36729
|
+
description: terminalText([f.reason ?? "", checked].filter(Boolean).join(" "), 2e3),
|
|
36541
36730
|
fix: { description: `Trace: ${terminalText(f.trace.join(" \u2192 ") || "(initial state)", 2e3)}. Replay: ${terminalText(f.reason ?? "reproduced in the container", 2e3)}` },
|
|
36542
36731
|
source: "formal"
|
|
36543
|
-
}
|
|
36544
|
-
|
|
36545
|
-
|
|
36546
|
-
|
|
36732
|
+
};
|
|
36733
|
+
};
|
|
36734
|
+
response.findings = [...existing, ...blocking.map((f) => asFinding(f, true)), ...reported.map((f) => asFinding(f, false))];
|
|
36735
|
+
if (blocking.length > 0) response.gate_decision = "FAIL";
|
|
36736
|
+
else if (response.gate_decision === "PASS") response.gate_decision = "WARN";
|
|
36737
|
+
return { blocking: blocking.length, reported: reported.length };
|
|
36547
36738
|
}
|
|
36548
36739
|
|
|
36549
36740
|
// src/lib/prove/scalpel.ts
|
|
@@ -36717,15 +36908,15 @@ function nonNegative(v) {
|
|
|
36717
36908
|
return typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
|
|
36718
36909
|
}
|
|
36719
36910
|
function readLedger(root) {
|
|
36720
|
-
const
|
|
36721
|
-
const empty = { day:
|
|
36911
|
+
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
36912
|
+
const empty = { day: today2, models: 0, costUsd: 0 };
|
|
36722
36913
|
if (!isLocalState(root, AUTO_LEDGER)) return empty;
|
|
36723
36914
|
const read2 = readRegularFileInRoot(root, AUTO_LEDGER, 4096);
|
|
36724
36915
|
if (!read2.ok) return empty;
|
|
36725
36916
|
try {
|
|
36726
36917
|
const o = JSON.parse(read2.content);
|
|
36727
|
-
if (o.day !==
|
|
36728
|
-
return { day:
|
|
36918
|
+
if (o.day !== today2 || typeof o.models !== "number") return empty;
|
|
36919
|
+
return { day: today2, models: nonNegative(o.models), costUsd: nonNegative(o.costUsd) };
|
|
36729
36920
|
} catch {
|
|
36730
36921
|
return empty;
|
|
36731
36922
|
}
|
|
@@ -36780,6 +36971,8 @@ function bumpLedger(root) {
|
|
|
36780
36971
|
}
|
|
36781
36972
|
var REPLAY_RESERVE_MS = 45e3;
|
|
36782
36973
|
var MAX_REPLAYS = 3;
|
|
36974
|
+
var MAX_CHECKS = 2;
|
|
36975
|
+
var CHECK_VOTES = 2;
|
|
36783
36976
|
function isNetworkError(message) {
|
|
36784
36977
|
return /Network error|fetch failed|ETIMEDOUT|ECONNRESET|ECONNREFUSED|EAI_AGAIN|socket hang up/i.test(message);
|
|
36785
36978
|
}
|
|
@@ -36862,12 +37055,14 @@ async function runFormalPhase(input) {
|
|
|
36862
37055
|
symbol: f.symbol,
|
|
36863
37056
|
verdict: "reproduced",
|
|
36864
37057
|
reason: f.waived ? `waived ${f.waived.at.slice(0, 10)}: ${f.waived.reason} (standing since ${f.at.slice(0, 10)}; the file has not changed)` : `${f.reason ?? "reproduced on the real code"} (standing since ${f.at.slice(0, 10)}; the file has not changed)`,
|
|
36865
|
-
...f.waived ? { waived: true } : {}
|
|
37058
|
+
...f.waived ? { waived: true } : {},
|
|
37059
|
+
// Same bytes, same answer: the check is not paid for twice.
|
|
37060
|
+
...f.check ? { check: { outcome: "answered", rounds: 0, costUsd: 0, unpriced: 0, durationMs: 0, ...f.check } } : {}
|
|
36866
37061
|
});
|
|
36867
37062
|
}
|
|
36868
37063
|
}
|
|
36869
37064
|
if (kept.length !== persisted.length) writePersistedFindings(root, kept);
|
|
36870
|
-
if (standing.length > 0) {
|
|
37065
|
+
if (standing.length > 0 && !input.skipStanding) {
|
|
36871
37066
|
const first = kept.find((f) => f.file === standing[0].file);
|
|
36872
37067
|
return done({
|
|
36873
37068
|
status: "checked",
|
|
@@ -36895,7 +37090,7 @@ async function runFormalPhase(input) {
|
|
|
36895
37090
|
return a.source === "tree-sitter" && a.value.effects.length >= 2;
|
|
36896
37091
|
})());
|
|
36897
37092
|
};
|
|
36898
|
-
const eligible = signals.filter((s) => isEligible(s, largePush).ok || mapEligible(s.file)).slice(0, 5);
|
|
37093
|
+
const eligible = signals.filter((s) => input.relaxedGates || isEligible(s, largePush).ok || mapEligible(s.file)).slice(0, 5);
|
|
36899
37094
|
if (eligible.length === 0) {
|
|
36900
37095
|
const best = signals[0];
|
|
36901
37096
|
return done({ status: "skipped", skip: "not-eligible", detail: `${best.file}: ${isEligible(best, largePush).why}` });
|
|
@@ -36903,7 +37098,7 @@ async function runFormalPhase(input) {
|
|
|
36903
37098
|
const ranked = await deps.rank(eligible, root, input.changedLines);
|
|
36904
37099
|
if (!ranked.ok && ranked.disabled) return done({ status: "skipped", skip: "disabled-by-server", detail: ranked.error });
|
|
36905
37100
|
if (ranked.ok) spend(ranked);
|
|
36906
|
-
candidates2 = ranked.ranked.slice(0, 5).map((c) => ({ file: c.file, symbol: c.ai?.symbol ?? null, score: c.ai?.score ?? null, criteria: c.ai?.criteria ?? null, reasked: !!c.ai?.reasked, reasons: (c.ai?.reasons ?? []).map((r) => r.slice(0, 200)) }));
|
|
37101
|
+
candidates2 = ranked.ranked.slice(0, 5).map((c) => ({ file: c.file, symbol: c.ai?.symbol ?? null, score: c.ai?.score ?? null, criteria: c.ai?.criteria ?? null, reasked: !!c.ai?.reasked, reasons: (c.ai?.reasons ?? []).map((r) => r.slice(0, 200)), commits: c.commits, fixCommits: c.fixCommits, risk: c.risk }));
|
|
36907
37102
|
if (cancelled()) return done({ status: "skipped", skip: "deadline", detail: "cut off after ranking" });
|
|
36908
37103
|
const minScore = input.minScore ?? DEFAULT_MIN_SCORE;
|
|
36909
37104
|
let qualified = ranked.ranked.filter((c) => c.ai && c.ai.score >= minScore);
|
|
@@ -36949,6 +37144,10 @@ async function runFormalPhase(input) {
|
|
|
36949
37144
|
}
|
|
36950
37145
|
}
|
|
36951
37146
|
if (d.resolved && d.resolved !== c.ai.symbol) c.ai.symbol = d.resolved;
|
|
37147
|
+
if (input.exclude?.has(`${c.file}#${c.ai.symbol}`)) {
|
|
37148
|
+
note("verified", `${c.ai.symbol}: modelled earlier in this push`);
|
|
37149
|
+
continue;
|
|
37150
|
+
}
|
|
36952
37151
|
if (input.changedLines) {
|
|
36953
37152
|
const changed = input.changedLines.get(c.file) ?? [];
|
|
36954
37153
|
if (changed.length === 0) {
|
|
@@ -36990,7 +37189,7 @@ async function runFormalPhase(input) {
|
|
|
36990
37189
|
const hazard = hasHazard(functionHazard(d.numbered));
|
|
36991
37190
|
const shared = contextHazard(context);
|
|
36992
37191
|
const judged = (c.ai.criteria?.hazard ?? 0) >= 0.8;
|
|
36993
|
-
if (!hazard.ok && !shared?.ok && !judged) {
|
|
37192
|
+
if (!input.relaxedGates && !hazard.ok && !shared?.ok && !judged) {
|
|
36994
37193
|
note("no-hazard", `${c.ai.symbol}: ${hazard.why}`);
|
|
36995
37194
|
continue;
|
|
36996
37195
|
}
|
|
@@ -37012,7 +37211,7 @@ async function runFormalPhase(input) {
|
|
|
37012
37211
|
const sha2562 = sha256Of(chosen.content);
|
|
37013
37212
|
const chosenContent = chosen.content;
|
|
37014
37213
|
const { lines, numbered: numbered2 } = chosen;
|
|
37015
|
-
const target = { file: top.file, symbol: top.ai.symbol, lines, score: top.ai.score, reasons: [...top.reasons, ...top.ai.reasons], extent: chosen.extent, ...chosen.context ? { context: chosen.context.stats } : {}, ...floor ? { floor: true } : {} };
|
|
37214
|
+
const target = { file: top.file, symbol: top.ai.symbol, lines, score: top.ai.score, reasons: [...top.reasons, ...top.ai.reasons], extent: chosen.extent, ...chosen.context ? { context: chosen.context.stats } : {}, ...floor ? { floor: true } : {}, signals: { commits: top.commits, fixCommits: top.fixCommits, risk: top.risk } };
|
|
37016
37215
|
progress.target = target;
|
|
37017
37216
|
if (!REPLAYABLE.test(top.file)) return done({ status: "skipped", skip: "replay-unsupported", detail: `${top.file}: replay supports TS/JS and Python`, target });
|
|
37018
37217
|
if (timeLeft() < GENERATE_RESERVE_MS) return done({ status: "skipped", skip: "not-enough-time", detail: `${Math.round(timeLeft() / 1e3)} s left before generation`, target });
|
|
@@ -37023,7 +37222,7 @@ async function runFormalPhase(input) {
|
|
|
37023
37222
|
let report = null;
|
|
37024
37223
|
let modelName = "";
|
|
37025
37224
|
let rounds = 0;
|
|
37026
|
-
for (let round = 1; round <= 2; round++) {
|
|
37225
|
+
for (let round = 1; round <= (input.maxRounds ?? 2); round++) {
|
|
37027
37226
|
if (round > 1 && overCap()) return done({ status: "skipped", skip: "cost-cap", detail: `$${usage.costUsd.toFixed(2)} spent, cap $${costCap.toFixed(2)}; no retry`, target, model: { name: modelName, file: `${AUTO_MODELS_DIR}/${modelName}.lean`, rounds } });
|
|
37028
37227
|
if (cancelled()) return done({ status: "skipped", skip: "deadline", detail: "cut off before generation", target });
|
|
37029
37228
|
rounds = round;
|
|
@@ -37042,7 +37241,7 @@ async function runFormalPhase(input) {
|
|
|
37042
37241
|
modelName = gen.name;
|
|
37043
37242
|
const rel = `${AUTO_MODELS_DIR}/${gen.name}.lean`;
|
|
37044
37243
|
writeFileInRootNoFollow(root, rel, gen.source);
|
|
37045
|
-
const abs = resolveModelFile(root, rel) ?? (0,
|
|
37244
|
+
const abs = resolveModelFile(root, rel) ?? (0, import_node_path50.join)(root, rel);
|
|
37046
37245
|
progress.model = { name: gen.name, file: rel, rounds: round };
|
|
37047
37246
|
progress.step = "check";
|
|
37048
37247
|
report = await deps.check(root, abs);
|
|
@@ -37138,13 +37337,40 @@ async function runFormalPhase(input) {
|
|
|
37138
37337
|
const verdict = r.verdict === "reproduced" ? "reproduced" : r.verdict === "diverged" ? "diverged" : r.verdict === "unreplayable" ? "model-only" : "unverified";
|
|
37139
37338
|
findings.push({ ...baseOf(p), verdict, reason: r.reason || r.downgrade || void 0 });
|
|
37140
37339
|
}
|
|
37340
|
+
const toCheck = deps.verify && !cancelled() ? findings.filter((f) => f.verdict === "reproduced").slice(0, MAX_CHECKS) : [];
|
|
37341
|
+
if (toCheck.length > 0) {
|
|
37342
|
+
progress.step = "verify";
|
|
37343
|
+
const share = Math.max(0, costCap - usage.costUsd) / (toCheck.length * CHECK_VOTES);
|
|
37344
|
+
const failed = (error) => ({ outcome: "failed", verdict: null, introduced: "unknown", rounds: 0, costUsd: 0, unpriced: 0, durationMs: 0, error });
|
|
37345
|
+
await Promise.all(toCheck.map(async (f) => {
|
|
37346
|
+
const checks = await Promise.all(Array.from({ length: CHECK_VOTES }, () => deps.verify(f, { ...lines ? { lines } : {}, changedLines: input.changedLines?.get(f.file) ?? [], deadlineAt: input.deadlineAt, costLeftUsd: share }).catch((err2) => failed(String(err2?.message ?? err2).slice(0, 120)))));
|
|
37347
|
+
for (const c of checks) {
|
|
37348
|
+
if (c.costUsd > 0) spend({ costUsd: c.costUsd });
|
|
37349
|
+
for (let i2 = 0; i2 < c.unpriced; i2++) usage.unpriced++;
|
|
37350
|
+
}
|
|
37351
|
+
if (!cancelled()) f.check = cautiousCheck(f, checks);
|
|
37352
|
+
}));
|
|
37353
|
+
}
|
|
37141
37354
|
const reproduced = findings.filter((f) => f.verdict === "reproduced");
|
|
37142
37355
|
if (reproduced.length > 0 && !cancelled()) {
|
|
37143
37356
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
37144
37357
|
const others = readPersistedFindings(root).filter((f) => f.file !== top.file);
|
|
37145
37358
|
writePersistedFindings(root, [
|
|
37146
37359
|
...others,
|
|
37147
|
-
...reproduced.map((f) => ({
|
|
37360
|
+
...reproduced.map((f) => ({
|
|
37361
|
+
file: f.file,
|
|
37362
|
+
symbol: f.symbol,
|
|
37363
|
+
sha256: sha2562,
|
|
37364
|
+
property: f.property,
|
|
37365
|
+
desc: f.desc,
|
|
37366
|
+
kind: f.kind,
|
|
37367
|
+
trace: f.trace,
|
|
37368
|
+
model: modelName,
|
|
37369
|
+
reason: f.reason,
|
|
37370
|
+
...lines ? { lines } : {},
|
|
37371
|
+
at: now,
|
|
37372
|
+
...f.check?.outcome === "answered" ? { check: { verdict: f.check.verdict, introduced: f.check.introduced, trigger: f.check.trigger, preventedBy: f.check.preventedBy, effect: f.check.effect, reason: f.check.reason, ...f.check.votes ? { votes: f.check.votes } : {} } } : {}
|
|
37373
|
+
}))
|
|
37148
37374
|
]);
|
|
37149
37375
|
}
|
|
37150
37376
|
const clean2 = findings.every((f) => f.verdict === "diverged");
|
|
@@ -37164,7 +37390,7 @@ async function runFormalPhase(input) {
|
|
|
37164
37390
|
return done({
|
|
37165
37391
|
status: "checked",
|
|
37166
37392
|
target,
|
|
37167
|
-
model: { name: modelName, file: (0,
|
|
37393
|
+
model: { name: modelName, file: (0, import_node_path50.relative)(root, (0, import_node_path50.join)(root, modelFile)), rounds },
|
|
37168
37394
|
properties: report.properties,
|
|
37169
37395
|
findings
|
|
37170
37396
|
});
|
|
@@ -37197,7 +37423,19 @@ async function generateAndCheck(root, req, opts) {
|
|
|
37197
37423
|
const read2 = readSrc(req.file, 96 * 1024);
|
|
37198
37424
|
if (!read2.ok) return { ok: false, error: `${req.file}: ${read2.reason}`, rounds: 0, costUsd: 0 };
|
|
37199
37425
|
const sha2562 = sha256Of(read2.content);
|
|
37200
|
-
const { lines, numbered: numbered2 } = describeTarget(read2.content, req.symbol, req.file, req.lines, { codeMap: opts.deps.codeMap });
|
|
37426
|
+
const { lines, numbered: numbered2, extent } = describeTarget(read2.content, req.symbol, req.file, req.lines, { codeMap: opts.deps.codeMap });
|
|
37427
|
+
let warning;
|
|
37428
|
+
if (!lines) {
|
|
37429
|
+
const outline = extent === "fallback:not-found" ? opts.deps.codeMap?.outline(req.file, read2.content) : void 0;
|
|
37430
|
+
if (outline?.source === "tree-sitter") {
|
|
37431
|
+
const names2 = [...new Set(outline.value.filter((f) => f.name && f.kind !== "lambda").map((f) => f.qualified))];
|
|
37432
|
+
const last = (req.symbol.split(/[.#:]/).pop() ?? req.symbol).toLowerCase();
|
|
37433
|
+
const close = names2.filter((n) => n.toLowerCase().includes(last));
|
|
37434
|
+
const shown = (close.length > 0 ? close : names2).slice(0, 12);
|
|
37435
|
+
return { ok: false, error: `no function \`${req.symbol}\` in ${req.file}${shown.length ? ` (it has: ${shown.join(", ")})` : ""}. Name one as ${req.file}#<name>, or pass --lines a-b`, rounds: 0, costUsd: 0 };
|
|
37436
|
+
}
|
|
37437
|
+
warning = `could not find the lines of \`${req.symbol}\` in ${req.file} (${extent}): the model is written from the start of the file, and a replay must copy half of the whole file. Pass --lines a-b to name the code.`;
|
|
37438
|
+
}
|
|
37201
37439
|
const target = {
|
|
37202
37440
|
file: req.file,
|
|
37203
37441
|
symbol: req.symbol,
|
|
@@ -37205,7 +37443,9 @@ async function generateAndCheck(root, req, opts) {
|
|
|
37205
37443
|
sha256: sha2562,
|
|
37206
37444
|
numbered: numbered2,
|
|
37207
37445
|
reasons: req.hint ? [`the user's worry, in their words: ${req.hint.slice(0, 280)}`] : [],
|
|
37208
|
-
properties: []
|
|
37446
|
+
properties: [],
|
|
37447
|
+
// The run row records which extractor answered, as at push.
|
|
37448
|
+
extentSource: extent
|
|
37209
37449
|
};
|
|
37210
37450
|
const context = opts.deps.codeMap && !req.lines ? targetContext({ codeMap: opts.deps.codeMap, codeSource: opts.deps.codeSource, readSource: readSrc, file: req.file, content: read2.content, symbol: req.symbol }) : null;
|
|
37211
37451
|
Object.assign(target, context?.fields ?? {});
|
|
@@ -37227,7 +37467,7 @@ async function generateAndCheck(root, req, opts) {
|
|
|
37227
37467
|
}
|
|
37228
37468
|
const rel = `${dir}/${gen.name}.lean`;
|
|
37229
37469
|
writeFileInRootNoFollow(root, rel, gen.source);
|
|
37230
|
-
const abs = resolveModelFile(root, rel) ?? (0,
|
|
37470
|
+
const abs = resolveModelFile(root, rel) ?? (0, import_node_path50.join)(root, rel);
|
|
37231
37471
|
const report = await opts.deps.check(root, abs);
|
|
37232
37472
|
const abstracts = report.header?.abstracts ?? [];
|
|
37233
37473
|
const stray = abstracts.find((a) => !headerFiles.has(a.file)) ?? (abstracts[0] && abstracts[0].file !== req.file ? abstracts[0] : void 0);
|
|
@@ -37241,14 +37481,14 @@ async function generateAndCheck(root, req, opts) {
|
|
|
37241
37481
|
const g = basisOf(p.source, files);
|
|
37242
37482
|
return g.ok ? [] : [`${p.id}: ${g.why}`];
|
|
37243
37483
|
});
|
|
37244
|
-
if (bad.length === 0) return { ok: true, name: gen.name, file: rel, report, rounds: round, costUsd };
|
|
37484
|
+
if (bad.length === 0) return { ok: true, name: gen.name, file: rel, report, rounds: round, costUsd, ...warning ? { warning } : {} };
|
|
37245
37485
|
lastError = ungroundedMessage(bad.join("; "));
|
|
37246
37486
|
if (round < maxRounds) {
|
|
37247
37487
|
previous = { source: gen.source, error: lastError };
|
|
37248
37488
|
continue;
|
|
37249
37489
|
}
|
|
37250
37490
|
const grounded = report.properties.filter((p) => basisOf(p.source, files).ok);
|
|
37251
|
-
if (grounded.length > 0) return { ok: true, name: gen.name, file: rel, report: { ...report, properties: grounded }, rounds: round, costUsd };
|
|
37491
|
+
if (grounded.length > 0) return { ok: true, name: gen.name, file: rel, report: { ...report, properties: grounded }, rounds: round, costUsd, ...warning ? { warning } : {} };
|
|
37252
37492
|
break;
|
|
37253
37493
|
}
|
|
37254
37494
|
lastError = stray ? `the model abstracts ${stray.file}, not ${req.file}` : report.error ?? (report.malformed ? "the model printed malformed VERITY lines" : "the model reported no property");
|
|
@@ -37259,7 +37499,7 @@ async function generateAndCheck(root, req, opts) {
|
|
|
37259
37499
|
function skippedOutcome(skip, detail) {
|
|
37260
37500
|
return { status: "skipped", skip, ...detail ? { detail } : {}, findings: [], usage: { inputTokens: 0, outputTokens: 0, costUsd: 0, unpriced: 0 }, durationMs: 0 };
|
|
37261
37501
|
}
|
|
37262
|
-
async function prepareFormalPhase(root, env = process.env, auth2, readSource, codeSource) {
|
|
37502
|
+
async function prepareFormalPhase(root, env = process.env, auth2, readSource, codeSource, opts = {}) {
|
|
37263
37503
|
const direct = env.VERITY_PROVE_DIRECT === "1" && !!env.OPENAI_API_KEY;
|
|
37264
37504
|
if (!auth2 && !direct) return { ok: false, skip: "not-logged-in" };
|
|
37265
37505
|
const apiKey = direct ? env.OPENAI_API_KEY : void 0;
|
|
@@ -37274,9 +37514,16 @@ async function prepareFormalPhase(root, env = process.env, auth2, readSource, co
|
|
|
37274
37514
|
}
|
|
37275
37515
|
const build = await buildLibraryAsync(toolchain, root, 9e4);
|
|
37276
37516
|
if (!build.ok) return { ok: false, skip: "library-build-failed", detail: build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).join(" ").slice(0, 200) };
|
|
37517
|
+
const code = await loadCodeContext(root, env, codeSource);
|
|
37518
|
+
return { ok: true, deps: { ...defaultDeps({ auth: auth2, apiKey, env, toolchain, readSource, ...opts.tier ? { tier: opts.tier } : {}, ...code }), codeSource: code.codeSource } };
|
|
37519
|
+
}
|
|
37520
|
+
async function loadCodeContext(root, env = process.env, codeSource) {
|
|
37277
37521
|
const loaded = await loadCodeMap(env);
|
|
37278
|
-
|
|
37279
|
-
|
|
37522
|
+
return { codeMap: loaded.ok ? loaded.map : null, codeSource: codeSource ?? withoutPaths(worktreeSource(root), isDeniedPath) };
|
|
37523
|
+
}
|
|
37524
|
+
async function onDemandDeps(root, opts) {
|
|
37525
|
+
const code = await loadCodeContext(root, opts.env);
|
|
37526
|
+
return { ...defaultDeps({ ...opts, tier: "deep", ...code }), codeSource: code.codeSource };
|
|
37280
37527
|
}
|
|
37281
37528
|
function changedFunction(codeMap, file, content, changed) {
|
|
37282
37529
|
const outline = codeMap.outline(file, content);
|
|
@@ -37321,10 +37568,52 @@ function runFormalPhaseWithin(input) {
|
|
|
37321
37568
|
resolve9(cutOffOutcome(progress, `hard stop after ${Math.round(left / 1e3)} s during ${progress.step ?? "setup"}`, left));
|
|
37322
37569
|
}, left);
|
|
37323
37570
|
});
|
|
37324
|
-
return Promise.race([
|
|
37571
|
+
return Promise.race([runFormalPhaseTargets({ ...input, progress }), cutoff]).finally(() => {
|
|
37325
37572
|
if (timer) clearTimeout(timer);
|
|
37326
37573
|
});
|
|
37327
37574
|
}
|
|
37575
|
+
var NOTHING_ELSE_QUALIFIES = /* @__PURE__ */ new Set(["no-source-files", "not-eligible", "no-candidate", "no-symbol", "symbol-not-in-push", "verified", "no-hazard", "too-large"]);
|
|
37576
|
+
async function runFormalPhaseTargets(input) {
|
|
37577
|
+
const first = await runFormalPhase(input);
|
|
37578
|
+
const max = Math.max(1, Math.floor(input.maxTargets ?? 1));
|
|
37579
|
+
if (max === 1 || first.status !== "checked" || !first.target) return first;
|
|
37580
|
+
const outcomes = [first];
|
|
37581
|
+
const exclude = /* @__PURE__ */ new Set([`${first.target.file}#${first.target.symbol}`]);
|
|
37582
|
+
const cap2 = input.costCapUsd ?? PUSH_COST_CAP_USD;
|
|
37583
|
+
let stoppedAt;
|
|
37584
|
+
while (outcomes.length < max) {
|
|
37585
|
+
if (input.progress?.cancelled) {
|
|
37586
|
+
stoppedAt = { skip: "deadline", detail: "cut off between targets" };
|
|
37587
|
+
break;
|
|
37588
|
+
}
|
|
37589
|
+
const left = input.deadlineAt - input.deps.now();
|
|
37590
|
+
if (left < GENERATE_RESERVE_MS + REPLAY_RESERVE_MS) {
|
|
37591
|
+
stoppedAt = { skip: "not-enough-time", detail: `${Math.round(left / 1e3)} s left before target ${outcomes.length + 1}` };
|
|
37592
|
+
break;
|
|
37593
|
+
}
|
|
37594
|
+
const spent = outcomes.reduce((sum, o) => sum + o.usage.costUsd, 0);
|
|
37595
|
+
if (spent >= cap2) {
|
|
37596
|
+
stoppedAt = { skip: "cost-cap", detail: `$${spent.toFixed(2)} spent, cap $${cap2.toFixed(2)}` };
|
|
37597
|
+
break;
|
|
37598
|
+
}
|
|
37599
|
+
const next = await runFormalPhase({ ...input, exclude, skipStanding: true, costCapUsd: cap2 - spent, progress: {} });
|
|
37600
|
+
if (next.status !== "checked" && next.skip && !NOTHING_ELSE_QUALIFIES.has(next.skip)) stoppedAt = { skip: next.skip, ...next.detail ? { detail: next.detail } : {} };
|
|
37601
|
+
if (!next.target || next.status !== "checked" && exclude.has(`${next.target.file}#${next.target.symbol}`)) break;
|
|
37602
|
+
exclude.add(`${next.target.file}#${next.target.symbol}`);
|
|
37603
|
+
outcomes.push(next);
|
|
37604
|
+
if (next.status !== "checked") break;
|
|
37605
|
+
}
|
|
37606
|
+
if (outcomes.length === 1) return stoppedAt ? { ...first, stoppedAt } : first;
|
|
37607
|
+
return {
|
|
37608
|
+
...first,
|
|
37609
|
+
...stoppedAt ? { stoppedAt } : {},
|
|
37610
|
+
findings: outcomes.flatMap((o) => o.findings),
|
|
37611
|
+
properties: outcomes.flatMap((o) => o.properties ?? []),
|
|
37612
|
+
targets: outcomes.flatMap((o) => o.target ? [{ file: o.target.file, symbol: o.target.symbol, status: o.status, ...o.skip ? { skip: o.skip } : {}, findings: o.findings.length }] : []),
|
|
37613
|
+
usage: outcomes.reduce((u, o) => ({ inputTokens: u.inputTokens + o.usage.inputTokens, outputTokens: u.outputTokens + o.usage.outputTokens, costUsd: Math.round((u.costUsd + o.usage.costUsd) * 1e6) / 1e6, unpriced: u.unpriced + o.usage.unpriced }), { inputTokens: 0, outputTokens: 0, costUsd: 0, unpriced: 0 }),
|
|
37614
|
+
durationMs: outcomes.reduce((sum, o) => sum + o.durationMs, 0)
|
|
37615
|
+
};
|
|
37616
|
+
}
|
|
37328
37617
|
function cutOffOutcome(p, detail, elapsedMs) {
|
|
37329
37618
|
const usage = p.usage ?? { inputTokens: 0, outputTokens: 0, costUsd: 0, unpriced: 0 };
|
|
37330
37619
|
if (!p.report || !p.target || !p.model) {
|
|
@@ -37343,7 +37632,9 @@ function describeFormalOutcome(o) {
|
|
|
37343
37632
|
if (o.status === "skipped") return `formal: skipped (${o.skip}${o.detail ? `: ${o.detail}` : ""})`;
|
|
37344
37633
|
const parts2 = o.properties?.map((p) => {
|
|
37345
37634
|
const f = o.findings.find((x) => x.property === p.id);
|
|
37346
|
-
const
|
|
37635
|
+
const votes = f?.check?.votes && f.check.votes.length > 1 ? ` [${f.check.votes.join(", ")}]` : "";
|
|
37636
|
+
const checked = f?.check ? f.check.outcome === "answered" ? ` \u2192 checked ${f.check.verdict}${f.check.introduced === "no" ? " (pre-existing)" : ""}${votes}` : ` \u2192 not checked (${f.check.outcome})${votes}` : "";
|
|
37637
|
+
const tag = p.result === "counterexample" ? f ? f.verdict.toUpperCase() + (f.waived ? " (waived)" : "") + checked : "counterexample" : p.result;
|
|
37347
37638
|
return `${p.id} ${tag}`;
|
|
37348
37639
|
}) ?? [];
|
|
37349
37640
|
const cost = o.usage.costUsd > 0 ? ` \xB7 $${o.usage.costUsd.toFixed(2)}` : "";
|
|
@@ -37351,13 +37642,222 @@ function describeFormalOutcome(o) {
|
|
|
37351
37642
|
return `formal: ${o.model?.name ?? "?"} on ${o.target?.file ?? "?"}#${o.target?.symbol ?? "?"} (${o.model?.rounds ?? 1} round${o.model?.rounds === 1 ? "" : "s"}) \xB7 ${parts2.join(" \xB7 ")} \xB7 ${Math.round(o.durationMs / 1e3)} s${cost}${cut}`;
|
|
37352
37643
|
}
|
|
37353
37644
|
|
|
37645
|
+
// src/lib/prove/verify.ts
|
|
37646
|
+
var MIN_VERIFY_TURN_MS = 15e3;
|
|
37647
|
+
var MIN_VERIFY_START_MS = 45e3;
|
|
37648
|
+
var VERIFY_TURN_HOLD_USD = 0.1;
|
|
37649
|
+
var MAX_TURNS2 = 14;
|
|
37650
|
+
var VERDICTS = ["REAL", "REAL-LOW", "PREVENTED", "ARTIFACT", "UNSURE"];
|
|
37651
|
+
var verdictOf = (v) => typeof v === "string" && VERDICTS.includes(v) ? v : null;
|
|
37652
|
+
var introducedOf = (v) => v === "yes" || v === "no" ? v : "unknown";
|
|
37653
|
+
var text = (v, n) => typeof v === "string" ? v.slice(0, n) : "";
|
|
37654
|
+
function verifyPost(auth2) {
|
|
37655
|
+
return async (body2, timeoutMs) => {
|
|
37656
|
+
const res = await apiRequest({
|
|
37657
|
+
method: "POST",
|
|
37658
|
+
path: "/prove/verify",
|
|
37659
|
+
serviceUrl: auth2.serviceUrl,
|
|
37660
|
+
token: auth2.token,
|
|
37661
|
+
// Streamed with a heartbeat, like generate and replay (decision 53).
|
|
37662
|
+
extraHeaders: { "X-Verity-Keepalive": "1" },
|
|
37663
|
+
body: body2,
|
|
37664
|
+
timeout: timeoutMs,
|
|
37665
|
+
cmd: "prove-verify"
|
|
37666
|
+
});
|
|
37667
|
+
return res.ok ? { ok: true, data: res.data ?? {} } : { ok: false, error: res.error };
|
|
37668
|
+
};
|
|
37669
|
+
}
|
|
37670
|
+
async function verifyFinding(input, opts) {
|
|
37671
|
+
const now = opts.now ?? Date.now;
|
|
37672
|
+
const startedAt = now();
|
|
37673
|
+
const remaining = () => opts.deadlineAt - now();
|
|
37674
|
+
let rounds = 0;
|
|
37675
|
+
let costUsd = 0;
|
|
37676
|
+
let unpriced = 0;
|
|
37677
|
+
const end = (outcome, extra = {}) => ({ outcome, verdict: null, introduced: "unknown", rounds, costUsd, unpriced, durationMs: now() - startedAt, ...extra });
|
|
37678
|
+
if (remaining() < MIN_VERIFY_START_MS) return end("deadline", { error: "not enough time left" });
|
|
37679
|
+
let body2 = {
|
|
37680
|
+
target: {
|
|
37681
|
+
file: input.file,
|
|
37682
|
+
symbol: input.symbol,
|
|
37683
|
+
...input.lines ? { lines: input.lines } : {},
|
|
37684
|
+
property: input.property,
|
|
37685
|
+
replay_reason: input.replayReason,
|
|
37686
|
+
changed_lines: input.changedLines.slice(0, 200)
|
|
37687
|
+
},
|
|
37688
|
+
local_tools: opts.localTools
|
|
37689
|
+
};
|
|
37690
|
+
for (let turn = 0; turn < MAX_TURNS2; turn++) {
|
|
37691
|
+
if (remaining() < MIN_VERIFY_TURN_MS) return end("deadline");
|
|
37692
|
+
if (costUsd + VERIFY_TURN_HOLD_USD > opts.costLeftUsd) return end("cost-cap");
|
|
37693
|
+
const res = await opts.post({ ...body2, remaining_ms: remaining() }, Math.max(1, remaining()));
|
|
37694
|
+
if (!res.ok) return end("failed", { error: res.error.slice(0, 200) });
|
|
37695
|
+
const d = res.data;
|
|
37696
|
+
if (d.enabled === false) return end("disabled", { error: text(d.reason, 60) });
|
|
37697
|
+
if (d.error && typeof d.error === "object") return end("failed", { error: text(d.error.code, 60) || "SERVICE_ERROR" });
|
|
37698
|
+
rounds = typeof d.round === "number" ? d.round : rounds + 1;
|
|
37699
|
+
if (typeof d.cost_usd === "number") costUsd += d.cost_usd;
|
|
37700
|
+
else unpriced++;
|
|
37701
|
+
if (d.done) {
|
|
37702
|
+
const a = d.answer;
|
|
37703
|
+
if (!a) return end("failed", { error: text(d.error, 60) || "no verdict" });
|
|
37704
|
+
const verdict = verdictOf(a.verdict);
|
|
37705
|
+
if (!verdict) return end("failed", { error: "unknown verdict" });
|
|
37706
|
+
return end("answered", {
|
|
37707
|
+
verdict,
|
|
37708
|
+
claimed: verdictOf(a.claimed),
|
|
37709
|
+
introduced: introducedOf(a.introduced),
|
|
37710
|
+
trigger: text(a.trigger, 400),
|
|
37711
|
+
preventedBy: typeof a.prevented_by === "string" ? a.prevented_by.slice(0, 600) : null,
|
|
37712
|
+
effect: text(a.effect, 600),
|
|
37713
|
+
reason: text(a.reason, 2e3),
|
|
37714
|
+
quotes: (Array.isArray(a.quotes) ? a.quotes : []).slice(0, 12).flatMap((q) => {
|
|
37715
|
+
const o = q ?? {};
|
|
37716
|
+
return typeof o.path === "string" && typeof o.text === "string" ? [{ path: o.path.slice(0, 400), text: o.text.slice(0, 600), witnessed: o.witnessed === true }] : [];
|
|
37717
|
+
})
|
|
37718
|
+
});
|
|
37719
|
+
}
|
|
37720
|
+
if (typeof d.state !== "string" || !Array.isArray(d.calls)) return end("failed", { error: "malformed turn" });
|
|
37721
|
+
const results = await opts.executeTools(d.calls);
|
|
37722
|
+
body2 = { state: d.state, results };
|
|
37723
|
+
}
|
|
37724
|
+
return end("failed", { error: "too many turns" });
|
|
37725
|
+
}
|
|
37726
|
+
|
|
37727
|
+
// src/lib/prove/record.ts
|
|
37728
|
+
var RECORD_TIMEOUT_MS = 8e3;
|
|
37729
|
+
var HOOK_EXIT_MARGIN_MS = 5e3;
|
|
37730
|
+
var MIN_RECORD_POST_MS = 1e3;
|
|
37731
|
+
function guardRecordDeadline(hookStartedAt) {
|
|
37732
|
+
return hookStartedAt + GUARD_TIMEOUT_MS - HOOK_EXIT_MARGIN_MS;
|
|
37733
|
+
}
|
|
37734
|
+
function recordPostTimeout(now, deadlineAt, timeoutMs = RECORD_TIMEOUT_MS) {
|
|
37735
|
+
if (deadlineAt === void 0) return timeoutMs;
|
|
37736
|
+
const left = deadlineAt - now;
|
|
37737
|
+
return left < MIN_RECORD_POST_MS ? null : Math.min(timeoutMs, left);
|
|
37738
|
+
}
|
|
37739
|
+
var norm2 = (p) => p.replace(/\\/g, "/");
|
|
37740
|
+
var SAFE_SEGMENT = /^[A-Za-z0-9._@+~$()[\]-]{1,255}$/;
|
|
37741
|
+
function safeRepoPath(p) {
|
|
37742
|
+
const n = norm2(p);
|
|
37743
|
+
if (!n || n.length > 512 || n.startsWith("/") || /^[A-Za-z]:\//.test(n)) return null;
|
|
37744
|
+
return n.split("/").every((s) => s !== "." && s !== ".." && SAFE_SEGMENT.test(s)) ? n : null;
|
|
37745
|
+
}
|
|
37746
|
+
var SYMBOL = /^[A-Za-z_$][\w$]*(?:[.#:][A-Za-z_$][\w$]*)*$/;
|
|
37747
|
+
var IDENT3 = /^[A-Za-z][\w]*$/;
|
|
37748
|
+
var TRACE_STEP = /^[A-Za-z_]\w{0,63}$/;
|
|
37749
|
+
var ELIDED_STEP = "\u2026";
|
|
37750
|
+
function recordBasis(source2) {
|
|
37751
|
+
if (typeof source2 !== "string") return "";
|
|
37752
|
+
if (/^rule:[a-z-]+$/.test(source2)) return source2;
|
|
37753
|
+
const m = /^(?:([^:\s]+):)?L(\d+)(?::|$)/.exec(source2);
|
|
37754
|
+
return m ? m[1] ? `${norm2(m[1])}:L${m[2]}` : `L${m[2]}` : "";
|
|
37755
|
+
}
|
|
37756
|
+
function recordTrace(trace) {
|
|
37757
|
+
return trace.slice(0, 16).map((s) => {
|
|
37758
|
+
const name2 = (s.trim().split(/[\s(]/, 1)[0] ?? "").split(".").pop() ?? "";
|
|
37759
|
+
return TRACE_STEP.test(name2) ? name2 : ELIDED_STEP;
|
|
37760
|
+
});
|
|
37761
|
+
}
|
|
37762
|
+
var ident2 = (s, re, max) => typeof s === "string" && s.length <= max && re.test(s) ? s : null;
|
|
37763
|
+
var kind = (k) => k === "intent" ? "intent" : "structural";
|
|
37764
|
+
var signalsOf = (c) => c && typeof c.commits === "number" && typeof c.fixCommits === "number" ? { commits: c.commits, fix_commits: c.fixCommits, risk: Object.fromEntries(Object.entries(c.risk ?? {}).filter(([, n]) => typeof n === "number" && n > 0).slice(0, 16)) } : null;
|
|
37765
|
+
function buildPhaseRecord(outcome, ctx) {
|
|
37766
|
+
const pushed = new Set(ctx.pushedFiles.map(norm2));
|
|
37767
|
+
const blocks = (f) => ctx.moment === "push" && formalDisposition(f) === "block" && pushed.has(norm2(f.file));
|
|
37768
|
+
const symbol = (s) => ident2(s, SYMBOL, 200);
|
|
37769
|
+
return {
|
|
37770
|
+
moment: ctx.moment,
|
|
37771
|
+
status: outcome.status,
|
|
37772
|
+
skip: outcome.skip ?? null,
|
|
37773
|
+
parent_run_id: ctx.parentRunId,
|
|
37774
|
+
target: outcome.target && symbol(outcome.target.symbol) && safeRepoPath(outcome.target.file) ? {
|
|
37775
|
+
file: safeRepoPath(outcome.target.file),
|
|
37776
|
+
symbol: symbol(outcome.target.symbol),
|
|
37777
|
+
lines: outcome.target.lines ?? null,
|
|
37778
|
+
score: Math.max(0, Math.min(1, outcome.target.score)),
|
|
37779
|
+
extent: ident2(outcome.target.extent, /^[a-z-]+(?::[a-z-]+)?$/, 60),
|
|
37780
|
+
signals: signalsOf(outcome.target.signals)
|
|
37781
|
+
} : null,
|
|
37782
|
+
candidates: (outcome.candidates ?? []).filter((c) => safeRepoPath(c.file)).slice(0, 12).map((c) => ({
|
|
37783
|
+
file: safeRepoPath(c.file),
|
|
37784
|
+
symbol: c.symbol === null ? null : symbol(c.symbol),
|
|
37785
|
+
score: c.score === null ? null : Math.max(0, Math.min(1, c.score)),
|
|
37786
|
+
criteria: c.criteria,
|
|
37787
|
+
reasked: c.reasked,
|
|
37788
|
+
signals: signalsOf(c)
|
|
37789
|
+
})),
|
|
37790
|
+
model: outcome.model && ident2(outcome.model.name, /^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)*$/, 120) ? { name: outcome.model.name, rounds: Math.max(0, Math.min(20, outcome.model.rounds)) } : null,
|
|
37791
|
+
properties: (outcome.properties ?? []).filter((p) => ident2(p.id, IDENT3, 120)).slice(0, 16).map((p) => ({
|
|
37792
|
+
id: p.id,
|
|
37793
|
+
kind: kind(p.kind),
|
|
37794
|
+
basis: recordBasis(p.source),
|
|
37795
|
+
result: p.result,
|
|
37796
|
+
bound: p.bound ?? null,
|
|
37797
|
+
states: p.states ?? null
|
|
37798
|
+
})),
|
|
37799
|
+
findings: outcome.findings.filter((f) => ident2(f.property, IDENT3, 120) && symbol(f.symbol) && safeRepoPath(f.file)).slice(0, 8).map((f) => ({
|
|
37800
|
+
property: f.property,
|
|
37801
|
+
kind: kind(f.kind),
|
|
37802
|
+
trace: recordTrace(f.trace),
|
|
37803
|
+
file: safeRepoPath(f.file),
|
|
37804
|
+
symbol: f.symbol,
|
|
37805
|
+
verdict: f.verdict,
|
|
37806
|
+
waived: f.waived === true,
|
|
37807
|
+
blocked: blocks(f),
|
|
37808
|
+
// The check's closed codes only (decision 91): never its reason, trigger or quotes.
|
|
37809
|
+
check: f.check ? { outcome: f.check.outcome, verdict: f.check.verdict, introduced: f.check.introduced, rounds: f.check.rounds } : null
|
|
37810
|
+
})),
|
|
37811
|
+
grounding: outcome.grounding ? {
|
|
37812
|
+
sent_back: outcome.grounding.sentBack,
|
|
37813
|
+
dropped: outcome.grounding.dropped.filter((id) => ident2(id, IDENT3, 120)).slice(0, 16),
|
|
37814
|
+
trigger_missing: (outcome.grounding.triggerMissing ?? []).filter((id) => ident2(id, IDENT3, 120)).slice(0, 16)
|
|
37815
|
+
} : null,
|
|
37816
|
+
usage: {
|
|
37817
|
+
input_tokens: outcome.usage.inputTokens,
|
|
37818
|
+
output_tokens: outcome.usage.outputTokens,
|
|
37819
|
+
cost_usd: outcome.usage.costUsd,
|
|
37820
|
+
unpriced: outcome.usage.unpriced
|
|
37821
|
+
},
|
|
37822
|
+
duration_ms: Math.round(outcome.durationMs)
|
|
37823
|
+
};
|
|
37824
|
+
}
|
|
37825
|
+
async function postPhaseRecord(outcome, ctx, post) {
|
|
37826
|
+
try {
|
|
37827
|
+
const timeout = recordPostTimeout((post.now ?? Date.now)(), post.deadlineAt, post.timeoutMs ?? RECORD_TIMEOUT_MS);
|
|
37828
|
+
if (timeout === null) {
|
|
37829
|
+
logEvent("formal_record_skipped", { moment: ctx.moment, reason: "hook-deadline" });
|
|
37830
|
+
return null;
|
|
37831
|
+
}
|
|
37832
|
+
const res = await apiRequest({
|
|
37833
|
+
method: "POST",
|
|
37834
|
+
path: "/prove/record",
|
|
37835
|
+
serviceUrl: post.serviceUrl,
|
|
37836
|
+
token: post.token,
|
|
37837
|
+
body: buildPhaseRecord(outcome, ctx),
|
|
37838
|
+
timeout,
|
|
37839
|
+
cmd: "prove-record"
|
|
37840
|
+
});
|
|
37841
|
+
if (!res.ok) {
|
|
37842
|
+
logEvent("formal_record_failed", { moment: ctx.moment, category: res.category ?? "unknown", http_status: res.http_status ?? null });
|
|
37843
|
+
return null;
|
|
37844
|
+
}
|
|
37845
|
+
const runId = typeof res.data?.run_id === "string" ? res.data.run_id : null;
|
|
37846
|
+
logEvent("formal_record", { moment: ctx.moment, run_id: runId });
|
|
37847
|
+
return runId;
|
|
37848
|
+
} catch (err2) {
|
|
37849
|
+
logEvent("formal_record_failed", { moment: ctx.moment, category: "exception", name: err2?.constructor?.name ?? "Error" });
|
|
37850
|
+
return null;
|
|
37851
|
+
}
|
|
37852
|
+
}
|
|
37853
|
+
|
|
37354
37854
|
// src/commands/guard.ts
|
|
37355
37855
|
var EXCERPT_SOURCE_MAX_BYTES = 2 * 1024 * 1024;
|
|
37356
37856
|
var WRITERS_BUDGET_MS = 1500;
|
|
37357
37857
|
var EXCERPT_MAX_LINES2 = 30;
|
|
37358
37858
|
var VENDORED_READ_MAX_BYTES = 256 * 1024;
|
|
37359
37859
|
var GUARD_BLOCK_CAP = 2;
|
|
37360
|
-
var GUARD_ITER_FILE = (0,
|
|
37860
|
+
var GUARD_ITER_FILE = (0, import_node_path51.join)(VERITY_DIR, ".guard-iteration");
|
|
37361
37861
|
function readPreToolUseStdin() {
|
|
37362
37862
|
const empty = { command: "", cwd: null, sessionId: null };
|
|
37363
37863
|
return new Promise((resolve9) => {
|
|
@@ -37402,7 +37902,7 @@ function readPreToolUseStdin() {
|
|
|
37402
37902
|
}
|
|
37403
37903
|
function readIterMap() {
|
|
37404
37904
|
try {
|
|
37405
|
-
const raw = JSON.parse((0,
|
|
37905
|
+
const raw = JSON.parse((0, import_node_fs63.readFileSync)(GUARD_ITER_FILE, "utf-8"));
|
|
37406
37906
|
if (raw && typeof raw === "object") {
|
|
37407
37907
|
if (typeof raw.moment === "string" && typeof raw.count === "number") {
|
|
37408
37908
|
return { [raw.moment]: raw.count };
|
|
@@ -37422,10 +37922,10 @@ function readIter(moment) {
|
|
|
37422
37922
|
}
|
|
37423
37923
|
function writeIter(moment, count) {
|
|
37424
37924
|
try {
|
|
37425
|
-
(0,
|
|
37925
|
+
(0, import_node_fs63.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
37426
37926
|
const map = readIterMap();
|
|
37427
37927
|
map[moment] = count;
|
|
37428
|
-
(0,
|
|
37928
|
+
(0, import_node_fs63.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
37429
37929
|
} catch {
|
|
37430
37930
|
}
|
|
37431
37931
|
}
|
|
@@ -37435,10 +37935,10 @@ function resetIter(moment) {
|
|
|
37435
37935
|
if (!(moment in map)) return;
|
|
37436
37936
|
delete map[moment];
|
|
37437
37937
|
if (Object.keys(map).length === 0) {
|
|
37438
|
-
if ((0,
|
|
37938
|
+
if ((0, import_node_fs63.existsSync)(GUARD_ITER_FILE)) (0, import_node_fs63.unlinkSync)(GUARD_ITER_FILE);
|
|
37439
37939
|
} else {
|
|
37440
|
-
(0,
|
|
37441
|
-
(0,
|
|
37940
|
+
(0, import_node_fs63.mkdirSync)(VERITY_DIR, { recursive: true });
|
|
37941
|
+
(0, import_node_fs63.writeFileSync)(GUARD_ITER_FILE, JSON.stringify(map));
|
|
37442
37942
|
}
|
|
37443
37943
|
} catch {
|
|
37444
37944
|
}
|
|
@@ -37488,17 +37988,17 @@ function parsePrIntent(command) {
|
|
|
37488
37988
|
}
|
|
37489
37989
|
var TRIVIAL_INTENT = /^(wip|tmp|temp|test|fix|chore|amend|\.+|fixup!.*|squash!.*|merge\b.*)$/i;
|
|
37490
37990
|
var SHELL_PLUMBING = /\$\(|`|<<-?\s*['"]?[A-Za-z_]/;
|
|
37491
|
-
function isSubstantiveIntent(
|
|
37492
|
-
if (!
|
|
37493
|
-
const t =
|
|
37991
|
+
function isSubstantiveIntent(text2) {
|
|
37992
|
+
if (!text2) return false;
|
|
37993
|
+
const t = text2.trim();
|
|
37494
37994
|
if (t.length < 12) return false;
|
|
37495
37995
|
if (TRIVIAL_INTENT.test(t)) return false;
|
|
37496
37996
|
if (SHELL_PLUMBING.test(t)) return false;
|
|
37497
37997
|
return true;
|
|
37498
37998
|
}
|
|
37499
37999
|
function extractStatedIntent(moment, command, pushedMessages = null) {
|
|
37500
|
-
const
|
|
37501
|
-
return isSubstantiveIntent(
|
|
38000
|
+
const text2 = moment === "pre-commit" ? parseCommitMessage(command) : parsePrIntent(command) ?? pushedMessages;
|
|
38001
|
+
return isSubstantiveIntent(text2) ? text2 : null;
|
|
37502
38002
|
}
|
|
37503
38003
|
function hasBlockingFinding(response, sentFiles) {
|
|
37504
38004
|
const findings = response.findings ?? [];
|
|
@@ -37508,7 +38008,7 @@ function hasBlockingFinding(response, sentFiles) {
|
|
|
37508
38008
|
function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedIntent, coverageTelemetry) {
|
|
37509
38009
|
const analyzable = filterAnalyzable(files);
|
|
37510
38010
|
const securityFiles = filterSecurity(files);
|
|
37511
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0,
|
|
38011
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).map((f) => (0, import_node_fs63.existsSync)(f) ? f : resolveFile(f)).filter((f) => f !== null);
|
|
37512
38012
|
const staticResults = runCodacyAnalysisIfAvailable(scannable);
|
|
37513
38013
|
const trigger = moment === "pre-commit" ? "hook:pre-commit" : "hook:pre-push";
|
|
37514
38014
|
const requestBody = {
|
|
@@ -37521,7 +38021,7 @@ function buildGuardRequest(moment, files, codeDelta, iter, sessionId, statedInte
|
|
|
37521
38021
|
agent_harness: "claude-code",
|
|
37522
38022
|
// Prefer the session id Claude Code passes on the hook payload; fall back
|
|
37523
38023
|
// to the env var, then 'unknown'.
|
|
37524
|
-
session_id: sessionId ??
|
|
38024
|
+
session_id: sessionId ?? envSessionId() ?? "unknown",
|
|
37525
38025
|
trigger,
|
|
37526
38026
|
iteration: iter + 1
|
|
37527
38027
|
}
|
|
@@ -37589,6 +38089,14 @@ function oneShotLostOutcome(input) {
|
|
|
37589
38089
|
return input.agentGate === "FAIL" && input.agentBlocking ? "block" : "allow-without-review";
|
|
37590
38090
|
}
|
|
37591
38091
|
function withAgentVerdict(oneShot, agent) {
|
|
38092
|
+
if (agent.one_shot_source === "none" && agent.findings_mode === "agent" && agent.gate_decision !== null) {
|
|
38093
|
+
return {
|
|
38094
|
+
...oneShot,
|
|
38095
|
+
gate_decision: worstGate(agent.gate_decision, "WARN", "WARN"),
|
|
38096
|
+
findings: agent.findings.filter((f) => f.agent_added === true),
|
|
38097
|
+
agent_review: { ...agent.agent_review, gate_decision_before: oneShot.gate_decision ?? null, one_shot_source: "none", cleared: [], downgraded: [] }
|
|
38098
|
+
};
|
|
38099
|
+
}
|
|
37592
38100
|
if (agent.one_shot_source === "none" && typeof oneShot.gate_decision === "string") {
|
|
37593
38101
|
const added = agent.findings.filter((f) => f.agent_added === true);
|
|
37594
38102
|
return {
|
|
@@ -37652,7 +38160,8 @@ function startAgentReview(input) {
|
|
|
37652
38160
|
http: http2,
|
|
37653
38161
|
executeTools: makeToolExecutor(ctx),
|
|
37654
38162
|
startedAt: input.hookStartedAt,
|
|
37655
|
-
|
|
38163
|
+
// The push's deadline follows the review effort (lib/effort.ts); the commit's never does.
|
|
38164
|
+
deadlineMs: input.moment === "pre-push" ? effortProfile(input.root).pushDeadlineMs : AGENT_DEADLINE_MS[input.moment],
|
|
37656
38165
|
start: {
|
|
37657
38166
|
moment: input.moment,
|
|
37658
38167
|
iteration: input.iteration,
|
|
@@ -37677,7 +38186,8 @@ function startFormalPhase(input) {
|
|
|
37677
38186
|
const env = process.env.VERITY_GIT_MOMENT_FORMAL;
|
|
37678
38187
|
if (env === "off") return null;
|
|
37679
38188
|
if (env !== "push" && readProjectConfig().formal !== "push") return null;
|
|
37680
|
-
const
|
|
38189
|
+
const profile = effortProfile(input.root);
|
|
38190
|
+
const deadlineAt = input.hookStartedAt + profile.pushDeadlineMs - 1e4;
|
|
37681
38191
|
const ig = loadVerityIgnore();
|
|
37682
38192
|
const files = input.files.filter((f) => !isVerityOwnedPath(f) && !isIgnored3(ig, f));
|
|
37683
38193
|
let changedLines = /* @__PURE__ */ new Map();
|
|
@@ -37699,9 +38209,17 @@ function startFormalPhase(input) {
|
|
|
37699
38209
|
return { ok: true, content };
|
|
37700
38210
|
} : void 0;
|
|
37701
38211
|
const run4 = async () => {
|
|
37702
|
-
const prep = await prepareFormalPhase(input.root, process.env, input.auth, readSource, withoutPaths(tip ? revisionSource(input.root, tip) : worktreeSource(input.root), isDeniedPath));
|
|
38212
|
+
const prep = await prepareFormalPhase(input.root, process.env, input.auth, readSource, withoutPaths(tip ? revisionSource(input.root, tip) : worktreeSource(input.root), isDeniedPath), { tier: profile.formal.tier });
|
|
37703
38213
|
if (!prep.ok) return skippedOutcome(prep.skip, prep.detail);
|
|
37704
|
-
|
|
38214
|
+
if (process.env.VERITY_FORMAL_VERIFY !== "off") {
|
|
38215
|
+
const ctx = { root: input.root, range: input.range, codeMap: prep.deps.codeMap ?? null };
|
|
38216
|
+
const post = verifyPost(input.auth);
|
|
38217
|
+
prep.deps.verify = (f, v) => verifyFinding(
|
|
38218
|
+
{ file: f.file, symbol: f.symbol, ...v.lines ? { lines: v.lines } : {}, property: { desc: f.desc, kind: f.kind, trace: f.trace }, replayReason: f.reason ?? "", changedLines: v.changedLines },
|
|
38219
|
+
{ executeTools: makeToolExecutor(ctx), localTools: offeredLocalTools(ctx), deadlineAt: v.deadlineAt, costLeftUsd: v.costLeftUsd, post }
|
|
38220
|
+
);
|
|
38221
|
+
}
|
|
38222
|
+
return runFormalPhaseWithin({ root: input.root, files, changedLines, deadlineAt, deps: prep.deps, minScore: profile.formal.minScore, maxRounds: profile.formal.maxRounds, costCapUsd: profile.formal.costCapUsd, maxTargets: profile.formal.maxTargets, relaxedGates: profile.formal.relaxedGates, dailyCap: profile.formal.dailyModels, dailyCostCapUsd: profile.formal.dailyCostUsd });
|
|
37705
38223
|
};
|
|
37706
38224
|
return run4().catch((err2) => skippedOutcome("error", String(err2?.message ?? err2).slice(0, 200)));
|
|
37707
38225
|
}
|
|
@@ -37893,6 +38411,9 @@ async function runGuard(opts, globals) {
|
|
|
37893
38411
|
rounds: formalOutcome.model?.rounds ?? null,
|
|
37894
38412
|
properties: formalOutcome.properties?.map((p) => `${p.id}:${p.result}`) ?? [],
|
|
37895
38413
|
findings: formalOutcome.findings.map((f) => `${f.property}:${f.verdict}`),
|
|
38414
|
+
// Review effort "max" models more than one function: each one, and why the search stopped early.
|
|
38415
|
+
targets: (formalOutcome.targets ?? []).map((t) => `${t.file}#${t.symbol}:${t.status}${t.skip ? `(${t.skip})` : ""}`),
|
|
38416
|
+
stopped_at: formalOutcome.stoppedAt?.skip ?? null,
|
|
37896
38417
|
// Decision 81: what each property rests on (a rule, or "line"), what was
|
|
37897
38418
|
// sent back or dropped as ungrounded, and which counterexamples lack their
|
|
37898
38419
|
// property's trigger (shadow). Ids and rule names only, never code.
|
|
@@ -37925,6 +38446,13 @@ async function runGuard(opts, globals) {
|
|
|
37925
38446
|
const witnessed = [...codeDelta.files.map((f) => f.path), ...agentVerdict?.witnessed_files ?? []];
|
|
37926
38447
|
mergeFormalFindings(response, formalOutcome, files);
|
|
37927
38448
|
decision = response.gate_decision ?? "(unrecognised)";
|
|
38449
|
+
if (formalOutcome) {
|
|
38450
|
+
await postPhaseRecord(formalOutcome, {
|
|
38451
|
+
moment: "push",
|
|
38452
|
+
parentRunId: typeof response.run_id === "string" ? response.run_id : null,
|
|
38453
|
+
pushedFiles: files
|
|
38454
|
+
}, { serviceUrl: urlResult.data, token: tokenResult.data.token, deadlineAt: guardRecordDeadline(hookStartedAt) });
|
|
38455
|
+
}
|
|
37928
38456
|
if (!result.ok) {
|
|
37929
38457
|
const authRemedy = result.error.startsWith("STALE_VERIFICATION") ? " Your GitHub verification expired \u2014 run `verity login` to re-verify." : result.error.startsWith("FORBIDDEN") ? " No access grant for this repository \u2014 run `verity login` to refresh your grants." : result.error.startsWith("INVALID_TOKEN") ? " Your Verity login expired or was revoked \u2014 run `verity login` to sign in again." : "";
|
|
37930
38458
|
if (oneShotLostOutcome({ agentGate: decision, agentBlocking: hasBlockingFinding(response, witnessed) }) === "block") {
|
|
@@ -38042,7 +38570,7 @@ function writeBlockMessage(moment, response, covDetail) {
|
|
|
38042
38570
|
|
|
38043
38571
|
// src/commands/ignore.ts
|
|
38044
38572
|
function registerIgnoreCommand(program2) {
|
|
38045
|
-
const ignore = program2.command("ignore").description("Declare the next turn (or a short window) as housekeeping \u2014 no review needed").option("--turn", "Cover the next turn only (the default)").option("--for <duration>", "Cover a window: 30m, 45s, 1h (max 60m)").option("--reason <reason>", "Why this window needs no review \u2014 required, and recorded").option("--agent", "Mark the declaration as agent-invoked (a ledger label, not a permission)").option("--session-id <id>", "Session id (defaults to $CLAUDE_SESSION_ID)").option("--json", "Output raw JSON").action(async (opts) => {
|
|
38573
|
+
const ignore = program2.command("ignore").description("Declare the next turn (or a short window) as housekeeping \u2014 no review needed").option("--turn", "Cover the next turn only (the default)").option("--for <duration>", "Cover a window: 30m, 45s, 1h (max 60m)").option("--reason <reason>", "Why this window needs no review \u2014 required, and recorded").option("--agent", "Mark the declaration as agent-invoked (a ledger label, not a permission)").option("--session-id <id>", "Session id (defaults to $CLAUDE_SESSION_ID, then $CLAUDE_CODE_SESSION_ID)").option("--json", "Output raw JSON").action(async (opts) => {
|
|
38046
38574
|
const globals = program2.opts();
|
|
38047
38575
|
const now = Math.floor(Date.now() / 1e3);
|
|
38048
38576
|
const reason = opts.reason?.trim();
|
|
@@ -38069,7 +38597,7 @@ function registerIgnoreCommand(program2) {
|
|
|
38069
38597
|
}
|
|
38070
38598
|
const tokenResult = await resolveToken(globals.token);
|
|
38071
38599
|
const token = tokenResult.ok ? tokenResult.data.token : void 0;
|
|
38072
|
-
const sessionId = opts.sessionId ||
|
|
38600
|
+
const sessionId = opts.sessionId || envSessionId();
|
|
38073
38601
|
const keys = ignoreStateKeys(token, sessionId);
|
|
38074
38602
|
const existing = resolveIgnoreState(keys);
|
|
38075
38603
|
const spent = existing?.state.spent ?? 0;
|
|
@@ -38115,11 +38643,11 @@ function registerIgnoreCommand(program2) {
|
|
|
38115
38643
|
printInfo(`Verity will skip ${window2} \u2014 "${reason}" (${spent + 1}/${IGNORE_BUDGET} this session).`);
|
|
38116
38644
|
printInfo("It covers turns that author nothing. If anything is written, the declaration voids and the review runs.");
|
|
38117
38645
|
});
|
|
38118
|
-
ignore.command("clear").description("Cancel the active declaration (the spent budget is not refunded)").option("--session-id <id>", "Session id (defaults to $CLAUDE_SESSION_ID)").action(async (opts) => {
|
|
38646
|
+
ignore.command("clear").description("Cancel the active declaration (the spent budget is not refunded)").option("--session-id <id>", "Session id (defaults to $CLAUDE_SESSION_ID, then $CLAUDE_CODE_SESSION_ID)").action(async (opts) => {
|
|
38119
38647
|
const globals = program2.opts();
|
|
38120
38648
|
const tokenResult = await resolveToken(globals.token);
|
|
38121
38649
|
const token = tokenResult.ok ? tokenResult.data.token : void 0;
|
|
38122
|
-
const sessionId = opts.sessionId ||
|
|
38650
|
+
const sessionId = opts.sessionId || envSessionId();
|
|
38123
38651
|
const found = resolveIgnoreState(ignoreStateKeys(token, sessionId));
|
|
38124
38652
|
const active = resolveActive(found?.state ?? null, Math.floor(Date.now() / 1e3));
|
|
38125
38653
|
if (!found || !active) {
|
|
@@ -38134,7 +38662,7 @@ function registerIgnoreCommand(program2) {
|
|
|
38134
38662
|
|
|
38135
38663
|
// src/commands/waive.ts
|
|
38136
38664
|
var import_node_crypto20 = require("node:crypto");
|
|
38137
|
-
var
|
|
38665
|
+
var import_node_fs64 = require("node:fs");
|
|
38138
38666
|
function registerWaiveCommand(program2) {
|
|
38139
38667
|
program2.command("waive <pattern-id>").description("Record an accepted-risk disposition for an open finding (voids when the file changes)").option("--file <path>", "File the finding is anchored to, REPO-RELATIVE (recommended \u2014 narrows the waive)").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action(async (patternId, opts) => {
|
|
38140
38668
|
const globals = program2.opts();
|
|
@@ -38163,7 +38691,7 @@ function registerWaiveCommand(program2) {
|
|
|
38163
38691
|
if (opts.file) {
|
|
38164
38692
|
body2.file = opts.file;
|
|
38165
38693
|
try {
|
|
38166
|
-
body2.file_sha256 = (0, import_node_crypto20.createHash)("sha256").update((0,
|
|
38694
|
+
body2.file_sha256 = (0, import_node_crypto20.createHash)("sha256").update((0, import_node_fs64.readFileSync)(opts.file)).digest("hex");
|
|
38167
38695
|
} catch {
|
|
38168
38696
|
printError(`Cannot read ${opts.file} \u2014 run from the repo root, or omit --file to waive by pattern.`);
|
|
38169
38697
|
process.exit(1);
|
|
@@ -38188,10 +38716,10 @@ function registerWaiveCommand(program2) {
|
|
|
38188
38716
|
}
|
|
38189
38717
|
|
|
38190
38718
|
// src/commands/init.ts
|
|
38191
|
-
var
|
|
38719
|
+
var import_node_fs69 = require("node:fs");
|
|
38192
38720
|
var import_promises20 = require("node:fs/promises");
|
|
38193
|
-
var
|
|
38194
|
-
var
|
|
38721
|
+
var import_yaml7 = __toESM2(require_dist());
|
|
38722
|
+
var import_node_path55 = require("node:path");
|
|
38195
38723
|
var import_node_os11 = require("node:os");
|
|
38196
38724
|
var import_node_child_process19 = require("node:child_process");
|
|
38197
38725
|
|
|
@@ -38226,12 +38754,12 @@ function printBanner(opts) {
|
|
|
38226
38754
|
const color = colorEnabled();
|
|
38227
38755
|
const version = `v${cliVersion()}`;
|
|
38228
38756
|
const art = [WORDMARK, WORDMARK_NARROW].find((a) => artWidth(a) <= columns) ?? null;
|
|
38229
|
-
const dim = (
|
|
38757
|
+
const dim = (text2) => color ? `${DIM3}${text2}${RESET2}` : text2;
|
|
38230
38758
|
process.stderr.write("\n");
|
|
38231
38759
|
if (!art) {
|
|
38232
38760
|
const candidates2 = [`Verity ${version}`, "Verity"];
|
|
38233
|
-
const
|
|
38234
|
-
if (
|
|
38761
|
+
const text2 = candidates2.find((c) => c.length + INDENT.length <= columns);
|
|
38762
|
+
if (text2) process.stderr.write(`${INDENT}${dim(text2)}
|
|
38235
38763
|
`);
|
|
38236
38764
|
process.stderr.write("\n");
|
|
38237
38765
|
return;
|
|
@@ -38271,7 +38799,7 @@ function printPhase(n, of, title, subtitle) {
|
|
|
38271
38799
|
}
|
|
38272
38800
|
|
|
38273
38801
|
// src/commands/doctor.ts
|
|
38274
|
-
var
|
|
38802
|
+
var import_node_fs65 = require("node:fs");
|
|
38275
38803
|
|
|
38276
38804
|
// src/lib/prereqs.ts
|
|
38277
38805
|
var import_node_child_process16 = require("node:child_process");
|
|
@@ -38479,11 +39007,11 @@ async function buildReport() {
|
|
|
38479
39007
|
const hooks = wiring.status;
|
|
38480
39008
|
const provenance = cliProvenance();
|
|
38481
39009
|
const telemetry = await checkTelemetry();
|
|
38482
|
-
const hasConfig = (0,
|
|
39010
|
+
const hasConfig = (0, import_node_fs65.existsSync)(projectPath(CODACY_CONFIG_FILE));
|
|
38483
39011
|
const artifacts = {
|
|
38484
|
-
standard: (0,
|
|
39012
|
+
standard: (0, import_node_fs65.existsSync)(projectPath(STANDARD_FILE)),
|
|
38485
39013
|
analysisConfig: hasConfig,
|
|
38486
|
-
verityMd: (0,
|
|
39014
|
+
verityMd: (0, import_node_fs65.existsSync)(projectPath(VERITY_MD_FILE)),
|
|
38487
39015
|
analysisConfigIds: hasConfig ? validatePatternIds().status : "absent"
|
|
38488
39016
|
};
|
|
38489
39017
|
const next = [];
|
|
@@ -38642,8 +39170,8 @@ function registerDoctorCommand(program2) {
|
|
|
38642
39170
|
}
|
|
38643
39171
|
|
|
38644
39172
|
// src/commands/migrate.ts
|
|
38645
|
-
var
|
|
38646
|
-
var
|
|
39173
|
+
var import_node_fs66 = require("node:fs");
|
|
39174
|
+
var import_node_path52 = require("node:path");
|
|
38647
39175
|
var import_node_child_process17 = require("node:child_process");
|
|
38648
39176
|
var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
|
|
38649
39177
|
function defaultNpmRemover(pkg) {
|
|
@@ -38680,12 +39208,12 @@ async function runMigration(opts = {}) {
|
|
|
38680
39208
|
return { actions, migrated: actions.length > 0 };
|
|
38681
39209
|
}
|
|
38682
39210
|
function migrateProjectDir(root, actions) {
|
|
38683
|
-
const gateDir = (0,
|
|
38684
|
-
const verityDir = (0,
|
|
38685
|
-
if ((0,
|
|
39211
|
+
const gateDir = (0, import_node_path52.join)(root, ".gate");
|
|
39212
|
+
const verityDir = (0, import_node_path52.join)(root, ".verity");
|
|
39213
|
+
if ((0, import_node_fs66.existsSync)(gateDir) && !(0, import_node_fs66.existsSync)(verityDir)) {
|
|
38686
39214
|
return migrateProjectDirRename(root, gateDir, verityDir, actions);
|
|
38687
39215
|
}
|
|
38688
|
-
if ((0,
|
|
39216
|
+
if ((0, import_node_fs66.existsSync)(gateDir) && (0, import_node_fs66.existsSync)(verityDir)) {
|
|
38689
39217
|
return migrateProjectDirCarry(gateDir, verityDir, actions);
|
|
38690
39218
|
}
|
|
38691
39219
|
return false;
|
|
@@ -38706,13 +39234,13 @@ function migrateProjectDirRename(root, gateDir, verityDir, actions) {
|
|
|
38706
39234
|
}
|
|
38707
39235
|
}
|
|
38708
39236
|
if (moved) {
|
|
38709
|
-
if ((0,
|
|
39237
|
+
if ((0, import_node_fs66.existsSync)(gateDir)) {
|
|
38710
39238
|
const carried = carryLegacyContents(gateDir, verityDir);
|
|
38711
39239
|
if (carried > 0) {
|
|
38712
39240
|
actions.push(`Carried ${carried} untracked legacy file(s) from .gate/ into .verity/`);
|
|
38713
39241
|
}
|
|
38714
39242
|
try {
|
|
38715
|
-
(0,
|
|
39243
|
+
(0, import_node_fs66.rmSync)(gateDir, { recursive: true, force: true });
|
|
38716
39244
|
} catch {
|
|
38717
39245
|
}
|
|
38718
39246
|
}
|
|
@@ -38728,18 +39256,18 @@ function migrateProjectDirCarry(gateDir, verityDir, actions) {
|
|
|
38728
39256
|
actions.push(`Carried ${carried} legacy file(s) from .gate/ into .verity/`);
|
|
38729
39257
|
}
|
|
38730
39258
|
try {
|
|
38731
|
-
(0,
|
|
39259
|
+
(0, import_node_fs66.rmSync)(gateDir, { recursive: true, force: true });
|
|
38732
39260
|
} catch {
|
|
38733
39261
|
}
|
|
38734
39262
|
return carried > 0;
|
|
38735
39263
|
}
|
|
38736
39264
|
function migrateGlobalCredentials(home, actions) {
|
|
38737
39265
|
if (!home) return;
|
|
38738
|
-
const gateCreds = (0,
|
|
38739
|
-
const verityCreds = (0,
|
|
38740
|
-
if (!(0,
|
|
38741
|
-
if (!(0,
|
|
38742
|
-
(0,
|
|
39266
|
+
const gateCreds = (0, import_node_path52.join)(home, ".gate", "credentials");
|
|
39267
|
+
const verityCreds = (0, import_node_path52.join)(home, ".verity", "credentials");
|
|
39268
|
+
if (!(0, import_node_fs66.existsSync)(gateCreds)) return;
|
|
39269
|
+
if (!(0, import_node_fs66.existsSync)(verityCreds)) {
|
|
39270
|
+
(0, import_node_fs66.mkdirSync)((0, import_node_path52.join)(home, ".verity"), { recursive: true });
|
|
38743
39271
|
moveFile(gateCreds, verityCreds);
|
|
38744
39272
|
actions.push("Moved ~/.gate/credentials \u2192 ~/.verity/credentials");
|
|
38745
39273
|
return;
|
|
@@ -38761,8 +39289,8 @@ async function migrateLegacyHooks(root, actions) {
|
|
|
38761
39289
|
}
|
|
38762
39290
|
}
|
|
38763
39291
|
async function migrateClaudeMd(root, actions) {
|
|
38764
|
-
const claudeMd = (0,
|
|
38765
|
-
const hadLegacyBlock = (0,
|
|
39292
|
+
const claudeMd = (0, import_node_path52.join)(root, "CLAUDE.md");
|
|
39293
|
+
const hadLegacyBlock = (0, import_node_fs66.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd));
|
|
38766
39294
|
if (!hadLegacyBlock) return;
|
|
38767
39295
|
try {
|
|
38768
39296
|
await ensureClaudeMdPointer(root);
|
|
@@ -38772,9 +39300,9 @@ async function migrateClaudeMd(root, actions) {
|
|
|
38772
39300
|
}
|
|
38773
39301
|
}
|
|
38774
39302
|
function migrateStandardFile(root, actions) {
|
|
38775
|
-
const gateMd = (0,
|
|
38776
|
-
const verityMd = (0,
|
|
38777
|
-
if (!(0,
|
|
39303
|
+
const gateMd = (0, import_node_path52.join)(root, "GATE.md");
|
|
39304
|
+
const verityMd = (0, import_node_path52.join)(root, "VERITY.md");
|
|
39305
|
+
if (!(0, import_node_fs66.existsSync)(gateMd) || (0, import_node_fs66.existsSync)(verityMd)) return;
|
|
38778
39306
|
let moved = false;
|
|
38779
39307
|
if (isGitRepo(root) && isGitTracked(root, "GATE.md")) {
|
|
38780
39308
|
try {
|
|
@@ -38786,12 +39314,12 @@ function migrateStandardFile(root, actions) {
|
|
|
38786
39314
|
if (!moved) moveFile(gateMd, verityMd);
|
|
38787
39315
|
const content = readFileSyncSafe(verityMd);
|
|
38788
39316
|
const refreshed = content.split("GATE.md").join("VERITY.md");
|
|
38789
|
-
if (refreshed !== content) (0,
|
|
39317
|
+
if (refreshed !== content) (0, import_node_fs66.writeFileSync)(verityMd, refreshed);
|
|
38790
39318
|
actions.push("Renamed GATE.md \u2192 VERITY.md");
|
|
38791
39319
|
}
|
|
38792
39320
|
async function migrateTelemetryHeaders(root, actions) {
|
|
38793
|
-
const file = (0,
|
|
38794
|
-
if (!(0,
|
|
39321
|
+
const file = (0, import_node_path52.join)(root, ".claude", "settings.local.json");
|
|
39322
|
+
if (!(0, import_node_fs66.existsSync)(file)) return;
|
|
38795
39323
|
let settings;
|
|
38796
39324
|
try {
|
|
38797
39325
|
settings = JSON.parse(readFileSyncSafe(file) || "{}");
|
|
@@ -38838,15 +39366,15 @@ function mergeGlobalCredentials(gateCreds, verityCreds) {
|
|
|
38838
39366
|
toAppend.push(line2.replace(/\r$/, ""));
|
|
38839
39367
|
}
|
|
38840
39368
|
if (toAppend.length > 0) {
|
|
38841
|
-
const
|
|
38842
|
-
(0,
|
|
39369
|
+
const sep7 = verityContent.endsWith("\n") || verityContent === "" ? "" : "\n";
|
|
39370
|
+
(0, import_node_fs66.writeFileSync)(verityCreds, verityContent + sep7 + toAppend.join("\n") + "\n");
|
|
38843
39371
|
}
|
|
38844
|
-
(0,
|
|
39372
|
+
(0, import_node_fs66.rmSync)(gateCreds, { force: true });
|
|
38845
39373
|
return toAppend.length;
|
|
38846
39374
|
}
|
|
38847
39375
|
function readFileSyncSafe(path) {
|
|
38848
39376
|
try {
|
|
38849
|
-
return (0,
|
|
39377
|
+
return (0, import_node_fs66.readFileSync)(path, "utf-8");
|
|
38850
39378
|
} catch {
|
|
38851
39379
|
return "";
|
|
38852
39380
|
}
|
|
@@ -38861,35 +39389,35 @@ function hasStagedChanges(root) {
|
|
|
38861
39389
|
}
|
|
38862
39390
|
function moveDir(from, to) {
|
|
38863
39391
|
try {
|
|
38864
|
-
(0,
|
|
39392
|
+
(0, import_node_fs66.renameSync)(from, to);
|
|
38865
39393
|
} catch (err2) {
|
|
38866
39394
|
if (err2.code !== "EXDEV") throw err2;
|
|
38867
|
-
(0,
|
|
38868
|
-
(0,
|
|
39395
|
+
(0, import_node_fs66.cpSync)(from, to, { recursive: true });
|
|
39396
|
+
(0, import_node_fs66.rmSync)(from, { recursive: true, force: true });
|
|
38869
39397
|
}
|
|
38870
39398
|
}
|
|
38871
39399
|
function moveFile(from, to) {
|
|
38872
39400
|
try {
|
|
38873
|
-
(0,
|
|
39401
|
+
(0, import_node_fs66.renameSync)(from, to);
|
|
38874
39402
|
} catch (err2) {
|
|
38875
39403
|
if (err2.code !== "EXDEV") throw err2;
|
|
38876
|
-
(0,
|
|
38877
|
-
(0,
|
|
39404
|
+
(0, import_node_fs66.cpSync)(from, to);
|
|
39405
|
+
(0, import_node_fs66.rmSync)(from, { force: true });
|
|
38878
39406
|
}
|
|
38879
39407
|
}
|
|
38880
39408
|
function carryLegacyContents(gateDir, verityDir) {
|
|
38881
39409
|
let copied = 0;
|
|
38882
39410
|
const walk2 = (relDir) => {
|
|
38883
|
-
const srcDir = (0,
|
|
38884
|
-
for (const entry of (0,
|
|
38885
|
-
const rel = relDir ? (0,
|
|
38886
|
-
const src = (0,
|
|
38887
|
-
const dest = (0,
|
|
38888
|
-
if ((0,
|
|
39411
|
+
const srcDir = (0, import_node_path52.join)(gateDir, relDir);
|
|
39412
|
+
for (const entry of (0, import_node_fs66.readdirSync)(srcDir)) {
|
|
39413
|
+
const rel = relDir ? (0, import_node_path52.join)(relDir, entry) : entry;
|
|
39414
|
+
const src = (0, import_node_path52.join)(gateDir, rel);
|
|
39415
|
+
const dest = (0, import_node_path52.join)(verityDir, rel);
|
|
39416
|
+
if ((0, import_node_fs66.statSync)(src).isDirectory()) {
|
|
38889
39417
|
walk2(rel);
|
|
38890
|
-
} else if (!(0,
|
|
38891
|
-
(0,
|
|
38892
|
-
(0,
|
|
39418
|
+
} else if (!(0, import_node_fs66.existsSync)(dest)) {
|
|
39419
|
+
(0, import_node_fs66.mkdirSync)((0, import_node_path52.dirname)(dest), { recursive: true });
|
|
39420
|
+
(0, import_node_fs66.cpSync)(src, dest);
|
|
38893
39421
|
copied++;
|
|
38894
39422
|
}
|
|
38895
39423
|
}
|
|
@@ -38898,22 +39426,22 @@ function carryLegacyContents(gateDir, verityDir) {
|
|
|
38898
39426
|
return copied;
|
|
38899
39427
|
}
|
|
38900
39428
|
async function needsMigration(root = repoRoot()) {
|
|
38901
|
-
const gateDir = (0,
|
|
38902
|
-
const verityDir = (0,
|
|
38903
|
-
if ((0,
|
|
38904
|
-
if ((0,
|
|
38905
|
-
if ((0,
|
|
39429
|
+
const gateDir = (0, import_node_path52.join)(root, ".gate");
|
|
39430
|
+
const verityDir = (0, import_node_path52.join)(root, ".verity");
|
|
39431
|
+
if ((0, import_node_fs66.existsSync)(gateDir) && !(0, import_node_fs66.existsSync)(verityDir)) return true;
|
|
39432
|
+
if ((0, import_node_fs66.existsSync)(gateDir) && (0, import_node_fs66.existsSync)(verityDir)) {
|
|
39433
|
+
if ((0, import_node_fs66.existsSync)((0, import_node_path52.join)(gateDir, "credentials")) && !(0, import_node_fs66.existsSync)((0, import_node_path52.join)(verityDir, "credentials"))) {
|
|
38906
39434
|
return true;
|
|
38907
39435
|
}
|
|
38908
|
-
if ((0,
|
|
39436
|
+
if ((0, import_node_fs66.existsSync)((0, import_node_path52.join)(gateDir, "memory")) && !(0, import_node_fs66.existsSync)((0, import_node_path52.join)(verityDir, "memory"))) {
|
|
38909
39437
|
return true;
|
|
38910
39438
|
}
|
|
38911
39439
|
}
|
|
38912
|
-
const claudeMd = (0,
|
|
38913
|
-
if ((0,
|
|
39440
|
+
const claudeMd = (0, import_node_path52.join)(root, "CLAUDE.md");
|
|
39441
|
+
if ((0, import_node_fs66.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
|
|
38914
39442
|
return true;
|
|
38915
39443
|
}
|
|
38916
|
-
if ((0,
|
|
39444
|
+
if ((0, import_node_fs66.existsSync)((0, import_node_path52.join)(root, "GATE.md")) && !(0, import_node_fs66.existsSync)((0, import_node_path52.join)(root, "VERITY.md"))) {
|
|
38917
39445
|
return true;
|
|
38918
39446
|
}
|
|
38919
39447
|
if (await hasLegacyHooksAt(root)) return true;
|
|
@@ -39015,7 +39543,7 @@ var DIM4 = "\x1B[2m";
|
|
|
39015
39543
|
var BOLD2 = "\x1B[1m";
|
|
39016
39544
|
var RESET3 = "\x1B[0m";
|
|
39017
39545
|
function renderSelect(question, choices, state, mode2, color = colorEnabled()) {
|
|
39018
|
-
const paint = (
|
|
39546
|
+
const paint = (text2, code) => color ? `${code}${text2}${RESET3}` : text2;
|
|
39019
39547
|
const lines = ["", ` ${question}`];
|
|
39020
39548
|
const labelOf = (c) => `${c.label}${c.recommended ? " (recommended)" : ""}`;
|
|
39021
39549
|
const gutter = Math.max(...choices.map((c) => labelOf(c).length));
|
|
@@ -39194,11 +39722,11 @@ async function promptMultiSelect(question, choices, fallback) {
|
|
|
39194
39722
|
}
|
|
39195
39723
|
|
|
39196
39724
|
// src/lib/prove/lean-install.ts
|
|
39197
|
-
var
|
|
39725
|
+
var import_node_fs67 = require("node:fs");
|
|
39198
39726
|
var import_node_crypto21 = require("node:crypto");
|
|
39199
39727
|
var import_node_child_process18 = require("node:child_process");
|
|
39200
39728
|
var import_node_os10 = require("node:os");
|
|
39201
|
-
var
|
|
39729
|
+
var import_node_path53 = require("node:path");
|
|
39202
39730
|
var import_promises18 = require("node:stream/promises");
|
|
39203
39731
|
var import_node_stream = require("node:stream");
|
|
39204
39732
|
var RELEASES = "https://releases.lean-lang.org/lean4";
|
|
@@ -39209,10 +39737,10 @@ function freeBytes(dir) {
|
|
|
39209
39737
|
let d = dir;
|
|
39210
39738
|
for (let i2 = 0; i2 < 64; i2++) {
|
|
39211
39739
|
try {
|
|
39212
|
-
const st = (0,
|
|
39740
|
+
const st = (0, import_node_fs67.statfsSync)(d);
|
|
39213
39741
|
return Number(st.bavail) * Number(st.bsize);
|
|
39214
39742
|
} catch {
|
|
39215
|
-
const up = (0,
|
|
39743
|
+
const up = (0, import_node_path53.join)(d, "..");
|
|
39216
39744
|
if (up === d) return null;
|
|
39217
39745
|
d = up;
|
|
39218
39746
|
}
|
|
@@ -39234,7 +39762,7 @@ function expectedSha256(asset, version = pinnedVersion()) {
|
|
|
39234
39762
|
function sha256File(path) {
|
|
39235
39763
|
return new Promise((resolve9, reject) => {
|
|
39236
39764
|
const hash = (0, import_node_crypto21.createHash)("sha256");
|
|
39237
|
-
(0,
|
|
39765
|
+
(0, import_node_fs67.createReadStream)(path).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve9(hash.digest("hex"))).on("error", reject);
|
|
39238
39766
|
});
|
|
39239
39767
|
}
|
|
39240
39768
|
async function verifyDownload(zip, asset, version = pinnedVersion()) {
|
|
@@ -39254,7 +39782,7 @@ function leanAssetName(version = pinnedVersion()) {
|
|
|
39254
39782
|
return suffix ? `lean-${v}-${suffix}.zip` : null;
|
|
39255
39783
|
}
|
|
39256
39784
|
function pinnedVersionDir(env = process.env) {
|
|
39257
|
-
return (0,
|
|
39785
|
+
return (0, import_node_path53.join)(verityLeanHome(env), pinnedVersion());
|
|
39258
39786
|
}
|
|
39259
39787
|
function lakeBinary() {
|
|
39260
39788
|
return (0, import_node_os10.platform)() === "win32" ? "lake.exe" : "lake";
|
|
@@ -39265,12 +39793,12 @@ function unzip(zip, dest) {
|
|
|
39265
39793
|
for (const [cmd, args2] of attempts) {
|
|
39266
39794
|
try {
|
|
39267
39795
|
(0, import_node_child_process18.execFileSync)(cmd, args2, { stdio: ["ignore", "ignore", "pipe"], timeout: 15 * 6e4 });
|
|
39268
|
-
if ((0,
|
|
39796
|
+
if ((0, import_node_fs67.readdirSync)(dest).length > 0) return { ok: true, via: cmd };
|
|
39269
39797
|
errors.push(`${cmd}: produced nothing`);
|
|
39270
39798
|
} catch (err2) {
|
|
39271
39799
|
errors.push(`${cmd}: ${String(err2.message).split("\n")[0].slice(0, 120)}`);
|
|
39272
39800
|
try {
|
|
39273
|
-
for (const e of (0,
|
|
39801
|
+
for (const e of (0, import_node_fs67.readdirSync)(dest)) (0, import_node_fs67.rmSync)((0, import_node_path53.join)(dest, e), { recursive: true, force: true });
|
|
39274
39802
|
} catch {
|
|
39275
39803
|
}
|
|
39276
39804
|
}
|
|
@@ -39296,7 +39824,7 @@ async function download(url, dest, onProgress, stallMs = DOWNLOAD_STALL_MS) {
|
|
|
39296
39824
|
seen += chunk.length;
|
|
39297
39825
|
onProgress(seen, total);
|
|
39298
39826
|
});
|
|
39299
|
-
await (0, import_promises18.pipeline)(stream, (0,
|
|
39827
|
+
await (0, import_promises18.pipeline)(stream, (0, import_node_fs67.createWriteStream)(dest), { signal: ctrl.signal });
|
|
39300
39828
|
} catch (err2) {
|
|
39301
39829
|
if (ctrl.signal.aborted) throw new Error(`download stalled: nothing received for ${Math.round(stallMs / 1e3)} s`);
|
|
39302
39830
|
throw err2;
|
|
@@ -39346,10 +39874,10 @@ async function installLean(opts = {}) {
|
|
|
39346
39874
|
const gb = (n) => (n / 1024 ** 3).toFixed(1);
|
|
39347
39875
|
return { ok: false, error: `not enough disk space for Lean: ${gb(free)} GB free where ${home} lives, needs about ${gb(needed)} GB` };
|
|
39348
39876
|
}
|
|
39349
|
-
const tmp = (0,
|
|
39350
|
-
(0,
|
|
39351
|
-
(0,
|
|
39352
|
-
const zip = (0,
|
|
39877
|
+
const tmp = (0, import_node_path53.join)(home, ".tmp");
|
|
39878
|
+
(0, import_node_fs67.rmSync)(tmp, { recursive: true, force: true });
|
|
39879
|
+
(0, import_node_fs67.mkdirSync)(tmp, { recursive: true });
|
|
39880
|
+
const zip = (0, import_node_path53.join)(tmp, asset);
|
|
39353
39881
|
say(`downloading ${url}`);
|
|
39354
39882
|
let lastPct = -1;
|
|
39355
39883
|
try {
|
|
@@ -39362,41 +39890,41 @@ async function installLean(opts = {}) {
|
|
|
39362
39890
|
}
|
|
39363
39891
|
});
|
|
39364
39892
|
} catch (err2) {
|
|
39365
|
-
(0,
|
|
39893
|
+
(0, import_node_fs67.rmSync)(tmp, { recursive: true, force: true });
|
|
39366
39894
|
return { ok: false, error: err2.message };
|
|
39367
39895
|
}
|
|
39368
39896
|
say("verifying checksum");
|
|
39369
39897
|
const verified = await verifyDownload(zip, asset);
|
|
39370
39898
|
if (!verified.ok) {
|
|
39371
|
-
(0,
|
|
39899
|
+
(0, import_node_fs67.rmSync)(tmp, { recursive: true, force: true });
|
|
39372
39900
|
return { ok: false, error: verified.error };
|
|
39373
39901
|
}
|
|
39374
39902
|
say("unpacking (this takes a minute)");
|
|
39375
|
-
const unpack = (0,
|
|
39376
|
-
(0,
|
|
39903
|
+
const unpack = (0, import_node_path53.join)(tmp, "unpack");
|
|
39904
|
+
(0, import_node_fs67.mkdirSync)(unpack);
|
|
39377
39905
|
const unpacked = unzip(zip, unpack);
|
|
39378
39906
|
if (!unpacked.ok) {
|
|
39379
|
-
(0,
|
|
39907
|
+
(0, import_node_fs67.rmSync)(tmp, { recursive: true, force: true });
|
|
39380
39908
|
return { ok: false, error: `unpack failed: ${unpacked.error}` };
|
|
39381
39909
|
}
|
|
39382
|
-
const entries = (0,
|
|
39383
|
-
const top = entries.length === 1 && (0,
|
|
39384
|
-
if (!(0,
|
|
39385
|
-
(0,
|
|
39910
|
+
const entries = (0, import_node_fs67.readdirSync)(unpack);
|
|
39911
|
+
const top = entries.length === 1 && (0, import_node_fs67.statSync)((0, import_node_path53.join)(unpack, entries[0])).isDirectory() ? (0, import_node_path53.join)(unpack, entries[0]) : unpack;
|
|
39912
|
+
if (!(0, import_node_fs67.existsSync)((0, import_node_path53.join)(top, "bin", lakeBinary()))) {
|
|
39913
|
+
(0, import_node_fs67.rmSync)(tmp, { recursive: true, force: true });
|
|
39386
39914
|
return { ok: false, error: "the archive did not contain bin/lake" };
|
|
39387
39915
|
}
|
|
39388
|
-
(0,
|
|
39389
|
-
(0,
|
|
39390
|
-
(0,
|
|
39391
|
-
(0,
|
|
39916
|
+
(0, import_node_fs67.rmSync)(dir, { recursive: true, force: true });
|
|
39917
|
+
(0, import_node_fs67.mkdirSync)(home, { recursive: true });
|
|
39918
|
+
(0, import_node_fs67.renameSync)(top, dir);
|
|
39919
|
+
(0, import_node_fs67.rmSync)(tmp, { recursive: true, force: true });
|
|
39392
39920
|
return { ok: true, dir };
|
|
39393
39921
|
}
|
|
39394
39922
|
|
|
39395
39923
|
// src/lib/remote-config.ts
|
|
39396
|
-
var
|
|
39924
|
+
var import_node_fs68 = require("node:fs");
|
|
39397
39925
|
var import_promises19 = require("node:fs/promises");
|
|
39398
|
-
var
|
|
39399
|
-
var
|
|
39926
|
+
var import_node_path54 = require("node:path");
|
|
39927
|
+
var import_yaml6 = __toESM2(require_dist());
|
|
39400
39928
|
var IGNORE_RIDER = "verityignore";
|
|
39401
39929
|
async function fetchRemoteSetup(opts) {
|
|
39402
39930
|
const standard = await apiRequest({
|
|
@@ -39436,11 +39964,11 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
39436
39964
|
const content = { ...found.standard.content };
|
|
39437
39965
|
const rider = typeof content[IGNORE_RIDER] === "string" ? content[IGNORE_RIDER] : null;
|
|
39438
39966
|
delete content[IGNORE_RIDER];
|
|
39439
|
-
await writeOut(STANDARD_FILE, (0,
|
|
39967
|
+
await writeOut(STANDARD_FILE, (0, import_yaml6.stringify)(content));
|
|
39440
39968
|
written.push(STANDARD_FILE);
|
|
39441
39969
|
if (rider !== null) {
|
|
39442
39970
|
const localIgnore = projectPath(VERITYIGNORE_FILE);
|
|
39443
|
-
if (!(0,
|
|
39971
|
+
if (!(0, import_node_fs68.existsSync)(localIgnore)) {
|
|
39444
39972
|
await writeOut(VERITYIGNORE_FILE, rider);
|
|
39445
39973
|
written.push(VERITYIGNORE_FILE);
|
|
39446
39974
|
} else {
|
|
@@ -39471,9 +39999,9 @@ async function adoptRemoteSetup(found, opts) {
|
|
|
39471
39999
|
written.push(VERITY_MD_FILE);
|
|
39472
40000
|
return { written, notes };
|
|
39473
40001
|
}
|
|
39474
|
-
async function writeOut(
|
|
39475
|
-
const target = projectPath(
|
|
39476
|
-
await (0, import_promises19.mkdir)((0,
|
|
40002
|
+
async function writeOut(relative7, body2) {
|
|
40003
|
+
const target = projectPath(relative7);
|
|
40004
|
+
await (0, import_promises19.mkdir)((0, import_node_path54.dirname)(target), { recursive: true });
|
|
39477
40005
|
await (0, import_promises19.writeFile)(target, body2);
|
|
39478
40006
|
}
|
|
39479
40007
|
function describeRemote(found) {
|
|
@@ -39590,15 +40118,15 @@ async function runOptionalAuth(resolution, opts = {}) {
|
|
|
39590
40118
|
}
|
|
39591
40119
|
function resolveDataDir2() {
|
|
39592
40120
|
const candidates2 = [
|
|
39593
|
-
(0,
|
|
40121
|
+
(0, import_node_path55.join)(__dirname, "..", "data"),
|
|
39594
40122
|
// installed: node_modules/@codacy/verity-cli/data
|
|
39595
|
-
(0,
|
|
40123
|
+
(0, import_node_path55.join)(__dirname, "..", "..", "data"),
|
|
39596
40124
|
// edge case: nested resolution
|
|
39597
|
-
(0,
|
|
40125
|
+
(0, import_node_path55.join)(process.cwd(), "cli", "data")
|
|
39598
40126
|
// local dev: running from repo root
|
|
39599
40127
|
];
|
|
39600
40128
|
for (const candidate of candidates2) {
|
|
39601
|
-
if ((0,
|
|
40129
|
+
if ((0, import_node_fs69.existsSync)((0, import_node_path55.join)(candidate, "skills"))) {
|
|
39602
40130
|
return candidate;
|
|
39603
40131
|
}
|
|
39604
40132
|
}
|
|
@@ -39614,9 +40142,9 @@ async function skillIsCurrent(src, dest) {
|
|
|
39614
40142
|
const list2 = (dir) => {
|
|
39615
40143
|
const out2 = [];
|
|
39616
40144
|
const walk2 = (d, prefix) => {
|
|
39617
|
-
for (const e of (0,
|
|
40145
|
+
for (const e of (0, import_node_fs69.readdirSync)(d, { withFileTypes: true })) {
|
|
39618
40146
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
39619
|
-
if (e.isDirectory()) walk2((0,
|
|
40147
|
+
if (e.isDirectory()) walk2((0, import_node_path55.join)(d, e.name), rel);
|
|
39620
40148
|
else if (e.isFile()) out2.push(rel);
|
|
39621
40149
|
}
|
|
39622
40150
|
};
|
|
@@ -39627,8 +40155,8 @@ async function skillIsCurrent(src, dest) {
|
|
|
39627
40155
|
const shipped = list2(src);
|
|
39628
40156
|
if (JSON.stringify(shipped) !== JSON.stringify(list2(dest))) return false;
|
|
39629
40157
|
for (const rel of shipped) {
|
|
39630
|
-
const a = await (0, import_promises20.readFile)((0,
|
|
39631
|
-
const b = await (0, import_promises20.readFile)((0,
|
|
40158
|
+
const a = await (0, import_promises20.readFile)((0, import_node_path55.join)(src, rel), "utf-8");
|
|
40159
|
+
const b = await (0, import_promises20.readFile)((0, import_node_path55.join)(dest, rel), "utf-8");
|
|
39632
40160
|
if (a !== b) return false;
|
|
39633
40161
|
}
|
|
39634
40162
|
return true;
|
|
@@ -39724,7 +40252,7 @@ function parseTelemetryAnswer(raw) {
|
|
|
39724
40252
|
return null;
|
|
39725
40253
|
}
|
|
39726
40254
|
function insideClaudeCode() {
|
|
39727
|
-
return !!process.env.CLAUDECODE || !!
|
|
40255
|
+
return !!process.env.CLAUDECODE || !!envSessionId();
|
|
39728
40256
|
}
|
|
39729
40257
|
function resumeDeferredPending(previous) {
|
|
39730
40258
|
return previous?.telemetry === "deferred";
|
|
@@ -39831,13 +40359,13 @@ async function synthesizeLocally(opts) {
|
|
|
39831
40359
|
async function healStaleAnalysisConfig(globals) {
|
|
39832
40360
|
const configPath = projectPath(CODACY_CONFIG_FILE);
|
|
39833
40361
|
const standardPath = projectPath(STANDARD_FILE);
|
|
39834
|
-
if (!(0,
|
|
40362
|
+
if (!(0, import_node_fs69.existsSync)(configPath) || !(0, import_node_fs69.existsSync)(standardPath)) return;
|
|
39835
40363
|
const validation = validatePatternIds();
|
|
39836
40364
|
if (validation.status !== "invalid") return;
|
|
39837
40365
|
printWarn(" Your analysis config names pattern ids that no longer resolve \u2014 those tools were");
|
|
39838
40366
|
printWarn(" running silently with nothing enabled. Re-deriving it from your Standard\u2026");
|
|
39839
40367
|
try {
|
|
39840
|
-
const content = (0,
|
|
40368
|
+
const content = (0, import_yaml7.parse)(await (0, import_promises20.readFile)(standardPath, "utf-8"));
|
|
39841
40369
|
const derived = await deriveConfigForStandard(content);
|
|
39842
40370
|
for (const path of derived.written) printInfo(` ${path} \u2713 (re-derived)`);
|
|
39843
40371
|
for (const note of derived.notes) printWarn(` ${note}`);
|
|
@@ -39928,17 +40456,17 @@ async function handoffToSetup(enabled, claudeInstalled) {
|
|
|
39928
40456
|
async function installSkills(force, step) {
|
|
39929
40457
|
step("Installing skills");
|
|
39930
40458
|
const dataDir = resolveDataDir2();
|
|
39931
|
-
const skillsSource = (0,
|
|
40459
|
+
const skillsSource = (0, import_node_path55.join)(dataDir, "skills");
|
|
39932
40460
|
const skillsDest = ".claude/skills";
|
|
39933
40461
|
let skillsInstalled = 0;
|
|
39934
40462
|
for (const skill of SKILLS) {
|
|
39935
|
-
const src = (0,
|
|
39936
|
-
const dest = (0,
|
|
39937
|
-
if (!(0,
|
|
40463
|
+
const src = (0, import_node_path55.join)(skillsSource, skill);
|
|
40464
|
+
const dest = (0, import_node_path55.join)(skillsDest, skill);
|
|
40465
|
+
if (!(0, import_node_fs69.existsSync)(src)) {
|
|
39938
40466
|
printWarn(` Skill data not found: ${skill}`);
|
|
39939
40467
|
continue;
|
|
39940
40468
|
}
|
|
39941
|
-
if ((0,
|
|
40469
|
+
if ((0, import_node_fs69.existsSync)(dest) && !force && await skillIsCurrent(src, dest)) {
|
|
39942
40470
|
skillsInstalled++;
|
|
39943
40471
|
continue;
|
|
39944
40472
|
}
|
|
@@ -40087,7 +40615,7 @@ async function offerFormalVerification(defaultsOnly, pluginMode) {
|
|
|
40087
40615
|
if (!toolchain) {
|
|
40088
40616
|
const dir = pinnedVersionDir();
|
|
40089
40617
|
const home = (0, import_node_os11.homedir)();
|
|
40090
|
-
const shown = dir.startsWith(home +
|
|
40618
|
+
const shown = dir.startsWith(home + import_node_path55.sep) ? `~${dir.slice(home.length)}` : dir;
|
|
40091
40619
|
console.log("");
|
|
40092
40620
|
console.log(` "yes" installs Lean 4 (${LEAN_DOWNLOAD_SIZE}) into ${shown}`);
|
|
40093
40621
|
}
|
|
@@ -40146,7 +40674,7 @@ function registerInitCommand(program2) {
|
|
|
40146
40674
|
const staleMarker = clearStalePluginMarker();
|
|
40147
40675
|
const pluginMode = opts.plugin === false ? false : opts.pluginMode ?? pluginActiveHere();
|
|
40148
40676
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
40149
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
40677
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs69.existsSync)(m));
|
|
40150
40678
|
if (!isProject) {
|
|
40151
40679
|
printError("No project detected in the current directory.");
|
|
40152
40680
|
printInfo('Run "verity init" from your project root.');
|
|
@@ -40249,7 +40777,7 @@ function registerInitCommand(program2) {
|
|
|
40249
40777
|
untrackMemory: opts.untrackMemory === true,
|
|
40250
40778
|
untrackState: opts.untrackState === true
|
|
40251
40779
|
});
|
|
40252
|
-
const globalVerityDir = (0,
|
|
40780
|
+
const globalVerityDir = (0, import_node_path55.join)(process.env.HOME ?? "", ".verity");
|
|
40253
40781
|
await (0, import_promises20.mkdir)(globalVerityDir, { recursive: true });
|
|
40254
40782
|
console.log("");
|
|
40255
40783
|
step("Wiring Claude Code hooks");
|
|
@@ -40324,7 +40852,7 @@ function registerInitCommand(program2) {
|
|
|
40324
40852
|
}
|
|
40325
40853
|
step("Your project's Standard");
|
|
40326
40854
|
let haveStandard = false;
|
|
40327
|
-
if ((0,
|
|
40855
|
+
if ((0, import_node_fs69.existsSync)(projectPath(STANDARD_FILE))) {
|
|
40328
40856
|
printInfo(" This project already has .verity/standard.yaml \u2014 keeping it.");
|
|
40329
40857
|
haveStandard = true;
|
|
40330
40858
|
} else {
|
|
@@ -40354,7 +40882,7 @@ function registerInitCommand(program2) {
|
|
|
40354
40882
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
40355
40883
|
init: {
|
|
40356
40884
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
40357
|
-
cli_version: true ? "0.34.
|
|
40885
|
+
cli_version: true ? "0.34.2-experimental.2cad220" : "dev"
|
|
40358
40886
|
}
|
|
40359
40887
|
});
|
|
40360
40888
|
} catch (err2) {
|
|
@@ -40404,8 +40932,8 @@ function registerInitCommand(program2) {
|
|
|
40404
40932
|
}
|
|
40405
40933
|
|
|
40406
40934
|
// src/commands/uninstall.ts
|
|
40407
|
-
var
|
|
40408
|
-
var
|
|
40935
|
+
var import_node_fs70 = require("node:fs");
|
|
40936
|
+
var import_node_path56 = require("node:path");
|
|
40409
40937
|
function registerUninstallCommand(program2) {
|
|
40410
40938
|
program2.command("uninstall").description("Remove Verity from this project (skills, hooks, .verity/, VERITY.md)").option("--dry-run", "Show what would be removed without doing it").option("--purge-global", "Also remove ~/.verity/ (deletes saved tokens \u2014 reconnect requires re-registration)").option("--keep-verity-md", "Keep the project root VERITY.md file").action(async (opts) => {
|
|
40411
40939
|
const dryRun = opts.dryRun ?? false;
|
|
@@ -40414,11 +40942,11 @@ function registerUninstallCommand(program2) {
|
|
|
40414
40942
|
const actions = [];
|
|
40415
40943
|
const skillsRoot = projectPath(".claude/skills");
|
|
40416
40944
|
for (const name2 of PROJECT_SKILL_NAMES) {
|
|
40417
|
-
const dir = (0,
|
|
40418
|
-
if ((0,
|
|
40945
|
+
const dir = (0, import_node_path56.join)(skillsRoot, name2);
|
|
40946
|
+
if ((0, import_node_fs70.existsSync)(dir)) {
|
|
40419
40947
|
actions.push({
|
|
40420
40948
|
label: `Remove .claude/skills/${name2}/`,
|
|
40421
|
-
apply: () => (0,
|
|
40949
|
+
apply: () => (0, import_node_fs70.rmSync)(dir, { recursive: true, force: true })
|
|
40422
40950
|
});
|
|
40423
40951
|
}
|
|
40424
40952
|
}
|
|
@@ -40432,24 +40960,24 @@ function registerUninstallCommand(program2) {
|
|
|
40432
40960
|
});
|
|
40433
40961
|
}
|
|
40434
40962
|
const verityDir = projectPath(VERITY_DIR);
|
|
40435
|
-
if ((0,
|
|
40963
|
+
if ((0, import_node_fs70.existsSync)(verityDir)) {
|
|
40436
40964
|
actions.push({
|
|
40437
40965
|
label: `Remove ${VERITY_DIR}/`,
|
|
40438
|
-
apply: () => (0,
|
|
40966
|
+
apply: () => (0, import_node_fs70.rmSync)(verityDir, { recursive: true, force: true })
|
|
40439
40967
|
});
|
|
40440
40968
|
}
|
|
40441
40969
|
if (!keepVerityMd) {
|
|
40442
40970
|
const verityMd = projectPath(VERITY_MD_FILE);
|
|
40443
|
-
if ((0,
|
|
40971
|
+
if ((0, import_node_fs70.existsSync)(verityMd)) {
|
|
40444
40972
|
actions.push({
|
|
40445
40973
|
label: `Remove ${VERITY_MD_FILE}`,
|
|
40446
|
-
apply: () => (0,
|
|
40974
|
+
apply: () => (0, import_node_fs70.rmSync)(verityMd, { force: true })
|
|
40447
40975
|
});
|
|
40448
40976
|
}
|
|
40449
40977
|
}
|
|
40450
40978
|
const cleanupEmptyDir = (path) => {
|
|
40451
|
-
if ((0,
|
|
40452
|
-
(0,
|
|
40979
|
+
if ((0, import_node_fs70.existsSync)(path) && (0, import_node_fs70.statSync)(path).isDirectory() && (0, import_node_fs70.readdirSync)(path).length === 0) {
|
|
40980
|
+
(0, import_node_fs70.rmdirSync)(path);
|
|
40453
40981
|
}
|
|
40454
40982
|
};
|
|
40455
40983
|
actions.push({
|
|
@@ -40460,11 +40988,11 @@ function registerUninstallCommand(program2) {
|
|
|
40460
40988
|
}
|
|
40461
40989
|
});
|
|
40462
40990
|
const home = process.env.HOME ?? "";
|
|
40463
|
-
const globalVerityDir = (0,
|
|
40464
|
-
if (purgeGlobal && (0,
|
|
40991
|
+
const globalVerityDir = (0, import_node_path56.join)(home, ".verity");
|
|
40992
|
+
if (purgeGlobal && (0, import_node_fs70.existsSync)(globalVerityDir)) {
|
|
40465
40993
|
actions.push({
|
|
40466
40994
|
label: `Remove ~/.verity/ (global credentials \u2014 reconnect requires re-registration)`,
|
|
40467
|
-
apply: () => (0,
|
|
40995
|
+
apply: () => (0, import_node_fs70.rmSync)(globalVerityDir, { recursive: true, force: true })
|
|
40468
40996
|
});
|
|
40469
40997
|
}
|
|
40470
40998
|
if (actions.length === 0) {
|
|
@@ -40491,9 +41019,26 @@ function registerUninstallCommand(program2) {
|
|
|
40491
41019
|
|
|
40492
41020
|
// src/commands/task.ts
|
|
40493
41021
|
function memoryPath() {
|
|
40494
|
-
const sid =
|
|
41022
|
+
const sid = envSessionId();
|
|
40495
41023
|
return sid ? `/memory?session_id=${encodeURIComponent(sid)}` : "/memory";
|
|
40496
41024
|
}
|
|
41025
|
+
var TASK_STATUSES = ["active", "closed", "merged"];
|
|
41026
|
+
var TASK_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
41027
|
+
function isTaskId(value) {
|
|
41028
|
+
return typeof value === "string" && TASK_ID.test(value);
|
|
41029
|
+
}
|
|
41030
|
+
function taskListPath(status) {
|
|
41031
|
+
if (status === void 0) return "/tasks";
|
|
41032
|
+
if (!TASK_STATUSES.includes(status)) return null;
|
|
41033
|
+
return `/tasks?status=${encodeURIComponent(status)}`;
|
|
41034
|
+
}
|
|
41035
|
+
function taskActionPath(taskId, action) {
|
|
41036
|
+
return isTaskId(taskId) ? `/tasks/${encodeURIComponent(taskId)}/${action}` : null;
|
|
41037
|
+
}
|
|
41038
|
+
function refuse(message) {
|
|
41039
|
+
printError(message);
|
|
41040
|
+
process.exit(1);
|
|
41041
|
+
}
|
|
40497
41042
|
function timeAgo2(isoDate) {
|
|
40498
41043
|
const ms = Date.now() - new Date(isoDate).getTime();
|
|
40499
41044
|
const mins = Math.floor(ms / 6e4);
|
|
@@ -40521,10 +41066,11 @@ function registerTaskCommands(program2) {
|
|
|
40521
41066
|
task.command("list").description("List tasks").option("--status <status>", "Filter by status (active, closed, merged)").action(async (opts) => {
|
|
40522
41067
|
const globals = program2.opts();
|
|
40523
41068
|
const { token, serviceUrl } = await getAuth(globals);
|
|
40524
|
-
const
|
|
41069
|
+
const listPath = taskListPath(opts.status);
|
|
41070
|
+
if (!listPath) refuse(`Unknown status ${JSON.stringify(String(opts.status).slice(0, 40))} \u2014 use one of: ${TASK_STATUSES.join(", ")}`);
|
|
40525
41071
|
const result = await apiRequest({
|
|
40526
41072
|
method: "GET",
|
|
40527
|
-
path:
|
|
41073
|
+
path: listPath,
|
|
40528
41074
|
serviceUrl,
|
|
40529
41075
|
token,
|
|
40530
41076
|
verbose: globals.verbose,
|
|
@@ -40573,9 +41119,11 @@ function registerTaskCommands(program2) {
|
|
|
40573
41119
|
}
|
|
40574
41120
|
taskId = ct.id;
|
|
40575
41121
|
}
|
|
41122
|
+
const closePath = taskActionPath(taskId, "close");
|
|
41123
|
+
if (!closePath) refuse(`Not a task id (expected a UUID): ${JSON.stringify(String(taskId).slice(0, 80))}`);
|
|
40576
41124
|
const result = await apiRequest({
|
|
40577
41125
|
method: "POST",
|
|
40578
|
-
path:
|
|
41126
|
+
path: closePath,
|
|
40579
41127
|
serviceUrl,
|
|
40580
41128
|
token,
|
|
40581
41129
|
verbose: globals.verbose,
|
|
@@ -40622,9 +41170,11 @@ function registerTaskCommands(program2) {
|
|
|
40622
41170
|
}
|
|
40623
41171
|
taskId = ct.id;
|
|
40624
41172
|
}
|
|
41173
|
+
const renamePath = taskActionPath(taskId, "rename");
|
|
41174
|
+
if (!renamePath) refuse(`Not a task id (expected a UUID): ${JSON.stringify(String(taskId).slice(0, 80))}`);
|
|
40625
41175
|
const result = await apiRequest({
|
|
40626
41176
|
method: "POST",
|
|
40627
|
-
path:
|
|
41177
|
+
path: renamePath,
|
|
40628
41178
|
serviceUrl,
|
|
40629
41179
|
token,
|
|
40630
41180
|
body: { label: label2.slice(0, 120) },
|
|
@@ -40639,6 +41189,9 @@ function registerTaskCommands(program2) {
|
|
|
40639
41189
|
});
|
|
40640
41190
|
task.command("merge <source> <target>").description("Merge source task into target task").action(async (source2, target) => {
|
|
40641
41191
|
const globals = program2.opts();
|
|
41192
|
+
if (!isTaskId(source2) || !isTaskId(target)) {
|
|
41193
|
+
refuse("task merge takes two task ids (UUIDs): `verity task merge <source> <target>`");
|
|
41194
|
+
}
|
|
40642
41195
|
const { token, serviceUrl } = await getAuth(globals);
|
|
40643
41196
|
const result = await apiRequest({
|
|
40644
41197
|
method: "POST",
|
|
@@ -40658,8 +41211,8 @@ function registerTaskCommands(program2) {
|
|
|
40658
41211
|
}
|
|
40659
41212
|
|
|
40660
41213
|
// src/commands/reset.ts
|
|
40661
|
-
var
|
|
40662
|
-
var
|
|
41214
|
+
var import_node_fs71 = require("node:fs");
|
|
41215
|
+
var import_node_path57 = require("node:path");
|
|
40663
41216
|
function registerResetCommand(program2) {
|
|
40664
41217
|
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) => {
|
|
40665
41218
|
const globals = program2.opts();
|
|
@@ -40668,78 +41221,95 @@ function registerResetCommand(program2) {
|
|
|
40668
41221
|
const tokenResult = await resolveToken(globals.token);
|
|
40669
41222
|
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
40670
41223
|
if (tokenResult.ok && urlResult.ok) {
|
|
41224
|
+
const sessionId = envSessionId();
|
|
40671
41225
|
const mem = await apiRequest({
|
|
40672
41226
|
method: "GET",
|
|
40673
|
-
path:
|
|
41227
|
+
path: sessionId ? `/memory?session_id=${encodeURIComponent(sessionId)}` : "/memory",
|
|
40674
41228
|
serviceUrl: urlResult.data,
|
|
40675
41229
|
token: tokenResult.data.token,
|
|
40676
41230
|
timeout: 1e4,
|
|
40677
41231
|
cmd: "reset_lookup"
|
|
40678
41232
|
});
|
|
40679
41233
|
const ct = mem.ok ? mem.data.current_task : null;
|
|
40680
|
-
|
|
41234
|
+
const closePath = ct?.id ? taskActionPath(ct.id, "close") : null;
|
|
41235
|
+
if (ct?.id && !closePath) {
|
|
41236
|
+
printError("The current task in the service response has a malformed id \u2014 not closing it.");
|
|
41237
|
+
}
|
|
41238
|
+
if (closePath) {
|
|
40681
41239
|
const closeResult = await apiRequest({
|
|
40682
41240
|
method: "POST",
|
|
40683
|
-
path:
|
|
41241
|
+
path: closePath,
|
|
40684
41242
|
serviceUrl: urlResult.data,
|
|
40685
41243
|
token: tokenResult.data.token,
|
|
40686
41244
|
timeout: 1e4,
|
|
40687
41245
|
cmd: "reset_close"
|
|
40688
41246
|
});
|
|
40689
41247
|
if (closeResult.ok) {
|
|
40690
|
-
printInfo(`Closed task: "${ct
|
|
41248
|
+
printInfo(`Closed task: "${terminalText(ct?.label, 200) || "(unnamed)"}"`);
|
|
40691
41249
|
}
|
|
40692
41250
|
}
|
|
40693
41251
|
}
|
|
40694
41252
|
} catch {
|
|
40695
41253
|
}
|
|
40696
41254
|
}
|
|
40697
|
-
const
|
|
40698
|
-
|
|
40699
|
-
|
|
40700
|
-
for (const entry of (0, import_node_fs69.readdirSync)(cacheDir)) {
|
|
40701
|
-
if (entry.startsWith("pending-")) {
|
|
40702
|
-
try {
|
|
40703
|
-
(0, import_node_fs69.unlinkSync)((0, import_node_path54.join)(cacheDir, entry));
|
|
40704
|
-
purged++;
|
|
40705
|
-
} catch {
|
|
40706
|
-
}
|
|
40707
|
-
}
|
|
40708
|
-
}
|
|
40709
|
-
}
|
|
41255
|
+
const purged = purgeVerityDir((0, import_node_path57.basename)(CACHE_DIR), (name2) => name2.startsWith("pending-"));
|
|
41256
|
+
if (purged === null) printError(`Did not purge ${CACHE_DIR}: it is not a directory inside ${VERITY_DIR}.`);
|
|
41257
|
+
const stateDir2 = projectPath(VERITY_DIR);
|
|
40710
41258
|
const filesToClear = [
|
|
40711
|
-
|
|
40712
|
-
|
|
40713
|
-
|
|
40714
|
-
|
|
40715
|
-
|
|
41259
|
+
(0, import_node_path57.basename)(INTENT_FILE),
|
|
41260
|
+
(0, import_node_path57.basename)(HASH_FILE),
|
|
41261
|
+
(0, import_node_path57.basename)(BASELINE_SHA_FILE),
|
|
41262
|
+
".iteration-count",
|
|
41263
|
+
".last-analysis"
|
|
40716
41264
|
];
|
|
40717
|
-
for (const
|
|
40718
|
-
if ((0,
|
|
40719
|
-
|
|
40720
|
-
(0, import_node_fs69.writeFileSync)(file, "");
|
|
40721
|
-
} catch {
|
|
40722
|
-
}
|
|
41265
|
+
for (const name2 of filesToClear) {
|
|
41266
|
+
if (lstatOrNull((0, import_node_path57.join)(stateDir2, name2)) && !replaceInRoot(stateDir2, name2, "")) {
|
|
41267
|
+
printError(`Did not clear ${VERITY_DIR}/${name2}: it is not a regular file inside ${VERITY_DIR}.`);
|
|
40723
41268
|
}
|
|
40724
41269
|
}
|
|
40725
41270
|
if (opts.all) {
|
|
40726
|
-
const
|
|
40727
|
-
if (
|
|
40728
|
-
|
|
40729
|
-
try {
|
|
40730
|
-
(0, import_node_fs69.unlinkSync)((0, import_node_path54.join)(logsDir, entry));
|
|
40731
|
-
} catch {
|
|
40732
|
-
}
|
|
40733
|
-
}
|
|
40734
|
-
}
|
|
40735
|
-
printInfo("Cleared diagnostic logs.");
|
|
41271
|
+
const logs = purgeVerityDir(".logs", () => true);
|
|
41272
|
+
if (logs === null) printError(`Did not clear ${VERITY_DIR}/.logs: it is not a directory inside ${VERITY_DIR}.`);
|
|
41273
|
+
else printInfo("Cleared diagnostic logs.");
|
|
40736
41274
|
}
|
|
40737
|
-
|
|
41275
|
+
const count = purged ?? 0;
|
|
41276
|
+
printInfo(`Reset complete. Purged ${count} cached request${count !== 1 ? "s" : ""}.${opts.keepTask ? "" : " Next run starts a new task."}`);
|
|
40738
41277
|
});
|
|
40739
41278
|
}
|
|
41279
|
+
function lstatOrNull(path) {
|
|
41280
|
+
try {
|
|
41281
|
+
return (0, import_node_fs71.lstatSync)(path);
|
|
41282
|
+
} catch {
|
|
41283
|
+
return null;
|
|
41284
|
+
}
|
|
41285
|
+
}
|
|
41286
|
+
function purgeVerityDir(child, select) {
|
|
41287
|
+
const verityDir = projectPath(VERITY_DIR);
|
|
41288
|
+
const dir = (0, import_node_path57.join)(verityDir, child);
|
|
41289
|
+
const parent = lstatOrNull(verityDir);
|
|
41290
|
+
const st = lstatOrNull(dir);
|
|
41291
|
+
if (!st) return 0;
|
|
41292
|
+
if (!parent || parent.isSymbolicLink() || !parent.isDirectory()) return null;
|
|
41293
|
+
if (st.isSymbolicLink() || !st.isDirectory()) return null;
|
|
41294
|
+
try {
|
|
41295
|
+
if ((0, import_node_fs71.realpathSync)(dir) !== (0, import_node_path57.join)((0, import_node_fs71.realpathSync)(verityDir), child)) return null;
|
|
41296
|
+
} catch {
|
|
41297
|
+
return null;
|
|
41298
|
+
}
|
|
41299
|
+
let removed = 0;
|
|
41300
|
+
for (const entry of (0, import_node_fs71.readdirSync)(dir, { withFileTypes: true })) {
|
|
41301
|
+
if (entry.isDirectory() || !select(entry.name)) continue;
|
|
41302
|
+
try {
|
|
41303
|
+
(0, import_node_fs71.unlinkSync)((0, import_node_path57.join)(dir, entry.name));
|
|
41304
|
+
removed++;
|
|
41305
|
+
} catch {
|
|
41306
|
+
}
|
|
41307
|
+
}
|
|
41308
|
+
return removed;
|
|
41309
|
+
}
|
|
40740
41310
|
|
|
40741
41311
|
// src/commands/reflect.ts
|
|
40742
|
-
var
|
|
41312
|
+
var import_node_fs72 = require("node:fs");
|
|
40743
41313
|
|
|
40744
41314
|
// src/lib/reflection-globs.ts
|
|
40745
41315
|
var MAX_GLOBS = 6;
|
|
@@ -40753,11 +41323,11 @@ function resolve7(token, treePaths) {
|
|
|
40753
41323
|
const matches = treePaths.filter((p) => p.endsWith(suffix));
|
|
40754
41324
|
return matches.length === 1 ? matches[0] : null;
|
|
40755
41325
|
}
|
|
40756
|
-
function deriveFileGlobs(
|
|
40757
|
-
if (!
|
|
41326
|
+
function deriveFileGlobs(text2, treePaths) {
|
|
41327
|
+
if (!text2 || treePaths.length === 0) return [];
|
|
40758
41328
|
const out2 = [];
|
|
40759
41329
|
const seen = /* @__PURE__ */ new Set();
|
|
40760
|
-
for (const raw of
|
|
41330
|
+
for (const raw of text2.match(PATH_TOKEN) ?? []) {
|
|
40761
41331
|
const token = clean(raw);
|
|
40762
41332
|
if (!token) continue;
|
|
40763
41333
|
const path = resolve7(token, treePaths);
|
|
@@ -40777,7 +41347,7 @@ async function writeNodeToDisk(args2) {
|
|
|
40777
41347
|
{ treePaths: listTrackedFiles(), recordBaseline: false }
|
|
40778
41348
|
);
|
|
40779
41349
|
if (written === 0) return false;
|
|
40780
|
-
return (0,
|
|
41350
|
+
return (0, import_node_fs72.existsSync)(projectPath(`${VERITY_DIR}/memory/${args2.filePath}`));
|
|
40781
41351
|
} catch {
|
|
40782
41352
|
return false;
|
|
40783
41353
|
}
|
|
@@ -40808,7 +41378,7 @@ function registerReflectCommand(program2) {
|
|
|
40808
41378
|
let taskResolution = "flag";
|
|
40809
41379
|
let inheritedGlobs = [];
|
|
40810
41380
|
if (!taskId) {
|
|
40811
|
-
const sessionId =
|
|
41381
|
+
const sessionId = envSessionId() ?? "";
|
|
40812
41382
|
const memPath = sessionId ? `/memory?session_id=${encodeURIComponent(sessionId)}` : "/memory";
|
|
40813
41383
|
const mem = await apiRequest({
|
|
40814
41384
|
method: "GET",
|
|
@@ -40853,7 +41423,7 @@ function registerReflectCommand(program2) {
|
|
|
40853
41423
|
const userInput = input.text;
|
|
40854
41424
|
if (userInput) {
|
|
40855
41425
|
const validKinds = ["decision", "gotcha", "pattern", "security", "quality", "intent", "domain", "integration"];
|
|
40856
|
-
const
|
|
41426
|
+
const kind2 = validKinds.includes(opts.kind) ? opts.kind : "gotcha";
|
|
40857
41427
|
const confirmed = opts.confirmed === true;
|
|
40858
41428
|
const source2 = confirmed ? "user" : "agent";
|
|
40859
41429
|
const explicitGlobs = Array.isArray(opts.fileGlobs) ? opts.fileGlobs.map((g) => g.trim()).filter(Boolean) : [];
|
|
@@ -40865,7 +41435,7 @@ function registerReflectCommand(program2) {
|
|
|
40865
41435
|
serviceUrl,
|
|
40866
41436
|
token,
|
|
40867
41437
|
body: {
|
|
40868
|
-
kind,
|
|
41438
|
+
kind: kind2,
|
|
40869
41439
|
title: userInput.slice(0, 200),
|
|
40870
41440
|
body: userInput,
|
|
40871
41441
|
domains: [],
|
|
@@ -41214,9 +41784,9 @@ function registerRunCommand(program2) {
|
|
|
41214
41784
|
}
|
|
41215
41785
|
|
|
41216
41786
|
// src/commands/telemetry.ts
|
|
41217
|
-
var
|
|
41787
|
+
var import_node_fs73 = require("node:fs");
|
|
41218
41788
|
async function recordTelemetryChoice(choice) {
|
|
41219
|
-
if (!(0,
|
|
41789
|
+
if (!(0, import_node_fs73.existsSync)(projectPath(SETUP_STATE_FILE))) return;
|
|
41220
41790
|
try {
|
|
41221
41791
|
if ((await readSetupState())?.telemetry === choice) return;
|
|
41222
41792
|
await writeSetupState({ telemetry: choice });
|
|
@@ -41293,8 +41863,8 @@ function registerTelemetryCommands(program2) {
|
|
|
41293
41863
|
}
|
|
41294
41864
|
|
|
41295
41865
|
// src/commands/prove.ts
|
|
41296
|
-
var
|
|
41297
|
-
var
|
|
41866
|
+
var import_node_fs74 = require("node:fs");
|
|
41867
|
+
var import_node_path58 = require("node:path");
|
|
41298
41868
|
|
|
41299
41869
|
// src/lib/prove/hint-pool.ts
|
|
41300
41870
|
var STOP2 = /* @__PURE__ */ new Set([
|
|
@@ -41436,7 +42006,7 @@ function registerProveCommand(program2) {
|
|
|
41436
42006
|
process.exit(2);
|
|
41437
42007
|
}
|
|
41438
42008
|
const limit = Math.max(1, Math.min(50, Number(opts.limit) || 10));
|
|
41439
|
-
let signals = collectRiskSignals(root, { since: opts.since, limit, paths: paths.map((p) => (0,
|
|
42009
|
+
let signals = collectRiskSignals(root, { since: opts.since, limit, paths: paths.map((p) => (0, import_node_path58.relative)(root, (0, import_node_path58.resolve)(p)) || ".") });
|
|
41440
42010
|
if (opts.hint && paths.length === 0) {
|
|
41441
42011
|
const hit = hintMatches(root, opts.hint);
|
|
41442
42012
|
if (hit.files.length > 0) {
|
|
@@ -41490,7 +42060,7 @@ function registerProveCommand(program2) {
|
|
|
41490
42060
|
});
|
|
41491
42061
|
prove.command("check [model]").description("Elaborate a model (or every model) with the local Lean toolchain and report each property").option("--timeout <ms>", "Per-model timeout in ms", "120000").option("--json", "Machine-readable output").action((model, opts) => {
|
|
41492
42062
|
const root = repoRoot();
|
|
41493
|
-
if (!(0,
|
|
42063
|
+
if (!(0, import_node_fs74.existsSync)((0, import_node_path58.join)(root, PROOFS_DIR, "lakefile.toml"))) {
|
|
41494
42064
|
printError(`No ${PROOFS_DIR}/ project here. Run \`verity prove init\` first.`);
|
|
41495
42065
|
process.exit(2);
|
|
41496
42066
|
}
|
|
@@ -41514,7 +42084,7 @@ ${build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).slice(0, 20).j
|
|
|
41514
42084
|
const reports = [];
|
|
41515
42085
|
for (const f of files) {
|
|
41516
42086
|
const report = checkModel(tc, root, f, { timeoutMs: Math.max(1e3, Number(opts.timeout) || 12e4) });
|
|
41517
|
-
report.file = (0,
|
|
42087
|
+
report.file = (0, import_node_path58.relative)(root, f);
|
|
41518
42088
|
reports.push(report);
|
|
41519
42089
|
try {
|
|
41520
42090
|
writeResult(root, report);
|
|
@@ -41552,7 +42122,7 @@ ${build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).slice(0, 20).j
|
|
|
41552
42122
|
printError("Not logged in \u2014 replays run on the Verity service. Run `verity login` first.");
|
|
41553
42123
|
process.exit(2);
|
|
41554
42124
|
}
|
|
41555
|
-
if (!(0,
|
|
42125
|
+
if (!(0, import_node_fs74.existsSync)((0, import_node_path58.join)(root, PROOFS_DIR, "lakefile.toml"))) {
|
|
41556
42126
|
printError(`No ${PROOFS_DIR}/ project here. Run \`verity prove init\` first.`);
|
|
41557
42127
|
process.exit(2);
|
|
41558
42128
|
}
|
|
@@ -41583,7 +42153,7 @@ ${report.error ?? ""}`);
|
|
|
41583
42153
|
printInfo(opts.property ? `${model} ${opts.property} has no counterexample to replay` : `${model} has no counterexample to replay`);
|
|
41584
42154
|
return;
|
|
41585
42155
|
}
|
|
41586
|
-
const modelSource = readRegularFileInRoot(root, (0,
|
|
42156
|
+
const modelSource = readRegularFileInRoot(root, (0, import_node_path58.relative)(root, file), 512 * 1024);
|
|
41587
42157
|
if (!opts.json) printInfo(`replaying ${targets.length} counterexample(s) of ${model} in network-less containers (${Math.min(targets.length, REPLAY_CONCURRENCY)} at a time)\u2026`);
|
|
41588
42158
|
const outcomes = await mapPool(targets, REPLAY_CONCURRENCY, async (p) => {
|
|
41589
42159
|
const brief = buildReplayBrief(root, report, p, modelSource.ok ? modelSource.content : "");
|
|
@@ -41603,7 +42173,7 @@ ${report.error ?? ""}`);
|
|
|
41603
42173
|
});
|
|
41604
42174
|
prove.command("auto [files...]").description("The formal phase the pre-push guard runs: select one risky symbol among changed files, generate a model, check it, replay counterexamples (default files: the commits ahead of upstream)").option("--deadline <ms>", "Budget for the whole phase", "170000").option("--json", "Machine-readable output").action(async (paths, opts) => {
|
|
41605
42175
|
const root = repoRoot();
|
|
41606
|
-
let files = paths.map((p) => (0,
|
|
42176
|
+
let files = paths.map((p) => (0, import_node_path58.relative)(root, (0, import_node_path58.resolve)(p)));
|
|
41607
42177
|
if (files.length === 0) {
|
|
41608
42178
|
const ahead = runGitSync(root, ["diff", "--name-only", "@{upstream}...HEAD"]);
|
|
41609
42179
|
const fallback = ahead.ok ? ahead : runGitSync(root, ["diff", "--name-only", "HEAD~1..HEAD"]);
|
|
@@ -41613,8 +42183,10 @@ ${report.error ?? ""}`);
|
|
|
41613
42183
|
printInfo("No changed files to consider (nothing ahead of upstream). Pass paths explicitly.");
|
|
41614
42184
|
return;
|
|
41615
42185
|
}
|
|
41616
|
-
const
|
|
42186
|
+
const auth2 = await proveAuth(program2);
|
|
42187
|
+
const prep = await prepareFormalPhase(root, process.env, auth2 ?? void 0);
|
|
41617
42188
|
const outcome = prep.ok ? await runFormalPhaseWithin({ root, files, deadlineAt: Date.now() + Math.max(3e4, Number(opts.deadline) || 17e4), deps: prep.deps }).catch((err2) => skippedOutcome("error", String(err2?.message ?? err2).slice(0, 200))) : skippedOutcome(prep.skip, prep.detail);
|
|
42189
|
+
if (auth2) await postPhaseRecord(outcome, { moment: "on-demand", parentRunId: null, pushedFiles: [] }, auth2);
|
|
41618
42190
|
if (opts.json) {
|
|
41619
42191
|
printJson(outcome);
|
|
41620
42192
|
} else {
|
|
@@ -41675,7 +42247,7 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
41675
42247
|
let revise;
|
|
41676
42248
|
if (opts.revise) {
|
|
41677
42249
|
const existing = resolveModelFile(root, opts.revise);
|
|
41678
|
-
const src = existing ? readRegularFileInRoot(root, (0,
|
|
42250
|
+
const src = existing ? readRegularFileInRoot(root, (0, import_node_path58.relative)(root, existing), 64 * 1024) : null;
|
|
41679
42251
|
if (!src || !src.ok || !opts.note) {
|
|
41680
42252
|
printError("--revise needs an existing model under Models/ and --note - with what the replay showed on stdin");
|
|
41681
42253
|
process.exit(2);
|
|
@@ -41688,21 +42260,22 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
41688
42260
|
printError("Verity library did not build");
|
|
41689
42261
|
process.exit(2);
|
|
41690
42262
|
}
|
|
41691
|
-
const deps =
|
|
42263
|
+
const deps = await onDemandDeps(root, { auth: auth2 ?? void 0, apiKey: process.env.VERITY_PROVE_DIRECT === "1" ? process.env.OPENAI_API_KEY : void 0, toolchain: tc });
|
|
41692
42264
|
if (!opts.json) printInfo(`asking the Verity service for a model of ${symbol || `${file}:${opts.lines}`} \u2026`);
|
|
41693
42265
|
const out2 = await generateAndCheck(root, { file, symbol: symbol || `${file}:${opts.lines}`, lines, hint: opts.hint, revise }, { deps, maxRounds: 3 });
|
|
41694
42266
|
if (!out2.ok) {
|
|
41695
42267
|
if (opts.json) printJson(out2);
|
|
41696
|
-
else printError(`${out2.error} (${out2.rounds} round(s)${out2.costUsd ? `, $${out2.costUsd.toFixed(2)}` : ""}) \u2014 write the model by hand (Models/README.md) or narrow the target`);
|
|
42268
|
+
else printError(out2.rounds === 0 ? out2.error : `${out2.error} (${out2.rounds} round(s)${out2.costUsd ? `, $${out2.costUsd.toFixed(2)}` : ""}) \u2014 write the model by hand (Models/README.md) or narrow the target`);
|
|
41697
42269
|
process.exit(2);
|
|
41698
42270
|
}
|
|
42271
|
+
if (out2.warning && !opts.json) printWarn(out2.warning);
|
|
41699
42272
|
try {
|
|
41700
42273
|
writeResult(root, out2.report);
|
|
41701
42274
|
} catch (err2) {
|
|
41702
42275
|
if (!(err2 instanceof SafeWriteError)) throw err2;
|
|
41703
42276
|
}
|
|
41704
42277
|
if (opts.json) {
|
|
41705
|
-
printJson({ name: out2.name, file: out2.file, rounds: out2.rounds, cost_usd: out2.costUsd, report: { ...out2.report, passes: reportPasses(out2.report), summary: summarize(out2.report) } });
|
|
42278
|
+
printJson({ name: out2.name, file: out2.file, rounds: out2.rounds, cost_usd: out2.costUsd, ...out2.warning ? { warning: out2.warning } : {}, report: { ...out2.report, passes: reportPasses(out2.report), summary: summarize(out2.report) } });
|
|
41706
42279
|
return;
|
|
41707
42280
|
}
|
|
41708
42281
|
printInfo(`wrote ${out2.file} (${out2.rounds} round(s)${out2.costUsd ? `, $${out2.costUsd.toFixed(2)}` : ""})`);
|
|
@@ -41714,8 +42287,8 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
41714
42287
|
});
|
|
41715
42288
|
prove.command("waive <file>").description("Dismiss the remembered formal finding(s) on a file for its current bytes \u2014 the accepted-risk path for a formal block").requiredOption("--reason <text>", "The human disposition this records (reviewer finding, ADR, \u2026)").action((file, opts) => {
|
|
41716
42289
|
const root = repoRoot();
|
|
41717
|
-
const rel0 = (0,
|
|
41718
|
-
const rel = rel0.startsWith("..") || (0,
|
|
42290
|
+
const rel0 = (0, import_node_path58.relative)(root, (0, import_node_path58.isAbsolute)(file) ? file : (0, import_node_path58.join)(root, file)).replace(/\\/g, "/");
|
|
42291
|
+
const rel = rel0.startsWith("..") || (0, import_node_path58.isAbsolute)(rel0) ? null : rel0;
|
|
41719
42292
|
if (!rel) {
|
|
41720
42293
|
printError(`${file} is not inside this repository`);
|
|
41721
42294
|
process.exit(2);
|
|
@@ -41731,8 +42304,8 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
41731
42304
|
});
|
|
41732
42305
|
prove.command("hash <file>").description("Print the sha256 of a file, for a model header (Verity.model \u2026 sha256). Path is REPO-relative, as in the header").action((file) => {
|
|
41733
42306
|
const root = repoRoot();
|
|
41734
|
-
const rel = (0,
|
|
41735
|
-
const digest = rel.startsWith("..") || (0,
|
|
42307
|
+
const rel = (0, import_node_path58.relative)(root, (0, import_node_path58.isAbsolute)(file) ? file : (0, import_node_path58.join)(root, file));
|
|
42308
|
+
const digest = rel.startsWith("..") || (0, import_node_path58.isAbsolute)(rel) ? null : sha256InRoot(root, rel);
|
|
41736
42309
|
if (!digest) {
|
|
41737
42310
|
printError(`Cannot hash ${file}: it must be a regular file inside this repository (not a symlink)`);
|
|
41738
42311
|
process.exit(2);
|
|
@@ -41766,10 +42339,10 @@ function refreshScaffold(root) {
|
|
|
41766
42339
|
}
|
|
41767
42340
|
|
|
41768
42341
|
// src/commands/lean.ts
|
|
41769
|
-
var
|
|
42342
|
+
var import_node_fs75 = require("node:fs");
|
|
41770
42343
|
var import_node_child_process20 = require("node:child_process");
|
|
41771
42344
|
var import_node_os12 = require("node:os");
|
|
41772
|
-
var
|
|
42345
|
+
var import_node_path59 = require("node:path");
|
|
41773
42346
|
function registerLeanCommand(program2) {
|
|
41774
42347
|
const lean = program2.command("lean").description("The Lean 4 toolchain formal verification needs (managed download, pinned by this CLI)");
|
|
41775
42348
|
lean.command("status").option("--json", "Machine-readable output").description("Which toolchain would run, and whether it matches the pinned version").action((opts) => {
|
|
@@ -41786,7 +42359,7 @@ function registerLeanCommand(program2) {
|
|
|
41786
42359
|
const managed = pinnedVersionDir();
|
|
41787
42360
|
const matches = version ? version.includes(pin) : false;
|
|
41788
42361
|
if (opts.json) {
|
|
41789
|
-
printJson({ pinned: LEAN_TOOLCHAIN, found: tc?.lake ?? null, version, matches_pin: matches, managed_dir: managed, managed_installed: (0,
|
|
42362
|
+
printJson({ pinned: LEAN_TOOLCHAIN, found: tc?.lake ?? null, version, matches_pin: matches, managed_dir: managed, managed_installed: (0, import_node_fs75.existsSync)((0, import_node_path59.join)(managed, "bin")), asset: leanAssetName() });
|
|
41790
42363
|
return;
|
|
41791
42364
|
}
|
|
41792
42365
|
printInfo(`pinned: ${LEAN_TOOLCHAIN}`);
|
|
@@ -41804,7 +42377,7 @@ function registerLeanCommand(program2) {
|
|
|
41804
42377
|
process.exit(2);
|
|
41805
42378
|
}
|
|
41806
42379
|
const dir = pinnedVersionDir();
|
|
41807
|
-
if ((0,
|
|
42380
|
+
if ((0, import_node_fs75.existsSync)((0, import_node_path59.join)(dir, "bin", "lake")) && !opts.force) {
|
|
41808
42381
|
printInfo(`already installed at ${dir}`);
|
|
41809
42382
|
return;
|
|
41810
42383
|
}
|
|
@@ -41840,18 +42413,18 @@ function registerLeanCommand(program2) {
|
|
|
41840
42413
|
});
|
|
41841
42414
|
lean.command("remove").description("Delete the Verity-managed toolchain for the pinned version").action(() => {
|
|
41842
42415
|
const dir = pinnedVersionDir();
|
|
41843
|
-
if (!(0,
|
|
42416
|
+
if (!(0, import_node_fs75.existsSync)(dir)) {
|
|
41844
42417
|
printInfo("nothing to remove");
|
|
41845
42418
|
return;
|
|
41846
42419
|
}
|
|
41847
|
-
(0,
|
|
42420
|
+
(0, import_node_fs75.rmSync)(dir, { recursive: true, force: true });
|
|
41848
42421
|
printInfo(`removed ${dir}`);
|
|
41849
42422
|
});
|
|
41850
42423
|
}
|
|
41851
42424
|
|
|
41852
42425
|
// src/cli.ts
|
|
41853
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.34.
|
|
41854
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.
|
|
42426
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.34.2-experimental.2cad220").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) => {
|
|
42427
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.2-experimental.2cad220");
|
|
41855
42428
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
41856
42429
|
try {
|
|
41857
42430
|
await foldLegacyLocalCredential();
|