loki-mode 11.17.19 → 11.17.21
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/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/functional-verify.py +141 -3
- package/autonomy/loki +2 -0
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/BOARD.md +15 -15
- package/docs/v10/CLI-MODERN.md +1 -1
- package/docs/v10/FAILURE-CLASSES.md +7 -0
- package/docs/v10/PROGRESS.md +7 -0
- package/loki-ts/dist/loki.js +926 -922
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +393 -324
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-Dc62a8CS.js → AdminPage-DGg_5Yos.js} +1 -1
- package/web-app/dist/assets/{Avatar-3Z6DLFQZ.js → Avatar-BIDvM3U5.js} +1 -1
- package/web-app/dist/assets/{Badge-mkuAR2TD.js → Badge-AsUMPLOU.js} +1 -1
- package/web-app/dist/assets/{Button-EQyd4r_R.js → Button-DodbV8If.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BtlAhPdm.js → CockpitPage-BxL2zTsP.js} +1 -1
- package/web-app/dist/assets/{ComparePage-BbbQ5kC5.js → ComparePage-O1iC9fvU.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-VIK-1yJA.js → ErrorBoundary-Cll1sP40.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-B9EPySH2.js → EvidenceReceiptPanel-DXlOEyn9.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DrxLIcV6.js → GitHubIssuesPanel-DbbqZGUy.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BNuKtoKu.js → GitHubPRsPanel-B6XhdcJp.js} +1 -1
- package/web-app/dist/assets/{HomePage-sZJBAvuK.js → HomePage-DenelbJm.js} +2 -2
- package/web-app/dist/assets/{LoginPage-BNe7doQt.js → LoginPage-MF65tKQb.js} +1 -1
- package/web-app/dist/assets/{MagicPage-Djh-aWoE.js → MagicPage-Caa_kRza.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-B5RoFk1f.js → MetricsPage-BVSJe-I6.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-BiG9Qx-K.js → NotFoundPage-BPTMfi71.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-rQZIHvO1.js → ProjectPage-BbnEno5f.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-Br37M7yx.js → ProjectsPage-CYL7Eh40.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DxEcGRRT.js → SettingsPage-D5rk0Q-i.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-BQ_cOsd8.js → ShowcasePage-Cgsx2N4V.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-CJuMeLfn.js → SystemSettingsPage-DKPw7kf7.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-CxNvYxl0.js → TeamsPage-BOQyzfGG.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-CowBuPlo.js → TemplatesPage-C85kNfws.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Bs0qzgnx.js → TerminalOutput-CaZ75acm.js} +1 -1
- package/web-app/dist/assets/{activity-BZBTb6gx.js → activity-_vZZ0q95.js} +1 -1
- package/web-app/dist/assets/{bell-DWQ-mGsX.js → bell-BepNateL.js} +1 -1
- package/web-app/dist/assets/{bot-Cp-aoJki.js → bot-CLPO5bfI.js} +1 -1
- package/web-app/dist/assets/{check-CyFL_qpg.js → check-Cw2ZY8Hd.js} +1 -1
- package/web-app/dist/assets/{chevron-left-CSpNuW_B.js → chevron-left-CNkV8_tB.js} +1 -1
- package/web-app/dist/assets/{circle-alert-BLXbl8kD.js → circle-alert-CBgwfRV4.js} +1 -1
- package/web-app/dist/assets/{clock-BBWu569k.js → clock-Kbd5g1Q4.js} +1 -1
- package/web-app/dist/assets/{cloud-Ce7Luvrn.js → cloud-BUHvBaGU.js} +1 -1
- package/web-app/dist/assets/{code-xml-C_ID1rox.js → code-xml-BFtb44h7.js} +1 -1
- package/web-app/dist/assets/{database-_ed-qaFL.js → database-BKTm6rSV.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CYnJuf7T.js → dollar-sign-CxSlnHdr.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-jBR2MosN.js → file-code-corner-CzODg9ft.js} +1 -1
- package/web-app/dist/assets/{file-plus-DObnySLq.js → file-plus-DwR8w4_g.js} +1 -1
- package/web-app/dist/assets/{globe-CBYgMBCX.js → globe-BN26QQLG.js} +1 -1
- package/web-app/dist/assets/{hammer-Aopfj9DH.js → hammer-BMGuBFj7.js} +1 -1
- package/web-app/dist/assets/{index-Az6c4mLi.js → index-RYEDj5dp.js} +3 -3
- package/web-app/dist/assets/{layers-RU1n4mJF.js → layers-Bih4Qqbx.js} +1 -1
- package/web-app/dist/assets/{loader-circle-vkUFjVTs.js → loader-circle-DTh3fBtD.js} +1 -1
- package/web-app/dist/assets/{lock-DX7cm7nZ.js → lock-B77al7oQ.js} +1 -1
- package/web-app/dist/assets/{package-rQet8lbL.js → package-BMcYmquO.js} +1 -1
- package/web-app/dist/assets/{plus-B6lq3pKQ.js → plus-D40JVGe8.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-C5pY6vxn.js → refresh-cw-BzmtMb8b.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-B_66hj0H.js → rotate-ccw-B0-EyBz6.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DoY2VPSX.js → scroll-text-BQNWKEf4.js} +1 -1
- package/web-app/dist/assets/{server-Cur2b1Py.js → server-DrTKOH08.js} +1 -1
- package/web-app/dist/assets/{shield-alert-ZxlmrPzT.js → shield-alert-bacDs6zS.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-CO6PAF2d.js → thumbs-up-CKbEwA0r.js} +1 -1
- package/web-app/dist/assets/{trash-2-KkO1Q-C7.js → trash-2-BeWrrpHd.js} +1 -1
- package/web-app/dist/assets/{trending-down-eak_OVU-.js → trending-down-UfhUQ_MW.js} +1 -1
- package/web-app/dist/assets/{trending-up-X0avjdBr.js → trending-up-CLkxjmYM.js} +1 -1
- package/web-app/dist/assets/{upload-CMNuZ7nb.js → upload-DdaprL3w.js} +1 -1
- package/web-app/dist/assets/{usePolling-BOF9VJY_.js → usePolling-Btjcs4pC.js} +1 -1
- package/web-app/dist/assets/{user-CemBNbFR.js → user-DhyL9aMl.js} +1 -1
- package/web-app/dist/index.html +1 -1
|
@@ -9674,6 +9674,19 @@ var init_test_file_text = __esm(() => {
|
|
|
9674
9674
|
});
|
|
9675
9675
|
|
|
9676
9676
|
// ../../loki-ts/src/engine10/testmap.ts
|
|
9677
|
+
import { existsSync as existsSync22, readdirSync as readdirSync13, readFileSync as readFileSync28, realpathSync as realpathSync16 } from "fs";
|
|
9678
|
+
import { basename as basename10, extname, isAbsolute as isAbsolute2, join as join37, relative, sep as sep10 } from "path";
|
|
9679
|
+
function projectInterpreter(root) {
|
|
9680
|
+
const ve = process.env["VIRTUAL_ENV"], inRepo = (p) => {
|
|
9681
|
+
try {
|
|
9682
|
+
const r = relative(realpathSync16(root), realpathSync16(p));
|
|
9683
|
+
return r !== "" && !r.startsWith("..") && !isAbsolute2(r);
|
|
9684
|
+
} catch {
|
|
9685
|
+
return false;
|
|
9686
|
+
}
|
|
9687
|
+
};
|
|
9688
|
+
return [join37(root, ".venv", "bin", "python"), join37(root, "venv", "bin", "python"), ...ve && inRepo(ve) ? [join37(ve, "bin", "python")] : []].some(existsSync22) ? "project" : "system";
|
|
9689
|
+
}
|
|
9677
9690
|
var SKIP_DIRS;
|
|
9678
9691
|
var init_testmap = __esm(() => {
|
|
9679
9692
|
init_resolve();
|
|
@@ -9697,8 +9710,8 @@ var init_testmap = __esm(() => {
|
|
|
9697
9710
|
});
|
|
9698
9711
|
|
|
9699
9712
|
// ../../loki-ts/src/util/check_result.ts
|
|
9700
|
-
import { mkdirSync as mkdirSync13, readFileSync as
|
|
9701
|
-
import { basename as
|
|
9713
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync29, renameSync as renameSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
9714
|
+
import { basename as basename11, join as join38 } from "path";
|
|
9702
9715
|
function plainTestEnv(base = process.env) {
|
|
9703
9716
|
const e = {};
|
|
9704
9717
|
for (const [k, v] of Object.entries(tokenFreeEnv(base)))
|
|
@@ -9716,7 +9729,7 @@ function ran(raw2, path, ok) {
|
|
|
9716
9729
|
if (blk) {
|
|
9717
9730
|
const c = n2(blk, /(?:#|\u2139) pass (\d+)/) + n2(blk, /(?:#|\u2139) fail (\d+)/);
|
|
9718
9731
|
const nm = out2.match(/^(?:ok \d+ - |\u2714 )(\S+\.[cm]?[jt]s)(?: \(|$)/m)?.[1];
|
|
9719
|
-
return c === 1 && nm && (!path ||
|
|
9732
|
+
return c === 1 && nm && (!path || basename11(nm) === basename11(path)) ? 0 : c;
|
|
9720
9733
|
}
|
|
9721
9734
|
const cg = cargoTrailer(out2);
|
|
9722
9735
|
if (cg.length)
|
|
@@ -9807,16 +9820,16 @@ function goRunner(cmd, args) {
|
|
|
9807
9820
|
let k = 0;
|
|
9808
9821
|
for (;k < t.length; k++) {
|
|
9809
9822
|
const x = t[k];
|
|
9810
|
-
if (/^[A-Za-z_]\w*=/.test(x) || /^(?:env|command|exec|time|nohup)$/.test(
|
|
9823
|
+
if (/^[A-Za-z_]\w*=/.test(x) || /^(?:env|command|exec|time|nohup)$/.test(basename11(x)))
|
|
9811
9824
|
continue;
|
|
9812
|
-
if (/^-/.test(x) && k > 0 &&
|
|
9825
|
+
if (/^-/.test(x) && k > 0 && basename11(t[k - 1]) === "env") {
|
|
9813
9826
|
if (x === "-u" || x === "-C" || x === "-S")
|
|
9814
9827
|
k++;
|
|
9815
9828
|
continue;
|
|
9816
9829
|
}
|
|
9817
9830
|
break;
|
|
9818
9831
|
}
|
|
9819
|
-
if (t[k] !== undefined &&
|
|
9832
|
+
if (t[k] !== undefined && basename11(t[k]) === "go")
|
|
9820
9833
|
return { runner: "go" };
|
|
9821
9834
|
}
|
|
9822
9835
|
return {};
|
|
@@ -9993,7 +10006,7 @@ function diffFiles(repoDir, baseSha) {
|
|
|
9993
10006
|
return f;
|
|
9994
10007
|
let n2 = 0;
|
|
9995
10008
|
try {
|
|
9996
|
-
n2 =
|
|
10009
|
+
n2 = readFileSync29(join38(repoDir, path), "utf8").split(`
|
|
9997
10010
|
`).length;
|
|
9998
10011
|
} catch {}
|
|
9999
10012
|
return { path, added: n2, deleted: 0, status: "added" };
|
|
@@ -10001,7 +10014,7 @@ function diffFiles(repoDir, baseSha) {
|
|
|
10001
10014
|
}
|
|
10002
10015
|
function recordRisk(repoDir, a) {
|
|
10003
10016
|
try {
|
|
10004
|
-
const dir =
|
|
10017
|
+
const dir = join38(repoDir, ".loki", "state"), p = join38(dir, "risk-tier.json");
|
|
10005
10018
|
mkdirSync13(dir, { recursive: true });
|
|
10006
10019
|
writeFileSync16(`${p}.tmp`, JSON.stringify(a, null, 2) + `
|
|
10007
10020
|
`);
|
|
@@ -10011,12 +10024,54 @@ function recordRisk(repoDir, a) {
|
|
|
10011
10024
|
return null;
|
|
10012
10025
|
}
|
|
10013
10026
|
}
|
|
10027
|
+
function truncateBytes(s, cap) {
|
|
10028
|
+
const buf = Buffer.from(s, "utf8");
|
|
10029
|
+
return buf.length <= cap ? s : buf.subarray(0, Math.max(0, cap)).toString("utf8").replace(/\uFFFD$/, "");
|
|
10030
|
+
}
|
|
10031
|
+
function failureExcerpt(out2, repoDir = "", cap = EXCERPT_GROUP_CAP) {
|
|
10032
|
+
let t = stripAnsi(out2.slice(-65536)).replace(/\r/g, "");
|
|
10033
|
+
if (repoDir)
|
|
10034
|
+
t = t.split(repoDir.replace(/\/+$/, "") + "/").join("");
|
|
10035
|
+
const lines = t.split(`
|
|
10036
|
+
`).map((l) => l.replace(/\s+$/, ""));
|
|
10037
|
+
const pick = new Set;
|
|
10038
|
+
const take = (i, n2 = 1) => {
|
|
10039
|
+
for (let k = 0;k < n2 && i + k < lines.length; k++)
|
|
10040
|
+
if (lines[i + k].trim())
|
|
10041
|
+
pick.add(i + k);
|
|
10042
|
+
};
|
|
10043
|
+
lines.forEach((l, i) => {
|
|
10044
|
+
if (/^E\s/.test(l))
|
|
10045
|
+
take(i);
|
|
10046
|
+
else if (/^\s*(Expected|Received)\b/.test(l) || /^\s*expect\(.*\)\.\w+/.test(l))
|
|
10047
|
+
take(i);
|
|
10048
|
+
else if (/^[\w./@-]+\.py:\d+: /.test(l))
|
|
10049
|
+
take(i);
|
|
10050
|
+
else if (/AssertionError|^\s*(expected|actual)\b.*[:=]|^\s*(not ok|FAILED)\b/.test(l))
|
|
10051
|
+
take(i, 3);
|
|
10052
|
+
else if (/^\s*--- FAIL/.test(l))
|
|
10053
|
+
take(i, 4);
|
|
10054
|
+
else if (/^[\w./@-]+\.\w+(\(\d+,\d+\)|:\d+(:\d+)?)[:\s].*\b(error|TS\d+|[A-Z]{1,3}\d{3,4})\b/.test(l))
|
|
10055
|
+
take(i);
|
|
10056
|
+
});
|
|
10057
|
+
const lastFrame = lines.map((l, i) => /^[\w./@-]+\.py:\d+: /.test(l) ? i : -1).filter((i) => i >= 0).pop();
|
|
10058
|
+
if (lastFrame !== undefined && [...pick].some((i) => /^E\s/.test(lines[i])))
|
|
10059
|
+
take(lastFrame);
|
|
10060
|
+
let body = [...pick].sort((a, b) => a - b).map((i) => lines[i]).join(`
|
|
10061
|
+
`);
|
|
10062
|
+
if (!body)
|
|
10063
|
+
body = lines.filter((l) => l.trim()).slice(-6).join(`
|
|
10064
|
+
`);
|
|
10065
|
+
body = redactSecrets(body);
|
|
10066
|
+
return truncateBytes(body, cap);
|
|
10067
|
+
}
|
|
10014
10068
|
var NO_TESTS_REASON = "no tests executed", GO_EXIT0_REASON = "test count could not be confirmed: go test output is produced by the code under test and cannot confirm execution (a Go exit 0 is never a pass)", UNCONFIRMED_REASON = "test count could not be confirmed", FAIL_EVIDENCE, GO_FAIL_EVIDENCE, UNMEASURED_REASON = "executed count unmeasured (Loki could not parse the runner summary, harness-owned)", stripAnsi = (s) => s.replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)/g, "").replace(/(?:\u001b\[|\u009b)[0-9;?]*[ -\/]*[@-~]/g, "").replace(/\r\n?/g, `
|
|
10015
10069
|
`), tailLines = (out2) => out2.split(`
|
|
10016
|
-
`).filter((x) => x.trim()).slice(-12), GO_PKG_RE, isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0, hasExecutedProof = (checks) => checks.some(isExecutedProof), LLM_JUDGES, NON_RUNNER, SENSITIVE, API, TEST_CFG, RANK2, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c));
|
|
10070
|
+
`).filter((x) => x.trim()).slice(-12), GO_PKG_RE, isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0, hasExecutedProof = (checks) => checks.some(isExecutedProof), LLM_JUDGES, NON_RUNNER, SENSITIVE, API, TEST_CFG, RANK2, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c)), EXCERPT_GROUP_CAP = 1500, EXCERPT_TOTAL_CAP = 6144;
|
|
10017
10071
|
var init_check_result = __esm(() => {
|
|
10018
10072
|
init_testmap();
|
|
10019
10073
|
init_safe_git();
|
|
10074
|
+
init_redact();
|
|
10020
10075
|
FAIL_EVIDENCE = /\[(?:build|setup) failed\]|^--- FAIL|^[\w./-]+\.go:\d+:\d+: \S|\b[1-9]\d* (?:failed|errors?)\b/m;
|
|
10021
10076
|
GO_FAIL_EVIDENCE = /^FAIL\t\S+\t[\d.]+s$|^panic: /m;
|
|
10022
10077
|
GO_PKG_RE = /^(?:ok|FAIL|\?)\s+\S+\s+(?:\(cached\)|[\d.]+s\b|\[(?:no test files|build failed|setup failed)\])/;
|
|
@@ -10062,11 +10117,11 @@ var init_state = __esm(() => {
|
|
|
10062
10117
|
});
|
|
10063
10118
|
|
|
10064
10119
|
// ../../loki-ts/src/runner/repo_profile.ts
|
|
10065
|
-
import { existsSync as
|
|
10066
|
-
import { basename as
|
|
10120
|
+
import { existsSync as existsSync23, readFileSync as readFileSync30, mkdirSync as mkdirSync14, readdirSync as readdirSync14, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "fs";
|
|
10121
|
+
import { basename as basename12, join as join39, resolve as resolve13, isAbsolute as isAbsolute3 } from "path";
|
|
10067
10122
|
function loadProfile(repoDir) {
|
|
10068
10123
|
try {
|
|
10069
|
-
const p = JSON.parse(
|
|
10124
|
+
const p = JSON.parse(readFileSync30(commandProfilePath(repoDir), "utf8"));
|
|
10070
10125
|
return p?.version === 1 && Array.isArray(p.commands) && p.baseline ? p : null;
|
|
10071
10126
|
} catch {
|
|
10072
10127
|
return null;
|
|
@@ -10157,7 +10212,7 @@ async function staticPreExisting(tool, prefix, files, io) {
|
|
|
10157
10212
|
}
|
|
10158
10213
|
return attributeStatic(tool, head.out, baseOut, 1).preExisting;
|
|
10159
10214
|
}
|
|
10160
|
-
var commandProfilePath = (repoDir) =>
|
|
10215
|
+
var commandProfilePath = (repoDir) => join39(repoDir, ".loki", "state", "repo-profile.json"), STATIC_DIAG, STATIC_NOISE, STATIC_SUMMARY;
|
|
10161
10216
|
var init_repo_profile = __esm(() => {
|
|
10162
10217
|
init_failures();
|
|
10163
10218
|
init_check_result();
|
|
@@ -10199,14 +10254,14 @@ var init_context = __esm(() => {
|
|
|
10199
10254
|
});
|
|
10200
10255
|
|
|
10201
10256
|
// ../../loki-ts/src/util/steer.ts
|
|
10202
|
-
import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as
|
|
10257
|
+
import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as readdirSync15, lstatSync as lstatSync9, mkdirSync as mkdirSync15, linkSync as linkSync2, openSync as openSync8, readFileSync as readFileSync31, readSync as readSync7, renameSync as renameSync10, statSync as statSync15, lutimesSync, rmSync as rmSync9, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18, existsSync as existsSync24 } from "fs";
|
|
10203
10258
|
import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
|
|
10204
|
-
import { basename as
|
|
10259
|
+
import { basename as basename13, join as join40 } from "path";
|
|
10205
10260
|
function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
10206
10261
|
for (let i = 0;; i++) {
|
|
10207
10262
|
const name = i === 0 ? `${prefix}.md` : `${prefix}-${i}.md`;
|
|
10208
10263
|
try {
|
|
10209
|
-
link(src,
|
|
10264
|
+
link(src, join40(logs, name));
|
|
10210
10265
|
} catch (e) {
|
|
10211
10266
|
const code = e.code;
|
|
10212
10267
|
if (code === "EEXIST")
|
|
@@ -10214,7 +10269,7 @@ function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
|
10214
10269
|
if (code !== "EPERM" && code !== "ENOTSUP" && code !== "EXDEV" && code !== "EMLINK")
|
|
10215
10270
|
throw e;
|
|
10216
10271
|
const name2 = `${prefix}-${randomBytes4(4).toString("hex")}.md`;
|
|
10217
|
-
renameSync10(src,
|
|
10272
|
+
renameSync10(src, join40(logs, name2));
|
|
10218
10273
|
onLinked?.(name2);
|
|
10219
10274
|
return name2;
|
|
10220
10275
|
}
|
|
@@ -10229,14 +10284,14 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
10229
10284
|
const c = lstatSync9(claim);
|
|
10230
10285
|
if (!c.isFile())
|
|
10231
10286
|
return false;
|
|
10232
|
-
for (const a of
|
|
10287
|
+
for (const a of readdirSync15(logs)) {
|
|
10233
10288
|
if (!/^human-input-.*\.md$/.test(a))
|
|
10234
10289
|
continue;
|
|
10235
10290
|
try {
|
|
10236
|
-
const s = statSync15(
|
|
10291
|
+
const s = statSync15(join40(logs, a));
|
|
10237
10292
|
if (s.ino !== c.ino || s.dev !== c.dev)
|
|
10238
10293
|
continue;
|
|
10239
|
-
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) ||
|
|
10294
|
+
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) || existsSync24(appliedMarker(logs, a)))
|
|
10240
10295
|
return true;
|
|
10241
10296
|
} catch {}
|
|
10242
10297
|
}
|
|
@@ -10245,7 +10300,7 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
10245
10300
|
function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
10246
10301
|
let names;
|
|
10247
10302
|
try {
|
|
10248
|
-
names =
|
|
10303
|
+
names = readdirSync15(logs);
|
|
10249
10304
|
} catch {
|
|
10250
10305
|
return;
|
|
10251
10306
|
}
|
|
@@ -10253,7 +10308,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10253
10308
|
for (const n2 of names)
|
|
10254
10309
|
if (n2.startsWith(".applied-") && !present.has(n2.slice(".applied-".length))) {
|
|
10255
10310
|
try {
|
|
10256
|
-
unlinkSync5(
|
|
10311
|
+
unlinkSync5(join40(logs, n2));
|
|
10257
10312
|
} catch {}
|
|
10258
10313
|
}
|
|
10259
10314
|
for (const n2 of names) {
|
|
@@ -10270,7 +10325,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10270
10325
|
if (alive) {
|
|
10271
10326
|
let ageMs = 0;
|
|
10272
10327
|
try {
|
|
10273
|
-
ageMs = nowMs - statSync15(
|
|
10328
|
+
ageMs = nowMs - statSync15(join40(logs, n2)).mtimeMs;
|
|
10274
10329
|
} catch {
|
|
10275
10330
|
continue;
|
|
10276
10331
|
}
|
|
@@ -10278,11 +10333,11 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10278
10333
|
continue;
|
|
10279
10334
|
}
|
|
10280
10335
|
try {
|
|
10281
|
-
if (orphanAlreadyArchived(logs,
|
|
10282
|
-
unlinkSync5(
|
|
10336
|
+
if (orphanAlreadyArchived(logs, join40(logs, n2))) {
|
|
10337
|
+
unlinkSync5(join40(logs, n2));
|
|
10283
10338
|
continue;
|
|
10284
10339
|
}
|
|
10285
|
-
archiveTo(logs, `human-input-ORPHAN-${stamp2}`,
|
|
10340
|
+
archiveTo(logs, `human-input-ORPHAN-${stamp2}`, join40(logs, n2), link);
|
|
10286
10341
|
unapplied("orphaned claim");
|
|
10287
10342
|
} catch (e) {
|
|
10288
10343
|
if (e.code === "ENOENT")
|
|
@@ -10294,17 +10349,17 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10294
10349
|
function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, hooks2) {
|
|
10295
10350
|
if (/^(0|false)$/i.test(env.LOKI_PROMPT_INJECTION ?? ""))
|
|
10296
10351
|
return null;
|
|
10297
|
-
const f =
|
|
10352
|
+
const f = join40(repoDir, ".loki", "HUMAN_INPUT.md");
|
|
10298
10353
|
const unapplied = (reason) => {
|
|
10299
10354
|
sink?.push({ rev: 0, source: null, actor: null, sha: "", at: now2().getTime(), unapplied: true, reason });
|
|
10300
10355
|
};
|
|
10301
10356
|
let fd = -1, claimed = "";
|
|
10302
10357
|
try {
|
|
10303
|
-
const logs =
|
|
10358
|
+
const logs = join40(repoDir, ".loki", "logs");
|
|
10304
10359
|
mkdirSync15(logs, { recursive: true });
|
|
10305
10360
|
const stamp2 = now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "");
|
|
10306
10361
|
sweepOrphans(logs, stamp2, unapplied, hooks2?.link, now2().getTime());
|
|
10307
|
-
claimed =
|
|
10362
|
+
claimed = join40(logs, `.claim-${process.pid}-${randomBytes4(6).toString("hex")}`);
|
|
10308
10363
|
try {
|
|
10309
10364
|
renameSync10(f, claimed);
|
|
10310
10365
|
} catch (e) {
|
|
@@ -10395,10 +10450,10 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
10395
10450
|
} catch {
|
|
10396
10451
|
if (claimed) {
|
|
10397
10452
|
try {
|
|
10398
|
-
archiveTo(
|
|
10453
|
+
archiveTo(join40(repoDir, ".loki", "logs"), `human-input-${now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "")}`, claimed, hooks2?.link);
|
|
10399
10454
|
unapplied("logs dir unwritable or file unreadable");
|
|
10400
10455
|
} catch {
|
|
10401
|
-
unapplied(`steer stranded at .loki/logs/${
|
|
10456
|
+
unapplied(`steer stranded at .loki/logs/${basename13(claimed)}`);
|
|
10402
10457
|
}
|
|
10403
10458
|
} else
|
|
10404
10459
|
try {
|
|
@@ -10414,10 +10469,10 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
10414
10469
|
}
|
|
10415
10470
|
}
|
|
10416
10471
|
function recordRevisions(repoDir, text2, archived, at) {
|
|
10417
|
-
const file =
|
|
10472
|
+
const file = join40(repoDir, ".loki", "intent-revisions.jsonl");
|
|
10418
10473
|
let last = 0;
|
|
10419
10474
|
try {
|
|
10420
|
-
for (const l of
|
|
10475
|
+
for (const l of readFileSync31(file, "utf8").split(`
|
|
10421
10476
|
`)) {
|
|
10422
10477
|
try {
|
|
10423
10478
|
last = Math.max(last, Number(JSON.parse(l).rev) || 0);
|
|
@@ -10471,7 +10526,7 @@ function staleAtSeal(repoDir, ctx) {
|
|
|
10471
10526
|
const frozen = ctx.outputs === undefined || ctx.outputs().wall !== undefined || ctx.wallSealed === true;
|
|
10472
10527
|
return [...new Set([...staleWallRevisions(ctx.intentRevisions, frozen ? ctx.timeline : []), ...late])];
|
|
10473
10528
|
}
|
|
10474
|
-
var STEER_MAX_BYTES, STEER_STAGES, STEER_CLAIM_MAX_AGE_MS, appliedMarker = (logs, archive) =>
|
|
10529
|
+
var STEER_MAX_BYTES, STEER_STAGES, STEER_CLAIM_MAX_AGE_MS, appliedMarker = (logs, archive) => join40(logs, `.applied-${archive}`), REV_HDR, STEER_REMEDY;
|
|
10475
10530
|
var init_steer = __esm(() => {
|
|
10476
10531
|
init_context();
|
|
10477
10532
|
STEER_MAX_BYTES = 1024 * 1024;
|
|
@@ -10534,18 +10589,18 @@ var init_seal_drift = __esm(() => {
|
|
|
10534
10589
|
});
|
|
10535
10590
|
|
|
10536
10591
|
// ../../loki-ts/src/util/spec_file.ts
|
|
10537
|
-
import { isAbsolute as
|
|
10592
|
+
import { isAbsolute as isAbsolute4, join as join41, relative as relative2 } from "path";
|
|
10538
10593
|
function specReceiptBlock(env) {
|
|
10539
10594
|
const { LOKI_E10_SPEC_PATH: p, LOKI_E10_SPEC_SHA256: sha2 } = env;
|
|
10540
10595
|
if (!p || !sha2)
|
|
10541
10596
|
return {};
|
|
10542
|
-
const rel =
|
|
10597
|
+
const rel = isAbsolute4(p) && env.LOKI_E10_REPO_DIR ? relative2(env.LOKI_E10_REPO_DIR, p) : p;
|
|
10543
10598
|
return { spec: { path: rel, sha256: sha2 } };
|
|
10544
10599
|
}
|
|
10545
10600
|
var SPEC_DIR;
|
|
10546
10601
|
var init_spec_file = __esm(() => {
|
|
10547
10602
|
init_types();
|
|
10548
|
-
SPEC_DIR =
|
|
10603
|
+
SPEC_DIR = join41(".loki", "specs");
|
|
10549
10604
|
});
|
|
10550
10605
|
|
|
10551
10606
|
// ../../loki-ts/src/engine10/pr_body.ts
|
|
@@ -10565,11 +10620,11 @@ var init_run_cap = __esm(() => {
|
|
|
10565
10620
|
});
|
|
10566
10621
|
|
|
10567
10622
|
// ../../loki-ts/src/util/mutation_proof.ts
|
|
10568
|
-
import { existsSync as
|
|
10623
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync3, readFileSync as readFileSync32, rmSync as rmSync10, symlinkSync, writeFileSync as writeFileSync19 } from "fs";
|
|
10569
10624
|
import { tmpdir as tmpdir4 } from "os";
|
|
10570
|
-
import { basename as
|
|
10625
|
+
import { basename as basename14, dirname as dirname13, isAbsolute as isAbsolute5, join as join42, relative as relative3 } from "path";
|
|
10571
10626
|
function mutationProof(i) {
|
|
10572
|
-
const rels = i.wallFiles.map((f) =>
|
|
10627
|
+
const rels = i.wallFiles.map((f) => isAbsolute5(f.path) ? relative3(i.repoDir, f.path) : f.path);
|
|
10573
10628
|
if (rels.length === 0)
|
|
10574
10629
|
return np("no Wall tests");
|
|
10575
10630
|
const tests = rels.flatMap((rel) => {
|
|
@@ -10585,26 +10640,26 @@ function mutationProof(i) {
|
|
|
10585
10640
|
const deadline = Date.now() + budgetS * 1000, remaining = () => deadline - Date.now();
|
|
10586
10641
|
let parent = null, wt = null, added = false;
|
|
10587
10642
|
try {
|
|
10588
|
-
parent = mkdtempSync3(
|
|
10589
|
-
wt =
|
|
10643
|
+
parent = mkdtempSync3(join42(tmpdir4(), "loki-mutproof-"));
|
|
10644
|
+
wt = join42(parent, "wt");
|
|
10590
10645
|
const add3 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
|
|
10591
|
-
added =
|
|
10646
|
+
added = existsSync25(wt) || add3.status === 0;
|
|
10592
10647
|
if (add3.status !== 0)
|
|
10593
10648
|
return np("could not create the base worktree");
|
|
10594
10649
|
for (const rel of rels) {
|
|
10595
|
-
const sealed =
|
|
10596
|
-
if (!
|
|
10650
|
+
const sealed = join42(i.runDir, "wall", basename14(rel)), src = existsSync25(sealed) ? sealed : join42(i.repoDir, rel);
|
|
10651
|
+
if (!existsSync25(src))
|
|
10597
10652
|
return np(`Wall file missing: ${rel}`);
|
|
10598
|
-
mkdirSync16(dirname13(
|
|
10599
|
-
writeFileSync19(
|
|
10653
|
+
mkdirSync16(dirname13(join42(wt, rel)), { recursive: true });
|
|
10654
|
+
writeFileSync19(join42(wt, rel), readFileSync32(src));
|
|
10600
10655
|
}
|
|
10601
10656
|
for (const rel of rels) {
|
|
10602
10657
|
const parts = rel.split("/").slice(0, -1);
|
|
10603
10658
|
for (let n2 = 0;n2 <= parts.length; n2++) {
|
|
10604
10659
|
const anc = parts.slice(0, n2).join("/");
|
|
10605
10660
|
for (const d of DEP_DIRS) {
|
|
10606
|
-
const src =
|
|
10607
|
-
if (
|
|
10661
|
+
const src = join42(i.repoDir, anc, d), dst = join42(wt, anc, d);
|
|
10662
|
+
if (existsSync25(src) && !existsSync25(dst)) {
|
|
10608
10663
|
try {
|
|
10609
10664
|
symlinkSync(src, dst);
|
|
10610
10665
|
} catch {}
|
|
@@ -10732,7 +10787,7 @@ var init_shell = __esm(() => {
|
|
|
10732
10787
|
});
|
|
10733
10788
|
|
|
10734
10789
|
// ../../loki-ts/src/util/python.ts
|
|
10735
|
-
import { accessSync, constants as constants3, existsSync as
|
|
10790
|
+
import { accessSync, constants as constants3, existsSync as existsSync26, mkdtempSync as mkdtempSync4, readFileSync as readFileSync33, realpathSync as realpathSync17, rmSync as rmSync11, statSync as statSync16 } from "fs";
|
|
10736
10791
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10737
10792
|
import { tmpdir as tmpdir5 } from "os";
|
|
10738
10793
|
function resolvePython3() {
|
|
@@ -11073,7 +11128,7 @@ var init_wall_manifest = __esm(() => {
|
|
|
11073
11128
|
|
|
11074
11129
|
// ../../loki-ts/src/features/wall_manifest_wire.ts
|
|
11075
11130
|
import { createHash as createHash11 } from "crypto";
|
|
11076
|
-
import { basename as
|
|
11131
|
+
import { basename as basename15, dirname as dirname14 } from "path";
|
|
11077
11132
|
function blobEntries(ls) {
|
|
11078
11133
|
const out2 = [];
|
|
11079
11134
|
for (const raw2 of ls.toString("latin1").split("\x00")) {
|
|
@@ -11103,12 +11158,12 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
|
|
|
11103
11158
|
return null;
|
|
11104
11159
|
const low = task.toLowerCase().replace(/\\/g, "/");
|
|
11105
11160
|
const token = (n2) => new RegExp(`(?<![A-Za-z0-9_])${n2.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`).test(low);
|
|
11106
|
-
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(
|
|
11107
|
-
const matched = all.filter((e) => SOURCE.test(e.path) && (token(
|
|
11161
|
+
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename15(e.path)) && e.path.includes("/") && token(dirname14(e.path));
|
|
11162
|
+
const matched = all.filter((e) => SOURCE.test(e.path) && (token(basename15(e.path)) || token(e.path) || token(basename15(e.path).replace(/\.[^.]*$/, "")) || dirModule(e)));
|
|
11108
11163
|
const spans = (p) => [...low.matchAll(new RegExp(`(?<![A-Za-z0-9_])${p.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`, "g"))].map((m) => [m.index, m.index + m[0].length]);
|
|
11109
11164
|
const occ = new Map(matched.map((e) => [e, spans(e.path)]));
|
|
11110
11165
|
const exact = (e) => occ.get(e).some(([s, t]) => !matched.some((o) => o !== e && o.path.length > e.path.length && occ.get(o).some(([s2, t2]) => s2 <= s && t <= t2)));
|
|
11111
|
-
const byPath2 = matched.filter(exact).sort((a, b) => b.path.length - a.path.length), byBase = matched.filter((e) => !byPath2.includes(e) && token(
|
|
11166
|
+
const byPath2 = matched.filter(exact).sort((a, b) => b.path.length - a.path.length), byBase = matched.filter((e) => !byPath2.includes(e) && token(basename15(e.path)));
|
|
11112
11167
|
const named = [...byPath2, ...byBase, ...matched.filter((e) => !byPath2.includes(e) && !byBase.includes(e))].slice(0, MAX_NAMED);
|
|
11113
11168
|
const tests = all.filter((e) => TESTISH.test(e.path)).slice(0, MAX_FILES), listed = tests.filter((e) => !SOURCE.test(e.path));
|
|
11114
11169
|
const want = [...new Set([...all.filter((e) => CONFIG.test(e.path)), ...tests.filter((e) => SOURCE.test(e.path)), ...named])];
|
|
@@ -11165,9 +11220,9 @@ Example: test('name', () => { assert.strictEqual(fn(1), 2); }); Run: node --tes
|
|
|
11165
11220
|
|
|
11166
11221
|
// ../../loki-ts/src/util/holdout.ts
|
|
11167
11222
|
import { createHash as createHash12 } from "crypto";
|
|
11168
|
-
import { appendFileSync as appendFileSync3, copyFileSync as copyFileSync2, existsSync as
|
|
11223
|
+
import { appendFileSync as appendFileSync3, copyFileSync as copyFileSync2, existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync34, rmSync as rmSync12, writeFileSync as writeFileSync20 } from "fs";
|
|
11169
11224
|
import { tmpdir as tmpdir6 } from "os";
|
|
11170
|
-
import { basename as
|
|
11225
|
+
import { basename as basename16, join as join43, relative as relative4 } from "path";
|
|
11171
11226
|
function wallHoldoutRatio(env = process.env) {
|
|
11172
11227
|
if (env["LOKI_WALL_HOLDOUT"]?.trim() === "0")
|
|
11173
11228
|
return 0;
|
|
@@ -11195,32 +11250,32 @@ function stashHoldout(o) {
|
|
|
11195
11250
|
rmSync12(dir, { recursive: true, force: true });
|
|
11196
11251
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
11197
11252
|
const files = held.map((name) => {
|
|
11198
|
-
copyFileSync2(
|
|
11199
|
-
rmSync12(
|
|
11200
|
-
return { name, runner: o.runnerOf(name), sha256: sha2(
|
|
11253
|
+
copyFileSync2(join43(o.srcDir, name), join43(dir, name));
|
|
11254
|
+
rmSync12(join43(o.srcDir, name), { force: true });
|
|
11255
|
+
return { name, runner: o.runnerOf(name), sha256: sha2(readFileSync34(join43(dir, name), "utf8")) };
|
|
11201
11256
|
});
|
|
11202
|
-
writeFileSync20(
|
|
11257
|
+
writeFileSync20(join43(dir, MANIFEST), JSON.stringify({ targetDir: o.targetDir, files }));
|
|
11203
11258
|
return { dir, names: new Set(held) };
|
|
11204
11259
|
}
|
|
11205
11260
|
function stageHoldout(dir, repoDir) {
|
|
11206
11261
|
const put = [], tests = [], missing = [];
|
|
11207
11262
|
let man = null;
|
|
11208
11263
|
try {
|
|
11209
|
-
man = JSON.parse(
|
|
11264
|
+
man = JSON.parse(readFileSync34(join43(dir, MANIFEST), "utf8"));
|
|
11210
11265
|
} catch {}
|
|
11211
11266
|
if (!man)
|
|
11212
|
-
return { tests, missing: [`holdout store unreadable: ${
|
|
11267
|
+
return { tests, missing: [`holdout store unreadable: ${basename16(dir)}`], cleanup: () => {} };
|
|
11213
11268
|
mkdirSync17(man.targetDir, { recursive: true });
|
|
11214
11269
|
man.files.forEach((f, i) => {
|
|
11215
|
-
const src =
|
|
11216
|
-
if (!
|
|
11270
|
+
const src = join43(dir, f.name);
|
|
11271
|
+
if (!existsSync27(src) || sha2(readFileSync34(src, "utf8")) !== f.sha256) {
|
|
11217
11272
|
missing.push(`holdout ${i + 1} missing or altered`);
|
|
11218
11273
|
return;
|
|
11219
11274
|
}
|
|
11220
|
-
const dest =
|
|
11275
|
+
const dest = join43(man.targetDir, `loki_wall_holdout_${i + 1}${f.name.slice(f.name.indexOf("."))}`);
|
|
11221
11276
|
copyFileSync2(src, dest);
|
|
11222
11277
|
put.push(dest);
|
|
11223
|
-
tests.push({ runner: f.runner, path:
|
|
11278
|
+
tests.push({ runner: f.runner, path: relative4(repoDir, dest) });
|
|
11224
11279
|
});
|
|
11225
11280
|
return { tests, missing, cleanup: () => {
|
|
11226
11281
|
for (const p of put)
|
|
@@ -11230,16 +11285,16 @@ function stageHoldout(dir, repoDir) {
|
|
|
11230
11285
|
function recordHoldoutTriage(runDir, entry) {
|
|
11231
11286
|
try {
|
|
11232
11287
|
mkdirSync17(runDir, { recursive: true });
|
|
11233
|
-
appendFileSync3(
|
|
11288
|
+
appendFileSync3(join43(runDir, HOLDOUT_TRIAGE_FILE), JSON.stringify(entry) + `
|
|
11234
11289
|
`, { mode: 384 });
|
|
11235
11290
|
} catch {}
|
|
11236
11291
|
}
|
|
11237
|
-
var sha2 = (s) => createHash12("sha256").update(s).digest("hex"), WALL_HOLDOUT_DEFAULT_RATIO = 0.2, isHoldoutCheck = (name) => name.startsWith("holdout:"), holdoutDirFor = (runId, repoDir) =>
|
|
11292
|
+
var sha2 = (s) => createHash12("sha256").update(s).digest("hex"), WALL_HOLDOUT_DEFAULT_RATIO = 0.2, isHoldoutCheck = (name) => name.startsWith("holdout:"), holdoutDirFor = (runId, repoDir) => join43(tmpdir6(), `loki-e10-holdout-${sha2(`${runId}:${repoDir}`).slice(0, 16)}`), MANIFEST = "manifest.json", WALL_HOLDOUT_MIN = 5, HOLDOUT_TRIAGE_FILE = "holdout-triage.jsonl";
|
|
11238
11293
|
var init_holdout = () => {};
|
|
11239
11294
|
|
|
11240
11295
|
// ../../loki-ts/src/features/runner_config.ts
|
|
11241
|
-
import { readFileSync as
|
|
11242
|
-
import { dirname as dirname15, join as
|
|
11296
|
+
import { readFileSync as readFileSync35 } from "fs";
|
|
11297
|
+
import { dirname as dirname15, join as join44, normalize as normalize2 } from "path";
|
|
11243
11298
|
function tomlKey2(s, i = 0, eq2 = true) {
|
|
11244
11299
|
const parts = [], ws = () => {
|
|
11245
11300
|
while (/\s/.test(s[i] ?? "x"))
|
|
@@ -11516,8 +11571,8 @@ function referenced(cfg, text2) {
|
|
|
11516
11571
|
}
|
|
11517
11572
|
const dir = dirname15(cfg), explicit = ROOT_DIR.exec(text2), roots = [dir];
|
|
11518
11573
|
if (explicit)
|
|
11519
|
-
roots.push("", ...explicit[1] ? [
|
|
11520
|
-
return [...raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(
|
|
11574
|
+
roots.push("", ...explicit[1] ? [join44(dir, explicit[1])] : []);
|
|
11575
|
+
return [...raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(join44(root, r.replace(/^<rootDir>\/?/, ""))))), ...patchedTargets(cfg, text2).map((t) => normalize2(join44(dir, t)))];
|
|
11521
11576
|
}
|
|
11522
11577
|
function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
11523
11578
|
const notes = new Set, ch = new Set(changed.map((c) => normalize2(c)));
|
|
@@ -11597,7 +11652,7 @@ var PKG_KEYS, RAW_CONFIGS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, dep
|
|
|
11597
11652
|
}
|
|
11598
11653
|
}, headText = (dir, f) => {
|
|
11599
11654
|
try {
|
|
11600
|
-
return
|
|
11655
|
+
return readFileSync35(join44(dir, f), "utf8");
|
|
11601
11656
|
} catch {
|
|
11602
11657
|
return "";
|
|
11603
11658
|
}
|
|
@@ -11637,19 +11692,19 @@ var init_runner_config = __esm(() => {
|
|
|
11637
11692
|
|
|
11638
11693
|
// ../../loki-ts/src/e10ext/assert_delta.ts
|
|
11639
11694
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
11640
|
-
import { mkdtempSync as mkdtempSync5, readFileSync as
|
|
11695
|
+
import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync36, rmSync as rmSync13 } from "fs";
|
|
11641
11696
|
import { tmpdir as tmpdir7 } from "os";
|
|
11642
|
-
import { join as
|
|
11643
|
-
import { basename as
|
|
11697
|
+
import { join as join45 } from "path";
|
|
11698
|
+
import { basename as basename17 } from "path";
|
|
11644
11699
|
function classifyAssertDelta(inp) {
|
|
11645
|
-
const f =
|
|
11700
|
+
const f = basename17(inp.path);
|
|
11646
11701
|
if (!/^(test_.*|.*_test)\.py$/.test(f))
|
|
11647
11702
|
return WEAKENED;
|
|
11648
11703
|
if (inp.headCounts.run !== inp.baseCounts.run || inp.headCounts.skipped !== inp.baseCounts.skipped)
|
|
11649
11704
|
return WEAKENED;
|
|
11650
11705
|
let cwd = "";
|
|
11651
11706
|
try {
|
|
11652
|
-
cwd = mkdtempSync5(
|
|
11707
|
+
cwd = mkdtempSync5(join45(tmpdir7(), "loki-ad-"));
|
|
11653
11708
|
const raw2 = execFileSync3("python3", ["-I", "-c", PY], {
|
|
11654
11709
|
input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
|
|
11655
11710
|
cwd,
|
|
@@ -11680,7 +11735,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
|
|
|
11680
11735
|
return null;
|
|
11681
11736
|
try {
|
|
11682
11737
|
const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
|
|
11683
|
-
const head = headRef ? show(headRef) :
|
|
11738
|
+
const head = headRef ? show(headRef) : readFileSync36(join45(repoDir, path), "utf8");
|
|
11684
11739
|
const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
|
|
11685
11740
|
return r[0]?.kind === "literal-only" ? r.map((e) => `assertion value changed (not shown to be required by the task): ${e.file}:${e.line} ${e.old} -> ${e.new}`) : null;
|
|
11686
11741
|
} catch {
|
|
@@ -11887,19 +11942,19 @@ var init_runner_errors = __esm(() => {
|
|
|
11887
11942
|
|
|
11888
11943
|
// ../../loki-ts/src/runner/load_owner.ts
|
|
11889
11944
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
11890
|
-
import { mkdtempSync as mkdtempSync6, realpathSync as
|
|
11945
|
+
import { mkdtempSync as mkdtempSync6, realpathSync as realpathSync18, rmSync as rmSync14 } from "fs";
|
|
11891
11946
|
import { tmpdir as tmpdir8 } from "os";
|
|
11892
|
-
import { basename as
|
|
11947
|
+
import { basename as basename18, extname as extname2, join as join46 } from "path";
|
|
11893
11948
|
function changedFilesNamed(out2, repoDir, changed) {
|
|
11894
11949
|
return changed.filter((f) => {
|
|
11895
|
-
if (out2.includes(f) || out2.includes(
|
|
11950
|
+
if (out2.includes(f) || out2.includes(join46(repoDir, f)))
|
|
11896
11951
|
return true;
|
|
11897
11952
|
const segs = f.split("/");
|
|
11898
11953
|
if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
|
|
11899
11954
|
return true;
|
|
11900
|
-
if (
|
|
11955
|
+
if (extname2(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
|
|
11901
11956
|
return true;
|
|
11902
|
-
const stem =
|
|
11957
|
+
const stem = basename18(f, extname2(f));
|
|
11903
11958
|
if (stem.length < 2 || stem === "index" || stem === "__init__")
|
|
11904
11959
|
return false;
|
|
11905
11960
|
return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
|
|
@@ -11909,7 +11964,7 @@ function loadSignature(out2, roots) {
|
|
|
11909
11964
|
let o = out2;
|
|
11910
11965
|
for (const r of roots.flatMap((x) => {
|
|
11911
11966
|
try {
|
|
11912
|
-
return [x,
|
|
11967
|
+
return [x, realpathSync18(x)];
|
|
11913
11968
|
} catch {
|
|
11914
11969
|
return [x];
|
|
11915
11970
|
}
|
|
@@ -12003,7 +12058,7 @@ async function loadErrorIsHarnessOwned(i) {
|
|
|
12003
12058
|
return false;
|
|
12004
12059
|
if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
|
|
12005
12060
|
return false;
|
|
12006
|
-
const dir = mkdtempSync6(
|
|
12061
|
+
const dir = mkdtempSync6(join46(tmpdir8(), "e10-loadown-"));
|
|
12007
12062
|
const git3 = (args) => {
|
|
12008
12063
|
safeGit(i.repoDir, args, { stdio: "ignore" });
|
|
12009
12064
|
};
|
|
@@ -12035,7 +12090,7 @@ var init_load_owner = __esm(() => {
|
|
|
12035
12090
|
});
|
|
12036
12091
|
|
|
12037
12092
|
// ../../loki-ts/src/util/wall_owned.ts
|
|
12038
|
-
import { isAbsolute as
|
|
12093
|
+
import { isAbsolute as isAbsolute6, join as join47, relative as relative5 } from "path";
|
|
12039
12094
|
function failingLocations(raw2, cwd, repoDir) {
|
|
12040
12095
|
const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
|
|
12041
12096
|
`), files = new Set;
|
|
@@ -12067,7 +12122,7 @@ function failingLocations(raw2, cwd, repoDir) {
|
|
|
12067
12122
|
}
|
|
12068
12123
|
if (errors2 === 0 || located !== errors2)
|
|
12069
12124
|
return null;
|
|
12070
|
-
return [...files].map((f) =>
|
|
12125
|
+
return [...files].map((f) => relative5(repoDir, isAbsolute6(f) ? f : join47(cwd, f)));
|
|
12071
12126
|
}
|
|
12072
12127
|
function wallOwnedFailure(raw2, cwd, repoDir, wall) {
|
|
12073
12128
|
const locs = failingLocations(raw2, cwd, repoDir);
|
|
@@ -12081,21 +12136,21 @@ var init_wall_owned = __esm(() => {
|
|
|
12081
12136
|
// ../../loki-ts/src/project_graph.ts
|
|
12082
12137
|
import { createHash as createHash13 } from "crypto";
|
|
12083
12138
|
import {
|
|
12084
|
-
existsSync as
|
|
12085
|
-
readdirSync as
|
|
12086
|
-
readFileSync as
|
|
12139
|
+
existsSync as existsSync28,
|
|
12140
|
+
readdirSync as readdirSync16,
|
|
12141
|
+
readFileSync as readFileSync37,
|
|
12087
12142
|
statSync as statSync17,
|
|
12088
12143
|
writeFileSync as writeFileSync21,
|
|
12089
12144
|
mkdirSync as mkdirSync18
|
|
12090
12145
|
} from "fs";
|
|
12091
|
-
import { basename as
|
|
12146
|
+
import { basename as basename19, dirname as dirname16, join as join48, resolve as resolve14 } from "path";
|
|
12092
12147
|
function readManifest(path) {
|
|
12093
|
-
if (!
|
|
12148
|
+
if (!existsSync28(path)) {
|
|
12094
12149
|
return null;
|
|
12095
12150
|
}
|
|
12096
12151
|
let raw2;
|
|
12097
12152
|
try {
|
|
12098
|
-
raw2 =
|
|
12153
|
+
raw2 = readFileSync37(path, "utf8");
|
|
12099
12154
|
} catch {
|
|
12100
12155
|
return null;
|
|
12101
12156
|
}
|
|
@@ -12132,7 +12187,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12132
12187
|
const seen = new Set;
|
|
12133
12188
|
let children;
|
|
12134
12189
|
try {
|
|
12135
|
-
children =
|
|
12190
|
+
children = readdirSync16(rootDir);
|
|
12136
12191
|
} catch {
|
|
12137
12192
|
children = [];
|
|
12138
12193
|
}
|
|
@@ -12147,7 +12202,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12147
12202
|
for (const child of children) {
|
|
12148
12203
|
if (!matchPattern(name, child))
|
|
12149
12204
|
continue;
|
|
12150
|
-
const full =
|
|
12205
|
+
const full = join48(rootDir, child);
|
|
12151
12206
|
if (seen.has(full))
|
|
12152
12207
|
continue;
|
|
12153
12208
|
let st;
|
|
@@ -12164,7 +12219,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12164
12219
|
}
|
|
12165
12220
|
if (declared.length === 0) {
|
|
12166
12221
|
for (const child of children) {
|
|
12167
|
-
const full =
|
|
12222
|
+
const full = join48(rootDir, child);
|
|
12168
12223
|
if (seen.has(full))
|
|
12169
12224
|
continue;
|
|
12170
12225
|
let st;
|
|
@@ -12175,7 +12230,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12175
12230
|
}
|
|
12176
12231
|
if (!st.isDirectory())
|
|
12177
12232
|
continue;
|
|
12178
|
-
if (!
|
|
12233
|
+
if (!existsSync28(join48(full, ".loki", "app.json")))
|
|
12179
12234
|
continue;
|
|
12180
12235
|
seen.add(full);
|
|
12181
12236
|
out2.push(full);
|
|
@@ -12196,26 +12251,26 @@ function cacheKey(manifestPaths) {
|
|
|
12196
12251
|
}
|
|
12197
12252
|
function writeCache(targetDir, key, result) {
|
|
12198
12253
|
try {
|
|
12199
|
-
const cacheDir =
|
|
12254
|
+
const cacheDir = join48(targetDir, ".loki", "state");
|
|
12200
12255
|
mkdirSync18(cacheDir, { recursive: true });
|
|
12201
|
-
const cachePath =
|
|
12256
|
+
const cachePath = join48(cacheDir, "project-graph.json");
|
|
12202
12257
|
writeFileSync21(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
|
|
12203
12258
|
} catch {}
|
|
12204
12259
|
}
|
|
12205
12260
|
function discoverProjectGraph(targetDir) {
|
|
12206
12261
|
const absTarget = resolve14(targetDir);
|
|
12207
|
-
const targetManifest =
|
|
12262
|
+
const targetManifest = join48(absTarget, ".loki", "app.json");
|
|
12208
12263
|
const parentDir = dirname16(absTarget);
|
|
12209
|
-
const parentManifest =
|
|
12264
|
+
const parentManifest = join48(parentDir, ".loki", "app.json");
|
|
12210
12265
|
const examined = [];
|
|
12211
12266
|
let chosenManifest = null;
|
|
12212
12267
|
let chosenRoot = "";
|
|
12213
|
-
if (
|
|
12268
|
+
if (existsSync28(parentManifest) && parentDir !== absTarget) {
|
|
12214
12269
|
examined.push(parentManifest);
|
|
12215
12270
|
chosenManifest = readManifest(parentManifest);
|
|
12216
12271
|
chosenRoot = parentDir;
|
|
12217
12272
|
}
|
|
12218
|
-
if (!chosenManifest &&
|
|
12273
|
+
if (!chosenManifest && existsSync28(targetManifest)) {
|
|
12219
12274
|
examined.push(targetManifest);
|
|
12220
12275
|
chosenManifest = readManifest(targetManifest);
|
|
12221
12276
|
chosenRoot = absTarget;
|
|
@@ -12223,11 +12278,11 @@ function discoverProjectGraph(targetDir) {
|
|
|
12223
12278
|
if (!chosenManifest)
|
|
12224
12279
|
return null;
|
|
12225
12280
|
const declared = chosenManifest.members ?? [];
|
|
12226
|
-
const members = resolveMembers(chosenRoot, declared,
|
|
12281
|
+
const members = resolveMembers(chosenRoot, declared, basename19(absTarget));
|
|
12227
12282
|
const filtered = [];
|
|
12228
12283
|
for (const m of members) {
|
|
12229
|
-
const sibManifestPath =
|
|
12230
|
-
if (
|
|
12284
|
+
const sibManifestPath = join48(m, ".loki", "app.json");
|
|
12285
|
+
if (existsSync28(sibManifestPath)) {
|
|
12231
12286
|
examined.push(sibManifestPath);
|
|
12232
12287
|
const sibManifest = readManifest(sibManifestPath);
|
|
12233
12288
|
if (sibManifest && sibManifest.app_id !== chosenManifest.app_id) {
|
|
@@ -12355,9 +12410,9 @@ var init_route_block = __esm(() => {
|
|
|
12355
12410
|
// ../../loki-ts/src/features/visual_evidence.ts
|
|
12356
12411
|
import { spawn as spawn7 } from "child_process";
|
|
12357
12412
|
import { createHash as createHash14, randomBytes as randomBytes5 } from "crypto";
|
|
12358
|
-
import { existsSync as
|
|
12413
|
+
import { existsSync as existsSync29, lstatSync as lstatSync10, mkdirSync as mkdirSync19, readdirSync as readdirSync17, readFileSync as readFileSync38, writeFileSync as writeFileSync22 } from "fs";
|
|
12359
12414
|
import { createServer } from "net";
|
|
12360
|
-
import { dirname as dirname17, isAbsolute as
|
|
12415
|
+
import { dirname as dirname17, isAbsolute as isAbsolute7, join as join49, normalize as normalize3, relative as relative6, sep as sep11 } from "path";
|
|
12361
12416
|
function routeFor(file) {
|
|
12362
12417
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
12363
12418
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -12367,7 +12422,7 @@ function hashScreens(runDir, rels) {
|
|
|
12367
12422
|
const out2 = [];
|
|
12368
12423
|
for (const rel of rels) {
|
|
12369
12424
|
try {
|
|
12370
|
-
out2.push({ path: rel, sha256: sha256File(
|
|
12425
|
+
out2.push({ path: rel, sha256: sha256File(join49(runDir, rel)) });
|
|
12371
12426
|
} catch {}
|
|
12372
12427
|
}
|
|
12373
12428
|
return out2;
|
|
@@ -12378,16 +12433,16 @@ function checkScreens(runDir, screens) {
|
|
|
12378
12433
|
for (const s of screens) {
|
|
12379
12434
|
if (typeof s?.path !== "string" || typeof s.sha256 !== "string")
|
|
12380
12435
|
return "evidence_screens entry is malformed";
|
|
12381
|
-
if (
|
|
12436
|
+
if (isAbsolute7(s.path) || normalize3(s.path).startsWith(".."))
|
|
12382
12437
|
return `evidence screenshot path escapes the evidence dir: ${s.path}`;
|
|
12383
|
-
const file =
|
|
12438
|
+
const file = join49(runDir, s.path);
|
|
12384
12439
|
let cur = runDir;
|
|
12385
|
-
for (const seg of normalize3(s.path).split(
|
|
12386
|
-
cur =
|
|
12440
|
+
for (const seg of normalize3(s.path).split(sep11)) {
|
|
12441
|
+
cur = join49(cur, seg);
|
|
12387
12442
|
if (isSymlink(cur))
|
|
12388
12443
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
12389
12444
|
}
|
|
12390
|
-
if (!
|
|
12445
|
+
if (!existsSync29(file))
|
|
12391
12446
|
return `evidence screenshot is missing: ${s.path}`;
|
|
12392
12447
|
if (!isRegularFile(file))
|
|
12393
12448
|
return `evidence screenshot is not a regular file: ${s.path}`;
|
|
@@ -12430,11 +12485,11 @@ async function waitUp(url, ms, signal) {
|
|
|
12430
12485
|
}
|
|
12431
12486
|
function openapiPaths(repoDir) {
|
|
12432
12487
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
12433
|
-
const p =
|
|
12434
|
-
if (!
|
|
12488
|
+
const p = join49(repoDir, f);
|
|
12489
|
+
if (!existsSync29(p))
|
|
12435
12490
|
continue;
|
|
12436
12491
|
try {
|
|
12437
|
-
const txt =
|
|
12492
|
+
const txt = readFileSync38(p, "utf8");
|
|
12438
12493
|
const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
|
|
12439
12494
|
return paths.filter((x) => !x.includes("{")).slice(0, 10);
|
|
12440
12495
|
} catch {
|
|
@@ -12448,24 +12503,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
|
|
|
12448
12503
|
if (!pw || !pkg)
|
|
12449
12504
|
return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
|
|
12450
12505
|
try {
|
|
12451
|
-
const dir =
|
|
12506
|
+
const dir = join49(runDir, relDir, "e2e");
|
|
12452
12507
|
mkdirSync19(dir, { recursive: true });
|
|
12453
|
-
writeFileSync22(
|
|
12454
|
-
writeFileSync22(
|
|
12508
|
+
writeFileSync22(join49(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
|
|
12509
|
+
writeFileSync22(join49(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
|
|
12455
12510
|
`);
|
|
12456
|
-
if (!await shoot(pw, ["test", "--config",
|
|
12511
|
+
if (!await shoot(pw, ["test", "--config", join49(dir, "playwright.config.cjs")], repoDir, ms, signal))
|
|
12457
12512
|
return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
|
|
12458
12513
|
const rels = [];
|
|
12459
12514
|
const walk = (d) => {
|
|
12460
|
-
for (const e of
|
|
12461
|
-
const full =
|
|
12515
|
+
for (const e of readdirSync17(d, { withFileTypes: true })) {
|
|
12516
|
+
const full = join49(d, e.name);
|
|
12462
12517
|
if (e.isDirectory())
|
|
12463
12518
|
walk(full);
|
|
12464
12519
|
else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
|
|
12465
|
-
rels.push(
|
|
12520
|
+
rels.push(join49(relDir, "e2e", relative6(dir, full)));
|
|
12466
12521
|
}
|
|
12467
12522
|
};
|
|
12468
|
-
walk(
|
|
12523
|
+
walk(join49(dir, "out"));
|
|
12469
12524
|
return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
|
|
12470
12525
|
} catch (e) {
|
|
12471
12526
|
return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
|
|
@@ -12544,22 +12599,22 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12544
12599
|
if (!visualEvidenceEnabled(opts.env))
|
|
12545
12600
|
return skip("LOKI_VISUAL_EVIDENCE is 0");
|
|
12546
12601
|
const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
|
|
12547
|
-
const appDir = boot ?
|
|
12548
|
-
const pkgPath =
|
|
12602
|
+
const appDir = boot ? join49(repoDir, boot.boot.cwd) : repoDir;
|
|
12603
|
+
const pkgPath = join49(appDir, "package.json");
|
|
12549
12604
|
let script = null;
|
|
12550
12605
|
if (!boot) {
|
|
12551
|
-
if (!
|
|
12552
|
-
const subs = ["backend", "frontend"].filter((d) =>
|
|
12606
|
+
if (!existsSync29(pkgPath)) {
|
|
12607
|
+
const subs = ["backend", "frontend"].filter((d) => existsSync29(join49(repoDir, d, "package.json")));
|
|
12553
12608
|
const has = (d) => {
|
|
12554
12609
|
try {
|
|
12555
|
-
return pickScript(JSON.parse(
|
|
12610
|
+
return pickScript(JSON.parse(readFileSync38(join49(repoDir, d, "package.json"), "utf8"))) !== null;
|
|
12556
12611
|
} catch {
|
|
12557
12612
|
return false;
|
|
12558
12613
|
}
|
|
12559
12614
|
};
|
|
12560
12615
|
return skip(noRootReason(subs, subs.filter((d) => !has(d))));
|
|
12561
12616
|
}
|
|
12562
|
-
script = pickScript(JSON.parse(
|
|
12617
|
+
script = pickScript(JSON.parse(readFileSync38(pkgPath, "utf8")));
|
|
12563
12618
|
if (!script)
|
|
12564
12619
|
return skip("no dev, preview or start script");
|
|
12565
12620
|
}
|
|
@@ -12586,20 +12641,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12586
12641
|
}
|
|
12587
12642
|
if (!await waitUp(base, left(), signal))
|
|
12588
12643
|
return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
|
|
12589
|
-
const evRoot =
|
|
12644
|
+
const evRoot = join49(runDir, "evidence");
|
|
12590
12645
|
if (isSymlink(evRoot))
|
|
12591
12646
|
return skip("evidence dir is a symlink");
|
|
12592
12647
|
mkdirSync19(evRoot, { recursive: true });
|
|
12593
12648
|
if (pages.length > 0) {
|
|
12594
|
-
const rel0 =
|
|
12595
|
-
mkdirSync19(
|
|
12649
|
+
const rel0 = join49("evidence", randomBytes5(6).toString("hex"));
|
|
12650
|
+
mkdirSync19(join49(runDir, rel0));
|
|
12596
12651
|
const rels = [];
|
|
12597
12652
|
for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
|
|
12598
12653
|
if (aborted() || left() <= 0)
|
|
12599
12654
|
break;
|
|
12600
|
-
const rel =
|
|
12601
|
-
const ok = await shoot(pw, ["screenshot", `${base}${route}`,
|
|
12602
|
-
if (ok && !aborted() && !isSymlink(
|
|
12655
|
+
const rel = join49(rel0, `${screenName(route)}.png`);
|
|
12656
|
+
const ok = await shoot(pw, ["screenshot", `${base}${route}`, join49(runDir, rel)], appDir, left(), signal);
|
|
12657
|
+
if (ok && !aborted() && !isSymlink(join49(runDir, rel)) && existsSync29(join49(runDir, rel)))
|
|
12603
12658
|
rels.push(rel);
|
|
12604
12659
|
}
|
|
12605
12660
|
if (aborted())
|
|
@@ -12624,9 +12679,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12624
12679
|
}
|
|
12625
12680
|
if (aborted())
|
|
12626
12681
|
return skip("aborted");
|
|
12627
|
-
const hdir =
|
|
12682
|
+
const hdir = join49(evRoot, randomBytes5(6).toString("hex"));
|
|
12628
12683
|
mkdirSync19(hdir);
|
|
12629
|
-
writeFileSync22(
|
|
12684
|
+
writeFileSync22(join49(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
|
|
12630
12685
|
`);
|
|
12631
12686
|
return { screens: [], http: true, skipped: null };
|
|
12632
12687
|
} catch (e) {
|
|
@@ -12655,12 +12710,12 @@ function receiptScreensProblem(receiptPath, receipt) {
|
|
|
12655
12710
|
return `visual evidence failed (LOKI_VISUAL_GATE=1): ${receipt["evidence_failed"]}`;
|
|
12656
12711
|
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname17(receiptPath), receipt["evidence_screens"]);
|
|
12657
12712
|
}
|
|
12658
|
-
var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0", visualGateEnabled = (env = process.env) => env["LOKI_VISUAL_GATE"] === "1", PAGE_RE, isPageFile = (p) => PAGE_RE.test(p), screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index", sha256File = (p) => createHash14("sha256").update(
|
|
12659
|
-
const bin =
|
|
12660
|
-
return
|
|
12713
|
+
var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0", visualGateEnabled = (env = process.env) => env["LOKI_VISUAL_GATE"] === "1", PAGE_RE, isPageFile = (p) => PAGE_RE.test(p), screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index", sha256File = (p) => createHash14("sha256").update(readFileSync38(p)).digest("hex"), playwrightBin = (repoDir) => {
|
|
12714
|
+
const bin = join49(repoDir, "node_modules", ".bin", "playwright");
|
|
12715
|
+
return existsSync29(bin) ? bin : null;
|
|
12661
12716
|
}, playwrightTestPkg = (repoDir) => {
|
|
12662
|
-
const d =
|
|
12663
|
-
return
|
|
12717
|
+
const d = join49(repoDir, "node_modules", "@playwright", "test");
|
|
12718
|
+
return existsSync29(join49(d, "package.json")) ? d : null;
|
|
12664
12719
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
12665
12720
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
12666
12721
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -12703,7 +12758,7 @@ var init_outbox = __esm(() => {
|
|
|
12703
12758
|
});
|
|
12704
12759
|
|
|
12705
12760
|
// ../../loki-ts/src/engine10/stages/pr.ts
|
|
12706
|
-
import { join as
|
|
12761
|
+
import { join as join50 } from "path";
|
|
12707
12762
|
var DEFAULT_PUSH_SH;
|
|
12708
12763
|
var init_pr = __esm(() => {
|
|
12709
12764
|
init_types();
|
|
@@ -12720,19 +12775,19 @@ var init_pr = __esm(() => {
|
|
|
12720
12775
|
init_run_outputs();
|
|
12721
12776
|
init_yaml_key();
|
|
12722
12777
|
init_outbox();
|
|
12723
|
-
DEFAULT_PUSH_SH =
|
|
12778
|
+
DEFAULT_PUSH_SH = join50(REPO_ROOT, "autonomy/lib/engine10-push.sh");
|
|
12724
12779
|
});
|
|
12725
12780
|
|
|
12726
12781
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
12727
|
-
import { existsSync as
|
|
12728
|
-
import { dirname as dirname18, join as
|
|
12782
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync20, mkdtempSync as mkdtempSync7, readFileSync as readFileSync39, rmSync as rmSync15, writeFileSync as writeFileSync23 } from "fs";
|
|
12783
|
+
import { dirname as dirname18, join as join51 } from "path";
|
|
12729
12784
|
import { createHash as createHash15 } from "crypto";
|
|
12730
12785
|
function loadLessons(repoDir) {
|
|
12731
12786
|
const p = lessonsPath(repoDir);
|
|
12732
|
-
if (!
|
|
12787
|
+
if (!existsSync30(p))
|
|
12733
12788
|
return [];
|
|
12734
12789
|
try {
|
|
12735
|
-
const j = JSON.parse(
|
|
12790
|
+
const j = JSON.parse(readFileSync39(p, "utf-8"));
|
|
12736
12791
|
return Array.isArray(j.lessons) ? j.lessons : [];
|
|
12737
12792
|
} catch {
|
|
12738
12793
|
return [];
|
|
@@ -12774,7 +12829,7 @@ function recordRunVerdict(repoDir, runId, verdict) {
|
|
|
12774
12829
|
if (dirty)
|
|
12775
12830
|
save(repoDir, lessons);
|
|
12776
12831
|
}
|
|
12777
|
-
var lessonsPath = (repoDir) =>
|
|
12832
|
+
var lessonsPath = (repoDir) => join51(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
|
|
12778
12833
|
var init_pr_lessons = __esm(() => {
|
|
12779
12834
|
init_atomic();
|
|
12780
12835
|
init_safe_git();
|
|
@@ -12806,7 +12861,7 @@ var init_attempts = __esm(() => {
|
|
|
12806
12861
|
var init_mcp_config = () => {};
|
|
12807
12862
|
|
|
12808
12863
|
// ../../loki-ts/src/providers/claude_flags.ts
|
|
12809
|
-
import { existsSync as
|
|
12864
|
+
import { existsSync as existsSync31, readFileSync as readFileSync40 } from "fs";
|
|
12810
12865
|
import { resolve as resolvePath, dirname as dirname19 } from "path";
|
|
12811
12866
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12812
12867
|
function claudeFlagSupported(flag, helpText) {
|
|
@@ -12860,8 +12915,8 @@ function designArchetypesText() {
|
|
|
12860
12915
|
["..", "..", "references", "design-archetypes.md"]
|
|
12861
12916
|
]) {
|
|
12862
12917
|
const p = resolvePath(moduleDir, ...rel);
|
|
12863
|
-
if (
|
|
12864
|
-
return
|
|
12918
|
+
if (existsSync31(p))
|
|
12919
|
+
return readFileSync40(p, "utf8");
|
|
12865
12920
|
}
|
|
12866
12921
|
} catch {}
|
|
12867
12922
|
return "";
|
|
@@ -12945,14 +13000,14 @@ var init_providers = __esm(() => {
|
|
|
12945
13000
|
});
|
|
12946
13001
|
|
|
12947
13002
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
12948
|
-
import { existsSync as
|
|
12949
|
-
import { join as
|
|
13003
|
+
import { existsSync as existsSync32, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
|
|
13004
|
+
import { join as join52 } from "path";
|
|
12950
13005
|
function loadRouteRecord(runDir) {
|
|
12951
13006
|
try {
|
|
12952
|
-
const p =
|
|
12953
|
-
if (!
|
|
13007
|
+
const p = join52(runDir, ROUTE_RECORD_FILE);
|
|
13008
|
+
if (!existsSync32(p) || !lstatSync11(p).isFile())
|
|
12954
13009
|
return;
|
|
12955
|
-
const v = JSON.parse(
|
|
13010
|
+
const v = JSON.parse(readFileSync41(p, "utf8"));
|
|
12956
13011
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
|
|
12957
13012
|
} catch {
|
|
12958
13013
|
return;
|
|
@@ -13079,7 +13134,7 @@ var init_worker = __esm(() => {
|
|
|
13079
13134
|
});
|
|
13080
13135
|
|
|
13081
13136
|
// ../../loki-ts/src/project_model/package_suite.ts
|
|
13082
|
-
import { join as
|
|
13137
|
+
import { join as join53 } from "path";
|
|
13083
13138
|
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
13084
13139
|
const api = loadProjectApi(repoDir);
|
|
13085
13140
|
if (!isMultiRoot(api))
|
|
@@ -13090,7 +13145,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13090
13145
|
for (const pkg of withTests) {
|
|
13091
13146
|
const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
|
|
13092
13147
|
const started = Date.now();
|
|
13093
|
-
const r = await run(["bash", "-c", tc.cmd], { cwd:
|
|
13148
|
+
const r = await run(["bash", "-c", tc.cmd], { cwd: join53(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
13094
13149
|
const duration_s = (Date.now() - started) / 1000;
|
|
13095
13150
|
if (signal.aborted) {
|
|
13096
13151
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
@@ -13099,7 +13154,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13099
13154
|
}
|
|
13100
13155
|
const out2 = `${r.stdout}
|
|
13101
13156
|
${r.stderr}`;
|
|
13102
|
-
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd:
|
|
13157
|
+
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd: join53(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
13103
13158
|
if (lr) {
|
|
13104
13159
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
13105
13160
|
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
@@ -13133,14 +13188,14 @@ __export(exports_deep, {
|
|
|
13133
13188
|
DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
|
|
13134
13189
|
DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH2
|
|
13135
13190
|
});
|
|
13136
|
-
import { existsSync as
|
|
13191
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync8, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "fs";
|
|
13137
13192
|
import { tmpdir as tmpdir9 } from "os";
|
|
13138
|
-
import { join as
|
|
13193
|
+
import { join as join54 } from "path";
|
|
13139
13194
|
function sessionCouncil(sessions) {
|
|
13140
13195
|
return { async run(input, signal) {
|
|
13141
|
-
const cwd = mkdtempSync8(
|
|
13196
|
+
const cwd = mkdtempSync8(join54(tmpdir9(), "loki-deep-council-"));
|
|
13142
13197
|
try {
|
|
13143
|
-
writeFileSync25(
|
|
13198
|
+
writeFileSync25(join54(cwd, "diff.patch"), input.diff, "utf8");
|
|
13144
13199
|
const r = await sessions.run({
|
|
13145
13200
|
stage: "deep",
|
|
13146
13201
|
tier: "development",
|
|
@@ -13250,7 +13305,7 @@ async function runCouncilCheck(ctx, changed, baseSha, signal, opts, checks, notP
|
|
|
13250
13305
|
async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
13251
13306
|
const scriptPath = opts.secretScanShPath ?? DEFAULT_SECRET_SCAN_SH;
|
|
13252
13307
|
const name = "security scan";
|
|
13253
|
-
if (!
|
|
13308
|
+
if (!existsSync33(scriptPath)) {
|
|
13254
13309
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: 0 });
|
|
13255
13310
|
notProven.add(`not run: ${name} (secret-scan.sh not found)`);
|
|
13256
13311
|
return;
|
|
@@ -13261,7 +13316,7 @@ async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
|
13261
13316
|
}
|
|
13262
13317
|
const inline = 'script="$1"; shift; . "$script" || exit 3; hit=0; for f in "$@"; do if _commit_scan_secret_file "$f" || _commit_path_looks_secret "$f"; then printf "%s\\n" "$f"; hit=1; fi; done; exit "$hit"';
|
|
13263
13318
|
const started = Date.now();
|
|
13264
|
-
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) =>
|
|
13319
|
+
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) => join54(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
|
|
13265
13320
|
const durationS = (Date.now() - started) / 1000;
|
|
13266
13321
|
if (r.exitCode === 3) {
|
|
13267
13322
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: durationS });
|
|
@@ -13296,7 +13351,7 @@ async function postResults(ctx, opts, checks, notProven, statusState) {
|
|
|
13296
13351
|
const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
|
|
13297
13352
|
if (prNumber) {
|
|
13298
13353
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13299
|
-
const bodyFile =
|
|
13354
|
+
const bodyFile = join54(ctx.runDir, "deep-comment.md");
|
|
13300
13355
|
writeFileSync25(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
|
|
13301
13356
|
const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
|
|
13302
13357
|
if (commentResult.exitCode !== 0)
|
|
@@ -13350,7 +13405,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
13350
13405
|
const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
|
|
13351
13406
|
const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
13352
13407
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13353
|
-
writeFileSync25(
|
|
13408
|
+
writeFileSync25(join54(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
|
|
13354
13409
|
`);
|
|
13355
13410
|
const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
|
|
13356
13411
|
const allNotProven = [...notProvenList, ...pushNotProven];
|
|
@@ -13394,20 +13449,20 @@ var init_deep = __esm(() => {
|
|
|
13394
13449
|
});
|
|
13395
13450
|
|
|
13396
13451
|
// ../../loki-ts/src/engine10/stages/verify.ts
|
|
13397
|
-
import { existsSync as
|
|
13452
|
+
import { existsSync as existsSync34, mkdtempSync as mkdtempSync9, realpathSync as realpathSync19, rmSync as rmSync17 } from "fs";
|
|
13398
13453
|
import { tmpdir as tmpdir10 } from "os";
|
|
13399
|
-
import { dirname as dirname20, isAbsolute as
|
|
13454
|
+
import { dirname as dirname20, isAbsolute as isAbsolute8, join as join55, relative as relative7 } from "path";
|
|
13400
13455
|
function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
13401
13456
|
const inRepo = (p) => {
|
|
13402
13457
|
try {
|
|
13403
|
-
const r =
|
|
13404
|
-
return r !== "" && !r.startsWith("..") && !
|
|
13458
|
+
const r = relative7(realpathSync19(repoDir), realpathSync19(p));
|
|
13459
|
+
return r !== "" && !r.startsWith("..") && !isAbsolute8(r);
|
|
13405
13460
|
} catch {
|
|
13406
13461
|
return false;
|
|
13407
13462
|
}
|
|
13408
13463
|
};
|
|
13409
13464
|
const venvEnv = process.env["VIRTUAL_ENV"];
|
|
13410
|
-
const project = [
|
|
13465
|
+
const project = [join55(repoDir, ".venv", "bin", bin), join55(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join55(venvEnv, "bin", bin)] : []].find(existsSync34);
|
|
13411
13466
|
return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
|
|
13412
13467
|
}
|
|
13413
13468
|
function runnerCmd(t, repoDir) {
|
|
@@ -13504,6 +13559,8 @@ async function runCheck(ctx, name, cmd, args, signal, checks, opts = {}) {
|
|
|
13504
13559
|
}
|
|
13505
13560
|
const reason = c.reason;
|
|
13506
13561
|
const check = { name, cmd: cmdStr, result, duration_s: (Date.now() - started) / 1000, ...result === "fail" ? { first_error: firstError(attempt.out), ids: failIds(attempt.out) } : result === "pass" && kind === "test" ? { n: c.n ?? 0, sk: skipped(attempt.out) } : {}, ...reason ? { reason } : {}, ...c.owner ? { owner: "harness" } : {}, ...opts.interpreter ? { interpreter: opts.interpreter } : {} };
|
|
13562
|
+
if (result === "fail" && !opts.opaque && !isHold(check))
|
|
13563
|
+
excerpts.set(check, failureExcerpt(attempt.out, ctx.repoDir));
|
|
13507
13564
|
checks.push(check);
|
|
13508
13565
|
if (opts.opaque && check.result !== "pass" && check.reason)
|
|
13509
13566
|
recordHoldoutTriage(ctx.runDir, { check: name, result: check.result, reason: check.reason });
|
|
@@ -13520,7 +13577,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13520
13577
|
const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
|
|
13521
13578
|
if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
|
|
13522
13579
|
return out2;
|
|
13523
|
-
const dir = mkdtempSync9(
|
|
13580
|
+
const dir = mkdtempSync9(join55(tmpdir10(), "e10-base-"));
|
|
13524
13581
|
const git3 = (args) => {
|
|
13525
13582
|
safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
|
|
13526
13583
|
};
|
|
@@ -13558,7 +13615,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13558
13615
|
return out2;
|
|
13559
13616
|
}
|
|
13560
13617
|
function isLokiModeRepo(repoDir) {
|
|
13561
|
-
return
|
|
13618
|
+
return existsSync34(join55(repoDir, "scripts", "select-tests.sh"));
|
|
13562
13619
|
}
|
|
13563
13620
|
async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
13564
13621
|
const { api, ...runOpts } = opts;
|
|
@@ -13580,9 +13637,9 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
|
13580
13637
|
}
|
|
13581
13638
|
for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
|
|
13582
13639
|
const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
|
|
13583
|
-
if (
|
|
13640
|
+
if (existsSync34(join55(g.cwd, "tsconfig.json")))
|
|
13584
13641
|
await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
|
|
13585
|
-
if (ESLINT_CONFIGS.some((f) =>
|
|
13642
|
+
if (ESLINT_CONFIGS.some((f) => existsSync34(join55(g.cwd, f)))) {
|
|
13586
13643
|
const c = await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
|
|
13587
13644
|
if (await excuseLint(ctx, signal, c, "eslint", "npx", ["eslint"], g.cwd, g.rel, co))
|
|
13588
13645
|
pre.push(c.name);
|
|
@@ -13590,14 +13647,14 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
|
13590
13647
|
}
|
|
13591
13648
|
return pre;
|
|
13592
13649
|
}
|
|
13593
|
-
var CHECK_TIMEOUT_MS = 60000, isHold = (c) => isHoldoutCheck(c.name), pubHold = (c) => ({ name: "holdout", cmd: "holdout", result: c.result, duration_s: c.duration_s, ...c.n !== undefined ? { n: c.n } : {}, ...c.sk !== undefined ? { sk: c.sk } : {}, ...c.owner ? { owner: c.owner, reason: "holdout infrastructure failure" } : {} }), testCheckName = (t) => `${t.runner}:${t.path}`, dedupeTests = (tests) => [...new Map(tests.map((t) => [`${t.runner}:${t.path}`, t])).values()], CODE_EXT, ESLINT_CONFIGS, excuseLint = (ctx, signal, c, tool, cmd, prefix, cwd, rel, opts) => c.result !== "fail" || signal.aborted ? Promise.resolve(false) : staticPreExisting(tool, prefix, rel, { run: async (a, stdin) => {
|
|
13650
|
+
var CHECK_TIMEOUT_MS = 60000, excerpts, isHold = (c) => isHoldoutCheck(c.name), pubHold = (c) => ({ name: "holdout", cmd: "holdout", result: c.result, duration_s: c.duration_s, ...c.n !== undefined ? { n: c.n } : {}, ...c.sk !== undefined ? { sk: c.sk } : {}, ...c.owner ? { owner: c.owner, reason: "holdout infrastructure failure" } : {} }), testCheckName = (t) => `${t.runner}:${t.path}`, dedupeTests = (tests) => [...new Map(tests.map((t) => [`${t.runner}:${t.path}`, t])).values()], CODE_EXT, ESLINT_CONFIGS, excuseLint = (ctx, signal, c, tool, cmd, prefix, cwd, rel, opts) => c.result !== "fail" || signal.aborted ? Promise.resolve(false) : staticPreExisting(tool, prefix, rel, { run: async (a, stdin) => {
|
|
13594
13651
|
if (signal.aborted)
|
|
13595
13652
|
return null;
|
|
13596
13653
|
const r = await runOnce2(cmd, a, cwd, AbortSignal.any([signal, AbortSignal.timeout(opts.timeoutMs ?? CHECK_TIMEOUT_MS)]), { ...opts, ...stdin !== undefined ? { stdin } : {} });
|
|
13597
13654
|
return r.missing || r.cut ? null : r;
|
|
13598
13655
|
}, base: (f) => {
|
|
13599
13656
|
try {
|
|
13600
|
-
return safeGit(ctx.repoDir, ["show", `${ctx.baseSha}:${
|
|
13657
|
+
return safeGit(ctx.repoDir, ["show", `${ctx.baseSha}:${relative7(ctx.repoDir, join55(cwd, f))}`], { stdio: ["ignore", "pipe", "ignore"] });
|
|
13601
13658
|
} catch {
|
|
13602
13659
|
return null;
|
|
13603
13660
|
}
|
|
@@ -13620,6 +13677,7 @@ var init_verify = __esm(() => {
|
|
|
13620
13677
|
init_check_result();
|
|
13621
13678
|
init_check_result();
|
|
13622
13679
|
init_runner_config();
|
|
13680
|
+
excerpts = new WeakMap;
|
|
13623
13681
|
CODE_EXT = /\.(?:[cm]?[jt]sx?|py|go)$/;
|
|
13624
13682
|
ESLINT_CONFIGS = [".eslintrc", ".eslintrc.json", ".eslintrc.js", ".eslintrc.cjs", "eslint.config.js", "eslint.config.mjs", "eslint.config.cjs"];
|
|
13625
13683
|
verifyStage = {
|
|
@@ -13655,7 +13713,7 @@ var init_verify = __esm(() => {
|
|
|
13655
13713
|
const impacted = ctx.tests.impacted(map, changed);
|
|
13656
13714
|
const changedTestFiles = map.tests.filter((t) => changed.includes(t.path));
|
|
13657
13715
|
const wall = ctx.outputs().wall ?? {};
|
|
13658
|
-
const wallPaths = new Set((wall.files ?? []).map((f) =>
|
|
13716
|
+
const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute8(f.path) ? relative7(ctx.repoDir, f.path) : f.path));
|
|
13659
13717
|
const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
|
|
13660
13718
|
const intake = ctx.outputs().intake, relevant2 = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
|
|
13661
13719
|
const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant2]);
|
|
@@ -13730,7 +13788,13 @@ var init_verify = __esm(() => {
|
|
|
13730
13788
|
const covered = (f) => ctx.tests.impacted(map, [f]).some((t) => checks.some((c) => c.name === testCheckName(t) && hasExecutedProof([c])));
|
|
13731
13789
|
const uncoveredChanged = changed.filter((f) => CODE_EXT.test(f) && !isTestFile(f) && !wallPaths.has(f) && !cfgChanged.includes(f) && !covered(f));
|
|
13732
13790
|
const flaky = checks.filter((c) => c.result === "flaky").map((c) => isHold(c) ? "holdout" : c.name);
|
|
13733
|
-
|
|
13791
|
+
let excerptLeft = EXCERPT_TOTAL_CAP;
|
|
13792
|
+
const failuresGrouped = checks.filter((c) => c.result === "fail" && !preRed.names.includes(c.name) && !isHold(c)).map((c) => {
|
|
13793
|
+
const x = isHold(c) ? "" : truncateBytes(excerpts.get(c) ?? "", Math.max(0, excerptLeft));
|
|
13794
|
+
excerptLeft -= Buffer.byteLength(x);
|
|
13795
|
+
return { signature: c.first_error ? `${c.name} ${c.first_error}` : c.name, count: 1, sample: x ? `${c.cmd}
|
|
13796
|
+
${x}` : c.cmd };
|
|
13797
|
+
});
|
|
13734
13798
|
const pub = checks.map((c) => isHold(c) ? pubHold(c) : c), holdoutFailed = checks.filter((c) => c.result === "fail" && isHold(c) && !preRed.names.includes(c.name)).length;
|
|
13735
13799
|
const inBase = (f) => {
|
|
13736
13800
|
try {
|
|
@@ -13755,8 +13819,8 @@ var init_verify = __esm(() => {
|
|
|
13755
13819
|
});
|
|
13756
13820
|
|
|
13757
13821
|
// ../../loki-ts/src/project_model/conventions.ts
|
|
13758
|
-
import { existsSync as
|
|
13759
|
-
import { dirname as dirname21, join as
|
|
13822
|
+
import { existsSync as existsSync35, readdirSync as readdirSync18, readFileSync as readFileSync42 } from "fs";
|
|
13823
|
+
import { dirname as dirname21, join as join56 } from "path";
|
|
13760
13824
|
function parseJsonc(text2) {
|
|
13761
13825
|
let out2 = "", i = 0;
|
|
13762
13826
|
while (i < text2.length) {
|
|
@@ -13791,25 +13855,25 @@ function moduleOf(file, depth = 0) {
|
|
|
13791
13855
|
const ext = typeof j.extends === "string" ? j.extends : null;
|
|
13792
13856
|
if (!ext || !ext.startsWith("."))
|
|
13793
13857
|
return null;
|
|
13794
|
-
const next =
|
|
13795
|
-
return
|
|
13858
|
+
const next = join56(dirname21(file), ext.endsWith(".json") ? ext : `${ext}.json`);
|
|
13859
|
+
return existsSync35(next) ? moduleOf(next, depth + 1) : null;
|
|
13796
13860
|
}
|
|
13797
13861
|
function readPackageConventions(pkgDir, runner = null) {
|
|
13798
13862
|
let names = [];
|
|
13799
13863
|
try {
|
|
13800
|
-
names =
|
|
13864
|
+
names = readdirSync18(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
|
|
13801
13865
|
} catch {
|
|
13802
13866
|
return null;
|
|
13803
13867
|
}
|
|
13804
13868
|
let packageType = null, tsModule = null;
|
|
13805
13869
|
for (const n2 of names) {
|
|
13806
|
-
const j = readJson4(
|
|
13870
|
+
const j = readJson4(join56(pkgDir, n2));
|
|
13807
13871
|
if (!j)
|
|
13808
13872
|
continue;
|
|
13809
13873
|
if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
|
|
13810
13874
|
packageType = j.type;
|
|
13811
13875
|
if (tsModule === null && j.compilerOptions !== undefined)
|
|
13812
|
-
tsModule = moduleOf(
|
|
13876
|
+
tsModule = moduleOf(join56(pkgDir, n2));
|
|
13813
13877
|
}
|
|
13814
13878
|
if (packageType === null && tsModule === null)
|
|
13815
13879
|
return null;
|
|
@@ -13831,7 +13895,7 @@ function conventionViolation(c, fileName, content) {
|
|
|
13831
13895
|
}
|
|
13832
13896
|
var readJson4 = (p) => {
|
|
13833
13897
|
try {
|
|
13834
|
-
const v = parseJsonc(
|
|
13898
|
+
const v = parseJsonc(readFileSync42(p, "utf8"));
|
|
13835
13899
|
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
13836
13900
|
} catch {
|
|
13837
13901
|
return null;
|
|
@@ -13841,15 +13905,15 @@ var init_conventions = () => {};
|
|
|
13841
13905
|
|
|
13842
13906
|
// ../../loki-ts/src/engine10/stages/wall.ts
|
|
13843
13907
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
13844
|
-
import { existsSync as
|
|
13908
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync10, readFileSync as readFileSync43, readdirSync as readdirSync19, realpathSync as realpathSync20, rmSync as rmSync18, writeFileSync as writeFileSync26 } from "fs";
|
|
13845
13909
|
import { tmpdir as tmpdir11 } from "os";
|
|
13846
|
-
import { dirname as dirname22, isAbsolute as
|
|
13910
|
+
import { dirname as dirname22, isAbsolute as isAbsolute9, join as join57, relative as relative8 } from "path";
|
|
13847
13911
|
function pytestCollectionIsRed(output, repoDir) {
|
|
13848
13912
|
if (/ModuleNotFoundError/.test(output))
|
|
13849
13913
|
return false;
|
|
13850
13914
|
const real2 = (p) => {
|
|
13851
13915
|
try {
|
|
13852
|
-
return
|
|
13916
|
+
return realpathSync20(isAbsolute9(p) ? p : join57(repoDir, p));
|
|
13853
13917
|
} catch {
|
|
13854
13918
|
return null;
|
|
13855
13919
|
}
|
|
@@ -13886,7 +13950,7 @@ function pytestCollectionIsRed(output, repoDir) {
|
|
|
13886
13950
|
}
|
|
13887
13951
|
function moduleUnderRepo(repoDir, name) {
|
|
13888
13952
|
const rel = name.replace(/\./g, "/");
|
|
13889
|
-
return
|
|
13953
|
+
return existsSync36(join57(repoDir, `${rel}.py`)) || existsSync36(join57(repoDir, rel, "__init__.py"));
|
|
13890
13954
|
}
|
|
13891
13955
|
function pytestExit1IsRed(output) {
|
|
13892
13956
|
if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
|
|
@@ -13985,10 +14049,10 @@ ${acceptance.map((a) => `Acceptance: ${a}`).join(`
|
|
|
13985
14049
|
function loadTaskText(ctx, fromPrior) {
|
|
13986
14050
|
if (fromPrior)
|
|
13987
14051
|
return fromPrior;
|
|
13988
|
-
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ??
|
|
13989
|
-
if (
|
|
14052
|
+
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join57(ctx.runDir, "issue.json");
|
|
14053
|
+
if (existsSync36(issueJsonPath)) {
|
|
13990
14054
|
try {
|
|
13991
|
-
const issue = JSON.parse(
|
|
14055
|
+
const issue = JSON.parse(readFileSync43(issueJsonPath, "utf8"));
|
|
13992
14056
|
const text2 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
|
|
13993
14057
|
|
|
13994
14058
|
`);
|
|
@@ -14000,7 +14064,7 @@ function loadTaskText(ctx, fromPrior) {
|
|
|
14000
14064
|
}
|
|
14001
14065
|
function wallTargetDir(repoDir, existingTests) {
|
|
14002
14066
|
const first = existingTests[0];
|
|
14003
|
-
return first ?
|
|
14067
|
+
return first ? join57(repoDir, dirname22(first.path)) : join57(repoDir, "tests");
|
|
14004
14068
|
}
|
|
14005
14069
|
function guessRunner(fileName, runners) {
|
|
14006
14070
|
if (fileName.endsWith(".py"))
|
|
@@ -14028,14 +14092,16 @@ async function wallAuthor(ctx, signal) {
|
|
|
14028
14092
|
}
|
|
14029
14093
|
if (testMap && runners.length === 0 && !(repoMap?.files ?? []).some((p) => /\.(py|go)$/.test(p)))
|
|
14030
14094
|
return done({ status: "skipped", data: { size: sz.size, files: [], no_runner: true }, reason: "no runnable test command detected: the Wall cannot write a runnable check" });
|
|
14095
|
+
if (testMap && (runners.length === 0 ? (repoMap?.files ?? []).some((p) => p.endsWith(".py")) && !(repoMap?.files ?? []).some((p) => p.endsWith(".go")) : runners.every((r) => r === "pytest")) && projectInterpreter(ctx.repoDir) === "system" && wallHoldoutRatio() === 0)
|
|
14096
|
+
return done({ status: "skipped", data: { size: sz.size, files: [], no_interpreter: true, not_proven: ["Wall skipped: no project test interpreter"] }, reason: "Wall skipped: no project test interpreter" });
|
|
14031
14097
|
const tree = prior.intake?.tree;
|
|
14032
14098
|
const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
|
|
14033
|
-
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${
|
|
14034
|
-
const conv2 = readPackageConventions(
|
|
14035
|
-
const cwd = mkdtempSync10(
|
|
14099
|
+
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative8(ctx.repoDir, targetDir)}/x`);
|
|
14100
|
+
const conv2 = readPackageConventions(join57(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
|
|
14101
|
+
const cwd = mkdtempSync10(join57(tmpdir11(), "loki-e15-wall-"));
|
|
14036
14102
|
const wm = wallManifestFor(ctx.repoDir, tree, task);
|
|
14037
14103
|
for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
|
|
14038
|
-
writeFileSync26(
|
|
14104
|
+
writeFileSync26(join57(cwd, n2), c, "utf8");
|
|
14039
14105
|
const session = await ctx.sessions.run({
|
|
14040
14106
|
stage: "wall",
|
|
14041
14107
|
brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2), unitSpec()?.acceptance ?? []),
|
|
@@ -14050,15 +14116,15 @@ async function wallAuthor(ctx, signal) {
|
|
|
14050
14116
|
rmSync18(cwd, { recursive: true, force: true });
|
|
14051
14117
|
return done({ status: "failed", data: {}, reason: "wall session aborted, killed, or timed out", killed: true });
|
|
14052
14118
|
}
|
|
14053
|
-
const all =
|
|
14054
|
-
const sealedDir =
|
|
14119
|
+
const all = readdirSync19(cwd).filter((f) => f.startsWith(WALL_PREFIX)), held = stashHoldout({ runId: ctx.runId, repoDir: ctx.repoDir, srcDir: cwd, targetDir, names: all.filter((n2) => !conventionViolation(conv2, n2, readFileSync43(join57(cwd, n2), "utf8"))), runnerOf: (n2) => guessRunner(n2, runners) }), generated = all.filter((n2) => !held?.names.has(n2));
|
|
14120
|
+
const sealedDir = join57(ctx.runDir, "wall");
|
|
14055
14121
|
if (generated.length > 0)
|
|
14056
14122
|
mkdirSync23(sealedDir, { recursive: true });
|
|
14057
14123
|
const contents = new Map;
|
|
14058
14124
|
const discarded = [];
|
|
14059
14125
|
for (const name of generated) {
|
|
14060
|
-
const content =
|
|
14061
|
-
writeFileSync26(
|
|
14126
|
+
const content = readFileSync43(join57(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
|
|
14127
|
+
writeFileSync26(join57(sealedDir, name), content, "utf8");
|
|
14062
14128
|
if (bad)
|
|
14063
14129
|
discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
|
|
14064
14130
|
else
|
|
@@ -14078,18 +14144,18 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
14078
14144
|
const content = contents.get(name);
|
|
14079
14145
|
if (content === undefined)
|
|
14080
14146
|
continue;
|
|
14081
|
-
const dest =
|
|
14147
|
+
const dest = join57(targetDir, name), runner = guessRunner(name, runners);
|
|
14082
14148
|
writeFileSync26(dest, content, "utf8");
|
|
14083
14149
|
sealedFiles.push({ path: dest, sha256: sha2562(content) });
|
|
14084
14150
|
readOnlyFiles.push({ path: dest, content });
|
|
14085
14151
|
if (runner)
|
|
14086
|
-
wallTests.push({ runner, path:
|
|
14152
|
+
wallTests.push({ runner, path: relative8(ctx.repoDir, dest) });
|
|
14087
14153
|
}
|
|
14088
14154
|
ctx.wallSealed = true;
|
|
14089
14155
|
ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
|
|
14090
14156
|
const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
|
|
14091
14157
|
for (const t of wallTests) {
|
|
14092
|
-
const r = baseRunner.run(baseDir, [t]), abs =
|
|
14158
|
+
const r = baseRunner.run(baseDir, [t]), abs = join57(ctx.repoDir, t.path);
|
|
14093
14159
|
baseRun.pass += r.pass;
|
|
14094
14160
|
baseRun.fail += r.fail;
|
|
14095
14161
|
baseRun.not_run += r.not_run ?? 0;
|
|
@@ -14130,6 +14196,7 @@ var init_wall = __esm(() => {
|
|
|
14130
14196
|
init_seal();
|
|
14131
14197
|
init_holdout();
|
|
14132
14198
|
init_verify();
|
|
14199
|
+
init_testmap();
|
|
14133
14200
|
init_resolve();
|
|
14134
14201
|
init_check_result();
|
|
14135
14202
|
init_conventions();
|
|
@@ -14143,15 +14210,15 @@ var init_wall = __esm(() => {
|
|
|
14143
14210
|
});
|
|
14144
14211
|
|
|
14145
14212
|
// ../../loki-ts/src/e10ext/discard.ts
|
|
14146
|
-
import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as lstatSync12, mkdirSync as mkdirSync24, openSync as openSync9, readFileSync as
|
|
14147
|
-
import { dirname as dirname23, join as
|
|
14213
|
+
import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as lstatSync12, mkdirSync as mkdirSync24, openSync as openSync9, readFileSync as readFileSync44, realpathSync as realpathSync21, rmdirSync, unlinkSync as unlinkSync6, writeFileSync as writeFileSync27 } from "fs";
|
|
14214
|
+
import { dirname as dirname23, join as join58, relative as relative9, sep as sep12 } from "path";
|
|
14148
14215
|
function safeRestore(repoDir, f, want, mode) {
|
|
14149
|
-
const root =
|
|
14216
|
+
const root = realpathSync21(repoDir), fp = join58(root, f), rel = relative9(root, dirname23(fp));
|
|
14150
14217
|
if (rel.startsWith(".."))
|
|
14151
14218
|
throw new Error("outside repo");
|
|
14152
14219
|
let cur = root;
|
|
14153
|
-
for (const part of rel === "" ? [] : rel.split(
|
|
14154
|
-
cur =
|
|
14220
|
+
for (const part of rel === "" ? [] : rel.split(sep12)) {
|
|
14221
|
+
cur = join58(cur, part);
|
|
14155
14222
|
let st2;
|
|
14156
14223
|
try {
|
|
14157
14224
|
st2 = lstatSync12(cur);
|
|
@@ -14168,7 +14235,7 @@ function safeRestore(repoDir, f, want, mode) {
|
|
|
14168
14235
|
} catch {
|
|
14169
14236
|
st = null;
|
|
14170
14237
|
}
|
|
14171
|
-
if (st?.isFile() &&
|
|
14238
|
+
if (st?.isFile() && readFileSync44(fp).equals(want)) {
|
|
14172
14239
|
chmodSync5(fp, mode);
|
|
14173
14240
|
return;
|
|
14174
14241
|
}
|
|
@@ -14206,7 +14273,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14206
14273
|
return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
|
|
14207
14274
|
const notProven = [];
|
|
14208
14275
|
for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
|
|
14209
|
-
const fp =
|
|
14276
|
+
const fp = join58(repoDir, f);
|
|
14210
14277
|
try {
|
|
14211
14278
|
if (v.startsWith("!")) {
|
|
14212
14279
|
const st = lstatSync12(fp);
|
|
@@ -14225,7 +14292,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14225
14292
|
try {
|
|
14226
14293
|
let m = 420;
|
|
14227
14294
|
try {
|
|
14228
|
-
const l = lstatSync12(
|
|
14295
|
+
const l = lstatSync12(join58(repoDir, f));
|
|
14229
14296
|
if (l.isFile())
|
|
14230
14297
|
m = l.mode & 511;
|
|
14231
14298
|
} catch {}
|
|
@@ -14269,7 +14336,7 @@ var init_commit_filter = __esm(() => {
|
|
|
14269
14336
|
});
|
|
14270
14337
|
|
|
14271
14338
|
// ../../loki-ts/src/e10ext/scope.ts
|
|
14272
|
-
import { basename as
|
|
14339
|
+
import { basename as basename21, dirname as dirname25 } from "path";
|
|
14273
14340
|
function contractText(o) {
|
|
14274
14341
|
const c = o.intake?.contract_snapshot?.contract;
|
|
14275
14342
|
return Array.isArray(c?.criteria) ? c.criteria.map((x) => typeof x?.text === "string" ? x.text : "").join(`
|
|
@@ -14284,7 +14351,7 @@ function outsideScope(o, staged) {
|
|
|
14284
14351
|
${typeof o.intake?.task === "string" ? o.intake.task : ""}
|
|
14285
14352
|
${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
|
|
14286
14353
|
const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname25(r)).filter((d) => d !== "."));
|
|
14287
|
-
return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2,
|
|
14354
|
+
return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2, basename21(f)) && !plannedDirs.has(dirname25(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
|
|
14288
14355
|
}
|
|
14289
14356
|
function flagOutsideScope(o, staged) {
|
|
14290
14357
|
const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
|
|
@@ -14299,14 +14366,14 @@ var init_scope2 = __esm(() => {
|
|
|
14299
14366
|
});
|
|
14300
14367
|
|
|
14301
14368
|
// ../../loki-ts/src/council/role_agents.ts
|
|
14302
|
-
import { existsSync as
|
|
14369
|
+
import { existsSync as existsSync37, readdirSync as readdirSync20, readFileSync as readFileSync45 } from "fs";
|
|
14303
14370
|
import { homedir as homedir9 } from "os";
|
|
14304
|
-
import { join as
|
|
14371
|
+
import { join as join59 } from "path";
|
|
14305
14372
|
function agentDirs(repoDir, env = process.env) {
|
|
14306
|
-
return [env["LOKI_AGENTS_PROJECT_DIR"] ||
|
|
14373
|
+
return [env["LOKI_AGENTS_PROJECT_DIR"] || join59(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join59(env["XDG_CONFIG_HOME"] || join59(homedir9(), ".config"), "loki", "agents")];
|
|
14307
14374
|
}
|
|
14308
14375
|
function parseAgent(file, stem2) {
|
|
14309
|
-
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(
|
|
14376
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync45(file, "utf8"));
|
|
14310
14377
|
if (!m)
|
|
14311
14378
|
return null;
|
|
14312
14379
|
const body = m[2].trim();
|
|
@@ -14320,18 +14387,18 @@ function parseAgent(file, stem2) {
|
|
|
14320
14387
|
}
|
|
14321
14388
|
function loadRoleAgent(repoDir, role, env = process.env) {
|
|
14322
14389
|
for (const d of agentDirs(repoDir, env)) {
|
|
14323
|
-
if (!
|
|
14390
|
+
if (!existsSync37(d))
|
|
14324
14391
|
continue;
|
|
14325
14392
|
let names;
|
|
14326
14393
|
try {
|
|
14327
|
-
names =
|
|
14394
|
+
names = readdirSync20(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
|
|
14328
14395
|
} catch {
|
|
14329
14396
|
continue;
|
|
14330
14397
|
}
|
|
14331
14398
|
const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
|
|
14332
14399
|
for (const n2 of ordered) {
|
|
14333
14400
|
try {
|
|
14334
|
-
const a = parseAgent(
|
|
14401
|
+
const a = parseAgent(join59(d, n2), n2.slice(0, -3));
|
|
14335
14402
|
if (a && a.role === role)
|
|
14336
14403
|
return a;
|
|
14337
14404
|
} catch {}
|
|
@@ -14349,7 +14416,7 @@ var init_role_agents = __esm(() => {
|
|
|
14349
14416
|
|
|
14350
14417
|
// ../../loki-ts/src/util/child_ledger.ts
|
|
14351
14418
|
import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync25 } from "fs";
|
|
14352
|
-
import { join as
|
|
14419
|
+
import { join as join60 } from "path";
|
|
14353
14420
|
function unmeasuredRecord(phase, model, source) {
|
|
14354
14421
|
return { phase, model, input_tokens: 0, output_tokens: 0, cache_creation_tokens: 0, cache_read_tokens: 0, source, cost_status: "unmeasured" };
|
|
14355
14422
|
}
|
|
@@ -14374,9 +14441,9 @@ function recordFromClaudeResult(phase, payload, source = "claude-json") {
|
|
|
14374
14441
|
}
|
|
14375
14442
|
function appendChildLedger(lokiDir2, rec2) {
|
|
14376
14443
|
try {
|
|
14377
|
-
const dir =
|
|
14444
|
+
const dir = join60(lokiDir2, "metrics");
|
|
14378
14445
|
mkdirSync25(dir, { recursive: true });
|
|
14379
|
-
appendFileSync4(
|
|
14446
|
+
appendFileSync4(join60(dir, "child-sessions.jsonl"), `${JSON.stringify(rec2)}
|
|
14380
14447
|
`);
|
|
14381
14448
|
return true;
|
|
14382
14449
|
} catch {
|
|
@@ -14406,14 +14473,14 @@ var init_child_ledger = __esm(() => {
|
|
|
14406
14473
|
});
|
|
14407
14474
|
|
|
14408
14475
|
// ../../loki-ts/src/util/run_summary.ts
|
|
14409
|
-
import { existsSync as
|
|
14410
|
-
import { join as
|
|
14476
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync26, readFileSync as readFileSync46, renameSync as renameSync11, statSync as statSync18, writeFileSync as writeFileSync28 } from "fs";
|
|
14477
|
+
import { join as join61 } from "path";
|
|
14411
14478
|
function readRiskRecord(repoDir, sinceMs = 0) {
|
|
14412
14479
|
try {
|
|
14413
|
-
const p =
|
|
14480
|
+
const p = join61(repoDir, ".loki", "state", "risk-tier.json");
|
|
14414
14481
|
if (statSync18(p).mtimeMs < sinceMs)
|
|
14415
14482
|
return null;
|
|
14416
|
-
const r = JSON.parse(
|
|
14483
|
+
const r = JSON.parse(readFileSync46(p, "utf8"));
|
|
14417
14484
|
return r && typeof r === "object" ? r : null;
|
|
14418
14485
|
} catch {
|
|
14419
14486
|
return null;
|
|
@@ -14427,8 +14494,8 @@ var init_run_summary = __esm(() => {
|
|
|
14427
14494
|
});
|
|
14428
14495
|
|
|
14429
14496
|
// ../../loki-ts/src/engine10/stages/xreview.ts
|
|
14430
|
-
import { existsSync as
|
|
14431
|
-
import { join as
|
|
14497
|
+
import { existsSync as existsSync39, readFileSync as readFileSync47 } from "fs";
|
|
14498
|
+
import { join as join62 } from "path";
|
|
14432
14499
|
function minVerdict(verdict, review) {
|
|
14433
14500
|
const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
|
|
14434
14501
|
return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
|
|
@@ -14441,11 +14508,11 @@ function explicitReview(repoDir, env) {
|
|
|
14441
14508
|
if (flag && isOff(ev))
|
|
14442
14509
|
return "off";
|
|
14443
14510
|
for (const f of ["loki.yaml", "loki.yml"]) {
|
|
14444
|
-
const p =
|
|
14445
|
-
if (!
|
|
14511
|
+
const p = join62(repoDir, f);
|
|
14512
|
+
if (!existsSync39(p))
|
|
14446
14513
|
continue;
|
|
14447
14514
|
try {
|
|
14448
|
-
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(
|
|
14515
|
+
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync47(p, "utf8"));
|
|
14449
14516
|
const v = asProvider(m?.[1]);
|
|
14450
14517
|
if (v)
|
|
14451
14518
|
return v;
|
|
@@ -14527,7 +14594,7 @@ Review ONLY the diff below. Do not modify files.` : "You are an independent code
|
|
|
14527
14594
|
try {
|
|
14528
14595
|
if (p === "claude")
|
|
14529
14596
|
await ensureClaudeHelpCache();
|
|
14530
|
-
const r = await withChildLedger(run,
|
|
14597
|
+
const r = await withChildLedger(run, join62(ctx.repoDir, ".loki"), "xreview")(reviewArgv(p, prompt, process.env, p === "claude" ? agent?.model : undefined), { cwd: ctx.repoDir, timeoutMs: TIMEOUT_MS });
|
|
14531
14598
|
if (r.exitCode !== 0)
|
|
14532
14599
|
return { provider: p, level: "not_run", notes: [`cross-review not run: ${p} exited ${r.exitCode}`] };
|
|
14533
14600
|
return parseReview(p, r.stdout);
|
|
@@ -14621,8 +14688,8 @@ See also: loki cost --detail (what a run ALREADY spent)
|
|
|
14621
14688
|
});
|
|
14622
14689
|
|
|
14623
14690
|
// ../../loki-ts/src/features/contract.ts
|
|
14624
|
-
import { existsSync as
|
|
14625
|
-
import { dirname as dirname26, join as
|
|
14691
|
+
import { existsSync as existsSync40, lstatSync as lstatSync13, mkdirSync as mkdirSync27, readFileSync as readFileSync48, rmSync as rmSync19, writeFileSync as writeFileSync29 } from "fs";
|
|
14692
|
+
import { dirname as dirname26, join as join63 } from "path";
|
|
14626
14693
|
import { createHash as createHash16 } from "crypto";
|
|
14627
14694
|
function contractEnabled(env = process.env) {
|
|
14628
14695
|
return env["LOKI_CONTRACT"] !== "0";
|
|
@@ -14654,7 +14721,7 @@ function untracedLines(trace) {
|
|
|
14654
14721
|
return trace.criteria.filter((c) => c.status === "no_match").map((c) => `contract ${sanitizeCriterion(c.id)} untraced (no keyword match in changed files): ${sanitizeCriterion(c.text)}`);
|
|
14655
14722
|
}
|
|
14656
14723
|
function contractPath(repoDir) {
|
|
14657
|
-
return
|
|
14724
|
+
return join63(repoDir, ".loki", "contract.json");
|
|
14658
14725
|
}
|
|
14659
14726
|
function readContract(repoDir) {
|
|
14660
14727
|
const p = contractPath(repoDir);
|
|
@@ -14670,7 +14737,7 @@ function readContract(repoDir) {
|
|
|
14670
14737
|
return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
|
|
14671
14738
|
let raw2;
|
|
14672
14739
|
try {
|
|
14673
|
-
raw2 =
|
|
14740
|
+
raw2 = readFileSync48(p);
|
|
14674
14741
|
} catch {
|
|
14675
14742
|
return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
|
|
14676
14743
|
}
|
|
@@ -14739,17 +14806,17 @@ var init_contract = __esm(() => {
|
|
|
14739
14806
|
init_safe_git();
|
|
14740
14807
|
STOP2 = new Set(["the", "and", "for", "with", "that", "this", "must", "should", "shall", "when", "then", "are", "was", "all", "any", "can", "not", "has", "have", "from", "into", "each", "user", "users"]);
|
|
14741
14808
|
MAX_CONTRACT_BYTES = 1024 * 1024;
|
|
14742
|
-
REQ_MAP_REL =
|
|
14809
|
+
REQ_MAP_REL = join63(".loki", "state", "requirements-map.json");
|
|
14743
14810
|
REQ_STOP = new Set(["with", "that", "this", "from", "have", "will", "should", "must", "when", "then", "into", "each", "every", "user", "users", "page", "able", "allow", "support", "ensure", "using", "their", "there", "which", "shall"]);
|
|
14744
14811
|
});
|
|
14745
14812
|
|
|
14746
14813
|
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
14747
14814
|
import { createHash as createHash17 } from "crypto";
|
|
14748
|
-
import { existsSync as
|
|
14749
|
-
import { dirname as dirname27, join as
|
|
14815
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync28, readdirSync as readdirSync21, readFileSync as readFileSync49, renameSync as renameSync12, statSync as statSync19, writeFileSync as writeFileSync30 } from "fs";
|
|
14816
|
+
import { dirname as dirname27, join as join64 } from "path";
|
|
14750
14817
|
function sealGroup(runDir, rh) {
|
|
14751
|
-
const manifestPath =
|
|
14752
|
-
if (!
|
|
14818
|
+
const manifestPath = join64(runDir, "group", "manifest.json");
|
|
14819
|
+
if (!existsSync41(manifestPath))
|
|
14753
14820
|
return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
|
|
14754
14821
|
const notProven = [];
|
|
14755
14822
|
let problems = 0;
|
|
@@ -14773,10 +14840,10 @@ function sealGroup(runDir, rh) {
|
|
|
14773
14840
|
return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
|
|
14774
14841
|
seen.add(id);
|
|
14775
14842
|
seenLower.add(id.toLowerCase());
|
|
14776
|
-
const dir =
|
|
14843
|
+
const dir = join64(unitsDir(runDir), id), rp = join64(dir, "receipt.json"), ep = join64(dir, "events.jsonl");
|
|
14777
14844
|
let bytes;
|
|
14778
14845
|
try {
|
|
14779
|
-
bytes =
|
|
14846
|
+
bytes = readFileSync49(rp);
|
|
14780
14847
|
} catch {
|
|
14781
14848
|
return fail(`unit ${id} sub-receipt missing`);
|
|
14782
14849
|
}
|
|
@@ -14793,7 +14860,7 @@ function sealGroup(runDir, rh) {
|
|
|
14793
14860
|
unit_id: id,
|
|
14794
14861
|
sub_receipt_sha256: sha3(bytes),
|
|
14795
14862
|
receipt_sha256: sub["receipt_sha256"],
|
|
14796
|
-
events_file_sha256:
|
|
14863
|
+
events_file_sha256: existsSync41(ep) ? sha3(readFileSync49(ep)) : null,
|
|
14797
14864
|
verdict,
|
|
14798
14865
|
goal: text2(u["goal"], 200),
|
|
14799
14866
|
files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
|
|
@@ -14818,7 +14885,7 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14818
14885
|
const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
|
|
14819
14886
|
const g = receipt["group"];
|
|
14820
14887
|
if (g === undefined)
|
|
14821
|
-
return
|
|
14888
|
+
return existsSync41(join64(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
|
|
14822
14889
|
if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
|
|
14823
14890
|
return bad("group section malformed");
|
|
14824
14891
|
const entries = g["units"];
|
|
@@ -14830,20 +14897,20 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14830
14897
|
return bad("unit directories do not match the receipt (missing or extra unit)");
|
|
14831
14898
|
let unchecked = null;
|
|
14832
14899
|
for (let i = 0;i < entries.length; i++) {
|
|
14833
|
-
const e = entries[i], id = ids[i], dir =
|
|
14900
|
+
const e = entries[i], id = ids[i], dir = join64(unitsDir(runDir), id), rp = join64(dir, "receipt.json"), ep = join64(dir, "events.jsonl");
|
|
14834
14901
|
if (e["index"] !== i)
|
|
14835
14902
|
return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
|
|
14836
14903
|
let bytes;
|
|
14837
14904
|
try {
|
|
14838
14905
|
if (!statSync19(dir).isDirectory())
|
|
14839
14906
|
return bad(`unit ${id} is not a directory`);
|
|
14840
|
-
bytes =
|
|
14907
|
+
bytes = readFileSync49(rp);
|
|
14841
14908
|
} catch {
|
|
14842
14909
|
return bad(`unit ${id} sub-receipt missing`);
|
|
14843
14910
|
}
|
|
14844
14911
|
if (sha3(bytes) !== e["sub_receipt_sha256"])
|
|
14845
14912
|
return bad(`unit ${id} sub-receipt does not match its recorded hash`);
|
|
14846
|
-
const evSha =
|
|
14913
|
+
const evSha = existsSync41(ep) ? sha3(readFileSync49(ep)) : null;
|
|
14847
14914
|
if (evSha !== (e["events_file_sha256"] ?? null))
|
|
14848
14915
|
return bad(`unit ${id} events.jsonl does not match its recorded hash`);
|
|
14849
14916
|
const sub = readJson5(rp);
|
|
@@ -14866,15 +14933,15 @@ function compositeVerdict(childVerdicts) {
|
|
|
14866
14933
|
const failed2 = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
|
|
14867
14934
|
return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed2, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
|
|
14868
14935
|
}
|
|
14869
|
-
var ID_RE, PASSING, sha3 = (b) => createHash17("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) =>
|
|
14936
|
+
var ID_RE, PASSING, sha3 = (b) => createHash17("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) => join64(runDir, "group", "units"), readJson5 = (p) => {
|
|
14870
14937
|
try {
|
|
14871
|
-
return JSON.parse(
|
|
14938
|
+
return JSON.parse(readFileSync49(p, "utf8"));
|
|
14872
14939
|
} catch {
|
|
14873
14940
|
return;
|
|
14874
14941
|
}
|
|
14875
14942
|
}, dirNames = (d) => {
|
|
14876
14943
|
try {
|
|
14877
|
-
return
|
|
14944
|
+
return readdirSync21(d).filter((n3) => !n3.startsWith(".")).sort();
|
|
14878
14945
|
} catch {
|
|
14879
14946
|
return null;
|
|
14880
14947
|
}
|
|
@@ -14886,8 +14953,8 @@ var init_seal_group = __esm(() => {
|
|
|
14886
14953
|
});
|
|
14887
14954
|
|
|
14888
14955
|
// ../../loki-ts/src/supply/supply_guard.ts
|
|
14889
|
-
import { existsSync as
|
|
14890
|
-
import { basename as
|
|
14956
|
+
import { existsSync as existsSync42, readFileSync as readFileSync50, statSync as statSync20 } from "fs";
|
|
14957
|
+
import { basename as basename22, join as join65 } from "path";
|
|
14891
14958
|
function supplyEnabled(env) {
|
|
14892
14959
|
return env["LOKI_SUPPLY_GUARD"] !== "0";
|
|
14893
14960
|
}
|
|
@@ -14899,16 +14966,16 @@ function supplyVerdict(verdict, r) {
|
|
|
14899
14966
|
return r.blocked && verdict === "VERIFIED" ? "FAILED" : verdict;
|
|
14900
14967
|
}
|
|
14901
14968
|
function isManifestPath(path) {
|
|
14902
|
-
return MANIFESTS.test(
|
|
14969
|
+
return MANIFESTS.test(basename22(path));
|
|
14903
14970
|
}
|
|
14904
14971
|
function readDeclared(repoDir) {
|
|
14905
|
-
const p =
|
|
14906
|
-
if (!
|
|
14972
|
+
const p = join65(repoDir, ".loki", DECLARED_FILE);
|
|
14973
|
+
if (!existsSync42(p))
|
|
14907
14974
|
return { deps: [], problem: null };
|
|
14908
14975
|
try {
|
|
14909
14976
|
if (statSync20(p).size > MAX_FILE_BYTES)
|
|
14910
14977
|
return { deps: [], problem: "declaration file too large" };
|
|
14911
|
-
const j = JSON.parse(
|
|
14978
|
+
const j = JSON.parse(readFileSync50(p, "utf8"));
|
|
14912
14979
|
if (!Array.isArray(j))
|
|
14913
14980
|
return { deps: [], problem: "declaration is not a JSON array" };
|
|
14914
14981
|
const deps = [];
|
|
@@ -14928,11 +14995,11 @@ function readDeclared(repoDir) {
|
|
|
14928
14995
|
}
|
|
14929
14996
|
}
|
|
14930
14997
|
function readAllowlist(repoDir) {
|
|
14931
|
-
const p =
|
|
14932
|
-
if (!
|
|
14998
|
+
const p = join65(repoDir, ".loki", "supply-allowlist");
|
|
14999
|
+
if (!existsSync42(p))
|
|
14933
15000
|
return new Set;
|
|
14934
15001
|
try {
|
|
14935
|
-
return new Set(
|
|
15002
|
+
return new Set(readFileSync50(p, "utf8").split(`
|
|
14936
15003
|
`).map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean));
|
|
14937
15004
|
} catch {
|
|
14938
15005
|
return new Set;
|
|
@@ -14973,7 +15040,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
14973
15040
|
if (eco === "npm") {
|
|
14974
15041
|
if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
|
|
14975
15042
|
return true;
|
|
14976
|
-
return files(
|
|
15043
|
+
return files(join65(repoDir, ".npmrc"), home ? join65(home, ".npmrc") : "").some((t) => t.split(`
|
|
14977
15044
|
`).some((l) => {
|
|
14978
15045
|
const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
|
|
14979
15046
|
return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
|
|
@@ -14982,7 +15049,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
14982
15049
|
if (eco === "pypi") {
|
|
14983
15050
|
if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
|
|
14984
15051
|
return true;
|
|
14985
|
-
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ?
|
|
15052
|
+
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join65(home, ".config", "pip", "pip.conf") : "", home ? join65(home, ".pip", "pip.conf") : "", join65(repoDir, "pip.conf")];
|
|
14986
15053
|
return files(...cfg).some((t) => t.split(`
|
|
14987
15054
|
`).some((l) => {
|
|
14988
15055
|
const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
|
|
@@ -14992,7 +15059,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
14992
15059
|
if (eco === "cargo") {
|
|
14993
15060
|
if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
|
|
14994
15061
|
return true;
|
|
14995
|
-
return files(
|
|
15062
|
+
return files(join65(repoDir, ".cargo", "config.toml"), join65(repoDir, ".cargo", "config"), home ? join65(home, ".cargo", "config.toml") : "", home ? join65(home, ".cargo", "config") : "").some((t) => /^\s*\[(registries\.|source\.)/m.test(t) || /replace-with\s*=/.test(t));
|
|
14996
15063
|
}
|
|
14997
15064
|
if (eco === "go") {
|
|
14998
15065
|
const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
|
|
@@ -15115,7 +15182,7 @@ var MIN_AGE_DAYS = 7, DECLARED_FILE = "supply-declared.json", MAX_CHECKED = 50,
|
|
|
15115
15182
|
}
|
|
15116
15183
|
}, PUBLIC_HOSTS, hostOf = (u) => u.trim().toLowerCase().replace(/^[a-z][a-z0-9+.-]*:\/\//, "").replace(/^www\./, "").split(/[/?#\s]/)[0].replace(/^[^@]*@/, "").replace(/:\d+$/, ""), privateUrl = (u) => /[a-z0-9]/i.test(u) && !PUBLIC_HOSTS.has(hostOf(u)), readSmall = (p) => {
|
|
15117
15184
|
try {
|
|
15118
|
-
return statSync20(p).size <= MAX_FILE_BYTES ?
|
|
15185
|
+
return statSync20(p).size <= MAX_FILE_BYTES ? readFileSync50(p, "utf8") : "";
|
|
15119
15186
|
} catch {
|
|
15120
15187
|
return "";
|
|
15121
15188
|
}
|
|
@@ -15131,8 +15198,8 @@ var init_supply_guard = __esm(() => {
|
|
|
15131
15198
|
|
|
15132
15199
|
// ../../loki-ts/src/engine10/stages/seal.ts
|
|
15133
15200
|
import { createHash as createHash18 } from "crypto";
|
|
15134
|
-
import { existsSync as
|
|
15135
|
-
import { basename as
|
|
15201
|
+
import { existsSync as existsSync43, readdirSync as readdirSync22, mkdirSync as mkdirSync29, readFileSync as readFileSync51, writeFileSync as writeFileSync31 } from "fs";
|
|
15202
|
+
import { basename as basename23, isAbsolute as isAbsolute10, join as join66, relative as relative10 } from "path";
|
|
15136
15203
|
function sanitizeReason(s) {
|
|
15137
15204
|
const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
|
|
15138
15205
|
const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
|
|
@@ -15207,8 +15274,8 @@ function renderReceiptMd(r) {
|
|
|
15207
15274
|
`);
|
|
15208
15275
|
}
|
|
15209
15276
|
var DEEP_NOT_PROVEN, SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)", EXCLUDE_LOKI = ":(exclude).loki", sha2562 = (s) => createHash18("sha256").update(s).digest("hex"), str3 = (v) => typeof v === "string" && v !== "" ? v : null, strs2 = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string" && x !== "") : [], receiptRel = (ctx) => {
|
|
15210
|
-
const r =
|
|
15211
|
-
return r.startsWith("..") ||
|
|
15277
|
+
const r = relative10(ctx.repoDir, join66(ctx.runDir, "receipt.json"));
|
|
15278
|
+
return r.startsWith("..") || isAbsolute10(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
|
|
15212
15279
|
}, commitStage, sealStage;
|
|
15213
15280
|
var init_seal = __esm(() => {
|
|
15214
15281
|
init_spec_file();
|
|
@@ -15307,6 +15374,8 @@ var init_seal = __esm(() => {
|
|
|
15307
15374
|
}
|
|
15308
15375
|
if (wallNotRun > 0)
|
|
15309
15376
|
notProven.add(`wall base run not_run: ${wallNotRun}`);
|
|
15377
|
+
for (const n3 of strs2(o.wall?.not_proven))
|
|
15378
|
+
notProven.add(n3);
|
|
15310
15379
|
for (const d of Array.isArray(o.wall?.discarded) ? o.wall.discarded : [])
|
|
15311
15380
|
notProven.add(`wall test discarded: ${String(d.file)} (${String(d.reason)})`);
|
|
15312
15381
|
for (const d of Array.isArray(o.wall?.not_run_files) ? o.wall.not_run_files : [])
|
|
@@ -15315,8 +15384,8 @@ var init_seal = __esm(() => {
|
|
|
15315
15384
|
notProven.add(`Wall test not executed: ${wallNotRun} file(s), no reason recorded`);
|
|
15316
15385
|
if (wallNotRun > 0) {
|
|
15317
15386
|
try {
|
|
15318
|
-
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) =>
|
|
15319
|
-
for (const n3 of
|
|
15387
|
+
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename23(String(f.path))));
|
|
15388
|
+
for (const n3 of readdirSync22(join66(ctx.runDir, "wall")).sort())
|
|
15320
15389
|
if (!kept.has(n3))
|
|
15321
15390
|
notProven.add(`wall test discarded: ${n3} (not_run)`);
|
|
15322
15391
|
} catch {}
|
|
@@ -15379,19 +15448,19 @@ var init_seal = __esm(() => {
|
|
|
15379
15448
|
for (const [s, d] of Object.entries(o))
|
|
15380
15449
|
if (typeof d?.duration_s === "number")
|
|
15381
15450
|
stages[s] = d.duration_s;
|
|
15382
|
-
const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(
|
|
15451
|
+
const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(join66(ctx.runDir, "events.jsonl"))) : { wall_s: Object.values(stages).reduce((a, b) => a + (b ?? 0), 0), stages }, totalS = T?.reconciled(time) ?? null;
|
|
15383
15452
|
const iterIds = Object.values(o).flatMap((d) => [...strs2(d?.iteration_ids), ...strs2([d?.iteration_id])]);
|
|
15384
15453
|
if (iterIds.length === 0)
|
|
15385
15454
|
notProven.add("cost not measured (no iteration ids recorded)");
|
|
15386
15455
|
const cost = ctx.cost.read(ctx.repoDir, iterIds);
|
|
15387
15456
|
if (cost.unmetered)
|
|
15388
15457
|
notProven.add("cost unmetered (CLI invoker; recorded as 0)");
|
|
15389
|
-
const eventsPath =
|
|
15458
|
+
const eventsPath = join66(ctx.runDir, "events.jsonl");
|
|
15390
15459
|
const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
|
|
15391
15460
|
const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
|
|
15392
15461
|
if (wallFiles.length > 0 && wallPassed === null)
|
|
15393
15462
|
notProven.add("wall result not recorded by verify");
|
|
15394
|
-
const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route ?? o.plan?.route_record ?? (routerEnabled(process.env) ? loadRouteRecord(ctx.runDir) : undefined), cost.router ?? (routerEnabled(process.env) ? sumResultCosts(
|
|
15463
|
+
const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route ?? o.plan?.route_record ?? (routerEnabled(process.env) ? loadRouteRecord(ctx.runDir) : undefined), cost.router ?? (routerEnabled(process.env) ? sumResultCosts(join66(ctx.repoDir, ".loki"), liveArchivedCosts(join66(ctx.repoDir, ".loki"), iterIds, UNMETERED)).router : undefined), ctx.model);
|
|
15395
15464
|
if (routeBlock)
|
|
15396
15465
|
for (const l of routeNotProven(routeBlock))
|
|
15397
15466
|
notProven.add(l);
|
|
@@ -15433,7 +15502,7 @@ var init_seal = __esm(() => {
|
|
|
15433
15502
|
provider: ctx.provider,
|
|
15434
15503
|
model: ctx.model,
|
|
15435
15504
|
resumed: o.intake?.resumed === true,
|
|
15436
|
-
events_sha256: sha2562(
|
|
15505
|
+
events_sha256: sha2562(existsSync43(eventsPath) ? readFileSync51(eventsPath) : ""),
|
|
15437
15506
|
...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
|
|
15438
15507
|
log_seal: true,
|
|
15439
15508
|
...receiptBlock(process.env, cost.usd, cost.unmetered === true, totalS),
|
|
@@ -15455,10 +15524,10 @@ var init_seal = __esm(() => {
|
|
|
15455
15524
|
}
|
|
15456
15525
|
const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
15457
15526
|
mkdirSync29(ctx.runDir, { recursive: true });
|
|
15458
|
-
const path =
|
|
15527
|
+
const path = join66(ctx.runDir, "receipt.json");
|
|
15459
15528
|
writeFileSync31(path, JSON.stringify(receipt, null, 2) + `
|
|
15460
15529
|
`);
|
|
15461
|
-
writeFileSync31(
|
|
15530
|
+
writeFileSync31(join66(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
|
|
15462
15531
|
recordRun(process.env, ctx.repoDir, ranModel(o.implement, ctx.model, o.fix), verdict, cost.usd, cost.unmetered === true, totalS);
|
|
15463
15532
|
try {
|
|
15464
15533
|
hooks.sealed?.(ctx.runDir, JSON.parse(JSON.stringify(receipt), (_k, v) => v && typeof v === "object" ? Object.freeze(v) : v));
|
|
@@ -15484,7 +15553,7 @@ var init_seal = __esm(() => {
|
|
|
15484
15553
|
|
|
15485
15554
|
// ../../loki-ts/src/features/receipt_dsse.ts
|
|
15486
15555
|
import { createPublicKey as createPublicKey3, sign as sign2, verify as verify3 } from "crypto";
|
|
15487
|
-
import { readFileSync as
|
|
15556
|
+
import { readFileSync as readFileSync52 } from "fs";
|
|
15488
15557
|
function pae(payloadType, body) {
|
|
15489
15558
|
const t = Buffer.from(payloadType, "utf8");
|
|
15490
15559
|
return Buffer.concat([Buffer.from(`DSSEv1 ${t.length} `), t, Buffer.from(` ${body.length} `), body]);
|
|
@@ -15561,7 +15630,7 @@ function verifyDsseReceipt(env, d) {
|
|
|
15561
15630
|
}
|
|
15562
15631
|
function runIdGuard(receiptPath, runId) {
|
|
15563
15632
|
try {
|
|
15564
|
-
return envelopeRunIdProblem(JSON.parse(
|
|
15633
|
+
return envelopeRunIdProblem(JSON.parse(readFileSync52(receiptPath, "utf8")), runId);
|
|
15565
15634
|
} catch {
|
|
15566
15635
|
return null;
|
|
15567
15636
|
}
|
|
@@ -15570,14 +15639,14 @@ var DSSE_PAYLOAD_TYPE = "application/vnd.in-toto+json", STATEMENT_TYPE = "https:
|
|
|
15570
15639
|
var init_receipt_dsse = () => {};
|
|
15571
15640
|
|
|
15572
15641
|
// ../../loki-ts/src/util/composite_seal.ts
|
|
15573
|
-
import { existsSync as
|
|
15574
|
-
import { basename as
|
|
15642
|
+
import { existsSync as existsSync44, readFileSync as readFileSync53 } from "fs";
|
|
15643
|
+
import { basename as basename24, dirname as dirname29, join as join67 } from "path";
|
|
15575
15644
|
function logProblem(runDir, integ) {
|
|
15576
15645
|
if (typeof integ["log_sha256"] !== "string")
|
|
15577
15646
|
return null;
|
|
15578
15647
|
let b;
|
|
15579
15648
|
try {
|
|
15580
|
-
b =
|
|
15649
|
+
b = readFileSync53(join67(runDir, "integration.log"));
|
|
15581
15650
|
} catch {
|
|
15582
15651
|
return "integration.log is missing but integration.json records its hash";
|
|
15583
15652
|
}
|
|
@@ -15600,13 +15669,13 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15600
15669
|
return bad("body malformed");
|
|
15601
15670
|
let ibytes;
|
|
15602
15671
|
try {
|
|
15603
|
-
ibytes =
|
|
15672
|
+
ibytes = readFileSync53(join67(runDir, "integration.json"));
|
|
15604
15673
|
} catch {
|
|
15605
15674
|
return bad("integration.json missing");
|
|
15606
15675
|
}
|
|
15607
15676
|
if (sha3(ibytes) !== receipt["integration_sha256"])
|
|
15608
15677
|
return bad("integration.json does not match its recorded hash");
|
|
15609
|
-
const integ = readJson5(
|
|
15678
|
+
const integ = readJson5(join67(runDir, "integration.json"));
|
|
15610
15679
|
if (!isObj10(integ) || !isObj10(integ["outcomes"]))
|
|
15611
15680
|
return bad("integration.json has no outcomes");
|
|
15612
15681
|
const iprob = integrationProblem(integ);
|
|
@@ -15636,10 +15705,10 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15636
15705
|
return bad(`child ${text2(repo, 80) || "?"} has an invalid receipt path`);
|
|
15637
15706
|
if (outcomes[repo] !== "ok")
|
|
15638
15707
|
return bad(`child ${text2(repo, 80)} did not finish ok in integration.json`);
|
|
15639
|
-
const rp =
|
|
15708
|
+
const rp = join67(runDir, rel);
|
|
15640
15709
|
let bytes;
|
|
15641
15710
|
try {
|
|
15642
|
-
bytes =
|
|
15711
|
+
bytes = readFileSync53(rp);
|
|
15643
15712
|
} catch {
|
|
15644
15713
|
return bad(`child ${repo} receipt missing`);
|
|
15645
15714
|
}
|
|
@@ -15688,8 +15757,8 @@ var init_keys_cmd = __esm(() => {
|
|
|
15688
15757
|
});
|
|
15689
15758
|
|
|
15690
15759
|
// ../../loki-ts/src/engine10/verify_cmd.ts
|
|
15691
|
-
import { existsSync as
|
|
15692
|
-
import { basename as
|
|
15760
|
+
import { existsSync as existsSync45, readFileSync as readFileSync54, renameSync as renameSync13, statSync as statSync22, writeFileSync as writeFileSync32 } from "fs";
|
|
15761
|
+
import { basename as basename25, dirname as dirname30, join as join68 } from "path";
|
|
15693
15762
|
import { createHash as createHash19, createPublicKey as createPublicKey4, verify as verify4 } from "crypto";
|
|
15694
15763
|
function pubFor(kid, given) {
|
|
15695
15764
|
if (given)
|
|
@@ -15697,7 +15766,7 @@ function pubFor(kid, given) {
|
|
|
15697
15766
|
const active = loadSigningKey(false);
|
|
15698
15767
|
const pubs = (process.env["LOKI_RECEIPT_RETIRED_PUBKEYS"] ?? "").split(":").map((f) => f.trim()).filter(Boolean).flatMap((f) => {
|
|
15699
15768
|
try {
|
|
15700
|
-
return [createPublicKey4(
|
|
15769
|
+
return [createPublicKey4(readFileSync54(f))];
|
|
15701
15770
|
} catch {
|
|
15702
15771
|
return [];
|
|
15703
15772
|
}
|
|
@@ -15741,10 +15810,10 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15741
15810
|
const claims = st !== null && typeof st === "object" && Object.keys(st).length > 0;
|
|
15742
15811
|
return claims ? "the receipt records stages but binds the empty-log hash, so no events.jsonl can back it (missing, empty or non-empty); the receipt is forged or was sealed without a log. Re-run the task to produce a fresh receipt" : null;
|
|
15743
15812
|
}
|
|
15744
|
-
const path =
|
|
15745
|
-
if (!
|
|
15813
|
+
const path = join68(dirname30(receiptPath), "events.jsonl");
|
|
15814
|
+
if (!existsSync45(path))
|
|
15746
15815
|
return "events.jsonl is missing";
|
|
15747
|
-
const raw2 =
|
|
15816
|
+
const raw2 = readFileSync54(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
|
|
15748
15817
|
`).filter((l) => l.trim() !== "");
|
|
15749
15818
|
if (events2.length !== lines2.length || events2.some((e, i) => e.seq !== i))
|
|
15750
15819
|
return "events.jsonl has a forged, edited or missing line";
|
|
@@ -15760,7 +15829,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15760
15829
|
return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
|
|
15761
15830
|
}
|
|
15762
15831
|
function checkLogSeal(receiptPath, hash, kid, given) {
|
|
15763
|
-
const path =
|
|
15832
|
+
const path = join68(dirname30(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
|
|
15764
15833
|
if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
|
|
15765
15834
|
return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
|
|
15766
15835
|
if (done < 0)
|
|
@@ -15768,7 +15837,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15768
15837
|
const seal = events2[done + 1], d = seal?.type === "log.sealed" ? seal.data : null;
|
|
15769
15838
|
if (!d)
|
|
15770
15839
|
return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
|
|
15771
|
-
const lines2 =
|
|
15840
|
+
const lines2 = readFileSync54(path, "utf8").split(`
|
|
15772
15841
|
`).filter((l) => l.trim() !== ""), sha4 = createHash19("sha256").update(lines2.slice(0, done + 1).join(`
|
|
15773
15842
|
`) + `
|
|
15774
15843
|
`).digest("hex");
|
|
@@ -15778,11 +15847,11 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15778
15847
|
return null;
|
|
15779
15848
|
}
|
|
15780
15849
|
async function verifyReceipt(receiptPath, deps = {}) {
|
|
15781
|
-
if (!
|
|
15850
|
+
if (!existsSync45(receiptPath))
|
|
15782
15851
|
return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
|
|
15783
15852
|
let receipt;
|
|
15784
15853
|
try {
|
|
15785
|
-
receipt = JSON.parse((deps.read ?? ((p) =>
|
|
15854
|
+
receipt = JSON.parse((deps.read ?? ((p) => readFileSync54(p, "utf8")))(receiptPath));
|
|
15786
15855
|
} catch {
|
|
15787
15856
|
return { verdict: "UNCHECKED", reasons: ["receipt.json is not valid JSON"] };
|
|
15788
15857
|
}
|
|
@@ -15870,8 +15939,8 @@ var init_verify_cmd = __esm(() => {
|
|
|
15870
15939
|
});
|
|
15871
15940
|
|
|
15872
15941
|
// src/server/app.ts
|
|
15873
|
-
import { existsSync as
|
|
15874
|
-
import { join as
|
|
15942
|
+
import { existsSync as existsSync47, readFileSync as readFileSync57, statSync as statSync23 } from "fs";
|
|
15943
|
+
import { join as join71, resolve as resolve15, sep as sep14 } from "path";
|
|
15875
15944
|
|
|
15876
15945
|
// node_modules/hono/dist/request/constants.js
|
|
15877
15946
|
var GET_MATCH_RESULT = Symbol();
|
|
@@ -26153,9 +26222,9 @@ function mount20(ctx) {
|
|
|
26153
26222
|
}
|
|
26154
26223
|
|
|
26155
26224
|
// src/server/routes/verify.ts
|
|
26156
|
-
import { readFileSync as
|
|
26225
|
+
import { readFileSync as readFileSync55, realpathSync as realpathSync22 } from "fs";
|
|
26157
26226
|
import { createPublicKey as createPublicKey5 } from "crypto";
|
|
26158
|
-
import { join as
|
|
26227
|
+
import { join as join69, sep as sep13 } from "path";
|
|
26159
26228
|
init_verify_cmd();
|
|
26160
26229
|
init_seal();
|
|
26161
26230
|
init_receipt_dsse();
|
|
@@ -26182,15 +26251,15 @@ function mount21(ctx) {
|
|
|
26182
26251
|
return done(404, "receipt not available", "not_found");
|
|
26183
26252
|
let runDir, file;
|
|
26184
26253
|
try {
|
|
26185
|
-
const root =
|
|
26186
|
-
runDir =
|
|
26187
|
-
if (runDir !==
|
|
26254
|
+
const root = realpathSync22(join69(repo.p, ".loki", "runs"));
|
|
26255
|
+
runDir = realpathSync22(join69(root, run2));
|
|
26256
|
+
if (runDir !== join69(root, run2))
|
|
26188
26257
|
return done(404, "receipt not found", "not_found");
|
|
26189
|
-
file =
|
|
26258
|
+
file = realpathSync22(join69(runDir, "receipt.json"));
|
|
26190
26259
|
} catch {
|
|
26191
26260
|
return done(404, "receipt not found", "not_found");
|
|
26192
26261
|
}
|
|
26193
|
-
if (!file.startsWith(runDir +
|
|
26262
|
+
if (!file.startsWith(runDir + sep13))
|
|
26194
26263
|
return done(404, "receipt not found", "not_found");
|
|
26195
26264
|
let integrity, reasons, sha4 = null, outcome = "UNREADABLE";
|
|
26196
26265
|
try {
|
|
@@ -26205,7 +26274,7 @@ function mount21(ctx) {
|
|
|
26205
26274
|
sha4 = r.receiptSha256 ?? null;
|
|
26206
26275
|
}
|
|
26207
26276
|
try {
|
|
26208
|
-
outcome = outcomeOf(JSON.parse(
|
|
26277
|
+
outcome = outcomeOf(JSON.parse(readFileSync55(file, "utf8")));
|
|
26209
26278
|
} catch {
|
|
26210
26279
|
outcome = "UNREADABLE";
|
|
26211
26280
|
}
|
|
@@ -26267,8 +26336,8 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
|
|
|
26267
26336
|
}
|
|
26268
26337
|
|
|
26269
26338
|
// src/server/legacy/shim.ts
|
|
26270
|
-
import { existsSync as
|
|
26271
|
-
import { join as
|
|
26339
|
+
import { existsSync as existsSync46, readFileSync as readFileSync56 } from "fs";
|
|
26340
|
+
import { join as join70 } from "path";
|
|
26272
26341
|
|
|
26273
26342
|
// src/server/legacy/routes.ts
|
|
26274
26343
|
var LEGACY_ROUTES = [
|
|
@@ -26646,10 +26715,10 @@ var logged = new Set;
|
|
|
26646
26715
|
var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
|
|
26647
26716
|
var NOT_SUPPORTED = "not yet supported by the Control Plane";
|
|
26648
26717
|
var repoVersion = () => {
|
|
26649
|
-
for (const f of [
|
|
26718
|
+
for (const f of [join70(import.meta.dir, "../../../../../VERSION")]) {
|
|
26650
26719
|
try {
|
|
26651
|
-
if (
|
|
26652
|
-
return
|
|
26720
|
+
if (existsSync46(f))
|
|
26721
|
+
return readFileSync56(f, "utf8").trim();
|
|
26653
26722
|
} catch {}
|
|
26654
26723
|
}
|
|
26655
26724
|
return "unknown";
|
|
@@ -26831,7 +26900,7 @@ function legacyShim(opts) {
|
|
|
26831
26900
|
|
|
26832
26901
|
// src/server/app.ts
|
|
26833
26902
|
var MAX_BODY2 = 1e6;
|
|
26834
|
-
var defaultUiDir = () => [
|
|
26903
|
+
var defaultUiDir = () => [join71(import.meta.dir, "../../ui/dist"), join71(import.meta.dir, "../ui/dist")].find((d) => existsSync47(join71(d, "index.html")));
|
|
26835
26904
|
function createApp(opts) {
|
|
26836
26905
|
const uiDir = opts.uiDir ?? defaultUiDir();
|
|
26837
26906
|
const { db, sqlite } = openDb(opts.dbPath);
|
|
@@ -26860,10 +26929,10 @@ function createApp(opts) {
|
|
|
26860
26929
|
await next();
|
|
26861
26930
|
});
|
|
26862
26931
|
const readInstalled = () => {
|
|
26863
|
-
for (const f of [process.env.LOKI_VERSION_FILE,
|
|
26932
|
+
for (const f of [process.env.LOKI_VERSION_FILE, join71(import.meta.dir, "../../../../VERSION")]) {
|
|
26864
26933
|
try {
|
|
26865
26934
|
if (f)
|
|
26866
|
-
return
|
|
26935
|
+
return readFileSync57(f, "utf8").trim() || "unknown";
|
|
26867
26936
|
} catch {}
|
|
26868
26937
|
}
|
|
26869
26938
|
return "unknown";
|
|
@@ -26974,11 +27043,11 @@ function createApp(opts) {
|
|
|
26974
27043
|
return c.json({ error: "not found" }, 404);
|
|
26975
27044
|
const root = resolve15(uiDir);
|
|
26976
27045
|
const f = resolve15(root, `.${p}`);
|
|
26977
|
-
if (f.startsWith(root +
|
|
27046
|
+
if (f.startsWith(root + sep14) && existsSync47(f) && statSync23(f).isFile())
|
|
26978
27047
|
return new Response(Bun.file(f));
|
|
26979
27048
|
if (/\.[a-z0-9]+$/i.test(p))
|
|
26980
27049
|
return c.json({ error: "not found" }, 404);
|
|
26981
|
-
return new Response(Bun.file(
|
|
27050
|
+
return new Response(Bun.file(join71(root, "index.html")));
|
|
26982
27051
|
});
|
|
26983
27052
|
return { app, db, close: () => {
|
|
26984
27053
|
clearInterval(reconciler);
|