loki-mode 11.17.67 → 11.17.69
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/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/FAILURE-CLASSES.md +17 -0
- package/docs/v10/PROGRESS.md +6 -0
- package/loki-ts/dist/loki.js +1125 -1123
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +391 -339
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-Qa4gBgov.js → AdminPage-C_qR4zy7.js} +1 -1
- package/web-app/dist/assets/{Avatar-efTNmkmO.js → Avatar-DnvHXfPI.js} +1 -1
- package/web-app/dist/assets/{Badge-CK4rc7EB.js → Badge-C4ZYHMuc.js} +1 -1
- package/web-app/dist/assets/{Button-EJaTtEtn.js → Button-EMp1tPF9.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BQTfAMqI.js → CockpitPage-lml6VuTn.js} +1 -1
- package/web-app/dist/assets/{ComparePage-BVrkV0Ng.js → ComparePage-Wjm2LdZC.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-BNuHgr9r.js → ErrorBoundary-BTm5xHyL.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel--Wa-QyXy.js → EvidenceReceiptPanel-id7I2aqm.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-D-rAxU57.js → GitHubIssuesPanel-CbCd9Otj.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-D-EkwtNX.js → GitHubPRsPanel-Bq8tMMu6.js} +1 -1
- package/web-app/dist/assets/{HomePage-DOqpDt3n.js → HomePage-BzUB8e--.js} +2 -2
- package/web-app/dist/assets/{LoginPage-BdIpRA07.js → LoginPage-DUUI2zrl.js} +1 -1
- package/web-app/dist/assets/{MagicPage-JmGuSXOw.js → MagicPage-BEX4S1KC.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-rZmEbfYy.js → MetricsPage-DfBbEsEu.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-0f68R93z.js → NotFoundPage-Bkv9ZZzQ.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-Bp-ESNWK.js → ProjectPage-DOgdtOXN.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-BsBCWYpr.js → ProjectsPage-B-slNM2P.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-CNX97dyG.js → SettingsPage-CFGC7fFg.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-B6USf2fE.js → ShowcasePage-BbQ3ccy6.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-JOg76RLX.js → SystemSettingsPage-DYodJebp.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-C_MbEYKQ.js → TeamsPage-BVIx-if5.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-D6GG3YaD.js → TemplatesPage-Ct9-8u8u.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-xPHdR6Pn.js → TerminalOutput-D-X-i_Uy.js} +1 -1
- package/web-app/dist/assets/{activity-BsfOdOmx.js → activity-XtVDm9YM.js} +1 -1
- package/web-app/dist/assets/{bell-Bv2c5maD.js → bell-DZ1AzOTU.js} +1 -1
- package/web-app/dist/assets/{bot-CwISrbFp.js → bot-Dqrsif0B.js} +1 -1
- package/web-app/dist/assets/{check-4UMCmMrx.js → check-DaBVVPd9.js} +1 -1
- package/web-app/dist/assets/{chevron-left-DpKdpXdw.js → chevron-left-BeoAdvKm.js} +1 -1
- package/web-app/dist/assets/{circle-alert-B10hQv6x.js → circle-alert-BGOBsaeF.js} +1 -1
- package/web-app/dist/assets/{clock-_fgSSzc8.js → clock-BCFnT4yz.js} +1 -1
- package/web-app/dist/assets/{cloud-DcqwLZCt.js → cloud-BaGTh9cq.js} +1 -1
- package/web-app/dist/assets/{code-xml-DWSzxARy.js → code-xml-BO-JH0jv.js} +1 -1
- package/web-app/dist/assets/{database-BZNt8CdB.js → database-RaYcmIax.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-T2Q2FX-M.js → dollar-sign-CgdQQcxn.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-CNVXYv89.js → file-code-corner-Cbf_1Rlv.js} +1 -1
- package/web-app/dist/assets/{file-plus-J498H8Gi.js → file-plus-CdXrKEem.js} +1 -1
- package/web-app/dist/assets/{globe-yPUkr5E_.js → globe-S0Hf2_GX.js} +1 -1
- package/web-app/dist/assets/{hammer-CiEKjMkP.js → hammer-CH1L0xVv.js} +1 -1
- package/web-app/dist/assets/{index-B9O_HR7I.js → index-B7GtD7qX.js} +3 -3
- package/web-app/dist/assets/{layers-C5je2Gm3.js → layers-DBH-gqE9.js} +1 -1
- package/web-app/dist/assets/{loader-circle-i2izIIWo.js → loader-circle-BfLPVZuJ.js} +1 -1
- package/web-app/dist/assets/{lock-B-jl4ziA.js → lock-Pw97OPl8.js} +1 -1
- package/web-app/dist/assets/{package-D5x3FL7c.js → package-Dre4l_Xj.js} +1 -1
- package/web-app/dist/assets/{plus-BzSslmtd.js → plus-B1HQ5-9a.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-DfnUhgek.js → refresh-cw-Bza9QU8W.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-iuRaooxt.js → rotate-ccw-DrXwMAXs.js} +1 -1
- package/web-app/dist/assets/{scroll-text-C7vGPzBx.js → scroll-text-VwVYqam1.js} +1 -1
- package/web-app/dist/assets/{server-CQqjDruY.js → server-DSAmHFdH.js} +1 -1
- package/web-app/dist/assets/{shield-alert-DhvInzrc.js → shield-alert-CcCMi6RY.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BJkdEnFB.js → thumbs-up-Cc33ahlR.js} +1 -1
- package/web-app/dist/assets/{trash-2-DRXkf-Xt.js → trash-2-DhR9mcV-.js} +1 -1
- package/web-app/dist/assets/{trending-down-LoBkUtqd.js → trending-down-C3uQ1vsQ.js} +1 -1
- package/web-app/dist/assets/{trending-up-BZrKN4XD.js → trending-up-rsrDQbJY.js} +1 -1
- package/web-app/dist/assets/{upload-ChWk0ZsA.js → upload-b_j9Aw4d.js} +1 -1
- package/web-app/dist/assets/{usePolling-Ttl__jEW.js → usePolling-YKiwb1w5.js} +1 -1
- package/web-app/dist/assets/{user-CuR9mmaM.js → user-DnHQrkf4.js} +1 -1
- package/web-app/dist/index.html +1 -1
|
@@ -9418,15 +9418,15 @@ function classifyRisk(files, env = process.env) {
|
|
|
9418
9418
|
summary
|
|
9419
9419
|
};
|
|
9420
9420
|
}
|
|
9421
|
-
function changedFiles(repoDir, baseSha) {
|
|
9421
|
+
function changedFiles(repoDir, baseSha, skip) {
|
|
9422
9422
|
const run = (args) => safeGit(repoDir, args).split(`
|
|
9423
9423
|
`).map((l) => l.trim()).filter(Boolean);
|
|
9424
9424
|
const tracked = run(["diff", "--name-only", baseSha]);
|
|
9425
9425
|
const untracked = run(["ls-files", "--others", "--exclude-standard"]);
|
|
9426
|
-
return [...new Set([...tracked, ...untracked])].filter((f) => !f.startsWith(".loki/"));
|
|
9426
|
+
return [...new Set([...tracked, ...untracked])].filter((f) => !f.startsWith(".loki/") && !skip?.(f));
|
|
9427
9427
|
}
|
|
9428
|
-
function diffFiles(repoDir, baseSha) {
|
|
9429
|
-
const paths = changedFiles(repoDir, baseSha), stat = new Map;
|
|
9428
|
+
function diffFiles(repoDir, baseSha, skip) {
|
|
9429
|
+
const paths = changedFiles(repoDir, baseSha, skip), stat = new Map;
|
|
9430
9430
|
for (const l of safeGit(repoDir, ["diff", "--numstat", baseSha]).split(`
|
|
9431
9431
|
`)) {
|
|
9432
9432
|
const [a, d, ...p] = l.split("\t"), path = p.join("\t");
|
|
@@ -9710,7 +9710,7 @@ var NO_TESTS_REASON = "no tests executed", GO_EXIT0_REASON = "test count could n
|
|
|
9710
9710
|
`).filter((x) => x.trim()).slice(-12), GO_PKG_RE, isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0, hasExecutedProof = (checks) => checks.some(isExecutedProof), LLM_JUDGES, NON_RUNNER, normPath = (p) => p.replace(/^(?:\.\/)+/, ""), hasExogenousProof = (checks, ctx) => checks.some((c) => isExecutedProof(c) && ((p) => p !== "agent_authored" && p !== "llm_judge")(checkProvenance(c.name ?? "", ctx))), SENSITIVE, API, TEST_CFG, RANK2, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c)), MANIFEST_LOCKS, dirOf = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "", PKG_DEP_KEYS, PYPROJECT_NONDEP, EXCERPT_GROUP_CAP = 1500, EXCERPT_TOTAL_CAP = 6144, verifyJobs = () => {
|
|
9711
9711
|
const n2 = Number.parseInt(process.env["LOKI_E10_VERIFY_JOBS"] ?? "", 10);
|
|
9712
9712
|
return Number.isFinite(n2) && n2 >= 1 ? Math.min(n2, 8) : 1;
|
|
9713
|
-
};
|
|
9713
|
+
}, FULL_SUITE_CMD;
|
|
9714
9714
|
var init_check_result = __esm(() => {
|
|
9715
9715
|
init_resolve();
|
|
9716
9716
|
init_testmap();
|
|
@@ -9748,6 +9748,16 @@ var init_check_result = __esm(() => {
|
|
|
9748
9748
|
];
|
|
9749
9749
|
PKG_DEP_KEYS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
9750
9750
|
PYPROJECT_NONDEP = /^(name|version|description|readme|license|requires-python|python|authors|maintainers|keywords|classifiers|homepage|repository|documentation|packages|include|exclude)$/;
|
|
9751
|
+
FULL_SUITE_CMD = {
|
|
9752
|
+
pytest: { cmd: "python", args: ["-m", "pytest", "-q"] },
|
|
9753
|
+
vitest: { cmd: "npx", args: ["vitest", "run"] },
|
|
9754
|
+
jest: { cmd: "npx", args: ["jest"] },
|
|
9755
|
+
bun: { cmd: "bun", args: ["test"] },
|
|
9756
|
+
node: { cmd: "node", args: ["--test"] },
|
|
9757
|
+
npm: { cmd: "npm", args: ["test", "--silent"] },
|
|
9758
|
+
go: { cmd: "go", args: ["test", "-json", "./..."] },
|
|
9759
|
+
cargo: { cmd: "cargo", args: ["test"] }
|
|
9760
|
+
};
|
|
9751
9761
|
});
|
|
9752
9762
|
|
|
9753
9763
|
// ../../loki-ts/src/util/receipt_signer.ts
|
|
@@ -10713,7 +10723,7 @@ function failIds(output) {
|
|
|
10713
10723
|
}
|
|
10714
10724
|
var ID_LINE;
|
|
10715
10725
|
var init_failures = __esm(() => {
|
|
10716
|
-
ID_LINE = /^(?:(?:FAILED|ERROR)\s+(\S+::\S*)(?:\s.*)?|\u25cf\s+(?!Console|Test suite failed)(.+)|not ok \d+ - (.+?)(?:\s+#.*)?|\u2716\s+(?!failing tests:)(.+?)(?:\s+\([\d.]+ms\))?|(
|
|
10726
|
+
ID_LINE = /^(?:(?:FAILED|ERROR)\s+(\S+::\S*)(?:\s.*)?|\u25cf\s+(?!Console|Test suite failed)(.+)|not ok \d+ - (.+?)(?:\s+#.*)?|\u2716\s+(?!failing tests:)(.+?)(?:\s+\([\d.]+ms\))?|FAIL\s+(.+)|\u00d7\s+(.+?)(?:\s+\d+(?:\.\d+)?\s*m?s)?)$/;
|
|
10717
10727
|
});
|
|
10718
10728
|
|
|
10719
10729
|
// ../../loki-ts/src/runner/state.ts
|
|
@@ -10785,10 +10795,14 @@ function attribute(repoDir, baseSha, failing) {
|
|
|
10785
10795
|
const p = loadProfile(repoDir), none = { preExistingChecks: [], preExistingIds: [], introducedChecks: failing.map((f) => f.name), line: null };
|
|
10786
10796
|
if (!p || p.revision !== baseSha || !p.baseline.attributable || p.baseline.failing_ids.length === 0 || failing.length === 0)
|
|
10787
10797
|
return none;
|
|
10788
|
-
const base = new Set(p.baseline.failing_ids)
|
|
10798
|
+
const base = new Set(p.baseline.failing_ids);
|
|
10799
|
+
return split(failing.map((f) => ({ ...f, base })), base.size);
|
|
10800
|
+
}
|
|
10801
|
+
function split(failing, known) {
|
|
10802
|
+
const pre = failing.filter((f) => f.eligible && f.ids?.length && f.ids.every((i) => f.base.has(i)));
|
|
10789
10803
|
const introduced = failing.filter((f) => !pre.includes(f)).map((f) => f.name);
|
|
10790
10804
|
if (pre.length === 0)
|
|
10791
|
-
return {
|
|
10805
|
+
return { preExistingChecks: [], preExistingIds: [], introducedChecks: introduced, line: `baseline: ${known} known failure(s) before this run; none of the failing checks match them, ${introduced.length} introduced (blocking)` };
|
|
10792
10806
|
return {
|
|
10793
10807
|
preExistingChecks: pre.map((f) => f.name),
|
|
10794
10808
|
preExistingIds: pre.flatMap((f) => f.ids ?? []),
|
|
@@ -10797,14 +10811,20 @@ function attribute(repoDir, baseSha, failing) {
|
|
|
10797
10811
|
};
|
|
10798
10812
|
}
|
|
10799
10813
|
function attributeFullSuite(repoDir, baseSha, full, blocked, changed) {
|
|
10800
|
-
const bad = full.filter((c) => c.result === "fail"), none = { preExistingChecks: [], preExistingIds: [], introducedChecks: bad.map((c) => c.name), line: null };
|
|
10801
|
-
|
|
10802
|
-
if (!bad.length || !p || p.revision !== baseSha || !p.baseline.attributable || !p.baseline.failing_ids.length)
|
|
10814
|
+
const bad = full.filter((c) => c.result === "fail"), none = { preExistingChecks: [], preExistingIds: [], introducedChecks: bad.map((c) => c.name), line: null }, p = loadProfile(repoDir);
|
|
10815
|
+
if (!bad.length || !p || p.revision !== baseSha)
|
|
10803
10816
|
return none;
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10817
|
+
const runs2 = [p.baseline, ...p.suites ?? []].filter((b) => b.ran), of = (cmd) => runs2.find((b) => normCmd(b.command ?? "") === normCmd(cmd));
|
|
10818
|
+
const ids = (cmd) => {
|
|
10819
|
+
const b = of(cmd);
|
|
10820
|
+
return b?.attributable ? b.failing_ids : [];
|
|
10821
|
+
}, miss = bad.find((c) => !of(c.cmd));
|
|
10822
|
+
if (miss)
|
|
10823
|
+
return { ...none, line: `baseline: ran ${runs2.map((b) => `"${b.command}"`).join(", ") || "nothing"}, not the full suite command "${miss.cmd}", ids not comparable, full suite failures not excused` };
|
|
10824
|
+
const known = new Set(bad.flatMap((c) => ids(c.cmd))), block = new Set(blocked);
|
|
10825
|
+
if (known.size === 0)
|
|
10826
|
+
return none;
|
|
10827
|
+
return split(bad.map((c) => ({ name: c.name, ...c.ids ? { ids: c.ids } : {}, eligible: (c.ids ?? []).every((i) => !block.has(i) && !changed.some((f) => i.includes(f))), base: new Set(ids(c.cmd)) })), known.size);
|
|
10808
10828
|
}
|
|
10809
10829
|
function parseStatic(tool, out2) {
|
|
10810
10830
|
const re = STATIC_DIAG[tool], m = new Map;
|
|
@@ -10872,7 +10892,7 @@ var commandProfilePath = (repoDir) => join39(repoDir, ".loki", "state", "repo-pr
|
|
|
10872
10892
|
} catch {
|
|
10873
10893
|
return "";
|
|
10874
10894
|
}
|
|
10875
|
-
}, STATIC_DIAG, STATIC_NOISE, STATIC_SUMMARY;
|
|
10895
|
+
}, normCmd = (s) => s.replace(/\s+--silent\b/, "").trim(), STATIC_DIAG, STATIC_NOISE, STATIC_SUMMARY;
|
|
10876
10896
|
var init_repo_profile = __esm(() => {
|
|
10877
10897
|
init_failures();
|
|
10878
10898
|
init_check_result();
|
|
@@ -12388,9 +12408,278 @@ function recordHoldoutTriage(runDir, entry) {
|
|
|
12388
12408
|
var sha2 = (s) => createHash13("sha256").update(s).digest("hex"), WALL_HOLDOUT_DEFAULT_RATIO = 0.2, isHoldoutCheck = (name) => name.startsWith("holdout:"), holdoutDirFor = (runId2, repoDir) => join44(tmpdir6(), `loki-e10-holdout-${sha2(`${runId2}:${repoDir}`).slice(0, 16)}`), MANIFEST = "manifest.json", WALL_HOLDOUT_MIN = 5, HOLDOUT_TRIAGE_FILE = "holdout-triage.jsonl";
|
|
12389
12409
|
var init_holdout = () => {};
|
|
12390
12410
|
|
|
12411
|
+
// ../../loki-ts/src/runner/runner_errors.ts
|
|
12412
|
+
function hasRealTestFailure(out2) {
|
|
12413
|
+
return /^\s*Tests:?\s+.*\b[1-9]\d* failed\b/m.test(out2) || /^(?:=+ )?.*\b[1-9]\d* failed\b.* in [\d.]+s/m.test(out2) || /^FAILED \S+::/m.test(out2) || /^(?:#|\u2139) fail [1-9]/m.test(out2) || /^\s*[1-9]\d*\s+fail\s*$/m.test(out2) || /^\s*(?:FAIL|\u00D7)\s+\S.*\s>\s/m.test(out2) || /\bAssertionError\b/.test(out2);
|
|
12414
|
+
}
|
|
12415
|
+
function firstLoadLine(out2) {
|
|
12416
|
+
const lines = out2.split(`
|
|
12417
|
+
`).map((l2) => l2.trim()).filter(Boolean);
|
|
12418
|
+
const l = lines.find((x) => /^(?:E\s+)?(?:Error|\w*Error|ERROR|Failed|FAIL)\b|Cannot find|Interrupted:|No test files found|\d+: [\w.-]+: not found$|: command not found$|canceled due to missing packages/.test(x)) ?? lines[0] ?? "";
|
|
12419
|
+
return l.replace(/\s+/g, " ").slice(0, 160);
|
|
12420
|
+
}
|
|
12421
|
+
function classifyRunnerOutput(out2) {
|
|
12422
|
+
if (!hasRealTestFailure(out2)) {
|
|
12423
|
+
for (const [re, why] of LOAD_PATTERNS) {
|
|
12424
|
+
if (re.test(out2))
|
|
12425
|
+
return { kind: "load_error", owner: "harness", reason: `runner could not load: ${why}: ${firstLoadLine(out2)}` };
|
|
12426
|
+
}
|
|
12427
|
+
}
|
|
12428
|
+
return { kind: "test_failure", owner: "code" };
|
|
12429
|
+
}
|
|
12430
|
+
var LOAD_PATTERNS;
|
|
12431
|
+
var init_runner_errors = __esm(() => {
|
|
12432
|
+
LOAD_PATTERNS = [
|
|
12433
|
+
[/Failed Suites\s+[1-9]/, "test suite failed to load"],
|
|
12434
|
+
[/Test suite failed to run/, "test suite failed to run"],
|
|
12435
|
+
[/Failed to load (?:url|config)|failed to load config|Failed to resolve (?:import|entry)/i, "runner config or import could not be loaded"],
|
|
12436
|
+
[/^\s*(?:\w*Error: )?Cannot find (?:module|package) '[^']+'/m, "module not found while loading tests"],
|
|
12437
|
+
[/ERR_MODULE_NOT_FOUND/, "module not found while loading tests"],
|
|
12438
|
+
[/Interrupted: \d+ errors? during collection/, "collection error"],
|
|
12439
|
+
[/^_+ ERROR collecting /m, "collection error"],
|
|
12440
|
+
[/ImportError while importing test module/, "test module import error"],
|
|
12441
|
+
[/ImportError: Failed to import test module/, "unittest test module import error"],
|
|
12442
|
+
[/^ERROR: (?:file or directory not found|not found:)/m, "test path not found by the runner"],
|
|
12443
|
+
[/No test files found, exiting with code [1-9]/, "runner found no test files (wrong cwd or path)"],
|
|
12444
|
+
[/\[setup failed\]|cannot find package|no required module provides package/, "go package could not be set up"],
|
|
12445
|
+
[/could not determine executable to run/i, "test runner executable not found"],
|
|
12446
|
+
[/^(?:\S+: )?(?:line \d+: )?[\w.-]+: command not found$/m, "test runner executable not found"],
|
|
12447
|
+
[/^(?:\S+: )?\d+: [\w.-]+: not found$/m, "test runner executable not found (not installed)"],
|
|
12448
|
+
[/^npm (?:error|ERR!) (?:npx )?canceled due to missing packages/m, "test runner package not installed"]
|
|
12449
|
+
];
|
|
12450
|
+
});
|
|
12451
|
+
|
|
12452
|
+
// ../../loki-ts/src/runner/load_owner.ts
|
|
12453
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
12454
|
+
import { mkdtempSync as mkdtempSync5, realpathSync as realpathSync19, rmSync as rmSync13 } from "fs";
|
|
12455
|
+
import { tmpdir as tmpdir7 } from "os";
|
|
12456
|
+
import { basename as basename18, extname as extname2, join as join45 } from "path";
|
|
12457
|
+
function changedFilesNamed(out2, repoDir, changed) {
|
|
12458
|
+
return changed.filter((f) => {
|
|
12459
|
+
if (out2.includes(f) || out2.includes(join45(repoDir, f)))
|
|
12460
|
+
return true;
|
|
12461
|
+
const segs = f.split("/");
|
|
12462
|
+
if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
|
|
12463
|
+
return true;
|
|
12464
|
+
if (extname2(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
|
|
12465
|
+
return true;
|
|
12466
|
+
const stem = basename18(f, extname2(f));
|
|
12467
|
+
if (stem.length < 2 || stem === "index" || stem === "__init__")
|
|
12468
|
+
return false;
|
|
12469
|
+
return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
|
|
12470
|
+
});
|
|
12471
|
+
}
|
|
12472
|
+
function loadSignature(out2, roots) {
|
|
12473
|
+
let o = out2;
|
|
12474
|
+
for (const r of roots.flatMap((x) => {
|
|
12475
|
+
try {
|
|
12476
|
+
return [x, realpathSync19(x)];
|
|
12477
|
+
} catch {
|
|
12478
|
+
return [x];
|
|
12479
|
+
}
|
|
12480
|
+
}).sort((a, b) => b.length - a.length))
|
|
12481
|
+
o = o.split(r).join("<repo>");
|
|
12482
|
+
const keys = new Set;
|
|
12483
|
+
for (const m of o.matchAll(/Cannot find (?:module|package) '([^']+)'/g))
|
|
12484
|
+
keys.add(`mod:${m[1]}`);
|
|
12485
|
+
for (const m of o.matchAll(/([\w.-]+): command not found/g))
|
|
12486
|
+
keys.add(`cmd:${m[1]}`);
|
|
12487
|
+
for (const m of o.matchAll(/^(?:\S+: )?\d+: ([\w.-]+): not found$/gm))
|
|
12488
|
+
keys.add(`cmd:${m[1]}`);
|
|
12489
|
+
for (const m of o.matchAll(/canceled due to missing packages[^\[\n]*\[([^\]\n]*)\]/g))
|
|
12490
|
+
for (const p of (m[1] ?? "").split(",")) {
|
|
12491
|
+
const n2 = p.trim().replace(/^["']|["']$/g, "").replace(/(?<=.)@[^@/]*$/, "");
|
|
12492
|
+
if (n2)
|
|
12493
|
+
keys.add(`pkg:${n2}`);
|
|
12494
|
+
}
|
|
12495
|
+
return { keys, reason: (classifyRunnerOutput(o).reason ?? "").replace(/:\d+(?::\d+)?/g, "") };
|
|
12496
|
+
}
|
|
12497
|
+
function sameLoadError(head, base, headRoots, baseRoots) {
|
|
12498
|
+
const h = loadSignature(head, headRoots), b = loadSignature(base, baseRoots);
|
|
12499
|
+
if (b.keys.size)
|
|
12500
|
+
return h.keys.size > 0 && [...b.keys].every((k) => h.keys.has(k));
|
|
12501
|
+
return h.keys.size === 0 && h.reason === b.reason;
|
|
12502
|
+
}
|
|
12503
|
+
function killTree(pid) {
|
|
12504
|
+
const all = [pid];
|
|
12505
|
+
for (let k = 0;k < all.length; k++) {
|
|
12506
|
+
const kids = spawnSync5("pgrep", ["-P", String(all[k])], { encoding: "utf8", env: process.env }).stdout.split(/\s+/).filter(Boolean).map(Number);
|
|
12507
|
+
all.push(...kids.filter((x) => Number.isInteger(x) && !all.includes(x)));
|
|
12508
|
+
}
|
|
12509
|
+
try {
|
|
12510
|
+
if (Number.isInteger(pid) && pid > 1)
|
|
12511
|
+
process.kill(-pid, "SIGKILL");
|
|
12512
|
+
} catch {}
|
|
12513
|
+
for (const p of all.reverse()) {
|
|
12514
|
+
try {
|
|
12515
|
+
process.kill(p, "SIGKILL");
|
|
12516
|
+
} catch {}
|
|
12517
|
+
}
|
|
12518
|
+
}
|
|
12519
|
+
async function runOnBase(i, dir) {
|
|
12520
|
+
const sub2 = (s) => s.split(i.repoDir).join(dir);
|
|
12521
|
+
const stop = AbortSignal.any([i.signal, AbortSignal.timeout(i.timeoutMs ?? 60000)]);
|
|
12522
|
+
try {
|
|
12523
|
+
const proc = Bun.spawn([sub2(i.cmd), ...i.args.map(sub2)], {
|
|
12524
|
+
cwd: sub2(i.cwd ?? i.repoDir),
|
|
12525
|
+
stdin: "ignore",
|
|
12526
|
+
stdout: "pipe",
|
|
12527
|
+
stderr: "pipe",
|
|
12528
|
+
detached: true,
|
|
12529
|
+
env: { ...plainTestEnv(), ...i.env ?? {} }
|
|
12530
|
+
});
|
|
12531
|
+
let tail = "";
|
|
12532
|
+
const rs = [proc.stdout, proc.stderr].map((x) => x.getReader());
|
|
12533
|
+
const pumps = rs.map(async (r) => {
|
|
12534
|
+
const d = new TextDecoder;
|
|
12535
|
+
for (;; ) {
|
|
12536
|
+
const c = await r.read().catch(() => ({ done: true, value: undefined }));
|
|
12537
|
+
if (c.done)
|
|
12538
|
+
return;
|
|
12539
|
+
tail = (tail + d.decode(c.value, { stream: true })).slice(-65536);
|
|
12540
|
+
}
|
|
12541
|
+
});
|
|
12542
|
+
const cut = new Promise((res) => {
|
|
12543
|
+
if (stop.aborted)
|
|
12544
|
+
res(null);
|
|
12545
|
+
else
|
|
12546
|
+
stop.addEventListener("abort", () => res(null), { once: true });
|
|
12547
|
+
});
|
|
12548
|
+
const code = await Promise.race([proc.exited, cut]);
|
|
12549
|
+
if (code === null) {
|
|
12550
|
+
killTree(proc.pid);
|
|
12551
|
+
return null;
|
|
12552
|
+
}
|
|
12553
|
+
await Promise.race([Promise.all(pumps), new Promise((r) => setTimeout(r, 300))]);
|
|
12554
|
+
rs.forEach((r) => r.cancel().catch(() => {}));
|
|
12555
|
+
return stop.aborted || code === 0 ? null : stripAnsi(tail);
|
|
12556
|
+
} catch {
|
|
12557
|
+
return null;
|
|
12558
|
+
}
|
|
12559
|
+
}
|
|
12560
|
+
function changedSince(repoDir, baseSha, skip) {
|
|
12561
|
+
const g = (a) => safeGit(repoDir, a).split(`
|
|
12562
|
+
`).map((l) => l.trim()).filter(Boolean);
|
|
12563
|
+
return [...new Set([...g(["diff", "--name-only", baseSha]), ...g(["ls-files", "--others", "--exclude-standard"])])].filter((f) => !f.startsWith(".loki/") && !skip?.(f));
|
|
12564
|
+
}
|
|
12565
|
+
async function loadErrorIsHarnessOwned(i) {
|
|
12566
|
+
if (i.protect || !i.baseSha || i.signal.aborted)
|
|
12567
|
+
return false;
|
|
12568
|
+
let changed;
|
|
12569
|
+
try {
|
|
12570
|
+
changed = changedSince(i.repoDir, i.baseSha, i.skip);
|
|
12571
|
+
} catch {
|
|
12572
|
+
return false;
|
|
12573
|
+
}
|
|
12574
|
+
if (changedFilesNamed(i.out, i.repoDir, changed).length > 0)
|
|
12575
|
+
return false;
|
|
12576
|
+
if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
|
|
12577
|
+
return false;
|
|
12578
|
+
const dir = mkdtempSync5(join45(tmpdir7(), "e10-loadown-"));
|
|
12579
|
+
const git3 = (args) => {
|
|
12580
|
+
safeGit(i.repoDir, args, { stdio: "ignore" });
|
|
12581
|
+
};
|
|
12582
|
+
try {
|
|
12583
|
+
git3(["worktree", "add", "--detach", dir, i.baseSha]);
|
|
12584
|
+
const base = await runOnBase(i, dir);
|
|
12585
|
+
return base !== null && classifyRunnerOutput(base).kind === "load_error" && sameLoadError(i.out, base, [i.repoDir, ...i.cwd ? [i.cwd] : []], [dir]);
|
|
12586
|
+
} catch {
|
|
12587
|
+
return false;
|
|
12588
|
+
} finally {
|
|
12589
|
+
try {
|
|
12590
|
+
git3(["worktree", "remove", "--force", dir]);
|
|
12591
|
+
} catch {}
|
|
12592
|
+
rmSync13(dir, { recursive: true, force: true });
|
|
12593
|
+
try {
|
|
12594
|
+
git3(["worktree", "prune"]);
|
|
12595
|
+
} catch {}
|
|
12596
|
+
}
|
|
12597
|
+
}
|
|
12598
|
+
async function harnessLoadReason(i) {
|
|
12599
|
+
const c = classifyRunnerOutput(i.out);
|
|
12600
|
+
return c.kind === "load_error" && await loadErrorIsHarnessOwned(i) ? c.reason : undefined;
|
|
12601
|
+
}
|
|
12602
|
+
var esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), suffixes = (segs, min) => segs.map((_, k) => segs.slice(k).join("/")).filter((x) => x.split("/").length >= min), bounded = (out2, tok2, tail) => new RegExp(`(?<![\\w.-])${esc(tok2)}${tail}`).test(out2);
|
|
12603
|
+
var init_load_owner = __esm(() => {
|
|
12604
|
+
init_runner_errors();
|
|
12605
|
+
init_safe_git();
|
|
12606
|
+
init_check_result();
|
|
12607
|
+
});
|
|
12608
|
+
|
|
12609
|
+
// ../../loki-ts/src/project_model/package_suite.ts
|
|
12610
|
+
import { join as join46 } from "path";
|
|
12611
|
+
function packageSuiteSpecs(api) {
|
|
12612
|
+
if (!isMultiRoot(api))
|
|
12613
|
+
return null;
|
|
12614
|
+
const specs = api.packages().filter((p) => p.commands.test).map((p) => {
|
|
12615
|
+
const tc = p.commands.test;
|
|
12616
|
+
return { name: `full suite: ${p.name}`, cmd: `(cd ${tc.cwd} && ${tc.cmd})`, cwd: tc.cwd, run: tc.cmd };
|
|
12617
|
+
});
|
|
12618
|
+
return specs.length ? specs : null;
|
|
12619
|
+
}
|
|
12620
|
+
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
12621
|
+
const api = loadProjectApi(repoDir), specs = packageSuiteSpecs(api);
|
|
12622
|
+
if (!api || !specs)
|
|
12623
|
+
return false;
|
|
12624
|
+
for (const { name, cmd: cmd2, cwd, run: line2 } of specs) {
|
|
12625
|
+
const started = Date.now();
|
|
12626
|
+
const r = await run(["bash", "-c", line2], { cwd: join46(repoDir, cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
12627
|
+
const duration_s = (Date.now() - started) / 1000;
|
|
12628
|
+
if (signal.aborted) {
|
|
12629
|
+
checks.push({ name, cmd: cmd2, result: "not_run", duration_s });
|
|
12630
|
+
notProven.add(`not run: ${name} (aborted)`);
|
|
12631
|
+
continue;
|
|
12632
|
+
}
|
|
12633
|
+
const out2 = `${r.stdout}
|
|
12634
|
+
${r.stderr}`;
|
|
12635
|
+
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, ...opts.skip ? { skip: opts.skip } : {}, out: out2, cmd: "bash", args: ["-c", line2], signal, cwd: join46(repoDir, cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
12636
|
+
if (lr) {
|
|
12637
|
+
checks.push({ name, cmd: cmd2, result: "not_run", duration_s });
|
|
12638
|
+
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
12639
|
+
continue;
|
|
12640
|
+
}
|
|
12641
|
+
const cls = classifyCheck({ kind: "test", ok: r.exitCode === 0, out: out2, ...goRunner(line2) });
|
|
12642
|
+
checks.push({ name, cmd: cmd2, result: cls.result, duration_s, ...cls.result === "fail" ? { ids: failIds(out2) } : {} });
|
|
12643
|
+
if (cls.result === "not_run")
|
|
12644
|
+
notProven.add(`not run: ${name} (${cls.reason ?? NO_TESTS_REASON})`);
|
|
12645
|
+
}
|
|
12646
|
+
for (const pkg of api.packages().filter((p) => !p.commands.test))
|
|
12647
|
+
notProven.add(`full suite: package ${pkg.name} defines no test command`);
|
|
12648
|
+
return true;
|
|
12649
|
+
}
|
|
12650
|
+
var init_package_suite = __esm(() => {
|
|
12651
|
+
init_load_owner();
|
|
12652
|
+
init_check_result();
|
|
12653
|
+
init_shell();
|
|
12654
|
+
init_failures();
|
|
12655
|
+
init_resolve();
|
|
12656
|
+
});
|
|
12657
|
+
|
|
12658
|
+
// ../../loki-ts/src/project_model/install.ts
|
|
12659
|
+
function installOwned(repoDir, rec, env = process.env) {
|
|
12660
|
+
const r = rec, files = r && typeof r.files === "object" && r.files ? r.files : {}, dirs = Array.isArray(r?.dirs) ? r.dirs : [];
|
|
12661
|
+
return (f) => dirs.some((d) => typeof d === "string" && f.startsWith(d)) || Object.hasOwn(files, f) && (() => {
|
|
12662
|
+
try {
|
|
12663
|
+
return hashOf(repoDir, f, env) === files[f];
|
|
12664
|
+
} catch {
|
|
12665
|
+
return false;
|
|
12666
|
+
}
|
|
12667
|
+
})();
|
|
12668
|
+
}
|
|
12669
|
+
var memo3, STATUS_MAX_BUFFER, hashOf = (repoDir, path, env = process.env) => safeGit(repoDir, ["hash-object", "--no-filters", "--", path], { env }).trim();
|
|
12670
|
+
var init_install = __esm(() => {
|
|
12671
|
+
init_safe_git();
|
|
12672
|
+
init_yaml_key();
|
|
12673
|
+
init_repo_profile();
|
|
12674
|
+
init_package_suite();
|
|
12675
|
+
init_resolve();
|
|
12676
|
+
memo3 = new Set;
|
|
12677
|
+
STATUS_MAX_BUFFER = 64 * 1024 * 1024;
|
|
12678
|
+
});
|
|
12679
|
+
|
|
12391
12680
|
// ../../loki-ts/src/features/runner_config.ts
|
|
12392
12681
|
import { readFileSync as readFileSync37 } from "fs";
|
|
12393
|
-
import { dirname as dirname17, join as
|
|
12682
|
+
import { dirname as dirname17, join as join47, normalize as normalize2 } from "path";
|
|
12394
12683
|
function tomlKey2(s, i = 0, eq2 = true) {
|
|
12395
12684
|
const parts = [], ws = () => {
|
|
12396
12685
|
while (/\s/.test(s[i] ?? "x"))
|
|
@@ -12667,8 +12956,8 @@ function referenced(cfg, text2) {
|
|
|
12667
12956
|
}
|
|
12668
12957
|
const dir = dirname17(cfg), explicit = ROOT_DIR.exec(text2), roots = [dir];
|
|
12669
12958
|
if (explicit)
|
|
12670
|
-
roots.push("", ...explicit[1] ? [
|
|
12671
|
-
return [...raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(
|
|
12959
|
+
roots.push("", ...explicit[1] ? [join47(dir, explicit[1])] : []);
|
|
12960
|
+
return [...raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(join47(root, r.replace(/^<rootDir>\/?/, ""))))), ...patchedTargets(cfg, text2).map((t) => normalize2(join47(dir, t)))];
|
|
12672
12961
|
}
|
|
12673
12962
|
function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
12674
12963
|
const notes = new Set, ch = new Set(changed.map((c) => normalize2(c)));
|
|
@@ -12748,7 +13037,7 @@ var PKG_KEYS, RAW_CONFIGS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, dep
|
|
|
12748
13037
|
}
|
|
12749
13038
|
}, headText = (dir, f) => {
|
|
12750
13039
|
try {
|
|
12751
|
-
return readFileSync37(
|
|
13040
|
+
return readFileSync37(join47(dir, f), "utf8");
|
|
12752
13041
|
} catch {
|
|
12753
13042
|
return "";
|
|
12754
13043
|
}
|
|
@@ -12787,21 +13076,21 @@ var init_runner_config = __esm(() => {
|
|
|
12787
13076
|
});
|
|
12788
13077
|
|
|
12789
13078
|
// ../../loki-ts/src/e10ext/assert_delta.ts
|
|
12790
|
-
import { execFileSync as
|
|
12791
|
-
import { mkdtempSync as
|
|
12792
|
-
import { tmpdir as
|
|
12793
|
-
import { join as
|
|
12794
|
-
import { basename as
|
|
13079
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
13080
|
+
import { mkdtempSync as mkdtempSync6, readFileSync as readFileSync38, rmSync as rmSync14 } from "fs";
|
|
13081
|
+
import { tmpdir as tmpdir8 } from "os";
|
|
13082
|
+
import { join as join48 } from "path";
|
|
13083
|
+
import { basename as basename19 } from "path";
|
|
12795
13084
|
function classifyAssertDelta(inp) {
|
|
12796
|
-
const f =
|
|
13085
|
+
const f = basename19(inp.path);
|
|
12797
13086
|
if (!/^(test_.*|.*_test)\.py$/.test(f))
|
|
12798
13087
|
return WEAKENED;
|
|
12799
13088
|
if (inp.headCounts.run !== inp.baseCounts.run || inp.headCounts.skipped !== inp.baseCounts.skipped)
|
|
12800
13089
|
return WEAKENED;
|
|
12801
13090
|
let cwd = "";
|
|
12802
13091
|
try {
|
|
12803
|
-
cwd =
|
|
12804
|
-
const raw2 =
|
|
13092
|
+
cwd = mkdtempSync6(join48(tmpdir8(), "loki-ad-"));
|
|
13093
|
+
const raw2 = execFileSync4("python3", ["-I", "-c", PY], {
|
|
12805
13094
|
input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
|
|
12806
13095
|
cwd,
|
|
12807
13096
|
env: process.env,
|
|
@@ -12823,7 +13112,7 @@ function classifyAssertDelta(inp) {
|
|
|
12823
13112
|
return WEAKENED;
|
|
12824
13113
|
} finally {
|
|
12825
13114
|
if (cwd)
|
|
12826
|
-
|
|
13115
|
+
rmSync14(cwd, { recursive: true, force: true });
|
|
12827
13116
|
}
|
|
12828
13117
|
}
|
|
12829
13118
|
function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, headCounts) {
|
|
@@ -12831,7 +13120,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
|
|
|
12831
13120
|
return null;
|
|
12832
13121
|
try {
|
|
12833
13122
|
const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
|
|
12834
|
-
const head = headRef ? show(headRef) : readFileSync38(
|
|
13123
|
+
const head = headRef ? show(headRef) : readFileSync38(join48(repoDir, path), "utf8");
|
|
12835
13124
|
const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
|
|
12836
13125
|
return r[0]?.kind === "literal-only" ? r.map((e) => `assertion value changed (not shown to be required by the task): ${e.file}:${e.line} ${e.old} -> ${e.new}`) : null;
|
|
12837
13126
|
} catch {
|
|
@@ -13013,196 +13302,8 @@ var init_select = __esm(() => {
|
|
|
13013
13302
|
PYTEST_COLLECTION_EXITS = new Set([2, 3, 4, 5]);
|
|
13014
13303
|
});
|
|
13015
13304
|
|
|
13016
|
-
// ../../loki-ts/src/runner/runner_errors.ts
|
|
13017
|
-
function hasRealTestFailure(out2) {
|
|
13018
|
-
return /^\s*Tests:?\s+.*\b[1-9]\d* failed\b/m.test(out2) || /^(?:=+ )?.*\b[1-9]\d* failed\b.* in [\d.]+s/m.test(out2) || /^FAILED \S+::/m.test(out2) || /^(?:#|\u2139) fail [1-9]/m.test(out2) || /^\s*[1-9]\d*\s+fail\s*$/m.test(out2) || /^\s*(?:FAIL|\u00D7)\s+\S.*\s>\s/m.test(out2) || /\bAssertionError\b/.test(out2);
|
|
13019
|
-
}
|
|
13020
|
-
function firstLoadLine(out2) {
|
|
13021
|
-
const lines2 = out2.split(`
|
|
13022
|
-
`).map((l2) => l2.trim()).filter(Boolean);
|
|
13023
|
-
const l = lines2.find((x) => /^(?:E\s+)?(?:Error|\w*Error|ERROR|Failed|FAIL)\b|Cannot find|Interrupted:|No test files found/.test(x)) ?? lines2[0] ?? "";
|
|
13024
|
-
return l.replace(/\s+/g, " ").slice(0, 160);
|
|
13025
|
-
}
|
|
13026
|
-
function classifyRunnerOutput(out2) {
|
|
13027
|
-
if (!hasRealTestFailure(out2)) {
|
|
13028
|
-
for (const [re, why] of LOAD_PATTERNS) {
|
|
13029
|
-
if (re.test(out2))
|
|
13030
|
-
return { kind: "load_error", owner: "harness", reason: `runner could not load: ${why}: ${firstLoadLine(out2)}` };
|
|
13031
|
-
}
|
|
13032
|
-
}
|
|
13033
|
-
return { kind: "test_failure", owner: "code" };
|
|
13034
|
-
}
|
|
13035
|
-
var LOAD_PATTERNS;
|
|
13036
|
-
var init_runner_errors = __esm(() => {
|
|
13037
|
-
LOAD_PATTERNS = [
|
|
13038
|
-
[/Failed Suites\s+[1-9]/, "test suite failed to load"],
|
|
13039
|
-
[/Test suite failed to run/, "test suite failed to run"],
|
|
13040
|
-
[/Failed to load (?:url|config)|failed to load config|Failed to resolve (?:import|entry)/i, "runner config or import could not be loaded"],
|
|
13041
|
-
[/^\s*(?:\w*Error: )?Cannot find (?:module|package) '[^']+'/m, "module not found while loading tests"],
|
|
13042
|
-
[/ERR_MODULE_NOT_FOUND/, "module not found while loading tests"],
|
|
13043
|
-
[/Interrupted: \d+ errors? during collection/, "collection error"],
|
|
13044
|
-
[/^_+ ERROR collecting /m, "collection error"],
|
|
13045
|
-
[/ImportError while importing test module/, "test module import error"],
|
|
13046
|
-
[/ImportError: Failed to import test module/, "unittest test module import error"],
|
|
13047
|
-
[/^ERROR: (?:file or directory not found|not found:)/m, "test path not found by the runner"],
|
|
13048
|
-
[/No test files found, exiting with code [1-9]/, "runner found no test files (wrong cwd or path)"],
|
|
13049
|
-
[/\[setup failed\]|cannot find package|no required module provides package/, "go package could not be set up"],
|
|
13050
|
-
[/could not determine executable to run/i, "test runner executable not found"],
|
|
13051
|
-
[/^(?:\S+: )?(?:line \d+: )?[\w.-]+: command not found$/m, "test runner executable not found"]
|
|
13052
|
-
];
|
|
13053
|
-
});
|
|
13054
|
-
|
|
13055
|
-
// ../../loki-ts/src/runner/load_owner.ts
|
|
13056
|
-
import { spawnSync as spawnSync5 } from "child_process";
|
|
13057
|
-
import { mkdtempSync as mkdtempSync6, realpathSync as realpathSync19, rmSync as rmSync14 } from "fs";
|
|
13058
|
-
import { tmpdir as tmpdir8 } from "os";
|
|
13059
|
-
import { basename as basename19, extname as extname2, join as join47 } from "path";
|
|
13060
|
-
function changedFilesNamed(out2, repoDir, changed) {
|
|
13061
|
-
return changed.filter((f) => {
|
|
13062
|
-
if (out2.includes(f) || out2.includes(join47(repoDir, f)))
|
|
13063
|
-
return true;
|
|
13064
|
-
const segs = f.split("/");
|
|
13065
|
-
if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
|
|
13066
|
-
return true;
|
|
13067
|
-
if (extname2(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
|
|
13068
|
-
return true;
|
|
13069
|
-
const stem = basename19(f, extname2(f));
|
|
13070
|
-
if (stem.length < 2 || stem === "index" || stem === "__init__")
|
|
13071
|
-
return false;
|
|
13072
|
-
return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
|
|
13073
|
-
});
|
|
13074
|
-
}
|
|
13075
|
-
function loadSignature(out2, roots) {
|
|
13076
|
-
let o = out2;
|
|
13077
|
-
for (const r of roots.flatMap((x) => {
|
|
13078
|
-
try {
|
|
13079
|
-
return [x, realpathSync19(x)];
|
|
13080
|
-
} catch {
|
|
13081
|
-
return [x];
|
|
13082
|
-
}
|
|
13083
|
-
}).sort((a, b) => b.length - a.length))
|
|
13084
|
-
o = o.split(r).join("<repo>");
|
|
13085
|
-
const keys = new Set;
|
|
13086
|
-
for (const m of o.matchAll(/Cannot find (?:module|package) '([^']+)'/g))
|
|
13087
|
-
keys.add(`mod:${m[1]}`);
|
|
13088
|
-
for (const m of o.matchAll(/([\w.-]+): command not found/g))
|
|
13089
|
-
keys.add(`cmd:${m[1]}`);
|
|
13090
|
-
return { keys, reason: (classifyRunnerOutput(o).reason ?? "").replace(/:\d+(?::\d+)?/g, "") };
|
|
13091
|
-
}
|
|
13092
|
-
function sameLoadError(head, base, headRoots, baseRoots) {
|
|
13093
|
-
const h = loadSignature(head, headRoots), b = loadSignature(base, baseRoots);
|
|
13094
|
-
if (b.keys.size)
|
|
13095
|
-
return h.keys.size > 0 && [...b.keys].every((k) => h.keys.has(k));
|
|
13096
|
-
return h.keys.size === 0 && h.reason === b.reason;
|
|
13097
|
-
}
|
|
13098
|
-
function killTree(pid) {
|
|
13099
|
-
const all = [pid];
|
|
13100
|
-
for (let k = 0;k < all.length; k++) {
|
|
13101
|
-
const kids = spawnSync5("pgrep", ["-P", String(all[k])], { encoding: "utf8", env: process.env }).stdout.split(/\s+/).filter(Boolean).map(Number);
|
|
13102
|
-
all.push(...kids.filter((x) => Number.isInteger(x) && !all.includes(x)));
|
|
13103
|
-
}
|
|
13104
|
-
try {
|
|
13105
|
-
if (Number.isInteger(pid) && pid > 1)
|
|
13106
|
-
process.kill(-pid, "SIGKILL");
|
|
13107
|
-
} catch {}
|
|
13108
|
-
for (const p of all.reverse()) {
|
|
13109
|
-
try {
|
|
13110
|
-
process.kill(p, "SIGKILL");
|
|
13111
|
-
} catch {}
|
|
13112
|
-
}
|
|
13113
|
-
}
|
|
13114
|
-
async function runOnBase(i, dir) {
|
|
13115
|
-
const sub2 = (s) => s.split(i.repoDir).join(dir);
|
|
13116
|
-
const stop = AbortSignal.any([i.signal, AbortSignal.timeout(i.timeoutMs ?? 60000)]);
|
|
13117
|
-
try {
|
|
13118
|
-
const proc = Bun.spawn([sub2(i.cmd), ...i.args.map(sub2)], {
|
|
13119
|
-
cwd: sub2(i.cwd ?? i.repoDir),
|
|
13120
|
-
stdin: "ignore",
|
|
13121
|
-
stdout: "pipe",
|
|
13122
|
-
stderr: "pipe",
|
|
13123
|
-
detached: true,
|
|
13124
|
-
env: { ...plainTestEnv(), ...i.env ?? {} }
|
|
13125
|
-
});
|
|
13126
|
-
let tail = "";
|
|
13127
|
-
const rs = [proc.stdout, proc.stderr].map((x) => x.getReader());
|
|
13128
|
-
const pumps = rs.map(async (r) => {
|
|
13129
|
-
const d = new TextDecoder;
|
|
13130
|
-
for (;; ) {
|
|
13131
|
-
const c = await r.read().catch(() => ({ done: true, value: undefined }));
|
|
13132
|
-
if (c.done)
|
|
13133
|
-
return;
|
|
13134
|
-
tail = (tail + d.decode(c.value, { stream: true })).slice(-65536);
|
|
13135
|
-
}
|
|
13136
|
-
});
|
|
13137
|
-
const cut = new Promise((res) => {
|
|
13138
|
-
if (stop.aborted)
|
|
13139
|
-
res(null);
|
|
13140
|
-
else
|
|
13141
|
-
stop.addEventListener("abort", () => res(null), { once: true });
|
|
13142
|
-
});
|
|
13143
|
-
const code = await Promise.race([proc.exited, cut]);
|
|
13144
|
-
if (code === null) {
|
|
13145
|
-
killTree(proc.pid);
|
|
13146
|
-
return null;
|
|
13147
|
-
}
|
|
13148
|
-
await Promise.race([Promise.all(pumps), new Promise((r) => setTimeout(r, 300))]);
|
|
13149
|
-
rs.forEach((r) => r.cancel().catch(() => {}));
|
|
13150
|
-
return stop.aborted || code === 0 ? null : stripAnsi(tail);
|
|
13151
|
-
} catch {
|
|
13152
|
-
return null;
|
|
13153
|
-
}
|
|
13154
|
-
}
|
|
13155
|
-
function changedSince(repoDir, baseSha) {
|
|
13156
|
-
const g = (a) => safeGit(repoDir, a).split(`
|
|
13157
|
-
`).map((l) => l.trim()).filter(Boolean);
|
|
13158
|
-
return [...new Set([...g(["diff", "--name-only", baseSha]), ...g(["ls-files", "--others", "--exclude-standard"])])].filter((f) => !f.startsWith(".loki/"));
|
|
13159
|
-
}
|
|
13160
|
-
async function loadErrorIsHarnessOwned(i) {
|
|
13161
|
-
if (i.protect || !i.baseSha || i.signal.aborted)
|
|
13162
|
-
return false;
|
|
13163
|
-
let changed;
|
|
13164
|
-
try {
|
|
13165
|
-
changed = changedSince(i.repoDir, i.baseSha);
|
|
13166
|
-
} catch {
|
|
13167
|
-
return false;
|
|
13168
|
-
}
|
|
13169
|
-
if (changedFilesNamed(i.out, i.repoDir, changed).length > 0)
|
|
13170
|
-
return false;
|
|
13171
|
-
if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
|
|
13172
|
-
return false;
|
|
13173
|
-
const dir = mkdtempSync6(join47(tmpdir8(), "e10-loadown-"));
|
|
13174
|
-
const git3 = (args) => {
|
|
13175
|
-
safeGit(i.repoDir, args, { stdio: "ignore" });
|
|
13176
|
-
};
|
|
13177
|
-
try {
|
|
13178
|
-
git3(["worktree", "add", "--detach", dir, i.baseSha]);
|
|
13179
|
-
const base = await runOnBase(i, dir);
|
|
13180
|
-
return base !== null && classifyRunnerOutput(base).kind === "load_error" && sameLoadError(i.out, base, [i.repoDir, ...i.cwd ? [i.cwd] : []], [dir]);
|
|
13181
|
-
} catch {
|
|
13182
|
-
return false;
|
|
13183
|
-
} finally {
|
|
13184
|
-
try {
|
|
13185
|
-
git3(["worktree", "remove", "--force", dir]);
|
|
13186
|
-
} catch {}
|
|
13187
|
-
rmSync14(dir, { recursive: true, force: true });
|
|
13188
|
-
try {
|
|
13189
|
-
git3(["worktree", "prune"]);
|
|
13190
|
-
} catch {}
|
|
13191
|
-
}
|
|
13192
|
-
}
|
|
13193
|
-
async function harnessLoadReason(i) {
|
|
13194
|
-
const c = classifyRunnerOutput(i.out);
|
|
13195
|
-
return c.kind === "load_error" && await loadErrorIsHarnessOwned(i) ? c.reason : undefined;
|
|
13196
|
-
}
|
|
13197
|
-
var esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), suffixes = (segs, min) => segs.map((_, k) => segs.slice(k).join("/")).filter((x) => x.split("/").length >= min), bounded = (out2, tok2, tail) => new RegExp(`(?<![\\w.-])${esc(tok2)}${tail}`).test(out2);
|
|
13198
|
-
var init_load_owner = __esm(() => {
|
|
13199
|
-
init_runner_errors();
|
|
13200
|
-
init_safe_git();
|
|
13201
|
-
init_check_result();
|
|
13202
|
-
});
|
|
13203
|
-
|
|
13204
13305
|
// ../../loki-ts/src/util/wall_owned.ts
|
|
13205
|
-
import { isAbsolute as isAbsolute7, join as
|
|
13306
|
+
import { isAbsolute as isAbsolute7, join as join49, relative as relative6 } from "path";
|
|
13206
13307
|
function failingLocations(raw2, cwd, repoDir) {
|
|
13207
13308
|
const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
|
|
13208
13309
|
`), files = new Set;
|
|
@@ -13234,7 +13335,7 @@ function failingLocations(raw2, cwd, repoDir) {
|
|
|
13234
13335
|
}
|
|
13235
13336
|
if (errors2 === 0 || located !== errors2)
|
|
13236
13337
|
return null;
|
|
13237
|
-
return [...files].map((f) => relative6(repoDir, isAbsolute7(f) ? f :
|
|
13338
|
+
return [...files].map((f) => relative6(repoDir, isAbsolute7(f) ? f : join49(cwd, f)));
|
|
13238
13339
|
}
|
|
13239
13340
|
function wallOwnedFailure(raw2, cwd, repoDir, wall) {
|
|
13240
13341
|
const locs = failingLocations(raw2, cwd, repoDir);
|
|
@@ -13248,7 +13349,7 @@ var init_wall_owned = __esm(() => {
|
|
|
13248
13349
|
// ../../loki-ts/src/util/app_probe.ts
|
|
13249
13350
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
13250
13351
|
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync39, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "fs";
|
|
13251
|
-
import { join as
|
|
13352
|
+
import { join as join50 } from "path";
|
|
13252
13353
|
function readJson4(p) {
|
|
13253
13354
|
try {
|
|
13254
13355
|
const v = JSON.parse(readFileSync39(p, "utf8"));
|
|
@@ -13258,14 +13359,14 @@ function readJson4(p) {
|
|
|
13258
13359
|
}
|
|
13259
13360
|
}
|
|
13260
13361
|
function stopApp(repoDir, opts = {}) {
|
|
13261
|
-
const runner = opts.runnerPath ??
|
|
13262
|
-
if (!existsSync30(runner) || !existsSync30(
|
|
13362
|
+
const runner = opts.runnerPath ?? join50(REPO_ROOT, "autonomy", "app-runner.sh");
|
|
13363
|
+
if (!existsSync30(runner) || !existsSync30(join50(repoDir, ".loki", "app-runner", "app.pid")))
|
|
13263
13364
|
return;
|
|
13264
13365
|
spawnSync6("bash", ["-c", STOP, "app-probe", repoDir, runner], { cwd: repoDir, env: plainTestEnv(), timeout: opts.timeoutMs ?? 60000, killSignal: "SIGKILL", stdio: "ignore" });
|
|
13265
13366
|
}
|
|
13266
13367
|
async function appProbe(repoDir, lokiDir2, opts = {}) {
|
|
13267
|
-
const timeoutMs = opts.timeoutMs ?? 60000, runner = opts.runnerPath ??
|
|
13268
|
-
const dir =
|
|
13368
|
+
const timeoutMs = opts.timeoutMs ?? 60000, runner = opts.runnerPath ?? join50(REPO_ROOT, "autonomy", "app-runner.sh");
|
|
13369
|
+
const dir = join50(repoDir, ".loki", "app-runner"), checks = [];
|
|
13269
13370
|
const t0 = Date.now();
|
|
13270
13371
|
const mk2 = (name, result, reason) => ({ name, cmd: "autonomy/app-runner.sh", result, duration_s: (Date.now() - t0) / 1000, reason });
|
|
13271
13372
|
const sh = (script) => {
|
|
@@ -13283,9 +13384,9 @@ async function appProbe(repoDir, lokiDir2, opts = {}) {
|
|
|
13283
13384
|
return { checks, pid, url };
|
|
13284
13385
|
}
|
|
13285
13386
|
const ir = Number(m[1]), sr = Number(m[2]), hr = Number(m[3]);
|
|
13286
|
-
const pidTxt = existsSync30(
|
|
13387
|
+
const pidTxt = existsSync30(join50(dir, "app.pid")) ? readFileSync39(join50(dir, "app.pid"), "utf8").trim() : "";
|
|
13287
13388
|
pid = /^\d+$/.test(pidTxt) && sr >= 0 ? Number(pidTxt) : null;
|
|
13288
|
-
const st = readJson4(
|
|
13389
|
+
const st = readJson4(join50(dir, "state.json"));
|
|
13289
13390
|
url = typeof st?.["url"] === "string" ? st["url"] : null;
|
|
13290
13391
|
if (sr < 0) {
|
|
13291
13392
|
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"));
|
|
@@ -13296,7 +13397,7 @@ async function appProbe(repoDir, lokiDir2, opts = {}) {
|
|
|
13296
13397
|
return { checks, pid, url };
|
|
13297
13398
|
}
|
|
13298
13399
|
checks.push(mk2("app boot", "pass", "app process started"));
|
|
13299
|
-
const health = readJson4(
|
|
13400
|
+
const health = readJson4(join50(dir, "health.json"));
|
|
13300
13401
|
checks.push(hr === 0 && health?.["ok"] === true ? mk2("http probe", "pass", "health.json ok") : mk2("http probe", "fail", "app-runner health check failed"));
|
|
13301
13402
|
if (opts.specText !== undefined && checks[1]?.result === "pass" && url)
|
|
13302
13403
|
checks.push(await functionalVerify(opts, url, dir, lokiDir2, timeoutMs));
|
|
@@ -13309,10 +13410,10 @@ async function appProbe(repoDir, lokiDir2, opts = {}) {
|
|
|
13309
13410
|
async function functionalVerify(opts, url, dir, lokiDir2, timeoutMs) {
|
|
13310
13411
|
const t0 = Date.now();
|
|
13311
13412
|
const res = (result, reason) => ({ name: "functional verify", cmd: "autonomy/lib/functional-verify.py", result, duration_s: (Date.now() - t0) / 1000, reason });
|
|
13312
|
-
const py = await findPython3(), script = opts.verifyPath ??
|
|
13413
|
+
const py = await findPython3(), script = opts.verifyPath ?? join50(REPO_ROOT, "autonomy", "lib", "functional-verify.py");
|
|
13313
13414
|
if (!py || !existsSync30(script))
|
|
13314
13415
|
return res("not_run", "python3 or functional-verify.py unavailable");
|
|
13315
|
-
const specFile =
|
|
13416
|
+
const specFile = join50(dir, "spec.txt");
|
|
13316
13417
|
writeFileSync22(specFile, opts.specText ?? "");
|
|
13317
13418
|
const r = spawnSync6(py, ["-I", script, specFile, url], { env: plainTestEnv(), encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", stdio: ["ignore", "pipe", "ignore"] });
|
|
13318
13419
|
let out2 = null;
|
|
@@ -13324,11 +13425,11 @@ async function functionalVerify(opts, url, dir, lokiDir2, timeoutMs) {
|
|
|
13324
13425
|
}
|
|
13325
13426
|
if (!out2 || r.status !== 0)
|
|
13326
13427
|
return res("not_run", "functional harness produced no result");
|
|
13327
|
-
const q =
|
|
13428
|
+
const q = join50(lokiDir2, "quality");
|
|
13328
13429
|
mkdirSync19(q, { recursive: true });
|
|
13329
|
-
const tmp =
|
|
13430
|
+
const tmp = join50(q, `functional-results.json.tmp.${process.pid}`);
|
|
13330
13431
|
writeFileSync22(tmp, JSON.stringify(out2, null, 2));
|
|
13331
|
-
renameSync11(tmp,
|
|
13432
|
+
renameSync11(tmp, join50(q, "functional-results.json"));
|
|
13332
13433
|
const s = String(out2["functional_status"] ?? "inconclusive");
|
|
13333
13434
|
return res(s === "verified" ? "pass" : s === "failed" ? "fail" : "not_run", `functional_status ${s}`);
|
|
13334
13435
|
}
|
|
@@ -13361,12 +13462,12 @@ app_runner_stop >/dev/null 2>&1
|
|
|
13361
13462
|
import { existsSync as existsSync31, mkdirSync as mkdirSync20, mkdtempSync as mkdtempSync7, readFileSync as readFileSync40, realpathSync as realpathSync20, rmSync as rmSync15, statSync as statSync19, writeFileSync as writeFileSync23 } from "fs";
|
|
13362
13463
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
13363
13464
|
import { tmpdir as tmpdir9 } from "os";
|
|
13364
|
-
import { basename as basename20, dirname as dirname18, join as
|
|
13465
|
+
import { basename as basename20, dirname as dirname18, join as join51, resolve as resolve15, sep as sep11 } from "path";
|
|
13365
13466
|
function fail(error) {
|
|
13366
13467
|
return { ok: false, findings: [], error };
|
|
13367
13468
|
}
|
|
13368
13469
|
async function runSecureScan(targetDir, opts = {}) {
|
|
13369
|
-
const script = opts.scriptPath ??
|
|
13470
|
+
const script = opts.scriptPath ?? join51(REPO_ROOT, "autonomy", "lib", "secure-scan.py");
|
|
13370
13471
|
if (!existsSync31(script))
|
|
13371
13472
|
return fail(`secure-scan script not found: ${script}`);
|
|
13372
13473
|
const py = await findPython3();
|
|
@@ -13536,7 +13637,7 @@ async function scanAddedLines(repoDir, opts = {}) {
|
|
|
13536
13637
|
const skipped2 = [];
|
|
13537
13638
|
for (const p of untracked.split("\x00").filter(Boolean)) {
|
|
13538
13639
|
try {
|
|
13539
|
-
const st = statSync19(
|
|
13640
|
+
const st = statSync19(join51(repoDir, p));
|
|
13540
13641
|
if (!st.isFile())
|
|
13541
13642
|
continue;
|
|
13542
13643
|
if (st.size > MAX_ADDED_FILE_BYTES) {
|
|
@@ -13551,14 +13652,14 @@ async function scanAddedLines(repoDir, opts = {}) {
|
|
|
13551
13652
|
continue;
|
|
13552
13653
|
}
|
|
13553
13654
|
const lines2 = new Map;
|
|
13554
|
-
readFileSync40(
|
|
13655
|
+
readFileSync40(join51(repoDir, p), "utf8").split(`
|
|
13555
13656
|
`).forEach((t, i) => lines2.set(i + 1, t));
|
|
13556
13657
|
added.set(p, lines2);
|
|
13557
13658
|
} catch {}
|
|
13558
13659
|
}
|
|
13559
13660
|
if (added.size === 0)
|
|
13560
13661
|
return { ok: true, findings: skipped2 };
|
|
13561
|
-
const mirror = mkdtempSync7(
|
|
13662
|
+
const mirror = mkdtempSync7(join51(tmpdir9(), "loki-secure-added-"));
|
|
13562
13663
|
try {
|
|
13563
13664
|
const root = resolve15(mirror) + sep11;
|
|
13564
13665
|
const chunkMap = new Map;
|
|
@@ -13604,7 +13705,7 @@ async function scanAddedLines(repoDir, opts = {}) {
|
|
|
13604
13705
|
chunks.push(cur);
|
|
13605
13706
|
const whole = chunks.length === 1;
|
|
13606
13707
|
for (const c of chunks) {
|
|
13607
|
-
const rel = whole ? p :
|
|
13708
|
+
const rel = whole ? p : join51(chunkRoot, String(chunkSeq++), basename20(p));
|
|
13608
13709
|
const out2 = whole ? dest : resolve15(mirror, rel);
|
|
13609
13710
|
if (!out2.startsWith(root))
|
|
13610
13711
|
break;
|
|
@@ -13756,7 +13857,7 @@ import { spawn as spawn8 } from "child_process";
|
|
|
13756
13857
|
import { createHash as createHash14, randomBytes as randomBytes6 } from "crypto";
|
|
13757
13858
|
import { existsSync as existsSync32, lstatSync as lstatSync12, mkdirSync as mkdirSync21, readdirSync as readdirSync18, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
|
|
13758
13859
|
import { createServer } from "net";
|
|
13759
|
-
import { dirname as dirname19, isAbsolute as isAbsolute8, join as
|
|
13860
|
+
import { dirname as dirname19, isAbsolute as isAbsolute8, join as join52, normalize as normalize3, relative as relative7, sep as sep12 } from "path";
|
|
13760
13861
|
function routeFor(file) {
|
|
13761
13862
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
13762
13863
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -13766,7 +13867,7 @@ function hashScreens(runDir, rels) {
|
|
|
13766
13867
|
const out2 = [];
|
|
13767
13868
|
for (const rel of rels) {
|
|
13768
13869
|
try {
|
|
13769
|
-
out2.push({ path: rel, sha256: sha256File(
|
|
13870
|
+
out2.push({ path: rel, sha256: sha256File(join52(runDir, rel)) });
|
|
13770
13871
|
} catch {}
|
|
13771
13872
|
}
|
|
13772
13873
|
return out2;
|
|
@@ -13779,10 +13880,10 @@ function checkScreens(runDir, screens) {
|
|
|
13779
13880
|
return "evidence_screens entry is malformed";
|
|
13780
13881
|
if (isAbsolute8(s.path) || normalize3(s.path).startsWith(".."))
|
|
13781
13882
|
return `evidence screenshot path escapes the evidence dir: ${s.path}`;
|
|
13782
|
-
const file =
|
|
13883
|
+
const file = join52(runDir, s.path);
|
|
13783
13884
|
let cur = runDir;
|
|
13784
13885
|
for (const seg of normalize3(s.path).split(sep12)) {
|
|
13785
|
-
cur =
|
|
13886
|
+
cur = join52(cur, seg);
|
|
13786
13887
|
if (isSymlink(cur))
|
|
13787
13888
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
13788
13889
|
}
|
|
@@ -13829,7 +13930,7 @@ async function waitUp(url, ms, signal) {
|
|
|
13829
13930
|
}
|
|
13830
13931
|
function openapiPaths(repoDir) {
|
|
13831
13932
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
13832
|
-
const p =
|
|
13933
|
+
const p = join52(repoDir, f);
|
|
13833
13934
|
if (!existsSync32(p))
|
|
13834
13935
|
continue;
|
|
13835
13936
|
try {
|
|
@@ -13847,24 +13948,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
|
|
|
13847
13948
|
if (!pw || !pkg)
|
|
13848
13949
|
return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
|
|
13849
13950
|
try {
|
|
13850
|
-
const dir =
|
|
13951
|
+
const dir = join52(runDir, relDir, "e2e");
|
|
13851
13952
|
mkdirSync21(dir, { recursive: true });
|
|
13852
|
-
writeFileSync24(
|
|
13853
|
-
writeFileSync24(
|
|
13953
|
+
writeFileSync24(join52(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
|
|
13954
|
+
writeFileSync24(join52(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
|
|
13854
13955
|
`);
|
|
13855
|
-
if (!await shoot(pw, ["test", "--config",
|
|
13956
|
+
if (!await shoot(pw, ["test", "--config", join52(dir, "playwright.config.cjs")], repoDir, ms, signal))
|
|
13856
13957
|
return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
|
|
13857
13958
|
const rels = [];
|
|
13858
13959
|
const walk = (d) => {
|
|
13859
13960
|
for (const e of readdirSync18(d, { withFileTypes: true })) {
|
|
13860
|
-
const full =
|
|
13961
|
+
const full = join52(d, e.name);
|
|
13861
13962
|
if (e.isDirectory())
|
|
13862
13963
|
walk(full);
|
|
13863
13964
|
else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
|
|
13864
|
-
rels.push(
|
|
13965
|
+
rels.push(join52(relDir, "e2e", relative7(dir, full)));
|
|
13865
13966
|
}
|
|
13866
13967
|
};
|
|
13867
|
-
walk(
|
|
13968
|
+
walk(join52(dir, "out"));
|
|
13868
13969
|
return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
|
|
13869
13970
|
} catch (e) {
|
|
13870
13971
|
return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
|
|
@@ -13943,15 +14044,15 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
13943
14044
|
if (!visualEvidenceEnabled(opts.env))
|
|
13944
14045
|
return skip("LOKI_VISUAL_EVIDENCE is 0");
|
|
13945
14046
|
const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
|
|
13946
|
-
const appDir = boot ?
|
|
13947
|
-
const pkgPath =
|
|
14047
|
+
const appDir = boot ? join52(repoDir, boot.boot.cwd) : repoDir;
|
|
14048
|
+
const pkgPath = join52(appDir, "package.json");
|
|
13948
14049
|
let script = null;
|
|
13949
14050
|
if (!boot) {
|
|
13950
14051
|
if (!existsSync32(pkgPath)) {
|
|
13951
|
-
const subs = ["backend", "frontend"].filter((d) => existsSync32(
|
|
14052
|
+
const subs = ["backend", "frontend"].filter((d) => existsSync32(join52(repoDir, d, "package.json")));
|
|
13952
14053
|
const has = (d) => {
|
|
13953
14054
|
try {
|
|
13954
|
-
return pickScript(JSON.parse(readFileSync41(
|
|
14055
|
+
return pickScript(JSON.parse(readFileSync41(join52(repoDir, d, "package.json"), "utf8"))) !== null;
|
|
13955
14056
|
} catch {
|
|
13956
14057
|
return false;
|
|
13957
14058
|
}
|
|
@@ -13985,20 +14086,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
13985
14086
|
}
|
|
13986
14087
|
if (!await waitUp(base, left(), signal))
|
|
13987
14088
|
return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
|
|
13988
|
-
const evRoot =
|
|
14089
|
+
const evRoot = join52(runDir, "evidence");
|
|
13989
14090
|
if (isSymlink(evRoot))
|
|
13990
14091
|
return skip("evidence dir is a symlink");
|
|
13991
14092
|
mkdirSync21(evRoot, { recursive: true });
|
|
13992
14093
|
if (pages.length > 0) {
|
|
13993
|
-
const rel0 =
|
|
13994
|
-
mkdirSync21(
|
|
14094
|
+
const rel0 = join52("evidence", randomBytes6(6).toString("hex"));
|
|
14095
|
+
mkdirSync21(join52(runDir, rel0));
|
|
13995
14096
|
const rels = [];
|
|
13996
14097
|
for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
|
|
13997
14098
|
if (aborted() || left() <= 0)
|
|
13998
14099
|
break;
|
|
13999
|
-
const rel =
|
|
14000
|
-
const ok = await shoot(pw, ["screenshot", `${base}${route}`,
|
|
14001
|
-
if (ok && !aborted() && !isSymlink(
|
|
14100
|
+
const rel = join52(rel0, `${screenName(route)}.png`);
|
|
14101
|
+
const ok = await shoot(pw, ["screenshot", `${base}${route}`, join52(runDir, rel)], appDir, left(), signal);
|
|
14102
|
+
if (ok && !aborted() && !isSymlink(join52(runDir, rel)) && existsSync32(join52(runDir, rel)))
|
|
14002
14103
|
rels.push(rel);
|
|
14003
14104
|
}
|
|
14004
14105
|
if (aborted())
|
|
@@ -14023,9 +14124,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
14023
14124
|
}
|
|
14024
14125
|
if (aborted())
|
|
14025
14126
|
return skip("aborted");
|
|
14026
|
-
const hdir =
|
|
14127
|
+
const hdir = join52(evRoot, randomBytes6(6).toString("hex"));
|
|
14027
14128
|
mkdirSync21(hdir);
|
|
14028
|
-
writeFileSync24(
|
|
14129
|
+
writeFileSync24(join52(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
|
|
14029
14130
|
`);
|
|
14030
14131
|
return { screens: [], http: true, skipped: null };
|
|
14031
14132
|
} catch (e) {
|
|
@@ -14055,11 +14156,11 @@ function receiptScreensProblem(receiptPath, receipt) {
|
|
|
14055
14156
|
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname19(receiptPath), receipt["evidence_screens"]);
|
|
14056
14157
|
}
|
|
14057
14158
|
var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0", visualGateEnabled = (env = process.env) => env["LOKI_VISUAL_GATE"] === "1", PAGE_RE, isPageFile = (p) => PAGE_RE.test(p), screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index", sha256File = (p) => createHash14("sha256").update(readFileSync41(p)).digest("hex"), playwrightBin = (repoDir) => {
|
|
14058
|
-
const bin =
|
|
14159
|
+
const bin = join52(repoDir, "node_modules", ".bin", "playwright");
|
|
14059
14160
|
return existsSync32(bin) ? bin : null;
|
|
14060
14161
|
}, playwrightTestPkg = (repoDir) => {
|
|
14061
|
-
const d =
|
|
14062
|
-
return existsSync32(
|
|
14162
|
+
const d = join52(repoDir, "node_modules", "@playwright", "test");
|
|
14163
|
+
return existsSync32(join52(d, "package.json")) ? d : null;
|
|
14063
14164
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
14064
14165
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
14065
14166
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -14105,7 +14206,7 @@ var init_outbox = __esm(() => {
|
|
|
14105
14206
|
});
|
|
14106
14207
|
|
|
14107
14208
|
// ../../loki-ts/src/engine10/stages/pr.ts
|
|
14108
|
-
import { join as
|
|
14209
|
+
import { join as join53 } from "path";
|
|
14109
14210
|
var DEFAULT_PUSH_SH, DEFAULT_PUSH_GITLAB_SH;
|
|
14110
14211
|
var init_pr = __esm(() => {
|
|
14111
14212
|
init_types();
|
|
@@ -14124,13 +14225,13 @@ var init_pr = __esm(() => {
|
|
|
14124
14225
|
init_receipt_surface();
|
|
14125
14226
|
init_yaml_key();
|
|
14126
14227
|
init_outbox();
|
|
14127
|
-
DEFAULT_PUSH_SH =
|
|
14128
|
-
DEFAULT_PUSH_GITLAB_SH =
|
|
14228
|
+
DEFAULT_PUSH_SH = join53(REPO_ROOT, "autonomy/lib/engine10-push.sh");
|
|
14229
|
+
DEFAULT_PUSH_GITLAB_SH = join53(REPO_ROOT, "autonomy/lib/engine10-push-gitlab.sh");
|
|
14129
14230
|
});
|
|
14130
14231
|
|
|
14131
14232
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
14132
14233
|
import { existsSync as existsSync33, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync8, readFileSync as readFileSync42, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "fs";
|
|
14133
|
-
import { dirname as dirname20, join as
|
|
14234
|
+
import { dirname as dirname20, join as join54 } from "path";
|
|
14134
14235
|
import { createHash as createHash15 } from "crypto";
|
|
14135
14236
|
function loadLessons(repoDir) {
|
|
14136
14237
|
const p = lessonsPath(repoDir);
|
|
@@ -14179,7 +14280,7 @@ function recordRunVerdict(repoDir, runId2, verdict) {
|
|
|
14179
14280
|
if (dirty)
|
|
14180
14281
|
save(repoDir, lessons);
|
|
14181
14282
|
}
|
|
14182
|
-
var lessonsPath = (repoDir) =>
|
|
14283
|
+
var lessonsPath = (repoDir) => join54(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
|
|
14183
14284
|
var init_pr_lessons = __esm(() => {
|
|
14184
14285
|
init_atomic();
|
|
14185
14286
|
init_safe_git();
|
|
@@ -14346,10 +14447,10 @@ var init_providers = __esm(() => {
|
|
|
14346
14447
|
|
|
14347
14448
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
14348
14449
|
import { existsSync as existsSync35, lstatSync as lstatSync13, mkdirSync as mkdirSync23, readFileSync as readFileSync44, writeFileSync as writeFileSync26 } from "fs";
|
|
14349
|
-
import { join as
|
|
14450
|
+
import { join as join55 } from "path";
|
|
14350
14451
|
function loadRouteRecord(runDir) {
|
|
14351
14452
|
try {
|
|
14352
|
-
const p =
|
|
14453
|
+
const p = join55(runDir, ROUTE_RECORD_FILE);
|
|
14353
14454
|
if (!existsSync35(p) || !lstatSync13(p).isFile())
|
|
14354
14455
|
return;
|
|
14355
14456
|
const v = JSON.parse(readFileSync44(p, "utf8"));
|
|
@@ -14411,6 +14512,7 @@ var init_implement_route = __esm(() => {
|
|
|
14411
14512
|
|
|
14412
14513
|
// ../../loki-ts/src/engine10/stages/implement.ts
|
|
14413
14514
|
var init_implement = __esm(() => {
|
|
14515
|
+
init_install();
|
|
14414
14516
|
init_lean_prefix();
|
|
14415
14517
|
init_pr_lessons();
|
|
14416
14518
|
init_context();
|
|
@@ -14488,50 +14590,6 @@ var init_worker = __esm(() => {
|
|
|
14488
14590
|
init_safe_git();
|
|
14489
14591
|
});
|
|
14490
14592
|
|
|
14491
|
-
// ../../loki-ts/src/project_model/package_suite.ts
|
|
14492
|
-
import { join as join55 } from "path";
|
|
14493
|
-
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
14494
|
-
const api = loadProjectApi(repoDir);
|
|
14495
|
-
if (!isMultiRoot(api))
|
|
14496
|
-
return false;
|
|
14497
|
-
const withTests = api.packages().filter((p) => p.commands.test);
|
|
14498
|
-
if (withTests.length === 0)
|
|
14499
|
-
return false;
|
|
14500
|
-
for (const pkg of withTests) {
|
|
14501
|
-
const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd2 = `(cd ${tc.cwd} && ${tc.cmd})`;
|
|
14502
|
-
const started = Date.now();
|
|
14503
|
-
const r = await run(["bash", "-c", tc.cmd], { cwd: join55(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
14504
|
-
const duration_s = (Date.now() - started) / 1000;
|
|
14505
|
-
if (signal.aborted) {
|
|
14506
|
-
checks.push({ name, cmd: cmd2, result: "not_run", duration_s });
|
|
14507
|
-
notProven.add(`not run: ${name} (aborted)`);
|
|
14508
|
-
continue;
|
|
14509
|
-
}
|
|
14510
|
-
const out2 = `${r.stdout}
|
|
14511
|
-
${r.stderr}`;
|
|
14512
|
-
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd: join55(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
14513
|
-
if (lr) {
|
|
14514
|
-
checks.push({ name, cmd: cmd2, result: "not_run", duration_s });
|
|
14515
|
-
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
14516
|
-
continue;
|
|
14517
|
-
}
|
|
14518
|
-
const cls = classifyCheck({ kind: "test", ok: r.exitCode === 0, out: out2, ...goRunner(tc.cmd) });
|
|
14519
|
-
checks.push({ name, cmd: cmd2, result: cls.result, duration_s, ...cls.result === "fail" ? { ids: failIds(out2) } : {} });
|
|
14520
|
-
if (cls.result === "not_run")
|
|
14521
|
-
notProven.add(`not run: ${name} (${cls.reason ?? NO_TESTS_REASON})`);
|
|
14522
|
-
}
|
|
14523
|
-
for (const pkg of api.packages().filter((p) => !p.commands.test))
|
|
14524
|
-
notProven.add(`full suite: package ${pkg.name} defines no test command`);
|
|
14525
|
-
return true;
|
|
14526
|
-
}
|
|
14527
|
-
var init_package_suite = __esm(() => {
|
|
14528
|
-
init_load_owner();
|
|
14529
|
-
init_check_result();
|
|
14530
|
-
init_shell();
|
|
14531
|
-
init_failures();
|
|
14532
|
-
init_resolve();
|
|
14533
|
-
});
|
|
14534
|
-
|
|
14535
14593
|
// ../../loki-ts/src/engine10/stages/deep.ts
|
|
14536
14594
|
var exports_deep = {};
|
|
14537
14595
|
__export(exports_deep, {
|
|
@@ -14577,7 +14635,7 @@ function sessionCouncil(sessions) {
|
|
|
14577
14635
|
} };
|
|
14578
14636
|
}
|
|
14579
14637
|
async function runFullSuite(ctx, signal, opts, checks, notProven) {
|
|
14580
|
-
if (await runPackageSuites(ctx.repoDir, signal, { path: opts.path, timeoutMs: opts.fullSuiteTimeoutMs ?? FULL_SUITE_TIMEOUT_MS, baseSha: ctx.baseSha }, checks, notProven))
|
|
14638
|
+
if (await runPackageSuites(ctx.repoDir, signal, { path: opts.path, timeoutMs: opts.fullSuiteTimeoutMs ?? FULL_SUITE_TIMEOUT_MS, baseSha: ctx.baseSha, skip: installOwned(ctx.repoDir, ctx.outputs().intake?.install_created) }, checks, notProven))
|
|
14581
14639
|
return;
|
|
14582
14640
|
const map = await ctx.tests.detect(ctx.repoDir);
|
|
14583
14641
|
if (map.runners.length === 0) {
|
|
@@ -14605,7 +14663,7 @@ async function runFullSuite(ctx, signal, opts, checks, notProven) {
|
|
|
14605
14663
|
continue;
|
|
14606
14664
|
}
|
|
14607
14665
|
const out2 = `${r.stdout}
|
|
14608
|
-
${r.stderr}`, lr = r.exitCode === 0 ? undefined : await harnessLoadReason({ repoDir: ctx.repoDir, baseSha: ctx.baseSha, out: out2, cmd: spec.cmd, args: spec.args, signal, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
14666
|
+
${r.stderr}`, lr = r.exitCode === 0 ? undefined : await harnessLoadReason({ repoDir: ctx.repoDir, baseSha: ctx.baseSha, skip: installOwned(ctx.repoDir, ctx.outputs().intake?.install_created), out: out2, cmd: spec.cmd, args: spec.args, signal, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
14609
14667
|
if (lr) {
|
|
14610
14668
|
checks.push({ name, cmd: [spec.cmd, ...spec.args].join(" "), result: "not_run", duration_s: durationS });
|
|
14611
14669
|
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
@@ -14757,7 +14815,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
14757
14815
|
}
|
|
14758
14816
|
let changed;
|
|
14759
14817
|
try {
|
|
14760
|
-
changed = changedFiles(ctx.repoDir, ctx.baseSha);
|
|
14818
|
+
changed = changedFiles(ctx.repoDir, ctx.baseSha, installOwned(ctx.repoDir, ctx.outputs().intake?.install_created));
|
|
14761
14819
|
} catch (err) {
|
|
14762
14820
|
return { status: "failed", data: {}, reason: `git diff against base failed: ${err.message}` };
|
|
14763
14821
|
}
|
|
@@ -14789,8 +14847,9 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
14789
14847
|
ctx.emit("deep.completed", "deep", { checks, status_state: statusState, addendum_sha256: addendumSha256 });
|
|
14790
14848
|
return { status: "completed", data: { checks, addendum_sha256: addendumSha256, status_state: statusState, not_proven: allNotProven } };
|
|
14791
14849
|
}
|
|
14792
|
-
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,
|
|
14850
|
+
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, deepStage, stage;
|
|
14793
14851
|
var init_deep = __esm(() => {
|
|
14852
|
+
init_install();
|
|
14794
14853
|
init_app_probe();
|
|
14795
14854
|
init_secure_scan();
|
|
14796
14855
|
init_shell();
|
|
@@ -14808,16 +14867,6 @@ var init_deep = __esm(() => {
|
|
|
14808
14867
|
DEFAULT_SECRET_SCAN_SH = new URL("../../../../autonomy/lib/secret-scan.sh", import.meta.url).pathname;
|
|
14809
14868
|
PR_NUMBER_RE = /\/pull\/(\d+)$/;
|
|
14810
14869
|
SHA_RE = /^[0-9a-f]{40}$/;
|
|
14811
|
-
FULL_SUITE_CMD = {
|
|
14812
|
-
pytest: { cmd: "python", args: ["-m", "pytest", "-q"] },
|
|
14813
|
-
vitest: { cmd: "npx", args: ["vitest", "run"] },
|
|
14814
|
-
jest: { cmd: "npx", args: ["jest"] },
|
|
14815
|
-
bun: { cmd: "bun", args: ["test"] },
|
|
14816
|
-
node: { cmd: "node", args: ["--test"] },
|
|
14817
|
-
npm: { cmd: "npm", args: ["test", "--silent"] },
|
|
14818
|
-
go: { cmd: "go", args: ["test", "-json", "./..."] },
|
|
14819
|
-
cargo: { cmd: "cargo", args: ["test"] }
|
|
14820
|
-
};
|
|
14821
14870
|
deepStage = {
|
|
14822
14871
|
name: "deep",
|
|
14823
14872
|
...STAGE_BUDGETS.deep,
|
|
@@ -14866,7 +14915,7 @@ async function runCheck(ctx, name, cmd2, args, signal, checks, opts = {}) {
|
|
|
14866
14915
|
const cwd = opts.cwd ?? ctx.repoDir;
|
|
14867
14916
|
const one = async (a) => {
|
|
14868
14917
|
let c2 = classifyCheck({ kind, ok: a.ok, cut: a.cut, missing: a.missing, out: a.out, ...goRunner(cmd2, args), path: /\.[cm]?[jt]s$/.test(args[args.length - 1] ?? "") ? args[args.length - 1] : undefined });
|
|
14869
|
-
const lr = kind === "test" && !a.ok && !a.cut && !a.missing ? await harnessLoadReason({ repoDir: ctx.repoDir, baseSha: ctx.baseSha, out: a.out, cmd: cmd2, args, signal, cwd, protect: opts.protect, ...opts.path ? { env: { PATH: opts.path } } : {} }) : undefined;
|
|
14918
|
+
const lr = kind === "test" && !a.ok && !a.cut && !a.missing ? await harnessLoadReason({ repoDir: ctx.repoDir, baseSha: ctx.baseSha, skip: installOwned(ctx.repoDir, ctx.outputs?.().intake?.install_created), out: a.out, cmd: cmd2, args, signal, cwd, protect: opts.protect, ...opts.path ? { env: { PATH: opts.path } } : {} }) : undefined;
|
|
14870
14919
|
if (lr)
|
|
14871
14920
|
c2 = { result: "not_run", reason: lr, owner: "harness" };
|
|
14872
14921
|
if (!lr && kind === "static" && !a.ok && !a.cut && !a.missing && opts.wall?.size && wallOwnedFailure(a.out, cwd, ctx.repoDir, opts.wall))
|
|
@@ -14985,6 +15034,7 @@ var CHECK_TIMEOUT_MS = 60000, excerpts, isHold = (c) => isHoldoutCheck(c.name),
|
|
|
14985
15034
|
}
|
|
14986
15035
|
} }), verifyStage;
|
|
14987
15036
|
var init_verify = __esm(() => {
|
|
15037
|
+
init_install();
|
|
14988
15038
|
init_scope();
|
|
14989
15039
|
init_runner_config();
|
|
14990
15040
|
init_assert_delta();
|
|
@@ -15015,7 +15065,7 @@ var init_verify = __esm(() => {
|
|
|
15015
15065
|
async run(ctx, signal) {
|
|
15016
15066
|
let changed;
|
|
15017
15067
|
try {
|
|
15018
|
-
changed = changedFiles(ctx.repoDir, ctx.baseSha);
|
|
15068
|
+
changed = changedFiles(ctx.repoDir, ctx.baseSha, installOwned(ctx.repoDir, ctx.outputs().intake?.install_created));
|
|
15019
15069
|
} catch (err) {
|
|
15020
15070
|
return { status: "failed", data: {}, reason: `git diff against base failed: ${err.message}` };
|
|
15021
15071
|
}
|
|
@@ -15028,7 +15078,7 @@ var init_verify = __esm(() => {
|
|
|
15028
15078
|
}
|
|
15029
15079
|
let risk = (() => {
|
|
15030
15080
|
try {
|
|
15031
|
-
const r = classifyRisk(diffFiles(ctx.repoDir, ctx.baseSha));
|
|
15081
|
+
const r = classifyRisk(diffFiles(ctx.repoDir, ctx.baseSha, installOwned(ctx.repoDir, ctx.outputs().intake?.install_created)));
|
|
15032
15082
|
recordRisk(ctx.repoDir, r);
|
|
15033
15083
|
return r;
|
|
15034
15084
|
} catch {
|
|
@@ -15139,7 +15189,7 @@ ${x}` : c.cmd };
|
|
|
15139
15189
|
return [`weakened test: ${t.path}`, ...assertDeltaNotes(ctx.repoDir, ctx.baseSha, null, t.path, intake?.task ?? "", k?.b, k?.h) ?? []];
|
|
15140
15190
|
});
|
|
15141
15191
|
const weakened = [...modifiedRel, ...cfgChanged.map((f) => `test configuration changed: ${f}`), ...preRed.weak.map((n2) => `skipped or fewer tests than base: ${n2}`)];
|
|
15142
|
-
const notProven = [...weakened, ...pub.filter((c) => c.name === "holdout" && c.result !== "pass").map((c) => c.result === "not_run" ? "holdout not executed" : "holdout check failed"), ...[...fullNotProven].filter((n2) => !n2.startsWith("full suite (no test runner")), ...pub.filter((c) => c.owner === "harness" && c.name !== "holdout").map((c) => `${c.reason} (${c.name}; harness-owned, no fix rounds)`), ...new Set(checks.filter((c) => c.interpreter === "system" && c.result !== "not_run").map((c) => c.name.startsWith("lint:") ? "lint ran on the system ruff" : "tests ran on the system interpreter"))];
|
|
15192
|
+
const notProven = [...weakened, ...intake?.deps_not_proven ?? [], ...pub.filter((c) => c.name === "holdout" && c.result !== "pass").map((c) => c.result === "not_run" ? "holdout not executed" : "holdout check failed"), ...[...fullNotProven].filter((n2) => !n2.startsWith("full suite (no test runner")), ...pub.filter((c) => c.owner === "harness" && c.name !== "holdout").map((c) => `${c.reason} (${c.name}; harness-owned, no fix rounds)`), ...new Set(checks.filter((c) => c.interpreter === "system" && c.result !== "not_run").map((c) => c.name.startsWith("lint:") ? "lint ran on the system ruff" : "tests ran on the system interpreter"))];
|
|
15143
15193
|
const wallNames = new Set(wallTests.map(testCheckName)), wallRun = checks.filter((c) => wallNames.has(c.name) || isHold(c)), wallPassed = wallRun.some((c) => c.result === "fail") ? false : wallRun.length > 0 && wallRun.every((c) => c.result === "pass") ? true : undefined;
|
|
15144
15194
|
return { status: "completed", data: { checks: pub, flaky, ...wallPassed === undefined ? {} : { wall_passed: wallPassed }, failures_grouped: failuresGrouped, holdout_failed: holdoutFailed, changed_files: changed, not_proven: notProven, pre_red: preRed.ids, pre_red_checks: preRed.names, ...attr.line ? { baseline_line: attr.line, introduced_checks: attr.introducedChecks } : {}, test_counts: testCounts, uncovered_changed: uncoveredChanged, target_checks: checks.filter((c) => c.result === "pass" && targetNames.has(c.name)).map((c) => isHold(c) ? "holdout" : c.name), risk } };
|
|
15145
15195
|
}
|
|
@@ -15213,7 +15263,7 @@ function conventionsBrief(c) {
|
|
|
15213
15263
|
if (!c)
|
|
15214
15264
|
return "";
|
|
15215
15265
|
const decl = `manifest type: ${c.packageType ?? "(unset)"}, compiler module: ${c.tsModule ?? "(unset)"}${c.runner ? `, test runner: ${c.runner}` : ""}`;
|
|
15216
|
-
return c.moduleSystem === "commonjs" ? `Package conventions (${decl}): this package compiles as CommonJS. Never use import.meta or top-level await (TS1470, the package's own tsc rejects them); use __dirname
|
|
15266
|
+
return c.moduleSystem === "commonjs" ? `Package conventions (${decl}): this package compiles as CommonJS. Never use import.meta or top-level await (TS1470, the package's own tsc rejects them); use __dirname and __filename for paths. In TypeScript files write import statements (they compile to CommonJS) and never require(): a package lint config commonly forbids require() and runs over your file; use require() only in plain .js or .cjs files.` : `Package conventions (${decl}): this package is ES modules. Use import syntax; use import.meta.url for file locations; never use require(), __dirname or __filename.`;
|
|
15217
15267
|
}
|
|
15218
15268
|
function conventionViolation(c, fileName, content) {
|
|
15219
15269
|
if (!c || c.moduleSystem !== "commonjs" || !/\.[cm]?[jt]sx?$/.test(fileName) || /\.m[jt]s$/.test(fileName))
|
|
@@ -15605,12 +15655,14 @@ var init_preexisting_dirty = __esm(() => {
|
|
|
15605
15655
|
|
|
15606
15656
|
// ../../loki-ts/src/e10ext/commit_filter.ts
|
|
15607
15657
|
import { dirname as dirname26 } from "path";
|
|
15608
|
-
function dropSet(repoDir, staged, preexistingDirty, env = process.env) {
|
|
15609
|
-
|
|
15658
|
+
function dropSet(repoDir, staged, preexistingDirty, env = process.env, installCreated) {
|
|
15659
|
+
const owned = installOwned(repoDir, installCreated, env), made = installCreated?.files ?? {};
|
|
15660
|
+
return staged.concat(untouchedSinceIntake(repoDir, preexistingDirty, env).map((f) => ({ st: "L", f })), staged.filter(({ f }) => owned(f)).map(({ f }) => ({ st: "L", f }))).filter(({ st, f }) => f.startsWith(".loki/") || st === "L" || /(^|\/)loki_wall_[^/]*$/.test(f) || st === "A" && !Object.hasOwn(made, f) && !staged.some(({ f: m }) => /(^|\/)(package\.json|pyproject\.toml|requirements\.txt|Cargo\.toml|go\.mod)$/.test(m) && dirname26(m) === dirname26(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
|
|
15610
15661
|
}
|
|
15611
15662
|
var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []), formatChanged = (repoDir, staged, dropped2, env = process.env) => runFormatters(repoDir, staged.filter(({ st, f }) => (st === "A" || st === "M") && !dropped2.has(f) && !f.startsWith(".loki/")).map(({ f }) => f), tokenFreeEnv(env));
|
|
15612
15663
|
var init_commit_filter = __esm(() => {
|
|
15613
15664
|
init_preexisting_dirty();
|
|
15665
|
+
init_install();
|
|
15614
15666
|
init_repo_profile();
|
|
15615
15667
|
init_safe_git();
|
|
15616
15668
|
});
|
|
@@ -16623,7 +16675,7 @@ var init_seal = __esm(() => {
|
|
|
16623
16675
|
if (sd.code !== 0)
|
|
16624
16676
|
return { status: "failed", data: {}, reason: "git diff against base failed" };
|
|
16625
16677
|
const staged = parseStaged(sd.out);
|
|
16626
|
-
const drop = dropSet(ctx.repoDir, staged, ctx.outputs().intake?.preexisting_dirty);
|
|
16678
|
+
const drop = dropSet(ctx.repoDir, staged, ctx.outputs().intake?.preexisting_dirty, process.env, ctx.outputs().intake?.install_created);
|
|
16627
16679
|
const sat = await discardIfSatisfied((a) => git4(ctx, a), ctx.baseSha, ctx.outputs(), staged, new Set(drop.filter(({ st }) => st === "L").map(({ f }) => f)), ctx.repoDir);
|
|
16628
16680
|
if (sat)
|
|
16629
16681
|
return sat;
|