loki-mode 11.17.6 → 11.17.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/cost-summary.py +5 -2
- package/autonomy/lib/efficiency_cost.py +21 -1
- package/autonomy/lib/proof-generator.py +5 -0
- package/autonomy/lib/proof-template.html +21 -6
- package/autonomy/lib/trust_trajectory.py +11 -1
- package/autonomy/loki +42 -28
- package/completions/_loki +1 -0
- package/completions/loki.bash +1 -1
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/BOARD.md +108 -4
- package/docs/v10/FAILURE-CLASSES.md +106 -2
- package/docs/v10/MODERNIZE.md +7 -1
- package/docs/v10/PROGRESS.md +10 -0
- package/loki-ts/dist/loki.js +1014 -999
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/ask-tools-server.js +218 -12
- package/packages/control-plane/dist/server.js +719 -593
- package/packages/control-plane/src/server/diffstat.ts +2 -2
- package/packages/control-plane/src/server/routes/checkpoints.ts +2 -2
- package/packages/control-plane/src/server/routes/integrations.ts +1 -1
- package/packages/control-plane/src/shipper/discover.ts +2 -2
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-CCedYmn3.js → AdminPage-CwtSZac4.js} +1 -1
- package/web-app/dist/assets/{Avatar-DMrDsuGe.js → Avatar-BfguNHDC.js} +1 -1
- package/web-app/dist/assets/{Badge-K4Ui2tJz.js → Badge-DQGEOIqb.js} +1 -1
- package/web-app/dist/assets/{Button-Bhjts5QZ.js → Button-CRb-wJga.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-Be7sEVqh.js → CockpitPage-DnA9wewN.js} +1 -1
- package/web-app/dist/assets/{ComparePage-D4ty3jiF.js → ComparePage-DX6F_G0l.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-Cmt2x_mL.js → ErrorBoundary-VVIdgfkb.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-D2IXLnp9.js → EvidenceReceiptPanel-FxknNXxU.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-CyXitr6h.js → GitHubIssuesPanel-DqiraoJP.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-RRM3H-xd.js → GitHubPRsPanel-BYkTsRfQ.js} +1 -1
- package/web-app/dist/assets/{HomePage-CMtrrgfs.js → HomePage-BjpWZdl4.js} +2 -2
- package/web-app/dist/assets/{LoginPage-BrzNhnMJ.js → LoginPage-DdBnFY4Y.js} +1 -1
- package/web-app/dist/assets/{MagicPage-D7VynOKM.js → MagicPage-ihQmO1wm.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-DJ-gDbfP.js → MetricsPage-Dq5YARm1.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-BJh0XVTj.js → NotFoundPage-CLzwsmxk.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-CAodVUpE.js → ProjectPage-Dm8X4ntm.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-m3siS0Rf.js → ProjectsPage-DI3PhBwa.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-CFGgjOvy.js → SettingsPage-D3bL3Ll-.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-Dd9tpSKJ.js → ShowcasePage-ypNyQAKe.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-DXd0PtTI.js → SystemSettingsPage-a9KPi49-.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-C5KaLIGW.js → TeamsPage-B2KmQjeS.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-CDbzE0ZZ.js → TemplatesPage-BnK5NB62.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-CKG79r_-.js → TerminalOutput-CYbPu51X.js} +1 -1
- package/web-app/dist/assets/{activity-BaQQRhDp.js → activity-DBIfCcER.js} +1 -1
- package/web-app/dist/assets/{bell-OeFqvU4e.js → bell-B9HN4QkY.js} +1 -1
- package/web-app/dist/assets/{bot-CSxaA0KU.js → bot-DamtEiBN.js} +1 -1
- package/web-app/dist/assets/{check-DJml2Xdn.js → check-DXifl-uv.js} +1 -1
- package/web-app/dist/assets/{chevron-left-DGnt-DtK.js → chevron-left-BrlJBb8m.js} +1 -1
- package/web-app/dist/assets/{circle-alert-BV5rVL7K.js → circle-alert-CVKCTAb9.js} +1 -1
- package/web-app/dist/assets/{clock-CZ7SvULz.js → clock-HQ6E5gSp.js} +1 -1
- package/web-app/dist/assets/{cloud-lkIzrZps.js → cloud-B15Ysqug.js} +1 -1
- package/web-app/dist/assets/{code-xml-DzA2wL8F.js → code-xml-hqFIp0_h.js} +1 -1
- package/web-app/dist/assets/{database-CLFG5upC.js → database-CcSm0M_K.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-DgWePGsv.js → dollar-sign-acxpddMc.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-DGQX2bmv.js → file-code-corner-B5IIv12W.js} +1 -1
- package/web-app/dist/assets/{file-plus-LkaXeYd6.js → file-plus-CkbMFWJb.js} +1 -1
- package/web-app/dist/assets/{globe-rSsEzPYv.js → globe-CWmZ3xTF.js} +1 -1
- package/web-app/dist/assets/{hammer-CPogONt9.js → hammer-BSaCsCAo.js} +1 -1
- package/web-app/dist/assets/{index-DpBLuMuz.js → index-BCf0fCNu.js} +3 -3
- package/web-app/dist/assets/{layers-CwFaqidn.js → layers-CL82nJ3b.js} +1 -1
- package/web-app/dist/assets/{loader-circle-C43izEm5.js → loader-circle-DBhm8R7M.js} +1 -1
- package/web-app/dist/assets/{lock-Bc_Uqxpp.js → lock-wWcqImfq.js} +1 -1
- package/web-app/dist/assets/{package-BM25lcR-.js → package-BaZa22IO.js} +1 -1
- package/web-app/dist/assets/{plus-D0xoiY6N.js → plus-TFOQPEeK.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-COI1R5Oo.js → refresh-cw-BOKfYIta.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-BoNZx4xe.js → rotate-ccw-DrH5oGwW.js} +1 -1
- package/web-app/dist/assets/{scroll-text-Cakp8XHd.js → scroll-text-aY8_wIJd.js} +1 -1
- package/web-app/dist/assets/{server-CjfIlPmE.js → server-C6FQ01rB.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BilhziJF.js → shield-alert-DurYyWUo.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-CglMrtrt.js → thumbs-up-wUuSs67Q.js} +1 -1
- package/web-app/dist/assets/{trash-2-B6zVvnoG.js → trash-2-DAob0LKZ.js} +1 -1
- package/web-app/dist/assets/{trending-down-BVhwD9bt.js → trending-down-yKL9mp2O.js} +1 -1
- package/web-app/dist/assets/{trending-up-CVJ1ox6c.js → trending-up-BD55eCE3.js} +1 -1
- package/web-app/dist/assets/{upload-DmuR09WL.js → upload-0IJxnT31.js} +1 -1
- package/web-app/dist/assets/{usePolling-BTALfO91.js → usePolling-DuBiboP5.js} +1 -1
- package/web-app/dist/assets/{user-CRdHMZNH.js → user-BDw_rGaY.js} +1 -1
- package/web-app/dist/index.html +1 -1
|
@@ -150,11 +150,251 @@ var init_redact = __esm(() => {
|
|
|
150
150
|
];
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
// ../../loki-ts/src/util/credential_env.ts
|
|
154
|
+
import { mkdtempSync, rmSync, statSync, lstatSync } from "fs";
|
|
155
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
156
|
+
import { join as join4 } from "path";
|
|
157
|
+
import { randomBytes } from "crypto";
|
|
158
|
+
function withheldSentinel(fresh = false) {
|
|
159
|
+
if (fresh)
|
|
160
|
+
sentinel = null;
|
|
161
|
+
return sentinel ??= `${SENTINEL_PREFIX}${process.pid}${randomBytes(8).toString("hex")}INVALID`;
|
|
162
|
+
}
|
|
163
|
+
function removeConfigDir() {
|
|
164
|
+
if (configDir)
|
|
165
|
+
try {
|
|
166
|
+
rmSync(configDir, { recursive: true, force: true });
|
|
167
|
+
} catch {}
|
|
168
|
+
}
|
|
169
|
+
function emptyGhConfigDir(env = process.env) {
|
|
170
|
+
if (configDir && isDir(configDir))
|
|
171
|
+
return configDir;
|
|
172
|
+
const runTmp = env["LOKI_RUN_TMP"] ?? "";
|
|
173
|
+
const root = runTmp !== "" && isDir(runTmp) ? runTmp : tmpdir2();
|
|
174
|
+
try {
|
|
175
|
+
configDir = mkdtempSync(join4(root, "loki-gh-config-"));
|
|
176
|
+
} catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
if (!exitHooked) {
|
|
180
|
+
exitHooked = true;
|
|
181
|
+
process.once("exit", removeConfigDir);
|
|
182
|
+
}
|
|
183
|
+
if (!sigtermHooked) {
|
|
184
|
+
sigtermHooked = true;
|
|
185
|
+
process.prependListener("SIGTERM", () => {
|
|
186
|
+
removeConfigDir();
|
|
187
|
+
if (process.listenerCount("SIGTERM") === 1)
|
|
188
|
+
process.exit(143);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return configDir;
|
|
192
|
+
}
|
|
193
|
+
function hardenCredentialEnv(env, fresh = false) {
|
|
194
|
+
const s = withheldSentinel(fresh);
|
|
195
|
+
for (const v of GITHUB_TOKEN_VARS)
|
|
196
|
+
env[v] = s;
|
|
197
|
+
const dir = emptyGhConfigDir(env);
|
|
198
|
+
if (dir)
|
|
199
|
+
env["GH_CONFIG_DIR"] = dir;
|
|
200
|
+
const existing = Number(env["GIT_CONFIG_COUNT"]);
|
|
201
|
+
const n2 = Number.isInteger(existing) && existing >= 0 ? existing : 0;
|
|
202
|
+
const alreadyLast = n2 > 0 && env[`GIT_CONFIG_KEY_${n2 - 1}`] === "credential.helper" && env[`GIT_CONFIG_VALUE_${n2 - 1}`] === "";
|
|
203
|
+
if (!alreadyLast) {
|
|
204
|
+
env[`GIT_CONFIG_KEY_${n2}`] = "credential.helper";
|
|
205
|
+
env[`GIT_CONFIG_VALUE_${n2}`] = "";
|
|
206
|
+
env["GIT_CONFIG_COUNT"] = String(n2 + 1);
|
|
207
|
+
}
|
|
208
|
+
const params = env["GIT_CONFIG_PARAMETERS"];
|
|
209
|
+
if (params && !params.trimEnd().endsWith("'credential.helper'=''"))
|
|
210
|
+
env["GIT_CONFIG_PARAMETERS"] = `${params} 'credential.helper'=''`;
|
|
211
|
+
env["GIT_TERMINAL_PROMPT"] = "0";
|
|
212
|
+
env["GCM_INTERACTIVE"] = "never";
|
|
213
|
+
}
|
|
214
|
+
var GITHUB_TOKEN_VARS, SENTINEL_PREFIX = "ghp_LOKIWITHHELDsentinel", sentinel = null, configDir = null, exitHooked = false, sigtermHooked = false, isDir = (p) => {
|
|
215
|
+
try {
|
|
216
|
+
return !lstatSync(p).isSymbolicLink() && statSync(p).isDirectory();
|
|
217
|
+
} catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
var init_credential_env = __esm(() => {
|
|
222
|
+
GITHUB_TOKEN_VARS = ["GH_TOKEN", "GITHUB_TOKEN", "GH_ENTERPRISE_TOKEN", "GITHUB_ENTERPRISE_TOKEN"];
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// ../../loki-ts/src/util/safe_git.ts
|
|
226
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
227
|
+
function tokenFreeEnv(env = process.env) {
|
|
228
|
+
const out = { ...env };
|
|
229
|
+
for (const k of SECRET_VARS)
|
|
230
|
+
delete out[k];
|
|
231
|
+
hardenCredentialEnv(out);
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
function driverKeys(repoDir) {
|
|
235
|
+
const r = spawnSync("git", [...SAFE_GIT_CONFIG, "config", "--includes", "--show-scope", "-z", "--get-regexp", DRIVER_KEY_RE], { cwd: repoDir, env: safeGitEnv(), encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
236
|
+
if (r.error)
|
|
237
|
+
throw r.error;
|
|
238
|
+
if (r.status === 1)
|
|
239
|
+
return [];
|
|
240
|
+
if (r.status !== 0)
|
|
241
|
+
throw new Error(`safeGit: cannot enumerate git config drivers (status ${r.status})`);
|
|
242
|
+
const t = r.stdout.split("\x00"), keys = [];
|
|
243
|
+
for (let i = 0;i + 1 < t.length; i += 2) {
|
|
244
|
+
const k = t[i + 1].split(`
|
|
245
|
+
`)[0];
|
|
246
|
+
if (REPO_SCOPES.has(t[i]) && k)
|
|
247
|
+
keys.push(k);
|
|
248
|
+
}
|
|
249
|
+
return [...new Set(keys)];
|
|
250
|
+
}
|
|
251
|
+
function netCommandOverrides(repoDir, env) {
|
|
252
|
+
const r = spawnSync("git", [...CREDENTIAL_CONFIG, "config", "--includes", "--show-scope", "-z", "--get-regexp", NET_CMD_KEY_RE], { cwd: repoDir, env: safeGitEnv(env, true), encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
253
|
+
if (r.error)
|
|
254
|
+
throw r.error;
|
|
255
|
+
if (r.status === 1)
|
|
256
|
+
return { cfg: [], opts: [] };
|
|
257
|
+
if (r.status !== 0)
|
|
258
|
+
throw new Error(`safeGit: cannot enumerate git network config (status ${r.status})`);
|
|
259
|
+
const t = r.stdout.split("\x00"), all = [];
|
|
260
|
+
for (let i = 0;i + 1 < t.length; i += 2) {
|
|
261
|
+
const nl = t[i + 1].indexOf(`
|
|
262
|
+
`), k = nl < 0 ? t[i + 1] : t[i + 1].slice(0, nl), v = nl < 0 ? "" : t[i + 1].slice(nl + 1);
|
|
263
|
+
if (k)
|
|
264
|
+
all.push({ k, scope: t[i], value: v });
|
|
265
|
+
}
|
|
266
|
+
const tainted = new Set(all.filter((e) => LOCAL_SCOPES.has(e.scope)).map((e) => e.k));
|
|
267
|
+
const cfg = [], opts = [], packs = new Map;
|
|
268
|
+
const isCred = (k) => /^credential(\..*)?\.helper$/.test(k);
|
|
269
|
+
for (const k of tainted) {
|
|
270
|
+
const pack = PACK_OPTS.find((o) => o.re.test(k));
|
|
271
|
+
if (pack) {
|
|
272
|
+
if (!packs.has(pack.flag))
|
|
273
|
+
packs.set(pack.flag, all.find((e) => e.k === k && !LOCAL_SCOPES.has(e.scope) && e.value !== "")?.value ?? pack.dflt);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
cfg.push("-c", `${k}=`);
|
|
277
|
+
if (!isCred(k)) {
|
|
278
|
+
for (const e of all)
|
|
279
|
+
if (e.k === k && !LOCAL_SCOPES.has(e.scope) && e.value !== "")
|
|
280
|
+
cfg.push("-c", `${k}=${e.value}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if ([...tainted].some(isCred)) {
|
|
284
|
+
for (const e of all)
|
|
285
|
+
if (isCred(e.k) && !LOCAL_SCOPES.has(e.scope) && e.value !== "")
|
|
286
|
+
cfg.push("-c", `${e.k}=${e.value}`);
|
|
287
|
+
}
|
|
288
|
+
for (const o of PACK_OPTS)
|
|
289
|
+
if (packs.has(o.flag))
|
|
290
|
+
opts.push({ flag: `${o.flag}${packs.get(o.flag)}`, cmds: o.cmds });
|
|
291
|
+
return { cfg, opts };
|
|
292
|
+
}
|
|
293
|
+
function cmdIndex(args) {
|
|
294
|
+
let i = 0;
|
|
295
|
+
while (i < args.length && args[i].startsWith("-"))
|
|
296
|
+
i += OPT_WITH_VALUE.has(args[i]) ? 2 : 1;
|
|
297
|
+
return i;
|
|
298
|
+
}
|
|
299
|
+
function injectPackOpts(args, opts) {
|
|
300
|
+
if (opts.length === 0)
|
|
301
|
+
return args;
|
|
302
|
+
const i = cmdIndex(args), cmd = args[i];
|
|
303
|
+
const extra = opts.filter((o) => cmd !== undefined && o.cmds.has(cmd)).map((o) => o.flag);
|
|
304
|
+
if (cmd !== undefined && !TRANSPORT_OR_LOCAL.has(cmd))
|
|
305
|
+
throw new Error(`safeGit: ${cmd} with allowToken is refused: the repo sets remote uploadpack/receivepack and the option cannot be pinned`);
|
|
306
|
+
return [...args.slice(0, i + 1), ...extra, ...args.slice(i + 1)];
|
|
307
|
+
}
|
|
308
|
+
function safeGitArgs(args, allowToken = false, repoDir, keep = {}, env = process.env) {
|
|
309
|
+
if (keep.userHooks && allowToken)
|
|
310
|
+
throw new Error("safeGit: userHooks with allowToken is refused (a hook would run holding the credential)");
|
|
311
|
+
const off = new Set([...keep.repoDrivers ? [ATTRS_OFF] : [], ...keep.userHooks ? [HOOKS_OFF, SIGN_OFF] : []]);
|
|
312
|
+
const cfg = [...allowToken ? CREDENTIAL_CONFIG : SAFE_GIT_CONFIG, ...DRIVER_CONFIG];
|
|
313
|
+
const flags = cfg.flatMap((v, i) => i % 2 === 1 && !off.has(v) ? [cfg[i - 1], v] : []);
|
|
314
|
+
const net = allowToken && repoDir ? netCommandOverrides(repoDir, env) : { cfg: [], opts: [] };
|
|
315
|
+
return [...flags, ...net.cfg, ...repoDir && !keep.repoDrivers ? driverKeys(repoDir).flatMap((k) => ["-c", `${k}=`]) : [], ...injectPackOpts(noExtDiff(args), net.opts)];
|
|
316
|
+
}
|
|
317
|
+
function noExtDiff(args) {
|
|
318
|
+
const i = cmdIndex(args), cmd = args[i];
|
|
319
|
+
if (cmd === undefined || !PATCH_CMDS.has(cmd))
|
|
320
|
+
return [...args];
|
|
321
|
+
const rest = args.slice(i + 1);
|
|
322
|
+
const end = rest.indexOf("--");
|
|
323
|
+
const opts = (end < 0 ? rest : rest.slice(0, end)).filter((a) => a !== "--ext-diff" && a !== "--textconv" && a !== "--no-ext-diff" && a !== "--no-textconv");
|
|
324
|
+
return [...args.slice(0, i + 1), "--no-ext-diff", "--no-textconv", ...opts, ...end < 0 ? [] : rest.slice(end)];
|
|
325
|
+
}
|
|
326
|
+
function safeGit(repoDir, args, opts = {}) {
|
|
327
|
+
const { env, allowToken, repoDrivers, userHooks, ...rest } = opts;
|
|
328
|
+
const out = execFileSync("git", safeGitArgs(args, allowToken, repoDir, { repoDrivers, userHooks }, env ?? process.env), { stdio: ["ignore", "pipe", "ignore"], ...rest, cwd: repoDir, env: safeGitEnv(env ?? process.env, allowToken), encoding: "utf8" });
|
|
329
|
+
return typeof out === "string" ? out : "";
|
|
330
|
+
}
|
|
331
|
+
function safeGitSpawn(repoDir, args, opts = {}) {
|
|
332
|
+
const { env, allowToken, repoDrivers, userHooks, ...rest } = opts;
|
|
333
|
+
let argv;
|
|
334
|
+
try {
|
|
335
|
+
argv = safeGitArgs(args, allowToken, repoDir, { repoDrivers, userHooks }, env ?? process.env);
|
|
336
|
+
} catch (e) {
|
|
337
|
+
return { pid: 0, output: [], stdout: "", stderr: "", status: null, signal: null, error: e };
|
|
338
|
+
}
|
|
339
|
+
return spawnSync("git", argv, { ...rest, cwd: repoDir, env: safeGitEnv(env ?? process.env, allowToken) });
|
|
340
|
+
}
|
|
341
|
+
async function safeGitRun(repoDir, args, opts = {}) {
|
|
342
|
+
let argv;
|
|
343
|
+
try {
|
|
344
|
+
argv = safeGitArgs(args, opts.allowToken, repoDir, { repoDrivers: opts.repoDrivers, userHooks: opts.userHooks }, opts.env ?? process.env);
|
|
345
|
+
} catch (e) {
|
|
346
|
+
return { stdout: "", stderr: String(e), exitCode: 128 };
|
|
347
|
+
}
|
|
348
|
+
let proc;
|
|
349
|
+
try {
|
|
350
|
+
proc = Bun.spawn({ cmd: ["git", ...argv], cwd: repoDir, env: safeGitEnv(opts.env ?? process.env, opts.allowToken), stdin: "ignore", stdout: "pipe", stderr: "pipe", signal: opts.signal });
|
|
351
|
+
} catch (e) {
|
|
352
|
+
return { stdout: "", stderr: String(e), exitCode: 127 };
|
|
353
|
+
}
|
|
354
|
+
let timer;
|
|
355
|
+
if (opts.timeoutMs && opts.timeoutMs > 0)
|
|
356
|
+
timer = setTimeout(() => {
|
|
357
|
+
try {
|
|
358
|
+
proc.kill("SIGKILL");
|
|
359
|
+
} catch {}
|
|
360
|
+
}, opts.timeoutMs);
|
|
361
|
+
try {
|
|
362
|
+
const [stdout, stderr, exitCode] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]);
|
|
363
|
+
return { stdout, stderr, exitCode };
|
|
364
|
+
} finally {
|
|
365
|
+
if (timer)
|
|
366
|
+
clearTimeout(timer);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
var SAFE_GIT_CONFIG, CREDENTIAL_CONFIG, DRIVER_CONFIG, ATTRS_OFF = "core.attributesFile=/dev/null", HOOKS_OFF = "core.hooksPath=/dev/null", SIGN_OFF = "commit.gpgSign=false", REPO_SCOPES, DRIVER_KEY_RE = "^(filter\\..*\\.(clean|smudge|process)|diff\\..*\\.(textconv|command))$", PATCH_CMDS, OPT_WITH_VALUE, SECRET_VARS, safeGitEnv = (base = process.env, allowToken = false) => {
|
|
370
|
+
const env = { ...allowToken ? base : tokenFreeEnv(base), GIT_CONFIG_NOSYSTEM: "1" };
|
|
371
|
+
delete env.GIT_ATTR_SOURCE;
|
|
372
|
+
delete env.GIT_EXTERNAL_DIFF;
|
|
373
|
+
return env;
|
|
374
|
+
}, NET_CMD_KEY_RE = "^(core\\.(sshcommand|gitproxy)|remote\\..*\\.(uploadpack|receivepack)|credential(\\..*)?\\.helper)$", LOCAL_SCOPES, PUSH_CMD, PACK_OPTS, TRANSPORT_OR_LOCAL;
|
|
375
|
+
var init_safe_git = __esm(() => {
|
|
376
|
+
init_credential_env();
|
|
377
|
+
SAFE_GIT_CONFIG = ["-c", "core.fsmonitor=", "-c", "core.hooksPath=/dev/null", "-c", "core.sshCommand=", "-c", "protocol.ext.allow=never", "-c", "credential.helper="];
|
|
378
|
+
CREDENTIAL_CONFIG = ["-c", "core.fsmonitor=", "-c", "core.hooksPath=/dev/null", "-c", "protocol.ext.allow=never"];
|
|
379
|
+
DRIVER_CONFIG = ["-c", "diff.external=", "-c", "commit.gpgSign=false", "-c", "core.attributesFile=/dev/null"];
|
|
380
|
+
REPO_SCOPES = new Set(["local", "worktree", "command"]);
|
|
381
|
+
PATCH_CMDS = new Set(["diff", "show", "log", "whatchanged"]);
|
|
382
|
+
OPT_WITH_VALUE = new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--exec-path", "--config-env", "--attr-source"]);
|
|
383
|
+
SECRET_VARS = ["GH_TOKEN", "GITHUB_TOKEN", "GH_ENTERPRISE_TOKEN", "GITHUB_ENTERPRISE_TOKEN", "SSH_AUTH_SOCK"];
|
|
384
|
+
LOCAL_SCOPES = new Set(["local", "worktree"]);
|
|
385
|
+
PUSH_CMD = ["pu", "sh"].join("");
|
|
386
|
+
PACK_OPTS = [
|
|
387
|
+
{ re: /\.uploadpack$/, dflt: "git-upload-pack", flag: "--upload-pack=", cmds: new Set(["fetch", "pull", "ls-remote", "clone"]) },
|
|
388
|
+
{ re: /\.receivepack$/, dflt: "git-receive-pack", flag: "--receive-pack=", cmds: new Set([PUSH_CMD]) }
|
|
389
|
+
];
|
|
390
|
+
TRANSPORT_OR_LOCAL = new Set(["fetch", "pull", "ls-remote", "clone", PUSH_CMD, "config", "rev-parse", "rev-list", "log", "show", "status", "diff", "for-each-ref", "cat-file", "symbolic-ref", "branch", "merge-base", "ls-files", "credential"]);
|
|
391
|
+
});
|
|
392
|
+
|
|
153
393
|
// src/shipper/ship.ts
|
|
154
394
|
import { createHash as createHash4 } from "crypto";
|
|
155
395
|
import { existsSync as existsSync4, readFileSync as readFileSync3, realpathSync as realpathSync3, renameSync, writeFileSync as writeFileSync2 } from "fs";
|
|
156
396
|
import { hostname } from "os";
|
|
157
|
-
import { join as
|
|
397
|
+
import { join as join7 } from "path";
|
|
158
398
|
function sourceId(repoDir) {
|
|
159
399
|
let real2 = repoDir;
|
|
160
400
|
try {
|
|
@@ -164,24 +404,24 @@ function sourceId(repoDir) {
|
|
|
164
404
|
}
|
|
165
405
|
function readShip(runDir, url) {
|
|
166
406
|
try {
|
|
167
|
-
const s = JSON.parse(readFileSync3(
|
|
407
|
+
const s = JSON.parse(readFileSync3(join7(runDir, "ship.json"), "utf8"));
|
|
168
408
|
if (s.url === url && Number.isInteger(s.acked_seq))
|
|
169
409
|
return { acked_seq: s.acked_seq, url };
|
|
170
410
|
} catch {}
|
|
171
411
|
return { acked_seq: -1, url };
|
|
172
412
|
}
|
|
173
413
|
function writeShip(runDir, s) {
|
|
174
|
-
const tmp =
|
|
414
|
+
const tmp = join7(runDir, `ship.json.${process.pid}.tmp`);
|
|
175
415
|
writeFileSync2(tmp, JSON.stringify(s) + `
|
|
176
416
|
`);
|
|
177
|
-
renameSync(tmp,
|
|
417
|
+
renameSync(tmp, join7(runDir, "ship.json"));
|
|
178
418
|
}
|
|
179
419
|
async function shipRun(o) {
|
|
180
420
|
const st = readShip(o.runDir, o.url);
|
|
181
|
-
const all = readEvents(
|
|
421
|
+
const all = readEvents(join7(o.runDir, "events.jsonl"));
|
|
182
422
|
let lines = 0;
|
|
183
423
|
try {
|
|
184
|
-
lines = readFileSync3(
|
|
424
|
+
lines = readFileSync3(join7(o.runDir, "events.jsonl"), "utf8").split(`
|
|
185
425
|
`).filter((l) => l.trim() !== "").length;
|
|
186
426
|
} catch {}
|
|
187
427
|
const skipped = lines - all.length;
|
|
@@ -223,7 +463,7 @@ async function shipRun(o) {
|
|
|
223
463
|
}
|
|
224
464
|
return { ok: true, sent, acked_seq: st.acked_seq, pending: 0 };
|
|
225
465
|
}
|
|
226
|
-
var BATCH = 200, MAX_BYTES = 800000, redactDeep = (x) => typeof x === "string" ? redactSecrets(x) : Array.isArray(x) ? x.map(redactDeep) : x && typeof x === "object" ? Object.fromEntries(Object.entries(x).map(([k, v]) => [k, redactDeep(v)])) : x, redactEvent = (e) => ({ ...e, data: redactDeep(e.data) }), backoffMs = (failures, rnd = Math.random) => Math.min(60000, 1000 * 2 ** Math.max(0, failures - 1)) * (1 + 0.25 * rnd()), shipEnabled = (env) => env.LOKI_CONTROL_URL || null, hasSpool = (runDir) => existsSync4(
|
|
466
|
+
var BATCH = 200, MAX_BYTES = 800000, redactDeep = (x) => typeof x === "string" ? redactSecrets(x) : Array.isArray(x) ? x.map(redactDeep) : x && typeof x === "object" ? Object.fromEntries(Object.entries(x).map(([k, v]) => [k, redactDeep(v)])) : x, redactEvent = (e) => ({ ...e, data: redactDeep(e.data) }), backoffMs = (failures, rnd = Math.random) => Math.min(60000, 1000 * 2 ** Math.max(0, failures - 1)) * (1 + 0.25 * rnd()), shipEnabled = (env) => env.LOKI_CONTROL_URL || null, hasSpool = (runDir) => existsSync4(join7(runDir, "events.jsonl"));
|
|
227
467
|
var init_ship = __esm(() => {
|
|
228
468
|
init_events();
|
|
229
469
|
init_redact();
|
|
@@ -231,7 +471,7 @@ var init_ship = __esm(() => {
|
|
|
231
471
|
|
|
232
472
|
// src/shipper/backfill.ts
|
|
233
473
|
import { readdirSync } from "fs";
|
|
234
|
-
import { join as
|
|
474
|
+
import { join as join8 } from "path";
|
|
235
475
|
async function backfill(o) {
|
|
236
476
|
const env = o.env ?? process.env;
|
|
237
477
|
const url = shipEnabled(env);
|
|
@@ -239,7 +479,7 @@ async function backfill(o) {
|
|
|
239
479
|
return { runs: 0, sent: 0, failed: [] };
|
|
240
480
|
const sleep = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
241
481
|
const attempts = o.attempts ?? 3;
|
|
242
|
-
const root =
|
|
482
|
+
const root = join8(o.repoDir, ".loki", "runs");
|
|
243
483
|
let ids = [];
|
|
244
484
|
try {
|
|
245
485
|
ids = readdirSync(root).sort();
|
|
@@ -250,7 +490,7 @@ async function backfill(o) {
|
|
|
250
490
|
let runs2 = 0, sent = 0;
|
|
251
491
|
const failed2 = [];
|
|
252
492
|
for (const id of ids) {
|
|
253
|
-
const runDir =
|
|
493
|
+
const runDir = join8(root, id);
|
|
254
494
|
if (!hasSpool(runDir))
|
|
255
495
|
continue;
|
|
256
496
|
runs2++;
|
|
@@ -274,8 +514,8 @@ var init_backfill = __esm(() => {
|
|
|
274
514
|
|
|
275
515
|
// ../../loki-ts/src/util/run_pid.ts
|
|
276
516
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
277
|
-
import { chmodSync as chmodSync2, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
278
|
-
import { join as
|
|
517
|
+
import { chmodSync as chmodSync2, readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
518
|
+
import { join as join9 } from "path";
|
|
279
519
|
function processStartTime(pid) {
|
|
280
520
|
if (!Number.isInteger(pid) || pid <= 1)
|
|
281
521
|
return null;
|
|
@@ -311,18 +551,18 @@ function verifyRunPid(runDir, runId, startOf = processStartTime) {
|
|
|
311
551
|
return { ok: false, reason: "the pid now belongs to a different process (start time differs)" };
|
|
312
552
|
return { ok: true, pid: rec.pid };
|
|
313
553
|
}
|
|
314
|
-
var runPidPath = (runDir) =>
|
|
554
|
+
var runPidPath = (runDir) => join9(runDir, "run.pid"), liveSessions;
|
|
315
555
|
var init_run_pid = __esm(() => {
|
|
316
556
|
liveSessions = new Set;
|
|
317
557
|
});
|
|
318
558
|
|
|
319
559
|
// src/shipper/watch.ts
|
|
320
|
-
import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync } from "fs";
|
|
560
|
+
import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
321
561
|
import { homedir as homedir4 } from "os";
|
|
322
|
-
import { join as
|
|
562
|
+
import { join as join11 } from "path";
|
|
323
563
|
function registryRepos(env) {
|
|
324
564
|
try {
|
|
325
|
-
const reg = JSON.parse(readFileSync5(
|
|
565
|
+
const reg = JSON.parse(readFileSync5(join11(env.HOME || homedir4(), ".loki", "dashboard", "projects.json"), "utf8"));
|
|
326
566
|
return Object.values(reg.projects ?? {}).map((p) => p.path).filter((p) => typeof p === "string" && p.startsWith("/"));
|
|
327
567
|
} catch {
|
|
328
568
|
return [];
|
|
@@ -335,14 +575,14 @@ var init_watch = __esm(() => {
|
|
|
335
575
|
});
|
|
336
576
|
|
|
337
577
|
// src/shipper/discover.ts
|
|
338
|
-
import { readFileSync as readFileSync6, realpathSync as realpathSync5, statSync as
|
|
339
|
-
import { basename, dirname, join as
|
|
578
|
+
import { readFileSync as readFileSync6, realpathSync as realpathSync5, statSync as statSync3 } from "fs";
|
|
579
|
+
import { basename, dirname, join as join12, resolve as resolve2 } from "path";
|
|
340
580
|
function discoverLocalRepos(repoDir, env = process.env) {
|
|
341
581
|
const out = new Map;
|
|
342
582
|
for (const dir of [repoDir, ...registryRepos(env)]) {
|
|
343
583
|
try {
|
|
344
584
|
const real2 = realpathSync5(dir);
|
|
345
|
-
if (!
|
|
585
|
+
if (!statSync3(real2).isDirectory())
|
|
346
586
|
continue;
|
|
347
587
|
const id = sourceId(real2);
|
|
348
588
|
if (!out.has(id))
|
|
@@ -352,6 +592,7 @@ function discoverLocalRepos(repoDir, env = process.env) {
|
|
|
352
592
|
return [...out.values()];
|
|
353
593
|
}
|
|
354
594
|
var init_discover = __esm(() => {
|
|
595
|
+
init_safe_git();
|
|
355
596
|
init_ship();
|
|
356
597
|
init_watch();
|
|
357
598
|
});
|
|
@@ -7326,10 +7567,10 @@ var init_paths = __esm(() => {
|
|
|
7326
7567
|
});
|
|
7327
7568
|
|
|
7328
7569
|
// ../../loki-ts/src/util/receipt_signer.ts
|
|
7329
|
-
import { createHash as createHash6, randomBytes as
|
|
7330
|
-
import { chmodSync as chmodSync4, linkSync, mkdirSync as mkdirSync5, readdirSync as readdirSync9, readFileSync as readFileSync18, renameSync as renameSync4, statSync as
|
|
7570
|
+
import { createHash as createHash6, randomBytes as randomBytes3, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign, verify as verify2 } from "crypto";
|
|
7571
|
+
import { chmodSync as chmodSync4, linkSync, mkdirSync as mkdirSync5, readdirSync as readdirSync9, readFileSync as readFileSync18, renameSync as renameSync4, statSync as statSync12, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
7331
7572
|
import { homedir as homedir8 } from "os";
|
|
7332
|
-
import { dirname as dirname7, join as
|
|
7573
|
+
import { dirname as dirname7, join as join27 } from "path";
|
|
7333
7574
|
function canonicalJson(x) {
|
|
7334
7575
|
const walk = (v) => {
|
|
7335
7576
|
if (Array.isArray(v))
|
|
@@ -7348,12 +7589,12 @@ function loadSigningKey(generate = true) {
|
|
|
7348
7589
|
let pem = inline ?? "";
|
|
7349
7590
|
if (!inline) {
|
|
7350
7591
|
const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
|
|
7351
|
-
const file = given ||
|
|
7592
|
+
const file = given || join27(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
|
|
7352
7593
|
try {
|
|
7353
7594
|
pem = readFileSync18(file);
|
|
7354
7595
|
if (!given) {
|
|
7355
7596
|
for (const [f, m] of [[file, 384], [dirname7(file), 448]])
|
|
7356
|
-
if (
|
|
7597
|
+
if (statSync12(f).mode & 63)
|
|
7357
7598
|
chmodSync4(f, m);
|
|
7358
7599
|
}
|
|
7359
7600
|
} catch (e) {
|
|
@@ -7361,7 +7602,7 @@ function loadSigningKey(generate = true) {
|
|
|
7361
7602
|
return null;
|
|
7362
7603
|
mkdirSync5(dirname7(dirname7(file)), { recursive: true, mode: 448 });
|
|
7363
7604
|
mkdirSync5(dirname7(file), { recursive: true, mode: 448 });
|
|
7364
|
-
const tmp = `${file}.${
|
|
7605
|
+
const tmp = `${file}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
7365
7606
|
writeFileSync8(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
|
|
7366
7607
|
try {
|
|
7367
7608
|
linkSync(tmp, file);
|
|
@@ -7394,10 +7635,43 @@ var init_receipt_signer = () => {};
|
|
|
7394
7635
|
// ../../loki-ts/src/engine10/registry.ts
|
|
7395
7636
|
var init_registry = () => {};
|
|
7396
7637
|
|
|
7638
|
+
// ../../loki-ts/src/engine10/types.ts
|
|
7639
|
+
function pushArgv(a) {
|
|
7640
|
+
switch (a.cmd) {
|
|
7641
|
+
case "push-pr":
|
|
7642
|
+
return ["push-pr", a.repoDir, a.branch, a.title, a.bodyFile, a.draft ? "1" : "0"];
|
|
7643
|
+
case "comment":
|
|
7644
|
+
return ["comment", a.runId, a.prUrl, a.file];
|
|
7645
|
+
case "status":
|
|
7646
|
+
return ["status", a.sha, a.state, a.description];
|
|
7647
|
+
case "issue-comment":
|
|
7648
|
+
return a.update ? ["issue-comment", "--update", a.issueRef, a.bodyFile] : ["issue-comment", a.issueRef, a.bodyFile];
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
function taskBlock(task) {
|
|
7652
|
+
return ["Task (untrusted, quoted verbatim):", "<<<TASK", task, "TASK"];
|
|
7653
|
+
}
|
|
7654
|
+
var STAGE_BUDGETS;
|
|
7655
|
+
var init_types = __esm(() => {
|
|
7656
|
+
STAGE_BUDGETS = {
|
|
7657
|
+
intake: { targetS: 15, limitS: 60 },
|
|
7658
|
+
plan: { targetS: 45, limitS: 90 },
|
|
7659
|
+
wall: { targetS: 45, limitS: 90 },
|
|
7660
|
+
implement: { targetS: 180, limitS: 480 },
|
|
7661
|
+
verify: { targetS: 60, limitS: 120 },
|
|
7662
|
+
fix: { targetS: 90, limitS: 180 },
|
|
7663
|
+
commit: { targetS: 5, limitS: 30 },
|
|
7664
|
+
seal: { targetS: 15, limitS: 60 },
|
|
7665
|
+
pr: { targetS: 15, limitS: 60 },
|
|
7666
|
+
deep: { targetS: null, limitS: 2700 }
|
|
7667
|
+
};
|
|
7668
|
+
});
|
|
7669
|
+
|
|
7397
7670
|
// ../../loki-ts/src/engine10/output.ts
|
|
7398
7671
|
var init_output = __esm(() => {
|
|
7399
7672
|
init_registry();
|
|
7400
7673
|
init_redact();
|
|
7674
|
+
init_types();
|
|
7401
7675
|
});
|
|
7402
7676
|
|
|
7403
7677
|
// ../../loki-ts/src/util/atomic.ts
|
|
@@ -7405,13 +7679,13 @@ import {
|
|
|
7405
7679
|
closeSync as closeSync5,
|
|
7406
7680
|
fstatSync as fstatSync4,
|
|
7407
7681
|
fsyncSync as fsyncSync2,
|
|
7408
|
-
lstatSync as
|
|
7682
|
+
lstatSync as lstatSync5,
|
|
7409
7683
|
mkdirSync as mkdirSync6,
|
|
7410
7684
|
openSync as openSync5,
|
|
7411
7685
|
readSync as readSync4,
|
|
7412
7686
|
renameSync as renameSync5,
|
|
7413
|
-
rmSync as
|
|
7414
|
-
statSync as
|
|
7687
|
+
rmSync as rmSync5,
|
|
7688
|
+
statSync as statSync13,
|
|
7415
7689
|
unlinkSync as unlinkSync4,
|
|
7416
7690
|
writeFileSync as writeFileSync9,
|
|
7417
7691
|
writeSync as writeSync3
|
|
@@ -7455,184 +7729,6 @@ var init_atomic = __esm(() => {
|
|
|
7455
7729
|
_appendChains = new Map;
|
|
7456
7730
|
});
|
|
7457
7731
|
|
|
7458
|
-
// ../../loki-ts/src/util/credential_env.ts
|
|
7459
|
-
import { mkdtempSync as mkdtempSync2, rmSync as rmSync5, statSync as statSync13, lstatSync as lstatSync5 } from "fs";
|
|
7460
|
-
import { tmpdir as tmpdir3 } from "os";
|
|
7461
|
-
import { join as join27 } from "path";
|
|
7462
|
-
import { randomBytes as randomBytes3 } from "crypto";
|
|
7463
|
-
function withheldSentinel(fresh = false) {
|
|
7464
|
-
if (fresh)
|
|
7465
|
-
sentinel = null;
|
|
7466
|
-
return sentinel ??= `${SENTINEL_PREFIX}${process.pid}${randomBytes3(8).toString("hex")}INVALID`;
|
|
7467
|
-
}
|
|
7468
|
-
function removeConfigDir() {
|
|
7469
|
-
if (configDir)
|
|
7470
|
-
try {
|
|
7471
|
-
rmSync5(configDir, { recursive: true, force: true });
|
|
7472
|
-
} catch {}
|
|
7473
|
-
}
|
|
7474
|
-
function emptyGhConfigDir(env = process.env) {
|
|
7475
|
-
if (configDir && isDir(configDir))
|
|
7476
|
-
return configDir;
|
|
7477
|
-
const runTmp = env["LOKI_RUN_TMP"] ?? "";
|
|
7478
|
-
const root = runTmp !== "" && isDir(runTmp) ? runTmp : tmpdir3();
|
|
7479
|
-
try {
|
|
7480
|
-
configDir = mkdtempSync2(join27(root, "loki-gh-config-"));
|
|
7481
|
-
} catch {
|
|
7482
|
-
return null;
|
|
7483
|
-
}
|
|
7484
|
-
if (!exitHooked) {
|
|
7485
|
-
exitHooked = true;
|
|
7486
|
-
process.once("exit", removeConfigDir);
|
|
7487
|
-
}
|
|
7488
|
-
if (!sigtermHooked) {
|
|
7489
|
-
sigtermHooked = true;
|
|
7490
|
-
process.prependListener("SIGTERM", () => {
|
|
7491
|
-
removeConfigDir();
|
|
7492
|
-
if (process.listenerCount("SIGTERM") === 1)
|
|
7493
|
-
process.exit(143);
|
|
7494
|
-
});
|
|
7495
|
-
}
|
|
7496
|
-
return configDir;
|
|
7497
|
-
}
|
|
7498
|
-
function hardenCredentialEnv(env, fresh = false) {
|
|
7499
|
-
const s = withheldSentinel(fresh);
|
|
7500
|
-
for (const v of GITHUB_TOKEN_VARS)
|
|
7501
|
-
env[v] = s;
|
|
7502
|
-
const dir = emptyGhConfigDir(env);
|
|
7503
|
-
if (dir)
|
|
7504
|
-
env["GH_CONFIG_DIR"] = dir;
|
|
7505
|
-
const existing = Number(env["GIT_CONFIG_COUNT"]);
|
|
7506
|
-
const n2 = Number.isInteger(existing) && existing >= 0 ? existing : 0;
|
|
7507
|
-
const alreadyLast = n2 > 0 && env[`GIT_CONFIG_KEY_${n2 - 1}`] === "credential.helper" && env[`GIT_CONFIG_VALUE_${n2 - 1}`] === "";
|
|
7508
|
-
if (!alreadyLast) {
|
|
7509
|
-
env[`GIT_CONFIG_KEY_${n2}`] = "credential.helper";
|
|
7510
|
-
env[`GIT_CONFIG_VALUE_${n2}`] = "";
|
|
7511
|
-
env["GIT_CONFIG_COUNT"] = String(n2 + 1);
|
|
7512
|
-
}
|
|
7513
|
-
const params = env["GIT_CONFIG_PARAMETERS"];
|
|
7514
|
-
if (params && !params.trimEnd().endsWith("'credential.helper'=''"))
|
|
7515
|
-
env["GIT_CONFIG_PARAMETERS"] = `${params} 'credential.helper'=''`;
|
|
7516
|
-
env["GIT_TERMINAL_PROMPT"] = "0";
|
|
7517
|
-
env["GCM_INTERACTIVE"] = "never";
|
|
7518
|
-
}
|
|
7519
|
-
var GITHUB_TOKEN_VARS, SENTINEL_PREFIX = "ghp_LOKIWITHHELDsentinel", sentinel = null, configDir = null, exitHooked = false, sigtermHooked = false, isDir = (p) => {
|
|
7520
|
-
try {
|
|
7521
|
-
return !lstatSync5(p).isSymbolicLink() && statSync13(p).isDirectory();
|
|
7522
|
-
} catch {
|
|
7523
|
-
return false;
|
|
7524
|
-
}
|
|
7525
|
-
};
|
|
7526
|
-
var init_credential_env = __esm(() => {
|
|
7527
|
-
GITHUB_TOKEN_VARS = ["GH_TOKEN", "GITHUB_TOKEN", "GH_ENTERPRISE_TOKEN", "GITHUB_ENTERPRISE_TOKEN"];
|
|
7528
|
-
});
|
|
7529
|
-
|
|
7530
|
-
// ../../loki-ts/src/util/safe_git.ts
|
|
7531
|
-
import { execFileSync as execFileSync4, spawnSync } from "child_process";
|
|
7532
|
-
function tokenFreeEnv(env = process.env) {
|
|
7533
|
-
const out2 = { ...env };
|
|
7534
|
-
for (const k of SECRET_VARS)
|
|
7535
|
-
delete out2[k];
|
|
7536
|
-
hardenCredentialEnv(out2);
|
|
7537
|
-
return out2;
|
|
7538
|
-
}
|
|
7539
|
-
function driverKeys(repoDir) {
|
|
7540
|
-
const r = spawnSync("git", [...SAFE_GIT_CONFIG, "config", "--includes", "--show-scope", "-z", "--get-regexp", DRIVER_KEY_RE], { cwd: repoDir, env: safeGitEnv(), encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
7541
|
-
if (r.error)
|
|
7542
|
-
throw r.error;
|
|
7543
|
-
if (r.status === 1)
|
|
7544
|
-
return [];
|
|
7545
|
-
if (r.status !== 0)
|
|
7546
|
-
throw new Error(`safeGit: cannot enumerate git config drivers (status ${r.status})`);
|
|
7547
|
-
const t = r.stdout.split("\x00"), keys = [];
|
|
7548
|
-
for (let i = 0;i + 1 < t.length; i += 2) {
|
|
7549
|
-
const k = t[i + 1].split(`
|
|
7550
|
-
`)[0];
|
|
7551
|
-
if (REPO_SCOPES.has(t[i]) && k)
|
|
7552
|
-
keys.push(k);
|
|
7553
|
-
}
|
|
7554
|
-
return [...new Set(keys)];
|
|
7555
|
-
}
|
|
7556
|
-
function safeGitArgs(args, allowToken = false, repoDir, keep = {}) {
|
|
7557
|
-
if (keep.userHooks && allowToken)
|
|
7558
|
-
throw new Error("safeGit: userHooks with allowToken is refused (a hook would run holding the credential)");
|
|
7559
|
-
const off = new Set([...keep.repoDrivers ? [ATTRS_OFF] : [], ...keep.userHooks ? [HOOKS_OFF, SIGN_OFF] : []]);
|
|
7560
|
-
const cfg = [...allowToken ? CREDENTIAL_CONFIG : SAFE_GIT_CONFIG, ...DRIVER_CONFIG];
|
|
7561
|
-
const flags = cfg.flatMap((v, i) => i % 2 === 1 && !off.has(v) ? [cfg[i - 1], v] : []);
|
|
7562
|
-
return [...flags, ...repoDir && !keep.repoDrivers ? driverKeys(repoDir).flatMap((k) => ["-c", `${k}=`]) : [], ...noExtDiff(args)];
|
|
7563
|
-
}
|
|
7564
|
-
function noExtDiff(args) {
|
|
7565
|
-
let i = 0;
|
|
7566
|
-
while (i < args.length && args[i].startsWith("-"))
|
|
7567
|
-
i += OPT_WITH_VALUE.has(args[i]) ? 2 : 1;
|
|
7568
|
-
const cmd = args[i];
|
|
7569
|
-
if (cmd === undefined || !PATCH_CMDS.has(cmd))
|
|
7570
|
-
return [...args];
|
|
7571
|
-
const rest = args.slice(i + 1);
|
|
7572
|
-
const end = rest.indexOf("--");
|
|
7573
|
-
const opts = (end < 0 ? rest : rest.slice(0, end)).filter((a) => a !== "--ext-diff" && a !== "--textconv" && a !== "--no-ext-diff" && a !== "--no-textconv");
|
|
7574
|
-
return [...args.slice(0, i + 1), "--no-ext-diff", "--no-textconv", ...opts, ...end < 0 ? [] : rest.slice(end)];
|
|
7575
|
-
}
|
|
7576
|
-
function safeGit(repoDir, args, opts = {}) {
|
|
7577
|
-
const { env, allowToken, repoDrivers, userHooks, ...rest } = opts;
|
|
7578
|
-
const out2 = execFileSync4("git", safeGitArgs(args, allowToken, repoDir, { repoDrivers, userHooks }), { stdio: ["ignore", "pipe", "ignore"], ...rest, cwd: repoDir, env: safeGitEnv(env ?? process.env, allowToken), encoding: "utf8" });
|
|
7579
|
-
return typeof out2 === "string" ? out2 : "";
|
|
7580
|
-
}
|
|
7581
|
-
function safeGitSpawn(repoDir, args, opts = {}) {
|
|
7582
|
-
const { env, allowToken, repoDrivers, userHooks, ...rest } = opts;
|
|
7583
|
-
let argv;
|
|
7584
|
-
try {
|
|
7585
|
-
argv = safeGitArgs(args, allowToken, repoDir, { repoDrivers, userHooks });
|
|
7586
|
-
} catch (e) {
|
|
7587
|
-
return { pid: 0, output: [], stdout: "", stderr: "", status: null, signal: null, error: e };
|
|
7588
|
-
}
|
|
7589
|
-
return spawnSync("git", argv, { ...rest, cwd: repoDir, env: safeGitEnv(env ?? process.env, allowToken) });
|
|
7590
|
-
}
|
|
7591
|
-
async function safeGitRun(repoDir, args, opts = {}) {
|
|
7592
|
-
let argv;
|
|
7593
|
-
try {
|
|
7594
|
-
argv = safeGitArgs(args, opts.allowToken, repoDir, { repoDrivers: opts.repoDrivers, userHooks: opts.userHooks });
|
|
7595
|
-
} catch (e) {
|
|
7596
|
-
return { stdout: "", stderr: String(e), exitCode: 128 };
|
|
7597
|
-
}
|
|
7598
|
-
let proc;
|
|
7599
|
-
try {
|
|
7600
|
-
proc = Bun.spawn({ cmd: ["git", ...argv], cwd: repoDir, env: safeGitEnv(opts.env ?? process.env, opts.allowToken), stdin: "ignore", stdout: "pipe", stderr: "pipe", signal: opts.signal });
|
|
7601
|
-
} catch (e) {
|
|
7602
|
-
return { stdout: "", stderr: String(e), exitCode: 127 };
|
|
7603
|
-
}
|
|
7604
|
-
let timer;
|
|
7605
|
-
if (opts.timeoutMs && opts.timeoutMs > 0)
|
|
7606
|
-
timer = setTimeout(() => {
|
|
7607
|
-
try {
|
|
7608
|
-
proc.kill("SIGKILL");
|
|
7609
|
-
} catch {}
|
|
7610
|
-
}, opts.timeoutMs);
|
|
7611
|
-
try {
|
|
7612
|
-
const [stdout, stderr, exitCode] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]);
|
|
7613
|
-
return { stdout, stderr, exitCode };
|
|
7614
|
-
} finally {
|
|
7615
|
-
if (timer)
|
|
7616
|
-
clearTimeout(timer);
|
|
7617
|
-
}
|
|
7618
|
-
}
|
|
7619
|
-
var SAFE_GIT_CONFIG, CREDENTIAL_CONFIG, DRIVER_CONFIG, ATTRS_OFF = "core.attributesFile=/dev/null", HOOKS_OFF = "core.hooksPath=/dev/null", SIGN_OFF = "commit.gpgSign=false", REPO_SCOPES, DRIVER_KEY_RE = "^(filter\\..*\\.(clean|smudge|process)|diff\\..*\\.(textconv|command))$", PATCH_CMDS, OPT_WITH_VALUE, SECRET_VARS, safeGitEnv = (base = process.env, allowToken = false) => {
|
|
7620
|
-
const env = { ...allowToken ? base : tokenFreeEnv(base), GIT_CONFIG_NOSYSTEM: "1" };
|
|
7621
|
-
delete env.GIT_ATTR_SOURCE;
|
|
7622
|
-
delete env.GIT_EXTERNAL_DIFF;
|
|
7623
|
-
return env;
|
|
7624
|
-
};
|
|
7625
|
-
var init_safe_git = __esm(() => {
|
|
7626
|
-
init_credential_env();
|
|
7627
|
-
SAFE_GIT_CONFIG = ["-c", "core.fsmonitor=", "-c", "core.hooksPath=/dev/null", "-c", "core.sshCommand=", "-c", "protocol.ext.allow=never", "-c", "credential.helper="];
|
|
7628
|
-
CREDENTIAL_CONFIG = ["-c", "core.fsmonitor=", "-c", "core.hooksPath=/dev/null", "-c", "protocol.ext.allow=never"];
|
|
7629
|
-
DRIVER_CONFIG = ["-c", "diff.external=", "-c", "commit.gpgSign=false", "-c", "core.attributesFile=/dev/null"];
|
|
7630
|
-
REPO_SCOPES = new Set(["local", "worktree", "command"]);
|
|
7631
|
-
PATCH_CMDS = new Set(["diff", "show", "log", "whatchanged"]);
|
|
7632
|
-
OPT_WITH_VALUE = new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--exec-path", "--config-env", "--attr-source"]);
|
|
7633
|
-
SECRET_VARS = ["GH_TOKEN", "GITHUB_TOKEN", "GH_ENTERPRISE_TOKEN", "GITHUB_ENTERPRISE_TOKEN", "SSH_AUTH_SOCK"];
|
|
7634
|
-
});
|
|
7635
|
-
|
|
7636
7732
|
// ../../loki-ts/src/util/engine_origin.ts
|
|
7637
7733
|
function readOriginUrl(repoDir) {
|
|
7638
7734
|
try {
|
|
@@ -8060,38 +8156,6 @@ var init_budget = __esm(() => {
|
|
|
8060
8156
|
PRICING = Object.freeze(_loadPricing());
|
|
8061
8157
|
});
|
|
8062
8158
|
|
|
8063
|
-
// ../../loki-ts/src/engine10/types.ts
|
|
8064
|
-
function pushArgv(a) {
|
|
8065
|
-
switch (a.cmd) {
|
|
8066
|
-
case "push-pr":
|
|
8067
|
-
return ["push-pr", a.repoDir, a.branch, a.title, a.bodyFile, a.draft ? "1" : "0"];
|
|
8068
|
-
case "comment":
|
|
8069
|
-
return ["comment", a.runId, a.prUrl, a.file];
|
|
8070
|
-
case "status":
|
|
8071
|
-
return ["status", a.sha, a.state, a.description];
|
|
8072
|
-
case "issue-comment":
|
|
8073
|
-
return a.update ? ["issue-comment", "--update", a.issueRef, a.bodyFile] : ["issue-comment", a.issueRef, a.bodyFile];
|
|
8074
|
-
}
|
|
8075
|
-
}
|
|
8076
|
-
function taskBlock(task) {
|
|
8077
|
-
return ["Task (untrusted, quoted verbatim):", "<<<TASK", task, "TASK"];
|
|
8078
|
-
}
|
|
8079
|
-
var STAGE_BUDGETS;
|
|
8080
|
-
var init_types = __esm(() => {
|
|
8081
|
-
STAGE_BUDGETS = {
|
|
8082
|
-
intake: { targetS: 15, limitS: 60 },
|
|
8083
|
-
plan: { targetS: 45, limitS: 90 },
|
|
8084
|
-
wall: { targetS: 45, limitS: 90 },
|
|
8085
|
-
implement: { targetS: 180, limitS: 480 },
|
|
8086
|
-
verify: { targetS: 60, limitS: 120 },
|
|
8087
|
-
fix: { targetS: 90, limitS: 180 },
|
|
8088
|
-
commit: { targetS: 5, limitS: 30 },
|
|
8089
|
-
seal: { targetS: 15, limitS: 60 },
|
|
8090
|
-
pr: { targetS: 15, limitS: 60 },
|
|
8091
|
-
deep: { targetS: null, limitS: 2700 }
|
|
8092
|
-
};
|
|
8093
|
-
});
|
|
8094
|
-
|
|
8095
8159
|
// ../../loki-ts/src/runner/router/decision.ts
|
|
8096
8160
|
var init_decision = () => {};
|
|
8097
8161
|
|
|
@@ -8801,16 +8865,25 @@ var init_scope = __esm(() => {
|
|
|
8801
8865
|
dropped = new WeakMap;
|
|
8802
8866
|
});
|
|
8803
8867
|
|
|
8804
|
-
// ../../loki-ts/src/
|
|
8805
|
-
import { basename as basename9
|
|
8868
|
+
// ../../loki-ts/src/util/test_file_text.ts
|
|
8869
|
+
import { basename as basename9 } from "path";
|
|
8806
8870
|
function isTestFile(rel) {
|
|
8807
8871
|
const name = basename9(rel);
|
|
8808
8872
|
return JS_TEST_RE.test(name) || PY_TEST_RE.test(name) || GO_TEST_RE.test(name);
|
|
8809
8873
|
}
|
|
8810
|
-
var
|
|
8874
|
+
var JS_TEST_RE, PY_TEST_RE, GO_TEST_RE;
|
|
8875
|
+
var init_test_file_text = __esm(() => {
|
|
8876
|
+
JS_TEST_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
|
|
8877
|
+
PY_TEST_RE = /^(test_.+|.+_test)\.py$/;
|
|
8878
|
+
GO_TEST_RE = /_test\.go$/;
|
|
8879
|
+
});
|
|
8880
|
+
|
|
8881
|
+
// ../../loki-ts/src/engine10/testmap.ts
|
|
8882
|
+
var SKIP_DIRS;
|
|
8811
8883
|
var init_testmap = __esm(() => {
|
|
8812
8884
|
init_resolve();
|
|
8813
8885
|
init_scope();
|
|
8886
|
+
init_test_file_text();
|
|
8814
8887
|
SKIP_DIRS = new Set([
|
|
8815
8888
|
".git",
|
|
8816
8889
|
"node_modules",
|
|
@@ -8826,14 +8899,11 @@ var init_testmap = __esm(() => {
|
|
|
8826
8899
|
".loki",
|
|
8827
8900
|
".next"
|
|
8828
8901
|
]);
|
|
8829
|
-
JS_TEST_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
|
|
8830
|
-
PY_TEST_RE = /^(test_.+|.+_test)\.py$/;
|
|
8831
|
-
GO_TEST_RE = /_test\.go$/;
|
|
8832
8902
|
});
|
|
8833
8903
|
|
|
8834
8904
|
// ../../loki-ts/src/util/check_result.ts
|
|
8835
8905
|
import { mkdirSync as mkdirSync13, readFileSync as readFileSync28, renameSync as renameSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
8836
|
-
import { basename as basename10, join as
|
|
8906
|
+
import { basename as basename10, join as join37 } from "path";
|
|
8837
8907
|
function plainTestEnv(base = process.env) {
|
|
8838
8908
|
const e = {};
|
|
8839
8909
|
for (const [k, v] of Object.entries(tokenFreeEnv(base)))
|
|
@@ -9128,7 +9198,7 @@ function diffFiles(repoDir, baseSha) {
|
|
|
9128
9198
|
return f;
|
|
9129
9199
|
let n2 = 0;
|
|
9130
9200
|
try {
|
|
9131
|
-
n2 = readFileSync28(
|
|
9201
|
+
n2 = readFileSync28(join37(repoDir, path), "utf8").split(`
|
|
9132
9202
|
`).length;
|
|
9133
9203
|
} catch {}
|
|
9134
9204
|
return { path, added: n2, deleted: 0, status: "added" };
|
|
@@ -9136,7 +9206,7 @@ function diffFiles(repoDir, baseSha) {
|
|
|
9136
9206
|
}
|
|
9137
9207
|
function recordRisk(repoDir, a) {
|
|
9138
9208
|
try {
|
|
9139
|
-
const dir =
|
|
9209
|
+
const dir = join37(repoDir, ".loki", "state"), p = join37(dir, "risk-tier.json");
|
|
9140
9210
|
mkdirSync13(dir, { recursive: true });
|
|
9141
9211
|
writeFileSync16(`${p}.tmp`, JSON.stringify(a, null, 2) + `
|
|
9142
9212
|
`);
|
|
@@ -9196,7 +9266,7 @@ var init_state = __esm(() => {
|
|
|
9196
9266
|
|
|
9197
9267
|
// ../../loki-ts/src/runner/repo_profile.ts
|
|
9198
9268
|
import { existsSync as existsSync22, readFileSync as readFileSync29, mkdirSync as mkdirSync14, readdirSync as readdirSync13, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "fs";
|
|
9199
|
-
import { basename as basename11, join as
|
|
9269
|
+
import { basename as basename11, join as join38, resolve as resolve13, isAbsolute as isAbsolute2 } from "path";
|
|
9200
9270
|
function loadProfile(repoDir) {
|
|
9201
9271
|
try {
|
|
9202
9272
|
const p = JSON.parse(readFileSync29(commandProfilePath(repoDir), "utf8"));
|
|
@@ -9230,7 +9300,7 @@ function attributeFullSuite(repoDir, baseSha, full, blocked, changed) {
|
|
|
9230
9300
|
const block = new Set(blocked);
|
|
9231
9301
|
return attribute(repoDir, baseSha, bad.map((c) => ({ name: c.name, ...c.ids ? { ids: c.ids } : {}, eligible: (c.ids ?? []).every((i) => !block.has(i) && !changed.some((f) => i.includes(f))) })));
|
|
9232
9302
|
}
|
|
9233
|
-
var commandProfilePath = (repoDir) =>
|
|
9303
|
+
var commandProfilePath = (repoDir) => join38(repoDir, ".loki", "state", "repo-profile.json");
|
|
9234
9304
|
var init_repo_profile = __esm(() => {
|
|
9235
9305
|
init_failures();
|
|
9236
9306
|
init_check_result();
|
|
@@ -9266,12 +9336,12 @@ var init_context = __esm(() => {
|
|
|
9266
9336
|
// ../../loki-ts/src/util/steer.ts
|
|
9267
9337
|
import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as readdirSync14, lstatSync as lstatSync9, mkdirSync as mkdirSync15, linkSync as linkSync2, openSync as openSync8, readFileSync as readFileSync30, readSync as readSync7, renameSync as renameSync10, statSync as statSync15, lutimesSync, rmSync as rmSync9, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18, existsSync as existsSync23 } from "fs";
|
|
9268
9338
|
import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
|
|
9269
|
-
import { basename as basename12, join as
|
|
9339
|
+
import { basename as basename12, join as join39 } from "path";
|
|
9270
9340
|
function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
9271
9341
|
for (let i = 0;; i++) {
|
|
9272
9342
|
const name = i === 0 ? `${prefix}.md` : `${prefix}-${i}.md`;
|
|
9273
9343
|
try {
|
|
9274
|
-
link(src,
|
|
9344
|
+
link(src, join39(logs, name));
|
|
9275
9345
|
} catch (e) {
|
|
9276
9346
|
const code = e.code;
|
|
9277
9347
|
if (code === "EEXIST")
|
|
@@ -9279,7 +9349,7 @@ function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
|
|
|
9279
9349
|
if (code !== "EPERM" && code !== "ENOTSUP" && code !== "EXDEV" && code !== "EMLINK")
|
|
9280
9350
|
throw e;
|
|
9281
9351
|
const name2 = `${prefix}-${randomBytes4(4).toString("hex")}.md`;
|
|
9282
|
-
renameSync10(src,
|
|
9352
|
+
renameSync10(src, join39(logs, name2));
|
|
9283
9353
|
onLinked?.(name2);
|
|
9284
9354
|
return name2;
|
|
9285
9355
|
}
|
|
@@ -9298,7 +9368,7 @@ function orphanAlreadyArchived(logs, claim) {
|
|
|
9298
9368
|
if (!/^human-input-.*\.md$/.test(a))
|
|
9299
9369
|
continue;
|
|
9300
9370
|
try {
|
|
9301
|
-
const s = statSync15(
|
|
9371
|
+
const s = statSync15(join39(logs, a));
|
|
9302
9372
|
if (s.ino !== c.ino || s.dev !== c.dev)
|
|
9303
9373
|
continue;
|
|
9304
9374
|
if (/^human-input-(ORPHAN|REJECTED)-/.test(a) || existsSync23(appliedMarker(logs, a)))
|
|
@@ -9318,7 +9388,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
9318
9388
|
for (const n2 of names)
|
|
9319
9389
|
if (n2.startsWith(".applied-") && !present.has(n2.slice(".applied-".length))) {
|
|
9320
9390
|
try {
|
|
9321
|
-
unlinkSync5(
|
|
9391
|
+
unlinkSync5(join39(logs, n2));
|
|
9322
9392
|
} catch {}
|
|
9323
9393
|
}
|
|
9324
9394
|
for (const n2 of names) {
|
|
@@ -9335,7 +9405,7 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
9335
9405
|
if (alive) {
|
|
9336
9406
|
let ageMs = 0;
|
|
9337
9407
|
try {
|
|
9338
|
-
ageMs = nowMs - statSync15(
|
|
9408
|
+
ageMs = nowMs - statSync15(join39(logs, n2)).mtimeMs;
|
|
9339
9409
|
} catch {
|
|
9340
9410
|
continue;
|
|
9341
9411
|
}
|
|
@@ -9343,11 +9413,11 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
9343
9413
|
continue;
|
|
9344
9414
|
}
|
|
9345
9415
|
try {
|
|
9346
|
-
if (orphanAlreadyArchived(logs,
|
|
9347
|
-
unlinkSync5(
|
|
9416
|
+
if (orphanAlreadyArchived(logs, join39(logs, n2))) {
|
|
9417
|
+
unlinkSync5(join39(logs, n2));
|
|
9348
9418
|
continue;
|
|
9349
9419
|
}
|
|
9350
|
-
archiveTo(logs, `human-input-ORPHAN-${stamp2}`,
|
|
9420
|
+
archiveTo(logs, `human-input-ORPHAN-${stamp2}`, join39(logs, n2), link);
|
|
9351
9421
|
unapplied("orphaned claim");
|
|
9352
9422
|
} catch (e) {
|
|
9353
9423
|
if (e.code === "ENOENT")
|
|
@@ -9359,17 +9429,17 @@ function sweepOrphans(logs, stamp2, unapplied, link, nowMs = Date.now()) {
|
|
|
9359
9429
|
function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, hooks2) {
|
|
9360
9430
|
if (/^(0|false)$/i.test(env.LOKI_PROMPT_INJECTION ?? ""))
|
|
9361
9431
|
return null;
|
|
9362
|
-
const f =
|
|
9432
|
+
const f = join39(repoDir, ".loki", "HUMAN_INPUT.md");
|
|
9363
9433
|
const unapplied = (reason) => {
|
|
9364
9434
|
sink?.push({ rev: 0, source: null, actor: null, sha: "", at: now2().getTime(), unapplied: true, reason });
|
|
9365
9435
|
};
|
|
9366
9436
|
let fd = -1, claimed = "";
|
|
9367
9437
|
try {
|
|
9368
|
-
const logs =
|
|
9438
|
+
const logs = join39(repoDir, ".loki", "logs");
|
|
9369
9439
|
mkdirSync15(logs, { recursive: true });
|
|
9370
9440
|
const stamp2 = now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "");
|
|
9371
9441
|
sweepOrphans(logs, stamp2, unapplied, hooks2?.link, now2().getTime());
|
|
9372
|
-
claimed =
|
|
9442
|
+
claimed = join39(logs, `.claim-${process.pid}-${randomBytes4(6).toString("hex")}`);
|
|
9373
9443
|
try {
|
|
9374
9444
|
renameSync10(f, claimed);
|
|
9375
9445
|
} catch (e) {
|
|
@@ -9460,7 +9530,7 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
9460
9530
|
} catch {
|
|
9461
9531
|
if (claimed) {
|
|
9462
9532
|
try {
|
|
9463
|
-
archiveTo(
|
|
9533
|
+
archiveTo(join39(repoDir, ".loki", "logs"), `human-input-${now2().toISOString().replace(/[-:]/g, "").replace(/\..*/, "")}`, claimed, hooks2?.link);
|
|
9464
9534
|
unapplied("logs dir unwritable or file unreadable");
|
|
9465
9535
|
} catch {
|
|
9466
9536
|
unapplied(`steer stranded at .loki/logs/${basename12(claimed)}`);
|
|
@@ -9479,7 +9549,7 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
|
|
|
9479
9549
|
}
|
|
9480
9550
|
}
|
|
9481
9551
|
function recordRevisions(repoDir, text2, archived, at) {
|
|
9482
|
-
const file =
|
|
9552
|
+
const file = join39(repoDir, ".loki", "intent-revisions.jsonl");
|
|
9483
9553
|
let last = 0;
|
|
9484
9554
|
try {
|
|
9485
9555
|
for (const l of readFileSync30(file, "utf8").split(`
|
|
@@ -9536,7 +9606,7 @@ function staleAtSeal(repoDir, ctx) {
|
|
|
9536
9606
|
const frozen = ctx.outputs === undefined || ctx.outputs().wall !== undefined || ctx.wallSealed === true;
|
|
9537
9607
|
return [...new Set([...staleWallRevisions(ctx.intentRevisions, frozen ? ctx.timeline : []), ...late])];
|
|
9538
9608
|
}
|
|
9539
|
-
var STEER_MAX_BYTES, STEER_STAGES, STEER_CLAIM_MAX_AGE_MS, appliedMarker = (logs, archive) =>
|
|
9609
|
+
var STEER_MAX_BYTES, STEER_STAGES, STEER_CLAIM_MAX_AGE_MS, appliedMarker = (logs, archive) => join39(logs, `.applied-${archive}`), REV_HDR, STEER_REMEDY;
|
|
9540
9610
|
var init_steer = __esm(() => {
|
|
9541
9611
|
init_context();
|
|
9542
9612
|
STEER_MAX_BYTES = 1024 * 1024;
|
|
@@ -9599,18 +9669,18 @@ var init_seal_drift = __esm(() => {
|
|
|
9599
9669
|
});
|
|
9600
9670
|
|
|
9601
9671
|
// ../../loki-ts/src/util/spec_file.ts
|
|
9602
|
-
import { isAbsolute as isAbsolute3, join as
|
|
9672
|
+
import { isAbsolute as isAbsolute3, join as join40, relative } from "path";
|
|
9603
9673
|
function specReceiptBlock(env) {
|
|
9604
9674
|
const { LOKI_E10_SPEC_PATH: p, LOKI_E10_SPEC_SHA256: sha2 } = env;
|
|
9605
9675
|
if (!p || !sha2)
|
|
9606
9676
|
return {};
|
|
9607
|
-
const rel = isAbsolute3(p) && env.LOKI_E10_REPO_DIR ?
|
|
9677
|
+
const rel = isAbsolute3(p) && env.LOKI_E10_REPO_DIR ? relative(env.LOKI_E10_REPO_DIR, p) : p;
|
|
9608
9678
|
return { spec: { path: rel, sha256: sha2 } };
|
|
9609
9679
|
}
|
|
9610
9680
|
var SPEC_DIR;
|
|
9611
9681
|
var init_spec_file = __esm(() => {
|
|
9612
9682
|
init_types();
|
|
9613
|
-
SPEC_DIR =
|
|
9683
|
+
SPEC_DIR = join40(".loki", "specs");
|
|
9614
9684
|
});
|
|
9615
9685
|
|
|
9616
9686
|
// ../../loki-ts/src/engine10/pr_body.ts
|
|
@@ -9632,9 +9702,9 @@ var init_run_cap = __esm(() => {
|
|
|
9632
9702
|
// ../../loki-ts/src/util/mutation_proof.ts
|
|
9633
9703
|
import { existsSync as existsSync24, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync3, readFileSync as readFileSync31, rmSync as rmSync10, symlinkSync, writeFileSync as writeFileSync19 } from "fs";
|
|
9634
9704
|
import { tmpdir as tmpdir4 } from "os";
|
|
9635
|
-
import { basename as basename13, dirname as dirname13, isAbsolute as isAbsolute4, join as
|
|
9705
|
+
import { basename as basename13, dirname as dirname13, isAbsolute as isAbsolute4, join as join41, relative as relative2 } from "path";
|
|
9636
9706
|
function mutationProof(i) {
|
|
9637
|
-
const rels = i.wallFiles.map((f) => isAbsolute4(f.path) ?
|
|
9707
|
+
const rels = i.wallFiles.map((f) => isAbsolute4(f.path) ? relative2(i.repoDir, f.path) : f.path);
|
|
9638
9708
|
if (rels.length === 0)
|
|
9639
9709
|
return np("no Wall tests");
|
|
9640
9710
|
const tests = rels.flatMap((rel) => {
|
|
@@ -9650,25 +9720,25 @@ function mutationProof(i) {
|
|
|
9650
9720
|
const deadline = Date.now() + budgetS * 1000, remaining = () => deadline - Date.now();
|
|
9651
9721
|
let parent = null, wt = null, added = false;
|
|
9652
9722
|
try {
|
|
9653
|
-
parent = mkdtempSync3(
|
|
9654
|
-
wt =
|
|
9723
|
+
parent = mkdtempSync3(join41(tmpdir4(), "loki-mutproof-"));
|
|
9724
|
+
wt = join41(parent, "wt");
|
|
9655
9725
|
const add3 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
|
|
9656
9726
|
added = existsSync24(wt) || add3.status === 0;
|
|
9657
9727
|
if (add3.status !== 0)
|
|
9658
9728
|
return np("could not create the base worktree");
|
|
9659
9729
|
for (const rel of rels) {
|
|
9660
|
-
const sealed =
|
|
9730
|
+
const sealed = join41(i.runDir, "wall", basename13(rel)), src = existsSync24(sealed) ? sealed : join41(i.repoDir, rel);
|
|
9661
9731
|
if (!existsSync24(src))
|
|
9662
9732
|
return np(`Wall file missing: ${rel}`);
|
|
9663
|
-
mkdirSync16(dirname13(
|
|
9664
|
-
writeFileSync19(
|
|
9733
|
+
mkdirSync16(dirname13(join41(wt, rel)), { recursive: true });
|
|
9734
|
+
writeFileSync19(join41(wt, rel), readFileSync31(src));
|
|
9665
9735
|
}
|
|
9666
9736
|
for (const rel of rels) {
|
|
9667
9737
|
const parts = rel.split("/").slice(0, -1);
|
|
9668
9738
|
for (let n2 = 0;n2 <= parts.length; n2++) {
|
|
9669
9739
|
const anc = parts.slice(0, n2).join("/");
|
|
9670
9740
|
for (const d of DEP_DIRS) {
|
|
9671
|
-
const src =
|
|
9741
|
+
const src = join41(i.repoDir, anc, d), dst = join41(wt, anc, d);
|
|
9672
9742
|
if (existsSync24(src) && !existsSync24(dst)) {
|
|
9673
9743
|
try {
|
|
9674
9744
|
symlinkSync(src, dst);
|
|
@@ -10965,7 +11035,7 @@ Example: test('name', () => { assert.strictEqual(fn(1), 2); }); Run: node --tes
|
|
|
10965
11035
|
import { createHash as createHash12 } from "crypto";
|
|
10966
11036
|
import { appendFileSync as appendFileSync3, copyFileSync as copyFileSync2, existsSync as existsSync26, mkdirSync as mkdirSync17, readFileSync as readFileSync33, rmSync as rmSync12, writeFileSync as writeFileSync20 } from "fs";
|
|
10967
11037
|
import { tmpdir as tmpdir6 } from "os";
|
|
10968
|
-
import { basename as basename15, join as
|
|
11038
|
+
import { basename as basename15, join as join42, relative as relative3 } from "path";
|
|
10969
11039
|
function wallHoldoutRatio(env = process.env) {
|
|
10970
11040
|
if (env["LOKI_WALL_HOLDOUT"]?.trim() === "0")
|
|
10971
11041
|
return 0;
|
|
@@ -10993,32 +11063,32 @@ function stashHoldout(o) {
|
|
|
10993
11063
|
rmSync12(dir, { recursive: true, force: true });
|
|
10994
11064
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
10995
11065
|
const files = held.map((name) => {
|
|
10996
|
-
copyFileSync2(
|
|
10997
|
-
rmSync12(
|
|
10998
|
-
return { name, runner: o.runnerOf(name), sha256: sha2(readFileSync33(
|
|
11066
|
+
copyFileSync2(join42(o.srcDir, name), join42(dir, name));
|
|
11067
|
+
rmSync12(join42(o.srcDir, name), { force: true });
|
|
11068
|
+
return { name, runner: o.runnerOf(name), sha256: sha2(readFileSync33(join42(dir, name), "utf8")) };
|
|
10999
11069
|
});
|
|
11000
|
-
writeFileSync20(
|
|
11070
|
+
writeFileSync20(join42(dir, MANIFEST), JSON.stringify({ targetDir: o.targetDir, files }));
|
|
11001
11071
|
return { dir, names: new Set(held) };
|
|
11002
11072
|
}
|
|
11003
11073
|
function stageHoldout(dir, repoDir) {
|
|
11004
11074
|
const put = [], tests = [], missing = [];
|
|
11005
11075
|
let man = null;
|
|
11006
11076
|
try {
|
|
11007
|
-
man = JSON.parse(readFileSync33(
|
|
11077
|
+
man = JSON.parse(readFileSync33(join42(dir, MANIFEST), "utf8"));
|
|
11008
11078
|
} catch {}
|
|
11009
11079
|
if (!man)
|
|
11010
11080
|
return { tests, missing: [`holdout store unreadable: ${basename15(dir)}`], cleanup: () => {} };
|
|
11011
11081
|
mkdirSync17(man.targetDir, { recursive: true });
|
|
11012
11082
|
man.files.forEach((f, i) => {
|
|
11013
|
-
const src =
|
|
11083
|
+
const src = join42(dir, f.name);
|
|
11014
11084
|
if (!existsSync26(src) || sha2(readFileSync33(src, "utf8")) !== f.sha256) {
|
|
11015
11085
|
missing.push(`holdout ${i + 1} missing or altered`);
|
|
11016
11086
|
return;
|
|
11017
11087
|
}
|
|
11018
|
-
const dest =
|
|
11088
|
+
const dest = join42(man.targetDir, `loki_wall_holdout_${i + 1}${f.name.slice(f.name.indexOf("."))}`);
|
|
11019
11089
|
copyFileSync2(src, dest);
|
|
11020
11090
|
put.push(dest);
|
|
11021
|
-
tests.push({ runner: f.runner, path:
|
|
11091
|
+
tests.push({ runner: f.runner, path: relative3(repoDir, dest) });
|
|
11022
11092
|
});
|
|
11023
11093
|
return { tests, missing, cleanup: () => {
|
|
11024
11094
|
for (const p of put)
|
|
@@ -11028,16 +11098,16 @@ function stageHoldout(dir, repoDir) {
|
|
|
11028
11098
|
function recordHoldoutTriage(runDir, entry) {
|
|
11029
11099
|
try {
|
|
11030
11100
|
mkdirSync17(runDir, { recursive: true });
|
|
11031
|
-
appendFileSync3(
|
|
11101
|
+
appendFileSync3(join42(runDir, HOLDOUT_TRIAGE_FILE), JSON.stringify(entry) + `
|
|
11032
11102
|
`, { mode: 384 });
|
|
11033
11103
|
} catch {}
|
|
11034
11104
|
}
|
|
11035
|
-
var sha2 = (s) => createHash12("sha256").update(s).digest("hex"), WALL_HOLDOUT_DEFAULT_RATIO = 0.2, isHoldoutCheck = (name) => name.startsWith("holdout:"), holdoutDirFor = (runId, repoDir) =>
|
|
11105
|
+
var sha2 = (s) => createHash12("sha256").update(s).digest("hex"), WALL_HOLDOUT_DEFAULT_RATIO = 0.2, isHoldoutCheck = (name) => name.startsWith("holdout:"), holdoutDirFor = (runId, repoDir) => join42(tmpdir6(), `loki-e10-holdout-${sha2(`${runId}:${repoDir}`).slice(0, 16)}`), MANIFEST = "manifest.json", WALL_HOLDOUT_MIN = 5, HOLDOUT_TRIAGE_FILE = "holdout-triage.jsonl";
|
|
11036
11106
|
var init_holdout = () => {};
|
|
11037
11107
|
|
|
11038
11108
|
// ../../loki-ts/src/features/runner_config.ts
|
|
11039
11109
|
import { readFileSync as readFileSync34 } from "fs";
|
|
11040
|
-
import { dirname as dirname15, join as
|
|
11110
|
+
import { dirname as dirname15, join as join43, normalize as normalize2 } from "path";
|
|
11041
11111
|
function tomlKey2(s, i = 0, eq2 = true) {
|
|
11042
11112
|
const parts = [], ws = () => {
|
|
11043
11113
|
while (/\s/.test(s[i] ?? "x"))
|
|
@@ -11257,6 +11327,53 @@ function testConfigChanged(repoDir, baseSha, changed) {
|
|
|
11257
11327
|
}
|
|
11258
11328
|
});
|
|
11259
11329
|
}
|
|
11330
|
+
function patchedTargets(cfg, text2) {
|
|
11331
|
+
const out2 = [], unq = (v) => v.replace(/^["']|["']$/g, "");
|
|
11332
|
+
if (/package\.json$/i.test(cfg)) {
|
|
11333
|
+
try {
|
|
11334
|
+
const j = JSON.parse(text2);
|
|
11335
|
+
for (const m of [j.patchedDependencies, j.pnpm?.patchedDependencies])
|
|
11336
|
+
if (m && typeof m === "object") {
|
|
11337
|
+
for (const v of Object.values(m))
|
|
11338
|
+
if (typeof v === "string")
|
|
11339
|
+
out2.push(v);
|
|
11340
|
+
}
|
|
11341
|
+
} catch {}
|
|
11342
|
+
} else if (/pnpm-workspace\.yaml$/i.test(cfg)) {
|
|
11343
|
+
let on = false, flow = 0;
|
|
11344
|
+
const pairs = (t) => {
|
|
11345
|
+
for (const m of t.matchAll(/:\s*("[^"]*"|'[^']*'|[^\s,}#]+)/g))
|
|
11346
|
+
out2.push(unq(m[1]));
|
|
11347
|
+
}, depth = (t) => (t.match(/{/g) ?? []).length - (t.match(/}/g) ?? []).length;
|
|
11348
|
+
for (const l of text2.split(/\r?\n/)) {
|
|
11349
|
+
if (flow) {
|
|
11350
|
+
const c = l.replace(/#.*$/, "");
|
|
11351
|
+
pairs(c);
|
|
11352
|
+
flow = Math.max(0, flow + depth(c));
|
|
11353
|
+
continue;
|
|
11354
|
+
}
|
|
11355
|
+
const h = /^patchedDependencies\s*:(.*)$/.exec(l);
|
|
11356
|
+
if (h) {
|
|
11357
|
+
const rest = h[1].trim(), c = rest.replace(/#.*$/, "");
|
|
11358
|
+
on = !rest || rest.startsWith("#");
|
|
11359
|
+
pairs(c);
|
|
11360
|
+
if (c.startsWith("{"))
|
|
11361
|
+
flow = Math.max(0, depth(c));
|
|
11362
|
+
continue;
|
|
11363
|
+
}
|
|
11364
|
+
if (!on)
|
|
11365
|
+
continue;
|
|
11366
|
+
if (/^\S/.test(l)) {
|
|
11367
|
+
on = false;
|
|
11368
|
+
continue;
|
|
11369
|
+
}
|
|
11370
|
+
const m = /^\s+(?:"[^"]*"|'[^']*'|[^\s:'"][^:]*?)\s*:\s*("[^"]*"|'[^']*'|[^\s#]+)/.exec(l);
|
|
11371
|
+
if (m)
|
|
11372
|
+
out2.push(unq(m[1]));
|
|
11373
|
+
}
|
|
11374
|
+
}
|
|
11375
|
+
return out2.filter((t) => t && !t.startsWith("/"));
|
|
11376
|
+
}
|
|
11260
11377
|
function referenced(cfg, text2) {
|
|
11261
11378
|
const raw2 = [...text2.matchAll(REFS)].flatMap((m) => [...m[1].matchAll(QUOTED)].map((q) => q[1]));
|
|
11262
11379
|
for (const m of text2.matchAll(MAPPER))
|
|
@@ -11267,8 +11384,8 @@ function referenced(cfg, text2) {
|
|
|
11267
11384
|
}
|
|
11268
11385
|
const dir = dirname15(cfg), explicit = ROOT_DIR.exec(text2), roots = [dir];
|
|
11269
11386
|
if (explicit)
|
|
11270
|
-
roots.push("", ...explicit[1] ? [
|
|
11271
|
-
return raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(
|
|
11387
|
+
roots.push("", ...explicit[1] ? [join43(dir, explicit[1])] : []);
|
|
11388
|
+
return [...raw2.flatMap((r) => r.startsWith("/") ? [normalize2(r.slice(1))] : roots.map((root) => normalize2(join43(root, r.replace(/^<rootDir>\/?/, ""))))), ...patchedTargets(cfg, text2).map((t) => normalize2(join43(dir, t)))];
|
|
11272
11389
|
}
|
|
11273
11390
|
function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
11274
11391
|
const notes = new Set, ch = new Set(changed.map((c) => normalize2(c)));
|
|
@@ -11303,7 +11420,7 @@ function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
|
11303
11420
|
if (spec.shared && t)
|
|
11304
11421
|
try {
|
|
11305
11422
|
relevant(spec.shared, t);
|
|
11306
|
-
} catch {
|
|
11423
|
+
} catch (x) {
|
|
11307
11424
|
bad = true;
|
|
11308
11425
|
}
|
|
11309
11426
|
for (const c of referenced(cfg, t))
|
|
@@ -11311,7 +11428,7 @@ function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
|
11311
11428
|
}
|
|
11312
11429
|
const e = typeof spec.shared === "string" && spec.shared !== "tsconfig" ? "" : "{}";
|
|
11313
11430
|
if (!bad && !same)
|
|
11314
|
-
changedHere = !spec.shared || /conftest\.py
|
|
11431
|
+
changedHere = !spec.shared || /conftest\.py$/i.test(cfg) || relevant(spec.shared, texts[0] || e) !== relevant(spec.shared, texts[1] || e);
|
|
11315
11432
|
} catch {
|
|
11316
11433
|
bad = true;
|
|
11317
11434
|
}
|
|
@@ -11328,7 +11445,7 @@ function runnerConfigNotes(repoDir, baseSha, head, changed, signal) {
|
|
|
11328
11445
|
}
|
|
11329
11446
|
return [...notes];
|
|
11330
11447
|
}
|
|
11331
|
-
var PKG_KEYS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, depGuard = (j) => DEP_MAPS.map((m) => Object.entries(j[m] ?? {}).filter(([k, v]) => RUNNER_DEP.test(k) || LOCAL_SPEC.test(String(v)))), KW, lines = (t) => t.split(`
|
|
11448
|
+
var PKG_KEYS, RAW_CONFIGS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, depGuard = (j) => DEP_MAPS.map((m) => Object.entries(j[m] ?? {}).filter(([k, v]) => RUNNER_DEP.test(k) || LOCAL_SPEC.test(String(v)))), KW, lines = (t) => t.split(`
|
|
11332
11449
|
`).map((l) => l.trim()).filter((l) => l && !l.startsWith("#")), ESC, unesc = (s) => s.replace(/\\(?:u([0-9a-fA-F]{4})|U([0-9a-fA-F]{8})|([\s\S]))/g, (_m, u, U2, c) => {
|
|
11333
11450
|
if (c !== undefined) {
|
|
11334
11451
|
const e = ESC[c];
|
|
@@ -11348,26 +11465,29 @@ var PKG_KEYS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, depGuard = (j) =
|
|
|
11348
11465
|
}
|
|
11349
11466
|
}, headText = (dir, f) => {
|
|
11350
11467
|
try {
|
|
11351
|
-
return readFileSync34(
|
|
11468
|
+
return readFileSync34(join43(dir, f), "utf8");
|
|
11352
11469
|
} catch {
|
|
11353
11470
|
return "";
|
|
11354
11471
|
}
|
|
11355
11472
|
}, REFS, MAPPER, ROOT_DIR, QUOTED, EXT, gitOut = (dir, args, signal) => safeGit(dir, args, { timeout: 20000, maxBuffer: 64 << 20, ...signal ? { signal } : {} }), NON_SOURCE;
|
|
11356
11473
|
var init_runner_config = __esm(() => {
|
|
11357
11474
|
init_safe_git();
|
|
11358
|
-
PKG_KEYS = ["scripts", "jest", "overrides", "resolutions", "imports", "pnpm", "mocha", "vitest", "ava", "c8", "nyc", "babel", "bun"];
|
|
11359
|
-
|
|
11475
|
+
PKG_KEYS = ["scripts", "jest", "overrides", "resolutions", "imports", "pnpm", "mocha", "vitest", "ava", "c8", "nyc", "babel", "bun", "patchedDependencies"];
|
|
11476
|
+
RAW_CONFIGS = [
|
|
11360
11477
|
{ re: /(^|\/)(conftest\.py|tox\.ini|bunfig\.toml|\.?pytest\.(ini|toml)|\.mocharc[\w.]*)$/ },
|
|
11361
11478
|
{ re: /(^|\/)(vitest|vite|jest)\.(config|workspace)\.[\w.]+$/ },
|
|
11362
11479
|
{ re: /(^|\/)\.cargo\/config(\.toml)?$/ },
|
|
11363
11480
|
{ re: /(^|\/)(babel\.config\.[\w.]+|\.babelrc(\.[\w]+)?|\.pnpmfile\.(cjs|mjs))$/ },
|
|
11364
11481
|
{ re: /(^|\/)package\.json$/, shared: PKG_KEYS },
|
|
11482
|
+
{ re: /(^|\/)(pnpm-workspace\.yaml|\.yarnrc\.yml|\.npmrc)$/ },
|
|
11483
|
+
{ re: /(^|\/)patches\/|\.patch$/ },
|
|
11365
11484
|
{ re: /(^|\/)pyproject\.toml$/, shared: /^\[tool\.pytest/ },
|
|
11366
11485
|
{ re: /(^|\/)setup\.cfg$/, shared: /^\[tool:pytest\]/ },
|
|
11367
11486
|
{ re: /(^|\/)go\.(mod|work)$/, shared: "go" },
|
|
11368
11487
|
{ re: /(^|\/)Cargo\.toml$/, shared: "cargo" },
|
|
11369
11488
|
{ re: /(^|\/)[jt]sconfig(\.[\w-]+)?\.json$/, shared: "tsconfig" }
|
|
11370
11489
|
];
|
|
11490
|
+
RUNNER_CONFIGS = RAW_CONFIGS.map((s) => ({ ...s, re: new RegExp(s.re.source, "i") }));
|
|
11371
11491
|
DEP_MAPS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
|
|
11372
11492
|
RUNNER_DEP = /^(jest|vitest|mocha|ava|c8|nyc|pytest[\w-]*|@jest\/.*|ts-jest|babel-jest)$/;
|
|
11373
11493
|
LOCAL_SPEC = /^(file|link|npm|workspace):/;
|
|
@@ -11384,10 +11504,10 @@ var init_runner_config = __esm(() => {
|
|
|
11384
11504
|
});
|
|
11385
11505
|
|
|
11386
11506
|
// ../../loki-ts/src/e10ext/assert_delta.ts
|
|
11387
|
-
import { execFileSync as
|
|
11507
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
11388
11508
|
import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync35, rmSync as rmSync13 } from "fs";
|
|
11389
11509
|
import { tmpdir as tmpdir7 } from "os";
|
|
11390
|
-
import { join as
|
|
11510
|
+
import { join as join44 } from "path";
|
|
11391
11511
|
import { basename as basename16 } from "path";
|
|
11392
11512
|
function classifyAssertDelta(inp) {
|
|
11393
11513
|
const f = basename16(inp.path);
|
|
@@ -11397,8 +11517,8 @@ function classifyAssertDelta(inp) {
|
|
|
11397
11517
|
return WEAKENED;
|
|
11398
11518
|
let cwd = "";
|
|
11399
11519
|
try {
|
|
11400
|
-
cwd = mkdtempSync5(
|
|
11401
|
-
const raw2 =
|
|
11520
|
+
cwd = mkdtempSync5(join44(tmpdir7(), "loki-ad-"));
|
|
11521
|
+
const raw2 = execFileSync3("python3", ["-I", "-c", PY], {
|
|
11402
11522
|
input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
|
|
11403
11523
|
cwd,
|
|
11404
11524
|
env: process.env,
|
|
@@ -11428,7 +11548,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
|
|
|
11428
11548
|
return null;
|
|
11429
11549
|
try {
|
|
11430
11550
|
const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
|
|
11431
|
-
const head = headRef ? show(headRef) : readFileSync35(
|
|
11551
|
+
const head = headRef ? show(headRef) : readFileSync35(join44(repoDir, path), "utf8");
|
|
11432
11552
|
const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
|
|
11433
11553
|
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;
|
|
11434
11554
|
} catch {
|
|
@@ -11637,17 +11757,17 @@ var init_runner_errors = __esm(() => {
|
|
|
11637
11757
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
11638
11758
|
import { mkdtempSync as mkdtempSync6, realpathSync as realpathSync17, rmSync as rmSync14 } from "fs";
|
|
11639
11759
|
import { tmpdir as tmpdir8 } from "os";
|
|
11640
|
-
import { basename as basename17, extname
|
|
11760
|
+
import { basename as basename17, extname, join as join45 } from "path";
|
|
11641
11761
|
function changedFilesNamed(out2, repoDir, changed) {
|
|
11642
11762
|
return changed.filter((f) => {
|
|
11643
|
-
if (out2.includes(f) || out2.includes(
|
|
11763
|
+
if (out2.includes(f) || out2.includes(join45(repoDir, f)))
|
|
11644
11764
|
return true;
|
|
11645
11765
|
const segs = f.split("/");
|
|
11646
11766
|
if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
|
|
11647
11767
|
return true;
|
|
11648
|
-
if (
|
|
11768
|
+
if (extname(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
|
|
11649
11769
|
return true;
|
|
11650
|
-
const stem = basename17(f,
|
|
11770
|
+
const stem = basename17(f, extname(f));
|
|
11651
11771
|
if (stem.length < 2 || stem === "index" || stem === "__init__")
|
|
11652
11772
|
return false;
|
|
11653
11773
|
return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
|
|
@@ -11751,7 +11871,7 @@ async function loadErrorIsHarnessOwned(i) {
|
|
|
11751
11871
|
return false;
|
|
11752
11872
|
if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
|
|
11753
11873
|
return false;
|
|
11754
|
-
const dir = mkdtempSync6(
|
|
11874
|
+
const dir = mkdtempSync6(join45(tmpdir8(), "e10-loadown-"));
|
|
11755
11875
|
const git3 = (args) => {
|
|
11756
11876
|
safeGit(i.repoDir, args, { stdio: "ignore" });
|
|
11757
11877
|
};
|
|
@@ -11783,7 +11903,7 @@ var init_load_owner = __esm(() => {
|
|
|
11783
11903
|
});
|
|
11784
11904
|
|
|
11785
11905
|
// ../../loki-ts/src/util/wall_owned.ts
|
|
11786
|
-
import { isAbsolute as isAbsolute5, join as
|
|
11906
|
+
import { isAbsolute as isAbsolute5, join as join46, relative as relative4 } from "path";
|
|
11787
11907
|
function failingLocations(raw2, cwd, repoDir) {
|
|
11788
11908
|
const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
|
|
11789
11909
|
`), files = new Set;
|
|
@@ -11815,7 +11935,7 @@ function failingLocations(raw2, cwd, repoDir) {
|
|
|
11815
11935
|
}
|
|
11816
11936
|
if (errors2 === 0 || located !== errors2)
|
|
11817
11937
|
return null;
|
|
11818
|
-
return [...files].map((f) =>
|
|
11938
|
+
return [...files].map((f) => relative4(repoDir, isAbsolute5(f) ? f : join46(cwd, f)));
|
|
11819
11939
|
}
|
|
11820
11940
|
function wallOwnedFailure(raw2, cwd, repoDir, wall) {
|
|
11821
11941
|
const locs = failingLocations(raw2, cwd, repoDir);
|
|
@@ -11836,7 +11956,7 @@ import {
|
|
|
11836
11956
|
writeFileSync as writeFileSync21,
|
|
11837
11957
|
mkdirSync as mkdirSync18
|
|
11838
11958
|
} from "fs";
|
|
11839
|
-
import { basename as basename18, dirname as dirname16, join as
|
|
11959
|
+
import { basename as basename18, dirname as dirname16, join as join47, resolve as resolve14 } from "path";
|
|
11840
11960
|
function readManifest(path) {
|
|
11841
11961
|
if (!existsSync27(path)) {
|
|
11842
11962
|
return null;
|
|
@@ -11895,7 +12015,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
11895
12015
|
for (const child of children) {
|
|
11896
12016
|
if (!matchPattern(name, child))
|
|
11897
12017
|
continue;
|
|
11898
|
-
const full =
|
|
12018
|
+
const full = join47(rootDir, child);
|
|
11899
12019
|
if (seen.has(full))
|
|
11900
12020
|
continue;
|
|
11901
12021
|
let st;
|
|
@@ -11912,7 +12032,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
11912
12032
|
}
|
|
11913
12033
|
if (declared.length === 0) {
|
|
11914
12034
|
for (const child of children) {
|
|
11915
|
-
const full =
|
|
12035
|
+
const full = join47(rootDir, child);
|
|
11916
12036
|
if (seen.has(full))
|
|
11917
12037
|
continue;
|
|
11918
12038
|
let st;
|
|
@@ -11923,7 +12043,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
11923
12043
|
}
|
|
11924
12044
|
if (!st.isDirectory())
|
|
11925
12045
|
continue;
|
|
11926
|
-
if (!existsSync27(
|
|
12046
|
+
if (!existsSync27(join47(full, ".loki", "app.json")))
|
|
11927
12047
|
continue;
|
|
11928
12048
|
seen.add(full);
|
|
11929
12049
|
out2.push(full);
|
|
@@ -11944,17 +12064,17 @@ function cacheKey(manifestPaths) {
|
|
|
11944
12064
|
}
|
|
11945
12065
|
function writeCache(targetDir, key, result) {
|
|
11946
12066
|
try {
|
|
11947
|
-
const cacheDir =
|
|
12067
|
+
const cacheDir = join47(targetDir, ".loki", "state");
|
|
11948
12068
|
mkdirSync18(cacheDir, { recursive: true });
|
|
11949
|
-
const cachePath =
|
|
12069
|
+
const cachePath = join47(cacheDir, "project-graph.json");
|
|
11950
12070
|
writeFileSync21(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
|
|
11951
12071
|
} catch {}
|
|
11952
12072
|
}
|
|
11953
12073
|
function discoverProjectGraph(targetDir) {
|
|
11954
12074
|
const absTarget = resolve14(targetDir);
|
|
11955
|
-
const targetManifest =
|
|
12075
|
+
const targetManifest = join47(absTarget, ".loki", "app.json");
|
|
11956
12076
|
const parentDir = dirname16(absTarget);
|
|
11957
|
-
const parentManifest =
|
|
12077
|
+
const parentManifest = join47(parentDir, ".loki", "app.json");
|
|
11958
12078
|
const examined = [];
|
|
11959
12079
|
let chosenManifest = null;
|
|
11960
12080
|
let chosenRoot = "";
|
|
@@ -11974,7 +12094,7 @@ function discoverProjectGraph(targetDir) {
|
|
|
11974
12094
|
const members = resolveMembers(chosenRoot, declared, basename18(absTarget));
|
|
11975
12095
|
const filtered = [];
|
|
11976
12096
|
for (const m of members) {
|
|
11977
|
-
const sibManifestPath =
|
|
12097
|
+
const sibManifestPath = join47(m, ".loki", "app.json");
|
|
11978
12098
|
if (existsSync27(sibManifestPath)) {
|
|
11979
12099
|
examined.push(sibManifestPath);
|
|
11980
12100
|
const sibManifest = readManifest(sibManifestPath);
|
|
@@ -12105,7 +12225,7 @@ import { spawn as spawn7 } from "child_process";
|
|
|
12105
12225
|
import { createHash as createHash14, randomBytes as randomBytes5 } from "crypto";
|
|
12106
12226
|
import { existsSync as existsSync28, lstatSync as lstatSync10, mkdirSync as mkdirSync19, readdirSync as readdirSync16, readFileSync as readFileSync37, writeFileSync as writeFileSync22 } from "fs";
|
|
12107
12227
|
import { createServer } from "net";
|
|
12108
|
-
import { dirname as dirname17, isAbsolute as isAbsolute6, join as
|
|
12228
|
+
import { dirname as dirname17, isAbsolute as isAbsolute6, join as join48, normalize as normalize3, relative as relative5, sep as sep10 } from "path";
|
|
12109
12229
|
function routeFor(file) {
|
|
12110
12230
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
12111
12231
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -12115,7 +12235,7 @@ function hashScreens(runDir, rels) {
|
|
|
12115
12235
|
const out2 = [];
|
|
12116
12236
|
for (const rel of rels) {
|
|
12117
12237
|
try {
|
|
12118
|
-
out2.push({ path: rel, sha256: sha256File(
|
|
12238
|
+
out2.push({ path: rel, sha256: sha256File(join48(runDir, rel)) });
|
|
12119
12239
|
} catch {}
|
|
12120
12240
|
}
|
|
12121
12241
|
return out2;
|
|
@@ -12128,10 +12248,10 @@ function checkScreens(runDir, screens) {
|
|
|
12128
12248
|
return "evidence_screens entry is malformed";
|
|
12129
12249
|
if (isAbsolute6(s.path) || normalize3(s.path).startsWith(".."))
|
|
12130
12250
|
return `evidence screenshot path escapes the evidence dir: ${s.path}`;
|
|
12131
|
-
const file =
|
|
12251
|
+
const file = join48(runDir, s.path);
|
|
12132
12252
|
let cur = runDir;
|
|
12133
|
-
for (const seg of normalize3(s.path).split(
|
|
12134
|
-
cur =
|
|
12253
|
+
for (const seg of normalize3(s.path).split(sep10)) {
|
|
12254
|
+
cur = join48(cur, seg);
|
|
12135
12255
|
if (isSymlink(cur))
|
|
12136
12256
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
12137
12257
|
}
|
|
@@ -12178,7 +12298,7 @@ async function waitUp(url, ms, signal) {
|
|
|
12178
12298
|
}
|
|
12179
12299
|
function openapiPaths(repoDir) {
|
|
12180
12300
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
12181
|
-
const p =
|
|
12301
|
+
const p = join48(repoDir, f);
|
|
12182
12302
|
if (!existsSync28(p))
|
|
12183
12303
|
continue;
|
|
12184
12304
|
try {
|
|
@@ -12196,24 +12316,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
|
|
|
12196
12316
|
if (!pw || !pkg)
|
|
12197
12317
|
return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
|
|
12198
12318
|
try {
|
|
12199
|
-
const dir =
|
|
12319
|
+
const dir = join48(runDir, relDir, "e2e");
|
|
12200
12320
|
mkdirSync19(dir, { recursive: true });
|
|
12201
|
-
writeFileSync22(
|
|
12202
|
-
writeFileSync22(
|
|
12321
|
+
writeFileSync22(join48(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
|
|
12322
|
+
writeFileSync22(join48(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
|
|
12203
12323
|
`);
|
|
12204
|
-
if (!await shoot(pw, ["test", "--config",
|
|
12324
|
+
if (!await shoot(pw, ["test", "--config", join48(dir, "playwright.config.cjs")], repoDir, ms, signal))
|
|
12205
12325
|
return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
|
|
12206
12326
|
const rels = [];
|
|
12207
12327
|
const walk = (d) => {
|
|
12208
12328
|
for (const e of readdirSync16(d, { withFileTypes: true })) {
|
|
12209
|
-
const full =
|
|
12329
|
+
const full = join48(d, e.name);
|
|
12210
12330
|
if (e.isDirectory())
|
|
12211
12331
|
walk(full);
|
|
12212
12332
|
else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
|
|
12213
|
-
rels.push(
|
|
12333
|
+
rels.push(join48(relDir, "e2e", relative5(dir, full)));
|
|
12214
12334
|
}
|
|
12215
12335
|
};
|
|
12216
|
-
walk(
|
|
12336
|
+
walk(join48(dir, "out"));
|
|
12217
12337
|
return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
|
|
12218
12338
|
} catch (e) {
|
|
12219
12339
|
return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
|
|
@@ -12292,15 +12412,15 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12292
12412
|
if (!visualEvidenceEnabled(opts.env))
|
|
12293
12413
|
return skip("LOKI_VISUAL_EVIDENCE is 0");
|
|
12294
12414
|
const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
|
|
12295
|
-
const appDir = boot ?
|
|
12296
|
-
const pkgPath =
|
|
12415
|
+
const appDir = boot ? join48(repoDir, boot.boot.cwd) : repoDir;
|
|
12416
|
+
const pkgPath = join48(appDir, "package.json");
|
|
12297
12417
|
let script = null;
|
|
12298
12418
|
if (!boot) {
|
|
12299
12419
|
if (!existsSync28(pkgPath)) {
|
|
12300
|
-
const subs = ["backend", "frontend"].filter((d) => existsSync28(
|
|
12420
|
+
const subs = ["backend", "frontend"].filter((d) => existsSync28(join48(repoDir, d, "package.json")));
|
|
12301
12421
|
const has = (d) => {
|
|
12302
12422
|
try {
|
|
12303
|
-
return pickScript(JSON.parse(readFileSync37(
|
|
12423
|
+
return pickScript(JSON.parse(readFileSync37(join48(repoDir, d, "package.json"), "utf8"))) !== null;
|
|
12304
12424
|
} catch {
|
|
12305
12425
|
return false;
|
|
12306
12426
|
}
|
|
@@ -12334,20 +12454,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12334
12454
|
}
|
|
12335
12455
|
if (!await waitUp(base, left(), signal))
|
|
12336
12456
|
return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
|
|
12337
|
-
const evRoot =
|
|
12457
|
+
const evRoot = join48(runDir, "evidence");
|
|
12338
12458
|
if (isSymlink(evRoot))
|
|
12339
12459
|
return skip("evidence dir is a symlink");
|
|
12340
12460
|
mkdirSync19(evRoot, { recursive: true });
|
|
12341
12461
|
if (pages.length > 0) {
|
|
12342
|
-
const rel0 =
|
|
12343
|
-
mkdirSync19(
|
|
12462
|
+
const rel0 = join48("evidence", randomBytes5(6).toString("hex"));
|
|
12463
|
+
mkdirSync19(join48(runDir, rel0));
|
|
12344
12464
|
const rels = [];
|
|
12345
12465
|
for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
|
|
12346
12466
|
if (aborted() || left() <= 0)
|
|
12347
12467
|
break;
|
|
12348
|
-
const rel =
|
|
12349
|
-
const ok = await shoot(pw, ["screenshot", `${base}${route}`,
|
|
12350
|
-
if (ok && !aborted() && !isSymlink(
|
|
12468
|
+
const rel = join48(rel0, `${screenName(route)}.png`);
|
|
12469
|
+
const ok = await shoot(pw, ["screenshot", `${base}${route}`, join48(runDir, rel)], appDir, left(), signal);
|
|
12470
|
+
if (ok && !aborted() && !isSymlink(join48(runDir, rel)) && existsSync28(join48(runDir, rel)))
|
|
12351
12471
|
rels.push(rel);
|
|
12352
12472
|
}
|
|
12353
12473
|
if (aborted())
|
|
@@ -12372,9 +12492,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12372
12492
|
}
|
|
12373
12493
|
if (aborted())
|
|
12374
12494
|
return skip("aborted");
|
|
12375
|
-
const hdir =
|
|
12495
|
+
const hdir = join48(evRoot, randomBytes5(6).toString("hex"));
|
|
12376
12496
|
mkdirSync19(hdir);
|
|
12377
|
-
writeFileSync22(
|
|
12497
|
+
writeFileSync22(join48(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
|
|
12378
12498
|
`);
|
|
12379
12499
|
return { screens: [], http: true, skipped: null };
|
|
12380
12500
|
} catch (e) {
|
|
@@ -12404,11 +12524,11 @@ function receiptScreensProblem(receiptPath, receipt) {
|
|
|
12404
12524
|
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname17(receiptPath), receipt["evidence_screens"]);
|
|
12405
12525
|
}
|
|
12406
12526
|
var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0", visualGateEnabled = (env = process.env) => env["LOKI_VISUAL_GATE"] === "1", PAGE_RE, isPageFile = (p) => PAGE_RE.test(p), screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index", sha256File = (p) => createHash14("sha256").update(readFileSync37(p)).digest("hex"), playwrightBin = (repoDir) => {
|
|
12407
|
-
const bin =
|
|
12527
|
+
const bin = join48(repoDir, "node_modules", ".bin", "playwright");
|
|
12408
12528
|
return existsSync28(bin) ? bin : null;
|
|
12409
12529
|
}, playwrightTestPkg = (repoDir) => {
|
|
12410
|
-
const d =
|
|
12411
|
-
return existsSync28(
|
|
12530
|
+
const d = join48(repoDir, "node_modules", "@playwright", "test");
|
|
12531
|
+
return existsSync28(join48(d, "package.json")) ? d : null;
|
|
12412
12532
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
12413
12533
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
12414
12534
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -12451,7 +12571,7 @@ var init_outbox = __esm(() => {
|
|
|
12451
12571
|
});
|
|
12452
12572
|
|
|
12453
12573
|
// ../../loki-ts/src/engine10/stages/pr.ts
|
|
12454
|
-
import { join as
|
|
12574
|
+
import { join as join49 } from "path";
|
|
12455
12575
|
var DEFAULT_PUSH_SH;
|
|
12456
12576
|
var init_pr = __esm(() => {
|
|
12457
12577
|
init_types();
|
|
@@ -12468,12 +12588,12 @@ var init_pr = __esm(() => {
|
|
|
12468
12588
|
init_run_outputs();
|
|
12469
12589
|
init_yaml_key();
|
|
12470
12590
|
init_outbox();
|
|
12471
|
-
DEFAULT_PUSH_SH =
|
|
12591
|
+
DEFAULT_PUSH_SH = join49(REPO_ROOT, "autonomy/lib/engine10-push.sh");
|
|
12472
12592
|
});
|
|
12473
12593
|
|
|
12474
12594
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
12475
12595
|
import { existsSync as existsSync29, mkdirSync as mkdirSync20, mkdtempSync as mkdtempSync7, readFileSync as readFileSync38, rmSync as rmSync15, writeFileSync as writeFileSync23 } from "fs";
|
|
12476
|
-
import { dirname as dirname18, join as
|
|
12596
|
+
import { dirname as dirname18, join as join50 } from "path";
|
|
12477
12597
|
import { createHash as createHash15 } from "crypto";
|
|
12478
12598
|
function loadLessons(repoDir) {
|
|
12479
12599
|
const p = lessonsPath(repoDir);
|
|
@@ -12522,7 +12642,7 @@ function recordRunVerdict(repoDir, runId, verdict) {
|
|
|
12522
12642
|
if (dirty)
|
|
12523
12643
|
save(repoDir, lessons);
|
|
12524
12644
|
}
|
|
12525
|
-
var lessonsPath = (repoDir) =>
|
|
12645
|
+
var lessonsPath = (repoDir) => join50(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
|
|
12526
12646
|
var init_pr_lessons = __esm(() => {
|
|
12527
12647
|
init_atomic();
|
|
12528
12648
|
init_safe_git();
|
|
@@ -12657,10 +12777,10 @@ var init_providers = __esm(() => {
|
|
|
12657
12777
|
|
|
12658
12778
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
12659
12779
|
import { existsSync as existsSync31, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readFileSync as readFileSync40, writeFileSync as writeFileSync24 } from "fs";
|
|
12660
|
-
import { join as
|
|
12780
|
+
import { join as join51 } from "path";
|
|
12661
12781
|
function loadRouteRecord(runDir) {
|
|
12662
12782
|
try {
|
|
12663
|
-
const p =
|
|
12783
|
+
const p = join51(runDir, ROUTE_RECORD_FILE);
|
|
12664
12784
|
if (!existsSync31(p) || !lstatSync11(p).isFile())
|
|
12665
12785
|
return;
|
|
12666
12786
|
const v = JSON.parse(readFileSync40(p, "utf8"));
|
|
@@ -12789,7 +12909,7 @@ var init_worker = __esm(() => {
|
|
|
12789
12909
|
});
|
|
12790
12910
|
|
|
12791
12911
|
// ../../loki-ts/src/project_model/package_suite.ts
|
|
12792
|
-
import { join as
|
|
12912
|
+
import { join as join52 } from "path";
|
|
12793
12913
|
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
12794
12914
|
const api = loadProjectApi(repoDir);
|
|
12795
12915
|
if (!isMultiRoot(api))
|
|
@@ -12800,7 +12920,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
12800
12920
|
for (const pkg of withTests) {
|
|
12801
12921
|
const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
|
|
12802
12922
|
const started = Date.now();
|
|
12803
|
-
const r = await run(["bash", "-c", tc.cmd], { cwd:
|
|
12923
|
+
const r = await run(["bash", "-c", tc.cmd], { cwd: join52(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
12804
12924
|
const duration_s = (Date.now() - started) / 1000;
|
|
12805
12925
|
if (signal.aborted) {
|
|
12806
12926
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
@@ -12809,7 +12929,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
12809
12929
|
}
|
|
12810
12930
|
const out2 = `${r.stdout}
|
|
12811
12931
|
${r.stderr}`;
|
|
12812
|
-
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd:
|
|
12932
|
+
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd: join52(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
12813
12933
|
if (lr) {
|
|
12814
12934
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
12815
12935
|
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
@@ -12843,7 +12963,7 @@ __export(exports_deep, {
|
|
|
12843
12963
|
DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH2
|
|
12844
12964
|
});
|
|
12845
12965
|
import { existsSync as existsSync32, mkdirSync as mkdirSync22, writeFileSync as writeFileSync25 } from "fs";
|
|
12846
|
-
import { join as
|
|
12966
|
+
import { join as join53 } from "path";
|
|
12847
12967
|
async function runFullSuite(ctx, signal, opts, checks, notProven) {
|
|
12848
12968
|
if (await runPackageSuites(ctx.repoDir, signal, { path: opts.path, timeoutMs: opts.fullSuiteTimeoutMs ?? FULL_SUITE_TIMEOUT_MS, baseSha: ctx.baseSha }, checks, notProven))
|
|
12849
12969
|
return;
|
|
@@ -12940,7 +13060,7 @@ async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
|
12940
13060
|
}
|
|
12941
13061
|
const inline = 'script="$1"; shift; . "$script" || exit 3; hit=0; for f in "$@"; do if _commit_scan_secret_file "$f" || _commit_path_looks_secret "$f"; then printf "%s\\n" "$f"; hit=1; fi; done; exit "$hit"';
|
|
12942
13062
|
const started = Date.now();
|
|
12943
|
-
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) =>
|
|
13063
|
+
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) => join53(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
|
|
12944
13064
|
const durationS = (Date.now() - started) / 1000;
|
|
12945
13065
|
if (r.exitCode === 3) {
|
|
12946
13066
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: durationS });
|
|
@@ -12981,7 +13101,7 @@ async function postResults(ctx, opts, checks, notProven, statusState) {
|
|
|
12981
13101
|
const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
|
|
12982
13102
|
if (prNumber) {
|
|
12983
13103
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
12984
|
-
const bodyFile =
|
|
13104
|
+
const bodyFile = join53(ctx.runDir, "deep-comment.md");
|
|
12985
13105
|
writeFileSync25(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
|
|
12986
13106
|
const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
|
|
12987
13107
|
if (commentResult.exitCode !== 0)
|
|
@@ -13035,7 +13155,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
13035
13155
|
const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
|
|
13036
13156
|
const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
13037
13157
|
mkdirSync22(ctx.runDir, { recursive: true });
|
|
13038
|
-
writeFileSync25(
|
|
13158
|
+
writeFileSync25(join53(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
|
|
13039
13159
|
`);
|
|
13040
13160
|
const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
|
|
13041
13161
|
const allNotProven = [...notProvenList, ...pushNotProven];
|
|
@@ -13080,18 +13200,18 @@ var init_deep = __esm(() => {
|
|
|
13080
13200
|
// ../../loki-ts/src/engine10/stages/verify.ts
|
|
13081
13201
|
import { existsSync as existsSync33, mkdtempSync as mkdtempSync8, realpathSync as realpathSync18, rmSync as rmSync16 } from "fs";
|
|
13082
13202
|
import { tmpdir as tmpdir9 } from "os";
|
|
13083
|
-
import { dirname as dirname20, isAbsolute as isAbsolute7, join as
|
|
13203
|
+
import { dirname as dirname20, isAbsolute as isAbsolute7, join as join54, relative as relative6 } from "path";
|
|
13084
13204
|
function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
13085
13205
|
const inRepo = (p) => {
|
|
13086
13206
|
try {
|
|
13087
|
-
const r =
|
|
13207
|
+
const r = relative6(realpathSync18(repoDir), realpathSync18(p));
|
|
13088
13208
|
return r !== "" && !r.startsWith("..") && !isAbsolute7(r);
|
|
13089
13209
|
} catch {
|
|
13090
13210
|
return false;
|
|
13091
13211
|
}
|
|
13092
13212
|
};
|
|
13093
13213
|
const venvEnv = process.env["VIRTUAL_ENV"];
|
|
13094
|
-
const project = [
|
|
13214
|
+
const project = [join54(repoDir, ".venv", "bin", bin), join54(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join54(venvEnv, "bin", bin)] : []].find(existsSync33);
|
|
13095
13215
|
return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
|
|
13096
13216
|
}
|
|
13097
13217
|
function runnerCmd(t, repoDir) {
|
|
@@ -13204,7 +13324,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13204
13324
|
const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
|
|
13205
13325
|
if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
|
|
13206
13326
|
return out2;
|
|
13207
|
-
const dir = mkdtempSync8(
|
|
13327
|
+
const dir = mkdtempSync8(join54(tmpdir9(), "e10-base-"));
|
|
13208
13328
|
const git3 = (args) => {
|
|
13209
13329
|
safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
|
|
13210
13330
|
};
|
|
@@ -13242,7 +13362,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
13242
13362
|
return out2;
|
|
13243
13363
|
}
|
|
13244
13364
|
function isLokiModeRepo(repoDir) {
|
|
13245
|
-
return existsSync33(
|
|
13365
|
+
return existsSync33(join54(repoDir, "scripts", "select-tests.sh"));
|
|
13246
13366
|
}
|
|
13247
13367
|
async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
13248
13368
|
const { api, ...runOpts } = opts;
|
|
@@ -13259,9 +13379,9 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
|
13259
13379
|
}
|
|
13260
13380
|
for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
|
|
13261
13381
|
const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
|
|
13262
|
-
if (existsSync33(
|
|
13382
|
+
if (existsSync33(join54(g.cwd, "tsconfig.json")))
|
|
13263
13383
|
await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
|
|
13264
|
-
if (ESLINT_CONFIGS.some((f) => existsSync33(
|
|
13384
|
+
if (ESLINT_CONFIGS.some((f) => existsSync33(join54(g.cwd, f))))
|
|
13265
13385
|
await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
|
|
13266
13386
|
}
|
|
13267
13387
|
}
|
|
@@ -13319,7 +13439,7 @@ var init_verify = __esm(() => {
|
|
|
13319
13439
|
const impacted = ctx.tests.impacted(map, changed);
|
|
13320
13440
|
const changedTestFiles = map.tests.filter((t) => changed.includes(t.path));
|
|
13321
13441
|
const wall = ctx.outputs().wall ?? {};
|
|
13322
|
-
const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute7(f.path) ?
|
|
13442
|
+
const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute7(f.path) ? relative6(ctx.repoDir, f.path) : f.path));
|
|
13323
13443
|
const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
|
|
13324
13444
|
const intake = ctx.outputs().intake, relevant2 = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
|
|
13325
13445
|
const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant2]);
|
|
@@ -13417,7 +13537,7 @@ var init_verify = __esm(() => {
|
|
|
13417
13537
|
|
|
13418
13538
|
// ../../loki-ts/src/project_model/conventions.ts
|
|
13419
13539
|
import { existsSync as existsSync34, readdirSync as readdirSync17, readFileSync as readFileSync41 } from "fs";
|
|
13420
|
-
import { dirname as dirname21, join as
|
|
13540
|
+
import { dirname as dirname21, join as join55 } from "path";
|
|
13421
13541
|
function parseJsonc(text2) {
|
|
13422
13542
|
let out2 = "", i = 0;
|
|
13423
13543
|
while (i < text2.length) {
|
|
@@ -13452,7 +13572,7 @@ function moduleOf(file, depth = 0) {
|
|
|
13452
13572
|
const ext = typeof j.extends === "string" ? j.extends : null;
|
|
13453
13573
|
if (!ext || !ext.startsWith("."))
|
|
13454
13574
|
return null;
|
|
13455
|
-
const next =
|
|
13575
|
+
const next = join55(dirname21(file), ext.endsWith(".json") ? ext : `${ext}.json`);
|
|
13456
13576
|
return existsSync34(next) ? moduleOf(next, depth + 1) : null;
|
|
13457
13577
|
}
|
|
13458
13578
|
function readPackageConventions(pkgDir, runner = null) {
|
|
@@ -13464,13 +13584,13 @@ function readPackageConventions(pkgDir, runner = null) {
|
|
|
13464
13584
|
}
|
|
13465
13585
|
let packageType = null, tsModule = null;
|
|
13466
13586
|
for (const n2 of names) {
|
|
13467
|
-
const j = readJson4(
|
|
13587
|
+
const j = readJson4(join55(pkgDir, n2));
|
|
13468
13588
|
if (!j)
|
|
13469
13589
|
continue;
|
|
13470
13590
|
if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
|
|
13471
13591
|
packageType = j.type;
|
|
13472
13592
|
if (tsModule === null && j.compilerOptions !== undefined)
|
|
13473
|
-
tsModule = moduleOf(
|
|
13593
|
+
tsModule = moduleOf(join55(pkgDir, n2));
|
|
13474
13594
|
}
|
|
13475
13595
|
if (packageType === null && tsModule === null)
|
|
13476
13596
|
return null;
|
|
@@ -13504,13 +13624,13 @@ var init_conventions = () => {};
|
|
|
13504
13624
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
13505
13625
|
import { existsSync as existsSync35, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync9, readFileSync as readFileSync42, readdirSync as readdirSync18, realpathSync as realpathSync19, rmSync as rmSync17, writeFileSync as writeFileSync26 } from "fs";
|
|
13506
13626
|
import { tmpdir as tmpdir10 } from "os";
|
|
13507
|
-
import { dirname as dirname22, isAbsolute as isAbsolute8, join as
|
|
13627
|
+
import { dirname as dirname22, isAbsolute as isAbsolute8, join as join56, relative as relative7 } from "path";
|
|
13508
13628
|
function pytestCollectionIsRed(output, repoDir) {
|
|
13509
13629
|
if (/ModuleNotFoundError/.test(output))
|
|
13510
13630
|
return false;
|
|
13511
13631
|
const real2 = (p) => {
|
|
13512
13632
|
try {
|
|
13513
|
-
return realpathSync19(isAbsolute8(p) ? p :
|
|
13633
|
+
return realpathSync19(isAbsolute8(p) ? p : join56(repoDir, p));
|
|
13514
13634
|
} catch {
|
|
13515
13635
|
return null;
|
|
13516
13636
|
}
|
|
@@ -13547,7 +13667,7 @@ function pytestCollectionIsRed(output, repoDir) {
|
|
|
13547
13667
|
}
|
|
13548
13668
|
function moduleUnderRepo(repoDir, name) {
|
|
13549
13669
|
const rel = name.replace(/\./g, "/");
|
|
13550
|
-
return existsSync35(
|
|
13670
|
+
return existsSync35(join56(repoDir, `${rel}.py`)) || existsSync35(join56(repoDir, rel, "__init__.py"));
|
|
13551
13671
|
}
|
|
13552
13672
|
function pytestExit1IsRed(output) {
|
|
13553
13673
|
if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
|
|
@@ -13645,7 +13765,7 @@ ${acceptance.map((a) => `Acceptance: ${a}`).join(`
|
|
|
13645
13765
|
function loadTaskText(ctx, fromPrior) {
|
|
13646
13766
|
if (fromPrior)
|
|
13647
13767
|
return fromPrior;
|
|
13648
|
-
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ??
|
|
13768
|
+
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join56(ctx.runDir, "issue.json");
|
|
13649
13769
|
if (existsSync35(issueJsonPath)) {
|
|
13650
13770
|
try {
|
|
13651
13771
|
const issue = JSON.parse(readFileSync42(issueJsonPath, "utf8"));
|
|
@@ -13660,7 +13780,7 @@ function loadTaskText(ctx, fromPrior) {
|
|
|
13660
13780
|
}
|
|
13661
13781
|
function wallTargetDir(repoDir, existingTests) {
|
|
13662
13782
|
const first = existingTests[0];
|
|
13663
|
-
return first ?
|
|
13783
|
+
return first ? join56(repoDir, dirname22(first.path)) : join56(repoDir, "tests");
|
|
13664
13784
|
}
|
|
13665
13785
|
function guessRunner(fileName, runners) {
|
|
13666
13786
|
if (fileName.endsWith(".py"))
|
|
@@ -13690,12 +13810,12 @@ async function wallAuthor(ctx, signal) {
|
|
|
13690
13810
|
return done({ status: "skipped", data: { size: sz.size, files: [], no_runner: true }, reason: "no runnable test command detected: the Wall cannot write a runnable check" });
|
|
13691
13811
|
const tree = prior.intake?.tree;
|
|
13692
13812
|
const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
|
|
13693
|
-
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${
|
|
13694
|
-
const conv2 = readPackageConventions(
|
|
13695
|
-
const cwd = mkdtempSync9(
|
|
13813
|
+
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative7(ctx.repoDir, targetDir)}/x`);
|
|
13814
|
+
const conv2 = readPackageConventions(join56(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
|
|
13815
|
+
const cwd = mkdtempSync9(join56(tmpdir10(), "loki-e15-wall-"));
|
|
13696
13816
|
const wm = wallManifestFor(ctx.repoDir, tree, task);
|
|
13697
13817
|
for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
|
|
13698
|
-
writeFileSync26(
|
|
13818
|
+
writeFileSync26(join56(cwd, n2), c, "utf8");
|
|
13699
13819
|
const session = await ctx.sessions.run({
|
|
13700
13820
|
stage: "wall",
|
|
13701
13821
|
brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2), unitSpec()?.acceptance ?? []),
|
|
@@ -13710,15 +13830,15 @@ async function wallAuthor(ctx, signal) {
|
|
|
13710
13830
|
rmSync17(cwd, { recursive: true, force: true });
|
|
13711
13831
|
return done({ status: "failed", data: {}, reason: "wall session aborted, killed, or timed out", killed: true });
|
|
13712
13832
|
}
|
|
13713
|
-
const all = readdirSync18(cwd).filter((f) => f.startsWith(WALL_PREFIX)), held = stashHoldout({ runId: ctx.runId, repoDir: ctx.repoDir, srcDir: cwd, targetDir, names: all.filter((n2) => !conventionViolation(conv2, n2, readFileSync42(
|
|
13714
|
-
const sealedDir =
|
|
13833
|
+
const all = readdirSync18(cwd).filter((f) => f.startsWith(WALL_PREFIX)), held = stashHoldout({ runId: ctx.runId, repoDir: ctx.repoDir, srcDir: cwd, targetDir, names: all.filter((n2) => !conventionViolation(conv2, n2, readFileSync42(join56(cwd, n2), "utf8"))), runnerOf: (n2) => guessRunner(n2, runners) }), generated = all.filter((n2) => !held?.names.has(n2));
|
|
13834
|
+
const sealedDir = join56(ctx.runDir, "wall");
|
|
13715
13835
|
if (generated.length > 0)
|
|
13716
13836
|
mkdirSync23(sealedDir, { recursive: true });
|
|
13717
13837
|
const contents = new Map;
|
|
13718
13838
|
const discarded = [];
|
|
13719
13839
|
for (const name of generated) {
|
|
13720
|
-
const content = readFileSync42(
|
|
13721
|
-
writeFileSync26(
|
|
13840
|
+
const content = readFileSync42(join56(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
|
|
13841
|
+
writeFileSync26(join56(sealedDir, name), content, "utf8");
|
|
13722
13842
|
if (bad)
|
|
13723
13843
|
discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
|
|
13724
13844
|
else
|
|
@@ -13738,18 +13858,18 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
13738
13858
|
const content = contents.get(name);
|
|
13739
13859
|
if (content === undefined)
|
|
13740
13860
|
continue;
|
|
13741
|
-
const dest =
|
|
13861
|
+
const dest = join56(targetDir, name), runner = guessRunner(name, runners);
|
|
13742
13862
|
writeFileSync26(dest, content, "utf8");
|
|
13743
13863
|
sealedFiles.push({ path: dest, sha256: sha2562(content) });
|
|
13744
13864
|
readOnlyFiles.push({ path: dest, content });
|
|
13745
13865
|
if (runner)
|
|
13746
|
-
wallTests.push({ runner, path:
|
|
13866
|
+
wallTests.push({ runner, path: relative7(ctx.repoDir, dest) });
|
|
13747
13867
|
}
|
|
13748
13868
|
ctx.wallSealed = true;
|
|
13749
13869
|
ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
|
|
13750
13870
|
const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
|
|
13751
13871
|
for (const t of wallTests) {
|
|
13752
|
-
const r = baseRunner.run(baseDir, [t]), abs =
|
|
13872
|
+
const r = baseRunner.run(baseDir, [t]), abs = join56(ctx.repoDir, t.path);
|
|
13753
13873
|
baseRun.pass += r.pass;
|
|
13754
13874
|
baseRun.fail += r.fail;
|
|
13755
13875
|
baseRun.not_run += r.not_run ?? 0;
|
|
@@ -13804,14 +13924,14 @@ var init_wall = __esm(() => {
|
|
|
13804
13924
|
|
|
13805
13925
|
// ../../loki-ts/src/e10ext/discard.ts
|
|
13806
13926
|
import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as lstatSync12, mkdirSync as mkdirSync24, openSync as openSync9, readFileSync as readFileSync43, realpathSync as realpathSync20, rmdirSync, unlinkSync as unlinkSync6, writeFileSync as writeFileSync27 } from "fs";
|
|
13807
|
-
import { dirname as dirname23, join as
|
|
13927
|
+
import { dirname as dirname23, join as join57, relative as relative8, sep as sep11 } from "path";
|
|
13808
13928
|
function safeRestore(repoDir, f, want, mode) {
|
|
13809
|
-
const root = realpathSync20(repoDir), fp =
|
|
13929
|
+
const root = realpathSync20(repoDir), fp = join57(root, f), rel = relative8(root, dirname23(fp));
|
|
13810
13930
|
if (rel.startsWith(".."))
|
|
13811
13931
|
throw new Error("outside repo");
|
|
13812
13932
|
let cur = root;
|
|
13813
|
-
for (const part of rel === "" ? [] : rel.split(
|
|
13814
|
-
cur =
|
|
13933
|
+
for (const part of rel === "" ? [] : rel.split(sep11)) {
|
|
13934
|
+
cur = join57(cur, part);
|
|
13815
13935
|
let st2;
|
|
13816
13936
|
try {
|
|
13817
13937
|
st2 = lstatSync12(cur);
|
|
@@ -13866,7 +13986,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
13866
13986
|
return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
|
|
13867
13987
|
const notProven = [];
|
|
13868
13988
|
for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
|
|
13869
|
-
const fp =
|
|
13989
|
+
const fp = join57(repoDir, f);
|
|
13870
13990
|
try {
|
|
13871
13991
|
if (v.startsWith("!")) {
|
|
13872
13992
|
const st = lstatSync12(fp);
|
|
@@ -13885,7 +14005,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
13885
14005
|
try {
|
|
13886
14006
|
let m = 420;
|
|
13887
14007
|
try {
|
|
13888
|
-
const l = lstatSync12(
|
|
14008
|
+
const l = lstatSync12(join57(repoDir, f));
|
|
13889
14009
|
if (l.isFile())
|
|
13890
14010
|
m = l.mode & 511;
|
|
13891
14011
|
} catch {}
|
|
@@ -13961,9 +14081,9 @@ var init_scope2 = __esm(() => {
|
|
|
13961
14081
|
// ../../loki-ts/src/council/role_agents.ts
|
|
13962
14082
|
import { existsSync as existsSync36, readdirSync as readdirSync19, readFileSync as readFileSync44 } from "fs";
|
|
13963
14083
|
import { homedir as homedir9 } from "os";
|
|
13964
|
-
import { join as
|
|
14084
|
+
import { join as join58 } from "path";
|
|
13965
14085
|
function agentDirs(repoDir, env = process.env) {
|
|
13966
|
-
return [env["LOKI_AGENTS_PROJECT_DIR"] ||
|
|
14086
|
+
return [env["LOKI_AGENTS_PROJECT_DIR"] || join58(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join58(env["XDG_CONFIG_HOME"] || join58(homedir9(), ".config"), "loki", "agents")];
|
|
13967
14087
|
}
|
|
13968
14088
|
function parseAgent(file, stem2) {
|
|
13969
14089
|
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync44(file, "utf8"));
|
|
@@ -13991,7 +14111,7 @@ function loadRoleAgent(repoDir, role, env = process.env) {
|
|
|
13991
14111
|
const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
|
|
13992
14112
|
for (const n2 of ordered) {
|
|
13993
14113
|
try {
|
|
13994
|
-
const a = parseAgent(
|
|
14114
|
+
const a = parseAgent(join58(d, n2), n2.slice(0, -3));
|
|
13995
14115
|
if (a && a.role === role)
|
|
13996
14116
|
return a;
|
|
13997
14117
|
} catch {}
|
|
@@ -14009,10 +14129,10 @@ var init_role_agents = __esm(() => {
|
|
|
14009
14129
|
|
|
14010
14130
|
// ../../loki-ts/src/util/run_summary.ts
|
|
14011
14131
|
import { existsSync as existsSync37, mkdirSync as mkdirSync25, readFileSync as readFileSync45, renameSync as renameSync11, statSync as statSync18, writeFileSync as writeFileSync28 } from "fs";
|
|
14012
|
-
import { join as
|
|
14132
|
+
import { join as join59 } from "path";
|
|
14013
14133
|
function readRiskRecord(repoDir, sinceMs = 0) {
|
|
14014
14134
|
try {
|
|
14015
|
-
const p =
|
|
14135
|
+
const p = join59(repoDir, ".loki", "state", "risk-tier.json");
|
|
14016
14136
|
if (statSync18(p).mtimeMs < sinceMs)
|
|
14017
14137
|
return null;
|
|
14018
14138
|
const r = JSON.parse(readFileSync45(p, "utf8"));
|
|
@@ -14030,7 +14150,7 @@ var init_run_summary = __esm(() => {
|
|
|
14030
14150
|
|
|
14031
14151
|
// ../../loki-ts/src/engine10/stages/xreview.ts
|
|
14032
14152
|
import { existsSync as existsSync38, readFileSync as readFileSync46 } from "fs";
|
|
14033
|
-
import { join as
|
|
14153
|
+
import { join as join60 } from "path";
|
|
14034
14154
|
function minVerdict(verdict, review) {
|
|
14035
14155
|
const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
|
|
14036
14156
|
return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
|
|
@@ -14043,7 +14163,7 @@ function explicitReview(repoDir, env) {
|
|
|
14043
14163
|
if (flag && isOff(ev))
|
|
14044
14164
|
return "off";
|
|
14045
14165
|
for (const f of ["loki.yaml", "loki.yml"]) {
|
|
14046
|
-
const p =
|
|
14166
|
+
const p = join60(repoDir, f);
|
|
14047
14167
|
if (!existsSync38(p))
|
|
14048
14168
|
continue;
|
|
14049
14169
|
try {
|
|
@@ -14212,7 +14332,7 @@ See also: loki cost --detail (what a run ALREADY spent)
|
|
|
14212
14332
|
|
|
14213
14333
|
// ../../loki-ts/src/features/contract.ts
|
|
14214
14334
|
import { existsSync as existsSync39, lstatSync as lstatSync13, mkdirSync as mkdirSync26, readFileSync as readFileSync47, rmSync as rmSync18, writeFileSync as writeFileSync29 } from "fs";
|
|
14215
|
-
import { dirname as dirname26, join as
|
|
14335
|
+
import { dirname as dirname26, join as join61 } from "path";
|
|
14216
14336
|
import { createHash as createHash16 } from "crypto";
|
|
14217
14337
|
function contractEnabled(env = process.env) {
|
|
14218
14338
|
return env["LOKI_CONTRACT"] !== "0";
|
|
@@ -14244,7 +14364,7 @@ function untracedLines(trace) {
|
|
|
14244
14364
|
return trace.criteria.filter((c) => c.status === "no_match").map((c) => `contract ${sanitizeCriterion(c.id)} untraced (no keyword match in changed files): ${sanitizeCriterion(c.text)}`);
|
|
14245
14365
|
}
|
|
14246
14366
|
function contractPath(repoDir) {
|
|
14247
|
-
return
|
|
14367
|
+
return join61(repoDir, ".loki", "contract.json");
|
|
14248
14368
|
}
|
|
14249
14369
|
function readContract(repoDir) {
|
|
14250
14370
|
const p = contractPath(repoDir);
|
|
@@ -14329,16 +14449,16 @@ var init_contract = __esm(() => {
|
|
|
14329
14449
|
init_safe_git();
|
|
14330
14450
|
STOP2 = new Set(["the", "and", "for", "with", "that", "this", "must", "should", "shall", "when", "then", "are", "was", "all", "any", "can", "not", "has", "have", "from", "into", "each", "user", "users"]);
|
|
14331
14451
|
MAX_CONTRACT_BYTES = 1024 * 1024;
|
|
14332
|
-
REQ_MAP_REL =
|
|
14452
|
+
REQ_MAP_REL = join61(".loki", "state", "requirements-map.json");
|
|
14333
14453
|
REQ_STOP = new Set(["with", "that", "this", "from", "have", "will", "should", "must", "when", "then", "into", "each", "every", "user", "users", "page", "able", "allow", "support", "ensure", "using", "their", "there", "which", "shall"]);
|
|
14334
14454
|
});
|
|
14335
14455
|
|
|
14336
14456
|
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
14337
14457
|
import { createHash as createHash17 } from "crypto";
|
|
14338
14458
|
import { existsSync as existsSync40, mkdirSync as mkdirSync27, readdirSync as readdirSync20, readFileSync as readFileSync48, renameSync as renameSync12, statSync as statSync19, writeFileSync as writeFileSync30 } from "fs";
|
|
14339
|
-
import { dirname as dirname27, join as
|
|
14459
|
+
import { dirname as dirname27, join as join62 } from "path";
|
|
14340
14460
|
function sealGroup(runDir, rh) {
|
|
14341
|
-
const manifestPath =
|
|
14461
|
+
const manifestPath = join62(runDir, "group", "manifest.json");
|
|
14342
14462
|
if (!existsSync40(manifestPath))
|
|
14343
14463
|
return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
|
|
14344
14464
|
const notProven = [];
|
|
@@ -14363,7 +14483,7 @@ function sealGroup(runDir, rh) {
|
|
|
14363
14483
|
return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
|
|
14364
14484
|
seen.add(id);
|
|
14365
14485
|
seenLower.add(id.toLowerCase());
|
|
14366
|
-
const dir =
|
|
14486
|
+
const dir = join62(unitsDir(runDir), id), rp = join62(dir, "receipt.json"), ep = join62(dir, "events.jsonl");
|
|
14367
14487
|
let bytes;
|
|
14368
14488
|
try {
|
|
14369
14489
|
bytes = readFileSync48(rp);
|
|
@@ -14408,7 +14528,7 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14408
14528
|
const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
|
|
14409
14529
|
const g = receipt["group"];
|
|
14410
14530
|
if (g === undefined)
|
|
14411
|
-
return existsSync40(
|
|
14531
|
+
return existsSync40(join62(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
|
|
14412
14532
|
if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
|
|
14413
14533
|
return bad("group section malformed");
|
|
14414
14534
|
const entries = g["units"];
|
|
@@ -14420,7 +14540,7 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
14420
14540
|
return bad("unit directories do not match the receipt (missing or extra unit)");
|
|
14421
14541
|
let unchecked = null;
|
|
14422
14542
|
for (let i = 0;i < entries.length; i++) {
|
|
14423
|
-
const e = entries[i], id = ids[i], dir =
|
|
14543
|
+
const e = entries[i], id = ids[i], dir = join62(unitsDir(runDir), id), rp = join62(dir, "receipt.json"), ep = join62(dir, "events.jsonl");
|
|
14424
14544
|
if (e["index"] !== i)
|
|
14425
14545
|
return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
|
|
14426
14546
|
let bytes;
|
|
@@ -14456,7 +14576,7 @@ function compositeVerdict(childVerdicts) {
|
|
|
14456
14576
|
const failed2 = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
|
|
14457
14577
|
return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed2, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
|
|
14458
14578
|
}
|
|
14459
|
-
var ID_RE, PASSING, sha3 = (b) => createHash17("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) =>
|
|
14579
|
+
var ID_RE, PASSING, sha3 = (b) => createHash17("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) => join62(runDir, "group", "units"), readJson5 = (p) => {
|
|
14460
14580
|
try {
|
|
14461
14581
|
return JSON.parse(readFileSync48(p, "utf8"));
|
|
14462
14582
|
} catch {
|
|
@@ -14477,7 +14597,7 @@ var init_seal_group = __esm(() => {
|
|
|
14477
14597
|
|
|
14478
14598
|
// ../../loki-ts/src/supply/supply_guard.ts
|
|
14479
14599
|
import { existsSync as existsSync41, readFileSync as readFileSync49, statSync as statSync20 } from "fs";
|
|
14480
|
-
import { basename as basename21, join as
|
|
14600
|
+
import { basename as basename21, join as join63 } from "path";
|
|
14481
14601
|
function supplyEnabled(env) {
|
|
14482
14602
|
return env["LOKI_SUPPLY_GUARD"] !== "0";
|
|
14483
14603
|
}
|
|
@@ -14492,7 +14612,7 @@ function isManifestPath(path) {
|
|
|
14492
14612
|
return MANIFESTS.test(basename21(path));
|
|
14493
14613
|
}
|
|
14494
14614
|
function readDeclared(repoDir) {
|
|
14495
|
-
const p =
|
|
14615
|
+
const p = join63(repoDir, ".loki", DECLARED_FILE);
|
|
14496
14616
|
if (!existsSync41(p))
|
|
14497
14617
|
return { deps: [], problem: null };
|
|
14498
14618
|
try {
|
|
@@ -14518,7 +14638,7 @@ function readDeclared(repoDir) {
|
|
|
14518
14638
|
}
|
|
14519
14639
|
}
|
|
14520
14640
|
function readAllowlist(repoDir) {
|
|
14521
|
-
const p =
|
|
14641
|
+
const p = join63(repoDir, ".loki", "supply-allowlist");
|
|
14522
14642
|
if (!existsSync41(p))
|
|
14523
14643
|
return new Set;
|
|
14524
14644
|
try {
|
|
@@ -14563,7 +14683,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
14563
14683
|
if (eco === "npm") {
|
|
14564
14684
|
if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
|
|
14565
14685
|
return true;
|
|
14566
|
-
return files(
|
|
14686
|
+
return files(join63(repoDir, ".npmrc"), home ? join63(home, ".npmrc") : "").some((t) => t.split(`
|
|
14567
14687
|
`).some((l) => {
|
|
14568
14688
|
const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
|
|
14569
14689
|
return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
|
|
@@ -14572,7 +14692,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
14572
14692
|
if (eco === "pypi") {
|
|
14573
14693
|
if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
|
|
14574
14694
|
return true;
|
|
14575
|
-
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ?
|
|
14695
|
+
const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join63(home, ".config", "pip", "pip.conf") : "", home ? join63(home, ".pip", "pip.conf") : "", join63(repoDir, "pip.conf")];
|
|
14576
14696
|
return files(...cfg).some((t) => t.split(`
|
|
14577
14697
|
`).some((l) => {
|
|
14578
14698
|
const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
|
|
@@ -14582,7 +14702,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
|
|
|
14582
14702
|
if (eco === "cargo") {
|
|
14583
14703
|
if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
|
|
14584
14704
|
return true;
|
|
14585
|
-
return files(
|
|
14705
|
+
return files(join63(repoDir, ".cargo", "config.toml"), join63(repoDir, ".cargo", "config"), home ? join63(home, ".cargo", "config.toml") : "", home ? join63(home, ".cargo", "config") : "").some((t) => /^\s*\[(registries\.|source\.)/m.test(t) || /replace-with\s*=/.test(t));
|
|
14586
14706
|
}
|
|
14587
14707
|
if (eco === "go") {
|
|
14588
14708
|
const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
|
|
@@ -14722,7 +14842,7 @@ var init_supply_guard = __esm(() => {
|
|
|
14722
14842
|
// ../../loki-ts/src/engine10/stages/seal.ts
|
|
14723
14843
|
import { createHash as createHash18 } from "crypto";
|
|
14724
14844
|
import { existsSync as existsSync42, readdirSync as readdirSync21, mkdirSync as mkdirSync28, readFileSync as readFileSync50, writeFileSync as writeFileSync31 } from "fs";
|
|
14725
|
-
import { basename as basename22, isAbsolute as isAbsolute9, join as
|
|
14845
|
+
import { basename as basename22, isAbsolute as isAbsolute9, join as join64, relative as relative9 } from "path";
|
|
14726
14846
|
function sanitizeReason(s) {
|
|
14727
14847
|
const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
|
|
14728
14848
|
const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
|
|
@@ -14797,7 +14917,7 @@ function renderReceiptMd(r) {
|
|
|
14797
14917
|
`);
|
|
14798
14918
|
}
|
|
14799
14919
|
var DEEP_NOT_PROVEN, SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)", EXCLUDE_LOKI = ":(exclude).loki", sha2562 = (s) => createHash18("sha256").update(s).digest("hex"), str3 = (v) => typeof v === "string" && v !== "" ? v : null, strs2 = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string" && x !== "") : [], receiptRel = (ctx) => {
|
|
14800
|
-
const r =
|
|
14920
|
+
const r = relative9(ctx.repoDir, join64(ctx.runDir, "receipt.json"));
|
|
14801
14921
|
return r.startsWith("..") || isAbsolute9(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
|
|
14802
14922
|
}, commitStage, sealStage;
|
|
14803
14923
|
var init_seal = __esm(() => {
|
|
@@ -14906,7 +15026,7 @@ var init_seal = __esm(() => {
|
|
|
14906
15026
|
if (wallNotRun > 0) {
|
|
14907
15027
|
try {
|
|
14908
15028
|
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename22(String(f.path))));
|
|
14909
|
-
for (const n2 of readdirSync21(
|
|
15029
|
+
for (const n2 of readdirSync21(join64(ctx.runDir, "wall")).sort())
|
|
14910
15030
|
if (!kept.has(n2))
|
|
14911
15031
|
notProven.add(`wall test discarded: ${n2} (not_run)`);
|
|
14912
15032
|
} catch {}
|
|
@@ -14969,19 +15089,19 @@ var init_seal = __esm(() => {
|
|
|
14969
15089
|
for (const [s, d] of Object.entries(o))
|
|
14970
15090
|
if (typeof d?.duration_s === "number")
|
|
14971
15091
|
stages[s] = d.duration_s;
|
|
14972
|
-
const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(
|
|
15092
|
+
const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(join64(ctx.runDir, "events.jsonl"))) : { wall_s: Object.values(stages).reduce((a, b) => a + (b ?? 0), 0), stages }, totalS = T?.reconciled(time) ?? null;
|
|
14973
15093
|
const iterIds = Object.values(o).flatMap((d) => [...strs2(d?.iteration_ids), ...strs2([d?.iteration_id])]);
|
|
14974
15094
|
if (iterIds.length === 0)
|
|
14975
15095
|
notProven.add("cost not measured (no iteration ids recorded)");
|
|
14976
15096
|
const cost = ctx.cost.read(ctx.repoDir, iterIds);
|
|
14977
15097
|
if (cost.unmetered)
|
|
14978
15098
|
notProven.add("cost unmetered (CLI invoker; recorded as 0)");
|
|
14979
|
-
const eventsPath =
|
|
15099
|
+
const eventsPath = join64(ctx.runDir, "events.jsonl");
|
|
14980
15100
|
const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
|
|
14981
15101
|
const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
|
|
14982
15102
|
if (wallFiles.length > 0 && wallPassed === null)
|
|
14983
15103
|
notProven.add("wall result not recorded by verify");
|
|
14984
|
-
const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route ?? o.plan?.route_record ?? (routerEnabled(process.env) ? loadRouteRecord(ctx.runDir) : undefined), cost.router ?? (routerEnabled(process.env) ? sumResultCosts(
|
|
15104
|
+
const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route ?? o.plan?.route_record ?? (routerEnabled(process.env) ? loadRouteRecord(ctx.runDir) : undefined), cost.router ?? (routerEnabled(process.env) ? sumResultCosts(join64(ctx.repoDir, ".loki"), liveArchivedCosts(join64(ctx.repoDir, ".loki"), iterIds, UNMETERED)).router : undefined), ctx.model);
|
|
14985
15105
|
if (routeBlock)
|
|
14986
15106
|
for (const l of routeNotProven(routeBlock))
|
|
14987
15107
|
notProven.add(l);
|
|
@@ -15045,11 +15165,17 @@ var init_seal = __esm(() => {
|
|
|
15045
15165
|
}
|
|
15046
15166
|
const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
15047
15167
|
mkdirSync28(ctx.runDir, { recursive: true });
|
|
15048
|
-
const path =
|
|
15168
|
+
const path = join64(ctx.runDir, "receipt.json");
|
|
15049
15169
|
writeFileSync31(path, JSON.stringify(receipt, null, 2) + `
|
|
15050
15170
|
`);
|
|
15051
|
-
writeFileSync31(
|
|
15171
|
+
writeFileSync31(join64(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
|
|
15052
15172
|
recordRun(process.env, ctx.repoDir, ranModel(o.implement, ctx.model, o.fix), verdict, cost.usd, cost.unmetered === true, totalS);
|
|
15173
|
+
try {
|
|
15174
|
+
hooks.sealed?.(ctx.runDir, JSON.parse(JSON.stringify(receipt), (_k, v) => v && typeof v === "object" ? Object.freeze(v) : v));
|
|
15175
|
+
} catch (e) {
|
|
15176
|
+
process.stderr.write(`ai-bom skipped: ${e.message}
|
|
15177
|
+
`);
|
|
15178
|
+
}
|
|
15053
15179
|
const signed = sig.jwt !== null;
|
|
15054
15180
|
const data = { receipt_path: path, receipt_sha256: hash, signed, kid: sig.kid, verdict, not_proven: receipt.not_proven, ...mp ? { mutation_line: mp.line } : {}, ...routeBlock ? { route_line: routePrLine(routeBlock) } : {} };
|
|
15055
15181
|
try {
|
|
@@ -15155,13 +15281,13 @@ var init_receipt_dsse = () => {};
|
|
|
15155
15281
|
|
|
15156
15282
|
// ../../loki-ts/src/util/composite_seal.ts
|
|
15157
15283
|
import { existsSync as existsSync43, readFileSync as readFileSync52 } from "fs";
|
|
15158
|
-
import { basename as basename23, dirname as dirname29, join as
|
|
15284
|
+
import { basename as basename23, dirname as dirname29, join as join65 } from "path";
|
|
15159
15285
|
function logProblem(runDir, integ) {
|
|
15160
15286
|
if (typeof integ["log_sha256"] !== "string")
|
|
15161
15287
|
return null;
|
|
15162
15288
|
let b;
|
|
15163
15289
|
try {
|
|
15164
|
-
b = readFileSync52(
|
|
15290
|
+
b = readFileSync52(join65(runDir, "integration.log"));
|
|
15165
15291
|
} catch {
|
|
15166
15292
|
return "integration.log is missing but integration.json records its hash";
|
|
15167
15293
|
}
|
|
@@ -15184,13 +15310,13 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15184
15310
|
return bad("body malformed");
|
|
15185
15311
|
let ibytes;
|
|
15186
15312
|
try {
|
|
15187
|
-
ibytes = readFileSync52(
|
|
15313
|
+
ibytes = readFileSync52(join65(runDir, "integration.json"));
|
|
15188
15314
|
} catch {
|
|
15189
15315
|
return bad("integration.json missing");
|
|
15190
15316
|
}
|
|
15191
15317
|
if (sha3(ibytes) !== receipt["integration_sha256"])
|
|
15192
15318
|
return bad("integration.json does not match its recorded hash");
|
|
15193
|
-
const integ = readJson5(
|
|
15319
|
+
const integ = readJson5(join65(runDir, "integration.json"));
|
|
15194
15320
|
if (!isObj10(integ) || !isObj10(integ["outcomes"]))
|
|
15195
15321
|
return bad("integration.json has no outcomes");
|
|
15196
15322
|
const iprob = integrationProblem(integ);
|
|
@@ -15220,7 +15346,7 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
15220
15346
|
return bad(`child ${text2(repo, 80) || "?"} has an invalid receipt path`);
|
|
15221
15347
|
if (outcomes[repo] !== "ok")
|
|
15222
15348
|
return bad(`child ${text2(repo, 80)} did not finish ok in integration.json`);
|
|
15223
|
-
const rp =
|
|
15349
|
+
const rp = join65(runDir, rel);
|
|
15224
15350
|
let bytes;
|
|
15225
15351
|
try {
|
|
15226
15352
|
bytes = readFileSync52(rp);
|
|
@@ -15273,7 +15399,7 @@ var init_keys_cmd = __esm(() => {
|
|
|
15273
15399
|
|
|
15274
15400
|
// ../../loki-ts/src/engine10/verify_cmd.ts
|
|
15275
15401
|
import { existsSync as existsSync44, readFileSync as readFileSync53, renameSync as renameSync13, statSync as statSync22, writeFileSync as writeFileSync32 } from "fs";
|
|
15276
|
-
import { basename as basename24, dirname as dirname30, join as
|
|
15402
|
+
import { basename as basename24, dirname as dirname30, join as join66 } from "path";
|
|
15277
15403
|
import { createHash as createHash19, createPublicKey as createPublicKey4, verify as verify4 } from "crypto";
|
|
15278
15404
|
function pubFor(kid, given) {
|
|
15279
15405
|
if (given)
|
|
@@ -15325,7 +15451,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15325
15451
|
const claims = st !== null && typeof st === "object" && Object.keys(st).length > 0;
|
|
15326
15452
|
return claims ? "the receipt records stages but binds the empty-log hash, so no events.jsonl can back it (missing, empty or non-empty); the receipt is forged or was sealed without a log. Re-run the task to produce a fresh receipt" : null;
|
|
15327
15453
|
}
|
|
15328
|
-
const path =
|
|
15454
|
+
const path = join66(dirname30(receiptPath), "events.jsonl");
|
|
15329
15455
|
if (!existsSync44(path))
|
|
15330
15456
|
return "events.jsonl is missing";
|
|
15331
15457
|
const raw2 = readFileSync53(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
|
|
@@ -15344,7 +15470,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
15344
15470
|
return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
|
|
15345
15471
|
}
|
|
15346
15472
|
function checkLogSeal(receiptPath, hash, kid, given) {
|
|
15347
|
-
const path =
|
|
15473
|
+
const path = join66(dirname30(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
|
|
15348
15474
|
if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
|
|
15349
15475
|
return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
|
|
15350
15476
|
if (done < 0)
|
|
@@ -15455,7 +15581,7 @@ var init_verify_cmd = __esm(() => {
|
|
|
15455
15581
|
|
|
15456
15582
|
// src/server/app.ts
|
|
15457
15583
|
import { existsSync as existsSync46, readFileSync as readFileSync56, statSync as statSync23 } from "fs";
|
|
15458
|
-
import { join as
|
|
15584
|
+
import { join as join69, resolve as resolve15, sep as sep13 } from "path";
|
|
15459
15585
|
|
|
15460
15586
|
// node_modules/hono/dist/request/constants.js
|
|
15461
15587
|
var GET_MATCH_RESULT = Symbol();
|
|
@@ -21219,9 +21345,9 @@ function writeAnswer(dir, source, run, answer) {
|
|
|
21219
21345
|
}
|
|
21220
21346
|
|
|
21221
21347
|
// src/server/diffstat.ts
|
|
21222
|
-
|
|
21348
|
+
init_safe_git();
|
|
21223
21349
|
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readSync as readSync2, realpathSync as realpathSync2 } from "fs";
|
|
21224
|
-
import { join as
|
|
21350
|
+
import { join as join5, sep as sep2 } from "path";
|
|
21225
21351
|
var ID2 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
21226
21352
|
var SHA = /^[0-9a-f]{40,64}$/;
|
|
21227
21353
|
var MAX_RECEIPT_BYTES = 1024 * 1024;
|
|
@@ -21245,7 +21371,7 @@ function parseNumstat(out) {
|
|
|
21245
21371
|
function readReceipt(runDir) {
|
|
21246
21372
|
let fd;
|
|
21247
21373
|
try {
|
|
21248
|
-
fd = openSync2(
|
|
21374
|
+
fd = openSync2(join5(runDir, "receipt.json"), "r");
|
|
21249
21375
|
} catch {
|
|
21250
21376
|
return null;
|
|
21251
21377
|
}
|
|
@@ -21276,12 +21402,12 @@ function diffStatFor(db, source, run) {
|
|
|
21276
21402
|
let repoReal, runsRoot, runDir;
|
|
21277
21403
|
try {
|
|
21278
21404
|
repoReal = realpathSync2(repo.p);
|
|
21279
|
-
runsRoot = realpathSync2(
|
|
21280
|
-
runDir = realpathSync2(
|
|
21405
|
+
runsRoot = realpathSync2(join5(repoReal, ".loki", "runs"));
|
|
21406
|
+
runDir = realpathSync2(join5(runsRoot, run));
|
|
21281
21407
|
} catch {
|
|
21282
21408
|
return null;
|
|
21283
21409
|
}
|
|
21284
|
-
if (runDir !==
|
|
21410
|
+
if (runDir !== join5(runsRoot, run) || !runDir.startsWith(runsRoot + sep2))
|
|
21285
21411
|
return null;
|
|
21286
21412
|
const r = readReceipt(runDir);
|
|
21287
21413
|
const base = typeof r?.base_sha === "string" ? r.base_sha : "", head = typeof r?.head_sha === "string" ? r.head_sha : "";
|
|
@@ -21293,7 +21419,7 @@ function diffStatFor(db, source, run) {
|
|
|
21293
21419
|
return null;
|
|
21294
21420
|
try {
|
|
21295
21421
|
diffStatGitRuns.n++;
|
|
21296
|
-
const out =
|
|
21422
|
+
const out = safeGit(repoReal, ["-c", "core.quotePath=false", "diff", "--numstat", "--no-renames", `${base}..${head}`, "--"], { env: gitEnv(), timeout: GIT_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024 });
|
|
21297
21423
|
const files = parseNumstat(out);
|
|
21298
21424
|
const stat = { base, head, files, added: files.reduce((n2, f) => n2 + (f.added ?? 0), 0), removed: files.reduce((n2, f) => n2 + (f.removed ?? 0), 0), source: "git" };
|
|
21299
21425
|
cache.set(key, stat);
|
|
@@ -21308,7 +21434,7 @@ function diffStatFor(db, source, run) {
|
|
|
21308
21434
|
import { createHash, createPublicKey, verify } from "crypto";
|
|
21309
21435
|
import { readFileSync as readFileSync2 } from "fs";
|
|
21310
21436
|
import { homedir as homedir3 } from "os";
|
|
21311
|
-
import { join as
|
|
21437
|
+
import { join as join6 } from "path";
|
|
21312
21438
|
var SHA2 = /^[0-9a-f]{64}$/;
|
|
21313
21439
|
var SEAL_LINE = "log.sealed";
|
|
21314
21440
|
var REDACTED = /\[REDACTED(?::[A-Z_]+)?\]/;
|
|
@@ -21326,7 +21452,7 @@ function localKeyInfo(env = process.env) {
|
|
|
21326
21452
|
if (inline)
|
|
21327
21453
|
pub = createPublicKey(inline);
|
|
21328
21454
|
else {
|
|
21329
|
-
const file = given ||
|
|
21455
|
+
const file = given || join6(env["HOME"] || homedir3(), ".loki", "keys", "receipt-ed25519.pem");
|
|
21330
21456
|
try {
|
|
21331
21457
|
pub = createPublicKey(readFileSync2(file));
|
|
21332
21458
|
} catch (e) {
|
|
@@ -21820,7 +21946,7 @@ init_backfill();
|
|
|
21820
21946
|
|
|
21821
21947
|
// src/server/reconcile.ts
|
|
21822
21948
|
import { realpathSync as realpathSync4 } from "fs";
|
|
21823
|
-
import { join as
|
|
21949
|
+
import { join as join10, resolve, sep as sep3 } from "path";
|
|
21824
21950
|
init_run_pid();
|
|
21825
21951
|
var STOPPED_VERDICT = "STOPPED";
|
|
21826
21952
|
var STALE_GRACE_MS = 120000;
|
|
@@ -21840,7 +21966,7 @@ function reconcileDeadRuns(db, o = {}) {
|
|
|
21840
21966
|
} catch {
|
|
21841
21967
|
continue;
|
|
21842
21968
|
}
|
|
21843
|
-
const root =
|
|
21969
|
+
const root = join10(repo, ".loki", "runs"), dir = resolve(root, r.runId);
|
|
21844
21970
|
if (!dir.startsWith(root + sep3))
|
|
21845
21971
|
continue;
|
|
21846
21972
|
if (verify2(dir, r.runId).ok)
|
|
@@ -21907,7 +22033,7 @@ function mountRepos(act, db, peerIsLoopback2, repoDir, gh = defaultGh) {
|
|
|
21907
22033
|
|
|
21908
22034
|
// src/server/routes/artifacts.ts
|
|
21909
22035
|
import { closeSync as closeSync3, fstatSync as fstatSync3, openSync as openSync3, readSync as readSync3, realpathSync as realpathSync6 } from "fs";
|
|
21910
|
-
import { join as
|
|
22036
|
+
import { join as join13, sep as sep4 } from "path";
|
|
21911
22037
|
var MAX_ARTIFACT_BYTES = 5 * 1024 * 1024;
|
|
21912
22038
|
var EVENTS_DEFAULT = 500;
|
|
21913
22039
|
var EVENTS_MAX = 1000;
|
|
@@ -21988,15 +22114,15 @@ function mount(ctx) {
|
|
|
21988
22114
|
return c.json({ error: "artifact not available" }, 404);
|
|
21989
22115
|
let runsRoot, runDir, file;
|
|
21990
22116
|
try {
|
|
21991
|
-
runsRoot = realpathSync6(
|
|
21992
|
-
runDir = realpathSync6(
|
|
22117
|
+
runsRoot = realpathSync6(join13(repo.p, ".loki", "runs"));
|
|
22118
|
+
runDir = realpathSync6(join13(runsRoot, run));
|
|
21993
22119
|
} catch {
|
|
21994
22120
|
return c.json({ error: "artifact not found" }, 404);
|
|
21995
22121
|
}
|
|
21996
|
-
if (runDir !==
|
|
22122
|
+
if (runDir !== join13(runsRoot, run))
|
|
21997
22123
|
return c.json({ error: "artifact not found" }, 404);
|
|
21998
22124
|
try {
|
|
21999
|
-
file = realpathSync6(
|
|
22125
|
+
file = realpathSync6(join13(runDir, name));
|
|
22000
22126
|
} catch {
|
|
22001
22127
|
return c.json({ error: "artifact not found" }, 404);
|
|
22002
22128
|
}
|
|
@@ -22025,9 +22151,9 @@ function mount(ctx) {
|
|
|
22025
22151
|
import { basename as basename4 } from "path";
|
|
22026
22152
|
|
|
22027
22153
|
// src/ask/policy.ts
|
|
22028
|
-
import { chmodSync as chmodSync3, existsSync as existsSync5, lstatSync, mkdtempSync, readFileSync as readFileSync7, realpathSync as realpathSync7, rmSync as
|
|
22029
|
-
import { tmpdir as
|
|
22030
|
-
import { dirname as dirname2, join as
|
|
22154
|
+
import { chmodSync as chmodSync3, existsSync as existsSync5, lstatSync as lstatSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, realpathSync as realpathSync7, rmSync as rmSync3, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
22155
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
22156
|
+
import { dirname as dirname2, join as join14, parse } from "path";
|
|
22031
22157
|
var MCP_SERVER_NAME = "loki-ask";
|
|
22032
22158
|
var MCP_SERVER_SCRIPT = "packages/control-plane/src/ask/tools_server.ts";
|
|
22033
22159
|
var MCP_SERVER_BUNDLE = "ask-tools-server.js";
|
|
@@ -22038,8 +22164,8 @@ function resolveToolsServer(startDir) {
|
|
|
22038
22164
|
if (d === parse(d).root)
|
|
22039
22165
|
break;
|
|
22040
22166
|
}
|
|
22041
|
-
const bundles = dirs.flatMap((d) => [
|
|
22042
|
-
const sources2 = dirs.flatMap((d) => [
|
|
22167
|
+
const bundles = dirs.flatMap((d) => [join14(d, MCP_SERVER_BUNDLE), join14(d, "dist", MCP_SERVER_BUNDLE), join14(d, "packages/control-plane/dist", MCP_SERVER_BUNDLE)]);
|
|
22168
|
+
const sources2 = dirs.flatMap((d) => [join14(d, "src/ask/tools_server.ts"), join14(d, MCP_SERVER_SCRIPT)]);
|
|
22043
22169
|
return [...bundles, ...sources2].find((f) => existsSync5(f)) ?? null;
|
|
22044
22170
|
}
|
|
22045
22171
|
var ALLOWED_TOOLS = `mcp__${MCP_SERVER_NAME}__*`;
|
|
@@ -22072,38 +22198,38 @@ function buildMcpConfig(serverScript, dbPath) {
|
|
|
22072
22198
|
var PREFIX = "loki-ask.";
|
|
22073
22199
|
var MARKER = ".loki-ask-owned";
|
|
22074
22200
|
function createJobDir() {
|
|
22075
|
-
const root = realpathSync7(
|
|
22201
|
+
const root = realpathSync7(tmpdir3());
|
|
22076
22202
|
for (let d = root;; d = dirname2(d)) {
|
|
22077
|
-
if (existsSync5(
|
|
22203
|
+
if (existsSync5(join14(d, ".git")))
|
|
22078
22204
|
throw new Error(`temp root is inside a repo: ${d}`);
|
|
22079
22205
|
if (d === dirname2(d))
|
|
22080
22206
|
break;
|
|
22081
22207
|
}
|
|
22082
|
-
const dir =
|
|
22208
|
+
const dir = mkdtempSync2(join14(root, PREFIX));
|
|
22083
22209
|
chmodSync3(dir, 448);
|
|
22084
|
-
writeFileSync4(
|
|
22210
|
+
writeFileSync4(join14(dir, MARKER), dir, { mode: 384 });
|
|
22085
22211
|
return dir;
|
|
22086
22212
|
}
|
|
22087
22213
|
function removeJobDir(dir) {
|
|
22088
|
-
const root = realpathSync7(
|
|
22214
|
+
const root = realpathSync7(tmpdir3());
|
|
22089
22215
|
const refuse = (why) => {
|
|
22090
22216
|
throw new Error(`refusing to remove ${dir}: ${why}`);
|
|
22091
22217
|
};
|
|
22092
22218
|
if (dirname2(dir) !== root || !dir.slice(root.length + 1).startsWith(PREFIX))
|
|
22093
22219
|
refuse("not a scratch dir name");
|
|
22094
|
-
const st =
|
|
22220
|
+
const st = lstatSync2(dir);
|
|
22095
22221
|
if (!st.isDirectory() || st.isSymbolicLink())
|
|
22096
22222
|
refuse("not a plain directory");
|
|
22097
22223
|
if (st.uid !== process.getuid())
|
|
22098
22224
|
refuse("not owned by this user");
|
|
22099
22225
|
if ((st.mode & 511) !== 448)
|
|
22100
22226
|
refuse("mode is not 0700");
|
|
22101
|
-
const marker =
|
|
22227
|
+
const marker = join14(dir, MARKER);
|
|
22102
22228
|
if (!existsSync5(marker) || readFileSync7(marker, "utf8") !== dir)
|
|
22103
22229
|
refuse("marker missing or wrong");
|
|
22104
|
-
if (!
|
|
22230
|
+
if (!statSync4(marker).isFile())
|
|
22105
22231
|
refuse("marker is not a file");
|
|
22106
|
-
|
|
22232
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
22107
22233
|
}
|
|
22108
22234
|
|
|
22109
22235
|
// src/ask/invoke.ts
|
|
@@ -22222,13 +22348,13 @@ function pidAlive(pid) {
|
|
|
22222
22348
|
// src/ask/worker.ts
|
|
22223
22349
|
import { spawn as spawn2 } from "child_process";
|
|
22224
22350
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
22225
|
-
import { join as
|
|
22351
|
+
import { join as join16 } from "path";
|
|
22226
22352
|
|
|
22227
22353
|
// src/server/spawn.ts
|
|
22228
22354
|
import { spawn } from "child_process";
|
|
22229
|
-
import { existsSync as existsSync6, readFileSync as readFileSync8, realpathSync as realpathSync8, statSync as
|
|
22355
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, realpathSync as realpathSync8, statSync as statSync5 } from "fs";
|
|
22230
22356
|
import { homedir as homedir5 } from "os";
|
|
22231
|
-
import { basename as basename3, dirname as dirname3, join as
|
|
22357
|
+
import { basename as basename3, dirname as dirname3, join as join15, resolve as resolve4 } from "path";
|
|
22232
22358
|
var ISSUE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}\/[A-Za-z0-9._-]{1,100}#[1-9][0-9]{0,8}$/;
|
|
22233
22359
|
var TASK = /^[A-Za-z0-9][A-Za-z0-9 .,_/#@+=-]{0,499}$/;
|
|
22234
22360
|
var hasDotDot = (t) => t.split(/[\\/ ]/).some((seg) => seg.startsWith(".."));
|
|
@@ -22257,14 +22383,14 @@ function repoRefusal(cwd, env = process.env) {
|
|
|
22257
22383
|
if (dir === home)
|
|
22258
22384
|
return "refusing to start a run in your home directory; pick a project repository (a folder with its own .git)";
|
|
22259
22385
|
for (let d = dir;d !== "/" && d !== home && d !== dirname3(d); d = dirname3(d))
|
|
22260
|
-
if (existsSync6(
|
|
22386
|
+
if (existsSync6(join15(d, ".git")))
|
|
22261
22387
|
return null;
|
|
22262
22388
|
return `${cwd} is not a git repository; pick a registered project repository`;
|
|
22263
22389
|
}
|
|
22264
22390
|
function registryRepos2(env = process.env) {
|
|
22265
22391
|
try {
|
|
22266
|
-
const j = JSON.parse(readFileSync8(
|
|
22267
|
-
return Object.values(j.projects ?? {}).map((p) => typeof p?.path === "string" ? p.path : "").filter((p) => p && existsSync6(p) &&
|
|
22392
|
+
const j = JSON.parse(readFileSync8(join15(env.HOME || homedir5(), ".loki", "dashboard", "projects.json"), "utf8"));
|
|
22393
|
+
return Object.values(j.projects ?? {}).map((p) => typeof p?.path === "string" ? p.path : "").filter((p) => p && existsSync6(p) && statSync5(p).isDirectory());
|
|
22268
22394
|
} catch {
|
|
22269
22395
|
return [];
|
|
22270
22396
|
}
|
|
@@ -22519,7 +22645,7 @@ async function runAskJob(db, messageId, o) {
|
|
|
22519
22645
|
if (!toolsServer)
|
|
22520
22646
|
return fail("Ask tools server not found (expected ask-tools-server.js in dist/ or src/ask/tools_server.ts); rebuild with bun run build:server");
|
|
22521
22647
|
jobDir = createJobDir();
|
|
22522
|
-
const mcpConfigPath =
|
|
22648
|
+
const mcpConfigPath = join16(jobDir, "mcp.json");
|
|
22523
22649
|
writeFileSync5(mcpConfigPath, JSON.stringify(buildMcpConfig(toolsServer, o.dbPath)), { mode: 384 });
|
|
22524
22650
|
const inv = buildInvocation({
|
|
22525
22651
|
provider: thread.provider,
|
|
@@ -22982,13 +23108,13 @@ function mount4(ctx) {
|
|
|
22982
23108
|
}
|
|
22983
23109
|
|
|
22984
23110
|
// src/server/routes/checkpoints.ts
|
|
22985
|
-
|
|
22986
|
-
import { appendFileSync, copyFileSync, cpSync, existsSync as existsSync8, lstatSync as
|
|
22987
|
-
import { join as
|
|
23111
|
+
init_safe_git();
|
|
23112
|
+
import { appendFileSync, copyFileSync, cpSync, existsSync as existsSync8, lstatSync as lstatSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync4, readFileSync as readFileSync10, realpathSync as realpathSync9, rmSync as rmSync4, statSync as statSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
23113
|
+
import { join as join18, sep as sep5 } from "path";
|
|
22988
23114
|
|
|
22989
23115
|
// src/server/routes/cost_ledger.ts
|
|
22990
|
-
import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as
|
|
22991
|
-
import { join as
|
|
23116
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync6 } from "fs";
|
|
23117
|
+
import { join as join17 } from "path";
|
|
22992
23118
|
var isNum = (v) => typeof v === "number" && Number.isFinite(v);
|
|
22993
23119
|
var isObj3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
22994
23120
|
var r6 = (n2) => Math.round(n2 * 1e6) / 1e6;
|
|
@@ -23019,7 +23145,7 @@ var DEFAULT_PRICING = {
|
|
|
23019
23145
|
"gpt-5.6-luna": { input: 0.5, output: 4 }
|
|
23020
23146
|
};
|
|
23021
23147
|
function pricing(lokiDir) {
|
|
23022
|
-
const d = readJson(
|
|
23148
|
+
const d = readJson(join17(lokiDir, "pricing.json"));
|
|
23023
23149
|
const models = isObj3(d) && isObj3(d.models) ? d.models : {};
|
|
23024
23150
|
return { ...DEFAULT_PRICING, ...models };
|
|
23025
23151
|
}
|
|
@@ -23032,7 +23158,7 @@ function modelCost(table, model, inp, out, cr = 0, cw = 0) {
|
|
|
23032
23158
|
return r6((inp * ir + out * or2 + cr * crr + cw * cwr) / 1e6);
|
|
23033
23159
|
}
|
|
23034
23160
|
function iterationRecords(lokiDir) {
|
|
23035
|
-
const dir =
|
|
23161
|
+
const dir = join17(lokiDir, "metrics", "efficiency");
|
|
23036
23162
|
let names = [];
|
|
23037
23163
|
try {
|
|
23038
23164
|
names = readdirSync3(dir).filter((n2) => /^iteration-.*\.json$/.test(n2)).sort();
|
|
@@ -23041,7 +23167,7 @@ function iterationRecords(lokiDir) {
|
|
|
23041
23167
|
}
|
|
23042
23168
|
const out = [];
|
|
23043
23169
|
for (const n2 of names) {
|
|
23044
|
-
const d = readJson(
|
|
23170
|
+
const d = readJson(join17(dir, n2));
|
|
23045
23171
|
if (isObj3(d))
|
|
23046
23172
|
out.push(d);
|
|
23047
23173
|
}
|
|
@@ -23078,7 +23204,7 @@ function costSnapshot(lokiDir) {
|
|
|
23078
23204
|
}
|
|
23079
23205
|
}
|
|
23080
23206
|
if (tIn === 0 && tOut === 0) {
|
|
23081
|
-
const ctx = readJson(
|
|
23207
|
+
const ctx = readJson(join17(lokiDir, "context", "tracking.json"));
|
|
23082
23208
|
const totals = isObj3(ctx) && isObj3(ctx.totals) ? ctx.totals : {};
|
|
23083
23209
|
tIn = num0(totals.total_input);
|
|
23084
23210
|
tOut = num0(totals.total_output);
|
|
@@ -23104,7 +23230,7 @@ function costSnapshot(lokiDir) {
|
|
|
23104
23230
|
}
|
|
23105
23231
|
}
|
|
23106
23232
|
let limit = null, used = null, remaining = null;
|
|
23107
|
-
const bd = readJson(
|
|
23233
|
+
const bd = readJson(join17(lokiDir, "metrics", "budget.json"));
|
|
23108
23234
|
if (isObj3(bd) && isNum(bd.limit)) {
|
|
23109
23235
|
limit = bd.limit;
|
|
23110
23236
|
if (recorded && !unknownUsd) {
|
|
@@ -23155,7 +23281,7 @@ function budgetSnapshot(lokiDir) {
|
|
|
23155
23281
|
total += priced(table, d);
|
|
23156
23282
|
}
|
|
23157
23283
|
let limit = null;
|
|
23158
|
-
const bd = readJson(
|
|
23284
|
+
const bd = readJson(join17(lokiDir, "metrics", "budget.json"));
|
|
23159
23285
|
if (isObj3(bd)) {
|
|
23160
23286
|
const l = bd.limit || bd.budget_limit;
|
|
23161
23287
|
limit = isNum(l) ? l : null;
|
|
@@ -23206,19 +23332,19 @@ function costTimeline(lokiDir) {
|
|
|
23206
23332
|
}
|
|
23207
23333
|
const runs2 = [];
|
|
23208
23334
|
let projectTotal = 0, runsMeasured = 0;
|
|
23209
|
-
const proofs =
|
|
23335
|
+
const proofs = join17(lokiDir, "proofs");
|
|
23210
23336
|
let entries = [];
|
|
23211
23337
|
try {
|
|
23212
23338
|
entries = readdirSync3(proofs).sort();
|
|
23213
23339
|
} catch {}
|
|
23214
23340
|
for (const e of entries) {
|
|
23215
23341
|
try {
|
|
23216
|
-
if (!
|
|
23342
|
+
if (!statSync6(join17(proofs, e)).isDirectory())
|
|
23217
23343
|
continue;
|
|
23218
23344
|
} catch {
|
|
23219
23345
|
continue;
|
|
23220
23346
|
}
|
|
23221
|
-
const p = readJson(
|
|
23347
|
+
const p = readJson(join17(proofs, e, "proof.json"));
|
|
23222
23348
|
if (!isObj3(p))
|
|
23223
23349
|
continue;
|
|
23224
23350
|
const cost = isObj3(p.cost) ? p.cost : {};
|
|
@@ -23248,7 +23374,7 @@ function costTimeline(lokiDir) {
|
|
|
23248
23374
|
...recorded || runsMeasured ? {} : { not_measured: NOT_MEASURED }
|
|
23249
23375
|
};
|
|
23250
23376
|
}
|
|
23251
|
-
var lokiDirOf = (repoDir) =>
|
|
23377
|
+
var lokiDirOf = (repoDir) => join17(repoDir, ".loki");
|
|
23252
23378
|
var lokiDirExists = (repoDir) => existsSync7(lokiDirOf(repoDir));
|
|
23253
23379
|
function mount5(ctx) {
|
|
23254
23380
|
const deny = { error: "loopback only without a token" };
|
|
@@ -23263,8 +23389,8 @@ var SAFE_ID = /^[A-Za-z0-9_-]{1,128}$/;
|
|
|
23263
23389
|
var MAX_CHECKPOINTS = 50;
|
|
23264
23390
|
var ROLLBACK_ALLOW = new Set(["session.json", "dashboard-state.json", "CONTINUITY.md", "autonomy-state.json", "state", "queue"]);
|
|
23265
23391
|
var validCheckpointId = (id) => SAFE_ID.test(id);
|
|
23266
|
-
var storeOf = (repoDir) =>
|
|
23267
|
-
var lokiOf = (repoDir) =>
|
|
23392
|
+
var storeOf = (repoDir) => join18(repoDir, ".loki", "state", "checkpoints");
|
|
23393
|
+
var lokiOf = (repoDir) => join18(repoDir, ".loki");
|
|
23268
23394
|
var readObj = (f) => {
|
|
23269
23395
|
try {
|
|
23270
23396
|
const d = JSON.parse(readFileSync10(f, "utf8"));
|
|
@@ -23278,7 +23404,7 @@ function listCheckpoints(repoDir, limit = 20) {
|
|
|
23278
23404
|
const store = storeOf(repoDir);
|
|
23279
23405
|
let lines = [];
|
|
23280
23406
|
try {
|
|
23281
|
-
lines = readFileSync10(
|
|
23407
|
+
lines = readFileSync10(join18(store, "index.jsonl"), "utf8").split(`
|
|
23282
23408
|
`);
|
|
23283
23409
|
} catch {
|
|
23284
23410
|
return [];
|
|
@@ -23306,7 +23432,7 @@ function listCheckpoints(repoDir, limit = 20) {
|
|
|
23306
23432
|
message: str2(raw2.task) ?? str2(raw2.message) ?? str2(raw2.task_description),
|
|
23307
23433
|
iteration: Number.isInteger(it) ? it : null
|
|
23308
23434
|
};
|
|
23309
|
-
const meta = readObj(
|
|
23435
|
+
const meta = readObj(join18(store, id, "metadata.json"));
|
|
23310
23436
|
if (meta) {
|
|
23311
23437
|
cp.git_branch = str2(meta.git_branch);
|
|
23312
23438
|
cp.provider = str2(meta.provider);
|
|
@@ -23314,7 +23440,7 @@ function listCheckpoints(repoDir, limit = 20) {
|
|
|
23314
23440
|
cp.message ??= str2(meta.task_description);
|
|
23315
23441
|
cp.git_sha ??= str2(meta.git_sha);
|
|
23316
23442
|
cp.created_at ??= str2(meta.timestamp);
|
|
23317
|
-
cp.files_count = countFiles(
|
|
23443
|
+
cp.files_count = countFiles(join18(store, id));
|
|
23318
23444
|
}
|
|
23319
23445
|
out.push(cp);
|
|
23320
23446
|
}
|
|
@@ -23325,7 +23451,7 @@ function countFiles(dir) {
|
|
|
23325
23451
|
const walk = (d, top) => {
|
|
23326
23452
|
for (const e of readdirSync4(d, { withFileTypes: true })) {
|
|
23327
23453
|
if (e.isDirectory())
|
|
23328
|
-
walk(
|
|
23454
|
+
walk(join18(d, e.name), false);
|
|
23329
23455
|
else if (e.isFile() && !(top && e.name === "metadata.json"))
|
|
23330
23456
|
n2++;
|
|
23331
23457
|
}
|
|
@@ -23336,11 +23462,11 @@ function countFiles(dir) {
|
|
|
23336
23462
|
return n2;
|
|
23337
23463
|
}
|
|
23338
23464
|
function getCheckpoint(repoDir, id) {
|
|
23339
|
-
return validCheckpointId(id) ? readObj(
|
|
23465
|
+
return validCheckpointId(id) ? readObj(join18(storeOf(repoDir), id, "metadata.json")) : null;
|
|
23340
23466
|
}
|
|
23341
23467
|
var gitHead = (repoDir) => {
|
|
23342
23468
|
try {
|
|
23343
|
-
return
|
|
23469
|
+
return safeGit(repoDir, ["rev-parse", "HEAD"], { timeout: 5000 }).trim() || null;
|
|
23344
23470
|
} catch {
|
|
23345
23471
|
return null;
|
|
23346
23472
|
}
|
|
@@ -23348,60 +23474,60 @@ var gitHead = (repoDir) => {
|
|
|
23348
23474
|
function createCheckpoint(repoDir, message, now2 = new Date) {
|
|
23349
23475
|
const store = storeOf(repoDir), loki = lokiOf(repoDir);
|
|
23350
23476
|
mkdirSync3(store, { recursive: true });
|
|
23351
|
-
const id = `chk-${stamp(now2)}`, dir =
|
|
23477
|
+
const id = `chk-${stamp(now2)}`, dir = join18(store, id);
|
|
23352
23478
|
mkdirSync3(dir, { recursive: true });
|
|
23353
23479
|
for (const f of ["dashboard-state.json", "session.json"]) {
|
|
23354
23480
|
try {
|
|
23355
|
-
if (existsSync8(
|
|
23356
|
-
copyFileSync(
|
|
23481
|
+
if (existsSync8(join18(loki, f)))
|
|
23482
|
+
copyFileSync(join18(loki, f), join18(dir, f));
|
|
23357
23483
|
} catch {}
|
|
23358
23484
|
}
|
|
23359
23485
|
try {
|
|
23360
|
-
if (existsSync8(
|
|
23361
|
-
cpSync(
|
|
23486
|
+
if (existsSync8(join18(loki, "queue")))
|
|
23487
|
+
cpSync(join18(loki, "queue"), join18(dir, "queue"), { recursive: true });
|
|
23362
23488
|
} catch {}
|
|
23363
23489
|
const meta = { id, created_at: now2.toISOString(), git_sha: gitHead(repoDir), message: message || null, files: readdirSync4(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name) };
|
|
23364
|
-
writeFileSync6(
|
|
23365
|
-
appendFileSync(
|
|
23490
|
+
writeFileSync6(join18(dir, "metadata.json"), JSON.stringify(meta, null, 2));
|
|
23491
|
+
appendFileSync(join18(store, "index.jsonl"), `${JSON.stringify(meta)}
|
|
23366
23492
|
`);
|
|
23367
23493
|
const mine = readdirSync4(store, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("chk-")).map((e) => e.name).sort();
|
|
23368
23494
|
while (mine.length > MAX_CHECKPOINTS)
|
|
23369
|
-
|
|
23495
|
+
rmSync4(join18(store, mine.shift()), { recursive: true, force: true });
|
|
23370
23496
|
return meta;
|
|
23371
23497
|
}
|
|
23372
23498
|
function rollbackCheckpoint(repoDir, id, now2 = new Date) {
|
|
23373
23499
|
const store = storeOf(repoDir), loki = lokiOf(repoDir);
|
|
23374
23500
|
let real2 = "", realStore = "";
|
|
23375
23501
|
try {
|
|
23376
|
-
real2 = realpathSync9(
|
|
23502
|
+
real2 = realpathSync9(join18(store, id));
|
|
23377
23503
|
realStore = realpathSync9(store);
|
|
23378
23504
|
} catch {
|
|
23379
23505
|
return null;
|
|
23380
23506
|
}
|
|
23381
|
-
if (!real2.startsWith(`${realStore}${sep5}`) || !
|
|
23507
|
+
if (!real2.startsWith(`${realStore}${sep5}`) || !statSync7(real2).isDirectory())
|
|
23382
23508
|
return null;
|
|
23383
|
-
const preId = `rb-pre-${stamp(now2)}`, pre =
|
|
23509
|
+
const preId = `rb-pre-${stamp(now2)}`, pre = join18(store, preId);
|
|
23384
23510
|
mkdirSync3(pre, { recursive: true });
|
|
23385
23511
|
const notStore = (src) => src !== store;
|
|
23386
23512
|
for (const n2 of ["session.json", "dashboard-state.json", "CONTINUITY.md", "autonomy-state.json"]) {
|
|
23387
23513
|
try {
|
|
23388
|
-
if (existsSync8(
|
|
23389
|
-
copyFileSync(
|
|
23514
|
+
if (existsSync8(join18(loki, n2)))
|
|
23515
|
+
copyFileSync(join18(loki, n2), join18(pre, n2));
|
|
23390
23516
|
} catch {}
|
|
23391
23517
|
}
|
|
23392
23518
|
for (const d of ["state", "queue"]) {
|
|
23393
23519
|
try {
|
|
23394
|
-
if (existsSync8(
|
|
23395
|
-
cpSync(
|
|
23520
|
+
if (existsSync8(join18(loki, d)))
|
|
23521
|
+
cpSync(join18(loki, d), join18(pre, d), { recursive: true, filter: notStore });
|
|
23396
23522
|
} catch {}
|
|
23397
23523
|
}
|
|
23398
23524
|
const preMeta = { id: preId, created_at: now2.toISOString(), message: `pre-rollback snapshot (before restoring ${id})`, created_by: "control plane rollback" };
|
|
23399
|
-
writeFileSync6(
|
|
23400
|
-
appendFileSync(
|
|
23525
|
+
writeFileSync6(join18(pre, "metadata.json"), JSON.stringify(preMeta, null, 2));
|
|
23526
|
+
appendFileSync(join18(store, "index.jsonl"), `${JSON.stringify(preMeta)}
|
|
23401
23527
|
`);
|
|
23402
23528
|
let restored = 0;
|
|
23403
23529
|
const errors = [];
|
|
23404
|
-
const skipped = (src) => src ===
|
|
23530
|
+
const skipped = (src) => src === join18(real2, "state", "checkpoints");
|
|
23405
23531
|
for (const e of readdirSync4(real2, { withFileTypes: true })) {
|
|
23406
23532
|
if (e.name === "metadata.json" || e.name === "worktree-snapshot.txt")
|
|
23407
23533
|
continue;
|
|
@@ -23409,20 +23535,20 @@ function rollbackCheckpoint(repoDir, id, now2 = new Date) {
|
|
|
23409
23535
|
errors.push(`${e.name}: not in the rollback allowlist, skipped`);
|
|
23410
23536
|
continue;
|
|
23411
23537
|
}
|
|
23412
|
-
const src =
|
|
23538
|
+
const src = join18(real2, e.name), dst = join18(loki, e.name);
|
|
23413
23539
|
try {
|
|
23414
|
-
if (
|
|
23540
|
+
if (lstatSync3(src).isSymbolicLink()) {
|
|
23415
23541
|
errors.push(`${e.name}: symlink skipped`);
|
|
23416
23542
|
continue;
|
|
23417
23543
|
}
|
|
23418
|
-
if (existsSync8(dst) &&
|
|
23544
|
+
if (existsSync8(dst) && lstatSync3(dst).isSymbolicLink()) {
|
|
23419
23545
|
errors.push(`${e.name}: destination is a symlink, skipped`);
|
|
23420
23546
|
continue;
|
|
23421
23547
|
}
|
|
23422
23548
|
cpSync(src, dst, { recursive: true, filter: (s) => {
|
|
23423
23549
|
if (skipped(s))
|
|
23424
23550
|
return false;
|
|
23425
|
-
if (
|
|
23551
|
+
if (lstatSync3(s).isSymbolicLink()) {
|
|
23426
23552
|
errors.push(`${s.slice(real2.length + 1)}: nested symlink skipped`);
|
|
23427
23553
|
return false;
|
|
23428
23554
|
}
|
|
@@ -23509,9 +23635,9 @@ function mount6(ctx) {
|
|
|
23509
23635
|
}
|
|
23510
23636
|
|
|
23511
23637
|
// src/server/routes/config.ts
|
|
23512
|
-
import { createHash as createHash5, randomBytes } from "crypto";
|
|
23513
|
-
import { closeSync as closeSync4, fchmodSync, fsyncSync, lstatSync as
|
|
23514
|
-
import { basename as basename5, dirname as dirname4, join as
|
|
23638
|
+
import { createHash as createHash5, randomBytes as randomBytes2 } from "crypto";
|
|
23639
|
+
import { closeSync as closeSync4, fchmodSync, fsyncSync, lstatSync as lstatSync4, openSync as openSync4, readFileSync as readFileSync11, realpathSync as realpathSync10, renameSync as renameSync3, statSync as statSync8, unlinkSync, writeSync as writeSync2 } from "fs";
|
|
23640
|
+
import { basename as basename5, dirname as dirname4, join as join19, sep as sep6 } from "path";
|
|
23515
23641
|
|
|
23516
23642
|
// node_modules/yaml/dist/index.js
|
|
23517
23643
|
var composer = require_composer();
|
|
@@ -23950,10 +24076,10 @@ function resolveConfigFile(repoDir) {
|
|
|
23950
24076
|
} catch {
|
|
23951
24077
|
return { ok: false, status: 400, error: "repo directory not found" };
|
|
23952
24078
|
}
|
|
23953
|
-
const p =
|
|
24079
|
+
const p = join19(root, "loki.yaml");
|
|
23954
24080
|
let st;
|
|
23955
24081
|
try {
|
|
23956
|
-
st =
|
|
24082
|
+
st = lstatSync4(p);
|
|
23957
24083
|
} catch {
|
|
23958
24084
|
return { ok: true, file: p, exists: false };
|
|
23959
24085
|
}
|
|
@@ -23966,7 +24092,7 @@ function resolveConfigFile(repoDir) {
|
|
|
23966
24092
|
}
|
|
23967
24093
|
if (!real2.startsWith(root + sep6))
|
|
23968
24094
|
return { ok: false, status: 400, error: "loki.yaml is a symlink that resolves outside the repo" };
|
|
23969
|
-
if (!
|
|
24095
|
+
if (!statSync8(real2).isFile())
|
|
23970
24096
|
return { ok: false, status: 422, error: "loki.yaml is not a regular file" };
|
|
23971
24097
|
return { ok: true, file: real2, exists: true };
|
|
23972
24098
|
}
|
|
@@ -23975,7 +24101,7 @@ function resolveConfigFile(repoDir) {
|
|
|
23975
24101
|
return { ok: true, file: p, exists: true };
|
|
23976
24102
|
}
|
|
23977
24103
|
function atomicWrite(file, text2, mode) {
|
|
23978
|
-
const tmp =
|
|
24104
|
+
const tmp = join19(dirname4(file), `.${basename5(file)}.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`);
|
|
23979
24105
|
const fd = openSync4(tmp, "wx", mode);
|
|
23980
24106
|
try {
|
|
23981
24107
|
writeSync2(fd, text2);
|
|
@@ -24015,7 +24141,7 @@ function mount8(ctx) {
|
|
|
24015
24141
|
return deny(c, "config.read", r.status, r.error);
|
|
24016
24142
|
let raw2 = "";
|
|
24017
24143
|
if (r.exists) {
|
|
24018
|
-
if (
|
|
24144
|
+
if (statSync8(r.file).size > MAX_FILE)
|
|
24019
24145
|
return deny(c, "config.read", 413, "loki.yaml is too large");
|
|
24020
24146
|
raw2 = readFileSync11(r.file, "utf8");
|
|
24021
24147
|
}
|
|
@@ -24080,7 +24206,7 @@ function mount8(ctx) {
|
|
|
24080
24206
|
return refuse(r.status, r.error);
|
|
24081
24207
|
let raw2 = "";
|
|
24082
24208
|
if (r.exists) {
|
|
24083
|
-
if (
|
|
24209
|
+
if (statSync8(r.file).size > MAX_FILE)
|
|
24084
24210
|
return refuse(400, "loki.yaml is too large");
|
|
24085
24211
|
raw2 = readFileSync11(r.file, "utf8");
|
|
24086
24212
|
}
|
|
@@ -24107,7 +24233,7 @@ function mount8(ctx) {
|
|
|
24107
24233
|
return refuse(400, "could not render the config safely");
|
|
24108
24234
|
const changed = [...new Set([...Object.keys(prev), ...Object.keys(next)])].filter((k) => !deepEq(prev[k], next[k]));
|
|
24109
24235
|
try {
|
|
24110
|
-
const mode = r.exists ?
|
|
24236
|
+
const mode = r.exists ? statSync8(r.file).mode & 511 : 420;
|
|
24111
24237
|
if (r.exists)
|
|
24112
24238
|
atomicWrite(`${r.file}.bak`, raw2, 384);
|
|
24113
24239
|
atomicWrite(r.file, out, mode);
|
|
@@ -24126,7 +24252,7 @@ function mount8(ctx) {
|
|
|
24126
24252
|
|
|
24127
24253
|
// src/server/routes/control.ts
|
|
24128
24254
|
import { existsSync as existsSync9, realpathSync as realpathSync11 } from "fs";
|
|
24129
|
-
import { join as
|
|
24255
|
+
import { join as join20, resolve as resolve5, sep as sep7 } from "path";
|
|
24130
24256
|
init_run_pid();
|
|
24131
24257
|
var ID4 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
24132
24258
|
var busy = new Set;
|
|
@@ -24152,7 +24278,7 @@ function mount9(ctx) {
|
|
|
24152
24278
|
}
|
|
24153
24279
|
if (!repo)
|
|
24154
24280
|
return done(404, "refused", { error: "this run's repo is not known on this machine" });
|
|
24155
|
-
const runsRoot =
|
|
24281
|
+
const runsRoot = join20(repo, ".loki", "runs"), runDir = resolve5(runsRoot, id);
|
|
24156
24282
|
if (!runDir.startsWith(runsRoot + sep7))
|
|
24157
24283
|
return done(400, "refused", { error: "invalid run id" }, "path escape");
|
|
24158
24284
|
return handler({ source, run: id, repo, runDir }, done);
|
|
@@ -24200,7 +24326,7 @@ function mount9(ctx) {
|
|
|
24200
24326
|
return done(404, "refused", { error: "run not found" });
|
|
24201
24327
|
if (!blockedQuestion(loadEvents(db, a.source, a.run), row.verdict))
|
|
24202
24328
|
return done(409, "refused", { error: "run is not BLOCKED, so there is nothing to resume" });
|
|
24203
|
-
if (!existsSync9(
|
|
24329
|
+
if (!existsSync9(join20(answerDir, a.source, `${a.run}.answer.txt`)))
|
|
24204
24330
|
return done(409, "refused", { error: "no answer recorded for this run; answer it first" });
|
|
24205
24331
|
return launch(a, [bin, "answer", a.run], done);
|
|
24206
24332
|
});
|
|
@@ -24385,10 +24511,10 @@ function mount11(ctx) {
|
|
|
24385
24511
|
// src/server/routes/fleet.ts
|
|
24386
24512
|
import { readdirSync as readdirSync5, readFileSync as readFileSync12 } from "fs";
|
|
24387
24513
|
import { homedir as homedir6 } from "os";
|
|
24388
|
-
import { basename as basename6, join as
|
|
24514
|
+
import { basename as basename6, join as join21 } from "path";
|
|
24389
24515
|
var isNum2 = (v) => typeof v === "number" && Number.isFinite(v);
|
|
24390
24516
|
var isObj6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
24391
|
-
var registryFile = () =>
|
|
24517
|
+
var registryFile = () => join21(process.env.HOME ?? homedir6(), ".loki", "dashboard", "projects.json");
|
|
24392
24518
|
function pidAlive2(pid) {
|
|
24393
24519
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
|
|
24394
24520
|
return false;
|
|
@@ -24403,33 +24529,33 @@ function projectSnapshot(path) {
|
|
|
24403
24529
|
const snap = { phase: "", iteration: null, cost_usd: null, started_at: null, ended_at: null };
|
|
24404
24530
|
if (!path)
|
|
24405
24531
|
return snap;
|
|
24406
|
-
const loki =
|
|
24407
|
-
const st = readJson(
|
|
24532
|
+
const loki = join21(path, ".loki");
|
|
24533
|
+
const st = readJson(join21(loki, "dashboard-state.json"));
|
|
24408
24534
|
if (isObj6(st)) {
|
|
24409
24535
|
snap.phase = typeof st.phase === "string" ? st.phase : "";
|
|
24410
24536
|
snap.iteration = Number.isInteger(st.iteration) ? st.iteration : null;
|
|
24411
24537
|
}
|
|
24412
|
-
const ss = readJson(
|
|
24538
|
+
const ss = readJson(join21(loki, "session.json"));
|
|
24413
24539
|
if (isObj6(ss)) {
|
|
24414
24540
|
const a = ss.startedAt || ss.started_at, b = ss.endedAt || ss.ended_at;
|
|
24415
24541
|
snap.started_at = typeof a === "string" ? a : null;
|
|
24416
24542
|
snap.ended_at = typeof b === "string" ? b : null;
|
|
24417
24543
|
}
|
|
24418
24544
|
let cost = 0, found = false;
|
|
24419
|
-
const eff =
|
|
24545
|
+
const eff = join21(loki, "metrics", "efficiency");
|
|
24420
24546
|
let names = [];
|
|
24421
24547
|
try {
|
|
24422
24548
|
names = readdirSync5(eff).filter((n2) => n2.endsWith(".json"));
|
|
24423
24549
|
} catch {}
|
|
24424
24550
|
for (const n2 of names) {
|
|
24425
|
-
const d = readJson(
|
|
24551
|
+
const d = readJson(join21(eff, n2));
|
|
24426
24552
|
if (isObj6(d) && isNum2(d.cost_usd) && recordIsMeasured(d)) {
|
|
24427
24553
|
cost += d.cost_usd;
|
|
24428
24554
|
found = true;
|
|
24429
24555
|
}
|
|
24430
24556
|
}
|
|
24431
24557
|
if (!found) {
|
|
24432
|
-
const t = readJson(
|
|
24558
|
+
const t = readJson(join21(loki, "context", "tracking.json"));
|
|
24433
24559
|
const totals = isObj6(t) && isObj6(t.totals) ? t.totals : null;
|
|
24434
24560
|
if (totals && isNum2(totals.total_cost_usd) && recordIsMeasured({ cost_usd: totals.total_cost_usd, input_tokens: totals.total_input, output_tokens: totals.total_output })) {
|
|
24435
24561
|
cost = totals.total_cost_usd;
|
|
@@ -24502,8 +24628,8 @@ function mount12(ctx) {
|
|
|
24502
24628
|
}
|
|
24503
24629
|
|
|
24504
24630
|
// src/server/routes/memory.ts
|
|
24505
|
-
import { existsSync as existsSync10, readFileSync as readFileSync13, readdirSync as readdirSync6, realpathSync as realpathSync12, statSync as
|
|
24506
|
-
import { join as
|
|
24631
|
+
import { existsSync as existsSync10, readFileSync as readFileSync13, readdirSync as readdirSync6, realpathSync as realpathSync12, statSync as statSync9 } from "fs";
|
|
24632
|
+
import { join as join22, sep as sep8 } from "path";
|
|
24507
24633
|
var isObj7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
24508
24634
|
var nonEmpty = (v) => !(v === undefined || v === null || v === "" || Array.isArray(v) && v.length === 0 || isObj7(v) && Object.keys(v).length === 0);
|
|
24509
24635
|
var focus = { dir: null };
|
|
@@ -24534,7 +24660,7 @@ function jsonFiles(dir, cap = Infinity) {
|
|
|
24534
24660
|
for (const e of ents.sort((a, b) => a.name < b.name ? -1 : 1)) {
|
|
24535
24661
|
if (out2.length >= cap)
|
|
24536
24662
|
return;
|
|
24537
|
-
const p =
|
|
24663
|
+
const p = join22(d, e.name);
|
|
24538
24664
|
if (e.isDirectory())
|
|
24539
24665
|
walk(p);
|
|
24540
24666
|
else if (e.isFile() && e.name.endsWith(".json"))
|
|
@@ -24556,12 +24682,12 @@ function setFocus(repoDir, raw2, registry = registryFile()) {
|
|
|
24556
24682
|
let real2 = "";
|
|
24557
24683
|
try {
|
|
24558
24684
|
real2 = realpathSync12(s);
|
|
24559
|
-
if (!
|
|
24685
|
+
if (!statSync9(real2).isDirectory())
|
|
24560
24686
|
throw new Error("not a dir");
|
|
24561
24687
|
} catch {
|
|
24562
24688
|
return { ok: false, error: `Directory does not exist: ${s}` };
|
|
24563
24689
|
}
|
|
24564
|
-
if (!existsSync10(
|
|
24690
|
+
if (!existsSync10(join22(real2, ".loki")) || !statSync9(join22(real2, ".loki")).isDirectory())
|
|
24565
24691
|
return { ok: false, error: `Directory does not contain a .loki/ subdirectory: ${s}` };
|
|
24566
24692
|
const allowed = new Set;
|
|
24567
24693
|
try {
|
|
@@ -24586,7 +24712,7 @@ var QUEUES = [["pending.json", "pending"], ["in-progress.json", "in_progress"],
|
|
|
24586
24712
|
var RANK = { done: 3, in_progress: 2, review: 1, pending: 0 };
|
|
24587
24713
|
function tasksList(loki, status) {
|
|
24588
24714
|
const all = [];
|
|
24589
|
-
const st = readJson(
|
|
24715
|
+
const st = readJson(join22(loki, "dashboard-state.json"));
|
|
24590
24716
|
const groups = isObj7(st) && isObj7(st.tasks) ? st.tasks : {};
|
|
24591
24717
|
for (const [key, mapped] of GROUPS) {
|
|
24592
24718
|
const g = groups[key];
|
|
@@ -24608,7 +24734,7 @@ function tasksList(loki, status) {
|
|
|
24608
24734
|
});
|
|
24609
24735
|
}
|
|
24610
24736
|
for (const [file, qs] of QUEUES) {
|
|
24611
|
-
const raw2 = readJson(
|
|
24737
|
+
const raw2 = readJson(join22(loki, "queue", file));
|
|
24612
24738
|
const items = isObj7(raw2) ? raw2.tasks : raw2;
|
|
24613
24739
|
if (!Array.isArray(items))
|
|
24614
24740
|
continue;
|
|
@@ -24662,7 +24788,7 @@ function tasksList(loki, status) {
|
|
|
24662
24788
|
}
|
|
24663
24789
|
return status ? out2.filter((t) => t.status === status) : out2;
|
|
24664
24790
|
}
|
|
24665
|
-
var memDir = (loki, sub) =>
|
|
24791
|
+
var memDir = (loki, sub) => join22(loki, "memory", sub);
|
|
24666
24792
|
function memoryEpisodes(loki, limit = 50) {
|
|
24667
24793
|
const eps = jsonFiles(memDir(loki, "episodic")).map(readJson).filter(isObj7);
|
|
24668
24794
|
eps.sort((a, b) => String(b.timestamp ?? "").localeCompare(String(a.timestamp ?? "")));
|
|
@@ -24677,13 +24803,13 @@ function memoryEpisode(loki, id) {
|
|
|
24677
24803
|
return null;
|
|
24678
24804
|
}
|
|
24679
24805
|
function memoryPatterns(loki) {
|
|
24680
|
-
const d = readJson(
|
|
24806
|
+
const d = readJson(join22(memDir(loki, "semantic"), "patterns.json"));
|
|
24681
24807
|
const list = Array.isArray(d) ? d : isObj7(d) && Array.isArray(d.patterns) ? d.patterns : [];
|
|
24682
24808
|
return list.filter(isObj7);
|
|
24683
24809
|
}
|
|
24684
24810
|
var memorySkills = (loki) => jsonFiles(memDir(loki, "skills")).map(readJson).filter(isObj7);
|
|
24685
24811
|
function memoryEconomics(loki) {
|
|
24686
|
-
const rawV = readJson(
|
|
24812
|
+
const rawV = readJson(join22(loki, "memory", "token_economics.json"));
|
|
24687
24813
|
const raw2 = isObj7(rawV) ? rawV : {};
|
|
24688
24814
|
const m = isObj7(raw2.metrics) ? raw2.metrics : {};
|
|
24689
24815
|
const n2 = (v) => typeof v === "number" && Number.isFinite(v) ? Math.trunc(v) : 0;
|
|
@@ -24719,7 +24845,7 @@ function memoryEconomics(loki) {
|
|
|
24719
24845
|
};
|
|
24720
24846
|
}
|
|
24721
24847
|
function contextTracking(loki) {
|
|
24722
|
-
const f =
|
|
24848
|
+
const f = join22(loki, "context", "tracking.json");
|
|
24723
24849
|
if (!existsSync10(f)) {
|
|
24724
24850
|
return { status: 200, body: {
|
|
24725
24851
|
session_id: null,
|
|
@@ -24780,8 +24906,8 @@ function mount13(ctx) {
|
|
|
24780
24906
|
}
|
|
24781
24907
|
|
|
24782
24908
|
// src/server/routes/metrics.ts
|
|
24783
|
-
import { readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as
|
|
24784
|
-
import { join as
|
|
24909
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync10 } from "fs";
|
|
24910
|
+
import { join as join23 } from "path";
|
|
24785
24911
|
var isObj8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
24786
24912
|
var arr = (v) => Array.isArray(v) ? v : [];
|
|
24787
24913
|
function buildMetricsText(repoDir, now2 = Date.now()) {
|
|
@@ -24798,7 +24924,7 @@ function buildMetricsText(repoDir, now2 = Date.now()) {
|
|
|
24798
24924
|
L.push(...samples);
|
|
24799
24925
|
L.push("");
|
|
24800
24926
|
};
|
|
24801
|
-
const stRaw = readJson(
|
|
24927
|
+
const stRaw = readJson(join23(loki, "dashboard-state.json"));
|
|
24802
24928
|
const state = isObj8(stRaw) ? stRaw : null;
|
|
24803
24929
|
let status = 0;
|
|
24804
24930
|
if (state?.mode === "paused")
|
|
@@ -24807,7 +24933,7 @@ function buildMetricsText(repoDir, now2 = Date.now()) {
|
|
|
24807
24933
|
status = 1;
|
|
24808
24934
|
else {
|
|
24809
24935
|
try {
|
|
24810
|
-
if (pidAlive2(parseInt(readFileSync14(
|
|
24936
|
+
if (pidAlive2(parseInt(readFileSync14(join23(loki, "loki.pid"), "utf8").trim(), 10)))
|
|
24811
24937
|
status = 1;
|
|
24812
24938
|
} catch {}
|
|
24813
24939
|
}
|
|
@@ -24823,7 +24949,7 @@ function buildMetricsText(repoDir, now2 = Date.now()) {
|
|
|
24823
24949
|
`loki_tasks_total{status="failed"} ${arr(tasks.failed).length}`
|
|
24824
24950
|
] : null);
|
|
24825
24951
|
let agents = null;
|
|
24826
|
-
const af = readJson(
|
|
24952
|
+
const af = readJson(join23(loki, "state", "agents.json"));
|
|
24827
24953
|
if (Array.isArray(af) && af.length)
|
|
24828
24954
|
agents = af;
|
|
24829
24955
|
else if (state && Array.isArray(state.agents) && state.agents.length)
|
|
@@ -24835,7 +24961,7 @@ function buildMetricsText(repoDir, now2 = Date.now()) {
|
|
|
24835
24961
|
gauge("loki_cost_usd", "Estimated total cost in USD", "gauge", cost.estimated_cost_usd !== null ? [`loki_cost_usd ${cost.estimated_cost_usd}`] : null);
|
|
24836
24962
|
let events2 = null;
|
|
24837
24963
|
try {
|
|
24838
|
-
events2 = readFileSync14(
|
|
24964
|
+
events2 = readFileSync14(join23(loki, "events.jsonl"), "utf8").split(`
|
|
24839
24965
|
`).filter((l) => l.trim()).length;
|
|
24840
24966
|
} catch {}
|
|
24841
24967
|
gauge("loki_events_total", "Total number of events recorded", "counter", events2 !== null ? [`loki_events_total ${events2}`] : null);
|
|
@@ -24847,19 +24973,19 @@ function buildMetricsText(repoDir, now2 = Date.now()) {
|
|
|
24847
24973
|
}
|
|
24848
24974
|
gauge("loki_uptime_seconds", "Seconds since session started", "gauge", uptime !== null ? [`loki_uptime_seconds ${uptime}`] : null);
|
|
24849
24975
|
let total = 0, ver = 0, gaps = 0, notver = 0, unk = 0, att = 0, sig = 0;
|
|
24850
|
-
const pdir =
|
|
24976
|
+
const pdir = join23(loki, "proofs");
|
|
24851
24977
|
let entries = [];
|
|
24852
24978
|
try {
|
|
24853
24979
|
entries = readdirSync7(pdir).sort();
|
|
24854
24980
|
} catch {}
|
|
24855
24981
|
for (const e of entries) {
|
|
24856
24982
|
try {
|
|
24857
|
-
if (!
|
|
24983
|
+
if (!statSync10(join23(pdir, e)).isDirectory())
|
|
24858
24984
|
continue;
|
|
24859
24985
|
} catch {
|
|
24860
24986
|
continue;
|
|
24861
24987
|
}
|
|
24862
|
-
const d = readJson(
|
|
24988
|
+
const d = readJson(join23(pdir, e, "proof.json"));
|
|
24863
24989
|
if (!isObj8(d))
|
|
24864
24990
|
continue;
|
|
24865
24991
|
total++;
|
|
@@ -24904,7 +25030,7 @@ function mount14(ctx) {
|
|
|
24904
25030
|
|
|
24905
25031
|
// src/server/routes/session_control.ts
|
|
24906
25032
|
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readdirSync as readdirSync8, readFileSync as readFileSync15, unlinkSync as unlinkSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
24907
|
-
import { dirname as dirname5, join as
|
|
25033
|
+
import { dirname as dirname5, join as join24 } from "path";
|
|
24908
25034
|
var isObj9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
24909
25035
|
var ACTIONS = ["pause", "resume", "stop", "council-review"];
|
|
24910
25036
|
var isAction = (v) => ACTIONS.includes(v);
|
|
@@ -24929,7 +25055,7 @@ var readJson2 = (p) => {
|
|
|
24929
25055
|
};
|
|
24930
25056
|
function runnerPid(loki) {
|
|
24931
25057
|
try {
|
|
24932
|
-
const pid = parseInt(readFileSync15(
|
|
25058
|
+
const pid = parseInt(readFileSync15(join24(loki, "loki.pid"), "utf8").trim(), 10);
|
|
24933
25059
|
return pidAlive2(pid) ? pid : null;
|
|
24934
25060
|
} catch {
|
|
24935
25061
|
return null;
|
|
@@ -24939,18 +25065,18 @@ function applyControl(repoDir, action) {
|
|
|
24939
25065
|
const loki = lokiDirOf(repoDir);
|
|
24940
25066
|
const running = runnerPid(loki) !== null;
|
|
24941
25067
|
const put = (rel) => {
|
|
24942
|
-
const f =
|
|
25068
|
+
const f = join24(loki, rel);
|
|
24943
25069
|
mkdirSync4(dirname5(f), { recursive: true });
|
|
24944
25070
|
writeFileSync7(f, new Date().toISOString());
|
|
24945
25071
|
};
|
|
24946
25072
|
if (action === "council-review") {
|
|
24947
|
-
put(
|
|
25073
|
+
put(join24("signals", "COUNCIL_REVIEW_REQUESTED"));
|
|
24948
25074
|
return { status: 200, body: { success: true, message: "Council review requested" } };
|
|
24949
25075
|
}
|
|
24950
25076
|
if (action === "resume") {
|
|
24951
25077
|
for (const n2 of ["PAUSE", "STOP"]) {
|
|
24952
25078
|
try {
|
|
24953
|
-
unlinkSync2(
|
|
25079
|
+
unlinkSync2(join24(loki, n2));
|
|
24954
25080
|
} catch {}
|
|
24955
25081
|
}
|
|
24956
25082
|
return running ? { status: 200, body: { success: true, message: "Session resumed", process_verified: true } } : { status: 503, body: { success: false, message: "Session process is not running; the signal files were cleared" } };
|
|
@@ -24970,16 +25096,16 @@ function runControl(db, repoDir, action, c, via) {
|
|
|
24970
25096
|
return c.json(r.body, r.status);
|
|
24971
25097
|
}
|
|
24972
25098
|
function councilState(loki) {
|
|
24973
|
-
const f =
|
|
25099
|
+
const f = join24(loki, "council", "state.json");
|
|
24974
25100
|
if (!existsSync11(f))
|
|
24975
25101
|
return { enabled: false, total_votes: 0, verdicts: [] };
|
|
24976
25102
|
const d = readJson2(f);
|
|
24977
25103
|
return isObj9(d) ? d : { enabled: null, total_votes: null, verdicts: null, error: "unreadable_state" };
|
|
24978
25104
|
}
|
|
24979
25105
|
function councilVerdicts(loki, limit = 20) {
|
|
24980
|
-
const st = readJson2(
|
|
25106
|
+
const st = readJson2(join24(loki, "council", "state.json"));
|
|
24981
25107
|
const verdicts = isObj9(st) && Array.isArray(st.verdicts) ? st.verdicts : [];
|
|
24982
|
-
const votes =
|
|
25108
|
+
const votes = join24(loki, "council", "votes");
|
|
24983
25109
|
const details = [];
|
|
24984
25110
|
let names = [];
|
|
24985
25111
|
try {
|
|
@@ -24993,8 +25119,8 @@ function councilVerdicts(loki, limit = 20) {
|
|
|
24993
25119
|
}
|
|
24994
25120
|
};
|
|
24995
25121
|
for (const n2 of names.slice(0, limit)) {
|
|
24996
|
-
const dir =
|
|
24997
|
-
const ev = text2(
|
|
25122
|
+
const dir = join24(votes, n2), d = { iteration: n2 };
|
|
25123
|
+
const ev = text2(join24(dir, "evidence.md"));
|
|
24998
25124
|
if (ev !== null)
|
|
24999
25125
|
d.evidence_preview = ev.slice(0, 500);
|
|
25000
25126
|
let files = [];
|
|
@@ -25002,10 +25128,10 @@ function councilVerdicts(loki, limit = 20) {
|
|
|
25002
25128
|
files = readdirSync8(dir).filter((f) => /^member-.*\.txt$/.test(f)).sort();
|
|
25003
25129
|
} catch {}
|
|
25004
25130
|
d.members = files.flatMap((f) => {
|
|
25005
|
-
const t = text2(
|
|
25131
|
+
const t = text2(join24(dir, f));
|
|
25006
25132
|
return t === null ? [] : [{ member: f.replace(/\.txt$/, ""), content: t.trim() }];
|
|
25007
25133
|
});
|
|
25008
|
-
const con = text2(
|
|
25134
|
+
const con = text2(join24(dir, "contrarian.txt"));
|
|
25009
25135
|
if (con !== null)
|
|
25010
25136
|
d.contrarian = con.trim();
|
|
25011
25137
|
details.push(d);
|
|
@@ -25016,7 +25142,7 @@ function councilConvergence(loki) {
|
|
|
25016
25142
|
const dataPoints = [];
|
|
25017
25143
|
let raw2 = "";
|
|
25018
25144
|
try {
|
|
25019
|
-
raw2 = readFileSync15(
|
|
25145
|
+
raw2 = readFileSync15(join24(loki, "council", "convergence.log"), "utf8");
|
|
25020
25146
|
} catch {}
|
|
25021
25147
|
for (const line2 of raw2.trim().split(`
|
|
25022
25148
|
`)) {
|
|
@@ -25032,7 +25158,7 @@ function councilConvergence(loki) {
|
|
|
25032
25158
|
}
|
|
25033
25159
|
function councilReport(loki) {
|
|
25034
25160
|
try {
|
|
25035
|
-
return { report: readFileSync15(
|
|
25161
|
+
return { report: readFileSync15(join24(loki, "council", "report.md"), "utf8") };
|
|
25036
25162
|
} catch {
|
|
25037
25163
|
return { report: null };
|
|
25038
25164
|
}
|
|
@@ -25045,7 +25171,7 @@ function councilTranscripts(loki, q) {
|
|
|
25045
25171
|
if (Number.isNaN(since))
|
|
25046
25172
|
return { error: "Invalid 'since' timestamp format; expected ISO8601" };
|
|
25047
25173
|
}
|
|
25048
|
-
const dir =
|
|
25174
|
+
const dir = join24(loki, "council", "transcripts");
|
|
25049
25175
|
let names = [];
|
|
25050
25176
|
try {
|
|
25051
25177
|
names = readdirSync8(dir).filter((f) => /^iter-.*\.json$/.test(f)).sort().reverse();
|
|
@@ -25054,7 +25180,7 @@ function councilTranscripts(loki, q) {
|
|
|
25054
25180
|
}
|
|
25055
25181
|
const out2 = [];
|
|
25056
25182
|
for (const n2 of names) {
|
|
25057
|
-
const rec = readJson2(
|
|
25183
|
+
const rec = readJson2(join24(dir, n2));
|
|
25058
25184
|
if (!isObj9(rec) || typeof rec.iteration_id !== "string")
|
|
25059
25185
|
continue;
|
|
25060
25186
|
if (since !== null) {
|
|
@@ -25106,12 +25232,12 @@ function mount15(ctx) {
|
|
|
25106
25232
|
|
|
25107
25233
|
// src/server/routes/integrations.ts
|
|
25108
25234
|
import { spawn as spawn4 } from "child_process";
|
|
25109
|
-
import { existsSync as existsSync12, readFileSync as readFileSync16, statSync as
|
|
25110
|
-
import { delimiter, join as
|
|
25235
|
+
import { existsSync as existsSync12, readFileSync as readFileSync16, statSync as statSync11 } from "fs";
|
|
25236
|
+
import { delimiter, join as join25 } from "path";
|
|
25111
25237
|
var GH_TIMEOUT_MS = 3000;
|
|
25112
25238
|
var isSet = (n2) => !!n2 && (process.env[n2] ?? "") !== "";
|
|
25113
25239
|
function ghAuthed(pathVar = process.env.PATH ?? "", timeoutMs = GH_TIMEOUT_MS) {
|
|
25114
|
-
const exe = pathVar.split(delimiter).filter(Boolean).map((d) =>
|
|
25240
|
+
const exe = pathVar.split(delimiter).filter(Boolean).map((d) => join25(d, "gh")).find((p) => existsSync12(p));
|
|
25115
25241
|
if (!exe)
|
|
25116
25242
|
return Promise.resolve(null);
|
|
25117
25243
|
return new Promise((resolve6) => {
|
|
@@ -25143,7 +25269,7 @@ function ghAuthed(pathVar = process.env.PATH ?? "", timeoutMs = GH_TIMEOUT_MS) {
|
|
|
25143
25269
|
function configuredName(repoDir, path) {
|
|
25144
25270
|
try {
|
|
25145
25271
|
const r = resolveConfigFile(repoDir);
|
|
25146
|
-
if (!r.ok || !r.exists ||
|
|
25272
|
+
if (!r.ok || !r.exists || statSync11(r.file).size > 1e6)
|
|
25147
25273
|
return null;
|
|
25148
25274
|
const doc = $parseDocument(readFileSync16(r.file, "utf8"));
|
|
25149
25275
|
if (doc.errors.length)
|
|
@@ -25156,8 +25282,8 @@ function configuredName(repoDir, path) {
|
|
|
25156
25282
|
}
|
|
25157
25283
|
function mcpServers(repoDir) {
|
|
25158
25284
|
try {
|
|
25159
|
-
const p =
|
|
25160
|
-
if (!existsSync12(p) ||
|
|
25285
|
+
const p = join25(repoDir, ".mcp.json");
|
|
25286
|
+
if (!existsSync12(p) || statSync11(p).size > 1e6)
|
|
25161
25287
|
return null;
|
|
25162
25288
|
const j = JSON.parse(readFileSync16(p, "utf8"));
|
|
25163
25289
|
return j.mcpServers && typeof j.mcpServers === "object" ? Object.keys(j.mcpServers).length : null;
|
|
@@ -25186,7 +25312,7 @@ function conv(s) {
|
|
|
25186
25312
|
}
|
|
25187
25313
|
async function listIntegrations(repoDir, gh = () => ghAuthed()) {
|
|
25188
25314
|
const rows = [];
|
|
25189
|
-
const gitEnv2 = configuredName(repoDir,
|
|
25315
|
+
const gitEnv2 = configuredName(repoDir, "git.token_env".split("."));
|
|
25190
25316
|
const ghOk = await gh();
|
|
25191
25317
|
const gitEnvSet = isSet(gitEnv2);
|
|
25192
25318
|
rows.push({
|
|
@@ -25548,7 +25674,7 @@ function mount18(ctx) {
|
|
|
25548
25674
|
// src/server/routes/providers.ts
|
|
25549
25675
|
import { spawn as spawn6 } from "child_process";
|
|
25550
25676
|
import { existsSync as existsSync13, readFileSync as readFileSync17 } from "fs";
|
|
25551
|
-
import { delimiter as delimiter2, join as
|
|
25677
|
+
import { delimiter as delimiter2, join as join26 } from "path";
|
|
25552
25678
|
var ORDER = ["claude", "codex", "cline", "aider", "opencode"];
|
|
25553
25679
|
var DEPRECATED = ["gemini"];
|
|
25554
25680
|
var AUTH_ENV = {
|
|
@@ -25564,7 +25690,7 @@ function findOnPath(bin, pathVar) {
|
|
|
25564
25690
|
for (const d of pathVar.split(delimiter2)) {
|
|
25565
25691
|
if (!d)
|
|
25566
25692
|
continue;
|
|
25567
|
-
const p =
|
|
25693
|
+
const p = join26(d, bin);
|
|
25568
25694
|
if (existsSync13(p))
|
|
25569
25695
|
return p;
|
|
25570
25696
|
}
|
|
@@ -25609,14 +25735,14 @@ function probeCli(bin, timeoutMs, pathVar = process.env.PATH ?? "") {
|
|
|
25609
25735
|
});
|
|
25610
25736
|
}
|
|
25611
25737
|
function providersDir() {
|
|
25612
|
-
const cands = [process.env.LOKI_PROVIDERS_DIR,
|
|
25613
|
-
return cands.find((d) => !!d && existsSync13(
|
|
25738
|
+
const cands = [process.env.LOKI_PROVIDERS_DIR, join26(import.meta.dir, "../../../../../providers"), join26(import.meta.dir, "../../../providers")];
|
|
25739
|
+
return cands.find((d) => !!d && existsSync13(join26(d, "model_catalog.json"))) ?? null;
|
|
25614
25740
|
}
|
|
25615
25741
|
function loadCatalog(dir) {
|
|
25616
25742
|
if (!dir)
|
|
25617
25743
|
return { providers: {}, updated: null };
|
|
25618
25744
|
try {
|
|
25619
|
-
const j = JSON.parse(readFileSync17(
|
|
25745
|
+
const j = JSON.parse(readFileSync17(join26(dir, "model_catalog.json"), "utf8"));
|
|
25620
25746
|
return { providers: j.providers ?? {}, updated: typeof j.updated === "string" ? j.updated : null };
|
|
25621
25747
|
} catch {
|
|
25622
25748
|
return { providers: {}, updated: null };
|
|
@@ -25739,7 +25865,7 @@ function mount20(ctx) {
|
|
|
25739
25865
|
// src/server/routes/verify.ts
|
|
25740
25866
|
import { readFileSync as readFileSync54, realpathSync as realpathSync21 } from "fs";
|
|
25741
25867
|
import { createPublicKey as createPublicKey5 } from "crypto";
|
|
25742
|
-
import { join as
|
|
25868
|
+
import { join as join67, sep as sep12 } from "path";
|
|
25743
25869
|
init_verify_cmd();
|
|
25744
25870
|
init_seal();
|
|
25745
25871
|
init_receipt_dsse();
|
|
@@ -25766,15 +25892,15 @@ function mount21(ctx) {
|
|
|
25766
25892
|
return done(404, "receipt not available", "not_found");
|
|
25767
25893
|
let runDir, file;
|
|
25768
25894
|
try {
|
|
25769
|
-
const root = realpathSync21(
|
|
25770
|
-
runDir = realpathSync21(
|
|
25771
|
-
if (runDir !==
|
|
25895
|
+
const root = realpathSync21(join67(repo.p, ".loki", "runs"));
|
|
25896
|
+
runDir = realpathSync21(join67(root, run2));
|
|
25897
|
+
if (runDir !== join67(root, run2))
|
|
25772
25898
|
return done(404, "receipt not found", "not_found");
|
|
25773
|
-
file = realpathSync21(
|
|
25899
|
+
file = realpathSync21(join67(runDir, "receipt.json"));
|
|
25774
25900
|
} catch {
|
|
25775
25901
|
return done(404, "receipt not found", "not_found");
|
|
25776
25902
|
}
|
|
25777
|
-
if (!file.startsWith(runDir +
|
|
25903
|
+
if (!file.startsWith(runDir + sep12))
|
|
25778
25904
|
return done(404, "receipt not found", "not_found");
|
|
25779
25905
|
let integrity, reasons, sha4 = null, outcome = "UNREADABLE";
|
|
25780
25906
|
try {
|
|
@@ -25852,7 +25978,7 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
|
|
|
25852
25978
|
|
|
25853
25979
|
// src/server/legacy/shim.ts
|
|
25854
25980
|
import { existsSync as existsSync45, readFileSync as readFileSync55 } from "fs";
|
|
25855
|
-
import { join as
|
|
25981
|
+
import { join as join68 } from "path";
|
|
25856
25982
|
|
|
25857
25983
|
// src/server/legacy/routes.ts
|
|
25858
25984
|
var LEGACY_ROUTES = [
|
|
@@ -26230,7 +26356,7 @@ var logged = new Set;
|
|
|
26230
26356
|
var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
|
|
26231
26357
|
var NOT_SUPPORTED = "not yet supported by the Control Plane";
|
|
26232
26358
|
var repoVersion = () => {
|
|
26233
|
-
for (const f of [
|
|
26359
|
+
for (const f of [join68(import.meta.dir, "../../../../../VERSION")]) {
|
|
26234
26360
|
try {
|
|
26235
26361
|
if (existsSync45(f))
|
|
26236
26362
|
return readFileSync55(f, "utf8").trim();
|
|
@@ -26415,7 +26541,7 @@ function legacyShim(opts) {
|
|
|
26415
26541
|
|
|
26416
26542
|
// src/server/app.ts
|
|
26417
26543
|
var MAX_BODY2 = 1e6;
|
|
26418
|
-
var defaultUiDir = () => [
|
|
26544
|
+
var defaultUiDir = () => [join69(import.meta.dir, "../../ui/dist"), join69(import.meta.dir, "../ui/dist")].find((d) => existsSync46(join69(d, "index.html")));
|
|
26419
26545
|
function createApp(opts) {
|
|
26420
26546
|
const uiDir = opts.uiDir ?? defaultUiDir();
|
|
26421
26547
|
const { db, sqlite } = openDb(opts.dbPath);
|
|
@@ -26444,7 +26570,7 @@ function createApp(opts) {
|
|
|
26444
26570
|
await next();
|
|
26445
26571
|
});
|
|
26446
26572
|
const readInstalled = () => {
|
|
26447
|
-
for (const f of [process.env.LOKI_VERSION_FILE,
|
|
26573
|
+
for (const f of [process.env.LOKI_VERSION_FILE, join69(import.meta.dir, "../../../../VERSION")]) {
|
|
26448
26574
|
try {
|
|
26449
26575
|
if (f)
|
|
26450
26576
|
return readFileSync56(f, "utf8").trim() || "unknown";
|
|
@@ -26558,11 +26684,11 @@ function createApp(opts) {
|
|
|
26558
26684
|
return c.json({ error: "not found" }, 404);
|
|
26559
26685
|
const root = resolve15(uiDir);
|
|
26560
26686
|
const f = resolve15(root, `.${p}`);
|
|
26561
|
-
if (f.startsWith(root +
|
|
26687
|
+
if (f.startsWith(root + sep13) && existsSync46(f) && statSync23(f).isFile())
|
|
26562
26688
|
return new Response(Bun.file(f));
|
|
26563
26689
|
if (/\.[a-z0-9]+$/i.test(p))
|
|
26564
26690
|
return c.json({ error: "not found" }, 404);
|
|
26565
|
-
return new Response(Bun.file(
|
|
26691
|
+
return new Response(Bun.file(join69(root, "index.html")));
|
|
26566
26692
|
});
|
|
26567
26693
|
return { app, db, close: () => {
|
|
26568
26694
|
clearInterval(reconciler);
|