loki-mode 11.17.34 → 11.17.35
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/proof-generator.py +53 -0
- package/autonomy/loki +171 -14
- package/completions/_loki +1 -0
- package/completions/loki.bash +1 -1
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/BOARD.md +4 -4
- package/docs/v10/DECISIONS.md +8 -0
- package/docs/v10/PROGRESS.md +3 -0
- package/loki-ts/dist/loki.js +927 -927
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +453 -412
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-o3gtaCnU.js → AdminPage-DtJ40-0A.js} +1 -1
- package/web-app/dist/assets/{Avatar-C02t-Irl.js → Avatar-BroDCINh.js} +1 -1
- package/web-app/dist/assets/{Badge-BuN80MKq.js → Badge-BS02diTl.js} +1 -1
- package/web-app/dist/assets/{Button-lPXsKVcs.js → Button-DV7QKQIh.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-8CNxkZSh.js → CockpitPage-_jJB0SSp.js} +1 -1
- package/web-app/dist/assets/{ComparePage-j-XhFiwH.js → ComparePage-9G53m6VG.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-D8nyc_y_.js → ErrorBoundary-BxAWorBT.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-DtTSMxZm.js → EvidenceReceiptPanel-D5_6xbqU.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-Bzmm3gBY.js → GitHubIssuesPanel-D4lz3Q9l.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-Dh6vSHLE.js → GitHubPRsPanel-BDHX9d5m.js} +1 -1
- package/web-app/dist/assets/{HomePage-CKKPOMOg.js → HomePage-DP1R90H7.js} +2 -2
- package/web-app/dist/assets/{LoginPage-49FrYkL9.js → LoginPage-DWMnArZX.js} +1 -1
- package/web-app/dist/assets/{MagicPage-D5psAu69.js → MagicPage-DVvZ-ytQ.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-oQXV5q4J.js → MetricsPage-BM5Zifpz.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-C2hj6k1f.js → NotFoundPage-CYrJ2hCM.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-Bo8ocjwn.js → ProjectPage-C_KU_B2Z.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-QUhbz991.js → ProjectsPage-BKOoyezO.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-6XW8I3LO.js → SettingsPage-D0YIMzR4.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-9CHGu9uW.js → ShowcasePage-AgAwQE4Q.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-gZZK7T45.js → SystemSettingsPage-Cin_takd.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DSlKvZhA.js → TeamsPage-BhpuLv8p.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-BVDR5mF2.js → TemplatesPage-DysLVH1s.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-DnOFdmTG.js → TerminalOutput-BNwZci_n.js} +1 -1
- package/web-app/dist/assets/{activity-D22UFJWA.js → activity-CWziiy0I.js} +1 -1
- package/web-app/dist/assets/{bell-B2Mfgp26.js → bell-DXJj9c93.js} +1 -1
- package/web-app/dist/assets/{bot-CTXo6aac.js → bot-BXjVlRf9.js} +1 -1
- package/web-app/dist/assets/{check-D9kJod1H.js → check-B0m-S8D_.js} +1 -1
- package/web-app/dist/assets/{chevron-left-XI4pnrlY.js → chevron-left-kFvUdte6.js} +1 -1
- package/web-app/dist/assets/{circle-alert-CvS3mi0t.js → circle-alert-CxRoiGmA.js} +1 -1
- package/web-app/dist/assets/{clock-CCgwQ80p.js → clock-BJ39Nl09.js} +1 -1
- package/web-app/dist/assets/{cloud-S-SuEsEp.js → cloud-DK2q56ot.js} +1 -1
- package/web-app/dist/assets/{code-xml-PRnhUKWP.js → code-xml-BQUCyHmu.js} +1 -1
- package/web-app/dist/assets/{database-C_a7H_3N.js → database-CGGMJBY-.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-FDCzdLrB.js → dollar-sign-C6gRmaFY.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-28-hDPSO.js → file-code-corner-Cf25WTZR.js} +1 -1
- package/web-app/dist/assets/{file-plus-c0yygSC8.js → file-plus-D3z0a6s8.js} +1 -1
- package/web-app/dist/assets/{globe-DOA9Y_1n.js → globe-Ft1PAFtm.js} +1 -1
- package/web-app/dist/assets/{hammer-Omzy4vB3.js → hammer-uSNPcG6-.js} +1 -1
- package/web-app/dist/assets/{index-Dp6emuTo.js → index-CVdTpox_.js} +3 -3
- package/web-app/dist/assets/{layers-D7ZjWXJQ.js → layers-Dc50swfm.js} +1 -1
- package/web-app/dist/assets/{loader-circle-CJ2SKm0h.js → loader-circle-VEyejUbH.js} +1 -1
- package/web-app/dist/assets/{lock-HKmv1nIN.js → lock-DjSnxn6I.js} +1 -1
- package/web-app/dist/assets/{package-FQl71HNO.js → package-DZoaxJbK.js} +1 -1
- package/web-app/dist/assets/{plus-DY8mlU6I.js → plus-CfEwV_6v.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-CJ_pkRQQ.js → refresh-cw-8UjV3w0I.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-rGU_udZ1.js → rotate-ccw-Br7s9zAf.js} +1 -1
- package/web-app/dist/assets/{scroll-text-CeVAfOXM.js → scroll-text-CuAQTRV9.js} +1 -1
- package/web-app/dist/assets/{server-D-N_u9OT.js → server-BDj53pad.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CJfx3HCX.js → shield-alert-Yq8Exf7A.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BrC-E9mS.js → thumbs-up-DbolTUui.js} +1 -1
- package/web-app/dist/assets/{trash-2-Bb3mW1oq.js → trash-2-Band0V5Q.js} +1 -1
- package/web-app/dist/assets/{trending-down-CrgUJZLA.js → trending-down-tVJY7vOw.js} +1 -1
- package/web-app/dist/assets/{trending-up-Dk_GS57K.js → trending-up-DzJ3qeYe.js} +1 -1
- package/web-app/dist/assets/{upload-BAxHyFqH.js → upload-kvP9eEgy.js} +1 -1
- package/web-app/dist/assets/{usePolling-CkTdc2YU.js → usePolling-CBydUyUd.js} +1 -1
- package/web-app/dist/assets/{user-Dr6XCReg.js → user-CglUAW3P.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/web-app/server.py +164 -132
|
@@ -10877,6 +10877,21 @@ async function run(argv, opts = {}) {
|
|
|
10877
10877
|
clearTimeout(killTimer);
|
|
10878
10878
|
}
|
|
10879
10879
|
}
|
|
10880
|
+
async function commandExists(name) {
|
|
10881
|
+
const safe = shEscape(name);
|
|
10882
|
+
const r = await run(["sh", "-c", `command -v ${safe}`], { timeoutMs: 5000 });
|
|
10883
|
+
if (r.exitCode === 0) {
|
|
10884
|
+
const path = r.stdout.trim();
|
|
10885
|
+
return path || null;
|
|
10886
|
+
}
|
|
10887
|
+
return null;
|
|
10888
|
+
}
|
|
10889
|
+
function shEscape(name) {
|
|
10890
|
+
if (!/^[A-Za-z0-9._/-]+$/.test(name)) {
|
|
10891
|
+
throw new Error(`refused to shell-escape suspect token: ${name}`);
|
|
10892
|
+
}
|
|
10893
|
+
return name;
|
|
10894
|
+
}
|
|
10880
10895
|
var MAX_STDOUT_BYTES;
|
|
10881
10896
|
var init_shell = __esm(() => {
|
|
10882
10897
|
MAX_STDOUT_BYTES = 16 * 1024 * 1024;
|
|
@@ -10886,6 +10901,23 @@ var init_shell = __esm(() => {
|
|
|
10886
10901
|
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";
|
|
10887
10902
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10888
10903
|
import { tmpdir as tmpdir5 } from "os";
|
|
10904
|
+
async function findPython3() {
|
|
10905
|
+
if (_pythonCache !== undefined)
|
|
10906
|
+
return _pythonCache;
|
|
10907
|
+
const homebrew = "/opt/homebrew/bin/python3.12";
|
|
10908
|
+
if (existsSync26(homebrew)) {
|
|
10909
|
+
_pythonCache = homebrew;
|
|
10910
|
+
return homebrew;
|
|
10911
|
+
}
|
|
10912
|
+
const py312 = await commandExists("python3.12");
|
|
10913
|
+
if (py312) {
|
|
10914
|
+
_pythonCache = py312;
|
|
10915
|
+
return py312;
|
|
10916
|
+
}
|
|
10917
|
+
const py3 = await commandExists("python3");
|
|
10918
|
+
_pythonCache = py3;
|
|
10919
|
+
return py3;
|
|
10920
|
+
}
|
|
10889
10921
|
function resolvePython3() {
|
|
10890
10922
|
for (const dir of (process.env.PATH ?? "").split(":")) {
|
|
10891
10923
|
if (!dir || !dir.startsWith("/"))
|
|
@@ -10922,7 +10954,7 @@ function pySignatures(src) {
|
|
|
10922
10954
|
return [];
|
|
10923
10955
|
}
|
|
10924
10956
|
}
|
|
10925
|
-
var PY_TIMEOUT_MS = 5000, PY_SCRIPT = `
|
|
10957
|
+
var _pythonCache, PY_TIMEOUT_MS = 5000, PY_SCRIPT = `
|
|
10926
10958
|
import ast, sys, json, re
|
|
10927
10959
|
def u(n): return ast.unparse(n)
|
|
10928
10960
|
def chain(n):
|
|
@@ -12232,176 +12264,162 @@ var init_wall_owned = __esm(() => {
|
|
|
12232
12264
|
ANSI2 = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
12233
12265
|
});
|
|
12234
12266
|
|
|
12235
|
-
// ../../loki-ts/src/
|
|
12236
|
-
import {
|
|
12237
|
-
import {
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
readFileSync as readFileSync37,
|
|
12241
|
-
statSync as statSync17,
|
|
12242
|
-
writeFileSync as writeFileSync21,
|
|
12243
|
-
mkdirSync as mkdirSync18
|
|
12244
|
-
} from "fs";
|
|
12245
|
-
import { basename as basename19, dirname as dirname16, join as join48, resolve as resolve14 } from "path";
|
|
12246
|
-
function readManifest(path) {
|
|
12247
|
-
if (!existsSync28(path)) {
|
|
12248
|
-
return null;
|
|
12249
|
-
}
|
|
12250
|
-
let raw2;
|
|
12251
|
-
try {
|
|
12252
|
-
raw2 = readFileSync37(path, "utf8");
|
|
12253
|
-
} catch {
|
|
12254
|
-
return null;
|
|
12255
|
-
}
|
|
12256
|
-
let parsed;
|
|
12267
|
+
// ../../loki-ts/src/util/app_probe.ts
|
|
12268
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
12269
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync18, readFileSync as readFileSync37, renameSync as renameSync11, writeFileSync as writeFileSync21 } from "fs";
|
|
12270
|
+
import { join as join48 } from "path";
|
|
12271
|
+
function readJson4(p) {
|
|
12257
12272
|
try {
|
|
12258
|
-
|
|
12273
|
+
const v = JSON.parse(readFileSync37(p, "utf8"));
|
|
12274
|
+
return v && typeof v === "object" ? v : null;
|
|
12259
12275
|
} catch {
|
|
12260
12276
|
return null;
|
|
12261
12277
|
}
|
|
12262
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
12263
|
-
return null;
|
|
12264
|
-
}
|
|
12265
|
-
const obj = parsed;
|
|
12266
|
-
if (obj["schema_version"] !== SUPPORTED_SCHEMA_VERSION) {
|
|
12267
|
-
console.warn(`[loki:project_graph] unsupported schema_version in ${path}: ` + `${String(obj["schema_version"])} (expected ${SUPPORTED_SCHEMA_VERSION})`);
|
|
12268
|
-
return null;
|
|
12269
|
-
}
|
|
12270
|
-
const appId = obj["app_id"];
|
|
12271
|
-
if (typeof appId !== "string" || !APP_ID_REGEX.test(appId)) {
|
|
12272
|
-
console.warn(`[loki:project_graph] invalid app_id in ${path}: ${String(appId)}`);
|
|
12273
|
-
return null;
|
|
12274
|
-
}
|
|
12275
|
-
const members = Array.isArray(obj["members"]) ? obj["members"].filter((m) => typeof m === "string") : [];
|
|
12276
|
-
const sharedMemoryDir = typeof obj["shared_memory_dir"] === "string" ? obj["shared_memory_dir"] : undefined;
|
|
12277
|
-
return {
|
|
12278
|
-
schema_version: SUPPORTED_SCHEMA_VERSION,
|
|
12279
|
-
app_id: appId,
|
|
12280
|
-
members,
|
|
12281
|
-
shared_memory_dir: sharedMemoryDir
|
|
12282
|
-
};
|
|
12283
12278
|
}
|
|
12284
|
-
function
|
|
12285
|
-
const
|
|
12286
|
-
|
|
12287
|
-
|
|
12279
|
+
function stopApp(repoDir, opts = {}) {
|
|
12280
|
+
const runner = opts.runnerPath ?? join48(REPO_ROOT, "autonomy", "app-runner.sh");
|
|
12281
|
+
if (!existsSync28(runner) || !existsSync28(join48(repoDir, ".loki", "app-runner", "app.pid")))
|
|
12282
|
+
return;
|
|
12283
|
+
spawnSync4("bash", ["-c", STOP, "app-probe", repoDir, runner], { cwd: repoDir, env: plainTestEnv(), timeout: opts.timeoutMs ?? 60000, killSignal: "SIGKILL", stdio: "ignore" });
|
|
12284
|
+
}
|
|
12285
|
+
async function appProbe(repoDir, lokiDir2, opts = {}) {
|
|
12286
|
+
const timeoutMs = opts.timeoutMs ?? 60000, runner = opts.runnerPath ?? join48(REPO_ROOT, "autonomy", "app-runner.sh");
|
|
12287
|
+
const dir = join48(repoDir, ".loki", "app-runner"), checks = [];
|
|
12288
|
+
const t0 = Date.now();
|
|
12289
|
+
const mk2 = (name, result, reason) => ({ name, cmd: "autonomy/app-runner.sh", result, duration_s: (Date.now() - t0) / 1000, reason });
|
|
12290
|
+
const sh = (script) => {
|
|
12291
|
+
const r = spawnSync4("bash", ["-c", script, "app-probe", repoDir, runner], { cwd: repoDir, env: { ...plainTestEnv(), ...opts.env ?? {} }, encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", stdio: ["ignore", "pipe", "ignore"] });
|
|
12292
|
+
return { out: r.stdout ?? "", status: r.error ? null : r.status };
|
|
12293
|
+
};
|
|
12294
|
+
let pid = null, url = null;
|
|
12295
|
+
if (!existsSync28(runner))
|
|
12296
|
+
return { checks: [mk2("app boot", "not_run", "app-runner.sh not found"), mk2("http probe", "not_run", "app not booted")], pid, url };
|
|
12288
12297
|
try {
|
|
12289
|
-
|
|
12298
|
+
const b = sh(BOOT);
|
|
12299
|
+
const m = b.out.match(/__APP_PROBE__ (-?\d+) (-?\d+) (-?\d+)/);
|
|
12300
|
+
if (!m) {
|
|
12301
|
+
checks.push(mk2("app boot", "not_run", b.status === null ? "bash unavailable or boot timed out" : "app-runner did not report"), mk2("http probe", "not_run", "app not booted"));
|
|
12302
|
+
return { checks, pid, url };
|
|
12303
|
+
}
|
|
12304
|
+
const ir = Number(m[1]), sr = Number(m[2]), hr = Number(m[3]);
|
|
12305
|
+
const pidTxt = existsSync28(join48(dir, "app.pid")) ? readFileSync37(join48(dir, "app.pid"), "utf8").trim() : "";
|
|
12306
|
+
pid = /^\d+$/.test(pidTxt) && sr >= 0 ? Number(pidTxt) : null;
|
|
12307
|
+
const st = readJson4(join48(dir, "state.json"));
|
|
12308
|
+
url = typeof st?.["url"] === "string" ? st["url"] : null;
|
|
12309
|
+
if (sr < 0) {
|
|
12310
|
+
checks.push(mk2("app boot", "not_run", ir === 0 ? "app-runner detected no app" : "no runnable app detected or runtime missing"), mk2("http probe", "not_run", "app not booted"));
|
|
12311
|
+
return { checks, pid, url };
|
|
12312
|
+
}
|
|
12313
|
+
if (sr !== 0) {
|
|
12314
|
+
checks.push(mk2("app boot", "fail", "app start command failed or exited"), mk2("http probe", "not_run", "app not booted"));
|
|
12315
|
+
return { checks, pid, url };
|
|
12316
|
+
}
|
|
12317
|
+
checks.push(mk2("app boot", "pass", "app process started"));
|
|
12318
|
+
const health = readJson4(join48(dir, "health.json"));
|
|
12319
|
+
checks.push(hr === 0 && health?.["ok"] === true ? mk2("http probe", "pass", "health.json ok") : mk2("http probe", "fail", "app-runner health check failed"));
|
|
12320
|
+
if (opts.specText !== undefined && checks[1]?.result === "pass" && url)
|
|
12321
|
+
checks.push(await functionalVerify(opts, url, dir, lokiDir2, timeoutMs));
|
|
12322
|
+
return { checks, pid, url };
|
|
12323
|
+
} finally {
|
|
12324
|
+
if (!opts.skipStop)
|
|
12325
|
+
stopApp(repoDir, { runnerPath: runner, timeoutMs });
|
|
12326
|
+
}
|
|
12327
|
+
}
|
|
12328
|
+
async function functionalVerify(opts, url, dir, lokiDir2, timeoutMs) {
|
|
12329
|
+
const t0 = Date.now();
|
|
12330
|
+
const res = (result, reason) => ({ name: "functional verify", cmd: "autonomy/lib/functional-verify.py", result, duration_s: (Date.now() - t0) / 1000, reason });
|
|
12331
|
+
const py = await findPython3(), script = opts.verifyPath ?? join48(REPO_ROOT, "autonomy", "lib", "functional-verify.py");
|
|
12332
|
+
if (!py || !existsSync28(script))
|
|
12333
|
+
return res("not_run", "python3 or functional-verify.py unavailable");
|
|
12334
|
+
const specFile = join48(dir, "spec.txt");
|
|
12335
|
+
writeFileSync21(specFile, opts.specText ?? "");
|
|
12336
|
+
const r = spawnSync4(py, ["-I", script, specFile, url], { env: plainTestEnv(), encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", stdio: ["ignore", "pipe", "ignore"] });
|
|
12337
|
+
let out2 = null;
|
|
12338
|
+
try {
|
|
12339
|
+
const v = JSON.parse(r.stdout ?? "");
|
|
12340
|
+
out2 = v && typeof v === "object" ? v : null;
|
|
12290
12341
|
} catch {
|
|
12291
|
-
|
|
12292
|
-
}
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
}
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
const
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
} catch {}
|
|
12347
|
-
parts.push(`${p}:${mtime}`);
|
|
12348
|
-
}
|
|
12349
|
-
return createHash13("sha256").update(parts.join("|")).digest("hex");
|
|
12350
|
-
}
|
|
12351
|
-
function writeCache(targetDir, key, result) {
|
|
12342
|
+
out2 = null;
|
|
12343
|
+
}
|
|
12344
|
+
if (!out2 || r.status !== 0)
|
|
12345
|
+
return res("not_run", "functional harness produced no result");
|
|
12346
|
+
const q = join48(lokiDir2, "quality");
|
|
12347
|
+
mkdirSync18(q, { recursive: true });
|
|
12348
|
+
const tmp = join48(q, `functional-results.json.tmp.${process.pid}`);
|
|
12349
|
+
writeFileSync21(tmp, JSON.stringify(out2, null, 2));
|
|
12350
|
+
renameSync11(tmp, join48(q, "functional-results.json"));
|
|
12351
|
+
const s = String(out2["functional_status"] ?? "inconclusive");
|
|
12352
|
+
return res(s === "verified" ? "pass" : s === "failed" ? "fail" : "not_run", `functional_status ${s}`);
|
|
12353
|
+
}
|
|
12354
|
+
var PRELUDE = `set +e
|
|
12355
|
+
log_info() { :; }; log_warn() { :; }; log_error() { :; }; log_step() { :; }; register_pid() { :; }
|
|
12356
|
+
export APP_RUNNER_ENABLED=true
|
|
12357
|
+
export TARGET_DIR="$1"
|
|
12358
|
+
source "$2" >/dev/null 2>&1 || exit 90
|
|
12359
|
+
`, BOOT, STOP;
|
|
12360
|
+
var init_app_probe = __esm(() => {
|
|
12361
|
+
init_check_result();
|
|
12362
|
+
init_python();
|
|
12363
|
+
init_paths();
|
|
12364
|
+
BOOT = `${PRELUDE}
|
|
12365
|
+
app_runner_init >/dev/null 2>&1; ir=$?
|
|
12366
|
+
sr=-1; hr=-1
|
|
12367
|
+
if [ "$ir" -eq 0 ] && [ -s "$TARGET_DIR/.loki/app-runner/detection.json" ]; then
|
|
12368
|
+
app_runner_start >/dev/null 2>&1; sr=$?
|
|
12369
|
+
[ "$sr" -eq 0 ] && { app_runner_health_check >/dev/null 2>&1; hr=$?; }
|
|
12370
|
+
fi
|
|
12371
|
+
printf '__APP_PROBE__ %s %s %s\\n' "$ir" "$sr" "$hr"
|
|
12372
|
+
`;
|
|
12373
|
+
STOP = `${PRELUDE}
|
|
12374
|
+
_app_runner_dir
|
|
12375
|
+
app_runner_stop >/dev/null 2>&1
|
|
12376
|
+
`;
|
|
12377
|
+
});
|
|
12378
|
+
|
|
12379
|
+
// ../../loki-ts/src/util/secure_scan.ts
|
|
12380
|
+
import { existsSync as existsSync29 } from "fs";
|
|
12381
|
+
import { join as join49 } from "path";
|
|
12382
|
+
function fail(error) {
|
|
12383
|
+
return { ok: false, findings: [], error };
|
|
12384
|
+
}
|
|
12385
|
+
async function runSecureScan(targetDir, opts = {}) {
|
|
12386
|
+
const script = opts.scriptPath ?? join49(REPO_ROOT, "autonomy", "lib", "secure-scan.py");
|
|
12387
|
+
if (!existsSync29(script))
|
|
12388
|
+
return fail(`secure-scan script not found: ${script}`);
|
|
12389
|
+
const py = await findPython3();
|
|
12390
|
+
if (!py)
|
|
12391
|
+
return fail("python3 not found");
|
|
12392
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SECURE_SCAN_TIMEOUT_MS;
|
|
12393
|
+
const started = Date.now();
|
|
12394
|
+
const res = await run([py, script, targetDir, "--json", ...opts.secretsEverywhere ? ["--secrets-everywhere"] : []], { timeoutMs });
|
|
12395
|
+
const elapsed = Date.now() - started;
|
|
12396
|
+
let parsed;
|
|
12352
12397
|
try {
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
if (
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
}
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
return null;
|
|
12379
|
-
const declared = chosenManifest.members ?? [];
|
|
12380
|
-
const members = resolveMembers(chosenRoot, declared, basename19(absTarget));
|
|
12381
|
-
const filtered = [];
|
|
12382
|
-
for (const m of members) {
|
|
12383
|
-
const sibManifestPath = join48(m, ".loki", "app.json");
|
|
12384
|
-
if (existsSync28(sibManifestPath)) {
|
|
12385
|
-
examined.push(sibManifestPath);
|
|
12386
|
-
const sibManifest = readManifest(sibManifestPath);
|
|
12387
|
-
if (sibManifest && sibManifest.app_id !== chosenManifest.app_id) {
|
|
12388
|
-
continue;
|
|
12389
|
-
}
|
|
12390
|
-
}
|
|
12391
|
-
filtered.push(m);
|
|
12392
|
-
}
|
|
12393
|
-
const result = {
|
|
12394
|
-
appId: chosenManifest.app_id,
|
|
12395
|
-
root: chosenRoot,
|
|
12396
|
-
members: filtered,
|
|
12397
|
-
sharedMemoryDir: chosenManifest.shared_memory_dir
|
|
12398
|
-
};
|
|
12399
|
-
writeCache(absTarget, cacheKey(examined), result);
|
|
12400
|
-
return result;
|
|
12401
|
-
}
|
|
12402
|
-
var APP_ID_REGEX, SUPPORTED_SCHEMA_VERSION = 1;
|
|
12403
|
-
var init_project_graph = __esm(() => {
|
|
12404
|
-
APP_ID_REGEX = /^[a-z0-9-]{3,40}$/;
|
|
12398
|
+
parsed = JSON.parse(res.stdout);
|
|
12399
|
+
} catch {
|
|
12400
|
+
parsed = undefined;
|
|
12401
|
+
}
|
|
12402
|
+
const obj = parsed && typeof parsed === "object" ? parsed : undefined;
|
|
12403
|
+
if ((res.exitCode === 0 || res.exitCode === 1) && obj && Array.isArray(obj.findings)) {
|
|
12404
|
+
const findings = obj.findings;
|
|
12405
|
+
if (res.exitCode === 1 === findings.length > 0)
|
|
12406
|
+
return { ok: true, findings };
|
|
12407
|
+
return fail(`secure-scan exit ${res.exitCode} disagrees with ${findings.length} findings`);
|
|
12408
|
+
}
|
|
12409
|
+
if (res.exitCode !== 0 && res.exitCode !== 1 && res.exitCode !== 2 && elapsed >= timeoutMs) {
|
|
12410
|
+
return fail(`secure-scan timed out after ${timeoutMs}ms`);
|
|
12411
|
+
}
|
|
12412
|
+
if (obj && typeof obj.error === "string")
|
|
12413
|
+
return fail(`secure-scan: ${obj.error}`);
|
|
12414
|
+
const tail = (res.stderr || res.stdout).trim().split(`
|
|
12415
|
+
`).slice(-3).join(" | ");
|
|
12416
|
+
return fail(`secure-scan failed (exit ${res.exitCode}): ${tail}`);
|
|
12417
|
+
}
|
|
12418
|
+
var DEFAULT_SECURE_SCAN_TIMEOUT_MS = 120000;
|
|
12419
|
+
var init_secure_scan = __esm(() => {
|
|
12420
|
+
init_paths();
|
|
12421
|
+
init_python();
|
|
12422
|
+
init_shell();
|
|
12405
12423
|
});
|
|
12406
12424
|
|
|
12407
12425
|
// ../../loki-ts/src/runner/retry_class.ts
|
|
@@ -12509,10 +12527,10 @@ var init_route_block = __esm(() => {
|
|
|
12509
12527
|
|
|
12510
12528
|
// ../../loki-ts/src/features/visual_evidence.ts
|
|
12511
12529
|
import { spawn as spawn7 } from "child_process";
|
|
12512
|
-
import { createHash as
|
|
12513
|
-
import { existsSync as
|
|
12530
|
+
import { createHash as createHash13, randomBytes as randomBytes5 } from "crypto";
|
|
12531
|
+
import { existsSync as existsSync30, lstatSync as lstatSync10, mkdirSync as mkdirSync19, readdirSync as readdirSync16, readFileSync as readFileSync38, writeFileSync as writeFileSync22 } from "fs";
|
|
12514
12532
|
import { createServer } from "net";
|
|
12515
|
-
import { dirname as
|
|
12533
|
+
import { dirname as dirname16, isAbsolute as isAbsolute7, join as join50, normalize as normalize3, relative as relative6, sep as sep11 } from "path";
|
|
12516
12534
|
function routeFor(file) {
|
|
12517
12535
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
12518
12536
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -12522,7 +12540,7 @@ function hashScreens(runDir, rels) {
|
|
|
12522
12540
|
const out2 = [];
|
|
12523
12541
|
for (const rel of rels) {
|
|
12524
12542
|
try {
|
|
12525
|
-
out2.push({ path: rel, sha256: sha256File(
|
|
12543
|
+
out2.push({ path: rel, sha256: sha256File(join50(runDir, rel)) });
|
|
12526
12544
|
} catch {}
|
|
12527
12545
|
}
|
|
12528
12546
|
return out2;
|
|
@@ -12535,14 +12553,14 @@ function checkScreens(runDir, screens) {
|
|
|
12535
12553
|
return "evidence_screens entry is malformed";
|
|
12536
12554
|
if (isAbsolute7(s.path) || normalize3(s.path).startsWith(".."))
|
|
12537
12555
|
return `evidence screenshot path escapes the evidence dir: ${s.path}`;
|
|
12538
|
-
const file =
|
|
12556
|
+
const file = join50(runDir, s.path);
|
|
12539
12557
|
let cur = runDir;
|
|
12540
12558
|
for (const seg of normalize3(s.path).split(sep11)) {
|
|
12541
|
-
cur =
|
|
12559
|
+
cur = join50(cur, seg);
|
|
12542
12560
|
if (isSymlink(cur))
|
|
12543
12561
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
12544
12562
|
}
|
|
12545
|
-
if (!
|
|
12563
|
+
if (!existsSync30(file))
|
|
12546
12564
|
return `evidence screenshot is missing: ${s.path}`;
|
|
12547
12565
|
if (!isRegularFile(file))
|
|
12548
12566
|
return `evidence screenshot is not a regular file: ${s.path}`;
|
|
@@ -12585,8 +12603,8 @@ async function waitUp(url, ms, signal) {
|
|
|
12585
12603
|
}
|
|
12586
12604
|
function openapiPaths(repoDir) {
|
|
12587
12605
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
12588
|
-
const p =
|
|
12589
|
-
if (!
|
|
12606
|
+
const p = join50(repoDir, f);
|
|
12607
|
+
if (!existsSync30(p))
|
|
12590
12608
|
continue;
|
|
12591
12609
|
try {
|
|
12592
12610
|
const txt = readFileSync38(p, "utf8");
|
|
@@ -12603,24 +12621,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
|
|
|
12603
12621
|
if (!pw || !pkg)
|
|
12604
12622
|
return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
|
|
12605
12623
|
try {
|
|
12606
|
-
const dir =
|
|
12624
|
+
const dir = join50(runDir, relDir, "e2e");
|
|
12607
12625
|
mkdirSync19(dir, { recursive: true });
|
|
12608
|
-
writeFileSync22(
|
|
12609
|
-
writeFileSync22(
|
|
12626
|
+
writeFileSync22(join50(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
|
|
12627
|
+
writeFileSync22(join50(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
|
|
12610
12628
|
`);
|
|
12611
|
-
if (!await shoot(pw, ["test", "--config",
|
|
12629
|
+
if (!await shoot(pw, ["test", "--config", join50(dir, "playwright.config.cjs")], repoDir, ms, signal))
|
|
12612
12630
|
return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
|
|
12613
12631
|
const rels = [];
|
|
12614
12632
|
const walk = (d) => {
|
|
12615
|
-
for (const e of
|
|
12616
|
-
const full =
|
|
12633
|
+
for (const e of readdirSync16(d, { withFileTypes: true })) {
|
|
12634
|
+
const full = join50(d, e.name);
|
|
12617
12635
|
if (e.isDirectory())
|
|
12618
12636
|
walk(full);
|
|
12619
12637
|
else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
|
|
12620
|
-
rels.push(
|
|
12638
|
+
rels.push(join50(relDir, "e2e", relative6(dir, full)));
|
|
12621
12639
|
}
|
|
12622
12640
|
};
|
|
12623
|
-
walk(
|
|
12641
|
+
walk(join50(dir, "out"));
|
|
12624
12642
|
return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
|
|
12625
12643
|
} catch (e) {
|
|
12626
12644
|
return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
|
|
@@ -12699,15 +12717,15 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12699
12717
|
if (!visualEvidenceEnabled(opts.env))
|
|
12700
12718
|
return skip("LOKI_VISUAL_EVIDENCE is 0");
|
|
12701
12719
|
const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
|
|
12702
|
-
const appDir = boot ?
|
|
12703
|
-
const pkgPath =
|
|
12720
|
+
const appDir = boot ? join50(repoDir, boot.boot.cwd) : repoDir;
|
|
12721
|
+
const pkgPath = join50(appDir, "package.json");
|
|
12704
12722
|
let script = null;
|
|
12705
12723
|
if (!boot) {
|
|
12706
|
-
if (!
|
|
12707
|
-
const subs = ["backend", "frontend"].filter((d) =>
|
|
12724
|
+
if (!existsSync30(pkgPath)) {
|
|
12725
|
+
const subs = ["backend", "frontend"].filter((d) => existsSync30(join50(repoDir, d, "package.json")));
|
|
12708
12726
|
const has = (d) => {
|
|
12709
12727
|
try {
|
|
12710
|
-
return pickScript(JSON.parse(readFileSync38(
|
|
12728
|
+
return pickScript(JSON.parse(readFileSync38(join50(repoDir, d, "package.json"), "utf8"))) !== null;
|
|
12711
12729
|
} catch {
|
|
12712
12730
|
return false;
|
|
12713
12731
|
}
|
|
@@ -12741,20 +12759,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12741
12759
|
}
|
|
12742
12760
|
if (!await waitUp(base, left(), signal))
|
|
12743
12761
|
return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
|
|
12744
|
-
const evRoot =
|
|
12762
|
+
const evRoot = join50(runDir, "evidence");
|
|
12745
12763
|
if (isSymlink(evRoot))
|
|
12746
12764
|
return skip("evidence dir is a symlink");
|
|
12747
12765
|
mkdirSync19(evRoot, { recursive: true });
|
|
12748
12766
|
if (pages.length > 0) {
|
|
12749
|
-
const rel0 =
|
|
12750
|
-
mkdirSync19(
|
|
12767
|
+
const rel0 = join50("evidence", randomBytes5(6).toString("hex"));
|
|
12768
|
+
mkdirSync19(join50(runDir, rel0));
|
|
12751
12769
|
const rels = [];
|
|
12752
12770
|
for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
|
|
12753
12771
|
if (aborted() || left() <= 0)
|
|
12754
12772
|
break;
|
|
12755
|
-
const rel =
|
|
12756
|
-
const ok = await shoot(pw, ["screenshot", `${base}${route}`,
|
|
12757
|
-
if (ok && !aborted() && !isSymlink(
|
|
12773
|
+
const rel = join50(rel0, `${screenName(route)}.png`);
|
|
12774
|
+
const ok = await shoot(pw, ["screenshot", `${base}${route}`, join50(runDir, rel)], appDir, left(), signal);
|
|
12775
|
+
if (ok && !aborted() && !isSymlink(join50(runDir, rel)) && existsSync30(join50(runDir, rel)))
|
|
12758
12776
|
rels.push(rel);
|
|
12759
12777
|
}
|
|
12760
12778
|
if (aborted())
|
|
@@ -12779,9 +12797,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12779
12797
|
}
|
|
12780
12798
|
if (aborted())
|
|
12781
12799
|
return skip("aborted");
|
|
12782
|
-
const hdir =
|
|
12800
|
+
const hdir = join50(evRoot, randomBytes5(6).toString("hex"));
|
|
12783
12801
|
mkdirSync19(hdir);
|
|
12784
|
-
writeFileSync22(
|
|
12802
|
+
writeFileSync22(join50(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
|
|
12785
12803
|
`);
|
|
12786
12804
|
return { screens: [], http: true, skipped: null };
|
|
12787
12805
|
} catch (e) {
|
|
@@ -12808,14 +12826,14 @@ async function sealEvidence(repoDir, runDir, o, notProven, signal, emit) {
|
|
|
12808
12826
|
function receiptScreensProblem(receiptPath, receipt) {
|
|
12809
12827
|
if (visualGateEnabled() && typeof receipt["evidence_failed"] === "string")
|
|
12810
12828
|
return `visual evidence failed (LOKI_VISUAL_GATE=1): ${receipt["evidence_failed"]}`;
|
|
12811
|
-
return receipt["evidence_screens"] === undefined ? null : checkScreens(
|
|
12829
|
+
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname16(receiptPath), receipt["evidence_screens"]);
|
|
12812
12830
|
}
|
|
12813
|
-
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) =>
|
|
12814
|
-
const bin =
|
|
12815
|
-
return
|
|
12831
|
+
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) => createHash13("sha256").update(readFileSync38(p)).digest("hex"), playwrightBin = (repoDir) => {
|
|
12832
|
+
const bin = join50(repoDir, "node_modules", ".bin", "playwright");
|
|
12833
|
+
return existsSync30(bin) ? bin : null;
|
|
12816
12834
|
}, playwrightTestPkg = (repoDir) => {
|
|
12817
|
-
const d =
|
|
12818
|
-
return
|
|
12835
|
+
const d = join50(repoDir, "node_modules", "@playwright", "test");
|
|
12836
|
+
return existsSync30(join50(d, "package.json")) ? d : null;
|
|
12819
12837
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
12820
12838
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
12821
12839
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -12858,7 +12876,7 @@ var init_outbox = __esm(() => {
|
|
|
12858
12876
|
});
|
|
12859
12877
|
|
|
12860
12878
|
// ../../loki-ts/src/engine10/stages/pr.ts
|
|
12861
|
-
import { join as
|
|
12879
|
+
import { join as join51 } from "path";
|
|
12862
12880
|
var DEFAULT_PUSH_SH;
|
|
12863
12881
|
var init_pr = __esm(() => {
|
|
12864
12882
|
init_types();
|
|
@@ -12875,16 +12893,16 @@ var init_pr = __esm(() => {
|
|
|
12875
12893
|
init_run_outputs();
|
|
12876
12894
|
init_yaml_key();
|
|
12877
12895
|
init_outbox();
|
|
12878
|
-
DEFAULT_PUSH_SH =
|
|
12896
|
+
DEFAULT_PUSH_SH = join51(REPO_ROOT, "autonomy/lib/engine10-push.sh");
|
|
12879
12897
|
});
|
|
12880
12898
|
|
|
12881
12899
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
12882
|
-
import { existsSync as
|
|
12883
|
-
import { dirname as
|
|
12884
|
-
import { createHash as
|
|
12900
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync20, mkdtempSync as mkdtempSync7, readFileSync as readFileSync39, rmSync as rmSync15, writeFileSync as writeFileSync23 } from "fs";
|
|
12901
|
+
import { dirname as dirname17, join as join52 } from "path";
|
|
12902
|
+
import { createHash as createHash14 } from "crypto";
|
|
12885
12903
|
function loadLessons(repoDir) {
|
|
12886
12904
|
const p = lessonsPath(repoDir);
|
|
12887
|
-
if (!
|
|
12905
|
+
if (!existsSync31(p))
|
|
12888
12906
|
return [];
|
|
12889
12907
|
try {
|
|
12890
12908
|
const j = JSON.parse(readFileSync39(p, "utf-8"));
|
|
@@ -12895,11 +12913,11 @@ function loadLessons(repoDir) {
|
|
|
12895
12913
|
}
|
|
12896
12914
|
function save(repoDir, lessons) {
|
|
12897
12915
|
const p = lessonsPath(repoDir);
|
|
12898
|
-
mkdirSync20(
|
|
12916
|
+
mkdirSync20(dirname17(p), { recursive: true });
|
|
12899
12917
|
atomicWriteJson(p, { version: 2, lessons });
|
|
12900
12918
|
}
|
|
12901
12919
|
function appendReceiptFact(repoDir, f, now2 = () => new Date) {
|
|
12902
|
-
const id = `rcp-${
|
|
12920
|
+
const id = `rcp-${createHash14("sha256").update(f.runId).digest("hex").slice(0, 12)}`;
|
|
12903
12921
|
const lessons = loadLessons(repoDir);
|
|
12904
12922
|
if (lessons.some((l) => l.id === id))
|
|
12905
12923
|
return false;
|
|
@@ -12929,7 +12947,7 @@ function recordRunVerdict(repoDir, runId, verdict) {
|
|
|
12929
12947
|
if (dirty)
|
|
12930
12948
|
save(repoDir, lessons);
|
|
12931
12949
|
}
|
|
12932
|
-
var lessonsPath = (repoDir) =>
|
|
12950
|
+
var lessonsPath = (repoDir) => join52(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
|
|
12933
12951
|
var init_pr_lessons = __esm(() => {
|
|
12934
12952
|
init_atomic();
|
|
12935
12953
|
init_safe_git();
|
|
@@ -12961,8 +12979,8 @@ var init_attempts = __esm(() => {
|
|
|
12961
12979
|
var init_mcp_config = () => {};
|
|
12962
12980
|
|
|
12963
12981
|
// ../../loki-ts/src/providers/claude_flags.ts
|
|
12964
|
-
import { existsSync as
|
|
12965
|
-
import { resolve as resolvePath, dirname as
|
|
12982
|
+
import { existsSync as existsSync32, readFileSync as readFileSync40 } from "fs";
|
|
12983
|
+
import { resolve as resolvePath, dirname as dirname18 } from "path";
|
|
12966
12984
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12967
12985
|
function claudeFlagSupported(flag, helpText) {
|
|
12968
12986
|
const txt = helpText ?? _claudeHelpCache;
|
|
@@ -13009,13 +13027,13 @@ function leanReviewerFlags(opts = {}) {
|
|
|
13009
13027
|
}
|
|
13010
13028
|
function designArchetypesText() {
|
|
13011
13029
|
try {
|
|
13012
|
-
const moduleDir =
|
|
13030
|
+
const moduleDir = dirname18(fileURLToPath4(import.meta.url));
|
|
13013
13031
|
for (const rel of [
|
|
13014
13032
|
["..", "..", "..", "references", "design-archetypes.md"],
|
|
13015
13033
|
["..", "..", "references", "design-archetypes.md"]
|
|
13016
13034
|
]) {
|
|
13017
13035
|
const p = resolvePath(moduleDir, ...rel);
|
|
13018
|
-
if (
|
|
13036
|
+
if (existsSync32(p))
|
|
13019
13037
|
return readFileSync40(p, "utf8");
|
|
13020
13038
|
}
|
|
13021
13039
|
} catch {}
|
|
@@ -13100,12 +13118,12 @@ var init_providers = __esm(() => {
|
|
|
13100
13118
|
});
|
|
13101
13119
|
|
|
13102
13120
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
13103
|
-
import { existsSync as
|
|
13104
|
-
import { join as
|
|
13121
|
+
import { existsSync as existsSync33, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
|
|
13122
|
+
import { join as join53 } from "path";
|
|
13105
13123
|
function loadRouteRecord(runDir) {
|
|
13106
13124
|
try {
|
|
13107
|
-
const p =
|
|
13108
|
-
if (!
|
|
13125
|
+
const p = join53(runDir, ROUTE_RECORD_FILE);
|
|
13126
|
+
if (!existsSync33(p) || !lstatSync11(p).isFile())
|
|
13109
13127
|
return;
|
|
13110
13128
|
const v = JSON.parse(readFileSync41(p, "utf8"));
|
|
13111
13129
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
|
|
@@ -13236,7 +13254,7 @@ var init_worker = __esm(() => {
|
|
|
13236
13254
|
});
|
|
13237
13255
|
|
|
13238
13256
|
// ../../loki-ts/src/project_model/package_suite.ts
|
|
13239
|
-
import { join as
|
|
13257
|
+
import { join as join54 } from "path";
|
|
13240
13258
|
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
13241
13259
|
const api = loadProjectApi(repoDir);
|
|
13242
13260
|
if (!isMultiRoot(api))
|
|
@@ -13247,7 +13265,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13247
13265
|
for (const pkg of withTests) {
|
|
13248
13266
|
const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
|
|
13249
13267
|
const started = Date.now();
|
|
13250
|
-
const r = await run(["bash", "-c", tc.cmd], { cwd:
|
|
13268
|
+
const r = await run(["bash", "-c", tc.cmd], { cwd: join54(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
13251
13269
|
const duration_s = (Date.now() - started) / 1000;
|
|
13252
13270
|
if (signal.aborted) {
|
|
13253
13271
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
@@ -13256,7 +13274,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
13256
13274
|
}
|
|
13257
13275
|
const out2 = `${r.stdout}
|
|
13258
13276
|
${r.stderr}`;
|
|
13259
|
-
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd:
|
|
13277
|
+
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd: join54(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
13260
13278
|
if (lr) {
|
|
13261
13279
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
13262
13280
|
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
@@ -13290,14 +13308,14 @@ __export(exports_deep, {
|
|
|
13290
13308
|
DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
|
|
13291
13309
|
DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH2
|
|
13292
13310
|
});
|
|
13293
|
-
import { existsSync as
|
|
13311
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync34, lstatSync as lstatSync12, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync8, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "fs";
|
|
13294
13312
|
import { tmpdir as tmpdir9 } from "os";
|
|
13295
|
-
import { join as
|
|
13313
|
+
import { dirname as dirname19, join as join55 } from "path";
|
|
13296
13314
|
function sessionCouncil(sessions) {
|
|
13297
13315
|
return { async run(input, signal) {
|
|
13298
|
-
const cwd = mkdtempSync8(
|
|
13316
|
+
const cwd = mkdtempSync8(join55(tmpdir9(), "loki-deep-council-"));
|
|
13299
13317
|
try {
|
|
13300
|
-
writeFileSync25(
|
|
13318
|
+
writeFileSync25(join55(cwd, "diff.patch"), input.diff, "utf8");
|
|
13301
13319
|
const r = await sessions.run({
|
|
13302
13320
|
stage: "deep",
|
|
13303
13321
|
tier: "development",
|
|
@@ -13364,16 +13382,20 @@ ${r.stderr}`, lr = r.exitCode === 0 ? undefined : await harnessLoadReason({ repo
|
|
|
13364
13382
|
notProven.add(`not run: ${name} (${cls.reason ?? NO_TESTS_REASON})`);
|
|
13365
13383
|
}
|
|
13366
13384
|
}
|
|
13367
|
-
function runAppBoot(ctx, opts, checks, notProven) {
|
|
13368
|
-
|
|
13369
|
-
let graph = null;
|
|
13385
|
+
async function runAppBoot(ctx, opts, checks, notProven) {
|
|
13386
|
+
let r;
|
|
13370
13387
|
try {
|
|
13371
|
-
|
|
13372
|
-
} catch {
|
|
13373
|
-
|
|
13388
|
+
r = await (opts.appProbe ?? appProbe)(ctx.repoDir, join55(ctx.repoDir, ".loki"));
|
|
13389
|
+
} catch (err) {
|
|
13390
|
+
r = { checks: [{ name: "app boot", cmd: "autonomy/app-runner.sh", result: "not_run", duration_s: 0, reason: `app probe threw: ${err.message}` }], pid: null, url: null };
|
|
13391
|
+
}
|
|
13392
|
+
if (!r.checks.some((c) => c.name === "app boot"))
|
|
13393
|
+
notProven.add("not run: app boot (app probe reported no result)");
|
|
13394
|
+
for (const c of r.checks) {
|
|
13395
|
+
checks.push(c);
|
|
13396
|
+
if (c.result === "not_run")
|
|
13397
|
+
notProven.add(`not run: ${c.name} (${c.reason ?? "no reason given"})`);
|
|
13374
13398
|
}
|
|
13375
|
-
checks.push({ name: "app boot", cmd: "project_graph.ts discoverProjectGraph", result: "not_run", duration_s: 0 });
|
|
13376
|
-
notProven.add(graph ? `app boot not run (app graph discovered, ${graph.members.length} member(s))` : "app boot not run (no app graph discovered)");
|
|
13377
13399
|
}
|
|
13378
13400
|
async function runCouncilCheck(ctx, changed, baseSha, signal, opts, checks, notProven) {
|
|
13379
13401
|
const codeFiles = changed.filter((f) => !f.endsWith(".md"));
|
|
@@ -13404,30 +13426,48 @@ async function runCouncilCheck(ctx, changed, baseSha, signal, opts, checks, notP
|
|
|
13404
13426
|
notProven.add(`council (refused: ${err.message})`);
|
|
13405
13427
|
}
|
|
13406
13428
|
}
|
|
13429
|
+
async function secureScanChanged(repoDir, changed, opts) {
|
|
13430
|
+
const dir = mkdtempSync8(join55(tmpdir9(), "loki-deep-secure-"));
|
|
13431
|
+
try {
|
|
13432
|
+
for (const f of changed)
|
|
13433
|
+
if (existsSync34(join55(repoDir, f)) && lstatSync12(join55(repoDir, f)).isFile()) {
|
|
13434
|
+
mkdirSync22(dirname19(join55(dir, f)), { recursive: true });
|
|
13435
|
+
copyFileSync3(join55(repoDir, f), join55(dir, f));
|
|
13436
|
+
}
|
|
13437
|
+
return await runSecureScan(dir, { ...opts.secureScanPath ? { scriptPath: opts.secureScanPath } : {}, timeoutMs: 60000 });
|
|
13438
|
+
} finally {
|
|
13439
|
+
rmSync16(dir, { recursive: true, force: true });
|
|
13440
|
+
}
|
|
13441
|
+
}
|
|
13407
13442
|
async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
13408
|
-
const scriptPath = opts.secretScanShPath ?? DEFAULT_SECRET_SCAN_SH;
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: 0 });
|
|
13443
|
+
const scriptPath = opts.secretScanShPath ?? DEFAULT_SECRET_SCAN_SH, name = "security scan", cmd = "secret-scan.sh + secure-scan.py";
|
|
13444
|
+
if (!existsSync34(scriptPath)) {
|
|
13445
|
+
checks.push({ name, cmd, result: "not_run", duration_s: 0 });
|
|
13412
13446
|
notProven.add(`not run: ${name} (secret-scan.sh not found)`);
|
|
13413
13447
|
return;
|
|
13414
13448
|
}
|
|
13415
13449
|
if (changed.length === 0) {
|
|
13416
|
-
checks.push({ name, cmd
|
|
13450
|
+
checks.push({ name, cmd, result: "pass", duration_s: 0 });
|
|
13417
13451
|
return;
|
|
13418
13452
|
}
|
|
13419
13453
|
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"';
|
|
13420
13454
|
const started = Date.now();
|
|
13421
|
-
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) =>
|
|
13422
|
-
const
|
|
13423
|
-
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13428
|
-
|
|
13429
|
-
|
|
13430
|
-
|
|
13455
|
+
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) => join55(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
|
|
13456
|
+
const sec = await secureScanChanged(ctx.repoDir, changed, opts), gaps = [], reasons = [];
|
|
13457
|
+
const hits = r.exitCode === 3 ? [] : r.stdout.split(`
|
|
13458
|
+
`).map((l) => l.trim()).filter(Boolean), high = sec.findings.filter((f) => String(f.severity).toUpperCase() === "HIGH");
|
|
13459
|
+
if (r.exitCode === 3)
|
|
13460
|
+
gaps.push("secret-scan.sh failed to load");
|
|
13461
|
+
if (!sec.ok)
|
|
13462
|
+
gaps.push(sec.error ?? "secure-scan failed");
|
|
13463
|
+
if (hits.length > 0)
|
|
13464
|
+
reasons.push(`secret match: ${hits.join(", ")}`);
|
|
13465
|
+
if (high.length > 0)
|
|
13466
|
+
reasons.push(`secure-scan: ${high.map((f) => `${f.rule}: ${f.file}:${f.line}`).join(", ")}`);
|
|
13467
|
+
const result = reasons.length > 0 ? "fail" : gaps.length > 0 ? "not_run" : "pass";
|
|
13468
|
+
checks.push({ name, cmd, result, duration_s: (Date.now() - started) / 1000, ...result === "pass" ? {} : { reason: (result === "fail" ? reasons : gaps).join("; ") } });
|
|
13469
|
+
if (result === "not_run")
|
|
13470
|
+
notProven.add(`not run: ${name} (${gaps.join("; ")})`);
|
|
13431
13471
|
}
|
|
13432
13472
|
function commentArgv(prNumber, bodyFile) {
|
|
13433
13473
|
return ["comment", prNumber, bodyFile];
|
|
@@ -13453,7 +13493,7 @@ async function postResults(ctx, opts, checks, notProven, statusState) {
|
|
|
13453
13493
|
const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
|
|
13454
13494
|
if (prNumber) {
|
|
13455
13495
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13456
|
-
const bodyFile =
|
|
13496
|
+
const bodyFile = join55(ctx.runDir, "deep-comment.md");
|
|
13457
13497
|
writeFileSync25(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
|
|
13458
13498
|
const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
|
|
13459
13499
|
if (commentResult.exitCode !== 0)
|
|
@@ -13489,7 +13529,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
13489
13529
|
const checks = [];
|
|
13490
13530
|
const notProven = new Set;
|
|
13491
13531
|
await runFullSuite(ctx, signal, opts, checks, notProven);
|
|
13492
|
-
runAppBoot(ctx, opts, checks, notProven);
|
|
13532
|
+
await runAppBoot(ctx, opts, checks, notProven);
|
|
13493
13533
|
await runCouncilCheck(ctx, changed, ctx.baseSha, signal, opts, checks, notProven);
|
|
13494
13534
|
await runSecretScan(ctx, changed, opts, checks, notProven);
|
|
13495
13535
|
const statusState = checks.some((c) => c.result === "fail") ? "failure" : "success";
|
|
@@ -13507,7 +13547,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
13507
13547
|
const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
|
|
13508
13548
|
const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
13509
13549
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13510
|
-
writeFileSync25(
|
|
13550
|
+
writeFileSync25(join55(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
|
|
13511
13551
|
`);
|
|
13512
13552
|
const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
|
|
13513
13553
|
const allNotProven = [...notProvenList, ...pushNotProven];
|
|
@@ -13516,7 +13556,8 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
13516
13556
|
}
|
|
13517
13557
|
var DEFAULT_PUSH_SH2, DEFAULT_SECRET_SCAN_SH, MAX_COUNCIL_DIFF_BYTES = 400000, COUNCIL_LIMIT_S = 600, FULL_SUITE_TIMEOUT_MS = 300000, PR_NUMBER_RE, SHA_RE, FULL_SUITE_CMD, deepStage, stage;
|
|
13518
13558
|
var init_deep = __esm(() => {
|
|
13519
|
-
|
|
13559
|
+
init_app_probe();
|
|
13560
|
+
init_secure_scan();
|
|
13520
13561
|
init_shell();
|
|
13521
13562
|
init_load_owner();
|
|
13522
13563
|
init_worker();
|
|
@@ -13551,9 +13592,9 @@ var init_deep = __esm(() => {
|
|
|
13551
13592
|
});
|
|
13552
13593
|
|
|
13553
13594
|
// ../../loki-ts/src/engine10/stages/verify.ts
|
|
13554
|
-
import { existsSync as
|
|
13595
|
+
import { existsSync as existsSync35, mkdtempSync as mkdtempSync9, realpathSync as realpathSync19, rmSync as rmSync17 } from "fs";
|
|
13555
13596
|
import { tmpdir as tmpdir10 } from "os";
|
|
13556
|
-
import { dirname as dirname20, isAbsolute as isAbsolute8, join as
|
|
13597
|
+
import { dirname as dirname20, isAbsolute as isAbsolute8, join as join56, relative as relative7 } from "path";
|
|
13557
13598
|
function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
13558
13599
|
const inRepo = (p) => {
|
|
13559
13600
|
try {
|
|
@@ -13564,7 +13605,7 @@ function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
|
13564
13605
|
}
|
|
13565
13606
|
};
|
|
13566
13607
|
const venvEnv = process.env["VIRTUAL_ENV"];
|
|
13567
|
-
const project = [
|
|
13608
|
+
const project = [join56(repoDir, ".venv", "bin", bin), join56(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join56(venvEnv, "bin", bin)] : []].find(existsSync35);
|
|
13568
13609
|
return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
|
|
13569
13610
|
}
|
|
13570
13611
|
function runnerCmd(t, repoDir) {
|
|
@@ -13679,7 +13720,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13679
13720
|
const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
|
|
13680
13721
|
if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
|
|
13681
13722
|
return out2;
|
|
13682
|
-
const dir = mkdtempSync9(
|
|
13723
|
+
const dir = mkdtempSync9(join56(tmpdir10(), "e10-base-"));
|
|
13683
13724
|
const git3 = (args) => {
|
|
13684
13725
|
safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
|
|
13685
13726
|
};
|
|
@@ -13717,7 +13758,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13717
13758
|
return out2;
|
|
13718
13759
|
}
|
|
13719
13760
|
function isLokiModeRepo(repoDir) {
|
|
13720
|
-
return
|
|
13761
|
+
return existsSync35(join56(repoDir, "scripts", "select-tests.sh"));
|
|
13721
13762
|
}
|
|
13722
13763
|
async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
13723
13764
|
const { api, ...runOpts } = opts;
|
|
@@ -13739,9 +13780,9 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
|
13739
13780
|
}
|
|
13740
13781
|
for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
|
|
13741
13782
|
const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
|
|
13742
|
-
if (
|
|
13783
|
+
if (existsSync35(join56(g.cwd, "tsconfig.json")))
|
|
13743
13784
|
await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
|
|
13744
|
-
if (ESLINT_CONFIGS.some((f) =>
|
|
13785
|
+
if (ESLINT_CONFIGS.some((f) => existsSync35(join56(g.cwd, f)))) {
|
|
13745
13786
|
const c = await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
|
|
13746
13787
|
if (await excuseLint(ctx, signal, c, "eslint", "npx", ["eslint"], g.cwd, g.rel, co))
|
|
13747
13788
|
pre.push(c.name);
|
|
@@ -13756,7 +13797,7 @@ var CHECK_TIMEOUT_MS = 60000, excerpts, isHold = (c) => isHoldoutCheck(c.name),
|
|
|
13756
13797
|
return r.missing || r.cut ? null : r;
|
|
13757
13798
|
}, base: (f) => {
|
|
13758
13799
|
try {
|
|
13759
|
-
return safeGit(ctx.repoDir, ["show", `${ctx.baseSha}:${relative7(ctx.repoDir,
|
|
13800
|
+
return safeGit(ctx.repoDir, ["show", `${ctx.baseSha}:${relative7(ctx.repoDir, join56(cwd, f))}`], { stdio: ["ignore", "pipe", "ignore"] });
|
|
13760
13801
|
} catch {
|
|
13761
13802
|
return null;
|
|
13762
13803
|
}
|
|
@@ -13921,8 +13962,8 @@ ${x}` : c.cmd };
|
|
|
13921
13962
|
});
|
|
13922
13963
|
|
|
13923
13964
|
// ../../loki-ts/src/project_model/conventions.ts
|
|
13924
|
-
import { existsSync as
|
|
13925
|
-
import { dirname as dirname21, join as
|
|
13965
|
+
import { existsSync as existsSync36, readdirSync as readdirSync17, readFileSync as readFileSync42 } from "fs";
|
|
13966
|
+
import { dirname as dirname21, join as join57 } from "path";
|
|
13926
13967
|
function parseJsonc(text2) {
|
|
13927
13968
|
let out2 = "", i = 0;
|
|
13928
13969
|
while (i < text2.length) {
|
|
@@ -13948,7 +13989,7 @@ function parseJsonc(text2) {
|
|
|
13948
13989
|
return JSON.parse(out2.replace(/,(\s*[}\]])/g, "$1"));
|
|
13949
13990
|
}
|
|
13950
13991
|
function moduleOf(file, depth = 0) {
|
|
13951
|
-
const j =
|
|
13992
|
+
const j = readJson5(file);
|
|
13952
13993
|
if (!j || depth > 4)
|
|
13953
13994
|
return null;
|
|
13954
13995
|
const m = j.compilerOptions?.module;
|
|
@@ -13957,25 +13998,25 @@ function moduleOf(file, depth = 0) {
|
|
|
13957
13998
|
const ext = typeof j.extends === "string" ? j.extends : null;
|
|
13958
13999
|
if (!ext || !ext.startsWith("."))
|
|
13959
14000
|
return null;
|
|
13960
|
-
const next =
|
|
13961
|
-
return
|
|
14001
|
+
const next = join57(dirname21(file), ext.endsWith(".json") ? ext : `${ext}.json`);
|
|
14002
|
+
return existsSync36(next) ? moduleOf(next, depth + 1) : null;
|
|
13962
14003
|
}
|
|
13963
14004
|
function readPackageConventions(pkgDir, runner = null) {
|
|
13964
14005
|
let names = [];
|
|
13965
14006
|
try {
|
|
13966
|
-
names =
|
|
14007
|
+
names = readdirSync17(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
|
|
13967
14008
|
} catch {
|
|
13968
14009
|
return null;
|
|
13969
14010
|
}
|
|
13970
14011
|
let packageType = null, tsModule = null;
|
|
13971
14012
|
for (const n2 of names) {
|
|
13972
|
-
const j =
|
|
14013
|
+
const j = readJson5(join57(pkgDir, n2));
|
|
13973
14014
|
if (!j)
|
|
13974
14015
|
continue;
|
|
13975
14016
|
if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
|
|
13976
14017
|
packageType = j.type;
|
|
13977
14018
|
if (tsModule === null && j.compilerOptions !== undefined)
|
|
13978
|
-
tsModule = moduleOf(
|
|
14019
|
+
tsModule = moduleOf(join57(pkgDir, n2));
|
|
13979
14020
|
}
|
|
13980
14021
|
if (packageType === null && tsModule === null)
|
|
13981
14022
|
return null;
|
|
@@ -13995,7 +14036,7 @@ function conventionViolation(c, fileName, content) {
|
|
|
13995
14036
|
const code = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/(["'`])(?:\\.|(?!\1)[^\\\n])*\1/g, '""');
|
|
13996
14037
|
return /\bimport\.meta\b/.test(code) ? "import.meta is not allowed in a CommonJS package (TS1470)" : null;
|
|
13997
14038
|
}
|
|
13998
|
-
var
|
|
14039
|
+
var readJson5 = (p) => {
|
|
13999
14040
|
try {
|
|
14000
14041
|
const v = parseJsonc(readFileSync42(p, "utf8"));
|
|
14001
14042
|
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
@@ -14006,16 +14047,16 @@ var readJson4 = (p) => {
|
|
|
14006
14047
|
var init_conventions = () => {};
|
|
14007
14048
|
|
|
14008
14049
|
// ../../loki-ts/src/engine10/stages/wall.ts
|
|
14009
|
-
import { spawnSync as
|
|
14010
|
-
import { existsSync as
|
|
14050
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
14051
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync10, readFileSync as readFileSync43, readdirSync as readdirSync18, realpathSync as realpathSync20, rmSync as rmSync18, writeFileSync as writeFileSync26 } from "fs";
|
|
14011
14052
|
import { tmpdir as tmpdir11 } from "os";
|
|
14012
|
-
import { dirname as dirname22, isAbsolute as isAbsolute9, join as
|
|
14053
|
+
import { dirname as dirname22, isAbsolute as isAbsolute9, join as join58, relative as relative8 } from "path";
|
|
14013
14054
|
function pytestCollectionIsRed(output, repoDir) {
|
|
14014
14055
|
if (/ModuleNotFoundError/.test(output))
|
|
14015
14056
|
return false;
|
|
14016
14057
|
const real2 = (p) => {
|
|
14017
14058
|
try {
|
|
14018
|
-
return realpathSync20(isAbsolute9(p) ? p :
|
|
14059
|
+
return realpathSync20(isAbsolute9(p) ? p : join58(repoDir, p));
|
|
14019
14060
|
} catch {
|
|
14020
14061
|
return null;
|
|
14021
14062
|
}
|
|
@@ -14052,7 +14093,7 @@ function pytestCollectionIsRed(output, repoDir) {
|
|
|
14052
14093
|
}
|
|
14053
14094
|
function moduleUnderRepo(repoDir, name) {
|
|
14054
14095
|
const rel = name.replace(/\./g, "/");
|
|
14055
|
-
return
|
|
14096
|
+
return existsSync37(join58(repoDir, `${rel}.py`)) || existsSync37(join58(repoDir, rel, "__init__.py"));
|
|
14056
14097
|
}
|
|
14057
14098
|
function pytestExit1IsRed(output) {
|
|
14058
14099
|
if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
|
|
@@ -14107,26 +14148,26 @@ class RealBaseTestRunner {
|
|
|
14107
14148
|
}
|
|
14108
14149
|
run(repoDir, files) {
|
|
14109
14150
|
this.lastNotRunFiles = [];
|
|
14110
|
-
let pass = 0,
|
|
14151
|
+
let pass = 0, fail2 = 0, not_run = 0;
|
|
14111
14152
|
const not_run_files = [];
|
|
14112
14153
|
const api = this.api === undefined ? loadProjectApi(repoDir) : this.api;
|
|
14113
14154
|
for (const f of files) {
|
|
14114
14155
|
const { cmd, args, interpreter, cwd } = commandFor(f, repoDir, api);
|
|
14115
|
-
const r =
|
|
14156
|
+
const r = spawnSync5(cmd, f.runner === "pytest" ? [...args, "-rfE"] : args, { cwd, encoding: "utf8", timeout: Math.max(1000, this.timeoutMs), env: plainTestEnv() });
|
|
14116
14157
|
const status = r.error ? null : r.status;
|
|
14117
14158
|
const result = classify(f, status, stripAnsi(`${r.stdout ?? ""}
|
|
14118
14159
|
${r.stderr ?? ""}`), repoDir, interpreter);
|
|
14119
14160
|
if (result === "pass")
|
|
14120
14161
|
pass++;
|
|
14121
14162
|
else if (result === "fail")
|
|
14122
|
-
|
|
14163
|
+
fail2++;
|
|
14123
14164
|
else {
|
|
14124
14165
|
not_run++;
|
|
14125
14166
|
not_run_files.push({ file: f.path, reason: notRunReason(status, interpreter) });
|
|
14126
14167
|
}
|
|
14127
14168
|
}
|
|
14128
14169
|
this.lastNotRunFiles = not_run_files;
|
|
14129
|
-
return { pass, fail, not_run };
|
|
14170
|
+
return { pass, fail: fail2, not_run };
|
|
14130
14171
|
}
|
|
14131
14172
|
}
|
|
14132
14173
|
function buildWallBrief(task, repomapText = "", runners = [], hasManifest = false, conventions = "", acceptance = []) {
|
|
@@ -14151,8 +14192,8 @@ ${acceptance.map((a) => `Acceptance: ${a}`).join(`
|
|
|
14151
14192
|
function loadTaskText(ctx, fromPrior) {
|
|
14152
14193
|
if (fromPrior)
|
|
14153
14194
|
return fromPrior;
|
|
14154
|
-
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ??
|
|
14155
|
-
if (
|
|
14195
|
+
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join58(ctx.runDir, "issue.json");
|
|
14196
|
+
if (existsSync37(issueJsonPath)) {
|
|
14156
14197
|
try {
|
|
14157
14198
|
const issue = JSON.parse(readFileSync43(issueJsonPath, "utf8"));
|
|
14158
14199
|
const text2 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
|
|
@@ -14166,7 +14207,7 @@ function loadTaskText(ctx, fromPrior) {
|
|
|
14166
14207
|
}
|
|
14167
14208
|
function wallTargetDir(repoDir, existingTests) {
|
|
14168
14209
|
const first = existingTests[0];
|
|
14169
|
-
return first ?
|
|
14210
|
+
return first ? join58(repoDir, dirname22(first.path)) : join58(repoDir, "tests");
|
|
14170
14211
|
}
|
|
14171
14212
|
function guessRunner(fileName, runners) {
|
|
14172
14213
|
if (fileName.endsWith(".py"))
|
|
@@ -14199,11 +14240,11 @@ async function wallAuthor(ctx, signal, retry) {
|
|
|
14199
14240
|
const tree = prior.intake?.tree;
|
|
14200
14241
|
const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
|
|
14201
14242
|
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative8(ctx.repoDir, targetDir)}/x`);
|
|
14202
|
-
const conv2 = readPackageConventions(
|
|
14203
|
-
const cwd = mkdtempSync10(
|
|
14243
|
+
const conv2 = readPackageConventions(join58(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
|
|
14244
|
+
const cwd = mkdtempSync10(join58(tmpdir11(), "loki-e15-wall-"));
|
|
14204
14245
|
const wm = wallManifestFor(ctx.repoDir, tree, task);
|
|
14205
14246
|
for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
|
|
14206
|
-
writeFileSync26(
|
|
14247
|
+
writeFileSync26(join58(cwd, n2), c, "utf8");
|
|
14207
14248
|
const model = retry?.model ?? wallFirstModel(sz.size), iterationId = `${ctx.runId}-wall${retry?.suffix ?? ""}`;
|
|
14208
14249
|
const session = await ctx.sessions.run({
|
|
14209
14250
|
stage: "wall",
|
|
@@ -14219,15 +14260,15 @@ async function wallAuthor(ctx, signal, retry) {
|
|
|
14219
14260
|
rmSync18(cwd, { recursive: true, force: true });
|
|
14220
14261
|
return done({ status: "failed", data: { iteration_ids: [iterationId], model }, reason: "wall session aborted, killed, or timed out", killed: true });
|
|
14221
14262
|
}
|
|
14222
|
-
const all =
|
|
14223
|
-
const sealedDir =
|
|
14263
|
+
const all = readdirSync18(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(join58(cwd, n2), "utf8"))), runnerOf: (n2) => guessRunner(n2, runners) }), generated = all.filter((n2) => !held?.names.has(n2));
|
|
14264
|
+
const sealedDir = join58(ctx.runDir, "wall");
|
|
14224
14265
|
if (generated.length > 0)
|
|
14225
14266
|
mkdirSync23(sealedDir, { recursive: true });
|
|
14226
14267
|
const contents = new Map;
|
|
14227
14268
|
const discarded = [];
|
|
14228
14269
|
for (const name of generated) {
|
|
14229
|
-
const content = readFileSync43(
|
|
14230
|
-
writeFileSync26(
|
|
14270
|
+
const content = readFileSync43(join58(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
|
|
14271
|
+
writeFileSync26(join58(sealedDir, name), content, "utf8");
|
|
14231
14272
|
if (bad)
|
|
14232
14273
|
discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
|
|
14233
14274
|
else
|
|
@@ -14247,7 +14288,7 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
14247
14288
|
const content = contents.get(name);
|
|
14248
14289
|
if (content === undefined)
|
|
14249
14290
|
continue;
|
|
14250
|
-
const dest =
|
|
14291
|
+
const dest = join58(targetDir, name), runner = guessRunner(name, runners);
|
|
14251
14292
|
writeFileSync26(dest, content, "utf8");
|
|
14252
14293
|
sealedFiles.push({ path: dest, sha256: sha2562(content) });
|
|
14253
14294
|
readOnlyFiles.push({ path: dest, content });
|
|
@@ -14258,7 +14299,7 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
14258
14299
|
ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
|
|
14259
14300
|
const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
|
|
14260
14301
|
for (const t of wallTests) {
|
|
14261
|
-
const r = baseRunner.run(baseDir, [t]), abs =
|
|
14302
|
+
const r = baseRunner.run(baseDir, [t]), abs = join58(ctx.repoDir, t.path);
|
|
14262
14303
|
baseRun.pass += r.pass;
|
|
14263
14304
|
baseRun.fail += r.fail;
|
|
14264
14305
|
baseRun.not_run += r.not_run ?? 0;
|
|
@@ -14298,7 +14339,7 @@ async function runWall(ctx, signal, opts = {}) {
|
|
|
14298
14339
|
if (a.kind === "authored") {
|
|
14299
14340
|
for (const f of first.data.files ?? [])
|
|
14300
14341
|
rmSync18(f.path, { force: true });
|
|
14301
|
-
rmSync18(
|
|
14342
|
+
rmSync18(join58(ctx.runDir, "wall"), { recursive: true, force: true });
|
|
14302
14343
|
ctx.wallSealed = false;
|
|
14303
14344
|
}
|
|
14304
14345
|
removeHoldout(ctx.runId, ctx.repoDir);
|
|
@@ -14333,18 +14374,18 @@ var init_wall = __esm(() => {
|
|
|
14333
14374
|
});
|
|
14334
14375
|
|
|
14335
14376
|
// ../../loki-ts/src/e10ext/discard.ts
|
|
14336
|
-
import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as
|
|
14337
|
-
import { dirname as dirname23, join as
|
|
14377
|
+
import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as lstatSync13, mkdirSync as mkdirSync24, openSync as openSync9, readFileSync as readFileSync44, realpathSync as realpathSync21, rmdirSync, unlinkSync as unlinkSync6, writeFileSync as writeFileSync27 } from "fs";
|
|
14378
|
+
import { dirname as dirname23, join as join59, relative as relative9, sep as sep12 } from "path";
|
|
14338
14379
|
function safeRestore(repoDir, f, want, mode) {
|
|
14339
|
-
const root = realpathSync21(repoDir), fp =
|
|
14380
|
+
const root = realpathSync21(repoDir), fp = join59(root, f), rel = relative9(root, dirname23(fp));
|
|
14340
14381
|
if (rel.startsWith(".."))
|
|
14341
14382
|
throw new Error("outside repo");
|
|
14342
14383
|
let cur = root;
|
|
14343
14384
|
for (const part of rel === "" ? [] : rel.split(sep12)) {
|
|
14344
|
-
cur =
|
|
14385
|
+
cur = join59(cur, part);
|
|
14345
14386
|
let st2;
|
|
14346
14387
|
try {
|
|
14347
|
-
st2 =
|
|
14388
|
+
st2 = lstatSync13(cur);
|
|
14348
14389
|
} catch {
|
|
14349
14390
|
mkdirSync24(cur);
|
|
14350
14391
|
continue;
|
|
@@ -14354,7 +14395,7 @@ function safeRestore(repoDir, f, want, mode) {
|
|
|
14354
14395
|
}
|
|
14355
14396
|
let st;
|
|
14356
14397
|
try {
|
|
14357
|
-
st =
|
|
14398
|
+
st = lstatSync13(fp);
|
|
14358
14399
|
} catch {
|
|
14359
14400
|
st = null;
|
|
14360
14401
|
}
|
|
@@ -14396,10 +14437,10 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14396
14437
|
return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
|
|
14397
14438
|
const notProven = [];
|
|
14398
14439
|
for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
|
|
14399
|
-
const fp =
|
|
14440
|
+
const fp = join59(repoDir, f);
|
|
14400
14441
|
try {
|
|
14401
14442
|
if (v.startsWith("!")) {
|
|
14402
|
-
const st =
|
|
14443
|
+
const st = lstatSync13(fp);
|
|
14403
14444
|
if (`!${st.size}:${st.mtimeMs}:${st.ctimeMs}` !== v)
|
|
14404
14445
|
throw new Error("changed, not snapshotted");
|
|
14405
14446
|
continue;
|
|
@@ -14415,7 +14456,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
14415
14456
|
try {
|
|
14416
14457
|
let m = 420;
|
|
14417
14458
|
try {
|
|
14418
|
-
const l =
|
|
14459
|
+
const l = lstatSync13(join59(repoDir, f));
|
|
14419
14460
|
if (l.isFile())
|
|
14420
14461
|
m = l.mode & 511;
|
|
14421
14462
|
} catch {}
|
|
@@ -14459,7 +14500,7 @@ var init_commit_filter = __esm(() => {
|
|
|
14459
14500
|
});
|
|
14460
14501
|
|
|
14461
14502
|
// ../../loki-ts/src/e10ext/scope.ts
|
|
14462
|
-
import { basename as
|
|
14503
|
+
import { basename as basename20, dirname as dirname25 } from "path";
|
|
14463
14504
|
function contractText(o) {
|
|
14464
14505
|
const c = o.intake?.contract_snapshot?.contract;
|
|
14465
14506
|
return Array.isArray(c?.criteria) ? c.criteria.map((x) => typeof x?.text === "string" ? x.text : "").join(`
|
|
@@ -14474,26 +14515,26 @@ function outsideScope(o, staged) {
|
|
|
14474
14515
|
${typeof o.intake?.task === "string" ? o.intake.task : ""}
|
|
14475
14516
|
${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
|
|
14476
14517
|
const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname25(r)).filter((d) => d !== "."));
|
|
14477
|
-
return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2,
|
|
14518
|
+
return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2, basename20(f)) && !plannedDirs.has(dirname25(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
|
|
14478
14519
|
}
|
|
14479
14520
|
function flagOutsideScope(o, staged) {
|
|
14480
14521
|
const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
|
|
14481
14522
|
const un = outsideScope(o, staged), seen = new Set((unit ?? []).map(outsideNote));
|
|
14482
14523
|
return [...(unit ?? []).map(outsideNote), ...un ? un.map(outsideNote).filter((n2) => !seen.has(n2)) : staged.length > 0 ? [SCOPE_UNDETERMINED] : []];
|
|
14483
14524
|
}
|
|
14484
|
-
var SCOPE_UNDETERMINED = "scope not determined; all edits committed", outsideNote = (f) => `outside stated scope: ${f}`, esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), mentions = (text2, name) => new RegExp(`(?<![\\w./-])${esc2(name)}(?![\\w-]|\\.\\w)`).test(text2),
|
|
14525
|
+
var SCOPE_UNDETERMINED = "scope not determined; all edits committed", outsideNote = (f) => `outside stated scope: ${f}`, esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), mentions = (text2, name) => new RegExp(`(?<![\\w./-])${esc2(name)}(?![\\w-]|\\.\\w)`).test(text2), STOP2, stem = (w) => w.length > 3 && w.endsWith("s") ? w.slice(0, -1) : w, surfaceTokens = (text2) => new Set((text2.toLowerCase().match(/[a-z][a-z0-9_-]{2,}/g) ?? []).filter((w) => !STOP2.has(w)).map(stem)), dirSegs = (f) => f.split("/").slice(0, -1).map((d) => stem(d.toLowerCase()));
|
|
14485
14526
|
var init_scope2 = __esm(() => {
|
|
14486
14527
|
init_testmap();
|
|
14487
14528
|
init_unit_mode();
|
|
14488
|
-
|
|
14529
|
+
STOP2 = new Set(["the", "and", "for", "with", "that", "this", "all", "any", "src", "from", "into", "each", "across", "apply", "add", "use", "make"]);
|
|
14489
14530
|
});
|
|
14490
14531
|
|
|
14491
14532
|
// ../../loki-ts/src/council/role_agents.ts
|
|
14492
|
-
import { existsSync as
|
|
14533
|
+
import { existsSync as existsSync38, readdirSync as readdirSync19, readFileSync as readFileSync45 } from "fs";
|
|
14493
14534
|
import { homedir as homedir9 } from "os";
|
|
14494
|
-
import { join as
|
|
14535
|
+
import { join as join60 } from "path";
|
|
14495
14536
|
function agentDirs(repoDir, env = process.env) {
|
|
14496
|
-
return [env["LOKI_AGENTS_PROJECT_DIR"] ||
|
|
14537
|
+
return [env["LOKI_AGENTS_PROJECT_DIR"] || join60(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join60(env["XDG_CONFIG_HOME"] || join60(homedir9(), ".config"), "loki", "agents")];
|
|
14497
14538
|
}
|
|
14498
14539
|
function parseAgent(file, stem2) {
|
|
14499
14540
|
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync45(file, "utf8"));
|
|
@@ -14510,18 +14551,18 @@ function parseAgent(file, stem2) {
|
|
|
14510
14551
|
}
|
|
14511
14552
|
function loadRoleAgent(repoDir, role, env = process.env) {
|
|
14512
14553
|
for (const d of agentDirs(repoDir, env)) {
|
|
14513
|
-
if (!
|
|
14554
|
+
if (!existsSync38(d))
|
|
14514
14555
|
continue;
|
|
14515
14556
|
let names;
|
|
14516
14557
|
try {
|
|
14517
|
-
names =
|
|
14558
|
+
names = readdirSync19(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
|
|
14518
14559
|
} catch {
|
|
14519
14560
|
continue;
|
|
14520
14561
|
}
|
|
14521
14562
|
const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
|
|
14522
14563
|
for (const n2 of ordered) {
|
|
14523
14564
|
try {
|
|
14524
|
-
const a = parseAgent(
|
|
14565
|
+
const a = parseAgent(join60(d, n2), n2.slice(0, -3));
|
|
14525
14566
|
if (a && a.role === role)
|
|
14526
14567
|
return a;
|
|
14527
14568
|
} catch {}
|
|
@@ -14539,7 +14580,7 @@ var init_role_agents = __esm(() => {
|
|
|
14539
14580
|
|
|
14540
14581
|
// ../../loki-ts/src/util/child_ledger.ts
|
|
14541
14582
|
import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync25 } from "fs";
|
|
14542
|
-
import { join as
|
|
14583
|
+
import { join as join61 } from "path";
|
|
14543
14584
|
function unmeasuredRecord(phase, model, source) {
|
|
14544
14585
|
return { phase, model, input_tokens: 0, output_tokens: 0, cache_creation_tokens: 0, cache_read_tokens: 0, source, cost_status: "unmeasured" };
|
|
14545
14586
|
}
|
|
@@ -14564,9 +14605,9 @@ function recordFromClaudeResult(phase, payload, source = "claude-json") {
|
|
|
14564
14605
|
}
|
|
14565
14606
|
function appendChildLedger(lokiDir2, rec2) {
|
|
14566
14607
|
try {
|
|
14567
|
-
const dir =
|
|
14608
|
+
const dir = join61(lokiDir2, "metrics");
|
|
14568
14609
|
mkdirSync25(dir, { recursive: true });
|
|
14569
|
-
appendFileSync4(
|
|
14610
|
+
appendFileSync4(join61(dir, "child-sessions.jsonl"), `${JSON.stringify(rec2)}
|
|
14570
14611
|
`);
|
|
14571
14612
|
return true;
|
|
14572
14613
|
} catch {
|
|
@@ -14596,12 +14637,12 @@ var init_child_ledger = __esm(() => {
|
|
|
14596
14637
|
});
|
|
14597
14638
|
|
|
14598
14639
|
// ../../loki-ts/src/util/run_summary.ts
|
|
14599
|
-
import { existsSync as
|
|
14600
|
-
import { join as
|
|
14640
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync46, renameSync as renameSync12, statSync as statSync17, writeFileSync as writeFileSync28 } from "fs";
|
|
14641
|
+
import { join as join62 } from "path";
|
|
14601
14642
|
function readRiskRecord(repoDir, sinceMs = 0) {
|
|
14602
14643
|
try {
|
|
14603
|
-
const p =
|
|
14604
|
-
if (
|
|
14644
|
+
const p = join62(repoDir, ".loki", "state", "risk-tier.json");
|
|
14645
|
+
if (statSync17(p).mtimeMs < sinceMs)
|
|
14605
14646
|
return null;
|
|
14606
14647
|
const r = JSON.parse(readFileSync46(p, "utf8"));
|
|
14607
14648
|
return r && typeof r === "object" ? r : null;
|
|
@@ -14617,8 +14658,8 @@ var init_run_summary = __esm(() => {
|
|
|
14617
14658
|
});
|
|
14618
14659
|
|
|
14619
14660
|
// ../../loki-ts/src/engine10/stages/xreview.ts
|
|
14620
|
-
import { existsSync as
|
|
14621
|
-
import { join as
|
|
14661
|
+
import { existsSync as existsSync40, readFileSync as readFileSync47 } from "fs";
|
|
14662
|
+
import { join as join63 } from "path";
|
|
14622
14663
|
function minVerdict(verdict, review) {
|
|
14623
14664
|
const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
|
|
14624
14665
|
return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
|
|
@@ -14631,8 +14672,8 @@ function explicitReview(repoDir, env) {
|
|
|
14631
14672
|
if (flag && isOff(ev))
|
|
14632
14673
|
return "off";
|
|
14633
14674
|
for (const f of ["loki.yaml", "loki.yml"]) {
|
|
14634
|
-
const p =
|
|
14635
|
-
if (!
|
|
14675
|
+
const p = join63(repoDir, f);
|
|
14676
|
+
if (!existsSync40(p))
|
|
14636
14677
|
continue;
|
|
14637
14678
|
try {
|
|
14638
14679
|
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync47(p, "utf8"));
|
|
@@ -14717,7 +14758,7 @@ Review ONLY the diff below. Do not modify files.` : "You are an independent code
|
|
|
14717
14758
|
try {
|
|
14718
14759
|
if (p === "claude")
|
|
14719
14760
|
await ensureClaudeHelpCache();
|
|
14720
|
-
const r = await withChildLedger(run,
|
|
14761
|
+
const r = await withChildLedger(run, join63(ctx.repoDir, ".loki"), "xreview")(reviewArgv(p, prompt, process.env, p === "claude" ? agent?.model : undefined), { cwd: ctx.repoDir, timeoutMs: TIMEOUT_MS });
|
|
14721
14762
|
if (r.exitCode !== 0)
|
|
14722
14763
|
return { provider: p, level: "not_run", notes: [`cross-review not run: ${p} exited ${r.exitCode}`] };
|
|
14723
14764
|
return parseReview(p, r.stdout);
|
|
@@ -14811,14 +14852,14 @@ See also: loki cost --detail (what a run ALREADY spent)
|
|
|
14811
14852
|
});
|
|
14812
14853
|
|
|
14813
14854
|
// ../../loki-ts/src/features/contract.ts
|
|
14814
|
-
import { existsSync as
|
|
14815
|
-
import { dirname as dirname26, join as
|
|
14816
|
-
import { createHash as
|
|
14855
|
+
import { existsSync as existsSync41, lstatSync as lstatSync14, mkdirSync as mkdirSync27, readFileSync as readFileSync48, rmSync as rmSync19, writeFileSync as writeFileSync29 } from "fs";
|
|
14856
|
+
import { dirname as dirname26, join as join64 } from "path";
|
|
14857
|
+
import { createHash as createHash15 } from "crypto";
|
|
14817
14858
|
function contractEnabled(env = process.env) {
|
|
14818
14859
|
return env["LOKI_CONTRACT"] !== "0";
|
|
14819
14860
|
}
|
|
14820
14861
|
function words(s) {
|
|
14821
|
-
return [...new Set(s.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length >= 3 && !
|
|
14862
|
+
return [...new Set(s.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length >= 3 && !STOP3.has(w)))];
|
|
14822
14863
|
}
|
|
14823
14864
|
function overlaps(criterionWords, target) {
|
|
14824
14865
|
const tw = new Set(words(target));
|
|
@@ -14844,13 +14885,13 @@ function untracedLines(trace) {
|
|
|
14844
14885
|
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)}`);
|
|
14845
14886
|
}
|
|
14846
14887
|
function contractPath(repoDir) {
|
|
14847
|
-
return
|
|
14888
|
+
return join64(repoDir, ".loki", "contract.json");
|
|
14848
14889
|
}
|
|
14849
14890
|
function readContract(repoDir) {
|
|
14850
14891
|
const p = contractPath(repoDir);
|
|
14851
14892
|
let st;
|
|
14852
14893
|
try {
|
|
14853
|
-
st =
|
|
14894
|
+
st = lstatSync14(p);
|
|
14854
14895
|
} catch {
|
|
14855
14896
|
return { contract: null, notes: [], sha256: null };
|
|
14856
14897
|
}
|
|
@@ -14864,7 +14905,7 @@ function readContract(repoDir) {
|
|
|
14864
14905
|
} catch {
|
|
14865
14906
|
return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
|
|
14866
14907
|
}
|
|
14867
|
-
const sha2563 =
|
|
14908
|
+
const sha2563 = createHash15("sha256").update(raw2).digest("hex");
|
|
14868
14909
|
let j;
|
|
14869
14910
|
try {
|
|
14870
14911
|
j = JSON.parse(raw2.toString("utf8"));
|
|
@@ -14895,7 +14936,7 @@ function sealContract(repoDir, body, rawDiff, checks, env = process.env, snap) {
|
|
|
14895
14936
|
const live2 = readContract(repoDir);
|
|
14896
14937
|
let exists2 = true;
|
|
14897
14938
|
try {
|
|
14898
|
-
|
|
14939
|
+
lstatSync14(contractPath(repoDir));
|
|
14899
14940
|
} catch {
|
|
14900
14941
|
exists2 = false;
|
|
14901
14942
|
}
|
|
@@ -14921,36 +14962,36 @@ function sealContract(repoDir, body, rawDiff, checks, env = process.env, snap) {
|
|
|
14921
14962
|
return [`contract trace failed: ${sanitizeCriterion(e instanceof Error ? e.message : String(e))}`];
|
|
14922
14963
|
}
|
|
14923
14964
|
}
|
|
14924
|
-
var MAX_CRITERIA = 50, MAX_TEXT = 500,
|
|
14965
|
+
var MAX_CRITERIA = 50, MAX_TEXT = 500, STOP3, MAX_CONTRACT_BYTES, REQ_MAP_REL, REQ_STOP;
|
|
14925
14966
|
var init_contract = __esm(() => {
|
|
14926
14967
|
init_atomic();
|
|
14927
14968
|
init_spec_file();
|
|
14928
14969
|
init_paths();
|
|
14929
14970
|
init_safe_git();
|
|
14930
|
-
|
|
14971
|
+
STOP3 = 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"]);
|
|
14931
14972
|
MAX_CONTRACT_BYTES = 1024 * 1024;
|
|
14932
|
-
REQ_MAP_REL =
|
|
14973
|
+
REQ_MAP_REL = join64(".loki", "state", "requirements-map.json");
|
|
14933
14974
|
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"]);
|
|
14934
14975
|
});
|
|
14935
14976
|
|
|
14936
14977
|
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
14937
|
-
import { createHash as
|
|
14938
|
-
import { existsSync as
|
|
14939
|
-
import { dirname as dirname27, join as
|
|
14978
|
+
import { createHash as createHash16 } from "crypto";
|
|
14979
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync28, readdirSync as readdirSync20, readFileSync as readFileSync49, renameSync as renameSync13, statSync as statSync18, writeFileSync as writeFileSync30 } from "fs";
|
|
14980
|
+
import { dirname as dirname27, join as join65 } from "path";
|
|
14940
14981
|
function sealGroup(runDir, rh) {
|
|
14941
|
-
const manifestPath =
|
|
14942
|
-
if (!
|
|
14982
|
+
const manifestPath = join65(runDir, "group", "manifest.json");
|
|
14983
|
+
if (!existsSync42(manifestPath))
|
|
14943
14984
|
return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
|
|
14944
14985
|
const notProven = [];
|
|
14945
14986
|
let problems = 0;
|
|
14946
|
-
const
|
|
14987
|
+
const fail2 = (m2) => {
|
|
14947
14988
|
problems++;
|
|
14948
14989
|
notProven.push(`group: ${m2}`);
|
|
14949
14990
|
};
|
|
14950
|
-
const m =
|
|
14991
|
+
const m = readJson6(manifestPath);
|
|
14951
14992
|
const list = isObj10(m) && Array.isArray(m["units"]) ? m["units"] : [];
|
|
14952
14993
|
if (!isObj10(m) || !ID_RE.test(String(m["group_id"] ?? "")) || list.length === 0) {
|
|
14953
|
-
|
|
14994
|
+
fail2("manifest missing, unreadable or empty");
|
|
14954
14995
|
return { section: undefined, notProven, problems, allUnitsPass: false };
|
|
14955
14996
|
}
|
|
14956
14997
|
const units = [];
|
|
@@ -14960,19 +15001,19 @@ function sealGroup(runDir, rh) {
|
|
|
14960
15001
|
const u = isObj10(raw2) ? raw2 : {};
|
|
14961
15002
|
const id = String(u["unit_id"] ?? "");
|
|
14962
15003
|
if (!ID_RE.test(id) || seen.has(id) || seenLower.has(id.toLowerCase()))
|
|
14963
|
-
return
|
|
15004
|
+
return fail2(`unit ${index2} has an invalid, duplicate or case-colliding id`);
|
|
14964
15005
|
seen.add(id);
|
|
14965
15006
|
seenLower.add(id.toLowerCase());
|
|
14966
|
-
const dir =
|
|
15007
|
+
const dir = join65(unitsDir(runDir), id), rp = join65(dir, "receipt.json"), ep = join65(dir, "events.jsonl");
|
|
14967
15008
|
let bytes;
|
|
14968
15009
|
try {
|
|
14969
15010
|
bytes = readFileSync49(rp);
|
|
14970
15011
|
} catch {
|
|
14971
|
-
return
|
|
15012
|
+
return fail2(`unit ${id} sub-receipt missing`);
|
|
14972
15013
|
}
|
|
14973
|
-
const sub =
|
|
15014
|
+
const sub = readJson6(rp);
|
|
14974
15015
|
if (!isObj10(sub) || typeof sub["receipt_sha256"] !== "string" || rh(sub) !== sub["receipt_sha256"])
|
|
14975
|
-
return
|
|
15016
|
+
return fail2(`unit ${id} sub-receipt unreadable or its hash does not recompute`);
|
|
14976
15017
|
const verdict = String(sub["verdict"] ?? "");
|
|
14977
15018
|
if (!PASSING.has(verdict)) {
|
|
14978
15019
|
allUnitsPass = false;
|
|
@@ -14983,7 +15024,7 @@ function sealGroup(runDir, rh) {
|
|
|
14983
15024
|
unit_id: id,
|
|
14984
15025
|
sub_receipt_sha256: sha3(bytes),
|
|
14985
15026
|
receipt_sha256: sub["receipt_sha256"],
|
|
14986
|
-
events_file_sha256:
|
|
15027
|
+
events_file_sha256: existsSync42(ep) ? sha3(readFileSync49(ep)) : null,
|
|
14987
15028
|
verdict,
|
|
14988
15029
|
goal: text2(u["goal"], 200),
|
|
14989
15030
|
files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
|
|
@@ -14994,7 +15035,7 @@ function sealGroup(runDir, rh) {
|
|
|
14994
15035
|
});
|
|
14995
15036
|
const extra = (dirNames(unitsDir(runDir)) ?? []).filter((n3) => !seen.has(n3));
|
|
14996
15037
|
for (const n3 of extra)
|
|
14997
|
-
|
|
15038
|
+
fail2(`unit directory ${text2(n3, 64)} is not in the manifest`);
|
|
14998
15039
|
return { section: problems === 0 ? { group_id: String(m["group_id"]), units } : undefined, notProven, problems, allUnitsPass: allUnitsPass && problems === 0 };
|
|
14999
15040
|
}
|
|
15000
15041
|
function capGroupVerdict(v, g) {
|
|
@@ -15008,7 +15049,7 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15008
15049
|
const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
|
|
15009
15050
|
const g = receipt["group"];
|
|
15010
15051
|
if (g === undefined)
|
|
15011
|
-
return
|
|
15052
|
+
return existsSync42(join65(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
|
|
15012
15053
|
if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
|
|
15013
15054
|
return bad("group section malformed");
|
|
15014
15055
|
const entries = g["units"];
|
|
@@ -15020,12 +15061,12 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15020
15061
|
return bad("unit directories do not match the receipt (missing or extra unit)");
|
|
15021
15062
|
let unchecked = null;
|
|
15022
15063
|
for (let i = 0;i < entries.length; i++) {
|
|
15023
|
-
const e = entries[i], id = ids[i], dir =
|
|
15064
|
+
const e = entries[i], id = ids[i], dir = join65(unitsDir(runDir), id), rp = join65(dir, "receipt.json"), ep = join65(dir, "events.jsonl");
|
|
15024
15065
|
if (e["index"] !== i)
|
|
15025
15066
|
return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
|
|
15026
15067
|
let bytes;
|
|
15027
15068
|
try {
|
|
15028
|
-
if (!
|
|
15069
|
+
if (!statSync18(dir).isDirectory())
|
|
15029
15070
|
return bad(`unit ${id} is not a directory`);
|
|
15030
15071
|
bytes = readFileSync49(rp);
|
|
15031
15072
|
} catch {
|
|
@@ -15033,10 +15074,10 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15033
15074
|
}
|
|
15034
15075
|
if (sha3(bytes) !== e["sub_receipt_sha256"])
|
|
15035
15076
|
return bad(`unit ${id} sub-receipt does not match its recorded hash`);
|
|
15036
|
-
const evSha =
|
|
15077
|
+
const evSha = existsSync42(ep) ? sha3(readFileSync49(ep)) : null;
|
|
15037
15078
|
if (evSha !== (e["events_file_sha256"] ?? null))
|
|
15038
15079
|
return bad(`unit ${id} events.jsonl does not match its recorded hash`);
|
|
15039
|
-
const sub =
|
|
15080
|
+
const sub = readJson6(rp);
|
|
15040
15081
|
if (!isObj10(sub) || sub["receipt_sha256"] !== e["receipt_sha256"] || rh(sub) !== e["receipt_sha256"])
|
|
15041
15082
|
return bad(`unit ${id} sub-receipt hash does not recompute`);
|
|
15042
15083
|
if (String(sub["verdict"] ?? "") !== e["verdict"])
|
|
@@ -15056,7 +15097,7 @@ function compositeVerdict(childVerdicts) {
|
|
|
15056
15097
|
const failed2 = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
|
|
15057
15098
|
return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed2, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
|
|
15058
15099
|
}
|
|
15059
|
-
var ID_RE, PASSING, sha3 = (b) =>
|
|
15100
|
+
var ID_RE, PASSING, sha3 = (b) => createHash16("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) => join65(runDir, "group", "units"), readJson6 = (p) => {
|
|
15060
15101
|
try {
|
|
15061
15102
|
return JSON.parse(readFileSync49(p, "utf8"));
|
|
15062
15103
|
} catch {
|
|
@@ -15064,7 +15105,7 @@ var ID_RE, PASSING, sha3 = (b) => createHash17("sha256").update(b).digest("hex")
|
|
|
15064
15105
|
}
|
|
15065
15106
|
}, dirNames = (d) => {
|
|
15066
15107
|
try {
|
|
15067
|
-
return
|
|
15108
|
+
return readdirSync20(d).filter((n3) => !n3.startsWith(".")).sort();
|
|
15068
15109
|
} catch {
|
|
15069
15110
|
return null;
|
|
15070
15111
|
}
|
|
@@ -15076,8 +15117,8 @@ var init_seal_group = __esm(() => {
|
|
|
15076
15117
|
});
|
|
15077
15118
|
|
|
15078
15119
|
// ../../loki-ts/src/supply/supply_guard.ts
|
|
15079
|
-
import { existsSync as
|
|
15080
|
-
import { basename as
|
|
15120
|
+
import { existsSync as existsSync43, readFileSync as readFileSync50, statSync as statSync19 } from "fs";
|
|
15121
|
+
import { basename as basename21, join as join66 } from "path";
|
|
15081
15122
|
function supplyEnabled(env) {
|
|
15082
15123
|
return env["LOKI_SUPPLY_GUARD"] !== "0";
|
|
15083
15124
|
}
|
|
@@ -15089,14 +15130,14 @@ function supplyVerdict(verdict, r) {
|
|
|
15089
15130
|
return r.blocked && verdict === "VERIFIED" ? "FAILED" : verdict;
|
|
15090
15131
|
}
|
|
15091
15132
|
function isManifestPath(path) {
|
|
15092
|
-
return MANIFESTS.test(
|
|
15133
|
+
return MANIFESTS.test(basename21(path));
|
|
15093
15134
|
}
|
|
15094
15135
|
function readDeclared(repoDir) {
|
|
15095
|
-
const p =
|
|
15096
|
-
if (!
|
|
15136
|
+
const p = join66(repoDir, ".loki", DECLARED_FILE);
|
|
15137
|
+
if (!existsSync43(p))
|
|
15097
15138
|
return { deps: [], problem: null };
|
|
15098
15139
|
try {
|
|
15099
|
-
if (
|
|
15140
|
+
if (statSync19(p).size > MAX_FILE_BYTES)
|
|
15100
15141
|
return { deps: [], problem: "declaration file too large" };
|
|
15101
15142
|
const j = JSON.parse(readFileSync50(p, "utf8"));
|
|
15102
15143
|
if (!Array.isArray(j))
|
|
@@ -15118,8 +15159,8 @@ function readDeclared(repoDir) {
|
|
|
15118
15159
|
}
|
|
15119
15160
|
}
|
|
15120
15161
|
function readAllowlist(repoDir) {
|
|
15121
|
-
const p =
|
|
15122
|
-
if (!
|
|
15162
|
+
const p = join66(repoDir, ".loki", "supply-allowlist");
|
|
15163
|
+
if (!existsSync43(p))
|
|
15123
15164
|
return new Set;
|
|
15124
15165
|
try {
|
|
15125
15166
|
return new Set(readFileSync50(p, "utf8").split(`
|
|
@@ -15163,7 +15204,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15163
15204
|
if (eco === "npm") {
|
|
15164
15205
|
if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
|
|
15165
15206
|
return true;
|
|
15166
|
-
return files(
|
|
15207
|
+
return files(join66(repoDir, ".npmrc"), home ? join66(home, ".npmrc") : "").some((t) => t.split(`
|
|
15167
15208
|
`).some((l) => {
|
|
15168
15209
|
const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
|
|
15169
15210
|
return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
|
|
@@ -15172,7 +15213,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15172
15213
|
if (eco === "pypi") {
|
|
15173
15214
|
if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
|
|
15174
15215
|
return true;
|
|
15175
|
-
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ?
|
|
15216
|
+
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join66(home, ".config", "pip", "pip.conf") : "", home ? join66(home, ".pip", "pip.conf") : "", join66(repoDir, "pip.conf")];
|
|
15176
15217
|
return files(...cfg).some((t) => t.split(`
|
|
15177
15218
|
`).some((l) => {
|
|
15178
15219
|
const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
|
|
@@ -15182,7 +15223,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
15182
15223
|
if (eco === "cargo") {
|
|
15183
15224
|
if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
|
|
15184
15225
|
return true;
|
|
15185
|
-
return files(
|
|
15226
|
+
return files(join66(repoDir, ".cargo", "config.toml"), join66(repoDir, ".cargo", "config"), home ? join66(home, ".cargo", "config.toml") : "", home ? join66(home, ".cargo", "config") : "").some((t) => /^\s*\[(registries\.|source\.)/m.test(t) || /replace-with\s*=/.test(t));
|
|
15186
15227
|
}
|
|
15187
15228
|
if (eco === "go") {
|
|
15188
15229
|
const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
|
|
@@ -15305,7 +15346,7 @@ var MIN_AGE_DAYS = 7, DECLARED_FILE = "supply-declared.json", MAX_CHECKED = 50,
|
|
|
15305
15346
|
}
|
|
15306
15347
|
}, 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) => {
|
|
15307
15348
|
try {
|
|
15308
|
-
return
|
|
15349
|
+
return statSync19(p).size <= MAX_FILE_BYTES ? readFileSync50(p, "utf8") : "";
|
|
15309
15350
|
} catch {
|
|
15310
15351
|
return "";
|
|
15311
15352
|
}
|
|
@@ -15320,9 +15361,9 @@ var init_supply_guard = __esm(() => {
|
|
|
15320
15361
|
});
|
|
15321
15362
|
|
|
15322
15363
|
// ../../loki-ts/src/engine10/stages/seal.ts
|
|
15323
|
-
import { createHash as
|
|
15324
|
-
import { existsSync as
|
|
15325
|
-
import { basename as
|
|
15364
|
+
import { createHash as createHash17 } from "crypto";
|
|
15365
|
+
import { existsSync as existsSync44, readdirSync as readdirSync21, mkdirSync as mkdirSync29, readFileSync as readFileSync51, writeFileSync as writeFileSync31 } from "fs";
|
|
15366
|
+
import { basename as basename22, isAbsolute as isAbsolute10, join as join67, relative as relative10 } from "path";
|
|
15326
15367
|
function sanitizeReason(s) {
|
|
15327
15368
|
const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
|
|
15328
15369
|
const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
|
|
@@ -15397,8 +15438,8 @@ function renderReceiptMd(r) {
|
|
|
15397
15438
|
].join(`
|
|
15398
15439
|
`);
|
|
15399
15440
|
}
|
|
15400
|
-
var DEEP_NOT_PROVEN, SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)", AGENT_ONLY_REASON = "only agent-authored tests executed (no agent-independent proof)", EXCLUDE_LOKI = ":(exclude).loki", sha2562 = (s) =>
|
|
15401
|
-
const r = relative10(ctx.repoDir,
|
|
15441
|
+
var DEEP_NOT_PROVEN, SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)", AGENT_ONLY_REASON = "only agent-authored tests executed (no agent-independent proof)", EXCLUDE_LOKI = ":(exclude).loki", sha2562 = (s) => createHash17("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) => {
|
|
15442
|
+
const r = relative10(ctx.repoDir, join67(ctx.runDir, "receipt.json"));
|
|
15402
15443
|
return r.startsWith("..") || isAbsolute10(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
|
|
15403
15444
|
}, commitStage, wallGreenOnBaseOf = (o) => {
|
|
15404
15445
|
const b = o.wall?.base_run ?? {};
|
|
@@ -15510,8 +15551,8 @@ var init_seal = __esm(() => {
|
|
|
15510
15551
|
notProven.add(`Wall test not executed: ${wallNotRun} file(s), no reason recorded`);
|
|
15511
15552
|
if (wallNotRun > 0) {
|
|
15512
15553
|
try {
|
|
15513
|
-
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) =>
|
|
15514
|
-
for (const n3 of
|
|
15554
|
+
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename22(String(f.path))));
|
|
15555
|
+
for (const n3 of readdirSync21(join67(ctx.runDir, "wall")).sort())
|
|
15515
15556
|
if (!kept.has(n3))
|
|
15516
15557
|
notProven.add(`wall test discarded: ${n3} (not_run)`);
|
|
15517
15558
|
} catch {}
|
|
@@ -15574,19 +15615,19 @@ var init_seal = __esm(() => {
|
|
|
15574
15615
|
for (const [s, d] of Object.entries(o))
|
|
15575
15616
|
if (typeof d?.duration_s === "number")
|
|
15576
15617
|
stages[s] = d.duration_s;
|
|
15577
|
-
const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(
|
|
15618
|
+
const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(join67(ctx.runDir, "events.jsonl"))) : { wall_s: Object.values(stages).reduce((a, b) => a + (b ?? 0), 0), stages }, totalS = T?.reconciled(time) ?? null;
|
|
15578
15619
|
const iterIds = [...new Set([...Object.values(o).flatMap((d) => [...strs2(d?.iteration_ids), ...strs2([d?.iteration_id])]), ...ctx.sessionIds?.() ?? []])];
|
|
15579
15620
|
if (iterIds.length === 0)
|
|
15580
15621
|
notProven.add("cost not measured (no iteration ids recorded)");
|
|
15581
15622
|
const cost = ctx.cost.read(ctx.repoDir, iterIds);
|
|
15582
15623
|
if (cost.unmetered)
|
|
15583
15624
|
notProven.add("cost unmetered (CLI invoker; recorded as 0)");
|
|
15584
|
-
const eventsPath =
|
|
15625
|
+
const eventsPath = join67(ctx.runDir, "events.jsonl");
|
|
15585
15626
|
const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
|
|
15586
15627
|
const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
|
|
15587
15628
|
if (wallFiles.length > 0 && wallPassed === null)
|
|
15588
15629
|
notProven.add("wall result not recorded by verify");
|
|
15589
|
-
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(
|
|
15630
|
+
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(join67(ctx.repoDir, ".loki"), liveArchivedCosts(join67(ctx.repoDir, ".loki"), iterIds, UNMETERED)).router : undefined), ctx.model);
|
|
15590
15631
|
if (routeBlock)
|
|
15591
15632
|
for (const l of routeNotProven(routeBlock))
|
|
15592
15633
|
notProven.add(l);
|
|
@@ -15628,7 +15669,7 @@ var init_seal = __esm(() => {
|
|
|
15628
15669
|
provider: ctx.provider,
|
|
15629
15670
|
model: ctx.model,
|
|
15630
15671
|
resumed: o.intake?.resumed === true,
|
|
15631
|
-
events_sha256: sha2562(
|
|
15672
|
+
events_sha256: sha2562(existsSync44(eventsPath) ? readFileSync51(eventsPath) : ""),
|
|
15632
15673
|
...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
|
|
15633
15674
|
log_seal: true,
|
|
15634
15675
|
...receiptBlock(process.env, cost.usd, cost.unmetered === true, totalS),
|
|
@@ -15650,10 +15691,10 @@ var init_seal = __esm(() => {
|
|
|
15650
15691
|
}
|
|
15651
15692
|
const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
15652
15693
|
mkdirSync29(ctx.runDir, { recursive: true });
|
|
15653
|
-
const path =
|
|
15694
|
+
const path = join67(ctx.runDir, "receipt.json");
|
|
15654
15695
|
writeFileSync31(path, JSON.stringify(receipt, null, 2) + `
|
|
15655
15696
|
`);
|
|
15656
|
-
writeFileSync31(
|
|
15697
|
+
writeFileSync31(join67(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
|
|
15657
15698
|
recordRun(process.env, ctx.repoDir, ranModel(o.implement, ctx.model, o.fix), verdict, cost.usd, cost.unmetered === true, totalS);
|
|
15658
15699
|
try {
|
|
15659
15700
|
hooks.sealed?.(ctx.runDir, JSON.parse(JSON.stringify(receipt), (_k, v) => v && typeof v === "object" ? Object.freeze(v) : v));
|
|
@@ -15765,14 +15806,14 @@ var DSSE_PAYLOAD_TYPE = "application/vnd.in-toto+json", STATEMENT_TYPE = "https:
|
|
|
15765
15806
|
var init_receipt_dsse = () => {};
|
|
15766
15807
|
|
|
15767
15808
|
// ../../loki-ts/src/util/composite_seal.ts
|
|
15768
|
-
import { existsSync as
|
|
15769
|
-
import { basename as
|
|
15809
|
+
import { existsSync as existsSync45, readFileSync as readFileSync53 } from "fs";
|
|
15810
|
+
import { basename as basename23, dirname as dirname29, join as join68 } from "path";
|
|
15770
15811
|
function logProblem(runDir, integ) {
|
|
15771
15812
|
if (typeof integ["log_sha256"] !== "string")
|
|
15772
15813
|
return null;
|
|
15773
15814
|
let b;
|
|
15774
15815
|
try {
|
|
15775
|
-
b = readFileSync53(
|
|
15816
|
+
b = readFileSync53(join68(runDir, "integration.log"));
|
|
15776
15817
|
} catch {
|
|
15777
15818
|
return "integration.log is missing but integration.json records its hash";
|
|
15778
15819
|
}
|
|
@@ -15795,13 +15836,13 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15795
15836
|
return bad("body malformed");
|
|
15796
15837
|
let ibytes;
|
|
15797
15838
|
try {
|
|
15798
|
-
ibytes = readFileSync53(
|
|
15839
|
+
ibytes = readFileSync53(join68(runDir, "integration.json"));
|
|
15799
15840
|
} catch {
|
|
15800
15841
|
return bad("integration.json missing");
|
|
15801
15842
|
}
|
|
15802
15843
|
if (sha3(ibytes) !== receipt["integration_sha256"])
|
|
15803
15844
|
return bad("integration.json does not match its recorded hash");
|
|
15804
|
-
const integ =
|
|
15845
|
+
const integ = readJson6(join68(runDir, "integration.json"));
|
|
15805
15846
|
if (!isObj10(integ) || !isObj10(integ["outcomes"]))
|
|
15806
15847
|
return bad("integration.json has no outcomes");
|
|
15807
15848
|
const iprob = integrationProblem(integ);
|
|
@@ -15831,7 +15872,7 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15831
15872
|
return bad(`child ${text2(repo, 80) || "?"} has an invalid receipt path`);
|
|
15832
15873
|
if (outcomes[repo] !== "ok")
|
|
15833
15874
|
return bad(`child ${text2(repo, 80)} did not finish ok in integration.json`);
|
|
15834
|
-
const rp =
|
|
15875
|
+
const rp = join68(runDir, rel);
|
|
15835
15876
|
let bytes;
|
|
15836
15877
|
try {
|
|
15837
15878
|
bytes = readFileSync53(rp);
|
|
@@ -15840,7 +15881,7 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15840
15881
|
}
|
|
15841
15882
|
if (sha3(bytes) !== c["receipt_file_sha256"])
|
|
15842
15883
|
return bad(`child ${repo} receipt does not match its recorded hash (swapped or edited)`);
|
|
15843
|
-
const sub =
|
|
15884
|
+
const sub = readJson6(rp);
|
|
15844
15885
|
if (!isObj10(sub) || sub["receipt_sha256"] !== c["receipt_sha256"] || rh(sub) !== c["receipt_sha256"])
|
|
15845
15886
|
return bad(`child ${repo} receipt hash does not recompute`);
|
|
15846
15887
|
if (String(sub["verdict"] ?? "") !== c["verdict"])
|
|
@@ -15883,9 +15924,9 @@ var init_keys_cmd = __esm(() => {
|
|
|
15883
15924
|
});
|
|
15884
15925
|
|
|
15885
15926
|
// ../../loki-ts/src/engine10/verify_cmd.ts
|
|
15886
|
-
import { existsSync as
|
|
15887
|
-
import { basename as
|
|
15888
|
-
import { createHash as
|
|
15927
|
+
import { existsSync as existsSync46, readFileSync as readFileSync54, renameSync as renameSync14, statSync as statSync21, writeFileSync as writeFileSync32 } from "fs";
|
|
15928
|
+
import { basename as basename24, dirname as dirname30, join as join69 } from "path";
|
|
15929
|
+
import { createHash as createHash18, createPublicKey as createPublicKey4, verify as verify4 } from "crypto";
|
|
15889
15930
|
function pubFor(kid, given) {
|
|
15890
15931
|
if (given)
|
|
15891
15932
|
return kidOf2(given) === kid ? given : undefined;
|
|
@@ -15931,13 +15972,13 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15931
15972
|
}
|
|
15932
15973
|
if (typeof bound !== "string")
|
|
15933
15974
|
return null;
|
|
15934
|
-
if (bound ===
|
|
15975
|
+
if (bound === createHash18("sha256").digest("hex")) {
|
|
15935
15976
|
const st = receipt["time"]?.stages;
|
|
15936
15977
|
const claims = st !== null && typeof st === "object" && Object.keys(st).length > 0;
|
|
15937
15978
|
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;
|
|
15938
15979
|
}
|
|
15939
|
-
const path =
|
|
15940
|
-
if (!
|
|
15980
|
+
const path = join69(dirname30(receiptPath), "events.jsonl");
|
|
15981
|
+
if (!existsSync46(path))
|
|
15941
15982
|
return "events.jsonl is missing";
|
|
15942
15983
|
const raw2 = readFileSync54(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
|
|
15943
15984
|
`).filter((l) => l.trim() !== "");
|
|
@@ -15945,7 +15986,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15945
15986
|
return "events.jsonl has a forged, edited or missing line";
|
|
15946
15987
|
if (events2.some((e) => e.type === "tamper.detected"))
|
|
15947
15988
|
return "the supervisor detected events.jsonl being modified during the run";
|
|
15948
|
-
const h =
|
|
15989
|
+
const h = createHash18("sha256");
|
|
15949
15990
|
for (const l of lines2) {
|
|
15950
15991
|
if (h.copy().digest("hex") === bound)
|
|
15951
15992
|
return null;
|
|
@@ -15955,7 +15996,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15955
15996
|
return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
|
|
15956
15997
|
}
|
|
15957
15998
|
function checkLogSeal(receiptPath, hash, kid, given) {
|
|
15958
|
-
const path =
|
|
15999
|
+
const path = join69(dirname30(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
|
|
15959
16000
|
if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
|
|
15960
16001
|
return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
|
|
15961
16002
|
if (done < 0)
|
|
@@ -15964,7 +16005,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15964
16005
|
if (!d)
|
|
15965
16006
|
return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
|
|
15966
16007
|
const lines2 = readFileSync54(path, "utf8").split(`
|
|
15967
|
-
`).filter((l) => l.trim() !== ""), sha4 =
|
|
16008
|
+
`).filter((l) => l.trim() !== ""), sha4 = createHash18("sha256").update(lines2.slice(0, done + 1).join(`
|
|
15968
16009
|
`) + `
|
|
15969
16010
|
`).digest("hex");
|
|
15970
16011
|
const pub = d["kid"] === kid ? pubFor(kid, given) : undefined;
|
|
@@ -15973,7 +16014,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
15973
16014
|
return null;
|
|
15974
16015
|
}
|
|
15975
16016
|
async function verifyReceipt(receiptPath, deps = {}) {
|
|
15976
|
-
if (!
|
|
16017
|
+
if (!existsSync46(receiptPath))
|
|
15977
16018
|
return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
|
|
15978
16019
|
let receipt;
|
|
15979
16020
|
try {
|
|
@@ -16066,8 +16107,8 @@ var init_verify_cmd = __esm(() => {
|
|
|
16066
16107
|
});
|
|
16067
16108
|
|
|
16068
16109
|
// src/server/app.ts
|
|
16069
|
-
import { existsSync as
|
|
16070
|
-
import { join as
|
|
16110
|
+
import { existsSync as existsSync48, readFileSync as readFileSync57, statSync as statSync22 } from "fs";
|
|
16111
|
+
import { join as join72, resolve as resolve14, sep as sep14 } from "path";
|
|
16071
16112
|
|
|
16072
16113
|
// node_modules/hono/dist/request/constants.js
|
|
16073
16114
|
var GET_MATCH_RESULT = Symbol();
|
|
@@ -26351,7 +26392,7 @@ function mount20(ctx) {
|
|
|
26351
26392
|
// src/server/routes/verify.ts
|
|
26352
26393
|
import { readFileSync as readFileSync55, realpathSync as realpathSync22 } from "fs";
|
|
26353
26394
|
import { createPublicKey as createPublicKey5 } from "crypto";
|
|
26354
|
-
import { join as
|
|
26395
|
+
import { join as join70, sep as sep13 } from "path";
|
|
26355
26396
|
init_verify_cmd();
|
|
26356
26397
|
init_seal();
|
|
26357
26398
|
init_receipt_dsse();
|
|
@@ -26378,11 +26419,11 @@ function mount21(ctx) {
|
|
|
26378
26419
|
return done(404, "receipt not available", "not_found");
|
|
26379
26420
|
let runDir, file;
|
|
26380
26421
|
try {
|
|
26381
|
-
const root = realpathSync22(
|
|
26382
|
-
runDir = realpathSync22(
|
|
26383
|
-
if (runDir !==
|
|
26422
|
+
const root = realpathSync22(join70(repo.p, ".loki", "runs"));
|
|
26423
|
+
runDir = realpathSync22(join70(root, run2));
|
|
26424
|
+
if (runDir !== join70(root, run2))
|
|
26384
26425
|
return done(404, "receipt not found", "not_found");
|
|
26385
|
-
file = realpathSync22(
|
|
26426
|
+
file = realpathSync22(join70(runDir, "receipt.json"));
|
|
26386
26427
|
} catch {
|
|
26387
26428
|
return done(404, "receipt not found", "not_found");
|
|
26388
26429
|
}
|
|
@@ -26463,8 +26504,8 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
|
|
|
26463
26504
|
}
|
|
26464
26505
|
|
|
26465
26506
|
// src/server/legacy/shim.ts
|
|
26466
|
-
import { existsSync as
|
|
26467
|
-
import { join as
|
|
26507
|
+
import { existsSync as existsSync47, readFileSync as readFileSync56 } from "fs";
|
|
26508
|
+
import { join as join71 } from "path";
|
|
26468
26509
|
|
|
26469
26510
|
// src/server/legacy/routes.ts
|
|
26470
26511
|
var LEGACY_ROUTES = [
|
|
@@ -26842,9 +26883,9 @@ var logged = new Set;
|
|
|
26842
26883
|
var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
|
|
26843
26884
|
var NOT_SUPPORTED = "not yet supported by the Control Plane";
|
|
26844
26885
|
var repoVersion = () => {
|
|
26845
|
-
for (const f of [
|
|
26886
|
+
for (const f of [join71(import.meta.dir, "../../../../../VERSION")]) {
|
|
26846
26887
|
try {
|
|
26847
|
-
if (
|
|
26888
|
+
if (existsSync47(f))
|
|
26848
26889
|
return readFileSync56(f, "utf8").trim();
|
|
26849
26890
|
} catch {}
|
|
26850
26891
|
}
|
|
@@ -27027,7 +27068,7 @@ function legacyShim(opts) {
|
|
|
27027
27068
|
|
|
27028
27069
|
// src/server/app.ts
|
|
27029
27070
|
var MAX_BODY2 = 1e6;
|
|
27030
|
-
var defaultUiDir = () => [
|
|
27071
|
+
var defaultUiDir = () => [join72(import.meta.dir, "../../ui/dist"), join72(import.meta.dir, "../ui/dist")].find((d) => existsSync48(join72(d, "index.html")));
|
|
27031
27072
|
function createApp(opts) {
|
|
27032
27073
|
const uiDir = opts.uiDir ?? defaultUiDir();
|
|
27033
27074
|
const { db, sqlite } = openDb(opts.dbPath);
|
|
@@ -27056,7 +27097,7 @@ function createApp(opts) {
|
|
|
27056
27097
|
await next();
|
|
27057
27098
|
});
|
|
27058
27099
|
const readInstalled = () => {
|
|
27059
|
-
for (const f of [process.env.LOKI_VERSION_FILE,
|
|
27100
|
+
for (const f of [process.env.LOKI_VERSION_FILE, join72(import.meta.dir, "../../../../VERSION")]) {
|
|
27060
27101
|
try {
|
|
27061
27102
|
if (f)
|
|
27062
27103
|
return readFileSync57(f, "utf8").trim() || "unknown";
|
|
@@ -27168,13 +27209,13 @@ function createApp(opts) {
|
|
|
27168
27209
|
}
|
|
27169
27210
|
if (!uiDir || p.startsWith("/v1/"))
|
|
27170
27211
|
return c.json({ error: "not found" }, 404);
|
|
27171
|
-
const root =
|
|
27172
|
-
const f =
|
|
27173
|
-
if (f.startsWith(root + sep14) &&
|
|
27212
|
+
const root = resolve14(uiDir);
|
|
27213
|
+
const f = resolve14(root, `.${p}`);
|
|
27214
|
+
if (f.startsWith(root + sep14) && existsSync48(f) && statSync22(f).isFile())
|
|
27174
27215
|
return new Response(Bun.file(f));
|
|
27175
27216
|
if (/\.[a-z0-9]+$/i.test(p))
|
|
27176
27217
|
return c.json({ error: "not found" }, 404);
|
|
27177
|
-
return new Response(Bun.file(
|
|
27218
|
+
return new Response(Bun.file(join72(root, "index.html")));
|
|
27178
27219
|
});
|
|
27179
27220
|
return { app, db, close: () => {
|
|
27180
27221
|
clearInterval(reconciler);
|