@codacy/verity-cli 0.34.2 → 0.34.4
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 +42 -0
- package/bin/verity.js +1001 -620
- 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}
|
|
@@ -3919,8 +3919,8 @@ var require_Collection = __commonJS2({
|
|
|
3919
3919
|
return this.items.every((node) => {
|
|
3920
3920
|
if (!identity.isPair(node))
|
|
3921
3921
|
return false;
|
|
3922
|
-
const
|
|
3923
|
-
return
|
|
3922
|
+
const n2 = node.value;
|
|
3923
|
+
return n2 == null || allowScalar && identity.isScalar(n2) && n2.value == null && !n2.commentBefore && !n2.comment && !n2.tag;
|
|
3924
3924
|
});
|
|
3925
3925
|
}
|
|
3926
3926
|
/**
|
|
@@ -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;
|
|
@@ -5360,18 +5360,18 @@ var require_stringifyNumber = __commonJS2({
|
|
|
5360
5360
|
const num = typeof value === "number" ? value : Number(value);
|
|
5361
5361
|
if (!isFinite(num))
|
|
5362
5362
|
return isNaN(num) ? ".nan" : num < 0 ? "-.inf" : ".inf";
|
|
5363
|
-
let
|
|
5364
|
-
if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^\d/.test(
|
|
5365
|
-
let i2 =
|
|
5363
|
+
let n2 = Object.is(value, -0) ? "-0" : JSON.stringify(value);
|
|
5364
|
+
if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^\d/.test(n2)) {
|
|
5365
|
+
let i2 = n2.indexOf(".");
|
|
5366
5366
|
if (i2 < 0) {
|
|
5367
|
-
i2 =
|
|
5368
|
-
|
|
5367
|
+
i2 = n2.length;
|
|
5368
|
+
n2 += ".";
|
|
5369
5369
|
}
|
|
5370
|
-
let d = minFractionDigits - (
|
|
5370
|
+
let d = minFractionDigits - (n2.length - i2 - 1);
|
|
5371
5371
|
while (d-- > 0)
|
|
5372
|
-
|
|
5372
|
+
n2 += "0";
|
|
5373
5373
|
}
|
|
5374
|
-
return
|
|
5374
|
+
return n2;
|
|
5375
5375
|
}
|
|
5376
5376
|
exports2.stringifyNumber = stringifyNumber;
|
|
5377
5377
|
}
|
|
@@ -5615,9 +5615,9 @@ var require_binary = __commonJS2({
|
|
|
5615
5615
|
type ?? (type = Scalar.Scalar.BLOCK_LITERAL);
|
|
5616
5616
|
if (type !== Scalar.Scalar.QUOTE_DOUBLE) {
|
|
5617
5617
|
const lineWidth = Math.max(ctx.options.lineWidth - ctx.indent.length, ctx.options.minContentWidth);
|
|
5618
|
-
const
|
|
5619
|
-
const lines = new Array(
|
|
5620
|
-
for (let i2 = 0, o = 0; i2 <
|
|
5618
|
+
const n2 = Math.ceil(str3.length / lineWidth);
|
|
5619
|
+
const lines = new Array(n2);
|
|
5620
|
+
for (let i2 = 0, o = 0; i2 < n2; ++i2, o += lineWidth) {
|
|
5621
5621
|
lines[i2] = str3.substr(o, lineWidth);
|
|
5622
5622
|
}
|
|
5623
5623
|
str3 = lines.join(type === Scalar.Scalar.BLOCK_LITERAL ? "\n" : " ");
|
|
@@ -5889,11 +5889,11 @@ var require_int2 = __commonJS2({
|
|
|
5889
5889
|
str3 = `0x${str3}`;
|
|
5890
5890
|
break;
|
|
5891
5891
|
}
|
|
5892
|
-
const
|
|
5893
|
-
return sign === "-" ? BigInt(-1) *
|
|
5892
|
+
const n3 = BigInt(str3);
|
|
5893
|
+
return sign === "-" ? BigInt(-1) * n3 : n3;
|
|
5894
5894
|
}
|
|
5895
|
-
const
|
|
5896
|
-
return sign === "-" ? -1 *
|
|
5895
|
+
const n2 = parseInt(str3, radix);
|
|
5896
|
+
return sign === "-" ? -1 * n2 : n2;
|
|
5897
5897
|
}
|
|
5898
5898
|
function intStringify(node, radix, prefix) {
|
|
5899
5899
|
const { value } = node;
|
|
@@ -6042,15 +6042,15 @@ var require_timestamp = __commonJS2({
|
|
|
6042
6042
|
function parseSexagesimal(str3, asBigInt) {
|
|
6043
6043
|
const sign = str3[0];
|
|
6044
6044
|
const parts2 = sign === "-" || sign === "+" ? str3.substring(1) : str3;
|
|
6045
|
-
const num = (
|
|
6045
|
+
const num = (n2) => asBigInt ? BigInt(n2) : Number(n2);
|
|
6046
6046
|
const res = parts2.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num(60) + num(p), num(0));
|
|
6047
6047
|
return sign === "-" ? num(-1) * res : res;
|
|
6048
6048
|
}
|
|
6049
6049
|
function stringifySexagesimal(node) {
|
|
6050
6050
|
let { value } = node;
|
|
6051
|
-
let num = (
|
|
6051
|
+
let num = (n2) => n2;
|
|
6052
6052
|
if (typeof value === "bigint")
|
|
6053
|
-
num = (
|
|
6053
|
+
num = (n2) => BigInt(n2);
|
|
6054
6054
|
else if (isNaN(value) || !isFinite(value))
|
|
6055
6055
|
return stringifyNumber.stringifyNumber(node);
|
|
6056
6056
|
let sign = "";
|
|
@@ -6070,7 +6070,7 @@ var require_timestamp = __commonJS2({
|
|
|
6070
6070
|
parts2.unshift(value);
|
|
6071
6071
|
}
|
|
6072
6072
|
}
|
|
6073
|
-
return sign + parts2.map((
|
|
6073
|
+
return sign + parts2.map((n2) => String(n2).padStart(2, "0")).join(":").replace(/000000\d*$/, "");
|
|
6074
6074
|
}
|
|
6075
6075
|
var intTime = {
|
|
6076
6076
|
identify: (value) => typeof value === "bigint" || Number.isInteger(value),
|
|
@@ -7541,9 +7541,9 @@ var require_resolve_block_scalar = __commonJS2({
|
|
|
7541
7541
|
if (!chomp && (ch === "-" || ch === "+"))
|
|
7542
7542
|
chomp = ch;
|
|
7543
7543
|
else {
|
|
7544
|
-
const
|
|
7545
|
-
if (!indent &&
|
|
7546
|
-
indent =
|
|
7544
|
+
const n2 = Number(ch);
|
|
7545
|
+
if (!indent && n2)
|
|
7546
|
+
indent = n2;
|
|
7547
7547
|
else if (error === -1)
|
|
7548
7548
|
error = offset + i2;
|
|
7549
7549
|
}
|
|
@@ -8760,8 +8760,8 @@ var require_lexer = __commonJS2({
|
|
|
8760
8760
|
return this.buffer[i2 + 1] === "\n";
|
|
8761
8761
|
return false;
|
|
8762
8762
|
}
|
|
8763
|
-
charAt(
|
|
8764
|
-
return this.buffer[this.pos +
|
|
8763
|
+
charAt(n2) {
|
|
8764
|
+
return this.buffer[this.pos + n2];
|
|
8765
8765
|
}
|
|
8766
8766
|
continueScalar(offset) {
|
|
8767
8767
|
let ch = this.buffer[offset];
|
|
@@ -8795,8 +8795,8 @@ var require_lexer = __commonJS2({
|
|
|
8795
8795
|
end -= 1;
|
|
8796
8796
|
return this.buffer.substring(this.pos, end);
|
|
8797
8797
|
}
|
|
8798
|
-
hasChars(
|
|
8799
|
-
return this.pos +
|
|
8798
|
+
hasChars(n2) {
|
|
8799
|
+
return this.pos + n2 <= this.buffer.length;
|
|
8800
8800
|
}
|
|
8801
8801
|
setNext(state) {
|
|
8802
8802
|
this.buffer = this.buffer.substring(this.pos);
|
|
@@ -8805,8 +8805,8 @@ var require_lexer = __commonJS2({
|
|
|
8805
8805
|
this.next = state;
|
|
8806
8806
|
return null;
|
|
8807
8807
|
}
|
|
8808
|
-
peek(
|
|
8809
|
-
return this.buffer.substr(this.pos,
|
|
8808
|
+
peek(n2) {
|
|
8809
|
+
return this.buffer.substr(this.pos, n2);
|
|
8810
8810
|
}
|
|
8811
8811
|
*parseNext(next) {
|
|
8812
8812
|
switch (next) {
|
|
@@ -8855,8 +8855,8 @@ var require_lexer = __commonJS2({
|
|
|
8855
8855
|
else
|
|
8856
8856
|
break;
|
|
8857
8857
|
}
|
|
8858
|
-
const
|
|
8859
|
-
yield* this.pushCount(line2.length -
|
|
8858
|
+
const n2 = (yield* this.pushCount(dirEnd)) + (yield* this.pushSpaces(true));
|
|
8859
|
+
yield* this.pushCount(line2.length - n2);
|
|
8860
8860
|
this.pushNewline();
|
|
8861
8861
|
return "stream";
|
|
8862
8862
|
}
|
|
@@ -8894,9 +8894,9 @@ var require_lexer = __commonJS2({
|
|
|
8894
8894
|
if (!ch1 && !this.atEnd)
|
|
8895
8895
|
return this.setNext("block-start");
|
|
8896
8896
|
if ((ch0 === "-" || ch0 === "?" || ch0 === ":") && isEmpty(ch1)) {
|
|
8897
|
-
const
|
|
8897
|
+
const n2 = (yield* this.pushCount(1)) + (yield* this.pushSpaces(true));
|
|
8898
8898
|
this.indentNext = this.indentValue + 1;
|
|
8899
|
-
this.indentValue +=
|
|
8899
|
+
this.indentValue += n2;
|
|
8900
8900
|
return yield* this.parseBlockStart();
|
|
8901
8901
|
}
|
|
8902
8902
|
return "doc";
|
|
@@ -8906,10 +8906,10 @@ var require_lexer = __commonJS2({
|
|
|
8906
8906
|
const line2 = this.getLine();
|
|
8907
8907
|
if (line2 === null)
|
|
8908
8908
|
return this.setNext("doc");
|
|
8909
|
-
let
|
|
8910
|
-
switch (line2[
|
|
8909
|
+
let n2 = yield* this.pushIndicators();
|
|
8910
|
+
switch (line2[n2]) {
|
|
8911
8911
|
case "#":
|
|
8912
|
-
yield* this.pushCount(line2.length -
|
|
8912
|
+
yield* this.pushCount(line2.length - n2);
|
|
8913
8913
|
// fallthrough
|
|
8914
8914
|
case void 0:
|
|
8915
8915
|
yield* this.pushNewline();
|
|
@@ -8932,9 +8932,9 @@ var require_lexer = __commonJS2({
|
|
|
8932
8932
|
return yield* this.parseQuotedScalar();
|
|
8933
8933
|
case "|":
|
|
8934
8934
|
case ">":
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
yield* this.pushCount(line2.length -
|
|
8935
|
+
n2 += yield* this.parseBlockScalarHeader();
|
|
8936
|
+
n2 += yield* this.pushSpaces(true);
|
|
8937
|
+
yield* this.pushCount(line2.length - n2);
|
|
8938
8938
|
yield* this.pushNewline();
|
|
8939
8939
|
return yield* this.parseBlockScalar();
|
|
8940
8940
|
default:
|
|
@@ -8965,18 +8965,18 @@ var require_lexer = __commonJS2({
|
|
|
8965
8965
|
return yield* this.parseLineStart();
|
|
8966
8966
|
}
|
|
8967
8967
|
}
|
|
8968
|
-
let
|
|
8969
|
-
while (line2[
|
|
8970
|
-
|
|
8971
|
-
|
|
8968
|
+
let n2 = 0;
|
|
8969
|
+
while (line2[n2] === ",") {
|
|
8970
|
+
n2 += yield* this.pushCount(1);
|
|
8971
|
+
n2 += yield* this.pushSpaces(true);
|
|
8972
8972
|
this.flowKey = false;
|
|
8973
8973
|
}
|
|
8974
|
-
|
|
8975
|
-
switch (line2[
|
|
8974
|
+
n2 += yield* this.pushIndicators();
|
|
8975
|
+
switch (line2[n2]) {
|
|
8976
8976
|
case void 0:
|
|
8977
8977
|
return "flow";
|
|
8978
8978
|
case "#":
|
|
8979
|
-
yield* this.pushCount(line2.length -
|
|
8979
|
+
yield* this.pushCount(line2.length - n2);
|
|
8980
8980
|
return "flow";
|
|
8981
8981
|
case "{":
|
|
8982
8982
|
case "[":
|
|
@@ -9020,10 +9020,10 @@ var require_lexer = __commonJS2({
|
|
|
9020
9020
|
end = this.buffer.indexOf("'", end + 2);
|
|
9021
9021
|
} else {
|
|
9022
9022
|
while (end !== -1) {
|
|
9023
|
-
let
|
|
9024
|
-
while (this.buffer[end - 1 -
|
|
9025
|
-
|
|
9026
|
-
if (
|
|
9023
|
+
let n2 = 0;
|
|
9024
|
+
while (this.buffer[end - 1 - n2] === "\\")
|
|
9025
|
+
n2 += 1;
|
|
9026
|
+
if (n2 % 2 === 0)
|
|
9027
9027
|
break;
|
|
9028
9028
|
end = this.buffer.indexOf('"', end + 1);
|
|
9029
9029
|
}
|
|
@@ -9177,11 +9177,11 @@ var require_lexer = __commonJS2({
|
|
|
9177
9177
|
yield* this.pushToIndex(end + 1, true);
|
|
9178
9178
|
return inFlow ? "flow" : "doc";
|
|
9179
9179
|
}
|
|
9180
|
-
*pushCount(
|
|
9181
|
-
if (
|
|
9182
|
-
yield this.buffer.substr(this.pos,
|
|
9183
|
-
this.pos +=
|
|
9184
|
-
return
|
|
9180
|
+
*pushCount(n2) {
|
|
9181
|
+
if (n2 > 0) {
|
|
9182
|
+
yield this.buffer.substr(this.pos, n2);
|
|
9183
|
+
this.pos += n2;
|
|
9184
|
+
return n2;
|
|
9185
9185
|
}
|
|
9186
9186
|
return 0;
|
|
9187
9187
|
}
|
|
@@ -9255,12 +9255,12 @@ var require_lexer = __commonJS2({
|
|
|
9255
9255
|
do {
|
|
9256
9256
|
ch = this.buffer[++i2];
|
|
9257
9257
|
} while (ch === " " || allowTabs && ch === " ");
|
|
9258
|
-
const
|
|
9259
|
-
if (
|
|
9260
|
-
yield this.buffer.substr(this.pos,
|
|
9258
|
+
const n2 = i2 - this.pos;
|
|
9259
|
+
if (n2 > 0) {
|
|
9260
|
+
yield this.buffer.substr(this.pos, n2);
|
|
9261
9261
|
this.pos = i2;
|
|
9262
9262
|
}
|
|
9263
|
-
return
|
|
9263
|
+
return n2;
|
|
9264
9264
|
}
|
|
9265
9265
|
*pushUntil(test) {
|
|
9266
9266
|
let i2 = this.pos;
|
|
@@ -9528,8 +9528,8 @@ var require_parser = __commonJS2({
|
|
|
9528
9528
|
}
|
|
9529
9529
|
yield* this.pop();
|
|
9530
9530
|
}
|
|
9531
|
-
peek(
|
|
9532
|
-
return this.stack[this.stack.length -
|
|
9531
|
+
peek(n2) {
|
|
9532
|
+
return this.stack[this.stack.length - n2];
|
|
9533
9533
|
}
|
|
9534
9534
|
*pop(error) {
|
|
9535
9535
|
const token = error ?? this.stack.pop();
|
|
@@ -10895,8 +10895,8 @@ var require_web_tree_sitter2 = __commonJS2({
|
|
|
10895
10895
|
}, "getMemory");
|
|
10896
10896
|
var isInternalSym = /* @__PURE__ */ __name((symName) => ["__cpp_exception", "__c_longjmp", "__wasm_apply_data_relocs", "__dso_handle", "__tls_size", "__tls_align", "__set_stack_limits", "_emscripten_tls_init", "__wasm_init_tls", "__wasm_call_ctors", "__start_em_asm", "__stop_em_asm", "__start_em_js", "__stop_em_js"].includes(symName) || symName.startsWith("__em_js__"), "isInternalSym");
|
|
10897
10897
|
var uleb128EncodeWithLen = /* @__PURE__ */ __name((arr) => {
|
|
10898
|
-
const
|
|
10899
|
-
return [
|
|
10898
|
+
const n2 = arr.length;
|
|
10899
|
+
return [n2 % 128 | 128, n2 >> 7, ...arr];
|
|
10900
10900
|
}, "uleb128EncodeWithLen");
|
|
10901
10901
|
var wasmTypeCodes = {
|
|
10902
10902
|
"i": 127,
|
|
@@ -13001,13 +13001,13 @@ var require_web_tree_sitter2 = __commonJS2({
|
|
|
13001
13001
|
symbols.push(65535);
|
|
13002
13002
|
}
|
|
13003
13003
|
}
|
|
13004
|
-
for (let i2 = 0,
|
|
13004
|
+
for (let i2 = 0, n2 = typesBySymbol.length; i2 < n2; i2++) {
|
|
13005
13005
|
if (types.includes(typesBySymbol[i2])) {
|
|
13006
13006
|
symbols.push(i2);
|
|
13007
13007
|
}
|
|
13008
13008
|
}
|
|
13009
13009
|
const symbolsAddress = C._malloc(SIZE_OF_INT * symbols.length);
|
|
13010
|
-
for (let i2 = 0,
|
|
13010
|
+
for (let i2 = 0, n2 = symbols.length; i2 < n2; i2++) {
|
|
13011
13011
|
C.setValue(symbolsAddress + i2 * SIZE_OF_INT, symbols[i2], "i32");
|
|
13012
13012
|
}
|
|
13013
13013
|
marshalNode(this);
|
|
@@ -13196,7 +13196,7 @@ var require_web_tree_sitter2 = __commonJS2({
|
|
|
13196
13196
|
}
|
|
13197
13197
|
};
|
|
13198
13198
|
function unmarshalCaptures(query, tree, address, patternIndex, result) {
|
|
13199
|
-
for (let i2 = 0,
|
|
13199
|
+
for (let i2 = 0, n2 = result.length; i2 < n2; i2++) {
|
|
13200
13200
|
const captureIndex = C.getValue(address, "i32");
|
|
13201
13201
|
address += SIZE_OF_INT;
|
|
13202
13202
|
const node = unmarshalNode(tree, address);
|
|
@@ -13335,13 +13335,13 @@ var require_web_tree_sitter2 = __commonJS2({
|
|
|
13335
13335
|
assertInternal(internal);
|
|
13336
13336
|
this[0] = address;
|
|
13337
13337
|
this.types = new Array(C._ts_language_symbol_count(this[0]));
|
|
13338
|
-
for (let i2 = 0,
|
|
13338
|
+
for (let i2 = 0, n2 = this.types.length; i2 < n2; i2++) {
|
|
13339
13339
|
if (C._ts_language_symbol_type(this[0], i2) < 2) {
|
|
13340
13340
|
this.types[i2] = C.UTF8ToString(C._ts_language_symbol_name(this[0], i2));
|
|
13341
13341
|
}
|
|
13342
13342
|
}
|
|
13343
13343
|
this.fields = new Array(C._ts_language_field_count(this[0]) + 1);
|
|
13344
|
-
for (let i2 = 0,
|
|
13344
|
+
for (let i2 = 0, n2 = this.fields.length; i2 < n2; i2++) {
|
|
13345
13345
|
const fieldName = C._ts_language_field_name_for_id(this[0], i2);
|
|
13346
13346
|
if (fieldName !== 0) {
|
|
13347
13347
|
this.fields[i2] = C.UTF8ToString(fieldName);
|
|
@@ -13844,8 +13844,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
13844
13844
|
} else {
|
|
13845
13845
|
const captureName = steps[1].name;
|
|
13846
13846
|
const stringValue = steps[2].value;
|
|
13847
|
-
const matches = /* @__PURE__ */ __name((
|
|
13848
|
-
const doesNotMatch = /* @__PURE__ */ __name((
|
|
13847
|
+
const matches = /* @__PURE__ */ __name((n2) => n2.text === stringValue, "matches");
|
|
13848
|
+
const doesNotMatch = /* @__PURE__ */ __name((n2) => n2.text !== stringValue, "doesNotMatch");
|
|
13849
13849
|
textPredicates[index].push((captures) => {
|
|
13850
13850
|
const nodes = [];
|
|
13851
13851
|
for (const c of captures) {
|
|
@@ -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");
|
|
@@ -15210,8 +15210,8 @@ function commitsSincePaths(sha, paths) {
|
|
|
15210
15210
|
encoding: "utf-8",
|
|
15211
15211
|
stdio: ["pipe", "pipe", "pipe"]
|
|
15212
15212
|
}).trim();
|
|
15213
|
-
const
|
|
15214
|
-
return Number.isFinite(
|
|
15213
|
+
const n2 = Number.parseInt(out2, 10);
|
|
15214
|
+
return Number.isFinite(n2) ? n2 : null;
|
|
15215
15215
|
} catch {
|
|
15216
15216
|
return null;
|
|
15217
15217
|
}
|
|
@@ -15579,15 +15579,15 @@ function reverifyNudge(who) {
|
|
|
15579
15579
|
}
|
|
15580
15580
|
return null;
|
|
15581
15581
|
}
|
|
15582
|
-
function isLegacyPerRepoCredential(
|
|
15583
|
-
return
|
|
15582
|
+
function isLegacyPerRepoCredential(auth3) {
|
|
15583
|
+
return auth3.source === "local" || auth3.source === "global" && auth3.keyed === true;
|
|
15584
15584
|
}
|
|
15585
|
-
async function shouldUpgradeOnLogin(
|
|
15586
|
-
if (!isLegacyPerRepoCredential(
|
|
15587
|
-
if (
|
|
15585
|
+
async function shouldUpgradeOnLogin(auth3) {
|
|
15586
|
+
if (!isLegacyPerRepoCredential(auth3)) return false;
|
|
15587
|
+
if (auth3.userId == null) return true;
|
|
15588
15588
|
const bare = await readGlobalCredential("");
|
|
15589
15589
|
if (bare?.userId == null) return true;
|
|
15590
|
-
return bare.userId ===
|
|
15590
|
+
return bare.userId === auth3.userId;
|
|
15591
15591
|
}
|
|
15592
15592
|
function authDenialRemedy(error) {
|
|
15593
15593
|
if (error.startsWith("STALE_VERIFICATION")) {
|
|
@@ -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
|
});
|
|
@@ -16073,8 +16073,8 @@ async function loginOnce(opts) {
|
|
|
16073
16073
|
|
|
16074
16074
|
// src/commands/auth.ts
|
|
16075
16075
|
function registerAuthCommands(program2) {
|
|
16076
|
-
const
|
|
16077
|
-
|
|
16076
|
+
const auth3 = program2.command("auth").description("Manage project authentication");
|
|
16077
|
+
auth3.command("register").description("Register a project with Verity").requiredOption("--project <name>", "Project name").option("--remote <url>", "Git remote URL (auto-detected if omitted)").action(async (opts) => {
|
|
16078
16078
|
const globals = program2.opts();
|
|
16079
16079
|
const serviceUrl = globals.serviceUrl ?? DEFAULT_SERVICE_URL;
|
|
16080
16080
|
let remote = opts.remote;
|
|
@@ -16101,7 +16101,7 @@ function registerAuthCommands(program2) {
|
|
|
16101
16101
|
if (email) printInfo(`Authenticated as: ${email}`);
|
|
16102
16102
|
printJson({ project_id: projectId, service_url: resolvedUrl });
|
|
16103
16103
|
});
|
|
16104
|
-
|
|
16104
|
+
auth3.command("verify").description("Verify the current token is valid").action(async () => {
|
|
16105
16105
|
const globals = program2.opts();
|
|
16106
16106
|
const tokenResult = await resolveToken(globals.token);
|
|
16107
16107
|
if (!tokenResult.ok) {
|
|
@@ -16127,7 +16127,7 @@ function registerAuthCommands(program2) {
|
|
|
16127
16127
|
printInfo(`Token valid. Project: ${result.data.project_name}`);
|
|
16128
16128
|
printJson(result.data);
|
|
16129
16129
|
});
|
|
16130
|
-
|
|
16130
|
+
auth3.command("discover").description("Check if a project is registered").option("--remote <url>", "Git remote URL (auto-detected if omitted)").action(async (opts) => {
|
|
16131
16131
|
const globals = program2.opts();
|
|
16132
16132
|
let remote = opts.remote;
|
|
16133
16133
|
if (!remote) {
|
|
@@ -16718,8 +16718,8 @@ function registerLogoutCommand(program2) {
|
|
|
16718
16718
|
explain(result.error);
|
|
16719
16719
|
process.exit(1);
|
|
16720
16720
|
}
|
|
16721
|
-
const
|
|
16722
|
-
printInfo(`Revoked ${
|
|
16721
|
+
const n2 = result.data.revoked;
|
|
16722
|
+
printInfo(`Revoked ${n2} login${n2 === 1 ? "" : "s"}. \u2713`);
|
|
16723
16723
|
if (opts.others) {
|
|
16724
16724
|
printInfo(" This machine is still signed in.");
|
|
16725
16725
|
return;
|
|
@@ -17444,13 +17444,13 @@ function scrub(s) {
|
|
|
17444
17444
|
var installed = false;
|
|
17445
17445
|
var wroteBanner = false;
|
|
17446
17446
|
var banner = "";
|
|
17447
|
-
function append(
|
|
17447
|
+
function append(text2) {
|
|
17448
17448
|
try {
|
|
17449
17449
|
const dir = projectPath(DEBUG_LOG_DIR);
|
|
17450
17450
|
const file = projectPath(STDERR_LOG_FILE);
|
|
17451
17451
|
(0, import_node_fs9.mkdirSync)(dir, { recursive: true });
|
|
17452
17452
|
rotateIfNeeded(file);
|
|
17453
|
-
(0, import_node_fs9.appendFileSync)(file,
|
|
17453
|
+
(0, import_node_fs9.appendFileSync)(file, text2);
|
|
17454
17454
|
} catch {
|
|
17455
17455
|
}
|
|
17456
17456
|
}
|
|
@@ -17472,19 +17472,19 @@ function installStderrLog(cmd, argv, version) {
|
|
|
17472
17472
|
const result = original(...args2);
|
|
17473
17473
|
try {
|
|
17474
17474
|
const chunk = args2[0];
|
|
17475
|
-
const
|
|
17475
|
+
const text2 = typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf-8") : String(chunk);
|
|
17476
17476
|
ensureBanner();
|
|
17477
|
-
append(scrub(
|
|
17477
|
+
append(scrub(text2));
|
|
17478
17478
|
} catch {
|
|
17479
17479
|
}
|
|
17480
17480
|
return result;
|
|
17481
17481
|
};
|
|
17482
17482
|
process.stderr.write = tee;
|
|
17483
17483
|
}
|
|
17484
|
-
function logToFileOnly(
|
|
17484
|
+
function logToFileOnly(text2) {
|
|
17485
17485
|
if (!installed) return;
|
|
17486
17486
|
ensureBanner();
|
|
17487
|
-
append(
|
|
17487
|
+
append(text2.endsWith("\n") ? text2 : `${text2}
|
|
17488
17488
|
`);
|
|
17489
17489
|
}
|
|
17490
17490
|
|
|
@@ -18055,8 +18055,8 @@ var import_promises5 = require("node:fs/promises");
|
|
|
18055
18055
|
var import_node_fs12 = require("node:fs");
|
|
18056
18056
|
var import_node_child_process6 = require("node:child_process");
|
|
18057
18057
|
var import_node_crypto2 = require("node:crypto");
|
|
18058
|
-
function stripImageReferences(
|
|
18059
|
-
return
|
|
18058
|
+
function stripImageReferences(text2) {
|
|
18059
|
+
return text2.replace(/\[Image #\d+\]/g, "[screenshot \u2014 not available for review]");
|
|
18060
18060
|
}
|
|
18061
18061
|
function bufferTmpPath() {
|
|
18062
18062
|
return `${CONVERSATION_BUFFER_FILE}.${process.pid}.${(0, import_node_crypto2.randomBytes)(4).toString("hex")}.tmp`;
|
|
@@ -18631,12 +18631,12 @@ function renderIndex(orgName, nodes) {
|
|
|
18631
18631
|
""
|
|
18632
18632
|
];
|
|
18633
18633
|
const byKind = /* @__PURE__ */ new Map();
|
|
18634
|
-
for (const
|
|
18634
|
+
for (const n2 of nodes) byKind.set(n2.kind, [...byKind.get(n2.kind) ?? [], n2]);
|
|
18635
18635
|
for (const kind2 of ORG_KINDS) {
|
|
18636
18636
|
const list2 = byKind.get(kind2);
|
|
18637
18637
|
if (!list2?.length) continue;
|
|
18638
18638
|
lines.push(`## ${kind2}/ (${list2.length})`);
|
|
18639
|
-
for (const
|
|
18639
|
+
for (const n2 of list2) lines.push(`- [[${orgNodePath(n2).split("/")[1].replace(/\.md$/, "")}]] \u2014 ${n2.title} \xB7 ${n2.origin}`);
|
|
18640
18640
|
lines.push("");
|
|
18641
18641
|
}
|
|
18642
18642
|
if (nodes.length === 0) lines.push("No org knowledge yet.", "");
|
|
@@ -18661,26 +18661,26 @@ async function pullOrgKnowledge(opts) {
|
|
|
18661
18661
|
const page = res.data;
|
|
18662
18662
|
if (page.unchanged) return { ok: true, status: "unchanged", received: 0, dir };
|
|
18663
18663
|
const org = page.organization;
|
|
18664
|
-
const nodes = org ? (page.nodes ?? []).flatMap((
|
|
18665
|
-
tag_id:
|
|
18666
|
-
node_id: typeof
|
|
18667
|
-
kind: typeof
|
|
18668
|
-
title:
|
|
18669
|
-
body:
|
|
18670
|
-
origin: typeof
|
|
18671
|
-
signal: typeof
|
|
18672
|
-
tier: typeof
|
|
18673
|
-
applies_to: Array.isArray(
|
|
18674
|
-
source_repo_count: typeof
|
|
18675
|
-
promoted_at: typeof
|
|
18664
|
+
const nodes = org ? (page.nodes ?? []).flatMap((n2) => typeof n2.tag_id === "string" && typeof n2.title === "string" && typeof n2.body === "string" ? [{
|
|
18665
|
+
tag_id: n2.tag_id,
|
|
18666
|
+
node_id: typeof n2.node_id === "string" ? n2.node_id : "",
|
|
18667
|
+
kind: typeof n2.kind === "string" ? n2.kind : "domain",
|
|
18668
|
+
title: n2.title,
|
|
18669
|
+
body: n2.body.slice(0, BODY_MAX),
|
|
18670
|
+
origin: typeof n2.origin === "string" ? n2.origin : "",
|
|
18671
|
+
signal: typeof n2.signal === "string" ? n2.signal : "",
|
|
18672
|
+
tier: typeof n2.tier === "number" ? n2.tier : null,
|
|
18673
|
+
applies_to: Array.isArray(n2.applies_to) ? n2.applies_to.filter((v) => typeof v === "string") : [],
|
|
18674
|
+
source_repo_count: typeof n2.source_repo_count === "number" ? n2.source_repo_count : 1,
|
|
18675
|
+
promoted_at: typeof n2.promoted_at === "string" ? n2.promoted_at : ""
|
|
18676
18676
|
}] : []) : [];
|
|
18677
18677
|
const written = /* @__PURE__ */ new Set();
|
|
18678
18678
|
await (0, import_promises7.mkdir)(dir, { recursive: true });
|
|
18679
|
-
for (const
|
|
18680
|
-
const rel = orgNodePath(
|
|
18679
|
+
for (const n2 of nodes) {
|
|
18680
|
+
const rel = orgNodePath(n2);
|
|
18681
18681
|
if (written.has(rel)) continue;
|
|
18682
18682
|
await (0, import_promises7.mkdir)((0, import_node_path14.join)(dir, rel.split("/")[0]), { recursive: true });
|
|
18683
|
-
await (0, import_promises7.writeFile)((0, import_node_path14.join)(dir, rel), renderOrgNode(
|
|
18683
|
+
await (0, import_promises7.writeFile)((0, import_node_path14.join)(dir, rel), renderOrgNode(n2, org?.name ?? ""));
|
|
18684
18684
|
written.add(rel);
|
|
18685
18685
|
}
|
|
18686
18686
|
for (const rel of state.files) {
|
|
@@ -18779,9 +18779,9 @@ function readOpened(fd, size) {
|
|
|
18779
18779
|
const buffer = Buffer.alloc(size);
|
|
18780
18780
|
let offset = 0;
|
|
18781
18781
|
while (offset < size) {
|
|
18782
|
-
const
|
|
18783
|
-
if (
|
|
18784
|
-
offset +=
|
|
18782
|
+
const n2 = (0, import_node_fs15.readSync)(fd, buffer, offset, size - offset, offset);
|
|
18783
|
+
if (n2 === 0) break;
|
|
18784
|
+
offset += n2;
|
|
18785
18785
|
}
|
|
18786
18786
|
return buffer.subarray(0, offset);
|
|
18787
18787
|
} finally {
|
|
@@ -18922,9 +18922,9 @@ var STOPWORDS = /* @__PURE__ */ new Set([
|
|
|
18922
18922
|
"within",
|
|
18923
18923
|
"without"
|
|
18924
18924
|
]);
|
|
18925
|
-
function tokenize(
|
|
18925
|
+
function tokenize(text2) {
|
|
18926
18926
|
return new Set(
|
|
18927
|
-
|
|
18927
|
+
text2.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w))
|
|
18928
18928
|
);
|
|
18929
18929
|
}
|
|
18930
18930
|
function jaccardKeywords(a, b) {
|
|
@@ -18976,18 +18976,18 @@ function posteriorFor(kind2, own, pooled) {
|
|
|
18976
18976
|
return { alpha: p.alpha + Math.max(0, own.alpha), beta: p.beta + Math.max(0, own.beta) };
|
|
18977
18977
|
}
|
|
18978
18978
|
function posteriorMean(p) {
|
|
18979
|
-
const
|
|
18980
|
-
return
|
|
18979
|
+
const n2 = p.alpha + p.beta;
|
|
18980
|
+
return n2 <= 0 ? DEFAULT_PRIOR_MEAN : p.alpha / n2;
|
|
18981
18981
|
}
|
|
18982
18982
|
function scoreCandidates(nodes, ctx, opts = {}) {
|
|
18983
18983
|
const floor = opts.relevanceFloor ?? RELEVANCE_FLOOR;
|
|
18984
18984
|
const out2 = [];
|
|
18985
|
-
for (const
|
|
18986
|
-
const rel = relevance(
|
|
18985
|
+
for (const n2 of nodes) {
|
|
18986
|
+
const rel = relevance(n2, ctx);
|
|
18987
18987
|
if (rel.score < floor) continue;
|
|
18988
|
-
const post = posteriorFor(
|
|
18988
|
+
const post = posteriorFor(n2.kind, opts.posteriors?.get(n2.id), opts.kindPosteriors?.get(n2.kind));
|
|
18989
18989
|
const usefulness = posteriorMean(post);
|
|
18990
|
-
out2.push({ id:
|
|
18990
|
+
out2.push({ id: n2.id, score: rel.score * usefulness, relevance: rel.score, usefulness, via: rel.via });
|
|
18991
18991
|
}
|
|
18992
18992
|
out2.sort((a, b) => b.score - a.score || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
18993
18993
|
return out2;
|
|
@@ -19001,29 +19001,29 @@ var MAX_BUDGET_TOKENS = 4e3;
|
|
|
19001
19001
|
var MAX_NODE_FILE_BYTES = 64 * 1024;
|
|
19002
19002
|
var MIN_SCORE = RELEVANCE_FLOOR * 0.5;
|
|
19003
19003
|
var ORG_MIN_SHARED_TERMS = 2;
|
|
19004
|
-
function orgTerms(
|
|
19004
|
+
function orgTerms(text2) {
|
|
19005
19005
|
return new Set(
|
|
19006
|
-
|
|
19006
|
+
text2.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2)
|
|
19007
19007
|
);
|
|
19008
19008
|
}
|
|
19009
19009
|
function sharedTerms(a, b) {
|
|
19010
|
-
let
|
|
19011
|
-
for (const w of a) if (b.has(w))
|
|
19012
|
-
return
|
|
19010
|
+
let n2 = 0;
|
|
19011
|
+
for (const w of a) if (b.has(w)) n2++;
|
|
19012
|
+
return n2;
|
|
19013
19013
|
}
|
|
19014
|
-
function orgNodeToLocal(
|
|
19014
|
+
function orgNodeToLocal(n2) {
|
|
19015
19015
|
return {
|
|
19016
|
-
path: `org:${
|
|
19017
|
-
nodeId:
|
|
19018
|
-
kind:
|
|
19019
|
-
title:
|
|
19020
|
-
body:
|
|
19016
|
+
path: `org:${n2.tag_id}`,
|
|
19017
|
+
nodeId: n2.tag_id,
|
|
19018
|
+
kind: n2.kind,
|
|
19019
|
+
title: n2.title,
|
|
19020
|
+
body: n2.body.slice(0, 2e3),
|
|
19021
19021
|
fileGlobs: [],
|
|
19022
19022
|
confidence: 0.5,
|
|
19023
19023
|
citedCount: 0,
|
|
19024
|
-
tokenEstimate: Math.ceil((
|
|
19024
|
+
tokenEstimate: Math.ceil((n2.title.length + n2.body.length) / 4) + 20,
|
|
19025
19025
|
scope: "org",
|
|
19026
|
-
origin:
|
|
19026
|
+
origin: n2.origin
|
|
19027
19027
|
};
|
|
19028
19028
|
}
|
|
19029
19029
|
function globMatch(glob, filePath) {
|
|
@@ -19136,11 +19136,11 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
19136
19136
|
} catch {
|
|
19137
19137
|
}
|
|
19138
19138
|
if (nodes.length === 0) return null;
|
|
19139
|
-
const scored = nodes.map((
|
|
19140
|
-
...
|
|
19141
|
-
score: scoreNode(
|
|
19139
|
+
const scored = nodes.map((n2) => ({
|
|
19140
|
+
...n2,
|
|
19141
|
+
score: scoreNode(n2, promptTokens, taskFiles)
|
|
19142
19142
|
}));
|
|
19143
|
-
const filtered = scored.filter((
|
|
19143
|
+
const filtered = scored.filter((n2) => n2.score >= MIN_SCORE);
|
|
19144
19144
|
filtered.sort((a, b) => b.score - a.score);
|
|
19145
19145
|
const selected = [];
|
|
19146
19146
|
let tokensUsed = 0;
|
|
@@ -19153,7 +19153,7 @@ async function retrieveForInjection(promptText, taskFiles = [], budgetTokens = D
|
|
|
19153
19153
|
const lines = [
|
|
19154
19154
|
"## Project Knowledge (auto-injected)",
|
|
19155
19155
|
"",
|
|
19156
|
-
`*${selected.length} node(s) relevant to your current task. See \`.verity/memory/index.md\` for the full knowledge base${selected.some((
|
|
19156
|
+
`*${selected.length} node(s) relevant to your current task. See \`.verity/memory/index.md\` for the full knowledge base${selected.some((n2) => n2.scope === "org") ? ", and `~/.verity/orgs/` for what the organization's other repositories learned" : ""}.*`,
|
|
19157
19157
|
""
|
|
19158
19158
|
];
|
|
19159
19159
|
for (const node of selected) {
|
|
@@ -19286,15 +19286,15 @@ function runHook(hooks) {
|
|
|
19286
19286
|
return false;
|
|
19287
19287
|
}
|
|
19288
19288
|
}
|
|
19289
|
-
function appendInRoot(root, name2,
|
|
19289
|
+
function appendInRoot(root, name2, text2, hooks = {}) {
|
|
19290
19290
|
return writeVerified(root, name2, hooks, true, (fd) => {
|
|
19291
|
-
(0, import_node_fs17.writeSync)(fd,
|
|
19291
|
+
(0, import_node_fs17.writeSync)(fd, text2);
|
|
19292
19292
|
});
|
|
19293
19293
|
}
|
|
19294
|
-
function replaceInRoot(root, name2,
|
|
19294
|
+
function replaceInRoot(root, name2, text2, hooks = {}) {
|
|
19295
19295
|
return writeVerified(root, name2, hooks, false, (fd) => {
|
|
19296
19296
|
(0, import_node_fs17.ftruncateSync)(fd, 0);
|
|
19297
|
-
(0, import_node_fs17.writeSync)(fd,
|
|
19297
|
+
(0, import_node_fs17.writeSync)(fd, text2, 0);
|
|
19298
19298
|
});
|
|
19299
19299
|
}
|
|
19300
19300
|
|
|
@@ -19317,9 +19317,9 @@ function parseInjectionEvent(raw) {
|
|
|
19317
19317
|
if (!nonNegInt(o.eligible, 1e5) || !nonNegInt(o.tokens, 1e6)) return null;
|
|
19318
19318
|
if (!Array.isArray(o.nodes) || o.nodes.length > MAX_NODES) return null;
|
|
19319
19319
|
const nodes = [];
|
|
19320
|
-
for (const
|
|
19321
|
-
if (!
|
|
19322
|
-
const r =
|
|
19320
|
+
for (const n2 of o.nodes) {
|
|
19321
|
+
if (!n2 || typeof n2 !== "object") return null;
|
|
19322
|
+
const r = n2;
|
|
19323
19323
|
if (typeof r.id !== "string" || !SAFE_ID.test(r.id)) return null;
|
|
19324
19324
|
if (typeof r.score !== "number" || !Number.isFinite(r.score) || r.score < 0 || r.score > 10) return null;
|
|
19325
19325
|
if (typeof r.via !== "string" || !VIA.test(r.via)) return null;
|
|
@@ -19484,12 +19484,12 @@ function ensureVerityGitignore() {
|
|
|
19484
19484
|
if (hasSupersededMemory && !memoryIsCommitted) {
|
|
19485
19485
|
next = fenceMemoryLines(next);
|
|
19486
19486
|
}
|
|
19487
|
-
let
|
|
19487
|
+
let text2 = next.join("\n");
|
|
19488
19488
|
if (!hasMarker) {
|
|
19489
|
-
const sep7 =
|
|
19490
|
-
|
|
19489
|
+
const sep7 = text2 === "" ? "" : text2.endsWith("\n") ? "\n" : "\n\n";
|
|
19490
|
+
text2 = text2 + sep7 + VERITY_GITIGNORE_BLOCK;
|
|
19491
19491
|
}
|
|
19492
|
-
if (
|
|
19492
|
+
if (text2 !== content) (0, import_node_fs19.writeFileSync)(".gitignore", text2);
|
|
19493
19493
|
return verified(
|
|
19494
19494
|
memoryIsCommitted ? "memory-tracked" : hasSupersededMemory ? "memory-fenced" : needsRepair ? "repaired" : "added"
|
|
19495
19495
|
);
|
|
@@ -19515,13 +19515,13 @@ function writeFencedBlock() {
|
|
|
19515
19515
|
const hasMarker = content.includes(VERITY_GITIGNORE_MARKER);
|
|
19516
19516
|
let lines = content.split("\n").map((l) => BREAKING_ENTRIES.has(l.trim()) ? ".verity/*" : l);
|
|
19517
19517
|
lines = fenceMemoryLines(lines);
|
|
19518
|
-
let
|
|
19518
|
+
let text2 = lines.join("\n");
|
|
19519
19519
|
if (!hasMarker) {
|
|
19520
|
-
const sep7 =
|
|
19521
|
-
|
|
19520
|
+
const sep7 = text2 === "" ? "" : text2.endsWith("\n") ? "\n" : "\n\n";
|
|
19521
|
+
text2 = text2 + sep7 + VERITY_GITIGNORE_BLOCK;
|
|
19522
19522
|
}
|
|
19523
19523
|
try {
|
|
19524
|
-
(0, import_node_fs19.writeFileSync)(".gitignore",
|
|
19524
|
+
(0, import_node_fs19.writeFileSync)(".gitignore", text2);
|
|
19525
19525
|
return true;
|
|
19526
19526
|
} catch {
|
|
19527
19527
|
return false;
|
|
@@ -19671,9 +19671,9 @@ function readFileInside(baseDir, candidate, maxBytes) {
|
|
|
19671
19671
|
// src/lib/glob-match.ts
|
|
19672
19672
|
function globToRegex(glob) {
|
|
19673
19673
|
let out2 = "";
|
|
19674
|
-
const
|
|
19674
|
+
const n2 = glob.length;
|
|
19675
19675
|
let i2 = 0;
|
|
19676
|
-
while (i2 <
|
|
19676
|
+
while (i2 < n2) {
|
|
19677
19677
|
const c = glob[i2];
|
|
19678
19678
|
if (c === "*" && glob[i2 + 1] === "*") {
|
|
19679
19679
|
if (i2 > 0 && glob[i2 - 1] === "/" && glob[i2 + 2] === "/") {
|
|
@@ -19681,7 +19681,7 @@ function globToRegex(glob) {
|
|
|
19681
19681
|
i2 += 3;
|
|
19682
19682
|
continue;
|
|
19683
19683
|
}
|
|
19684
|
-
if (i2 > 0 && glob[i2 - 1] === "/" && i2 + 2 ===
|
|
19684
|
+
if (i2 > 0 && glob[i2 - 1] === "/" && i2 + 2 === n2) {
|
|
19685
19685
|
out2 = out2.slice(0, -1) + "(?:/.*)?";
|
|
19686
19686
|
i2 += 2;
|
|
19687
19687
|
continue;
|
|
@@ -19821,7 +19821,7 @@ async function readSyncBaseline() {
|
|
|
19821
19821
|
try {
|
|
19822
19822
|
const parsed = JSON.parse(await (0, import_promises9.readFile)(syncStateFile(), "utf-8"));
|
|
19823
19823
|
if (Array.isArray(parsed?.nodes)) {
|
|
19824
|
-
for (const
|
|
19824
|
+
for (const n2 of parsed.nodes) if (n2?.path) out2.set(n2.path, n2.hash ?? null);
|
|
19825
19825
|
} else if (Array.isArray(parsed?.paths)) {
|
|
19826
19826
|
for (const p of parsed.paths) out2.set(p, null);
|
|
19827
19827
|
}
|
|
@@ -19901,7 +19901,7 @@ async function applyMemoryWrites(writes, opts = {}) {
|
|
|
19901
19901
|
}
|
|
19902
19902
|
}
|
|
19903
19903
|
const logLines = [`- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)} \u2014 Applied ${count} write(s) from server`];
|
|
19904
|
-
for (const
|
|
19904
|
+
for (const n2 of notes) logLines.push(` - ${n2}`);
|
|
19905
19905
|
try {
|
|
19906
19906
|
const existing = (0, import_node_fs21.existsSync)((0, import_node_path19.join)(memoryDir2(), "log.md")) ? await (0, import_promises9.readFile)((0, import_node_path19.join)(memoryDir2(), "log.md"), "utf-8") : "# Memory Log\n\n";
|
|
19907
19907
|
await (0, import_promises9.writeFile)((0, import_node_path19.join)(memoryDir2(), "log.md"), existing + logLines.join("\n") + "\n");
|
|
@@ -20500,26 +20500,26 @@ var CLAUDE_MD_PROSE_LEGACY = [
|
|
|
20500
20500
|
"superseded \u2014 ignore them unless investigating history."
|
|
20501
20501
|
].join("\n");
|
|
20502
20502
|
var PRESERVE_PLACEHOLDER = "<!-- Add binding, hand-curated guidance here; it survives Verity regeneration. -->";
|
|
20503
|
-
function* scanLines(
|
|
20503
|
+
function* scanLines(text2) {
|
|
20504
20504
|
let offset = 0;
|
|
20505
20505
|
let inFence = false;
|
|
20506
|
-
for (const line2 of
|
|
20506
|
+
for (const line2 of text2.split("\n")) {
|
|
20507
20507
|
const isFence = /^(`{3,}|~{3,})/.test(line2.trim());
|
|
20508
20508
|
if (isFence) inFence = !inFence;
|
|
20509
20509
|
yield { line: line2, start: offset, inFence: inFence || isFence };
|
|
20510
20510
|
offset += line2.length + 1;
|
|
20511
20511
|
}
|
|
20512
20512
|
}
|
|
20513
|
-
function findMarker(
|
|
20514
|
-
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)) {
|
|
20515
20515
|
if (!inFence && start2 >= from && line2.startsWith(marker)) {
|
|
20516
20516
|
return start2;
|
|
20517
20517
|
}
|
|
20518
20518
|
}
|
|
20519
20519
|
return -1;
|
|
20520
20520
|
}
|
|
20521
|
-
function hasLegacyMemoryBlock(
|
|
20522
|
-
return findMarker(
|
|
20521
|
+
function hasLegacyMemoryBlock(text2) {
|
|
20522
|
+
return findMarker(text2, LEGACY_MD_START) !== -1;
|
|
20523
20523
|
}
|
|
20524
20524
|
async function ensureClaudeMdPointer(cwd = repoRoot()) {
|
|
20525
20525
|
const claudeMdPath = (0, import_node_path19.join)(cwd, "CLAUDE.md");
|
|
@@ -20719,10 +20719,10 @@ var STOP = /* @__PURE__ */ new Set([
|
|
|
20719
20719
|
"verify",
|
|
20720
20720
|
"check"
|
|
20721
20721
|
]);
|
|
20722
|
-
function pendingTokens(
|
|
20723
|
-
if (!
|
|
20722
|
+
function pendingTokens(text2) {
|
|
20723
|
+
if (!text2 || typeof text2 !== "string") return [];
|
|
20724
20724
|
const out2 = /* @__PURE__ */ new Set();
|
|
20725
|
-
for (const raw of
|
|
20725
|
+
for (const raw of text2.toLowerCase().split(/[^a-z0-9]+/)) {
|
|
20726
20726
|
if (raw.length <= 3) continue;
|
|
20727
20727
|
if (STOP.has(raw)) continue;
|
|
20728
20728
|
out2.add(raw);
|
|
@@ -20737,8 +20737,8 @@ function overlapCoefficient(a, b) {
|
|
|
20737
20737
|
for (const t of a) if (setB.has(t)) shared++;
|
|
20738
20738
|
return shared / Math.min(a.length, b.length);
|
|
20739
20739
|
}
|
|
20740
|
-
function isRepeatOfAny(
|
|
20741
|
-
const tokens = pendingTokens(
|
|
20740
|
+
function isRepeatOfAny(text2, priorFingerprints, threshold = REPEAT_THRESHOLD) {
|
|
20741
|
+
const tokens = pendingTokens(text2);
|
|
20742
20742
|
if (tokens.length === 0) return false;
|
|
20743
20743
|
return priorFingerprints.some((prior) => overlapCoefficient(tokens, prior) >= threshold);
|
|
20744
20744
|
}
|
|
@@ -21246,7 +21246,7 @@ function compactState(s) {
|
|
|
21246
21246
|
// cached row.
|
|
21247
21247
|
g: s.goal.map((g) => [g.seq, ms(g.at), g.hash, g.superseded_by, g.text ?? 0, g.text_len ?? 0, g.source ?? 0, g.status ?? 0, g.repeats ?? 0, g.truncated ? 1 : 0, g.collapsed ? 1 : 0, g.delivered ? ms(g.delivered.at) : 0, g.delivered?.seq ?? 0, g.delivered?.summary ?? 0]),
|
|
21248
21248
|
a: s.authored?.map((a) => [a.path, a.origin, a.edits, a.hunks, a.adds, a.dels, a.hash_now, a.hash_at_last_verdict, a.first_seq, a.last_seq]) ?? null,
|
|
21249
|
-
n: s.not_mine?.map((
|
|
21249
|
+
n: s.not_mine?.map((n2) => [n2.path, n2.reason, ms(n2.at), n2.head_sha]) ?? null,
|
|
21250
21250
|
t: s.statements.map((x) => [x.anchor_key, x.file, x.line, x.pattern_id, x.title_hash, x.register, x.line_sha, x.said_at_seq, ms(x.said_at), x.outcome, x.outcome_at ? ms(x.outcome_at) : 0, x.repeats, x.carried ? 1 : 0]),
|
|
21251
21251
|
c: s.commands.map((c) => [c.cls, c.cmd_hash, c.head, c.last_status, ms(c.last_at), c.last_seq, c.streak, c.edits_since, c.runs]),
|
|
21252
21252
|
d: [s.divergence.events.map((e) => [e.kind, e.path, ms(e.at)]), s.divergence.counts, s.divergence.seen],
|
|
@@ -21257,10 +21257,10 @@ function compactState(s) {
|
|
|
21257
21257
|
}
|
|
21258
21258
|
function expandState(raw) {
|
|
21259
21259
|
try {
|
|
21260
|
-
const iso = (
|
|
21260
|
+
const iso = (n3) => new Date(n3).toISOString();
|
|
21261
21261
|
const g = raw.g;
|
|
21262
21262
|
const a = raw.a;
|
|
21263
|
-
const
|
|
21263
|
+
const n2 = raw.n;
|
|
21264
21264
|
const t = raw.t;
|
|
21265
21265
|
const c = raw.c;
|
|
21266
21266
|
const dv = raw.d;
|
|
@@ -21306,7 +21306,7 @@ function expandState(raw) {
|
|
|
21306
21306
|
// which always folds the live log. If the cache is ever put on that path,
|
|
21307
21307
|
// the full list has to be encoded — see the note on `authored_all`.
|
|
21308
21308
|
authored_all: decodedAuthored ?? [],
|
|
21309
|
-
not_mine:
|
|
21309
|
+
not_mine: n2?.map((x) => ({
|
|
21310
21310
|
path: x[0],
|
|
21311
21311
|
reason: x[1],
|
|
21312
21312
|
at: iso(x[2]),
|
|
@@ -21428,8 +21428,8 @@ function assessContinuity(i2) {
|
|
|
21428
21428
|
// src/lib/dossier/reanchor.ts
|
|
21429
21429
|
var import_node_crypto8 = require("node:crypto");
|
|
21430
21430
|
var import_node_fs25 = require("node:fs");
|
|
21431
|
-
function lineSha(
|
|
21432
|
-
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);
|
|
21433
21433
|
}
|
|
21434
21434
|
function fileHash(path) {
|
|
21435
21435
|
try {
|
|
@@ -21553,7 +21553,7 @@ function projectMemory(state, opts) {
|
|
|
21553
21553
|
}));
|
|
21554
21554
|
}
|
|
21555
21555
|
if (state.not_mine && state.not_mine.length > 0) {
|
|
21556
|
-
p.not_mine = { n: state.not_mine.length, paths: state.not_mine.map((
|
|
21556
|
+
p.not_mine = { n: state.not_mine.length, paths: state.not_mine.map((n2) => n2.path) };
|
|
21557
21557
|
} else if (state.not_mine === null) {
|
|
21558
21558
|
p.not_mine = { n: -1, paths: [] };
|
|
21559
21559
|
}
|
|
@@ -21647,8 +21647,8 @@ function stateProvenance(state, opts = {}) {
|
|
|
21647
21647
|
for (const c of state.commands) {
|
|
21648
21648
|
items.push({ key: `command:${c.cls}:${c.cmd_hash}`, kind: "command", owner: "agent", age: age(c.last_seq, false) });
|
|
21649
21649
|
}
|
|
21650
|
-
for (const
|
|
21651
|
-
items.push({ key: `not_mine:${
|
|
21650
|
+
for (const n2 of state.not_mine ?? []) {
|
|
21651
|
+
items.push({ key: `not_mine:${n2.path}`, kind: "not_mine", owner: "git", age: "this_session" });
|
|
21652
21652
|
}
|
|
21653
21653
|
for (const m of state.marks) {
|
|
21654
21654
|
items.push({ key: `mark:${m.kind}:${m.seq}`, kind: "mark", owner: "agent", age: age(m.seq, false) });
|
|
@@ -21902,10 +21902,10 @@ function recordGoal(d, prompt, source2 = "prompt") {
|
|
|
21902
21902
|
appendEvent(d, { k: "goal_continue", text: prompt.slice(0, 64) });
|
|
21903
21903
|
return;
|
|
21904
21904
|
}
|
|
21905
|
-
const
|
|
21905
|
+
const text2 = prompt.slice(0, MAX_GOAL_CHARS);
|
|
21906
21906
|
appendEvent(d, {
|
|
21907
21907
|
k: "goal",
|
|
21908
|
-
text,
|
|
21908
|
+
text: text2,
|
|
21909
21909
|
text_len: prompt.length,
|
|
21910
21910
|
source: source2,
|
|
21911
21911
|
...prompt.length > MAX_GOAL_CHARS && { truncated: true }
|
|
@@ -21979,9 +21979,9 @@ function normaliseClass(cls) {
|
|
|
21979
21979
|
const known = ["test", "build", "lint", "typecheck", "git", "other"];
|
|
21980
21980
|
return known.includes(cls) ? cls : "other";
|
|
21981
21981
|
}
|
|
21982
|
-
function toStatus(
|
|
21983
|
-
if (
|
|
21984
|
-
if (
|
|
21982
|
+
function toStatus(n2) {
|
|
21983
|
+
if (n2 === 0) return "pass";
|
|
21984
|
+
if (n2 === 1) return "fail";
|
|
21985
21985
|
return "unknown";
|
|
21986
21986
|
}
|
|
21987
21987
|
function recordVerdict(d, v) {
|
|
@@ -22187,10 +22187,10 @@ function registerIntentCommands(program2) {
|
|
|
22187
22187
|
arm: "injected",
|
|
22188
22188
|
eligible: injection.eligible,
|
|
22189
22189
|
tokens: injection.tokensUsed,
|
|
22190
|
-
nodes: injection.nodes.map((
|
|
22191
|
-
id:
|
|
22192
|
-
score: Math.round(
|
|
22193
|
-
via: `${
|
|
22190
|
+
nodes: injection.nodes.map((n2) => ({
|
|
22191
|
+
id: n2.nodeId,
|
|
22192
|
+
score: Math.round(n2.score * 1e3) / 1e3,
|
|
22193
|
+
via: `${n2.fileGlobs.length ? "g" : ""}${n2.scope === "org" ? "o" : ""}x`
|
|
22194
22194
|
}))
|
|
22195
22195
|
});
|
|
22196
22196
|
}
|
|
@@ -23005,8 +23005,8 @@ function buildCompactionContext(session) {
|
|
|
23005
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.`
|
|
23006
23006
|
);
|
|
23007
23007
|
}
|
|
23008
|
-
const
|
|
23009
|
-
if (
|
|
23008
|
+
const text2 = lines.join("\n");
|
|
23009
|
+
if (text2.length <= MAX_CHARS) return text2;
|
|
23010
23010
|
const trimmed = [...lines.slice(0, 5), ...lines.slice(5, 5 + 2)].join("\n");
|
|
23011
23011
|
return trimmed.length <= MAX_CHARS ? trimmed : null;
|
|
23012
23012
|
}
|
|
@@ -23324,9 +23324,9 @@ function declaredDependencies(root, files) {
|
|
|
23324
23324
|
for (const path of pythonManifests) {
|
|
23325
23325
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
23326
23326
|
try {
|
|
23327
|
-
const
|
|
23328
|
-
for (const m of
|
|
23329
|
-
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")) {
|
|
23330
23330
|
if (!/dependencies\s*=/.test(line2)) continue;
|
|
23331
23331
|
for (const m of line2.matchAll(/["']([A-Za-z][A-Za-z0-9._-]+)/g)) names2.push(m[1]);
|
|
23332
23332
|
}
|
|
@@ -23340,8 +23340,8 @@ function declaredDependencies(root, files) {
|
|
|
23340
23340
|
for (const path of goMods) {
|
|
23341
23341
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
23342
23342
|
try {
|
|
23343
|
-
const
|
|
23344
|
-
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)) {
|
|
23345
23345
|
names2.push(m[1].replace(/^github\.com\//, ""));
|
|
23346
23346
|
}
|
|
23347
23347
|
} catch {
|
|
@@ -23351,8 +23351,8 @@ function declaredDependencies(root, files) {
|
|
|
23351
23351
|
const path = (0, import_node_path28.join)(root, file);
|
|
23352
23352
|
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
23353
23353
|
try {
|
|
23354
|
-
const
|
|
23355
|
-
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]);
|
|
23356
23356
|
} catch {
|
|
23357
23357
|
}
|
|
23358
23358
|
}
|
|
@@ -24483,8 +24483,8 @@ function formatFindingsSummary(fc) {
|
|
|
24483
24483
|
if (!fc) return "-";
|
|
24484
24484
|
const parts2 = [];
|
|
24485
24485
|
for (const [key, abbrev] of SEV_ABBREV) {
|
|
24486
|
-
const
|
|
24487
|
-
if (
|
|
24486
|
+
const n2 = fc[key] ?? 0;
|
|
24487
|
+
if (n2 > 0) parts2.push(`${n2} ${abbrev}`);
|
|
24488
24488
|
}
|
|
24489
24489
|
return parts2.length > 0 ? parts2.join(", ") : "clean";
|
|
24490
24490
|
}
|
|
@@ -24674,13 +24674,13 @@ function parseJsonState(raw) {
|
|
|
24674
24674
|
}
|
|
24675
24675
|
function parseLegacyState(raw) {
|
|
24676
24676
|
const parts2 = raw.split(":");
|
|
24677
|
-
const
|
|
24678
|
-
if (isNaN(
|
|
24677
|
+
const n2 = parseInt(parts2[0], 10);
|
|
24678
|
+
if (isNaN(n2)) return null;
|
|
24679
24679
|
return {
|
|
24680
|
-
attempts:
|
|
24680
|
+
attempts: n2,
|
|
24681
24681
|
// The old file has no separate block count; the old counter is the closest
|
|
24682
24682
|
// honest answer, and it errs toward releasing sooner rather than later.
|
|
24683
|
-
blocks:
|
|
24683
|
+
blocks: n2,
|
|
24684
24684
|
fingerprint: parts2.slice(3).join(":") || null,
|
|
24685
24685
|
commit: parts2[1] ?? "",
|
|
24686
24686
|
ts: parseInt(parts2[2] ?? "0", 10)
|
|
@@ -24723,12 +24723,12 @@ function parseDuration(input) {
|
|
|
24723
24723
|
if (!m) {
|
|
24724
24724
|
return { ok: false, error: `Could not read "${input}" as a duration. Use 30m, 45s, or 1h.` };
|
|
24725
24725
|
}
|
|
24726
|
-
const
|
|
24727
|
-
if (!Number.isFinite(
|
|
24726
|
+
const n2 = parseInt(m[1], 10);
|
|
24727
|
+
if (!Number.isFinite(n2) || n2 <= 0) {
|
|
24728
24728
|
return { ok: false, error: `A duration must be a positive number of seconds, minutes or hours \u2014 got "${input}".` };
|
|
24729
24729
|
}
|
|
24730
24730
|
const unit = m[2] ?? "m";
|
|
24731
|
-
const seconds = unit === "s" ?
|
|
24731
|
+
const seconds = unit === "s" ? n2 : unit === "h" ? n2 * 3600 : n2 * 60;
|
|
24732
24732
|
if (seconds > MAX_WINDOW_SECONDS) {
|
|
24733
24733
|
return {
|
|
24734
24734
|
ok: false,
|
|
@@ -25060,9 +25060,9 @@ function readTextInput(value, flag, readStdin2 = () => (0, import_node_fs39.read
|
|
|
25060
25060
|
if (raw.length > MAX_STDIN_BYTES) {
|
|
25061
25061
|
return { ok: false, error: `${flag} from stdin is ${raw.length} bytes; the limit is ${MAX_STDIN_BYTES}.` };
|
|
25062
25062
|
}
|
|
25063
|
-
const
|
|
25064
|
-
if (!
|
|
25065
|
-
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 };
|
|
25066
25066
|
}
|
|
25067
25067
|
|
|
25068
25068
|
// src/lib/terminal-text.ts
|
|
@@ -25080,8 +25080,8 @@ function terminalUrl(value) {
|
|
|
25080
25080
|
// src/commands/feedback.ts
|
|
25081
25081
|
function registerFeedbackCommand(program2) {
|
|
25082
25082
|
const feedbackCmd = program2.command("feedback").description("Send feedback to the Verity team");
|
|
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 (
|
|
25084
|
-
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());
|
|
25085
25085
|
});
|
|
25086
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) => {
|
|
25087
25087
|
const globals = program2.opts();
|
|
@@ -25596,8 +25596,8 @@ function extractFileSymbols(path, content, signals) {
|
|
|
25596
25596
|
add(declNameOn(deleted, rules));
|
|
25597
25597
|
}
|
|
25598
25598
|
for (const [start2, end] of signals.addedRanges) {
|
|
25599
|
-
for (let
|
|
25600
|
-
add(declNameOn(lines[
|
|
25599
|
+
for (let n2 = start2; n2 <= Math.min(end, lines.length); n2++) {
|
|
25600
|
+
add(declNameOn(lines[n2 - 1] ?? "", rules));
|
|
25601
25601
|
}
|
|
25602
25602
|
}
|
|
25603
25603
|
const scanStarts = [
|
|
@@ -25606,8 +25606,8 @@ function extractFileSymbols(path, content, signals) {
|
|
|
25606
25606
|
];
|
|
25607
25607
|
for (const start2 of scanStarts) {
|
|
25608
25608
|
const floor = Math.max(1, start2 - ENCLOSING_SCAN_LINES);
|
|
25609
|
-
for (let
|
|
25610
|
-
const name2 = declNameOn(lines[
|
|
25609
|
+
for (let n2 = Math.min(start2, lines.length); n2 >= floor; n2--) {
|
|
25610
|
+
const name2 = declNameOn(lines[n2 - 1] ?? "", rules);
|
|
25611
25611
|
if (acceptable(name2)) {
|
|
25612
25612
|
add(name2);
|
|
25613
25613
|
break;
|
|
@@ -25681,33 +25681,33 @@ function parseRgLine(line2) {
|
|
|
25681
25681
|
if (first <= 0) return null;
|
|
25682
25682
|
const second = line2.indexOf(":", first + 1);
|
|
25683
25683
|
if (second < 0) return null;
|
|
25684
|
-
const
|
|
25685
|
-
if (!Number.isFinite(
|
|
25686
|
-
return { file: line2.slice(0, first), line:
|
|
25684
|
+
const n2 = parseInt(line2.slice(first + 1, second), 10);
|
|
25685
|
+
if (!Number.isFinite(n2) || n2 < 1) return null;
|
|
25686
|
+
return { file: line2.slice(0, first), line: n2, text: line2.slice(second + 1) };
|
|
25687
25687
|
}
|
|
25688
25688
|
var isWordChar = (c) => c !== void 0 && /[A-Za-z0-9_]/.test(c);
|
|
25689
|
-
function wordHit(
|
|
25689
|
+
function wordHit(text2, symbol) {
|
|
25690
25690
|
let from = 0;
|
|
25691
25691
|
for (; ; ) {
|
|
25692
|
-
const at =
|
|
25692
|
+
const at = text2.indexOf(symbol, from);
|
|
25693
25693
|
if (at < 0) return false;
|
|
25694
|
-
const before = at === 0 ? void 0 :
|
|
25695
|
-
const after =
|
|
25694
|
+
const before = at === 0 ? void 0 : text2[at - 1];
|
|
25695
|
+
const after = text2[at + symbol.length];
|
|
25696
25696
|
if (!isWordChar(before) && !isWordChar(after)) return true;
|
|
25697
25697
|
from = at + 1;
|
|
25698
25698
|
}
|
|
25699
25699
|
}
|
|
25700
|
-
function isContractLine(
|
|
25700
|
+
function isContractLine(text2, symbol) {
|
|
25701
25701
|
for (const kw of ["implements", "extends"]) {
|
|
25702
25702
|
let from = 0;
|
|
25703
25703
|
for (; ; ) {
|
|
25704
|
-
const at =
|
|
25704
|
+
const at = text2.indexOf(kw, from);
|
|
25705
25705
|
if (at < 0) break;
|
|
25706
25706
|
from = at + 1;
|
|
25707
|
-
const before = at === 0 ? void 0 :
|
|
25708
|
-
const after =
|
|
25707
|
+
const before = at === 0 ? void 0 : text2[at - 1];
|
|
25708
|
+
const after = text2[at + kw.length];
|
|
25709
25709
|
if (isWordChar(before) || isWordChar(after)) continue;
|
|
25710
|
-
let clause =
|
|
25710
|
+
let clause = text2.slice(at + kw.length);
|
|
25711
25711
|
const stop2 = Math.min(
|
|
25712
25712
|
...[clause.indexOf(";"), clause.indexOf("{")].filter((i2) => i2 >= 0)
|
|
25713
25713
|
);
|
|
@@ -25739,29 +25739,29 @@ function partitionSites(rgLines, symbols, opts) {
|
|
|
25739
25739
|
if (opts.sentPaths.has(h.file)) continue;
|
|
25740
25740
|
if (opts.isExcluded(h.file)) continue;
|
|
25741
25741
|
if (!isCodeSiteFile(h.file)) continue;
|
|
25742
|
-
const
|
|
25743
|
-
if (
|
|
25744
|
-
if (COMMENT_LINE.test(
|
|
25745
|
-
if (BARE_MEMBER_LINE.test(
|
|
25746
|
-
const
|
|
25747
|
-
if (
|
|
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;
|
|
25746
|
+
const n2 = perFile.get(h.file) ?? 0;
|
|
25747
|
+
if (n2 >= MAX_SITES_PER_FILE) continue;
|
|
25748
25748
|
const site = {
|
|
25749
25749
|
file: h.file,
|
|
25750
25750
|
line: h.line,
|
|
25751
|
-
text:
|
|
25751
|
+
text: text2.slice(0, SITE_TEXT_MAX),
|
|
25752
25752
|
symbol: h.symbol,
|
|
25753
25753
|
// R2 falls out of R1 for free: a word search for `Sym` already matches
|
|
25754
25754
|
// `implements Sym` / `extends Sym` lines — classification is all R2 is.
|
|
25755
|
-
...isContractLine(
|
|
25755
|
+
...isContractLine(text2, h.symbol) ? { kind: "contract" } : {}
|
|
25756
25756
|
};
|
|
25757
25757
|
if (isTestPath(h.file)) {
|
|
25758
25758
|
if (tests.length < MAX_TEST_SLOTS) {
|
|
25759
25759
|
tests.push(site);
|
|
25760
|
-
perFile.set(h.file,
|
|
25760
|
+
perFile.set(h.file, n2 + 1);
|
|
25761
25761
|
}
|
|
25762
25762
|
} else if (callers.length + tests.length < MAX_SITES) {
|
|
25763
25763
|
callers.push(site);
|
|
25764
|
-
perFile.set(h.file,
|
|
25764
|
+
perFile.set(h.file, n2 + 1);
|
|
25765
25765
|
}
|
|
25766
25766
|
}
|
|
25767
25767
|
while (callers.length + tests.length > MAX_SITES) callers.pop();
|
|
@@ -25772,8 +25772,8 @@ var MAX_IMPORTERS_PER_FILE = 2;
|
|
|
25772
25772
|
function moduleKey(path) {
|
|
25773
25773
|
return path.replace(/\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/i, "").replace(/\/index$/, "");
|
|
25774
25774
|
}
|
|
25775
|
-
function importSpecifier(
|
|
25776
|
-
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);
|
|
25777
25777
|
return m?.[1] ?? null;
|
|
25778
25778
|
}
|
|
25779
25779
|
function resolveSpecifier(fromFile, spec) {
|
|
@@ -25809,9 +25809,9 @@ function partitionImporters(rgLines, changedPaths, opts) {
|
|
|
25809
25809
|
if (!resolved) continue;
|
|
25810
25810
|
const changed = changedByKey.get(resolved);
|
|
25811
25811
|
if (!changed) continue;
|
|
25812
|
-
const
|
|
25813
|
-
if (
|
|
25814
|
-
perFile.set(h.file,
|
|
25812
|
+
const used2 = perFile.get(h.file) ?? 0;
|
|
25813
|
+
if (used2 >= MAX_IMPORTERS_PER_FILE) continue;
|
|
25814
|
+
perFile.set(h.file, used2 + 1);
|
|
25815
25815
|
out2.push({ file: h.file, line: h.line, text: h.text.trim().slice(0, SITE_TEXT_MAX), symbol: changed });
|
|
25816
25816
|
}
|
|
25817
25817
|
return out2;
|
|
@@ -25909,9 +25909,9 @@ function revisionSearch(root, rev) {
|
|
|
25909
25909
|
const line2 = prefix && raw.startsWith(prefix) ? raw.slice(prefix.length) : raw;
|
|
25910
25910
|
const hit = parseRgLine(line2);
|
|
25911
25911
|
if (!hit) continue;
|
|
25912
|
-
const
|
|
25913
|
-
if (
|
|
25914
|
-
perFile.set(hit.file,
|
|
25912
|
+
const n2 = perFile.get(hit.file) ?? 0;
|
|
25913
|
+
if (n2 >= HITS_PER_FILE) continue;
|
|
25914
|
+
perFile.set(hit.file, n2 + 1);
|
|
25915
25915
|
lines.push(`${hit.file}:${hit.line}:${hit.text.slice(0, HIT_TEXT_COLUMNS)}`);
|
|
25916
25916
|
}
|
|
25917
25917
|
return { ok: true, lines };
|
|
@@ -26030,9 +26030,9 @@ function extractEnclosingExcerpt(content, siteLine, path) {
|
|
|
26030
26030
|
if (siteLine < 1 || siteLine > lines.length) return null;
|
|
26031
26031
|
let declStart = null;
|
|
26032
26032
|
const floor = Math.max(1, siteLine - EXCERPT_DECL_SCAN);
|
|
26033
|
-
for (let
|
|
26034
|
-
if (declNameOn(lines[
|
|
26035
|
-
declStart =
|
|
26033
|
+
for (let n2 = siteLine; n2 >= floor; n2--) {
|
|
26034
|
+
if (declNameOn(lines[n2 - 1] ?? "", rules) !== null) {
|
|
26035
|
+
declStart = n2;
|
|
26036
26036
|
break;
|
|
26037
26037
|
}
|
|
26038
26038
|
}
|
|
@@ -26043,8 +26043,8 @@ function extractEnclosingExcerpt(content, siteLine, path) {
|
|
|
26043
26043
|
start2 = Math.max(1, siteLine - (EXCERPT_MAX_LINES - 6));
|
|
26044
26044
|
}
|
|
26045
26045
|
const end = Math.min(lines.length, start2 + EXCERPT_MAX_LINES - 1);
|
|
26046
|
-
const
|
|
26047
|
-
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 };
|
|
26048
26048
|
}
|
|
26049
26049
|
function upgradeToExcerpts(rc, opts) {
|
|
26050
26050
|
if (rc.state !== "ok") return;
|
|
@@ -26059,8 +26059,8 @@ function upgradeToExcerpts(rc, opts) {
|
|
|
26059
26059
|
let totalBytes = 0;
|
|
26060
26060
|
for (const site of ranked) {
|
|
26061
26061
|
if (excerpts.length >= MAX_EXCERPTS) break;
|
|
26062
|
-
const
|
|
26063
|
-
if (
|
|
26062
|
+
const used2 = perFile.get(site.file) ?? 0;
|
|
26063
|
+
if (used2 >= MAX_EXCERPTS_PER_FILE) continue;
|
|
26064
26064
|
if (!contentCache.has(site.file)) contentCache.set(site.file, opts.readFile(site.file));
|
|
26065
26065
|
const content = contentCache.get(site.file);
|
|
26066
26066
|
if (content === null || content === void 0) continue;
|
|
@@ -26076,7 +26076,7 @@ function upgradeToExcerpts(rc, opts) {
|
|
|
26076
26076
|
text: ex.text
|
|
26077
26077
|
});
|
|
26078
26078
|
totalBytes += ex.text.length;
|
|
26079
|
-
perFile.set(site.file,
|
|
26079
|
+
perFile.set(site.file, used2 + 1);
|
|
26080
26080
|
}
|
|
26081
26081
|
if (excerpts.length > 0) rc.excerpts = excerpts;
|
|
26082
26082
|
}
|
|
@@ -27141,12 +27141,12 @@ function parseKnowledgeNote(raw) {
|
|
|
27141
27141
|
if (!raw || typeof raw !== "object") return null;
|
|
27142
27142
|
const o = raw;
|
|
27143
27143
|
const node_id = typeof o.node_id === "string" ? o.node_id.trim() : "";
|
|
27144
|
-
const
|
|
27145
|
-
if (!node_id || !
|
|
27146
|
-
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;
|
|
27147
27147
|
return {
|
|
27148
27148
|
node_id,
|
|
27149
|
-
text,
|
|
27149
|
+
text: text2,
|
|
27150
27150
|
file: typeof o.file === "string" && o.file ? o.file : null,
|
|
27151
27151
|
line: typeof o.line === "number" && Number.isFinite(o.line) && o.line > 0 ? Math.floor(o.line) : null
|
|
27152
27152
|
};
|
|
@@ -27184,10 +27184,10 @@ function episodeForWire(e, humanSpoke) {
|
|
|
27184
27184
|
var MAX_AGENT_CONTEXT_CHARS = 1500;
|
|
27185
27185
|
var MAX_AGENT_ITEMS = 5;
|
|
27186
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):";
|
|
27187
|
-
function renderItem(label2,
|
|
27187
|
+
function renderItem(label2, text2, patternId, file, line2) {
|
|
27188
27188
|
const where2 = file ? ` (${file}${line2 !== void 0 && line2 !== "" ? `:${line2}` : ""})` : "";
|
|
27189
27189
|
const id = patternId ? ` [${patternId}]` : "";
|
|
27190
|
-
return `- ${label2}${
|
|
27190
|
+
return `- ${label2}${text2}${where2}${id}`;
|
|
27191
27191
|
}
|
|
27192
27192
|
function channelInputFrom(response, intentRepeat = 0, priorPendingFingerprints = []) {
|
|
27193
27193
|
const metadata2 = response.metadata ?? {};
|
|
@@ -27269,11 +27269,11 @@ function buildAgentContext(input) {
|
|
|
27269
27269
|
for (const p of input.pendingItems ?? []) {
|
|
27270
27270
|
if (lines.length >= MAX_AGENT_ITEMS) break;
|
|
27271
27271
|
if (p.pattern_id === "intent-misalignment") continue;
|
|
27272
|
-
const
|
|
27273
|
-
if (!
|
|
27274
|
-
const seenBefore = isRepeatOfAny(
|
|
27272
|
+
const text2 = p.description ?? p.title ?? p.reason;
|
|
27273
|
+
if (!text2) continue;
|
|
27274
|
+
const seenBefore = isRepeatOfAny(text2, input.priorPendingFingerprints ?? []);
|
|
27275
27275
|
lines.push(
|
|
27276
|
-
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)" : "")
|
|
27277
27277
|
);
|
|
27278
27278
|
}
|
|
27279
27279
|
if (lines.length === 0) return null;
|
|
@@ -27281,11 +27281,11 @@ function buildAgentContext(input) {
|
|
|
27281
27281
|
${lines.slice(0, MAX_AGENT_ITEMS).join("\n")}`;
|
|
27282
27282
|
return truncateToCap(body2);
|
|
27283
27283
|
}
|
|
27284
|
-
function truncateToCap(
|
|
27285
|
-
if (
|
|
27284
|
+
function truncateToCap(text2) {
|
|
27285
|
+
if (text2.length <= MAX_AGENT_CONTEXT_CHARS) return text2;
|
|
27286
27286
|
const marker = "\n- (truncated)";
|
|
27287
27287
|
const budget = MAX_AGENT_CONTEXT_CHARS - marker.length;
|
|
27288
|
-
const lines =
|
|
27288
|
+
const lines = text2.slice(0, budget).split("\n");
|
|
27289
27289
|
lines.pop();
|
|
27290
27290
|
return `${lines.join("\n")}${marker}`;
|
|
27291
27291
|
}
|
|
@@ -27313,7 +27313,7 @@ function channelSilence(input) {
|
|
|
27313
27313
|
// src/lib/cli-version.ts
|
|
27314
27314
|
function cliVersion() {
|
|
27315
27315
|
try {
|
|
27316
|
-
return true ? "0.34.
|
|
27316
|
+
return true ? "0.34.4" : "dev";
|
|
27317
27317
|
} catch {
|
|
27318
27318
|
return "dev";
|
|
27319
27319
|
}
|
|
@@ -27668,10 +27668,10 @@ function interpretAnalyzerRun(run4) {
|
|
|
27668
27668
|
function reconcileCoverage(changed, coverage) {
|
|
27669
27669
|
const changedSet = new Set(changed);
|
|
27670
27670
|
const reviewed = coverage.reviewed.filter((p) => changedSet.has(p));
|
|
27671
|
-
const claimed = /* @__PURE__ */ new Set([...reviewed, ...coverage.notReviewed.map((
|
|
27671
|
+
const claimed = /* @__PURE__ */ new Set([...reviewed, ...coverage.notReviewed.map((n2) => n2.path)]);
|
|
27672
27672
|
const unaccounted = [...changedSet].filter((p) => !claimed.has(p)).sort();
|
|
27673
27673
|
const notReviewed = [
|
|
27674
|
-
...coverage.notReviewed.filter((
|
|
27674
|
+
...coverage.notReviewed.filter((n2) => changedSet.has(n2.path)),
|
|
27675
27675
|
...unaccounted.map((path) => ({
|
|
27676
27676
|
path,
|
|
27677
27677
|
reason: "unaccounted",
|
|
@@ -27692,18 +27692,18 @@ function reconcileCoverage(changed, coverage) {
|
|
|
27692
27692
|
}
|
|
27693
27693
|
function resolveVerdict(proposed, coverage) {
|
|
27694
27694
|
if (proposed === "FAIL") return "FAIL";
|
|
27695
|
-
const blocking = coverage.notReviewed.filter((
|
|
27695
|
+
const blocking = coverage.notReviewed.filter((n2) => (n2.kind ?? "capacity") !== "policy");
|
|
27696
27696
|
if (blocking.length === 0) return proposed;
|
|
27697
27697
|
return "WARN";
|
|
27698
27698
|
}
|
|
27699
27699
|
function describeCoverage(coverage, maxPaths = 5) {
|
|
27700
|
-
const relevant = coverage.notReviewed.filter((
|
|
27700
|
+
const relevant = coverage.notReviewed.filter((n2) => (n2.kind ?? "capacity") !== "policy");
|
|
27701
27701
|
if (relevant.length === 0) return null;
|
|
27702
27702
|
const byReason = /* @__PURE__ */ new Map();
|
|
27703
|
-
for (const
|
|
27704
|
-
const key = `${
|
|
27703
|
+
for (const n2 of relevant) {
|
|
27704
|
+
const key = `${n2.reason}`;
|
|
27705
27705
|
const list2 = byReason.get(key) ?? [];
|
|
27706
|
-
list2.push(
|
|
27706
|
+
list2.push(n2.path);
|
|
27707
27707
|
byReason.set(key, list2);
|
|
27708
27708
|
}
|
|
27709
27709
|
const lines = [];
|
|
@@ -29145,10 +29145,10 @@ var MAX_WITHIN = 6;
|
|
|
29145
29145
|
var PLACEHOLDER = "${\u2026}";
|
|
29146
29146
|
var MAX_PARAMS = 12;
|
|
29147
29147
|
var PY_LOCK_ITEM = /(?:lock|Lock|mutex|Mutex|semaphore|Semaphore)\b/;
|
|
29148
|
-
var line = (
|
|
29149
|
-
var cap = (s,
|
|
29148
|
+
var line = (n2) => n2.startPosition.row + 1;
|
|
29149
|
+
var cap = (s, n2) => {
|
|
29150
29150
|
const flat = s.replace(/\s+/g, " ");
|
|
29151
|
-
return flat.length >
|
|
29151
|
+
return flat.length > n2 ? `${flat.slice(0, n2)}\u2026` : flat;
|
|
29152
29152
|
};
|
|
29153
29153
|
function qualifierOf(node, spec) {
|
|
29154
29154
|
if (spec.id === "go" && node.type === "method_declaration") {
|
|
@@ -29174,38 +29174,38 @@ function definitionsIn(root, spec) {
|
|
|
29174
29174
|
const q = qualifierOf(owner, spec);
|
|
29175
29175
|
out2.push({ name: name2, qualified: q ? `${q}.${name2}` : name2, kind: kind2, extent, last, fn });
|
|
29176
29176
|
};
|
|
29177
|
-
const visit = (
|
|
29178
|
-
const kind2 = spec.definitions[
|
|
29179
|
-
if (kind2 &&
|
|
29180
|
-
const nameNode =
|
|
29177
|
+
const visit = (n2) => {
|
|
29178
|
+
const kind2 = spec.definitions[n2.type];
|
|
29179
|
+
if (kind2 && n2.childForFieldName("body")) {
|
|
29180
|
+
const nameNode = n2.childForFieldName("name");
|
|
29181
29181
|
if (nameNode && nameNode.type !== "computed_property_name") {
|
|
29182
|
-
const inClass = qualifierOf(
|
|
29182
|
+
const inClass = qualifierOf(n2, spec) !== null;
|
|
29183
29183
|
const k = spec.id === "python" ? inClass ? "method" : "function" : kind2;
|
|
29184
|
-
add(nameNode.text, k, extentOf(
|
|
29184
|
+
add(nameNode.text, k, extentOf(n2), n2, n2, n2.parent?.type === "decorated_definition" ? n2.parent : n2);
|
|
29185
29185
|
}
|
|
29186
|
-
} else if (spec.functionValues.has(
|
|
29187
|
-
const p =
|
|
29188
|
-
const kind3 =
|
|
29189
|
-
const bound = p.childForFieldName("value")?.id ===
|
|
29186
|
+
} else if (spec.functionValues.has(n2.type) && n2.parent) {
|
|
29187
|
+
const p = n2.parent;
|
|
29188
|
+
const kind3 = n2.type === "arrow_function" ? "arrow" : n2.type === "lambda" || n2.type === "lambda_expression" ? "lambda" : "function";
|
|
29189
|
+
const bound = p.childForFieldName("value")?.id === n2.id;
|
|
29190
29190
|
if (bound && p.type === "variable_declarator" && p.childForFieldName("name")?.type === "identifier") {
|
|
29191
29191
|
const decl = p.parent && p.parent.namedChildren.filter((c) => c.type === "variable_declarator").length === 1 ? p.parent : p;
|
|
29192
|
-
add(p.childForFieldName("name").text, kind3, decl,
|
|
29192
|
+
add(p.childForFieldName("name").text, kind3, decl, n2, p);
|
|
29193
29193
|
} else if (bound && (p.type === "public_field_definition" || p.type === "field_definition")) {
|
|
29194
29194
|
const nameNode = p.childForFieldName("name") ?? p.childForFieldName("property");
|
|
29195
|
-
if (nameNode && nameNode.type !== "computed_property_name") add(nameNode.text, kind3, extentOf(p),
|
|
29195
|
+
if (nameNode && nameNode.type !== "computed_property_name") add(nameNode.text, kind3, extentOf(p), n2, p, p);
|
|
29196
29196
|
} else if (bound && p.type === "pair") {
|
|
29197
29197
|
const key = p.childForFieldName("key");
|
|
29198
|
-
if (key && (key.type === "property_identifier" || key.type === "identifier")) add(key.text, kind3, p,
|
|
29198
|
+
if (key && (key.type === "property_identifier" || key.type === "identifier")) add(key.text, kind3, p, n2, p);
|
|
29199
29199
|
} else if (p.type === "arguments" && moduleCall(p.parent)) {
|
|
29200
29200
|
const call = p.parent;
|
|
29201
29201
|
const route = p.namedChildren[0];
|
|
29202
|
-
const quoted = route && route.id !==
|
|
29202
|
+
const quoted = route && route.id !== n2.id && route.type === "string" ? unquote2(route.text) : null;
|
|
29203
29203
|
const path = quoted && /^[\w/:.{}*-]{1,60}$/.test(quoted) ? quoted : null;
|
|
29204
29204
|
const callee = call.childForFieldName("function").text;
|
|
29205
|
-
add(path ? `${callee} ${path}` : callee, kind3, call.parent,
|
|
29205
|
+
add(path ? `${callee} ${path}` : callee, kind3, call.parent, n2, call);
|
|
29206
29206
|
}
|
|
29207
29207
|
}
|
|
29208
|
-
for (const c of
|
|
29208
|
+
for (const c of n2.namedChildren) visit(c);
|
|
29209
29209
|
};
|
|
29210
29210
|
visit(root);
|
|
29211
29211
|
return out2;
|
|
@@ -29219,10 +29219,10 @@ function unquote2(s) {
|
|
|
29219
29219
|
const q3 = body2.startsWith('"""') || body2.startsWith("'''");
|
|
29220
29220
|
return q3 ? body2.slice(3, -3) : body2.slice(1, -1);
|
|
29221
29221
|
}
|
|
29222
|
-
function callParts(
|
|
29223
|
-
const args2 =
|
|
29224
|
-
if (spec.id === "java") return { receiver:
|
|
29225
|
-
let f =
|
|
29222
|
+
function callParts(n2, spec) {
|
|
29223
|
+
const args2 = n2.childForFieldName("arguments");
|
|
29224
|
+
if (spec.id === "java") return { receiver: n2.childForFieldName("object"), name: n2.childForFieldName("name")?.text ?? null, args: args2 };
|
|
29225
|
+
let f = n2.childForFieldName("function");
|
|
29226
29226
|
if (f?.type === "await_expression") f = f.namedChildren[0] ?? null;
|
|
29227
29227
|
if (!f) return { receiver: null, name: null, args: args2 };
|
|
29228
29228
|
if (f.type === "identifier") return { receiver: null, name: f.text, args: args2 };
|
|
@@ -29252,14 +29252,14 @@ function withLabel(item) {
|
|
|
29252
29252
|
if (value.type === "attribute") return value.childForFieldName("attribute")?.text ?? null;
|
|
29253
29253
|
return value.text;
|
|
29254
29254
|
}
|
|
29255
|
-
function isChained(
|
|
29256
|
-
const p =
|
|
29255
|
+
function isChained(n2) {
|
|
29256
|
+
const p = n2.parent;
|
|
29257
29257
|
if (!p) return false;
|
|
29258
29258
|
const object = p.childForFieldName("object") ?? p.childForFieldName("operand");
|
|
29259
|
-
return object?.id ===
|
|
29259
|
+
return object?.id === n2.id && (p.type === "member_expression" || p.type === "attribute" || p.type === "selector_expression" || p.type === "method_invocation");
|
|
29260
29260
|
}
|
|
29261
|
-
function isAwaited(
|
|
29262
|
-
let p =
|
|
29261
|
+
function isAwaited(n2) {
|
|
29262
|
+
let p = n2.parent;
|
|
29263
29263
|
while (p && p.type === "parenthesized_expression") p = p.parent;
|
|
29264
29264
|
return !!p && (p.type === "await_expression" || p.type === "await");
|
|
29265
29265
|
}
|
|
@@ -29283,17 +29283,17 @@ function factsOf(def, spec, defs, path) {
|
|
|
29283
29283
|
const tries = [];
|
|
29284
29284
|
const locks = [];
|
|
29285
29285
|
const bindings = {};
|
|
29286
|
-
const bind = (
|
|
29286
|
+
const bind = (n2) => {
|
|
29287
29287
|
let name2 = null;
|
|
29288
29288
|
let value = null;
|
|
29289
|
-
if (
|
|
29290
|
-
name2 =
|
|
29291
|
-
value =
|
|
29292
|
-
} else if (
|
|
29293
|
-
name2 =
|
|
29294
|
-
value =
|
|
29295
|
-
} else if (
|
|
29296
|
-
const l =
|
|
29289
|
+
if (n2.type === "variable_declarator") {
|
|
29290
|
+
name2 = n2.childForFieldName("name");
|
|
29291
|
+
value = n2.childForFieldName("value");
|
|
29292
|
+
} else if (n2.type === "assignment" && spec.id === "python") {
|
|
29293
|
+
name2 = n2.childForFieldName("left");
|
|
29294
|
+
value = n2.childForFieldName("right");
|
|
29295
|
+
} else if (n2.type === "short_var_declaration") {
|
|
29296
|
+
const l = n2.childForFieldName("left"), r = n2.childForFieldName("right");
|
|
29297
29297
|
if (l?.namedChildren.length === 1 && r?.namedChildren.length === 1) {
|
|
29298
29298
|
name2 = l.namedChildren[0];
|
|
29299
29299
|
value = r.namedChildren[0];
|
|
@@ -29301,68 +29301,68 @@ function factsOf(def, spec, defs, path) {
|
|
|
29301
29301
|
}
|
|
29302
29302
|
if (name2?.type === "identifier" && value && Object.keys(bindings).length < 40 && !(name2.text in bindings)) bindings[name2.text] = cap(value.text, TEXT_CAP);
|
|
29303
29303
|
};
|
|
29304
|
-
const throwsIn = (
|
|
29305
|
-
if (spec.throws.has(
|
|
29306
|
-
if (defs.has(
|
|
29307
|
-
return
|
|
29304
|
+
const throwsIn = (n2) => {
|
|
29305
|
+
if (spec.throws.has(n2.type)) return true;
|
|
29306
|
+
if (defs.has(n2.id) || spec.functionValues.has(n2.type)) return false;
|
|
29307
|
+
return n2.namedChildren.some(throwsIn);
|
|
29308
29308
|
};
|
|
29309
|
-
const walk2 = (
|
|
29310
|
-
const anonymousMember =
|
|
29311
|
-
if (
|
|
29312
|
-
const t =
|
|
29313
|
-
bind(
|
|
29309
|
+
const walk2 = (n2, ctx) => {
|
|
29310
|
+
const anonymousMember = n2.parent?.type === "class_body" && n2.parent.parent?.type === "object_creation_expression";
|
|
29311
|
+
if (n2.id !== def.fn.id && !anonymousMember && (defs.has(n2.id) || spec.classes.has(n2.type) || spec.definitions[n2.type])) return;
|
|
29312
|
+
const t = n2.type;
|
|
29313
|
+
bind(n2);
|
|
29314
29314
|
const down = (c, next = ctx) => walk2(c, next);
|
|
29315
29315
|
if (spec.calls.has(t)) {
|
|
29316
|
-
const { receiver, name: name2, args: args2 } = callParts(
|
|
29316
|
+
const { receiver, name: name2, args: args2 } = callParts(n2, spec);
|
|
29317
29317
|
if (name2) {
|
|
29318
29318
|
calls.push({
|
|
29319
|
-
line: line(
|
|
29320
|
-
col:
|
|
29319
|
+
line: line(n2),
|
|
29320
|
+
col: n2.startPosition.column,
|
|
29321
29321
|
receiver: receiver ? cap(receiver.text, TEXT_CAP) : null,
|
|
29322
29322
|
name: name2,
|
|
29323
29323
|
args: argsOf(args2, spec),
|
|
29324
|
-
awaited: isAwaited(
|
|
29325
|
-
chained: isChained(
|
|
29324
|
+
awaited: isAwaited(n2) || n2.childForFieldName("function")?.type === "await_expression",
|
|
29325
|
+
chained: isChained(n2),
|
|
29326
29326
|
inLoop: ctx.inLoop,
|
|
29327
29327
|
inTry: ctx.tryAt !== null,
|
|
29328
29328
|
tryAt: ctx.tryAt,
|
|
29329
29329
|
within: ctx.within.slice(-MAX_WITHIN)
|
|
29330
29330
|
});
|
|
29331
|
-
if (spec.lockCalls.has(name2)) locks.push(line(
|
|
29332
|
-
for (const c of
|
|
29331
|
+
if (spec.lockCalls.has(name2)) locks.push(line(n2));
|
|
29332
|
+
for (const c of n2.namedChildren) down(c, c.id === args2?.id ? { ...ctx, within: [...ctx.within, name2] } : ctx);
|
|
29333
29333
|
return;
|
|
29334
29334
|
}
|
|
29335
29335
|
}
|
|
29336
|
-
if (spec.awaits.has(t)) awaits.push(line(
|
|
29336
|
+
if (spec.awaits.has(t)) awaits.push(line(n2));
|
|
29337
29337
|
if (t === "defer_statement") {
|
|
29338
|
-
for (const c of
|
|
29338
|
+
for (const c of n2.namedChildren) down(c, { ...ctx, within: [...ctx.within, "defer"] });
|
|
29339
29339
|
return;
|
|
29340
29340
|
}
|
|
29341
29341
|
if (spec.lockNodes.has(t)) {
|
|
29342
|
-
locks.push(line(
|
|
29343
|
-
for (const c of
|
|
29342
|
+
locks.push(line(n2));
|
|
29343
|
+
for (const c of n2.namedChildren) down(c, { ...ctx, within: [...ctx.within, "synchronized"] });
|
|
29344
29344
|
return;
|
|
29345
29345
|
}
|
|
29346
29346
|
if (t === "with_statement") {
|
|
29347
|
-
const item =
|
|
29348
|
-
if (PY_LOCK_ITEM.test(item?.text ?? "")) locks.push(line(
|
|
29347
|
+
const item = n2.namedChildren[0];
|
|
29348
|
+
if (PY_LOCK_ITEM.test(item?.text ?? "")) locks.push(line(n2));
|
|
29349
29349
|
const label2 = withLabel(item);
|
|
29350
|
-
for (const c of
|
|
29350
|
+
for (const c of n2.namedChildren) down(c, c.type === "block" && label2 ? { ...ctx, within: [...ctx.within, label2] } : ctx);
|
|
29351
29351
|
return;
|
|
29352
29352
|
}
|
|
29353
29353
|
if (spec.loops.has(t)) {
|
|
29354
|
-
loops.push(line(
|
|
29355
|
-
for (const c of
|
|
29354
|
+
loops.push(line(n2));
|
|
29355
|
+
for (const c of n2.namedChildren) down(c, { ...ctx, inLoop: true });
|
|
29356
29356
|
return;
|
|
29357
29357
|
}
|
|
29358
29358
|
if (spec.tries.has(t)) {
|
|
29359
|
-
const handlers =
|
|
29360
|
-
tries.push({ line: line(
|
|
29361
|
-
const body2 =
|
|
29362
|
-
for (const c of
|
|
29359
|
+
const handlers = n2.namedChildren.filter((c) => spec.handlers.has(c.type));
|
|
29360
|
+
tries.push({ line: line(n2), end: n2.endPosition.row + 1, catches: handlers.length > 0, rethrows: handlers.some(throwsIn) });
|
|
29361
|
+
const body2 = n2.childForFieldName("body");
|
|
29362
|
+
for (const c of n2.namedChildren) down(c, c.id === body2?.id ? { ...ctx, tryAt: line(n2) } : ctx);
|
|
29363
29363
|
return;
|
|
29364
29364
|
}
|
|
29365
|
-
for (const c of
|
|
29365
|
+
for (const c of n2.namedChildren) down(c);
|
|
29366
29366
|
};
|
|
29367
29367
|
const synchronizedMethod = spec.id === "java" && /\bsynchronized\b/.test(def.fn.namedChildren.find((c) => c.type === "modifiers")?.text ?? "");
|
|
29368
29368
|
walk2(def.fn, { inLoop: false, tryAt: null, within: synchronizedMethod ? ["synchronized"] : [] });
|
|
@@ -29432,11 +29432,11 @@ function regionOf(rt, path, content, fn, changed, maxLines, deadlineAt) {
|
|
|
29432
29432
|
if (!tree) return { source: "fallback", reason: "deadline", elapsedMs: Date.now() - started };
|
|
29433
29433
|
try {
|
|
29434
29434
|
const lines = content.split("\n");
|
|
29435
|
-
let
|
|
29435
|
+
let n2 = tree.rootNode.descendantForPosition({ row: from - 1, column: 0 }, { row: to - 1, column: (lines[to - 1] ?? "").length });
|
|
29436
29436
|
let block = null;
|
|
29437
|
-
for (;
|
|
29438
|
-
if (BLOCKS.has(
|
|
29439
|
-
block =
|
|
29437
|
+
for (; n2 && line(n2) >= fn.start.line; n2 = n2.parent) {
|
|
29438
|
+
if (BLOCKS.has(n2.type) && n2.endPosition.row + 1 - line(n2) + 1 > maxLines) {
|
|
29439
|
+
block = n2;
|
|
29440
29440
|
break;
|
|
29441
29441
|
}
|
|
29442
29442
|
}
|
|
@@ -29482,15 +29482,15 @@ var STABLE_EXPRESSION = (t) => {
|
|
|
29482
29482
|
function argResource(kind2, arg) {
|
|
29483
29483
|
if (!arg) return { kind: kind2, name: null, confidence: "unknown" };
|
|
29484
29484
|
if (arg.literal !== null) {
|
|
29485
|
-
const
|
|
29486
|
-
return
|
|
29485
|
+
const n2 = literalName(arg.literal);
|
|
29486
|
+
return n2 ? { kind: kind2, name: n2.name, confidence: n2.confidence } : { kind: kind2, name: null, confidence: "unknown" };
|
|
29487
29487
|
}
|
|
29488
29488
|
if (SIMPLE_EXPRESSION.test(arg.text) && STABLE_EXPRESSION(arg.text)) return { kind: kind2, name: arg.text, confidence: "expression" };
|
|
29489
29489
|
const keyed = keyedCall(arg.text);
|
|
29490
29490
|
return keyed ? { kind: kind2, name: keyed, confidence: "expression" } : { kind: kind2, name: null, confidence: "unknown" };
|
|
29491
29491
|
}
|
|
29492
|
-
function keyedCall(
|
|
29493
|
-
const t =
|
|
29492
|
+
function keyedCall(text2) {
|
|
29493
|
+
const t = text2.trim();
|
|
29494
29494
|
const open = t.indexOf("(");
|
|
29495
29495
|
if (open <= 0 || !t.endsWith(")")) return null;
|
|
29496
29496
|
const callee = t.slice(0, open);
|
|
@@ -29524,16 +29524,16 @@ var SQL_TABLE = [
|
|
|
29524
29524
|
[/\bfrom\s+[`"[]?([\w.]+)/i, "read"]
|
|
29525
29525
|
];
|
|
29526
29526
|
function sqlLiteral(c) {
|
|
29527
|
-
const
|
|
29528
|
-
if (!
|
|
29527
|
+
const text2 = c.args.find((a) => a.literal !== null && SQL.test(a.literal))?.literal;
|
|
29528
|
+
if (!text2) return null;
|
|
29529
29529
|
for (const [re, op] of SQL_TABLE) {
|
|
29530
|
-
const m = re.exec(
|
|
29530
|
+
const m = re.exec(text2);
|
|
29531
29531
|
if (m) {
|
|
29532
29532
|
const name2 = m[1].split(".").pop();
|
|
29533
|
-
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) };
|
|
29534
29534
|
}
|
|
29535
29535
|
}
|
|
29536
|
-
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" };
|
|
29537
29537
|
}
|
|
29538
29538
|
var SB_WRITE = /* @__PURE__ */ new Set(["insert", "update", "upsert", "delete"]);
|
|
29539
29539
|
var SB_FROM = /\bfrom\(\s*(['"`])([\w.-]+)\1\s*\)\s*$/;
|
|
@@ -29832,7 +29832,7 @@ function accessMap(input) {
|
|
|
29832
29832
|
const effects = effectsWithHelpers(target, fileFns, lang, 2, state);
|
|
29833
29833
|
const byName = new Map(fileFns.map((f) => [f.name, f]));
|
|
29834
29834
|
const helperNames = new Set(effects.flatMap((e) => e.via));
|
|
29835
|
-
const helpers = [...helperNames].map((
|
|
29835
|
+
const helpers = [...helperNames].map((n2) => byName.get(n2)).filter((f) => !!f && f !== target && !inside(f, target)).slice(0, MAX_HELPERS);
|
|
29836
29836
|
const named = effects.filter((e) => e.resource.name !== null && e.resource.confidence !== "unknown");
|
|
29837
29837
|
const resources = [];
|
|
29838
29838
|
for (const e of [...named.filter((x) => x.op === "write"), ...named.filter((x) => x.op === "read")]) {
|
|
@@ -29929,28 +29929,28 @@ var ALIAS_OF = "alias-of:";
|
|
|
29929
29929
|
var FIELD_OF = "field-of:";
|
|
29930
29930
|
var IDENT_CHAR = /[\w$]/;
|
|
29931
29931
|
var isIdent = (s) => /^[A-Za-z_$][\w$]*$/.test(s);
|
|
29932
|
-
function wordAt(
|
|
29932
|
+
function wordAt(text2, word) {
|
|
29933
29933
|
const out2 = [];
|
|
29934
|
-
for (let i2 =
|
|
29935
|
-
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;
|
|
29936
29936
|
out2.push(i2);
|
|
29937
29937
|
}
|
|
29938
29938
|
return out2;
|
|
29939
29939
|
}
|
|
29940
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"]);
|
|
29941
|
-
function typeAt(
|
|
29941
|
+
function typeAt(text2, i2, lang) {
|
|
29942
29942
|
let j = i2;
|
|
29943
29943
|
const skip = () => {
|
|
29944
|
-
while (j <
|
|
29944
|
+
while (j < text2.length && /[\s?*&]/.test(text2[j])) j++;
|
|
29945
29945
|
};
|
|
29946
29946
|
skip();
|
|
29947
|
-
for (const kw of ["new ", "readonly ", "await "]) if (
|
|
29947
|
+
for (const kw of ["new ", "readonly ", "await "]) if (text2.startsWith(kw, j)) {
|
|
29948
29948
|
j += kw.length;
|
|
29949
29949
|
skip();
|
|
29950
29950
|
}
|
|
29951
29951
|
let k = j;
|
|
29952
|
-
while (k <
|
|
29953
|
-
const name2 =
|
|
29952
|
+
while (k < text2.length && /[\w$.]/.test(text2[k])) k++;
|
|
29953
|
+
const name2 = text2.slice(j, k).split(".").pop() ?? "";
|
|
29954
29954
|
if (lang === "go") return /^[A-Za-z_]\w*$/.test(name2) && !GO_NOT_TYPES.has(name2) ? name2 : null;
|
|
29955
29955
|
return /^[A-Z][\w$]*$/.test(name2) ? name2 : null;
|
|
29956
29956
|
}
|
|
@@ -29995,8 +29995,8 @@ function declaredType(scope2, v, lang) {
|
|
|
29995
29995
|
function classesIn(content, lang) {
|
|
29996
29996
|
const lines = content.split("\n");
|
|
29997
29997
|
const out2 = [];
|
|
29998
|
-
for (let
|
|
29999
|
-
const l = lines[
|
|
29998
|
+
for (let n2 = 0; n2 < lines.length; n2++) {
|
|
29999
|
+
const l = lines[n2];
|
|
30000
30000
|
let name2 = null, base = null, impl = [];
|
|
30001
30001
|
if (lang === "python") {
|
|
30002
30002
|
const m2 = /^(\s*)class\s+([A-Za-z_]\w*)\s*(?:\(([^)]*)\))?\s*:/.exec(l);
|
|
@@ -30004,17 +30004,17 @@ function classesIn(content, lang) {
|
|
|
30004
30004
|
name2 = m2[2];
|
|
30005
30005
|
base = (m2[3] ?? "").split(",").map((x) => x.trim().split(".").pop() ?? "").find((x) => /^[A-Z]/.test(x) && x !== "object") ?? null;
|
|
30006
30006
|
const indent = m2[1].length;
|
|
30007
|
-
let end2 =
|
|
30007
|
+
let end2 = n2 + 1;
|
|
30008
30008
|
while (end2 < lines.length && (lines[end2].trim() === "" || lines[end2].search(/\S/) > indent)) end2++;
|
|
30009
|
-
out2.push({ name: name2, base, implementsList: [], start:
|
|
30009
|
+
out2.push({ name: name2, base, implementsList: [], start: n2 + 1, end: end2 });
|
|
30010
30010
|
continue;
|
|
30011
30011
|
}
|
|
30012
30012
|
if (lang === "go") {
|
|
30013
30013
|
const m2 = /^\s*type\s+([A-Z_a-z]\w*)\s+(struct|interface)\s*\{/.exec(l);
|
|
30014
30014
|
if (!m2) continue;
|
|
30015
|
-
let end2 =
|
|
30015
|
+
let end2 = n2;
|
|
30016
30016
|
while (end2 < lines.length && !/^\s*\}/.test(lines[end2])) end2++;
|
|
30017
|
-
out2.push({ name: m2[1], base: null, implementsList: [], start:
|
|
30017
|
+
out2.push({ name: m2[1], base: null, implementsList: [], start: n2 + 1, end: end2 + 1 });
|
|
30018
30018
|
continue;
|
|
30019
30019
|
}
|
|
30020
30020
|
const m = /\b(?:class|interface)\s+([A-Za-z_$][\w$]*)(?:<[^{]*?>)?\s*(?:extends\s+([\w$.]+)(?:<[^{]*?>)?)?\s*(?:implements\s+([^{]+))?\{?/.exec(l);
|
|
@@ -30022,8 +30022,8 @@ function classesIn(content, lang) {
|
|
|
30022
30022
|
name2 = m[1];
|
|
30023
30023
|
base = m[2] ? m[2].split(".").pop() ?? null : null;
|
|
30024
30024
|
impl = (m[3] ?? "").split(",").map((x) => x.trim().replace(/<.*$/, "").split(".").pop() ?? "").filter(isIdent);
|
|
30025
|
-
let depth = 0, seen = false, end =
|
|
30026
|
-
for (let k =
|
|
30025
|
+
let depth = 0, seen = false, end = n2;
|
|
30026
|
+
for (let k = n2; k < lines.length; k++) {
|
|
30027
30027
|
for (const ch of lines[k]) {
|
|
30028
30028
|
if (ch === "{") {
|
|
30029
30029
|
depth++;
|
|
@@ -30036,7 +30036,7 @@ function classesIn(content, lang) {
|
|
|
30036
30036
|
}
|
|
30037
30037
|
end = k;
|
|
30038
30038
|
}
|
|
30039
|
-
out2.push({ name: name2, base, implementsList: impl, start:
|
|
30039
|
+
out2.push({ name: name2, base, implementsList: impl, start: n2 + 1, end: end + 1 });
|
|
30040
30040
|
}
|
|
30041
30041
|
return out2;
|
|
30042
30042
|
}
|
|
@@ -30100,10 +30100,10 @@ function boundInGo(fnText, name2) {
|
|
|
30100
30100
|
const brace = fnText.indexOf("{");
|
|
30101
30101
|
return wordAt(brace < 0 ? fnText : fnText.slice(0, brace), name2).length > 0;
|
|
30102
30102
|
}
|
|
30103
|
-
function rebindsInGo(
|
|
30104
|
-
for (const i2 of wordAt(
|
|
30105
|
-
const lineEnd =
|
|
30106
|
-
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);
|
|
30107
30107
|
const decl = rest.indexOf(":=");
|
|
30108
30108
|
if (decl >= 0 && /^[\s\w,]*$/.test(rest.slice(0, decl))) return true;
|
|
30109
30109
|
}
|
|
@@ -30329,15 +30329,15 @@ function importOf(content, lang, name2, receiver) {
|
|
|
30329
30329
|
return null;
|
|
30330
30330
|
}
|
|
30331
30331
|
var TS_EXTS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
30332
|
-
function parseJsonc(
|
|
30332
|
+
function parseJsonc(text2) {
|
|
30333
30333
|
let out2 = "";
|
|
30334
30334
|
let inString = false;
|
|
30335
|
-
for (let i2 = 0; i2 <
|
|
30336
|
-
const c =
|
|
30335
|
+
for (let i2 = 0; i2 < text2.length; i2++) {
|
|
30336
|
+
const c = text2[i2];
|
|
30337
30337
|
if (inString) {
|
|
30338
30338
|
out2 += c;
|
|
30339
30339
|
if (c === "\\") {
|
|
30340
|
-
out2 +=
|
|
30340
|
+
out2 += text2[++i2] ?? "";
|
|
30341
30341
|
continue;
|
|
30342
30342
|
}
|
|
30343
30343
|
if (c === '"') inString = false;
|
|
@@ -30348,14 +30348,14 @@ function parseJsonc(text) {
|
|
|
30348
30348
|
out2 += c;
|
|
30349
30349
|
continue;
|
|
30350
30350
|
}
|
|
30351
|
-
if (c === "/" &&
|
|
30352
|
-
while (i2 <
|
|
30351
|
+
if (c === "/" && text2[i2 + 1] === "/") {
|
|
30352
|
+
while (i2 < text2.length && text2[i2] !== "\n") i2++;
|
|
30353
30353
|
out2 += "\n";
|
|
30354
30354
|
continue;
|
|
30355
30355
|
}
|
|
30356
|
-
if (c === "/" &&
|
|
30356
|
+
if (c === "/" && text2[i2 + 1] === "*") {
|
|
30357
30357
|
i2 += 2;
|
|
30358
|
-
while (i2 <
|
|
30358
|
+
while (i2 < text2.length && !(text2[i2] === "*" && text2[i2 + 1] === "/")) i2++;
|
|
30359
30359
|
i2++;
|
|
30360
30360
|
continue;
|
|
30361
30361
|
}
|
|
@@ -30494,7 +30494,7 @@ function definitionOf(input) {
|
|
|
30494
30494
|
const caller = at ? fns.filter((f) => f.start.line <= at && at <= f.end.line).sort((a, b) => a.end.line - a.start.line - (b.end.line - b.start.line))[0] ?? null : null;
|
|
30495
30495
|
const tsCache = /* @__PURE__ */ new Map();
|
|
30496
30496
|
const resolveImport = (spec, from) => moduleFiles(source2, spec, from, lang, tsCache);
|
|
30497
|
-
const imports = (c,
|
|
30497
|
+
const imports = (c, n2) => importOf(c, lang, n2, null);
|
|
30498
30498
|
let type = receiverType(content, lang, caller, receiver, at) ?? fieldChainType({ content, lang, caller, receiver, line: at, fromPath: path, source: source2, resolveImport, importOf: imports });
|
|
30499
30499
|
if (type?.startsWith(RESULT_OF)) {
|
|
30500
30500
|
const [fnName, idx] = type.slice(RESULT_OF.length).split("#");
|
|
@@ -30519,7 +30519,7 @@ function definitionOf(input) {
|
|
|
30519
30519
|
source: source2,
|
|
30520
30520
|
outline,
|
|
30521
30521
|
resolveImport: (spec, from) => moduleFiles(source2, spec, from, lang, tsCache),
|
|
30522
|
-
importOf: (c,
|
|
30522
|
+
importOf: (c, n2) => importOf(c, lang, n2, null)
|
|
30523
30523
|
});
|
|
30524
30524
|
for (const h of hits) add([h.fn], h.how === "class" ? "type" : h.how);
|
|
30525
30525
|
}
|
|
@@ -30564,36 +30564,36 @@ function definitionOf(input) {
|
|
|
30564
30564
|
}
|
|
30565
30565
|
var MAX_CALLER_SCAN_FILES = 60;
|
|
30566
30566
|
var isWordChar2 = (c) => c !== void 0 && /[\w$]/.test(c);
|
|
30567
|
-
function callStarts(
|
|
30567
|
+
function callStarts(text2, name2) {
|
|
30568
30568
|
const out2 = [];
|
|
30569
|
-
for (let i2 =
|
|
30569
|
+
for (let i2 = text2.indexOf(name2); i2 >= 0; i2 = text2.indexOf(name2, i2 + 1)) {
|
|
30570
30570
|
let j = i2 + name2.length;
|
|
30571
|
-
if (
|
|
30571
|
+
if (text2[j] === "<") {
|
|
30572
30572
|
let depth = 0;
|
|
30573
|
-
for (; j <
|
|
30574
|
-
if (
|
|
30575
|
-
else if (
|
|
30573
|
+
for (; j < text2.length; j++) {
|
|
30574
|
+
if (text2[j] === "<") depth++;
|
|
30575
|
+
else if (text2[j] === ">" && --depth === 0) break;
|
|
30576
30576
|
}
|
|
30577
30577
|
j++;
|
|
30578
30578
|
}
|
|
30579
|
-
if (
|
|
30579
|
+
if (text2[j] === "(") out2.push({ index: i2, open: j });
|
|
30580
30580
|
}
|
|
30581
30581
|
return out2;
|
|
30582
30582
|
}
|
|
30583
|
-
function callsName(
|
|
30584
|
-
const t =
|
|
30583
|
+
function callsName(text2, name2) {
|
|
30584
|
+
const t = text2.trim();
|
|
30585
30585
|
if (t.startsWith("//") || t.startsWith("*") || t.startsWith("/*") || t.startsWith("#")) return false;
|
|
30586
|
-
for (const at of callStarts(
|
|
30586
|
+
for (const at of callStarts(text2, name2)) {
|
|
30587
30587
|
const i2 = at.index;
|
|
30588
|
-
const spread =
|
|
30589
|
-
if (isWordChar2(
|
|
30588
|
+
const spread = text2.slice(Math.max(0, i2 - 3), i2) === "...";
|
|
30589
|
+
if (isWordChar2(text2[i2 - 1]) || text2[i2 - 1] === "." && !spread) continue;
|
|
30590
30590
|
let depth = 0;
|
|
30591
30591
|
let j = at.open;
|
|
30592
|
-
for (; j <
|
|
30593
|
-
if (
|
|
30594
|
-
else if (
|
|
30592
|
+
for (; j < text2.length; j++) {
|
|
30593
|
+
if (text2[j] === "(") depth++;
|
|
30594
|
+
else if (text2[j] === ")" && --depth === 0) break;
|
|
30595
30595
|
}
|
|
30596
|
-
const after =
|
|
30596
|
+
const after = text2.slice(j + 1).trimStart();
|
|
30597
30597
|
if (after.startsWith(":") || after.startsWith("{")) continue;
|
|
30598
30598
|
return true;
|
|
30599
30599
|
}
|
|
@@ -30663,7 +30663,7 @@ function callersOf(input) {
|
|
|
30663
30663
|
let tie = fileTie;
|
|
30664
30664
|
if (owner) {
|
|
30665
30665
|
if (!c.receiver) continue;
|
|
30666
|
-
const imports = (cc,
|
|
30666
|
+
const imports = (cc, n2) => importOf(cc, lang, n2, null);
|
|
30667
30667
|
const resolveImport = (spec, from) => moduleFiles(source2, spec, from, lang, cache);
|
|
30668
30668
|
const type = receiverType(read2.content, lang, fn, c.receiver, c.line) ?? fieldChainType({ content: read2.content, lang, caller: fn, receiver: c.receiver, line: c.line, fromPath: p, source: source2, resolveImport, importOf: imports });
|
|
30669
30669
|
if (type !== owner) continue;
|
|
@@ -30683,11 +30683,11 @@ function callersOf(input) {
|
|
|
30683
30683
|
if (seen.has(line2) || declared.has(line2)) continue;
|
|
30684
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));
|
|
30685
30685
|
if (inside2) continue;
|
|
30686
|
-
const
|
|
30687
|
-
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;
|
|
30688
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];
|
|
30689
30689
|
seen.add(line2);
|
|
30690
|
-
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 });
|
|
30691
30691
|
}
|
|
30692
30692
|
}
|
|
30693
30693
|
}
|
|
@@ -30809,8 +30809,8 @@ var SOURCE_EXTS = ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs", "py", "
|
|
|
30809
30809
|
function parseHit(line2) {
|
|
30810
30810
|
const m = /^(.+?):(\d+):(.*)$/.exec(line2);
|
|
30811
30811
|
if (!m) return null;
|
|
30812
|
-
const
|
|
30813
|
-
return
|
|
30812
|
+
const n2 = Number(m[2]);
|
|
30813
|
+
return n2 >= 1 ? { path: m[1], line: n2, text: m[3] } : null;
|
|
30814
30814
|
}
|
|
30815
30815
|
function capHits(lines, maxHits) {
|
|
30816
30816
|
const hits = [];
|
|
@@ -30994,16 +30994,16 @@ ${m.accessors.map((x) => ` ${x.fn.path}:${x.fn.start.line} ${x.fn.qualified} \u
|
|
|
30994
30994
|
return { ok: true, value: lines.join("\n") };
|
|
30995
30995
|
};
|
|
30996
30996
|
var KINDS = ["table", "cache", "file", "http", "queue", "service", "memory"];
|
|
30997
|
-
function parseResource(
|
|
30998
|
-
const colon =
|
|
30999
|
-
const kind2 = colon > 0 ?
|
|
31000
|
-
if (KINDS.includes(kind2)) return { kinds: [kind2], name:
|
|
31001
|
-
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 };
|
|
31002
31002
|
}
|
|
31003
31003
|
var writersOfTool = async (ctx, args2) => {
|
|
31004
|
-
const
|
|
31005
|
-
if (!
|
|
31006
|
-
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);
|
|
31007
31007
|
if (name2.length < 2) return { ok: false, error: "resource name too short to search for" };
|
|
31008
31008
|
const deadline = Date.now() + TOOL_MS;
|
|
31009
31009
|
const src = source(ctx);
|
|
@@ -31042,7 +31042,7 @@ var writersOfTool = async (ctx, args2) => {
|
|
|
31042
31042
|
if (files.size > 25) truncated = true;
|
|
31043
31043
|
const list2 = (xs) => xs.length ? xs.slice(0, MAX_LIST).map((x) => ` ${x}`).join("\n") + (xs.length > MAX_LIST ? `
|
|
31044
31044
|
\u2026 ${xs.length - MAX_LIST} more` : "") : " none found";
|
|
31045
|
-
return { ok: true, value: `${
|
|
31045
|
+
return { ok: true, value: `${text2.value} (${where(ctx)}), heuristic${truncated ? ", search cut short" : ""}
|
|
31046
31046
|
writers:
|
|
31047
31047
|
${list2(writers)}
|
|
31048
31048
|
readers:
|
|
@@ -31100,9 +31100,9 @@ function validateRepoPath(value, { allowRoot = false } = {}) {
|
|
|
31100
31100
|
function lineNumber(value, fallback) {
|
|
31101
31101
|
return typeof value === "number" && Number.isInteger(value) && value >= 1 ? value : fallback;
|
|
31102
31102
|
}
|
|
31103
|
-
function capOutput(
|
|
31104
|
-
return
|
|
31105
|
-
[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;
|
|
31106
31106
|
}
|
|
31107
31107
|
function git(ctx, args2, opts = {}) {
|
|
31108
31108
|
return runGit(ctx.root, args2, { timeoutMs: opts.timeoutMs ?? TOOL_LIMITS.gitTimeoutMs, maxBuffer: opts.maxBuffer ?? TOOL_LIMITS.fileBytes });
|
|
@@ -31236,8 +31236,8 @@ var listFilesTool = async (ctx, args2) => {
|
|
|
31236
31236
|
\u2026 ${more} more` : ""}` : "no matching files" };
|
|
31237
31237
|
};
|
|
31238
31238
|
var searchTool = async (ctx, args2) => {
|
|
31239
|
-
const
|
|
31240
|
-
if (typeof
|
|
31239
|
+
const text2 = args2.text;
|
|
31240
|
+
if (typeof text2 !== "string" || text2.length === 0 || text2.length > TOOL_LIMITS.textChars || /[\n\r]/.test(text2)) {
|
|
31241
31241
|
return { ok: false, error: `text must be 1-${TOOL_LIMITS.textChars} characters on one line` };
|
|
31242
31242
|
}
|
|
31243
31243
|
const glob = typeof args2.path_glob === "string" && args2.path_glob.length > 0 ? args2.path_glob : null;
|
|
@@ -31246,7 +31246,7 @@ var searchTool = async (ctx, args2) => {
|
|
|
31246
31246
|
}
|
|
31247
31247
|
const pathspec = glob ? [`:(glob)${glob}`] : [];
|
|
31248
31248
|
const revision = ctx.range.kind === "push" ? [ctx.range.head] : ["--cached"];
|
|
31249
|
-
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]);
|
|
31250
31250
|
if (!res.ok) {
|
|
31251
31251
|
if (res.error === "failed" && res.stderr.trim() === "") return { ok: true, value: "no matches" };
|
|
31252
31252
|
return { ok: false, error: gitFailure(res, "search") };
|
|
@@ -31284,7 +31284,7 @@ function makeToolExecutor(ctx) {
|
|
|
31284
31284
|
const index = next++;
|
|
31285
31285
|
const call = calls[index];
|
|
31286
31286
|
const codeTool = ctx.codeMap && CODE_TOOL_NAMES.includes(call.name) ? CODE_TOOLS[call.name] : null;
|
|
31287
|
-
const tool = codeTool ? (c, args2) => codeTool({ root: c.root, revision: c.range.kind === "push" ? c.range.head : null, codeMap: c.codeMap, validatePath: (v) => validateRepoPath(v), denied: isDeniedPath }, args2) : TOOLS[call.name]
|
|
31287
|
+
const tool = codeTool ? (c, args2) => codeTool({ root: c.root, revision: c.range.kind === "push" ? c.range.head : null, codeMap: c.codeMap, validatePath: (v) => validateRepoPath(v), denied: isDeniedPath }, args2) : Object.hasOwn(TOOLS, call.name) ? TOOLS[call.name] : null;
|
|
31288
31288
|
if (!tool) {
|
|
31289
31289
|
results[index] = { call_id: call.call_id, ok: false, error: `unknown tool ${call.name}` };
|
|
31290
31290
|
continue;
|
|
@@ -31374,16 +31374,16 @@ function functionWindow(codeMap, path, content, line2, maxLines) {
|
|
|
31374
31374
|
}
|
|
31375
31375
|
function writerExcerpts(codeMap, writers, read2, maxLines, maxChars, budget) {
|
|
31376
31376
|
const out2 = [];
|
|
31377
|
-
let
|
|
31377
|
+
let used2 = 0;
|
|
31378
31378
|
for (const w of writers) {
|
|
31379
31379
|
const content = read2(w.file);
|
|
31380
31380
|
if (content === null) continue;
|
|
31381
31381
|
const win = functionWindow(codeMap, w.file, content, w.line, maxLines);
|
|
31382
31382
|
if (!win) continue;
|
|
31383
|
-
const
|
|
31384
|
-
if (
|
|
31385
|
-
|
|
31386
|
-
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 (used2 + text2.length > budget) break;
|
|
31385
|
+
used2 += 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 });
|
|
31387
31387
|
}
|
|
31388
31388
|
return out2;
|
|
31389
31389
|
}
|
|
@@ -31509,7 +31509,7 @@ function splitClaudeMdSections(content) {
|
|
|
31509
31509
|
}
|
|
31510
31510
|
function classifyClaudeSection(heading) {
|
|
31511
31511
|
const h = heading.toLowerCase();
|
|
31512
|
-
const hasAny = (needles) => needles.some((
|
|
31512
|
+
const hasAny = (needles) => needles.some((n2) => h.includes(n2));
|
|
31513
31513
|
if (hasAny(["security", "auth", "secret", "credential", "cwe", "vulnerabilit", "sanitiz"])) return "security";
|
|
31514
31514
|
if (hasAny(["gotcha", "caveat", "pitfall", "footgun", "beware", "watch out", "known issue", "warning"])) return "gotcha";
|
|
31515
31515
|
if (hasAny(["decision", "adr", "rationale", "why we", "chose", "trade-off", "tradeoff"])) return "decision";
|
|
@@ -31722,7 +31722,7 @@ async function serverSeedTitles(opts) {
|
|
|
31722
31722
|
});
|
|
31723
31723
|
if (!res.ok || !Array.isArray(res.data.nodes)) return null;
|
|
31724
31724
|
const titles = /* @__PURE__ */ new Set();
|
|
31725
|
-
for (const
|
|
31725
|
+
for (const n2 of res.data.nodes) if (typeof n2?.title === "string") titles.add(normalizeTitle(n2.title));
|
|
31726
31726
|
return titles;
|
|
31727
31727
|
}
|
|
31728
31728
|
function renderNodeMarkdown(candidate, nodeId, createdAt) {
|
|
@@ -32508,7 +32508,7 @@ function redactRequest(body2) {
|
|
|
32508
32508
|
undelivered: true,
|
|
32509
32509
|
total_files: files.length,
|
|
32510
32510
|
total_bytes: files.reduce(
|
|
32511
|
-
(
|
|
32511
|
+
(n2, f) => n2 + (typeof f.content === "string" ? f.content.length : 0),
|
|
32512
32512
|
0
|
|
32513
32513
|
),
|
|
32514
32514
|
// Paths only. A path is already visible in the repository; the content is not.
|
|
@@ -33027,10 +33027,10 @@ async function writePullState(state) {
|
|
|
33027
33027
|
} catch {
|
|
33028
33028
|
}
|
|
33029
33029
|
}
|
|
33030
|
-
function pullsAtSessionStart(
|
|
33030
|
+
function pullsAtSessionStart(auth3, source2) {
|
|
33031
33031
|
if (source2 === "compact") return false;
|
|
33032
|
-
if (
|
|
33033
|
-
return
|
|
33032
|
+
if (auth3.source === "env" || auth3.source === "flag") return true;
|
|
33033
|
+
return auth3.userId != null;
|
|
33034
33034
|
}
|
|
33035
33035
|
function spawnBackgroundPull(deps = {}) {
|
|
33036
33036
|
const d = {
|
|
@@ -33151,7 +33151,7 @@ async function render(run4) {
|
|
|
33151
33151
|
const memoryNodesUsed = response.memory_nodes_used;
|
|
33152
33152
|
const lessonsUsed = response.lessons_used;
|
|
33153
33153
|
if (memoryNodesUsed && memoryNodesUsed.length > 0) {
|
|
33154
|
-
const nodeRefs = memoryNodesUsed.slice(0, 5).map((
|
|
33154
|
+
const nodeRefs = memoryNodesUsed.slice(0, 5).map((n2) => n2.node_id).join(", ");
|
|
33155
33155
|
process.stderr.write(`${DIM}Memory: ${memoryNodesUsed.length} nodes \u2014 ${nodeRefs}${NC}
|
|
33156
33156
|
`);
|
|
33157
33157
|
} else if (lessonsUsed && lessonsUsed.length > 0) {
|
|
@@ -34056,14 +34056,14 @@ function trackedSourceFiles(root, opts = {}) {
|
|
|
34056
34056
|
return files.slice(0, opts.maxFiles ?? 5e3);
|
|
34057
34057
|
}
|
|
34058
34058
|
var EFFECT_LINE = /\bawait\b|\basync\s+with\b|\.then\(|\bsetTimeout\(|\bsetInterval\(|\bwith\s+\w[\w.]*\.(?:lock|acquire)\b|\bLock\(\)/;
|
|
34059
|
-
function countEffects(
|
|
34060
|
-
let
|
|
34061
|
-
for (const line2 of
|
|
34062
|
-
return
|
|
34059
|
+
function countEffects(text2) {
|
|
34060
|
+
let n2 = 0;
|
|
34061
|
+
for (const line2 of text2.split("\n")) if (EFFECT_LINE.test(line2)) n2++;
|
|
34062
|
+
return n2;
|
|
34063
34063
|
}
|
|
34064
|
-
function scanRisk(
|
|
34064
|
+
function scanRisk(text2) {
|
|
34065
34065
|
const counts = Object.fromEntries(RISK_PATTERNS.map(([c]) => [c, 0]));
|
|
34066
|
-
for (const line2 of
|
|
34066
|
+
for (const line2 of text2.split("\n")) {
|
|
34067
34067
|
for (const [category, re] of RISK_PATTERNS) {
|
|
34068
34068
|
if (re.test(line2)) counts[category]++;
|
|
34069
34069
|
}
|
|
@@ -34141,7 +34141,7 @@ function collectRiskSignals(root, opts = {}) {
|
|
|
34141
34141
|
}
|
|
34142
34142
|
|
|
34143
34143
|
// src/lib/prove/grounding.ts
|
|
34144
|
-
var BASIS_RULES = ["conservation", "once", "no-lost-update", "fail-closed", "progress"];
|
|
34144
|
+
var BASIS_RULES = ["conservation", "once", "no-lost-update", "fail-closed", "progress", "isolation", "revocation", "flow-binding", "event-order", "check-use"];
|
|
34145
34145
|
var RULE = /^rule:([a-z-]+)$/;
|
|
34146
34146
|
var LINE = /^(?:([^\s:]+):)?L?(\d{1,6})(?::\s*|\s+)(?:comment\s+)?([\s\S]+)$/;
|
|
34147
34147
|
var norm = (s) => s.replace(/\s+/g, " ").trim().toLowerCase();
|
|
@@ -34152,17 +34152,17 @@ function basisOf(source2, files) {
|
|
|
34152
34152
|
const m = LINE.exec(s);
|
|
34153
34153
|
if (!m) return { ok: false, why: s ? `"${s.slice(0, 60)}" is neither L<n>: <words> nor a rule` : "no source" };
|
|
34154
34154
|
const path = m[1];
|
|
34155
|
-
const
|
|
34155
|
+
const n2 = Number(m[2]);
|
|
34156
34156
|
const quoted = m[3].trim().replace(/^["'`“”]+|["'`“”]+$/g, "");
|
|
34157
34157
|
const fragments = quoted.split(/…|\.\.\./).map(norm).filter((f) => f.length >= 4);
|
|
34158
|
-
if (fragments.length === 0) return { ok: false, why: `L${
|
|
34158
|
+
if (fragments.length === 0) return { ok: false, why: `L${n2}: too few words to find on the line` };
|
|
34159
34159
|
const pool = path ? [...files].filter(([f]) => f === path || f.endsWith(`/${path}`)).map(([, c]) => c) : [...files.values()];
|
|
34160
34160
|
if (path && pool.length === 0) return { ok: false, why: `${path} is not one of the given files` };
|
|
34161
34161
|
for (const content of pool) {
|
|
34162
|
-
const line2 = content.split("\n")[
|
|
34163
|
-
if (line2 !== void 0 && fragments.every((f) => norm(line2).includes(f))) return { ok: true, basis: `L${
|
|
34162
|
+
const line2 = content.split("\n")[n2 - 1];
|
|
34163
|
+
if (line2 !== void 0 && fragments.every((f) => norm(line2).includes(f))) return { ok: true, basis: `L${n2}: ${quoted.slice(0, 120)}` };
|
|
34164
34164
|
}
|
|
34165
|
-
return { ok: false, why: `line ${
|
|
34165
|
+
return { ok: false, why: `line ${n2} does not contain "${quoted.slice(0, 60)}"` };
|
|
34166
34166
|
}
|
|
34167
34167
|
var NOT_A_MENTION = "(?<!\\b(?:even|including|also|or) )";
|
|
34168
34168
|
var UNTIL_FIRST = "(?:(?!\\bor\\b)[^,.;:]){0,60}?";
|
|
@@ -34192,6 +34192,19 @@ var STRUCTURAL_CATALOGUE = [
|
|
|
34192
34192
|
"check_then_act_is_atomic",
|
|
34193
34193
|
"no_double_effect"
|
|
34194
34194
|
];
|
|
34195
|
+
var SECURITY_CATALOGUE = [
|
|
34196
|
+
"limit_holds_under_concurrency",
|
|
34197
|
+
"single_use",
|
|
34198
|
+
"no_cross_subject_leak",
|
|
34199
|
+
"revocation_holds",
|
|
34200
|
+
"flow_binding",
|
|
34201
|
+
"event_order_holds",
|
|
34202
|
+
"fails_closed",
|
|
34203
|
+
"checked_value_is_used",
|
|
34204
|
+
"idempotency_scoped"
|
|
34205
|
+
];
|
|
34206
|
+
var MAX_HYPOTHESES = 3;
|
|
34207
|
+
var CATALOGUE = [...STRUCTURAL_CATALOGUE, ...SECURITY_CATALOGUE];
|
|
34195
34208
|
function combineScore(c) {
|
|
34196
34209
|
const f = (x) => Math.max(0.01, Math.min(1, x));
|
|
34197
34210
|
return Math.round(Math.pow(f(c.hazard), 0.45) * Math.pow(f(c.critical), 0.35) * Math.pow(f(c.error_prone), 0.2) * 1e3) / 1e3;
|
|
@@ -34260,13 +34273,13 @@ function changedExcerpt(content, changed, bytes, context = 30) {
|
|
|
34260
34273
|
else acc.push({ ...w });
|
|
34261
34274
|
return acc;
|
|
34262
34275
|
}, []);
|
|
34263
|
-
const isChanged = (
|
|
34276
|
+
const isChanged = (n2) => changed.some((r) => n2 >= r.from && n2 <= r.to);
|
|
34264
34277
|
const out2 = [];
|
|
34265
34278
|
let size = 0;
|
|
34266
34279
|
for (const w of windows) {
|
|
34267
34280
|
if (out2.length) out2.push(" \u2026");
|
|
34268
|
-
for (let
|
|
34269
|
-
const line2 = `${String(
|
|
34281
|
+
for (let n2 = w.from; n2 <= w.to; n2++) {
|
|
34282
|
+
const line2 = `${String(n2).padStart(5)}${isChanged(n2) ? "*" : " "}| ${lines[n2 - 1] ?? ""}`;
|
|
34270
34283
|
size += line2.length + 1;
|
|
34271
34284
|
if (size > bytes) {
|
|
34272
34285
|
out2.push(" \u2026 (truncated)");
|
|
@@ -34294,9 +34307,11 @@ var LUNA_SCHEMA = {
|
|
|
34294
34307
|
error_prone: { type: "number" },
|
|
34295
34308
|
reasons: { type: "array", items: { type: "string" } },
|
|
34296
34309
|
symbol: { type: "string" },
|
|
34297
|
-
properties: { type: "array", items: { type: "string", enum: [...STRUCTURAL_CATALOGUE] } }
|
|
34310
|
+
properties: { type: "array", items: { type: "string", enum: [...STRUCTURAL_CATALOGUE, ...SECURITY_CATALOGUE] } },
|
|
34311
|
+
lens: { type: "string", enum: ["security", "reliability"] },
|
|
34312
|
+
hypotheses: { type: "array", items: { type: "string" } }
|
|
34298
34313
|
},
|
|
34299
|
-
required: ["file", "critical", "hazard", "error_prone", "reasons", "symbol", "properties"]
|
|
34314
|
+
required: ["file", "critical", "hazard", "error_prone", "reasons", "symbol", "properties", "lens", "hypotheses"]
|
|
34300
34315
|
}
|
|
34301
34316
|
}
|
|
34302
34317
|
},
|
|
@@ -34309,7 +34324,9 @@ For each file you get its git-history signals (commits, fix commits), risk keywo
|
|
|
34309
34324
|
- error_prone: fix commits in its history (the strongest evidence: this code has already been wrong), high churn, several branches or error paths, a concurrency primitive \u2014 a hazard nobody sees by reading the function once.
|
|
34310
34325
|
Rate a criterion LOW (below 0.5) when it is missing: rendering, formatting, configuration, command registration, wiring, types, a single read, a single write with nothing before it, logging, or a function whose correctness is plain from reading it. A crash window alone (an external call, then a local write, where a re-run repairs the state and nothing is lost for good) is not enough for a high score. A model of a function longer than about 150 lines abstracts too much to find anything: name the smaller function inside it that holds the hazard, or score lower.
|
|
34311
34326
|
Name the single symbol (function) most worth modelling, and the applicable properties from the catalogue only. Reasons: at most 3, each a short concrete sentence about THIS code \u2014 its hazard, what a mistake costs, its history \u2014 never about the change. Return every file you were given, exactly once.
|
|
34312
|
-
When a file lists \`changed\` lines, this is a review of a push: the excerpt is numbered around the changes (changed lines starred). Name the function that CONTAINS a changed line, and score THAT FUNCTION'S CURRENT CODE as a whole, never the edit itself. A one-line change (a log line, a rename) to a function that meets all three still scores high: a latent bug in it is exactly what this is for. A large change to a function that misses one still scores low. An excerpt may open with "Functions this push changed:", from a parser: when it says a changed function "shares state with" another, judge the PAIR \u2014 a function that alone is a single write or an invalidation is error-prone when the other reads and repopulates, or also writes, the same state (a cache invalidated here and refilled there, two writers of one ledger or file); score it as that pair would be scored, but name ONE symbol \u2014 the changed function, never both ("a/b", "a and b" name nothing). "reads then writes" names a check-then-act the parser saw with no transaction or lock around it. "effects" lists the state the function reads and writes (a table, a file, a cache key, a queue, an outside service). "Fix commits that changed these lines" quotes the history of THIS code: each one is evidence it has been wrong before (error_prone), and its subject often says what a mistake cost (critical) \u2014 a subject about duplicates, lost writes, double charges or stuck jobs is a costly mistake that already happened
|
|
34327
|
+
When a file lists \`changed\` lines, this is a review of a push: the excerpt is numbered around the changes (changed lines starred). Name the function that CONTAINS a changed line, and score THAT FUNCTION'S CURRENT CODE as a whole, never the edit itself. A one-line change (a log line, a rename) to a function that meets all three still scores high: a latent bug in it is exactly what this is for. A large change to a function that misses one still scores low. An excerpt may open with "Functions this push changed:", from a parser: when it says a changed function "shares state with" another, judge the PAIR \u2014 a function that alone is a single write or an invalidation is error-prone when the other reads and repopulates, or also writes, the same state (a cache invalidated here and refilled there, two writers of one ledger or file); score it as that pair would be scored, but name ONE symbol \u2014 the changed function, never both ("a/b", "a and b" name nothing). "reads then writes" names a check-then-act the parser saw with no transaction or lock around it. "effects" lists the state the function reads and writes (a table, a file, a cache key, a queue, an outside service). "Fix commits that changed these lines" quotes the history of THIS code: each one is evidence it has been wrong before (error_prone), and its subject often says what a mistake cost (critical) \u2014 a subject about duplicates, lost writes, double charges or stuck jobs is a costly mistake that already happened.
|
|
34328
|
+
SECURITY LENS. Also decide who can drive the hazard. Set lens to "security" when an attacker outside the trust boundary can drive it: another user, an anonymous caller, another tenant, a holder of a stolen or revoked credential, the sender of a replayed or delayed event, or the owner of a domain or URL the code fetches. Otherwise set lens to "reliability". For the security lens, critical includes what the attacker gains (money, data, rights, another user's or tenant's data, free service), and hazard includes the moves an attacker controls: many copies of one request at once; the steps of a multi-step flow skipped, repeated or reordered; a right revoked between two steps; an event duplicated, delayed or reordered; a dependency that fails, times out or is circuit-broken; state shared across requests, users or tenants (module variables, caches, fallback answers, idempotency keys); a value that changes between its check and its use (a DNS answer, a redirect, a path).
|
|
34329
|
+
HYPOTHESES. For the symbol you name, give up to 3 concrete hypotheses for the model to try to break. Each is one sentence about THIS code that says who acts, the two or more steps, and the harm (for example "two concurrent redeem requests by one user both pass the count check, so the credit is added twice"). When a file lists \`changed\` lines, at least one hypothesis is about what the change made possible. A hypothesis is a question for the model, not a verdict. Give none when you see no concrete one.`;
|
|
34313
34330
|
var lunaRanker = {
|
|
34314
34331
|
name: "luna",
|
|
34315
34332
|
async rank(candidates2, ctx) {
|
|
@@ -34340,7 +34357,7 @@ var lunaRanker = {
|
|
|
34340
34357
|
store: false,
|
|
34341
34358
|
instructions: LUNA_INSTRUCTIONS,
|
|
34342
34359
|
input: JSON.stringify({
|
|
34343
|
-
catalogue: STRUCTURAL_CATALOGUE,
|
|
34360
|
+
catalogue: [...STRUCTURAL_CATALOGUE, ...SECURITY_CATALOGUE],
|
|
34344
34361
|
...ctx.hint ? { user_hint: `The user said what they want checked: "${ctx.hint.slice(0, 500)}". Score files and name symbols relevant to it higher; do not invent relevance.` } : {},
|
|
34345
34362
|
files: payload
|
|
34346
34363
|
}),
|
|
@@ -34357,13 +34374,13 @@ var lunaRanker = {
|
|
|
34357
34374
|
signal: controller.signal
|
|
34358
34375
|
});
|
|
34359
34376
|
if (!res.ok) {
|
|
34360
|
-
const
|
|
34361
|
-
return { ok: false, ranker: "luna", error: `OpenAI ${res.status}: ${
|
|
34377
|
+
const text3 = await res.text().catch(() => "");
|
|
34378
|
+
return { ok: false, ranker: "luna", error: `OpenAI ${res.status}: ${text3.slice(0, 200)}`, ranked: fallback };
|
|
34362
34379
|
}
|
|
34363
34380
|
const data = await res.json();
|
|
34364
|
-
const
|
|
34365
|
-
if (!
|
|
34366
|
-
const parsed = JSON.parse(
|
|
34381
|
+
const text2 = (data.output ?? []).flatMap((o) => o.content ?? []).find((c) => c.type === "output_text")?.text;
|
|
34382
|
+
if (!text2) return { ok: false, ranker: "luna", error: "no output_text in response", ranked: fallback };
|
|
34383
|
+
const parsed = JSON.parse(text2);
|
|
34367
34384
|
const items = parsed.items.map((i2) => {
|
|
34368
34385
|
const legacy = i2.critical === void 0 && i2.hazard === void 0 && i2.error_prone === void 0;
|
|
34369
34386
|
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 };
|
|
@@ -34378,14 +34395,14 @@ var lunaRanker = {
|
|
|
34378
34395
|
}
|
|
34379
34396
|
}
|
|
34380
34397
|
};
|
|
34381
|
-
async function rankViaServer(candidates2, ctx,
|
|
34398
|
+
async function rankViaServer(candidates2, ctx, auth3) {
|
|
34382
34399
|
const fallback = deterministicOrder(candidates2);
|
|
34383
34400
|
const excerptBytes = ctx.excerptBytes ?? 6 * 1024;
|
|
34384
34401
|
const res = await apiRequest({
|
|
34385
34402
|
method: "POST",
|
|
34386
34403
|
path: "/prove/rank",
|
|
34387
|
-
serviceUrl:
|
|
34388
|
-
token:
|
|
34404
|
+
serviceUrl: auth3.serviceUrl,
|
|
34405
|
+
token: auth3.token,
|
|
34389
34406
|
body: {
|
|
34390
34407
|
candidates: candidates2.map((c) => ({
|
|
34391
34408
|
file: c.file,
|
|
@@ -34415,7 +34432,7 @@ function applyAnnotations(candidates2, items) {
|
|
|
34415
34432
|
const annotated = candidates2.map((c) => {
|
|
34416
34433
|
const a = byFile.get(c.file);
|
|
34417
34434
|
if (!a) return { ...c, rank: 0 };
|
|
34418
|
-
const properties = (a.properties ?? []).filter((p) =>
|
|
34435
|
+
const properties = (a.properties ?? []).filter((p) => CATALOGUE.includes(p));
|
|
34419
34436
|
const score = Math.max(0, Math.min(1, Number(a.score) || 0));
|
|
34420
34437
|
const ai = { score, reasons: (a.reasons ?? []).slice(0, 3), properties };
|
|
34421
34438
|
if (a.criteria && typeof a.criteria === "object") {
|
|
@@ -34424,6 +34441,9 @@ function applyAnnotations(candidates2, items) {
|
|
|
34424
34441
|
}
|
|
34425
34442
|
if (a.reasked) ai.reasked = true;
|
|
34426
34443
|
if (a.symbol && a.symbol.trim()) ai.symbol = a.symbol.trim();
|
|
34444
|
+
if (a.lens === "security") ai.lens = "security";
|
|
34445
|
+
const hypotheses = (Array.isArray(a.hypotheses) ? a.hypotheses : []).filter((h) => typeof h === "string" && h.trim().length > 0).slice(0, MAX_HYPOTHESES).map((h) => h.trim().slice(0, 300));
|
|
34446
|
+
if (hypotheses.length) ai.hypotheses = hypotheses;
|
|
34427
34447
|
return { ...c, rank: 0, ai };
|
|
34428
34448
|
});
|
|
34429
34449
|
annotated.sort((x, y) => {
|
|
@@ -34545,16 +34565,16 @@ function tokenizeLean(source2) {
|
|
|
34545
34565
|
const out2 = [];
|
|
34546
34566
|
const reasons = [];
|
|
34547
34567
|
let i2 = 0;
|
|
34548
|
-
const
|
|
34568
|
+
const n2 = source2.length;
|
|
34549
34569
|
const blank = (ch) => ch === "\n" ? "\n" : " ";
|
|
34550
|
-
while (i2 <
|
|
34570
|
+
while (i2 < n2) {
|
|
34551
34571
|
const c = source2[i2];
|
|
34552
34572
|
const next = source2[i2 + 1];
|
|
34553
34573
|
if (c === "/" && next === "-") {
|
|
34554
34574
|
let depth = 1;
|
|
34555
34575
|
out2.push(" ");
|
|
34556
34576
|
i2 += 2;
|
|
34557
|
-
while (i2 <
|
|
34577
|
+
while (i2 < n2 && depth > 0) {
|
|
34558
34578
|
if (source2[i2] === "/" && source2[i2 + 1] === "-") {
|
|
34559
34579
|
depth++;
|
|
34560
34580
|
out2.push(" ");
|
|
@@ -34573,7 +34593,7 @@ function tokenizeLean(source2) {
|
|
|
34573
34593
|
continue;
|
|
34574
34594
|
}
|
|
34575
34595
|
if (c === "-" && next === "-") {
|
|
34576
|
-
while (i2 <
|
|
34596
|
+
while (i2 < n2 && source2[i2] !== "\n") {
|
|
34577
34597
|
out2.push(" ");
|
|
34578
34598
|
i2++;
|
|
34579
34599
|
}
|
|
@@ -34590,11 +34610,11 @@ function tokenizeLean(source2) {
|
|
|
34590
34610
|
out2.push(" ".repeat(j + 1 - i2));
|
|
34591
34611
|
i2 = j + 1;
|
|
34592
34612
|
const close = '"' + "#".repeat(hashes);
|
|
34593
|
-
while (i2 <
|
|
34613
|
+
while (i2 < n2 && source2.slice(i2, i2 + close.length) !== close) {
|
|
34594
34614
|
out2.push(blank(source2[i2]));
|
|
34595
34615
|
i2++;
|
|
34596
34616
|
}
|
|
34597
|
-
out2.push(" ".repeat(Math.min(close.length,
|
|
34617
|
+
out2.push(" ".repeat(Math.min(close.length, n2 - i2)));
|
|
34598
34618
|
i2 += close.length;
|
|
34599
34619
|
continue;
|
|
34600
34620
|
}
|
|
@@ -34603,7 +34623,7 @@ function tokenizeLean(source2) {
|
|
|
34603
34623
|
const interpolated = source2[i2 - 1] === "!" && source2[i2 - 2] === "s";
|
|
34604
34624
|
out2.push(" ");
|
|
34605
34625
|
i2++;
|
|
34606
|
-
while (i2 <
|
|
34626
|
+
while (i2 < n2 && source2[i2] !== '"') {
|
|
34607
34627
|
if (source2[i2] === "\\") {
|
|
34608
34628
|
out2.push(" ");
|
|
34609
34629
|
i2 += 2;
|
|
@@ -34612,7 +34632,7 @@ function tokenizeLean(source2) {
|
|
|
34612
34632
|
if (interpolated && source2[i2] === "{") {
|
|
34613
34633
|
let j = i2 + 1;
|
|
34614
34634
|
let expr = "";
|
|
34615
|
-
while (j <
|
|
34635
|
+
while (j < n2 && source2[j] !== "}" && source2[j] !== '"' && source2[j] !== "\n") expr += source2[j++];
|
|
34616
34636
|
if (source2[j] !== "}") reasons.push(`string interpolation must close before a quote or line end: \`{${expr.trim().slice(0, 40)}\``);
|
|
34617
34637
|
const words = expr.trim().split(/\s+/);
|
|
34618
34638
|
if (words.length === 0 || words.some((w) => !/^[A-Za-z_][A-Za-z0-9_.']*$/.test(w))) {
|
|
@@ -34753,6 +34773,8 @@ var MAX_CO_ACCESSORS = 2;
|
|
|
34753
34773
|
var MAX_HELPERS2 = 3;
|
|
34754
34774
|
var MAX_CONTEXT_LINES = 120;
|
|
34755
34775
|
var MAX_CALLERS2 = 3;
|
|
34776
|
+
var MAX_CHANGED_RANGES = 50;
|
|
34777
|
+
var MAX_HYPOTHESES2 = 3;
|
|
34756
34778
|
var MAX_CALLER_LINES = 9;
|
|
34757
34779
|
var MAX_HELPER_LINES = 80;
|
|
34758
34780
|
var MAX_CONTEXT_BYTES = 48 * 1024;
|
|
@@ -34905,6 +34927,10 @@ def P1 : Property := { id := "parts_sum_to_total", kind := .structural, desc :=
|
|
|
34905
34927
|
end Models.Split`;
|
|
34906
34928
|
var RULES2 = `Write ONE Lean 4 model of the code below that could expose a real bug in it. Work in three steps.
|
|
34907
34929
|
|
|
34930
|
+
A PUSH. When the code below marks lines \`*|\`, this is the review of a push and those are the lines it changed. Look first for a bug the CHANGE introduced: what the changed lines made possible, removed or reordered \u2014 a check dropped, or moved after the write it guarded; a write moved before another; a new path that skips a dedup, a lock or a transaction; a new early return or exception that leaves state half-written; a new caller of shared state. Model the changed lines as actions (STEP 1). Among the properties (STEP 3), list FIRST those a trace through a changed line can break; a property that holds or fails the same without the change comes after them.
|
|
34931
|
+
|
|
34932
|
+
AN ATTACKER. When the input says SECURITY, model the environment as an ATTACKER, not as nature. The attacker controls: how many requests they send, when, and in which interleaving (many copies of the same request at once included); the order of their own steps in a multi-step flow (they may skip, repeat or reorder steps); which of their own accounts they use (they may hold several); the inputs they type, and the DNS of domains they own; and when they act relative to other users, to outages and to slow dependencies. The attacker does not control secrets, other users' credentials or the server code. A property counts only when the attacker can cause its violation and gains data, rights, money or service they must not get. The promises to check: limits, balances, counters, single-use tokens and "already done" checks hold for EVERY interleaving (\`rule:once\`, \`rule:no-lost-update\`); state shared across requests never lets one user or tenant read or act with another's data or rights (\`rule:isolation\`); a removed right is never kept or regained through a refresh, a cache or a copied claim (\`rule:revocation\`); every step of a multi-step flow is bound to the same subject and value an earlier step proved (\`rule:flow-binding\`); duplicated, late or reordered events end in the state of the order they were produced in (\`rule:event-order\`); a failing dependency yields deny, never another subject's answer (\`rule:fail-closed\`); the value checked is the value used (\`rule:check-use\`).
|
|
34933
|
+
|
|
34908
34934
|
STEP 1 \u2014 Effects. The input lists the target's EFFECT SITES: awaits, calls on its dependencies, loops, try/catch, locks. Those are the only points where the real world can interleave, fail or crash. Each one that reads or writes shared state becomes an action, named after the real call and its line \u2014 "db.setBalance (L14)" \u2014 so a trace reads as a scenario someone can replay.
|
|
34909
34935
|
|
|
34910
34936
|
STEP 2 \u2014 The environment's moves that exist in reality for THIS code, and only those:
|
|
@@ -34928,7 +34954,7 @@ STEP 3 \u2014 Properties: 2 to 4, in this order of priority:
|
|
|
34928
34954
|
A counterexample must run the real function: a trace made only of environment moves (another writer, a clock) says nothing about this code. A promise about the END result (nothing lost, nothing charged twice, totals add up) is checked on states where every invocation has finished or crashed \u2014 guard the \`inv\` with the program counters, as exemplar 2's second property does; a violation that exists only while work is still pending is not a bug.
|
|
34929
34955
|
A property is about an OUTCOME someone would call a bug \u2014 money, stock or records wrong, access granted, work lost or done twice, a job stuck forever \u2014 never about the mechanism's internals (a key's format, two timestamps being distinct, a lease's exact boundary tick). A comment that says HOW the code works ("make each attempt's key unique") is not the promise; the promise is what that mechanism is for.
|
|
34930
34956
|
A comment that states a SAFE design choice ("a spent token presented again ends every session", "consumers dedupe, so publishing twice is harmless") is the design: never claim the opposite. A comment never makes an UNSAFE outcome safe: granting access on an error, losing or double-counting money, stock or records is a bug whatever the comment says ("don't block people when the permission service is flaky" describes a fail-open bug). Fail-open means an ACCESS decision: running WITHOUT an optional check when the check itself is unavailable, and saying so (a warning, a log line), is a stated degradation, not a fail-open \u2014 never claim it must fail closed.
|
|
34931
|
-
Every property says what it rests on, in \`source\`: either \`L<n>: <words copied from that line>\` \u2014 a line of the numbered source above (a comment, docstring, check, error message or name) that states the promise \u2014 or one rule: \`rule:conservation\` (money, stock or counts add up), \`rule:once\` (no double effect: where the code dedups, or where the SAME input can arrive twice \u2014 an input that carries its own identity, such as an event, message, delivery or request id, redelivered or retried \u2014 even when the code has no dedup at all; a missing dedup is the bug, not a reason to drop the property. Two calls whose input carries no such identity are two operations: reserving a seat twice or creating a record twice from two requests is what the caller asked for, not a double effect), \`rule:no-lost-update\`, \`rule:fail-closed\` (an error in an access decision never grants access; an operation that failed is never reported as done), \`rule:progress\` (nothing stuck forever). A property that neither a line nor one of these rules supports is not a promise: do not state it. A property whose \`source\` is empty, or cites words its line does not contain, sends the model back.
|
|
34957
|
+
Every property says what it rests on, in \`source\`: either \`L<n>: <words copied from that line>\` \u2014 a line of the numbered source above (a comment, docstring, check, error message or name) that states the promise \u2014 or one rule: \`rule:conservation\` (money, stock or counts add up), \`rule:once\` (no double effect: where the code dedups, or where the SAME input can arrive twice \u2014 an input that carries its own identity, such as an event, message, delivery or request id, redelivered or retried \u2014 even when the code has no dedup at all; a missing dedup is the bug, not a reason to drop the property. Two calls whose input carries no such identity are two operations: reserving a seat twice or creating a record twice from two requests is what the caller asked for, not a double effect), \`rule:no-lost-update\`, \`rule:fail-closed\` (an error in an access decision never grants access; an operation that failed is never reported as done), \`rule:progress\` (nothing stuck forever); and for an attacker (SECURITY) \`rule:isolation\`, \`rule:revocation\`, \`rule:flow-binding\`, \`rule:event-order\`, \`rule:check-use\` (AN ATTACKER says what each means). A property that neither a line nor one of these rules supports is not a promise: do not state it. A property whose \`source\` is empty, or cites words its line does not contain, sends the model back.
|
|
34932
34958
|
When the input lists where the function is called, a caller's guard bounds its inputs: never build a counterexample from an input no caller can pass (an empty list a caller refuses).
|
|
34933
34959
|
Property ids name the promise in snake_case (refund_total_within_capture) \u2014 never P1. \`desc\` states the promise in the code's own terms and names the move the trace needs ("two concurrent calls \u2026", "after the charge succeeded and the call timed out \u2026").
|
|
34934
34960
|
A PURE computation (no effect sites) is checked with \`Verity.checkData\` on small concrete inputs, including the edge cases (exemplar 3).
|
|
@@ -34998,19 +35024,19 @@ var PURE_METHODS2 = /* @__PURE__ */ new Set([
|
|
|
34998
35024
|
"test",
|
|
34999
35025
|
"match"
|
|
35000
35026
|
]);
|
|
35001
|
-
function callsOn(
|
|
35027
|
+
function callsOn(text2, name2) {
|
|
35002
35028
|
const needle = `${name2}.`;
|
|
35003
|
-
for (let i2 =
|
|
35004
|
-
if (i2 > 0 && IDENT_CHAR2.test(
|
|
35005
|
-
const call = CALL_AFTER_DOT.exec(
|
|
35029
|
+
for (let i2 = text2.indexOf(needle); i2 >= 0; i2 = text2.indexOf(needle, i2 + 1)) {
|
|
35030
|
+
if (i2 > 0 && IDENT_CHAR2.test(text2[i2 - 1])) continue;
|
|
35031
|
+
const call = CALL_AFTER_DOT.exec(text2.slice(i2 + needle.length));
|
|
35006
35032
|
if (call && !PURE_METHODS2.has(call[1])) return true;
|
|
35007
35033
|
}
|
|
35008
35034
|
return false;
|
|
35009
35035
|
}
|
|
35010
|
-
function callsDirect(
|
|
35036
|
+
function callsDirect(text2, name2) {
|
|
35011
35037
|
const needle = `${name2}(`;
|
|
35012
|
-
for (let i2 =
|
|
35013
|
-
if (i2 > 0 && IDENT_CHAR2.test(
|
|
35038
|
+
for (let i2 = text2.indexOf(needle); i2 >= 0; i2 = text2.indexOf(needle, i2 + 1)) {
|
|
35039
|
+
if (i2 > 0 && IDENT_CHAR2.test(text2[i2 - 1])) continue;
|
|
35014
35040
|
return true;
|
|
35015
35041
|
}
|
|
35016
35042
|
return false;
|
|
@@ -35042,17 +35068,44 @@ function effectSites(numbered2) {
|
|
|
35042
35068
|
}
|
|
35043
35069
|
return out2;
|
|
35044
35070
|
}
|
|
35071
|
+
function starChanged(numbered2, changed) {
|
|
35072
|
+
const isChanged = (n2) => !!changed?.some((r) => n2 >= r.from && n2 <= r.to);
|
|
35073
|
+
const starred = [];
|
|
35074
|
+
let total = 0;
|
|
35075
|
+
const text2 = numbered2.split("\n").map((raw) => {
|
|
35076
|
+
const m = NUMBERED_LINE.exec(raw);
|
|
35077
|
+
if (!m) return raw;
|
|
35078
|
+
total++;
|
|
35079
|
+
const n2 = Number(m[1]);
|
|
35080
|
+
if (!isChanged(n2)) return raw;
|
|
35081
|
+
starred.push(n2);
|
|
35082
|
+
return raw.replace("|", "*|");
|
|
35083
|
+
}).join("\n");
|
|
35084
|
+
const runs = [];
|
|
35085
|
+
for (let i2 = 0; i2 < starred.length; i2++) {
|
|
35086
|
+
let j = i2;
|
|
35087
|
+
while (j + 1 < starred.length && starred[j + 1] === starred[j] + 1) j++;
|
|
35088
|
+
runs.push(i2 === j ? `${starred[i2]}` : `${starred[i2]}\u2013${starred[j]}`);
|
|
35089
|
+
i2 = j;
|
|
35090
|
+
}
|
|
35091
|
+
return { text: text2, ranges: runs.join(", "), count: starred.length, total };
|
|
35092
|
+
}
|
|
35045
35093
|
function renderGenerateInput(t, previous) {
|
|
35046
35094
|
const parts2 = [];
|
|
35047
35095
|
parts2.push(`# Target: ${t.file} \u2014 \`${t.symbol}\`${t.lines ? ` (lines ${t.lines.from}\u2013${t.lines.to})` : ""}`);
|
|
35048
35096
|
parts2.push(`Header values: file := "${t.file}", symbol := "${t.symbol}", sha256 := "${t.sha256}", lines := "${t.lines ? `${t.lines.from}-${t.lines.to}` : ""}"`);
|
|
35049
35097
|
if (t.reasons.length) parts2.push(`Why it was selected: ${t.reasons.join(" \xB7 ")}`);
|
|
35050
35098
|
if (t.properties.length) parts2.push(`Suggested properties: ${t.properties.join(", ")}`);
|
|
35099
|
+
if (t.lens === "security") parts2.push("SECURITY: an attacker outside the trust boundary can drive this code. Follow AN ATTACKER.");
|
|
35100
|
+
if (t.hypotheses?.length) parts2.push(`Hypotheses from the selector (questions to try, not verdicts):
|
|
35101
|
+
${t.hypotheses.slice(0, MAX_HYPOTHESES2).map((h) => ` - ${h}`).join("\n")}`);
|
|
35051
35102
|
const numbered2 = t.numbered.slice(0, MAX_NUMBERED_BYTES);
|
|
35052
35103
|
const sites = effectSites(numbered2);
|
|
35104
|
+
const push = starChanged(numbered2, t.changed);
|
|
35105
|
+
if (push.count > 0) parts2.push(`A push: it changed ${push.count} of these ${push.total} lines (${push.ranges}), marked \`*|\` below. Look first for a bug the change introduced.`);
|
|
35053
35106
|
parts2.push("", sites.length ? `Effect sites (STEP 1 \u2014 where the real world can interleave, fail or crash):
|
|
35054
35107
|
${sites.map((s) => ` ${s}`).join("\n")}` : "Effect sites: none \u2014 a pure computation (STEP 3: Verity.checkData on concrete inputs).");
|
|
35055
|
-
parts2.push("", "```", numbered2, "```");
|
|
35108
|
+
parts2.push("", "```", push.count > 0 ? push.text : numbered2, "```");
|
|
35056
35109
|
if (t.effects?.length) {
|
|
35057
35110
|
parts2.push("", `State this function touches (from the parser; "via" names the helper that does it):
|
|
35058
35111
|
${t.effects.slice(0, MAX_CONTEXT_EFFECTS).map((e) => ` ${e}`).join("\n")}`);
|
|
@@ -35166,11 +35219,11 @@ async function generateModel(target, opts) {
|
|
|
35166
35219
|
return { ok: false, error: name2 === "TimeoutError" || name2 === "AbortError" ? "timed out" : err2.message };
|
|
35167
35220
|
}
|
|
35168
35221
|
const usage = data.usage ? { inputTokens: Number(data.usage.input_tokens ?? 0), outputTokens: Number(data.usage.output_tokens ?? 0) } : null;
|
|
35169
|
-
const
|
|
35170
|
-
if (!
|
|
35222
|
+
const text2 = (data.output ?? []).flatMap((o) => o.content ?? []).find((c) => c.type === "output_text")?.text;
|
|
35223
|
+
if (!text2) return { ok: false, error: "no output_text in response", usage };
|
|
35171
35224
|
let parsed;
|
|
35172
35225
|
try {
|
|
35173
|
-
parsed = JSON.parse(
|
|
35226
|
+
parsed = JSON.parse(text2);
|
|
35174
35227
|
} catch {
|
|
35175
35228
|
return { ok: false, error: "answer was not JSON", usage };
|
|
35176
35229
|
}
|
|
@@ -35180,8 +35233,8 @@ async function generateModel(target, opts) {
|
|
|
35180
35233
|
// src/lib/prove/replay.ts
|
|
35181
35234
|
var MAX_SOURCE_BYTES = 96 * 1024;
|
|
35182
35235
|
var MAX_MODEL_BYTES = 32 * 1024;
|
|
35183
|
-
function numberLines(
|
|
35184
|
-
return
|
|
35236
|
+
function numberLines(text2, from = 1) {
|
|
35237
|
+
return text2.split("\n").map((l, i2) => `${String(i2 + from).padStart(5)}| ${l}`).join("\n");
|
|
35185
35238
|
}
|
|
35186
35239
|
var PY_DECL = /^\s*(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(/;
|
|
35187
35240
|
var TS_DECLS = [
|
|
@@ -35255,9 +35308,9 @@ function extractSymbolBody(source2, symbol, file, range) {
|
|
|
35255
35308
|
}
|
|
35256
35309
|
return null;
|
|
35257
35310
|
}
|
|
35258
|
-
function significantLines(
|
|
35311
|
+
function significantLines(text2) {
|
|
35259
35312
|
const out2 = [];
|
|
35260
|
-
for (const raw of
|
|
35313
|
+
for (const raw of text2.split("\n")) {
|
|
35261
35314
|
const l = raw.trim();
|
|
35262
35315
|
if (l.length < 12) continue;
|
|
35263
35316
|
if (/^(\/\/|\/\*|\*|#)/.test(l)) continue;
|
|
@@ -35282,14 +35335,14 @@ function isTrackedInRoot(root, file) {
|
|
|
35282
35335
|
function buildReplayBrief(root, report, property, modelSource, readSource) {
|
|
35283
35336
|
const sources = (report.header?.abstracts ?? []).map((a) => {
|
|
35284
35337
|
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" };
|
|
35285
|
-
const
|
|
35338
|
+
const text2 = read2.ok ? read2.content : "";
|
|
35286
35339
|
return {
|
|
35287
35340
|
file: a.file,
|
|
35288
35341
|
symbol: a.symbol,
|
|
35289
|
-
numbered:
|
|
35290
|
-
symbolBody:
|
|
35342
|
+
numbered: text2 ? numberLines(text2) : `(could not read ${a.file}: ${read2.ok ? "" : read2.reason})`,
|
|
35343
|
+
symbolBody: text2 ? extractSymbolBody(text2, a.symbol, a.file, a.lines) : null,
|
|
35291
35344
|
lines: a.lines,
|
|
35292
|
-
content:
|
|
35345
|
+
content: text2
|
|
35293
35346
|
};
|
|
35294
35347
|
});
|
|
35295
35348
|
return { model: report.model, property, modelSource: modelSource.slice(0, MAX_MODEL_BYTES), sources };
|
|
@@ -35371,7 +35424,7 @@ function parseReplayOutput(output) {
|
|
|
35371
35424
|
let executedCalls = 0;
|
|
35372
35425
|
const shellTexts = [];
|
|
35373
35426
|
const outputTexts = [];
|
|
35374
|
-
let
|
|
35427
|
+
let text2 = null;
|
|
35375
35428
|
for (const item of output) {
|
|
35376
35429
|
if (item.type === "shell_call") {
|
|
35377
35430
|
shellCalls++;
|
|
@@ -35387,13 +35440,13 @@ function parseReplayOutput(output) {
|
|
|
35387
35440
|
}
|
|
35388
35441
|
} else if (item.type === "message" && Array.isArray(item.content)) {
|
|
35389
35442
|
const t = item.content.find((c) => c.type === "output_text")?.text;
|
|
35390
|
-
if (typeof t === "string")
|
|
35443
|
+
if (typeof t === "string") text2 = t;
|
|
35391
35444
|
}
|
|
35392
35445
|
}
|
|
35393
35446
|
let claim = null;
|
|
35394
|
-
if (
|
|
35447
|
+
if (text2) {
|
|
35395
35448
|
try {
|
|
35396
|
-
const o = JSON.parse(
|
|
35449
|
+
const o = JSON.parse(text2);
|
|
35397
35450
|
const verdict = o.verdict;
|
|
35398
35451
|
if (verdict === "reproduced" || verdict === "diverged" || verdict === "unreplayable") {
|
|
35399
35452
|
claim = {
|
|
@@ -35614,14 +35667,14 @@ async function runReplayInContainer(brief, opts) {
|
|
|
35614
35667
|
}
|
|
35615
35668
|
}
|
|
35616
35669
|
}
|
|
35617
|
-
async function runReplayViaServer(brief,
|
|
35670
|
+
async function runReplayViaServer(brief, auth3, budgetMs = 24e4) {
|
|
35618
35671
|
const started = Date.now();
|
|
35619
35672
|
const budget = Math.max(2e4, Math.round(budgetMs));
|
|
35620
35673
|
const res = await apiRequest({
|
|
35621
35674
|
method: "POST",
|
|
35622
35675
|
path: "/prove/replay",
|
|
35623
|
-
serviceUrl:
|
|
35624
|
-
token:
|
|
35676
|
+
serviceUrl: auth3.serviceUrl,
|
|
35677
|
+
token: auth3.token,
|
|
35625
35678
|
body: {
|
|
35626
35679
|
model: brief.model,
|
|
35627
35680
|
model_source: brief.modelSource,
|
|
@@ -36271,14 +36324,14 @@ function parseProperty(obj) {
|
|
|
36271
36324
|
if (!model || !id || !kind2 || !result || source2 === null || desc === null) return null;
|
|
36272
36325
|
const p = { model, id, kind: kind2, source: source2, desc, result };
|
|
36273
36326
|
if (obj.bound !== void 0) {
|
|
36274
|
-
const
|
|
36275
|
-
if (
|
|
36276
|
-
p.bound =
|
|
36327
|
+
const n2 = nat(obj.bound);
|
|
36328
|
+
if (n2 === null) return null;
|
|
36329
|
+
p.bound = n2;
|
|
36277
36330
|
}
|
|
36278
36331
|
if (obj.states !== void 0) {
|
|
36279
|
-
const
|
|
36280
|
-
if (
|
|
36281
|
-
p.states =
|
|
36332
|
+
const n2 = nat(obj.states);
|
|
36333
|
+
if (n2 === null) return null;
|
|
36334
|
+
p.states = n2;
|
|
36282
36335
|
}
|
|
36283
36336
|
if (obj.trace !== void 0) {
|
|
36284
36337
|
const t = strArr(obj.trace, LIMITS.traceItems, LIMITS.traceItem);
|
|
@@ -36577,8 +36630,8 @@ function listModelFiles(root) {
|
|
|
36577
36630
|
if (!(0, import_node_fs61.existsSync)(modelsAbs)) return [];
|
|
36578
36631
|
return (0, import_node_fs61.readdirSync)(modelsAbs).filter((f) => isModelInRoot(modelsAbs, f)).sort().map((f) => (0, import_node_path48.join)(modelsAbs, f));
|
|
36579
36632
|
}
|
|
36580
|
-
function trimDiagnostics(
|
|
36581
|
-
return
|
|
36633
|
+
function trimDiagnostics(text2) {
|
|
36634
|
+
return text2.split("\n").filter((l) => !l.startsWith("trace:")).join("\n").trim().slice(0, 4e3);
|
|
36582
36635
|
}
|
|
36583
36636
|
function checkModel(tc, root, modelFile, opts = {}) {
|
|
36584
36637
|
const proofsAbs = (0, import_node_path48.join)(root, PROOFS_DIR);
|
|
@@ -36646,33 +36699,70 @@ function writeResult(root, report) {
|
|
|
36646
36699
|
function isCrashTrace(trace) {
|
|
36647
36700
|
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));
|
|
36648
36701
|
}
|
|
36702
|
+
function formalDisposition(f) {
|
|
36703
|
+
if (f.verdict !== "reproduced" || f.waived) return "none";
|
|
36704
|
+
const c = f.check;
|
|
36705
|
+
if (!c || c.outcome !== "answered") return "block";
|
|
36706
|
+
switch (c.verdict) {
|
|
36707
|
+
case "REAL":
|
|
36708
|
+
return c.introduced === "no" ? "report" : "block";
|
|
36709
|
+
case "REAL-LOW":
|
|
36710
|
+
return "report";
|
|
36711
|
+
case "PREVENTED":
|
|
36712
|
+
case "ARTIFACT":
|
|
36713
|
+
return "checked";
|
|
36714
|
+
default:
|
|
36715
|
+
return "block";
|
|
36716
|
+
}
|
|
36717
|
+
}
|
|
36718
|
+
var CAUTION = { block: 3, report: 2, checked: 1, none: 0 };
|
|
36719
|
+
function cautiousCheck(f, checks) {
|
|
36720
|
+
if (checks.length === 0) return void 0;
|
|
36721
|
+
let chosen = checks[0];
|
|
36722
|
+
for (const c of checks.slice(1)) if (CAUTION[formalDisposition({ ...f, check: c })] > CAUTION[formalDisposition({ ...f, check: chosen })]) chosen = c;
|
|
36723
|
+
return { ...chosen, votes: checks.map((c) => c.outcome === "answered" && c.verdict ? c.verdict : c.outcome), costUsd: checks.reduce((n2, c) => n2 + c.costUsd, 0), unpriced: checks.reduce((n2, c) => n2 + c.unpriced, 0) };
|
|
36724
|
+
}
|
|
36725
|
+
function checkLine(f) {
|
|
36726
|
+
const c = f.check;
|
|
36727
|
+
if (!c || c.outcome !== "answered" || !c.verdict) return "";
|
|
36728
|
+
const why = c.verdict === "PREVENTED" ? c.preventedBy || c.reason : c.reason;
|
|
36729
|
+
const from = c.trigger ? ` Reached from: ${c.trigger}.` : "";
|
|
36730
|
+
const pre = c.introduced === "no" ? " Already possible before this change." : "";
|
|
36731
|
+
const votes = c.votes && c.votes.length > 1 ? ` (${c.votes.length} checks: ${c.votes.join(", ")})` : "";
|
|
36732
|
+
return `Checked: ${c.verdict}${votes}.${from}${pre} ${why ?? ""}`.trim();
|
|
36733
|
+
}
|
|
36649
36734
|
function mergeFormalFindings(response, outcome, pushedFiles) {
|
|
36650
|
-
if (!outcome) return { blocking: 0 };
|
|
36735
|
+
if (!outcome) return { blocking: 0, reported: 0 };
|
|
36651
36736
|
const norm3 = (p) => p.replace(/\\/g, "/");
|
|
36652
36737
|
const pushed = new Set(pushedFiles.map(norm3));
|
|
36653
|
-
const
|
|
36654
|
-
|
|
36738
|
+
const onPush = outcome.findings.filter((f) => pushed.has(norm3(f.file)));
|
|
36739
|
+
const blocking = onPush.filter((f) => formalDisposition(f) === "block");
|
|
36740
|
+
const reported = onPush.filter((f) => formalDisposition(f) === "report");
|
|
36741
|
+
if (blocking.length === 0 && reported.length === 0) return { blocking: 0, reported: 0 };
|
|
36655
36742
|
const existing = Array.isArray(response.findings) ? response.findings : [];
|
|
36656
|
-
|
|
36657
|
-
|
|
36658
|
-
|
|
36743
|
+
const asFinding = (f, blocks) => {
|
|
36744
|
+
const checked = checkLine(f);
|
|
36745
|
+
return {
|
|
36659
36746
|
pattern_id: "formal-counterexample",
|
|
36660
|
-
severity: "high",
|
|
36661
|
-
|
|
36747
|
+
severity: blocks ? "high" : "medium",
|
|
36748
|
+
// A bug this change did not introduce is filed the way the gate files everything it will not block on.
|
|
36749
|
+
scope: f.check?.introduced === "no" && !blocks ? "pre-existing" : "change",
|
|
36662
36750
|
file: f.file,
|
|
36663
36751
|
line: outcome.target?.lines?.from ?? null,
|
|
36664
36752
|
// Worded as the VIOLATION: the property text is what should hold, and
|
|
36665
36753
|
// as a title it read backwards (e2e, 2026-09-26). A trace that needs a
|
|
36666
36754
|
// crash between two writes is labelled: reproducing it means injecting
|
|
36667
36755
|
// the crash, so it is a crash-consistency finding, not a race.
|
|
36668
|
-
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`,
|
|
36669
|
-
description: terminalText(f.reason ?? "", 2e3),
|
|
36756
|
+
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}` : ""}`,
|
|
36757
|
+
description: terminalText([f.reason ?? "", checked].filter(Boolean).join(" "), 2e3),
|
|
36670
36758
|
fix: { description: `Trace: ${terminalText(f.trace.join(" \u2192 ") || "(initial state)", 2e3)}. Replay: ${terminalText(f.reason ?? "reproduced in the container", 2e3)}` },
|
|
36671
36759
|
source: "formal"
|
|
36672
|
-
}
|
|
36673
|
-
|
|
36674
|
-
|
|
36675
|
-
|
|
36760
|
+
};
|
|
36761
|
+
};
|
|
36762
|
+
response.findings = [...existing, ...blocking.map((f) => asFinding(f, true)), ...reported.map((f) => asFinding(f, false))];
|
|
36763
|
+
if (blocking.length > 0) response.gate_decision = "FAIL";
|
|
36764
|
+
else if (response.gate_decision === "PASS") response.gate_decision = "WARN";
|
|
36765
|
+
return { blocking: blocking.length, reported: reported.length };
|
|
36676
36766
|
}
|
|
36677
36767
|
|
|
36678
36768
|
// src/lib/prove/scalpel.ts
|
|
@@ -36836,6 +36926,11 @@ function isEligible(s, largePush) {
|
|
|
36836
36926
|
if (critical) return { ok: true, why: "domain-critical" };
|
|
36837
36927
|
return { ok: false, why: "no effects, no risky shape, not domain-critical" };
|
|
36838
36928
|
}
|
|
36929
|
+
function changedWithin(changed, lines) {
|
|
36930
|
+
if (!changed?.length) return [];
|
|
36931
|
+
const inside2 = lines ? changed.filter((r) => r.from <= lines.to && lines.from <= r.to).map((r) => ({ from: Math.max(r.from, lines.from), to: Math.min(r.to, lines.to) })) : changed;
|
|
36932
|
+
return inside2.slice(0, MAX_CHANGED_RANGES);
|
|
36933
|
+
}
|
|
36839
36934
|
function intersects(a, ranges) {
|
|
36840
36935
|
return ranges.some((b) => a.from <= b.to && b.from <= a.to);
|
|
36841
36936
|
}
|
|
@@ -36887,14 +36982,14 @@ function readPersistedFindings(root) {
|
|
|
36887
36982
|
function waiveFormalFindings(root, file, reason) {
|
|
36888
36983
|
const all = readPersistedFindings(root);
|
|
36889
36984
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
36890
|
-
let
|
|
36985
|
+
let n2 = 0;
|
|
36891
36986
|
const next = all.map((f) => {
|
|
36892
36987
|
if (f.file !== file || f.waived) return f;
|
|
36893
|
-
|
|
36988
|
+
n2++;
|
|
36894
36989
|
return { ...f, waived: { reason: reason.slice(0, 500), at } };
|
|
36895
36990
|
});
|
|
36896
|
-
if (
|
|
36897
|
-
return
|
|
36991
|
+
if (n2 > 0) writePersistedFindings(root, next);
|
|
36992
|
+
return n2;
|
|
36898
36993
|
}
|
|
36899
36994
|
function writePersistedFindings(root, findings) {
|
|
36900
36995
|
if (!isLocalState(root, FINDINGS_FILE)) return;
|
|
@@ -36909,6 +37004,8 @@ function bumpLedger(root) {
|
|
|
36909
37004
|
}
|
|
36910
37005
|
var REPLAY_RESERVE_MS = 45e3;
|
|
36911
37006
|
var MAX_REPLAYS = 3;
|
|
37007
|
+
var MAX_CHECKS = 2;
|
|
37008
|
+
var CHECK_VOTES = 2;
|
|
36912
37009
|
function isNetworkError(message) {
|
|
36913
37010
|
return /Network error|fetch failed|ETIMEDOUT|ECONNRESET|ECONNREFUSED|EAI_AGAIN|socket hang up/i.test(message);
|
|
36914
37011
|
}
|
|
@@ -36991,7 +37088,9 @@ async function runFormalPhase(input) {
|
|
|
36991
37088
|
symbol: f.symbol,
|
|
36992
37089
|
verdict: "reproduced",
|
|
36993
37090
|
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)`,
|
|
36994
|
-
...f.waived ? { waived: true } : {}
|
|
37091
|
+
...f.waived ? { waived: true } : {},
|
|
37092
|
+
// Same bytes, same answer: the check is not paid for twice.
|
|
37093
|
+
...f.check ? { check: { outcome: "answered", rounds: 0, costUsd: 0, unpriced: 0, durationMs: 0, ...f.check } } : {}
|
|
36995
37094
|
});
|
|
36996
37095
|
}
|
|
36997
37096
|
}
|
|
@@ -37013,13 +37112,13 @@ async function runFormalPhase(input) {
|
|
|
37013
37112
|
if (signals.length === 0) return done({ status: "skipped", skip: "no-source-files" });
|
|
37014
37113
|
const largePush = signals.length >= LARGE_PUSH_FILES || files.length >= LARGE_PUSH_FILES * 2;
|
|
37015
37114
|
const mapEligible = (file) => {
|
|
37016
|
-
const
|
|
37017
|
-
if (!deps.codeMap || largePush || !
|
|
37115
|
+
const changed2 = input.changedLines?.get(file);
|
|
37116
|
+
if (!deps.codeMap || largePush || !changed2?.length) return false;
|
|
37018
37117
|
const read2 = readSrc(file, 96 * 1024);
|
|
37019
37118
|
if (!read2.ok) return false;
|
|
37020
37119
|
const outline = deps.codeMap.outline(file, read2.content);
|
|
37021
37120
|
if (outline.source !== "tree-sitter") return false;
|
|
37022
|
-
return outline.value.some((f) =>
|
|
37121
|
+
return outline.value.some((f) => changed2.some((r) => f.start.line <= r.to && r.from <= f.end.line) && (() => {
|
|
37023
37122
|
const a = deps.codeMap.access(file, read2.content, f);
|
|
37024
37123
|
return a.source === "tree-sitter" && a.value.effects.length >= 2;
|
|
37025
37124
|
})());
|
|
@@ -37079,8 +37178,8 @@ async function runFormalPhase(input) {
|
|
|
37079
37178
|
}
|
|
37080
37179
|
if (d.resolved && d.resolved !== c.ai.symbol) c.ai.symbol = d.resolved;
|
|
37081
37180
|
if (input.changedLines) {
|
|
37082
|
-
const
|
|
37083
|
-
if (
|
|
37181
|
+
const changed2 = input.changedLines.get(c.file) ?? [];
|
|
37182
|
+
if (changed2.length === 0) {
|
|
37084
37183
|
note("symbol-not-in-push", `${c.file}: no changed lines in this push`);
|
|
37085
37184
|
continue;
|
|
37086
37185
|
}
|
|
@@ -37088,7 +37187,7 @@ async function runFormalPhase(input) {
|
|
|
37088
37187
|
note("symbol-not-in-push", `${c.ai.symbol}: body not found, cannot tell whether the push touched it`);
|
|
37089
37188
|
continue;
|
|
37090
37189
|
}
|
|
37091
|
-
if (!intersects(d.lines,
|
|
37190
|
+
if (!intersects(d.lines, changed2)) {
|
|
37092
37191
|
note("symbol-not-in-push", `${c.ai.symbol} (lines ${d.lines.from}\u2013${d.lines.to}) unchanged by this push`);
|
|
37093
37192
|
continue;
|
|
37094
37193
|
}
|
|
@@ -37146,7 +37245,8 @@ async function runFormalPhase(input) {
|
|
|
37146
37245
|
if (!REPLAYABLE.test(top.file)) return done({ status: "skipped", skip: "replay-unsupported", detail: `${top.file}: replay supports TS/JS and Python`, target });
|
|
37147
37246
|
if (timeLeft() < GENERATE_RESERVE_MS) return done({ status: "skipped", skip: "not-enough-time", detail: `${Math.round(timeLeft() / 1e3)} s left before generation`, target });
|
|
37148
37247
|
bumpLedger(root);
|
|
37149
|
-
const
|
|
37248
|
+
const changed = changedWithin(input.changedLines?.get(top.file), lines);
|
|
37249
|
+
const genTarget = { file: top.file, symbol: top.ai.symbol, lines, sha256: sha2562, numbered: numbered2, reasons: target.reasons, properties: top.ai.properties, ...chosen.context?.fields ?? {}, extentSource: chosen.extent, ...changed.length ? { changed } : {}, ...top.ai.lens === "security" ? { lens: "security" } : {}, ...top.ai.hypotheses?.length ? { hypotheses: top.ai.hypotheses } : {} };
|
|
37150
37250
|
const headerFiles = /* @__PURE__ */ new Set([top.file, ...chosen.context?.files ?? []]);
|
|
37151
37251
|
let previous;
|
|
37152
37252
|
let report = null;
|
|
@@ -37267,13 +37367,40 @@ async function runFormalPhase(input) {
|
|
|
37267
37367
|
const verdict = r.verdict === "reproduced" ? "reproduced" : r.verdict === "diverged" ? "diverged" : r.verdict === "unreplayable" ? "model-only" : "unverified";
|
|
37268
37368
|
findings.push({ ...baseOf(p), verdict, reason: r.reason || r.downgrade || void 0 });
|
|
37269
37369
|
}
|
|
37370
|
+
const toCheck = deps.verify && !cancelled() ? findings.filter((f) => f.verdict === "reproduced").slice(0, MAX_CHECKS) : [];
|
|
37371
|
+
if (toCheck.length > 0) {
|
|
37372
|
+
progress.step = "verify";
|
|
37373
|
+
const share = Math.max(0, costCap - usage.costUsd) / (toCheck.length * CHECK_VOTES);
|
|
37374
|
+
const failed = (error) => ({ outcome: "failed", verdict: null, introduced: "unknown", rounds: 0, costUsd: 0, unpriced: 0, durationMs: 0, error });
|
|
37375
|
+
await Promise.all(toCheck.map(async (f) => {
|
|
37376
|
+
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)))));
|
|
37377
|
+
for (const c of checks) {
|
|
37378
|
+
if (c.costUsd > 0) spend({ costUsd: c.costUsd });
|
|
37379
|
+
for (let i2 = 0; i2 < c.unpriced; i2++) usage.unpriced++;
|
|
37380
|
+
}
|
|
37381
|
+
if (!cancelled()) f.check = cautiousCheck(f, checks);
|
|
37382
|
+
}));
|
|
37383
|
+
}
|
|
37270
37384
|
const reproduced = findings.filter((f) => f.verdict === "reproduced");
|
|
37271
37385
|
if (reproduced.length > 0 && !cancelled()) {
|
|
37272
37386
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
37273
37387
|
const others = readPersistedFindings(root).filter((f) => f.file !== top.file);
|
|
37274
37388
|
writePersistedFindings(root, [
|
|
37275
37389
|
...others,
|
|
37276
|
-
...reproduced.map((f) => ({
|
|
37390
|
+
...reproduced.map((f) => ({
|
|
37391
|
+
file: f.file,
|
|
37392
|
+
symbol: f.symbol,
|
|
37393
|
+
sha256: sha2562,
|
|
37394
|
+
property: f.property,
|
|
37395
|
+
desc: f.desc,
|
|
37396
|
+
kind: f.kind,
|
|
37397
|
+
trace: f.trace,
|
|
37398
|
+
model: modelName,
|
|
37399
|
+
reason: f.reason,
|
|
37400
|
+
...lines ? { lines } : {},
|
|
37401
|
+
at: now,
|
|
37402
|
+
...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 } : {} } } : {}
|
|
37403
|
+
}))
|
|
37277
37404
|
]);
|
|
37278
37405
|
}
|
|
37279
37406
|
const clean2 = findings.every((f) => f.verdict === "diverged");
|
|
@@ -37317,9 +37444,9 @@ function describeTarget(content, symbol, file, range, opts = {}) {
|
|
|
37317
37444
|
}
|
|
37318
37445
|
const body2 = extractSymbolBody(content, symbol, file);
|
|
37319
37446
|
if (!body2) return { numbered: numberLines(content.slice(0, 24 * 1024)), extent };
|
|
37320
|
-
const
|
|
37321
|
-
const from = all.findIndex((_, i2) => all.slice(i2, i2 +
|
|
37322
|
-
return { lines: from > 0 ? { from, to: from +
|
|
37447
|
+
const n2 = body2.split("\n").length;
|
|
37448
|
+
const from = all.findIndex((_, i2) => all.slice(i2, i2 + n2).join("\n") === body2) + 1;
|
|
37449
|
+
return { lines: from > 0 ? { from, to: from + n2 - 1 } : void 0, numbered: numberLines(body2, from > 0 ? from : 1), extent };
|
|
37323
37450
|
}
|
|
37324
37451
|
async function generateAndCheck(root, req, opts) {
|
|
37325
37452
|
const readSrc = opts.deps.readSource ?? workingTreeReader(root);
|
|
@@ -37333,7 +37460,7 @@ async function generateAndCheck(root, req, opts) {
|
|
|
37333
37460
|
if (outline?.source === "tree-sitter") {
|
|
37334
37461
|
const names2 = [...new Set(outline.value.filter((f) => f.name && f.kind !== "lambda").map((f) => f.qualified))];
|
|
37335
37462
|
const last = (req.symbol.split(/[.#:]/).pop() ?? req.symbol).toLowerCase();
|
|
37336
|
-
const close = names2.filter((
|
|
37463
|
+
const close = names2.filter((n2) => n2.toLowerCase().includes(last));
|
|
37337
37464
|
const shown = (close.length > 0 ? close : names2).slice(0, 12);
|
|
37338
37465
|
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 };
|
|
37339
37466
|
}
|
|
@@ -37402,9 +37529,9 @@ async function generateAndCheck(root, req, opts) {
|
|
|
37402
37529
|
function skippedOutcome(skip, detail) {
|
|
37403
37530
|
return { status: "skipped", skip, ...detail ? { detail } : {}, findings: [], usage: { inputTokens: 0, outputTokens: 0, costUsd: 0, unpriced: 0 }, durationMs: 0 };
|
|
37404
37531
|
}
|
|
37405
|
-
async function prepareFormalPhase(root, env = process.env,
|
|
37532
|
+
async function prepareFormalPhase(root, env = process.env, auth3, readSource, codeSource) {
|
|
37406
37533
|
const direct = env.VERITY_PROVE_DIRECT === "1" && !!env.OPENAI_API_KEY;
|
|
37407
|
-
if (!
|
|
37534
|
+
if (!auth3 && !direct) return { ok: false, skip: "not-logged-in" };
|
|
37408
37535
|
const apiKey = direct ? env.OPENAI_API_KEY : void 0;
|
|
37409
37536
|
const toolchain = findToolchain(env);
|
|
37410
37537
|
if (!toolchain) return { ok: false, skip: "no-toolchain" };
|
|
@@ -37418,7 +37545,7 @@ async function prepareFormalPhase(root, env = process.env, auth2, readSource, co
|
|
|
37418
37545
|
const build = await buildLibraryAsync(toolchain, root, 9e4);
|
|
37419
37546
|
if (!build.ok) return { ok: false, skip: "library-build-failed", detail: build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).join(" ").slice(0, 200) };
|
|
37420
37547
|
const code = await loadCodeContext(root, env, codeSource);
|
|
37421
|
-
return { ok: true, deps: { ...defaultDeps({ auth:
|
|
37548
|
+
return { ok: true, deps: { ...defaultDeps({ auth: auth3, apiKey, env, toolchain, readSource, ...code }), codeSource: code.codeSource } };
|
|
37422
37549
|
}
|
|
37423
37550
|
async function loadCodeContext(root, env = process.env, codeSource) {
|
|
37424
37551
|
const loaded = await loadCodeMap(env);
|
|
@@ -37493,7 +37620,9 @@ function describeFormalOutcome(o) {
|
|
|
37493
37620
|
if (o.status === "skipped") return `formal: skipped (${o.skip}${o.detail ? `: ${o.detail}` : ""})`;
|
|
37494
37621
|
const parts2 = o.properties?.map((p) => {
|
|
37495
37622
|
const f = o.findings.find((x) => x.property === p.id);
|
|
37496
|
-
const
|
|
37623
|
+
const votes = f?.check?.votes && f.check.votes.length > 1 ? ` [${f.check.votes.join(", ")}]` : "";
|
|
37624
|
+
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}` : "";
|
|
37625
|
+
const tag = p.result === "counterexample" ? f ? f.verdict.toUpperCase() + (f.waived ? " (waived)" : "") + checked : "counterexample" : p.result;
|
|
37497
37626
|
return `${p.id} ${tag}`;
|
|
37498
37627
|
}) ?? [];
|
|
37499
37628
|
const cost = o.usage.costUsd > 0 ? ` \xB7 $${o.usage.costUsd.toFixed(2)}` : "";
|
|
@@ -37501,6 +37630,105 @@ function describeFormalOutcome(o) {
|
|
|
37501
37630
|
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}`;
|
|
37502
37631
|
}
|
|
37503
37632
|
|
|
37633
|
+
// src/lib/prove/verify.ts
|
|
37634
|
+
var MIN_VERIFY_TURN_MS = 15e3;
|
|
37635
|
+
var MIN_VERIFY_START_MS = 45e3;
|
|
37636
|
+
var VERIFY_TURN_HOLD_USD = 0.1;
|
|
37637
|
+
var MAX_TURNS2 = 14;
|
|
37638
|
+
var VERDICTS = ["REAL", "REAL-LOW", "PREVENTED", "ARTIFACT", "UNSURE"];
|
|
37639
|
+
var verdictOf = (v) => typeof v === "string" && VERDICTS.includes(v) ? v : null;
|
|
37640
|
+
var introducedOf = (v) => v === "yes" || v === "no" ? v : "unknown";
|
|
37641
|
+
var text = (v, n2) => typeof v === "string" ? v.slice(0, n2) : "";
|
|
37642
|
+
function verifyPost(auth3) {
|
|
37643
|
+
return async (body2, timeoutMs) => {
|
|
37644
|
+
const res = await apiRequest({
|
|
37645
|
+
method: "POST",
|
|
37646
|
+
path: "/prove/verify",
|
|
37647
|
+
serviceUrl: auth3.serviceUrl,
|
|
37648
|
+
token: auth3.token,
|
|
37649
|
+
// Streamed with a heartbeat, like generate and replay (decision 53).
|
|
37650
|
+
extraHeaders: { "X-Verity-Keepalive": "1" },
|
|
37651
|
+
body: body2,
|
|
37652
|
+
timeout: timeoutMs,
|
|
37653
|
+
cmd: "prove-verify"
|
|
37654
|
+
});
|
|
37655
|
+
return res.ok ? { ok: true, data: res.data ?? {} } : { ok: false, error: res.error };
|
|
37656
|
+
};
|
|
37657
|
+
}
|
|
37658
|
+
function wellFormedCalls(raw, offered) {
|
|
37659
|
+
const calls = [];
|
|
37660
|
+
for (const c of raw) {
|
|
37661
|
+
if (!c || typeof c !== "object" || Array.isArray(c)) return null;
|
|
37662
|
+
const o = c;
|
|
37663
|
+
if (typeof o.call_id !== "string" || o.call_id.length === 0 || o.call_id.length > 200) return null;
|
|
37664
|
+
if (typeof o.name !== "string" || !offered.includes(o.name)) return null;
|
|
37665
|
+
const args2 = o.arguments ?? {};
|
|
37666
|
+
if (!args2 || typeof args2 !== "object" || Array.isArray(args2)) return null;
|
|
37667
|
+
calls.push({ call_id: o.call_id, name: o.name, arguments: args2 });
|
|
37668
|
+
}
|
|
37669
|
+
return calls;
|
|
37670
|
+
}
|
|
37671
|
+
async function verifyFinding(input, opts) {
|
|
37672
|
+
const now = opts.now ?? Date.now;
|
|
37673
|
+
const startedAt = now();
|
|
37674
|
+
const remaining = () => opts.deadlineAt - now();
|
|
37675
|
+
let rounds = 0;
|
|
37676
|
+
let costUsd = 0;
|
|
37677
|
+
let unpriced = 0;
|
|
37678
|
+
const end = (outcome, extra = {}) => ({ outcome, verdict: null, introduced: "unknown", rounds, costUsd, unpriced, durationMs: now() - startedAt, ...extra });
|
|
37679
|
+
if (remaining() < MIN_VERIFY_START_MS) return end("deadline", { error: "not enough time left" });
|
|
37680
|
+
let body2 = {
|
|
37681
|
+
target: {
|
|
37682
|
+
file: input.file,
|
|
37683
|
+
symbol: input.symbol,
|
|
37684
|
+
...input.lines ? { lines: input.lines } : {},
|
|
37685
|
+
property: input.property,
|
|
37686
|
+
replay_reason: input.replayReason,
|
|
37687
|
+
changed_lines: input.changedLines.slice(0, 200)
|
|
37688
|
+
},
|
|
37689
|
+
local_tools: opts.localTools
|
|
37690
|
+
};
|
|
37691
|
+
for (let turn = 0; turn < MAX_TURNS2; turn++) {
|
|
37692
|
+
if (remaining() < MIN_VERIFY_TURN_MS) return end("deadline");
|
|
37693
|
+
if (costUsd + VERIFY_TURN_HOLD_USD > opts.costLeftUsd) return end("cost-cap");
|
|
37694
|
+
const res = await opts.post({ ...body2, remaining_ms: remaining() }, Math.max(1, remaining()));
|
|
37695
|
+
if (!res.ok) return end("failed", { error: res.error.slice(0, 200) });
|
|
37696
|
+
const d = res.data;
|
|
37697
|
+
if (d.enabled === false) return end("disabled", { error: text(d.reason, 60) });
|
|
37698
|
+
if (d.error && typeof d.error === "object") return end("failed", { error: text(d.error.code, 60) || "SERVICE_ERROR" });
|
|
37699
|
+
rounds = typeof d.round === "number" && Number.isInteger(d.round) && d.round >= 0 ? d.round : rounds + 1;
|
|
37700
|
+
if (typeof d.cost_usd === "number") {
|
|
37701
|
+
if (!Number.isFinite(d.cost_usd) || d.cost_usd < 0) return end("failed", { error: "invalid cost" });
|
|
37702
|
+
costUsd += d.cost_usd;
|
|
37703
|
+
} else unpriced++;
|
|
37704
|
+
if (d.done) {
|
|
37705
|
+
const a = d.answer;
|
|
37706
|
+
if (!a) return end("failed", { error: text(d.error, 60) || "no verdict" });
|
|
37707
|
+
const verdict = verdictOf(a.verdict);
|
|
37708
|
+
if (!verdict) return end("failed", { error: "unknown verdict" });
|
|
37709
|
+
return end("answered", {
|
|
37710
|
+
verdict,
|
|
37711
|
+
claimed: verdictOf(a.claimed),
|
|
37712
|
+
introduced: introducedOf(a.introduced),
|
|
37713
|
+
trigger: text(a.trigger, 400),
|
|
37714
|
+
preventedBy: typeof a.prevented_by === "string" ? a.prevented_by.slice(0, 600) : null,
|
|
37715
|
+
effect: text(a.effect, 600),
|
|
37716
|
+
reason: text(a.reason, 2e3),
|
|
37717
|
+
quotes: (Array.isArray(a.quotes) ? a.quotes : []).slice(0, 12).flatMap((q) => {
|
|
37718
|
+
const o = q ?? {};
|
|
37719
|
+
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 }] : [];
|
|
37720
|
+
})
|
|
37721
|
+
});
|
|
37722
|
+
}
|
|
37723
|
+
if (typeof d.state !== "string" || !Array.isArray(d.calls)) return end("failed", { error: "malformed turn" });
|
|
37724
|
+
const calls = wellFormedCalls(d.calls, opts.localTools);
|
|
37725
|
+
if (!calls) return end("failed", { error: "malformed tool calls" });
|
|
37726
|
+
const results = await opts.executeTools(calls);
|
|
37727
|
+
body2 = { state: d.state, results };
|
|
37728
|
+
}
|
|
37729
|
+
return end("failed", { error: "too many turns" });
|
|
37730
|
+
}
|
|
37731
|
+
|
|
37504
37732
|
// src/lib/prove/record.ts
|
|
37505
37733
|
var RECORD_TIMEOUT_MS = 8e3;
|
|
37506
37734
|
var HOOK_EXIT_MARGIN_MS = 5e3;
|
|
@@ -37516,9 +37744,9 @@ function recordPostTimeout(now, deadlineAt, timeoutMs = RECORD_TIMEOUT_MS) {
|
|
|
37516
37744
|
var norm2 = (p) => p.replace(/\\/g, "/");
|
|
37517
37745
|
var SAFE_SEGMENT = /^[A-Za-z0-9._@+~$()[\]-]{1,255}$/;
|
|
37518
37746
|
function safeRepoPath(p) {
|
|
37519
|
-
const
|
|
37520
|
-
if (!
|
|
37521
|
-
return
|
|
37747
|
+
const n2 = norm2(p);
|
|
37748
|
+
if (!n2 || n2.length > 512 || n2.startsWith("/") || /^[A-Za-z]:\//.test(n2)) return null;
|
|
37749
|
+
return n2.split("/").every((s) => s !== "." && s !== ".." && SAFE_SEGMENT.test(s)) ? n2 : null;
|
|
37522
37750
|
}
|
|
37523
37751
|
var SYMBOL = /^[A-Za-z_$][\w$]*(?:[.#:][A-Za-z_$][\w$]*)*$/;
|
|
37524
37752
|
var IDENT3 = /^[A-Za-z][\w]*$/;
|
|
@@ -37538,10 +37766,10 @@ function recordTrace(trace) {
|
|
|
37538
37766
|
}
|
|
37539
37767
|
var ident2 = (s, re, max) => typeof s === "string" && s.length <= max && re.test(s) ? s : null;
|
|
37540
37768
|
var kind = (k) => k === "intent" ? "intent" : "structural";
|
|
37541
|
-
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(([,
|
|
37769
|
+
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(([, n2]) => typeof n2 === "number" && n2 > 0).slice(0, 16)) } : null;
|
|
37542
37770
|
function buildPhaseRecord(outcome, ctx) {
|
|
37543
37771
|
const pushed = new Set(ctx.pushedFiles.map(norm2));
|
|
37544
|
-
const blocks = (f) => ctx.moment === "push" && f
|
|
37772
|
+
const blocks = (f) => ctx.moment === "push" && formalDisposition(f) === "block" && pushed.has(norm2(f.file));
|
|
37545
37773
|
const symbol = (s) => ident2(s, SYMBOL, 200);
|
|
37546
37774
|
return {
|
|
37547
37775
|
moment: ctx.moment,
|
|
@@ -37581,7 +37809,9 @@ function buildPhaseRecord(outcome, ctx) {
|
|
|
37581
37809
|
symbol: f.symbol,
|
|
37582
37810
|
verdict: f.verdict,
|
|
37583
37811
|
waived: f.waived === true,
|
|
37584
|
-
blocked: blocks(f)
|
|
37812
|
+
blocked: blocks(f),
|
|
37813
|
+
// The check's closed codes only (decision 91): never its reason, trigger or quotes.
|
|
37814
|
+
check: f.check ? { outcome: f.check.outcome, verdict: f.check.verdict, introduced: f.check.introduced, rounds: f.check.rounds } : null
|
|
37585
37815
|
})),
|
|
37586
37816
|
grounding: outcome.grounding ? {
|
|
37587
37817
|
sent_back: outcome.grounding.sentBack,
|
|
@@ -37763,17 +37993,17 @@ function parsePrIntent(command) {
|
|
|
37763
37993
|
}
|
|
37764
37994
|
var TRIVIAL_INTENT = /^(wip|tmp|temp|test|fix|chore|amend|\.+|fixup!.*|squash!.*|merge\b.*)$/i;
|
|
37765
37995
|
var SHELL_PLUMBING = /\$\(|`|<<-?\s*['"]?[A-Za-z_]/;
|
|
37766
|
-
function isSubstantiveIntent(
|
|
37767
|
-
if (!
|
|
37768
|
-
const t =
|
|
37996
|
+
function isSubstantiveIntent(text2) {
|
|
37997
|
+
if (!text2) return false;
|
|
37998
|
+
const t = text2.trim();
|
|
37769
37999
|
if (t.length < 12) return false;
|
|
37770
38000
|
if (TRIVIAL_INTENT.test(t)) return false;
|
|
37771
38001
|
if (SHELL_PLUMBING.test(t)) return false;
|
|
37772
38002
|
return true;
|
|
37773
38003
|
}
|
|
37774
38004
|
function extractStatedIntent(moment, command, pushedMessages = null) {
|
|
37775
|
-
const
|
|
37776
|
-
return isSubstantiveIntent(
|
|
38005
|
+
const text2 = moment === "pre-commit" ? parseCommitMessage(command) : parsePrIntent(command) ?? pushedMessages;
|
|
38006
|
+
return isSubstantiveIntent(text2) ? text2 : null;
|
|
37777
38007
|
}
|
|
37778
38008
|
function hasBlockingFinding(response, sentFiles) {
|
|
37779
38009
|
const findings = response.findings ?? [];
|
|
@@ -37938,7 +38168,7 @@ function startAgentReview(input) {
|
|
|
37938
38168
|
diffs: await buildAgentDiffs(ctx, sentPaths),
|
|
37939
38169
|
repo_context: input.requestBody.repo_context,
|
|
37940
38170
|
static_results: input.requestBody.static_results,
|
|
37941
|
-
one_shot_chars: input.codeDelta.files.reduce((
|
|
38171
|
+
one_shot_chars: input.codeDelta.files.reduce((n2, f) => n2 + f.content.length, 0),
|
|
37942
38172
|
local_tools: offeredLocalTools(ctx)
|
|
37943
38173
|
},
|
|
37944
38174
|
oneShot: input.oneShot.then((r) => r.ok ? { ok: true, response: r.data } : { ok: false }),
|
|
@@ -37960,7 +38190,7 @@ function startFormalPhase(input) {
|
|
|
37960
38190
|
for (const [path, sig] of rangeChangeSignals(input.frame, input.range, files)) {
|
|
37961
38191
|
changedLines.set(path, [
|
|
37962
38192
|
...sig.addedRanges.map(([from, to]) => ({ from, to })),
|
|
37963
|
-
...sig.touchPoints.map((
|
|
38193
|
+
...sig.touchPoints.map((n2) => ({ from: n2, to: n2 }))
|
|
37964
38194
|
]);
|
|
37965
38195
|
}
|
|
37966
38196
|
} catch {
|
|
@@ -37976,6 +38206,14 @@ function startFormalPhase(input) {
|
|
|
37976
38206
|
const run4 = async () => {
|
|
37977
38207
|
const prep = await prepareFormalPhase(input.root, process.env, input.auth, readSource, withoutPaths(tip ? revisionSource(input.root, tip) : worktreeSource(input.root), isDeniedPath));
|
|
37978
38208
|
if (!prep.ok) return skippedOutcome(prep.skip, prep.detail);
|
|
38209
|
+
if (process.env.VERITY_FORMAL_VERIFY !== "off") {
|
|
38210
|
+
const ctx = { root: input.root, range: input.range, codeMap: prep.deps.codeMap ?? null };
|
|
38211
|
+
const post = verifyPost(input.auth);
|
|
38212
|
+
prep.deps.verify = (f, v) => verifyFinding(
|
|
38213
|
+
{ 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 },
|
|
38214
|
+
{ executeTools: makeToolExecutor(ctx), localTools: offeredLocalTools(ctx), deadlineAt: v.deadlineAt, costLeftUsd: v.costLeftUsd, post }
|
|
38215
|
+
);
|
|
38216
|
+
}
|
|
37979
38217
|
return runFormalPhaseWithin({ root: input.root, files, changedLines, deadlineAt, deps: prep.deps });
|
|
37980
38218
|
};
|
|
37981
38219
|
return run4().catch((err2) => skippedOutcome("error", String(err2?.message ?? err2).slice(0, 200)));
|
|
@@ -38508,12 +38746,12 @@ function printBanner(opts) {
|
|
|
38508
38746
|
const color = colorEnabled();
|
|
38509
38747
|
const version = `v${cliVersion()}`;
|
|
38510
38748
|
const art = [WORDMARK, WORDMARK_NARROW].find((a) => artWidth(a) <= columns) ?? null;
|
|
38511
|
-
const dim = (
|
|
38749
|
+
const dim = (text2) => color ? `${DIM3}${text2}${RESET2}` : text2;
|
|
38512
38750
|
process.stderr.write("\n");
|
|
38513
38751
|
if (!art) {
|
|
38514
38752
|
const candidates2 = [`Verity ${version}`, "Verity"];
|
|
38515
|
-
const
|
|
38516
|
-
if (
|
|
38753
|
+
const text2 = candidates2.find((c) => c.length + INDENT.length <= columns);
|
|
38754
|
+
if (text2) process.stderr.write(`${INDENT}${dim(text2)}
|
|
38517
38755
|
`);
|
|
38518
38756
|
process.stderr.write("\n");
|
|
38519
38757
|
return;
|
|
@@ -38534,11 +38772,11 @@ function printBanner(opts) {
|
|
|
38534
38772
|
}
|
|
38535
38773
|
process.stderr.write("\n");
|
|
38536
38774
|
}
|
|
38537
|
-
function printPhase(
|
|
38775
|
+
function printPhase(n2, of, title, subtitle) {
|
|
38538
38776
|
const color = colorEnabled();
|
|
38539
38777
|
const columns = process.stderr.columns ?? 72;
|
|
38540
38778
|
const width = Math.min(columns, 72);
|
|
38541
|
-
const label2 = `\u2500\u2500 Phase ${
|
|
38779
|
+
const label2 = `\u2500\u2500 Phase ${n2} of ${of} \xB7 ${title} `;
|
|
38542
38780
|
const rule = label2 + "\u2500".repeat(Math.max(0, width - label2.length - 2));
|
|
38543
38781
|
process.stderr.write("\n");
|
|
38544
38782
|
process.stderr.write(color ? ` ${DIM3}${rule}${RESET2}
|
|
@@ -38915,7 +39153,7 @@ function registerDoctorCommand(program2) {
|
|
|
38915
39153
|
if (report.next.length > 0) {
|
|
38916
39154
|
console.log("");
|
|
38917
39155
|
printWarn("Next:");
|
|
38918
|
-
for (const
|
|
39156
|
+
for (const n2 of report.next) printWarn(` - ${n2}`);
|
|
38919
39157
|
} else {
|
|
38920
39158
|
printInfo("Setup is complete.");
|
|
38921
39159
|
}
|
|
@@ -39297,7 +39535,7 @@ var DIM4 = "\x1B[2m";
|
|
|
39297
39535
|
var BOLD2 = "\x1B[1m";
|
|
39298
39536
|
var RESET3 = "\x1B[0m";
|
|
39299
39537
|
function renderSelect(question, choices, state, mode2, color = colorEnabled()) {
|
|
39300
|
-
const paint = (
|
|
39538
|
+
const paint = (text2, code) => color ? `${code}${text2}${RESET3}` : text2;
|
|
39301
39539
|
const lines = ["", ` ${question}`];
|
|
39302
39540
|
const labelOf = (c) => `${c.label}${c.recommended ? " (recommended)" : ""}`;
|
|
39303
39541
|
const gutter = Math.max(...choices.map((c) => labelOf(c).length));
|
|
@@ -39306,8 +39544,8 @@ function renderSelect(question, choices, state, mode2, color = colorEnabled()) {
|
|
|
39306
39544
|
const marker = state.chosen.has(i2) ? "\u25C9" : "\u25CB";
|
|
39307
39545
|
const cursor = here ? "\u276F" : " ";
|
|
39308
39546
|
const label2 = labelOf(choice);
|
|
39309
|
-
const
|
|
39310
|
-
const hint = choice.hint ? `${
|
|
39547
|
+
const pad2 = choice.hint ? " ".repeat(gutter - label2.length) : "";
|
|
39548
|
+
const hint = choice.hint ? `${pad2} ${paint(choice.hint, DIM4)}` : "";
|
|
39311
39549
|
lines.push(` ${cursor} ${marker} ${here ? paint(label2, BOLD2) : label2}${hint}`);
|
|
39312
39550
|
});
|
|
39313
39551
|
const keys = mode2 === "multi" ? "\u2191\u2193 move \xB7 space or number toggle \xB7 enter confirm" : "\u2191\u2193 move \xB7 number jumps \xB7 enter confirm";
|
|
@@ -39418,9 +39656,9 @@ function parseMultiSelect(answer, choices, fallback) {
|
|
|
39418
39656
|
if (a === "") return { ids: [...fallback], recognized: true };
|
|
39419
39657
|
const picked = /* @__PURE__ */ new Set();
|
|
39420
39658
|
for (const part of a.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
39421
|
-
const
|
|
39422
|
-
if (Number.isInteger(
|
|
39423
|
-
picked.add(choices[
|
|
39659
|
+
const n2 = Number.parseInt(part, 10);
|
|
39660
|
+
if (Number.isInteger(n2) && n2 >= 1 && n2 <= choices.length) {
|
|
39661
|
+
picked.add(choices[n2 - 1].id);
|
|
39424
39662
|
continue;
|
|
39425
39663
|
}
|
|
39426
39664
|
const byId = choices.find((c) => c.id.toLowerCase() === part || c.label.toLowerCase() === part);
|
|
@@ -39590,7 +39828,7 @@ function inPlaceProgress(label2, write = (s) => process.stderr.write(s)) {
|
|
|
39590
39828
|
let active = false;
|
|
39591
39829
|
let lastAt = 0;
|
|
39592
39830
|
let lastPct = -1;
|
|
39593
|
-
const mb = (
|
|
39831
|
+
const mb = (n2) => (n2 / 1048576).toFixed(0);
|
|
39594
39832
|
return {
|
|
39595
39833
|
update(seen, total) {
|
|
39596
39834
|
const now = Date.now();
|
|
@@ -39625,7 +39863,7 @@ async function installLean(opts = {}) {
|
|
|
39625
39863
|
const free = freeBytes(home);
|
|
39626
39864
|
const needed = opts.minFreeBytes ?? LEAN_DISK_NEEDED_BYTES;
|
|
39627
39865
|
if (free !== null && free < needed) {
|
|
39628
|
-
const gb = (
|
|
39866
|
+
const gb = (n2) => (n2 / 1024 ** 3).toFixed(1);
|
|
39629
39867
|
return { ok: false, error: `not enough disk space for Lean: ${gb(free)} GB free where ${home} lives, needs about ${gb(needed)} GB` };
|
|
39630
39868
|
}
|
|
39631
39869
|
const tmp = (0, import_node_path52.join)(home, ".tmp");
|
|
@@ -40636,7 +40874,7 @@ function registerInitCommand(program2) {
|
|
|
40636
40874
|
...telemetryChoice ? { telemetry: telemetryChoice } : {},
|
|
40637
40875
|
init: {
|
|
40638
40876
|
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
40639
|
-
cli_version: true ? "0.34.
|
|
40877
|
+
cli_version: true ? "0.34.4" : "dev"
|
|
40640
40878
|
}
|
|
40641
40879
|
});
|
|
40642
40880
|
} catch (err2) {
|
|
@@ -41077,11 +41315,11 @@ function resolve7(token, treePaths) {
|
|
|
41077
41315
|
const matches = treePaths.filter((p) => p.endsWith(suffix));
|
|
41078
41316
|
return matches.length === 1 ? matches[0] : null;
|
|
41079
41317
|
}
|
|
41080
|
-
function deriveFileGlobs(
|
|
41081
|
-
if (!
|
|
41318
|
+
function deriveFileGlobs(text2, treePaths) {
|
|
41319
|
+
if (!text2 || treePaths.length === 0) return [];
|
|
41082
41320
|
const out2 = [];
|
|
41083
41321
|
const seen = /* @__PURE__ */ new Set();
|
|
41084
|
-
for (const raw of
|
|
41322
|
+
for (const raw of text2.match(PATH_TOKEN) ?? []) {
|
|
41085
41323
|
const token = clean(raw);
|
|
41086
41324
|
if (!token) continue;
|
|
41087
41325
|
const path = resolve7(token, treePaths);
|
|
@@ -41616,6 +41854,148 @@ function registerTelemetryCommands(program2) {
|
|
|
41616
41854
|
});
|
|
41617
41855
|
}
|
|
41618
41856
|
|
|
41857
|
+
// src/commands/usage.ts
|
|
41858
|
+
var PLAN = { free: "Free", pro: "Pro", fleet: "Fleet" };
|
|
41859
|
+
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
41860
|
+
function n(v) {
|
|
41861
|
+
return v.toLocaleString("en-US");
|
|
41862
|
+
}
|
|
41863
|
+
function used(v, limit) {
|
|
41864
|
+
return limit === void 0 ? n(v) : `${n(v)} / ${n(limit)}`;
|
|
41865
|
+
}
|
|
41866
|
+
function secs(ms) {
|
|
41867
|
+
return ms === null ? "\u2014" : `${(ms / 1e3).toFixed(1)} s`;
|
|
41868
|
+
}
|
|
41869
|
+
function utcHm(iso) {
|
|
41870
|
+
const d = new Date(iso);
|
|
41871
|
+
return `${String(d.getUTCHours()).padStart(2, "0")}:${String(d.getUTCMinutes()).padStart(2, "0")} UTC`;
|
|
41872
|
+
}
|
|
41873
|
+
function utcDay(iso) {
|
|
41874
|
+
const d = new Date(iso);
|
|
41875
|
+
return `${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]}`;
|
|
41876
|
+
}
|
|
41877
|
+
function inText(now, at) {
|
|
41878
|
+
const min = Math.max(0, Math.round((at.getTime() - now.getTime()) / 6e4));
|
|
41879
|
+
if (min < 60) return `${min} min`;
|
|
41880
|
+
const h = Math.floor(min / 60);
|
|
41881
|
+
return h < 48 ? `${h} h ${min % 60} min` : `${Math.floor(h / 24)} d ${h % 24} h`;
|
|
41882
|
+
}
|
|
41883
|
+
function pad(s, w) {
|
|
41884
|
+
return s.length >= w ? s : s + " ".repeat(w - s.length);
|
|
41885
|
+
}
|
|
41886
|
+
function renderSeatUsage(d, now = /* @__PURE__ */ new Date()) {
|
|
41887
|
+
const lim = d.plan?.limits;
|
|
41888
|
+
const pool = d.plan?.week_pool ?? null;
|
|
41889
|
+
const memberWeek = (m) => pool ? void 0 : lim?.[m].week;
|
|
41890
|
+
const lines = [];
|
|
41891
|
+
lines.push(`=== Verity usage \xB7 ${d.organization.name}${d.plan ? ` (${PLAN[d.plan.id] ?? d.plan.id})` : ""} ===`);
|
|
41892
|
+
lines.push(
|
|
41893
|
+
`Session ${utcHm(d.session.start)}\u2013${utcHm(d.session.resets_at)} (resets in ${inText(now, new Date(d.session.resets_at))}) \xB7 week from Mon ${utcDay(d.week.start)} (resets Mon ${utcDay(d.week.resets_at)}, 00:00 UTC)`
|
|
41894
|
+
);
|
|
41895
|
+
if (!d.plan) lines.push("No plan is set for this org: counts only. Plan limits apply from Nov 2.");
|
|
41896
|
+
else if (!d.enforced) lines.push("Limits are shown for information. They are not enforced before Nov 2.");
|
|
41897
|
+
const me = d.members.find((m) => m.me);
|
|
41898
|
+
if (me) {
|
|
41899
|
+
const w = me.weeks[0];
|
|
41900
|
+
lines.push("");
|
|
41901
|
+
lines.push(`You (${me.email ?? `user #${me.user_id}`})`);
|
|
41902
|
+
lines.push(` ${pad("Commit & push reviews", 24)}session ${pad(used(me.session.commit, lim?.commit.session), 12)}week ${pad(used(w.commit, memberWeek("commit")), 14)}busiest session ${n(w.peak_session.commit)}`);
|
|
41903
|
+
lines.push(` ${pad("Turn reviews", 24)}session ${pad(used(me.session.turn, lim?.turn.session), 12)}week ${pad(used(w.turn, memberWeek("turn")), 14)}busiest session ${n(w.peak_session.turn)}`);
|
|
41904
|
+
lines.push(` This week: ${n(w.blocked)} blocked, ${n(w.warned)} warned \xB7 review time p50 ${secs(w.latency_ms.p50)}, p90 ${secs(w.latency_ms.p90)}`);
|
|
41905
|
+
}
|
|
41906
|
+
const t = d.totals.weeks[0];
|
|
41907
|
+
lines.push("");
|
|
41908
|
+
lines.push(`Team \xB7 ${n(d.totals.active_members)} active this week`);
|
|
41909
|
+
if (pool && lim) {
|
|
41910
|
+
lines.push(
|
|
41911
|
+
` Week pool: ${n(t.commit)} / ${n(pool.commit)} commit & push, ${n(t.turn)} / ${n(pool.turn)} turn (${n(pool.members)} members \xD7 ${n(lim.commit.week)} and ${n(lim.turn.week)}; the session limit is each member's)`
|
|
41912
|
+
);
|
|
41913
|
+
}
|
|
41914
|
+
if (d.viewer !== "member" && d.members.length > 0) {
|
|
41915
|
+
const rows = d.members.map((m) => [
|
|
41916
|
+
`${m.email ?? `user #${m.user_id}`}${m.me ? " (you)" : ""}`,
|
|
41917
|
+
used(m.session.commit, lim?.commit.session),
|
|
41918
|
+
used(m.weeks[0].commit, memberWeek("commit")),
|
|
41919
|
+
n(m.weeks[0].peak_session.commit),
|
|
41920
|
+
used(m.session.turn, lim?.turn.session),
|
|
41921
|
+
used(m.weeks[0].turn, memberWeek("turn")),
|
|
41922
|
+
n(m.weeks[0].blocked),
|
|
41923
|
+
`${secs(m.weeks[0].latency_ms.p50)} / ${secs(m.weeks[0].latency_ms.p90)}`
|
|
41924
|
+
]);
|
|
41925
|
+
const head = ["Member", "C&P session", "C&P week", "C&P peak", "Turn session", "Turn week", "Blocked", "p50 / p90"];
|
|
41926
|
+
const total = [
|
|
41927
|
+
"Team total",
|
|
41928
|
+
n(d.totals.session.commit),
|
|
41929
|
+
used(t.commit, pool?.commit),
|
|
41930
|
+
n(t.peak_session.commit),
|
|
41931
|
+
n(d.totals.session.turn),
|
|
41932
|
+
used(t.turn, pool?.turn),
|
|
41933
|
+
n(t.blocked),
|
|
41934
|
+
`${secs(t.latency_ms.p50)} / ${secs(t.latency_ms.p90)}`
|
|
41935
|
+
];
|
|
41936
|
+
const widths = head.map((h, i2) => Math.max(h.length, ...rows.map((r) => r[i2].length), total[i2].length) + 2);
|
|
41937
|
+
lines.push(" " + head.map((h, i2) => pad(h, widths[i2])).join("").trimEnd());
|
|
41938
|
+
for (const r of rows) lines.push(" " + r.map((c, i2) => pad(c, widths[i2])).join("").trimEnd());
|
|
41939
|
+
lines.push(" " + total.map((c, i2) => pad(c, widths[i2])).join("").trimEnd());
|
|
41940
|
+
} else {
|
|
41941
|
+
lines.push(` This week: ${n(t.commit)} commit & push reviews, ${n(t.turn)} turn reviews, ${n(t.blocked)} blocked.`);
|
|
41942
|
+
if (d.viewer === "member") lines.push(` Only the admins of ${d.organization.name} see every member.`);
|
|
41943
|
+
}
|
|
41944
|
+
if (d.truncated) lines.push(" (Partial: the org has more reviews than one report reads.)");
|
|
41945
|
+
lines.push("");
|
|
41946
|
+
lines.push(`Counted: ${d.counting}`);
|
|
41947
|
+
return lines;
|
|
41948
|
+
}
|
|
41949
|
+
async function auth2(globals) {
|
|
41950
|
+
const tokenResult = await resolveToken(globals.token);
|
|
41951
|
+
if (!tokenResult.ok) {
|
|
41952
|
+
printError(tokenResult.error);
|
|
41953
|
+
process.exit(1);
|
|
41954
|
+
}
|
|
41955
|
+
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
41956
|
+
if (!urlResult.ok) {
|
|
41957
|
+
printError(urlResult.error);
|
|
41958
|
+
process.exit(1);
|
|
41959
|
+
}
|
|
41960
|
+
return { token: tokenResult.data.token, serviceUrl: urlResult.data };
|
|
41961
|
+
}
|
|
41962
|
+
function registerUsageCommand(program2) {
|
|
41963
|
+
program2.command("usage").description("Show reviews per member of this org, this session and this week, against the plan limits").option("--org <name>", "The org to show (default: the org of this repository)").option("--weeks <n>", "Weeks of history in --json (1-12)", "4").option("--json", "Machine-readable output").action(async (opts) => {
|
|
41964
|
+
const globals = program2.opts();
|
|
41965
|
+
const { token, serviceUrl } = await auth2(globals);
|
|
41966
|
+
const weeks = Math.min(12, Math.max(1, Number.parseInt(opts.weeks ?? "4", 10) || 4));
|
|
41967
|
+
const query = `weeks=${weeks}${opts.org ? `&org=${encodeURIComponent(opts.org)}` : ""}`;
|
|
41968
|
+
const res = await apiRequest({
|
|
41969
|
+
method: "GET",
|
|
41970
|
+
path: `/usage/seats?${query}`,
|
|
41971
|
+
serviceUrl,
|
|
41972
|
+
token,
|
|
41973
|
+
verbose: globals.verbose,
|
|
41974
|
+
cmd: "usage"
|
|
41975
|
+
});
|
|
41976
|
+
if (!res.ok) {
|
|
41977
|
+
const denial = authDenialRemedy(res.error);
|
|
41978
|
+
printError(denial && denial.code !== "FORBIDDEN" ? denial.remedy : res.error);
|
|
41979
|
+
process.exit(1);
|
|
41980
|
+
}
|
|
41981
|
+
if (opts.json) {
|
|
41982
|
+
printJson(res.data);
|
|
41983
|
+
return;
|
|
41984
|
+
}
|
|
41985
|
+
if ("orgs" in res.data) {
|
|
41986
|
+
const orgs = res.data.orgs;
|
|
41987
|
+
if (orgs.length === 0) {
|
|
41988
|
+
printInfo("You have no repository in an org that Verity knows yet. Run a review in one first.");
|
|
41989
|
+
return;
|
|
41990
|
+
}
|
|
41991
|
+
printInfo("Choose an org: verity usage --org <name>");
|
|
41992
|
+
for (const o of orgs) printInfo(` ${o.name}${o.viewer === "admin" ? " (admin)" : ""}`);
|
|
41993
|
+
return;
|
|
41994
|
+
}
|
|
41995
|
+
for (const line2 of renderSeatUsage(res.data)) printInfo(line2);
|
|
41996
|
+
});
|
|
41997
|
+
}
|
|
41998
|
+
|
|
41619
41999
|
// src/commands/prove.ts
|
|
41620
42000
|
var import_node_fs73 = require("node:fs");
|
|
41621
42001
|
var import_node_path57 = require("node:path");
|
|
@@ -41871,8 +42251,8 @@ ${build.stderr.split("\n").filter((l) => !l.startsWith("trace:")).slice(0, 20).j
|
|
|
41871
42251
|
});
|
|
41872
42252
|
prove.command("replay <model>").description("Replay a model's counterexample on the real code in an OpenAI container (network off) \u2014 reproduced / diverged").option("--property <id>", "Only this property (default: every counterexample)").option("--model-name <name>", "OpenAI model for the replay", "gpt-5.6-terra").option("--timeout <ms>", "Per-property timeout in ms", "240000").option("--json", "Machine-readable output").action(async (model, opts) => {
|
|
41873
42253
|
const root = repoRoot();
|
|
41874
|
-
const
|
|
41875
|
-
if (!
|
|
42254
|
+
const auth3 = await proveAuth(program2);
|
|
42255
|
+
if (!auth3 && !(process.env.VERITY_PROVE_DIRECT === "1" && process.env.OPENAI_API_KEY)) {
|
|
41876
42256
|
printError("Not logged in \u2014 replays run on the Verity service. Run `verity login` first.");
|
|
41877
42257
|
process.exit(2);
|
|
41878
42258
|
}
|
|
@@ -41911,7 +42291,7 @@ ${report.error ?? ""}`);
|
|
|
41911
42291
|
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`);
|
|
41912
42292
|
const outcomes = await mapPool(targets, REPLAY_CONCURRENCY, async (p) => {
|
|
41913
42293
|
const brief = buildReplayBrief(root, report, p, modelSource.ok ? modelSource.content : "");
|
|
41914
|
-
const outcome = await runReplay(brief, { auth:
|
|
42294
|
+
const outcome = await runReplay(brief, { auth: auth3 ?? void 0, apiKey: process.env.OPENAI_API_KEY, model: opts.modelName, timeoutMs: Math.max(1e4, Number(opts.timeout) || 24e4) });
|
|
41915
42295
|
if (!opts.json) process.stdout.write(renderReplay(model, p, outcome) + "\n");
|
|
41916
42296
|
try {
|
|
41917
42297
|
writeReplayResult(root, report.model, p.id, outcome);
|
|
@@ -41937,10 +42317,10 @@ ${report.error ?? ""}`);
|
|
|
41937
42317
|
printInfo("No changed files to consider (nothing ahead of upstream). Pass paths explicitly.");
|
|
41938
42318
|
return;
|
|
41939
42319
|
}
|
|
41940
|
-
const
|
|
41941
|
-
const prep = await prepareFormalPhase(root, process.env,
|
|
42320
|
+
const auth3 = await proveAuth(program2);
|
|
42321
|
+
const prep = await prepareFormalPhase(root, process.env, auth3 ?? void 0);
|
|
41942
42322
|
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);
|
|
41943
|
-
if (
|
|
42323
|
+
if (auth3) await postPhaseRecord(outcome, { moment: "on-demand", parentRunId: null, pushedFiles: [] }, auth3);
|
|
41944
42324
|
if (opts.json) {
|
|
41945
42325
|
printJson(outcome);
|
|
41946
42326
|
} else {
|
|
@@ -41972,8 +42352,8 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
41972
42352
|
opts[flag] = input.text;
|
|
41973
42353
|
}
|
|
41974
42354
|
const root = repoRoot();
|
|
41975
|
-
const
|
|
41976
|
-
if (!
|
|
42355
|
+
const auth3 = await proveAuth(program2);
|
|
42356
|
+
if (!auth3 && !(process.env.VERITY_PROVE_DIRECT === "1" && process.env.OPENAI_API_KEY)) {
|
|
41977
42357
|
printError("Not logged in \u2014 models are written by the Verity service. Run `verity login` first.");
|
|
41978
42358
|
process.exit(2);
|
|
41979
42359
|
}
|
|
@@ -42014,7 +42394,7 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
42014
42394
|
printError("Verity library did not build");
|
|
42015
42395
|
process.exit(2);
|
|
42016
42396
|
}
|
|
42017
|
-
const deps = await onDemandDeps(root, { auth:
|
|
42397
|
+
const deps = await onDemandDeps(root, { auth: auth3 ?? void 0, apiKey: process.env.VERITY_PROVE_DIRECT === "1" ? process.env.OPENAI_API_KEY : void 0, toolchain: tc });
|
|
42018
42398
|
if (!opts.json) printInfo(`asking the Verity service for a model of ${symbol || `${file}:${opts.lines}`} \u2026`);
|
|
42019
42399
|
const out2 = await generateAndCheck(root, { file, symbol: symbol || `${file}:${opts.lines}`, lines, hint: opts.hint, revise }, { deps, maxRounds: 3 });
|
|
42020
42400
|
if (!out2.ok) {
|
|
@@ -42052,9 +42432,9 @@ ${f.reason ? ` ${terminalText(f.reason, 2e3)}
|
|
|
42052
42432
|
printWarn(`No remembered formal finding on ${rel}. A finding is remembered only after a REPRODUCED replay at push.`);
|
|
42053
42433
|
process.exit(1);
|
|
42054
42434
|
}
|
|
42055
|
-
const
|
|
42056
|
-
logEvent("formal_waive", { file: rel, waived:
|
|
42057
|
-
printInfo(`Waived ${
|
|
42435
|
+
const n2 = waiveFormalFindings(root, rel, opts.reason);
|
|
42436
|
+
logEvent("formal_waive", { file: rel, waived: n2 });
|
|
42437
|
+
printInfo(`Waived ${n2} formal finding(s) on ${rel} for its current bytes; the waive voids when the file changes. Reason recorded: ${terminalText(opts.reason, 200)}`);
|
|
42058
42438
|
});
|
|
42059
42439
|
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) => {
|
|
42060
42440
|
const root = repoRoot();
|
|
@@ -42177,8 +42557,8 @@ function registerLeanCommand(program2) {
|
|
|
42177
42557
|
}
|
|
42178
42558
|
|
|
42179
42559
|
// src/cli.ts
|
|
42180
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.34.
|
|
42181
|
-
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.
|
|
42560
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.34.4").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) => {
|
|
42561
|
+
installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.4");
|
|
42182
42562
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
42183
42563
|
try {
|
|
42184
42564
|
await foldLegacyLocalCredential();
|
|
@@ -42213,6 +42593,7 @@ registerMemoryCommand(program);
|
|
|
42213
42593
|
registerRunCommand(program);
|
|
42214
42594
|
registerMigrateCommand(program);
|
|
42215
42595
|
registerTelemetryCommands(program);
|
|
42596
|
+
registerUsageCommand(program);
|
|
42216
42597
|
registerProveCommand(program);
|
|
42217
42598
|
registerLeanCommand(program);
|
|
42218
42599
|
program.parseAsync().catch((err2) => {
|