loki-mode 11.51.0 → 11.51.2
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/loki-ts/dist/loki.js +1105 -1103
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +440 -439
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-CaIJn6cH.js → AdminPage-ByOJNu5y.js} +1 -1
- package/web-app/dist/assets/{Avatar-dVmwCh5N.js → Avatar-CoZ-ofeP.js} +1 -1
- package/web-app/dist/assets/{Badge-HvHbM4jj.js → Badge-BOZM8PNP.js} +1 -1
- package/web-app/dist/assets/{Button-5fe1mbnW.js → Button-CzMxcI0Q.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-CD0RvCiF.js → CockpitPage-B278f5SK.js} +1 -1
- package/web-app/dist/assets/{ComparePage-CbaluJD-.js → ComparePage-Cp88FKzT.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-BpK2aRWD.js → ErrorBoundary-CRw4LAKs.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-CyEySJZi.js → EvidenceReceiptPanel-8wmYECtQ.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-Ci2AAQkj.js → GitHubIssuesPanel-Bj5oJskW.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BUYaYXHS.js → GitHubPRsPanel-Cbe7kg0X.js} +1 -1
- package/web-app/dist/assets/{HomePage-D5_HXS1Q.js → HomePage-CRcJUAy0.js} +2 -2
- package/web-app/dist/assets/{LoginPage-D3gyY-ls.js → LoginPage-DLQL2Kvm.js} +1 -1
- package/web-app/dist/assets/{MagicPage-Bsn48Ur5.js → MagicPage-M9J5khqf.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-B6YUOQT2.js → MetricsPage-C2aSq2eq.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-ChVB9LFE.js → NotFoundPage-z7Ad3b5Z.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-Xtbz9rr-.js → ProjectPage-CCij-iYF.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-Cd5cM4xT.js → ProjectsPage-DzYXxvEH.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DbullC_M.js → SettingsPage-kaIblmv8.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-C-ptVozh.js → ShowcasePage-C3UsOlE6.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-BqKjLA_f.js → SystemSettingsPage-L9alZW2b.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-Cs-MLZLd.js → TeamsPage-CUN1TLAC.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-BhZCjlR8.js → TemplatesPage-B1NtMQlZ.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Bd8EQQ0X.js → TerminalOutput-D0pKSlc-.js} +1 -1
- package/web-app/dist/assets/{activity-Ghjc1KL0.js → activity-C03x03AH.js} +1 -1
- package/web-app/dist/assets/{bell-B6yS64ng.js → bell-8hDBaFQB.js} +1 -1
- package/web-app/dist/assets/{bot-6O9QuDQ4.js → bot-DLQhJqda.js} +1 -1
- package/web-app/dist/assets/{check-BbWxeQg7.js → check-CLzpVJ44.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D_1VwLoo.js → chevron-left-CQ7OLcYf.js} +1 -1
- package/web-app/dist/assets/{circle-alert-BnExIPLS.js → circle-alert-cEdG9TXw.js} +1 -1
- package/web-app/dist/assets/{clock-CZtHVj7a.js → clock-ChFx5TEw.js} +1 -1
- package/web-app/dist/assets/{cloud-DarO4XFf.js → cloud-MYMvEmfN.js} +1 -1
- package/web-app/dist/assets/{code-xml-B1bGHzXN.js → code-xml-bvE5DDtJ.js} +1 -1
- package/web-app/dist/assets/{database-lDd4a5mU.js → database-D9zj2H1_.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-i28QkMfY.js → dollar-sign-BsbH0RG0.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-3ohb1kRc.js → file-code-corner-DGarmzGt.js} +1 -1
- package/web-app/dist/assets/{file-plus-Cp5yulA3.js → file-plus-k4z_rNeN.js} +1 -1
- package/web-app/dist/assets/{globe-cNc9gWtx.js → globe-MJLSZC2e.js} +1 -1
- package/web-app/dist/assets/{hammer-BRFscyI0.js → hammer-Dd5_Zi5s.js} +1 -1
- package/web-app/dist/assets/{index-p3XpK3ZT.js → index-BMcYE1jz.js} +3 -3
- package/web-app/dist/assets/{layers-CGy_6jwr.js → layers-DvcCkeHJ.js} +1 -1
- package/web-app/dist/assets/{loader-circle-B0t6WEe8.js → loader-circle-D-ZWcTLu.js} +1 -1
- package/web-app/dist/assets/{lock-CtMLtv4v.js → lock-BISBkUVy.js} +1 -1
- package/web-app/dist/assets/{package-ATt-2SH-.js → package-7qbdDVIE.js} +1 -1
- package/web-app/dist/assets/{plus-cGAE5CuJ.js → plus-o52_30l5.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-D0J0Bnaz.js → refresh-cw-BVvykHjR.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-BSZHcpHe.js → rotate-ccw-BtYo8dnt.js} +1 -1
- package/web-app/dist/assets/{scroll-text-BShob4O2.js → scroll-text-CL4yV4VG.js} +1 -1
- package/web-app/dist/assets/{server-saMTHour.js → server-UCe-Ic3k.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BO6n8obe.js → shield-alert-Bq1Elbpw.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BY687kRl.js → thumbs-up-Y4uvYI48.js} +1 -1
- package/web-app/dist/assets/{trash-2-B3OnxR-U.js → trash-2-CzG_qlyk.js} +1 -1
- package/web-app/dist/assets/{trending-down-BiNXdXei.js → trending-down-Cmubfmha.js} +1 -1
- package/web-app/dist/assets/{trending-up-B9M18Jr4.js → trending-up-D5zMFb3Q.js} +1 -1
- package/web-app/dist/assets/{upload-COmaSiCG.js → upload-Cglleu88.js} +1 -1
- package/web-app/dist/assets/{usePolling-DaYeZTBV.js → usePolling-7I8GJNXT.js} +1 -1
- package/web-app/dist/assets/{user-Bz0wAwau.js → user-BjDOr5qQ.js} +1 -1
- package/web-app/dist/index.html +1 -1
|
@@ -8806,6 +8806,289 @@ var init_session_route = __esm(() => {
|
|
|
8806
8806
|
init_unit_model();
|
|
8807
8807
|
});
|
|
8808
8808
|
|
|
8809
|
+
// ../../loki-ts/src/runner/worker_proc.ts
|
|
8810
|
+
function killGroup2(pid, sig) {
|
|
8811
|
+
if (!pid)
|
|
8812
|
+
return;
|
|
8813
|
+
try {
|
|
8814
|
+
process.kill(-pid, sig);
|
|
8815
|
+
} catch {}
|
|
8816
|
+
}
|
|
8817
|
+
var CANCEL_GRACE_MS;
|
|
8818
|
+
var init_worker_proc = __esm(() => {
|
|
8819
|
+
CANCEL_GRACE_MS = Number(process.env["LOKI_E10_CANCEL_GRACE_MS"]) > 0 ? Number(process.env["LOKI_E10_CANCEL_GRACE_MS"]) : 1e4;
|
|
8820
|
+
});
|
|
8821
|
+
|
|
8822
|
+
// ../../loki-ts/src/util/shell.ts
|
|
8823
|
+
async function readStreamCapped(stream, maxBytes = MAX_STDOUT_BYTES, onFirstChunk) {
|
|
8824
|
+
const reader = stream.getReader();
|
|
8825
|
+
let first = onFirstChunk;
|
|
8826
|
+
const decoder = new TextDecoder;
|
|
8827
|
+
let out2 = "";
|
|
8828
|
+
let total = 0;
|
|
8829
|
+
try {
|
|
8830
|
+
while (total < maxBytes) {
|
|
8831
|
+
const { done, value } = await reader.read();
|
|
8832
|
+
if (done)
|
|
8833
|
+
break;
|
|
8834
|
+
if (!value)
|
|
8835
|
+
continue;
|
|
8836
|
+
if (first && value.byteLength > 0) {
|
|
8837
|
+
const cb = first;
|
|
8838
|
+
first = undefined;
|
|
8839
|
+
try {
|
|
8840
|
+
cb();
|
|
8841
|
+
} catch {}
|
|
8842
|
+
}
|
|
8843
|
+
total += value.byteLength;
|
|
8844
|
+
if (total > maxBytes) {
|
|
8845
|
+
const keep = value.byteLength - (total - maxBytes);
|
|
8846
|
+
out2 += decoder.decode(value.subarray(0, keep), { stream: true });
|
|
8847
|
+
break;
|
|
8848
|
+
}
|
|
8849
|
+
out2 += decoder.decode(value, { stream: true });
|
|
8850
|
+
}
|
|
8851
|
+
out2 += decoder.decode();
|
|
8852
|
+
} finally {
|
|
8853
|
+
try {
|
|
8854
|
+
await reader.cancel();
|
|
8855
|
+
} catch {}
|
|
8856
|
+
reader.releaseLock();
|
|
8857
|
+
}
|
|
8858
|
+
return out2;
|
|
8859
|
+
}
|
|
8860
|
+
async function run(argv, opts = {}) {
|
|
8861
|
+
const proc = Bun.spawn({
|
|
8862
|
+
cmd: [...argv],
|
|
8863
|
+
stdout: "pipe",
|
|
8864
|
+
stderr: "pipe",
|
|
8865
|
+
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
8866
|
+
cwd: opts.cwd,
|
|
8867
|
+
...opts.group ? { detached: true } : {}
|
|
8868
|
+
});
|
|
8869
|
+
let timer;
|
|
8870
|
+
let killTimer;
|
|
8871
|
+
const stop = () => {
|
|
8872
|
+
try {
|
|
8873
|
+
if (opts.group)
|
|
8874
|
+
killGroup2(proc.pid, "SIGTERM");
|
|
8875
|
+
else
|
|
8876
|
+
proc.kill("SIGTERM");
|
|
8877
|
+
} catch {}
|
|
8878
|
+
killTimer ??= setTimeout(() => {
|
|
8879
|
+
try {
|
|
8880
|
+
if (opts.group)
|
|
8881
|
+
killGroup2(proc.pid, "SIGKILL");
|
|
8882
|
+
else
|
|
8883
|
+
proc.kill("SIGKILL");
|
|
8884
|
+
} catch {}
|
|
8885
|
+
}, 2000);
|
|
8886
|
+
};
|
|
8887
|
+
if (opts.timeoutMs && opts.timeoutMs > 0)
|
|
8888
|
+
timer = setTimeout(stop, opts.timeoutMs);
|
|
8889
|
+
if (opts.signal) {
|
|
8890
|
+
if (opts.signal.aborted)
|
|
8891
|
+
stop();
|
|
8892
|
+
else
|
|
8893
|
+
opts.signal.addEventListener("abort", stop, { once: true });
|
|
8894
|
+
}
|
|
8895
|
+
try {
|
|
8896
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
8897
|
+
readStreamCapped(proc.stdout, MAX_STDOUT_BYTES, opts.onFirstStdout),
|
|
8898
|
+
new Response(proc.stderr).text(),
|
|
8899
|
+
proc.exited
|
|
8900
|
+
]);
|
|
8901
|
+
return { stdout, stderr, exitCode };
|
|
8902
|
+
} finally {
|
|
8903
|
+
if (timer)
|
|
8904
|
+
clearTimeout(timer);
|
|
8905
|
+
if (killTimer)
|
|
8906
|
+
clearTimeout(killTimer);
|
|
8907
|
+
opts.signal?.removeEventListener("abort", stop);
|
|
8908
|
+
if (opts.group)
|
|
8909
|
+
killGroup2(proc.pid, "SIGKILL");
|
|
8910
|
+
}
|
|
8911
|
+
}
|
|
8912
|
+
async function commandExists(name) {
|
|
8913
|
+
const safe = shEscape(name);
|
|
8914
|
+
const r = await run(["sh", "-c", `command -v ${safe}`], { timeoutMs: 5000 });
|
|
8915
|
+
if (r.exitCode === 0) {
|
|
8916
|
+
const path = r.stdout.trim();
|
|
8917
|
+
return path || null;
|
|
8918
|
+
}
|
|
8919
|
+
return null;
|
|
8920
|
+
}
|
|
8921
|
+
function shEscape(name) {
|
|
8922
|
+
if (!/^[A-Za-z0-9._/-]+$/.test(name)) {
|
|
8923
|
+
throw new Error(`refused to shell-escape suspect token: ${name}`);
|
|
8924
|
+
}
|
|
8925
|
+
return name;
|
|
8926
|
+
}
|
|
8927
|
+
var MAX_STDOUT_BYTES;
|
|
8928
|
+
var init_shell = __esm(() => {
|
|
8929
|
+
init_worker_proc();
|
|
8930
|
+
MAX_STDOUT_BYTES = 16 * 1024 * 1024;
|
|
8931
|
+
});
|
|
8932
|
+
|
|
8933
|
+
// ../../loki-ts/src/providers/mcp_config.ts
|
|
8934
|
+
var init_mcp_config = () => {};
|
|
8935
|
+
|
|
8936
|
+
// ../../loki-ts/src/providers/claude_flags.ts
|
|
8937
|
+
import { existsSync as existsSync20, readFileSync as readFileSync26 } from "fs";
|
|
8938
|
+
import { resolve as resolvePath, dirname as dirname13 } from "path";
|
|
8939
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
8940
|
+
function claudeFlagSupported(flag, helpText) {
|
|
8941
|
+
const txt = helpText ?? _claudeHelpCache;
|
|
8942
|
+
if (txt === null || txt === undefined) {
|
|
8943
|
+
return false;
|
|
8944
|
+
}
|
|
8945
|
+
return txt.includes(flag);
|
|
8946
|
+
}
|
|
8947
|
+
async function ensureClaudeHelpCache() {
|
|
8948
|
+
if (_claudeHelpCache !== null)
|
|
8949
|
+
return;
|
|
8950
|
+
try {
|
|
8951
|
+
const proc = Bun.spawn(["claude", "--help"], {
|
|
8952
|
+
stdout: "pipe",
|
|
8953
|
+
stderr: "pipe",
|
|
8954
|
+
env: { ...process.env }
|
|
8955
|
+
});
|
|
8956
|
+
const text2 = await new Response(proc.stdout).text();
|
|
8957
|
+
await proc.exited;
|
|
8958
|
+
_claudeHelpCache = text2 || "";
|
|
8959
|
+
} catch {
|
|
8960
|
+
_claudeHelpCache = "";
|
|
8961
|
+
}
|
|
8962
|
+
}
|
|
8963
|
+
function leanReviewerFlags(opts = {}) {
|
|
8964
|
+
const env = opts.env ?? process.env;
|
|
8965
|
+
if (env["LOKI_LEAN_CHILDREN"] === "0")
|
|
8966
|
+
return [];
|
|
8967
|
+
const ok = opts.flagSupported ?? ((f) => claudeFlagSupported(f));
|
|
8968
|
+
const out2 = [];
|
|
8969
|
+
if (env["LOKI_BARE_SUBCALLS"] !== "0" && (env["ANTHROPIC_API_KEY"] ?? "").trim() !== "" && ok("--bare")) {
|
|
8970
|
+
out2.push("--bare");
|
|
8971
|
+
} else {
|
|
8972
|
+
if (ok("--setting-sources"))
|
|
8973
|
+
out2.push("--setting-sources", opts.settingSources ?? "project");
|
|
8974
|
+
if (ok("--strict-mcp-config"))
|
|
8975
|
+
out2.push("--strict-mcp-config", "--mcp-config", '{"mcpServers":{}}');
|
|
8976
|
+
if (ok("--disable-slash-commands"))
|
|
8977
|
+
out2.push("--disable-slash-commands");
|
|
8978
|
+
}
|
|
8979
|
+
if (ok("--tools"))
|
|
8980
|
+
out2.push(`--tools=${opts.tools ?? ""}`);
|
|
8981
|
+
return out2;
|
|
8982
|
+
}
|
|
8983
|
+
function designArchetypesText() {
|
|
8984
|
+
try {
|
|
8985
|
+
const moduleDir = dirname13(fileURLToPath5(import.meta.url));
|
|
8986
|
+
for (const rel of [
|
|
8987
|
+
["..", "..", "..", "references", "design-archetypes.md"],
|
|
8988
|
+
["..", "..", "references", "design-archetypes.md"]
|
|
8989
|
+
]) {
|
|
8990
|
+
const p = resolvePath(moduleDir, ...rel);
|
|
8991
|
+
if (existsSync20(p))
|
|
8992
|
+
return readFileSync26(p, "utf8");
|
|
8993
|
+
}
|
|
8994
|
+
} catch {}
|
|
8995
|
+
return "";
|
|
8996
|
+
}
|
|
8997
|
+
var REVIEW_GUARD_DENYLIST = "Edit,Write,NotebookEdit,Bash(git commit:*),Bash(git reset:*),Bash(git push:*),Bash(git checkout:*),Bash(git clean:*),Bash(git rm:*),Bash(git stash:*),Bash(git -C:*),Bash(git --git-dir:*),Bash(git -c:*),Bash(git --exec-path:*),Bash(git diff --output:*),Bash(git diff --output=:*),Bash(git diff --ext-diff:*),Bash(git diff --no-index:*),Bash(git log --output:*),Bash(git log --output=:*),Bash(git log --ext-diff:*),Bash(git show --output:*),Bash(git show --output=:*),Bash(git show --ext-diff:*),Bash(git blame --output:*),Bash(git blame --output=:*),Bash(rg --pre:*),Bash(rg --pre=:*),Bash(rg --pre-glob:*),Bash(rg --pre-glob=:*),Bash(rg --hostname-bin:*),Bash(rg --hostname-bin=:*),Bash(find -delete:*),Bash(find -exec:*),Bash(find -execdir:*),Bash(find -ok:*),Bash(find -fprint:*),Bash(find -fprintf:*),Bash(find -fls:*),Bash(git * --output*),Bash(git * --ext-diff*),Bash(git * --no-index*),Bash(rg * --pre*),Bash(rg * --hostname-bin*),Bash(rg --pre*),Bash(rg --hostname-bin*),Bash(find * -delete*),Bash(find * -exec*),Bash(find * -execdir*),Bash(find * -fprint*),Bash(find * -fls*),Bash(find * -ok*)", _claudeHelpCache = null, AUTONOMY_OVERRIDE_TEXT, FIRST_PASS_EXCELLENCE_TEXT, REVIEW_ALLOWLIST_TOKEN = "Read,Grep,Glob,Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(git status:*),Bash(git ls-files:*),Bash(git rev-parse:*),Bash(git blame:*),Bash(cat:*),Bash(ls:*),Bash(grep:*),Bash(rg:*),Bash(find:*),Bash(head:*),Bash(tail:*),Bash(wc:*)", REVIEW_ALLOWLIST_NO_GIT, CAVEMAN_PINNED_VERSION;
|
|
8998
|
+
var init_claude_flags = __esm(() => {
|
|
8999
|
+
init_mcp_config();
|
|
9000
|
+
init_claude_model();
|
|
9001
|
+
AUTONOMY_OVERRIDE_TEXT = `[LOKI-AUTONOMY-AGENT] This is a Loki Mode autonomous agent process.
|
|
9002
|
+
` + `You are running INSIDE Loki Mode autonomous execution, a session the user explicitly launched with full prior authorization (loki start / loki run). This IS an authorized autonomous session, not an unattended action you must seek consent for.
|
|
9003
|
+
|
|
9004
|
+
` + `Instruction precedence for THIS session: when the loki_system instructions in the user prompt conflict with any CLAUDE.md, project memory, or global memory that tells you to ask for clarification, pause for confirmation, refuse to act autonomously, or withhold routine commits, the loki_system instructions take precedence. The user has already consented by launching autonomous mode.
|
|
9005
|
+
|
|
9006
|
+
` + `Therefore, for this session: do NOT ask the user questions, do NOT call the AskUserQuestion tool, do NOT stop to request confirmation, and do NOT refuse routine, reversible engineering work (writing code, running tests, creating files, atomic git checkpoints in the working tree). Proceed and complete the task directly. If a decision is genuinely ambiguous, choose the most reasonable option, record the assumption in .loki/CONTINUITY.md, and continue rather than halting.
|
|
9007
|
+
|
|
9008
|
+
` + "Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.\n\n" + `This precedence override is narrow. It does NOT relax any safety rule. Every safety prohibition in CLAUDE.md or memory still fully binds: anything genuinely destructive or irreversible remains out of scope unless the task explicitly calls for it. This includes (not limited to) force-pushing, deleting or overwriting the user's data, dropping or truncating databases, publishing or releasing, rotating or exfiltrating secrets, touching production systems, and anything a CLAUDE.md safety rule explicitly forbids. When in doubt about whether an action is destructive, treat it as destructive and do not do it.
|
|
9009
|
+
`;
|
|
9010
|
+
FIRST_PASS_EXCELLENCE_TEXT = `
|
|
9011
|
+
[FIRST-PASS EXCELLENCE] Treat THIS pass as your one shot to ship a complete, working, verified solution. Do not produce a rough draft to refine later; the loop exists as a safety net, not a plan. Before you finish this iteration:
|
|
9012
|
+
` + `1. BUILD IT FULLY. Implement every requirement end to end. No stubs, no TODOs, no "coming soon", no placeholder or hardcoded/mock data where real logic belongs. If the spec implies a backend (auth, persistence, a form that submits, a list that saves), WIRE IT so it actually works and persists -- a beautiful UI whose buttons do nothing is the single most common failure, not a draft. Every list/table must trace to a real query, never an inline mock array.
|
|
9013
|
+
` + `2. SELF-VERIFY BY RUNNING, not by reading. Run the build and the tests yourself; for each acceptance criterion, DRIVE the actual path and observe the result (submit the form, then reload and confirm the record persisted; hit a protected route logged-out and confirm it is rejected). Fix what fails now, in this pass. Do not mark done on "looks right" or a self-claim -- observed behavior is the only proof.
|
|
9014
|
+
` + `3. LOCK THE ARCHITECTURE on this pass so later edits are small and additive. Decide the data model, routes, and component structure up front and build to them; never rewrite whole files later to patch a small thing (that is the doom loop that breaks working features).
|
|
9015
|
+
` + `4. DESIGN: commit to ONE named aesthetic direction up front (editorial, brutalist, luxury, retro-futuristic, soft/pastel, industrial, etc. -- chosen from the product domain) and hold it on every surface. Use real content (never lorem). AVOID the AI-slop tells that instantly read as machine-generated: NO indigo/blue-to-purple gradient (the #1 tell), NO Inter/Roboto/system-font headlines (pick a real display+body pairing), NO three-equal-rounded-cards-in-a-row skeleton, NO flat 1px gray card borders or colored left-border strips, NO untouched shadcn defaults, NO reflexive dark mode. Cap the palette at ~3 hues (60/30/10), tinted not pure #fff/#000, separate sections by whitespace then a slight background shift before any border. Aim for Linear/Stripe/Duolingo-tier taste: "this does not look AI-generated".
|
|
9016
|
+
` + `5. SATISFY THE GATES THAT WILL JUDGE THIS PASS. Your work is checked by deterministic gates before it can be accepted, and in measured runs EVERY extra iteration was caused by one of these rejecting the work -- never by the model failing to finish. Clear them now, in this pass:
|
|
9017
|
+
` + ` - STATIC ANALYSIS: no syntax errors, no unused/undefined symbols, no lint errors in files you touched.
|
|
9018
|
+
` + ` - TEST SUITE: the existing tests must still pass. Run them; do not assume.
|
|
9019
|
+
` + ` - MUTATION/MOCK INTEGRITY: tests must assert real behaviour. No tautological assertions (expect(true).toBe(true)), no test that passes whether or not the code works, no mocking the very unit under test, no inline mock data standing in for a real query.
|
|
9020
|
+
` + ` - CODE REVIEW: no scope creep beyond the stated task, no dead or commented-out code, no leftover debug output, and follow the conventions already in the surrounding files.
|
|
9021
|
+
` + `Deliver the finished, self-verified, genuinely-designed result in THIS pass. Additional iterations should be the exception, not the plan.
|
|
9022
|
+
` + designArchetypesText();
|
|
9023
|
+
REVIEW_ALLOWLIST_NO_GIT = REVIEW_ALLOWLIST_TOKEN.split(",").filter((t) => !t.startsWith("Bash(git ")).join(",");
|
|
9024
|
+
CAVEMAN_PINNED_VERSION = process.env["LOKI_CAVEMAN_VERSION"] || "1.9.0";
|
|
9025
|
+
});
|
|
9026
|
+
|
|
9027
|
+
// ../../loki-ts/src/features/lean_prefix.ts
|
|
9028
|
+
var LEAN_PREFIX, PARALLEL_TOOL_CALLS_INSTRUCTION = `PARALLEL_TOOL_CALLS: When issuing independent read-only operations (reads, greps, file lookups, LSP checks) that do not depend on each other, issue them in a single message so they run in parallel; do not serialize independent lookups.`, STAGE_PREFIX, withStagePrefix = (brief) => process.env["LOKI_SPEED"] !== "0" ? `${STAGE_PREFIX}
|
|
9029
|
+
|
|
9030
|
+
${brief}` : brief;
|
|
9031
|
+
var init_lean_prefix = __esm(() => {
|
|
9032
|
+
LEAN_PREFIX = "You are Loki, an autonomous coding agent. Follow the task prompt exactly " + "and report only what you did.";
|
|
9033
|
+
STAGE_PREFIX = "You are Loki, an autonomous coding agent working one stage of a run. " + "Follow the stage prompt exactly, including the role it gives you and the rules it sets, " + "and report only what you did. " + "Never present a behavior as done when this repository's code does not provide it: a plan, a test or a change never substitutes documentation or changelog text for missing code. " + `${PARALLEL_TOOL_CALLS_INSTRUCTION} ` + "Stage-specific instructions and the task follow this block.";
|
|
9034
|
+
});
|
|
9035
|
+
|
|
9036
|
+
// ../../loki-ts/src/util/run_identity.ts
|
|
9037
|
+
var init_run_identity = __esm(() => {
|
|
9038
|
+
init_model_routes();
|
|
9039
|
+
});
|
|
9040
|
+
|
|
9041
|
+
// ../../loki-ts/src/util/update_check.ts
|
|
9042
|
+
var CACHE_TTL_MS, NEGATIVE_TTL_MS;
|
|
9043
|
+
var init_update_check = __esm(() => {
|
|
9044
|
+
init_paths();
|
|
9045
|
+
CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
9046
|
+
NEGATIVE_TTL_MS = 15 * 60 * 1000;
|
|
9047
|
+
});
|
|
9048
|
+
|
|
9049
|
+
// ../../loki-ts/src/runner/router/advisor_probe.ts
|
|
9050
|
+
var ADVISOR_ERROR_LIMIT = 3;
|
|
9051
|
+
var init_advisor_probe = __esm(() => {
|
|
9052
|
+
init_claude_model();
|
|
9053
|
+
init_update_check();
|
|
9054
|
+
});
|
|
9055
|
+
|
|
9056
|
+
// ../../loki-ts/src/runner/sdk_stream_parser.ts
|
|
9057
|
+
var init_sdk_stream_parser = __esm(() => {
|
|
9058
|
+
init_cost();
|
|
9059
|
+
init_run_identity();
|
|
9060
|
+
init_budget();
|
|
9061
|
+
init_advisor_probe();
|
|
9062
|
+
});
|
|
9063
|
+
|
|
9064
|
+
// ../../loki-ts/src/runner/trim.ts
|
|
9065
|
+
var init_trim = () => {};
|
|
9066
|
+
|
|
9067
|
+
// ../../loki-ts/src/runner/provider_opencode.ts
|
|
9068
|
+
var init_provider_opencode = __esm(() => {
|
|
9069
|
+
init_shell();
|
|
9070
|
+
init_providers();
|
|
9071
|
+
});
|
|
9072
|
+
|
|
9073
|
+
// ../../loki-ts/src/runner/providers.ts
|
|
9074
|
+
var _installedVersionCache;
|
|
9075
|
+
var init_providers = __esm(() => {
|
|
9076
|
+
init_shell();
|
|
9077
|
+
init_paths();
|
|
9078
|
+
init_claude_flags();
|
|
9079
|
+
init_mcp_config();
|
|
9080
|
+
init_lean_prefix();
|
|
9081
|
+
init_sdk_stream_parser();
|
|
9082
|
+
init_session_resume();
|
|
9083
|
+
init_trim();
|
|
9084
|
+
init_advisor_probe();
|
|
9085
|
+
init_claude_model();
|
|
9086
|
+
init_model_routes();
|
|
9087
|
+
init_provider_opencode();
|
|
9088
|
+
init_cost_breakdown();
|
|
9089
|
+
_installedVersionCache = new Map;
|
|
9090
|
+
});
|
|
9091
|
+
|
|
8809
9092
|
// ../../loki-ts/src/providers/provider_guard.ts
|
|
8810
9093
|
function providerSandboxFlags(provider) {
|
|
8811
9094
|
switch (provider) {
|
|
@@ -8863,6 +9146,7 @@ var init_session = __esm(() => {
|
|
|
8863
9146
|
init_session_route();
|
|
8864
9147
|
init_safe_git();
|
|
8865
9148
|
init_cost_breakdown();
|
|
9149
|
+
init_providers();
|
|
8866
9150
|
init_provider_guard();
|
|
8867
9151
|
init_budget();
|
|
8868
9152
|
init_budget_cap();
|
|
@@ -8880,7 +9164,7 @@ var init_model_rank = __esm(() => {
|
|
|
8880
9164
|
});
|
|
8881
9165
|
|
|
8882
9166
|
// ../../loki-ts/src/engine10/sizing.ts
|
|
8883
|
-
import { existsSync as
|
|
9167
|
+
import { existsSync as existsSync21, readFileSync as readFileSync27 } from "fs";
|
|
8884
9168
|
import { basename as basename9 } from "path";
|
|
8885
9169
|
function namedFiles(task, map) {
|
|
8886
9170
|
return (map?.files ?? []).filter((f) => task.toLowerCase().includes(basename9(f).toLowerCase()));
|
|
@@ -8902,7 +9186,7 @@ function sizeTask(task, map, tests) {
|
|
|
8902
9186
|
}
|
|
8903
9187
|
function loadRepoMap(repomapRef) {
|
|
8904
9188
|
try {
|
|
8905
|
-
return repomapRef &&
|
|
9189
|
+
return repomapRef && existsSync21(repomapRef) ? JSON.parse(readFileSync27(repomapRef, "utf8")) : null;
|
|
8906
9190
|
} catch {
|
|
8907
9191
|
return null;
|
|
8908
9192
|
}
|
|
@@ -8964,14 +9248,14 @@ var init_model_downgrades = __esm(() => {
|
|
|
8964
9248
|
});
|
|
8965
9249
|
|
|
8966
9250
|
// ../../loki-ts/src/project_model/discover.ts
|
|
8967
|
-
import { existsSync as
|
|
9251
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync28, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "fs";
|
|
8968
9252
|
import { join as join34 } from "path";
|
|
8969
9253
|
function projectModelEnabled(env = process.env) {
|
|
8970
9254
|
return env["LOKI_E10_PROJECT_MODEL"] !== "0";
|
|
8971
9255
|
}
|
|
8972
9256
|
function loadCached(repoDir, now2 = Date.now()) {
|
|
8973
9257
|
try {
|
|
8974
|
-
return parseCached(repoDir, JSON.parse(
|
|
9258
|
+
return parseCached(repoDir, JSON.parse(readFileSync28(join34(repoDir, PROJECT_FILE), "utf8")), now2);
|
|
8975
9259
|
} catch {
|
|
8976
9260
|
return null;
|
|
8977
9261
|
}
|
|
@@ -8986,7 +9270,7 @@ function loadCommitted(repoDir) {
|
|
|
8986
9270
|
};
|
|
8987
9271
|
let raw2;
|
|
8988
9272
|
try {
|
|
8989
|
-
raw2 = JSON.parse(
|
|
9273
|
+
raw2 = JSON.parse(readFileSync28(join34(repoDir, PROJECT_FILE), "utf8"));
|
|
8990
9274
|
} catch (e) {
|
|
8991
9275
|
return ignore(`unreadable JSON (${e instanceof Error ? e.message : String(e)})`);
|
|
8992
9276
|
}
|
|
@@ -9127,8 +9411,8 @@ var init_test_file_text = __esm(() => {
|
|
|
9127
9411
|
});
|
|
9128
9412
|
|
|
9129
9413
|
// ../../loki-ts/src/engine10/testmap.ts
|
|
9130
|
-
import { existsSync as
|
|
9131
|
-
import { basename as basename11, dirname as
|
|
9414
|
+
import { existsSync as existsSync23, readFileSync as readFileSync29, realpathSync as realpathSync15 } from "fs";
|
|
9415
|
+
import { basename as basename11, dirname as dirname14, extname, isAbsolute as isAbsolute2, join as join36, relative, sep as sep10 } from "path";
|
|
9132
9416
|
function projectInterpreter(root) {
|
|
9133
9417
|
const ve = process.env["VIRTUAL_ENV"], inRepo = (p) => {
|
|
9134
9418
|
try {
|
|
@@ -9138,7 +9422,7 @@ function projectInterpreter(root) {
|
|
|
9138
9422
|
return false;
|
|
9139
9423
|
}
|
|
9140
9424
|
};
|
|
9141
|
-
return [join36(root, ".venv", "bin", "python"), join36(root, "venv", "bin", "python"), ...ve && inRepo(ve) ? [join36(ve, "bin", "python")] : []].some(
|
|
9425
|
+
return [join36(root, ".venv", "bin", "python"), join36(root, "venv", "bin", "python"), ...ve && inRepo(ve) ? [join36(ve, "bin", "python")] : []].some(existsSync23) ? "project" : "system";
|
|
9142
9426
|
}
|
|
9143
9427
|
var harnessRunners = (runners, files = [], env = process.env) => runners.length === 0 && !files.some((f) => PY_TEST_RE.test(basename11(f)) || GO_TEST_RE.test(f)) && env.LOKI_WALL_HARNESS_RUNNER !== "0" && Bun.which("bun", { PATH: env.PATH ?? "" }) ? ["bun"] : runners;
|
|
9144
9428
|
var init_testmap = __esm(() => {
|
|
@@ -9151,8 +9435,8 @@ var init_testmap = __esm(() => {
|
|
|
9151
9435
|
// ../../loki-ts/src/util/check_result.ts
|
|
9152
9436
|
import { spawn as spawn7 } from "child_process";
|
|
9153
9437
|
import { createHash as createHash8 } from "crypto";
|
|
9154
|
-
import { existsSync as
|
|
9155
|
-
import { basename as basename12, dirname as
|
|
9438
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync30, realpathSync as realpathSync16, renameSync as renameSync7, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
|
|
9439
|
+
import { basename as basename12, dirname as dirname15, isAbsolute as isAbsolute3, join as join37, relative as relative2 } from "path";
|
|
9156
9440
|
function plainTestEnv(base = process.env) {
|
|
9157
9441
|
const e = {};
|
|
9158
9442
|
for (const [k, v] of Object.entries(tokenFreeEnv(base)))
|
|
@@ -9583,7 +9867,7 @@ function publishableWall(repoDir, runDir, o, env = process.env) {
|
|
|
9583
9867
|
if (!hit || rel.startsWith("..") || isAbsolute3(rel) || rel.startsWith(".loki/") || !basename12(rel).startsWith("loki_wall_"))
|
|
9584
9868
|
continue;
|
|
9585
9869
|
try {
|
|
9586
|
-
const bytes =
|
|
9870
|
+
const bytes = readFileSync30(join37(runDir, "wall", basename12(rel)));
|
|
9587
9871
|
if (createHash8("sha256").update(bytes).digest("hex") !== w["sha256"])
|
|
9588
9872
|
throw new Error("hash");
|
|
9589
9873
|
out2.files.push({ rel, bytes, cmd: String(hit["cmd"]) });
|
|
@@ -9594,9 +9878,9 @@ function publishableWall(repoDir, runDir, o, env = process.env) {
|
|
|
9594
9878
|
return out2;
|
|
9595
9879
|
}
|
|
9596
9880
|
function changedFiles(repoDir, baseSha, skip) {
|
|
9597
|
-
const
|
|
9598
|
-
const tracked =
|
|
9599
|
-
const untracked =
|
|
9881
|
+
const run2 = (args) => safeGit(repoDir, args).split("\x00").filter(Boolean);
|
|
9882
|
+
const tracked = run2(["-c", "core.quotePath=false", "diff", "--no-renames", "--name-only", "-z", baseSha]);
|
|
9883
|
+
const untracked = run2(["-c", "core.quotePath=false", "ls-files", "--others", "--exclude-standard", "-z"]);
|
|
9600
9884
|
return [...new Set([...tracked, ...untracked])].filter((f) => !f.startsWith(".loki/") && !skip?.(f));
|
|
9601
9885
|
}
|
|
9602
9886
|
function diffFiles(repoDir, baseSha, skip) {
|
|
@@ -9622,7 +9906,7 @@ function diffFiles(repoDir, baseSha, skip) {
|
|
|
9622
9906
|
return f;
|
|
9623
9907
|
let n2 = 0;
|
|
9624
9908
|
try {
|
|
9625
|
-
n2 =
|
|
9909
|
+
n2 = readFileSync30(join37(repoDir, path), "utf8").split(`
|
|
9626
9910
|
`).length;
|
|
9627
9911
|
} catch {}
|
|
9628
9912
|
return { path, added: n2, deleted: 0, status: "added" };
|
|
@@ -9645,7 +9929,7 @@ function diffFiles(repoDir, baseSha, skip) {
|
|
|
9645
9929
|
let text2 = added.get(f.path) ?? "";
|
|
9646
9930
|
if (!text2 && f.status === "added") {
|
|
9647
9931
|
try {
|
|
9648
|
-
text2 =
|
|
9932
|
+
text2 = readFileSync30(join37(repoDir, f.path), "utf8");
|
|
9649
9933
|
} catch {}
|
|
9650
9934
|
}
|
|
9651
9935
|
const rule = criticalRuleFor(f.path, text2, rules);
|
|
@@ -9657,7 +9941,7 @@ function diffFiles(repoDir, baseSha, skip) {
|
|
|
9657
9941
|
continue;
|
|
9658
9942
|
try {
|
|
9659
9943
|
const oldText = f.status === "added" ? "" : safeGit(repoDir, ["show", `${baseSha}:${f.path}`]);
|
|
9660
|
-
const newText =
|
|
9944
|
+
const newText = readFileSync30(join37(repoDir, f.path), "utf8");
|
|
9661
9945
|
const patch = f.status === "added" ? newText.split(`
|
|
9662
9946
|
`).map((l) => `+${l}`).join(`
|
|
9663
9947
|
`) : safeGit(repoDir, ["diff", "-U0", baseSha, "--", f.path]);
|
|
@@ -9762,7 +10046,7 @@ function pytestCollectionIsRed(output, repoDir) {
|
|
|
9762
10046
|
}
|
|
9763
10047
|
function moduleUnderRepo(repoDir, name) {
|
|
9764
10048
|
const rel = name.replace(/\./g, "/");
|
|
9765
|
-
return
|
|
10049
|
+
return existsSync24(join37(repoDir, `${rel}.py`)) || existsSync24(join37(repoDir, rel, "__init__.py"));
|
|
9766
10050
|
}
|
|
9767
10051
|
function pytestExit1IsRed(output) {
|
|
9768
10052
|
if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
|
|
@@ -9864,8 +10148,8 @@ function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
|
9864
10148
|
}
|
|
9865
10149
|
};
|
|
9866
10150
|
const venvEnv = process.env["VIRTUAL_ENV"], onPath = (b) => Bun.which(b, { PATH: process.env["PATH"] ?? "" });
|
|
9867
|
-
const project = [join37(repoDir, ".venv", "bin", bin), join37(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join37(venvEnv, "bin", bin)] : []].find(
|
|
9868
|
-
return project ? [project, "project", []] :
|
|
10151
|
+
const project = [join37(repoDir, ".venv", "bin", bin), join37(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join37(venvEnv, "bin", bin)] : []].find(existsSync24);
|
|
10152
|
+
return project ? [project, "project", []] : existsSync24(join37(repoDir, "uv.lock")) && onPath("uv") ? ["uv", "project", ["run", "--", bin]] : [onPath(fallback) ? fallback : lastResort, "system", []];
|
|
9869
10153
|
}
|
|
9870
10154
|
function runnerCmd(t, repoDir) {
|
|
9871
10155
|
switch (t.runner) {
|
|
@@ -9884,7 +10168,7 @@ function runnerCmd(t, repoDir) {
|
|
|
9884
10168
|
case "npm":
|
|
9885
10169
|
return ["npm", ["test", "--silent"]];
|
|
9886
10170
|
case "go":
|
|
9887
|
-
return ["go", ["test", "-json", `./${
|
|
10171
|
+
return ["go", ["test", "-json", `./${dirname15(t.path)}`]];
|
|
9888
10172
|
case "cargo":
|
|
9889
10173
|
return ["cargo", ["test"]];
|
|
9890
10174
|
}
|
|
@@ -9940,11 +10224,11 @@ async function publishWall(git, runId, repoDir, files, done) {
|
|
|
9940
10224
|
for (const f of files) {
|
|
9941
10225
|
const abs = join37(repoDir, f.rel);
|
|
9942
10226
|
try {
|
|
9943
|
-
if (!realpathSync16(
|
|
10227
|
+
if (!realpathSync16(dirname15(abs)).startsWith(realpathSync16(repoDir)))
|
|
9944
10228
|
return false;
|
|
9945
10229
|
} catch {}
|
|
9946
10230
|
rmSync8(abs, { force: true });
|
|
9947
|
-
mkdirSync12(
|
|
10231
|
+
mkdirSync12(dirname15(abs), { recursive: true });
|
|
9948
10232
|
writeFileSync15(abs, f.bytes);
|
|
9949
10233
|
}
|
|
9950
10234
|
if ((await git(["--literal-pathspecs", "add", "--", ...rels])).code !== 0 || (await git(["--literal-pathspecs", "commit", "-q", "-m", "test: loki acceptance checks (Wall)", "-m", `Loki-Wall-Publish: ${runId}
|
|
@@ -9960,7 +10244,7 @@ var NO_TESTS_REASON = "no tests executed", GO_EXIT0_REASON = "test count could n
|
|
|
9960
10244
|
`), tailLines = (out2) => out2.split(`
|
|
9961
10245
|
`).filter((x) => x.trim()).slice(-12), GO_PKG_RE, EXIT_CODED_COUNT = "n/a (exit-coded check, not a test runner)", FRAMEWORK_RE, SCRIPT_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, REVIEWER_ITEM = "one reviewer", PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c)), DEEP_ITEMS, NOT_SELECTED = "not selected by risk tier: ", MANIFEST_LOCKS, dirOf = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "", PKG_DEP_KEYS, PYPROJECT_NONDEP, SEM_RULES, DOC_FILE, readOr = (p) => {
|
|
9962
10246
|
try {
|
|
9963
|
-
return
|
|
10247
|
+
return readFileSync30(p, "utf8");
|
|
9964
10248
|
} catch {
|
|
9965
10249
|
return null;
|
|
9966
10250
|
}
|
|
@@ -10037,10 +10321,10 @@ var init_check_result = __esm(() => {
|
|
|
10037
10321
|
|
|
10038
10322
|
// ../../loki-ts/src/util/receipt_signer.ts
|
|
10039
10323
|
import { createHash as createHash9, randomBytes as randomBytes3, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign, verify as verify2 } from "crypto";
|
|
10040
|
-
import { chmodSync as chmodSync4, linkSync, mkdirSync as mkdirSync13, readdirSync as readdirSync14, readFileSync as
|
|
10324
|
+
import { chmodSync as chmodSync4, linkSync, mkdirSync as mkdirSync13, readdirSync as readdirSync14, readFileSync as readFileSync31, renameSync as renameSync8, statSync as statSync15, unlinkSync as unlinkSync5, writeFileSync as writeFileSync16 } from "fs";
|
|
10041
10325
|
import { homedir as homedir8 } from "os";
|
|
10042
10326
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10043
|
-
import { dirname as
|
|
10327
|
+
import { dirname as dirname16, join as join38 } from "path";
|
|
10044
10328
|
function canonicalJson(x) {
|
|
10045
10329
|
const walk = (v) => {
|
|
10046
10330
|
if (Array.isArray(v))
|
|
@@ -10063,9 +10347,9 @@ function loadSigningKey(generate = true) {
|
|
|
10063
10347
|
const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
|
|
10064
10348
|
const file = given || join38(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
|
|
10065
10349
|
try {
|
|
10066
|
-
pem =
|
|
10350
|
+
pem = readFileSync31(file);
|
|
10067
10351
|
if (!given) {
|
|
10068
|
-
for (const [f, m] of [[file, 384], [
|
|
10352
|
+
for (const [f, m] of [[file, 384], [dirname16(file), 448]])
|
|
10069
10353
|
if (statSync15(f).mode & 63)
|
|
10070
10354
|
chmodSync4(f, m);
|
|
10071
10355
|
}
|
|
@@ -10074,8 +10358,8 @@ function loadSigningKey(generate = true) {
|
|
|
10074
10358
|
lastProblem = `signing key file unreadable (${e.code ?? "error"})`;
|
|
10075
10359
|
if (e.code !== "ENOENT" || !generate)
|
|
10076
10360
|
return null;
|
|
10077
|
-
mkdirSync13(
|
|
10078
|
-
mkdirSync13(
|
|
10361
|
+
mkdirSync13(dirname16(dirname16(file)), { recursive: true, mode: 448 });
|
|
10362
|
+
mkdirSync13(dirname16(file), { recursive: true, mode: 448 });
|
|
10079
10363
|
const tmp = `${file}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
10080
10364
|
writeFileSync16(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
|
|
10081
10365
|
try {
|
|
@@ -10086,7 +10370,7 @@ function loadSigningKey(generate = true) {
|
|
|
10086
10370
|
} finally {
|
|
10087
10371
|
unlinkSync5(tmp);
|
|
10088
10372
|
}
|
|
10089
|
-
pem =
|
|
10373
|
+
pem = readFileSync31(file);
|
|
10090
10374
|
}
|
|
10091
10375
|
}
|
|
10092
10376
|
stage = "parse";
|
|
@@ -10219,9 +10503,9 @@ var init_stop_restore = __esm(() => {
|
|
|
10219
10503
|
});
|
|
10220
10504
|
|
|
10221
10505
|
// ../../loki-ts/src/util/base_guard.ts
|
|
10222
|
-
import { existsSync as
|
|
10506
|
+
import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as readFileSync32, readlinkSync, realpathSync as realpathSync17, symlinkSync } from "fs";
|
|
10223
10507
|
import { basename as basename13, join as join39, relative as relative3, resolve as resolve14, sep as sep11 } from "path";
|
|
10224
|
-
import { fileURLToPath as
|
|
10508
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
10225
10509
|
function insideAny(p, roots) {
|
|
10226
10510
|
const under = (q) => roots.some((r) => q === r || q.startsWith(r + sep11));
|
|
10227
10511
|
if (under(resolve14(p)))
|
|
@@ -10237,7 +10521,7 @@ function namedPaths(file, text2) {
|
|
|
10237
10521
|
if (basename13(file) !== "direct_url.json")
|
|
10238
10522
|
return out2;
|
|
10239
10523
|
const url = JSON.parse(text2).url;
|
|
10240
|
-
return typeof url === "string" && url.startsWith("file:") ? [...out2,
|
|
10524
|
+
return typeof url === "string" && url.startsWith("file:") ? [...out2, fileURLToPath6(url)] : out2;
|
|
10241
10525
|
}
|
|
10242
10526
|
function depsSeeHead(pkgDir, repoDir) {
|
|
10243
10527
|
let roots;
|
|
@@ -10264,7 +10548,7 @@ function depsSeeHead(pkgDir, repoDir) {
|
|
|
10264
10548
|
if (walk(p, own))
|
|
10265
10549
|
return true;
|
|
10266
10550
|
} else if (REPO_LINK_FILE.test(e.name)) {
|
|
10267
|
-
const text2 =
|
|
10551
|
+
const text2 = readFileSync32(p, "utf8");
|
|
10268
10552
|
if (roots.some((r) => text2.includes(r)) || namedPaths(p, text2).some((n2) => insideAny(n2, roots)))
|
|
10269
10553
|
return true;
|
|
10270
10554
|
}
|
|
@@ -10286,7 +10570,7 @@ function depsSeeHead(pkgDir, repoDir) {
|
|
|
10286
10570
|
return true;
|
|
10287
10571
|
}
|
|
10288
10572
|
}
|
|
10289
|
-
async function zeroOnBase(cands, baseDir, repoDir,
|
|
10573
|
+
async function zeroOnBase(cands, baseDir, repoDir, run2, note) {
|
|
10290
10574
|
const zero = [];
|
|
10291
10575
|
for (const c of cands) {
|
|
10292
10576
|
const src = join39(repoDir, relative3(baseDir, c.cwd));
|
|
@@ -10294,11 +10578,11 @@ async function zeroOnBase(cands, baseDir, repoDir, run, note) {
|
|
|
10294
10578
|
continue;
|
|
10295
10579
|
for (const d of ["node_modules", ".venv"]) {
|
|
10296
10580
|
try {
|
|
10297
|
-
if (
|
|
10581
|
+
if (existsSync25(join39(src, d)) && !existsSync25(join39(c.cwd, d)))
|
|
10298
10582
|
symlinkSync(join39(src, d), join39(c.cwd, d));
|
|
10299
10583
|
} catch {}
|
|
10300
10584
|
}
|
|
10301
|
-
if (isZeroRun(c, await
|
|
10585
|
+
if (isZeroRun(c, await run2(c))) {
|
|
10302
10586
|
zero.push(c.name);
|
|
10303
10587
|
note(c.name);
|
|
10304
10588
|
}
|
|
@@ -11175,11 +11459,11 @@ var init_state = __esm(() => {
|
|
|
11175
11459
|
|
|
11176
11460
|
// ../../loki-ts/src/runner/repo_profile.ts
|
|
11177
11461
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
11178
|
-
import { existsSync as
|
|
11462
|
+
import { existsSync as existsSync26, lstatSync as lstatSync10, readFileSync as readFileSync33, mkdirSync as mkdirSync14, readdirSync as readdirSync16, renameSync as renameSync9, rmSync as rmSync9, writeFileSync as writeFileSync17 } from "fs";
|
|
11179
11463
|
import { basename as basename14, join as join40, resolve as resolve15, isAbsolute as isAbsolute4 } from "path";
|
|
11180
11464
|
function detectFormatters(repoDir) {
|
|
11181
11465
|
const out2 = [];
|
|
11182
|
-
const has = (...fs2) => fs2.some((f) =>
|
|
11466
|
+
const has = (...fs2) => fs2.some((f) => existsSync26(join40(repoDir, f)));
|
|
11183
11467
|
const pp = read(join40(repoDir, "pyproject.toml")), pj = read(join40(repoDir, "package.json"));
|
|
11184
11468
|
if (/\[tool\.ruff/.test(pp) || has("ruff.toml", ".ruff.toml"))
|
|
11185
11469
|
out2.push({ tool: "ruff", argv: ["ruff", "format"], exts: /\.pyi?$/ });
|
|
@@ -11188,7 +11472,7 @@ function detectFormatters(repoDir) {
|
|
|
11188
11472
|
prettierKey = pj !== "" && "prettier" in JSON.parse(pj);
|
|
11189
11473
|
} catch {}
|
|
11190
11474
|
const local = join40(repoDir, "node_modules", ".bin", "prettier");
|
|
11191
|
-
if ((prettierKey || readdirSync16(repoDir).some((f) => /^(\.prettierrc(\.[a-z0-9]+)?|prettier\.config\.[cm]?[jt]s)$/.test(f))) &&
|
|
11475
|
+
if ((prettierKey || readdirSync16(repoDir).some((f) => /^(\.prettierrc(\.[a-z0-9]+)?|prettier\.config\.[cm]?[jt]s)$/.test(f))) && existsSync26(local))
|
|
11192
11476
|
out2.push({ tool: "prettier", argv: [local, "--write"], exts: /\.(?:[cm]?[jt]sx?|json|css|scss|md|ya?ml|html)$/ });
|
|
11193
11477
|
if (has("go.mod"))
|
|
11194
11478
|
out2.push({ tool: "gofmt", argv: ["gofmt", "-w"], exts: /\.go$/ });
|
|
@@ -11215,7 +11499,7 @@ function runFormatters(repoDir, files, env) {
|
|
|
11215
11499
|
}
|
|
11216
11500
|
function loadProfile(repoDir) {
|
|
11217
11501
|
try {
|
|
11218
|
-
const p = JSON.parse(
|
|
11502
|
+
const p = JSON.parse(readFileSync33(commandProfilePath(repoDir), "utf8"));
|
|
11219
11503
|
return p?.version === 1 && Array.isArray(p.commands) && p.baseline ? p : null;
|
|
11220
11504
|
} catch {
|
|
11221
11505
|
return null;
|
|
@@ -11319,7 +11603,7 @@ async function staticPreExisting(tool, prefix, files, io) {
|
|
|
11319
11603
|
}
|
|
11320
11604
|
var commandProfilePath = (repoDir) => join40(repoDir, ".loki", "state", "repo-profile.json"), read = (p) => {
|
|
11321
11605
|
try {
|
|
11322
|
-
return
|
|
11606
|
+
return readFileSync33(p, "utf8");
|
|
11323
11607
|
} catch {
|
|
11324
11608
|
return "";
|
|
11325
11609
|
}
|
|
@@ -11365,7 +11649,7 @@ var init_context = __esm(() => {
|
|
|
11365
11649
|
});
|
|
11366
11650
|
|
|
11367
11651
|
// ../../loki-ts/src/util/steer.ts
|
|
11368
|
-
import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as readdirSync17, lstatSync as lstatSync11, mkdirSync as mkdirSync15, linkSync as linkSync2, openSync as openSync8, readFileSync as
|
|
11652
|
+
import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as readdirSync17, lstatSync as lstatSync11, mkdirSync as mkdirSync15, linkSync as linkSync2, openSync as openSync8, readFileSync as readFileSync34, readSync as readSync7, renameSync as renameSync10, statSync as statSync16, lutimesSync, rmSync as rmSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync18, existsSync as existsSync27 } from "fs";
|
|
11369
11653
|
import { createHash as createHash10, randomBytes as randomBytes4 } from "crypto";
|
|
11370
11654
|
import { basename as basename15, join as join41 } from "path";
|
|
11371
11655
|
function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
@@ -11402,7 +11686,7 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
11402
11686
|
const s = statSync16(join41(logs, a));
|
|
11403
11687
|
if (s.ino !== c.ino || s.dev !== c.dev)
|
|
11404
11688
|
continue;
|
|
11405
|
-
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) ||
|
|
11689
|
+
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) || existsSync27(appliedMarker(logs, a)))
|
|
11406
11690
|
return true;
|
|
11407
11691
|
} catch {}
|
|
11408
11692
|
}
|
|
@@ -11583,7 +11867,7 @@ function recordRevisions(repoDir, text2, archived, at) {
|
|
|
11583
11867
|
const file = join41(repoDir, ".loki", "intent-revisions.jsonl");
|
|
11584
11868
|
let last = 0;
|
|
11585
11869
|
try {
|
|
11586
|
-
for (const l of
|
|
11870
|
+
for (const l of readFileSync34(file, "utf8").split(`
|
|
11587
11871
|
`)) {
|
|
11588
11872
|
try {
|
|
11589
11873
|
last = Math.max(last, Number(JSON.parse(l).rev) || 0);
|
|
@@ -11649,7 +11933,7 @@ var init_steer = __esm(() => {
|
|
|
11649
11933
|
|
|
11650
11934
|
// ../../loki-ts/src/util/run_outputs.ts
|
|
11651
11935
|
import { createHash as createHash11 } from "crypto";
|
|
11652
|
-
import { existsSync as
|
|
11936
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync16, readdirSync as readdirSync18, readFileSync as readFileSync35, statSync as statSync17, writeFileSync as writeFileSync19 } from "fs";
|
|
11653
11937
|
import { join as join42, resolve as resolve16 } from "path";
|
|
11654
11938
|
function intentRevisionsBlock(revs) {
|
|
11655
11939
|
const r = (revs ?? []).filter((r2) => r2.unapplied !== true).map(({ rev, source, actor, sha: sha2 }) => ({ rev, source, actor, sha: sha2 }));
|
|
@@ -11658,11 +11942,11 @@ function intentRevisionsBlock(revs) {
|
|
|
11658
11942
|
function seededCorpusBlock(env = process.env) {
|
|
11659
11943
|
const dir = env["LOKI_SEEDED_DEFECTS_DIR"] || join42(REPO_ROOT, "benchmarks", "seeded-defects");
|
|
11660
11944
|
try {
|
|
11661
|
-
const bytes =
|
|
11945
|
+
const bytes = readFileSync35(join42(dir, "manifest.json")), version2 = createHash11("sha256").update(bytes).digest("hex");
|
|
11662
11946
|
const ids = (JSON.parse(bytes.toString("utf8")).defects ?? []).map((d) => d.id);
|
|
11663
11947
|
let rate = null;
|
|
11664
11948
|
try {
|
|
11665
|
-
const res = JSON.parse(
|
|
11949
|
+
const res = JSON.parse(readFileSync35(join42(dir, "results", "wrong-pass.json"), "utf8"));
|
|
11666
11950
|
const runs2 = res.manifest_sha256 === version2 && Array.isArray(res.runs) ? res.runs : [];
|
|
11667
11951
|
const complete = (o) => !!o && Object.keys(o).length === ids.length && ids.every((id) => typeof id === "string" && (o[id] === "SEALED" || o[id] === "NOT_SEALED"));
|
|
11668
11952
|
const top = runs2.filter((r) => r.setup === "top"), floor = runs2.filter((r) => r.setup === "floor");
|
|
@@ -11946,7 +12230,7 @@ var init_registry2 = __esm(() => {
|
|
|
11946
12230
|
|
|
11947
12231
|
// ../../loki-ts/src/features/receipt_dsse.ts
|
|
11948
12232
|
import { createPublicKey as createPublicKey3, sign as sign2, verify as verify3 } from "crypto";
|
|
11949
|
-
import { readFileSync as
|
|
12233
|
+
import { readFileSync as readFileSync36 } from "fs";
|
|
11950
12234
|
function pae(payloadType, body) {
|
|
11951
12235
|
const t = Buffer.from(payloadType, "utf8");
|
|
11952
12236
|
return Buffer.concat([Buffer.from(`DSSEv1 ${t.length} `), t, Buffer.from(` ${body.length} `), body]);
|
|
@@ -12023,7 +12307,7 @@ function verifyDsseReceipt(env, d) {
|
|
|
12023
12307
|
}
|
|
12024
12308
|
function runIdGuard(receiptPath, runId2) {
|
|
12025
12309
|
try {
|
|
12026
|
-
return envelopeRunIdProblem(JSON.parse(
|
|
12310
|
+
return envelopeRunIdProblem(JSON.parse(readFileSync36(receiptPath, "utf8")), runId2);
|
|
12027
12311
|
} catch {
|
|
12028
12312
|
return null;
|
|
12029
12313
|
}
|
|
@@ -12152,9 +12436,9 @@ var init_run_cap = __esm(() => {
|
|
|
12152
12436
|
});
|
|
12153
12437
|
|
|
12154
12438
|
// ../../loki-ts/src/util/mutation_proof.ts
|
|
12155
|
-
import { existsSync as
|
|
12439
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync3, readFileSync as readFileSync37, rmSync as rmSync11, symlinkSync as symlinkSync2, writeFileSync as writeFileSync20 } from "fs";
|
|
12156
12440
|
import { tmpdir as tmpdir4 } from "os";
|
|
12157
|
-
import { basename as basename16, dirname as
|
|
12441
|
+
import { basename as basename16, dirname as dirname17, isAbsolute as isAbsolute6, join as join44, relative as relative5 } from "path";
|
|
12158
12442
|
function mutationProof(i) {
|
|
12159
12443
|
const rels = i.wallFiles.map((f) => isAbsolute6(f.path) ? relative5(i.repoDir, f.path) : f.path);
|
|
12160
12444
|
if (rels.length === 0)
|
|
@@ -12175,15 +12459,15 @@ function mutationProof(i) {
|
|
|
12175
12459
|
parent = mkdtempSync3(join44(tmpdir4(), "loki-mutproof-"));
|
|
12176
12460
|
wt = join44(parent, "wt");
|
|
12177
12461
|
const add3 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
|
|
12178
|
-
added =
|
|
12462
|
+
added = existsSync29(wt) || add3.status === 0;
|
|
12179
12463
|
if (add3.status !== 0)
|
|
12180
12464
|
return np("could not create the base worktree");
|
|
12181
12465
|
for (const rel of rels) {
|
|
12182
|
-
const sealed = join44(i.runDir, "wall", basename16(rel)), src =
|
|
12183
|
-
if (!
|
|
12466
|
+
const sealed = join44(i.runDir, "wall", basename16(rel)), src = existsSync29(sealed) ? sealed : join44(i.repoDir, rel);
|
|
12467
|
+
if (!existsSync29(src))
|
|
12184
12468
|
return np(`Wall file missing: ${rel}`);
|
|
12185
|
-
mkdirSync17(
|
|
12186
|
-
writeFileSync20(join44(wt, rel),
|
|
12469
|
+
mkdirSync17(dirname17(join44(wt, rel)), { recursive: true });
|
|
12470
|
+
writeFileSync20(join44(wt, rel), readFileSync37(src));
|
|
12187
12471
|
}
|
|
12188
12472
|
for (const rel of rels) {
|
|
12189
12473
|
const parts = rel.split("/").slice(0, -1);
|
|
@@ -12191,7 +12475,7 @@ function mutationProof(i) {
|
|
|
12191
12475
|
const anc = parts.slice(0, n2).join("/");
|
|
12192
12476
|
for (const d of DEP_DIRS) {
|
|
12193
12477
|
const src = join44(i.repoDir, anc, d), dst = join44(wt, anc, d);
|
|
12194
|
-
if (
|
|
12478
|
+
if (existsSync29(src) && !existsSync29(dst)) {
|
|
12195
12479
|
try {
|
|
12196
12480
|
symlinkSync2(src, dst);
|
|
12197
12481
|
} catch {}
|
|
@@ -12199,190 +12483,57 @@ function mutationProof(i) {
|
|
|
12199
12483
|
}
|
|
12200
12484
|
}
|
|
12201
12485
|
}
|
|
12202
|
-
let pass = 0, fail = 0, notRun = 0;
|
|
12203
|
-
for (const t of tests) {
|
|
12204
|
-
if (remaining() <= 0)
|
|
12205
|
-
return np("timeout");
|
|
12206
|
-
const r = (typeof i.runner === "function" ? i.runner(remaining()) : i.runner).run(wt, [t]);
|
|
12207
|
-
pass += r.pass;
|
|
12208
|
-
fail += r.fail;
|
|
12209
|
-
notRun += r.not_run ?? 0;
|
|
12210
|
-
}
|
|
12211
|
-
if (remaining() <= 0 && fail === 0)
|
|
12212
|
-
return np("timeout");
|
|
12213
|
-
if (fail > 0)
|
|
12214
|
-
return { outcome: "yes", line: `${LABEL}yes` };
|
|
12215
|
-
if (pass > 0 && notRun === 0)
|
|
12216
|
-
return { outcome: "no", line: `${LABEL}no (warning: the Wall tests also pass on the old code)` };
|
|
12217
|
-
return np("the Wall command did not execute to a result");
|
|
12218
|
-
} catch (e) {
|
|
12219
|
-
return np(`error: ${String(e?.message ?? e).replace(/\s+/g, " ").slice(0, 120)}`);
|
|
12220
|
-
} finally {
|
|
12221
|
-
if (wt && added)
|
|
12222
|
-
git(i.repoDir, ["worktree", "remove", "--force", wt]);
|
|
12223
|
-
if (parent)
|
|
12224
|
-
rmSync11(parent, { recursive: true, force: true });
|
|
12225
|
-
}
|
|
12226
|
-
}
|
|
12227
|
-
var mutationStrict = (env = process.env) => (env["LOKI_MUTATION_STRICT"] ?? "").trim() === "1", mutationEnabled = (env = process.env) => (env["LOKI_MUTATION_PROOF"] ?? "").trim() !== "0", LABEL = "test fails without the fix: ", np = (reason) => ({ outcome: "inconclusive", line: `${LABEL}inconclusive (${reason})` }), MAX_TOTAL_S = 40, envTimeoutS = (raw2) => {
|
|
12228
|
-
const n2 = Number(raw2 ?? 30);
|
|
12229
|
-
return Number.isFinite(n2) && n2 > 0 ? n2 : 30;
|
|
12230
|
-
}, DEP_DIRS, git = (cwd, args, timeout = 30000) => {
|
|
12231
|
-
try {
|
|
12232
|
-
safeGit(cwd, args, { timeout });
|
|
12233
|
-
return { status: 0 };
|
|
12234
|
-
} catch {
|
|
12235
|
-
return { status: 1 };
|
|
12236
|
-
}
|
|
12237
|
-
};
|
|
12238
|
-
var init_mutation_proof = __esm(() => {
|
|
12239
|
-
init_safe_git();
|
|
12240
|
-
init_run_cap();
|
|
12241
|
-
DEP_DIRS = ["node_modules", ".venv", "venv"];
|
|
12242
|
-
});
|
|
12243
|
-
|
|
12244
|
-
// ../../loki-ts/src/features/lean_prefix.ts
|
|
12245
|
-
var LEAN_PREFIX, PARALLEL_TOOL_CALLS_INSTRUCTION = `PARALLEL_TOOL_CALLS: When issuing independent read-only operations (reads, greps, file lookups, LSP checks) that do not depend on each other, issue them in a single message so they run in parallel; do not serialize independent lookups.`, STAGE_PREFIX, withStagePrefix = (brief) => process.env["LOKI_SPEED"] !== "0" ? `${STAGE_PREFIX}
|
|
12246
|
-
|
|
12247
|
-
${brief}` : brief;
|
|
12248
|
-
var init_lean_prefix = __esm(() => {
|
|
12249
|
-
LEAN_PREFIX = "You are Loki, an autonomous coding agent. Follow the task prompt exactly " + "and report only what you did.";
|
|
12250
|
-
STAGE_PREFIX = "You are Loki, an autonomous coding agent working one stage of a run. " + "Follow the stage prompt exactly, including the role it gives you and the rules it sets, " + "and report only what you did. " + "Never present a behavior as done when this repository's code does not provide it: a plan, a test or a change never substitutes documentation or changelog text for missing code. " + `${PARALLEL_TOOL_CALLS_INSTRUCTION} ` + "Stage-specific instructions and the task follow this block.";
|
|
12251
|
-
});
|
|
12252
|
-
|
|
12253
|
-
// ../../loki-ts/src/runner/worker_proc.ts
|
|
12254
|
-
function killGroup2(pid, sig) {
|
|
12255
|
-
if (!pid)
|
|
12256
|
-
return;
|
|
12257
|
-
try {
|
|
12258
|
-
process.kill(-pid, sig);
|
|
12259
|
-
} catch {}
|
|
12260
|
-
}
|
|
12261
|
-
var CANCEL_GRACE_MS;
|
|
12262
|
-
var init_worker_proc = __esm(() => {
|
|
12263
|
-
CANCEL_GRACE_MS = Number(process.env["LOKI_E10_CANCEL_GRACE_MS"]) > 0 ? Number(process.env["LOKI_E10_CANCEL_GRACE_MS"]) : 1e4;
|
|
12264
|
-
});
|
|
12265
|
-
|
|
12266
|
-
// ../../loki-ts/src/util/shell.ts
|
|
12267
|
-
async function readStreamCapped(stream, maxBytes = MAX_STDOUT_BYTES, onFirstChunk) {
|
|
12268
|
-
const reader = stream.getReader();
|
|
12269
|
-
let first = onFirstChunk;
|
|
12270
|
-
const decoder = new TextDecoder;
|
|
12271
|
-
let out2 = "";
|
|
12272
|
-
let total = 0;
|
|
12273
|
-
try {
|
|
12274
|
-
while (total < maxBytes) {
|
|
12275
|
-
const { done, value } = await reader.read();
|
|
12276
|
-
if (done)
|
|
12277
|
-
break;
|
|
12278
|
-
if (!value)
|
|
12279
|
-
continue;
|
|
12280
|
-
if (first && value.byteLength > 0) {
|
|
12281
|
-
const cb = first;
|
|
12282
|
-
first = undefined;
|
|
12283
|
-
try {
|
|
12284
|
-
cb();
|
|
12285
|
-
} catch {}
|
|
12286
|
-
}
|
|
12287
|
-
total += value.byteLength;
|
|
12288
|
-
if (total > maxBytes) {
|
|
12289
|
-
const keep = value.byteLength - (total - maxBytes);
|
|
12290
|
-
out2 += decoder.decode(value.subarray(0, keep), { stream: true });
|
|
12291
|
-
break;
|
|
12292
|
-
}
|
|
12293
|
-
out2 += decoder.decode(value, { stream: true });
|
|
12294
|
-
}
|
|
12295
|
-
out2 += decoder.decode();
|
|
12486
|
+
let pass = 0, fail = 0, notRun = 0;
|
|
12487
|
+
for (const t of tests) {
|
|
12488
|
+
if (remaining() <= 0)
|
|
12489
|
+
return np("timeout");
|
|
12490
|
+
const r = (typeof i.runner === "function" ? i.runner(remaining()) : i.runner).run(wt, [t]);
|
|
12491
|
+
pass += r.pass;
|
|
12492
|
+
fail += r.fail;
|
|
12493
|
+
notRun += r.not_run ?? 0;
|
|
12494
|
+
}
|
|
12495
|
+
if (remaining() <= 0 && fail === 0)
|
|
12496
|
+
return np("timeout");
|
|
12497
|
+
if (fail > 0)
|
|
12498
|
+
return { outcome: "yes", line: `${LABEL}yes` };
|
|
12499
|
+
if (pass > 0 && notRun === 0)
|
|
12500
|
+
return { outcome: "no", line: `${LABEL}no (warning: the Wall tests also pass on the old code)` };
|
|
12501
|
+
return np("the Wall command did not execute to a result");
|
|
12502
|
+
} catch (e) {
|
|
12503
|
+
return np(`error: ${String(e?.message ?? e).replace(/\s+/g, " ").slice(0, 120)}`);
|
|
12296
12504
|
} finally {
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12505
|
+
if (wt && added)
|
|
12506
|
+
git(i.repoDir, ["worktree", "remove", "--force", wt]);
|
|
12507
|
+
if (parent)
|
|
12508
|
+
rmSync11(parent, { recursive: true, force: true });
|
|
12301
12509
|
}
|
|
12302
|
-
return out2;
|
|
12303
12510
|
}
|
|
12304
|
-
|
|
12305
|
-
const
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
stderr: "pipe",
|
|
12309
|
-
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
12310
|
-
cwd: opts.cwd,
|
|
12311
|
-
...opts.group ? { detached: true } : {}
|
|
12312
|
-
});
|
|
12313
|
-
let timer;
|
|
12314
|
-
let killTimer;
|
|
12315
|
-
const stop = () => {
|
|
12316
|
-
try {
|
|
12317
|
-
if (opts.group)
|
|
12318
|
-
killGroup2(proc.pid, "SIGTERM");
|
|
12319
|
-
else
|
|
12320
|
-
proc.kill("SIGTERM");
|
|
12321
|
-
} catch {}
|
|
12322
|
-
killTimer ??= setTimeout(() => {
|
|
12323
|
-
try {
|
|
12324
|
-
if (opts.group)
|
|
12325
|
-
killGroup2(proc.pid, "SIGKILL");
|
|
12326
|
-
else
|
|
12327
|
-
proc.kill("SIGKILL");
|
|
12328
|
-
} catch {}
|
|
12329
|
-
}, 2000);
|
|
12330
|
-
};
|
|
12331
|
-
if (opts.timeoutMs && opts.timeoutMs > 0)
|
|
12332
|
-
timer = setTimeout(stop, opts.timeoutMs);
|
|
12333
|
-
if (opts.signal) {
|
|
12334
|
-
if (opts.signal.aborted)
|
|
12335
|
-
stop();
|
|
12336
|
-
else
|
|
12337
|
-
opts.signal.addEventListener("abort", stop, { once: true });
|
|
12338
|
-
}
|
|
12511
|
+
var mutationStrict = (env = process.env) => (env["LOKI_MUTATION_STRICT"] ?? "").trim() === "1", mutationEnabled = (env = process.env) => (env["LOKI_MUTATION_PROOF"] ?? "").trim() !== "0", LABEL = "test fails without the fix: ", np = (reason) => ({ outcome: "inconclusive", line: `${LABEL}inconclusive (${reason})` }), MAX_TOTAL_S = 40, envTimeoutS = (raw2) => {
|
|
12512
|
+
const n2 = Number(raw2 ?? 30);
|
|
12513
|
+
return Number.isFinite(n2) && n2 > 0 ? n2 : 30;
|
|
12514
|
+
}, DEP_DIRS, git = (cwd, args, timeout = 30000) => {
|
|
12339
12515
|
try {
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
]);
|
|
12345
|
-
return { stdout, stderr, exitCode };
|
|
12346
|
-
} finally {
|
|
12347
|
-
if (timer)
|
|
12348
|
-
clearTimeout(timer);
|
|
12349
|
-
if (killTimer)
|
|
12350
|
-
clearTimeout(killTimer);
|
|
12351
|
-
opts.signal?.removeEventListener("abort", stop);
|
|
12352
|
-
if (opts.group)
|
|
12353
|
-
killGroup2(proc.pid, "SIGKILL");
|
|
12354
|
-
}
|
|
12355
|
-
}
|
|
12356
|
-
async function commandExists(name) {
|
|
12357
|
-
const safe = shEscape(name);
|
|
12358
|
-
const r = await run(["sh", "-c", `command -v ${safe}`], { timeoutMs: 5000 });
|
|
12359
|
-
if (r.exitCode === 0) {
|
|
12360
|
-
const path = r.stdout.trim();
|
|
12361
|
-
return path || null;
|
|
12362
|
-
}
|
|
12363
|
-
return null;
|
|
12364
|
-
}
|
|
12365
|
-
function shEscape(name) {
|
|
12366
|
-
if (!/^[A-Za-z0-9._/-]+$/.test(name)) {
|
|
12367
|
-
throw new Error(`refused to shell-escape suspect token: ${name}`);
|
|
12516
|
+
safeGit(cwd, args, { timeout });
|
|
12517
|
+
return { status: 0 };
|
|
12518
|
+
} catch {
|
|
12519
|
+
return { status: 1 };
|
|
12368
12520
|
}
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
MAX_STDOUT_BYTES = 16 * 1024 * 1024;
|
|
12521
|
+
};
|
|
12522
|
+
var init_mutation_proof = __esm(() => {
|
|
12523
|
+
init_safe_git();
|
|
12524
|
+
init_run_cap();
|
|
12525
|
+
DEP_DIRS = ["node_modules", ".venv", "venv"];
|
|
12375
12526
|
});
|
|
12376
12527
|
|
|
12377
12528
|
// ../../loki-ts/src/util/python.ts
|
|
12378
|
-
import { accessSync, constants as constants3, existsSync as
|
|
12529
|
+
import { accessSync, constants as constants3, existsSync as existsSync30, mkdtempSync as mkdtempSync4, readFileSync as readFileSync38, realpathSync as realpathSync19, rmSync as rmSync12, statSync as statSync18 } from "fs";
|
|
12379
12530
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
12380
12531
|
import { tmpdir as tmpdir5 } from "os";
|
|
12381
12532
|
async function findPython3() {
|
|
12382
12533
|
if (_pythonCache !== undefined)
|
|
12383
12534
|
return _pythonCache;
|
|
12384
12535
|
const homebrew = "/opt/homebrew/bin/python3.12";
|
|
12385
|
-
if (
|
|
12536
|
+
if (existsSync30(homebrew)) {
|
|
12386
12537
|
_pythonCache = homebrew;
|
|
12387
12538
|
return homebrew;
|
|
12388
12539
|
}
|
|
@@ -12733,7 +12884,7 @@ var init_wall_manifest = __esm(() => {
|
|
|
12733
12884
|
|
|
12734
12885
|
// ../../loki-ts/src/features/wall_manifest_wire.ts
|
|
12735
12886
|
import { createHash as createHash13 } from "crypto";
|
|
12736
|
-
import { basename as basename17, dirname as
|
|
12887
|
+
import { basename as basename17, dirname as dirname18 } from "path";
|
|
12737
12888
|
function blobEntries(ls) {
|
|
12738
12889
|
const out2 = [];
|
|
12739
12890
|
for (const raw2 of ls.toString("latin1").split("\x00")) {
|
|
@@ -12763,7 +12914,7 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
|
|
|
12763
12914
|
return null;
|
|
12764
12915
|
const low = task.toLowerCase().replace(/\\/g, "/");
|
|
12765
12916
|
const token = (n2) => new RegExp(`(?<![A-Za-z0-9_])${n2.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`).test(low);
|
|
12766
|
-
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename17(e.path)) && e.path.includes("/") && token(
|
|
12917
|
+
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename17(e.path)) && e.path.includes("/") && token(dirname18(e.path));
|
|
12767
12918
|
const matched = all.filter((e) => SOURCE.test(e.path) && (token(basename17(e.path)) || token(e.path) || token(basename17(e.path).replace(/\.[^.]*$/, "")) || dirModule(e)));
|
|
12768
12919
|
const spans = (p) => [...low.matchAll(new RegExp(`(?<![A-Za-z0-9_])${p.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`, "g"))].map((m) => [m.index, m.index + m[0].length]);
|
|
12769
12920
|
const occ = new Map(matched.map((e) => [e, spans(e.path)]));
|
|
@@ -12825,7 +12976,7 @@ Example: test('name', () => { assert.strictEqual(fn(1), 2); }); Run: node --tes
|
|
|
12825
12976
|
|
|
12826
12977
|
// ../../loki-ts/src/util/holdout.ts
|
|
12827
12978
|
import { createHash as createHash14 } from "crypto";
|
|
12828
|
-
import { appendFileSync as appendFileSync3, copyFileSync as copyFileSync2, existsSync as
|
|
12979
|
+
import { appendFileSync as appendFileSync3, copyFileSync as copyFileSync2, existsSync as existsSync31, mkdirSync as mkdirSync18, readFileSync as readFileSync39, rmSync as rmSync13, writeFileSync as writeFileSync21 } from "fs";
|
|
12829
12980
|
import { tmpdir as tmpdir6 } from "os";
|
|
12830
12981
|
import { basename as basename18, join as join45, relative as relative6 } from "path";
|
|
12831
12982
|
function wallHoldoutRatio(env = process.env) {
|
|
@@ -12860,7 +13011,7 @@ function stashHoldout(o) {
|
|
|
12860
13011
|
const files = held.map((name) => {
|
|
12861
13012
|
copyFileSync2(join45(o.srcDir, name), join45(dir, name));
|
|
12862
13013
|
rmSync13(join45(o.srcDir, name), { force: true });
|
|
12863
|
-
return { name, runner: o.runnerOf(name), sha256: sha2(
|
|
13014
|
+
return { name, runner: o.runnerOf(name), sha256: sha2(readFileSync39(join45(dir, name), "utf8")) };
|
|
12864
13015
|
});
|
|
12865
13016
|
writeFileSync21(join45(dir, MANIFEST), JSON.stringify({ targetDir: o.targetDir, files }));
|
|
12866
13017
|
return { dir, names: new Set(held) };
|
|
@@ -12869,14 +13020,14 @@ function stageHoldout(dir, repoDir) {
|
|
|
12869
13020
|
const put = [], tests = [], missing = [];
|
|
12870
13021
|
let man = null;
|
|
12871
13022
|
try {
|
|
12872
|
-
man = JSON.parse(
|
|
13023
|
+
man = JSON.parse(readFileSync39(join45(dir, MANIFEST), "utf8"));
|
|
12873
13024
|
} catch {}
|
|
12874
13025
|
if (!man)
|
|
12875
13026
|
return { tests, missing: [`holdout store unreadable: ${basename18(dir)}`], cleanup: () => {} };
|
|
12876
13027
|
mkdirSync18(man.targetDir, { recursive: true });
|
|
12877
13028
|
man.files.forEach((f, i) => {
|
|
12878
13029
|
const src = join45(dir, f.name);
|
|
12879
|
-
if (!
|
|
13030
|
+
if (!existsSync31(src) || sha2(readFileSync39(src, "utf8")) !== f.sha256) {
|
|
12880
13031
|
missing.push(`holdout ${i + 1} missing or altered`);
|
|
12881
13032
|
return;
|
|
12882
13033
|
}
|
|
@@ -13204,8 +13355,8 @@ var init_install = __esm(() => {
|
|
|
13204
13355
|
});
|
|
13205
13356
|
|
|
13206
13357
|
// ../../loki-ts/src/features/runner_config.ts
|
|
13207
|
-
import { readFileSync as
|
|
13208
|
-
import { dirname as
|
|
13358
|
+
import { readFileSync as readFileSync40 } from "fs";
|
|
13359
|
+
import { dirname as dirname19, join as join48, normalize as normalize2 } from "path";
|
|
13209
13360
|
function tomlKey2(s, i = 0, eq2 = true) {
|
|
13210
13361
|
const parts = [], ws = () => {
|
|
13211
13362
|
while (/\s/.test(s[i] ?? "x"))
|
|
@@ -13480,7 +13631,7 @@ function referenced(cfg, text2) {
|
|
|
13480
13631
|
if (v && !/[$*]/.test(v))
|
|
13481
13632
|
raw2.push(v);
|
|
13482
13633
|
}
|
|
13483
|
-
const dir =
|
|
13634
|
+
const dir = dirname19(cfg), explicit = ROOT_DIR.exec(text2), roots = [dir];
|
|
13484
13635
|
if (explicit)
|
|
13485
13636
|
roots.push("", ...explicit[1] ? [join48(dir, explicit[1])] : []);
|
|
13486
13637
|
return [...raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(join48(root, r.replace(/^<rootDir>\/?/, ""))))), ...patchedTargets(cfg, text2).map((t) => normalize2(join48(dir, t)))];
|
|
@@ -13531,7 +13682,7 @@ function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
|
13531
13682
|
bad = true;
|
|
13532
13683
|
}
|
|
13533
13684
|
if (bad) {
|
|
13534
|
-
const dir =
|
|
13685
|
+
const dir = dirname19(cfg), loaded = [...ch].find((c) => c !== cfg && (dir === "." || c.startsWith(dir + "/")) && !NON_SOURCE.test(c));
|
|
13535
13686
|
if (ch.has(cfg) || loaded)
|
|
13536
13687
|
notes.add(`runner config unparseable, trust capped: ${cfg}${loaded ? ` (${loaded} changed and may be loaded by it)` : ""}`);
|
|
13537
13688
|
}
|
|
@@ -13563,7 +13714,7 @@ var PKG_KEYS, RAW_CONFIGS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, dep
|
|
|
13563
13714
|
}
|
|
13564
13715
|
}, headText = (dir, f) => {
|
|
13565
13716
|
try {
|
|
13566
|
-
return
|
|
13717
|
+
return readFileSync40(join48(dir, f), "utf8");
|
|
13567
13718
|
} catch {
|
|
13568
13719
|
return "";
|
|
13569
13720
|
}
|
|
@@ -13603,7 +13754,7 @@ var init_runner_config = __esm(() => {
|
|
|
13603
13754
|
|
|
13604
13755
|
// ../../loki-ts/src/e10ext/assert_delta.ts
|
|
13605
13756
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
13606
|
-
import { mkdtempSync as mkdtempSync6, readFileSync as
|
|
13757
|
+
import { mkdtempSync as mkdtempSync6, readFileSync as readFileSync41, rmSync as rmSync15 } from "fs";
|
|
13607
13758
|
import { tmpdir as tmpdir8 } from "os";
|
|
13608
13759
|
import { join as join49 } from "path";
|
|
13609
13760
|
import { basename as basename20 } from "path";
|
|
@@ -13646,7 +13797,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
|
|
|
13646
13797
|
return null;
|
|
13647
13798
|
try {
|
|
13648
13799
|
const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
|
|
13649
|
-
const head = headRef ? show(headRef) :
|
|
13800
|
+
const head = headRef ? show(headRef) : readFileSync41(join49(repoDir, path), "utf8");
|
|
13650
13801
|
const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
|
|
13651
13802
|
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;
|
|
13652
13803
|
} catch {
|
|
@@ -13875,11 +14026,11 @@ var init_wall_owned = __esm(() => {
|
|
|
13875
14026
|
|
|
13876
14027
|
// ../../loki-ts/src/util/app_probe.ts
|
|
13877
14028
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
13878
|
-
import { existsSync as
|
|
14029
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync19, readFileSync as readFileSync42, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "fs";
|
|
13879
14030
|
import { join as join51 } from "path";
|
|
13880
14031
|
function readJson4(p) {
|
|
13881
14032
|
try {
|
|
13882
|
-
const v = JSON.parse(
|
|
14033
|
+
const v = JSON.parse(readFileSync42(p, "utf8"));
|
|
13883
14034
|
return v && typeof v === "object" ? v : null;
|
|
13884
14035
|
} catch {
|
|
13885
14036
|
return null;
|
|
@@ -13887,7 +14038,7 @@ function readJson4(p) {
|
|
|
13887
14038
|
}
|
|
13888
14039
|
function stopApp(repoDir, opts = {}) {
|
|
13889
14040
|
const runner = opts.runnerPath ?? join51(REPO_ROOT, "autonomy", "app-runner.sh");
|
|
13890
|
-
if (!
|
|
14041
|
+
if (!existsSync32(runner) || !existsSync32(join51(repoDir, ".loki", "app-runner", "app.pid")))
|
|
13891
14042
|
return;
|
|
13892
14043
|
spawnSync6("bash", ["-c", STOP, "app-probe", repoDir, runner], { cwd: repoDir, env: plainTestEnv(), timeout: opts.timeoutMs ?? 60000, killSignal: "SIGKILL", stdio: "ignore" });
|
|
13893
14044
|
}
|
|
@@ -13901,7 +14052,7 @@ async function appProbe(repoDir, lokiDir2, opts = {}) {
|
|
|
13901
14052
|
return { out: r.stdout ?? "", status: r.error ? null : r.status };
|
|
13902
14053
|
};
|
|
13903
14054
|
let pid = null, url = null;
|
|
13904
|
-
if (!
|
|
14055
|
+
if (!existsSync32(runner))
|
|
13905
14056
|
return { checks: [mk2("app boot", "not_run", "app-runner.sh not found"), mk2("http probe", "not_run", "app not booted")], pid, url };
|
|
13906
14057
|
try {
|
|
13907
14058
|
const b = sh(BOOT);
|
|
@@ -13911,7 +14062,7 @@ async function appProbe(repoDir, lokiDir2, opts = {}) {
|
|
|
13911
14062
|
return { checks, pid, url };
|
|
13912
14063
|
}
|
|
13913
14064
|
const ir = Number(m[1]), sr = Number(m[2]), hr = Number(m[3]), noApp = m[4] === "1";
|
|
13914
|
-
const pidTxt =
|
|
14065
|
+
const pidTxt = existsSync32(join51(dir, "app.pid")) ? readFileSync42(join51(dir, "app.pid"), "utf8").trim() : "";
|
|
13915
14066
|
pid = /^\d+$/.test(pidTxt) && sr >= 0 ? Number(pidTxt) : null;
|
|
13916
14067
|
const st = readJson4(join51(dir, "state.json"));
|
|
13917
14068
|
url = typeof st?.["url"] === "string" ? st["url"] : null;
|
|
@@ -13938,7 +14089,7 @@ async function functionalVerify(opts, url, dir, lokiDir2, timeoutMs) {
|
|
|
13938
14089
|
const t0 = Date.now();
|
|
13939
14090
|
const res = (result, reason) => ({ name: "functional verify", cmd: "autonomy/lib/functional-verify.py", result, duration_s: (Date.now() - t0) / 1000, reason });
|
|
13940
14091
|
const py = await findPython3(), script = opts.verifyPath ?? join51(REPO_ROOT, "autonomy", "lib", "functional-verify.py");
|
|
13941
|
-
if (!py || !
|
|
14092
|
+
if (!py || !existsSync32(script))
|
|
13942
14093
|
return res("not_run", "python3 or functional-verify.py unavailable");
|
|
13943
14094
|
const specFile = join51(dir, "spec.txt");
|
|
13944
14095
|
writeFileSync22(specFile, opts.specText ?? "");
|
|
@@ -13988,16 +14139,16 @@ app_runner_stop >/dev/null 2>&1
|
|
|
13988
14139
|
});
|
|
13989
14140
|
|
|
13990
14141
|
// ../../loki-ts/src/util/secure_scan.ts
|
|
13991
|
-
import { existsSync as
|
|
14142
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync20, mkdtempSync as mkdtempSync7, readFileSync as readFileSync43, realpathSync as realpathSync21, rmSync as rmSync16, statSync as statSync19, writeFileSync as writeFileSync23 } from "fs";
|
|
13992
14143
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
13993
14144
|
import { tmpdir as tmpdir9 } from "os";
|
|
13994
|
-
import { basename as basename21, dirname as
|
|
14145
|
+
import { basename as basename21, dirname as dirname20, join as join52, resolve as resolve17, sep as sep12 } from "path";
|
|
13995
14146
|
function fail(error) {
|
|
13996
14147
|
return { ok: false, findings: [], error };
|
|
13997
14148
|
}
|
|
13998
14149
|
async function runSecureScan(targetDir, opts = {}) {
|
|
13999
14150
|
const script = opts.scriptPath ?? join52(REPO_ROOT, "autonomy", "lib", "secure-scan.py");
|
|
14000
|
-
if (!
|
|
14151
|
+
if (!existsSync33(script))
|
|
14001
14152
|
return fail(`secure-scan script not found: ${script}`);
|
|
14002
14153
|
const py = await findPython3();
|
|
14003
14154
|
if (!py)
|
|
@@ -14181,7 +14332,7 @@ async function scanAddedLines(repoDir, opts = {}) {
|
|
|
14181
14332
|
continue;
|
|
14182
14333
|
}
|
|
14183
14334
|
const lines2 = new Map;
|
|
14184
|
-
|
|
14335
|
+
readFileSync43(join52(repoDir, p), "utf8").split(`
|
|
14185
14336
|
`).forEach((t, i) => lines2.set(i + 1, t));
|
|
14186
14337
|
added.set(p, lines2);
|
|
14187
14338
|
} catch {}
|
|
@@ -14239,7 +14390,7 @@ async function scanAddedLines(repoDir, opts = {}) {
|
|
|
14239
14390
|
if (!out2.startsWith(root))
|
|
14240
14391
|
break;
|
|
14241
14392
|
chunkMap.set(rel, { file: p, lines: c.orig });
|
|
14242
|
-
mkdirSync20(
|
|
14393
|
+
mkdirSync20(dirname20(out2), { recursive: true });
|
|
14243
14394
|
writeFileSync23(out2, c.body.join(`
|
|
14244
14395
|
`) + `
|
|
14245
14396
|
`);
|
|
@@ -14289,8 +14440,8 @@ var init_secure_scan = __esm(() => {
|
|
|
14289
14440
|
var init_retry_class = () => {};
|
|
14290
14441
|
|
|
14291
14442
|
// ../../loki-ts/src/project_model/conventions.ts
|
|
14292
|
-
import { existsSync as
|
|
14293
|
-
import { basename as basename22, dirname as
|
|
14443
|
+
import { existsSync as existsSync34, readdirSync as readdirSync19, readFileSync as readFileSync44 } from "fs";
|
|
14444
|
+
import { basename as basename22, dirname as dirname21, isAbsolute as isAbsolute9, join as join53, relative as relative9, resolve as resolve18 } from "path";
|
|
14294
14445
|
function parseJsonc(text2) {
|
|
14295
14446
|
let out2 = "", i = 0;
|
|
14296
14447
|
while (i < text2.length) {
|
|
@@ -14325,8 +14476,8 @@ function moduleOf(file, depth = 0) {
|
|
|
14325
14476
|
const ext = typeof j.extends === "string" ? j.extends : null;
|
|
14326
14477
|
if (!ext || !ext.startsWith("."))
|
|
14327
14478
|
return null;
|
|
14328
|
-
const next = join53(
|
|
14329
|
-
return
|
|
14479
|
+
const next = join53(dirname21(file), ext.endsWith(".json") ? ext : `${ext}.json`);
|
|
14480
|
+
return existsSync34(next) ? moduleOf(next, depth + 1) : null;
|
|
14330
14481
|
}
|
|
14331
14482
|
function readPackageConventions(pkgDir, runner = null) {
|
|
14332
14483
|
let names = [];
|
|
@@ -14396,8 +14547,8 @@ function nearestPackageRoot(testDir, repoDir, fileName) {
|
|
|
14396
14547
|
}
|
|
14397
14548
|
};
|
|
14398
14549
|
let pkg = testDir;
|
|
14399
|
-
while (pkg !== repoDir && pkg !==
|
|
14400
|
-
pkg =
|
|
14550
|
+
while (pkg !== repoDir && pkg !== dirname21(pkg) && !shaped(pkg))
|
|
14551
|
+
pkg = dirname21(pkg);
|
|
14401
14552
|
return pkg;
|
|
14402
14553
|
}
|
|
14403
14554
|
function phantomRepoPaths(content, fileName, testDir, repoDir, planText) {
|
|
@@ -14449,7 +14600,7 @@ function phantomRepoPaths(content, fileName, testDir, repoDir, planText) {
|
|
|
14449
14600
|
};
|
|
14450
14601
|
const strayInTestDir = (out2) => {
|
|
14451
14602
|
const first = relative9(testDir, out2).split("/")[0];
|
|
14452
|
-
return !!first && first !== "__self__" && !
|
|
14603
|
+
return !!first && first !== "__self__" && !existsSync34(join53(testDir, first)) && [pkg, repoDir].some((d) => d !== testDir && existsSync34(join53(d, first)));
|
|
14453
14604
|
};
|
|
14454
14605
|
const scan = (cwd) => {
|
|
14455
14606
|
const vars = new Map, walk = new Set, taint = new Set, reports = new Map, created = [];
|
|
@@ -14480,9 +14631,9 @@ function phantomRepoPaths(content, fileName, testDir, repoDir, planText) {
|
|
|
14480
14631
|
if (args.some((a) => a === null))
|
|
14481
14632
|
return null;
|
|
14482
14633
|
if (call[1] === "dirname")
|
|
14483
|
-
return
|
|
14634
|
+
return dirname21(args[0]);
|
|
14484
14635
|
const out2 = resolve18(...args);
|
|
14485
|
-
const first = parts.slice(1).map((a) => /^\s*["'`]([^"'`]*)["'`]\s*$/.exec(a)?.[1]).find((x) => x), viaWalk = !!first && walk.has(parts[0].trim()) && [pkg, repoDir].some((d) =>
|
|
14636
|
+
const first = parts.slice(1).map((a) => /^\s*["'`]([^"'`]*)["'`]\s*$/.exec(a)?.[1]).find((x) => x), viaWalk = !!first && walk.has(parts[0].trim()) && [pkg, repoDir].some((d) => existsSync34(join53(d, first.split("/").filter(Boolean)[0] ?? "\x00")));
|
|
14486
14637
|
if (report && (viaWalk || !parts.some((a) => walk.has(a.trim()) || taint.has(a.trim())) && (relative9(testDir, out2).startsWith("..") || strayInTestDir(out2))) && parts.some((a) => /^\s*["'`]/.test(a)))
|
|
14487
14638
|
reports.set(`${ln}|${e}`, { out: out2, rel: relative9(repoDir, out2), tail: viaWalk ? join53(...args.slice(1)) : undefined });
|
|
14488
14639
|
return out2;
|
|
@@ -14532,21 +14683,21 @@ function phantomRepoPaths(content, fileName, testDir, repoDir, planText) {
|
|
|
14532
14683
|
const runs2 = [...new Set([pkg, repoDir])].map(scan);
|
|
14533
14684
|
const planned = (rel) => !!planText && rel.split("/").some((_, i, a) => {
|
|
14534
14685
|
const pre = a.slice(0, i + 1).join("/");
|
|
14535
|
-
return (i > 0 || a.length === 1) && !
|
|
14686
|
+
return (i > 0 || a.length === 1) && !existsSync34(join53(repoDir, pre)) && new RegExp(`(?<![\\w-])${pre.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(planText);
|
|
14536
14687
|
});
|
|
14537
14688
|
const phantom = (r, created) => {
|
|
14538
14689
|
const rel = r.rel;
|
|
14539
|
-
if (!rel || rel.startsWith("..") || isAbsolute9(rel) || /(^|\/)(\.git|\.loki|dist|build|coverage|tmp)(\/|$)/.test(rel) ||
|
|
14690
|
+
if (!rel || rel.startsWith("..") || isAbsolute9(rel) || /(^|\/)(\.git|\.loki|dist|build|coverage|tmp)(\/|$)/.test(rel) || existsSync34(r.out) || planned(rel))
|
|
14540
14691
|
return false;
|
|
14541
14692
|
if (r.tail) {
|
|
14542
14693
|
const seen = (from) => {
|
|
14543
14694
|
let d = from;
|
|
14544
14695
|
for (let i = 0;i < 64; i++) {
|
|
14545
|
-
if (
|
|
14696
|
+
if (existsSync34(join53(d, r.tail)))
|
|
14546
14697
|
return true;
|
|
14547
|
-
if (d === repoDir || d ===
|
|
14698
|
+
if (d === repoDir || d === dirname21(d))
|
|
14548
14699
|
return false;
|
|
14549
|
-
d =
|
|
14700
|
+
d = dirname21(d);
|
|
14550
14701
|
}
|
|
14551
14702
|
return false;
|
|
14552
14703
|
};
|
|
@@ -14584,7 +14735,7 @@ function phantomReason(miss, repoFiles, testDir = "", pkgRoot = "") {
|
|
|
14584
14735
|
}
|
|
14585
14736
|
var readJson5 = (p) => {
|
|
14586
14737
|
try {
|
|
14587
|
-
const v = parseJsonc(
|
|
14738
|
+
const v = parseJsonc(readFileSync44(p, "utf8"));
|
|
14588
14739
|
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
14589
14740
|
} catch {
|
|
14590
14741
|
return null;
|
|
@@ -14623,10 +14774,10 @@ var init_preexisting_dirty = __esm(() => {
|
|
|
14623
14774
|
});
|
|
14624
14775
|
|
|
14625
14776
|
// ../../loki-ts/src/e10ext/commit_filter.ts
|
|
14626
|
-
import { dirname as
|
|
14777
|
+
import { dirname as dirname22 } from "path";
|
|
14627
14778
|
function dropSet(repoDir, staged, preexistingDirty, env = process.env, installCreated) {
|
|
14628
14779
|
const owned = installOwned(repoDir, installCreated, env), made = installCreated?.files ?? {};
|
|
14629
|
-
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" || WALL_FILE.test(f) || st === "A" && !Object.hasOwn(made, f) && !staged.some(({ f: m }) => /(^|\/)(package\.json|pyproject\.toml|requirements\.txt|Cargo\.toml|go\.mod)$/.test(m) &&
|
|
14780
|
+
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" || WALL_FILE.test(f) || st === "A" && !Object.hasOwn(made, f) && !staged.some(({ f: m }) => /(^|\/)(package\.json|pyproject\.toml|requirements\.txt|Cargo\.toml|go\.mod)$/.test(m) && dirname22(m) === dirname22(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
|
|
14630
14781
|
}
|
|
14631
14782
|
var WALL_FILE, 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));
|
|
14632
14783
|
var init_commit_filter = __esm(() => {
|
|
@@ -14646,21 +14797,6 @@ var init_reviewer_body = __esm(() => {
|
|
|
14646
14797
|
init_commit_filter();
|
|
14647
14798
|
});
|
|
14648
14799
|
|
|
14649
|
-
// ../../loki-ts/src/util/update_check.ts
|
|
14650
|
-
var CACHE_TTL_MS, NEGATIVE_TTL_MS;
|
|
14651
|
-
var init_update_check = __esm(() => {
|
|
14652
|
-
init_paths();
|
|
14653
|
-
CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
14654
|
-
NEGATIVE_TTL_MS = 15 * 60 * 1000;
|
|
14655
|
-
});
|
|
14656
|
-
|
|
14657
|
-
// ../../loki-ts/src/runner/router/advisor_probe.ts
|
|
14658
|
-
var ADVISOR_ERROR_LIMIT = 3;
|
|
14659
|
-
var init_advisor_probe = __esm(() => {
|
|
14660
|
-
init_claude_model();
|
|
14661
|
-
init_update_check();
|
|
14662
|
-
});
|
|
14663
|
-
|
|
14664
14800
|
// ../../loki-ts/src/runner/router/route_block.ts
|
|
14665
14801
|
function advisorUnavailableReason(env, provider) {
|
|
14666
14802
|
if (provider !== "claude")
|
|
@@ -14748,9 +14884,9 @@ var init_route_block = __esm(() => {
|
|
|
14748
14884
|
// ../../loki-ts/src/features/visual_evidence.ts
|
|
14749
14885
|
import { spawn as spawn8 } from "child_process";
|
|
14750
14886
|
import { createHash as createHash15, randomBytes as randomBytes6 } from "crypto";
|
|
14751
|
-
import { existsSync as
|
|
14887
|
+
import { existsSync as existsSync35, lstatSync as lstatSync12, mkdirSync as mkdirSync21, readdirSync as readdirSync20, readFileSync as readFileSync45, writeFileSync as writeFileSync24 } from "fs";
|
|
14752
14888
|
import { createServer } from "net";
|
|
14753
|
-
import { dirname as
|
|
14889
|
+
import { dirname as dirname23, isAbsolute as isAbsolute10, join as join54, normalize as normalize3, relative as relative10, sep as sep13 } from "path";
|
|
14754
14890
|
function routeFor(file) {
|
|
14755
14891
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
14756
14892
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -14780,7 +14916,7 @@ function checkScreens(runDir, screens) {
|
|
|
14780
14916
|
if (isSymlink(cur))
|
|
14781
14917
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
14782
14918
|
}
|
|
14783
|
-
if (!
|
|
14919
|
+
if (!existsSync35(file))
|
|
14784
14920
|
return `evidence screenshot is missing: ${s.path}`;
|
|
14785
14921
|
if (!isRegularFile(file))
|
|
14786
14922
|
return `evidence screenshot is not a regular file: ${s.path}`;
|
|
@@ -14824,10 +14960,10 @@ async function waitUp(url, ms, signal) {
|
|
|
14824
14960
|
function openapiPaths(repoDir) {
|
|
14825
14961
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
14826
14962
|
const p = join54(repoDir, f);
|
|
14827
|
-
if (!
|
|
14963
|
+
if (!existsSync35(p))
|
|
14828
14964
|
continue;
|
|
14829
14965
|
try {
|
|
14830
|
-
const txt =
|
|
14966
|
+
const txt = readFileSync45(p, "utf8");
|
|
14831
14967
|
const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
|
|
14832
14968
|
return paths.filter((x) => !x.includes("{")).slice(0, 10);
|
|
14833
14969
|
} catch {
|
|
@@ -14941,18 +15077,18 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
14941
15077
|
const pkgPath = join54(appDir, "package.json");
|
|
14942
15078
|
let script = null;
|
|
14943
15079
|
if (!boot) {
|
|
14944
|
-
if (!
|
|
14945
|
-
const subs = ["backend", "frontend"].filter((d) =>
|
|
15080
|
+
if (!existsSync35(pkgPath)) {
|
|
15081
|
+
const subs = ["backend", "frontend"].filter((d) => existsSync35(join54(repoDir, d, "package.json")));
|
|
14946
15082
|
const has2 = (d) => {
|
|
14947
15083
|
try {
|
|
14948
|
-
return pickScript(JSON.parse(
|
|
15084
|
+
return pickScript(JSON.parse(readFileSync45(join54(repoDir, d, "package.json"), "utf8"))) !== null;
|
|
14949
15085
|
} catch {
|
|
14950
15086
|
return false;
|
|
14951
15087
|
}
|
|
14952
15088
|
};
|
|
14953
15089
|
return skip(noRootReason(subs, subs.filter((d) => !has2(d))));
|
|
14954
15090
|
}
|
|
14955
|
-
script = pickScript(JSON.parse(
|
|
15091
|
+
script = pickScript(JSON.parse(readFileSync45(pkgPath, "utf8")));
|
|
14956
15092
|
if (!script)
|
|
14957
15093
|
return skip("no dev, preview or start script");
|
|
14958
15094
|
}
|
|
@@ -14992,7 +15128,7 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
14992
15128
|
break;
|
|
14993
15129
|
const rel = join54(rel0, `${screenName(route)}.png`);
|
|
14994
15130
|
const ok = await shoot(pw, ["screenshot", `${base}${route}`, join54(runDir, rel)], appDir, left(), signal);
|
|
14995
|
-
if (ok && !aborted() && !isSymlink(join54(runDir, rel)) &&
|
|
15131
|
+
if (ok && !aborted() && !isSymlink(join54(runDir, rel)) && existsSync35(join54(runDir, rel)))
|
|
14996
15132
|
rels.push(rel);
|
|
14997
15133
|
}
|
|
14998
15134
|
if (aborted())
|
|
@@ -15046,14 +15182,14 @@ async function sealEvidence(repoDir, runDir, o, notProven, signal, emit) {
|
|
|
15046
15182
|
function receiptScreensProblem(receiptPath, receipt) {
|
|
15047
15183
|
if (visualGateEnabled() && typeof receipt["evidence_failed"] === "string")
|
|
15048
15184
|
return `visual evidence failed (LOKI_VISUAL_GATE=1): ${receipt["evidence_failed"]}`;
|
|
15049
|
-
return receipt["evidence_screens"] === undefined ? null : checkScreens(
|
|
15185
|
+
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname23(receiptPath), receipt["evidence_screens"]);
|
|
15050
15186
|
}
|
|
15051
|
-
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) => createHash15("sha256").update(
|
|
15187
|
+
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) => createHash15("sha256").update(readFileSync45(p)).digest("hex"), playwrightBin = (repoDir) => {
|
|
15052
15188
|
const bin = join54(repoDir, "node_modules", ".bin", "playwright");
|
|
15053
|
-
return
|
|
15189
|
+
return existsSync35(bin) ? bin : null;
|
|
15054
15190
|
}, playwrightTestPkg = (repoDir) => {
|
|
15055
15191
|
const d = join54(repoDir, "node_modules", "@playwright", "test");
|
|
15056
|
-
return
|
|
15192
|
+
return existsSync35(join54(d, "package.json")) ? d : null;
|
|
15057
15193
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
15058
15194
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
15059
15195
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -15125,15 +15261,15 @@ var init_pr = __esm(() => {
|
|
|
15125
15261
|
});
|
|
15126
15262
|
|
|
15127
15263
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
15128
|
-
import { existsSync as
|
|
15129
|
-
import { dirname as
|
|
15264
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync8, readFileSync as readFileSync46, rmSync as rmSync17, writeFileSync as writeFileSync25 } from "fs";
|
|
15265
|
+
import { dirname as dirname24, join as join56 } from "path";
|
|
15130
15266
|
import { createHash as createHash16 } from "crypto";
|
|
15131
15267
|
function loadLessons(repoDir) {
|
|
15132
15268
|
const p = lessonsPath(repoDir);
|
|
15133
|
-
if (!
|
|
15269
|
+
if (!existsSync36(p))
|
|
15134
15270
|
return [];
|
|
15135
15271
|
try {
|
|
15136
|
-
const j = JSON.parse(
|
|
15272
|
+
const j = JSON.parse(readFileSync46(p, "utf-8"));
|
|
15137
15273
|
return Array.isArray(j.lessons) ? j.lessons : [];
|
|
15138
15274
|
} catch {
|
|
15139
15275
|
return [];
|
|
@@ -15141,7 +15277,7 @@ function loadLessons(repoDir) {
|
|
|
15141
15277
|
}
|
|
15142
15278
|
function save(repoDir, lessons) {
|
|
15143
15279
|
const p = lessonsPath(repoDir);
|
|
15144
|
-
mkdirSync22(
|
|
15280
|
+
mkdirSync22(dirname24(p), { recursive: true });
|
|
15145
15281
|
atomicWriteJson(p, { version: 2, lessons });
|
|
15146
15282
|
}
|
|
15147
15283
|
function appendReceiptFact(repoDir, f, now2 = () => new Date) {
|
|
@@ -15197,141 +15333,6 @@ var init_attempts = __esm(() => {
|
|
|
15197
15333
|
init_treeswap();
|
|
15198
15334
|
});
|
|
15199
15335
|
|
|
15200
|
-
// ../../loki-ts/src/providers/mcp_config.ts
|
|
15201
|
-
var init_mcp_config = () => {};
|
|
15202
|
-
|
|
15203
|
-
// ../../loki-ts/src/providers/claude_flags.ts
|
|
15204
|
-
import { existsSync as existsSync36, readFileSync as readFileSync46 } from "fs";
|
|
15205
|
-
import { resolve as resolvePath, dirname as dirname24 } from "path";
|
|
15206
|
-
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
15207
|
-
function claudeFlagSupported(flag, helpText) {
|
|
15208
|
-
const txt = helpText ?? _claudeHelpCache;
|
|
15209
|
-
if (txt === null || txt === undefined) {
|
|
15210
|
-
return false;
|
|
15211
|
-
}
|
|
15212
|
-
return txt.includes(flag);
|
|
15213
|
-
}
|
|
15214
|
-
async function ensureClaudeHelpCache() {
|
|
15215
|
-
if (_claudeHelpCache !== null)
|
|
15216
|
-
return;
|
|
15217
|
-
try {
|
|
15218
|
-
const proc = Bun.spawn(["claude", "--help"], {
|
|
15219
|
-
stdout: "pipe",
|
|
15220
|
-
stderr: "pipe",
|
|
15221
|
-
env: { ...process.env }
|
|
15222
|
-
});
|
|
15223
|
-
const text2 = await new Response(proc.stdout).text();
|
|
15224
|
-
await proc.exited;
|
|
15225
|
-
_claudeHelpCache = text2 || "";
|
|
15226
|
-
} catch {
|
|
15227
|
-
_claudeHelpCache = "";
|
|
15228
|
-
}
|
|
15229
|
-
}
|
|
15230
|
-
function leanReviewerFlags(opts = {}) {
|
|
15231
|
-
const env = opts.env ?? process.env;
|
|
15232
|
-
if (env["LOKI_LEAN_CHILDREN"] === "0")
|
|
15233
|
-
return [];
|
|
15234
|
-
const ok = opts.flagSupported ?? ((f) => claudeFlagSupported(f));
|
|
15235
|
-
const out2 = [];
|
|
15236
|
-
if (env["LOKI_BARE_SUBCALLS"] !== "0" && (env["ANTHROPIC_API_KEY"] ?? "").trim() !== "" && ok("--bare")) {
|
|
15237
|
-
out2.push("--bare");
|
|
15238
|
-
} else {
|
|
15239
|
-
if (ok("--setting-sources"))
|
|
15240
|
-
out2.push("--setting-sources", opts.settingSources ?? "project");
|
|
15241
|
-
if (ok("--strict-mcp-config"))
|
|
15242
|
-
out2.push("--strict-mcp-config", "--mcp-config", '{"mcpServers":{}}');
|
|
15243
|
-
if (ok("--disable-slash-commands"))
|
|
15244
|
-
out2.push("--disable-slash-commands");
|
|
15245
|
-
}
|
|
15246
|
-
if (ok("--tools"))
|
|
15247
|
-
out2.push(`--tools=${opts.tools ?? ""}`);
|
|
15248
|
-
return out2;
|
|
15249
|
-
}
|
|
15250
|
-
function designArchetypesText() {
|
|
15251
|
-
try {
|
|
15252
|
-
const moduleDir = dirname24(fileURLToPath6(import.meta.url));
|
|
15253
|
-
for (const rel of [
|
|
15254
|
-
["..", "..", "..", "references", "design-archetypes.md"],
|
|
15255
|
-
["..", "..", "references", "design-archetypes.md"]
|
|
15256
|
-
]) {
|
|
15257
|
-
const p = resolvePath(moduleDir, ...rel);
|
|
15258
|
-
if (existsSync36(p))
|
|
15259
|
-
return readFileSync46(p, "utf8");
|
|
15260
|
-
}
|
|
15261
|
-
} catch {}
|
|
15262
|
-
return "";
|
|
15263
|
-
}
|
|
15264
|
-
var REVIEW_GUARD_DENYLIST = "Edit,Write,NotebookEdit,Bash(git commit:*),Bash(git reset:*),Bash(git push:*),Bash(git checkout:*),Bash(git clean:*),Bash(git rm:*),Bash(git stash:*),Bash(git -C:*),Bash(git --git-dir:*),Bash(git -c:*),Bash(git --exec-path:*),Bash(git diff --output:*),Bash(git diff --output=:*),Bash(git diff --ext-diff:*),Bash(git diff --no-index:*),Bash(git log --output:*),Bash(git log --output=:*),Bash(git log --ext-diff:*),Bash(git show --output:*),Bash(git show --output=:*),Bash(git show --ext-diff:*),Bash(git blame --output:*),Bash(git blame --output=:*),Bash(rg --pre:*),Bash(rg --pre=:*),Bash(rg --pre-glob:*),Bash(rg --pre-glob=:*),Bash(rg --hostname-bin:*),Bash(rg --hostname-bin=:*),Bash(find -delete:*),Bash(find -exec:*),Bash(find -execdir:*),Bash(find -ok:*),Bash(find -fprint:*),Bash(find -fprintf:*),Bash(find -fls:*),Bash(git * --output*),Bash(git * --ext-diff*),Bash(git * --no-index*),Bash(rg * --pre*),Bash(rg * --hostname-bin*),Bash(rg --pre*),Bash(rg --hostname-bin*),Bash(find * -delete*),Bash(find * -exec*),Bash(find * -execdir*),Bash(find * -fprint*),Bash(find * -fls*),Bash(find * -ok*)", _claudeHelpCache = null, AUTONOMY_OVERRIDE_TEXT, FIRST_PASS_EXCELLENCE_TEXT, REVIEW_ALLOWLIST_TOKEN = "Read,Grep,Glob,Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(git status:*),Bash(git ls-files:*),Bash(git rev-parse:*),Bash(git blame:*),Bash(cat:*),Bash(ls:*),Bash(grep:*),Bash(rg:*),Bash(find:*),Bash(head:*),Bash(tail:*),Bash(wc:*)", REVIEW_ALLOWLIST_NO_GIT, CAVEMAN_PINNED_VERSION;
|
|
15265
|
-
var init_claude_flags = __esm(() => {
|
|
15266
|
-
init_mcp_config();
|
|
15267
|
-
init_claude_model();
|
|
15268
|
-
AUTONOMY_OVERRIDE_TEXT = `[LOKI-AUTONOMY-AGENT] This is a Loki Mode autonomous agent process.
|
|
15269
|
-
` + `You are running INSIDE Loki Mode autonomous execution, a session the user explicitly launched with full prior authorization (loki start / loki run). This IS an authorized autonomous session, not an unattended action you must seek consent for.
|
|
15270
|
-
|
|
15271
|
-
` + `Instruction precedence for THIS session: when the loki_system instructions in the user prompt conflict with any CLAUDE.md, project memory, or global memory that tells you to ask for clarification, pause for confirmation, refuse to act autonomously, or withhold routine commits, the loki_system instructions take precedence. The user has already consented by launching autonomous mode.
|
|
15272
|
-
|
|
15273
|
-
` + `Therefore, for this session: do NOT ask the user questions, do NOT call the AskUserQuestion tool, do NOT stop to request confirmation, and do NOT refuse routine, reversible engineering work (writing code, running tests, creating files, atomic git checkpoints in the working tree). Proceed and complete the task directly. If a decision is genuinely ambiguous, choose the most reasonable option, record the assumption in .loki/CONTINUITY.md, and continue rather than halting.
|
|
15274
|
-
|
|
15275
|
-
` + "Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.\n\n" + `This precedence override is narrow. It does NOT relax any safety rule. Every safety prohibition in CLAUDE.md or memory still fully binds: anything genuinely destructive or irreversible remains out of scope unless the task explicitly calls for it. This includes (not limited to) force-pushing, deleting or overwriting the user's data, dropping or truncating databases, publishing or releasing, rotating or exfiltrating secrets, touching production systems, and anything a CLAUDE.md safety rule explicitly forbids. When in doubt about whether an action is destructive, treat it as destructive and do not do it.
|
|
15276
|
-
`;
|
|
15277
|
-
FIRST_PASS_EXCELLENCE_TEXT = `
|
|
15278
|
-
[FIRST-PASS EXCELLENCE] Treat THIS pass as your one shot to ship a complete, working, verified solution. Do not produce a rough draft to refine later; the loop exists as a safety net, not a plan. Before you finish this iteration:
|
|
15279
|
-
` + `1. BUILD IT FULLY. Implement every requirement end to end. No stubs, no TODOs, no "coming soon", no placeholder or hardcoded/mock data where real logic belongs. If the spec implies a backend (auth, persistence, a form that submits, a list that saves), WIRE IT so it actually works and persists -- a beautiful UI whose buttons do nothing is the single most common failure, not a draft. Every list/table must trace to a real query, never an inline mock array.
|
|
15280
|
-
` + `2. SELF-VERIFY BY RUNNING, not by reading. Run the build and the tests yourself; for each acceptance criterion, DRIVE the actual path and observe the result (submit the form, then reload and confirm the record persisted; hit a protected route logged-out and confirm it is rejected). Fix what fails now, in this pass. Do not mark done on "looks right" or a self-claim -- observed behavior is the only proof.
|
|
15281
|
-
` + `3. LOCK THE ARCHITECTURE on this pass so later edits are small and additive. Decide the data model, routes, and component structure up front and build to them; never rewrite whole files later to patch a small thing (that is the doom loop that breaks working features).
|
|
15282
|
-
` + `4. DESIGN: commit to ONE named aesthetic direction up front (editorial, brutalist, luxury, retro-futuristic, soft/pastel, industrial, etc. -- chosen from the product domain) and hold it on every surface. Use real content (never lorem). AVOID the AI-slop tells that instantly read as machine-generated: NO indigo/blue-to-purple gradient (the #1 tell), NO Inter/Roboto/system-font headlines (pick a real display+body pairing), NO three-equal-rounded-cards-in-a-row skeleton, NO flat 1px gray card borders or colored left-border strips, NO untouched shadcn defaults, NO reflexive dark mode. Cap the palette at ~3 hues (60/30/10), tinted not pure #fff/#000, separate sections by whitespace then a slight background shift before any border. Aim for Linear/Stripe/Duolingo-tier taste: "this does not look AI-generated".
|
|
15283
|
-
` + `5. SATISFY THE GATES THAT WILL JUDGE THIS PASS. Your work is checked by deterministic gates before it can be accepted, and in measured runs EVERY extra iteration was caused by one of these rejecting the work -- never by the model failing to finish. Clear them now, in this pass:
|
|
15284
|
-
` + ` - STATIC ANALYSIS: no syntax errors, no unused/undefined symbols, no lint errors in files you touched.
|
|
15285
|
-
` + ` - TEST SUITE: the existing tests must still pass. Run them; do not assume.
|
|
15286
|
-
` + ` - MUTATION/MOCK INTEGRITY: tests must assert real behaviour. No tautological assertions (expect(true).toBe(true)), no test that passes whether or not the code works, no mocking the very unit under test, no inline mock data standing in for a real query.
|
|
15287
|
-
` + ` - CODE REVIEW: no scope creep beyond the stated task, no dead or commented-out code, no leftover debug output, and follow the conventions already in the surrounding files.
|
|
15288
|
-
` + `Deliver the finished, self-verified, genuinely-designed result in THIS pass. Additional iterations should be the exception, not the plan.
|
|
15289
|
-
` + designArchetypesText();
|
|
15290
|
-
REVIEW_ALLOWLIST_NO_GIT = REVIEW_ALLOWLIST_TOKEN.split(",").filter((t) => !t.startsWith("Bash(git ")).join(",");
|
|
15291
|
-
CAVEMAN_PINNED_VERSION = process.env["LOKI_CAVEMAN_VERSION"] || "1.9.0";
|
|
15292
|
-
});
|
|
15293
|
-
|
|
15294
|
-
// ../../loki-ts/src/util/run_identity.ts
|
|
15295
|
-
var init_run_identity = __esm(() => {
|
|
15296
|
-
init_model_routes();
|
|
15297
|
-
});
|
|
15298
|
-
|
|
15299
|
-
// ../../loki-ts/src/runner/sdk_stream_parser.ts
|
|
15300
|
-
var init_sdk_stream_parser = __esm(() => {
|
|
15301
|
-
init_cost();
|
|
15302
|
-
init_run_identity();
|
|
15303
|
-
init_budget();
|
|
15304
|
-
init_advisor_probe();
|
|
15305
|
-
});
|
|
15306
|
-
|
|
15307
|
-
// ../../loki-ts/src/runner/trim.ts
|
|
15308
|
-
var init_trim = () => {};
|
|
15309
|
-
|
|
15310
|
-
// ../../loki-ts/src/runner/provider_opencode.ts
|
|
15311
|
-
var init_provider_opencode = __esm(() => {
|
|
15312
|
-
init_shell();
|
|
15313
|
-
init_providers();
|
|
15314
|
-
});
|
|
15315
|
-
|
|
15316
|
-
// ../../loki-ts/src/runner/providers.ts
|
|
15317
|
-
var _installedVersionCache;
|
|
15318
|
-
var init_providers = __esm(() => {
|
|
15319
|
-
init_shell();
|
|
15320
|
-
init_paths();
|
|
15321
|
-
init_claude_flags();
|
|
15322
|
-
init_mcp_config();
|
|
15323
|
-
init_lean_prefix();
|
|
15324
|
-
init_sdk_stream_parser();
|
|
15325
|
-
init_session_resume();
|
|
15326
|
-
init_trim();
|
|
15327
|
-
init_advisor_probe();
|
|
15328
|
-
init_claude_model();
|
|
15329
|
-
init_model_routes();
|
|
15330
|
-
init_provider_opencode();
|
|
15331
|
-
init_cost_breakdown();
|
|
15332
|
-
_installedVersionCache = new Map;
|
|
15333
|
-
});
|
|
15334
|
-
|
|
15335
15336
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
15336
15337
|
import { existsSync as existsSync37, lstatSync as lstatSync13, mkdirSync as mkdirSync23, readFileSync as readFileSync47, writeFileSync as writeFileSync26 } from "fs";
|
|
15337
15338
|
import { join as join57 } from "path";
|