loki-mode 11.17.44 → 11.17.45

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 (70) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/loki +133 -4
  4. package/dashboard/__init__.py +1 -1
  5. package/docs/CLI-REFERENCE.md +1 -1
  6. package/docs/INSTALLATION.md +1 -1
  7. package/docs/WORKSPACES.md +1 -1
  8. package/docs/v10/BOARD.md +31 -1
  9. package/docs/v10/PROGRESS.md +3 -0
  10. package/loki-ts/dist/loki.js +2 -2
  11. package/mcp/__init__.py +1 -1
  12. package/package.json +2 -2
  13. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  14. package/web-app/dist/assets/{AdminPage-DQh0uMEZ.js → AdminPage-BCGIu6vt.js} +1 -1
  15. package/web-app/dist/assets/{Avatar-84eTYVHr.js → Avatar-FGro9b68.js} +1 -1
  16. package/web-app/dist/assets/{Badge-Cdj4WuMp.js → Badge-DZ0OOxdx.js} +1 -1
  17. package/web-app/dist/assets/{Button-B4wS8oEx.js → Button-C702FTxi.js} +1 -1
  18. package/web-app/dist/assets/{CockpitPage-CmaQv_rL.js → CockpitPage-B1CZaaXx.js} +1 -1
  19. package/web-app/dist/assets/{ComparePage-DfTjVQkq.js → ComparePage-DRd-w9yO.js} +1 -1
  20. package/web-app/dist/assets/{ErrorBoundary-C3TjOwpP.js → ErrorBoundary-B9T1V8_Q.js} +1 -1
  21. package/web-app/dist/assets/{EvidenceReceiptPanel-A_CiIZ4X.js → EvidenceReceiptPanel-CScPICN7.js} +1 -1
  22. package/web-app/dist/assets/{GitHubIssuesPanel-SVaeYaPy.js → GitHubIssuesPanel-BL8nzIoH.js} +1 -1
  23. package/web-app/dist/assets/{GitHubPRsPanel-DJt7g4Pp.js → GitHubPRsPanel-W0FX5DSl.js} +1 -1
  24. package/web-app/dist/assets/{HomePage-YMXFjgBp.js → HomePage-_3jq9WUA.js} +2 -2
  25. package/web-app/dist/assets/{LoginPage-DYg_NPth.js → LoginPage-DsPxoAOJ.js} +1 -1
  26. package/web-app/dist/assets/{MagicPage-DGX4Lq5U.js → MagicPage-nOER2-ZE.js} +1 -1
  27. package/web-app/dist/assets/{MetricsPage-uD_P4MCJ.js → MetricsPage-CoiAlCTC.js} +1 -1
  28. package/web-app/dist/assets/{NotFoundPage-DSmZyCJv.js → NotFoundPage-l46SOx1i.js} +1 -1
  29. package/web-app/dist/assets/{ProjectPage-gCZUZcT-.js → ProjectPage-DxO8dkf_.js} +3 -3
  30. package/web-app/dist/assets/{ProjectsPage-YRevZmdN.js → ProjectsPage-DtNSAVm9.js} +1 -1
  31. package/web-app/dist/assets/{SettingsPage-DwTsMRGS.js → SettingsPage-DbNetRfY.js} +1 -1
  32. package/web-app/dist/assets/{ShowcasePage-D3S-XKZm.js → ShowcasePage-BSzhjOYS.js} +1 -1
  33. package/web-app/dist/assets/{SystemSettingsPage-DQnfIRKG.js → SystemSettingsPage-DWrN72dn.js} +1 -1
  34. package/web-app/dist/assets/{TeamsPage-CWlL5x0m.js → TeamsPage-CVFEOL9r.js} +1 -1
  35. package/web-app/dist/assets/{TemplatesPage-iutuIUEE.js → TemplatesPage-IpcsZhEh.js} +1 -1
  36. package/web-app/dist/assets/{TerminalOutput-D9yF6zBW.js → TerminalOutput-Bv9Zgwyj.js} +1 -1
  37. package/web-app/dist/assets/{activity-9_w3VmWg.js → activity-CHgtGwwW.js} +1 -1
  38. package/web-app/dist/assets/{bell-D3OP8VZ7.js → bell-Ym0Mx2Xd.js} +1 -1
  39. package/web-app/dist/assets/{bot-DDG1cQxK.js → bot-C-6tA3JT.js} +1 -1
  40. package/web-app/dist/assets/{check-EW0lJblv.js → check-CyFyZ4Qi.js} +1 -1
  41. package/web-app/dist/assets/{chevron-left-B4rt_k4K.js → chevron-left-B3SPNdcz.js} +1 -1
  42. package/web-app/dist/assets/{circle-alert-DU98pynG.js → circle-alert-DcKKeKmd.js} +1 -1
  43. package/web-app/dist/assets/{clock-AbKik9uE.js → clock-CHLwYBFX.js} +1 -1
  44. package/web-app/dist/assets/{cloud-DwH-HIQ5.js → cloud-CBE7j7iG.js} +1 -1
  45. package/web-app/dist/assets/{code-xml-ISq7rL8q.js → code-xml-Cu-b65vO.js} +1 -1
  46. package/web-app/dist/assets/{database-CJHcL02M.js → database-DSJlQYxs.js} +1 -1
  47. package/web-app/dist/assets/{dollar-sign-C6-GwMUE.js → dollar-sign-BcPFsZq0.js} +1 -1
  48. package/web-app/dist/assets/{file-code-corner-oa05HcOf.js → file-code-corner-Dl_LDpv_.js} +1 -1
  49. package/web-app/dist/assets/{file-plus-p0HoytyR.js → file-plus-BoLEmKCc.js} +1 -1
  50. package/web-app/dist/assets/{globe-CL_RV__2.js → globe-4-KwsIUo.js} +1 -1
  51. package/web-app/dist/assets/{hammer-CRP8xWZl.js → hammer-CaG_crBz.js} +1 -1
  52. package/web-app/dist/assets/{index-D86O9Ak6.js → index-DD7FC7yd.js} +3 -3
  53. package/web-app/dist/assets/{layers-BJbaP6xJ.js → layers-BDQEO970.js} +1 -1
  54. package/web-app/dist/assets/{loader-circle-Btcxs-64.js → loader-circle-ENh48A-3.js} +1 -1
  55. package/web-app/dist/assets/{lock-Bd2Yj6rY.js → lock-CcI4ltMK.js} +1 -1
  56. package/web-app/dist/assets/{package-tKCkzim3.js → package-DA_Bt7Mx.js} +1 -1
  57. package/web-app/dist/assets/{plus-rxy1B7R4.js → plus-r_jqdmwV.js} +1 -1
  58. package/web-app/dist/assets/{refresh-cw-Bykzqbq7.js → refresh-cw-B0o3B073.js} +1 -1
  59. package/web-app/dist/assets/{rotate-ccw-B0zi3eqY.js → rotate-ccw-D5EyaAC-.js} +1 -1
  60. package/web-app/dist/assets/{scroll-text-J8wWrWX-.js → scroll-text-DKrZwpKk.js} +1 -1
  61. package/web-app/dist/assets/{server-B5cOTUHz.js → server-FMLinzaf.js} +1 -1
  62. package/web-app/dist/assets/{shield-alert-CryIgWVO.js → shield-alert-C5YWhIfX.js} +1 -1
  63. package/web-app/dist/assets/{thumbs-up-DSLZJsOW.js → thumbs-up-lWteH19H.js} +1 -1
  64. package/web-app/dist/assets/{trash-2-6P-i8jxc.js → trash-2-CTWsJujI.js} +1 -1
  65. package/web-app/dist/assets/{trending-down-LGEVSvWI.js → trending-down-n969VpQb.js} +1 -1
  66. package/web-app/dist/assets/{trending-up-BBN_6tC-.js → trending-up-hNpwNjdL.js} +1 -1
  67. package/web-app/dist/assets/{upload-1O3p1SX0.js → upload-DmcM8inI.js} +1 -1
  68. package/web-app/dist/assets/{usePolling-CFAGN7AY.js → usePolling-CQCRI-UO.js} +1 -1
  69. package/web-app/dist/assets/{user-BkD7wEFM.js → user-BCspLAnr.js} +1 -1
  70. package/web-app/dist/index.html +1 -1
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: An autonomous software factory that knows what it is supposed to deliver, and proves it did. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v11.17.44
6
+ # Loki Mode v11.17.45
7
7
 
8
8
  **Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
9
9
 
@@ -483,4 +483,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
483
483
 
484
484
  ---
485
485
 
486
- **v11.17.44 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
486
+ **v11.17.45 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.17.44
1
+ 11.17.45
package/autonomy/loki CHANGED
@@ -10056,7 +10056,7 @@ _deploy_latest_receipt() {
10056
10056
  return 0
10057
10057
  }
10058
10058
 
10059
- # _deploy_record <dir> <command> <exit_code> <run_id> <anchor_sha> [state] [health_status] [health_url] [rb_attempted] [rb_exit] [receipt_sha256] [started_at] [finished_at] [target] [canary] [post_rollback_health] [health_http_code] [health_match] [tree_sha] [destination] [deployed_url] [health_url_source] [env_keys_csv] [env_source] [domain] [domain_status] [tls_status] [tls_not_after] [domain_provenance]
10059
+ # _deploy_record <dir> <command> <exit_code> <run_id> <anchor_sha> [state] [health_status] [health_url] [rb_attempted] [rb_exit] [receipt_sha256] [started_at] [finished_at] [target] [canary] [post_rollback_health] [health_http_code] [health_match] [tree_sha] [destination] [deployed_url] [health_url_source] [env_keys_csv] [env_source] [domain] [domain_status] [tls_status] [tls_not_after] [domain_provenance] [live_binding]
10060
10060
  # Writes the executed deploy's own record, then signs it (loki.deploy/1, Ed25519 via the
10061
10061
  # receipt signer in loki-ts/src/util/receipt_signer.ts) so it is bound to the receipt that
10062
10062
  # authorized it; `loki verify <record>` re-checks it offline. An unsigned record is reported
@@ -10086,6 +10086,7 @@ _deploy_record() {
10086
10086
  local env_keys_csv="${23:-}" env_source="${24:-}"
10087
10087
  # --domain: tls_status is "unchecked" unless the openssl proof ran and said otherwise.
10088
10088
  local domain_rec="${25:-}" domain_status="${26:-}" tls_status="${27:-unchecked}" tls_not_after="${28:-}" domain_prov="${29:-}"
10089
+ local live_binding="${30:-}"
10089
10090
  local ddir="$dir/.loki/deploys"
10090
10091
  [ -d "${LOKI_DIR:-}" ] && ddir="${LOKI_DIR}/deploys"
10091
10092
  mkdir -p "$ddir" 2>/dev/null || return 0
@@ -10095,7 +10096,7 @@ _deploy_record() {
10095
10096
  DR_RBA="$rb_attempted" DR_RBX="$rb_exit" DR_RSHA="$receipt_sha" DR_T0="$started_at" \
10096
10097
  DR_T1="$finished_at" DR_TGT="$target" DR_CAN="$canary" DR_PRB="$post_rb" DR_HC="$hcode_rec" DR_HM="$hmatch" DR_TREE="$tree_sha" DR_DEST="$dest_rec" DR_DURL="$deployed_url" DR_HSRC="$hsrc" \
10097
10098
  DR_ENVK="$env_keys_csv" DR_ENVS="$env_source" \
10098
- DR_DOM="$domain_rec" DR_DOMS="$domain_status" DR_TLS="$tls_status" DR_TLSA="$tls_not_after" DR_DOMP="$domain_prov" \
10099
+ DR_DOM="$domain_rec" DR_DOMS="$domain_status" DR_TLS="$tls_status" DR_TLSA="$tls_not_after" DR_DOMP="$domain_prov" DR_LB="$live_binding" \
10099
10100
  python3 -c '
10100
10101
  import json, os, datetime
10101
10102
  state = os.environ.get("DR_STATE") or "anchored"
@@ -10134,6 +10135,7 @@ json.dump({
10134
10135
  "tls_status": os.environ.get("DR_TLS") or "unchecked",
10135
10136
  "tls_not_after": os.environ.get("DR_TLSA", ""),
10136
10137
  "domain_provenance": os.environ.get("DR_DOMP", ""),
10138
+ "live_binding": os.environ.get("DR_LB") or "unchecked",
10137
10139
  "health_http_code": int(os.environ["DR_HC"]) if os.environ.get("DR_HC", "").isdigit() else None,
10138
10140
  }, open(os.environ["DR_OUT"], "w"), indent=2)
10139
10141
  ' 2>/dev/null || return 0
@@ -10232,6 +10234,91 @@ _deploy_probe_health() {
10232
10234
  return 1
10233
10235
  }
10234
10236
 
10237
+ # _deploy_provenance_root <dir> <type>
10238
+ # Echoes the static root that ships with the deploy and may carry /.well-known/, or "" when no
10239
+ # such root exists. nextjs and Vite: public/. Built static: the detected dist/ then build/.
10240
+ # docker, python and node serve no static root, so they print "" and are never bound.
10241
+ _deploy_provenance_root() {
10242
+ local dir="${1:-.}" type="${2:-}"
10243
+ case "$type" in
10244
+ nextjs) printf '%s' "$dir/public" ;;
10245
+ static)
10246
+ if [ -f "$dir/dist/index.html" ]; then printf '%s' "$dir/dist"
10247
+ elif [ -f "$dir/build/index.html" ]; then printf '%s' "$dir/build"
10248
+ elif [ -f "$dir/package.json" ] && grep -q '"vite"' "$dir/package.json" 2>/dev/null; then printf '%s' "$dir/public"
10249
+ fi
10250
+ ;;
10251
+ esac
10252
+ return 0
10253
+ }
10254
+
10255
+ # _deploy_clear_provenance <dir>
10256
+ # Removes .well-known/loki-provenance.json from EVERY candidate static root (public/, dist/,
10257
+ # build/). Runs before each deploy decides whether to write a fresh doc, so a doc left by an
10258
+ # earlier deploy can never ship with a build it does not describe (unanchored override,
10259
+ # unsupported type, signing failure, or a root that moved between deploys).
10260
+ _deploy_clear_provenance() {
10261
+ local dir="${1:-.}" r
10262
+ for r in public dist build; do
10263
+ rm -f "$dir/$r/.well-known/loki-provenance.json" 2>/dev/null || true
10264
+ done
10265
+ return 0
10266
+ }
10267
+
10268
+ # _deploy_write_provenance <dir> <root> <head_sha> <tree_sha> <receipt_sha256> <run_id>
10269
+ # Writes <root>/.well-known/loki-provenance.json and signs it in place (loki verify
10270
+ # --sign-provenance). Called only after the gate (including the dirty-tree check) passed, so the
10271
+ # untracked file never dirties the tree that was verified; it is also added to .git/info/exclude
10272
+ # so the NEXT deploy's dirty-tree gate does not trip over it. Returns non-zero when not signed.
10273
+ _deploy_write_provenance() {
10274
+ local dir="$1" root="$2" head="$3" tree="$4" rsha="$5" rid="$6"
10275
+ local f="$root/.well-known/loki-provenance.json" ex
10276
+ rm -f "$f" 2>/dev/null
10277
+ [ -n "$head" ] && [ -n "$tree" ] && [ -n "$rsha" ] && [ -n "$rid" ] || return 1
10278
+ mkdir -p "$root/.well-known" 2>/dev/null || return 1
10279
+ PV_H="$head" PV_T="$tree" PV_R="$rsha" PV_I="$rid" PV_OUT="$f" python3 -c '
10280
+ import json, os, datetime
10281
+ json.dump({"schema": "loki.provenance/1", "head_sha": os.environ["PV_H"], "tree_sha": os.environ["PV_T"],
10282
+ "receipt_sha256": os.environ["PV_R"], "run_id": os.environ["PV_I"],
10283
+ "built_at": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")},
10284
+ open(os.environ["PV_OUT"], "w"), indent=2)
10285
+ ' 2>/dev/null || { rm -f "$f"; return 1; }
10286
+ ex="$(git -C "$dir" rev-parse --git-path info/exclude 2>/dev/null)" || ex=""
10287
+ if [ -n "$ex" ]; then
10288
+ case "$ex" in /*) ;; *) ex="$dir/$ex" ;; esac
10289
+ grep -qxF '**/.well-known/loki-provenance.json' "$ex" 2>/dev/null \
10290
+ || { mkdir -p "$(dirname "$ex")" 2>/dev/null; printf '%s\n' '**/.well-known/loki-provenance.json' >> "$ex" 2>/dev/null; } || true
10291
+ fi
10292
+ if ! ( cd "$dir" && _loki_bun_delegate engine10 verify --sign-provenance "$f" ) >/dev/null 2>&1; then
10293
+ rm -f "$f"
10294
+ return 1
10295
+ fi
10296
+ return 0
10297
+ }
10298
+
10299
+ # _deploy_probe_live_binding <dir> <url> <anchor>
10300
+ # Fetches <url>/.well-known/loki-provenance.json through loki verify --url --expect-sha.
10301
+ # Returns 0 VERIFIED (signature holds and head_sha equals the anchor), 1 MISMATCH (a doc
10302
+ # was served but is forged or names a different SHA, still so on the last bounded retry),
10303
+ # 2 UNCHECKED (no doc could be fetched or its key is unknown, after a bounded retry with the
10304
+ # health-probe tunables). Never VERIFIED on 2.
10305
+ _deploy_probe_live_binding() {
10306
+ local dir="$1" url="$2" anchor="$3"
10307
+ local attempts="${LOKI_DEPLOY_HEALTH_ATTEMPTS:-5}" interval="${LOKI_DEPLOY_HEALTH_INTERVAL:-3}" i=0 vrc=2
10308
+ case "$attempts" in ''|*[!0-9]*) attempts=5 ;; esac
10309
+ case "$interval" in ''|*[!0-9]*) interval=3 ;; esac
10310
+ while [ "$i" -lt "$attempts" ]; do
10311
+ i=$((i + 1))
10312
+ vrc=0
10313
+ ( cd "$dir" && _loki_bun_delegate engine10 verify --url "$url" --expect-sha "$anchor" ) >/dev/null 2>&1 || vrc=$?
10314
+ [ "$vrc" -eq 0 ] && return 0
10315
+ [ "$i" -lt "$attempts" ] && [ "$interval" -gt 0 ] && sleep "$interval"
10316
+ done
10317
+ # A mismatch on the last attempt is FAILED; earlier mismatches may be propagation of the previous build.
10318
+ [ "$vrc" -eq 1 ] && return 1
10319
+ return 2
10320
+ }
10321
+
10235
10322
  # _deploy_policy_refusal <dir>
10236
10323
  # Echoes a refusal reason when the policy file does not permit a deploy, else "".
10237
10324
  # No policy file: "" (unchanged behaviour). File present and node or check.js
@@ -10611,6 +10698,25 @@ _deploy_try_execute() {
10611
10698
  esac
10612
10699
  fi
10613
10700
 
10701
+ # Provenance doc: shipped with the build so the live URL can prove which SHA it serves.
10702
+ local live_binding="unchecked" prov_root="" prov_written=false
10703
+ prov_root="$(_deploy_provenance_root "$dir" "$type")"
10704
+ # Every branch below starts from no doc: only a doc written by THIS deploy may ship.
10705
+ _deploy_clear_provenance "$dir"
10706
+ if [ "$anchor_state" = "unanchored_overridden" ]; then
10707
+ live_binding="unanchored"
10708
+ echo "Live binding unanchored: the evidence gate was overridden with the anchor UNPROVEN, so no provenance doc is published and the live URL is not bound to ${anchor:0:12}." >&2
10709
+ elif [ -z "$prov_root" ]; then
10710
+ live_binding="unsupported"
10711
+ echo "Live binding unsupported: a ${type} project has no static root to serve /.well-known/loki-provenance.json, so the live URL is not bound to ${anchor:0:12}." >&2
10712
+ elif _deploy_write_provenance "$dir" "$prov_root" "$anchor" "$(git -C "$dir" rev-parse 'HEAD^{tree}' 2>/dev/null || true)" \
10713
+ "$(python3 -c 'import json,sys;print((json.load(open(sys.argv[1])).get("verification") or {}).get("hash") or "")' "$pj" 2>/dev/null || true)" "$run_id"; then
10714
+ prov_written=true
10715
+ echo "Provenance written: ${prov_root}/.well-known/loki-provenance.json"
10716
+ else
10717
+ echo -e "${YELLOW}WARNING: the provenance doc could not be signed, so the live URL will not be bound to this SHA.${NC}" >&2
10718
+ fi
10719
+
10614
10720
  local rc=0 started_at finished_at purl="" canary_out=""
10615
10721
  local -a deploy_argv=()
10616
10722
  read -r -a deploy_argv <<<"$exec_cmd"
@@ -10695,8 +10801,31 @@ _deploy_try_execute() {
10695
10801
  fi
10696
10802
  fi
10697
10803
 
10698
- if [ "$health_status" = "FAILED_HEALTH" ]; then
10804
+ # Live binding: the deployed URL must serve the provenance doc for THIS anchor.
10805
+ if [ "$prov_written" = true ] && [ "$rc" -eq 0 ] && [ "$health_status" != "FAILED_HEALTH" ] && [ -n "$deployed_url" ]; then
10806
+ echo "Probing live binding: ${deployed_url%/}/.well-known/loki-provenance.json"
10807
+ local lb_rc=0
10808
+ _deploy_probe_live_binding "$dir" "$deployed_url" "$anchor" || lb_rc=$?
10809
+ case "$lb_rc" in
10810
+ 0)
10811
+ live_binding="VERIFIED"
10812
+ echo -e "${GREEN}Live binding VERIFIED:${NC} ${deployed_url} serves a signed provenance doc for ${anchor:0:12}."
10813
+ ;;
10814
+ 1)
10815
+ live_binding="FAILED"
10816
+ health_status="FAILED_HEALTH"
10817
+ echo -e "${RED}FAILED_HEALTH: ${deployed_url} served a provenance doc that is forged or is not for ${anchor:0:12} (stale or wrong build served).${NC}" >&2
10818
+ ;;
10819
+ *)
10820
+ echo " Live binding unchecked: no verifiable provenance doc could be fetched from ${deployed_url}. Not a claim the live build is ${anchor:0:12}." >&2
10821
+ ;;
10822
+ esac
10823
+ fi
10824
+
10825
+ if [ "$health_status" = "FAILED_HEALTH" ] && [ "$live_binding" != "FAILED" ]; then
10699
10826
  echo -e "${RED}FAILED_HEALTH: ${health_url} did not return 2xx${health_match:+ containing \"${health_match}\"} (last status ${hcode:-000}).${NC}" >&2
10827
+ fi
10828
+ if [ "$health_status" = "FAILED_HEALTH" ]; then
10700
10829
  if [ "$auto_rollback" = true ] && [ -n "$rb_cmd" ] && ! _deploy_is_destructive "$rb_cmd"; then
10701
10830
  echo "Rolling back: ${rb_cmd}" >&2
10702
10831
  rb_attempted=true
@@ -10735,7 +10864,7 @@ _deploy_try_execute() {
10735
10864
  rec="$(_deploy_record "$dir" "$exec_disp" "$rc" "${run_id:-unknown}" "${anchor:-unknown}" \
10736
10865
  "$anchor_state" "$health_status" "$health_url" "$rb_attempted" "$rb_exit" \
10737
10866
  "$rsha" "$started_at" "$finished_at" "${command%% *}" "$canary" "$post_rb" "$hcode" "$health_match" "$(git -C "$dir" rev-parse 'HEAD^{tree}' 2>/dev/null || true)" "$dest" "$deployed_url" "$health_src" "$env_keys" "$env_file" \
10738
- "$domain" "$_DD_STATUS" "$_DD_TLS" "$_DD_NOTAFTER" "$_DD_PROV")"
10867
+ "$domain" "$_DD_STATUS" "$_DD_TLS" "$_DD_NOTAFTER" "$_DD_PROV" "$live_binding")"
10739
10868
  echo ""
10740
10869
  if [ "$rc" -eq 0 ]; then
10741
10870
  echo -e "${GREEN}Deploy command exited 0.${NC}"
@@ -7,6 +7,6 @@ Modules:
7
7
  control: Session control helpers (status, atomic writes, origin check)
8
8
  """
9
9
 
10
- __version__ = "11.17.44"
10
+ __version__ = "11.17.45"
11
11
 
12
12
  __all__ = ["__version__"]
@@ -1,6 +1,6 @@
1
1
  # CLI reference
2
2
 
3
- Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.17.44. Do not edit by hand.
3
+ Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.17.45. Do not edit by hand.
4
4
  Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for the full inventory.
5
5
 
6
6
  | Command | Description |
@@ -2,7 +2,7 @@
2
2
 
3
3
  Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
4
4
 
5
- **Version:** v11.17.44
5
+ **Version:** v11.17.45
6
6
 
7
7
  **Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
8
8
 
@@ -55,7 +55,7 @@ After `loki workspace run <name> <ref>` finishes, check the evidence rather than
55
55
  3. `.loki/workspaces/<name>/<run-id>/integration.json` holds `status`, the head SHA per repo and `timing`.
56
56
  4. `python3 autonomy/lib/workspace_metrics.py <run-dir> --attention-min <minutes>` prints `prs`, `prs_per_hour` and `prs_per_attention_minute`; any value it cannot measure prints `unmeasured`.
57
57
  5. Each repo PR for the run branch carries exactly one integration comment.
58
- 6. `loki verify <run-dir>/composite.json` re-checks the composite offline (add `--pubkey FILE` on another machine). It recomputes the composite hash, re-verifies every child receipt from disk and checks the signature. It prints the integration result and every repo head SHA it attests. It is TAMPERED for a tampered or swapped child, a child head that is not the integrated head, a failed or interrupted integration status or nonzero exit code, an edited integration section, or an `integration.log` that no longer matches its recorded hash. It is UNCHECKED for an unsigned child under a signed composite, and for a legacy composite that predates the integration section and has no integrated head to compare. Deployed-SHA binding is not implemented: the composite attests what was integrated and tested, not what is running anywhere. Exit codes are the single-receipt ones: 0 VERIFIED, 1 TAMPERED, 2 UNCHECKED, 3 UNSIGNED. The composite never reads higher than its weakest child: one PARTIAL child caps it at PARTIAL.
58
+ 6. `loki verify <run-dir>/composite.json` re-checks the composite offline (add `--pubkey FILE` on another machine). It recomputes the composite hash, re-verifies every child receipt from disk and checks the signature. It prints the integration result and every repo head SHA it attests. It is TAMPERED for a tampered or swapped child, a child head that is not the integrated head, a failed or interrupted integration status or nonzero exit code, an edited integration section, or an `integration.log` that no longer matches its recorded hash. It is UNCHECKED for an unsigned child under a signed composite, and for a legacy composite that predates the integration section and has no integrated head to compare. Deployed-SHA binding is partial: `loki deploy --execute` ships a signed `.well-known/loki-provenance.json` (head_sha, tree_sha, receipt_sha256, run_id, built_at) in the static root of a single-repo nextjs, Vite or built-static project (public/, dist/ or build/) and, when the provider prints a URL, fetches it back through `loki verify --url --expect-sha`. The deploy record's `live_binding` is VERIFIED only when the served doc is signed and names the anchor SHA; a stale or forged doc is FAILED (FAILED_HEALTH, exit 4), an unreachable one is `unchecked`, and docker, python and node projects (no static root) are `unsupported`. A mismatch is retried inside the health attempts and interval budget before it is FAILED, so a URL still serving the previous build for a few seconds is not rolled back at once. A live doc that is unsigned or signed with an unknown key is `unchecked`, not FAILED, so a stale non-loki build serving such a doc passes silently. Under `--allow-unanchored` the anchor is UNPROVEN, so no doc is published and `live_binding` is `unanchored`. The deploy appends `**/.well-known/loki-provenance.json` to `.git/info/exclude` and leaves the file in the working tree. Every `loki deploy --execute` first removes that file from public/, dist/ and build/, so only a doc written by the current deploy ships; an unanchored, unsupported or unsigned deploy ships none. A provider run by hand outside `loki deploy --execute` uploads whatever doc the last loki deploy left, which names that deploy's SHA, not the new build. If the provider rebuilds remotely from a gitignored root, the doc is lost and the result is `unchecked`. None of this binds a composite: the composite attests what was integrated and tested, not what is running anywhere, and no workspace deploy writes or probes a provenance doc. Exit codes are the single-receipt ones: 0 VERIFIED, 1 TAMPERED, 2 UNCHECKED, 3 UNSIGNED. The composite never reads higher than its weakest child: one PARTIAL child caps it at PARTIAL.
59
59
  7. A run that could not seal prints `composite not sealed: <reason>` (for example a repo with no receipt). Seal by hand with `loki verify --seal-composite <run-dir>`; it refuses unless every child has a receipt.
60
60
 
61
61
  Not measured: no scale test exists for large repo counts. Claim only what you have run.
package/docs/v10/BOARD.md CHANGED
@@ -1006,7 +1006,7 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
1006
1006
  | FC-23 | FC-23: the Wall writes tests matching the package's module system and test conventions from the Project Model; a lint or type error inside a Wall file is harness-owned, the Wall file is regenerated once or discarded with a NOT PROVEN note, and no fix round is spent on it | loki-ts/src/engine10/stages/wall.ts, the fix-round target filter, project_model conventions, plus tests | MEDIUM | a CommonJS package gets a Wall test with no import.meta; a forced type error in a Wall file yields regenerate-or-discard and zero fix rounds | released@2026-10-04T00:51Z | released@2026-10-04T00:51Z | Merged c0a1c43c2 (38c782386, review-fc23 sonnet APPROVE; nits: duplicate NOT PROVEN line for a discarded file, merged comment in verify.ts).
1007
1007
  | TEN-DEPLOY-01 | Capture the deployed public URL on every --execute path and probe it by default | autonomy/loki (_deploy_try_execute non-canary exec block and the _deploy_record arg list and JSON fields only), tests/test-deploy-receipt-gate.sh (new section after the existing 14-18 block), CHANGELOG.md | MEDIUM | see Wall in note | released@2026-10-17T02:57Z | merge 60a9bb709; TL APPROVE b14d908a4 (deploy-receipt-gate 56/0, test-deploy 6/6, shellcheck 91=91 vs main). wave 1; depends: none. Goal: After a deploy that exits 0, take the last https URL the provider CLI printed (the canary grep -Eo already does this; reuse that, do not add a second parser). Store it as deployed_url in loki.deploy/1. When no --health-url is given, probe deployed_url with _deploy_probe_health and record health_url_source=captured/flag. No URL printed: deployed_url is empty, health stays 'unchecked', and Loki never invents a URL. Print 'Live at: <url>' only when one was captured. Wall: RED: a new section stubs vercel to print 'https://app-x.vercel.app' and exit 0, and stubs curl to 200. The record lacks deployed_url, health_status is 'unchecked', and the test fails on main. GREEN: deployed_url equals the stub URL, health_status=healthy, health_url_source=captured. A second stub prints no URL: deployed_url is empty, health is 'unchecked', exit 0. A third case passes --health-url: health_url_source=flag. MUTATION: hardcode deployed_url to a constant and the no-URL case goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh && bash tests/test-deploy.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. v11.17.13 npm next 11.17.13 |
1008
1008
  | TEN-DEPLOY-02 | Signed live provenance doc (loki.provenance/1) and loki verify --url | loki-ts/src/util/receipt_signer.ts, loki-ts/tests/engine10/verify_cmd.test.ts (provenance cases; existing deploy-record tests live here), docs/SIGNED-RECEIPTS.md (one section), CHANGELOG.md. Engine10 core is not edited: verify_cmd.ts:164 already routes through deployAttestCmd, and a one-token --url passthrough there needs the budget test to stay green. | HIGH | see Wall in note | released v11.17.26@2026-10-17T05:48Z | SPLIT per CTO critic into (a) signProvenance plus --sign-provenance, (b) verify --url fetch and verdicts; build as two commits or two agents. wave 2; depends: none. Goal: Extend receipt_signer.ts, the owner of signed deploy attestations, with: signProvenance(head_sha, tree_sha, receipt_sha256, run_id, built_at), which signs with the same Ed25519 key as signDeployRecord; a `--sign-provenance FILE` dispatch in deployAttestCmd; and `loki verify --url https://host` plus a pubkey. The --url check fetches <url>/.well-known/loki-provenance.json with a timeout and size cap, checks the signature, and requires a 200 with JSON. The verdict is VERIFIED only when the signature verifies against the local JWKS or --pubkey AND the cited receipt (when present locally or via --receipt) is VERIFIED. The doc alone with an unknown kid is UNCHECKED rc 2. An edited doc is TAMPERED rc 1. A fetch failure is UNCHECKED and never VERIFIED. Optional --expect-sha SHA must equal head_sha. Wall: RED: tests serve a signed provenance doc from Bun.serve on 127.0.0.1. On main, `verify --url` is an unknown arg and exits 2, so the tests fail. GREEN: genuine doc with --pubkey gives VERIFIED rc 0. One edited byte of head_sha gives TAMPERED rc 1. An unknown kid gives UNCHECKED rc 2. A 404, a non-JSON body or a doc over 64KB gives UNCHECKED rc 2. A wrong --expect-sha gives TAMPERED rc 1. MUTATION: skip the signature verify and the edited-byte case goes red. Gate: cd loki-ts && bun test tests/engine10/verify_cmd.test.ts && bun test tests/engine10/ && bunx tsc --noEmit (the full engine10 suite runs the budget and spawn-env guards) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
1009
- | TEN-DEPLOY-03 | Ship the provenance doc with the build and prove the live URL serves the verified SHA | autonomy/loki (_deploy_try_execute pre-exec and post-health blocks, _deploy_record live_binding field only), tests/test-deploy-receipt-gate.sh (new section), docs/WORKSPACES.md, CHANGELOG.md | HIGH | see Wall in note | ready@2026-10-17T01:40Z | SPLIT per CTO critic into (a) provenance file into deploy root per project type, (b) post-deploy live-binding probe; build as two commits or two agents. wave 3; depends: TEN-DEPLOY-01, TEN-DEPLOY-02. Goal: In _deploy_try_execute, after the gate passes and before the provider runs, write a signed .well-known/loki-provenance.json into the deploy root via `verify --sign-provenance`. The deploy root is public/ for nextjs and vite, the detected dist/ or build/ for static, and is refused with a reason for docker/python where no static root exists. Write it as an untracked build artifact so the dirty-tree gate is evaluated before it. After the deploy, probe <deployed_url>/.well-known/loki-provenance.json. Set live_binding=VERIFIED only when its head_sha equals the anchor. A mismatch gives FAILED_HEALTH exit 4 (stale or wrong build served). Update docs/WORKSPACES.md and replace 'deployed-SHA binding is not implemented' with what is now bound and what is not. Wall: RED: a stubbed vercel copies dist/ into a served dir and a python http.server serves it. On main, no provenance file exists and the record has no live_binding. GREEN: the file exists in dist/.well-known, live_binding=VERIFIED, and its head_sha equals git rev-parse HEAD. A stub that serves an older provenance gives FAILED_HEALTH exit 4. A docker project prints the refusal reason and records live_binding=unsupported, never VERIFIED. The dirty-tree gate still refuses a dirty tree before the file is written. MUTATION: compare against a constant instead of the anchor and the stale-serve case goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh && (cd loki-ts && bun test tests/engine10/verify_cmd.test.ts) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
1009
+ | TEN-DEPLOY-03 | Ship the provenance doc with the build and prove the live URL serves the verified SHA | autonomy/loki (_deploy_try_execute pre-exec and post-health blocks, _deploy_record live_binding field only), tests/test-deploy-receipt-gate.sh (new section), docs/WORKSPACES.md, CHANGELOG.md | HIGH | see Wall in note | released v11.17.45 | SPLIT per CTO critic into (a) provenance file into deploy root per project type, (b) post-deploy live-binding probe; build as two commits or two agents. wave 3; depends: TEN-DEPLOY-01, TEN-DEPLOY-02. Goal: In _deploy_try_execute, after the gate passes and before the provider runs, write a signed .well-known/loki-provenance.json into the deploy root via `verify --sign-provenance`. The deploy root is public/ for nextjs and vite, the detected dist/ or build/ for static, and is refused with a reason for docker/python where no static root exists. Write it as an untracked build artifact so the dirty-tree gate is evaluated before it. After the deploy, probe <deployed_url>/.well-known/loki-provenance.json. Set live_binding=VERIFIED only when its head_sha equals the anchor. A mismatch gives FAILED_HEALTH exit 4 (stale or wrong build served). Update docs/WORKSPACES.md and replace 'deployed-SHA binding is not implemented' with what is now bound and what is not. Wall: RED: a stubbed vercel copies dist/ into a served dir and a python http.server serves it. On main, no provenance file exists and the record has no live_binding. GREEN: the file exists in dist/.well-known, live_binding=VERIFIED, and its head_sha equals git rev-parse HEAD. A stub that serves an older provenance gives FAILED_HEALTH exit 4. A docker project prints the refusal reason and records live_binding=unsupported, never VERIFIED. The dirty-tree gate still refuses a dirty tree before the file is written. MUTATION: compare against a constant instead of the anchor and the stale-serve case goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh && (cd loki-ts && bun test tests/engine10/verify_cmd.test.ts) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
1010
1010
  | TEN-DEPLOY-04 | Verified deploy badge from loki status --badge | loki-ts/src/commands/status.ts (renderLastDeploy plus --badge flag parse only), loki-ts/tests/commands/status.test.ts, CHANGELOG.md | MEDIUM | see Wall in note | released@2026-10-17T05:06Z | wave 4; depends: TEN-DEPLOY-01 (deployed_url field); live_binding from TEN-DEPLOY-03 is read if present, and its absence omits the badge. Goal: `loki status --badge` reads the newest loki.deploy/1 record (renderLastDeploy already loads it) and verifies it through the existing verify path. It prints a markdown shields badge linking to <deployed_url>/.well-known/loki-provenance.json. The message is 'deployed: verified' (brightgreen) ONLY when the record verifies and live_binding=VERIFIED. 'deployed: unverified' (red) is printed for TAMPERED or a failed health check. In all other cases the badge is omitted with a one-line reason. It never prints green from an unchecked field. The color mapping matches the share badge (autonomy/loki:38291), and no new vocabulary is added. Wall: RED: status.test.ts fixture with a signed healthy record, live_binding=VERIFIED and deployed_url. On main, --badge is unknown and no badge line is printed. GREEN: the badge line contains 'brightgreen' and deployed_url. A record with health FAILED_HEALTH gives a red badge. An unsigned record or a missing live_binding omits the badge and prints the reason. A record with no deployed_url omits the badge. MUTATION: drop the verify call and the unsigned case goes green, so the test goes red. Gate: cd loki-ts && bun test tests/commands/status.test.ts && bunx tsc --noEmit && bash tests/test-status-surface-agrees.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
1011
1011
  | TEN-DEPLOY-05 | loki deploy --env-file: push env to the provider with names-only records | autonomy/loki (cmd_deploy arg parse for --env-file, _deploy_try_execute env step, _deploy_record env_keys field only), tests/test-deploy-receipt-gate.sh (new section), autonomy/completions (loki deploy flag list only), CHANGELOG.md | HIGH | see Wall in note | released v11.17.35 | SPLIT per CTO critic into (a) env-file parser, .env.example check, masking, env_keys record, (b) four provider verbs; build as two commits or two agents. wave 4; depends: TEN-DEPLOY-03 (same function, serialized to avoid conflicts). Goal: `--env-file FILE` (with --execute only) parses KEY=VALUE with no shell eval. It refuses when a key in .env.example is missing from FILE, naming the keys. Env is applied through documented verbs only: Vercel `vercel --prod -e K=V` per key (args built as an array, never through the shell); Fly `fly secrets set --stage K=V ...` before `fly deploy`; Netlify `netlify env:import FILE`; Cloudflare `wrangler secret bulk FILE`. An unsupported provider refuses with nothing run. The record stores env_keys (names, sorted) and env_source; it NEVER stores values. Values never appear in stdout, the record or the printed 'Running:' line, where they are masked as K=***. Wall: RED: a recording vercel stub logs argv. On main, --env-file is ignored and no -e args appear. GREEN: argv has `-e API_URL=x -e TOKEN=s3cr3t`. Grepping stdout, stderr and the record for s3cr3t finds nothing; env_keys=[API_URL,TOKEN]. When .env.example lists DB_URL and the env file lacks it, the command refuses with rc 1, no stub calls and DB_URL named. A value with $(touch pwned) leaves no file named pwned. MUTATION: write values into the record and the secret-grep goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh && bash tests/test-completion-drift.sh (or whichever completion drift test the CHANGELOG cites) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
1012
1012
  | TEN-DEPLOY-06 | loki deploy --domain: attach a custom domain and prove TLS | autonomy/loki (cmd_deploy --domain parse and a post-health domain block in _deploy_try_execute, _deploy_record domain/tls fields only), tests/test-deploy-receipt-gate.sh (new section), CHANGELOG.md | MEDIUM | see Wall in note | released v11.17.38 | wave 5; depends: TEN-DEPLOY-05 (same function, serialized). Goal: `--domain example.com` (with --execute) runs documented verbs after a healthy deploy: Vercel `vercel alias set <deployed_url> <domain>`; Fly `fly certs add <domain>`. Netlify and Cloudflare print the manual dashboard step and set domain_status=manual. Then a TLS proof runs: `openssl s_client -servername <domain> -connect <domain>:443` plus `openssl x509 -noout -enddate -checkend 604800`. It records domain, tls_status (valid/expiring/invalid/unchecked) and tls_not_after, and re-probes https://<domain>/.well-known/loki-provenance.json for the same head_sha. DNS not yet pointed gives tls_status=invalid and exit 6, with the DNS record the provider needs printed. It never claims valid without the openssl check. Wall: RED: vercel, openssl and curl are stubbed. On main, --domain is ignored. GREEN: the alias set argv is recorded, tls_status=valid and tls_not_after is set. An openssl stub that fails -checkend gives expiring. An openssl handshake failure gives invalid and exit 6. A netlify project gives domain_status=manual, no alias call, and tls still checked. No openssl on PATH gives unchecked, never valid. MUTATION: default tls_status to valid and the missing-openssl case goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
@@ -1182,6 +1182,36 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
1182
1182
  | TEN-STABILITY-18 | P0 fix-forward: nightly 39016259458 reds still red on main e32ee1b5d (pr_body_golden not-recorded producer util/check_result.ts; sizing wall brief 726 vs cap 616; router_optout_golden wall stage haiku for development; verify.test uv resolution CI-only via Bun.which PATH; test-sigpipe-guard 1737 vs ceiling 1728; help-changelog-drift loki verify --require-exogenous; test-ui-bare-loki exact-match on new control lines; test-local-ci-gitleaks scope) | the failing tests, loki-ts/src/util/check_result.ts, loki-ts/src/engine10/stages/wall.ts, loki-ts/src/engine10/stages/verify.ts, verify help and completions, scripts/local-ci.sh, docs/v10/FAILURE-CLASSES.md | MEDIUM | red: each named test fails on e32ee1b5d; green: cd loki-ts && bun test tests/engine10/pr_body_golden.test.ts tests/engine10/sizing.test.ts tests/engine10/router_optout_golden.test.ts tests/engine10/verify.test.ts tests/util; bash tests/test-sigpipe-guard.sh; bash tests/test-help-changelog-drift.sh; bash tests/test-ui-bare-loki.sh; bash tests/test-local-ci-gitleaks.sh | released v11.17.42 | Diagnosis 2026-10-17 by nightly diag agent; one FAILURE-CLASSES row per class |
1183
1183
  | TEN-STABILITY-19 | P0 fix-forward: moat P8.ablation-dead-code-not-sealed positive control headline VERIFIED WITH GAPS (expected VERIFIED) and first-run-gate --stub FAILED with dirty tracked tree M sum.js at intake.ts:61 | tests/moat/p8-*.sh or the ablation producer, scripts/first-run-gate.sh, loki-ts/src/engine10/stages/intake.ts only if the honest fix is there | HIGH | red: bash tests/moat/run.sh prints moat suite: FAIL (1 rule failure(s)); bash scripts/first-run-gate.sh --stub fails 7 assertions; green: both exit 0 | released v11.17.42 | Diagnosis 2026-10-17; never weaken a moat assertion to pass |
1184
1184
  | TEN-STABILITY-20 | Fix help-changelog-drift red after v11.17.42: list report kpis --since and undo --list in Bun help, autonomy/loki help and both completions | completions/loki.bash, completions/_loki, loki-ts/src help, autonomy/loki, docs/v10/FAILURE-CLASSES.md | LOW | merged 3c4e2fcd9 | released v11.17.43 |
1185
+ | TEN-STABILITY-26 | fix: `loki control backfill --repo` with no value silently falls back to the first positional or cwd and ships that dir; fail with one error line naming --repo and exit 2 (same class as TEN-STABILITY-21) | loki-ts/src/commands/control.ts, loki-ts/tests/commands/control.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/control.test.ts -t "backfill repo missing value"` fails (exit 0, ingests cwd); green: passes, `--repo DIR` and bare DIR unchanged | ready | Gap: control.ts:234 `flag(rest, "--repo") ?? rest.find(...) ?? cwd`; flag() at :33 returns undefined for a trailing flag, missingValue() at :38 exists but is not applied here |
1186
+ | TEN-UX-24 | fix: the second `control` help block in autonomy/loki (cmd_control, ~line 34902) lists only serve, backfill, status; add prune, stop and `status --json` so it matches the Bun usage in control.ts | autonomy/loki, tests/test-help-discoverability.sh | LOW | red: `bash tests/test-help-discoverability.sh` fails on a new assertion that bash `loki control --help` names prune, stop and status --json; green: passes and `bash tests/test-help-changelog-drift.sh` still exits 0 | ready | Gap: control.ts:22 documents prune --repo/--before; the bash fallback help (LOKI_LEGACY_BASH) omits it |
1187
+ | TEN-UX-25 | fix: bash `cmd_provider` default arm (autonomy/loki:7488) prints help and returns 0 for an unknown subcommand; return 2 with one "unknown subcommand" line (TS side fixed in TEN-UX-20); chain after TEN-UX-24 | autonomy/loki, tests/test-help-discoverability.sh | LOW | red: `bash tests/test-help-discoverability.sh` fails on `loki provider frobnicate` expecting exit 2; green: passes, `loki provider` and `loki provider --help` still exit 0 | ready | Gap: the `*)` arm at autonomy/loki ~7517 echoes the help block with no return code; chain after TEN-UX-24 |
1188
+ | TEN-UX-26 | fix: sibling sweep of bash commands whose default arm prints help and exits 0 on an unknown subcommand (cmd_config ~14144 and cmd_api ~15932 are the first candidates; confirm each with a probe, skip any that already fail non-zero); make each exit 2 with an "unknown subcommand" line; chain after TEN-UX-25 | autonomy/loki, tests/test-help-discoverability.sh | LOW | red: `bash tests/test-help-discoverability.sh` fails on `loki config frobnicate` and `loki api frobnicate` expecting exit 2; green: passes, bare and --help forms still exit 0 | ready | Gap: FAILURE-CLASSES row required (siblings exist); chain after TEN-UX-25 |
1189
+ | TEN-UX-27 | fix: `loki doctor --quiet` writes `Install:` hint lines to stderr while the WARN/FAIL row goes to stdout, so the hint prints detached from its row; write each hint directly under its row on the same stream | loki-ts/src/commands/doctor.ts, loki-ts/tests/commands/doctor.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/doctor.test.ts -t "install hint follows its row"` fails (hint absent from stdout); green: passes and `bunx tsc --noEmit` exits 0 | ready | Gap: doctor.ts:1276 `process.stderr.write(... Install: ...)` after `process.stdout.write(formatToolLine(c))` at :1274 |
1190
+ | TEN-QUALITY-22 | test: pin the doctor disk text-mode "on <name> volume" label (home, cwd, tmp) so the low-volume name cannot regress; chain after TEN-UX-27 | loki-ts/src/commands/doctor.ts, loki-ts/tests/commands/doctor.test.ts | LOW | red: mutate lowestVolume to return null low_volume and `cd loki-ts && bun test tests/commands/doctor.test.ts -t "disk text volume label"` fails; green: passes unmutated | ready | Gap: doctor.test.ts:161 covers the JSON low_volume only; no test renders the text line; chain after TEN-UX-27 |
1191
+ | TEN-SPEED-10 | enhancement: `loki doctor --json` (buildDoctorJson) awaits checkSentrux, checkMemoryHealth and requirementsSection one after another; run them with Promise.all and keep output byte-identical; chain after TEN-QUALITY-22 | loki-ts/src/commands/doctor.ts, loki-ts/tests/commands/doctor.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/commands/doctor.test.ts -t "json checks run concurrently"` fails (elapsed ~ sum of stubbed 200ms probes); green: passes and `bun test tests/commands/doctor_router.test.ts tests/commands/doctor_count.test.ts` exit 0 | ready | Gap: doctor.ts:940-946 serial awaits; the text path already batches runAllToolChecks; chain after TEN-QUALITY-22 |
1192
+ | TEN-QUALITY-23 | test: help-changelog-drift guards exact completion cases; assert every `loki` subcommand and flag named in CHANGELOG appears as a literal case in completions/loki.bash and completions/_loki so a flag typo fails | tests/test-help-changelog-drift.sh, completions/loki.bash, completions/_loki | LOW | red: introduce a typo `--sinse` in completions/loki.bash and `bash tests/test-help-changelog-drift.sh` must exit 1 naming it; green: reverted typo exits 0 | ready | Gap: current test greps for substrings loosely, a misspelled flag in a different case arm still passes |
1193
+ | TEN-GATES-22 | feature: the per-run signed receipt (not only the composite) records the toolchain {bun,node,python3,git}, absent tools null, old receipts still verify (follow-up from the TEN-GATES-19 review) | loki-ts/src/util/receipt_signer.ts, loki-ts/tests/engine10/seal_group.test.ts | HIGH | red: `cd loki-ts && bun test tests/engine10/seal_group.test.ts -t "per-run receipt toolchain"` fails (no toolchain key); green: passes, `bun test tests/engine10 tests/util/receipt_bundle.test.ts` and `bunx tsc --noEmit` exit 0 | ready | Gap: collectToolchain is used only by composite_seal.ts:54; receipt_signer.ts has no toolchain reference |
1194
+ | TEN-COST-39 | fix: a malformed `.loki/metrics/budget.json` is discarded and returns null, so spend resets to zero and the cap is silently disarmed; rebuild budget_used from the efficiency records (readEfficiencyDir) and warn once | loki-ts/src/runner/budget.ts, loki-ts/tests/runner/budget.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/runner/budget.test.ts -t "corrupt budget state rebuilds used"` fails (used 0); green: passes and `bun test tests/runner/autonomous_budget.test.ts` exit 0 | ready | Gap: budget.ts:305-318 returns null on parse failure and the caller treats null as no spend |
1195
+ | TEN-COST-40 | fix: `loadDefaultMaxCostUsd` silently falls back to the literal 100 when model-pricing.json is unreadable; print one stderr warning naming the file and the fallback; chain after TEN-COST-39 | loki-ts/src/runner/budget.ts, loki-ts/tests/runner/budget.test.ts | LOW | red: `cd loki-ts && bun test tests/runner/budget.test.ts -t "pricing file missing warns"` fails (no warning); green: passes, warning emitted once per process | ready | Gap: budget.ts:24-33 swallows every read error; chain after TEN-COST-39 |
1196
+ | TEN-STABILITY-27 | fix: `LOKI_E10_STALL_S=abc` or `LOKI_E10_STALL_KILL_S=-5` is silently ignored and the default applies; warn once on stderr naming the variable and the value used | loki-ts/src/runner/watchdog.ts, loki-ts/tests/runner/watchdog.test.ts | LOW | red: `cd loki-ts && bun test tests/runner/watchdog.test.ts -t "invalid stall env warns"` fails (no warning); green: passes, valid and unset values unchanged | ready | Gap: watchdog.ts:8-17 return the default with no diagnostic |
1197
+ | TEN-STABILITY-28 | fix: `loki undo <run> --bogus` ignores unknown flags and proceeds; validate against the known set (--list --plan --dry-run --json --allow-unsigned --yes --close-pr --help) and exit 2 with one line naming the flag | loki-ts/src/commands/undo.ts, loki-ts/tests/commands/undo.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/commands/undo.test.ts -t "unknown flag"` fails (exit 0 or applies); green: passes, all valid combinations unchanged | ready | Gap: undo.ts:218-238 uses args.includes for each flag with no unknown-flag check; a typo such as `--dry-rn` falls through to apply |
1198
+ | TEN-STABILITY-29 | fix: `loki rollback <id> --forse` and other unknown flags are ignored (the typo drops --force silently); validate against known flags and exit 2 | loki-ts/src/commands/rollback.ts, loki-ts/tests/commands/rollback.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/rollback.test.ts -t "unknown flag"` fails; green: passes, --json and --force unchanged | ready | Gap: rollback.ts:77,116,128 use rest.includes only |
1199
+ | TEN-STABILITY-30 | fix: `loki start ./prd.md` with a mistyped or missing path treats the path string as an inline brief and starts a paid run on it; when the spec looks like a path (contains / or ends in .md/.txt/.yaml/.json) and does not exist, exit 2 "PRD file not found: <path>" | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/commands/start.test.ts -t "missing prd path"` fails (run starts); green: passes, real files and plain briefs unchanged | ready | Gap: start.ts:376 `existsSync(spec) ? readFileSync : spec` falls through to the literal string; verify the same fall-through on the --prd flag before building |
1200
+ | TEN-COST-41 | enhancement: `loki start` prints one line before the first iteration stating the effective per-run cap and where it came from (flag, env, loki.yaml, default $100) so a silent default cap is visible; skip if already printed (check first); chain after TEN-STABILITY-30 | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/start.test.ts -t "cap source line"` fails (no line); green: passes for flag, env and default sources | ready | Gap: capNote exists in e10ext/budget_cap.ts (start.ts:425); confirm it covers the legacy default path; chain after TEN-STABILITY-30 |
1201
+ | TEN-STABILITY-31 | fix: `listCheckpoints` silently skips a checkpoint whose metadata.json is corrupt or fails validation, so it vanishes from rollback choices with no trace; collect skipped ids and warn once on stderr | loki-ts/src/runner/checkpoint.ts, loki-ts/tests/runner/checkpoint.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/runner/checkpoint.test.ts -t "corrupt metadata warns"` fails (no warning); green: passes, valid listing order unchanged | ready | Gap: checkpoint.ts:414-436 readCheckpointSafe returns null in a bare catch |
1202
+ | TEN-QUALITY-25 | test: pin provider failover classification (rate limit vs outage vs killed vs clean exit) and nextProvider ordering with a fake installed() probe | loki-ts/src/runner/provider_failover.ts, loki-ts/tests/runner/provider_failover.test.ts | MEDIUM | red: mutate classifyOutage to return null for exit 137 and `cd loki-ts && bun test tests/runner/provider_failover.test.ts` fails; green: passes unmutated and `bunx tsc --noEmit` exits 0 | ready | Gap: no tests/runner file names provider_failover; new test file justified because no existing file owns it (verify with grep first) |
1203
+ | TEN-UX-28 | enhancement: `loki queue run` prints a progress line `[n/m] <ref>` before each item and the digest links each item verdict; skip if already present (check first) | loki-ts/src/commands/queue.ts, loki-ts/tests/commands/queue.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/queue.test.ts -t "progress line per item"` fails; green: passes and the existing digest test still exits 0 | ready | Gap: queue.ts run loop (~line 290-320) records results only in the final digest |
1204
+ | TEN-SPEED-11 | enhancement: `loki report kpis --since 7d` should skip run directories whose newest mtime is before the cutoff instead of parsing every run, with identical output | loki-ts/src/commands/kpis.ts, loki-ts/tests/commands/kpis.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/kpis.test.ts -t "since skips old runs"` fails (old run files read, counted by a spy); green: passes and output byte-identical on the fixture | ready | Gap: kpis.ts:96 computeKpis receives sinceMs; confirm it filters after reading (read computeKpis first, drop if already pruned by mtime) |
1205
+ | TEN-SECURITY-11 | fix: the SARIF secret scan misses common token formats (Hugging Face `hf_`, SendGrid `SG.`, Twilio `SK`+32 hex, Azure storage `AccountKey=`); add Tier 1 patterns that report label only, never the matched text, and mirror them in autonomy/lib/secret-scan.sh in the same change | loki-ts/src/commands/export_sarif.ts, loki-ts/tests/commands/export_sarif.test.ts, autonomy/lib/secret-scan.sh | MEDIUM | red: `cd loki-ts && bun test tests/commands/export_sarif.test.ts -t "extra token formats"` fails (0 findings); green: passes with label-only output and `bash tests/test-secret-scan.sh` exits 0 | ready | Gap: export_sarif.ts:12-24 lists 12 formats; none cover those four; parity with secret-scan.sh required |
1206
+ | TEN-DEPLOY-19 | fix: `loki start --deploy --health-url X --domain Y` accepts any string; validate --health-url is http or https with a host and --domain is a bare hostname, exit 2 with one line naming the flag, before any run work; chain after TEN-COST-41 | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/commands/start.test.ts -t "deploy flag validation"` fails (exit 0); green: passes, valid URLs unchanged | ready | Gap: start.ts:158 lists the deploy flags as value flags with no validation; verify on the Bun route and the bash route; chain after TEN-COST-41 |
1207
+ | TEN-DEPLOY-20 | fix: `loki start --deploy --env-file ./missing.env` is accepted and fails only after the build; check the file exists and is readable up front and exit 2; chain after TEN-DEPLOY-19 | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/start.test.ts -t "env-file missing"` fails (exit 0); green: passes, existing file unchanged | ready | Gap: start.ts:158 --env-file is passed through unchecked; chain after TEN-DEPLOY-19 |
1208
+ | TEN-ADOPTION-22 | enhancement: `loki provider list` marks each provider CLI as installed or missing and prints the install command for a missing one (reuse the table doctor.ts providerInstall) | loki-ts/src/commands/provider.ts, loki-ts/tests/commands/provider.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/provider.test.ts -t "list shows install hint"` fails; green: passes with a stubbed which() and `bunx tsc --noEmit` exits 0 | ready | Gap: check provider.ts list output first; doctor.ts:1263 holds the only install-hint table, move it to a shared export rather than copying |
1209
+ | TEN-ADOPTION-23 | fix: `loki completion fish` or an unknown shell must print the supported shells and exit 2; `loki completion` with no shell prints usage; check current behaviour first and drop if already correct | loki-ts/src/commands/completion.ts, loki-ts/tests/commands/cli_help_routes.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/cli_help_routes.test.ts -t "completion unknown shell"` fails; green: passes, bash and zsh output unchanged | ready | Gap: completion.ts has no dedicated test file; extend cli_help_routes.test.ts rather than add one |
1210
+ | TEN-GATES-23 | enhancement: record each quality gate's wall-clock duration in the gate result so `loki status` and the receipt can show which gate dominates a slow run; additive field only, old readers ignore it | loki-ts/src/runner/quality_gates.ts, loki-ts/tests/runner/quality_gates.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/runner/quality_gates.test.ts -t "gate duration recorded"` fails (no duration_ms); green: passes and `bun test tests/runner/quality_gates_inconclusive.test.ts` exits 0 | ready | Gap: grep duration in quality_gates.ts first; if present, narrow the row to surfacing it in status |
1211
+ | TEN-GATES-24 | fix: `loki verify-pr` on a PR with no receipt must exit with a code distinct from "receipt present, verdict fail" and say which it is; check current exit codes first and drop if already distinct | loki-ts/src/commands/verify_pr.ts, loki-ts/tests/commands/verify_pr.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/commands/verify_pr.test.ts -t "no receipt exit code"` fails; green: passes, existing verdict exits unchanged | ready | Gap: a CI caller cannot tell missing proof from failed proof if both exit 1 |
1212
+ | TEN-SPEED-12 | enhancement: cache the repo profile (LOKI_REPO_PROFILE=1 path) keyed on HEAD sha and dirty flag so a resumed run does not rescan the tree | loki-ts/src/runner/repo_profile.ts, loki-ts/tests/runner/autonomous.test.ts | MEDIUM | red: `cd loki-ts && bun test tests/runner/autonomous.test.ts -t "repo profile cache hit"` fails (scan runs twice); green: passes, cache invalidates on a new commit | ready | Gap: autonomous.ts:633 calls the profiler each start; read repo_profile.ts first and drop if a cache exists |
1213
+ | TEN-QUALITY-26 | fix: `loki wiki show <bad-section>` should list the valid sections (architecture, modules, data-flow) in the error and exit 2; extend the wiki test | loki-ts/src/commands/wiki.ts, loki-ts/tests/commands/wiki.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/wiki.test.ts -t "bad section lists valid"` fails; green: passes, valid sections unchanged | ready | Gap: wiki.ts:51 prints the section list only in the usage branch; check the unknown-section branch first |
1214
+ | TEN-UX-29 | fix: `loki report kpis --since` with no value, or followed by another flag, reports an empty invalid value and consumes the next flag; print "--since requires a value" and exit 1 without swallowing the next token; chain after TEN-SPEED-11 | loki-ts/src/commands/kpis.ts, loki-ts/tests/commands/kpis.test.ts | LOW | red: `cd loki-ts && bun test tests/commands/kpis.test.ts -t "since missing value"` fails (message names an empty value); green: passes, `--since 7d` and `--since=7d` unchanged | ready | Gap: kpis.ts:87 `args[++i] ?? ""` eats the next token; chain after TEN-SPEED-11 |
1185
1215
  | TEN-COST-35 | fix: `loki start --budget-limit=5` (and --provider=, --session-model=, --prd=, --brief=) is accepted by the flag validator then silently ignored, so the default $100 cap and default provider apply; read the `=` form everywhere argVal reads a flag | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | MEDIUM | red: bun test tests/commands/start.test.ts -t "equals form" fails (cap stays default); green: same test passes and `cd loki-ts && bunx tsc --noEmit` exits 0 | released v11.17.44 | Gap: start.ts:23 argVal matches only exact args via indexOf; start.ts:212 validator splits on "=" so the form is accepted; only --cost and --attempts parse "=" |
1186
1216
  | TEN-COST-36 | fix: `loki start --budget-limit abc`, `--max-iterations -1`, `--budget-limit 0x` and a trailing value flag with no value are silently dropped so the default cap applies; print one error line naming the flag and exit 2 | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | MEDIUM | red: bun test tests/commands/start.test.ts -t "invalid numeric" fails (exit 0, no message); green: passes, valid values unchanged | released v11.17.44 | Gap: start.ts:123 posNum returns undefined for non-numeric, zero or negative with no diagnostic; chain after TEN-COST-35 |
1187
1217
  | TEN-STABILITY-21 | fix: control `--port` with no value or a non-numeric value silently falls back to the default port; reject with a usage line and exit 2 | loki-ts/src/commands/control.ts, loki-ts/tests/commands/control.test.ts | LOW | red: bun test tests/commands/control.test.ts -t "port without value" fails; green: passes and existing control tests stay green | released v11.17.44 | Gap: control.ts:33 flag() returns args[i+1] unchecked (undefined or the next flag) and callers fall through to the default |
@@ -2512,3 +2512,6 @@ v11.17.21 published (Release success on 462fbc40a; npm latest 11.17.21, next 11.
2512
2512
 
2513
2513
  ## 2026-10-17T10:10Z (CoS) v11.17.44
2514
2514
  - Released waves AL (30 slices, 21 chains, all APPROVE) and AK (6 slices). Combined main: tsc rc 0; bun 1233/0 and 528/0; help-changelog-drift rc 0; secure-scan rc 0.
2515
+
2516
+ ## 2026-10-17T10:17Z (CoS) v11.17.45
2517
+ - Released TEN-DEPLOY-03 (wave AH fix round, APPROVE fe1026bf1). Board refilled with 30 TEN rows for wave AM (fbde018b2).
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var M_0=Object.create;var{getPrototypeOf:O_0,defineProperty:IW,getOwnPropertyNames:rd,getOwnPropertyDescriptor:A_0}=Object,td=Object.prototype.hasOwnProperty;function ed(Z){return this[Z]}var L_0,j_0,F_0=(Z,$,J)=>{var X=Z!=null&&typeof Z==="object";if(X){var Y=$?L_0??=new WeakMap:j_0??=new WeakMap,z=Y.get(Z);if(z)return z}J=Z!=null?M_0(O_0(Z)):{};let Q=$||!Z||!Z.__esModule?IW(J,"default",{value:Z,enumerable:!0}):J;for(let W of rd(Z))if(!td.call(Q,W))IW(Q,W,{get:ed.bind(Z,W),enumerable:!0});if(X)Y.set(Z,Q);return Q},C_0=(Z)=>{var $=(sd??=new WeakMap).get(Z),J;if($)return $;if($=IW({},"__esModule",{value:!0}),Z&&typeof Z==="object"||typeof Z==="function"){for(var X of rd(Z))if(!td.call($,X))IW($,X,{get:ed.bind(Z,X),enumerable:!(J=A_0(Z,X))||J.enumerable})}return sd.set(Z,$),$},sd,SB=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var I_0=(Z)=>Z;function T_0(Z,$){this[Z]=I_0.bind(null,$)}var O0=(Z,$)=>{for(var J in $)IW(Z,J,{get:$[J],enumerable:!0,configurable:!0,set:T_0.bind($,J)})};var S=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var u9=import.meta.require;var $l={};O0($l,{lokiDir:()=>P0,homeLokiDir:()=>Z2,findRepoRootForVersion:()=>TW,REPO_ROOT:()=>j0});import{resolve as eZ,dirname as YP}from"path";import{fileURLToPath as P_0}from"url";import{existsSync as bB}from"fs";import{homedir as E_0}from"os";function R_0(){let Z=Zl;for(let $=0;$<6;$++){if(bB(eZ(Z,"VERSION"))&&bB(eZ(Z,"autonomy/run.sh")))return Z;let J=YP(Z);if(J===Z)break;Z=J}return eZ(Zl,"..","..","..")}function TW(Z){let $=Z;for(let J=0;J<6;J++){if(bB(eZ($,"VERSION"))&&bB(eZ($,"autonomy/run.sh")))return $;let X=YP($);if(X===$)break;$=X}return eZ(Z,"..","..","..")}function P0(){return process.env.LOKI_DIR??eZ(process.cwd(),".loki")}function Z2(){return eZ(E_0(),".loki")}var Zl,j0;var n0=S(()=>{Zl=YP(P_0(import.meta.url));j0=R_0()});import{readFileSync as D_0}from"fs";import{resolve as w_0,dirname as __0}from"path";import{fileURLToPath as k_0}from"url";function Q6(){if(X1!==null)return X1;let Z="11.17.44";if(typeof Z==="string"&&Z.length>0)return X1=Z,X1;try{let $=__0(k_0(import.meta.url)),J=TW($);X1=D_0(w_0(J,"VERSION"),"utf-8").trim()}catch{X1="unknown"}return X1}var X1=null;var Z3=S(()=>{n0()});import{mkdirSync as Jl,readFileSync as QP,realpathSync as x_0,statSync as S_0,writeFileSync as Xl}from"fs";import{dirname as PW,join as zP,resolve as Yl}from"path";function h_0(){return Yl(Z2(),"cache","update-check.json")}function $3(Z){let $=/^(\d+)\.(\d+)\.(\d+)$/.exec(Z.trim());if(!$)return null;return[Number($[1]),Number($[2]),Number($[3])]}function EW(Z,$){let J=$3(Z),X=$3($);if(!J||!X)return!1;let[Y,z,Q]=J,[W,K,V]=X;if(Y!==W)return Y>W;if(z!==K)return z>K;return Q>V}function zl(){let Z=(process.env.LOKI_NO_UPDATE_CHECK??"").trim().toLowerCase();if(Z==="1"||Z==="true"||Z==="yes")return!0;if(process.env.CI)return!0;if(!process.stdout.isTTY)return!0;return!1}function f_0(Z){try{let $=QP(Z,"utf-8"),J=JSON.parse($);if(typeof J.checkedAt==="number"&&typeof J.latest==="string"&&$3(J.latest)!==null)return{checkedAt:J.checkedAt,latest:J.latest}}catch{}return null}function g_0(Z,$){try{Jl(PW(Z),{recursive:!0}),Xl(Z,JSON.stringify($),"utf-8")}catch{}}async function m_0(){try{let Z=await fetch(b_0,{signal:AbortSignal.timeout(v_0),headers:{accept:"application/json"}});if(!Z.ok)return null;let $=await Z.json();if(typeof $.version==="string"&&$3($.version)!==null)return $.version}catch{}return null}async function u_0(Z=Date.now(),$=m_0,J=h_0()){let X=f_0(J);if(X&&Z-X.checkedAt<y_0)return X.latest;let Y=await $();if(Y===null)return null;return g_0(J,{checkedAt:Z,latest:Y}),Y}function p_0(Z,$=process.env){if($3(Z)===null)return null;let X=$.PATH;if(!X)return null;let Y=new Set;for(let z of X.split(":")){if(!z)continue;let Q=zP(z,"loki"),W;try{S_0(Q),W=x_0(Q)}catch{continue}if(Y.has(W))continue;Y.add(W);try{let K=zP(PW(PW(W)),"package.json"),V=JSON.parse(QP(K,"utf8")).version;if(typeof V!=="string")continue;if(EW(V,Z))return{path:Q,version:V}}catch{continue}}return null}function c_0(){return Yl(Z2(),"cache","last-seen-version.json")}function d_0(Z,$={}){try{if(zl())return!1;if($3(Z)===null)return!1;let J=$.seenFile??c_0(),X=null;try{let z=JSON.parse(QP(J,"utf-8")).version;if(typeof z==="string"&&$3(z)!==null)X=z}catch{}if(X!==null&&!EW(Z,X))return!1;try{Jl(PW(J),{recursive:!0}),Xl(J,JSON.stringify({version:Z}),"utf-8")}catch{return!1}if(X===null)return!1;return($.write??((z)=>process.stderr.write(z)))(`Loki Mode upgraded ${X} -> ${Z}. What is new: https://github.com/asklokesh/loki-mode/releases/tag/v${Z}
2
+ var M_0=Object.create;var{getPrototypeOf:O_0,defineProperty:IW,getOwnPropertyNames:rd,getOwnPropertyDescriptor:A_0}=Object,td=Object.prototype.hasOwnProperty;function ed(Z){return this[Z]}var L_0,j_0,F_0=(Z,$,J)=>{var X=Z!=null&&typeof Z==="object";if(X){var Y=$?L_0??=new WeakMap:j_0??=new WeakMap,z=Y.get(Z);if(z)return z}J=Z!=null?M_0(O_0(Z)):{};let Q=$||!Z||!Z.__esModule?IW(J,"default",{value:Z,enumerable:!0}):J;for(let W of rd(Z))if(!td.call(Q,W))IW(Q,W,{get:ed.bind(Z,W),enumerable:!0});if(X)Y.set(Z,Q);return Q},C_0=(Z)=>{var $=(sd??=new WeakMap).get(Z),J;if($)return $;if($=IW({},"__esModule",{value:!0}),Z&&typeof Z==="object"||typeof Z==="function"){for(var X of rd(Z))if(!td.call($,X))IW($,X,{get:ed.bind(Z,X),enumerable:!(J=A_0(Z,X))||J.enumerable})}return sd.set(Z,$),$},sd,SB=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var I_0=(Z)=>Z;function T_0(Z,$){this[Z]=I_0.bind(null,$)}var O0=(Z,$)=>{for(var J in $)IW(Z,J,{get:$[J],enumerable:!0,configurable:!0,set:T_0.bind($,J)})};var S=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var u9=import.meta.require;var $l={};O0($l,{lokiDir:()=>P0,homeLokiDir:()=>Z2,findRepoRootForVersion:()=>TW,REPO_ROOT:()=>j0});import{resolve as eZ,dirname as YP}from"path";import{fileURLToPath as P_0}from"url";import{existsSync as bB}from"fs";import{homedir as E_0}from"os";function R_0(){let Z=Zl;for(let $=0;$<6;$++){if(bB(eZ(Z,"VERSION"))&&bB(eZ(Z,"autonomy/run.sh")))return Z;let J=YP(Z);if(J===Z)break;Z=J}return eZ(Zl,"..","..","..")}function TW(Z){let $=Z;for(let J=0;J<6;J++){if(bB(eZ($,"VERSION"))&&bB(eZ($,"autonomy/run.sh")))return $;let X=YP($);if(X===$)break;$=X}return eZ(Z,"..","..","..")}function P0(){return process.env.LOKI_DIR??eZ(process.cwd(),".loki")}function Z2(){return eZ(E_0(),".loki")}var Zl,j0;var n0=S(()=>{Zl=YP(P_0(import.meta.url));j0=R_0()});import{readFileSync as D_0}from"fs";import{resolve as w_0,dirname as __0}from"path";import{fileURLToPath as k_0}from"url";function Q6(){if(X1!==null)return X1;let Z="11.17.45";if(typeof Z==="string"&&Z.length>0)return X1=Z,X1;try{let $=__0(k_0(import.meta.url)),J=TW($);X1=D_0(w_0(J,"VERSION"),"utf-8").trim()}catch{X1="unknown"}return X1}var X1=null;var Z3=S(()=>{n0()});import{mkdirSync as Jl,readFileSync as QP,realpathSync as x_0,statSync as S_0,writeFileSync as Xl}from"fs";import{dirname as PW,join as zP,resolve as Yl}from"path";function h_0(){return Yl(Z2(),"cache","update-check.json")}function $3(Z){let $=/^(\d+)\.(\d+)\.(\d+)$/.exec(Z.trim());if(!$)return null;return[Number($[1]),Number($[2]),Number($[3])]}function EW(Z,$){let J=$3(Z),X=$3($);if(!J||!X)return!1;let[Y,z,Q]=J,[W,K,V]=X;if(Y!==W)return Y>W;if(z!==K)return z>K;return Q>V}function zl(){let Z=(process.env.LOKI_NO_UPDATE_CHECK??"").trim().toLowerCase();if(Z==="1"||Z==="true"||Z==="yes")return!0;if(process.env.CI)return!0;if(!process.stdout.isTTY)return!0;return!1}function f_0(Z){try{let $=QP(Z,"utf-8"),J=JSON.parse($);if(typeof J.checkedAt==="number"&&typeof J.latest==="string"&&$3(J.latest)!==null)return{checkedAt:J.checkedAt,latest:J.latest}}catch{}return null}function g_0(Z,$){try{Jl(PW(Z),{recursive:!0}),Xl(Z,JSON.stringify($),"utf-8")}catch{}}async function m_0(){try{let Z=await fetch(b_0,{signal:AbortSignal.timeout(v_0),headers:{accept:"application/json"}});if(!Z.ok)return null;let $=await Z.json();if(typeof $.version==="string"&&$3($.version)!==null)return $.version}catch{}return null}async function u_0(Z=Date.now(),$=m_0,J=h_0()){let X=f_0(J);if(X&&Z-X.checkedAt<y_0)return X.latest;let Y=await $();if(Y===null)return null;return g_0(J,{checkedAt:Z,latest:Y}),Y}function p_0(Z,$=process.env){if($3(Z)===null)return null;let X=$.PATH;if(!X)return null;let Y=new Set;for(let z of X.split(":")){if(!z)continue;let Q=zP(z,"loki"),W;try{S_0(Q),W=x_0(Q)}catch{continue}if(Y.has(W))continue;Y.add(W);try{let K=zP(PW(PW(W)),"package.json"),V=JSON.parse(QP(K,"utf8")).version;if(typeof V!=="string")continue;if(EW(V,Z))return{path:Q,version:V}}catch{continue}}return null}function c_0(){return Yl(Z2(),"cache","last-seen-version.json")}function d_0(Z,$={}){try{if(zl())return!1;if($3(Z)===null)return!1;let J=$.seenFile??c_0(),X=null;try{let z=JSON.parse(QP(J,"utf-8")).version;if(typeof z==="string"&&$3(z)!==null)X=z}catch{}if(X!==null&&!EW(Z,X))return!1;try{Jl(PW(J),{recursive:!0}),Xl(J,JSON.stringify({version:Z}),"utf-8")}catch{return!1}if(X===null)return!1;return($.write??((z)=>process.stderr.write(z)))(`Loki Mode upgraded ${X} -> ${Z}. What is new: https://github.com/asklokesh/loki-mode/releases/tag/v${Z}
3
3
  `),!0}catch{return!1}}function l_0(Z){let $=Z.replace(/\\/g,"/");if($.includes("/Cellar/"))return"brew upgrade loki-mode";if($.includes("/.bun/"))return"bun install -g loki-mode (or npm i -g loki-mode)";if($.includes("/lib/node_modules/"))return"npm i -g loki-mode (or bun install -g loki-mode)";if($.includes("/homebrew/"))return"brew upgrade loki-mode";return"bun install -g loki-mode (or npm i -g loki-mode)"}async function Ql(Z,$={}){try{if(zl())return;if($3(Z)===null)return;let J=$.write??((z)=>process.stderr.write(z));d_0(Z,{write:J,...$.cacheFile?{seenFile:zP(PW($.cacheFile),"last-seen-version.json")}:{}});let X=p_0(Z,$.env??process.env);if(X!==null){J(`Loki Mode ${X.version} is installed but not the one running (you are running ${Z}).
4
4
  Another loki earlier on PATH is winning. Newer copy: ${X.path}
5
5
  Run \`which -a loki\` to see the order, then remove or re-point the earlier entry.
@@ -3120,4 +3120,4 @@ Unknown commands exit 2 with a suggestion; run 'loki help' for the full list.
3120
3120
  `);{let{suggestCommand:X}=await Promise.resolve().then(() => (bd(),fw0)),Y=$===void 0?void 0:X($);if(Y)process.stderr.write(`Did you mean 'loki ${Y}'?
3121
3121
  `)}return process.stderr.write(K_0),2}}HO0();var V_0=()=>globalThis[Symbol.for("loki.ownsStopSignals")]===!0;process.on("SIGINT",()=>{if(!V_0())process.exit(130)});process.on("SIGTERM",()=>{if(!V_0())process.exit(143)});var pz9=await uz9(Bun.argv.slice(2));process.exit(pz9);
3122
3122
 
3123
- //# debugId=BFEAB6F85439520E3208A055F96A38BD
3123
+ //# debugId=58B54108AA49BBC25CD3FBBCAD1BB4A9
package/mcp/__init__.py CHANGED
@@ -75,4 +75,4 @@ try:
75
75
  except ImportError:
76
76
  __all__ = ['mcp']
77
77
 
78
- __version__ = '11.17.44'
78
+ __version__ = '11.17.45'
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.17.44",
4
+ "version": "11.17.45",
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",
@@ -158,5 +158,5 @@
158
158
  "dependencies": {
159
159
  "@resvg/resvg-wasm": "^2.6.2"
160
160
  },
161
- "gitHead": "9bbb63bd873e3d33328ba3b6ad99b297893bccd4"
161
+ "gitHead": "e8e750117f012f0ed560eef559fb14a195fe007d"
162
162
  }
@@ -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.17.44",
5
+ "version": "11.17.45",
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-D86O9Ak6.js";import{B as C}from"./Button-B4wS8oEx.js";import{T as $e}from"./trending-up-BBN_6tC-.js";import{C as z}from"./clock-AbKik9uE.js";import{A as Be,U as ue,M as De}from"./Avatar-84eTYVHr.js";import{A as J}from"./activity-9_w3VmWg.js";import{R as pe}from"./refresh-cw-Bykzqbq7.js";import{G as ze}from"./globe-CL_RV__2.js";import{C as Le}from"./chevron-left-B4rt_k4K.js";import{C as je}from"./check-EW0lJblv.js";import{D as Y}from"./dollar-sign-C6-GwMUE.js";import{U as Te}from"./user-BkD7wEFM.js";import{D as Me}from"./database-CJHcL02M.js";import{L as Ue}from"./lock-Bd2Yj6rY.js";import{S as Re}from"./scroll-text-J8wWrWX-.js";import{S as Ie}from"./shield-alert-CryIgWVO.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-DD7FC7yd.js";import{B as C}from"./Button-C702FTxi.js";import{T as $e}from"./trending-up-hNpwNjdL.js";import{C as z}from"./clock-CHLwYBFX.js";import{A as Be,U as ue,M as De}from"./Avatar-FGro9b68.js";import{A as J}from"./activity-CHgtGwwW.js";import{R as pe}from"./refresh-cw-B0o3B073.js";import{G as ze}from"./globe-4-KwsIUo.js";import{C as Le}from"./chevron-left-B3SPNdcz.js";import{C as je}from"./check-CyFyZ4Qi.js";import{D as Y}from"./dollar-sign-BcPFsZq0.js";import{U as Te}from"./user-BCspLAnr.js";import{D as Me}from"./database-DSJlQYxs.js";import{L as Ue}from"./lock-CcI4ltMK.js";import{S as Re}from"./scroll-text-DKrZwpKk.js";import{S as Ie}from"./shield-alert-C5YWhIfX.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-D86O9Ak6.js";/**
1
+ import{c as l,j as s}from"./index-DD7FC7yd.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-D86O9Ak6.js";import{C as r}from"./clock-AbKik9uE.js";import{C as a}from"./circle-alert-DU98pynG.js";import{C as l}from"./check-EW0lJblv.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-DD7FC7yd.js";import{C as r}from"./clock-CHLwYBFX.js";import{C as a}from"./circle-alert-DcKKeKmd.js";import{C as l}from"./check-CyFyZ4Qi.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-D86O9Ak6.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-DD7FC7yd.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-D86O9Ak6.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-C3TjOwpP.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-DSLZJsOW.js";import{C as oe}from"./check-EW0lJblv.js";import{C as Ye}from"./clock-AbKik9uE.js";import{D as Xe}from"./dollar-sign-C6-GwMUE.js";import{U as Ze}from"./upload-1O3p1SX0.js";import{L as V}from"./loader-circle-Btcxs-64.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-DD7FC7yd.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-B9T1V8_Q.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-lWteH19H.js";import{C as oe}from"./check-CyFyZ4Qi.js";import{C as Ye}from"./clock-CHLwYBFX.js";import{D as Xe}from"./dollar-sign-BcPFsZq0.js";import{U as Ze}from"./upload-DmcM8inI.js";import{L as V}from"./loader-circle-ENh48A-3.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-D86O9Ak6.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-DD7FC7yd.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-D86O9Ak6.js";/**
1
+ import{c as o,r as a,j as e,T as n,h as i,p as c}from"./index-DD7FC7yd.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.