loki-mode 11.17.20 → 11.17.22
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/FAILURE-CLASSES.md +7 -0
- package/docs/v10/PROGRESS.md +8 -0
- package/loki-ts/dist/loki.js +934 -934
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +412 -324
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-DSJJQf-T.js → AdminPage-CQWI_3mK.js} +1 -1
- package/web-app/dist/assets/{Avatar-BF6WFrAy.js → Avatar-BPmAoSfT.js} +1 -1
- package/web-app/dist/assets/{Badge-Cr5T8jJf.js → Badge-aGj4xspI.js} +1 -1
- package/web-app/dist/assets/{Button-cCj7HFSw.js → Button-pJQGPQG3.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-DYBvJECQ.js → CockpitPage-DHMIYaxA.js} +1 -1
- package/web-app/dist/assets/{ComparePage-jJQblAwt.js → ComparePage-D2V0hmdL.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-DoDYMsY5.js → ErrorBoundary-Cy2nQmav.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-jpaq7kZq.js → EvidenceReceiptPanel-CejdTO8x.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-CKzX14a1.js → GitHubIssuesPanel-DnhZq0EQ.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-ZCksAyIl.js → GitHubPRsPanel-Dt0qFVhr.js} +1 -1
- package/web-app/dist/assets/{HomePage-C_zXBI8n.js → HomePage-BmIuJ6x6.js} +2 -2
- package/web-app/dist/assets/{LoginPage-B05bavzr.js → LoginPage-CwIqLxDo.js} +1 -1
- package/web-app/dist/assets/{MagicPage-d4pG9StL.js → MagicPage-vHlxLhHy.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-iDDUkKmA.js → MetricsPage-Ch1_tLGT.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-XPzm1hsZ.js → NotFoundPage-CqbhVSVc.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-z5I7069v.js → ProjectPage-ebHX3sGB.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DEWjBPo6.js → ProjectsPage-B89zXpBD.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DVQrE47C.js → SettingsPage-ChFvJS_q.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-DN2Ejjrj.js → ShowcasePage-BwXsSLnZ.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-B1Icrjyg.js → SystemSettingsPage-DFpGUEWE.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-CiX4e5Ss.js → TeamsPage-DokKqNEm.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-DBMF4Bgy.js → TemplatesPage-C0nYB8LZ.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-BszbIyo2.js → TerminalOutput-DAY4Byu3.js} +1 -1
- package/web-app/dist/assets/{activity-CuNWAGl6.js → activity-BOOOTjKZ.js} +1 -1
- package/web-app/dist/assets/{bell-CVZY4-gh.js → bell-BJnn6bBl.js} +1 -1
- package/web-app/dist/assets/{bot-CsGTJ3O8.js → bot-Bf2uaoIj.js} +1 -1
- package/web-app/dist/assets/{check-DkG0Ea0z.js → check-8ImSobx9.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D0OVBrPl.js → chevron-left-CltmqJT_.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DQj17Suj.js → circle-alert-BbAswQCH.js} +1 -1
- package/web-app/dist/assets/{clock-BwPMUOV3.js → clock-BavtSHCG.js} +1 -1
- package/web-app/dist/assets/{cloud-nBHFumIO.js → cloud-CNROigPM.js} +1 -1
- package/web-app/dist/assets/{code-xml-g4JPPXMJ.js → code-xml-CPMgX0Yl.js} +1 -1
- package/web-app/dist/assets/{database-D2gl8Fu_.js → database-DbHRpxUI.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-DMl-Ua1u.js → dollar-sign-BMsw7HY3.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Cf6Urnli.js → file-code-corner-MmKizbcw.js} +1 -1
- package/web-app/dist/assets/{file-plus-CuN6tuNG.js → file-plus-B2klPCRF.js} +1 -1
- package/web-app/dist/assets/{globe-DJ9B9SDQ.js → globe-DSscdsP3.js} +1 -1
- package/web-app/dist/assets/{hammer-C22DSm6w.js → hammer-CROPWX47.js} +1 -1
- package/web-app/dist/assets/{index-C3mMUd0H.js → index-e6AJj_FZ.js} +3 -3
- package/web-app/dist/assets/{layers-C-21Q5yC.js → layers-CEObwoRd.js} +1 -1
- package/web-app/dist/assets/{loader-circle-Cudap_5T.js → loader-circle-BCqpe4tG.js} +1 -1
- package/web-app/dist/assets/{lock-BLVsgQuz.js → lock-BnMvxGFU.js} +1 -1
- package/web-app/dist/assets/{package-CCd-tsex.js → package-B17YBJlQ.js} +1 -1
- package/web-app/dist/assets/{plus-D007hFG1.js → plus-CDOsU3Nf.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BD0FUUXB.js → refresh-cw-B3e5PosV.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-mkHMAMo9.js → rotate-ccw-Bq7bL0VU.js} +1 -1
- package/web-app/dist/assets/{scroll-text-C4crADU2.js → scroll-text-DnDLp_Iy.js} +1 -1
- package/web-app/dist/assets/{server-Du8kdE7M.js → server-DlV0wYge.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CcKJ6wWy.js → shield-alert-BBHJ_lXm.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-DAfab5rz.js → thumbs-up-Bkv2XfEI.js} +1 -1
- package/web-app/dist/assets/{trash-2-BfzfCvzf.js → trash-2-D_G3y6X3.js} +1 -1
- package/web-app/dist/assets/{trending-down-oglIx8Or.js → trending-down-VAFpBENN.js} +1 -1
- package/web-app/dist/assets/{trending-up-DIP0FR8A.js → trending-up-C1xa0U9-.js} +1 -1
- package/web-app/dist/assets/{upload-BOS2j4YP.js → upload-YAZyAmu-.js} +1 -1
- package/web-app/dist/assets/{usePolling-DX0DJsSF.js → usePolling-CXWrIloO.js} +1 -1
- package/web-app/dist/assets/{user-DHoJdQR4.js → user-B1vdZy5k.js} +1 -1
- package/web-app/dist/index.html +1 -1
|
@@ -7802,12 +7802,79 @@ var init_cache = __esm(() => {
|
|
|
7802
7802
|
init_paths();
|
|
7803
7803
|
});
|
|
7804
7804
|
|
|
7805
|
+
// ../../loki-ts/src/util/relevance.ts
|
|
7806
|
+
var STOPWORDS;
|
|
7807
|
+
var init_relevance = __esm(() => {
|
|
7808
|
+
STOPWORDS = new Set([
|
|
7809
|
+
"the",
|
|
7810
|
+
"and",
|
|
7811
|
+
"for",
|
|
7812
|
+
"with",
|
|
7813
|
+
"that",
|
|
7814
|
+
"this",
|
|
7815
|
+
"from",
|
|
7816
|
+
"into",
|
|
7817
|
+
"onto",
|
|
7818
|
+
"are",
|
|
7819
|
+
"was",
|
|
7820
|
+
"were",
|
|
7821
|
+
"will",
|
|
7822
|
+
"can",
|
|
7823
|
+
"should",
|
|
7824
|
+
"would",
|
|
7825
|
+
"could",
|
|
7826
|
+
"add",
|
|
7827
|
+
"fix",
|
|
7828
|
+
"make",
|
|
7829
|
+
"use",
|
|
7830
|
+
"new",
|
|
7831
|
+
"get",
|
|
7832
|
+
"set",
|
|
7833
|
+
"all",
|
|
7834
|
+
"any",
|
|
7835
|
+
"not",
|
|
7836
|
+
"but",
|
|
7837
|
+
"has",
|
|
7838
|
+
"have",
|
|
7839
|
+
"its",
|
|
7840
|
+
"our",
|
|
7841
|
+
"your",
|
|
7842
|
+
"when",
|
|
7843
|
+
"then",
|
|
7844
|
+
"than",
|
|
7845
|
+
"also",
|
|
7846
|
+
"each",
|
|
7847
|
+
"must",
|
|
7848
|
+
"need",
|
|
7849
|
+
"needs",
|
|
7850
|
+
"file",
|
|
7851
|
+
"files",
|
|
7852
|
+
"code",
|
|
7853
|
+
"update",
|
|
7854
|
+
"change",
|
|
7855
|
+
"implement",
|
|
7856
|
+
"create",
|
|
7857
|
+
"support",
|
|
7858
|
+
"line",
|
|
7859
|
+
"error",
|
|
7860
|
+
"test",
|
|
7861
|
+
"tests",
|
|
7862
|
+
"bug",
|
|
7863
|
+
"issue",
|
|
7864
|
+
"task",
|
|
7865
|
+
"feature",
|
|
7866
|
+
"please"
|
|
7867
|
+
]);
|
|
7868
|
+
});
|
|
7869
|
+
|
|
7805
7870
|
// ../../loki-ts/src/engine10/relevant_files.ts
|
|
7806
7871
|
function keywords(task) {
|
|
7807
|
-
|
|
7808
|
-
return Array.from(new Set(words.filter((w) => w.length > 2)));
|
|
7872
|
+
return Array.from(new Set((task.toLowerCase().match(/[a-z0-9_]+/g) ?? []).filter((w) => w.length > 2)));
|
|
7809
7873
|
}
|
|
7810
7874
|
var MAX_RELEVANT_FILES = 8, haystack = (entry) => `${entry.path} ${entry.symbols.join(" ")}`.toLowerCase();
|
|
7875
|
+
var init_relevant_files = __esm(() => {
|
|
7876
|
+
init_relevance();
|
|
7877
|
+
});
|
|
7811
7878
|
|
|
7812
7879
|
// ../../loki-ts/src/features/speed/lean_select.ts
|
|
7813
7880
|
function selectSpecificFiles(task, repoMap, max = MAX_RELEVANT_FILES) {
|
|
@@ -7834,7 +7901,9 @@ function speedLikelyFiles(task, map, env = process.env) {
|
|
|
7834
7901
|
}
|
|
7835
7902
|
}
|
|
7836
7903
|
var wordTokens = (text2) => text2.toLowerCase().match(/[a-z0-9_]+/g) ?? [];
|
|
7837
|
-
var init_lean_select = () => {
|
|
7904
|
+
var init_lean_select = __esm(() => {
|
|
7905
|
+
init_relevant_files();
|
|
7906
|
+
});
|
|
7838
7907
|
|
|
7839
7908
|
// ../../loki-ts/src/util/claude_model.ts
|
|
7840
7909
|
import { readFileSync as readFileSync20 } from "fs";
|
|
@@ -9674,6 +9743,19 @@ var init_test_file_text = __esm(() => {
|
|
|
9674
9743
|
});
|
|
9675
9744
|
|
|
9676
9745
|
// ../../loki-ts/src/engine10/testmap.ts
|
|
9746
|
+
import { existsSync as existsSync22, readdirSync as readdirSync13, readFileSync as readFileSync28, realpathSync as realpathSync16 } from "fs";
|
|
9747
|
+
import { basename as basename10, extname, isAbsolute as isAbsolute2, join as join37, relative, sep as sep10 } from "path";
|
|
9748
|
+
function projectInterpreter(root) {
|
|
9749
|
+
const ve = process.env["VIRTUAL_ENV"], inRepo = (p) => {
|
|
9750
|
+
try {
|
|
9751
|
+
const r = relative(realpathSync16(root), realpathSync16(p));
|
|
9752
|
+
return r !== "" && !r.startsWith("..") && !isAbsolute2(r);
|
|
9753
|
+
} catch {
|
|
9754
|
+
return false;
|
|
9755
|
+
}
|
|
9756
|
+
};
|
|
9757
|
+
return [join37(root, ".venv", "bin", "python"), join37(root, "venv", "bin", "python"), ...ve && inRepo(ve) ? [join37(ve, "bin", "python")] : []].some(existsSync22) ? "project" : "system";
|
|
9758
|
+
}
|
|
9677
9759
|
var SKIP_DIRS;
|
|
9678
9760
|
var init_testmap = __esm(() => {
|
|
9679
9761
|
init_resolve();
|
|
@@ -9697,8 +9779,8 @@ var init_testmap = __esm(() => {
|
|
|
9697
9779
|
});
|
|
9698
9780
|
|
|
9699
9781
|
// ../../loki-ts/src/util/check_result.ts
|
|
9700
|
-
import { mkdirSync as mkdirSync13, readFileSync as
|
|
9701
|
-
import { basename as
|
|
9782
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync29, renameSync as renameSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
9783
|
+
import { basename as basename11, join as join38 } from "path";
|
|
9702
9784
|
function plainTestEnv(base = process.env) {
|
|
9703
9785
|
const e = {};
|
|
9704
9786
|
for (const [k, v] of Object.entries(tokenFreeEnv(base)))
|
|
@@ -9716,7 +9798,7 @@ function ran(raw2, path, ok) {
|
|
|
9716
9798
|
if (blk) {
|
|
9717
9799
|
const c = n2(blk, /(?:#|\u2139) pass (\d+)/) + n2(blk, /(?:#|\u2139) fail (\d+)/);
|
|
9718
9800
|
const nm = out2.match(/^(?:ok \d+ - |\u2714 )(\S+\.[cm]?[jt]s)(?: \(|$)/m)?.[1];
|
|
9719
|
-
return c === 1 && nm && (!path ||
|
|
9801
|
+
return c === 1 && nm && (!path || basename11(nm) === basename11(path)) ? 0 : c;
|
|
9720
9802
|
}
|
|
9721
9803
|
const cg = cargoTrailer(out2);
|
|
9722
9804
|
if (cg.length)
|
|
@@ -9807,16 +9889,16 @@ function goRunner(cmd, args) {
|
|
|
9807
9889
|
let k = 0;
|
|
9808
9890
|
for (;k < t.length; k++) {
|
|
9809
9891
|
const x = t[k];
|
|
9810
|
-
if (/^[A-Za-z_]\w*=/.test(x) || /^(?:env|command|exec|time|nohup)$/.test(
|
|
9892
|
+
if (/^[A-Za-z_]\w*=/.test(x) || /^(?:env|command|exec|time|nohup)$/.test(basename11(x)))
|
|
9811
9893
|
continue;
|
|
9812
|
-
if (/^-/.test(x) && k > 0 &&
|
|
9894
|
+
if (/^-/.test(x) && k > 0 && basename11(t[k - 1]) === "env") {
|
|
9813
9895
|
if (x === "-u" || x === "-C" || x === "-S")
|
|
9814
9896
|
k++;
|
|
9815
9897
|
continue;
|
|
9816
9898
|
}
|
|
9817
9899
|
break;
|
|
9818
9900
|
}
|
|
9819
|
-
if (t[k] !== undefined &&
|
|
9901
|
+
if (t[k] !== undefined && basename11(t[k]) === "go")
|
|
9820
9902
|
return { runner: "go" };
|
|
9821
9903
|
}
|
|
9822
9904
|
return {};
|
|
@@ -9993,7 +10075,7 @@ function diffFiles(repoDir, baseSha) {
|
|
|
9993
10075
|
return f;
|
|
9994
10076
|
let n2 = 0;
|
|
9995
10077
|
try {
|
|
9996
|
-
n2 =
|
|
10078
|
+
n2 = readFileSync29(join38(repoDir, path), "utf8").split(`
|
|
9997
10079
|
`).length;
|
|
9998
10080
|
} catch {}
|
|
9999
10081
|
return { path, added: n2, deleted: 0, status: "added" };
|
|
@@ -10001,7 +10083,7 @@ function diffFiles(repoDir, baseSha) {
|
|
|
10001
10083
|
}
|
|
10002
10084
|
function recordRisk(repoDir, a) {
|
|
10003
10085
|
try {
|
|
10004
|
-
const dir =
|
|
10086
|
+
const dir = join38(repoDir, ".loki", "state"), p = join38(dir, "risk-tier.json");
|
|
10005
10087
|
mkdirSync13(dir, { recursive: true });
|
|
10006
10088
|
writeFileSync16(`${p}.tmp`, JSON.stringify(a, null, 2) + `
|
|
10007
10089
|
`);
|
|
@@ -10104,11 +10186,11 @@ var init_state = __esm(() => {
|
|
|
10104
10186
|
});
|
|
10105
10187
|
|
|
10106
10188
|
// ../../loki-ts/src/runner/repo_profile.ts
|
|
10107
|
-
import { existsSync as
|
|
10108
|
-
import { basename as
|
|
10189
|
+
import { existsSync as existsSync23, readFileSync as readFileSync30, mkdirSync as mkdirSync14, readdirSync as readdirSync14, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "fs";
|
|
10190
|
+
import { basename as basename12, join as join39, resolve as resolve13, isAbsolute as isAbsolute3 } from "path";
|
|
10109
10191
|
function loadProfile(repoDir) {
|
|
10110
10192
|
try {
|
|
10111
|
-
const p = JSON.parse(
|
|
10193
|
+
const p = JSON.parse(readFileSync30(commandProfilePath(repoDir), "utf8"));
|
|
10112
10194
|
return p?.version === 1 && Array.isArray(p.commands) && p.baseline ? p : null;
|
|
10113
10195
|
} catch {
|
|
10114
10196
|
return null;
|
|
@@ -10199,7 +10281,7 @@ async function staticPreExisting(tool, prefix, files, io) {
|
|
|
10199
10281
|
}
|
|
10200
10282
|
return attributeStatic(tool, head.out, baseOut, 1).preExisting;
|
|
10201
10283
|
}
|
|
10202
|
-
var commandProfilePath = (repoDir) =>
|
|
10284
|
+
var commandProfilePath = (repoDir) => join39(repoDir, ".loki", "state", "repo-profile.json"), STATIC_DIAG, STATIC_NOISE, STATIC_SUMMARY;
|
|
10203
10285
|
var init_repo_profile = __esm(() => {
|
|
10204
10286
|
init_failures();
|
|
10205
10287
|
init_check_result();
|
|
@@ -10241,14 +10323,14 @@ var init_context = __esm(() => {
|
|
|
10241
10323
|
});
|
|
10242
10324
|
|
|
10243
10325
|
// ../../loki-ts/src/util/steer.ts
|
|
10244
|
-
import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as
|
|
10326
|
+
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
10327
|
import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
|
|
10246
|
-
import { basename as
|
|
10328
|
+
import { basename as basename13, join as join40 } from "path";
|
|
10247
10329
|
function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
10248
10330
|
for (let i = 0;; i++) {
|
|
10249
10331
|
const name = i === 0 ? `${prefix}.md` : `${prefix}-${i}.md`;
|
|
10250
10332
|
try {
|
|
10251
|
-
link(src,
|
|
10333
|
+
link(src, join40(logs, name));
|
|
10252
10334
|
} catch (e) {
|
|
10253
10335
|
const code = e.code;
|
|
10254
10336
|
if (code === "EEXIST")
|
|
@@ -10256,7 +10338,7 @@ function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
|
10256
10338
|
if (code !== "EPERM" && code !== "ENOTSUP" && code !== "EXDEV" && code !== "EMLINK")
|
|
10257
10339
|
throw e;
|
|
10258
10340
|
const name2 = `${prefix}-${randomBytes4(4).toString("hex")}.md`;
|
|
10259
|
-
renameSync10(src,
|
|
10341
|
+
renameSync10(src, join40(logs, name2));
|
|
10260
10342
|
onLinked?.(name2);
|
|
10261
10343
|
return name2;
|
|
10262
10344
|
}
|
|
@@ -10271,14 +10353,14 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
10271
10353
|
const c = lstatSync9(claim);
|
|
10272
10354
|
if (!c.isFile())
|
|
10273
10355
|
return false;
|
|
10274
|
-
for (const a of
|
|
10356
|
+
for (const a of readdirSync15(logs)) {
|
|
10275
10357
|
if (!/^human-input-.*\.md$/.test(a))
|
|
10276
10358
|
continue;
|
|
10277
10359
|
try {
|
|
10278
|
-
const s = statSync15(
|
|
10360
|
+
const s = statSync15(join40(logs, a));
|
|
10279
10361
|
if (s.ino !== c.ino || s.dev !== c.dev)
|
|
10280
10362
|
continue;
|
|
10281
|
-
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) ||
|
|
10363
|
+
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) || existsSync24(appliedMarker(logs, a)))
|
|
10282
10364
|
return true;
|
|
10283
10365
|
} catch {}
|
|
10284
10366
|
}
|
|
@@ -10287,7 +10369,7 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
10287
10369
|
function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
10288
10370
|
let names;
|
|
10289
10371
|
try {
|
|
10290
|
-
names =
|
|
10372
|
+
names = readdirSync15(logs);
|
|
10291
10373
|
} catch {
|
|
10292
10374
|
return;
|
|
10293
10375
|
}
|
|
@@ -10295,7 +10377,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10295
10377
|
for (const n2 of names)
|
|
10296
10378
|
if (n2.startsWith(".applied-") && !present.has(n2.slice(".applied-".length))) {
|
|
10297
10379
|
try {
|
|
10298
|
-
unlinkSync5(
|
|
10380
|
+
unlinkSync5(join40(logs, n2));
|
|
10299
10381
|
} catch {}
|
|
10300
10382
|
}
|
|
10301
10383
|
for (const n2 of names) {
|
|
@@ -10312,7 +10394,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10312
10394
|
if (alive) {
|
|
10313
10395
|
let ageMs = 0;
|
|
10314
10396
|
try {
|
|
10315
|
-
ageMs = nowMs - statSync15(
|
|
10397
|
+
ageMs = nowMs - statSync15(join40(logs, n2)).mtimeMs;
|
|
10316
10398
|
} catch {
|
|
10317
10399
|
continue;
|
|
10318
10400
|
}
|
|
@@ -10320,11 +10402,11 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10320
10402
|
continue;
|
|
10321
10403
|
}
|
|
10322
10404
|
try {
|
|
10323
|
-
if (orphanAlreadyArchived(logs,
|
|
10324
|
-
unlinkSync5(
|
|
10405
|
+
if (orphanAlreadyArchived(logs, join40(logs, n2))) {
|
|
10406
|
+
unlinkSync5(join40(logs, n2));
|
|
10325
10407
|
continue;
|
|
10326
10408
|
}
|
|
10327
|
-
archiveTo(logs, `human-input-ORPHAN-${stamp2}`,
|
|
10409
|
+
archiveTo(logs, `human-input-ORPHAN-${stamp2}`, join40(logs, n2), link);
|
|
10328
10410
|
unapplied("orphaned claim");
|
|
10329
10411
|
} catch (e) {
|
|
10330
10412
|
if (e.code === "ENOENT")
|
|
@@ -10336,17 +10418,17 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
10336
10418
|
function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, hooks2) {
|
|
10337
10419
|
if (/^(0|false)$/i.test(env.LOKI_PROMPT_INJECTION ?? ""))
|
|
10338
10420
|
return null;
|
|
10339
|
-
const f =
|
|
10421
|
+
const f = join40(repoDir, ".loki", "HUMAN_INPUT.md");
|
|
10340
10422
|
const unapplied = (reason) => {
|
|
10341
10423
|
sink?.push({ rev: 0, source: null, actor: null, sha: "", at: now2().getTime(), unapplied: true, reason });
|
|
10342
10424
|
};
|
|
10343
10425
|
let fd = -1, claimed = "";
|
|
10344
10426
|
try {
|
|
10345
|
-
const logs =
|
|
10427
|
+
const logs = join40(repoDir, ".loki", "logs");
|
|
10346
10428
|
mkdirSync15(logs, { recursive: true });
|
|
10347
10429
|
const stamp2 = now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "");
|
|
10348
10430
|
sweepOrphans(logs, stamp2, unapplied, hooks2?.link, now2().getTime());
|
|
10349
|
-
claimed =
|
|
10431
|
+
claimed = join40(logs, `.claim-${process.pid}-${randomBytes4(6).toString("hex")}`);
|
|
10350
10432
|
try {
|
|
10351
10433
|
renameSync10(f, claimed);
|
|
10352
10434
|
} catch (e) {
|
|
@@ -10437,10 +10519,10 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
10437
10519
|
} catch {
|
|
10438
10520
|
if (claimed) {
|
|
10439
10521
|
try {
|
|
10440
|
-
archiveTo(
|
|
10522
|
+
archiveTo(join40(repoDir, ".loki", "logs"), `human-input-${now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "")}`, claimed, hooks2?.link);
|
|
10441
10523
|
unapplied("logs dir unwritable or file unreadable");
|
|
10442
10524
|
} catch {
|
|
10443
|
-
unapplied(`steer stranded at .loki/logs/${
|
|
10525
|
+
unapplied(`steer stranded at .loki/logs/${basename13(claimed)}`);
|
|
10444
10526
|
}
|
|
10445
10527
|
} else
|
|
10446
10528
|
try {
|
|
@@ -10456,10 +10538,10 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
10456
10538
|
}
|
|
10457
10539
|
}
|
|
10458
10540
|
function recordRevisions(repoDir, text2, archived, at) {
|
|
10459
|
-
const file =
|
|
10541
|
+
const file = join40(repoDir, ".loki", "intent-revisions.jsonl");
|
|
10460
10542
|
let last = 0;
|
|
10461
10543
|
try {
|
|
10462
|
-
for (const l of
|
|
10544
|
+
for (const l of readFileSync31(file, "utf8").split(`
|
|
10463
10545
|
`)) {
|
|
10464
10546
|
try {
|
|
10465
10547
|
last = Math.max(last, Number(JSON.parse(l).rev) || 0);
|
|
@@ -10513,7 +10595,7 @@ function staleAtSeal(repoDir, ctx) {
|
|
|
10513
10595
|
const frozen = ctx.outputs === undefined || ctx.outputs().wall !== undefined || ctx.wallSealed === true;
|
|
10514
10596
|
return [...new Set([...staleWallRevisions(ctx.intentRevisions, frozen ? ctx.timeline : []), ...late])];
|
|
10515
10597
|
}
|
|
10516
|
-
var STEER_MAX_BYTES, STEER_STAGES, STEER_CLAIM_MAX_AGE_MS, appliedMarker = (logs, archive) =>
|
|
10598
|
+
var STEER_MAX_BYTES, STEER_STAGES, STEER_CLAIM_MAX_AGE_MS, appliedMarker = (logs, archive) => join40(logs, `.applied-${archive}`), REV_HDR, STEER_REMEDY;
|
|
10517
10599
|
var init_steer = __esm(() => {
|
|
10518
10600
|
init_context();
|
|
10519
10601
|
STEER_MAX_BYTES = 1024 * 1024;
|
|
@@ -10576,18 +10658,18 @@ var init_seal_drift = __esm(() => {
|
|
|
10576
10658
|
});
|
|
10577
10659
|
|
|
10578
10660
|
// ../../loki-ts/src/util/spec_file.ts
|
|
10579
|
-
import { isAbsolute as
|
|
10661
|
+
import { isAbsolute as isAbsolute4, join as join41, relative as relative2 } from "path";
|
|
10580
10662
|
function specReceiptBlock(env) {
|
|
10581
10663
|
const { LOKI_E10_SPEC_PATH: p, LOKI_E10_SPEC_SHA256: sha2 } = env;
|
|
10582
10664
|
if (!p || !sha2)
|
|
10583
10665
|
return {};
|
|
10584
|
-
const rel =
|
|
10666
|
+
const rel = isAbsolute4(p) && env.LOKI_E10_REPO_DIR ? relative2(env.LOKI_E10_REPO_DIR, p) : p;
|
|
10585
10667
|
return { spec: { path: rel, sha256: sha2 } };
|
|
10586
10668
|
}
|
|
10587
10669
|
var SPEC_DIR;
|
|
10588
10670
|
var init_spec_file = __esm(() => {
|
|
10589
10671
|
init_types();
|
|
10590
|
-
SPEC_DIR =
|
|
10672
|
+
SPEC_DIR = join41(".loki", "specs");
|
|
10591
10673
|
});
|
|
10592
10674
|
|
|
10593
10675
|
// ../../loki-ts/src/engine10/pr_body.ts
|
|
@@ -10607,11 +10689,11 @@ var init_run_cap = __esm(() => {
|
|
|
10607
10689
|
});
|
|
10608
10690
|
|
|
10609
10691
|
// ../../loki-ts/src/util/mutation_proof.ts
|
|
10610
|
-
import { existsSync as
|
|
10692
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync3, readFileSync as readFileSync32, rmSync as rmSync10, symlinkSync, writeFileSync as writeFileSync19 } from "fs";
|
|
10611
10693
|
import { tmpdir as tmpdir4 } from "os";
|
|
10612
|
-
import { basename as
|
|
10694
|
+
import { basename as basename14, dirname as dirname13, isAbsolute as isAbsolute5, join as join42, relative as relative3 } from "path";
|
|
10613
10695
|
function mutationProof(i) {
|
|
10614
|
-
const rels = i.wallFiles.map((f) =>
|
|
10696
|
+
const rels = i.wallFiles.map((f) => isAbsolute5(f.path) ? relative3(i.repoDir, f.path) : f.path);
|
|
10615
10697
|
if (rels.length === 0)
|
|
10616
10698
|
return np("no Wall tests");
|
|
10617
10699
|
const tests = rels.flatMap((rel) => {
|
|
@@ -10627,26 +10709,26 @@ function mutationProof(i) {
|
|
|
10627
10709
|
const deadline = Date.now() + budgetS * 1000, remaining = () => deadline - Date.now();
|
|
10628
10710
|
let parent = null, wt = null, added = false;
|
|
10629
10711
|
try {
|
|
10630
|
-
parent = mkdtempSync3(
|
|
10631
|
-
wt =
|
|
10712
|
+
parent = mkdtempSync3(join42(tmpdir4(), "loki-mutproof-"));
|
|
10713
|
+
wt = join42(parent, "wt");
|
|
10632
10714
|
const add3 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
|
|
10633
|
-
added =
|
|
10715
|
+
added = existsSync25(wt) || add3.status === 0;
|
|
10634
10716
|
if (add3.status !== 0)
|
|
10635
10717
|
return np("could not create the base worktree");
|
|
10636
10718
|
for (const rel of rels) {
|
|
10637
|
-
const sealed =
|
|
10638
|
-
if (!
|
|
10719
|
+
const sealed = join42(i.runDir, "wall", basename14(rel)), src = existsSync25(sealed) ? sealed : join42(i.repoDir, rel);
|
|
10720
|
+
if (!existsSync25(src))
|
|
10639
10721
|
return np(`Wall file missing: ${rel}`);
|
|
10640
|
-
mkdirSync16(dirname13(
|
|
10641
|
-
writeFileSync19(
|
|
10722
|
+
mkdirSync16(dirname13(join42(wt, rel)), { recursive: true });
|
|
10723
|
+
writeFileSync19(join42(wt, rel), readFileSync32(src));
|
|
10642
10724
|
}
|
|
10643
10725
|
for (const rel of rels) {
|
|
10644
10726
|
const parts = rel.split("/").slice(0, -1);
|
|
10645
10727
|
for (let n2 = 0;n2 <= parts.length; n2++) {
|
|
10646
10728
|
const anc = parts.slice(0, n2).join("/");
|
|
10647
10729
|
for (const d of DEP_DIRS) {
|
|
10648
|
-
const src =
|
|
10649
|
-
if (
|
|
10730
|
+
const src = join42(i.repoDir, anc, d), dst = join42(wt, anc, d);
|
|
10731
|
+
if (existsSync25(src) && !existsSync25(dst)) {
|
|
10650
10732
|
try {
|
|
10651
10733
|
symlinkSync(src, dst);
|
|
10652
10734
|
} catch {}
|
|
@@ -10774,7 +10856,7 @@ var init_shell = __esm(() => {
|
|
|
10774
10856
|
});
|
|
10775
10857
|
|
|
10776
10858
|
// ../../loki-ts/src/util/python.ts
|
|
10777
|
-
import { accessSync, constants as constants3, existsSync as
|
|
10859
|
+
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
10860
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10779
10861
|
import { tmpdir as tmpdir5 } from "os";
|
|
10780
10862
|
function resolvePython3() {
|
|
@@ -11115,7 +11197,7 @@ var init_wall_manifest = __esm(() => {
|
|
|
11115
11197
|
|
|
11116
11198
|
// ../../loki-ts/src/features/wall_manifest_wire.ts
|
|
11117
11199
|
import { createHash as createHash11 } from "crypto";
|
|
11118
|
-
import { basename as
|
|
11200
|
+
import { basename as basename15, dirname as dirname14 } from "path";
|
|
11119
11201
|
function blobEntries(ls) {
|
|
11120
11202
|
const out2 = [];
|
|
11121
11203
|
for (const raw2 of ls.toString("latin1").split("\x00")) {
|
|
@@ -11145,12 +11227,12 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
|
|
|
11145
11227
|
return null;
|
|
11146
11228
|
const low = task.toLowerCase().replace(/\\/g, "/");
|
|
11147
11229
|
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(
|
|
11230
|
+
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename15(e.path)) && e.path.includes("/") && token(dirname14(e.path));
|
|
11231
|
+
const matched = all.filter((e) => SOURCE.test(e.path) && (token(basename15(e.path)) || token(e.path) || token(basename15(e.path).replace(/\.[^.]*$/, "")) || dirModule(e)));
|
|
11150
11232
|
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
11233
|
const occ = new Map(matched.map((e) => [e, spans(e.path)]));
|
|
11152
11234
|
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(
|
|
11235
|
+
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
11236
|
const named = [...byPath2, ...byBase, ...matched.filter((e) => !byPath2.includes(e) && !byBase.includes(e))].slice(0, MAX_NAMED);
|
|
11155
11237
|
const tests = all.filter((e) => TESTISH.test(e.path)).slice(0, MAX_FILES), listed = tests.filter((e) => !SOURCE.test(e.path));
|
|
11156
11238
|
const want = [...new Set([...all.filter((e) => CONFIG.test(e.path)), ...tests.filter((e) => SOURCE.test(e.path)), ...named])];
|
|
@@ -11207,9 +11289,9 @@ Example: test('name', () => { assert.strictEqual(fn(1), 2); }); Run: node --tes
|
|
|
11207
11289
|
|
|
11208
11290
|
// ../../loki-ts/src/util/holdout.ts
|
|
11209
11291
|
import { createHash as createHash12 } from "crypto";
|
|
11210
|
-
import { appendFileSync as appendFileSync3, copyFileSync as copyFileSync2, existsSync as
|
|
11292
|
+
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
11293
|
import { tmpdir as tmpdir6 } from "os";
|
|
11212
|
-
import { basename as
|
|
11294
|
+
import { basename as basename16, join as join43, relative as relative4 } from "path";
|
|
11213
11295
|
function wallHoldoutRatio(env = process.env) {
|
|
11214
11296
|
if (env["LOKI_WALL_HOLDOUT"]?.trim() === "0")
|
|
11215
11297
|
return 0;
|
|
@@ -11237,32 +11319,32 @@ function stashHoldout(o) {
|
|
|
11237
11319
|
rmSync12(dir, { recursive: true, force: true });
|
|
11238
11320
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
11239
11321
|
const files = held.map((name) => {
|
|
11240
|
-
copyFileSync2(
|
|
11241
|
-
rmSync12(
|
|
11242
|
-
return { name, runner: o.runnerOf(name), sha256: sha2(
|
|
11322
|
+
copyFileSync2(join43(o.srcDir, name), join43(dir, name));
|
|
11323
|
+
rmSync12(join43(o.srcDir, name), { force: true });
|
|
11324
|
+
return { name, runner: o.runnerOf(name), sha256: sha2(readFileSync34(join43(dir, name), "utf8")) };
|
|
11243
11325
|
});
|
|
11244
|
-
writeFileSync20(
|
|
11326
|
+
writeFileSync20(join43(dir, MANIFEST), JSON.stringify({ targetDir: o.targetDir, files }));
|
|
11245
11327
|
return { dir, names: new Set(held) };
|
|
11246
11328
|
}
|
|
11247
11329
|
function stageHoldout(dir, repoDir) {
|
|
11248
11330
|
const put = [], tests = [], missing = [];
|
|
11249
11331
|
let man = null;
|
|
11250
11332
|
try {
|
|
11251
|
-
man = JSON.parse(
|
|
11333
|
+
man = JSON.parse(readFileSync34(join43(dir, MANIFEST), "utf8"));
|
|
11252
11334
|
} catch {}
|
|
11253
11335
|
if (!man)
|
|
11254
|
-
return { tests, missing: [`holdout store unreadable: ${
|
|
11336
|
+
return { tests, missing: [`holdout store unreadable: ${basename16(dir)}`], cleanup: () => {} };
|
|
11255
11337
|
mkdirSync17(man.targetDir, { recursive: true });
|
|
11256
11338
|
man.files.forEach((f, i) => {
|
|
11257
|
-
const src =
|
|
11258
|
-
if (!
|
|
11339
|
+
const src = join43(dir, f.name);
|
|
11340
|
+
if (!existsSync27(src) || sha2(readFileSync34(src, "utf8")) !== f.sha256) {
|
|
11259
11341
|
missing.push(`holdout ${i + 1} missing or altered`);
|
|
11260
11342
|
return;
|
|
11261
11343
|
}
|
|
11262
|
-
const dest =
|
|
11344
|
+
const dest = join43(man.targetDir, `loki_wall_holdout_${i + 1}${f.name.slice(f.name.indexOf("."))}`);
|
|
11263
11345
|
copyFileSync2(src, dest);
|
|
11264
11346
|
put.push(dest);
|
|
11265
|
-
tests.push({ runner: f.runner, path:
|
|
11347
|
+
tests.push({ runner: f.runner, path: relative4(repoDir, dest) });
|
|
11266
11348
|
});
|
|
11267
11349
|
return { tests, missing, cleanup: () => {
|
|
11268
11350
|
for (const p of put)
|
|
@@ -11272,16 +11354,16 @@ function stageHoldout(dir, repoDir) {
|
|
|
11272
11354
|
function recordHoldoutTriage(runDir, entry) {
|
|
11273
11355
|
try {
|
|
11274
11356
|
mkdirSync17(runDir, { recursive: true });
|
|
11275
|
-
appendFileSync3(
|
|
11357
|
+
appendFileSync3(join43(runDir, HOLDOUT_TRIAGE_FILE), JSON.stringify(entry) + `
|
|
11276
11358
|
`, { mode: 384 });
|
|
11277
11359
|
} catch {}
|
|
11278
11360
|
}
|
|
11279
|
-
var sha2 = (s) => createHash12("sha256").update(s).digest("hex"), WALL_HOLDOUT_DEFAULT_RATIO = 0.2, isHoldoutCheck = (name) => name.startsWith("holdout:"), holdoutDirFor = (runId, repoDir) =>
|
|
11361
|
+
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
11362
|
var init_holdout = () => {};
|
|
11281
11363
|
|
|
11282
11364
|
// ../../loki-ts/src/features/runner_config.ts
|
|
11283
|
-
import { readFileSync as
|
|
11284
|
-
import { dirname as dirname15, join as
|
|
11365
|
+
import { readFileSync as readFileSync35 } from "fs";
|
|
11366
|
+
import { dirname as dirname15, join as join44, normalize as normalize2 } from "path";
|
|
11285
11367
|
function tomlKey2(s, i = 0, eq2 = true) {
|
|
11286
11368
|
const parts = [], ws = () => {
|
|
11287
11369
|
while (/\s/.test(s[i] ?? "x"))
|
|
@@ -11558,8 +11640,8 @@ function referenced(cfg, text2) {
|
|
|
11558
11640
|
}
|
|
11559
11641
|
const dir = dirname15(cfg), explicit = ROOT_DIR.exec(text2), roots = [dir];
|
|
11560
11642
|
if (explicit)
|
|
11561
|
-
roots.push("", ...explicit[1] ? [
|
|
11562
|
-
return [...raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(
|
|
11643
|
+
roots.push("", ...explicit[1] ? [join44(dir, explicit[1])] : []);
|
|
11644
|
+
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
11645
|
}
|
|
11564
11646
|
function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
11565
11647
|
const notes = new Set, ch = new Set(changed.map((c) => normalize2(c)));
|
|
@@ -11639,7 +11721,7 @@ var PKG_KEYS, RAW_CONFIGS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, dep
|
|
|
11639
11721
|
}
|
|
11640
11722
|
}, headText = (dir, f) => {
|
|
11641
11723
|
try {
|
|
11642
|
-
return
|
|
11724
|
+
return readFileSync35(join44(dir, f), "utf8");
|
|
11643
11725
|
} catch {
|
|
11644
11726
|
return "";
|
|
11645
11727
|
}
|
|
@@ -11679,19 +11761,19 @@ var init_runner_config = __esm(() => {
|
|
|
11679
11761
|
|
|
11680
11762
|
// ../../loki-ts/src/e10ext/assert_delta.ts
|
|
11681
11763
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
11682
|
-
import { mkdtempSync as mkdtempSync5, readFileSync as
|
|
11764
|
+
import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync36, rmSync as rmSync13 } from "fs";
|
|
11683
11765
|
import { tmpdir as tmpdir7 } from "os";
|
|
11684
|
-
import { join as
|
|
11685
|
-
import { basename as
|
|
11766
|
+
import { join as join45 } from "path";
|
|
11767
|
+
import { basename as basename17 } from "path";
|
|
11686
11768
|
function classifyAssertDelta(inp) {
|
|
11687
|
-
const f =
|
|
11769
|
+
const f = basename17(inp.path);
|
|
11688
11770
|
if (!/^(test_.*|.*_test)\.py$/.test(f))
|
|
11689
11771
|
return WEAKENED;
|
|
11690
11772
|
if (inp.headCounts.run !== inp.baseCounts.run || inp.headCounts.skipped !== inp.baseCounts.skipped)
|
|
11691
11773
|
return WEAKENED;
|
|
11692
11774
|
let cwd = "";
|
|
11693
11775
|
try {
|
|
11694
|
-
cwd = mkdtempSync5(
|
|
11776
|
+
cwd = mkdtempSync5(join45(tmpdir7(), "loki-ad-"));
|
|
11695
11777
|
const raw2 = execFileSync3("python3", ["-I", "-c", PY], {
|
|
11696
11778
|
input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
|
|
11697
11779
|
cwd,
|
|
@@ -11722,7 +11804,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
|
|
|
11722
11804
|
return null;
|
|
11723
11805
|
try {
|
|
11724
11806
|
const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
|
|
11725
|
-
const head = headRef ? show(headRef) :
|
|
11807
|
+
const head = headRef ? show(headRef) : readFileSync36(join45(repoDir, path), "utf8");
|
|
11726
11808
|
const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
|
|
11727
11809
|
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
11810
|
} catch {
|
|
@@ -11929,19 +12011,19 @@ var init_runner_errors = __esm(() => {
|
|
|
11929
12011
|
|
|
11930
12012
|
// ../../loki-ts/src/runner/load_owner.ts
|
|
11931
12013
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
11932
|
-
import { mkdtempSync as mkdtempSync6, realpathSync as
|
|
12014
|
+
import { mkdtempSync as mkdtempSync6, realpathSync as realpathSync18, rmSync as rmSync14 } from "fs";
|
|
11933
12015
|
import { tmpdir as tmpdir8 } from "os";
|
|
11934
|
-
import { basename as
|
|
12016
|
+
import { basename as basename18, extname as extname2, join as join46 } from "path";
|
|
11935
12017
|
function changedFilesNamed(out2, repoDir, changed) {
|
|
11936
12018
|
return changed.filter((f) => {
|
|
11937
|
-
if (out2.includes(f) || out2.includes(
|
|
12019
|
+
if (out2.includes(f) || out2.includes(join46(repoDir, f)))
|
|
11938
12020
|
return true;
|
|
11939
12021
|
const segs = f.split("/");
|
|
11940
12022
|
if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
|
|
11941
12023
|
return true;
|
|
11942
|
-
if (
|
|
12024
|
+
if (extname2(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
|
|
11943
12025
|
return true;
|
|
11944
|
-
const stem =
|
|
12026
|
+
const stem = basename18(f, extname2(f));
|
|
11945
12027
|
if (stem.length < 2 || stem === "index" || stem === "__init__")
|
|
11946
12028
|
return false;
|
|
11947
12029
|
return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
|
|
@@ -11951,7 +12033,7 @@ function loadSignature(out2, roots) {
|
|
|
11951
12033
|
let o = out2;
|
|
11952
12034
|
for (const r of roots.flatMap((x) => {
|
|
11953
12035
|
try {
|
|
11954
|
-
return [x,
|
|
12036
|
+
return [x, realpathSync18(x)];
|
|
11955
12037
|
} catch {
|
|
11956
12038
|
return [x];
|
|
11957
12039
|
}
|
|
@@ -12045,7 +12127,7 @@ async function loadErrorIsHarnessOwned(i) {
|
|
|
12045
12127
|
return false;
|
|
12046
12128
|
if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
|
|
12047
12129
|
return false;
|
|
12048
|
-
const dir = mkdtempSync6(
|
|
12130
|
+
const dir = mkdtempSync6(join46(tmpdir8(), "e10-loadown-"));
|
|
12049
12131
|
const git3 = (args) => {
|
|
12050
12132
|
safeGit(i.repoDir, args, { stdio: "ignore" });
|
|
12051
12133
|
};
|
|
@@ -12077,7 +12159,7 @@ var init_load_owner = __esm(() => {
|
|
|
12077
12159
|
});
|
|
12078
12160
|
|
|
12079
12161
|
// ../../loki-ts/src/util/wall_owned.ts
|
|
12080
|
-
import { isAbsolute as
|
|
12162
|
+
import { isAbsolute as isAbsolute6, join as join47, relative as relative5 } from "path";
|
|
12081
12163
|
function failingLocations(raw2, cwd, repoDir) {
|
|
12082
12164
|
const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
|
|
12083
12165
|
`), files = new Set;
|
|
@@ -12109,7 +12191,7 @@ function failingLocations(raw2, cwd, repoDir) {
|
|
|
12109
12191
|
}
|
|
12110
12192
|
if (errors2 === 0 || located !== errors2)
|
|
12111
12193
|
return null;
|
|
12112
|
-
return [...files].map((f) =>
|
|
12194
|
+
return [...files].map((f) => relative5(repoDir, isAbsolute6(f) ? f : join47(cwd, f)));
|
|
12113
12195
|
}
|
|
12114
12196
|
function wallOwnedFailure(raw2, cwd, repoDir, wall) {
|
|
12115
12197
|
const locs = failingLocations(raw2, cwd, repoDir);
|
|
@@ -12123,21 +12205,21 @@ var init_wall_owned = __esm(() => {
|
|
|
12123
12205
|
// ../../loki-ts/src/project_graph.ts
|
|
12124
12206
|
import { createHash as createHash13 } from "crypto";
|
|
12125
12207
|
import {
|
|
12126
|
-
existsSync as
|
|
12127
|
-
readdirSync as
|
|
12128
|
-
readFileSync as
|
|
12208
|
+
existsSync as existsSync28,
|
|
12209
|
+
readdirSync as readdirSync16,
|
|
12210
|
+
readFileSync as readFileSync37,
|
|
12129
12211
|
statSync as statSync17,
|
|
12130
12212
|
writeFileSync as writeFileSync21,
|
|
12131
12213
|
mkdirSync as mkdirSync18
|
|
12132
12214
|
} from "fs";
|
|
12133
|
-
import { basename as
|
|
12215
|
+
import { basename as basename19, dirname as dirname16, join as join48, resolve as resolve14 } from "path";
|
|
12134
12216
|
function readManifest(path) {
|
|
12135
|
-
if (!
|
|
12217
|
+
if (!existsSync28(path)) {
|
|
12136
12218
|
return null;
|
|
12137
12219
|
}
|
|
12138
12220
|
let raw2;
|
|
12139
12221
|
try {
|
|
12140
|
-
raw2 =
|
|
12222
|
+
raw2 = readFileSync37(path, "utf8");
|
|
12141
12223
|
} catch {
|
|
12142
12224
|
return null;
|
|
12143
12225
|
}
|
|
@@ -12174,7 +12256,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12174
12256
|
const seen = new Set;
|
|
12175
12257
|
let children;
|
|
12176
12258
|
try {
|
|
12177
|
-
children =
|
|
12259
|
+
children = readdirSync16(rootDir);
|
|
12178
12260
|
} catch {
|
|
12179
12261
|
children = [];
|
|
12180
12262
|
}
|
|
@@ -12189,7 +12271,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12189
12271
|
for (const child of children) {
|
|
12190
12272
|
if (!matchPattern(name, child))
|
|
12191
12273
|
continue;
|
|
12192
|
-
const full =
|
|
12274
|
+
const full = join48(rootDir, child);
|
|
12193
12275
|
if (seen.has(full))
|
|
12194
12276
|
continue;
|
|
12195
12277
|
let st;
|
|
@@ -12206,7 +12288,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12206
12288
|
}
|
|
12207
12289
|
if (declared.length === 0) {
|
|
12208
12290
|
for (const child of children) {
|
|
12209
|
-
const full =
|
|
12291
|
+
const full = join48(rootDir, child);
|
|
12210
12292
|
if (seen.has(full))
|
|
12211
12293
|
continue;
|
|
12212
12294
|
let st;
|
|
@@ -12217,7 +12299,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
12217
12299
|
}
|
|
12218
12300
|
if (!st.isDirectory())
|
|
12219
12301
|
continue;
|
|
12220
|
-
if (!
|
|
12302
|
+
if (!existsSync28(join48(full, ".loki", "app.json")))
|
|
12221
12303
|
continue;
|
|
12222
12304
|
seen.add(full);
|
|
12223
12305
|
out2.push(full);
|
|
@@ -12238,26 +12320,26 @@ function cacheKey(manifestPaths) {
|
|
|
12238
12320
|
}
|
|
12239
12321
|
function writeCache(targetDir, key, result) {
|
|
12240
12322
|
try {
|
|
12241
|
-
const cacheDir =
|
|
12323
|
+
const cacheDir = join48(targetDir, ".loki", "state");
|
|
12242
12324
|
mkdirSync18(cacheDir, { recursive: true });
|
|
12243
|
-
const cachePath =
|
|
12325
|
+
const cachePath = join48(cacheDir, "project-graph.json");
|
|
12244
12326
|
writeFileSync21(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
|
|
12245
12327
|
} catch {}
|
|
12246
12328
|
}
|
|
12247
12329
|
function discoverProjectGraph(targetDir) {
|
|
12248
12330
|
const absTarget = resolve14(targetDir);
|
|
12249
|
-
const targetManifest =
|
|
12331
|
+
const targetManifest = join48(absTarget, ".loki", "app.json");
|
|
12250
12332
|
const parentDir = dirname16(absTarget);
|
|
12251
|
-
const parentManifest =
|
|
12333
|
+
const parentManifest = join48(parentDir, ".loki", "app.json");
|
|
12252
12334
|
const examined = [];
|
|
12253
12335
|
let chosenManifest = null;
|
|
12254
12336
|
let chosenRoot = "";
|
|
12255
|
-
if (
|
|
12337
|
+
if (existsSync28(parentManifest) && parentDir !== absTarget) {
|
|
12256
12338
|
examined.push(parentManifest);
|
|
12257
12339
|
chosenManifest = readManifest(parentManifest);
|
|
12258
12340
|
chosenRoot = parentDir;
|
|
12259
12341
|
}
|
|
12260
|
-
if (!chosenManifest &&
|
|
12342
|
+
if (!chosenManifest && existsSync28(targetManifest)) {
|
|
12261
12343
|
examined.push(targetManifest);
|
|
12262
12344
|
chosenManifest = readManifest(targetManifest);
|
|
12263
12345
|
chosenRoot = absTarget;
|
|
@@ -12265,11 +12347,11 @@ function discoverProjectGraph(targetDir) {
|
|
|
12265
12347
|
if (!chosenManifest)
|
|
12266
12348
|
return null;
|
|
12267
12349
|
const declared = chosenManifest.members ?? [];
|
|
12268
|
-
const members = resolveMembers(chosenRoot, declared,
|
|
12350
|
+
const members = resolveMembers(chosenRoot, declared, basename19(absTarget));
|
|
12269
12351
|
const filtered = [];
|
|
12270
12352
|
for (const m of members) {
|
|
12271
|
-
const sibManifestPath =
|
|
12272
|
-
if (
|
|
12353
|
+
const sibManifestPath = join48(m, ".loki", "app.json");
|
|
12354
|
+
if (existsSync28(sibManifestPath)) {
|
|
12273
12355
|
examined.push(sibManifestPath);
|
|
12274
12356
|
const sibManifest = readManifest(sibManifestPath);
|
|
12275
12357
|
if (sibManifest && sibManifest.app_id !== chosenManifest.app_id) {
|
|
@@ -12397,9 +12479,9 @@ var init_route_block = __esm(() => {
|
|
|
12397
12479
|
// ../../loki-ts/src/features/visual_evidence.ts
|
|
12398
12480
|
import { spawn as spawn7 } from "child_process";
|
|
12399
12481
|
import { createHash as createHash14, randomBytes as randomBytes5 } from "crypto";
|
|
12400
|
-
import { existsSync as
|
|
12482
|
+
import { existsSync as existsSync29, lstatSync as lstatSync10, mkdirSync as mkdirSync19, readdirSync as readdirSync17, readFileSync as readFileSync38, writeFileSync as writeFileSync22 } from "fs";
|
|
12401
12483
|
import { createServer } from "net";
|
|
12402
|
-
import { dirname as dirname17, isAbsolute as
|
|
12484
|
+
import { dirname as dirname17, isAbsolute as isAbsolute7, join as join49, normalize as normalize3, relative as relative6, sep as sep11 } from "path";
|
|
12403
12485
|
function routeFor(file) {
|
|
12404
12486
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
12405
12487
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -12409,7 +12491,7 @@ function hashScreens(runDir, rels) {
|
|
|
12409
12491
|
const out2 = [];
|
|
12410
12492
|
for (const rel of rels) {
|
|
12411
12493
|
try {
|
|
12412
|
-
out2.push({ path: rel, sha256: sha256File(
|
|
12494
|
+
out2.push({ path: rel, sha256: sha256File(join49(runDir, rel)) });
|
|
12413
12495
|
} catch {}
|
|
12414
12496
|
}
|
|
12415
12497
|
return out2;
|
|
@@ -12420,16 +12502,16 @@ function checkScreens(runDir, screens) {
|
|
|
12420
12502
|
for (const s of screens) {
|
|
12421
12503
|
if (typeof s?.path !== "string" || typeof s.sha256 !== "string")
|
|
12422
12504
|
return "evidence_screens entry is malformed";
|
|
12423
|
-
if (
|
|
12505
|
+
if (isAbsolute7(s.path) || normalize3(s.path).startsWith(".."))
|
|
12424
12506
|
return `evidence screenshot path escapes the evidence dir: ${s.path}`;
|
|
12425
|
-
const file =
|
|
12507
|
+
const file = join49(runDir, s.path);
|
|
12426
12508
|
let cur = runDir;
|
|
12427
|
-
for (const seg of normalize3(s.path).split(
|
|
12428
|
-
cur =
|
|
12509
|
+
for (const seg of normalize3(s.path).split(sep11)) {
|
|
12510
|
+
cur = join49(cur, seg);
|
|
12429
12511
|
if (isSymlink(cur))
|
|
12430
12512
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
12431
12513
|
}
|
|
12432
|
-
if (!
|
|
12514
|
+
if (!existsSync29(file))
|
|
12433
12515
|
return `evidence screenshot is missing: ${s.path}`;
|
|
12434
12516
|
if (!isRegularFile(file))
|
|
12435
12517
|
return `evidence screenshot is not a regular file: ${s.path}`;
|
|
@@ -12472,11 +12554,11 @@ async function waitUp(url, ms, signal) {
|
|
|
12472
12554
|
}
|
|
12473
12555
|
function openapiPaths(repoDir) {
|
|
12474
12556
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
12475
|
-
const p =
|
|
12476
|
-
if (!
|
|
12557
|
+
const p = join49(repoDir, f);
|
|
12558
|
+
if (!existsSync29(p))
|
|
12477
12559
|
continue;
|
|
12478
12560
|
try {
|
|
12479
|
-
const txt =
|
|
12561
|
+
const txt = readFileSync38(p, "utf8");
|
|
12480
12562
|
const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
|
|
12481
12563
|
return paths.filter((x) => !x.includes("{")).slice(0, 10);
|
|
12482
12564
|
} catch {
|
|
@@ -12490,24 +12572,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
|
|
|
12490
12572
|
if (!pw || !pkg)
|
|
12491
12573
|
return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
|
|
12492
12574
|
try {
|
|
12493
|
-
const dir =
|
|
12575
|
+
const dir = join49(runDir, relDir, "e2e");
|
|
12494
12576
|
mkdirSync19(dir, { recursive: true });
|
|
12495
|
-
writeFileSync22(
|
|
12496
|
-
writeFileSync22(
|
|
12577
|
+
writeFileSync22(join49(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
|
|
12578
|
+
writeFileSync22(join49(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
|
|
12497
12579
|
`);
|
|
12498
|
-
if (!await shoot(pw, ["test", "--config",
|
|
12580
|
+
if (!await shoot(pw, ["test", "--config", join49(dir, "playwright.config.cjs")], repoDir, ms, signal))
|
|
12499
12581
|
return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
|
|
12500
12582
|
const rels = [];
|
|
12501
12583
|
const walk = (d) => {
|
|
12502
|
-
for (const e of
|
|
12503
|
-
const full =
|
|
12584
|
+
for (const e of readdirSync17(d, { withFileTypes: true })) {
|
|
12585
|
+
const full = join49(d, e.name);
|
|
12504
12586
|
if (e.isDirectory())
|
|
12505
12587
|
walk(full);
|
|
12506
12588
|
else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
|
|
12507
|
-
rels.push(
|
|
12589
|
+
rels.push(join49(relDir, "e2e", relative6(dir, full)));
|
|
12508
12590
|
}
|
|
12509
12591
|
};
|
|
12510
|
-
walk(
|
|
12592
|
+
walk(join49(dir, "out"));
|
|
12511
12593
|
return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
|
|
12512
12594
|
} catch (e) {
|
|
12513
12595
|
return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
|
|
@@ -12586,22 +12668,22 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12586
12668
|
if (!visualEvidenceEnabled(opts.env))
|
|
12587
12669
|
return skip("LOKI_VISUAL_EVIDENCE is 0");
|
|
12588
12670
|
const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
|
|
12589
|
-
const appDir = boot ?
|
|
12590
|
-
const pkgPath =
|
|
12671
|
+
const appDir = boot ? join49(repoDir, boot.boot.cwd) : repoDir;
|
|
12672
|
+
const pkgPath = join49(appDir, "package.json");
|
|
12591
12673
|
let script = null;
|
|
12592
12674
|
if (!boot) {
|
|
12593
|
-
if (!
|
|
12594
|
-
const subs = ["backend", "frontend"].filter((d) =>
|
|
12675
|
+
if (!existsSync29(pkgPath)) {
|
|
12676
|
+
const subs = ["backend", "frontend"].filter((d) => existsSync29(join49(repoDir, d, "package.json")));
|
|
12595
12677
|
const has = (d) => {
|
|
12596
12678
|
try {
|
|
12597
|
-
return pickScript(JSON.parse(
|
|
12679
|
+
return pickScript(JSON.parse(readFileSync38(join49(repoDir, d, "package.json"), "utf8"))) !== null;
|
|
12598
12680
|
} catch {
|
|
12599
12681
|
return false;
|
|
12600
12682
|
}
|
|
12601
12683
|
};
|
|
12602
12684
|
return skip(noRootReason(subs, subs.filter((d) => !has(d))));
|
|
12603
12685
|
}
|
|
12604
|
-
script = pickScript(JSON.parse(
|
|
12686
|
+
script = pickScript(JSON.parse(readFileSync38(pkgPath, "utf8")));
|
|
12605
12687
|
if (!script)
|
|
12606
12688
|
return skip("no dev, preview or start script");
|
|
12607
12689
|
}
|
|
@@ -12628,20 +12710,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12628
12710
|
}
|
|
12629
12711
|
if (!await waitUp(base, left(), signal))
|
|
12630
12712
|
return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
|
|
12631
|
-
const evRoot =
|
|
12713
|
+
const evRoot = join49(runDir, "evidence");
|
|
12632
12714
|
if (isSymlink(evRoot))
|
|
12633
12715
|
return skip("evidence dir is a symlink");
|
|
12634
12716
|
mkdirSync19(evRoot, { recursive: true });
|
|
12635
12717
|
if (pages.length > 0) {
|
|
12636
|
-
const rel0 =
|
|
12637
|
-
mkdirSync19(
|
|
12718
|
+
const rel0 = join49("evidence", randomBytes5(6).toString("hex"));
|
|
12719
|
+
mkdirSync19(join49(runDir, rel0));
|
|
12638
12720
|
const rels = [];
|
|
12639
12721
|
for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
|
|
12640
12722
|
if (aborted() || left() <= 0)
|
|
12641
12723
|
break;
|
|
12642
|
-
const rel =
|
|
12643
|
-
const ok = await shoot(pw, ["screenshot", `${base}${route}`,
|
|
12644
|
-
if (ok && !aborted() && !isSymlink(
|
|
12724
|
+
const rel = join49(rel0, `${screenName(route)}.png`);
|
|
12725
|
+
const ok = await shoot(pw, ["screenshot", `${base}${route}`, join49(runDir, rel)], appDir, left(), signal);
|
|
12726
|
+
if (ok && !aborted() && !isSymlink(join49(runDir, rel)) && existsSync29(join49(runDir, rel)))
|
|
12645
12727
|
rels.push(rel);
|
|
12646
12728
|
}
|
|
12647
12729
|
if (aborted())
|
|
@@ -12666,9 +12748,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12666
12748
|
}
|
|
12667
12749
|
if (aborted())
|
|
12668
12750
|
return skip("aborted");
|
|
12669
|
-
const hdir =
|
|
12751
|
+
const hdir = join49(evRoot, randomBytes5(6).toString("hex"));
|
|
12670
12752
|
mkdirSync19(hdir);
|
|
12671
|
-
writeFileSync22(
|
|
12753
|
+
writeFileSync22(join49(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
|
|
12672
12754
|
`);
|
|
12673
12755
|
return { screens: [], http: true, skipped: null };
|
|
12674
12756
|
} catch (e) {
|
|
@@ -12697,12 +12779,12 @@ function receiptScreensProblem(receiptPath, receipt) {
|
|
|
12697
12779
|
return `visual evidence failed (LOKI_VISUAL_GATE=1): ${receipt["evidence_failed"]}`;
|
|
12698
12780
|
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname17(receiptPath), receipt["evidence_screens"]);
|
|
12699
12781
|
}
|
|
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
|
|
12782
|
+
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) => {
|
|
12783
|
+
const bin = join49(repoDir, "node_modules", ".bin", "playwright");
|
|
12784
|
+
return existsSync29(bin) ? bin : null;
|
|
12703
12785
|
}, playwrightTestPkg = (repoDir) => {
|
|
12704
|
-
const d =
|
|
12705
|
-
return
|
|
12786
|
+
const d = join49(repoDir, "node_modules", "@playwright", "test");
|
|
12787
|
+
return existsSync29(join49(d, "package.json")) ? d : null;
|
|
12706
12788
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
12707
12789
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
12708
12790
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -12745,7 +12827,7 @@ var init_outbox = __esm(() => {
|
|
|
12745
12827
|
});
|
|
12746
12828
|
|
|
12747
12829
|
// ../../loki-ts/src/engine10/stages/pr.ts
|
|
12748
|
-
import { join as
|
|
12830
|
+
import { join as join50 } from "path";
|
|
12749
12831
|
var DEFAULT_PUSH_SH;
|
|
12750
12832
|
var init_pr = __esm(() => {
|
|
12751
12833
|
init_types();
|
|
@@ -12762,19 +12844,19 @@ var init_pr = __esm(() => {
|
|
|
12762
12844
|
init_run_outputs();
|
|
12763
12845
|
init_yaml_key();
|
|
12764
12846
|
init_outbox();
|
|
12765
|
-
DEFAULT_PUSH_SH =
|
|
12847
|
+
DEFAULT_PUSH_SH = join50(REPO_ROOT, "autonomy/lib/engine10-push.sh");
|
|
12766
12848
|
});
|
|
12767
12849
|
|
|
12768
12850
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
12769
|
-
import { existsSync as
|
|
12770
|
-
import { dirname as dirname18, join as
|
|
12851
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync20, mkdtempSync as mkdtempSync7, readFileSync as readFileSync39, rmSync as rmSync15, writeFileSync as writeFileSync23 } from "fs";
|
|
12852
|
+
import { dirname as dirname18, join as join51 } from "path";
|
|
12771
12853
|
import { createHash as createHash15 } from "crypto";
|
|
12772
12854
|
function loadLessons(repoDir) {
|
|
12773
12855
|
const p = lessonsPath(repoDir);
|
|
12774
|
-
if (!
|
|
12856
|
+
if (!existsSync30(p))
|
|
12775
12857
|
return [];
|
|
12776
12858
|
try {
|
|
12777
|
-
const j = JSON.parse(
|
|
12859
|
+
const j = JSON.parse(readFileSync39(p, "utf-8"));
|
|
12778
12860
|
return Array.isArray(j.lessons) ? j.lessons : [];
|
|
12779
12861
|
} catch {
|
|
12780
12862
|
return [];
|
|
@@ -12816,7 +12898,7 @@ function recordRunVerdict(repoDir, runId, verdict) {
|
|
|
12816
12898
|
if (dirty)
|
|
12817
12899
|
save(repoDir, lessons);
|
|
12818
12900
|
}
|
|
12819
|
-
var lessonsPath = (repoDir) =>
|
|
12901
|
+
var lessonsPath = (repoDir) => join51(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
|
|
12820
12902
|
var init_pr_lessons = __esm(() => {
|
|
12821
12903
|
init_atomic();
|
|
12822
12904
|
init_safe_git();
|
|
@@ -12848,7 +12930,7 @@ var init_attempts = __esm(() => {
|
|
|
12848
12930
|
var init_mcp_config = () => {};
|
|
12849
12931
|
|
|
12850
12932
|
// ../../loki-ts/src/providers/claude_flags.ts
|
|
12851
|
-
import { existsSync as
|
|
12933
|
+
import { existsSync as existsSync31, readFileSync as readFileSync40 } from "fs";
|
|
12852
12934
|
import { resolve as resolvePath, dirname as dirname19 } from "path";
|
|
12853
12935
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12854
12936
|
function claudeFlagSupported(flag, helpText) {
|
|
@@ -12902,8 +12984,8 @@ function designArchetypesText() {
|
|
|
12902
12984
|
["..", "..", "references", "design-archetypes.md"]
|
|
12903
12985
|
]) {
|
|
12904
12986
|
const p = resolvePath(moduleDir, ...rel);
|
|
12905
|
-
if (
|
|
12906
|
-
return
|
|
12987
|
+
if (existsSync31(p))
|
|
12988
|
+
return readFileSync40(p, "utf8");
|
|
12907
12989
|
}
|
|
12908
12990
|
} catch {}
|
|
12909
12991
|
return "";
|
|
@@ -12987,14 +13069,14 @@ var init_providers = __esm(() => {
|
|
|
12987
13069
|
});
|
|
12988
13070
|
|
|
12989
13071
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
12990
|
-
import { existsSync as
|
|
12991
|
-
import { join as
|
|
13072
|
+
import { existsSync as existsSync32, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
|
|
13073
|
+
import { join as join52 } from "path";
|
|
12992
13074
|
function loadRouteRecord(runDir) {
|
|
12993
13075
|
try {
|
|
12994
|
-
const p =
|
|
12995
|
-
if (!
|
|
13076
|
+
const p = join52(runDir, ROUTE_RECORD_FILE);
|
|
13077
|
+
if (!existsSync32(p) || !lstatSync11(p).isFile())
|
|
12996
13078
|
return;
|
|
12997
|
-
const v = JSON.parse(
|
|
13079
|
+
const v = JSON.parse(readFileSync41(p, "utf8"));
|
|
12998
13080
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
|
|
12999
13081
|
} catch {
|
|
13000
13082
|
return;
|
|
@@ -13015,6 +13097,7 @@ var init_plan_route = __esm(() => {
|
|
|
13015
13097
|
|
|
13016
13098
|
// ../../loki-ts/src/engine10/stages/plan.ts
|
|
13017
13099
|
var init_plan = __esm(() => {
|
|
13100
|
+
init_relevant_files();
|
|
13018
13101
|
init_session();
|
|
13019
13102
|
init_sizing();
|
|
13020
13103
|
init_lean_prefix();
|
|
@@ -13121,7 +13204,7 @@ var init_worker = __esm(() => {
|
|
|
13121
13204
|
});
|
|
13122
13205
|
|
|
13123
13206
|
// ../../loki-ts/src/project_model/package_suite.ts
|
|
13124
|
-
import { join as
|
|
13207
|
+
import { join as join53 } from "path";
|
|
13125
13208
|
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
13126
13209
|
const api = loadProjectApi(repoDir);
|
|
13127
13210
|
if (!isMultiRoot(api))
|
|
@@ -13132,7 +13215,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13132
13215
|
for (const pkg of withTests) {
|
|
13133
13216
|
const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
|
|
13134
13217
|
const started = Date.now();
|
|
13135
|
-
const r = await run(["bash", "-c", tc.cmd], { cwd:
|
|
13218
|
+
const r = await run(["bash", "-c", tc.cmd], { cwd: join53(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
13136
13219
|
const duration_s = (Date.now() - started) / 1000;
|
|
13137
13220
|
if (signal.aborted) {
|
|
13138
13221
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
@@ -13141,7 +13224,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13141
13224
|
}
|
|
13142
13225
|
const out2 = `${r.stdout}
|
|
13143
13226
|
${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:
|
|
13227
|
+
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
13228
|
if (lr) {
|
|
13146
13229
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
13147
13230
|
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
@@ -13175,14 +13258,14 @@ __export(exports_deep, {
|
|
|
13175
13258
|
DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
|
|
13176
13259
|
DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH2
|
|
13177
13260
|
});
|
|
13178
|
-
import { existsSync as
|
|
13261
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync8, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "fs";
|
|
13179
13262
|
import { tmpdir as tmpdir9 } from "os";
|
|
13180
|
-
import { join as
|
|
13263
|
+
import { join as join54 } from "path";
|
|
13181
13264
|
function sessionCouncil(sessions) {
|
|
13182
13265
|
return { async run(input, signal) {
|
|
13183
|
-
const cwd = mkdtempSync8(
|
|
13266
|
+
const cwd = mkdtempSync8(join54(tmpdir9(), "loki-deep-council-"));
|
|
13184
13267
|
try {
|
|
13185
|
-
writeFileSync25(
|
|
13268
|
+
writeFileSync25(join54(cwd, "diff.patch"), input.diff, "utf8");
|
|
13186
13269
|
const r = await sessions.run({
|
|
13187
13270
|
stage: "deep",
|
|
13188
13271
|
tier: "development",
|
|
@@ -13292,7 +13375,7 @@ async function runCouncilCheck(ctx, changed, baseSha, signal, opts, checks, notP
|
|
|
13292
13375
|
async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
13293
13376
|
const scriptPath = opts.secretScanShPath ?? DEFAULT_SECRET_SCAN_SH;
|
|
13294
13377
|
const name = "security scan";
|
|
13295
|
-
if (!
|
|
13378
|
+
if (!existsSync33(scriptPath)) {
|
|
13296
13379
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: 0 });
|
|
13297
13380
|
notProven.add(`not run: ${name} (secret-scan.sh not found)`);
|
|
13298
13381
|
return;
|
|
@@ -13303,7 +13386,7 @@ async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
|
13303
13386
|
}
|
|
13304
13387
|
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
13388
|
const started = Date.now();
|
|
13306
|
-
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) =>
|
|
13389
|
+
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) => join54(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
|
|
13307
13390
|
const durationS = (Date.now() - started) / 1000;
|
|
13308
13391
|
if (r.exitCode === 3) {
|
|
13309
13392
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: durationS });
|
|
@@ -13338,7 +13421,7 @@ async function postResults(ctx, opts, checks, notProven, statusState) {
|
|
|
13338
13421
|
const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
|
|
13339
13422
|
if (prNumber) {
|
|
13340
13423
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13341
|
-
const bodyFile =
|
|
13424
|
+
const bodyFile = join54(ctx.runDir, "deep-comment.md");
|
|
13342
13425
|
writeFileSync25(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
|
|
13343
13426
|
const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
|
|
13344
13427
|
if (commentResult.exitCode !== 0)
|
|
@@ -13392,7 +13475,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
13392
13475
|
const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
|
|
13393
13476
|
const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
13394
13477
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13395
|
-
writeFileSync25(
|
|
13478
|
+
writeFileSync25(join54(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
|
|
13396
13479
|
`);
|
|
13397
13480
|
const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
|
|
13398
13481
|
const allNotProven = [...notProvenList, ...pushNotProven];
|
|
@@ -13436,20 +13519,20 @@ var init_deep = __esm(() => {
|
|
|
13436
13519
|
});
|
|
13437
13520
|
|
|
13438
13521
|
// ../../loki-ts/src/engine10/stages/verify.ts
|
|
13439
|
-
import { existsSync as
|
|
13522
|
+
import { existsSync as existsSync34, mkdtempSync as mkdtempSync9, realpathSync as realpathSync19, rmSync as rmSync17 } from "fs";
|
|
13440
13523
|
import { tmpdir as tmpdir10 } from "os";
|
|
13441
|
-
import { dirname as dirname20, isAbsolute as
|
|
13524
|
+
import { dirname as dirname20, isAbsolute as isAbsolute8, join as join55, relative as relative7 } from "path";
|
|
13442
13525
|
function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
13443
13526
|
const inRepo = (p) => {
|
|
13444
13527
|
try {
|
|
13445
|
-
const r =
|
|
13446
|
-
return r !== "" && !r.startsWith("..") && !
|
|
13528
|
+
const r = relative7(realpathSync19(repoDir), realpathSync19(p));
|
|
13529
|
+
return r !== "" && !r.startsWith("..") && !isAbsolute8(r);
|
|
13447
13530
|
} catch {
|
|
13448
13531
|
return false;
|
|
13449
13532
|
}
|
|
13450
13533
|
};
|
|
13451
13534
|
const venvEnv = process.env["VIRTUAL_ENV"];
|
|
13452
|
-
const project = [
|
|
13535
|
+
const project = [join55(repoDir, ".venv", "bin", bin), join55(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join55(venvEnv, "bin", bin)] : []].find(existsSync34);
|
|
13453
13536
|
return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
|
|
13454
13537
|
}
|
|
13455
13538
|
function runnerCmd(t, repoDir) {
|
|
@@ -13564,7 +13647,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13564
13647
|
const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
|
|
13565
13648
|
if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
|
|
13566
13649
|
return out2;
|
|
13567
|
-
const dir = mkdtempSync9(
|
|
13650
|
+
const dir = mkdtempSync9(join55(tmpdir10(), "e10-base-"));
|
|
13568
13651
|
const git3 = (args) => {
|
|
13569
13652
|
safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
|
|
13570
13653
|
};
|
|
@@ -13602,7 +13685,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13602
13685
|
return out2;
|
|
13603
13686
|
}
|
|
13604
13687
|
function isLokiModeRepo(repoDir) {
|
|
13605
|
-
return
|
|
13688
|
+
return existsSync34(join55(repoDir, "scripts", "select-tests.sh"));
|
|
13606
13689
|
}
|
|
13607
13690
|
async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
13608
13691
|
const { api, ...runOpts } = opts;
|
|
@@ -13624,9 +13707,9 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
|
13624
13707
|
}
|
|
13625
13708
|
for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
|
|
13626
13709
|
const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
|
|
13627
|
-
if (
|
|
13710
|
+
if (existsSync34(join55(g.cwd, "tsconfig.json")))
|
|
13628
13711
|
await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
|
|
13629
|
-
if (ESLINT_CONFIGS.some((f) =>
|
|
13712
|
+
if (ESLINT_CONFIGS.some((f) => existsSync34(join55(g.cwd, f)))) {
|
|
13630
13713
|
const c = await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
|
|
13631
13714
|
if (await excuseLint(ctx, signal, c, "eslint", "npx", ["eslint"], g.cwd, g.rel, co))
|
|
13632
13715
|
pre.push(c.name);
|
|
@@ -13641,7 +13724,7 @@ var CHECK_TIMEOUT_MS = 60000, excerpts, isHold = (c) => isHoldoutCheck(c.name),
|
|
|
13641
13724
|
return r.missing || r.cut ? null : r;
|
|
13642
13725
|
}, base: (f) => {
|
|
13643
13726
|
try {
|
|
13644
|
-
return safeGit(ctx.repoDir, ["show", `${ctx.baseSha}:${
|
|
13727
|
+
return safeGit(ctx.repoDir, ["show", `${ctx.baseSha}:${relative7(ctx.repoDir, join55(cwd, f))}`], { stdio: ["ignore", "pipe", "ignore"] });
|
|
13645
13728
|
} catch {
|
|
13646
13729
|
return null;
|
|
13647
13730
|
}
|
|
@@ -13700,7 +13783,7 @@ var init_verify = __esm(() => {
|
|
|
13700
13783
|
const impacted = ctx.tests.impacted(map, changed);
|
|
13701
13784
|
const changedTestFiles = map.tests.filter((t) => changed.includes(t.path));
|
|
13702
13785
|
const wall = ctx.outputs().wall ?? {};
|
|
13703
|
-
const wallPaths = new Set((wall.files ?? []).map((f) =>
|
|
13786
|
+
const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute8(f.path) ? relative7(ctx.repoDir, f.path) : f.path));
|
|
13704
13787
|
const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
|
|
13705
13788
|
const intake = ctx.outputs().intake, relevant2 = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
|
|
13706
13789
|
const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant2]);
|
|
@@ -13806,8 +13889,8 @@ ${x}` : c.cmd };
|
|
|
13806
13889
|
});
|
|
13807
13890
|
|
|
13808
13891
|
// ../../loki-ts/src/project_model/conventions.ts
|
|
13809
|
-
import { existsSync as
|
|
13810
|
-
import { dirname as dirname21, join as
|
|
13892
|
+
import { existsSync as existsSync35, readdirSync as readdirSync18, readFileSync as readFileSync42 } from "fs";
|
|
13893
|
+
import { dirname as dirname21, join as join56 } from "path";
|
|
13811
13894
|
function parseJsonc(text2) {
|
|
13812
13895
|
let out2 = "", i = 0;
|
|
13813
13896
|
while (i < text2.length) {
|
|
@@ -13842,25 +13925,25 @@ function moduleOf(file, depth = 0) {
|
|
|
13842
13925
|
const ext = typeof j.extends === "string" ? j.extends : null;
|
|
13843
13926
|
if (!ext || !ext.startsWith("."))
|
|
13844
13927
|
return null;
|
|
13845
|
-
const next =
|
|
13846
|
-
return
|
|
13928
|
+
const next = join56(dirname21(file), ext.endsWith(".json") ? ext : `${ext}.json`);
|
|
13929
|
+
return existsSync35(next) ? moduleOf(next, depth + 1) : null;
|
|
13847
13930
|
}
|
|
13848
13931
|
function readPackageConventions(pkgDir, runner = null) {
|
|
13849
13932
|
let names = [];
|
|
13850
13933
|
try {
|
|
13851
|
-
names =
|
|
13934
|
+
names = readdirSync18(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
|
|
13852
13935
|
} catch {
|
|
13853
13936
|
return null;
|
|
13854
13937
|
}
|
|
13855
13938
|
let packageType = null, tsModule = null;
|
|
13856
13939
|
for (const n2 of names) {
|
|
13857
|
-
const j = readJson4(
|
|
13940
|
+
const j = readJson4(join56(pkgDir, n2));
|
|
13858
13941
|
if (!j)
|
|
13859
13942
|
continue;
|
|
13860
13943
|
if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
|
|
13861
13944
|
packageType = j.type;
|
|
13862
13945
|
if (tsModule === null && j.compilerOptions !== undefined)
|
|
13863
|
-
tsModule = moduleOf(
|
|
13946
|
+
tsModule = moduleOf(join56(pkgDir, n2));
|
|
13864
13947
|
}
|
|
13865
13948
|
if (packageType === null && tsModule === null)
|
|
13866
13949
|
return null;
|
|
@@ -13882,7 +13965,7 @@ function conventionViolation(c, fileName, content) {
|
|
|
13882
13965
|
}
|
|
13883
13966
|
var readJson4 = (p) => {
|
|
13884
13967
|
try {
|
|
13885
|
-
const v = parseJsonc(
|
|
13968
|
+
const v = parseJsonc(readFileSync42(p, "utf8"));
|
|
13886
13969
|
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
13887
13970
|
} catch {
|
|
13888
13971
|
return null;
|
|
@@ -13892,15 +13975,15 @@ var init_conventions = () => {};
|
|
|
13892
13975
|
|
|
13893
13976
|
// ../../loki-ts/src/engine10/stages/wall.ts
|
|
13894
13977
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
13895
|
-
import { existsSync as
|
|
13978
|
+
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
13979
|
import { tmpdir as tmpdir11 } from "os";
|
|
13897
|
-
import { dirname as dirname22, isAbsolute as
|
|
13980
|
+
import { dirname as dirname22, isAbsolute as isAbsolute9, join as join57, relative as relative8 } from "path";
|
|
13898
13981
|
function pytestCollectionIsRed(output, repoDir) {
|
|
13899
13982
|
if (/ModuleNotFoundError/.test(output))
|
|
13900
13983
|
return false;
|
|
13901
13984
|
const real2 = (p) => {
|
|
13902
13985
|
try {
|
|
13903
|
-
return
|
|
13986
|
+
return realpathSync20(isAbsolute9(p) ? p : join57(repoDir, p));
|
|
13904
13987
|
} catch {
|
|
13905
13988
|
return null;
|
|
13906
13989
|
}
|
|
@@ -13937,7 +14020,7 @@ function pytestCollectionIsRed(output, repoDir) {
|
|
|
13937
14020
|
}
|
|
13938
14021
|
function moduleUnderRepo(repoDir, name) {
|
|
13939
14022
|
const rel = name.replace(/\./g, "/");
|
|
13940
|
-
return
|
|
14023
|
+
return existsSync36(join57(repoDir, `${rel}.py`)) || existsSync36(join57(repoDir, rel, "__init__.py"));
|
|
13941
14024
|
}
|
|
13942
14025
|
function pytestExit1IsRed(output) {
|
|
13943
14026
|
if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
|
|
@@ -14036,10 +14119,10 @@ ${acceptance.map((a) => `Acceptance: ${a}`).join(`
|
|
|
14036
14119
|
function loadTaskText(ctx, fromPrior) {
|
|
14037
14120
|
if (fromPrior)
|
|
14038
14121
|
return fromPrior;
|
|
14039
|
-
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ??
|
|
14040
|
-
if (
|
|
14122
|
+
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join57(ctx.runDir, "issue.json");
|
|
14123
|
+
if (existsSync36(issueJsonPath)) {
|
|
14041
14124
|
try {
|
|
14042
|
-
const issue = JSON.parse(
|
|
14125
|
+
const issue = JSON.parse(readFileSync43(issueJsonPath, "utf8"));
|
|
14043
14126
|
const text2 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
|
|
14044
14127
|
|
|
14045
14128
|
`);
|
|
@@ -14051,7 +14134,7 @@ function loadTaskText(ctx, fromPrior) {
|
|
|
14051
14134
|
}
|
|
14052
14135
|
function wallTargetDir(repoDir, existingTests) {
|
|
14053
14136
|
const first = existingTests[0];
|
|
14054
|
-
return first ?
|
|
14137
|
+
return first ? join57(repoDir, dirname22(first.path)) : join57(repoDir, "tests");
|
|
14055
14138
|
}
|
|
14056
14139
|
function guessRunner(fileName, runners) {
|
|
14057
14140
|
if (fileName.endsWith(".py"))
|
|
@@ -14079,14 +14162,16 @@ async function wallAuthor(ctx, signal) {
|
|
|
14079
14162
|
}
|
|
14080
14163
|
if (testMap && runners.length === 0 && !(repoMap?.files ?? []).some((p) => /\.(py|go)$/.test(p)))
|
|
14081
14164
|
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" });
|
|
14165
|
+
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)
|
|
14166
|
+
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
14167
|
const tree = prior.intake?.tree;
|
|
14083
14168
|
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(
|
|
14169
|
+
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative8(ctx.repoDir, targetDir)}/x`);
|
|
14170
|
+
const conv2 = readPackageConventions(join57(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
|
|
14171
|
+
const cwd = mkdtempSync10(join57(tmpdir11(), "loki-e15-wall-"));
|
|
14087
14172
|
const wm = wallManifestFor(ctx.repoDir, tree, task);
|
|
14088
14173
|
for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
|
|
14089
|
-
writeFileSync26(
|
|
14174
|
+
writeFileSync26(join57(cwd, n2), c, "utf8");
|
|
14090
14175
|
const session = await ctx.sessions.run({
|
|
14091
14176
|
stage: "wall",
|
|
14092
14177
|
brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2), unitSpec()?.acceptance ?? []),
|
|
@@ -14101,15 +14186,15 @@ async function wallAuthor(ctx, signal) {
|
|
|
14101
14186
|
rmSync18(cwd, { recursive: true, force: true });
|
|
14102
14187
|
return done({ status: "failed", data: {}, reason: "wall session aborted, killed, or timed out", killed: true });
|
|
14103
14188
|
}
|
|
14104
|
-
const all =
|
|
14105
|
-
const sealedDir =
|
|
14189
|
+
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));
|
|
14190
|
+
const sealedDir = join57(ctx.runDir, "wall");
|
|
14106
14191
|
if (generated.length > 0)
|
|
14107
14192
|
mkdirSync23(sealedDir, { recursive: true });
|
|
14108
14193
|
const contents = new Map;
|
|
14109
14194
|
const discarded = [];
|
|
14110
14195
|
for (const name of generated) {
|
|
14111
|
-
const content =
|
|
14112
|
-
writeFileSync26(
|
|
14196
|
+
const content = readFileSync43(join57(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
|
|
14197
|
+
writeFileSync26(join57(sealedDir, name), content, "utf8");
|
|
14113
14198
|
if (bad)
|
|
14114
14199
|
discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
|
|
14115
14200
|
else
|
|
@@ -14129,18 +14214,18 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
14129
14214
|
const content = contents.get(name);
|
|
14130
14215
|
if (content === undefined)
|
|
14131
14216
|
continue;
|
|
14132
|
-
const dest =
|
|
14217
|
+
const dest = join57(targetDir, name), runner = guessRunner(name, runners);
|
|
14133
14218
|
writeFileSync26(dest, content, "utf8");
|
|
14134
14219
|
sealedFiles.push({ path: dest, sha256: sha2562(content) });
|
|
14135
14220
|
readOnlyFiles.push({ path: dest, content });
|
|
14136
14221
|
if (runner)
|
|
14137
|
-
wallTests.push({ runner, path:
|
|
14222
|
+
wallTests.push({ runner, path: relative8(ctx.repoDir, dest) });
|
|
14138
14223
|
}
|
|
14139
14224
|
ctx.wallSealed = true;
|
|
14140
14225
|
ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
|
|
14141
14226
|
const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
|
|
14142
14227
|
for (const t of wallTests) {
|
|
14143
|
-
const r = baseRunner.run(baseDir, [t]), abs =
|
|
14228
|
+
const r = baseRunner.run(baseDir, [t]), abs = join57(ctx.repoDir, t.path);
|
|
14144
14229
|
baseRun.pass += r.pass;
|
|
14145
14230
|
baseRun.fail += r.fail;
|
|
14146
14231
|
baseRun.not_run += r.not_run ?? 0;
|
|
@@ -14181,6 +14266,7 @@ var init_wall = __esm(() => {
|
|
|
14181
14266
|
init_seal();
|
|
14182
14267
|
init_holdout();
|
|
14183
14268
|
init_verify();
|
|
14269
|
+
init_testmap();
|
|
14184
14270
|
init_resolve();
|
|
14185
14271
|
init_check_result();
|
|
14186
14272
|
init_conventions();
|
|
@@ -14194,15 +14280,15 @@ var init_wall = __esm(() => {
|
|
|
14194
14280
|
});
|
|
14195
14281
|
|
|
14196
14282
|
// ../../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
|
|
14283
|
+
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";
|
|
14284
|
+
import { dirname as dirname23, join as join58, relative as relative9, sep as sep12 } from "path";
|
|
14199
14285
|
function safeRestore(repoDir, f, want, mode) {
|
|
14200
|
-
const root =
|
|
14286
|
+
const root = realpathSync21(repoDir), fp = join58(root, f), rel = relative9(root, dirname23(fp));
|
|
14201
14287
|
if (rel.startsWith(".."))
|
|
14202
14288
|
throw new Error("outside repo");
|
|
14203
14289
|
let cur = root;
|
|
14204
|
-
for (const part of rel === "" ? [] : rel.split(
|
|
14205
|
-
cur =
|
|
14290
|
+
for (const part of rel === "" ? [] : rel.split(sep12)) {
|
|
14291
|
+
cur = join58(cur, part);
|
|
14206
14292
|
let st2;
|
|
14207
14293
|
try {
|
|
14208
14294
|
st2 = lstatSync12(cur);
|
|
@@ -14219,7 +14305,7 @@ function safeRestore(repoDir, f, want, mode) {
|
|
|
14219
14305
|
} catch {
|
|
14220
14306
|
st = null;
|
|
14221
14307
|
}
|
|
14222
|
-
if (st?.isFile() &&
|
|
14308
|
+
if (st?.isFile() && readFileSync44(fp).equals(want)) {
|
|
14223
14309
|
chmodSync5(fp, mode);
|
|
14224
14310
|
return;
|
|
14225
14311
|
}
|
|
@@ -14257,7 +14343,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14257
14343
|
return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
|
|
14258
14344
|
const notProven = [];
|
|
14259
14345
|
for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
|
|
14260
|
-
const fp =
|
|
14346
|
+
const fp = join58(repoDir, f);
|
|
14261
14347
|
try {
|
|
14262
14348
|
if (v.startsWith("!")) {
|
|
14263
14349
|
const st = lstatSync12(fp);
|
|
@@ -14276,7 +14362,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14276
14362
|
try {
|
|
14277
14363
|
let m = 420;
|
|
14278
14364
|
try {
|
|
14279
|
-
const l = lstatSync12(
|
|
14365
|
+
const l = lstatSync12(join58(repoDir, f));
|
|
14280
14366
|
if (l.isFile())
|
|
14281
14367
|
m = l.mode & 511;
|
|
14282
14368
|
} catch {}
|
|
@@ -14320,7 +14406,7 @@ var init_commit_filter = __esm(() => {
|
|
|
14320
14406
|
});
|
|
14321
14407
|
|
|
14322
14408
|
// ../../loki-ts/src/e10ext/scope.ts
|
|
14323
|
-
import { basename as
|
|
14409
|
+
import { basename as basename21, dirname as dirname25 } from "path";
|
|
14324
14410
|
function contractText(o) {
|
|
14325
14411
|
const c = o.intake?.contract_snapshot?.contract;
|
|
14326
14412
|
return Array.isArray(c?.criteria) ? c.criteria.map((x) => typeof x?.text === "string" ? x.text : "").join(`
|
|
@@ -14335,7 +14421,7 @@ function outsideScope(o, staged) {
|
|
|
14335
14421
|
${typeof o.intake?.task === "string" ? o.intake.task : ""}
|
|
14336
14422
|
${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
|
|
14337
14423
|
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,
|
|
14424
|
+
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
14425
|
}
|
|
14340
14426
|
function flagOutsideScope(o, staged) {
|
|
14341
14427
|
const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
|
|
@@ -14350,14 +14436,14 @@ var init_scope2 = __esm(() => {
|
|
|
14350
14436
|
});
|
|
14351
14437
|
|
|
14352
14438
|
// ../../loki-ts/src/council/role_agents.ts
|
|
14353
|
-
import { existsSync as
|
|
14439
|
+
import { existsSync as existsSync37, readdirSync as readdirSync20, readFileSync as readFileSync45 } from "fs";
|
|
14354
14440
|
import { homedir as homedir9 } from "os";
|
|
14355
|
-
import { join as
|
|
14441
|
+
import { join as join59 } from "path";
|
|
14356
14442
|
function agentDirs(repoDir, env = process.env) {
|
|
14357
|
-
return [env["LOKI_AGENTS_PROJECT_DIR"] ||
|
|
14443
|
+
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
14444
|
}
|
|
14359
14445
|
function parseAgent(file, stem2) {
|
|
14360
|
-
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(
|
|
14446
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync45(file, "utf8"));
|
|
14361
14447
|
if (!m)
|
|
14362
14448
|
return null;
|
|
14363
14449
|
const body = m[2].trim();
|
|
@@ -14371,18 +14457,18 @@ function parseAgent(file, stem2) {
|
|
|
14371
14457
|
}
|
|
14372
14458
|
function loadRoleAgent(repoDir, role, env = process.env) {
|
|
14373
14459
|
for (const d of agentDirs(repoDir, env)) {
|
|
14374
|
-
if (!
|
|
14460
|
+
if (!existsSync37(d))
|
|
14375
14461
|
continue;
|
|
14376
14462
|
let names;
|
|
14377
14463
|
try {
|
|
14378
|
-
names =
|
|
14464
|
+
names = readdirSync20(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
|
|
14379
14465
|
} catch {
|
|
14380
14466
|
continue;
|
|
14381
14467
|
}
|
|
14382
14468
|
const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
|
|
14383
14469
|
for (const n2 of ordered) {
|
|
14384
14470
|
try {
|
|
14385
|
-
const a = parseAgent(
|
|
14471
|
+
const a = parseAgent(join59(d, n2), n2.slice(0, -3));
|
|
14386
14472
|
if (a && a.role === role)
|
|
14387
14473
|
return a;
|
|
14388
14474
|
} catch {}
|
|
@@ -14400,7 +14486,7 @@ var init_role_agents = __esm(() => {
|
|
|
14400
14486
|
|
|
14401
14487
|
// ../../loki-ts/src/util/child_ledger.ts
|
|
14402
14488
|
import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync25 } from "fs";
|
|
14403
|
-
import { join as
|
|
14489
|
+
import { join as join60 } from "path";
|
|
14404
14490
|
function unmeasuredRecord(phase, model, source) {
|
|
14405
14491
|
return { phase, model, input_tokens: 0, output_tokens: 0, cache_creation_tokens: 0, cache_read_tokens: 0, source, cost_status: "unmeasured" };
|
|
14406
14492
|
}
|
|
@@ -14425,9 +14511,9 @@ function recordFromClaudeResult(phase, payload, source = "claude-json") {
|
|
|
14425
14511
|
}
|
|
14426
14512
|
function appendChildLedger(lokiDir2, rec2) {
|
|
14427
14513
|
try {
|
|
14428
|
-
const dir =
|
|
14514
|
+
const dir = join60(lokiDir2, "metrics");
|
|
14429
14515
|
mkdirSync25(dir, { recursive: true });
|
|
14430
|
-
appendFileSync4(
|
|
14516
|
+
appendFileSync4(join60(dir, "child-sessions.jsonl"), `${JSON.stringify(rec2)}
|
|
14431
14517
|
`);
|
|
14432
14518
|
return true;
|
|
14433
14519
|
} catch {
|
|
@@ -14457,14 +14543,14 @@ var init_child_ledger = __esm(() => {
|
|
|
14457
14543
|
});
|
|
14458
14544
|
|
|
14459
14545
|
// ../../loki-ts/src/util/run_summary.ts
|
|
14460
|
-
import { existsSync as
|
|
14461
|
-
import { join as
|
|
14546
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync26, readFileSync as readFileSync46, renameSync as renameSync11, statSync as statSync18, writeFileSync as writeFileSync28 } from "fs";
|
|
14547
|
+
import { join as join61 } from "path";
|
|
14462
14548
|
function readRiskRecord(repoDir, sinceMs = 0) {
|
|
14463
14549
|
try {
|
|
14464
|
-
const p =
|
|
14550
|
+
const p = join61(repoDir, ".loki", "state", "risk-tier.json");
|
|
14465
14551
|
if (statSync18(p).mtimeMs < sinceMs)
|
|
14466
14552
|
return null;
|
|
14467
|
-
const r = JSON.parse(
|
|
14553
|
+
const r = JSON.parse(readFileSync46(p, "utf8"));
|
|
14468
14554
|
return r && typeof r === "object" ? r : null;
|
|
14469
14555
|
} catch {
|
|
14470
14556
|
return null;
|
|
@@ -14478,8 +14564,8 @@ var init_run_summary = __esm(() => {
|
|
|
14478
14564
|
});
|
|
14479
14565
|
|
|
14480
14566
|
// ../../loki-ts/src/engine10/stages/xreview.ts
|
|
14481
|
-
import { existsSync as
|
|
14482
|
-
import { join as
|
|
14567
|
+
import { existsSync as existsSync39, readFileSync as readFileSync47 } from "fs";
|
|
14568
|
+
import { join as join62 } from "path";
|
|
14483
14569
|
function minVerdict(verdict, review) {
|
|
14484
14570
|
const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
|
|
14485
14571
|
return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
|
|
@@ -14492,11 +14578,11 @@ function explicitReview(repoDir, env) {
|
|
|
14492
14578
|
if (flag && isOff(ev))
|
|
14493
14579
|
return "off";
|
|
14494
14580
|
for (const f of ["loki.yaml", "loki.yml"]) {
|
|
14495
|
-
const p =
|
|
14496
|
-
if (!
|
|
14581
|
+
const p = join62(repoDir, f);
|
|
14582
|
+
if (!existsSync39(p))
|
|
14497
14583
|
continue;
|
|
14498
14584
|
try {
|
|
14499
|
-
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(
|
|
14585
|
+
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync47(p, "utf8"));
|
|
14500
14586
|
const v = asProvider(m?.[1]);
|
|
14501
14587
|
if (v)
|
|
14502
14588
|
return v;
|
|
@@ -14578,7 +14664,7 @@ Review ONLY the diff below. Do not modify files.` : "You are an independent code
|
|
|
14578
14664
|
try {
|
|
14579
14665
|
if (p === "claude")
|
|
14580
14666
|
await ensureClaudeHelpCache();
|
|
14581
|
-
const r = await withChildLedger(run,
|
|
14667
|
+
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
14668
|
if (r.exitCode !== 0)
|
|
14583
14669
|
return { provider: p, level: "not_run", notes: [`cross-review not run: ${p} exited ${r.exitCode}`] };
|
|
14584
14670
|
return parseReview(p, r.stdout);
|
|
@@ -14672,8 +14758,8 @@ See also: loki cost --detail (what a run ALREADY spent)
|
|
|
14672
14758
|
});
|
|
14673
14759
|
|
|
14674
14760
|
// ../../loki-ts/src/features/contract.ts
|
|
14675
|
-
import { existsSync as
|
|
14676
|
-
import { dirname as dirname26, join as
|
|
14761
|
+
import { existsSync as existsSync40, lstatSync as lstatSync13, mkdirSync as mkdirSync27, readFileSync as readFileSync48, rmSync as rmSync19, writeFileSync as writeFileSync29 } from "fs";
|
|
14762
|
+
import { dirname as dirname26, join as join63 } from "path";
|
|
14677
14763
|
import { createHash as createHash16 } from "crypto";
|
|
14678
14764
|
function contractEnabled(env = process.env) {
|
|
14679
14765
|
return env["LOKI_CONTRACT"] !== "0";
|
|
@@ -14705,7 +14791,7 @@ function untracedLines(trace) {
|
|
|
14705
14791
|
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
14792
|
}
|
|
14707
14793
|
function contractPath(repoDir) {
|
|
14708
|
-
return
|
|
14794
|
+
return join63(repoDir, ".loki", "contract.json");
|
|
14709
14795
|
}
|
|
14710
14796
|
function readContract(repoDir) {
|
|
14711
14797
|
const p = contractPath(repoDir);
|
|
@@ -14721,7 +14807,7 @@ function readContract(repoDir) {
|
|
|
14721
14807
|
return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
|
|
14722
14808
|
let raw2;
|
|
14723
14809
|
try {
|
|
14724
|
-
raw2 =
|
|
14810
|
+
raw2 = readFileSync48(p);
|
|
14725
14811
|
} catch {
|
|
14726
14812
|
return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
|
|
14727
14813
|
}
|
|
@@ -14790,17 +14876,17 @@ var init_contract = __esm(() => {
|
|
|
14790
14876
|
init_safe_git();
|
|
14791
14877
|
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
14878
|
MAX_CONTRACT_BYTES = 1024 * 1024;
|
|
14793
|
-
REQ_MAP_REL =
|
|
14879
|
+
REQ_MAP_REL = join63(".loki", "state", "requirements-map.json");
|
|
14794
14880
|
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
14881
|
});
|
|
14796
14882
|
|
|
14797
14883
|
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
14798
14884
|
import { createHash as createHash17 } from "crypto";
|
|
14799
|
-
import { existsSync as
|
|
14800
|
-
import { dirname as dirname27, join as
|
|
14885
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync28, readdirSync as readdirSync21, readFileSync as readFileSync49, renameSync as renameSync12, statSync as statSync19, writeFileSync as writeFileSync30 } from "fs";
|
|
14886
|
+
import { dirname as dirname27, join as join64 } from "path";
|
|
14801
14887
|
function sealGroup(runDir, rh) {
|
|
14802
|
-
const manifestPath =
|
|
14803
|
-
if (!
|
|
14888
|
+
const manifestPath = join64(runDir, "group", "manifest.json");
|
|
14889
|
+
if (!existsSync41(manifestPath))
|
|
14804
14890
|
return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
|
|
14805
14891
|
const notProven = [];
|
|
14806
14892
|
let problems = 0;
|
|
@@ -14824,10 +14910,10 @@ function sealGroup(runDir, rh) {
|
|
|
14824
14910
|
return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
|
|
14825
14911
|
seen.add(id);
|
|
14826
14912
|
seenLower.add(id.toLowerCase());
|
|
14827
|
-
const dir =
|
|
14913
|
+
const dir = join64(unitsDir(runDir), id), rp = join64(dir, "receipt.json"), ep = join64(dir, "events.jsonl");
|
|
14828
14914
|
let bytes;
|
|
14829
14915
|
try {
|
|
14830
|
-
bytes =
|
|
14916
|
+
bytes = readFileSync49(rp);
|
|
14831
14917
|
} catch {
|
|
14832
14918
|
return fail(`unit ${id} sub-receipt missing`);
|
|
14833
14919
|
}
|
|
@@ -14844,7 +14930,7 @@ function sealGroup(runDir, rh) {
|
|
|
14844
14930
|
unit_id: id,
|
|
14845
14931
|
sub_receipt_sha256: sha3(bytes),
|
|
14846
14932
|
receipt_sha256: sub["receipt_sha256"],
|
|
14847
|
-
events_file_sha256:
|
|
14933
|
+
events_file_sha256: existsSync41(ep) ? sha3(readFileSync49(ep)) : null,
|
|
14848
14934
|
verdict,
|
|
14849
14935
|
goal: text2(u["goal"], 200),
|
|
14850
14936
|
files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
|
|
@@ -14869,7 +14955,7 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14869
14955
|
const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
|
|
14870
14956
|
const g = receipt["group"];
|
|
14871
14957
|
if (g === undefined)
|
|
14872
|
-
return
|
|
14958
|
+
return existsSync41(join64(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
|
|
14873
14959
|
if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
|
|
14874
14960
|
return bad("group section malformed");
|
|
14875
14961
|
const entries = g["units"];
|
|
@@ -14881,20 +14967,20 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14881
14967
|
return bad("unit directories do not match the receipt (missing or extra unit)");
|
|
14882
14968
|
let unchecked = null;
|
|
14883
14969
|
for (let i = 0;i < entries.length; i++) {
|
|
14884
|
-
const e = entries[i], id = ids[i], dir =
|
|
14970
|
+
const e = entries[i], id = ids[i], dir = join64(unitsDir(runDir), id), rp = join64(dir, "receipt.json"), ep = join64(dir, "events.jsonl");
|
|
14885
14971
|
if (e["index"] !== i)
|
|
14886
14972
|
return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
|
|
14887
14973
|
let bytes;
|
|
14888
14974
|
try {
|
|
14889
14975
|
if (!statSync19(dir).isDirectory())
|
|
14890
14976
|
return bad(`unit ${id} is not a directory`);
|
|
14891
|
-
bytes =
|
|
14977
|
+
bytes = readFileSync49(rp);
|
|
14892
14978
|
} catch {
|
|
14893
14979
|
return bad(`unit ${id} sub-receipt missing`);
|
|
14894
14980
|
}
|
|
14895
14981
|
if (sha3(bytes) !== e["sub_receipt_sha256"])
|
|
14896
14982
|
return bad(`unit ${id} sub-receipt does not match its recorded hash`);
|
|
14897
|
-
const evSha =
|
|
14983
|
+
const evSha = existsSync41(ep) ? sha3(readFileSync49(ep)) : null;
|
|
14898
14984
|
if (evSha !== (e["events_file_sha256"] ?? null))
|
|
14899
14985
|
return bad(`unit ${id} events.jsonl does not match its recorded hash`);
|
|
14900
14986
|
const sub = readJson5(rp);
|
|
@@ -14917,15 +15003,15 @@ function compositeVerdict(childVerdicts) {
|
|
|
14917
15003
|
const failed2 = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
|
|
14918
15004
|
return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed2, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
|
|
14919
15005
|
}
|
|
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) =>
|
|
15006
|
+
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
15007
|
try {
|
|
14922
|
-
return JSON.parse(
|
|
15008
|
+
return JSON.parse(readFileSync49(p, "utf8"));
|
|
14923
15009
|
} catch {
|
|
14924
15010
|
return;
|
|
14925
15011
|
}
|
|
14926
15012
|
}, dirNames = (d) => {
|
|
14927
15013
|
try {
|
|
14928
|
-
return
|
|
15014
|
+
return readdirSync21(d).filter((n3) => !n3.startsWith(".")).sort();
|
|
14929
15015
|
} catch {
|
|
14930
15016
|
return null;
|
|
14931
15017
|
}
|
|
@@ -14937,8 +15023,8 @@ var init_seal_group = __esm(() => {
|
|
|
14937
15023
|
});
|
|
14938
15024
|
|
|
14939
15025
|
// ../../loki-ts/src/supply/supply_guard.ts
|
|
14940
|
-
import { existsSync as
|
|
14941
|
-
import { basename as
|
|
15026
|
+
import { existsSync as existsSync42, readFileSync as readFileSync50, statSync as statSync20 } from "fs";
|
|
15027
|
+
import { basename as basename22, join as join65 } from "path";
|
|
14942
15028
|
function supplyEnabled(env) {
|
|
14943
15029
|
return env["LOKI_SUPPLY_GUARD"] !== "0";
|
|
14944
15030
|
}
|
|
@@ -14950,16 +15036,16 @@ function supplyVerdict(verdict, r) {
|
|
|
14950
15036
|
return r.blocked && verdict === "VERIFIED" ? "FAILED" : verdict;
|
|
14951
15037
|
}
|
|
14952
15038
|
function isManifestPath(path) {
|
|
14953
|
-
return MANIFESTS.test(
|
|
15039
|
+
return MANIFESTS.test(basename22(path));
|
|
14954
15040
|
}
|
|
14955
15041
|
function readDeclared(repoDir) {
|
|
14956
|
-
const p =
|
|
14957
|
-
if (!
|
|
15042
|
+
const p = join65(repoDir, ".loki", DECLARED_FILE);
|
|
15043
|
+
if (!existsSync42(p))
|
|
14958
15044
|
return { deps: [], problem: null };
|
|
14959
15045
|
try {
|
|
14960
15046
|
if (statSync20(p).size > MAX_FILE_BYTES)
|
|
14961
15047
|
return { deps: [], problem: "declaration file too large" };
|
|
14962
|
-
const j = JSON.parse(
|
|
15048
|
+
const j = JSON.parse(readFileSync50(p, "utf8"));
|
|
14963
15049
|
if (!Array.isArray(j))
|
|
14964
15050
|
return { deps: [], problem: "declaration is not a JSON array" };
|
|
14965
15051
|
const deps = [];
|
|
@@ -14979,11 +15065,11 @@ function readDeclared(repoDir) {
|
|
|
14979
15065
|
}
|
|
14980
15066
|
}
|
|
14981
15067
|
function readAllowlist(repoDir) {
|
|
14982
|
-
const p =
|
|
14983
|
-
if (!
|
|
15068
|
+
const p = join65(repoDir, ".loki", "supply-allowlist");
|
|
15069
|
+
if (!existsSync42(p))
|
|
14984
15070
|
return new Set;
|
|
14985
15071
|
try {
|
|
14986
|
-
return new Set(
|
|
15072
|
+
return new Set(readFileSync50(p, "utf8").split(`
|
|
14987
15073
|
`).map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean));
|
|
14988
15074
|
} catch {
|
|
14989
15075
|
return new Set;
|
|
@@ -15024,7 +15110,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15024
15110
|
if (eco === "npm") {
|
|
15025
15111
|
if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
|
|
15026
15112
|
return true;
|
|
15027
|
-
return files(
|
|
15113
|
+
return files(join65(repoDir, ".npmrc"), home ? join65(home, ".npmrc") : "").some((t) => t.split(`
|
|
15028
15114
|
`).some((l) => {
|
|
15029
15115
|
const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
|
|
15030
15116
|
return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
|
|
@@ -15033,7 +15119,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15033
15119
|
if (eco === "pypi") {
|
|
15034
15120
|
if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
|
|
15035
15121
|
return true;
|
|
15036
|
-
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ?
|
|
15122
|
+
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join65(home, ".config", "pip", "pip.conf") : "", home ? join65(home, ".pip", "pip.conf") : "", join65(repoDir, "pip.conf")];
|
|
15037
15123
|
return files(...cfg).some((t) => t.split(`
|
|
15038
15124
|
`).some((l) => {
|
|
15039
15125
|
const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
|
|
@@ -15043,7 +15129,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15043
15129
|
if (eco === "cargo") {
|
|
15044
15130
|
if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
|
|
15045
15131
|
return true;
|
|
15046
|
-
return files(
|
|
15132
|
+
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
15133
|
}
|
|
15048
15134
|
if (eco === "go") {
|
|
15049
15135
|
const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
|
|
@@ -15166,7 +15252,7 @@ var MIN_AGE_DAYS = 7, DECLARED_FILE = "supply-declared.json", MAX_CHECKED = 50,
|
|
|
15166
15252
|
}
|
|
15167
15253
|
}, 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
15254
|
try {
|
|
15169
|
-
return statSync20(p).size <= MAX_FILE_BYTES ?
|
|
15255
|
+
return statSync20(p).size <= MAX_FILE_BYTES ? readFileSync50(p, "utf8") : "";
|
|
15170
15256
|
} catch {
|
|
15171
15257
|
return "";
|
|
15172
15258
|
}
|
|
@@ -15182,8 +15268,8 @@ var init_supply_guard = __esm(() => {
|
|
|
15182
15268
|
|
|
15183
15269
|
// ../../loki-ts/src/engine10/stages/seal.ts
|
|
15184
15270
|
import { createHash as createHash18 } from "crypto";
|
|
15185
|
-
import { existsSync as
|
|
15186
|
-
import { basename as
|
|
15271
|
+
import { existsSync as existsSync43, readdirSync as readdirSync22, mkdirSync as mkdirSync29, readFileSync as readFileSync51, writeFileSync as writeFileSync31 } from "fs";
|
|
15272
|
+
import { basename as basename23, isAbsolute as isAbsolute10, join as join66, relative as relative10 } from "path";
|
|
15187
15273
|
function sanitizeReason(s) {
|
|
15188
15274
|
const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
|
|
15189
15275
|
const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
|
|
@@ -15258,8 +15344,8 @@ function renderReceiptMd(r) {
|
|
|
15258
15344
|
`);
|
|
15259
15345
|
}
|
|
15260
15346
|
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("..") ||
|
|
15347
|
+
const r = relative10(ctx.repoDir, join66(ctx.runDir, "receipt.json"));
|
|
15348
|
+
return r.startsWith("..") || isAbsolute10(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
|
|
15263
15349
|
}, commitStage, sealStage;
|
|
15264
15350
|
var init_seal = __esm(() => {
|
|
15265
15351
|
init_spec_file();
|
|
@@ -15358,6 +15444,8 @@ var init_seal = __esm(() => {
|
|
|
15358
15444
|
}
|
|
15359
15445
|
if (wallNotRun > 0)
|
|
15360
15446
|
notProven.add(`wall base run not_run: ${wallNotRun}`);
|
|
15447
|
+
for (const n3 of strs2(o.wall?.not_proven))
|
|
15448
|
+
notProven.add(n3);
|
|
15361
15449
|
for (const d of Array.isArray(o.wall?.discarded) ? o.wall.discarded : [])
|
|
15362
15450
|
notProven.add(`wall test discarded: ${String(d.file)} (${String(d.reason)})`);
|
|
15363
15451
|
for (const d of Array.isArray(o.wall?.not_run_files) ? o.wall.not_run_files : [])
|
|
@@ -15366,8 +15454,8 @@ var init_seal = __esm(() => {
|
|
|
15366
15454
|
notProven.add(`Wall test not executed: ${wallNotRun} file(s), no reason recorded`);
|
|
15367
15455
|
if (wallNotRun > 0) {
|
|
15368
15456
|
try {
|
|
15369
|
-
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) =>
|
|
15370
|
-
for (const n3 of
|
|
15457
|
+
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename23(String(f.path))));
|
|
15458
|
+
for (const n3 of readdirSync22(join66(ctx.runDir, "wall")).sort())
|
|
15371
15459
|
if (!kept.has(n3))
|
|
15372
15460
|
notProven.add(`wall test discarded: ${n3} (not_run)`);
|
|
15373
15461
|
} catch {}
|
|
@@ -15430,19 +15518,19 @@ var init_seal = __esm(() => {
|
|
|
15430
15518
|
for (const [s, d] of Object.entries(o))
|
|
15431
15519
|
if (typeof d?.duration_s === "number")
|
|
15432
15520
|
stages[s] = d.duration_s;
|
|
15433
|
-
const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(
|
|
15521
|
+
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
15522
|
const iterIds = Object.values(o).flatMap((d) => [...strs2(d?.iteration_ids), ...strs2([d?.iteration_id])]);
|
|
15435
15523
|
if (iterIds.length === 0)
|
|
15436
15524
|
notProven.add("cost not measured (no iteration ids recorded)");
|
|
15437
15525
|
const cost = ctx.cost.read(ctx.repoDir, iterIds);
|
|
15438
15526
|
if (cost.unmetered)
|
|
15439
15527
|
notProven.add("cost unmetered (CLI invoker; recorded as 0)");
|
|
15440
|
-
const eventsPath =
|
|
15528
|
+
const eventsPath = join66(ctx.runDir, "events.jsonl");
|
|
15441
15529
|
const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
|
|
15442
15530
|
const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
|
|
15443
15531
|
if (wallFiles.length > 0 && wallPassed === null)
|
|
15444
15532
|
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(
|
|
15533
|
+
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
15534
|
if (routeBlock)
|
|
15447
15535
|
for (const l of routeNotProven(routeBlock))
|
|
15448
15536
|
notProven.add(l);
|
|
@@ -15484,7 +15572,7 @@ var init_seal = __esm(() => {
|
|
|
15484
15572
|
provider: ctx.provider,
|
|
15485
15573
|
model: ctx.model,
|
|
15486
15574
|
resumed: o.intake?.resumed === true,
|
|
15487
|
-
events_sha256: sha2562(
|
|
15575
|
+
events_sha256: sha2562(existsSync43(eventsPath) ? readFileSync51(eventsPath) : ""),
|
|
15488
15576
|
...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
|
|
15489
15577
|
log_seal: true,
|
|
15490
15578
|
...receiptBlock(process.env, cost.usd, cost.unmetered === true, totalS),
|
|
@@ -15506,10 +15594,10 @@ var init_seal = __esm(() => {
|
|
|
15506
15594
|
}
|
|
15507
15595
|
const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
15508
15596
|
mkdirSync29(ctx.runDir, { recursive: true });
|
|
15509
|
-
const path =
|
|
15597
|
+
const path = join66(ctx.runDir, "receipt.json");
|
|
15510
15598
|
writeFileSync31(path, JSON.stringify(receipt, null, 2) + `
|
|
15511
15599
|
`);
|
|
15512
|
-
writeFileSync31(
|
|
15600
|
+
writeFileSync31(join66(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
|
|
15513
15601
|
recordRun(process.env, ctx.repoDir, ranModel(o.implement, ctx.model, o.fix), verdict, cost.usd, cost.unmetered === true, totalS);
|
|
15514
15602
|
try {
|
|
15515
15603
|
hooks.sealed?.(ctx.runDir, JSON.parse(JSON.stringify(receipt), (_k, v) => v && typeof v === "object" ? Object.freeze(v) : v));
|
|
@@ -15535,7 +15623,7 @@ var init_seal = __esm(() => {
|
|
|
15535
15623
|
|
|
15536
15624
|
// ../../loki-ts/src/features/receipt_dsse.ts
|
|
15537
15625
|
import { createPublicKey as createPublicKey3, sign as sign2, verify as verify3 } from "crypto";
|
|
15538
|
-
import { readFileSync as
|
|
15626
|
+
import { readFileSync as readFileSync52 } from "fs";
|
|
15539
15627
|
function pae(payloadType, body) {
|
|
15540
15628
|
const t = Buffer.from(payloadType, "utf8");
|
|
15541
15629
|
return Buffer.concat([Buffer.from(`DSSEv1 ${t.length} `), t, Buffer.from(` ${body.length} `), body]);
|
|
@@ -15612,7 +15700,7 @@ function verifyDsseReceipt(env, d) {
|
|
|
15612
15700
|
}
|
|
15613
15701
|
function runIdGuard(receiptPath, runId) {
|
|
15614
15702
|
try {
|
|
15615
|
-
return envelopeRunIdProblem(JSON.parse(
|
|
15703
|
+
return envelopeRunIdProblem(JSON.parse(readFileSync52(receiptPath, "utf8")), runId);
|
|
15616
15704
|
} catch {
|
|
15617
15705
|
return null;
|
|
15618
15706
|
}
|
|
@@ -15621,14 +15709,14 @@ var DSSE_PAYLOAD_TYPE = "application/vnd.in-toto+json", STATEMENT_TYPE = "https:
|
|
|
15621
15709
|
var init_receipt_dsse = () => {};
|
|
15622
15710
|
|
|
15623
15711
|
// ../../loki-ts/src/util/composite_seal.ts
|
|
15624
|
-
import { existsSync as
|
|
15625
|
-
import { basename as
|
|
15712
|
+
import { existsSync as existsSync44, readFileSync as readFileSync53 } from "fs";
|
|
15713
|
+
import { basename as basename24, dirname as dirname29, join as join67 } from "path";
|
|
15626
15714
|
function logProblem(runDir, integ) {
|
|
15627
15715
|
if (typeof integ["log_sha256"] !== "string")
|
|
15628
15716
|
return null;
|
|
15629
15717
|
let b;
|
|
15630
15718
|
try {
|
|
15631
|
-
b =
|
|
15719
|
+
b = readFileSync53(join67(runDir, "integration.log"));
|
|
15632
15720
|
} catch {
|
|
15633
15721
|
return "integration.log is missing but integration.json records its hash";
|
|
15634
15722
|
}
|
|
@@ -15651,13 +15739,13 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15651
15739
|
return bad("body malformed");
|
|
15652
15740
|
let ibytes;
|
|
15653
15741
|
try {
|
|
15654
|
-
ibytes =
|
|
15742
|
+
ibytes = readFileSync53(join67(runDir, "integration.json"));
|
|
15655
15743
|
} catch {
|
|
15656
15744
|
return bad("integration.json missing");
|
|
15657
15745
|
}
|
|
15658
15746
|
if (sha3(ibytes) !== receipt["integration_sha256"])
|
|
15659
15747
|
return bad("integration.json does not match its recorded hash");
|
|
15660
|
-
const integ = readJson5(
|
|
15748
|
+
const integ = readJson5(join67(runDir, "integration.json"));
|
|
15661
15749
|
if (!isObj10(integ) || !isObj10(integ["outcomes"]))
|
|
15662
15750
|
return bad("integration.json has no outcomes");
|
|
15663
15751
|
const iprob = integrationProblem(integ);
|
|
@@ -15687,10 +15775,10 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15687
15775
|
return bad(`child ${text2(repo, 80) || "?"} has an invalid receipt path`);
|
|
15688
15776
|
if (outcomes[repo] !== "ok")
|
|
15689
15777
|
return bad(`child ${text2(repo, 80)} did not finish ok in integration.json`);
|
|
15690
|
-
const rp =
|
|
15778
|
+
const rp = join67(runDir, rel);
|
|
15691
15779
|
let bytes;
|
|
15692
15780
|
try {
|
|
15693
|
-
bytes =
|
|
15781
|
+
bytes = readFileSync53(rp);
|
|
15694
15782
|
} catch {
|
|
15695
15783
|
return bad(`child ${repo} receipt missing`);
|
|
15696
15784
|
}
|
|
@@ -15739,8 +15827,8 @@ var init_keys_cmd = __esm(() => {
|
|
|
15739
15827
|
});
|
|
15740
15828
|
|
|
15741
15829
|
// ../../loki-ts/src/engine10/verify_cmd.ts
|
|
15742
|
-
import { existsSync as
|
|
15743
|
-
import { basename as
|
|
15830
|
+
import { existsSync as existsSync45, readFileSync as readFileSync54, renameSync as renameSync13, statSync as statSync22, writeFileSync as writeFileSync32 } from "fs";
|
|
15831
|
+
import { basename as basename25, dirname as dirname30, join as join68 } from "path";
|
|
15744
15832
|
import { createHash as createHash19, createPublicKey as createPublicKey4, verify as verify4 } from "crypto";
|
|
15745
15833
|
function pubFor(kid, given) {
|
|
15746
15834
|
if (given)
|
|
@@ -15748,7 +15836,7 @@ function pubFor(kid, given) {
|
|
|
15748
15836
|
const active = loadSigningKey(false);
|
|
15749
15837
|
const pubs = (process.env["LOKI_RECEIPT_RETIRED_PUBKEYS"] ?? "").split(":").map((f) => f.trim()).filter(Boolean).flatMap((f) => {
|
|
15750
15838
|
try {
|
|
15751
|
-
return [createPublicKey4(
|
|
15839
|
+
return [createPublicKey4(readFileSync54(f))];
|
|
15752
15840
|
} catch {
|
|
15753
15841
|
return [];
|
|
15754
15842
|
}
|
|
@@ -15792,10 +15880,10 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15792
15880
|
const claims = st !== null && typeof st === "object" && Object.keys(st).length > 0;
|
|
15793
15881
|
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
15882
|
}
|
|
15795
|
-
const path =
|
|
15796
|
-
if (!
|
|
15883
|
+
const path = join68(dirname30(receiptPath), "events.jsonl");
|
|
15884
|
+
if (!existsSync45(path))
|
|
15797
15885
|
return "events.jsonl is missing";
|
|
15798
|
-
const raw2 =
|
|
15886
|
+
const raw2 = readFileSync54(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
|
|
15799
15887
|
`).filter((l) => l.trim() !== "");
|
|
15800
15888
|
if (events2.length !== lines2.length || events2.some((e, i) => e.seq !== i))
|
|
15801
15889
|
return "events.jsonl has a forged, edited or missing line";
|
|
@@ -15811,7 +15899,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15811
15899
|
return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
|
|
15812
15900
|
}
|
|
15813
15901
|
function checkLogSeal(receiptPath, hash, kid, given) {
|
|
15814
|
-
const path =
|
|
15902
|
+
const path = join68(dirname30(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
|
|
15815
15903
|
if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
|
|
15816
15904
|
return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
|
|
15817
15905
|
if (done < 0)
|
|
@@ -15819,7 +15907,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15819
15907
|
const seal = events2[done + 1], d = seal?.type === "log.sealed" ? seal.data : null;
|
|
15820
15908
|
if (!d)
|
|
15821
15909
|
return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
|
|
15822
|
-
const lines2 =
|
|
15910
|
+
const lines2 = readFileSync54(path, "utf8").split(`
|
|
15823
15911
|
`).filter((l) => l.trim() !== ""), sha4 = createHash19("sha256").update(lines2.slice(0, done + 1).join(`
|
|
15824
15912
|
`) + `
|
|
15825
15913
|
`).digest("hex");
|
|
@@ -15829,11 +15917,11 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15829
15917
|
return null;
|
|
15830
15918
|
}
|
|
15831
15919
|
async function verifyReceipt(receiptPath, deps = {}) {
|
|
15832
|
-
if (!
|
|
15920
|
+
if (!existsSync45(receiptPath))
|
|
15833
15921
|
return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
|
|
15834
15922
|
let receipt;
|
|
15835
15923
|
try {
|
|
15836
|
-
receipt = JSON.parse((deps.read ?? ((p) =>
|
|
15924
|
+
receipt = JSON.parse((deps.read ?? ((p) => readFileSync54(p, "utf8")))(receiptPath));
|
|
15837
15925
|
} catch {
|
|
15838
15926
|
return { verdict: "UNCHECKED", reasons: ["receipt.json is not valid JSON"] };
|
|
15839
15927
|
}
|
|
@@ -15921,8 +16009,8 @@ var init_verify_cmd = __esm(() => {
|
|
|
15921
16009
|
});
|
|
15922
16010
|
|
|
15923
16011
|
// src/server/app.ts
|
|
15924
|
-
import { existsSync as
|
|
15925
|
-
import { join as
|
|
16012
|
+
import { existsSync as existsSync47, readFileSync as readFileSync57, statSync as statSync23 } from "fs";
|
|
16013
|
+
import { join as join71, resolve as resolve15, sep as sep14 } from "path";
|
|
15926
16014
|
|
|
15927
16015
|
// node_modules/hono/dist/request/constants.js
|
|
15928
16016
|
var GET_MATCH_RESULT = Symbol();
|
|
@@ -26204,9 +26292,9 @@ function mount20(ctx) {
|
|
|
26204
26292
|
}
|
|
26205
26293
|
|
|
26206
26294
|
// src/server/routes/verify.ts
|
|
26207
|
-
import { readFileSync as
|
|
26295
|
+
import { readFileSync as readFileSync55, realpathSync as realpathSync22 } from "fs";
|
|
26208
26296
|
import { createPublicKey as createPublicKey5 } from "crypto";
|
|
26209
|
-
import { join as
|
|
26297
|
+
import { join as join69, sep as sep13 } from "path";
|
|
26210
26298
|
init_verify_cmd();
|
|
26211
26299
|
init_seal();
|
|
26212
26300
|
init_receipt_dsse();
|
|
@@ -26233,15 +26321,15 @@ function mount21(ctx) {
|
|
|
26233
26321
|
return done(404, "receipt not available", "not_found");
|
|
26234
26322
|
let runDir, file;
|
|
26235
26323
|
try {
|
|
26236
|
-
const root =
|
|
26237
|
-
runDir =
|
|
26238
|
-
if (runDir !==
|
|
26324
|
+
const root = realpathSync22(join69(repo.p, ".loki", "runs"));
|
|
26325
|
+
runDir = realpathSync22(join69(root, run2));
|
|
26326
|
+
if (runDir !== join69(root, run2))
|
|
26239
26327
|
return done(404, "receipt not found", "not_found");
|
|
26240
|
-
file =
|
|
26328
|
+
file = realpathSync22(join69(runDir, "receipt.json"));
|
|
26241
26329
|
} catch {
|
|
26242
26330
|
return done(404, "receipt not found", "not_found");
|
|
26243
26331
|
}
|
|
26244
|
-
if (!file.startsWith(runDir +
|
|
26332
|
+
if (!file.startsWith(runDir + sep13))
|
|
26245
26333
|
return done(404, "receipt not found", "not_found");
|
|
26246
26334
|
let integrity, reasons, sha4 = null, outcome = "UNREADABLE";
|
|
26247
26335
|
try {
|
|
@@ -26256,7 +26344,7 @@ function mount21(ctx) {
|
|
|
26256
26344
|
sha4 = r.receiptSha256 ?? null;
|
|
26257
26345
|
}
|
|
26258
26346
|
try {
|
|
26259
|
-
outcome = outcomeOf(JSON.parse(
|
|
26347
|
+
outcome = outcomeOf(JSON.parse(readFileSync55(file, "utf8")));
|
|
26260
26348
|
} catch {
|
|
26261
26349
|
outcome = "UNREADABLE";
|
|
26262
26350
|
}
|
|
@@ -26318,8 +26406,8 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
|
|
|
26318
26406
|
}
|
|
26319
26407
|
|
|
26320
26408
|
// src/server/legacy/shim.ts
|
|
26321
|
-
import { existsSync as
|
|
26322
|
-
import { join as
|
|
26409
|
+
import { existsSync as existsSync46, readFileSync as readFileSync56 } from "fs";
|
|
26410
|
+
import { join as join70 } from "path";
|
|
26323
26411
|
|
|
26324
26412
|
// src/server/legacy/routes.ts
|
|
26325
26413
|
var LEGACY_ROUTES = [
|
|
@@ -26697,10 +26785,10 @@ var logged = new Set;
|
|
|
26697
26785
|
var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
|
|
26698
26786
|
var NOT_SUPPORTED = "not yet supported by the Control Plane";
|
|
26699
26787
|
var repoVersion = () => {
|
|
26700
|
-
for (const f of [
|
|
26788
|
+
for (const f of [join70(import.meta.dir, "../../../../../VERSION")]) {
|
|
26701
26789
|
try {
|
|
26702
|
-
if (
|
|
26703
|
-
return
|
|
26790
|
+
if (existsSync46(f))
|
|
26791
|
+
return readFileSync56(f, "utf8").trim();
|
|
26704
26792
|
} catch {}
|
|
26705
26793
|
}
|
|
26706
26794
|
return "unknown";
|
|
@@ -26882,7 +26970,7 @@ function legacyShim(opts) {
|
|
|
26882
26970
|
|
|
26883
26971
|
// src/server/app.ts
|
|
26884
26972
|
var MAX_BODY2 = 1e6;
|
|
26885
|
-
var defaultUiDir = () => [
|
|
26973
|
+
var defaultUiDir = () => [join71(import.meta.dir, "../../ui/dist"), join71(import.meta.dir, "../ui/dist")].find((d) => existsSync47(join71(d, "index.html")));
|
|
26886
26974
|
function createApp(opts) {
|
|
26887
26975
|
const uiDir = opts.uiDir ?? defaultUiDir();
|
|
26888
26976
|
const { db, sqlite } = openDb(opts.dbPath);
|
|
@@ -26911,10 +26999,10 @@ function createApp(opts) {
|
|
|
26911
26999
|
await next();
|
|
26912
27000
|
});
|
|
26913
27001
|
const readInstalled = () => {
|
|
26914
|
-
for (const f of [process.env.LOKI_VERSION_FILE,
|
|
27002
|
+
for (const f of [process.env.LOKI_VERSION_FILE, join71(import.meta.dir, "../../../../VERSION")]) {
|
|
26915
27003
|
try {
|
|
26916
27004
|
if (f)
|
|
26917
|
-
return
|
|
27005
|
+
return readFileSync57(f, "utf8").trim() || "unknown";
|
|
26918
27006
|
} catch {}
|
|
26919
27007
|
}
|
|
26920
27008
|
return "unknown";
|
|
@@ -27025,11 +27113,11 @@ function createApp(opts) {
|
|
|
27025
27113
|
return c.json({ error: "not found" }, 404);
|
|
27026
27114
|
const root = resolve15(uiDir);
|
|
27027
27115
|
const f = resolve15(root, `.${p}`);
|
|
27028
|
-
if (f.startsWith(root +
|
|
27116
|
+
if (f.startsWith(root + sep14) && existsSync47(f) && statSync23(f).isFile())
|
|
27029
27117
|
return new Response(Bun.file(f));
|
|
27030
27118
|
if (/\.[a-z0-9]+$/i.test(p))
|
|
27031
27119
|
return c.json({ error: "not found" }, 404);
|
|
27032
|
-
return new Response(Bun.file(
|
|
27120
|
+
return new Response(Bun.file(join71(root, "index.html")));
|
|
27033
27121
|
});
|
|
27034
27122
|
return { app, db, close: () => {
|
|
27035
27123
|
clearInterval(reconciler);
|