loki-mode 11.63.7 → 11.63.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/FAILURE-CLASSES.md +32 -0
- package/loki-ts/dist/loki.js +1100 -1100
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +70 -52
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-Cp2bWPgv.js → AdminPage-MRok4gpK.js} +1 -1
- package/web-app/dist/assets/{Avatar-BWkjgfpQ.js → Avatar-C5naIgXq.js} +1 -1
- package/web-app/dist/assets/{Badge-DplLKpsq.js → Badge-zigD7yw6.js} +1 -1
- package/web-app/dist/assets/{Button-Bi9cmTkv.js → Button-DcMIUy9q.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-ZBt9jJqb.js → CockpitPage-D7Bunb6e.js} +1 -1
- package/web-app/dist/assets/{ComparePage-BtfjcKUw.js → ComparePage-r1MlVPTe.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-D7gzKuQl.js → ErrorBoundary-Dk4uHaS4.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-B0qgQSt7.js → EvidenceReceiptPanel-C9ab9NGb.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-D7DLUV5y.js → GitHubIssuesPanel-DXE21JW5.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-B-tSxFMu.js → GitHubPRsPanel-CEEJDQaF.js} +1 -1
- package/web-app/dist/assets/{HomePage-9zMRoQ2-.js → HomePage-Cc1RJgQP.js} +2 -2
- package/web-app/dist/assets/{LoginPage-CHahatjI.js → LoginPage-BgK3Un7s.js} +1 -1
- package/web-app/dist/assets/{MagicPage-CWDBY117.js → MagicPage-DracOHYk.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-i0sQqMu5.js → MetricsPage-dpzE7rHk.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-Cep2hjC4.js → NotFoundPage-CwR1prG_.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-B9jVtdf_.js → ProjectPage-DDeC9Cfy.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DT6qTa8F.js → ProjectsPage-o3OfxJRf.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DMVIxFyL.js → SettingsPage-PI85tG1v.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-CenA1vR9.js → ShowcasePage-iYe1cAHf.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-Qqy7C834.js → SystemSettingsPage-B-dy7aEZ.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-Dbc7PMBa.js → TeamsPage-CKN0wlJv.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-BNpJysCP.js → TemplatesPage-2Kkm5kRO.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-DrhATQOU.js → TerminalOutput-CsrWjt5Z.js} +1 -1
- package/web-app/dist/assets/{activity-DO1Lb3p_.js → activity-DRUoEUMH.js} +1 -1
- package/web-app/dist/assets/{bell-6USNNqOU.js → bell-DVtpHIbp.js} +1 -1
- package/web-app/dist/assets/{bot-C3WPr7Jc.js → bot-DQR3Z51i.js} +1 -1
- package/web-app/dist/assets/{check-0PtXKfN0.js → check-Cuz-bgBo.js} +1 -1
- package/web-app/dist/assets/{chevron-left-xlhDqXSB.js → chevron-left-D6t1u2bZ.js} +1 -1
- package/web-app/dist/assets/{circle-alert-GKhWaSzf.js → circle-alert-BrbRSY0L.js} +1 -1
- package/web-app/dist/assets/{clock-ui1bNcXF.js → clock-Ch7TiuRG.js} +1 -1
- package/web-app/dist/assets/{cloud-CKrUG6Hi.js → cloud-D9FgjItJ.js} +1 -1
- package/web-app/dist/assets/{code-xml-E0yaCnLv.js → code-xml-CTOxq-IZ.js} +1 -1
- package/web-app/dist/assets/{database-CKoePHfR.js → database-BXiIVvsI.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-BLLEGeDo.js → dollar-sign-DSOoLXMA.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-DNkK9sHC.js → file-code-corner-BSZSLbUC.js} +1 -1
- package/web-app/dist/assets/{file-plus-BZRpulA3.js → file-plus-wDq2a4vY.js} +1 -1
- package/web-app/dist/assets/{globe-B8KkmQx6.js → globe-DJKmdNYO.js} +1 -1
- package/web-app/dist/assets/{hammer-Bm6aLg_e.js → hammer-DL5Cuz8k.js} +1 -1
- package/web-app/dist/assets/{index-BQ_6SUYj.js → index-D7h5Efxx.js} +3 -3
- package/web-app/dist/assets/{layers-BwI4LLZC.js → layers-BMAnvaPd.js} +1 -1
- package/web-app/dist/assets/{loader-circle-DNNb2uHm.js → loader-circle-21-GyiHr.js} +1 -1
- package/web-app/dist/assets/{lock-C_-piZan.js → lock-D1n5V1WB.js} +1 -1
- package/web-app/dist/assets/{package-CGJ-QLzA.js → package-BZQKnof2.js} +1 -1
- package/web-app/dist/assets/{plus-BI3waAt8.js → plus-DcZZjvq4.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-Cyc0Be2K.js → refresh-cw-DhVQ14GV.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-BMF9rcHQ.js → rotate-ccw-B3FdQA22.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DeoapOot.js → scroll-text-CeT_KqRE.js} +1 -1
- package/web-app/dist/assets/{server-DvyYi0cU.js → server-DqUuxOrt.js} +1 -1
- package/web-app/dist/assets/{shield-alert-Bon6ZnUv.js → shield-alert-BtatVxYq.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-98YsSw4r.js → thumbs-up-D4fCUUuq.js} +1 -1
- package/web-app/dist/assets/{trash-2-1U-mCJzW.js → trash-2-BHNJqbo6.js} +1 -1
- package/web-app/dist/assets/{trending-down-BlHQF7ZA.js → trending-down-CPggV6Fp.js} +1 -1
- package/web-app/dist/assets/{trending-up-C3BNDS1Z.js → trending-up-CnR04ozf.js} +1 -1
- package/web-app/dist/assets/{upload-CGW0PxJo.js → upload-DGc43kol.js} +1 -1
- package/web-app/dist/assets/{usePolling-l8CCUq6q.js → usePolling-CJr1dy5R.js} +1 -1
- package/web-app/dist/assets/{user-CTHngdi9.js → user-45NLDfA3.js} +1 -1
- package/web-app/dist/index.html +1 -1
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "11.63.
|
|
4
|
+
"version": "11.63.8",
|
|
5
5
|
"description": "An autonomous software factory that knows what it is supposed to deliver, and proves it did.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -160,5 +160,5 @@
|
|
|
160
160
|
"dependencies": {
|
|
161
161
|
"@resvg/resvg-wasm": "^2.6.2"
|
|
162
162
|
},
|
|
163
|
-
"gitHead": "
|
|
163
|
+
"gitHead": "8eac2523ffe4553e7685a7b8e248b313f3f9d6c9"
|
|
164
164
|
}
|
|
@@ -10228,6 +10228,12 @@ function runnerCmd(t, repoDir) {
|
|
|
10228
10228
|
return CARGO_TEST_FILE_RE.test(t.path) ? ["cargo", ["test", "--test", basename12(t.path, ".rs")]] : ["cargo", ["test"]];
|
|
10229
10229
|
}
|
|
10230
10230
|
}
|
|
10231
|
+
function fullSuiteCmd(runner, repoDir) {
|
|
10232
|
+
if (runner !== "pytest")
|
|
10233
|
+
return FULL_SUITE_STATIC[runner];
|
|
10234
|
+
const [cmd, interpreter, pre] = resolveTool(repoDir, "python", "python3", "python");
|
|
10235
|
+
return { cmd, args: [...pre, "-m", "pytest", "-q"], interpreter };
|
|
10236
|
+
}
|
|
10231
10237
|
function commandFor(t, repoDir, api) {
|
|
10232
10238
|
const site = siteFor(api, repoDir, t.path);
|
|
10233
10239
|
const [cmd, args, interpreter] = runnerCmd(site ? { runner: t.runner, path: site.file } : t, repoDir);
|
|
@@ -10312,7 +10318,7 @@ var NO_TESTS_REASON = "no tests executed", NO_RUNNER_REASON = "no runner of this
|
|
|
10312
10318
|
}, EXCERPT_GROUP_CAP = 1500, EXCERPT_TOTAL_CAP = 6144, verifyJobs = () => {
|
|
10313
10319
|
const n2 = Number.parseInt(process.env["LOKI_E10_VERIFY_JOBS"] ?? "", 10);
|
|
10314
10320
|
return Number.isFinite(n2) && n2 >= 1 ? Math.min(n2, 8) : 1;
|
|
10315
|
-
},
|
|
10321
|
+
}, FULL_SUITE_STATIC, ALREADY_FAILING_ON_BASE = "already failing on base, not caused by this change", SKIPPED_BY_REPO = "skipped by the repo on base and head", checkResultLabel = (result, preRed, repoSkipped = false) => result === "fail" && preRed ? `fail (${ALREADY_FAILING_ON_BASE})` : result === "not_run" && repoSkipped ? `not_run (${SKIPPED_BY_REPO})` : result, blobSha = (b, hex) => createHash8(hex === 64 ? "sha256" : "sha1").update(Buffer.concat([Buffer.from(`blob ${b.length}\x00`), b])).digest("hex");
|
|
10316
10322
|
var init_check_result = __esm(() => {
|
|
10317
10323
|
init_resolve();
|
|
10318
10324
|
init_testmap();
|
|
@@ -10362,8 +10368,7 @@ var init_check_result = __esm(() => {
|
|
|
10362
10368
|
DOC_FILE = /\.(md|mdx|txt|rst|adoc)$/i;
|
|
10363
10369
|
OWNER_FILES = [".github/CODEOWNERS", "CODEOWNERS", "docs/CODEOWNERS"];
|
|
10364
10370
|
CRITICAL_TOKENS = /^(release|publish|sign|signing|signer|auth|security|seal|verif\w*)$/i;
|
|
10365
|
-
|
|
10366
|
-
pytest: { cmd: "python", args: ["-m", "pytest", "-q"] },
|
|
10371
|
+
FULL_SUITE_STATIC = {
|
|
10367
10372
|
vitest: { cmd: "npx", args: ["vitest", "run"] },
|
|
10368
10373
|
jest: { cmd: "npx", args: ["jest"] },
|
|
10369
10374
|
bun: { cmd: "bun", args: ["test"] },
|
|
@@ -15264,11 +15269,12 @@ async function sealEvidence(repoDir, runDir, o, notProven, signal, emit) {
|
|
|
15264
15269
|
const ev = await captureVisualEvidence(repoDir, runDir, cf, { signal, onServer: (pgid) => emit?.("session.started", "seal", { session_id: "visual-evidence", provider: "visual-evidence", model: null, pgid }) });
|
|
15265
15270
|
if (signal?.aborted)
|
|
15266
15271
|
throw new Error("seal aborted: visual evidence discarded");
|
|
15267
|
-
|
|
15272
|
+
const noUi = ev.skipped !== null && ev.skipped !== undefined && /^no package\.json$|^no dev, preview or start script$/.test(ev.skipped) && process.env["LOKI_VISUAL_EVIDENCE"] !== "1" && !cf.some(isPageFile);
|
|
15273
|
+
if (ev.skipped && !noUi)
|
|
15268
15274
|
notProven.add(`visual evidence skipped: ${ev.skipped}`);
|
|
15269
15275
|
if (ev.e2eSkipped)
|
|
15270
15276
|
notProven.add(ev.e2eSkipped);
|
|
15271
|
-
if (visualGateEnabled() && ev.skipped && !/^no changed page files/.test(ev.skipped))
|
|
15277
|
+
if (visualGateEnabled() && ev.skipped && !noUi && !/^no changed page files/.test(ev.skipped))
|
|
15272
15278
|
return { evidence_failed: ev.skipped };
|
|
15273
15279
|
return ev.screens.length > 0 ? { evidence_screens: ev.screens } : {};
|
|
15274
15280
|
}
|
|
@@ -15620,7 +15626,7 @@ async function runFullSuite(ctx, signal, opts, checks, notProven) {
|
|
|
15620
15626
|
return;
|
|
15621
15627
|
}
|
|
15622
15628
|
for (const runner of map.runners) {
|
|
15623
|
-
const spec =
|
|
15629
|
+
const spec = fullSuiteCmd(runner, ctx.repoDir);
|
|
15624
15630
|
const name = `full suite: ${runner}`;
|
|
15625
15631
|
if (!Bun.which(spec.cmd, opts.path ? { PATH: opts.path } : undefined)) {
|
|
15626
15632
|
checks.push({ name, cmd: [spec.cmd, ...spec.args].join(" "), result: "not_run", duration_s: 0 });
|
|
@@ -15854,7 +15860,7 @@ var init_deep = __esm(() => {
|
|
|
15854
15860
|
});
|
|
15855
15861
|
|
|
15856
15862
|
// ../../loki-ts/src/engine10/stages/verify.ts
|
|
15857
|
-
import { existsSync as existsSync39, mkdtempSync as mkdtempSync10, rmSync as rmSync19 } from "fs";
|
|
15863
|
+
import { existsSync as existsSync39, mkdtempSync as mkdtempSync10, readFileSync as readFileSync48, rmSync as rmSync19 } from "fs";
|
|
15858
15864
|
import { tmpdir as tmpdir11 } from "os";
|
|
15859
15865
|
import { basename as basename23, isAbsolute as isAbsolute11, join as join60, relative as relative12 } from "path";
|
|
15860
15866
|
async function runOnce2(cmd2, args, cwd, signal, opts) {
|
|
@@ -15971,13 +15977,25 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal,
|
|
|
15971
15977
|
function isLokiModeRepo(repoDir) {
|
|
15972
15978
|
return existsSync39(join60(repoDir, "scripts", "select-tests.sh"));
|
|
15973
15979
|
}
|
|
15980
|
+
function projectDeclaresRuff(repoDir) {
|
|
15981
|
+
if (["ruff.toml", ".ruff.toml"].some((f) => existsSync39(join60(repoDir, f))))
|
|
15982
|
+
return true;
|
|
15983
|
+
const files = ["pyproject.toml", "setup.cfg", "tox.ini", ".pre-commit-config.yaml", "Pipfile", "requirements.txt", "requirements-dev.txt", "dev-requirements.txt"];
|
|
15984
|
+
return files.some((f) => {
|
|
15985
|
+
try {
|
|
15986
|
+
return /\bruff\b/i.test(readFileSync48(join60(repoDir, f), "utf8"));
|
|
15987
|
+
} catch {
|
|
15988
|
+
return false;
|
|
15989
|
+
}
|
|
15990
|
+
});
|
|
15991
|
+
}
|
|
15974
15992
|
async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
15975
15993
|
const { api, ...runOpts } = opts;
|
|
15976
15994
|
opts = runOpts;
|
|
15977
15995
|
const pre = [];
|
|
15978
15996
|
const py = changed.filter((f) => f.endsWith(".py"));
|
|
15979
|
-
|
|
15980
|
-
|
|
15997
|
+
const [ruffCmd, interpreter, uvPre] = py.length ? resolveTool(ctx.repoDir, "ruff", "ruff") : ["ruff", "system", []];
|
|
15998
|
+
if (py.length && (interpreter !== "system" || Bun.which("ruff", { PATH: process.env["PATH"] ?? "" }) || projectDeclaresRuff(ctx.repoDir))) {
|
|
15981
15999
|
const c = await runCheck(ctx, "lint:ruff", ruffCmd, [...uvPre, "check", "--output-format=concise", ...py], signal, checks, { ...opts, interpreter, kind: "static" });
|
|
15982
16000
|
if (await excuseLint(ctx, signal, c, "ruff", ruffCmd, [...uvPre, "check"], ctx.repoDir, py, opts))
|
|
15983
16001
|
pre.push(c.name);
|
|
@@ -16192,7 +16210,7 @@ ${x}` : c.cmd };
|
|
|
16192
16210
|
|
|
16193
16211
|
// ../../loki-ts/src/engine10/stages/wall.ts
|
|
16194
16212
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
16195
|
-
import { existsSync as existsSync40, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync11, readFileSync as
|
|
16213
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync11, readFileSync as readFileSync49, readdirSync as readdirSync21, rmSync as rmSync20, writeFileSync as writeFileSync28 } from "fs";
|
|
16196
16214
|
import { tmpdir as tmpdir12 } from "os";
|
|
16197
16215
|
import { dirname as dirname26, join as join61, relative as relative13 } from "path";
|
|
16198
16216
|
|
|
@@ -16262,7 +16280,7 @@ function loadTaskText(ctx, fromPrior) {
|
|
|
16262
16280
|
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join61(ctx.runDir, "issue.json");
|
|
16263
16281
|
if (existsSync40(issueJsonPath)) {
|
|
16264
16282
|
try {
|
|
16265
|
-
const issue = JSON.parse(
|
|
16283
|
+
const issue = JSON.parse(readFileSync49(issueJsonPath, "utf8"));
|
|
16266
16284
|
const text2 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
|
|
16267
16285
|
|
|
16268
16286
|
`);
|
|
@@ -16322,20 +16340,20 @@ async function wallAuthor(ctx, signal, retry) {
|
|
|
16322
16340
|
}
|
|
16323
16341
|
const planText = typeof prior.plan?.plan === "string" ? prior.plan.plan : null, repoFiles = repoMap?.files ?? [];
|
|
16324
16342
|
const oor = () => readdirSync21(cwd).filter((f) => f.startsWith(WALL_PREFIX)).flatMap((name) => {
|
|
16325
|
-
const text2 =
|
|
16343
|
+
const text2 = readFileSync49(join61(cwd, name), "utf8"), why = outOfRepoTarget(text2) ?? phantomReason(phantomRepoPaths(text2, name, targetDir, ctx.repoDir, planText), repoFiles, relative13(ctx.repoDir, targetDir), pkg?.root ?? "");
|
|
16326
16344
|
return why ? [{ name, why }] : [];
|
|
16327
16345
|
});
|
|
16328
16346
|
const bad1 = oor();
|
|
16329
16347
|
if (bad1.length > 0 && !signal.aborted && !ctx.overCap?.())
|
|
16330
16348
|
await ctx.sessions.run({ stage: "wall", brief: withStagePrefix(outOfRepoReask("Rewrite these Wall files in place, keeping the same names and acceptance coverage.", bad1)), tier: "development", model, iterationId: `${iterationId}-oor`, limitS: wallLimitS(sz.size), signal, cwd });
|
|
16331
|
-
const oorBad = new Map(oor().map((b) => [b.name, b.why])), all = readdirSync21(cwd).filter((f) => f.startsWith(WALL_PREFIX)), held = stashHoldout({ runId: ctx.runId, repoDir: ctx.repoDir, srcDir: cwd, targetDir, names: all.filter((n2) => !oorBad.has(n2) && !conventionViolation(conv2, n2,
|
|
16349
|
+
const oorBad = new Map(oor().map((b) => [b.name, b.why])), all = readdirSync21(cwd).filter((f) => f.startsWith(WALL_PREFIX)), held = stashHoldout({ runId: ctx.runId, repoDir: ctx.repoDir, srcDir: cwd, targetDir, names: all.filter((n2) => !oorBad.has(n2) && !conventionViolation(conv2, n2, readFileSync49(join61(cwd, n2), "utf8"))), runnerOf: (n2) => guessRunner(n2, runners) }), generated = all.filter((n2) => !held?.names.has(n2));
|
|
16332
16350
|
const sealedDir = join61(ctx.runDir, "wall");
|
|
16333
16351
|
if (generated.length > 0)
|
|
16334
16352
|
mkdirSync25(sealedDir, { recursive: true });
|
|
16335
16353
|
const contents = new Map;
|
|
16336
16354
|
const discarded = [];
|
|
16337
16355
|
for (const name of generated) {
|
|
16338
|
-
const content =
|
|
16356
|
+
const content = readFileSync49(join61(cwd, name), "utf8"), oorWhy = oorBad.get(name), bad = oorWhy ?? conventionViolation(conv2, name, content);
|
|
16339
16357
|
writeFileSync28(join61(sealedDir, name), content, "utf8");
|
|
16340
16358
|
if (oorWhy)
|
|
16341
16359
|
discarded.push({ file: name, reason: `${oorWhy}; wall test discarded after one rewrite request` });
|
|
@@ -16459,7 +16477,7 @@ var init_wall = __esm(() => {
|
|
|
16459
16477
|
});
|
|
16460
16478
|
|
|
16461
16479
|
// ../../loki-ts/src/e10ext/discard.ts
|
|
16462
|
-
import { chmodSync as chmodSync6, closeSync as closeSync9, lstatSync as lstatSync16, mkdirSync as mkdirSync26, openSync as openSync9, readFileSync as
|
|
16480
|
+
import { chmodSync as chmodSync6, closeSync as closeSync9, lstatSync as lstatSync16, mkdirSync as mkdirSync26, openSync as openSync9, readFileSync as readFileSync50, realpathSync as realpathSync23, rmdirSync, unlinkSync as unlinkSync7, writeFileSync as writeFileSync29 } from "fs";
|
|
16463
16481
|
import { dirname as dirname27, join as join62, relative as relative14, sep as sep14 } from "path";
|
|
16464
16482
|
function safeRestore(repoDir, f, want, mode) {
|
|
16465
16483
|
const root = realpathSync23(repoDir), fp = join62(root, f), rel = relative14(root, dirname27(fp));
|
|
@@ -16484,7 +16502,7 @@ function safeRestore(repoDir, f, want, mode) {
|
|
|
16484
16502
|
} catch {
|
|
16485
16503
|
st = null;
|
|
16486
16504
|
}
|
|
16487
|
-
if (st?.isFile() &&
|
|
16505
|
+
if (st?.isFile() && readFileSync50(fp).equals(want)) {
|
|
16488
16506
|
chmodSync6(fp, mode);
|
|
16489
16507
|
return;
|
|
16490
16508
|
}
|
|
@@ -16586,14 +16604,14 @@ var init_scope2 = __esm(() => {
|
|
|
16586
16604
|
});
|
|
16587
16605
|
|
|
16588
16606
|
// ../../loki-ts/src/council/role_agents.ts
|
|
16589
|
-
import { existsSync as existsSync41, readdirSync as readdirSync22, readFileSync as
|
|
16607
|
+
import { existsSync as existsSync41, readdirSync as readdirSync22, readFileSync as readFileSync51 } from "fs";
|
|
16590
16608
|
import { homedir as homedir9 } from "os";
|
|
16591
16609
|
import { join as join63 } from "path";
|
|
16592
16610
|
function agentDirs(repoDir, env = process.env) {
|
|
16593
16611
|
return [env["LOKI_AGENTS_PROJECT_DIR"] || join63(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join63(env["XDG_CONFIG_HOME"] || join63(homedir9(), ".config"), "loki", "agents")];
|
|
16594
16612
|
}
|
|
16595
16613
|
function parseAgent(file, stem2) {
|
|
16596
|
-
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(
|
|
16614
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync51(file, "utf8"));
|
|
16597
16615
|
if (!m)
|
|
16598
16616
|
return null;
|
|
16599
16617
|
const body = m[2].trim();
|
|
@@ -16713,14 +16731,14 @@ var init_colors = __esm(() => {
|
|
|
16713
16731
|
});
|
|
16714
16732
|
|
|
16715
16733
|
// ../../loki-ts/src/util/run_summary.ts
|
|
16716
|
-
import { existsSync as existsSync42, mkdirSync as mkdirSync28, readFileSync as
|
|
16734
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync28, readFileSync as readFileSync52, renameSync as renameSync13, statSync as statSync20, writeFileSync as writeFileSync30 } from "fs";
|
|
16717
16735
|
import { join as join65 } from "path";
|
|
16718
16736
|
function readRiskRecord(repoDir, sinceMs = 0) {
|
|
16719
16737
|
try {
|
|
16720
16738
|
const p = join65(repoDir, ".loki", "state", "risk-tier.json");
|
|
16721
16739
|
if (statSync20(p).mtimeMs < sinceMs)
|
|
16722
16740
|
return null;
|
|
16723
|
-
const r = JSON.parse(
|
|
16741
|
+
const r = JSON.parse(readFileSync52(p, "utf8"));
|
|
16724
16742
|
return r && typeof r === "object" ? r : null;
|
|
16725
16743
|
} catch {
|
|
16726
16744
|
return null;
|
|
@@ -16736,7 +16754,7 @@ var init_run_summary = __esm(() => {
|
|
|
16736
16754
|
});
|
|
16737
16755
|
|
|
16738
16756
|
// ../../loki-ts/src/engine10/stages/xreview.ts
|
|
16739
|
-
import { existsSync as existsSync43, readFileSync as
|
|
16757
|
+
import { existsSync as existsSync43, readFileSync as readFileSync53 } from "fs";
|
|
16740
16758
|
import { join as join66 } from "path";
|
|
16741
16759
|
function minVerdict(verdict, review) {
|
|
16742
16760
|
const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
|
|
@@ -16754,7 +16772,7 @@ function explicitReview(repoDir, env) {
|
|
|
16754
16772
|
if (!existsSync43(p))
|
|
16755
16773
|
continue;
|
|
16756
16774
|
try {
|
|
16757
|
-
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(
|
|
16775
|
+
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync53(p, "utf8"));
|
|
16758
16776
|
const v = asProvider(m?.[1]);
|
|
16759
16777
|
if (v)
|
|
16760
16778
|
return v;
|
|
@@ -16949,7 +16967,7 @@ See also: loki cost --detail (what a run ALREADY spent)
|
|
|
16949
16967
|
});
|
|
16950
16968
|
|
|
16951
16969
|
// ../../loki-ts/src/features/contract.ts
|
|
16952
|
-
import { existsSync as existsSync44, lstatSync as lstatSync17, mkdirSync as mkdirSync29, readFileSync as
|
|
16970
|
+
import { existsSync as existsSync44, lstatSync as lstatSync17, mkdirSync as mkdirSync29, readFileSync as readFileSync54, rmSync as rmSync21, writeFileSync as writeFileSync31 } from "fs";
|
|
16953
16971
|
import { dirname as dirname29, join as join67 } from "path";
|
|
16954
16972
|
import { createHash as createHash18 } from "crypto";
|
|
16955
16973
|
function contractEnabled(env = process.env) {
|
|
@@ -16998,7 +17016,7 @@ function readContract(repoDir) {
|
|
|
16998
17016
|
return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
|
|
16999
17017
|
let raw2;
|
|
17000
17018
|
try {
|
|
17001
|
-
raw2 =
|
|
17019
|
+
raw2 = readFileSync54(p);
|
|
17002
17020
|
} catch {
|
|
17003
17021
|
return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
|
|
17004
17022
|
}
|
|
@@ -17073,7 +17091,7 @@ var init_contract = __esm(() => {
|
|
|
17073
17091
|
|
|
17074
17092
|
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
17075
17093
|
import { createHash as createHash19 } from "crypto";
|
|
17076
|
-
import { existsSync as existsSync45, mkdirSync as mkdirSync30, readdirSync as readdirSync23, readFileSync as
|
|
17094
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync30, readdirSync as readdirSync23, readFileSync as readFileSync55, renameSync as renameSync14, statSync as statSync21, writeFileSync as writeFileSync32 } from "fs";
|
|
17077
17095
|
import { dirname as dirname30, join as join68 } from "path";
|
|
17078
17096
|
function sealGroup(runDir, rh) {
|
|
17079
17097
|
const manifestPath = join68(runDir, "group", "manifest.json");
|
|
@@ -17104,7 +17122,7 @@ function sealGroup(runDir, rh) {
|
|
|
17104
17122
|
const dir = join68(unitsDir(runDir), id), rp = join68(dir, "receipt.json"), ep = join68(dir, "events.jsonl");
|
|
17105
17123
|
let bytes;
|
|
17106
17124
|
try {
|
|
17107
|
-
bytes =
|
|
17125
|
+
bytes = readFileSync55(rp);
|
|
17108
17126
|
} catch {
|
|
17109
17127
|
return fail2(`unit ${id} sub-receipt missing`);
|
|
17110
17128
|
}
|
|
@@ -17121,7 +17139,7 @@ function sealGroup(runDir, rh) {
|
|
|
17121
17139
|
unit_id: id,
|
|
17122
17140
|
sub_receipt_sha256: sha3(bytes),
|
|
17123
17141
|
receipt_sha256: sub2["receipt_sha256"],
|
|
17124
|
-
events_file_sha256: existsSync45(ep) ? sha3(
|
|
17142
|
+
events_file_sha256: existsSync45(ep) ? sha3(readFileSync55(ep)) : null,
|
|
17125
17143
|
verdict,
|
|
17126
17144
|
goal: text2(u["goal"], 200),
|
|
17127
17145
|
files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
|
|
@@ -17165,13 +17183,13 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
17165
17183
|
try {
|
|
17166
17184
|
if (!statSync21(dir).isDirectory())
|
|
17167
17185
|
return bad(`unit ${id} is not a directory`);
|
|
17168
|
-
bytes =
|
|
17186
|
+
bytes = readFileSync55(rp);
|
|
17169
17187
|
} catch {
|
|
17170
17188
|
return bad(`unit ${id} sub-receipt missing`);
|
|
17171
17189
|
}
|
|
17172
17190
|
if (sha3(bytes) !== e["sub_receipt_sha256"])
|
|
17173
17191
|
return bad(`unit ${id} sub-receipt does not match its recorded hash`);
|
|
17174
|
-
const evSha = existsSync45(ep) ? sha3(
|
|
17192
|
+
const evSha = existsSync45(ep) ? sha3(readFileSync55(ep)) : null;
|
|
17175
17193
|
if (evSha !== (e["events_file_sha256"] ?? null))
|
|
17176
17194
|
return bad(`unit ${id} events.jsonl does not match its recorded hash`);
|
|
17177
17195
|
const sub2 = readJson6(rp);
|
|
@@ -17196,7 +17214,7 @@ function compositeVerdict(childVerdicts) {
|
|
|
17196
17214
|
}
|
|
17197
17215
|
var ID_RE, PASSING, sha3 = (b) => createHash19("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) => join68(runDir, "group", "units"), readJson6 = (p) => {
|
|
17198
17216
|
try {
|
|
17199
|
-
return JSON.parse(
|
|
17217
|
+
return JSON.parse(readFileSync55(p, "utf8"));
|
|
17200
17218
|
} catch {
|
|
17201
17219
|
return;
|
|
17202
17220
|
}
|
|
@@ -17214,7 +17232,7 @@ var init_seal_group = __esm(() => {
|
|
|
17214
17232
|
});
|
|
17215
17233
|
|
|
17216
17234
|
// ../../loki-ts/src/supply/supply_guard.ts
|
|
17217
|
-
import { existsSync as existsSync46, readFileSync as
|
|
17235
|
+
import { existsSync as existsSync46, readFileSync as readFileSync56, statSync as statSync22 } from "fs";
|
|
17218
17236
|
import { basename as basename25, join as join69 } from "path";
|
|
17219
17237
|
function supplyEnabled(env) {
|
|
17220
17238
|
return env["LOKI_SUPPLY_GUARD"] !== "0";
|
|
@@ -17236,7 +17254,7 @@ function readDeclared(repoDir) {
|
|
|
17236
17254
|
try {
|
|
17237
17255
|
if (statSync22(p).size > MAX_FILE_BYTES)
|
|
17238
17256
|
return { deps: [], problem: "declaration file too large" };
|
|
17239
|
-
const j = JSON.parse(
|
|
17257
|
+
const j = JSON.parse(readFileSync56(p, "utf8"));
|
|
17240
17258
|
if (!Array.isArray(j))
|
|
17241
17259
|
return { deps: [], problem: "declaration is not a JSON array" };
|
|
17242
17260
|
const deps = [];
|
|
@@ -17260,7 +17278,7 @@ function readAllowlist(repoDir) {
|
|
|
17260
17278
|
if (!existsSync46(p))
|
|
17261
17279
|
return new Set;
|
|
17262
17280
|
try {
|
|
17263
|
-
return new Set(
|
|
17281
|
+
return new Set(readFileSync56(p, "utf8").split(`
|
|
17264
17282
|
`).map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean));
|
|
17265
17283
|
} catch {
|
|
17266
17284
|
return new Set;
|
|
@@ -17443,7 +17461,7 @@ var MIN_AGE_DAYS = 7, DECLARED_FILE = "supply-declared.json", MAX_CHECKED = 50,
|
|
|
17443
17461
|
}
|
|
17444
17462
|
}, PUBLIC_HOSTS, hostOf = (u) => u.trim().toLowerCase().replace(/^[a-z][a-z0-9+.-]*:\/\//, "").replace(/^www\./, "").split(/[/?#\s]/)[0].replace(/^[^@]*@/, "").replace(/:\d+$/, ""), privateUrl = (u) => /[a-z0-9]/i.test(u) && !PUBLIC_HOSTS.has(hostOf(u)), readSmall = (p) => {
|
|
17445
17463
|
try {
|
|
17446
|
-
return statSync22(p).size <= MAX_FILE_BYTES ?
|
|
17464
|
+
return statSync22(p).size <= MAX_FILE_BYTES ? readFileSync56(p, "utf8") : "";
|
|
17447
17465
|
} catch {
|
|
17448
17466
|
return "";
|
|
17449
17467
|
}
|
|
@@ -17459,7 +17477,7 @@ var init_supply_guard = __esm(() => {
|
|
|
17459
17477
|
|
|
17460
17478
|
// ../../loki-ts/src/engine10/stages/seal.ts
|
|
17461
17479
|
import { createHash as createHash20 } from "crypto";
|
|
17462
|
-
import { existsSync as existsSync47, readdirSync as readdirSync24, mkdirSync as mkdirSync31, readFileSync as
|
|
17480
|
+
import { existsSync as existsSync47, readdirSync as readdirSync24, mkdirSync as mkdirSync31, readFileSync as readFileSync57 } from "fs";
|
|
17463
17481
|
import { basename as basename26, isAbsolute as isAbsolute13, join as join70, relative as relative15 } from "path";
|
|
17464
17482
|
function receiptSha256(r) {
|
|
17465
17483
|
const { verification: _v, receipt_sha256: _h, ...body } = r;
|
|
@@ -17725,7 +17743,7 @@ var init_seal = __esm(() => {
|
|
|
17725
17743
|
if (mp?.outcome === "no")
|
|
17726
17744
|
notProven.add(`Wall tests passed without the fix (mutation proof)${verdict !== verdict2 ? "; verdict downgraded to PARTIAL (LOKI_MUTATION_STRICT=1, declared behavior change)" : ""}`);
|
|
17727
17745
|
if (repo === null)
|
|
17728
|
-
notProven.add("repo not recorded by intake");
|
|
17746
|
+
notProven.add(o.intake && "repo" in o.intake ? "repo identity unknown: the repo has no origin remote (run: git remote add origin <url>)" : "repo not recorded by intake");
|
|
17729
17747
|
if (typeof o.intake?.resumed !== "boolean")
|
|
17730
17748
|
notProven.add("resume state not recorded by intake");
|
|
17731
17749
|
const stages = {};
|
|
@@ -17786,7 +17804,7 @@ var init_seal = __esm(() => {
|
|
|
17786
17804
|
provider: ctx.provider,
|
|
17787
17805
|
model: ctx.model,
|
|
17788
17806
|
resumed: o.intake?.resumed === true,
|
|
17789
|
-
events_sha256: sha2562(existsSync47(eventsPath) ?
|
|
17807
|
+
events_sha256: sha2562(existsSync47(eventsPath) ? readFileSync57(eventsPath) : ""),
|
|
17790
17808
|
...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
|
|
17791
17809
|
log_seal: true,
|
|
17792
17810
|
toolchain: collectToolchain(),
|
|
@@ -17842,14 +17860,14 @@ var init_seal = __esm(() => {
|
|
|
17842
17860
|
});
|
|
17843
17861
|
|
|
17844
17862
|
// ../../loki-ts/src/util/composite_seal.ts
|
|
17845
|
-
import { existsSync as existsSync48, readFileSync as
|
|
17863
|
+
import { existsSync as existsSync48, readFileSync as readFileSync58 } from "fs";
|
|
17846
17864
|
import { basename as basename27, dirname as dirname32, join as join71 } from "path";
|
|
17847
17865
|
function logProblem(runDir, integ) {
|
|
17848
17866
|
if (typeof integ["log_sha256"] !== "string")
|
|
17849
17867
|
return null;
|
|
17850
17868
|
let b;
|
|
17851
17869
|
try {
|
|
17852
|
-
b =
|
|
17870
|
+
b = readFileSync58(join71(runDir, "integration.log"));
|
|
17853
17871
|
} catch {
|
|
17854
17872
|
return "integration.log is missing but integration.json records its hash";
|
|
17855
17873
|
}
|
|
@@ -17872,7 +17890,7 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
17872
17890
|
return bad("body malformed");
|
|
17873
17891
|
let ibytes;
|
|
17874
17892
|
try {
|
|
17875
|
-
ibytes =
|
|
17893
|
+
ibytes = readFileSync58(join71(runDir, "integration.json"));
|
|
17876
17894
|
} catch {
|
|
17877
17895
|
return bad("integration.json missing");
|
|
17878
17896
|
}
|
|
@@ -17916,7 +17934,7 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
|
17916
17934
|
const rp = join71(runDir, rel);
|
|
17917
17935
|
let bytes;
|
|
17918
17936
|
try {
|
|
17919
|
-
bytes =
|
|
17937
|
+
bytes = readFileSync58(rp);
|
|
17920
17938
|
} catch {
|
|
17921
17939
|
return bad(`child ${repo} receipt missing`);
|
|
17922
17940
|
}
|
|
@@ -17965,7 +17983,7 @@ var init_keys_cmd = __esm(() => {
|
|
|
17965
17983
|
});
|
|
17966
17984
|
|
|
17967
17985
|
// ../../loki-ts/src/engine10/verify_cmd.ts
|
|
17968
|
-
import { existsSync as existsSync49, readFileSync as
|
|
17986
|
+
import { existsSync as existsSync49, readFileSync as readFileSync59, renameSync as renameSync15, statSync as statSync24, writeFileSync as writeFileSync34 } from "fs";
|
|
17969
17987
|
import { basename as basename28, dirname as dirname33, join as join72 } from "path";
|
|
17970
17988
|
import { createHash as createHash21, createPublicKey as createPublicKey4, verify as verify4 } from "crypto";
|
|
17971
17989
|
function pubFor(kid, given) {
|
|
@@ -17974,7 +17992,7 @@ function pubFor(kid, given) {
|
|
|
17974
17992
|
const active = loadSigningKey(false);
|
|
17975
17993
|
const pubs = (process.env["LOKI_RECEIPT_RETIRED_PUBKEYS"] ?? "").split(":").map((f) => f.trim()).filter(Boolean).flatMap((f) => {
|
|
17976
17994
|
try {
|
|
17977
|
-
return [createPublicKey4(
|
|
17995
|
+
return [createPublicKey4(readFileSync59(f))];
|
|
17978
17996
|
} catch {
|
|
17979
17997
|
return [];
|
|
17980
17998
|
}
|
|
@@ -18021,7 +18039,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
18021
18039
|
const path = join72(dirname33(receiptPath), "events.jsonl");
|
|
18022
18040
|
if (!existsSync49(path))
|
|
18023
18041
|
return "events.jsonl is missing";
|
|
18024
|
-
const raw2 =
|
|
18042
|
+
const raw2 = readFileSync59(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
|
|
18025
18043
|
`).filter((l) => l.trim() !== "");
|
|
18026
18044
|
if (events2.length !== lines2.length || events2.some((e, i) => e.seq !== i))
|
|
18027
18045
|
return "events.jsonl has a forged, edited or missing line";
|
|
@@ -18045,7 +18063,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
18045
18063
|
const seal = events2[done + 1], d = seal?.type === "log.sealed" ? seal.data : null;
|
|
18046
18064
|
if (!d)
|
|
18047
18065
|
return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
|
|
18048
|
-
const lines2 =
|
|
18066
|
+
const lines2 = readFileSync59(path, "utf8").split(`
|
|
18049
18067
|
`).filter((l) => l.trim() !== ""), sha4 = createHash21("sha256").update(lines2.slice(0, done + 1).join(`
|
|
18050
18068
|
`) + `
|
|
18051
18069
|
`).digest("hex");
|
|
@@ -18059,7 +18077,7 @@ async function verifyReceipt(receiptPath, deps = {}) {
|
|
|
18059
18077
|
return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
|
|
18060
18078
|
let receipt;
|
|
18061
18079
|
try {
|
|
18062
|
-
receipt = JSON.parse((deps.read ?? ((p) =>
|
|
18080
|
+
receipt = JSON.parse((deps.read ?? ((p) => readFileSync59(p, "utf8")))(receiptPath));
|
|
18063
18081
|
} catch {
|
|
18064
18082
|
return { verdict: "UNCHECKED", reasons: ["receipt.json is not valid JSON"] };
|
|
18065
18083
|
}
|
|
@@ -18148,7 +18166,7 @@ var init_verify_cmd = __esm(() => {
|
|
|
18148
18166
|
});
|
|
18149
18167
|
|
|
18150
18168
|
// src/server/app.ts
|
|
18151
|
-
import { existsSync as existsSync51, readFileSync as
|
|
18169
|
+
import { existsSync as existsSync51, readFileSync as readFileSync62, statSync as statSync25 } from "fs";
|
|
18152
18170
|
import { join as join75, resolve as resolve19, sep as sep16 } from "path";
|
|
18153
18171
|
|
|
18154
18172
|
// node_modules/hono/dist/request/constants.js
|
|
@@ -28460,7 +28478,7 @@ function mount20(ctx) {
|
|
|
28460
28478
|
}
|
|
28461
28479
|
|
|
28462
28480
|
// src/server/routes/verify.ts
|
|
28463
|
-
import { readFileSync as
|
|
28481
|
+
import { readFileSync as readFileSync60, realpathSync as realpathSync25 } from "fs";
|
|
28464
28482
|
import { createPublicKey as createPublicKey5 } from "crypto";
|
|
28465
28483
|
import { join as join73, sep as sep15 } from "path";
|
|
28466
28484
|
init_verify_cmd();
|
|
@@ -28512,7 +28530,7 @@ function mount21(ctx) {
|
|
|
28512
28530
|
sha4 = r.receiptSha256 ?? null;
|
|
28513
28531
|
}
|
|
28514
28532
|
try {
|
|
28515
|
-
outcome = outcomeOf(JSON.parse(
|
|
28533
|
+
outcome = outcomeOf(JSON.parse(readFileSync60(file, "utf8")));
|
|
28516
28534
|
} catch {
|
|
28517
28535
|
outcome = "UNREADABLE";
|
|
28518
28536
|
}
|
|
@@ -28574,7 +28592,7 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
|
|
|
28574
28592
|
}
|
|
28575
28593
|
|
|
28576
28594
|
// src/server/legacy/shim.ts
|
|
28577
|
-
import { existsSync as existsSync50, readFileSync as
|
|
28595
|
+
import { existsSync as existsSync50, readFileSync as readFileSync61 } from "fs";
|
|
28578
28596
|
import { join as join74 } from "path";
|
|
28579
28597
|
|
|
28580
28598
|
// src/server/legacy/routes.ts
|
|
@@ -28956,7 +28974,7 @@ var repoVersion = () => {
|
|
|
28956
28974
|
for (const f of [join74(import.meta.dir, "../../../../../VERSION")]) {
|
|
28957
28975
|
try {
|
|
28958
28976
|
if (existsSync50(f))
|
|
28959
|
-
return
|
|
28977
|
+
return readFileSync61(f, "utf8").trim();
|
|
28960
28978
|
} catch {}
|
|
28961
28979
|
}
|
|
28962
28980
|
return "unknown";
|
|
@@ -29170,7 +29188,7 @@ function createApp(opts) {
|
|
|
29170
29188
|
for (const f of [process.env.LOKI_VERSION_FILE, join75(import.meta.dir, "../../../../VERSION")]) {
|
|
29171
29189
|
try {
|
|
29172
29190
|
if (f)
|
|
29173
|
-
return
|
|
29191
|
+
return readFileSync62(f, "utf8").trim() || "unknown";
|
|
29174
29192
|
} catch {}
|
|
29175
29193
|
}
|
|
29176
29194
|
return "unknown";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "loki-mode",
|
|
4
4
|
"displayName": "Loki Mode",
|
|
5
|
-
"version": "11.63.
|
|
5
|
+
"version": "11.63.8",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-
|
|
1
|
+
import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-D7h5Efxx.js";import{B as C}from"./Button-DcMIUy9q.js";import{T as $e}from"./trending-up-CnR04ozf.js";import{C as z}from"./clock-Ch7TiuRG.js";import{A as Be,U as ue,M as De}from"./Avatar-C5naIgXq.js";import{A as J}from"./activity-DRUoEUMH.js";import{R as pe}from"./refresh-cw-DhVQ14GV.js";import{G as ze}from"./globe-DJKmdNYO.js";import{C as Le}from"./chevron-left-D6t1u2bZ.js";import{C as je}from"./check-Cuz-bgBo.js";import{D as Y}from"./dollar-sign-DSOoLXMA.js";import{U as Te}from"./user-45NLDfA3.js";import{D as Me}from"./database-BXiIVvsI.js";import{L as Ue}from"./lock-D1n5V1WB.js";import{S as Re}from"./scroll-text-CeT_KqRE.js";import{S as Ie}from"./shield-alert-BtatVxYq.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./index-
|
|
1
|
+
import{j as e}from"./index-D7h5Efxx.js";import{C as r}from"./clock-Ch7TiuRG.js";import{C as a}from"./circle-alert-BrbRSY0L.js";import{C as l}from"./check-Cuz-bgBo.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as p,j as t}from"./index-
|
|
1
|
+
import{r as p,j as t}from"./index-D7h5Efxx.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-
|
|
1
|
+
import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-D7h5Efxx.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-Dk4uHaS4.js";import{C as qe,F as Ge,M as Ue,H as Ke,a as We,G as Ve,T as Qe}from"./thumbs-up-D4fCUUuq.js";import{C as oe}from"./check-Cuz-bgBo.js";import{C as Ye}from"./clock-Ch7TiuRG.js";import{D as Xe}from"./dollar-sign-DSOoLXMA.js";import{U as Ze}from"./upload-DGc43kol.js";import{L as V}from"./loader-circle-21-GyiHr.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as o,j as e}from"./index-BQ_6SUYj.js";function f({value:r,prefix:t="",suffix:s=""}){const[u,n]=o.useState(0),c=o.useRef(0);return o.useEffect(()=>{const a=c.current,h=r-a;if(h===0)return;const i=600,d=performance.now();function l(b){const v=b-d,m=Math.min(v/i,1),N=1-Math.pow(1-m,3),p=Math.round(a+h*N);n(p),c.current=p,m<1&&requestAnimationFrame(l)}requestAnimationFrame(l)},[r]),e.jsxs("span",{className:"tabular-nums",children:[t,u.toLocaleString(),s]})}function g(){const[r,t]=o.useState(5),[s,u]=o.useState(30),[n,c]=o.useState(75),a=.4,i=Math.round(r*s*a*4.33),d=Math.round(i*n);return e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-6 shadow-sm",children:[e.jsx("h3",{className:"text-lg font-bold text-[#36342E] mb-1",children:"ROI Calculator"}),e.jsx("p",{className:"text-sm text-[#6B6960] mb-6",children:"Estimate how much your team could save with autonomous development."}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Team size"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[r," developers"]})]}),e.jsx("input",{type:"range",min:1,max:50,value:r,onChange:l=>t(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"1"}),e.jsx("span",{children:"50"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Hours coding per week"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[s,"h"]})]}),e.jsx("input",{type:"range",min:5,max:60,value:s,onChange:l=>u(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"5h"}),e.jsx("span",{children:"60h"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Average hourly rate"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:["$",n,"/hr"]})]}),e.jsx("input",{type:"range",min:25,max:250,step:5,value:n,onChange:l=>c(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"$25"}),e.jsx("span",{children:"$250"})]})]})]}),e.jsxs("div",{className:"mt-6 pt-6 border-t border-[#ECEAE3]",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 text-center",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#553DE9]",children:e.jsx(f,{value:i,suffix:"h"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. hours saved / month"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#1FC5A8]",children:e.jsx(f,{value:d,prefix:"$"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. cost saved / month"})]})]}),e.jsxs("div",{className:"mt-4 p-3 rounded-lg bg-[#553DE9]/5 border border-[#553DE9]/10",children:[e.jsxs("p",{className:"text-sm text-[#36342E] text-center",children:["If Loki Mode saved ",Math.round(a*100),"% of coding time, your team could save"," ",e.jsxs("span",{className:"font-bold text-[#553DE9]",children:[i.toLocaleString()," hours"]})," ","and"," ",e.jsxs("span",{className:"font-bold text-[#1FC5A8]",children:["$",d.toLocaleString()]})," ","per month."]}),e.jsxs("p",{className:"mt-2 text-xs text-[#6B6960] text-center",children:["The ",Math.round(a*100),"% is an assumption, not a measurement. Model and API spend is not included."]})]})]})]})}const j=[{feature:"Claude (Opus/Sonnet/Haiku)",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!0},{feature:"GPT-4o / Codex",category:"AI Models",lokiMode:!0,boltNew:!0,replit:!0,lovable:!1},{feature:"5-provider auto-failover",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"8 automated quality gates",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Blind 3-reviewer code review",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Anti-sycophancy checks",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Automated test generation",category:"Quality",lokiMode:!0,boltNew:!1,replit:"Partial",lovable:!1},{feature:"Docker container generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"CI/CD pipeline generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"One-click cloud deploy",category:"Deployment",lokiMode:"Planned",boltNew:!0,replit:!0,lovable:!0},{feature:"Self-hosted (your keys)",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Free tier available",category:"Cost",lokiMode:"Source-available (BUSL-1.1)",boltNew:!0,replit:!0,lovable:!0},{feature:"No vendor lock-in",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"SSO / OIDC authentication",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"RBAC access control",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Audit logging",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Air-gapped deployment",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1}];function y(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M20 6L9 17l-5-5",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round"})})}function w(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#C45B5B]/40",children:e.jsx("path",{d:"M18 6L6 18M6 6l12 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function x({value:r}){return typeof r=="string"?e.jsx("span",{className:"text-xs text-[#6B6960] font-medium",children:r}):r?e.jsx(y,{}):e.jsx(w,{})}const k=[{title:"Full Autonomy",description:"Describe what you want. Loki Mode handles planning, coding, testing, and verification automatically.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#553DE9]",children:e.jsx("path",{d:"M13 2L3 14h9l-1 8 10-12h-9l1-8z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Production Quality",description:"8 quality gates, blind code review, and anti-sycophancy checks ensure code that actually works.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Your Infrastructure",description:"Self-hosted, source-available (BUSL-1.1), no data leaves your network. Use your own API keys across 5 providers.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#2F71E3]",children:[e.jsx("rect",{x:"2",y:"2",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("rect",{x:"2",y:"14",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("circle",{cx:"6",cy:"6",r:"1",fill:"currentColor"}),e.jsx("circle",{cx:"6",cy:"18",r:"1",fill:"currentColor"})]})},{title:"Built for Teams",description:"Enterprise auth, RBAC, audit logs, and parallel workflows for teams of any size.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#E93D82]",children:[e.jsx("path",{d:"M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("circle",{cx:"9",cy:"7",r:"4",stroke:"currentColor",strokeWidth:"2"}),e.jsx("path",{d:"M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}];function C(){const r=[...new Set(j.map(t=>t.category))];return e.jsx("div",{className:"min-h-screen bg-[#FAF9F6]",children:e.jsxs("div",{className:"max-w-6xl mx-auto px-6 py-8",children:[e.jsxs("div",{className:"mb-8",children:[e.jsx("h1",{className:"text-2xl font-bold text-[#36342E]",children:"Compare"}),e.jsx("p",{className:"text-[#6B6960] mt-1",children:"See how Loki Mode stacks up against other AI development platforms."})]}),e.jsx("div",{className:"bg-white border border-[#ECEAE3] rounded-xl overflow-hidden shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-[#ECEAE3]",children:[e.jsx("th",{className:"text-left px-4 py-3 font-medium text-[#6B6960] w-[240px]",children:"Feature"}),e.jsx("th",{className:"text-center px-4 py-3 font-bold text-[#553DE9] bg-[#553DE9]/5 w-[130px]",children:"Loki Mode"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"bolt.new"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Replit"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Lovable"})]})}),e.jsx("tbody",{children:r.map(t=>e.jsxs(e.Fragment,{children:[e.jsx("tr",{className:"bg-[#FAF9F6]",children:e.jsx("td",{colSpan:5,className:"px-4 py-2 text-xs font-bold text-[#939084] uppercase tracking-wider",children:t})},`cat-${t}`),j.filter(s=>s.category===t).map(s=>e.jsxs("tr",{className:"border-b border-[#ECEAE3] last:border-b-0",children:[e.jsx("td",{className:"px-4 py-2.5 text-[#36342E]",children:s.feature}),e.jsx("td",{className:"px-4 py-2.5 text-center bg-[#553DE9]/5",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lokiMode})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.boltNew})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.replit})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lovable})})})]},s.feature))]}))})]})})}),e.jsxs("div",{className:"mt-12",children:[e.jsx("h2",{className:"text-xl font-bold text-[#36342E] mb-6",children:"Why developers choose Loki Mode"}),e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-5",children:k.map(t=>e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-5 shadow-sm hover:shadow-md transition-shadow",children:[e.jsx("div",{className:"mb-3",children:t.icon}),e.jsx("h3",{className:"text-base font-bold text-[#36342E] mb-1",children:t.title}),e.jsx("p",{className:"text-sm text-[#6B6960]",children:t.description})]},t.title))})]}),e.jsx("div",{className:"mt-12 max-w-xl mx-auto",children:e.jsx(g,{})})]})})}export{C as default};
|
|
1
|
+
import{r as o,j as e}from"./index-D7h5Efxx.js";function f({value:r,prefix:t="",suffix:s=""}){const[u,n]=o.useState(0),c=o.useRef(0);return o.useEffect(()=>{const a=c.current,h=r-a;if(h===0)return;const i=600,d=performance.now();function l(b){const v=b-d,m=Math.min(v/i,1),N=1-Math.pow(1-m,3),p=Math.round(a+h*N);n(p),c.current=p,m<1&&requestAnimationFrame(l)}requestAnimationFrame(l)},[r]),e.jsxs("span",{className:"tabular-nums",children:[t,u.toLocaleString(),s]})}function g(){const[r,t]=o.useState(5),[s,u]=o.useState(30),[n,c]=o.useState(75),a=.4,i=Math.round(r*s*a*4.33),d=Math.round(i*n);return e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-6 shadow-sm",children:[e.jsx("h3",{className:"text-lg font-bold text-[#36342E] mb-1",children:"ROI Calculator"}),e.jsx("p",{className:"text-sm text-[#6B6960] mb-6",children:"Estimate how much your team could save with autonomous development."}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Team size"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[r," developers"]})]}),e.jsx("input",{type:"range",min:1,max:50,value:r,onChange:l=>t(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"1"}),e.jsx("span",{children:"50"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Hours coding per week"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[s,"h"]})]}),e.jsx("input",{type:"range",min:5,max:60,value:s,onChange:l=>u(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"5h"}),e.jsx("span",{children:"60h"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Average hourly rate"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:["$",n,"/hr"]})]}),e.jsx("input",{type:"range",min:25,max:250,step:5,value:n,onChange:l=>c(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"$25"}),e.jsx("span",{children:"$250"})]})]})]}),e.jsxs("div",{className:"mt-6 pt-6 border-t border-[#ECEAE3]",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 text-center",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#553DE9]",children:e.jsx(f,{value:i,suffix:"h"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. hours saved / month"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#1FC5A8]",children:e.jsx(f,{value:d,prefix:"$"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. cost saved / month"})]})]}),e.jsxs("div",{className:"mt-4 p-3 rounded-lg bg-[#553DE9]/5 border border-[#553DE9]/10",children:[e.jsxs("p",{className:"text-sm text-[#36342E] text-center",children:["If Loki Mode saved ",Math.round(a*100),"% of coding time, your team could save"," ",e.jsxs("span",{className:"font-bold text-[#553DE9]",children:[i.toLocaleString()," hours"]})," ","and"," ",e.jsxs("span",{className:"font-bold text-[#1FC5A8]",children:["$",d.toLocaleString()]})," ","per month."]}),e.jsxs("p",{className:"mt-2 text-xs text-[#6B6960] text-center",children:["The ",Math.round(a*100),"% is an assumption, not a measurement. Model and API spend is not included."]})]})]})]})}const j=[{feature:"Claude (Opus/Sonnet/Haiku)",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!0},{feature:"GPT-4o / Codex",category:"AI Models",lokiMode:!0,boltNew:!0,replit:!0,lovable:!1},{feature:"5-provider auto-failover",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"8 automated quality gates",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Blind 3-reviewer code review",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Anti-sycophancy checks",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Automated test generation",category:"Quality",lokiMode:!0,boltNew:!1,replit:"Partial",lovable:!1},{feature:"Docker container generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"CI/CD pipeline generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"One-click cloud deploy",category:"Deployment",lokiMode:"Planned",boltNew:!0,replit:!0,lovable:!0},{feature:"Self-hosted (your keys)",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Free tier available",category:"Cost",lokiMode:"Source-available (BUSL-1.1)",boltNew:!0,replit:!0,lovable:!0},{feature:"No vendor lock-in",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"SSO / OIDC authentication",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"RBAC access control",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Audit logging",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Air-gapped deployment",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1}];function y(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M20 6L9 17l-5-5",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round"})})}function w(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#C45B5B]/40",children:e.jsx("path",{d:"M18 6L6 18M6 6l12 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function x({value:r}){return typeof r=="string"?e.jsx("span",{className:"text-xs text-[#6B6960] font-medium",children:r}):r?e.jsx(y,{}):e.jsx(w,{})}const k=[{title:"Full Autonomy",description:"Describe what you want. Loki Mode handles planning, coding, testing, and verification automatically.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#553DE9]",children:e.jsx("path",{d:"M13 2L3 14h9l-1 8 10-12h-9l1-8z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Production Quality",description:"8 quality gates, blind code review, and anti-sycophancy checks ensure code that actually works.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Your Infrastructure",description:"Self-hosted, source-available (BUSL-1.1), no data leaves your network. Use your own API keys across 5 providers.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#2F71E3]",children:[e.jsx("rect",{x:"2",y:"2",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("rect",{x:"2",y:"14",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("circle",{cx:"6",cy:"6",r:"1",fill:"currentColor"}),e.jsx("circle",{cx:"6",cy:"18",r:"1",fill:"currentColor"})]})},{title:"Built for Teams",description:"Enterprise auth, RBAC, audit logs, and parallel workflows for teams of any size.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#E93D82]",children:[e.jsx("path",{d:"M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("circle",{cx:"9",cy:"7",r:"4",stroke:"currentColor",strokeWidth:"2"}),e.jsx("path",{d:"M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}];function C(){const r=[...new Set(j.map(t=>t.category))];return e.jsx("div",{className:"min-h-screen bg-[#FAF9F6]",children:e.jsxs("div",{className:"max-w-6xl mx-auto px-6 py-8",children:[e.jsxs("div",{className:"mb-8",children:[e.jsx("h1",{className:"text-2xl font-bold text-[#36342E]",children:"Compare"}),e.jsx("p",{className:"text-[#6B6960] mt-1",children:"See how Loki Mode stacks up against other AI development platforms."})]}),e.jsx("div",{className:"bg-white border border-[#ECEAE3] rounded-xl overflow-hidden shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-[#ECEAE3]",children:[e.jsx("th",{className:"text-left px-4 py-3 font-medium text-[#6B6960] w-[240px]",children:"Feature"}),e.jsx("th",{className:"text-center px-4 py-3 font-bold text-[#553DE9] bg-[#553DE9]/5 w-[130px]",children:"Loki Mode"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"bolt.new"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Replit"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Lovable"})]})}),e.jsx("tbody",{children:r.map(t=>e.jsxs(e.Fragment,{children:[e.jsx("tr",{className:"bg-[#FAF9F6]",children:e.jsx("td",{colSpan:5,className:"px-4 py-2 text-xs font-bold text-[#939084] uppercase tracking-wider",children:t})},`cat-${t}`),j.filter(s=>s.category===t).map(s=>e.jsxs("tr",{className:"border-b border-[#ECEAE3] last:border-b-0",children:[e.jsx("td",{className:"px-4 py-2.5 text-[#36342E]",children:s.feature}),e.jsx("td",{className:"px-4 py-2.5 text-center bg-[#553DE9]/5",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lokiMode})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.boltNew})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.replit})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lovable})})})]},s.feature))]}))})]})})}),e.jsxs("div",{className:"mt-12",children:[e.jsx("h2",{className:"text-xl font-bold text-[#36342E] mb-6",children:"Why developers choose Loki Mode"}),e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-5",children:k.map(t=>e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-5 shadow-sm hover:shadow-md transition-shadow",children:[e.jsx("div",{className:"mb-3",children:t.icon}),e.jsx("h3",{className:"text-base font-bold text-[#36342E] mb-1",children:t.title}),e.jsx("p",{className:"text-sm text-[#6B6960]",children:t.description})]},t.title))})]}),e.jsx("div",{className:"mt-12 max-w-xl mx-auto",children:e.jsx(g,{})})]})})}export{C as default};
|