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.
Files changed (68) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/dashboard/__init__.py +1 -1
  4. package/docs/CLI-REFERENCE.md +1 -1
  5. package/docs/INSTALLATION.md +1 -1
  6. package/docs/v10/FAILURE-CLASSES.md +32 -0
  7. package/loki-ts/dist/loki.js +1100 -1100
  8. package/mcp/__init__.py +1 -1
  9. package/package.json +2 -2
  10. package/packages/control-plane/dist/server.js +70 -52
  11. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  12. package/web-app/dist/assets/{AdminPage-Cp2bWPgv.js → AdminPage-MRok4gpK.js} +1 -1
  13. package/web-app/dist/assets/{Avatar-BWkjgfpQ.js → Avatar-C5naIgXq.js} +1 -1
  14. package/web-app/dist/assets/{Badge-DplLKpsq.js → Badge-zigD7yw6.js} +1 -1
  15. package/web-app/dist/assets/{Button-Bi9cmTkv.js → Button-DcMIUy9q.js} +1 -1
  16. package/web-app/dist/assets/{CockpitPage-ZBt9jJqb.js → CockpitPage-D7Bunb6e.js} +1 -1
  17. package/web-app/dist/assets/{ComparePage-BtfjcKUw.js → ComparePage-r1MlVPTe.js} +1 -1
  18. package/web-app/dist/assets/{ErrorBoundary-D7gzKuQl.js → ErrorBoundary-Dk4uHaS4.js} +1 -1
  19. package/web-app/dist/assets/{EvidenceReceiptPanel-B0qgQSt7.js → EvidenceReceiptPanel-C9ab9NGb.js} +1 -1
  20. package/web-app/dist/assets/{GitHubIssuesPanel-D7DLUV5y.js → GitHubIssuesPanel-DXE21JW5.js} +1 -1
  21. package/web-app/dist/assets/{GitHubPRsPanel-B-tSxFMu.js → GitHubPRsPanel-CEEJDQaF.js} +1 -1
  22. package/web-app/dist/assets/{HomePage-9zMRoQ2-.js → HomePage-Cc1RJgQP.js} +2 -2
  23. package/web-app/dist/assets/{LoginPage-CHahatjI.js → LoginPage-BgK3Un7s.js} +1 -1
  24. package/web-app/dist/assets/{MagicPage-CWDBY117.js → MagicPage-DracOHYk.js} +1 -1
  25. package/web-app/dist/assets/{MetricsPage-i0sQqMu5.js → MetricsPage-dpzE7rHk.js} +1 -1
  26. package/web-app/dist/assets/{NotFoundPage-Cep2hjC4.js → NotFoundPage-CwR1prG_.js} +1 -1
  27. package/web-app/dist/assets/{ProjectPage-B9jVtdf_.js → ProjectPage-DDeC9Cfy.js} +3 -3
  28. package/web-app/dist/assets/{ProjectsPage-DT6qTa8F.js → ProjectsPage-o3OfxJRf.js} +1 -1
  29. package/web-app/dist/assets/{SettingsPage-DMVIxFyL.js → SettingsPage-PI85tG1v.js} +1 -1
  30. package/web-app/dist/assets/{ShowcasePage-CenA1vR9.js → ShowcasePage-iYe1cAHf.js} +1 -1
  31. package/web-app/dist/assets/{SystemSettingsPage-Qqy7C834.js → SystemSettingsPage-B-dy7aEZ.js} +1 -1
  32. package/web-app/dist/assets/{TeamsPage-Dbc7PMBa.js → TeamsPage-CKN0wlJv.js} +1 -1
  33. package/web-app/dist/assets/{TemplatesPage-BNpJysCP.js → TemplatesPage-2Kkm5kRO.js} +1 -1
  34. package/web-app/dist/assets/{TerminalOutput-DrhATQOU.js → TerminalOutput-CsrWjt5Z.js} +1 -1
  35. package/web-app/dist/assets/{activity-DO1Lb3p_.js → activity-DRUoEUMH.js} +1 -1
  36. package/web-app/dist/assets/{bell-6USNNqOU.js → bell-DVtpHIbp.js} +1 -1
  37. package/web-app/dist/assets/{bot-C3WPr7Jc.js → bot-DQR3Z51i.js} +1 -1
  38. package/web-app/dist/assets/{check-0PtXKfN0.js → check-Cuz-bgBo.js} +1 -1
  39. package/web-app/dist/assets/{chevron-left-xlhDqXSB.js → chevron-left-D6t1u2bZ.js} +1 -1
  40. package/web-app/dist/assets/{circle-alert-GKhWaSzf.js → circle-alert-BrbRSY0L.js} +1 -1
  41. package/web-app/dist/assets/{clock-ui1bNcXF.js → clock-Ch7TiuRG.js} +1 -1
  42. package/web-app/dist/assets/{cloud-CKrUG6Hi.js → cloud-D9FgjItJ.js} +1 -1
  43. package/web-app/dist/assets/{code-xml-E0yaCnLv.js → code-xml-CTOxq-IZ.js} +1 -1
  44. package/web-app/dist/assets/{database-CKoePHfR.js → database-BXiIVvsI.js} +1 -1
  45. package/web-app/dist/assets/{dollar-sign-BLLEGeDo.js → dollar-sign-DSOoLXMA.js} +1 -1
  46. package/web-app/dist/assets/{file-code-corner-DNkK9sHC.js → file-code-corner-BSZSLbUC.js} +1 -1
  47. package/web-app/dist/assets/{file-plus-BZRpulA3.js → file-plus-wDq2a4vY.js} +1 -1
  48. package/web-app/dist/assets/{globe-B8KkmQx6.js → globe-DJKmdNYO.js} +1 -1
  49. package/web-app/dist/assets/{hammer-Bm6aLg_e.js → hammer-DL5Cuz8k.js} +1 -1
  50. package/web-app/dist/assets/{index-BQ_6SUYj.js → index-D7h5Efxx.js} +3 -3
  51. package/web-app/dist/assets/{layers-BwI4LLZC.js → layers-BMAnvaPd.js} +1 -1
  52. package/web-app/dist/assets/{loader-circle-DNNb2uHm.js → loader-circle-21-GyiHr.js} +1 -1
  53. package/web-app/dist/assets/{lock-C_-piZan.js → lock-D1n5V1WB.js} +1 -1
  54. package/web-app/dist/assets/{package-CGJ-QLzA.js → package-BZQKnof2.js} +1 -1
  55. package/web-app/dist/assets/{plus-BI3waAt8.js → plus-DcZZjvq4.js} +1 -1
  56. package/web-app/dist/assets/{refresh-cw-Cyc0Be2K.js → refresh-cw-DhVQ14GV.js} +1 -1
  57. package/web-app/dist/assets/{rotate-ccw-BMF9rcHQ.js → rotate-ccw-B3FdQA22.js} +1 -1
  58. package/web-app/dist/assets/{scroll-text-DeoapOot.js → scroll-text-CeT_KqRE.js} +1 -1
  59. package/web-app/dist/assets/{server-DvyYi0cU.js → server-DqUuxOrt.js} +1 -1
  60. package/web-app/dist/assets/{shield-alert-Bon6ZnUv.js → shield-alert-BtatVxYq.js} +1 -1
  61. package/web-app/dist/assets/{thumbs-up-98YsSw4r.js → thumbs-up-D4fCUUuq.js} +1 -1
  62. package/web-app/dist/assets/{trash-2-1U-mCJzW.js → trash-2-BHNJqbo6.js} +1 -1
  63. package/web-app/dist/assets/{trending-down-BlHQF7ZA.js → trending-down-CPggV6Fp.js} +1 -1
  64. package/web-app/dist/assets/{trending-up-C3BNDS1Z.js → trending-up-CnR04ozf.js} +1 -1
  65. package/web-app/dist/assets/{upload-CGW0PxJo.js → upload-DGc43kol.js} +1 -1
  66. package/web-app/dist/assets/{usePolling-l8CCUq6q.js → usePolling-CJr1dy5R.js} +1 -1
  67. package/web-app/dist/assets/{user-CTHngdi9.js → user-45NLDfA3.js} +1 -1
  68. package/web-app/dist/index.html +1 -1
package/mcp/__init__.py CHANGED
@@ -75,4 +75,4 @@ try:
75
75
  except ImportError:
76
76
  __all__ = ['mcp']
77
77
 
78
- __version__ = '11.63.7'
78
+ __version__ = '11.63.8'
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.7",
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": "d88d9353867c6fd4e04f94357ca0ef0cd4eca602"
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
- }, FULL_SUITE_CMD, 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");
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
- FULL_SUITE_CMD = {
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
- if (ev.skipped)
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 = FULL_SUITE_CMD[runner];
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
- if (py.length) {
15980
- const [ruffCmd, interpreter, uvPre] = resolveTool(ctx.repoDir, "ruff", "ruff");
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 readFileSync48, readdirSync as readdirSync21, rmSync as rmSync20, writeFileSync as writeFileSync28 } from "fs";
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(readFileSync48(issueJsonPath, "utf8"));
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 = readFileSync48(join61(cwd, name), "utf8"), why = outOfRepoTarget(text2) ?? phantomReason(phantomRepoPaths(text2, name, targetDir, ctx.repoDir, planText), repoFiles, relative13(ctx.repoDir, targetDir), pkg?.root ?? "");
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, readFileSync48(join61(cwd, n2), "utf8"))), runnerOf: (n2) => guessRunner(n2, runners) }), generated = all.filter((n2) => !held?.names.has(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 = readFileSync48(join61(cwd, name), "utf8"), oorWhy = oorBad.get(name), bad = oorWhy ?? conventionViolation(conv2, name, 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 readFileSync49, realpathSync as realpathSync23, rmdirSync, unlinkSync as unlinkSync7, writeFileSync as writeFileSync29 } from "fs";
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() && readFileSync49(fp).equals(want)) {
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 readFileSync50 } from "fs";
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(readFileSync50(file, "utf8"));
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 readFileSync51, renameSync as renameSync13, statSync as statSync20, writeFileSync as writeFileSync30 } from "fs";
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(readFileSync51(p, "utf8"));
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 readFileSync52 } from "fs";
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(readFileSync52(p, "utf8"));
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 readFileSync53, rmSync as rmSync21, writeFileSync as writeFileSync31 } from "fs";
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 = readFileSync53(p);
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 readFileSync54, renameSync as renameSync14, statSync as statSync21, writeFileSync as writeFileSync32 } from "fs";
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 = readFileSync54(rp);
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(readFileSync54(ep)) : null,
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 = readFileSync54(rp);
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(readFileSync54(ep)) : null;
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(readFileSync54(p, "utf8"));
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 readFileSync55, statSync as statSync22 } from "fs";
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(readFileSync55(p, "utf8"));
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(readFileSync55(p, "utf8").split(`
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 ? readFileSync55(p, "utf8") : "";
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 readFileSync56 } from "fs";
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) ? readFileSync56(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 readFileSync57 } from "fs";
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 = readFileSync57(join71(runDir, "integration.log"));
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 = readFileSync57(join71(runDir, "integration.json"));
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 = readFileSync57(rp);
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 readFileSync58, renameSync as renameSync15, statSync as statSync24, writeFileSync as writeFileSync34 } from "fs";
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(readFileSync58(f))];
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 = readFileSync58(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
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 = readFileSync58(path, "utf8").split(`
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) => readFileSync58(p, "utf8")))(receiptPath));
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 readFileSync61, statSync as statSync25 } from "fs";
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 readFileSync59, realpathSync as realpathSync25 } from "fs";
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(readFileSync59(file, "utf8")));
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 readFileSync60 } from "fs";
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 readFileSync60(f, "utf8").trim();
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 readFileSync61(f, "utf8").trim() || "unknown";
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.7",
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-BQ_6SUYj.js";import{B as C}from"./Button-Bi9cmTkv.js";import{T as $e}from"./trending-up-C3BNDS1Z.js";import{C as z}from"./clock-ui1bNcXF.js";import{A as Be,U as ue,M as De}from"./Avatar-BWkjgfpQ.js";import{A as J}from"./activity-DO1Lb3p_.js";import{R as pe}from"./refresh-cw-Cyc0Be2K.js";import{G as ze}from"./globe-B8KkmQx6.js";import{C as Le}from"./chevron-left-xlhDqXSB.js";import{C as je}from"./check-0PtXKfN0.js";import{D as Y}from"./dollar-sign-BLLEGeDo.js";import{U as Te}from"./user-CTHngdi9.js";import{D as Me}from"./database-CKoePHfR.js";import{L as Ue}from"./lock-C_-piZan.js";import{S as Re}from"./scroll-text-DeoapOot.js";import{S as Ie}from"./shield-alert-Bon6ZnUv.js";/**
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,4 +1,4 @@
1
- import{c as l,j as s}from"./index-BQ_6SUYj.js";/**
1
+ import{c as l,j as s}from"./index-D7h5Efxx.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-BQ_6SUYj.js";import{C as r}from"./clock-ui1bNcXF.js";import{C as a}from"./circle-alert-GKhWaSzf.js";import{C as l}from"./check-0PtXKfN0.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
+ 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-BQ_6SUYj.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
+ 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-BQ_6SUYj.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-D7gzKuQl.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-98YsSw4r.js";import{C as oe}from"./check-0PtXKfN0.js";import{C as Ye}from"./clock-ui1bNcXF.js";import{D as Xe}from"./dollar-sign-BLLEGeDo.js";import{U as Ze}from"./upload-CGW0PxJo.js";import{L as V}from"./loader-circle-DNNb2uHm.js";/**
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};
@@ -1,4 +1,4 @@
1
- import{c as o,r as a,j as e,T as n,h as i,p as c}from"./index-BQ_6SUYj.js";/**
1
+ import{c as o,r as a,j as e,T as n,h as i,p as c}from"./index-D7h5Efxx.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.