loki-mode 11.17.20 → 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/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/BOARD.md +10 -10
- package/docs/v10/PROGRESS.md +4 -0
- package/loki-ts/dist/loki.js +922 -922
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +339 -321
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-DSJJQf-T.js → AdminPage-DGg_5Yos.js} +1 -1
- package/web-app/dist/assets/{Avatar-BF6WFrAy.js → Avatar-BIDvM3U5.js} +1 -1
- package/web-app/dist/assets/{Badge-Cr5T8jJf.js → Badge-AsUMPLOU.js} +1 -1
- package/web-app/dist/assets/{Button-cCj7HFSw.js → Button-DodbV8If.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-DYBvJECQ.js → CockpitPage-BxL2zTsP.js} +1 -1
- package/web-app/dist/assets/{ComparePage-jJQblAwt.js → ComparePage-O1iC9fvU.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-DoDYMsY5.js → ErrorBoundary-Cll1sP40.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-jpaq7kZq.js → EvidenceReceiptPanel-DXlOEyn9.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-CKzX14a1.js → GitHubIssuesPanel-DbbqZGUy.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-ZCksAyIl.js → GitHubPRsPanel-B6XhdcJp.js} +1 -1
- package/web-app/dist/assets/{HomePage-C_zXBI8n.js → HomePage-DenelbJm.js} +2 -2
- package/web-app/dist/assets/{LoginPage-B05bavzr.js → LoginPage-MF65tKQb.js} +1 -1
- package/web-app/dist/assets/{MagicPage-d4pG9StL.js → MagicPage-Caa_kRza.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-iDDUkKmA.js → MetricsPage-BVSJe-I6.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-XPzm1hsZ.js → NotFoundPage-BPTMfi71.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-z5I7069v.js → ProjectPage-BbnEno5f.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DEWjBPo6.js → ProjectsPage-CYL7Eh40.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DVQrE47C.js → SettingsPage-D5rk0Q-i.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-DN2Ejjrj.js → ShowcasePage-Cgsx2N4V.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-B1Icrjyg.js → SystemSettingsPage-DKPw7kf7.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-CiX4e5Ss.js → TeamsPage-BOQyzfGG.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-DBMF4Bgy.js → TemplatesPage-C85kNfws.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-BszbIyo2.js → TerminalOutput-CaZ75acm.js} +1 -1
- package/web-app/dist/assets/{activity-CuNWAGl6.js → activity-_vZZ0q95.js} +1 -1
- package/web-app/dist/assets/{bell-CVZY4-gh.js → bell-BepNateL.js} +1 -1
- package/web-app/dist/assets/{bot-CsGTJ3O8.js → bot-CLPO5bfI.js} +1 -1
- package/web-app/dist/assets/{check-DkG0Ea0z.js → check-Cw2ZY8Hd.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D0OVBrPl.js → chevron-left-CNkV8_tB.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DQj17Suj.js → circle-alert-CBgwfRV4.js} +1 -1
- package/web-app/dist/assets/{clock-BwPMUOV3.js → clock-Kbd5g1Q4.js} +1 -1
- package/web-app/dist/assets/{cloud-nBHFumIO.js → cloud-BUHvBaGU.js} +1 -1
- package/web-app/dist/assets/{code-xml-g4JPPXMJ.js → code-xml-BFtb44h7.js} +1 -1
- package/web-app/dist/assets/{database-D2gl8Fu_.js → database-BKTm6rSV.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-DMl-Ua1u.js → dollar-sign-CxSlnHdr.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Cf6Urnli.js → file-code-corner-CzODg9ft.js} +1 -1
- package/web-app/dist/assets/{file-plus-CuN6tuNG.js → file-plus-DwR8w4_g.js} +1 -1
- package/web-app/dist/assets/{globe-DJ9B9SDQ.js → globe-BN26QQLG.js} +1 -1
- package/web-app/dist/assets/{hammer-C22DSm6w.js → hammer-BMGuBFj7.js} +1 -1
- package/web-app/dist/assets/{index-C3mMUd0H.js → index-RYEDj5dp.js} +3 -3
- package/web-app/dist/assets/{layers-C-21Q5yC.js → layers-Bih4Qqbx.js} +1 -1
- package/web-app/dist/assets/{loader-circle-Cudap_5T.js → loader-circle-DTh3fBtD.js} +1 -1
- package/web-app/dist/assets/{lock-BLVsgQuz.js → lock-B77al7oQ.js} +1 -1
- package/web-app/dist/assets/{package-CCd-tsex.js → package-BMcYmquO.js} +1 -1
- package/web-app/dist/assets/{plus-D007hFG1.js → plus-D40JVGe8.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BD0FUUXB.js → refresh-cw-BzmtMb8b.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-mkHMAMo9.js → rotate-ccw-B0-EyBz6.js} +1 -1
- package/web-app/dist/assets/{scroll-text-C4crADU2.js → scroll-text-BQNWKEf4.js} +1 -1
- package/web-app/dist/assets/{server-Du8kdE7M.js → server-DrTKOH08.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CcKJ6wWy.js → shield-alert-bacDs6zS.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-DAfab5rz.js → thumbs-up-CKbEwA0r.js} +1 -1
- package/web-app/dist/assets/{trash-2-BfzfCvzf.js → trash-2-BeWrrpHd.js} +1 -1
- package/web-app/dist/assets/{trending-down-oglIx8Or.js → trending-down-UfhUQ_MW.js} +1 -1
- package/web-app/dist/assets/{trending-up-DIP0FR8A.js → trending-up-CLkxjmYM.js} +1 -1
- package/web-app/dist/assets/{upload-BOS2j4YP.js → upload-DdaprL3w.js} +1 -1
- package/web-app/dist/assets/{usePolling-DX0DJsSF.js → usePolling-Btjcs4pC.js} +1 -1
- package/web-app/dist/assets/{user-DHoJdQR4.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
|
`);
|
|
@@ -10104,11 +10117,11 @@ var init_state = __esm(() => {
|
|
|
10104
10117
|
});
|
|
10105
10118
|
|
|
10106
10119
|
// ../../loki-ts/src/runner/repo_profile.ts
|
|
10107
|
-
import { existsSync as
|
|
10108
|
-
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";
|
|
10109
10122
|
function loadProfile(repoDir) {
|
|
10110
10123
|
try {
|
|
10111
|
-
const p = JSON.parse(
|
|
10124
|
+
const p = JSON.parse(readFileSync30(commandProfilePath(repoDir), "utf8"));
|
|
10112
10125
|
return p?.version === 1 && Array.isArray(p.commands) && p.baseline ? p : null;
|
|
10113
10126
|
} catch {
|
|
10114
10127
|
return null;
|
|
@@ -10199,7 +10212,7 @@ async function staticPreExisting(tool, prefix, files, io) {
|
|
|
10199
10212
|
}
|
|
10200
10213
|
return attributeStatic(tool, head.out, baseOut, 1).preExisting;
|
|
10201
10214
|
}
|
|
10202
|
-
var commandProfilePath = (repoDir) =>
|
|
10215
|
+
var commandProfilePath = (repoDir) => join39(repoDir, ".loki", "state", "repo-profile.json"), STATIC_DIAG, STATIC_NOISE, STATIC_SUMMARY;
|
|
10203
10216
|
var init_repo_profile = __esm(() => {
|
|
10204
10217
|
init_failures();
|
|
10205
10218
|
init_check_result();
|
|
@@ -10241,14 +10254,14 @@ var init_context = __esm(() => {
|
|
|
10241
10254
|
});
|
|
10242
10255
|
|
|
10243
10256
|
// ../../loki-ts/src/util/steer.ts
|
|
10244
|
-
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";
|
|
10245
10258
|
import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
|
|
10246
|
-
import { basename as
|
|
10259
|
+
import { basename as basename13, join as join40 } from "path";
|
|
10247
10260
|
function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
10248
10261
|
for (let i = 0;; i++) {
|
|
10249
10262
|
const name = i === 0 ? `${prefix}.md` : `${prefix}-${i}.md`;
|
|
10250
10263
|
try {
|
|
10251
|
-
link(src,
|
|
10264
|
+
link(src, join40(logs, name));
|
|
10252
10265
|
} catch (e) {
|
|
10253
10266
|
const code = e.code;
|
|
10254
10267
|
if (code === "EEXIST")
|
|
@@ -10256,7 +10269,7 @@ function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
|
10256
10269
|
if (code !== "EPERM" && code !== "ENOTSUP" && code !== "EXDEV" && code !== "EMLINK")
|
|
10257
10270
|
throw e;
|
|
10258
10271
|
const name2 = `${prefix}-${randomBytes4(4).toString("hex")}.md`;
|
|
10259
|
-
renameSync10(src,
|
|
10272
|
+
renameSync10(src, join40(logs, name2));
|
|
10260
10273
|
onLinked?.(name2);
|
|
10261
10274
|
return name2;
|
|
10262
10275
|
}
|
|
@@ -10271,14 +10284,14 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
10271
10284
|
const c = lstatSync9(claim);
|
|
10272
10285
|
if (!c.isFile())
|
|
10273
10286
|
return false;
|
|
10274
|
-
for (const a of
|
|
10287
|
+
for (const a of readdirSync15(logs)) {
|
|
10275
10288
|
if (!/^human-input-.*\.md$/.test(a))
|
|
10276
10289
|
continue;
|
|
10277
10290
|
try {
|
|
10278
|
-
const s = statSync15(
|
|
10291
|
+
const s = statSync15(join40(logs, a));
|
|
10279
10292
|
if (s.ino !== c.ino || s.dev !== c.dev)
|
|
10280
10293
|
continue;
|
|
10281
|
-
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) ||
|
|
10294
|
+
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) || existsSync24(appliedMarker(logs, a)))
|
|
10282
10295
|
return true;
|
|
10283
10296
|
} catch {}
|
|
10284
10297
|
}
|
|
@@ -10287,7 +10300,7 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
10287
10300
|
function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
10288
10301
|
let names;
|
|
10289
10302
|
try {
|
|
10290
|
-
names =
|
|
10303
|
+
names = readdirSync15(logs);
|
|
10291
10304
|
} catch {
|
|
10292
10305
|
return;
|
|
10293
10306
|
}
|
|
@@ -10295,7 +10308,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10295
10308
|
for (const n2 of names)
|
|
10296
10309
|
if (n2.startsWith(".applied-") && !present.has(n2.slice(".applied-".length))) {
|
|
10297
10310
|
try {
|
|
10298
|
-
unlinkSync5(
|
|
10311
|
+
unlinkSync5(join40(logs, n2));
|
|
10299
10312
|
} catch {}
|
|
10300
10313
|
}
|
|
10301
10314
|
for (const n2 of names) {
|
|
@@ -10312,7 +10325,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10312
10325
|
if (alive) {
|
|
10313
10326
|
let ageMs = 0;
|
|
10314
10327
|
try {
|
|
10315
|
-
ageMs = nowMs - statSync15(
|
|
10328
|
+
ageMs = nowMs - statSync15(join40(logs, n2)).mtimeMs;
|
|
10316
10329
|
} catch {
|
|
10317
10330
|
continue;
|
|
10318
10331
|
}
|
|
@@ -10320,11 +10333,11 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10320
10333
|
continue;
|
|
10321
10334
|
}
|
|
10322
10335
|
try {
|
|
10323
|
-
if (orphanAlreadyArchived(logs,
|
|
10324
|
-
unlinkSync5(
|
|
10336
|
+
if (orphanAlreadyArchived(logs, join40(logs, n2))) {
|
|
10337
|
+
unlinkSync5(join40(logs, n2));
|
|
10325
10338
|
continue;
|
|
10326
10339
|
}
|
|
10327
|
-
archiveTo(logs, `human-input-ORPHAN-${stamp2}`,
|
|
10340
|
+
archiveTo(logs, `human-input-ORPHAN-${stamp2}`, join40(logs, n2), link);
|
|
10328
10341
|
unapplied("orphaned claim");
|
|
10329
10342
|
} catch (e) {
|
|
10330
10343
|
if (e.code === "ENOENT")
|
|
@@ -10336,17 +10349,17 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10336
10349
|
function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, hooks2) {
|
|
10337
10350
|
if (/^(0|false)$/i.test(env.LOKI_PROMPT_INJECTION ?? ""))
|
|
10338
10351
|
return null;
|
|
10339
|
-
const f =
|
|
10352
|
+
const f = join40(repoDir, ".loki", "HUMAN_INPUT.md");
|
|
10340
10353
|
const unapplied = (reason) => {
|
|
10341
10354
|
sink?.push({ rev: 0, source: null, actor: null, sha: "", at: now2().getTime(), unapplied: true, reason });
|
|
10342
10355
|
};
|
|
10343
10356
|
let fd = -1, claimed = "";
|
|
10344
10357
|
try {
|
|
10345
|
-
const logs =
|
|
10358
|
+
const logs = join40(repoDir, ".loki", "logs");
|
|
10346
10359
|
mkdirSync15(logs, { recursive: true });
|
|
10347
10360
|
const stamp2 = now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "");
|
|
10348
10361
|
sweepOrphans(logs, stamp2, unapplied, hooks2?.link, now2().getTime());
|
|
10349
|
-
claimed =
|
|
10362
|
+
claimed = join40(logs, `.claim-${process.pid}-${randomBytes4(6).toString("hex")}`);
|
|
10350
10363
|
try {
|
|
10351
10364
|
renameSync10(f, claimed);
|
|
10352
10365
|
} catch (e) {
|
|
@@ -10437,10 +10450,10 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
10437
10450
|
} catch {
|
|
10438
10451
|
if (claimed) {
|
|
10439
10452
|
try {
|
|
10440
|
-
archiveTo(
|
|
10453
|
+
archiveTo(join40(repoDir, ".loki", "logs"), `human-input-${now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "")}`, claimed, hooks2?.link);
|
|
10441
10454
|
unapplied("logs dir unwritable or file unreadable");
|
|
10442
10455
|
} catch {
|
|
10443
|
-
unapplied(`steer stranded at .loki/logs/${
|
|
10456
|
+
unapplied(`steer stranded at .loki/logs/${basename13(claimed)}`);
|
|
10444
10457
|
}
|
|
10445
10458
|
} else
|
|
10446
10459
|
try {
|
|
@@ -10456,10 +10469,10 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
10456
10469
|
}
|
|
10457
10470
|
}
|
|
10458
10471
|
function recordRevisions(repoDir, text2, archived, at) {
|
|
10459
|
-
const file =
|
|
10472
|
+
const file = join40(repoDir, ".loki", "intent-revisions.jsonl");
|
|
10460
10473
|
let last = 0;
|
|
10461
10474
|
try {
|
|
10462
|
-
for (const l of
|
|
10475
|
+
for (const l of readFileSync31(file, "utf8").split(`
|
|
10463
10476
|
`)) {
|
|
10464
10477
|
try {
|
|
10465
10478
|
last = Math.max(last, Number(JSON.parse(l).rev) || 0);
|
|
@@ -10513,7 +10526,7 @@ function staleAtSeal(repoDir, ctx) {
|
|
|
10513
10526
|
const frozen = ctx.outputs === undefined || ctx.outputs().wall !== undefined || ctx.wallSealed === true;
|
|
10514
10527
|
return [...new Set([...staleWallRevisions(ctx.intentRevisions, frozen ? ctx.timeline : []), ...late])];
|
|
10515
10528
|
}
|
|
10516
|
-
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;
|
|
10517
10530
|
var init_steer = __esm(() => {
|
|
10518
10531
|
init_context();
|
|
10519
10532
|
STEER_MAX_BYTES = 1024 * 1024;
|
|
@@ -10576,18 +10589,18 @@ var init_seal_drift = __esm(() => {
|
|
|
10576
10589
|
});
|
|
10577
10590
|
|
|
10578
10591
|
// ../../loki-ts/src/util/spec_file.ts
|
|
10579
|
-
import { isAbsolute as
|
|
10592
|
+
import { isAbsolute as isAbsolute4, join as join41, relative as relative2 } from "path";
|
|
10580
10593
|
function specReceiptBlock(env) {
|
|
10581
10594
|
const { LOKI_E10_SPEC_PATH: p, LOKI_E10_SPEC_SHA256: sha2 } = env;
|
|
10582
10595
|
if (!p || !sha2)
|
|
10583
10596
|
return {};
|
|
10584
|
-
const rel =
|
|
10597
|
+
const rel = isAbsolute4(p) && env.LOKI_E10_REPO_DIR ? relative2(env.LOKI_E10_REPO_DIR, p) : p;
|
|
10585
10598
|
return { spec: { path: rel, sha256: sha2 } };
|
|
10586
10599
|
}
|
|
10587
10600
|
var SPEC_DIR;
|
|
10588
10601
|
var init_spec_file = __esm(() => {
|
|
10589
10602
|
init_types();
|
|
10590
|
-
SPEC_DIR =
|
|
10603
|
+
SPEC_DIR = join41(".loki", "specs");
|
|
10591
10604
|
});
|
|
10592
10605
|
|
|
10593
10606
|
// ../../loki-ts/src/engine10/pr_body.ts
|
|
@@ -10607,11 +10620,11 @@ var init_run_cap = __esm(() => {
|
|
|
10607
10620
|
});
|
|
10608
10621
|
|
|
10609
10622
|
// ../../loki-ts/src/util/mutation_proof.ts
|
|
10610
|
-
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";
|
|
10611
10624
|
import { tmpdir as tmpdir4 } from "os";
|
|
10612
|
-
import { basename as
|
|
10625
|
+
import { basename as basename14, dirname as dirname13, isAbsolute as isAbsolute5, join as join42, relative as relative3 } from "path";
|
|
10613
10626
|
function mutationProof(i) {
|
|
10614
|
-
const rels = i.wallFiles.map((f) =>
|
|
10627
|
+
const rels = i.wallFiles.map((f) => isAbsolute5(f.path) ? relative3(i.repoDir, f.path) : f.path);
|
|
10615
10628
|
if (rels.length === 0)
|
|
10616
10629
|
return np("no Wall tests");
|
|
10617
10630
|
const tests = rels.flatMap((rel) => {
|
|
@@ -10627,26 +10640,26 @@ function mutationProof(i) {
|
|
|
10627
10640
|
const deadline = Date.now() + budgetS * 1000, remaining = () => deadline - Date.now();
|
|
10628
10641
|
let parent = null, wt = null, added = false;
|
|
10629
10642
|
try {
|
|
10630
|
-
parent = mkdtempSync3(
|
|
10631
|
-
wt =
|
|
10643
|
+
parent = mkdtempSync3(join42(tmpdir4(), "loki-mutproof-"));
|
|
10644
|
+
wt = join42(parent, "wt");
|
|
10632
10645
|
const add3 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
|
|
10633
|
-
added =
|
|
10646
|
+
added = existsSync25(wt) || add3.status === 0;
|
|
10634
10647
|
if (add3.status !== 0)
|
|
10635
10648
|
return np("could not create the base worktree");
|
|
10636
10649
|
for (const rel of rels) {
|
|
10637
|
-
const sealed =
|
|
10638
|
-
if (!
|
|
10650
|
+
const sealed = join42(i.runDir, "wall", basename14(rel)), src = existsSync25(sealed) ? sealed : join42(i.repoDir, rel);
|
|
10651
|
+
if (!existsSync25(src))
|
|
10639
10652
|
return np(`Wall file missing: ${rel}`);
|
|
10640
|
-
mkdirSync16(dirname13(
|
|
10641
|
-
writeFileSync19(
|
|
10653
|
+
mkdirSync16(dirname13(join42(wt, rel)), { recursive: true });
|
|
10654
|
+
writeFileSync19(join42(wt, rel), readFileSync32(src));
|
|
10642
10655
|
}
|
|
10643
10656
|
for (const rel of rels) {
|
|
10644
10657
|
const parts = rel.split("/").slice(0, -1);
|
|
10645
10658
|
for (let n2 = 0;n2 <= parts.length; n2++) {
|
|
10646
10659
|
const anc = parts.slice(0, n2).join("/");
|
|
10647
10660
|
for (const d of DEP_DIRS) {
|
|
10648
|
-
const src =
|
|
10649
|
-
if (
|
|
10661
|
+
const src = join42(i.repoDir, anc, d), dst = join42(wt, anc, d);
|
|
10662
|
+
if (existsSync25(src) && !existsSync25(dst)) {
|
|
10650
10663
|
try {
|
|
10651
10664
|
symlinkSync(src, dst);
|
|
10652
10665
|
} catch {}
|
|
@@ -10774,7 +10787,7 @@ var init_shell = __esm(() => {
|
|
|
10774
10787
|
});
|
|
10775
10788
|
|
|
10776
10789
|
// ../../loki-ts/src/util/python.ts
|
|
10777
|
-
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";
|
|
10778
10791
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10779
10792
|
import { tmpdir as tmpdir5 } from "os";
|
|
10780
10793
|
function resolvePython3() {
|
|
@@ -11115,7 +11128,7 @@ var init_wall_manifest = __esm(() => {
|
|
|
11115
11128
|
|
|
11116
11129
|
// ../../loki-ts/src/features/wall_manifest_wire.ts
|
|
11117
11130
|
import { createHash as createHash11 } from "crypto";
|
|
11118
|
-
import { basename as
|
|
11131
|
+
import { basename as basename15, dirname as dirname14 } from "path";
|
|
11119
11132
|
function blobEntries(ls) {
|
|
11120
11133
|
const out2 = [];
|
|
11121
11134
|
for (const raw2 of ls.toString("latin1").split("\x00")) {
|
|
@@ -11145,12 +11158,12 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
|
|
|
11145
11158
|
return null;
|
|
11146
11159
|
const low = task.toLowerCase().replace(/\\/g, "/");
|
|
11147
11160
|
const token = (n2) => new RegExp(`(?<![A-Za-z0-9_])${n2.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`).test(low);
|
|
11148
|
-
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(
|
|
11149
|
-
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)));
|
|
11150
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]);
|
|
11151
11164
|
const occ = new Map(matched.map((e) => [e, spans(e.path)]));
|
|
11152
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)));
|
|
11153
|
-
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)));
|
|
11154
11167
|
const named = [...byPath2, ...byBase, ...matched.filter((e) => !byPath2.includes(e) && !byBase.includes(e))].slice(0, MAX_NAMED);
|
|
11155
11168
|
const tests = all.filter((e) => TESTISH.test(e.path)).slice(0, MAX_FILES), listed = tests.filter((e) => !SOURCE.test(e.path));
|
|
11156
11169
|
const want = [...new Set([...all.filter((e) => CONFIG.test(e.path)), ...tests.filter((e) => SOURCE.test(e.path)), ...named])];
|
|
@@ -11207,9 +11220,9 @@ Example: test('name', () => { assert.strictEqual(fn(1), 2); }); Run: node --tes
|
|
|
11207
11220
|
|
|
11208
11221
|
// ../../loki-ts/src/util/holdout.ts
|
|
11209
11222
|
import { createHash as createHash12 } from "crypto";
|
|
11210
|
-
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";
|
|
11211
11224
|
import { tmpdir as tmpdir6 } from "os";
|
|
11212
|
-
import { basename as
|
|
11225
|
+
import { basename as basename16, join as join43, relative as relative4 } from "path";
|
|
11213
11226
|
function wallHoldoutRatio(env = process.env) {
|
|
11214
11227
|
if (env["LOKI_WALL_HOLDOUT"]?.trim() === "0")
|
|
11215
11228
|
return 0;
|
|
@@ -11237,32 +11250,32 @@ function stashHoldout(o) {
|
|
|
11237
11250
|
rmSync12(dir, { recursive: true, force: true });
|
|
11238
11251
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
11239
11252
|
const files = held.map((name) => {
|
|
11240
|
-
copyFileSync2(
|
|
11241
|
-
rmSync12(
|
|
11242
|
-
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")) };
|
|
11243
11256
|
});
|
|
11244
|
-
writeFileSync20(
|
|
11257
|
+
writeFileSync20(join43(dir, MANIFEST), JSON.stringify({ targetDir: o.targetDir, files }));
|
|
11245
11258
|
return { dir, names: new Set(held) };
|
|
11246
11259
|
}
|
|
11247
11260
|
function stageHoldout(dir, repoDir) {
|
|
11248
11261
|
const put = [], tests = [], missing = [];
|
|
11249
11262
|
let man = null;
|
|
11250
11263
|
try {
|
|
11251
|
-
man = JSON.parse(
|
|
11264
|
+
man = JSON.parse(readFileSync34(join43(dir, MANIFEST), "utf8"));
|
|
11252
11265
|
} catch {}
|
|
11253
11266
|
if (!man)
|
|
11254
|
-
return { tests, missing: [`holdout store unreadable: ${
|
|
11267
|
+
return { tests, missing: [`holdout store unreadable: ${basename16(dir)}`], cleanup: () => {} };
|
|
11255
11268
|
mkdirSync17(man.targetDir, { recursive: true });
|
|
11256
11269
|
man.files.forEach((f, i) => {
|
|
11257
|
-
const src =
|
|
11258
|
-
if (!
|
|
11270
|
+
const src = join43(dir, f.name);
|
|
11271
|
+
if (!existsSync27(src) || sha2(readFileSync34(src, "utf8")) !== f.sha256) {
|
|
11259
11272
|
missing.push(`holdout ${i + 1} missing or altered`);
|
|
11260
11273
|
return;
|
|
11261
11274
|
}
|
|
11262
|
-
const dest =
|
|
11275
|
+
const dest = join43(man.targetDir, `loki_wall_holdout_${i + 1}${f.name.slice(f.name.indexOf("."))}`);
|
|
11263
11276
|
copyFileSync2(src, dest);
|
|
11264
11277
|
put.push(dest);
|
|
11265
|
-
tests.push({ runner: f.runner, path:
|
|
11278
|
+
tests.push({ runner: f.runner, path: relative4(repoDir, dest) });
|
|
11266
11279
|
});
|
|
11267
11280
|
return { tests, missing, cleanup: () => {
|
|
11268
11281
|
for (const p of put)
|
|
@@ -11272,16 +11285,16 @@ function stageHoldout(dir, repoDir) {
|
|
|
11272
11285
|
function recordHoldoutTriage(runDir, entry) {
|
|
11273
11286
|
try {
|
|
11274
11287
|
mkdirSync17(runDir, { recursive: true });
|
|
11275
|
-
appendFileSync3(
|
|
11288
|
+
appendFileSync3(join43(runDir, HOLDOUT_TRIAGE_FILE), JSON.stringify(entry) + `
|
|
11276
11289
|
`, { mode: 384 });
|
|
11277
11290
|
} catch {}
|
|
11278
11291
|
}
|
|
11279
|
-
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";
|
|
11280
11293
|
var init_holdout = () => {};
|
|
11281
11294
|
|
|
11282
11295
|
// ../../loki-ts/src/features/runner_config.ts
|
|
11283
|
-
import { readFileSync as
|
|
11284
|
-
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";
|
|
11285
11298
|
function tomlKey2(s, i = 0, eq2 = true) {
|
|
11286
11299
|
const parts = [], ws = () => {
|
|
11287
11300
|
while (/\s/.test(s[i] ?? "x"))
|
|
@@ -11558,8 +11571,8 @@ function referenced(cfg, text2) {
|
|
|
11558
11571
|
}
|
|
11559
11572
|
const dir = dirname15(cfg), explicit = ROOT_DIR.exec(text2), roots = [dir];
|
|
11560
11573
|
if (explicit)
|
|
11561
|
-
roots.push("", ...explicit[1] ? [
|
|
11562
|
-
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)))];
|
|
11563
11576
|
}
|
|
11564
11577
|
function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
11565
11578
|
const notes = new Set, ch = new Set(changed.map((c) => normalize2(c)));
|
|
@@ -11639,7 +11652,7 @@ var PKG_KEYS, RAW_CONFIGS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, dep
|
|
|
11639
11652
|
}
|
|
11640
11653
|
}, headText = (dir, f) => {
|
|
11641
11654
|
try {
|
|
11642
|
-
return
|
|
11655
|
+
return readFileSync35(join44(dir, f), "utf8");
|
|
11643
11656
|
} catch {
|
|
11644
11657
|
return "";
|
|
11645
11658
|
}
|
|
@@ -11679,19 +11692,19 @@ var init_runner_config = __esm(() => {
|
|
|
11679
11692
|
|
|
11680
11693
|
// ../../loki-ts/src/e10ext/assert_delta.ts
|
|
11681
11694
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
11682
|
-
import { mkdtempSync as mkdtempSync5, readFileSync as
|
|
11695
|
+
import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync36, rmSync as rmSync13 } from "fs";
|
|
11683
11696
|
import { tmpdir as tmpdir7 } from "os";
|
|
11684
|
-
import { join as
|
|
11685
|
-
import { basename as
|
|
11697
|
+
import { join as join45 } from "path";
|
|
11698
|
+
import { basename as basename17 } from "path";
|
|
11686
11699
|
function classifyAssertDelta(inp) {
|
|
11687
|
-
const f =
|
|
11700
|
+
const f = basename17(inp.path);
|
|
11688
11701
|
if (!/^(test_.*|.*_test)\.py$/.test(f))
|
|
11689
11702
|
return WEAKENED;
|
|
11690
11703
|
if (inp.headCounts.run !== inp.baseCounts.run || inp.headCounts.skipped !== inp.baseCounts.skipped)
|
|
11691
11704
|
return WEAKENED;
|
|
11692
11705
|
let cwd = "";
|
|
11693
11706
|
try {
|
|
11694
|
-
cwd = mkdtempSync5(
|
|
11707
|
+
cwd = mkdtempSync5(join45(tmpdir7(), "loki-ad-"));
|
|
11695
11708
|
const raw2 = execFileSync3("python3", ["-I", "-c", PY], {
|
|
11696
11709
|
input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
|
|
11697
11710
|
cwd,
|
|
@@ -11722,7 +11735,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
|
|
|
11722
11735
|
return null;
|
|
11723
11736
|
try {
|
|
11724
11737
|
const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
|
|
11725
|
-
const head = headRef ? show(headRef) :
|
|
11738
|
+
const head = headRef ? show(headRef) : readFileSync36(join45(repoDir, path), "utf8");
|
|
11726
11739
|
const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
|
|
11727
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;
|
|
11728
11741
|
} catch {
|
|
@@ -11929,19 +11942,19 @@ var init_runner_errors = __esm(() => {
|
|
|
11929
11942
|
|
|
11930
11943
|
// ../../loki-ts/src/runner/load_owner.ts
|
|
11931
11944
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
11932
|
-
import { mkdtempSync as mkdtempSync6, realpathSync as
|
|
11945
|
+
import { mkdtempSync as mkdtempSync6, realpathSync as realpathSync18, rmSync as rmSync14 } from "fs";
|
|
11933
11946
|
import { tmpdir as tmpdir8 } from "os";
|
|
11934
|
-
import { basename as
|
|
11947
|
+
import { basename as basename18, extname as extname2, join as join46 } from "path";
|
|
11935
11948
|
function changedFilesNamed(out2, repoDir, changed) {
|
|
11936
11949
|
return changed.filter((f) => {
|
|
11937
|
-
if (out2.includes(f) || out2.includes(
|
|
11950
|
+
if (out2.includes(f) || out2.includes(join46(repoDir, f)))
|
|
11938
11951
|
return true;
|
|
11939
11952
|
const segs = f.split("/");
|
|
11940
11953
|
if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
|
|
11941
11954
|
return true;
|
|
11942
|
-
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)))
|
|
11943
11956
|
return true;
|
|
11944
|
-
const stem =
|
|
11957
|
+
const stem = basename18(f, extname2(f));
|
|
11945
11958
|
if (stem.length < 2 || stem === "index" || stem === "__init__")
|
|
11946
11959
|
return false;
|
|
11947
11960
|
return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
|
|
@@ -11951,7 +11964,7 @@ function loadSignature(out2, roots) {
|
|
|
11951
11964
|
let o = out2;
|
|
11952
11965
|
for (const r of roots.flatMap((x) => {
|
|
11953
11966
|
try {
|
|
11954
|
-
return [x,
|
|
11967
|
+
return [x, realpathSync18(x)];
|
|
11955
11968
|
} catch {
|
|
11956
11969
|
return [x];
|
|
11957
11970
|
}
|
|
@@ -12045,7 +12058,7 @@ async function loadErrorIsHarnessOwned(i) {
|
|
|
12045
12058
|
return false;
|
|
12046
12059
|
if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
|
|
12047
12060
|
return false;
|
|
12048
|
-
const dir = mkdtempSync6(
|
|
12061
|
+
const dir = mkdtempSync6(join46(tmpdir8(), "e10-loadown-"));
|
|
12049
12062
|
const git3 = (args) => {
|
|
12050
12063
|
safeGit(i.repoDir, args, { stdio: "ignore" });
|
|
12051
12064
|
};
|
|
@@ -12077,7 +12090,7 @@ var init_load_owner = __esm(() => {
|
|
|
12077
12090
|
});
|
|
12078
12091
|
|
|
12079
12092
|
// ../../loki-ts/src/util/wall_owned.ts
|
|
12080
|
-
import { isAbsolute as
|
|
12093
|
+
import { isAbsolute as isAbsolute6, join as join47, relative as relative5 } from "path";
|
|
12081
12094
|
function failingLocations(raw2, cwd, repoDir) {
|
|
12082
12095
|
const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
|
|
12083
12096
|
`), files = new Set;
|
|
@@ -12109,7 +12122,7 @@ function failingLocations(raw2, cwd, repoDir) {
|
|
|
12109
12122
|
}
|
|
12110
12123
|
if (errors2 === 0 || located !== errors2)
|
|
12111
12124
|
return null;
|
|
12112
|
-
return [...files].map((f) =>
|
|
12125
|
+
return [...files].map((f) => relative5(repoDir, isAbsolute6(f) ? f : join47(cwd, f)));
|
|
12113
12126
|
}
|
|
12114
12127
|
function wallOwnedFailure(raw2, cwd, repoDir, wall) {
|
|
12115
12128
|
const locs = failingLocations(raw2, cwd, repoDir);
|
|
@@ -12123,21 +12136,21 @@ var init_wall_owned = __esm(() => {
|
|
|
12123
12136
|
// ../../loki-ts/src/project_graph.ts
|
|
12124
12137
|
import { createHash as createHash13 } from "crypto";
|
|
12125
12138
|
import {
|
|
12126
|
-
existsSync as
|
|
12127
|
-
readdirSync as
|
|
12128
|
-
readFileSync as
|
|
12139
|
+
existsSync as existsSync28,
|
|
12140
|
+
readdirSync as readdirSync16,
|
|
12141
|
+
readFileSync as readFileSync37,
|
|
12129
12142
|
statSync as statSync17,
|
|
12130
12143
|
writeFileSync as writeFileSync21,
|
|
12131
12144
|
mkdirSync as mkdirSync18
|
|
12132
12145
|
} from "fs";
|
|
12133
|
-
import { basename as
|
|
12146
|
+
import { basename as basename19, dirname as dirname16, join as join48, resolve as resolve14 } from "path";
|
|
12134
12147
|
function readManifest(path) {
|
|
12135
|
-
if (!
|
|
12148
|
+
if (!existsSync28(path)) {
|
|
12136
12149
|
return null;
|
|
12137
12150
|
}
|
|
12138
12151
|
let raw2;
|
|
12139
12152
|
try {
|
|
12140
|
-
raw2 =
|
|
12153
|
+
raw2 = readFileSync37(path, "utf8");
|
|
12141
12154
|
} catch {
|
|
12142
12155
|
return null;
|
|
12143
12156
|
}
|
|
@@ -12174,7 +12187,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12174
12187
|
const seen = new Set;
|
|
12175
12188
|
let children;
|
|
12176
12189
|
try {
|
|
12177
|
-
children =
|
|
12190
|
+
children = readdirSync16(rootDir);
|
|
12178
12191
|
} catch {
|
|
12179
12192
|
children = [];
|
|
12180
12193
|
}
|
|
@@ -12189,7 +12202,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12189
12202
|
for (const child of children) {
|
|
12190
12203
|
if (!matchPattern(name, child))
|
|
12191
12204
|
continue;
|
|
12192
|
-
const full =
|
|
12205
|
+
const full = join48(rootDir, child);
|
|
12193
12206
|
if (seen.has(full))
|
|
12194
12207
|
continue;
|
|
12195
12208
|
let st;
|
|
@@ -12206,7 +12219,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12206
12219
|
}
|
|
12207
12220
|
if (declared.length === 0) {
|
|
12208
12221
|
for (const child of children) {
|
|
12209
|
-
const full =
|
|
12222
|
+
const full = join48(rootDir, child);
|
|
12210
12223
|
if (seen.has(full))
|
|
12211
12224
|
continue;
|
|
12212
12225
|
let st;
|
|
@@ -12217,7 +12230,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12217
12230
|
}
|
|
12218
12231
|
if (!st.isDirectory())
|
|
12219
12232
|
continue;
|
|
12220
|
-
if (!
|
|
12233
|
+
if (!existsSync28(join48(full, ".loki", "app.json")))
|
|
12221
12234
|
continue;
|
|
12222
12235
|
seen.add(full);
|
|
12223
12236
|
out2.push(full);
|
|
@@ -12238,26 +12251,26 @@ function cacheKey(manifestPaths) {
|
|
|
12238
12251
|
}
|
|
12239
12252
|
function writeCache(targetDir, key, result) {
|
|
12240
12253
|
try {
|
|
12241
|
-
const cacheDir =
|
|
12254
|
+
const cacheDir = join48(targetDir, ".loki", "state");
|
|
12242
12255
|
mkdirSync18(cacheDir, { recursive: true });
|
|
12243
|
-
const cachePath =
|
|
12256
|
+
const cachePath = join48(cacheDir, "project-graph.json");
|
|
12244
12257
|
writeFileSync21(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
|
|
12245
12258
|
} catch {}
|
|
12246
12259
|
}
|
|
12247
12260
|
function discoverProjectGraph(targetDir) {
|
|
12248
12261
|
const absTarget = resolve14(targetDir);
|
|
12249
|
-
const targetManifest =
|
|
12262
|
+
const targetManifest = join48(absTarget, ".loki", "app.json");
|
|
12250
12263
|
const parentDir = dirname16(absTarget);
|
|
12251
|
-
const parentManifest =
|
|
12264
|
+
const parentManifest = join48(parentDir, ".loki", "app.json");
|
|
12252
12265
|
const examined = [];
|
|
12253
12266
|
let chosenManifest = null;
|
|
12254
12267
|
let chosenRoot = "";
|
|
12255
|
-
if (
|
|
12268
|
+
if (existsSync28(parentManifest) && parentDir !== absTarget) {
|
|
12256
12269
|
examined.push(parentManifest);
|
|
12257
12270
|
chosenManifest = readManifest(parentManifest);
|
|
12258
12271
|
chosenRoot = parentDir;
|
|
12259
12272
|
}
|
|
12260
|
-
if (!chosenManifest &&
|
|
12273
|
+
if (!chosenManifest && existsSync28(targetManifest)) {
|
|
12261
12274
|
examined.push(targetManifest);
|
|
12262
12275
|
chosenManifest = readManifest(targetManifest);
|
|
12263
12276
|
chosenRoot = absTarget;
|
|
@@ -12265,11 +12278,11 @@ function discoverProjectGraph(targetDir) {
|
|
|
12265
12278
|
if (!chosenManifest)
|
|
12266
12279
|
return null;
|
|
12267
12280
|
const declared = chosenManifest.members ?? [];
|
|
12268
|
-
const members = resolveMembers(chosenRoot, declared,
|
|
12281
|
+
const members = resolveMembers(chosenRoot, declared, basename19(absTarget));
|
|
12269
12282
|
const filtered = [];
|
|
12270
12283
|
for (const m of members) {
|
|
12271
|
-
const sibManifestPath =
|
|
12272
|
-
if (
|
|
12284
|
+
const sibManifestPath = join48(m, ".loki", "app.json");
|
|
12285
|
+
if (existsSync28(sibManifestPath)) {
|
|
12273
12286
|
examined.push(sibManifestPath);
|
|
12274
12287
|
const sibManifest = readManifest(sibManifestPath);
|
|
12275
12288
|
if (sibManifest && sibManifest.app_id !== chosenManifest.app_id) {
|
|
@@ -12397,9 +12410,9 @@ var init_route_block = __esm(() => {
|
|
|
12397
12410
|
// ../../loki-ts/src/features/visual_evidence.ts
|
|
12398
12411
|
import { spawn as spawn7 } from "child_process";
|
|
12399
12412
|
import { createHash as createHash14, randomBytes as randomBytes5 } from "crypto";
|
|
12400
|
-
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";
|
|
12401
12414
|
import { createServer } from "net";
|
|
12402
|
-
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";
|
|
12403
12416
|
function routeFor(file) {
|
|
12404
12417
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
12405
12418
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -12409,7 +12422,7 @@ function hashScreens(runDir, rels) {
|
|
|
12409
12422
|
const out2 = [];
|
|
12410
12423
|
for (const rel of rels) {
|
|
12411
12424
|
try {
|
|
12412
|
-
out2.push({ path: rel, sha256: sha256File(
|
|
12425
|
+
out2.push({ path: rel, sha256: sha256File(join49(runDir, rel)) });
|
|
12413
12426
|
} catch {}
|
|
12414
12427
|
}
|
|
12415
12428
|
return out2;
|
|
@@ -12420,16 +12433,16 @@ function checkScreens(runDir, screens) {
|
|
|
12420
12433
|
for (const s of screens) {
|
|
12421
12434
|
if (typeof s?.path !== "string" || typeof s.sha256 !== "string")
|
|
12422
12435
|
return "evidence_screens entry is malformed";
|
|
12423
|
-
if (
|
|
12436
|
+
if (isAbsolute7(s.path) || normalize3(s.path).startsWith(".."))
|
|
12424
12437
|
return `evidence screenshot path escapes the evidence dir: ${s.path}`;
|
|
12425
|
-
const file =
|
|
12438
|
+
const file = join49(runDir, s.path);
|
|
12426
12439
|
let cur = runDir;
|
|
12427
|
-
for (const seg of normalize3(s.path).split(
|
|
12428
|
-
cur =
|
|
12440
|
+
for (const seg of normalize3(s.path).split(sep11)) {
|
|
12441
|
+
cur = join49(cur, seg);
|
|
12429
12442
|
if (isSymlink(cur))
|
|
12430
12443
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
12431
12444
|
}
|
|
12432
|
-
if (!
|
|
12445
|
+
if (!existsSync29(file))
|
|
12433
12446
|
return `evidence screenshot is missing: ${s.path}`;
|
|
12434
12447
|
if (!isRegularFile(file))
|
|
12435
12448
|
return `evidence screenshot is not a regular file: ${s.path}`;
|
|
@@ -12472,11 +12485,11 @@ async function waitUp(url, ms, signal) {
|
|
|
12472
12485
|
}
|
|
12473
12486
|
function openapiPaths(repoDir) {
|
|
12474
12487
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
12475
|
-
const p =
|
|
12476
|
-
if (!
|
|
12488
|
+
const p = join49(repoDir, f);
|
|
12489
|
+
if (!existsSync29(p))
|
|
12477
12490
|
continue;
|
|
12478
12491
|
try {
|
|
12479
|
-
const txt =
|
|
12492
|
+
const txt = readFileSync38(p, "utf8");
|
|
12480
12493
|
const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
|
|
12481
12494
|
return paths.filter((x) => !x.includes("{")).slice(0, 10);
|
|
12482
12495
|
} catch {
|
|
@@ -12490,24 +12503,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
|
|
|
12490
12503
|
if (!pw || !pkg)
|
|
12491
12504
|
return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
|
|
12492
12505
|
try {
|
|
12493
|
-
const dir =
|
|
12506
|
+
const dir = join49(runDir, relDir, "e2e");
|
|
12494
12507
|
mkdirSync19(dir, { recursive: true });
|
|
12495
|
-
writeFileSync22(
|
|
12496
|
-
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" } };
|
|
12497
12510
|
`);
|
|
12498
|
-
if (!await shoot(pw, ["test", "--config",
|
|
12511
|
+
if (!await shoot(pw, ["test", "--config", join49(dir, "playwright.config.cjs")], repoDir, ms, signal))
|
|
12499
12512
|
return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
|
|
12500
12513
|
const rels = [];
|
|
12501
12514
|
const walk = (d) => {
|
|
12502
|
-
for (const e of
|
|
12503
|
-
const full =
|
|
12515
|
+
for (const e of readdirSync17(d, { withFileTypes: true })) {
|
|
12516
|
+
const full = join49(d, e.name);
|
|
12504
12517
|
if (e.isDirectory())
|
|
12505
12518
|
walk(full);
|
|
12506
12519
|
else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
|
|
12507
|
-
rels.push(
|
|
12520
|
+
rels.push(join49(relDir, "e2e", relative6(dir, full)));
|
|
12508
12521
|
}
|
|
12509
12522
|
};
|
|
12510
|
-
walk(
|
|
12523
|
+
walk(join49(dir, "out"));
|
|
12511
12524
|
return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
|
|
12512
12525
|
} catch (e) {
|
|
12513
12526
|
return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
|
|
@@ -12586,22 +12599,22 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12586
12599
|
if (!visualEvidenceEnabled(opts.env))
|
|
12587
12600
|
return skip("LOKI_VISUAL_EVIDENCE is 0");
|
|
12588
12601
|
const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
|
|
12589
|
-
const appDir = boot ?
|
|
12590
|
-
const pkgPath =
|
|
12602
|
+
const appDir = boot ? join49(repoDir, boot.boot.cwd) : repoDir;
|
|
12603
|
+
const pkgPath = join49(appDir, "package.json");
|
|
12591
12604
|
let script = null;
|
|
12592
12605
|
if (!boot) {
|
|
12593
|
-
if (!
|
|
12594
|
-
const subs = ["backend", "frontend"].filter((d) =>
|
|
12606
|
+
if (!existsSync29(pkgPath)) {
|
|
12607
|
+
const subs = ["backend", "frontend"].filter((d) => existsSync29(join49(repoDir, d, "package.json")));
|
|
12595
12608
|
const has = (d) => {
|
|
12596
12609
|
try {
|
|
12597
|
-
return pickScript(JSON.parse(
|
|
12610
|
+
return pickScript(JSON.parse(readFileSync38(join49(repoDir, d, "package.json"), "utf8"))) !== null;
|
|
12598
12611
|
} catch {
|
|
12599
12612
|
return false;
|
|
12600
12613
|
}
|
|
12601
12614
|
};
|
|
12602
12615
|
return skip(noRootReason(subs, subs.filter((d) => !has(d))));
|
|
12603
12616
|
}
|
|
12604
|
-
script = pickScript(JSON.parse(
|
|
12617
|
+
script = pickScript(JSON.parse(readFileSync38(pkgPath, "utf8")));
|
|
12605
12618
|
if (!script)
|
|
12606
12619
|
return skip("no dev, preview or start script");
|
|
12607
12620
|
}
|
|
@@ -12628,20 +12641,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12628
12641
|
}
|
|
12629
12642
|
if (!await waitUp(base, left(), signal))
|
|
12630
12643
|
return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
|
|
12631
|
-
const evRoot =
|
|
12644
|
+
const evRoot = join49(runDir, "evidence");
|
|
12632
12645
|
if (isSymlink(evRoot))
|
|
12633
12646
|
return skip("evidence dir is a symlink");
|
|
12634
12647
|
mkdirSync19(evRoot, { recursive: true });
|
|
12635
12648
|
if (pages.length > 0) {
|
|
12636
|
-
const rel0 =
|
|
12637
|
-
mkdirSync19(
|
|
12649
|
+
const rel0 = join49("evidence", randomBytes5(6).toString("hex"));
|
|
12650
|
+
mkdirSync19(join49(runDir, rel0));
|
|
12638
12651
|
const rels = [];
|
|
12639
12652
|
for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
|
|
12640
12653
|
if (aborted() || left() <= 0)
|
|
12641
12654
|
break;
|
|
12642
|
-
const rel =
|
|
12643
|
-
const ok = await shoot(pw, ["screenshot", `${base}${route}`,
|
|
12644
|
-
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)))
|
|
12645
12658
|
rels.push(rel);
|
|
12646
12659
|
}
|
|
12647
12660
|
if (aborted())
|
|
@@ -12666,9 +12679,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12666
12679
|
}
|
|
12667
12680
|
if (aborted())
|
|
12668
12681
|
return skip("aborted");
|
|
12669
|
-
const hdir =
|
|
12682
|
+
const hdir = join49(evRoot, randomBytes5(6).toString("hex"));
|
|
12670
12683
|
mkdirSync19(hdir);
|
|
12671
|
-
writeFileSync22(
|
|
12684
|
+
writeFileSync22(join49(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
|
|
12672
12685
|
`);
|
|
12673
12686
|
return { screens: [], http: true, skipped: null };
|
|
12674
12687
|
} catch (e) {
|
|
@@ -12697,12 +12710,12 @@ function receiptScreensProblem(receiptPath, receipt) {
|
|
|
12697
12710
|
return `visual evidence failed (LOKI_VISUAL_GATE=1): ${receipt["evidence_failed"]}`;
|
|
12698
12711
|
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname17(receiptPath), receipt["evidence_screens"]);
|
|
12699
12712
|
}
|
|
12700
|
-
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(
|
|
12701
|
-
const bin =
|
|
12702
|
-
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;
|
|
12703
12716
|
}, playwrightTestPkg = (repoDir) => {
|
|
12704
|
-
const d =
|
|
12705
|
-
return
|
|
12717
|
+
const d = join49(repoDir, "node_modules", "@playwright", "test");
|
|
12718
|
+
return existsSync29(join49(d, "package.json")) ? d : null;
|
|
12706
12719
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
12707
12720
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
12708
12721
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -12745,7 +12758,7 @@ var init_outbox = __esm(() => {
|
|
|
12745
12758
|
});
|
|
12746
12759
|
|
|
12747
12760
|
// ../../loki-ts/src/engine10/stages/pr.ts
|
|
12748
|
-
import { join as
|
|
12761
|
+
import { join as join50 } from "path";
|
|
12749
12762
|
var DEFAULT_PUSH_SH;
|
|
12750
12763
|
var init_pr = __esm(() => {
|
|
12751
12764
|
init_types();
|
|
@@ -12762,19 +12775,19 @@ var init_pr = __esm(() => {
|
|
|
12762
12775
|
init_run_outputs();
|
|
12763
12776
|
init_yaml_key();
|
|
12764
12777
|
init_outbox();
|
|
12765
|
-
DEFAULT_PUSH_SH =
|
|
12778
|
+
DEFAULT_PUSH_SH = join50(REPO_ROOT, "autonomy/lib/engine10-push.sh");
|
|
12766
12779
|
});
|
|
12767
12780
|
|
|
12768
12781
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
12769
|
-
import { existsSync as
|
|
12770
|
-
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";
|
|
12771
12784
|
import { createHash as createHash15 } from "crypto";
|
|
12772
12785
|
function loadLessons(repoDir) {
|
|
12773
12786
|
const p = lessonsPath(repoDir);
|
|
12774
|
-
if (!
|
|
12787
|
+
if (!existsSync30(p))
|
|
12775
12788
|
return [];
|
|
12776
12789
|
try {
|
|
12777
|
-
const j = JSON.parse(
|
|
12790
|
+
const j = JSON.parse(readFileSync39(p, "utf-8"));
|
|
12778
12791
|
return Array.isArray(j.lessons) ? j.lessons : [];
|
|
12779
12792
|
} catch {
|
|
12780
12793
|
return [];
|
|
@@ -12816,7 +12829,7 @@ function recordRunVerdict(repoDir, runId, verdict) {
|
|
|
12816
12829
|
if (dirty)
|
|
12817
12830
|
save(repoDir, lessons);
|
|
12818
12831
|
}
|
|
12819
|
-
var lessonsPath = (repoDir) =>
|
|
12832
|
+
var lessonsPath = (repoDir) => join51(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
|
|
12820
12833
|
var init_pr_lessons = __esm(() => {
|
|
12821
12834
|
init_atomic();
|
|
12822
12835
|
init_safe_git();
|
|
@@ -12848,7 +12861,7 @@ var init_attempts = __esm(() => {
|
|
|
12848
12861
|
var init_mcp_config = () => {};
|
|
12849
12862
|
|
|
12850
12863
|
// ../../loki-ts/src/providers/claude_flags.ts
|
|
12851
|
-
import { existsSync as
|
|
12864
|
+
import { existsSync as existsSync31, readFileSync as readFileSync40 } from "fs";
|
|
12852
12865
|
import { resolve as resolvePath, dirname as dirname19 } from "path";
|
|
12853
12866
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12854
12867
|
function claudeFlagSupported(flag, helpText) {
|
|
@@ -12902,8 +12915,8 @@ function designArchetypesText() {
|
|
|
12902
12915
|
["..", "..", "references", "design-archetypes.md"]
|
|
12903
12916
|
]) {
|
|
12904
12917
|
const p = resolvePath(moduleDir, ...rel);
|
|
12905
|
-
if (
|
|
12906
|
-
return
|
|
12918
|
+
if (existsSync31(p))
|
|
12919
|
+
return readFileSync40(p, "utf8");
|
|
12907
12920
|
}
|
|
12908
12921
|
} catch {}
|
|
12909
12922
|
return "";
|
|
@@ -12987,14 +13000,14 @@ var init_providers = __esm(() => {
|
|
|
12987
13000
|
});
|
|
12988
13001
|
|
|
12989
13002
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
12990
|
-
import { existsSync as
|
|
12991
|
-
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";
|
|
12992
13005
|
function loadRouteRecord(runDir) {
|
|
12993
13006
|
try {
|
|
12994
|
-
const p =
|
|
12995
|
-
if (!
|
|
13007
|
+
const p = join52(runDir, ROUTE_RECORD_FILE);
|
|
13008
|
+
if (!existsSync32(p) || !lstatSync11(p).isFile())
|
|
12996
13009
|
return;
|
|
12997
|
-
const v = JSON.parse(
|
|
13010
|
+
const v = JSON.parse(readFileSync41(p, "utf8"));
|
|
12998
13011
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
|
|
12999
13012
|
} catch {
|
|
13000
13013
|
return;
|
|
@@ -13121,7 +13134,7 @@ var init_worker = __esm(() => {
|
|
|
13121
13134
|
});
|
|
13122
13135
|
|
|
13123
13136
|
// ../../loki-ts/src/project_model/package_suite.ts
|
|
13124
|
-
import { join as
|
|
13137
|
+
import { join as join53 } from "path";
|
|
13125
13138
|
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
13126
13139
|
const api = loadProjectApi(repoDir);
|
|
13127
13140
|
if (!isMultiRoot(api))
|
|
@@ -13132,7 +13145,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13132
13145
|
for (const pkg of withTests) {
|
|
13133
13146
|
const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
|
|
13134
13147
|
const started = Date.now();
|
|
13135
|
-
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 } } : {} });
|
|
13136
13149
|
const duration_s = (Date.now() - started) / 1000;
|
|
13137
13150
|
if (signal.aborted) {
|
|
13138
13151
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
@@ -13141,7 +13154,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13141
13154
|
}
|
|
13142
13155
|
const out2 = `${r.stdout}
|
|
13143
13156
|
${r.stderr}`;
|
|
13144
|
-
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 } } : {} });
|
|
13145
13158
|
if (lr) {
|
|
13146
13159
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
13147
13160
|
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
@@ -13175,14 +13188,14 @@ __export(exports_deep, {
|
|
|
13175
13188
|
DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
|
|
13176
13189
|
DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH2
|
|
13177
13190
|
});
|
|
13178
|
-
import { existsSync as
|
|
13191
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync8, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "fs";
|
|
13179
13192
|
import { tmpdir as tmpdir9 } from "os";
|
|
13180
|
-
import { join as
|
|
13193
|
+
import { join as join54 } from "path";
|
|
13181
13194
|
function sessionCouncil(sessions) {
|
|
13182
13195
|
return { async run(input, signal) {
|
|
13183
|
-
const cwd = mkdtempSync8(
|
|
13196
|
+
const cwd = mkdtempSync8(join54(tmpdir9(), "loki-deep-council-"));
|
|
13184
13197
|
try {
|
|
13185
|
-
writeFileSync25(
|
|
13198
|
+
writeFileSync25(join54(cwd, "diff.patch"), input.diff, "utf8");
|
|
13186
13199
|
const r = await sessions.run({
|
|
13187
13200
|
stage: "deep",
|
|
13188
13201
|
tier: "development",
|
|
@@ -13292,7 +13305,7 @@ async function runCouncilCheck(ctx, changed, baseSha, signal, opts, checks, notP
|
|
|
13292
13305
|
async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
13293
13306
|
const scriptPath = opts.secretScanShPath ?? DEFAULT_SECRET_SCAN_SH;
|
|
13294
13307
|
const name = "security scan";
|
|
13295
|
-
if (!
|
|
13308
|
+
if (!existsSync33(scriptPath)) {
|
|
13296
13309
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: 0 });
|
|
13297
13310
|
notProven.add(`not run: ${name} (secret-scan.sh not found)`);
|
|
13298
13311
|
return;
|
|
@@ -13303,7 +13316,7 @@ async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
|
13303
13316
|
}
|
|
13304
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"';
|
|
13305
13318
|
const started = Date.now();
|
|
13306
|
-
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 });
|
|
13307
13320
|
const durationS = (Date.now() - started) / 1000;
|
|
13308
13321
|
if (r.exitCode === 3) {
|
|
13309
13322
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: durationS });
|
|
@@ -13338,7 +13351,7 @@ async function postResults(ctx, opts, checks, notProven, statusState) {
|
|
|
13338
13351
|
const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
|
|
13339
13352
|
if (prNumber) {
|
|
13340
13353
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13341
|
-
const bodyFile =
|
|
13354
|
+
const bodyFile = join54(ctx.runDir, "deep-comment.md");
|
|
13342
13355
|
writeFileSync25(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
|
|
13343
13356
|
const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
|
|
13344
13357
|
if (commentResult.exitCode !== 0)
|
|
@@ -13392,7 +13405,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
13392
13405
|
const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
|
|
13393
13406
|
const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
13394
13407
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13395
|
-
writeFileSync25(
|
|
13408
|
+
writeFileSync25(join54(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
|
|
13396
13409
|
`);
|
|
13397
13410
|
const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
|
|
13398
13411
|
const allNotProven = [...notProvenList, ...pushNotProven];
|
|
@@ -13436,20 +13449,20 @@ var init_deep = __esm(() => {
|
|
|
13436
13449
|
});
|
|
13437
13450
|
|
|
13438
13451
|
// ../../loki-ts/src/engine10/stages/verify.ts
|
|
13439
|
-
import { existsSync as
|
|
13452
|
+
import { existsSync as existsSync34, mkdtempSync as mkdtempSync9, realpathSync as realpathSync19, rmSync as rmSync17 } from "fs";
|
|
13440
13453
|
import { tmpdir as tmpdir10 } from "os";
|
|
13441
|
-
import { dirname as dirname20, isAbsolute as
|
|
13454
|
+
import { dirname as dirname20, isAbsolute as isAbsolute8, join as join55, relative as relative7 } from "path";
|
|
13442
13455
|
function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
13443
13456
|
const inRepo = (p) => {
|
|
13444
13457
|
try {
|
|
13445
|
-
const r =
|
|
13446
|
-
return r !== "" && !r.startsWith("..") && !
|
|
13458
|
+
const r = relative7(realpathSync19(repoDir), realpathSync19(p));
|
|
13459
|
+
return r !== "" && !r.startsWith("..") && !isAbsolute8(r);
|
|
13447
13460
|
} catch {
|
|
13448
13461
|
return false;
|
|
13449
13462
|
}
|
|
13450
13463
|
};
|
|
13451
13464
|
const venvEnv = process.env["VIRTUAL_ENV"];
|
|
13452
|
-
const project = [
|
|
13465
|
+
const project = [join55(repoDir, ".venv", "bin", bin), join55(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join55(venvEnv, "bin", bin)] : []].find(existsSync34);
|
|
13453
13466
|
return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
|
|
13454
13467
|
}
|
|
13455
13468
|
function runnerCmd(t, repoDir) {
|
|
@@ -13564,7 +13577,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13564
13577
|
const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
|
|
13565
13578
|
if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
|
|
13566
13579
|
return out2;
|
|
13567
|
-
const dir = mkdtempSync9(
|
|
13580
|
+
const dir = mkdtempSync9(join55(tmpdir10(), "e10-base-"));
|
|
13568
13581
|
const git3 = (args) => {
|
|
13569
13582
|
safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
|
|
13570
13583
|
};
|
|
@@ -13602,7 +13615,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13602
13615
|
return out2;
|
|
13603
13616
|
}
|
|
13604
13617
|
function isLokiModeRepo(repoDir) {
|
|
13605
|
-
return
|
|
13618
|
+
return existsSync34(join55(repoDir, "scripts", "select-tests.sh"));
|
|
13606
13619
|
}
|
|
13607
13620
|
async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
13608
13621
|
const { api, ...runOpts } = opts;
|
|
@@ -13624,9 +13637,9 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
|
13624
13637
|
}
|
|
13625
13638
|
for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
|
|
13626
13639
|
const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
|
|
13627
|
-
if (
|
|
13640
|
+
if (existsSync34(join55(g.cwd, "tsconfig.json")))
|
|
13628
13641
|
await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
|
|
13629
|
-
if (ESLINT_CONFIGS.some((f) =>
|
|
13642
|
+
if (ESLINT_CONFIGS.some((f) => existsSync34(join55(g.cwd, f)))) {
|
|
13630
13643
|
const c = await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
|
|
13631
13644
|
if (await excuseLint(ctx, signal, c, "eslint", "npx", ["eslint"], g.cwd, g.rel, co))
|
|
13632
13645
|
pre.push(c.name);
|
|
@@ -13641,7 +13654,7 @@ var CHECK_TIMEOUT_MS = 60000, excerpts, isHold = (c) => isHoldoutCheck(c.name),
|
|
|
13641
13654
|
return r.missing || r.cut ? null : r;
|
|
13642
13655
|
}, base: (f) => {
|
|
13643
13656
|
try {
|
|
13644
|
-
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"] });
|
|
13645
13658
|
} catch {
|
|
13646
13659
|
return null;
|
|
13647
13660
|
}
|
|
@@ -13700,7 +13713,7 @@ var init_verify = __esm(() => {
|
|
|
13700
13713
|
const impacted = ctx.tests.impacted(map, changed);
|
|
13701
13714
|
const changedTestFiles = map.tests.filter((t) => changed.includes(t.path));
|
|
13702
13715
|
const wall = ctx.outputs().wall ?? {};
|
|
13703
|
-
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));
|
|
13704
13717
|
const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
|
|
13705
13718
|
const intake = ctx.outputs().intake, relevant2 = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
|
|
13706
13719
|
const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant2]);
|
|
@@ -13806,8 +13819,8 @@ ${x}` : c.cmd };
|
|
|
13806
13819
|
});
|
|
13807
13820
|
|
|
13808
13821
|
// ../../loki-ts/src/project_model/conventions.ts
|
|
13809
|
-
import { existsSync as
|
|
13810
|
-
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";
|
|
13811
13824
|
function parseJsonc(text2) {
|
|
13812
13825
|
let out2 = "", i = 0;
|
|
13813
13826
|
while (i < text2.length) {
|
|
@@ -13842,25 +13855,25 @@ function moduleOf(file, depth = 0) {
|
|
|
13842
13855
|
const ext = typeof j.extends === "string" ? j.extends : null;
|
|
13843
13856
|
if (!ext || !ext.startsWith("."))
|
|
13844
13857
|
return null;
|
|
13845
|
-
const next =
|
|
13846
|
-
return
|
|
13858
|
+
const next = join56(dirname21(file), ext.endsWith(".json") ? ext : `${ext}.json`);
|
|
13859
|
+
return existsSync35(next) ? moduleOf(next, depth + 1) : null;
|
|
13847
13860
|
}
|
|
13848
13861
|
function readPackageConventions(pkgDir, runner = null) {
|
|
13849
13862
|
let names = [];
|
|
13850
13863
|
try {
|
|
13851
|
-
names =
|
|
13864
|
+
names = readdirSync18(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
|
|
13852
13865
|
} catch {
|
|
13853
13866
|
return null;
|
|
13854
13867
|
}
|
|
13855
13868
|
let packageType = null, tsModule = null;
|
|
13856
13869
|
for (const n2 of names) {
|
|
13857
|
-
const j = readJson4(
|
|
13870
|
+
const j = readJson4(join56(pkgDir, n2));
|
|
13858
13871
|
if (!j)
|
|
13859
13872
|
continue;
|
|
13860
13873
|
if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
|
|
13861
13874
|
packageType = j.type;
|
|
13862
13875
|
if (tsModule === null && j.compilerOptions !== undefined)
|
|
13863
|
-
tsModule = moduleOf(
|
|
13876
|
+
tsModule = moduleOf(join56(pkgDir, n2));
|
|
13864
13877
|
}
|
|
13865
13878
|
if (packageType === null && tsModule === null)
|
|
13866
13879
|
return null;
|
|
@@ -13882,7 +13895,7 @@ function conventionViolation(c, fileName, content) {
|
|
|
13882
13895
|
}
|
|
13883
13896
|
var readJson4 = (p) => {
|
|
13884
13897
|
try {
|
|
13885
|
-
const v = parseJsonc(
|
|
13898
|
+
const v = parseJsonc(readFileSync42(p, "utf8"));
|
|
13886
13899
|
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
13887
13900
|
} catch {
|
|
13888
13901
|
return null;
|
|
@@ -13892,15 +13905,15 @@ var init_conventions = () => {};
|
|
|
13892
13905
|
|
|
13893
13906
|
// ../../loki-ts/src/engine10/stages/wall.ts
|
|
13894
13907
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
13895
|
-
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";
|
|
13896
13909
|
import { tmpdir as tmpdir11 } from "os";
|
|
13897
|
-
import { dirname as dirname22, isAbsolute as
|
|
13910
|
+
import { dirname as dirname22, isAbsolute as isAbsolute9, join as join57, relative as relative8 } from "path";
|
|
13898
13911
|
function pytestCollectionIsRed(output, repoDir) {
|
|
13899
13912
|
if (/ModuleNotFoundError/.test(output))
|
|
13900
13913
|
return false;
|
|
13901
13914
|
const real2 = (p) => {
|
|
13902
13915
|
try {
|
|
13903
|
-
return
|
|
13916
|
+
return realpathSync20(isAbsolute9(p) ? p : join57(repoDir, p));
|
|
13904
13917
|
} catch {
|
|
13905
13918
|
return null;
|
|
13906
13919
|
}
|
|
@@ -13937,7 +13950,7 @@ function pytestCollectionIsRed(output, repoDir) {
|
|
|
13937
13950
|
}
|
|
13938
13951
|
function moduleUnderRepo(repoDir, name) {
|
|
13939
13952
|
const rel = name.replace(/\./g, "/");
|
|
13940
|
-
return
|
|
13953
|
+
return existsSync36(join57(repoDir, `${rel}.py`)) || existsSync36(join57(repoDir, rel, "__init__.py"));
|
|
13941
13954
|
}
|
|
13942
13955
|
function pytestExit1IsRed(output) {
|
|
13943
13956
|
if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
|
|
@@ -14036,10 +14049,10 @@ ${acceptance.map((a) => `Acceptance: ${a}`).join(`
|
|
|
14036
14049
|
function loadTaskText(ctx, fromPrior) {
|
|
14037
14050
|
if (fromPrior)
|
|
14038
14051
|
return fromPrior;
|
|
14039
|
-
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ??
|
|
14040
|
-
if (
|
|
14052
|
+
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join57(ctx.runDir, "issue.json");
|
|
14053
|
+
if (existsSync36(issueJsonPath)) {
|
|
14041
14054
|
try {
|
|
14042
|
-
const issue = JSON.parse(
|
|
14055
|
+
const issue = JSON.parse(readFileSync43(issueJsonPath, "utf8"));
|
|
14043
14056
|
const text2 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
|
|
14044
14057
|
|
|
14045
14058
|
`);
|
|
@@ -14051,7 +14064,7 @@ function loadTaskText(ctx, fromPrior) {
|
|
|
14051
14064
|
}
|
|
14052
14065
|
function wallTargetDir(repoDir, existingTests) {
|
|
14053
14066
|
const first = existingTests[0];
|
|
14054
|
-
return first ?
|
|
14067
|
+
return first ? join57(repoDir, dirname22(first.path)) : join57(repoDir, "tests");
|
|
14055
14068
|
}
|
|
14056
14069
|
function guessRunner(fileName, runners) {
|
|
14057
14070
|
if (fileName.endsWith(".py"))
|
|
@@ -14079,14 +14092,16 @@ async function wallAuthor(ctx, signal) {
|
|
|
14079
14092
|
}
|
|
14080
14093
|
if (testMap && runners.length === 0 && !(repoMap?.files ?? []).some((p) => /\.(py|go)$/.test(p)))
|
|
14081
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" });
|
|
14082
14097
|
const tree = prior.intake?.tree;
|
|
14083
14098
|
const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
|
|
14084
|
-
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${
|
|
14085
|
-
const conv2 = readPackageConventions(
|
|
14086
|
-
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-"));
|
|
14087
14102
|
const wm = wallManifestFor(ctx.repoDir, tree, task);
|
|
14088
14103
|
for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
|
|
14089
|
-
writeFileSync26(
|
|
14104
|
+
writeFileSync26(join57(cwd, n2), c, "utf8");
|
|
14090
14105
|
const session = await ctx.sessions.run({
|
|
14091
14106
|
stage: "wall",
|
|
14092
14107
|
brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2), unitSpec()?.acceptance ?? []),
|
|
@@ -14101,15 +14116,15 @@ async function wallAuthor(ctx, signal) {
|
|
|
14101
14116
|
rmSync18(cwd, { recursive: true, force: true });
|
|
14102
14117
|
return done({ status: "failed", data: {}, reason: "wall session aborted, killed, or timed out", killed: true });
|
|
14103
14118
|
}
|
|
14104
|
-
const all =
|
|
14105
|
-
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");
|
|
14106
14121
|
if (generated.length > 0)
|
|
14107
14122
|
mkdirSync23(sealedDir, { recursive: true });
|
|
14108
14123
|
const contents = new Map;
|
|
14109
14124
|
const discarded = [];
|
|
14110
14125
|
for (const name of generated) {
|
|
14111
|
-
const content =
|
|
14112
|
-
writeFileSync26(
|
|
14126
|
+
const content = readFileSync43(join57(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
|
|
14127
|
+
writeFileSync26(join57(sealedDir, name), content, "utf8");
|
|
14113
14128
|
if (bad)
|
|
14114
14129
|
discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
|
|
14115
14130
|
else
|
|
@@ -14129,18 +14144,18 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
14129
14144
|
const content = contents.get(name);
|
|
14130
14145
|
if (content === undefined)
|
|
14131
14146
|
continue;
|
|
14132
|
-
const dest =
|
|
14147
|
+
const dest = join57(targetDir, name), runner = guessRunner(name, runners);
|
|
14133
14148
|
writeFileSync26(dest, content, "utf8");
|
|
14134
14149
|
sealedFiles.push({ path: dest, sha256: sha2562(content) });
|
|
14135
14150
|
readOnlyFiles.push({ path: dest, content });
|
|
14136
14151
|
if (runner)
|
|
14137
|
-
wallTests.push({ runner, path:
|
|
14152
|
+
wallTests.push({ runner, path: relative8(ctx.repoDir, dest) });
|
|
14138
14153
|
}
|
|
14139
14154
|
ctx.wallSealed = true;
|
|
14140
14155
|
ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
|
|
14141
14156
|
const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
|
|
14142
14157
|
for (const t of wallTests) {
|
|
14143
|
-
const r = baseRunner.run(baseDir, [t]), abs =
|
|
14158
|
+
const r = baseRunner.run(baseDir, [t]), abs = join57(ctx.repoDir, t.path);
|
|
14144
14159
|
baseRun.pass += r.pass;
|
|
14145
14160
|
baseRun.fail += r.fail;
|
|
14146
14161
|
baseRun.not_run += r.not_run ?? 0;
|
|
@@ -14181,6 +14196,7 @@ var init_wall = __esm(() => {
|
|
|
14181
14196
|
init_seal();
|
|
14182
14197
|
init_holdout();
|
|
14183
14198
|
init_verify();
|
|
14199
|
+
init_testmap();
|
|
14184
14200
|
init_resolve();
|
|
14185
14201
|
init_check_result();
|
|
14186
14202
|
init_conventions();
|
|
@@ -14194,15 +14210,15 @@ var init_wall = __esm(() => {
|
|
|
14194
14210
|
});
|
|
14195
14211
|
|
|
14196
14212
|
// ../../loki-ts/src/e10ext/discard.ts
|
|
14197
|
-
import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as lstatSync12, mkdirSync as mkdirSync24, openSync as openSync9, readFileSync as
|
|
14198
|
-
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";
|
|
14199
14215
|
function safeRestore(repoDir, f, want, mode) {
|
|
14200
|
-
const root =
|
|
14216
|
+
const root = realpathSync21(repoDir), fp = join58(root, f), rel = relative9(root, dirname23(fp));
|
|
14201
14217
|
if (rel.startsWith(".."))
|
|
14202
14218
|
throw new Error("outside repo");
|
|
14203
14219
|
let cur = root;
|
|
14204
|
-
for (const part of rel === "" ? [] : rel.split(
|
|
14205
|
-
cur =
|
|
14220
|
+
for (const part of rel === "" ? [] : rel.split(sep12)) {
|
|
14221
|
+
cur = join58(cur, part);
|
|
14206
14222
|
let st2;
|
|
14207
14223
|
try {
|
|
14208
14224
|
st2 = lstatSync12(cur);
|
|
@@ -14219,7 +14235,7 @@ function safeRestore(repoDir, f, want, mode) {
|
|
|
14219
14235
|
} catch {
|
|
14220
14236
|
st = null;
|
|
14221
14237
|
}
|
|
14222
|
-
if (st?.isFile() &&
|
|
14238
|
+
if (st?.isFile() && readFileSync44(fp).equals(want)) {
|
|
14223
14239
|
chmodSync5(fp, mode);
|
|
14224
14240
|
return;
|
|
14225
14241
|
}
|
|
@@ -14257,7 +14273,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14257
14273
|
return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
|
|
14258
14274
|
const notProven = [];
|
|
14259
14275
|
for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
|
|
14260
|
-
const fp =
|
|
14276
|
+
const fp = join58(repoDir, f);
|
|
14261
14277
|
try {
|
|
14262
14278
|
if (v.startsWith("!")) {
|
|
14263
14279
|
const st = lstatSync12(fp);
|
|
@@ -14276,7 +14292,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14276
14292
|
try {
|
|
14277
14293
|
let m = 420;
|
|
14278
14294
|
try {
|
|
14279
|
-
const l = lstatSync12(
|
|
14295
|
+
const l = lstatSync12(join58(repoDir, f));
|
|
14280
14296
|
if (l.isFile())
|
|
14281
14297
|
m = l.mode & 511;
|
|
14282
14298
|
} catch {}
|
|
@@ -14320,7 +14336,7 @@ var init_commit_filter = __esm(() => {
|
|
|
14320
14336
|
});
|
|
14321
14337
|
|
|
14322
14338
|
// ../../loki-ts/src/e10ext/scope.ts
|
|
14323
|
-
import { basename as
|
|
14339
|
+
import { basename as basename21, dirname as dirname25 } from "path";
|
|
14324
14340
|
function contractText(o) {
|
|
14325
14341
|
const c = o.intake?.contract_snapshot?.contract;
|
|
14326
14342
|
return Array.isArray(c?.criteria) ? c.criteria.map((x) => typeof x?.text === "string" ? x.text : "").join(`
|
|
@@ -14335,7 +14351,7 @@ function outsideScope(o, staged) {
|
|
|
14335
14351
|
${typeof o.intake?.task === "string" ? o.intake.task : ""}
|
|
14336
14352
|
${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
|
|
14337
14353
|
const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname25(r)).filter((d) => d !== "."));
|
|
14338
|
-
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);
|
|
14339
14355
|
}
|
|
14340
14356
|
function flagOutsideScope(o, staged) {
|
|
14341
14357
|
const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
|
|
@@ -14350,14 +14366,14 @@ var init_scope2 = __esm(() => {
|
|
|
14350
14366
|
});
|
|
14351
14367
|
|
|
14352
14368
|
// ../../loki-ts/src/council/role_agents.ts
|
|
14353
|
-
import { existsSync as
|
|
14369
|
+
import { existsSync as existsSync37, readdirSync as readdirSync20, readFileSync as readFileSync45 } from "fs";
|
|
14354
14370
|
import { homedir as homedir9 } from "os";
|
|
14355
|
-
import { join as
|
|
14371
|
+
import { join as join59 } from "path";
|
|
14356
14372
|
function agentDirs(repoDir, env = process.env) {
|
|
14357
|
-
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")];
|
|
14358
14374
|
}
|
|
14359
14375
|
function parseAgent(file, stem2) {
|
|
14360
|
-
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"));
|
|
14361
14377
|
if (!m)
|
|
14362
14378
|
return null;
|
|
14363
14379
|
const body = m[2].trim();
|
|
@@ -14371,18 +14387,18 @@ function parseAgent(file, stem2) {
|
|
|
14371
14387
|
}
|
|
14372
14388
|
function loadRoleAgent(repoDir, role, env = process.env) {
|
|
14373
14389
|
for (const d of agentDirs(repoDir, env)) {
|
|
14374
|
-
if (!
|
|
14390
|
+
if (!existsSync37(d))
|
|
14375
14391
|
continue;
|
|
14376
14392
|
let names;
|
|
14377
14393
|
try {
|
|
14378
|
-
names =
|
|
14394
|
+
names = readdirSync20(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
|
|
14379
14395
|
} catch {
|
|
14380
14396
|
continue;
|
|
14381
14397
|
}
|
|
14382
14398
|
const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
|
|
14383
14399
|
for (const n2 of ordered) {
|
|
14384
14400
|
try {
|
|
14385
|
-
const a = parseAgent(
|
|
14401
|
+
const a = parseAgent(join59(d, n2), n2.slice(0, -3));
|
|
14386
14402
|
if (a && a.role === role)
|
|
14387
14403
|
return a;
|
|
14388
14404
|
} catch {}
|
|
@@ -14400,7 +14416,7 @@ var init_role_agents = __esm(() => {
|
|
|
14400
14416
|
|
|
14401
14417
|
// ../../loki-ts/src/util/child_ledger.ts
|
|
14402
14418
|
import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync25 } from "fs";
|
|
14403
|
-
import { join as
|
|
14419
|
+
import { join as join60 } from "path";
|
|
14404
14420
|
function unmeasuredRecord(phase, model, source) {
|
|
14405
14421
|
return { phase, model, input_tokens: 0, output_tokens: 0, cache_creation_tokens: 0, cache_read_tokens: 0, source, cost_status: "unmeasured" };
|
|
14406
14422
|
}
|
|
@@ -14425,9 +14441,9 @@ function recordFromClaudeResult(phase, payload, source = "claude-json") {
|
|
|
14425
14441
|
}
|
|
14426
14442
|
function appendChildLedger(lokiDir2, rec2) {
|
|
14427
14443
|
try {
|
|
14428
|
-
const dir =
|
|
14444
|
+
const dir = join60(lokiDir2, "metrics");
|
|
14429
14445
|
mkdirSync25(dir, { recursive: true });
|
|
14430
|
-
appendFileSync4(
|
|
14446
|
+
appendFileSync4(join60(dir, "child-sessions.jsonl"), `${JSON.stringify(rec2)}
|
|
14431
14447
|
`);
|
|
14432
14448
|
return true;
|
|
14433
14449
|
} catch {
|
|
@@ -14457,14 +14473,14 @@ var init_child_ledger = __esm(() => {
|
|
|
14457
14473
|
});
|
|
14458
14474
|
|
|
14459
14475
|
// ../../loki-ts/src/util/run_summary.ts
|
|
14460
|
-
import { existsSync as
|
|
14461
|
-
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";
|
|
14462
14478
|
function readRiskRecord(repoDir, sinceMs = 0) {
|
|
14463
14479
|
try {
|
|
14464
|
-
const p =
|
|
14480
|
+
const p = join61(repoDir, ".loki", "state", "risk-tier.json");
|
|
14465
14481
|
if (statSync18(p).mtimeMs < sinceMs)
|
|
14466
14482
|
return null;
|
|
14467
|
-
const r = JSON.parse(
|
|
14483
|
+
const r = JSON.parse(readFileSync46(p, "utf8"));
|
|
14468
14484
|
return r && typeof r === "object" ? r : null;
|
|
14469
14485
|
} catch {
|
|
14470
14486
|
return null;
|
|
@@ -14478,8 +14494,8 @@ var init_run_summary = __esm(() => {
|
|
|
14478
14494
|
});
|
|
14479
14495
|
|
|
14480
14496
|
// ../../loki-ts/src/engine10/stages/xreview.ts
|
|
14481
|
-
import { existsSync as
|
|
14482
|
-
import { join as
|
|
14497
|
+
import { existsSync as existsSync39, readFileSync as readFileSync47 } from "fs";
|
|
14498
|
+
import { join as join62 } from "path";
|
|
14483
14499
|
function minVerdict(verdict, review) {
|
|
14484
14500
|
const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
|
|
14485
14501
|
return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
|
|
@@ -14492,11 +14508,11 @@ function explicitReview(repoDir, env) {
|
|
|
14492
14508
|
if (flag && isOff(ev))
|
|
14493
14509
|
return "off";
|
|
14494
14510
|
for (const f of ["loki.yaml", "loki.yml"]) {
|
|
14495
|
-
const p =
|
|
14496
|
-
if (!
|
|
14511
|
+
const p = join62(repoDir, f);
|
|
14512
|
+
if (!existsSync39(p))
|
|
14497
14513
|
continue;
|
|
14498
14514
|
try {
|
|
14499
|
-
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(
|
|
14515
|
+
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync47(p, "utf8"));
|
|
14500
14516
|
const v = asProvider(m?.[1]);
|
|
14501
14517
|
if (v)
|
|
14502
14518
|
return v;
|
|
@@ -14578,7 +14594,7 @@ Review ONLY the diff below. Do not modify files.` : "You are an independent code
|
|
|
14578
14594
|
try {
|
|
14579
14595
|
if (p === "claude")
|
|
14580
14596
|
await ensureClaudeHelpCache();
|
|
14581
|
-
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 });
|
|
14582
14598
|
if (r.exitCode !== 0)
|
|
14583
14599
|
return { provider: p, level: "not_run", notes: [`cross-review not run: ${p} exited ${r.exitCode}`] };
|
|
14584
14600
|
return parseReview(p, r.stdout);
|
|
@@ -14672,8 +14688,8 @@ See also: loki cost --detail (what a run ALREADY spent)
|
|
|
14672
14688
|
});
|
|
14673
14689
|
|
|
14674
14690
|
// ../../loki-ts/src/features/contract.ts
|
|
14675
|
-
import { existsSync as
|
|
14676
|
-
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";
|
|
14677
14693
|
import { createHash as createHash16 } from "crypto";
|
|
14678
14694
|
function contractEnabled(env = process.env) {
|
|
14679
14695
|
return env["LOKI_CONTRACT"] !== "0";
|
|
@@ -14705,7 +14721,7 @@ function untracedLines(trace) {
|
|
|
14705
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)}`);
|
|
14706
14722
|
}
|
|
14707
14723
|
function contractPath(repoDir) {
|
|
14708
|
-
return
|
|
14724
|
+
return join63(repoDir, ".loki", "contract.json");
|
|
14709
14725
|
}
|
|
14710
14726
|
function readContract(repoDir) {
|
|
14711
14727
|
const p = contractPath(repoDir);
|
|
@@ -14721,7 +14737,7 @@ function readContract(repoDir) {
|
|
|
14721
14737
|
return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
|
|
14722
14738
|
let raw2;
|
|
14723
14739
|
try {
|
|
14724
|
-
raw2 =
|
|
14740
|
+
raw2 = readFileSync48(p);
|
|
14725
14741
|
} catch {
|
|
14726
14742
|
return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
|
|
14727
14743
|
}
|
|
@@ -14790,17 +14806,17 @@ var init_contract = __esm(() => {
|
|
|
14790
14806
|
init_safe_git();
|
|
14791
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"]);
|
|
14792
14808
|
MAX_CONTRACT_BYTES = 1024 * 1024;
|
|
14793
|
-
REQ_MAP_REL =
|
|
14809
|
+
REQ_MAP_REL = join63(".loki", "state", "requirements-map.json");
|
|
14794
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"]);
|
|
14795
14811
|
});
|
|
14796
14812
|
|
|
14797
14813
|
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
14798
14814
|
import { createHash as createHash17 } from "crypto";
|
|
14799
|
-
import { existsSync as
|
|
14800
|
-
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";
|
|
14801
14817
|
function sealGroup(runDir, rh) {
|
|
14802
|
-
const manifestPath =
|
|
14803
|
-
if (!
|
|
14818
|
+
const manifestPath = join64(runDir, "group", "manifest.json");
|
|
14819
|
+
if (!existsSync41(manifestPath))
|
|
14804
14820
|
return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
|
|
14805
14821
|
const notProven = [];
|
|
14806
14822
|
let problems = 0;
|
|
@@ -14824,10 +14840,10 @@ function sealGroup(runDir, rh) {
|
|
|
14824
14840
|
return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
|
|
14825
14841
|
seen.add(id);
|
|
14826
14842
|
seenLower.add(id.toLowerCase());
|
|
14827
|
-
const dir =
|
|
14843
|
+
const dir = join64(unitsDir(runDir), id), rp = join64(dir, "receipt.json"), ep = join64(dir, "events.jsonl");
|
|
14828
14844
|
let bytes;
|
|
14829
14845
|
try {
|
|
14830
|
-
bytes =
|
|
14846
|
+
bytes = readFileSync49(rp);
|
|
14831
14847
|
} catch {
|
|
14832
14848
|
return fail(`unit ${id} sub-receipt missing`);
|
|
14833
14849
|
}
|
|
@@ -14844,7 +14860,7 @@ function sealGroup(runDir, rh) {
|
|
|
14844
14860
|
unit_id: id,
|
|
14845
14861
|
sub_receipt_sha256: sha3(bytes),
|
|
14846
14862
|
receipt_sha256: sub["receipt_sha256"],
|
|
14847
|
-
events_file_sha256:
|
|
14863
|
+
events_file_sha256: existsSync41(ep) ? sha3(readFileSync49(ep)) : null,
|
|
14848
14864
|
verdict,
|
|
14849
14865
|
goal: text2(u["goal"], 200),
|
|
14850
14866
|
files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
|
|
@@ -14869,7 +14885,7 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14869
14885
|
const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
|
|
14870
14886
|
const g = receipt["group"];
|
|
14871
14887
|
if (g === undefined)
|
|
14872
|
-
return
|
|
14888
|
+
return existsSync41(join64(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
|
|
14873
14889
|
if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
|
|
14874
14890
|
return bad("group section malformed");
|
|
14875
14891
|
const entries = g["units"];
|
|
@@ -14881,20 +14897,20 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14881
14897
|
return bad("unit directories do not match the receipt (missing or extra unit)");
|
|
14882
14898
|
let unchecked = null;
|
|
14883
14899
|
for (let i = 0;i < entries.length; i++) {
|
|
14884
|
-
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");
|
|
14885
14901
|
if (e["index"] !== i)
|
|
14886
14902
|
return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
|
|
14887
14903
|
let bytes;
|
|
14888
14904
|
try {
|
|
14889
14905
|
if (!statSync19(dir).isDirectory())
|
|
14890
14906
|
return bad(`unit ${id} is not a directory`);
|
|
14891
|
-
bytes =
|
|
14907
|
+
bytes = readFileSync49(rp);
|
|
14892
14908
|
} catch {
|
|
14893
14909
|
return bad(`unit ${id} sub-receipt missing`);
|
|
14894
14910
|
}
|
|
14895
14911
|
if (sha3(bytes) !== e["sub_receipt_sha256"])
|
|
14896
14912
|
return bad(`unit ${id} sub-receipt does not match its recorded hash`);
|
|
14897
|
-
const evSha =
|
|
14913
|
+
const evSha = existsSync41(ep) ? sha3(readFileSync49(ep)) : null;
|
|
14898
14914
|
if (evSha !== (e["events_file_sha256"] ?? null))
|
|
14899
14915
|
return bad(`unit ${id} events.jsonl does not match its recorded hash`);
|
|
14900
14916
|
const sub = readJson5(rp);
|
|
@@ -14917,15 +14933,15 @@ function compositeVerdict(childVerdicts) {
|
|
|
14917
14933
|
const failed2 = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
|
|
14918
14934
|
return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed2, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
|
|
14919
14935
|
}
|
|
14920
|
-
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) => {
|
|
14921
14937
|
try {
|
|
14922
|
-
return JSON.parse(
|
|
14938
|
+
return JSON.parse(readFileSync49(p, "utf8"));
|
|
14923
14939
|
} catch {
|
|
14924
14940
|
return;
|
|
14925
14941
|
}
|
|
14926
14942
|
}, dirNames = (d) => {
|
|
14927
14943
|
try {
|
|
14928
|
-
return
|
|
14944
|
+
return readdirSync21(d).filter((n3) => !n3.startsWith(".")).sort();
|
|
14929
14945
|
} catch {
|
|
14930
14946
|
return null;
|
|
14931
14947
|
}
|
|
@@ -14937,8 +14953,8 @@ var init_seal_group = __esm(() => {
|
|
|
14937
14953
|
});
|
|
14938
14954
|
|
|
14939
14955
|
// ../../loki-ts/src/supply/supply_guard.ts
|
|
14940
|
-
import { existsSync as
|
|
14941
|
-
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";
|
|
14942
14958
|
function supplyEnabled(env) {
|
|
14943
14959
|
return env["LOKI_SUPPLY_GUARD"] !== "0";
|
|
14944
14960
|
}
|
|
@@ -14950,16 +14966,16 @@ function supplyVerdict(verdict, r) {
|
|
|
14950
14966
|
return r.blocked && verdict === "VERIFIED" ? "FAILED" : verdict;
|
|
14951
14967
|
}
|
|
14952
14968
|
function isManifestPath(path) {
|
|
14953
|
-
return MANIFESTS.test(
|
|
14969
|
+
return MANIFESTS.test(basename22(path));
|
|
14954
14970
|
}
|
|
14955
14971
|
function readDeclared(repoDir) {
|
|
14956
|
-
const p =
|
|
14957
|
-
if (!
|
|
14972
|
+
const p = join65(repoDir, ".loki", DECLARED_FILE);
|
|
14973
|
+
if (!existsSync42(p))
|
|
14958
14974
|
return { deps: [], problem: null };
|
|
14959
14975
|
try {
|
|
14960
14976
|
if (statSync20(p).size > MAX_FILE_BYTES)
|
|
14961
14977
|
return { deps: [], problem: "declaration file too large" };
|
|
14962
|
-
const j = JSON.parse(
|
|
14978
|
+
const j = JSON.parse(readFileSync50(p, "utf8"));
|
|
14963
14979
|
if (!Array.isArray(j))
|
|
14964
14980
|
return { deps: [], problem: "declaration is not a JSON array" };
|
|
14965
14981
|
const deps = [];
|
|
@@ -14979,11 +14995,11 @@ function readDeclared(repoDir) {
|
|
|
14979
14995
|
}
|
|
14980
14996
|
}
|
|
14981
14997
|
function readAllowlist(repoDir) {
|
|
14982
|
-
const p =
|
|
14983
|
-
if (!
|
|
14998
|
+
const p = join65(repoDir, ".loki", "supply-allowlist");
|
|
14999
|
+
if (!existsSync42(p))
|
|
14984
15000
|
return new Set;
|
|
14985
15001
|
try {
|
|
14986
|
-
return new Set(
|
|
15002
|
+
return new Set(readFileSync50(p, "utf8").split(`
|
|
14987
15003
|
`).map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean));
|
|
14988
15004
|
} catch {
|
|
14989
15005
|
return new Set;
|
|
@@ -15024,7 +15040,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15024
15040
|
if (eco === "npm") {
|
|
15025
15041
|
if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
|
|
15026
15042
|
return true;
|
|
15027
|
-
return files(
|
|
15043
|
+
return files(join65(repoDir, ".npmrc"), home ? join65(home, ".npmrc") : "").some((t) => t.split(`
|
|
15028
15044
|
`).some((l) => {
|
|
15029
15045
|
const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
|
|
15030
15046
|
return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
|
|
@@ -15033,7 +15049,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15033
15049
|
if (eco === "pypi") {
|
|
15034
15050
|
if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
|
|
15035
15051
|
return true;
|
|
15036
|
-
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")];
|
|
15037
15053
|
return files(...cfg).some((t) => t.split(`
|
|
15038
15054
|
`).some((l) => {
|
|
15039
15055
|
const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
|
|
@@ -15043,7 +15059,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15043
15059
|
if (eco === "cargo") {
|
|
15044
15060
|
if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
|
|
15045
15061
|
return true;
|
|
15046
|
-
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));
|
|
15047
15063
|
}
|
|
15048
15064
|
if (eco === "go") {
|
|
15049
15065
|
const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
|
|
@@ -15166,7 +15182,7 @@ var MIN_AGE_DAYS = 7, DECLARED_FILE = "supply-declared.json", MAX_CHECKED = 50,
|
|
|
15166
15182
|
}
|
|
15167
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) => {
|
|
15168
15184
|
try {
|
|
15169
|
-
return statSync20(p).size <= MAX_FILE_BYTES ?
|
|
15185
|
+
return statSync20(p).size <= MAX_FILE_BYTES ? readFileSync50(p, "utf8") : "";
|
|
15170
15186
|
} catch {
|
|
15171
15187
|
return "";
|
|
15172
15188
|
}
|
|
@@ -15182,8 +15198,8 @@ var init_supply_guard = __esm(() => {
|
|
|
15182
15198
|
|
|
15183
15199
|
// ../../loki-ts/src/engine10/stages/seal.ts
|
|
15184
15200
|
import { createHash as createHash18 } from "crypto";
|
|
15185
|
-
import { existsSync as
|
|
15186
|
-
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";
|
|
15187
15203
|
function sanitizeReason(s) {
|
|
15188
15204
|
const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
|
|
15189
15205
|
const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
|
|
@@ -15258,8 +15274,8 @@ function renderReceiptMd(r) {
|
|
|
15258
15274
|
`);
|
|
15259
15275
|
}
|
|
15260
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) => {
|
|
15261
|
-
const r =
|
|
15262
|
-
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;
|
|
15263
15279
|
}, commitStage, sealStage;
|
|
15264
15280
|
var init_seal = __esm(() => {
|
|
15265
15281
|
init_spec_file();
|
|
@@ -15358,6 +15374,8 @@ var init_seal = __esm(() => {
|
|
|
15358
15374
|
}
|
|
15359
15375
|
if (wallNotRun > 0)
|
|
15360
15376
|
notProven.add(`wall base run not_run: ${wallNotRun}`);
|
|
15377
|
+
for (const n3 of strs2(o.wall?.not_proven))
|
|
15378
|
+
notProven.add(n3);
|
|
15361
15379
|
for (const d of Array.isArray(o.wall?.discarded) ? o.wall.discarded : [])
|
|
15362
15380
|
notProven.add(`wall test discarded: ${String(d.file)} (${String(d.reason)})`);
|
|
15363
15381
|
for (const d of Array.isArray(o.wall?.not_run_files) ? o.wall.not_run_files : [])
|
|
@@ -15366,8 +15384,8 @@ var init_seal = __esm(() => {
|
|
|
15366
15384
|
notProven.add(`Wall test not executed: ${wallNotRun} file(s), no reason recorded`);
|
|
15367
15385
|
if (wallNotRun > 0) {
|
|
15368
15386
|
try {
|
|
15369
|
-
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) =>
|
|
15370
|
-
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())
|
|
15371
15389
|
if (!kept.has(n3))
|
|
15372
15390
|
notProven.add(`wall test discarded: ${n3} (not_run)`);
|
|
15373
15391
|
} catch {}
|
|
@@ -15430,19 +15448,19 @@ var init_seal = __esm(() => {
|
|
|
15430
15448
|
for (const [s, d] of Object.entries(o))
|
|
15431
15449
|
if (typeof d?.duration_s === "number")
|
|
15432
15450
|
stages[s] = d.duration_s;
|
|
15433
|
-
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;
|
|
15434
15452
|
const iterIds = Object.values(o).flatMap((d) => [...strs2(d?.iteration_ids), ...strs2([d?.iteration_id])]);
|
|
15435
15453
|
if (iterIds.length === 0)
|
|
15436
15454
|
notProven.add("cost not measured (no iteration ids recorded)");
|
|
15437
15455
|
const cost = ctx.cost.read(ctx.repoDir, iterIds);
|
|
15438
15456
|
if (cost.unmetered)
|
|
15439
15457
|
notProven.add("cost unmetered (CLI invoker; recorded as 0)");
|
|
15440
|
-
const eventsPath =
|
|
15458
|
+
const eventsPath = join66(ctx.runDir, "events.jsonl");
|
|
15441
15459
|
const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
|
|
15442
15460
|
const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
|
|
15443
15461
|
if (wallFiles.length > 0 && wallPassed === null)
|
|
15444
15462
|
notProven.add("wall result not recorded by verify");
|
|
15445
|
-
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);
|
|
15446
15464
|
if (routeBlock)
|
|
15447
15465
|
for (const l of routeNotProven(routeBlock))
|
|
15448
15466
|
notProven.add(l);
|
|
@@ -15484,7 +15502,7 @@ var init_seal = __esm(() => {
|
|
|
15484
15502
|
provider: ctx.provider,
|
|
15485
15503
|
model: ctx.model,
|
|
15486
15504
|
resumed: o.intake?.resumed === true,
|
|
15487
|
-
events_sha256: sha2562(
|
|
15505
|
+
events_sha256: sha2562(existsSync43(eventsPath) ? readFileSync51(eventsPath) : ""),
|
|
15488
15506
|
...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
|
|
15489
15507
|
log_seal: true,
|
|
15490
15508
|
...receiptBlock(process.env, cost.usd, cost.unmetered === true, totalS),
|
|
@@ -15506,10 +15524,10 @@ var init_seal = __esm(() => {
|
|
|
15506
15524
|
}
|
|
15507
15525
|
const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
15508
15526
|
mkdirSync29(ctx.runDir, { recursive: true });
|
|
15509
|
-
const path =
|
|
15527
|
+
const path = join66(ctx.runDir, "receipt.json");
|
|
15510
15528
|
writeFileSync31(path, JSON.stringify(receipt, null, 2) + `
|
|
15511
15529
|
`);
|
|
15512
|
-
writeFileSync31(
|
|
15530
|
+
writeFileSync31(join66(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
|
|
15513
15531
|
recordRun(process.env, ctx.repoDir, ranModel(o.implement, ctx.model, o.fix), verdict, cost.usd, cost.unmetered === true, totalS);
|
|
15514
15532
|
try {
|
|
15515
15533
|
hooks.sealed?.(ctx.runDir, JSON.parse(JSON.stringify(receipt), (_k, v) => v && typeof v === "object" ? Object.freeze(v) : v));
|
|
@@ -15535,7 +15553,7 @@ var init_seal = __esm(() => {
|
|
|
15535
15553
|
|
|
15536
15554
|
// ../../loki-ts/src/features/receipt_dsse.ts
|
|
15537
15555
|
import { createPublicKey as createPublicKey3, sign as sign2, verify as verify3 } from "crypto";
|
|
15538
|
-
import { readFileSync as
|
|
15556
|
+
import { readFileSync as readFileSync52 } from "fs";
|
|
15539
15557
|
function pae(payloadType, body) {
|
|
15540
15558
|
const t = Buffer.from(payloadType, "utf8");
|
|
15541
15559
|
return Buffer.concat([Buffer.from(`DSSEv1 ${t.length} `), t, Buffer.from(` ${body.length} `), body]);
|
|
@@ -15612,7 +15630,7 @@ function verifyDsseReceipt(env, d) {
|
|
|
15612
15630
|
}
|
|
15613
15631
|
function runIdGuard(receiptPath, runId) {
|
|
15614
15632
|
try {
|
|
15615
|
-
return envelopeRunIdProblem(JSON.parse(
|
|
15633
|
+
return envelopeRunIdProblem(JSON.parse(readFileSync52(receiptPath, "utf8")), runId);
|
|
15616
15634
|
} catch {
|
|
15617
15635
|
return null;
|
|
15618
15636
|
}
|
|
@@ -15621,14 +15639,14 @@ var DSSE_PAYLOAD_TYPE = "application/vnd.in-toto+json", STATEMENT_TYPE = "https:
|
|
|
15621
15639
|
var init_receipt_dsse = () => {};
|
|
15622
15640
|
|
|
15623
15641
|
// ../../loki-ts/src/util/composite_seal.ts
|
|
15624
|
-
import { existsSync as
|
|
15625
|
-
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";
|
|
15626
15644
|
function logProblem(runDir, integ) {
|
|
15627
15645
|
if (typeof integ["log_sha256"] !== "string")
|
|
15628
15646
|
return null;
|
|
15629
15647
|
let b;
|
|
15630
15648
|
try {
|
|
15631
|
-
b =
|
|
15649
|
+
b = readFileSync53(join67(runDir, "integration.log"));
|
|
15632
15650
|
} catch {
|
|
15633
15651
|
return "integration.log is missing but integration.json records its hash";
|
|
15634
15652
|
}
|
|
@@ -15651,13 +15669,13 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15651
15669
|
return bad("body malformed");
|
|
15652
15670
|
let ibytes;
|
|
15653
15671
|
try {
|
|
15654
|
-
ibytes =
|
|
15672
|
+
ibytes = readFileSync53(join67(runDir, "integration.json"));
|
|
15655
15673
|
} catch {
|
|
15656
15674
|
return bad("integration.json missing");
|
|
15657
15675
|
}
|
|
15658
15676
|
if (sha3(ibytes) !== receipt["integration_sha256"])
|
|
15659
15677
|
return bad("integration.json does not match its recorded hash");
|
|
15660
|
-
const integ = readJson5(
|
|
15678
|
+
const integ = readJson5(join67(runDir, "integration.json"));
|
|
15661
15679
|
if (!isObj10(integ) || !isObj10(integ["outcomes"]))
|
|
15662
15680
|
return bad("integration.json has no outcomes");
|
|
15663
15681
|
const iprob = integrationProblem(integ);
|
|
@@ -15687,10 +15705,10 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15687
15705
|
return bad(`child ${text2(repo, 80) || "?"} has an invalid receipt path`);
|
|
15688
15706
|
if (outcomes[repo] !== "ok")
|
|
15689
15707
|
return bad(`child ${text2(repo, 80)} did not finish ok in integration.json`);
|
|
15690
|
-
const rp =
|
|
15708
|
+
const rp = join67(runDir, rel);
|
|
15691
15709
|
let bytes;
|
|
15692
15710
|
try {
|
|
15693
|
-
bytes =
|
|
15711
|
+
bytes = readFileSync53(rp);
|
|
15694
15712
|
} catch {
|
|
15695
15713
|
return bad(`child ${repo} receipt missing`);
|
|
15696
15714
|
}
|
|
@@ -15739,8 +15757,8 @@ var init_keys_cmd = __esm(() => {
|
|
|
15739
15757
|
});
|
|
15740
15758
|
|
|
15741
15759
|
// ../../loki-ts/src/engine10/verify_cmd.ts
|
|
15742
|
-
import { existsSync as
|
|
15743
|
-
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";
|
|
15744
15762
|
import { createHash as createHash19, createPublicKey as createPublicKey4, verify as verify4 } from "crypto";
|
|
15745
15763
|
function pubFor(kid, given) {
|
|
15746
15764
|
if (given)
|
|
@@ -15748,7 +15766,7 @@ function pubFor(kid, given) {
|
|
|
15748
15766
|
const active = loadSigningKey(false);
|
|
15749
15767
|
const pubs = (process.env["LOKI_RECEIPT_RETIRED_PUBKEYS"] ?? "").split(":").map((f) => f.trim()).filter(Boolean).flatMap((f) => {
|
|
15750
15768
|
try {
|
|
15751
|
-
return [createPublicKey4(
|
|
15769
|
+
return [createPublicKey4(readFileSync54(f))];
|
|
15752
15770
|
} catch {
|
|
15753
15771
|
return [];
|
|
15754
15772
|
}
|
|
@@ -15792,10 +15810,10 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15792
15810
|
const claims = st !== null && typeof st === "object" && Object.keys(st).length > 0;
|
|
15793
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;
|
|
15794
15812
|
}
|
|
15795
|
-
const path =
|
|
15796
|
-
if (!
|
|
15813
|
+
const path = join68(dirname30(receiptPath), "events.jsonl");
|
|
15814
|
+
if (!existsSync45(path))
|
|
15797
15815
|
return "events.jsonl is missing";
|
|
15798
|
-
const raw2 =
|
|
15816
|
+
const raw2 = readFileSync54(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
|
|
15799
15817
|
`).filter((l) => l.trim() !== "");
|
|
15800
15818
|
if (events2.length !== lines2.length || events2.some((e, i) => e.seq !== i))
|
|
15801
15819
|
return "events.jsonl has a forged, edited or missing line";
|
|
@@ -15811,7 +15829,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15811
15829
|
return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
|
|
15812
15830
|
}
|
|
15813
15831
|
function checkLogSeal(receiptPath, hash, kid, given) {
|
|
15814
|
-
const path =
|
|
15832
|
+
const path = join68(dirname30(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
|
|
15815
15833
|
if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
|
|
15816
15834
|
return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
|
|
15817
15835
|
if (done < 0)
|
|
@@ -15819,7 +15837,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15819
15837
|
const seal = events2[done + 1], d = seal?.type === "log.sealed" ? seal.data : null;
|
|
15820
15838
|
if (!d)
|
|
15821
15839
|
return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
|
|
15822
|
-
const lines2 =
|
|
15840
|
+
const lines2 = readFileSync54(path, "utf8").split(`
|
|
15823
15841
|
`).filter((l) => l.trim() !== ""), sha4 = createHash19("sha256").update(lines2.slice(0, done + 1).join(`
|
|
15824
15842
|
`) + `
|
|
15825
15843
|
`).digest("hex");
|
|
@@ -15829,11 +15847,11 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15829
15847
|
return null;
|
|
15830
15848
|
}
|
|
15831
15849
|
async function verifyReceipt(receiptPath, deps = {}) {
|
|
15832
|
-
if (!
|
|
15850
|
+
if (!existsSync45(receiptPath))
|
|
15833
15851
|
return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
|
|
15834
15852
|
let receipt;
|
|
15835
15853
|
try {
|
|
15836
|
-
receipt = JSON.parse((deps.read ?? ((p) =>
|
|
15854
|
+
receipt = JSON.parse((deps.read ?? ((p) => readFileSync54(p, "utf8")))(receiptPath));
|
|
15837
15855
|
} catch {
|
|
15838
15856
|
return { verdict: "UNCHECKED", reasons: ["receipt.json is not valid JSON"] };
|
|
15839
15857
|
}
|
|
@@ -15921,8 +15939,8 @@ var init_verify_cmd = __esm(() => {
|
|
|
15921
15939
|
});
|
|
15922
15940
|
|
|
15923
15941
|
// src/server/app.ts
|
|
15924
|
-
import { existsSync as
|
|
15925
|
-
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";
|
|
15926
15944
|
|
|
15927
15945
|
// node_modules/hono/dist/request/constants.js
|
|
15928
15946
|
var GET_MATCH_RESULT = Symbol();
|
|
@@ -26204,9 +26222,9 @@ function mount20(ctx) {
|
|
|
26204
26222
|
}
|
|
26205
26223
|
|
|
26206
26224
|
// src/server/routes/verify.ts
|
|
26207
|
-
import { readFileSync as
|
|
26225
|
+
import { readFileSync as readFileSync55, realpathSync as realpathSync22 } from "fs";
|
|
26208
26226
|
import { createPublicKey as createPublicKey5 } from "crypto";
|
|
26209
|
-
import { join as
|
|
26227
|
+
import { join as join69, sep as sep13 } from "path";
|
|
26210
26228
|
init_verify_cmd();
|
|
26211
26229
|
init_seal();
|
|
26212
26230
|
init_receipt_dsse();
|
|
@@ -26233,15 +26251,15 @@ function mount21(ctx) {
|
|
|
26233
26251
|
return done(404, "receipt not available", "not_found");
|
|
26234
26252
|
let runDir, file;
|
|
26235
26253
|
try {
|
|
26236
|
-
const root =
|
|
26237
|
-
runDir =
|
|
26238
|
-
if (runDir !==
|
|
26254
|
+
const root = realpathSync22(join69(repo.p, ".loki", "runs"));
|
|
26255
|
+
runDir = realpathSync22(join69(root, run2));
|
|
26256
|
+
if (runDir !== join69(root, run2))
|
|
26239
26257
|
return done(404, "receipt not found", "not_found");
|
|
26240
|
-
file =
|
|
26258
|
+
file = realpathSync22(join69(runDir, "receipt.json"));
|
|
26241
26259
|
} catch {
|
|
26242
26260
|
return done(404, "receipt not found", "not_found");
|
|
26243
26261
|
}
|
|
26244
|
-
if (!file.startsWith(runDir +
|
|
26262
|
+
if (!file.startsWith(runDir + sep13))
|
|
26245
26263
|
return done(404, "receipt not found", "not_found");
|
|
26246
26264
|
let integrity, reasons, sha4 = null, outcome = "UNREADABLE";
|
|
26247
26265
|
try {
|
|
@@ -26256,7 +26274,7 @@ function mount21(ctx) {
|
|
|
26256
26274
|
sha4 = r.receiptSha256 ?? null;
|
|
26257
26275
|
}
|
|
26258
26276
|
try {
|
|
26259
|
-
outcome = outcomeOf(JSON.parse(
|
|
26277
|
+
outcome = outcomeOf(JSON.parse(readFileSync55(file, "utf8")));
|
|
26260
26278
|
} catch {
|
|
26261
26279
|
outcome = "UNREADABLE";
|
|
26262
26280
|
}
|
|
@@ -26318,8 +26336,8 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
|
|
|
26318
26336
|
}
|
|
26319
26337
|
|
|
26320
26338
|
// src/server/legacy/shim.ts
|
|
26321
|
-
import { existsSync as
|
|
26322
|
-
import { join as
|
|
26339
|
+
import { existsSync as existsSync46, readFileSync as readFileSync56 } from "fs";
|
|
26340
|
+
import { join as join70 } from "path";
|
|
26323
26341
|
|
|
26324
26342
|
// src/server/legacy/routes.ts
|
|
26325
26343
|
var LEGACY_ROUTES = [
|
|
@@ -26697,10 +26715,10 @@ var logged = new Set;
|
|
|
26697
26715
|
var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
|
|
26698
26716
|
var NOT_SUPPORTED = "not yet supported by the Control Plane";
|
|
26699
26717
|
var repoVersion = () => {
|
|
26700
|
-
for (const f of [
|
|
26718
|
+
for (const f of [join70(import.meta.dir, "../../../../../VERSION")]) {
|
|
26701
26719
|
try {
|
|
26702
|
-
if (
|
|
26703
|
-
return
|
|
26720
|
+
if (existsSync46(f))
|
|
26721
|
+
return readFileSync56(f, "utf8").trim();
|
|
26704
26722
|
} catch {}
|
|
26705
26723
|
}
|
|
26706
26724
|
return "unknown";
|
|
@@ -26882,7 +26900,7 @@ function legacyShim(opts) {
|
|
|
26882
26900
|
|
|
26883
26901
|
// src/server/app.ts
|
|
26884
26902
|
var MAX_BODY2 = 1e6;
|
|
26885
|
-
var defaultUiDir = () => [
|
|
26903
|
+
var defaultUiDir = () => [join71(import.meta.dir, "../../ui/dist"), join71(import.meta.dir, "../ui/dist")].find((d) => existsSync47(join71(d, "index.html")));
|
|
26886
26904
|
function createApp(opts) {
|
|
26887
26905
|
const uiDir = opts.uiDir ?? defaultUiDir();
|
|
26888
26906
|
const { db, sqlite } = openDb(opts.dbPath);
|
|
@@ -26911,10 +26929,10 @@ function createApp(opts) {
|
|
|
26911
26929
|
await next();
|
|
26912
26930
|
});
|
|
26913
26931
|
const readInstalled = () => {
|
|
26914
|
-
for (const f of [process.env.LOKI_VERSION_FILE,
|
|
26932
|
+
for (const f of [process.env.LOKI_VERSION_FILE, join71(import.meta.dir, "../../../../VERSION")]) {
|
|
26915
26933
|
try {
|
|
26916
26934
|
if (f)
|
|
26917
|
-
return
|
|
26935
|
+
return readFileSync57(f, "utf8").trim() || "unknown";
|
|
26918
26936
|
} catch {}
|
|
26919
26937
|
}
|
|
26920
26938
|
return "unknown";
|
|
@@ -27025,11 +27043,11 @@ function createApp(opts) {
|
|
|
27025
27043
|
return c.json({ error: "not found" }, 404);
|
|
27026
27044
|
const root = resolve15(uiDir);
|
|
27027
27045
|
const f = resolve15(root, `.${p}`);
|
|
27028
|
-
if (f.startsWith(root +
|
|
27046
|
+
if (f.startsWith(root + sep14) && existsSync47(f) && statSync23(f).isFile())
|
|
27029
27047
|
return new Response(Bun.file(f));
|
|
27030
27048
|
if (/\.[a-z0-9]+$/i.test(p))
|
|
27031
27049
|
return c.json({ error: "not found" }, 404);
|
|
27032
|
-
return new Response(Bun.file(
|
|
27050
|
+
return new Response(Bun.file(join71(root, "index.html")));
|
|
27033
27051
|
});
|
|
27034
27052
|
return { app, db, close: () => {
|
|
27035
27053
|
clearInterval(reconciler);
|