loki-mode 11.31.1 → 11.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/sandbox.sh +220 -2
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-A5UQEQzo.js → AdminPage-OCc-aouC.js} +1 -1
- package/web-app/dist/assets/{Avatar-xQ1gSPVB.js → Avatar-P8CySSFH.js} +1 -1
- package/web-app/dist/assets/{Badge-dQyhI3UH.js → Badge-Btxjz38F.js} +1 -1
- package/web-app/dist/assets/{Button-BehU-7tC.js → Button-BKE7kijL.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BPLFrfno.js → CockpitPage-B_0dgMaz.js} +1 -1
- package/web-app/dist/assets/{ComparePage-Dc7ecTbH.js → ComparePage-XMl2oBun.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-P4CkwBs3.js → ErrorBoundary-oVL59njg.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-CCC_Wc2o.js → EvidenceReceiptPanel-Ceif5573.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-Bi3c1_CN.js → GitHubIssuesPanel-jnlLMV-j.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-A7D7tuaQ.js → GitHubPRsPanel-DcXxfrgp.js} +1 -1
- package/web-app/dist/assets/{HomePage-Cj7XatdG.js → HomePage-B0_1Ubd8.js} +2 -2
- package/web-app/dist/assets/{LoginPage-lFQFWzTA.js → LoginPage-s-Q1WGev.js} +1 -1
- package/web-app/dist/assets/{MagicPage-sHngqPOB.js → MagicPage-CexVGatU.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-vmk3uj53.js → MetricsPage-DyvYyZkW.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-B37nihqx.js → NotFoundPage-CtLA5FFt.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-TrK9SBhV.js → ProjectPage-B5cKA8WR.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-BoKOqxu4.js → ProjectsPage-CgVb0y2u.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-Dfyhp6nl.js → SettingsPage-D3lfPSvp.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-DOCeqHxj.js → ShowcasePage-CEumy6-I.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-idLDGVpd.js → SystemSettingsPage-DZ-FEPPh.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-CG0cXstx.js → TeamsPage-Bf6TUaQj.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-cThU88IX.js → TemplatesPage-B-3-HIP5.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-CZcfr298.js → TerminalOutput-Cla9B3Ef.js} +1 -1
- package/web-app/dist/assets/{activity-JwnQAJzU.js → activity-BPaXjKEf.js} +1 -1
- package/web-app/dist/assets/{bell-EMBOci2m.js → bell-BIhXhta4.js} +1 -1
- package/web-app/dist/assets/{bot-Dwg7eFlL.js → bot-BREtMbFp.js} +1 -1
- package/web-app/dist/assets/{check-DNNlHviH.js → check-BBDkYdTy.js} +1 -1
- package/web-app/dist/assets/{chevron-left-BJ2VldHk.js → chevron-left-MJKoMYpu.js} +1 -1
- package/web-app/dist/assets/{circle-alert-0P4HhIzB.js → circle-alert-Bk6g0LfO.js} +1 -1
- package/web-app/dist/assets/{clock-DxxclmlE.js → clock-DphpX3yF.js} +1 -1
- package/web-app/dist/assets/{cloud-COohLeUE.js → cloud-CwIuA-VW.js} +1 -1
- package/web-app/dist/assets/{code-xml-BJ25iVx3.js → code-xml-DPGK4IbU.js} +1 -1
- package/web-app/dist/assets/{database-Dvy7Bbcf.js → database-D1oOHoQg.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-qUbMFHU4.js → dollar-sign-8w0iMGof.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-BHhWk-yB.js → file-code-corner-Do_wBHbQ.js} +1 -1
- package/web-app/dist/assets/{file-plus-CXDzSmIV.js → file-plus-yM8hYAJy.js} +1 -1
- package/web-app/dist/assets/{globe--nSuGAqH.js → globe-CvMW8-NT.js} +1 -1
- package/web-app/dist/assets/{hammer-CyPoRSsX.js → hammer-BgKbsMMT.js} +1 -1
- package/web-app/dist/assets/{index-sCyA5kT1.js → index-D_gr9DjQ.js} +3 -3
- package/web-app/dist/assets/{layers-D8YjFUHc.js → layers-kRENi5Kn.js} +1 -1
- package/web-app/dist/assets/{loader-circle-ZB7xFqz2.js → loader-circle-D1LGSlkG.js} +1 -1
- package/web-app/dist/assets/{lock-D1UH6v-O.js → lock-AWRWK-Aa.js} +1 -1
- package/web-app/dist/assets/{package-sDqydd_4.js → package-CGXLDs1G.js} +1 -1
- package/web-app/dist/assets/{plus-ClTe2QX5.js → plus-BXNCq6zK.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-D54nCHRH.js → refresh-cw-D1La5GDI.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CFJoICwQ.js → rotate-ccw-Dlm3A4yL.js} +1 -1
- package/web-app/dist/assets/{scroll-text-D_5t4SMl.js → scroll-text-BVziFaFm.js} +1 -1
- package/web-app/dist/assets/{server-cUdSs3Jw.js → server-C1QO24zQ.js} +1 -1
- package/web-app/dist/assets/{shield-alert-o3-54oNJ.js → shield-alert-DgWjn5rX.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-Bj5vm_ge.js → thumbs-up-B2v87stN.js} +1 -1
- package/web-app/dist/assets/{trash-2-D4yWbHl5.js → trash-2-BTk6wQb5.js} +1 -1
- package/web-app/dist/assets/{trending-down-DStUnNZ3.js → trending-down-YLEdCvay.js} +1 -1
- package/web-app/dist/assets/{trending-up-CL4ZFYFb.js → trending-up-B1v8JIc8.js} +1 -1
- package/web-app/dist/assets/{upload-Dem0HZRa.js → upload-iTjkpxy-.js} +1 -1
- package/web-app/dist/assets/{usePolling-14ezEt6p.js → usePolling-DaJm-uw5.js} +1 -1
- package/web-app/dist/assets/{user-DuS3X15u.js → user-DQDpD4Cu.js} +1 -1
- 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.
|
|
6
|
+
# Loki Mode v11.32.0
|
|
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
|
|
|
@@ -496,4 +496,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
496
496
|
|
|
497
497
|
---
|
|
498
498
|
|
|
499
|
-
**v11.
|
|
499
|
+
**v11.32.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.
|
|
1
|
+
11.32.0
|
package/autonomy/sandbox.sh
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# Environment Variables:
|
|
13
13
|
# LOKI_SANDBOX_IMAGE - Docker image to use (default: loki-mode:sandbox)
|
|
14
14
|
# LOKI_SANDBOX_NETWORK - Network mode: bridge, none, host (default: bridge)
|
|
15
|
+
# LOKI_SANDBOX_ALLOW_HOSTS - Opt-in egress allowlist (comma-separated hostnames);
|
|
16
|
+
# blocks link-local and private ranges (default: unset)
|
|
15
17
|
# LOKI_SANDBOX_CPUS - CPU limit (default: 2)
|
|
16
18
|
# LOKI_SANDBOX_MEMORY - Memory limit (default: 4g)
|
|
17
19
|
# LOKI_SANDBOX_READONLY - Mount project as read-only (default: false)
|
|
@@ -261,6 +263,7 @@ warn_missing_api_keys() {
|
|
|
261
263
|
cleanup_container() {
|
|
262
264
|
log_warn "Interrupted - cleaning up container..."
|
|
263
265
|
docker rm -f "$CONTAINER_NAME" 2>/dev/null || true
|
|
266
|
+
_sandbox_egress_down
|
|
264
267
|
exit 130
|
|
265
268
|
}
|
|
266
269
|
|
|
@@ -1083,6 +1086,196 @@ except: pass
|
|
|
1083
1086
|
fi
|
|
1084
1087
|
}
|
|
1085
1088
|
|
|
1089
|
+
#-------------------------------------------------------------------------------
|
|
1090
|
+
# Opt-in egress allowlist (LOKI_SANDBOX_ALLOW_HOSTS, comma-separated hostnames).
|
|
1091
|
+
# Unset: nothing below runs and the docker run argv is unchanged. Set: the sandbox
|
|
1092
|
+
# joins an --internal network (no route out) and reaches the world only through a
|
|
1093
|
+
# filtering proxy sidecar that permits the listed hosts and refuses any target
|
|
1094
|
+
# resolving to link-local, loopback or private ranges.
|
|
1095
|
+
#-------------------------------------------------------------------------------
|
|
1096
|
+
SANDBOX_ALLOW_HOSTS="${LOKI_SANDBOX_ALLOW_HOSTS:-}"
|
|
1097
|
+
EGRESS_PROXY_PORT=3128
|
|
1098
|
+
EGRESS_BLOCKED_CIDRS="169.254.0.0/16 fe80::/10 fec0::/10 100.64.0.0/10 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 127.0.0.0/8 ::1/128 fc00::/7"
|
|
1099
|
+
|
|
1100
|
+
# Print the validated allowlist one host per line. Rejects IP literals and
|
|
1101
|
+
# anything that is not a plain hostname, so a literal metadata IP can never be
|
|
1102
|
+
# allowlisted. Returns 1 on an invalid entry or an empty list.
|
|
1103
|
+
_sandbox_egress_hosts() {
|
|
1104
|
+
local raw="${1:-$SANDBOX_ALLOW_HOSTS}" h count=0
|
|
1105
|
+
local -a parts
|
|
1106
|
+
IFS=',' read -ra parts <<< "$raw"
|
|
1107
|
+
for h in "${parts[@]}"; do
|
|
1108
|
+
h="${h//[[:space:]]/}"
|
|
1109
|
+
[[ -z "$h" ]] && continue
|
|
1110
|
+
if [[ ! "$h" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)+$ ]] \
|
|
1111
|
+
|| [[ "$h" =~ ^[0-9.]+$ ]]; then
|
|
1112
|
+
log_error "LOKI_SANDBOX_ALLOW_HOSTS: invalid host (hostnames only, no IPs): $h"
|
|
1113
|
+
return 1
|
|
1114
|
+
fi
|
|
1115
|
+
printf '%s\n' "$h" | tr '[:upper:]' '[:lower:]'
|
|
1116
|
+
count=$((count+1))
|
|
1117
|
+
done
|
|
1118
|
+
[[ $count -gt 0 ]]
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
# Filtering proxy (CONNECT and plain HTTP). Decision function is check_target so
|
|
1122
|
+
# tests can exercise it with an injected resolver; no network needed.
|
|
1123
|
+
_sandbox_egress_proxy_source() {
|
|
1124
|
+
cat <<'PYEOF'
|
|
1125
|
+
import ipaddress, os, socket, sys, threading
|
|
1126
|
+
|
|
1127
|
+
ALLOW = {h.strip().lower() for h in os.environ.get("ALLOW_HOSTS", "").split(",") if h.strip()}
|
|
1128
|
+
BLOCKED = [ipaddress.ip_network(c) for c in os.environ.get("BLOCKED_CIDRS", "").split()]
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
def ip_blocked(ip):
|
|
1132
|
+
a = ipaddress.ip_address(ip)
|
|
1133
|
+
if getattr(a, "ipv4_mapped", None):
|
|
1134
|
+
a = a.ipv4_mapped
|
|
1135
|
+
return (not a.is_global or getattr(a, "is_site_local", False) or a.is_private or a.is_link_local or a.is_loopback or a.is_unspecified
|
|
1136
|
+
or a.is_multicast or a.is_reserved or any(a in n for n in BLOCKED))
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
def check_target(host, resolve=None, port=443):
|
|
1140
|
+
"""Return (ok, reason). Allowed only if host is listed, port is 80 or 443 and every resolved IP is global."""
|
|
1141
|
+
if port not in (80, 443):
|
|
1142
|
+
return False, "port not allowed"
|
|
1143
|
+
host = host.strip().lower().rstrip(".")
|
|
1144
|
+
if host not in ALLOW:
|
|
1145
|
+
return False, "host not in allowlist"
|
|
1146
|
+
resolve = resolve or (lambda h: [i[4][0] for i in socket.getaddrinfo(h, None)])
|
|
1147
|
+
try:
|
|
1148
|
+
ips = resolve(host)
|
|
1149
|
+
except Exception:
|
|
1150
|
+
return False, "resolution failed"
|
|
1151
|
+
if not ips:
|
|
1152
|
+
return False, "no address"
|
|
1153
|
+
for ip in ips:
|
|
1154
|
+
if ip_blocked(ip):
|
|
1155
|
+
return False, "resolves to blocked range " + ip
|
|
1156
|
+
return True, ips[0]
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
def pipe(a, b):
|
|
1160
|
+
try:
|
|
1161
|
+
while True:
|
|
1162
|
+
d = a.recv(65536)
|
|
1163
|
+
if not d:
|
|
1164
|
+
break
|
|
1165
|
+
b.sendall(d)
|
|
1166
|
+
except OSError:
|
|
1167
|
+
pass
|
|
1168
|
+
finally:
|
|
1169
|
+
for s in (a, b):
|
|
1170
|
+
try:
|
|
1171
|
+
s.shutdown(socket.SHUT_RDWR)
|
|
1172
|
+
except OSError:
|
|
1173
|
+
pass
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
def handle(c):
|
|
1177
|
+
try:
|
|
1178
|
+
buf = b""
|
|
1179
|
+
while b"\r\n\r\n" not in buf and len(buf) < 65536:
|
|
1180
|
+
d = c.recv(4096)
|
|
1181
|
+
if not d:
|
|
1182
|
+
return
|
|
1183
|
+
buf += d
|
|
1184
|
+
head, _, rest = buf.partition(b"\r\n\r\n")
|
|
1185
|
+
line = head.split(b"\r\n")[0].decode("latin1").split()
|
|
1186
|
+
if len(line) < 3:
|
|
1187
|
+
return
|
|
1188
|
+
method, target = line[0], line[1]
|
|
1189
|
+
if method.upper() == "CONNECT":
|
|
1190
|
+
host, _, port = target.rpartition(":")
|
|
1191
|
+
port = int(port or 443)
|
|
1192
|
+
rest_out = b""
|
|
1193
|
+
else:
|
|
1194
|
+
u = target.split("://", 1)[-1].split("/", 1)[0]
|
|
1195
|
+
host, _, port = u.partition(":")
|
|
1196
|
+
port = int(port or 80)
|
|
1197
|
+
rest_out = buf
|
|
1198
|
+
ok, info = check_target(host, port=port)
|
|
1199
|
+
if not ok:
|
|
1200
|
+
c.sendall(b"HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\n")
|
|
1201
|
+
return
|
|
1202
|
+
up = socket.create_connection((info, port), timeout=20)
|
|
1203
|
+
if method.upper() == "CONNECT":
|
|
1204
|
+
c.sendall(b"HTTP/1.1 200 Connection established\r\n\r\n")
|
|
1205
|
+
else:
|
|
1206
|
+
up.sendall(rest_out)
|
|
1207
|
+
t = threading.Thread(target=pipe, args=(up, c), daemon=True)
|
|
1208
|
+
t.start()
|
|
1209
|
+
pipe(c, up)
|
|
1210
|
+
except Exception:
|
|
1211
|
+
pass
|
|
1212
|
+
finally:
|
|
1213
|
+
c.close()
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
def main():
|
|
1217
|
+
s = socket.socket()
|
|
1218
|
+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
1219
|
+
s.bind(("0.0.0.0", int(os.environ.get("PROXY_PORT", "3128"))))
|
|
1220
|
+
s.listen(128)
|
|
1221
|
+
while True:
|
|
1222
|
+
conn, _ = s.accept()
|
|
1223
|
+
threading.Thread(target=handle, args=(conn,), daemon=True).start()
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
if __name__ == "__main__":
|
|
1227
|
+
main()
|
|
1228
|
+
PYEOF
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
# Echo the docker run argv fragments the sandbox container needs when the
|
|
1232
|
+
# allowlist is on: one token per line (network override first, then proxy env).
|
|
1233
|
+
_sandbox_egress_container_args() {
|
|
1234
|
+
local net="$1" proxy="http://${CONTAINER_NAME}-egress:${EGRESS_PROXY_PORT}"
|
|
1235
|
+
printf '%s\n' "--network=$net"
|
|
1236
|
+
local v
|
|
1237
|
+
for v in HTTP_PROXY HTTPS_PROXY http_proxy https_proxy; do
|
|
1238
|
+
printf '%s\n' "--env" "$v=$proxy"
|
|
1239
|
+
done
|
|
1240
|
+
printf '%s\n' "--env" "NO_PROXY=localhost,127.0.0.1"
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
# Echo the docker run argv for the proxy sidecar (test-visible, no side effects).
|
|
1244
|
+
_sandbox_egress_proxy_args() {
|
|
1245
|
+
local script="$1" hosts="$2"
|
|
1246
|
+
printf '%s\n' run --detach --name "${CONTAINER_NAME}-egress" \
|
|
1247
|
+
--network=bridge --cap-drop=ALL --security-opt=no-new-privileges:true \
|
|
1248
|
+
--read-only --pids-limit=128 --memory=256m \
|
|
1249
|
+
--env "ALLOW_HOSTS=$hosts" --env "BLOCKED_CIDRS=$EGRESS_BLOCKED_CIDRS" \
|
|
1250
|
+
--env "PROXY_PORT=$EGRESS_PROXY_PORT" \
|
|
1251
|
+
--volume "$script:/egress-proxy.py:ro" \
|
|
1252
|
+
--entrypoint python3 "$SANDBOX_IMAGE" /egress-proxy.py
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
# Create the internal network and proxy sidecar. Echoes the internal network name.
|
|
1256
|
+
_sandbox_egress_up() {
|
|
1257
|
+
local hosts="$1" net="${CONTAINER_NAME}-internal" script
|
|
1258
|
+
local dir="${LOKI_RUN_TMP:-${TMPDIR:-/tmp}/loki-egress-${CONTAINER_NAME}}"
|
|
1259
|
+
mkdir -p "$dir" && chmod 700 "$dir" || return 1
|
|
1260
|
+
script="$dir/egress-proxy.py"
|
|
1261
|
+
_sandbox_egress_proxy_source > "$script"
|
|
1262
|
+
docker rm -f "${CONTAINER_NAME}-egress" >/dev/null 2>&1 || true
|
|
1263
|
+
docker network rm "$net" >/dev/null 2>&1 || true
|
|
1264
|
+
docker network create --internal "$net" >/dev/null || return 1
|
|
1265
|
+
local -a pargs=()
|
|
1266
|
+
while IFS= read -r line; do pargs+=("$line"); done < <(_sandbox_egress_proxy_args "$script" "$(echo "$hosts" | paste -sd, -)")
|
|
1267
|
+
docker "${pargs[@]}" >/dev/null || return 1
|
|
1268
|
+
docker network connect --alias "${CONTAINER_NAME}-egress" "$net" "${CONTAINER_NAME}-egress" >/dev/null || return 1
|
|
1269
|
+
printf '%s\n' "$net"
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
_sandbox_egress_down() {
|
|
1273
|
+
local fb="${TMPDIR:-/tmp}/loki-egress-${CONTAINER_NAME}"
|
|
1274
|
+
if [[ -z "${LOKI_RUN_TMP:-}" && -d "$fb" && ! -L "$fb" ]]; then rm -rf -- "$fb"; fi
|
|
1275
|
+
docker rm -f "${CONTAINER_NAME}-egress" >/dev/null 2>&1 || true
|
|
1276
|
+
docker network rm "${CONTAINER_NAME}-internal" >/dev/null 2>&1 || true
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1086
1279
|
start_sandbox() {
|
|
1087
1280
|
# Parse arguments: extract flags before positional args
|
|
1088
1281
|
local prd_path=""
|
|
@@ -1158,6 +1351,22 @@ start_sandbox() {
|
|
|
1158
1351
|
# Clean up any stopped container with same name
|
|
1159
1352
|
docker rm -f "$CONTAINER_NAME" 2>/dev/null || true
|
|
1160
1353
|
|
|
1354
|
+
local network_arg="--network=$SANDBOX_NETWORK" egress_args=() egress_ok=1
|
|
1355
|
+
if [[ -n "$SANDBOX_ALLOW_HOSTS" ]]; then
|
|
1356
|
+
local egress_hosts egress_net
|
|
1357
|
+
egress_hosts=$(_sandbox_egress_hosts) || return 1
|
|
1358
|
+
if [[ "$SANDBOX_NETWORK" != "bridge" ]]; then
|
|
1359
|
+
log_error "LOKI_SANDBOX_ALLOW_HOSTS requires LOKI_SANDBOX_NETWORK=bridge (got $SANDBOX_NETWORK)"
|
|
1360
|
+
return 1
|
|
1361
|
+
fi
|
|
1362
|
+
egress_net=$(_sandbox_egress_up "$egress_hosts") || { _sandbox_egress_down; log_error "Failed to start egress proxy"; return 1; }
|
|
1363
|
+
# Any return after this point (refusal, failed docker run) must tear the proxy and network down.
|
|
1364
|
+
egress_ok=0
|
|
1365
|
+
trap '[[ "${egress_ok:-1}" == 1 ]] || _sandbox_egress_down; trap - RETURN' RETURN
|
|
1366
|
+
while IFS= read -r line; do egress_args+=("$line"); done < <(_sandbox_egress_container_args "$egress_net")
|
|
1367
|
+
network_arg="${egress_args[0]}"
|
|
1368
|
+
fi
|
|
1369
|
+
|
|
1161
1370
|
log_info "Starting sandbox container..."
|
|
1162
1371
|
log_info " Image: $SANDBOX_IMAGE"
|
|
1163
1372
|
log_info " Project: $PROJECT_DIR"
|
|
@@ -1188,8 +1397,12 @@ start_sandbox() {
|
|
|
1188
1397
|
# and should not be able to change UID/GID, which would undermine isolation
|
|
1189
1398
|
|
|
1190
1399
|
# Network
|
|
1191
|
-
"
|
|
1400
|
+
"$network_arg"
|
|
1192
1401
|
)
|
|
1402
|
+
if [[ ${#egress_args[@]} -gt 1 ]]; then
|
|
1403
|
+
docker_args+=("${egress_args[@]:1}")
|
|
1404
|
+
log_info " Egress: allowlist only ($(echo "$egress_hosts" | paste -sd, -)); private and link-local ranges blocked"
|
|
1405
|
+
fi
|
|
1193
1406
|
|
|
1194
1407
|
# Add seccomp profile if available
|
|
1195
1408
|
local seccomp_profile="$SKILL_DIR/autonomy/seccomp-sandbox.json"
|
|
@@ -1393,7 +1606,8 @@ start_sandbox() {
|
|
|
1393
1606
|
|
|
1394
1607
|
# Run container
|
|
1395
1608
|
local container_id
|
|
1396
|
-
container_id=$(docker "${docker_args[@]}")
|
|
1609
|
+
container_id=$(docker "${docker_args[@]}") || { log_error "docker run failed"; return 1; }
|
|
1610
|
+
egress_ok=1
|
|
1397
1611
|
|
|
1398
1612
|
log_success "Sandbox started: ${container_id:0:12}"
|
|
1399
1613
|
log_info ""
|
|
@@ -1435,6 +1649,7 @@ stop_sandbox() {
|
|
|
1435
1649
|
while [ $waited -lt 10 ]; do
|
|
1436
1650
|
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
1437
1651
|
log_success "Sandbox stopped gracefully"
|
|
1652
|
+
_sandbox_egress_down
|
|
1438
1653
|
# Remove the temp state dir now that the container has stopped.
|
|
1439
1654
|
if [[ -n "$_state_dir" ]] && [[ -d "$_state_dir" ]]; then
|
|
1440
1655
|
rm -rf -- "$_state_dir" 2>/dev/null || true
|
|
@@ -1455,8 +1670,10 @@ stop_sandbox() {
|
|
|
1455
1670
|
rm -rf -- "$_state_dir" 2>/dev/null || true
|
|
1456
1671
|
fi
|
|
1457
1672
|
|
|
1673
|
+
_sandbox_egress_down
|
|
1458
1674
|
log_success "Sandbox stopped"
|
|
1459
1675
|
else
|
|
1676
|
+
_sandbox_egress_down
|
|
1460
1677
|
log_warn "No running sandbox found"
|
|
1461
1678
|
fi
|
|
1462
1679
|
}
|
|
@@ -1880,6 +2097,7 @@ show_help() {
|
|
|
1880
2097
|
echo "Environment Variables:"
|
|
1881
2098
|
echo " LOKI_SANDBOX_IMAGE Docker image (default: loki-mode:sandbox)"
|
|
1882
2099
|
echo " LOKI_SANDBOX_NETWORK Network mode: bridge, none, host (default: bridge)"
|
|
2100
|
+
echo " LOKI_SANDBOX_ALLOW_HOSTS Egress allowlist, comma-separated hostnames (default: unset)"
|
|
1883
2101
|
echo " LOKI_SANDBOX_CPUS CPU limit (default: 2)"
|
|
1884
2102
|
echo " LOKI_SANDBOX_MEMORY Memory limit (default: 4g)"
|
|
1885
2103
|
echo " LOKI_SANDBOX_READONLY Mount project read-only (default: false)"
|
package/dashboard/__init__.py
CHANGED
package/docs/CLI-REFERENCE.md
CHANGED
|
@@ -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.
|
|
3
|
+
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.32.0. 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 |
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -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.
|
|
5
|
+
**Version:** v11.32.0
|
|
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
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var pb0=Object.create;var{getPrototypeOf:cb0,defineProperty:OK,getOwnPropertyNames:xi,getOwnPropertyDescriptor:db0}=Object,Si=Object.prototype.hasOwnProperty;function bi(Z){return this[Z]}var lb0,ab0,ib0=(Z,$,J)=>{var X=Z!=null&&typeof Z==="object";if(X){var Y=$?lb0??=new WeakMap:ab0??=new WeakMap,Q=Y.get(Z);if(Q)return Q}J=Z!=null?pb0(cb0(Z)):{};let z=$||!Z||!Z.__esModule?OK(J,"default",{value:Z,enumerable:!0}):J;for(let W of xi(Z))if(!Si.call(z,W))OK(z,W,{get:bi.bind(Z,W),enumerable:!0});if(X)Y.set(Z,z);return z},ob0=(Z)=>{var $=(ki??=new WeakMap).get(Z),J;if($)return $;if($=OK({},"__esModule",{value:!0}),Z&&typeof Z==="object"||typeof Z==="function"){for(var X of xi(Z))if(!Si.call($,X))OK($,X,{get:bi.bind(Z,X),enumerable:!(J=db0(Z,X))||J.enumerable})}return ki.set(Z,$),$},ki,gN=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var nb0=(Z)=>Z;function sb0(Z,$){this[Z]=nb0.bind(null,$)}var A0=(Z,$)=>{for(var J in $)OK(Z,J,{get:$[J],enumerable:!0,configurable:!0,set:sb0.bind($,J)})};var S=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var s9=import.meta.require;var vi={};A0(vi,{lokiDir:()=>P0,homeLokiDir:()=>B2,findRepoRootForVersion:()=>AK,REPO_ROOT:()=>F0});import{resolve as AZ,dirname as pR}from"path";import{fileURLToPath as rb0}from"url";import{existsSync as mN}from"fs";import{homedir as tb0}from"os";function eb0(){let Z=yi;for(let $=0;$<6;$++){if(mN(AZ(Z,"VERSION"))&&mN(AZ(Z,"autonomy/run.sh")))return Z;let J=pR(Z);if(J===Z)break;Z=J}return AZ(yi,"..","..","..")}function AK(Z){let $=Z;for(let J=0;J<6;J++){if(mN(AZ($,"VERSION"))&&mN(AZ($,"autonomy/run.sh")))return $;let X=pR($);if(X===$)break;$=X}return AZ(Z,"..","..","..")}function P0(){return process.env.LOKI_DIR??AZ(process.cwd(),".loki")}function B2(){return AZ(tb0(),".loki")}var yi,F0;var n0=S(()=>{yi=pR(rb0(import.meta.url));F0=eb0()});import{readFileSync as Zy0}from"fs";import{resolve as $y0,dirname as Jy0}from"path";import{fileURLToPath as Xy0}from"url";function q6(){if(D1!==null)return D1;let Z="11.
|
|
2
|
+
var pb0=Object.create;var{getPrototypeOf:cb0,defineProperty:OK,getOwnPropertyNames:xi,getOwnPropertyDescriptor:db0}=Object,Si=Object.prototype.hasOwnProperty;function bi(Z){return this[Z]}var lb0,ab0,ib0=(Z,$,J)=>{var X=Z!=null&&typeof Z==="object";if(X){var Y=$?lb0??=new WeakMap:ab0??=new WeakMap,Q=Y.get(Z);if(Q)return Q}J=Z!=null?pb0(cb0(Z)):{};let z=$||!Z||!Z.__esModule?OK(J,"default",{value:Z,enumerable:!0}):J;for(let W of xi(Z))if(!Si.call(z,W))OK(z,W,{get:bi.bind(Z,W),enumerable:!0});if(X)Y.set(Z,z);return z},ob0=(Z)=>{var $=(ki??=new WeakMap).get(Z),J;if($)return $;if($=OK({},"__esModule",{value:!0}),Z&&typeof Z==="object"||typeof Z==="function"){for(var X of xi(Z))if(!Si.call($,X))OK($,X,{get:bi.bind(Z,X),enumerable:!(J=db0(Z,X))||J.enumerable})}return ki.set(Z,$),$},ki,gN=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var nb0=(Z)=>Z;function sb0(Z,$){this[Z]=nb0.bind(null,$)}var A0=(Z,$)=>{for(var J in $)OK(Z,J,{get:$[J],enumerable:!0,configurable:!0,set:sb0.bind($,J)})};var S=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var s9=import.meta.require;var vi={};A0(vi,{lokiDir:()=>P0,homeLokiDir:()=>B2,findRepoRootForVersion:()=>AK,REPO_ROOT:()=>F0});import{resolve as AZ,dirname as pR}from"path";import{fileURLToPath as rb0}from"url";import{existsSync as mN}from"fs";import{homedir as tb0}from"os";function eb0(){let Z=yi;for(let $=0;$<6;$++){if(mN(AZ(Z,"VERSION"))&&mN(AZ(Z,"autonomy/run.sh")))return Z;let J=pR(Z);if(J===Z)break;Z=J}return AZ(yi,"..","..","..")}function AK(Z){let $=Z;for(let J=0;J<6;J++){if(mN(AZ($,"VERSION"))&&mN(AZ($,"autonomy/run.sh")))return $;let X=pR($);if(X===$)break;$=X}return AZ(Z,"..","..","..")}function P0(){return process.env.LOKI_DIR??AZ(process.cwd(),".loki")}function B2(){return AZ(tb0(),".loki")}var yi,F0;var n0=S(()=>{yi=pR(rb0(import.meta.url));F0=eb0()});import{readFileSync as Zy0}from"fs";import{resolve as $y0,dirname as Jy0}from"path";import{fileURLToPath as Xy0}from"url";function q6(){if(D1!==null)return D1;let Z="11.32.0";if(typeof Z==="string"&&Z.length>0)return D1=Z,D1;try{let $=Jy0(Xy0(import.meta.url)),J=AK($);D1=Zy0($y0(J,"VERSION"),"utf-8").trim()}catch{D1="unknown"}return D1}var D1=null;var LZ=S(()=>{n0()});import{mkdirSync as dR,readFileSync as uN,realpathSync as Yy0,statSync as Qy0,writeFileSync as lR}from"fs";import{dirname as XY,join as cR,resolve as hi}from"path";function Gy0(){return hi(B2(),"cache","update-check.json")}function jZ(Z){let $=/^(\d+)\.(\d+)\.(\d+)$/.exec(Z.trim());if(!$)return null;return[Number($[1]),Number($[2]),Number($[3])]}function LK(Z,$){let J=jZ(Z),X=jZ($);if(!J||!X)return!1;let[Y,Q,z]=J,[W,K,V]=X;if(Y!==W)return Y>W;if(Q!==K)return Q>K;return z>V}function fi(){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 gi(Z){try{let $=uN(Z,"utf-8"),J=JSON.parse($);if(typeof J.checkedAt==="number"&&typeof J.latest==="string"&&jZ(J.latest)!==null)return{checkedAt:J.checkedAt,latest:J.latest}}catch{}return null}function Hy0(Z){try{let $=JSON.parse(uN(Z,"utf-8")).failedAt;if(typeof $==="number")return $}catch{}return null}function qy0(Z,$){let J=gi(Z);try{dR(XY(Z),{recursive:!0}),lR(Z,JSON.stringify({...J??{},failedAt:$}),"utf-8")}catch{}}function Uy0(Z,$){try{dR(XY(Z),{recursive:!0}),lR(Z,JSON.stringify($),"utf-8")}catch{}}async function By0(){try{let Z=await fetch(zy0,{signal:AbortSignal.timeout(Ky0),headers:{accept:"application/json"}});if(!Z.ok)return null;let $=await Z.json();if(typeof $.version==="string"&&jZ($.version)!==null)return $.version}catch{}return null}async function Ny0(Z=Date.now(),$=By0,J=Gy0()){let X=gi(J);if(X&&Z-X.checkedAt<Wy0)return X.latest;let Y=Hy0(J);if(Y!==null&&Z-Y>=0&&Z-Y<Vy0)return null;let Q=await $();if(Q===null)return qy0(J,Z),null;return Uy0(J,{checkedAt:Z,latest:Q}),Q}function My0(Z,$=process.env){if(jZ(Z)===null)return null;let X=$.PATH;if(!X)return null;let Y=new Set;for(let Q of X.split(":")){if(!Q)continue;let z=cR(Q,"loki"),W;try{Qy0(z),W=Yy0(z)}catch{continue}if(Y.has(W))continue;Y.add(W);try{let K=cR(XY(XY(W)),"package.json"),V=JSON.parse(uN(K,"utf8")).version;if(typeof V!=="string")continue;if(LK(V,Z))return{path:z,version:V}}catch{continue}}return null}function Oy0(){return hi(B2(),"cache","last-seen-version.json")}function Ay0(Z,$={}){try{if(fi())return!1;if(jZ(Z)===null)return!1;let J=$.seenFile??Oy0(),X=null;try{let Q=JSON.parse(uN(J,"utf-8")).version;if(typeof Q==="string"&&jZ(Q)!==null)X=Q}catch{}if(X!==null&&!LK(Z,X))return!1;try{dR(XY(J),{recursive:!0}),lR(J,JSON.stringify({version:Z}),"utf-8")}catch{return!1}if(X===null)return!1;return($.write??((Q)=>process.stderr.write(Q)))(`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 Ly0(Z){let $=Z.replace(/\\/g,"/");if($.includes("/Cellar/"))return"brew upgrade loki-mode";if(/\/pnpm\//.test($)||$.includes("/.pnpm/"))return"pnpm add -g loki-mode (or npm i -g loki-mode)";if($.includes("/yarn/global/")||$.includes("/.yarn/"))return"yarn global add loki-mode (or npm i -g 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 mi(Z,$={}){try{if(fi())return;if(jZ(Z)===null)return;let J=$.write??((Q)=>process.stderr.write(Q));Ay0(Z,{write:J,...$.cacheFile?{seenFile:cR(XY($.cacheFile),"last-seen-version.json")}:{}});let X=My0(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.
|
|
@@ -3238,4 +3238,4 @@ Unknown commands exit 2 with a suggestion; run 'loki help' for the full list.
|
|
|
3238
3238
|
`);{let{suggestCommand:X}=await Promise.resolve().then(() => (t4(),Ao)),Y=$===void 0?void 0:X($);if(Y)process.stderr.write(`Did you mean 'loki ${Y}'?
|
|
3239
3239
|
`)}return process.stderr.write(yb0),2}}uF0();var vb0=()=>globalThis[Symbol.for("loki.ownsStopSignals")]===!0;process.on("SIGINT",()=>{if(!vb0())process.exit(130)});process.on("SIGTERM",()=>{if(!vb0())process.exit(143)});var Jq9=await $q9(Bun.argv.slice(2));process.exit(Jq9);
|
|
3240
3240
|
|
|
3241
|
-
//# debugId=
|
|
3241
|
+
//# debugId=097F6B5069B7BD2F2BE5278EF34F11FC
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "11.
|
|
4
|
+
"version": "11.32.0",
|
|
5
5
|
"description": "An autonomous software factory that knows what it is supposed to deliver, and proves it did.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -160,5 +160,5 @@
|
|
|
160
160
|
"dependencies": {
|
|
161
161
|
"@resvg/resvg-wasm": "^2.6.2"
|
|
162
162
|
},
|
|
163
|
-
"gitHead": "
|
|
163
|
+
"gitHead": "137a1518a4636d9fa33a622174d95326ff3874a3"
|
|
164
164
|
}
|
|
@@ -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.
|
|
5
|
+
"version": "11.32.0",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-
|
|
1
|
+
import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-D_gr9DjQ.js";import{B as C}from"./Button-BKE7kijL.js";import{T as $e}from"./trending-up-B1v8JIc8.js";import{C as z}from"./clock-DphpX3yF.js";import{A as Be,U as ue,M as De}from"./Avatar-P8CySSFH.js";import{A as J}from"./activity-BPaXjKEf.js";import{R as pe}from"./refresh-cw-D1La5GDI.js";import{G as ze}from"./globe-CvMW8-NT.js";import{C as Le}from"./chevron-left-MJKoMYpu.js";import{C as je}from"./check-BBDkYdTy.js";import{D as Y}from"./dollar-sign-8w0iMGof.js";import{U as Te}from"./user-DQDpD4Cu.js";import{D as Me}from"./database-D1oOHoQg.js";import{L as Ue}from"./lock-AWRWK-Aa.js";import{S as Re}from"./scroll-text-BVziFaFm.js";import{S as Ie}from"./shield-alert-DgWjn5rX.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./index-
|
|
1
|
+
import{j as e}from"./index-D_gr9DjQ.js";import{C as r}from"./clock-DphpX3yF.js";import{C as a}from"./circle-alert-Bk6g0LfO.js";import{C as l}from"./check-BBDkYdTy.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as p,j as t}from"./index-
|
|
1
|
+
import{r as p,j as t}from"./index-D_gr9DjQ.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-
|
|
1
|
+
import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-D_gr9DjQ.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-oVL59njg.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-B2v87stN.js";import{C as oe}from"./check-BBDkYdTy.js";import{C as Ye}from"./clock-DphpX3yF.js";import{D as Xe}from"./dollar-sign-8w0iMGof.js";import{U as Ze}from"./upload-iTjkpxy-.js";import{L as V}from"./loader-circle-D1LGSlkG.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-sCyA5kT1.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-D_gr9DjQ.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};
|
package/web-app/dist/assets/{EvidenceReceiptPanel-CCC_Wc2o.js → EvidenceReceiptPanel-Ceif5573.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as l,a as x,j as e}from"./index-
|
|
1
|
+
import{r as l,a as x,j as e}from"./index-D_gr9DjQ.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-
|
|
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-D_gr9DjQ.js";import{B as N}from"./Button-BKE7kijL.js";import{C as y}from"./thumbs-up-B2v87stN.js";import{R as S}from"./refresh-cw-D1La5GDI.js";import{C as z}from"./circle-alert-Bk6g0LfO.js";import{U as D}from"./user-DQDpD4Cu.js";import{L as G}from"./loader-circle-D1LGSlkG.js";import{R as T}from"./rotate-ccw-Dlm3A4yL.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-
|
|
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-D_gr9DjQ.js";import{B as y}from"./Button-BKE7kijL.js";import{C as ge}from"./chevron-left-MJKoMYpu.js";import{G as P}from"./thumbs-up-B2v87stN.js";import{R as $}from"./refresh-cw-D1La5GDI.js";import{C as Ne}from"./circle-alert-Bk6g0LfO.js";import{L as Q,S as je}from"./ProjectPage-B5cKA8WR.js";import{S as se}from"./shield-alert-DgWjn5rX.js";import{F as ye}from"./file-code-corner-Do_wBHbQ.js";import{C as V}from"./clock-DphpX3yF.js";import{C as re}from"./check-BBDkYdTy.js";import"./ErrorBoundary-oVL59njg.js";import"./TerminalOutput-Cla9B3Ef.js";import"./lock-AWRWK-Aa.js";import"./package-CGXLDs1G.js";import"./file-plus-yM8hYAJy.js";import"./activity-BPaXjKEf.js";import"./scroll-text-BVziFaFm.js";import"./bot-BREtMbFp.js";import"./loader-circle-D1LGSlkG.js";import"./hammer-BgKbsMMT.js";import"./dollar-sign-8w0iMGof.js";import"./globe-CvMW8-NT.js";import"./trash-2-BTk6wQb5.js";import"./upload-iTjkpxy-.js";import"./plus-BXNCq6zK.js";import"./rotate-ccw-Dlm3A4yL.js";import"./code-xml-DPGK4IbU.js";import"./trending-up-B1v8JIc8.js";import"./layers-kRENi5Kn.js";import"./trending-down-YLEdCvay.js";import"./server-C1QO24zQ.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|