loki-mode 11.3.9 → 11.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +34 -18
  2. package/SKILL.md +3 -3
  3. package/VERSION +1 -1
  4. package/agents/custom_agents.py +280 -0
  5. package/autonomy/council-v2.sh +22 -1
  6. package/autonomy/edit.sh +242 -0
  7. package/autonomy/lib/chat.sh +312 -0
  8. package/autonomy/lib/help-core.sh +164 -0
  9. package/autonomy/lib/json-output.sh +38 -0
  10. package/autonomy/lib/run-summary.sh +96 -0
  11. package/autonomy/loki +105 -10
  12. package/autonomy/route.sh +270 -0
  13. package/autonomy/run.sh +6 -0
  14. package/autonomy/setup-wizard.sh +161 -0
  15. package/autonomy/verify.sh +22 -2
  16. package/bin/loki +73 -18
  17. package/completions/_loki +55 -0
  18. package/completions/loki.bash +49 -3
  19. package/dashboard/__init__.py +1 -1
  20. package/docs/CLI-CORE-VERBS.md +112 -0
  21. package/docs/CLI-REFERENCE.md +7 -1
  22. package/docs/COMPARE-OPENCODE.md +94 -0
  23. package/docs/COMPONENTS.md +1 -0
  24. package/docs/INSTALLATION.md +56 -12
  25. package/docs/KNOWN-ISSUES.md +2 -12
  26. package/docs/QUICKSTART.md +108 -0
  27. package/docs/environment-variables.md +9 -2
  28. package/docs/exit-codes.md +29 -12
  29. package/docs/v10/CLI-MODERN.md +10 -4
  30. package/docs/v10/GUIDE.md +270 -44
  31. package/docs/v10/OPENCODE-PARITY-PLAN.md +84 -0
  32. package/loki-ts/dist/loki.js +968 -933
  33. package/mcp/__init__.py +1 -1
  34. package/package.json +2 -2
  35. package/packages/control-plane/dist/server.js +180 -80
  36. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  37. package/providers/claude.sh +16 -2
  38. package/providers/model_route_exec.sh +22 -0
  39. package/providers/model_routes.sh +188 -0
  40. package/skills/providers.md +13 -0
  41. package/templates/agents/planner.md +10 -0
  42. package/templates/agents/reviewer.md +10 -0
  43. package/templates/agents/tester.md +10 -0
  44. package/web-app/dist/assets/{AdminPage-QK-i_x-O.js → AdminPage-CYJ2BWRC.js} +1 -1
  45. package/web-app/dist/assets/{Avatar-DblkLNjB.js → Avatar-DdK4wynI.js} +1 -1
  46. package/web-app/dist/assets/{Badge-DIV2ny5H.js → Badge-CrX3MI7J.js} +1 -1
  47. package/web-app/dist/assets/{Button--rePJOlQ.js → Button-709-wwGM.js} +1 -1
  48. package/web-app/dist/assets/{CockpitPage-BZlKxpGy.js → CockpitPage-BapdTInO.js} +1 -1
  49. package/web-app/dist/assets/{ComparePage-3_INSVux.js → ComparePage-DT99pGvA.js} +1 -1
  50. package/web-app/dist/assets/{ErrorBoundary-DHG63CNr.js → ErrorBoundary-B0uJSys8.js} +1 -1
  51. package/web-app/dist/assets/{EvidenceReceiptPanel-DFsBnLlO.js → EvidenceReceiptPanel-BtMFgElP.js} +1 -1
  52. package/web-app/dist/assets/{GitHubIssuesPanel-phPGah98.js → GitHubIssuesPanel-DjJuU941.js} +1 -1
  53. package/web-app/dist/assets/{GitHubPRsPanel-T7KQqJmx.js → GitHubPRsPanel-HXfEX1BC.js} +1 -1
  54. package/web-app/dist/assets/{HomePage-DFjGUF5I.js → HomePage-Cqyves-S.js} +2 -2
  55. package/web-app/dist/assets/{LoginPage-CorUid_5.js → LoginPage-jUbtC7_Y.js} +1 -1
  56. package/web-app/dist/assets/{MagicPage-DofbSxKD.js → MagicPage-DHRsqjgR.js} +1 -1
  57. package/web-app/dist/assets/{MetricsPage-qzrhhfLC.js → MetricsPage-B-pED05R.js} +1 -1
  58. package/web-app/dist/assets/{NotFoundPage-BAZR0mMb.js → NotFoundPage-CsbUs21R.js} +1 -1
  59. package/web-app/dist/assets/{ProjectPage-BOSUzG9J.js → ProjectPage-BtlLEQwB.js} +3 -3
  60. package/web-app/dist/assets/{ProjectsPage-Ba0YLtzD.js → ProjectsPage-DaRbRjSp.js} +1 -1
  61. package/web-app/dist/assets/{SettingsPage-Cr10Ue2K.js → SettingsPage-DALrtP3F.js} +1 -1
  62. package/web-app/dist/assets/{ShowcasePage-Czn655fe.js → ShowcasePage-CoPHSNP0.js} +1 -1
  63. package/web-app/dist/assets/{SystemSettingsPage-Dwjnw6Ob.js → SystemSettingsPage-kOuSN50O.js} +1 -1
  64. package/web-app/dist/assets/{TeamsPage-D8nc69Be.js → TeamsPage-DGWK0LMp.js} +1 -1
  65. package/web-app/dist/assets/{TemplatesPage-DHsaCDGv.js → TemplatesPage-C-_10CwA.js} +1 -1
  66. package/web-app/dist/assets/{TerminalOutput-DBejni2a.js → TerminalOutput-Cz_vPbXL.js} +1 -1
  67. package/web-app/dist/assets/{activity-B2VsBl1C.js → activity-icIsXJVa.js} +1 -1
  68. package/web-app/dist/assets/{bell-CT77Fq2H.js → bell-DbPR2_4r.js} +1 -1
  69. package/web-app/dist/assets/{bot-DfaWgF4H.js → bot-DvjP3Yh5.js} +1 -1
  70. package/web-app/dist/assets/{check-D1yp7Ndv.js → check-D1OBxHeU.js} +1 -1
  71. package/web-app/dist/assets/{chevron-left-B6Pa8IOX.js → chevron-left-D09jDZ29.js} +1 -1
  72. package/web-app/dist/assets/{circle-alert-D5jrL_Y7.js → circle-alert-DyZMLOcC.js} +1 -1
  73. package/web-app/dist/assets/{clock-DIsY_fa_.js → clock-CdpdJTId.js} +1 -1
  74. package/web-app/dist/assets/{cloud-eGwLh1As.js → cloud-CoLTlmoj.js} +1 -1
  75. package/web-app/dist/assets/{code-xml-CGDIcZ3m.js → code-xml-DrkE2ZZY.js} +1 -1
  76. package/web-app/dist/assets/{database-CWpdaykI.js → database-CMQQuM2R.js} +1 -1
  77. package/web-app/dist/assets/{dollar-sign-DZEuTCs6.js → dollar-sign-CuioDaOG.js} +1 -1
  78. package/web-app/dist/assets/{file-code-corner-BHBW6m9v.js → file-code-corner-Cx9j9K1S.js} +1 -1
  79. package/web-app/dist/assets/{file-plus-D4h1jZSR.js → file-plus-CYD2zaaI.js} +1 -1
  80. package/web-app/dist/assets/{globe-CXdqKgwd.js → globe-6w-hnQkL.js} +1 -1
  81. package/web-app/dist/assets/{hammer-B3YuuYI_.js → hammer-BpqtautL.js} +1 -1
  82. package/web-app/dist/assets/{index-BLEnboSv.js → index-Dzs-9EgJ.js} +3 -3
  83. package/web-app/dist/assets/{layers-Dvp5nFtw.js → layers-D5hd7jb7.js} +1 -1
  84. package/web-app/dist/assets/{loader-circle-DodDmIZ3.js → loader-circle-C6Y9x_7H.js} +1 -1
  85. package/web-app/dist/assets/{lock-EiuaH1Ep.js → lock-D51L7rYh.js} +1 -1
  86. package/web-app/dist/assets/{package-Cx4m2hFg.js → package-BJF8hkP8.js} +1 -1
  87. package/web-app/dist/assets/{plus-D-Sd5rpH.js → plus-D5kUQ79n.js} +1 -1
  88. package/web-app/dist/assets/{refresh-cw-C0w1cdmF.js → refresh-cw-BKdlCa7F.js} +1 -1
  89. package/web-app/dist/assets/{rotate-ccw-C_qk6MTT.js → rotate-ccw-_bd_YI1e.js} +1 -1
  90. package/web-app/dist/assets/{scroll-text-DSxiFtkc.js → scroll-text-DbkegIxF.js} +1 -1
  91. package/web-app/dist/assets/{server-NTJt7I8M.js → server-DAwqFIsq.js} +1 -1
  92. package/web-app/dist/assets/{shield-alert-HBxMQOvH.js → shield-alert-BuR1tPHu.js} +1 -1
  93. package/web-app/dist/assets/{thumbs-up-DEgsHzSD.js → thumbs-up-BF6p3mRd.js} +1 -1
  94. package/web-app/dist/assets/{trash-2-px46FnTD.js → trash-2-BVpnkqqz.js} +1 -1
  95. package/web-app/dist/assets/{trending-down-CBosVGKa.js → trending-down-DpsDvRwW.js} +1 -1
  96. package/web-app/dist/assets/{trending-up-Dbd7zrQj.js → trending-up-mFogTjt3.js} +1 -1
  97. package/web-app/dist/assets/{upload-nhdFKAs1.js → upload-4T8zpBsi.js} +1 -1
  98. package/web-app/dist/assets/{usePolling-BgaGdinh.js → usePolling-DPXQv8WO.js} +1 -1
  99. package/web-app/dist/assets/{user-CzIihUy9.js → user-BYGIFaTm.js} +1 -1
  100. package/web-app/dist/index.html +1 -1
@@ -151,6 +151,11 @@ unset _loki_dap_root
151
151
 
152
152
  # Source the v7.5.22 Phase D mcp-config helper (idempotent).
153
153
  # shellcheck source=../autonomy/lib/mcp-config.sh
154
+ # OC-MODELS: model routes (openrouter/ollama/... over the Claude harness).
155
+ _loki_model_routes_helper="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/model_routes.sh"
156
+ # shellcheck disable=SC1090
157
+ [ -f "$_loki_model_routes_helper" ] && . "$_loki_model_routes_helper"
158
+
154
159
  _loki_mcp_config_helper="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/autonomy/lib/mcp-config.sh"
155
160
  if [ -f "$_loki_mcp_config_helper" ]; then
156
161
  # shellcheck disable=SC1090
@@ -385,7 +390,8 @@ provider_invoke() {
385
390
  # array is empty, and a bare "${arr[@]}" under `set -u` aborts with "unbound
386
391
  # variable" on bash 3.2 (stock macOS /bin/bash). ${arr[@]+...} expands to
387
392
  # nothing when unset/empty and preserves spaced elements otherwise.
388
- claude --dangerously-skip-permissions "${_LOKI_CLAUDE_AUTO_FLAGS[@]+"${_LOKI_CLAUDE_AUTO_FLAGS[@]}"}" -p "$prompt" "$@" < /dev/null
393
+ loki_model_route_prefix
394
+ "${_LOKI_ROUTE_EXEC[@]+"${_LOKI_ROUTE_EXEC[@]}"}" claude --dangerously-skip-permissions "${_LOKI_CLAUDE_AUTO_FLAGS[@]+"${_LOKI_CLAUDE_AUTO_FLAGS[@]}"}" -p "$prompt" "$@" < /dev/null
389
395
  }
390
396
 
391
397
  # provider_invoke_argv <tier> <prompt> -- populate _LOKI_INVOKE_ARGV with the
@@ -427,7 +433,9 @@ provider_invoke_argv() {
427
433
  # silently unenforced on exactly the timeout-safe seam. resolve_model_for_tier
428
434
  # is base -> route -> clamp -> alt-provider in one call; keep both paths on it.
429
435
  model="$(resolve_model_for_tier "$tier" 2>/dev/null || provider_get_tier_param "$tier")"
436
+ loki_model_route_prefix
430
437
  _LOKI_INVOKE_ARGV=(
438
+ "${_LOKI_ROUTE_EXEC[@]+"${_LOKI_ROUTE_EXEC[@]}"}"
431
439
  claude --dangerously-skip-permissions
432
440
  "${_LOKI_CLAUDE_AUTO_FLAGS[@]+"${_LOKI_CLAUDE_AUTO_FLAGS[@]}"}"
433
441
  )
@@ -638,6 +646,11 @@ resolve_model_for_tier() {
638
646
  model="$LOKI_MODEL_OVERRIDE"
639
647
  fi
640
648
 
649
+ # OC-MODELS: an active model route (openrouter/ollama/...) wins; plain ids unchanged.
650
+ local _route_model
651
+ _route_model="$(loki_model_route_model 2>/dev/null || true)"
652
+ [ -n "$_route_model" ] && model="$_route_model"
653
+
641
654
  echo "$model"
642
655
  }
643
656
 
@@ -656,5 +669,6 @@ provider_invoke_with_tier() {
656
669
  # Guard empty auto-flag array under `set -u` on bash 3.2 (stock macOS): a bare
657
670
  # "${arr[@]}" on an empty array aborts with "unbound variable". ${arr[@]+...}
658
671
  # expands to nothing when empty and preserves spaced elements otherwise.
659
- claude --dangerously-skip-permissions --model "$model" "${_LOKI_CLAUDE_AUTO_FLAGS[@]+"${_LOKI_CLAUDE_AUTO_FLAGS[@]}"}" -p "$prompt" "$@" < /dev/null
672
+ loki_model_route_prefix
673
+ "${_LOKI_ROUTE_EXEC[@]+"${_LOKI_ROUTE_EXEC[@]}"}" claude --dangerously-skip-permissions --model "$model" "${_LOKI_CLAUDE_AUTO_FLAGS[@]+"${_LOKI_CLAUDE_AUTO_FLAGS[@]}"}" -p "$prompt" "$@" < /dev/null
660
674
  }
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+ # Exec a command (the claude CLI) with the active model route applied to ITS env
3
+ # only. The token is read from the already-inherited env here, so it never
4
+ # appears on any command line and is never printed.
5
+ # Usage: bash model_route_exec.sh claude [args...]
6
+ _dir="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
7
+ # shellcheck source=model_routes.sh
8
+ . "$_dir/model_routes.sh"
9
+
10
+ spec="$(loki_model_route_spec)"
11
+ if [ -n "$spec" ] && loki_model_route_parse "$spec"; then
12
+ token=""
13
+ if [ -n "$LOKI_ROUTE_TOKEN_VAR" ]; then
14
+ token="${!LOKI_ROUTE_TOKEN_VAR:-}"
15
+ fi
16
+ export ANTHROPIC_BASE_URL="$LOKI_ROUTE_BASE"
17
+ export ANTHROPIC_MODEL="$LOKI_ROUTE_MODEL"
18
+ export ANTHROPIC_SMALL_FAST_MODEL="$LOKI_ROUTE_MODEL"
19
+ export ANTHROPIC_AUTH_TOKEN="${token:-loki-local-route}"
20
+ export ANTHROPIC_API_KEY=""
21
+ fi
22
+ exec "$@"
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env bash
2
+ # Model routes: run non-Anthropic models through the Tier-1 Claude harness.
3
+ #
4
+ # Claude Code honors ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN and ANTHROPIC_MODEL,
5
+ # so any Anthropic-compatible endpoint keeps every Loki control (cost, kill
6
+ # blocking, receipts). Mirror of loki-ts/src/providers/model_routes.ts.
7
+ #
8
+ # Spec forms (env LOKI_MODEL_ROUTE, or LOKI_MODEL_OVERRIDE when it is a route):
9
+ # openrouter/<id> https://openrouter.ai/api token: OPENROUTER_API_KEY
10
+ # ollama/<id> http://localhost:11434
11
+ # lmstudio/<id> http://localhost:1234
12
+ # llamacpp/<id> http://localhost:8080
13
+ # vllm/<id> http://localhost:8000
14
+ # custom/<id> LOKI_MODEL_BASE_URL (+ optional LOKI_MODEL_API_KEY)
15
+ # Plain Claude ids (opus, sonnet, claude-*) are not routes: behavior unchanged.
16
+ #
17
+ # The env is applied only inside providers/model_route_exec.sh, which execs the
18
+ # claude child. It is never exported into the parent shell, and the token is
19
+ # never placed on a command line or logged.
20
+
21
+ # kind -> "base_url|token_var"
22
+ loki_model_route_table() {
23
+ case "$1" in
24
+ openrouter) echo "https://openrouter.ai/api|OPENROUTER_API_KEY" ;;
25
+ ollama) echo "http://localhost:11434|" ;;
26
+ lmstudio) echo "http://localhost:1234|" ;;
27
+ llamacpp) echo "http://localhost:8080|" ;;
28
+ vllm) echo "http://localhost:8000|" ;;
29
+ custom) echo "${LOKI_MODEL_BASE_URL:-}|LOKI_MODEL_API_KEY" ;;
30
+ *) return 1 ;;
31
+ esac
32
+ }
33
+
34
+ # Echo the active route spec, or nothing when none is configured.
35
+ loki_model_route_spec() {
36
+ local s="${LOKI_MODEL_ROUTE:-}"
37
+ if [ -z "$s" ]; then
38
+ s="${LOKI_MODEL_OVERRIDE:-}"
39
+ case "$s" in
40
+ */*) loki_model_route_table "${s%%/*}" >/dev/null 2>&1 || s="" ;;
41
+ *) s="" ;;
42
+ esac
43
+ fi
44
+ [ -n "$s" ] && printf '%s\n' "$s"
45
+ return 0
46
+ }
47
+
48
+ # Parse a spec. Sets LOKI_ROUTE_KIND, LOKI_ROUTE_MODEL, LOKI_ROUTE_BASE, LOKI_ROUTE_TOKEN_VAR.
49
+ # Returns 1 when the spec is not a usable route.
50
+ loki_model_route_parse() {
51
+ local spec="${1:-}" kind model entry
52
+ case "$spec" in */*) ;; *) return 1 ;; esac
53
+ kind="${spec%%/*}"
54
+ model="${spec#*/}"
55
+ [ -n "$model" ] || return 1
56
+ entry="$(loki_model_route_table "$kind")" || return 1
57
+ LOKI_ROUTE_KIND="$kind"
58
+ LOKI_ROUTE_MODEL="$model"
59
+ LOKI_ROUTE_BASE="${entry%%|*}"
60
+ LOKI_ROUTE_TOKEN_VAR="${entry#*|}"
61
+ [ -n "$LOKI_ROUTE_BASE" ] || return 1
62
+ return 0
63
+ }
64
+
65
+ # Echo the model id served by the active route (empty when none).
66
+ loki_model_route_model() {
67
+ local spec
68
+ spec="$(loki_model_route_spec)"
69
+ [ -n "$spec" ] || return 0
70
+ loki_model_route_parse "$spec" && printf '%s\n' "$LOKI_ROUTE_MODEL"
71
+ return 0
72
+ }
73
+
74
+ # Populate _LOKI_ROUTE_EXEC with a command prefix for the claude child. Empty
75
+ # array when no route is active, so callers expand it with ${arr[@]+...}.
76
+ loki_model_route_prefix() {
77
+ _LOKI_ROUTE_EXEC=()
78
+ local spec dir
79
+ spec="$(loki_model_route_spec)"
80
+ [ -n "$spec" ] || return 0
81
+ loki_model_route_parse "$spec" || return 0
82
+ dir="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd)"
83
+ _LOKI_ROUTE_EXEC=(bash "$dir/model_route_exec.sh")
84
+ }
85
+
86
+ # Local runtime probe: print "<runtime>\t<model id>" per discovered model.
87
+ # 1s timeouts. Uses python3 only to parse JSON.
88
+ loki_models_probe_local() {
89
+ local rt url path body
90
+ for rt in "ollama|http://localhost:11434|/api/tags" \
91
+ "lmstudio|http://localhost:1234|/v1/models" \
92
+ "llamacpp|http://localhost:8080|/v1/models" \
93
+ "vllm|http://localhost:8000|/v1/models"; do
94
+ IFS='|' read -r name url path <<EOF
95
+ $rt
96
+ EOF
97
+ body="$(curl -s --connect-timeout 1 --max-time 1 "${url}${path}" 2>/dev/null)" || continue
98
+ [ -n "$body" ] || continue
99
+ printf '%s' "$body" | python3 -c '
100
+ import json, sys
101
+ name = sys.argv[1]
102
+ try:
103
+ d = json.load(sys.stdin)
104
+ except Exception:
105
+ sys.exit(0)
106
+ items = d.get("models") if isinstance(d, dict) and "models" in d else d.get("data", []) if isinstance(d, dict) else []
107
+ for m in items or []:
108
+ mid = (m.get("name") or m.get("model") or m.get("id")) if isinstance(m, dict) else None
109
+ if mid:
110
+ print(name + "\t" + mid)
111
+ ' "$name"
112
+ done
113
+ }
114
+
115
+ # loki models [--routes] [--local] [--json]
116
+ loki_models_cmd() {
117
+ local want_local=0 json=0 arg
118
+ for arg in "$@"; do
119
+ case "$arg" in
120
+ --local) want_local=1 ;;
121
+ --json) json=1 ;;
122
+ --routes) ;;
123
+ -h|--help)
124
+ echo "Usage: loki models [--local] [--json]"
125
+ echo ""
126
+ echo " (default) List model routes usable as --model / LOKI_MODEL_ROUTE values"
127
+ echo " --local Probe local runtimes (ollama, lmstudio, llamacpp, vllm) for models"
128
+ echo " --json Machine-readable output"
129
+ echo ""
130
+ echo "Route env: LOKI_MODEL_ROUTE=openrouter/<id> | ollama/<id> | lmstudio/<id> |"
131
+ echo " llamacpp/<id> | vllm/<id> | custom/<id> (needs LOKI_MODEL_BASE_URL)"
132
+ return 0
133
+ ;;
134
+ *) echo "loki models: unknown option: $arg" >&2; return 2 ;;
135
+ esac
136
+ done
137
+
138
+ local kinds="openrouter ollama lmstudio llamacpp vllm custom" k entry base tvar
139
+ if [ "$want_local" = "1" ]; then
140
+ local found
141
+ found="$(loki_models_probe_local)"
142
+ if [ "$json" = "1" ]; then
143
+ printf '%s' "$found" | python3 -c '
144
+ import json, sys
145
+ out = []
146
+ for line in sys.stdin.read().splitlines():
147
+ rt, _, mid = line.partition("\t")
148
+ out.append({"runtime": rt, "id": mid, "model": rt + "/" + mid})
149
+ print(json.dumps({"local": out}, indent=2))
150
+ '
151
+ elif [ -z "$found" ]; then
152
+ echo "No local runtimes responded (probed :11434 ollama, :1234 lmstudio, :8080 llamacpp, :8000 vllm)."
153
+ else
154
+ echo "Discovered local models (paste as LOKI_MODEL_ROUTE=<value>):"
155
+ printf '%s\n' "$found" | while IFS="$(printf '\t')" read -r rt mid; do
156
+ echo " $rt/$mid"
157
+ done
158
+ fi
159
+ return 0
160
+ fi
161
+
162
+ if [ "$json" = "1" ]; then
163
+ local sep="" first=1
164
+ printf '{"routes": ['
165
+ for k in $kinds; do
166
+ entry="$(loki_model_route_table "$k")"; base="${entry%%|*}"; tvar="${entry#*|}"
167
+ [ "$first" = "1" ] || printf ','
168
+ first=0
169
+ printf '{"kind":"%s","base_url":"%s","token_env":"%s","example":"%s/<model-id>"}' "$k" "$base" "$tvar" "$k"
170
+ done
171
+ printf ']}\n'
172
+ return 0
173
+ fi
174
+ echo "Model routes (run any Anthropic-compatible endpoint through the Claude harness):"
175
+ for k in $kinds; do
176
+ entry="$(loki_model_route_table "$k")"; base="${entry%%|*}"; tvar="${entry#*|}"
177
+ [ "$k" = "custom" ] && base="\$LOKI_MODEL_BASE_URL"
178
+ printf ' %-11s %-28s %s\n' "$k/<id>" "$base" "${tvar:+token: \$$tvar}"
179
+ done
180
+ echo ""
181
+ echo "Use: LOKI_MODEL_ROUTE=ollama/qwen3-coder loki start ./prd.md"
182
+ echo "Discover local models: loki models --local"
183
+ }
184
+
185
+ # Allow direct execution: bash providers/model_routes.sh [args]
186
+ if [ "${BASH_SOURCE[0]:-}" = "$0" ]; then
187
+ loki_models_cmd "$@"
188
+ fi
@@ -19,6 +19,7 @@ Loki Mode supports five AI providers for autonomous execution.
19
19
  | **Model Tiers** | 3 (opus/sonnet/haiku) | 1 (effort param) | 1 (external) | 1 (external) | 1 (external) |
20
20
  | **Multi-Provider** | Claude only | OpenAI only | 12+ providers | 18+ providers | 75+ providers + custom endpoints |
21
21
  | **Skill Directory** | ~/.claude/skills | None | None | None | ~/.config/opencode |
22
+ | **Guardrails (engine10)** | Native hooks + permission flags | Timeout + budget kill, diff scan, sandbox flag | Timeout + budget kill, diff scan | Timeout + budget kill, diff scan, no-auto-commits | Timeout + budget kill, diff scan |
22
23
 
23
24
  ## Provider Selection
24
25
 
@@ -396,3 +397,15 @@ PROVIDER_DEGRADED=false
396
397
  | Local models (Ollama, free) | opencode, Aider, or Cline |
397
398
  | Architect mode (dual model) | Aider |
398
399
  | Sequential-only is acceptable | Codex or Aider |
400
+
401
+ ---
402
+
403
+ ## Guardrail Parity (engine10)
404
+
405
+ Claude blocks destructive commands inline through its hooks and permission flags. For codex, cline, aider and opencode, engine10 applies `loki-ts/src/providers/provider_guard.ts` around every session:
406
+
407
+ 1. Wall-clock timeout (`limitS`) and a budget-stop poll (`BUDGET_LIMIT`) kill the whole process group.
408
+ 2. After each session a diff scan fails the iteration and reverts: mass deletion of tracked files, `.git/config` edits, new git hooks, symlinks or paths that point outside the project.
409
+ 3. Native CLI flags are used where they exist: codex `--sandbox workspace-write`, aider `--no-auto-commits`. Cline and opencode have no filesystem sandbox flag.
410
+
411
+ The scan is post-hoc, not inline, so the receipt still lists `kill blocking not enforced` for non-Claude providers. Violations emit a `guard.violation` event.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: planner
3
+ description: Breaks a goal into small ordered tasks with acceptance checks
4
+ model: opus
5
+ provider: claude
6
+ permission: plan
7
+ tools: [Read, Grep, Glob]
8
+ deny: [Edit, Write, Bash]
9
+ ---
10
+ You are a planning agent. Read the repository and split the goal into small, independently verifiable tasks. For each task give: goal, files likely touched, acceptance check, and risk. Order tasks by dependency. Do not write code.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: reviewer
3
+ description: Skeptical code reviewer for correctness, tests and maintainability
4
+ model: sonnet
5
+ provider: claude
6
+ permission: plan
7
+ tools: [Read, Grep, Glob]
8
+ deny: [Edit, Write]
9
+ ---
10
+ You are a senior code reviewer. Review the supplied evidence for correctness bugs, missing tests, security problems and maintainability issues. Cite file and line for every finding. Do not modify files. Report APPROVE only when you found no blocking issue.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: tester
3
+ description: Writes and runs focused tests for a change, reports gaps
4
+ model: sonnet
5
+ provider: claude
6
+ permission: edit
7
+ tools: [Read, Grep, Glob, Edit, Write, Bash]
8
+ deny: []
9
+ ---
10
+ You are a test engineer. For the given change, add the smallest set of tests that fail before the change and pass after. Run them and report exact commands and results. Do not alter production code; report any production bug you find instead.
@@ -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-BLEnboSv.js";import{B as C}from"./Button--rePJOlQ.js";import{T as $e}from"./trending-up-Dbd7zrQj.js";import{C as z}from"./clock-DIsY_fa_.js";import{A as Be,U as ue,M as De}from"./Avatar-DblkLNjB.js";import{A as J}from"./activity-B2VsBl1C.js";import{R as pe}from"./refresh-cw-C0w1cdmF.js";import{G as ze}from"./globe-CXdqKgwd.js";import{C as Le}from"./chevron-left-B6Pa8IOX.js";import{C as je}from"./check-D1yp7Ndv.js";import{D as Y}from"./dollar-sign-DZEuTCs6.js";import{U as Te}from"./user-CzIihUy9.js";import{D as Me}from"./database-CWpdaykI.js";import{L as Ue}from"./lock-EiuaH1Ep.js";import{S as Re}from"./scroll-text-DSxiFtkc.js";import{S as Ie}from"./shield-alert-HBxMQOvH.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-Dzs-9EgJ.js";import{B as C}from"./Button-709-wwGM.js";import{T as $e}from"./trending-up-mFogTjt3.js";import{C as z}from"./clock-CdpdJTId.js";import{A as Be,U as ue,M as De}from"./Avatar-DdK4wynI.js";import{A as J}from"./activity-icIsXJVa.js";import{R as pe}from"./refresh-cw-BKdlCa7F.js";import{G as ze}from"./globe-6w-hnQkL.js";import{C as Le}from"./chevron-left-D09jDZ29.js";import{C as je}from"./check-D1OBxHeU.js";import{D as Y}from"./dollar-sign-CuioDaOG.js";import{U as Te}from"./user-BYGIFaTm.js";import{D as Me}from"./database-CMQQuM2R.js";import{L as Ue}from"./lock-D51L7rYh.js";import{S as Re}from"./scroll-text-DbkegIxF.js";import{S as Ie}from"./shield-alert-BuR1tPHu.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-BLEnboSv.js";/**
1
+ import{c as l,j as s}from"./index-Dzs-9EgJ.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-BLEnboSv.js";import{C as r}from"./clock-DIsY_fa_.js";import{C as a}from"./circle-alert-D5jrL_Y7.js";import{C as l}from"./check-D1yp7Ndv.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-Dzs-9EgJ.js";import{C as r}from"./clock-CdpdJTId.js";import{C as a}from"./circle-alert-DyZMLOcC.js";import{C as l}from"./check-D1OBxHeU.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-BLEnboSv.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-Dzs-9EgJ.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-BLEnboSv.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-DHG63CNr.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-DEgsHzSD.js";import{C as oe}from"./check-D1yp7Ndv.js";import{C as Ye}from"./clock-DIsY_fa_.js";import{D as Xe}from"./dollar-sign-DZEuTCs6.js";import{U as Ze}from"./upload-nhdFKAs1.js";import{L as V}from"./loader-circle-DodDmIZ3.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-Dzs-9EgJ.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-B0uJSys8.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-BF6p3mRd.js";import{C as oe}from"./check-D1OBxHeU.js";import{C as Ye}from"./clock-CdpdJTId.js";import{D as Xe}from"./dollar-sign-CuioDaOG.js";import{U as Ze}from"./upload-4T8zpBsi.js";import{L as V}from"./loader-circle-C6Y9x_7H.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-BLEnboSv.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-Dzs-9EgJ.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-BLEnboSv.js";/**
1
+ import{c as o,r as a,j as e,T as n,h as i,p as c}from"./index-Dzs-9EgJ.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 l,a as x,j as e}from"./index-BLEnboSv.js";const N={verified:{badge:"bg-success/10 text-success border-success/20",dot:"bg-success",label:"Verified",proven:"The server recomputed the integrity hash and it matches, and the gpg signature verified against its keyring.",notProven:"That the code is correct, or that the recorded diff still matches your repo. A receipt records which checks ran, not that the result is right."},unsigned:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Unsigned",proven:"The server recomputed the integrity hash and it matches these receipt bytes.",notProven:"Who produced it. An unsigned receipt is forgeable: whoever controls the builder can rewrite the facts and recompute the hash."},unchecked:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Not checked",proven:"The server recomputed the integrity hash and it matches.",notProven:"Provenance. A signature is present but was not evaluated here, which is not the same as a bad signature."},tampered:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Tampered",proven:"Nothing. The server recomputed the integrity hash and it does not match the contents.",notProven:"Anything at all. This receipt was edited after it was written. Do not trust this build."},failed:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Failed verification",proven:"Nothing. A verification check ran on the server and said no.",notProven:"Anything the receipt claims. Read the reason below."},not_verified:{badge:"border-muted/20 text-muted",dot:"bg-muted/40",label:"Not verified here",proven:"Nothing. No verification result was computed for this receipt here.",notProven:"Integrity or provenance. Run the command below to check it yourself."}};function w(t){const n=t==null?void 0:t.integrity_check,r=t==null?void 0:t.verification;return n?n.status==="tampered"?"tampered":n.status==="failed"?"failed":n.status!=="verified"?"not_verified":n.gpg_ok===!0?"verified":r!=null&&r.attestation||r!=null&&r.gpg_signature?"unchecked":"unsigned":"not_verified"}const v=[{key:"verified",label:"Verified",bar:"bg-success",text:"text-success"},{key:"with_gaps",label:"With gaps",bar:"bg-warning",text:"text-warning"},{key:"not_verified",label:"Not verified",bar:"bg-danger",text:"text-danger"},{key:"unknown",label:"Unknown",bar:"bg-muted/40",text:"text-muted"}];function y({summary:t}){const n=t.total_receipts;return n?e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex h-1.5 rounded-full overflow-hidden bg-muted/10",children:v.map(({key:r,bar:s})=>{const i=t[r];return i?e.jsx("div",{className:s,style:{width:`${i/n*100}%`},title:`${i} ${r}`},r):null})}),e.jsx("div",{className:"flex flex-wrap gap-x-4 gap-y-1 text-xs",children:v.map(({key:r,label:s,text:i})=>{const c=t[r];return c?e.jsxs("span",{className:i,children:[e.jsx("span",{className:"font-semibold",children:c})," ",s.toLowerCase()]},r):null})}),e.jsxs("p",{className:"text-muted text-xs",children:["Recorded verdicts across ",n," receipt",n===1?"":"s",", not re-verified here."]})]}):null}function u({label:t,value:n}){return e.jsxs("div",{className:"flex items-baseline gap-2 text-xs",children:[e.jsx("span",{className:"text-muted w-28 flex-shrink-0",children:t}),e.jsx("span",{className:"font-mono truncate",title:n,children:n})]})}function k({proof:t}){var m,p,g,f,b;const[n,r]=l.useState(!1),[s,i]=l.useState(null),[c,d]=l.useState(null);l.useEffect(()=>{if(!n||s||c)return;let o=!1;return x.getProof(t.run_id).then(h=>{o||i(h)}).catch(h=>{o||d((h==null?void 0:h.message)||"could not load this receipt")}),()=>{o=!0}},[n,t.run_id,s,c]);const a=N[w(s)],j=t.generated_at?new Date(t.generated_at).toLocaleString():"unknown";return e.jsxs("div",{className:`border rounded-card overflow-hidden ${s?a.badge:"border-muted/20"}`,children:[e.jsxs("button",{type:"button",className:"w-full flex items-center gap-3 px-3 py-2.5 text-left",onClick:()=>r(!n),"aria-expanded":n,children:[e.jsx("span",{className:`w-2 h-2 rounded-full flex-shrink-0 ${s?a.dot:"bg-muted/40"}`}),e.jsx("span",{className:"text-sm font-medium flex-1 truncate",children:t.headline?`Recorded: ${t.headline}`:t.run_id}),t.final_verdict&&e.jsxs("span",{className:"text-xs font-mono uppercase tracking-wider flex-shrink-0 text-muted",children:["council ",t.final_verdict]}),e.jsx("span",{className:"text-muted text-xs flex-shrink-0",children:n?"−":"+"})]}),n&&e.jsxs("div",{className:"px-3 pb-3 space-y-3 border-t border-current/10 pt-3",children:[c&&e.jsxs("p",{className:"text-xs text-danger",children:["Could not load this receipt: ",c]}),!c&&!s&&e.jsx("p",{className:"text-xs text-muted",children:"Loading receipt…"}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(u,{label:"Run",value:s.run_id}),e.jsx(u,{label:"Generated",value:j}),e.jsx(u,{label:"Loki version",value:s.loki_version||"unknown"}),e.jsx(u,{label:"Cost",value:typeof((m=s.cost)==null?void 0:m.usd)=="number"?`${s.cost.cost_partial===!0?"at least ":""}$${s.cost.usd.toFixed(2)}`:"unknown"}),e.jsx(u,{label:"Files changed",value:typeof((p=s.files_changed)==null?void 0:p.count)=="number"?String(s.files_changed.count):"unknown"}),((g=s.verification)==null?void 0:g.hash)&&e.jsx(u,{label:"Recorded hash",value:s.verification.hash})]}),e.jsxs("div",{className:`rounded-card border px-3 py-2 ${a.badge}`,children:[e.jsx("p",{className:"text-xs font-semibold uppercase tracking-wider mb-1",children:a.label}),e.jsxs("p",{className:"text-xs mb-1",children:[e.jsx("span",{className:"font-semibold",children:"Proven: "}),a.proven]}),e.jsxs("p",{className:"text-xs opacity-80",children:[e.jsx("span",{className:"font-semibold",children:"Not proven: "}),a.notProven]}),(((f=s.integrity_check)==null?void 0:f.reasons)||[]).slice(0,2).map(o=>e.jsx("p",{className:"text-xs opacity-80 mt-1",children:o},o))]}),e.jsxs("p",{className:"text-xs text-muted",children:["Verify it yourself (also re-derives the diff against your repo):"," ",e.jsxs("code",{className:"font-mono",children:["loki proof verify ",s.run_id,(b=s.verification)!=null&&b.attestation?" --jwks <url|file>":""]})]}),t.pr_url&&e.jsx("a",{href:t.pr_url,target:"_blank",rel:"noreferrer noopener",className:"text-xs text-primary underline",children:"View the pull request"})]})]})]})}function P(){const[t,n]=l.useState(null),[r,s]=l.useState(null),[i,c]=l.useState(null);return l.useEffect(()=>{let d=!1;return x.listProofs().then(a=>{d||n(a.proofs||[])}).catch(a=>{d||c((a==null?void 0:a.message)||"could not load receipts")}),x.proofsSummary().then(a=>{d||s(a)}).catch(()=>{}),()=>{d=!0}},[]),e.jsxs("section",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Evidence Receipts"}),e.jsx("p",{className:"text-muted text-xs mt-1",children:"What each build actually checked, recorded so you can verify it yourself."})]}),i&&e.jsxs("p",{className:"text-xs text-danger",children:["Could not load receipts: ",i]}),!i&&t===null&&e.jsx("p",{className:"text-xs text-muted",children:"Loading…"}),r&&e.jsx(y,{summary:r}),t!==null&&t.length===0&&e.jsxs("p",{className:"text-xs text-muted",children:["No receipts yet. One is written at the end of each run (set ",e.jsx("code",{className:"font-mono",children:"LOKI_PROOF=0"})," to opt out)."]}),e.jsx("div",{className:"space-y-2",children:t==null?void 0:t.map(d=>e.jsx(k,{proof:d},d.run_id))})]})}export{P as E};
1
+ import{r as l,a as x,j as e}from"./index-Dzs-9EgJ.js";const N={verified:{badge:"bg-success/10 text-success border-success/20",dot:"bg-success",label:"Verified",proven:"The server recomputed the integrity hash and it matches, and the gpg signature verified against its keyring.",notProven:"That the code is correct, or that the recorded diff still matches your repo. A receipt records which checks ran, not that the result is right."},unsigned:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Unsigned",proven:"The server recomputed the integrity hash and it matches these receipt bytes.",notProven:"Who produced it. An unsigned receipt is forgeable: whoever controls the builder can rewrite the facts and recompute the hash."},unchecked:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Not checked",proven:"The server recomputed the integrity hash and it matches.",notProven:"Provenance. A signature is present but was not evaluated here, which is not the same as a bad signature."},tampered:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Tampered",proven:"Nothing. The server recomputed the integrity hash and it does not match the contents.",notProven:"Anything at all. This receipt was edited after it was written. Do not trust this build."},failed:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Failed verification",proven:"Nothing. A verification check ran on the server and said no.",notProven:"Anything the receipt claims. Read the reason below."},not_verified:{badge:"border-muted/20 text-muted",dot:"bg-muted/40",label:"Not verified here",proven:"Nothing. No verification result was computed for this receipt here.",notProven:"Integrity or provenance. Run the command below to check it yourself."}};function w(t){const n=t==null?void 0:t.integrity_check,r=t==null?void 0:t.verification;return n?n.status==="tampered"?"tampered":n.status==="failed"?"failed":n.status!=="verified"?"not_verified":n.gpg_ok===!0?"verified":r!=null&&r.attestation||r!=null&&r.gpg_signature?"unchecked":"unsigned":"not_verified"}const v=[{key:"verified",label:"Verified",bar:"bg-success",text:"text-success"},{key:"with_gaps",label:"With gaps",bar:"bg-warning",text:"text-warning"},{key:"not_verified",label:"Not verified",bar:"bg-danger",text:"text-danger"},{key:"unknown",label:"Unknown",bar:"bg-muted/40",text:"text-muted"}];function y({summary:t}){const n=t.total_receipts;return n?e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex h-1.5 rounded-full overflow-hidden bg-muted/10",children:v.map(({key:r,bar:s})=>{const i=t[r];return i?e.jsx("div",{className:s,style:{width:`${i/n*100}%`},title:`${i} ${r}`},r):null})}),e.jsx("div",{className:"flex flex-wrap gap-x-4 gap-y-1 text-xs",children:v.map(({key:r,label:s,text:i})=>{const c=t[r];return c?e.jsxs("span",{className:i,children:[e.jsx("span",{className:"font-semibold",children:c})," ",s.toLowerCase()]},r):null})}),e.jsxs("p",{className:"text-muted text-xs",children:["Recorded verdicts across ",n," receipt",n===1?"":"s",", not re-verified here."]})]}):null}function u({label:t,value:n}){return e.jsxs("div",{className:"flex items-baseline gap-2 text-xs",children:[e.jsx("span",{className:"text-muted w-28 flex-shrink-0",children:t}),e.jsx("span",{className:"font-mono truncate",title:n,children:n})]})}function k({proof:t}){var m,p,g,f,b;const[n,r]=l.useState(!1),[s,i]=l.useState(null),[c,d]=l.useState(null);l.useEffect(()=>{if(!n||s||c)return;let o=!1;return x.getProof(t.run_id).then(h=>{o||i(h)}).catch(h=>{o||d((h==null?void 0:h.message)||"could not load this receipt")}),()=>{o=!0}},[n,t.run_id,s,c]);const a=N[w(s)],j=t.generated_at?new Date(t.generated_at).toLocaleString():"unknown";return e.jsxs("div",{className:`border rounded-card overflow-hidden ${s?a.badge:"border-muted/20"}`,children:[e.jsxs("button",{type:"button",className:"w-full flex items-center gap-3 px-3 py-2.5 text-left",onClick:()=>r(!n),"aria-expanded":n,children:[e.jsx("span",{className:`w-2 h-2 rounded-full flex-shrink-0 ${s?a.dot:"bg-muted/40"}`}),e.jsx("span",{className:"text-sm font-medium flex-1 truncate",children:t.headline?`Recorded: ${t.headline}`:t.run_id}),t.final_verdict&&e.jsxs("span",{className:"text-xs font-mono uppercase tracking-wider flex-shrink-0 text-muted",children:["council ",t.final_verdict]}),e.jsx("span",{className:"text-muted text-xs flex-shrink-0",children:n?"−":"+"})]}),n&&e.jsxs("div",{className:"px-3 pb-3 space-y-3 border-t border-current/10 pt-3",children:[c&&e.jsxs("p",{className:"text-xs text-danger",children:["Could not load this receipt: ",c]}),!c&&!s&&e.jsx("p",{className:"text-xs text-muted",children:"Loading receipt…"}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(u,{label:"Run",value:s.run_id}),e.jsx(u,{label:"Generated",value:j}),e.jsx(u,{label:"Loki version",value:s.loki_version||"unknown"}),e.jsx(u,{label:"Cost",value:typeof((m=s.cost)==null?void 0:m.usd)=="number"?`${s.cost.cost_partial===!0?"at least ":""}$${s.cost.usd.toFixed(2)}`:"unknown"}),e.jsx(u,{label:"Files changed",value:typeof((p=s.files_changed)==null?void 0:p.count)=="number"?String(s.files_changed.count):"unknown"}),((g=s.verification)==null?void 0:g.hash)&&e.jsx(u,{label:"Recorded hash",value:s.verification.hash})]}),e.jsxs("div",{className:`rounded-card border px-3 py-2 ${a.badge}`,children:[e.jsx("p",{className:"text-xs font-semibold uppercase tracking-wider mb-1",children:a.label}),e.jsxs("p",{className:"text-xs mb-1",children:[e.jsx("span",{className:"font-semibold",children:"Proven: "}),a.proven]}),e.jsxs("p",{className:"text-xs opacity-80",children:[e.jsx("span",{className:"font-semibold",children:"Not proven: "}),a.notProven]}),(((f=s.integrity_check)==null?void 0:f.reasons)||[]).slice(0,2).map(o=>e.jsx("p",{className:"text-xs opacity-80 mt-1",children:o},o))]}),e.jsxs("p",{className:"text-xs text-muted",children:["Verify it yourself (also re-derives the diff against your repo):"," ",e.jsxs("code",{className:"font-mono",children:["loki proof verify ",s.run_id,(b=s.verification)!=null&&b.attestation?" --jwks <url|file>":""]})]}),t.pr_url&&e.jsx("a",{href:t.pr_url,target:"_blank",rel:"noreferrer noopener",className:"text-xs text-primary underline",children:"View the pull request"})]})]})]})}function P(){const[t,n]=l.useState(null),[r,s]=l.useState(null),[i,c]=l.useState(null);return l.useEffect(()=>{let d=!1;return x.listProofs().then(a=>{d||n(a.proofs||[])}).catch(a=>{d||c((a==null?void 0:a.message)||"could not load receipts")}),x.proofsSummary().then(a=>{d||s(a)}).catch(()=>{}),()=>{d=!0}},[]),e.jsxs("section",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Evidence Receipts"}),e.jsx("p",{className:"text-muted text-xs mt-1",children:"What each build actually checked, recorded so you can verify it yourself."})]}),i&&e.jsxs("p",{className:"text-xs text-danger",children:["Could not load receipts: ",i]}),!i&&t===null&&e.jsx("p",{className:"text-xs text-muted",children:"Loading…"}),r&&e.jsx(y,{summary:r}),t!==null&&t.length===0&&e.jsxs("p",{className:"text-xs text-muted",children:["No receipts yet. One is written at the end of each run (set ",e.jsx("code",{className:"font-mono",children:"LOKI_PROOF=0"})," to opt out)."]}),e.jsx("div",{className:"space-y-2",children:t==null?void 0:t.map(d=>e.jsx(k,{proof:d},d.run_id))})]})}export{P as E};
@@ -1,4 +1,4 @@
1
- import{c as _,r as o,a as k,j as e,m as B,J as v,N as h,a5 as H,M as L,l as q}from"./index-BLEnboSv.js";import{B as N}from"./Button--rePJOlQ.js";import{C as y}from"./thumbs-up-DEgsHzSD.js";import{R as S}from"./refresh-cw-C0w1cdmF.js";import{C as z}from"./circle-alert-D5jrL_Y7.js";import{U as D}from"./user-CzIihUy9.js";import{L as G}from"./loader-circle-DodDmIZ3.js";import{R as T}from"./rotate-ccw-C_qk6MTT.js";/**
1
+ import{c as _,r as o,a as k,j as e,m as B,J as v,N as h,a5 as H,M as L,l as q}from"./index-Dzs-9EgJ.js";import{B as N}from"./Button-709-wwGM.js";import{C as y}from"./thumbs-up-BF6p3mRd.js";import{R as S}from"./refresh-cw-BKdlCa7F.js";import{C as z}from"./circle-alert-DyZMLOcC.js";import{U as D}from"./user-BYGIFaTm.js";import{L as G}from"./loader-circle-C6Y9x_7H.js";import{R as T}from"./rotate-ccw-_bd_YI1e.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 I,r as c,a as b,j as e,G as me,A as ue,S as Z,k as ee,m as pe,h as he,p as fe,X as te,M as be}from"./index-BLEnboSv.js";import{B as y}from"./Button--rePJOlQ.js";import{C as ge}from"./chevron-left-B6Pa8IOX.js";import{G as P}from"./thumbs-up-DEgsHzSD.js";import{R as $}from"./refresh-cw-C0w1cdmF.js";import{C as Ne}from"./circle-alert-D5jrL_Y7.js";import{L as Q,S as je}from"./ProjectPage-BOSUzG9J.js";import{S as se}from"./shield-alert-HBxMQOvH.js";import{F as ye}from"./file-code-corner-BHBW6m9v.js";import{C as V}from"./clock-DIsY_fa_.js";import{C as re}from"./check-D1yp7Ndv.js";import"./ErrorBoundary-DHG63CNr.js";import"./TerminalOutput-DBejni2a.js";import"./lock-EiuaH1Ep.js";import"./package-Cx4m2hFg.js";import"./file-plus-D4h1jZSR.js";import"./activity-B2VsBl1C.js";import"./scroll-text-DSxiFtkc.js";import"./bot-DfaWgF4H.js";import"./loader-circle-DodDmIZ3.js";import"./hammer-B3YuuYI_.js";import"./dollar-sign-DZEuTCs6.js";import"./globe-CXdqKgwd.js";import"./trash-2-px46FnTD.js";import"./upload-nhdFKAs1.js";import"./plus-D-Sd5rpH.js";import"./rotate-ccw-C_qk6MTT.js";import"./code-xml-CGDIcZ3m.js";import"./trending-up-Dbd7zrQj.js";import"./layers-Dvp5nFtw.js";import"./trending-down-CBosVGKa.js";import"./server-NTJt7I8M.js";/**
1
+ import{c as I,r as c,a as b,j as e,G as me,A as ue,S as Z,k as ee,m as pe,h as he,p as fe,X as te,M as be}from"./index-Dzs-9EgJ.js";import{B as y}from"./Button-709-wwGM.js";import{C as ge}from"./chevron-left-D09jDZ29.js";import{G as P}from"./thumbs-up-BF6p3mRd.js";import{R as $}from"./refresh-cw-BKdlCa7F.js";import{C as Ne}from"./circle-alert-DyZMLOcC.js";import{L as Q,S as je}from"./ProjectPage-BtlLEQwB.js";import{S as se}from"./shield-alert-BuR1tPHu.js";import{F as ye}from"./file-code-corner-Cx9j9K1S.js";import{C as V}from"./clock-CdpdJTId.js";import{C as re}from"./check-D1OBxHeU.js";import"./ErrorBoundary-B0uJSys8.js";import"./TerminalOutput-Cz_vPbXL.js";import"./lock-D51L7rYh.js";import"./package-BJF8hkP8.js";import"./file-plus-CYD2zaaI.js";import"./activity-icIsXJVa.js";import"./scroll-text-DbkegIxF.js";import"./bot-DvjP3Yh5.js";import"./loader-circle-C6Y9x_7H.js";import"./hammer-BpqtautL.js";import"./dollar-sign-CuioDaOG.js";import"./globe-6w-hnQkL.js";import"./trash-2-BVpnkqqz.js";import"./upload-4T8zpBsi.js";import"./plus-D5kUQ79n.js";import"./rotate-ccw-_bd_YI1e.js";import"./code-xml-DrkE2ZZY.js";import"./trending-up-mFogTjt3.js";import"./layers-D5hd7jb7.js";import"./trending-down-DpsDvRwW.js";import"./server-DAwqFIsq.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.