loki-mode 7.104.1 → 7.104.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.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +28 -6
- package/autonomy/run.sh +134 -10
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +103 -101
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v7.104.
|
|
6
|
+
# Loki Mode v7.104.2
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -408,4 +408,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
408
408
|
|
|
409
409
|
---
|
|
410
410
|
|
|
411
|
-
**v7.104.
|
|
411
|
+
**v7.104.2 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.104.
|
|
1
|
+
7.104.2
|
package/autonomy/loki
CHANGED
|
@@ -9957,12 +9957,27 @@ cmd_doctor() {
|
|
|
9957
9957
|
echo -e " ${GREEN}PASS${NC} ANTHROPIC_API_KEY is set"
|
|
9958
9958
|
pass_count=$((pass_count + 1))
|
|
9959
9959
|
elif command -v claude &>/dev/null; then
|
|
9960
|
-
# Zero-network check:
|
|
9961
|
-
#
|
|
9962
|
-
#
|
|
9963
|
-
#
|
|
9960
|
+
# Zero-network login check. v7.104.2: prefer the CLI's own local
|
|
9961
|
+
# auth-status (JSON with "loggedIn"), which is authoritative for BOTH the
|
|
9962
|
+
# file-based and the native/Keychain login. This fixes doctor missing a
|
|
9963
|
+
# genuine Keychain login (native install writes NO ~/.claude/.credentials
|
|
9964
|
+
# .json). Fall back to the expiry stamp in the file for older CLIs.
|
|
9965
|
+
_claude_login="$(claude auth status 2>/dev/null | python3 -c "
|
|
9966
|
+
import json, sys
|
|
9967
|
+
try:
|
|
9968
|
+
v = json.load(sys.stdin).get('loggedIn')
|
|
9969
|
+
# Only the explicit booleans are trusted; a missing/renamed field is
|
|
9970
|
+
# inconclusive and falls through to the file-expiry check (never a spurious
|
|
9971
|
+
# 'not logged in' warning). Matches the run.sh helper + bun doctor.
|
|
9972
|
+
if v is True:
|
|
9973
|
+
print('yes')
|
|
9974
|
+
elif v is False:
|
|
9975
|
+
print('no')
|
|
9976
|
+
except Exception:
|
|
9977
|
+
pass
|
|
9978
|
+
" 2>/dev/null)"
|
|
9964
9979
|
_claude_creds="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/.credentials.json"
|
|
9965
|
-
|
|
9980
|
+
_claude_expired="$( [ -s "$_claude_creds" ] && python3 -c "
|
|
9966
9981
|
import json, sys, time
|
|
9967
9982
|
try:
|
|
9968
9983
|
d = json.load(open(sys.argv[1]))
|
|
@@ -9970,7 +9985,14 @@ try:
|
|
|
9970
9985
|
print('expired' if isinstance(exp,(int,float)) and exp>0 and (exp/1000.0)<=(time.time()+60) else 'ok')
|
|
9971
9986
|
except Exception:
|
|
9972
9987
|
print('ok')
|
|
9973
|
-
" "$_claude_creds" 2>/dev/null || echo ok)"
|
|
9988
|
+
" "$_claude_creds" 2>/dev/null || echo ok )"
|
|
9989
|
+
if [ "$_claude_login" = "yes" ]; then
|
|
9990
|
+
echo -e " ${GREEN}PASS${NC} Claude CLI is logged in (subscription/OAuth login)"
|
|
9991
|
+
pass_count=$((pass_count + 1))
|
|
9992
|
+
elif [ "$_claude_login" = "no" ]; then
|
|
9993
|
+
echo -e " ${YELLOW}WARN${NC} Claude CLI is NOT logged in -- run 'claude login' before a build (it would otherwise stall)"
|
|
9994
|
+
warn_count=$((warn_count + 1))
|
|
9995
|
+
elif [ "$_claude_expired" = "expired" ]; then
|
|
9974
9996
|
echo -e " ${YELLOW}WARN${NC} Claude login has EXPIRED -- run 'claude login' before a build (it would otherwise stall)"
|
|
9975
9997
|
warn_count=$((warn_count + 1))
|
|
9976
9998
|
else
|
package/autonomy/run.sh
CHANGED
|
@@ -2023,6 +2023,118 @@ _loki_check_git_present() {
|
|
|
2023
2023
|
return 0
|
|
2024
2024
|
}
|
|
2025
2025
|
|
|
2026
|
+
# _loki_claude_login_state: report the Claude Code login state WITHOUT a network
|
|
2027
|
+
# call, printing exactly one of: loggedin | expired | loggedout | unknown.
|
|
2028
|
+
#
|
|
2029
|
+
# v7.104.2: the previous preflight assumed OAuth credentials always live in
|
|
2030
|
+
# ~/.claude/.credentials.json. That is false for the native install (Claude Code
|
|
2031
|
+
# 2.x on macOS), which stores the login in the macOS Keychain under the service
|
|
2032
|
+
# "Claude Code-credentials" and creates NO .credentials.json. A genuinely logged
|
|
2033
|
+
# in subscription user was therefore falsely told "installed but not logged in"
|
|
2034
|
+
# and blocked from every build -- the exact opposite of the zero-friction intent.
|
|
2035
|
+
#
|
|
2036
|
+
# Design: prefer the durable, CLI-owned signal (`claude auth status`, local +
|
|
2037
|
+
# fast + non-interactive, JSON with "loggedIn"), because the credential STORE
|
|
2038
|
+
# location has now moved twice (file -> keychain) and will move again. Fall back
|
|
2039
|
+
# to the file, then the keychain, for older CLIs that lack `auth status`. Crucial
|
|
2040
|
+
# rule (inconclusive-never-false-fails applied to auth): only ever return a hard
|
|
2041
|
+
# "loggedout" on POSITIVE evidence of no login; when we cannot tell, return
|
|
2042
|
+
# "unknown" and let the caller fail OPEN (warn, proceed, let the real call
|
|
2043
|
+
# decide) -- never hard-block a paying user on uncertainty.
|
|
2044
|
+
_loki_claude_login_state() {
|
|
2045
|
+
# 1) Primary: the CLI's own local auth-status (zero-network, ~0.2s). Newer
|
|
2046
|
+
# claude CLIs print JSON with a boolean "loggedIn"; parse defensively.
|
|
2047
|
+
if command -v claude >/dev/null 2>&1; then
|
|
2048
|
+
local _status_json
|
|
2049
|
+
_status_json="$(claude auth status 2>/dev/null)"
|
|
2050
|
+
if [[ -n "$_status_json" ]]; then
|
|
2051
|
+
local _parsed
|
|
2052
|
+
_parsed="$(printf '%s' "$_status_json" | python3 -c "
|
|
2053
|
+
import json, sys
|
|
2054
|
+
try:
|
|
2055
|
+
d = json.load(sys.stdin)
|
|
2056
|
+
v = d.get('loggedIn')
|
|
2057
|
+
# ONLY the two explicit booleans are trusted. Anything else -- a missing
|
|
2058
|
+
# field, a renamed schema, a JSON error object -- is inconclusive and MUST
|
|
2059
|
+
# fall through to the file/keychain checks, never a hard 'loggedout' (that
|
|
2060
|
+
# would block a genuinely logged-in user with a valid creds file, violating
|
|
2061
|
+
# fail-open). Mirrors the bun doctor's === true / === false / else shape.
|
|
2062
|
+
if v is True:
|
|
2063
|
+
print('loggedin')
|
|
2064
|
+
elif v is False:
|
|
2065
|
+
print('loggedout')
|
|
2066
|
+
# else: print nothing -> fall through
|
|
2067
|
+
except Exception:
|
|
2068
|
+
pass # not JSON (older CLI / different output) -> stay silent, fall through
|
|
2069
|
+
" 2>/dev/null)"
|
|
2070
|
+
if [[ "$_parsed" == "loggedin" ]]; then
|
|
2071
|
+
echo "loggedin"; return 0
|
|
2072
|
+
elif [[ "$_parsed" == "loggedout" ]]; then
|
|
2073
|
+
echo "loggedout"; return 0
|
|
2074
|
+
fi
|
|
2075
|
+
# auth status ran but was inconclusive (unparseable, or valid JSON
|
|
2076
|
+
# without an explicit loggedIn boolean) -> do NOT trust it as a
|
|
2077
|
+
# negative; fall through to the credential-store checks below.
|
|
2078
|
+
fi
|
|
2079
|
+
fi
|
|
2080
|
+
|
|
2081
|
+
# 2) Fallback: a VALID (non-expired) OAuth credentials file (older CLIs write
|
|
2082
|
+
# it here). Compute the expiry once; a valid file is a positive login.
|
|
2083
|
+
# IMPORTANT: we do NOT conclude "expired" here yet -- a stale expired file
|
|
2084
|
+
# can sit next to a live macOS-Keychain login (the native install writes
|
|
2085
|
+
# the file once, then rotates only the Keychain). Concluding "expired" off
|
|
2086
|
+
# the file before consulting the Keychain would wrongly block a genuinely
|
|
2087
|
+
# logged-in user -- the exact class of bug this whole change fixes. So the
|
|
2088
|
+
# Keychain (step 3, a POSITIVE signal) is checked BEFORE we ever return
|
|
2089
|
+
# "expired" (step 4). Unknown schema -> treat as valid (fail open).
|
|
2090
|
+
local _creds="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/.credentials.json"
|
|
2091
|
+
local _file_state="" # ""=absent, "valid"=present+fresh, "expired"=present+stale
|
|
2092
|
+
if [[ -s "$_creds" ]]; then
|
|
2093
|
+
_file_state="$(python3 -c "
|
|
2094
|
+
import json, sys, time
|
|
2095
|
+
try:
|
|
2096
|
+
d = json.load(open(sys.argv[1]))
|
|
2097
|
+
exp = d.get('claudeAiOauth', {}).get('expiresAt')
|
|
2098
|
+
if isinstance(exp, (int, float)) and exp > 0 and (exp / 1000.0) <= (time.time() + 60):
|
|
2099
|
+
print('expired')
|
|
2100
|
+
else:
|
|
2101
|
+
print('valid')
|
|
2102
|
+
except Exception:
|
|
2103
|
+
print('valid') # unreadable/unknown -> fail open (treat as valid)
|
|
2104
|
+
" "$_creds" 2>/dev/null || echo valid)"
|
|
2105
|
+
fi
|
|
2106
|
+
if [[ "$_file_state" == "valid" ]]; then
|
|
2107
|
+
echo "loggedin"; return 0
|
|
2108
|
+
fi
|
|
2109
|
+
|
|
2110
|
+
# 3) macOS Keychain (native install stores the login here, often with NO file
|
|
2111
|
+
# at all, or alongside a now-stale file). A present Keychain entry is a
|
|
2112
|
+
# POSITIVE login signal and OVERRIDES an expired file. Existence check
|
|
2113
|
+
# ONLY -- never `-w` (reading the secret can pop a GUI keychain prompt that
|
|
2114
|
+
# would hang a headless/CI build). Guarded to Darwin.
|
|
2115
|
+
if [[ "$(uname 2>/dev/null)" == "Darwin" ]] && command -v security >/dev/null 2>&1; then
|
|
2116
|
+
if security find-generic-password -s "Claude Code-credentials" >/dev/null 2>&1; then
|
|
2117
|
+
echo "loggedin"; return 0
|
|
2118
|
+
fi
|
|
2119
|
+
fi
|
|
2120
|
+
|
|
2121
|
+
# 4) Only now, with no valid file and no Keychain login, is an expired file a
|
|
2122
|
+
# real "expired" state (genuine expiry that would 401 mid-build).
|
|
2123
|
+
if [[ "$_file_state" == "expired" ]]; then
|
|
2124
|
+
echo "expired"; return 0
|
|
2125
|
+
fi
|
|
2126
|
+
|
|
2127
|
+
# 5) No positive login evidence at all. On macOS (where the file AND the
|
|
2128
|
+
# Keychain are the two real stores, both absent) with the CLI present, that
|
|
2129
|
+
# is confident "logged out". Anywhere else we cannot prove absence of a
|
|
2130
|
+
# login (no Keychain to consult), so stay "unknown" and let the caller fail
|
|
2131
|
+
# open.
|
|
2132
|
+
if [[ "$(uname 2>/dev/null)" == "Darwin" ]] && command -v claude >/dev/null 2>&1; then
|
|
2133
|
+
echo "loggedout"; return 0
|
|
2134
|
+
fi
|
|
2135
|
+
echo "unknown"; return 0
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2026
2138
|
# _loki_check_workspace_writable: the build writes state, proofs, and source into
|
|
2027
2139
|
# the working directory and its .loki/ subtree on every iteration. A read-only
|
|
2028
2140
|
# volume, a permission-denied directory, or a full disk would otherwise fail
|
|
@@ -2108,21 +2220,33 @@ validate_api_keys() {
|
|
|
2108
2220
|
|
|
2109
2221
|
# Zero-friction auth preflight for LOCAL runs (must run BEFORE the early
|
|
2110
2222
|
# return below, which exits for non-Docker/K8s envs). When claude is the
|
|
2111
|
-
# provider
|
|
2112
|
-
#
|
|
2113
|
-
#
|
|
2114
|
-
# 401 -- the worst first impression --
|
|
2115
|
-
#
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2223
|
+
# provider and there is no ANTHROPIC_API_KEY, ask the login-state helper
|
|
2224
|
+
# (auth-status -> file -> keychain, all zero-network) whether the user is
|
|
2225
|
+
# actually logged in. A never-logged-in user would otherwise enter the build,
|
|
2226
|
+
# make a failing call, and 401 -- the worst first impression -- so we fail
|
|
2227
|
+
# fast with the one-step fix. But we ONLY hard-block on a confident
|
|
2228
|
+
# "loggedout"; an "expired" login gets its own message; "unknown" (we cannot
|
|
2229
|
+
# prove the login state, e.g. an older CLI on a non-macOS box with no file)
|
|
2230
|
+
# fails OPEN so a genuinely logged-in user is never blocked. This is the
|
|
2231
|
+
# v7.104.2 fix for the native/Keychain login being misread as logged out.
|
|
2232
|
+
# Opt out entirely with LOKI_SKIP_AUTH_PREFLIGHT=1.
|
|
2233
|
+
if [[ "$provider" == "claude" && "${LOKI_SKIP_AUTH_PREFLIGHT:-}" != "1" && -z "${ANTHROPIC_API_KEY:-}" ]]; then
|
|
2234
|
+
local _login_state
|
|
2235
|
+
_login_state="$(_loki_claude_login_state)"
|
|
2236
|
+
if [[ "$_login_state" == "loggedout" ]]; then
|
|
2120
2237
|
log_error "Claude Code is installed but not logged in -- the build would stall instead of running."
|
|
2121
2238
|
log_error "Log in once, then retry:"
|
|
2122
2239
|
log_error " claude login"
|
|
2123
2240
|
log_error "(or set ANTHROPIC_API_KEY, or LOKI_SKIP_AUTH_PREFLIGHT=1 to bypass this check)"
|
|
2124
2241
|
return 1
|
|
2242
|
+
elif [[ "$_login_state" == "expired" ]]; then
|
|
2243
|
+
log_error "Your Claude Code login has expired -- the build would stall instead of running."
|
|
2244
|
+
log_error "Fix it in one step, then retry:"
|
|
2245
|
+
log_error " claude login"
|
|
2246
|
+
log_error "(or set ANTHROPIC_API_KEY, or LOKI_SKIP_AUTH_PREFLIGHT=1 to bypass this check)"
|
|
2247
|
+
return 1
|
|
2125
2248
|
fi
|
|
2249
|
+
# "loggedin" or "unknown" -> proceed (fail open on uncertainty).
|
|
2126
2250
|
fi
|
|
2127
2251
|
|
|
2128
2252
|
# CLI tools (claude, codex, cline, aider) use their own login sessions.
|
|
@@ -19023,7 +19147,7 @@ main() {
|
|
|
19023
19147
|
_handoff_dir="${TARGET_DIR:-.}"
|
|
19024
19148
|
_handoff_md="$_handoff_dir/HANDOFF.md"
|
|
19025
19149
|
_handoff_tmp="$_handoff_dir/.HANDOFF.md.tmp"
|
|
19026
|
-
if python3 "$_own_render" --loki-dir "$LOKI_DIR" --md > "$_handoff_tmp" 2>/dev/null; then
|
|
19150
|
+
if python3 "$_own_render" --loki-dir "${LOKI_DIR:-${TARGET_DIR:-.}/.loki}" --md > "$_handoff_tmp" 2>/dev/null; then
|
|
19027
19151
|
mv -f "$_handoff_tmp" "$_handoff_md" 2>/dev/null || rm -f "$_handoff_tmp" 2>/dev/null || true
|
|
19028
19152
|
else
|
|
19029
19153
|
rm -f "$_handoff_tmp" 2>/dev/null || true
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
|
|
4
4
|
|
|
5
|
-
**Version:** v7.104.
|
|
5
|
+
**Version:** v7.104.2
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var X8=Object.defineProperty;var K8=($)=>$;function q8($,Q){this[$]=K8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)X8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:q8.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var J$=import.meta.require;var v1={};b(v1,{lokiDir:()=>P,homeLokiDir:()=>T$,findRepoRootForVersion:()=>e$,REPO_ROOT:()=>h});import{resolve as r,dirname as i$}from"path";import{fileURLToPath as J8}from"url";import{existsSync as x$}from"fs";import{homedir as V8}from"os";function W8(){let $=y1;for(let Q=0;Q<6;Q++){if(x$(r($,"VERSION"))&&x$(r($,"autonomy/run.sh")))return $;let Z=i$($);if(Z===$)break;$=Z}return r(y1,"..","..","..")}function e$($){let Q=$;for(let Z=0;Z<6;Z++){if(x$(r(Q,"VERSION"))&&x$(r(Q,"autonomy/run.sh")))return Q;let z=i$(Q);if(z===Q)break;Q=z}return r($,"..","..","..")}function P(){return process.env.LOKI_DIR??r(process.cwd(),".loki")}function T$(){return r(V8(),".loki")}var y1,h;var C=L(()=>{y1=i$(J8(import.meta.url));h=W8()});import{readFileSync as U8}from"fs";import{resolve as H8,dirname as G8}from"path";import{fileURLToPath as B8}from"url";function N$(){if(Q$!==null)return Q$;let $="7.104.2";if(typeof $==="string"&&$.length>0)return Q$=$,Q$;try{let Q=G8(B8(import.meta.url)),Z=e$(Q);Q$=U8(H8(Z,"VERSION"),"utf-8").trim()}catch{Q$="unknown"}return Q$}var Q$=null;var $1=L(()=>{C()});var c1={};b(c1,{runOrThrow:()=>x8,run:()=>F,readStreamCapped:()=>u1,commandVersion:()=>S8,commandExists:()=>f,ShellError:()=>Q1,MAX_STDOUT_BYTES:()=>f1});async function u1($,Q=f1){let Z=$.getReader(),z=new TextDecoder,X="",q=0;try{while(q<Q){let{done:K,value:W}=await Z.read();if(K)break;if(!W)continue;if(q+=W.byteLength,q>Q){let V=W.byteLength-(q-Q);X+=z.decode(W.subarray(0,V),{stream:!0});break}X+=z.decode(W,{stream:!0})}X+=z.decode()}finally{try{await Z.cancel()}catch{}Z.releaseLock()}return X}async function F($,Q={}){let Z=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:Q.env?{...process.env,...Q.env}:process.env,cwd:Q.cwd}),z,X;if(Q.timeoutMs&&Q.timeoutMs>0)z=setTimeout(()=>{try{Z.kill("SIGTERM")}catch{}X=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},2000)},Q.timeoutMs);try{let[q,K,W]=await Promise.all([u1(Z.stdout),new Response(Z.stderr).text(),Z.exited]);return{stdout:q,stderr:K,exitCode:W}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function x8($,Q={}){let Z=await F($,Q);if(Z.exitCode!==0)throw new Q1(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function f($){let Q=N8($),Z=await F(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function N8($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function S8($,Q="--version"){if(!await f($))return null;let z=await F([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var f1=16777216,Q1;var d=L(()=>{Q1=class Q1 extends Error{message;exitCode;stdout;stderr;constructor($,Q,Z,z){super($);this.message=$;this.exitCode=Q;this.stdout=Z;this.stderr=z;this.name="ShellError"}}});function t($){return D8?"":$}var D8,T,S,_,nZ,I,k,y,J;var c=L(()=>{D8=(process.env.NO_COLOR??"").length>0;T=t("\x1B[0;31m"),S=t("\x1B[0;32m"),_=t("\x1B[1;33m"),nZ=t("\x1B[0;34m"),I=t("\x1B[0;36m"),k=t("\x1B[1m"),y=t("\x1B[2m"),J=t("\x1B[0m")});import{existsSync as c8}from"fs";async function Z$(){if(A$!==void 0)return A$;let $="/opt/homebrew/bin/python3.12";if(c8($))return A$=$,$;let Q=await f("python3.12");if(Q)return A$=Q,Q;let Z=await f("python3");return A$=Z,Z}async function z$($,Q={}){let Z=await Z$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return F([Z,"-c",$],Q)}var A$;var V$=L(()=>{d()});var J0={};b(J0,{runStatus:()=>U3});import{existsSync as v,readFileSync as U$,readdirSync as e1,statSync as $0}from"fs";import{resolve as D,basename as Q3}from"path";import{homedir as Z3}from"os";function Q0($){let Q=Math.trunc($);if(Q>=1e6)return`${(Math.trunc(Q/1e6*10)/10).toFixed(1)}M`;if(Q>=1000)return`${(Math.trunc(Q/1000*10)/10).toFixed(1)}K`;return String(Q)}function Z0($,Q,Z){if(Q===0)return null;let z=Math.trunc($*100/Q),X=Math.trunc($*D$/Q);if(X>D$)X=D$;let q=D$-X,K=S;if(z>=80)K=T;else if(z>=50)K=_;let W="=".repeat(Math.max(0,X))+" ".repeat(Math.max(0,q)),V=Q0($),U=Q0(Q);return` ${k}${Z}${J} ${K}[${W}]${J} ${z}% (${V} / ${U})`}async function X3(){if(await f("jq"))return!0;return process.stdout.write(`${T}Error: jq is required but not installed.${J}
|
|
3
3
|
`),process.stdout.write(`Install with:
|
|
4
4
|
`),process.stdout.write(` brew install jq (macOS)
|
|
5
5
|
`),process.stdout.write(` apt install jq (Debian/Ubuntu)
|
|
6
6
|
`),process.stdout.write(` yum install jq (RHEL/CentOS)
|
|
7
|
-
`),!1}function C$($){if(!Number.isFinite($)||$<=0)return!1;try{return process.kill($,0),!0}catch{return!1}}function b$($){if(!v($))return null;try{let Q=U$($,"utf-8").trim();if(!Q)return null;let Z=Number.parseInt(Q,10);return Number.isFinite(Z)?Z:null}catch{return null}}function
|
|
7
|
+
`),!1}function C$($){if(!Number.isFinite($)||$<=0)return!1;try{return process.kill($,0),!0}catch{return!1}}function b$($){if(!v($))return null;try{let Q=U$($,"utf-8").trim();if(!Q)return null;let Z=Number.parseInt(Q,10);return Number.isFinite(Z)?Z:null}catch{return null}}function K3($){let Q=[],Z=b$(D($,"loki.pid"));if(Z!==null&&C$(Z))Q.push(`global:${Z}`);let z=D($,"sessions");if(v(z)){let X=[];try{X=e1(z)}catch{X=[]}for(let q of X){let K=D(z,q);try{if(!$0(K).isDirectory())continue}catch{continue}let W=D(K,"loki.pid"),V=b$(W);if(V!==null&&C$(V))Q.push(`${q}:${V}`)}}if(v($)){let X=[];try{X=e1($)}catch{X=[]}for(let q of X){if(!q.startsWith("run-")||!q.endsWith(".pid"))continue;let K=D($,q);try{if(!$0(K).isFile())continue}catch{continue}let W=Q3(q,".pid").slice(4),V=b$(K);if(V!==null&&C$(V)){if(!Q.some((H)=>H.startsWith(`${W}:`)))Q.push(`${W}:${V}`)}}}return Q}async function z0($,Q){let Z=await F(["jq","-r",$,Q]);if(Z.exitCode!==0)return null;return Z.stdout.trim()}function X0($,Q){try{let Z=U$($,"utf-8"),X=JSON.parse(Z)[Q];if(typeof X==="number"){if(Q==="budget_used"){let q=Math.round(X*100)/100;if(Number.isInteger(q))return String(q);return String(q)}return String(X)}if(X===void 0||X===null)return"0";return String(X)}catch{return"0"}}function K0($,Q,Z){try{let z=U$($,"utf-8"),q=JSON.parse(z)[Q];if(typeof q==="number"&&Number.isFinite(q))return q;return Z}catch{return Z}}async function q3(){let $=P();if(!await X3())return 1;if(!v($))return process.stdout.write(`${k}Loki Mode Status${J}
|
|
8
8
|
`),process.stdout.write(`
|
|
9
9
|
`),process.stdout.write(`${_}No active session found.${J}
|
|
10
10
|
`),process.stdout.write(`Loki Mode has not been initialized in this directory.
|
|
@@ -19,7 +19,7 @@ var z8=Object.defineProperty;var X8=($)=>$;function K8($,Q){this[$]=X8.bind(null
|
|
|
19
19
|
`);let Q="",Z=D($,"state","provider");if(v(Z))try{Q=U$(Z,"utf-8").trim()}catch{Q=""}let z=Q||process.env.LOKI_PROVIDER||"claude",X="full features";switch(z){case"codex":case"aider":X="degraded mode";break;case"cline":X="near-full mode";break;default:X="full features";break}process.stdout.write(`${I}Provider:${J} ${z} (${X})
|
|
20
20
|
`),process.stdout.write(`${y} Switch with: loki provider set <claude|codex|cline|aider>${J}
|
|
21
21
|
`),process.stdout.write(`
|
|
22
|
-
`);let q=
|
|
22
|
+
`);let q=K3($);if(q.length>0){process.stdout.write(`${S}Active Sessions: ${q.length}${J}
|
|
23
23
|
`);for(let Y of q){let O=Y.indexOf(":"),M=O>=0?Y.slice(0,O):Y,R=O>=0?Y.slice(O+1):"";if(M==="global")process.stdout.write(` ${I}[global]${J} PID ${R}
|
|
24
24
|
`);else process.stdout.write(` ${I}[#${M}]${J} PID ${R}
|
|
25
25
|
`)}process.stdout.write(`
|
|
@@ -41,21 +41,21 @@ var z8=Object.defineProperty;var X8=($)=>$;function K8($,Q){this[$]=X8.bind(null
|
|
|
41
41
|
`);let M=Math.trunc((Number.parseFloat(O)||0)*100),R=Number.parseFloat(Y),N=Number.isFinite(R)&&R!==0?Math.trunc(R*100):100,g=Z0(M,N,"Budget");if(g!==null)process.stdout.write(`${g}
|
|
42
42
|
`)}else process.stdout.write(`${I}Cost:${J} $${O} (no limit)
|
|
43
43
|
`)}let H=D($,"state","context-usage.json");if(v(H)){let Y=K0(H,"window_size",200000),O=K0(H,"used_tokens",0),M=Z0(O,Y,"Context");if(M!==null)process.stdout.write(`${M}
|
|
44
|
-
`)}let G=[D($,"dashboard","dashboard.pid"),D(
|
|
45
|
-
`)}}return await
|
|
44
|
+
`)}let G=[D($,"dashboard","dashboard.pid"),D(Z3(),".loki","dashboard","dashboard.pid")].find((Y)=>v(Y))??"";if(G&&v(G)){let Y=b$(G);if(Y!==null&&C$(Y)){let O=D(G,".."),M=(u,w)=>{let E=D(O,u);try{return v(E)?U$(E,"utf-8").trim()||w:w}catch{return w}},R=M("scheme","http"),N=M("host","127.0.0.1"),g=M("port",process.env.LOKI_DASHBOARD_PORT||"57374");if(N==="0.0.0.0")N="127.0.0.1";process.stdout.write(`${I}Dashboard:${J} ${R}://${N}:${g}/
|
|
45
|
+
`)}}return await J3($),process.stdout.write(`
|
|
46
46
|
`),process.stdout.write(`${y} Tip: loki analyze context show - detailed token breakdown${J}
|
|
47
47
|
`),process.stdout.write(`${y} Tip: loki analyze code overview - codebase intelligence${J}
|
|
48
|
-
`),0}async function
|
|
48
|
+
`),0}async function J3($){let Q=D($,"state"),Z=V3(Q),z=D(Q,"relevant-learnings.json"),X=D($,"escalations"),q=Z.length>0,K=v(z),W=v(X);if(!q&&!K&&!W)return;if(process.stdout.write(`
|
|
49
49
|
${I}Phase 1 artifacts:${J}
|
|
50
50
|
`),q){let V=Z[Z.length-1],U=q0(V);if(U&&Array.isArray(U.findings)){let H={Critical:0,High:0,Medium:0,Low:0};for(let G of U.findings){let Y=String(G.severity??"");if(Y in H)H[Y]=(H[Y]??0)+1}let B=Object.entries(H).filter(([,G])=>G>0).map(([G,Y])=>`${Y} ${G.toLowerCase()}`).join(", ");process.stdout.write(` Findings (iter ${U.iteration??"?"}): ${B||"none"} -- ${U.findings.length} total
|
|
51
51
|
`)}}if(K){let V=q0(z);if(V&&Array.isArray(V.learnings)&&V.learnings.length>0){let U=new Map;for(let B of V.learnings){let G=String(B.trigger??"unknown");U.set(G,(U.get(G)??0)+1)}let H=[...U.entries()].sort((B,G)=>G[1]-B[1]).slice(0,3).map(([B,G])=>`${G} ${B}`).join(", ");process.stdout.write(` Learnings: ${V.learnings.length} total (${H})
|
|
52
52
|
`)}}if(W){let V=0,U="";try{let B=(await import("fs")).readdirSync(X).filter((G)=>G.endsWith(".md"));if(V=B.length,B.length>0)B.sort(),U=B[B.length-1]??""}catch{}if(V>0)process.stdout.write(` Escalations: ${V} handoff doc${V===1?"":"s"} (latest: ${U})
|
|
53
|
-
`)}}function
|
|
54
|
-
`),1;let Q=h,Z=P(),z=process.env.LOKI_DASHBOARD_PORT||"57374",X=process.env.LOKI_PROVIDER||"claude",q=await F([$,"-c",
|
|
55
|
-
`),1;return process.stdout.write(q.stdout),0}async function
|
|
53
|
+
`)}}function V3($){if(!v($))return[];try{return J$("fs").readdirSync($).filter((z)=>/^findings-\d+\.json$/.test(z)).sort((z,X)=>{let q=Number.parseInt(z.replace(/[^0-9]/g,""),10)||0,K=Number.parseInt(X.replace(/[^0-9]/g,""),10)||0;return q-K}).map((z)=>D($,z))}catch{return[]}}function q0($){try{let Q=J$("fs");return JSON.parse(Q.readFileSync($,"utf-8"))}catch{return null}}async function W3(){let $=await Z$();if(!$)return process.stderr.write(`{"error": "Failed to generate JSON status. Ensure python3 is available."}
|
|
54
|
+
`),1;let Q=h,Z=P(),z=process.env.LOKI_DASHBOARD_PORT||"57374",X=process.env.LOKI_PROVIDER||"claude",q=await F([$,"-c",z3,Q,Z,z,X],{timeoutMs:30000});if(q.exitCode!==0)return process.stderr.write(`{"error": "Failed to generate JSON status. Ensure python3 is available."}
|
|
55
|
+
`),1;return process.stdout.write(q.stdout),0}async function U3($){let Q=[...$];while(Q.length>0){let Z=Q[0];if(Z==="--json")return W3();if(Z==="--help"||Z==="-h")return process.stdout.write(`Usage: loki status [--json]
|
|
56
56
|
`),0;return process.stdout.write(`${T}Unknown flag: ${Z}${J}
|
|
57
57
|
`),process.stdout.write(`Usage: loki status [--json]
|
|
58
|
-
`),1}return
|
|
58
|
+
`),1}return q3()}var D$=30,z3=`
|
|
59
59
|
import json, os, sys, time
|
|
60
60
|
|
|
61
61
|
skill_dir = sys.argv[1]
|
|
@@ -329,11 +329,11 @@ if os.path.isfile(gate_count_file):
|
|
|
329
329
|
result['phase1'] = phase1
|
|
330
330
|
|
|
331
331
|
print(json.dumps(result, indent=2))
|
|
332
|
-
`;var V0=L(()=>{d();V$();c();C()});var U0={};b(U0,{emitDeprecatedAlias:()=>X1,deprecatedAliasShouldSuppress:()=>W0});function W0($){let Q=$[0];if(Q!==void 0&&
|
|
333
|
-
`)}var
|
|
332
|
+
`;var V0=L(()=>{d();V$();c();C()});var U0={};b(U0,{emitDeprecatedAlias:()=>X1,deprecatedAliasShouldSuppress:()=>W0});function W0($){let Q=$[0];if(Q!==void 0&&G3.has(Q))return!0;for(let Z of $)if(H3.has(Z))return!0;return!1}function X1($,Q,Z){if(W0(Z))return;process.stderr.write(`note: 'loki ${$}' is now 'loki ${Q}'. The old form still works.
|
|
333
|
+
`)}var H3,G3;var K1=L(()=>{H3=new Set(["--json","-q","--quiet"]),G3=new Set(["json","csv","timeline"])});var Y0={};b(Y0,{runStats:()=>A3,computeStats:()=>B0});import{readdirSync as H0,readFileSync as B3,statSync as G0}from"fs";import{join as i}from"path";function H$($){try{if(!G0($).isFile())return null;return JSON.parse(B3($,"utf-8"))}catch{return null}}function V1($){try{return G0($).isDirectory()}catch{return!1}}function Y3($){if(!V1($))return[];try{let Q=H0($).filter((Z)=>Z.startsWith("iteration-")&&Z.endsWith(".json"));return Q.sort(),Q.map((Z)=>i($,Z))}catch{return[]}}function G$($){return Math.trunc($).toLocaleString("en-US")}function q1($){let Q=Math.trunc($);if(Q<60)return`${Q}s`;let Z=Math.trunc(Q/3600),z=Math.trunc(Q%3600/60),X=Q%60;if(Z>0)return`${Z}h ${String(z).padStart(2,"0")}m`;return`${z}m ${String(X).padStart(2,"0")}s`}function e($,Q=0){let Z=Math.pow(10,Q);return Math.round($*Z)/Z}function B$($,Q){return $.toFixed(Q)}function J1($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function M3($){let Q="N/A",Z=0,z=H$(i($,"state","orchestrator.json"));if(z&&typeof z==="object"){if(typeof z.currentPhase==="string")Q=z.currentPhase;if(typeof z.currentIteration==="number")Z=z.currentIteration}let X=i($,"metrics","efficiency"),q=Y3(X),K=[];for(let j of q){let x=H$(j);if(x&&typeof x==="object")K.push(x)}if(K.length>0)Z=Math.max(Z,K.length);let W=K.reduce((j,x)=>j+(x.input_tokens??0),0),V=K.reduce((j,x)=>j+(x.output_tokens??0),0),U=W+V,H=K.reduce((j,x)=>j+(x.cost_usd??0),0),B=K.reduce((j,x)=>j+(x.duration_seconds??0),0),G=0,Y=0,O=H$(i($,"metrics","budget.json"));if(O&&typeof O==="object"){if(typeof O.budget_limit==="number")G=O.budget_limit;if(typeof O.budget_used==="number")Y=O.budget_used}let M=0,R=0,N=H$(i($,"state","quality-gates.json"));if(N&&typeof N==="object"){if(Array.isArray(N)){for(let j of N)if(R+=1,j===!0)M+=1;else if(j&&typeof j==="object"){let x=j;if(x.passed===!0||x.status==="passed")M+=1}}else for(let j of Object.values(N))if(typeof j==="boolean"){if(R+=1,j)M+=1}else if(j&&typeof j==="object"){R+=1;let x=j;if(x.passed===!0||x.status==="passed")M+=1}}let g={},u=H$(i($,"quality","gate-failure-count.json"));if(u&&typeof u==="object"&&!Array.isArray(u)){let j={};for(let[x,l]of Object.entries(u))if(typeof l==="number")j[x]=l;g=j}let w=0,E=0,s=0,t$=i($,"quality");if(V1(t$)){let j=[];try{j=H0(t$)}catch{j=[]}for(let x of j){if(!x.endsWith(".json")||x==="gate-failure-count.json")continue;let l=H$(i(t$,x));if(!l||typeof l!=="object")continue;if(!(("verdict"in l)||("approved"in l)||("reviewers"in l)))continue;w+=1;let h1=(l.verdict??"").toString().toLowerCase();if(l.approved===!0||["approved","approve","pass"].includes(h1))E+=1;else if(["revision","revise","changes_requested","reject"].includes(h1))s+=1}}return{phase:Q,iterationCount:Z,iterations:K,totalInput:W,totalOutput:V,totalTokens:U,totalCost:H,totalDuration:B,budgetLimit:G,budgetUsed:Y,gatesPassed:M,gatesTotal:R,gateFailures:g,reviewsTotal:w,reviewsApproved:E,reviewsRevision:s}}function T3($,Q){let Z=$.iterationCount,z={session:{iterations:Z,duration_seconds:$.totalDuration,phase:$.phase},tokens:{input:$.totalInput,output:$.totalOutput,total:$.totalTokens,cost_usd:e($.totalCost,2)},quality:{gates_passed:$.gatesPassed,gates_total:$.gatesTotal,reviews_total:$.reviewsTotal,reviews_approved:$.reviewsApproved,reviews_revision:$.reviewsRevision,gate_failures:$.gateFailures},efficiency:{avg_tokens_per_iteration:Z>0?e($.totalTokens/Z,0):0,avg_cost_per_iteration:Z>0?e($.totalCost/Z,2):0,avg_duration_per_iteration:Z>0?e($.totalDuration/Z,1):0},budget:{used:e($.budgetUsed,2),limit:$.budgetLimit,percent:$.budgetLimit>0?e($.budgetUsed/$.budgetLimit*100,1):0}};if(Q)z.iterations=$.iterations.map((K,W)=>({number:W+1,input_tokens:K.input_tokens??0,output_tokens:K.output_tokens??0,cost_usd:e(K.cost_usd??0,2),duration_seconds:K.duration_seconds??0}));let X=JSON.stringify(z,null,2);function q(K,W){if(!W)return;let V=new RegExp(`("${K}": )(-?\\d+)(,?)$`,"m");X=X.replace(V,(U,H,B,G)=>`${H}${B}.0${G}`)}if(q("avg_duration_per_iteration",Z>0&&Number.isInteger(z.efficiency.avg_duration_per_iteration)),q("percent",$.budgetLimit>0&&Number.isInteger(z.budget.percent)),q("cost_usd",Z>0&&Number.isInteger(z.tokens.cost_usd)),Q)X=X.replace(/("cost_usd": )(-?\d+)(,?)$/gm,(K,W,V,U)=>`${W}${V}.0${U}`);return X}function O3($,Q){let Z=[];if(Z.push("Loki Mode Session Statistics"),Z.push("============================"),Z.push(""),Z.push("Session"),Z.push(` Iterations completed: ${$.iterationCount}`),Z.push(` Duration: ${q1($.totalDuration)}`),Z.push(` Current phase: ${$.phase}`),Z.push(""),Z.push("Token Usage"),$.iterations.length>0)Z.push(` Input tokens: ${G$($.totalInput)}`),Z.push(` Output tokens: ${G$($.totalOutput)}`),Z.push(` Total tokens: ${G$($.totalTokens)}`),Z.push(` Estimated cost: $${B$($.totalCost,2)}`);else Z.push(" N/A (no iteration metrics found)");if(Z.push(""),Z.push("Quality Gates"),$.gatesTotal>0){let z=Math.round($.gatesPassed/$.gatesTotal*100);Z.push(` Gates passed: ${$.gatesPassed}/${$.gatesTotal} (${z}%)`)}else Z.push(" Gates passed: N/A");if($.reviewsTotal>0){let z=[];if($.reviewsApproved>0)z.push(`${$.reviewsApproved} approved`);if($.reviewsRevision>0)z.push(`${$.reviewsRevision} revision requested`);let X=z.length>0?z.join(", "):"N/A";Z.push(` Code reviews: ${$.reviewsTotal} (${X})`)}if(Object.keys($.gateFailures).length>0){let z=Object.entries($.gateFailures).filter(([,X])=>X>0).map(([X,q])=>`${X} (${q})`);if(z.length>0)Z.push(` Gate failures: ${z.join(", ")}`)}if(Z.push(""),Z.push("Efficiency"),$.iterationCount>0&&$.iterations.length>0){let z=Math.round($.totalTokens/$.iterationCount),X=$.totalCost/$.iterationCount,q=$.totalDuration/$.iterationCount;Z.push(` Avg tokens/iteration: ${G$(z)}`),Z.push(` Avg cost/iteration: $${B$(X,2)}`),Z.push(` Avg duration/iteration: ${q1(q)}`)}else Z.push(" N/A (no iteration metrics found)");if(Z.push(""),Z.push("Budget"),$.budgetLimit>0){let z=e($.budgetUsed/$.budgetLimit*100,1),X=Number.isInteger(z)?`${z}.0`:`${z}`;Z.push(` Used: $${B$($.budgetUsed,2)} / $${B$($.budgetLimit,2)} (${X}%)`)}else if($.budgetUsed>0)Z.push(` Used: $${B$($.budgetUsed,2)} (no limit set)`);else Z.push(" N/A");if(Q&&$.iterations.length>0)Z.push(""),Z.push("Per-Iteration Breakdown"),$.iterations.forEach((z,X)=>{let q=X+1,K=J1(G$(z.input_tokens??0),10),W=J1(G$(z.output_tokens??0),10),V=z.cost_usd??0,U=q1(z.duration_seconds??0),H=J1(`${q}`,3);Z.push(` #${H} input: ${K} output: ${W} cost: $${B$(V,2)} time: ${U}`)});return Z.join(`
|
|
334
334
|
`)}function B0($){let Q=!1,Z=!1;for(let K of $)if(K==="--json")Q=!0;else if(K==="--efficiency")Z=!0;let z=P();if(!V1(z)){if(Q)return{exitCode:0,stdout:'{"error": "No active session"}'};return{exitCode:0,stdout:`${_}No active session found.${J}
|
|
335
|
-
Start a session with: loki start <prd>`}}let X=
|
|
336
|
-
`);if(G>0&&N.length>0)N=N.slice(1);N=N.map((g)=>g.trim()).filter((g)=>g.length>0),U=N.slice(-5)}}catch{U=[]}return{errors_log_path:H?V:null,recent_errors:U,recent_error_count:U.length,status:U.length===0?"pass":"warn"}}async function
|
|
335
|
+
Start a session with: loki start <prd>`}}let X=M3(z);return{exitCode:0,stdout:Q?T3(X,Z):O3(X,Z)}}async function A3($){let{emitDeprecatedAlias:Q}=await Promise.resolve().then(() => (K1(),U0));Q("stats","report session",$);let Z=B0($);return console.log(Z.stdout),Z.exitCode}var M0=L(()=>{C();c()});var j0={};b(j0,{runDoctor:()=>b3,pythonImportOk:()=>B1,httpReachable:()=>U1,checkTool:()=>_0,checkSkills:()=>I0,checkDisk:()=>G1,buildDoctorJson:()=>P0,_setPythonImportOkForTest:()=>F3});import{existsSync as T0,lstatSync as w3,readFileSync as _3,readlinkSync as I3,statfsSync as L3}from"fs";import{spawnSync as O0}from"child_process";import{homedir as H1}from"os";import{resolve as W1}from"path";function j3($){let Q=$.match(P3);return Q?Q[1]:null}async function A0($){try{let Q=await F([$,"--version"],{timeoutMs:5000}),Z=(Q.stdout||Q.stderr||"").trim();return j3(Z)}catch{return null}}function w0($,Q){let Z=$.split(".").map((X)=>parseInt(X,10)),z=Q.split(".").map((X)=>parseInt(X,10));while(Z.length<2)Z.push(0);while(z.length<2)z.push(0);for(let X=0;X<2;X++){let q=Z[X]??0,K=z[X]??0;if(Number.isNaN(q)||Number.isNaN(K))return 0;if(q!==K)return q-K}return 0}async function _0($,Q,Z,z=null){let X=await f(Q),q=X!==null,K=q?await A0(Q):null,W="pass";if(!q)W=Z==="required"?"fail":"warn";else if(z&&K){if(w0(K,z)<0)W=Z==="required"?"fail":"warn"}return{name:$,command:Q,found:q,version:K,required:Z,min_version:z,status:W,path:X}}function G1(){let $=null;try{let Z=L3(H1()),z=Number(Z.bavail)*Number(Z.bsize);$=Math.round(z/1073741824*10)/10}catch{$=null}let Q="pass";if($!==null){if($<1)Q="fail";else if($<5)Q="warn"}return{available_gb:$,status:Q}}async function U1($,Q=2000){try{return(await fetch($,{signal:AbortSignal.timeout(Q)})).ok}catch{return!1}}async function B1($,Q=!1){let Z=`import ${$}`,z=Q?30000:5000;if(!Q)return(await z$(Z,{timeoutMs:z})).exitCode===0;let X=await Z$();if(!X)return!1;return(await F([X,"-c",Z],{timeoutMs:z})).exitCode===0}function F3($){v$.fn=$??B1}function I0(){let $=H1();return k3.map(({name:Q,dir:Z})=>{let z=W1($,Z),X=z,q=W1(z,"SKILL.md");if(T0(q))return{name:Q,path:X,status:"pass",detail:""};try{if(w3(z).isSymbolicLink()){let W="unknown";try{W=I3(z)}catch{}return{name:Q,path:X,status:"fail",detail:`(broken symlink -> ${W})`}}}catch{}return{name:Q,path:X,status:"warn",detail:"(not found - run 'loki setup-skill')"}})}async function L0(){return Promise.all(R3.map(async($)=>{return{...await _0($.jsonName,$.cmd,$.required,$.min??null),displayName:$.displayName}}))}async function E3(){let Q=await f("sentrux")!==null,Z=Q?await A0("sentrux"):null;return{found:Q,version:Z,status:Q?"pass":"warn",required:"optional"}}async function x3(){let{openSync:$,statSync:Q,readSync:Z,closeSync:z,existsSync:X}=await import("fs"),{join:q}=await import("path"),K=65536,W=process.env.LOKI_DIR??".loki",V=q(W,"memory",".errors.log"),U=[],H=!1;try{if(X(V)){H=!0;let B=Q(V).size,G=Math.max(0,B-65536),Y=B-G,O=Buffer.alloc(Y),M=$(V,"r");try{Z(M,O,0,Y,G)}finally{z(M)}let N=O.toString("utf-8").split(`
|
|
336
|
+
`);if(G>0&&N.length>0)N=N.slice(1);N=N.map((g)=>g.trim()).filter((g)=>g.length>0),U=N.slice(-5)}}catch{U=[]}return{errors_log_path:H?V:null,recent_errors:U,recent_error_count:U.length,status:U.length===0?"pass":"warn"}}async function P0(){let Q=(await L0()).map(({displayName:V,...U})=>U),Z=G1(),z=await E3(),X=await x3(),q=0,K=0,W=0;for(let V of Q)if(V.status==="pass")q++;else if(V.status==="fail")K++;else W++;if(Z.status==="pass")q++;else if(Z.status==="fail")K++;else W++;return{loki_mode_version:N$(),checks:Q,disk:Z,sentrux:z,memory:X,summary:{passed:q,failed:K,warnings:W,ok:K===0}}}function N3(){try{let $=process.env.CLAUDE_CONFIG_DIR||`${H1()}/.claude`,Q=_3(`${$}/.credentials.json`,"utf8");if(!Q)return!1;let Z=JSON.parse(Q)?.claudeAiOauth?.expiresAt;return typeof Z==="number"&&Z>0&&Z/1000<=Date.now()/1000+60}catch{return!1}}function S3(){try{let Q=(O0("claude",["auth","status"],{encoding:"utf8",timeout:5000}).stdout||"").trim();if(!Q)return"";let Z=JSON.parse(Q);if(Z?.loggedIn===!0)return"yes";if(Z?.loggedIn===!1)return"no";return""}catch{return""}}function A($){switch($){case"pass":return`${S}PASS${J}`;case"fail":return`${T}FAIL${J}`;case"warn":return`${_}WARN${J}`}}function h$($){let Q=$.version?` (v${$.version})`:"",Z=$.displayName;if(!$.found){let z=$.required==="required"?"not found":$.required==="recommended"?"not found (recommended)":"not found (optional)";return` ${A($.status)} ${Z} - ${z}`}if($.min_version&&$.version&&w0($.version,$.min_version)<0){let z=$.required==="required"?"requires":"recommended";return` ${A($.status)} ${Z}${Q} - ${z} >= ${$.min_version}`}return` ${A($.status)} ${Z}${Q}`}function y$($,Q){if(Q==="pass")$.pass++;else if(Q==="fail")$.fail++;else $.warn++}function D3(){process.stdout.write(`${k}loki doctor${J} - Check system prerequisites
|
|
337
337
|
|
|
338
338
|
`),process.stdout.write(`Usage: loki doctor [--json]
|
|
339
339
|
|
|
@@ -342,11 +342,11 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
342
342
|
|
|
343
343
|
`),process.stdout.write(`Checks: node, python3, jq, git, curl, bash version,
|
|
344
344
|
`),process.stdout.write(` claude/codex CLIs, and disk space.
|
|
345
|
-
`)}async function
|
|
345
|
+
`)}async function C3(){process.stdout.write(`${k}Loki Mode Doctor${J}
|
|
346
346
|
|
|
347
347
|
`),process.stdout.write(`Checking system prerequisites...
|
|
348
348
|
|
|
349
|
-
`);let $={pass:0,fail:0,warn:0},Q=await
|
|
349
|
+
`);let $={pass:0,fail:0,warn:0},Q=await L0(),Z=new Map(Q.map((w)=>[w.command,w]));process.stdout.write(`${I}Required:${J}
|
|
350
350
|
`);for(let w of["node","python3","jq","git","curl"]){let E=Z.get(w);process.stdout.write(h$(E)+`
|
|
351
351
|
`),y$($,E.status)}process.stdout.write(`
|
|
352
352
|
`),process.stdout.write(`${I}AI Providers:${J}
|
|
@@ -354,19 +354,21 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
354
354
|
`),!E.found&&X[w])process.stderr.write(` ${_}Install: ${X[w]}${J}
|
|
355
355
|
`);if(y$($,E.status),E.found)q=!0}if(!q){if(process.stdout.write(` ${A("fail")} No AI provider CLI installed -- at least one is required
|
|
356
356
|
`),process.stdout.write(` ${_}Install: npm install -g @anthropic-ai/claude-code${J}
|
|
357
|
-
`),$.fail++,process.stdout.isTTY){let w=W1(h,"autonomy/provider-offer.sh");if(T0(w))
|
|
357
|
+
`),$.fail++,process.stdout.isTTY){let w=W1(h,"autonomy/provider-offer.sh");if(T0(w))O0("bash",[w,"report"],{stdio:"inherit"})}}process.stdout.write(`
|
|
358
358
|
`),process.stdout.write(`${I}API Keys:${J}
|
|
359
359
|
`);let K=Z.get("claude")?.found??!1,W=Z.get("codex")?.found??!1,V=process.env;if(V.ANTHROPIC_API_KEY)process.stdout.write(` ${A("pass")} ANTHROPIC_API_KEY is set
|
|
360
|
-
`),$.pass++;else if(K)if(
|
|
360
|
+
`),$.pass++;else if(K){let w=S3();if(w==="yes")process.stdout.write(` ${A("pass")} Claude CLI is logged in (subscription/OAuth login)
|
|
361
|
+
`),$.pass++;else if(w==="no")process.stdout.write(` ${A("warn")} Claude CLI is NOT logged in -- run 'claude login' before a build (it would otherwise stall)
|
|
362
|
+
`),$.warn++;else if(N3())process.stdout.write(` ${A("warn")} Claude login has EXPIRED -- run 'claude login' before a build (it would otherwise stall)
|
|
361
363
|
`),$.warn++;else process.stdout.write(` ${y} -- ${J} ANTHROPIC_API_KEY not set (Claude CLI uses its own login)
|
|
362
|
-
`)
|
|
364
|
+
`)}if(V.OPENAI_API_KEY)process.stdout.write(` ${A("pass")} OPENAI_API_KEY is set
|
|
363
365
|
`),$.pass++;else if(W)process.stdout.write(` ${y} -- ${J} OPENAI_API_KEY not set (Codex CLI uses its own login)
|
|
364
366
|
`);if(V.ANTHROPIC_BASE_URL){let w=V.ANTHROPIC_BASE_URL;if(process.stdout.write(` ${A("pass")} ANTHROPIC_BASE_URL: ${w}
|
|
365
367
|
`),$.pass++,!V.LOKI_MODEL_OVERRIDE)process.stdout.write(` ${A("warn")} LOKI_MODEL_OVERRIDE not set -- opus/sonnet/haiku aliases may not resolve on alt-provider
|
|
366
368
|
`),$.warn++;else process.stdout.write(` ${A("pass")} LOKI_MODEL_OVERRIDE: ${V.LOKI_MODEL_OVERRIDE}
|
|
367
369
|
`),$.pass++}process.stdout.write(`
|
|
368
370
|
`),process.stdout.write(`${I}Skills:${J}
|
|
369
|
-
`);for(let w of
|
|
371
|
+
`);for(let w of I0())if(w.status==="pass")process.stdout.write(` ${A("pass")} ${w.name} ${y}${w.path}${J}
|
|
370
372
|
`),$.pass++;else if(w.status==="fail")process.stdout.write(` ${A("fail")} ${w.name} ${y}${w.detail}${J}
|
|
371
373
|
`),process.stdout.write(` ${_}Fix: loki setup-skill${J}
|
|
372
374
|
`),$.fail++;else process.stdout.write(` ${A("warn")} ${w.name} ${y}${w.detail}${J}
|
|
@@ -416,14 +418,14 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
416
418
|
`);return process.stdout.write(`
|
|
417
419
|
`),process.stdout.write(`Next: loki quickstart (guided first build from your idea, no PRD needed)
|
|
418
420
|
`),process.stdout.write(` or loki demo (builds a sample todo app end to end) or loki start ./prd.md
|
|
419
|
-
`),0}async function
|
|
421
|
+
`),0}async function b3($){let Q=!1;for(let Z of $)if(Z==="--json")Q=!0;else if(Z==="--help"||Z==="-h")return D3(),0;else return process.stderr.write(`${T}Unknown option: ${Z}${J}
|
|
420
422
|
`),process.stderr.write(`Usage: loki doctor [--json]
|
|
421
|
-
`),1;if(Q){let Z=await
|
|
422
|
-
`),0}return
|
|
423
|
-
`)}var
|
|
423
|
+
`),1;if(Q){let Z=await P0();return process.stdout.write(JSON.stringify(Z,null,2)+`
|
|
424
|
+
`),0}return C3()}var P3,v$,k3,R3;var F0=L(()=>{C();d();V$();c();$1();P3=/(\d+\.\d+(?:\.\d+)*)/;v$={fn:B1};k3=[{name:"Claude Code",dir:".claude/skills/loki-mode"},{name:"Codex CLI",dir:".codex/skills/loki-mode"},{name:"Cline CLI",dir:".cline/skills/loki-mode"},{name:"Aider CLI",dir:".aider/skills/loki-mode"}];R3=[{displayName:"Node.js (>= 18)",jsonName:"Node.js",cmd:"node",required:"required",min:"18.0"},{displayName:"Python 3 (>= 3.8)",jsonName:"Python 3",cmd:"python3",required:"required",min:"3.8"},{displayName:"jq",jsonName:"jq",cmd:"jq",required:"required"},{displayName:"git",jsonName:"git",cmd:"git",required:"required"},{displayName:"curl",jsonName:"curl",cmd:"curl",required:"required"},{displayName:"bash (>= 4.0)",jsonName:"bash",cmd:"bash",required:"recommended",min:"4.0"},{displayName:"Bun (>= 1.3)",jsonName:"Bun",cmd:"bun",required:"recommended",min:"1.3"},{displayName:"Claude CLI",jsonName:"Claude CLI",cmd:"claude",required:"optional"},{displayName:"Codex CLI",jsonName:"Codex CLI",cmd:"codex",required:"optional"},{displayName:"Cline CLI",jsonName:"Cline CLI",cmd:"cline",required:"optional"},{displayName:"Aider CLI",jsonName:"Aider CLI",cmd:"aider",required:"optional"}]});import{existsSync as E0,mkdirSync as f9,readdirSync as h3,readFileSync as x0,renameSync as u9,writeFileSync as c9}from"fs";import{dirname as y3,join as v3,resolve as g3}from"path";import{fileURLToPath as m3}from"url";function f3(){try{let $=y3(m3(import.meta.url)),Q=g3($,"..","..","data","model-pricing.json");if(!E0(Q))return _$;let z=JSON.parse(x0(Q,"utf8")).pricing;if(!z||typeof z!=="object")return _$;let X={};for(let[q,K]of Object.entries(z))if(K!==null&&typeof K==="object"&&typeof K.input==="number"&&typeof K.output==="number")X[q]={input:K.input,output:K.output};for(let q of Object.keys(_$))if(!(q in X))return _$;return X}catch{return _$}}function u3($){return Math.round(($+Number.EPSILON)*1e4)/1e4}function c3($){let Q=($??R0).toLowerCase();return k0[Q]??k0[R0]}function N0($){let Q=0;for(let Z of $){if(typeof Z.cost_usd==="number"&&Number.isFinite(Z.cost_usd)){Q+=Z.cost_usd;continue}let z=c3(Z.model),X=typeof Z.input_tokens==="number"?Z.input_tokens:0,q=typeof Z.output_tokens==="number"?Z.output_tokens:0;Q+=X/1e6*z.input+q/1e6*z.output}return u3(Q)}function S0($){if(!E0($))return[];let Q=[],Z;try{Z=h3($)}catch{return[]}for(let z of Z){if(!z.endsWith(".json"))continue;let X=v3($,z);try{let q=x0(X,"utf8"),K=JSON.parse(q);if(K&&typeof K==="object")Q.push(K)}catch{}}return Q}var _$,k0,R0="sonnet";var D0=L(()=>{C();_$={fable:{input:10,output:50},opus:{input:5,output:25},sonnet:{input:3,output:15},haiku:{input:1,output:5},"gpt-5.3-codex":{input:1.5,output:12}};k0=Object.freeze(f3())});import{existsSync as g$,readdirSync as p3,readFileSync as l3,statSync as d3}from"fs";import{join as m$}from"path";function o3($){let Q=[],Z=m$($,"votes");if(!g$(Z))return Q;let z;try{z=p3(Z)}catch{return Q}for(let X of z){if(!X.startsWith("round-")||!X.endsWith(".json"))continue;try{let q=m$(Z,X);if(!d3(q).isFile())continue;let K=JSON.parse(l3(q,"utf8"));Q.push({iteration:typeof K.iteration==="number"?K.iteration:void 0,verdict:typeof K.verdict==="string"?K.verdict:void 0,complete_votes:typeof K.complete_votes==="number"?K.complete_votes:void 0,total_members:typeof K.total_members==="number"?K.total_members:void 0,threshold:typeof K.threshold==="number"?K.threshold:void 0})}catch{}}return Q}function n3(){return{iteration_count:0,total_cost_usd:0,avg_cost_per_iteration:null,total_input_tokens:0,total_output_tokens:0,total_duration_ms:0,avg_duration_ms_per_iteration:null,model_breakdown:{},phase_breakdown:{},status_breakdown:{}}}function a3(){return{council_rounds:0,unanimous_rate:null,approval_rate:null,iteration_success_rate:null}}function s3($){let Q=n3();if($.length===0)return Q;Q.iteration_count=$.length,Q.total_cost_usd=Math.round(N0($)*1e4)/1e4;for(let Z of $){if(typeof Z.input_tokens==="number")Q.total_input_tokens+=Z.input_tokens;if(typeof Z.output_tokens==="number")Q.total_output_tokens+=Z.output_tokens;let z=Z;if(typeof z.duration_ms==="number")Q.total_duration_ms+=z.duration_ms;if(typeof Z.model==="string")Q.model_breakdown[Z.model]=(Q.model_breakdown[Z.model]??0)+1;if(typeof z.phase==="string")Q.phase_breakdown[z.phase]=(Q.phase_breakdown[z.phase]??0)+1;if(typeof z.status==="string")Q.status_breakdown[z.status]=(Q.status_breakdown[z.status]??0)+1}return Q.avg_cost_per_iteration=Math.round(Q.total_cost_usd/Q.iteration_count*1e4)/1e4,Q.avg_duration_ms_per_iteration=Math.round(Q.total_duration_ms/Q.iteration_count),Q}function r3($,Q,Z){let z=a3();if(z.council_rounds=$.length,$.length>0){let X=0,q=0;for(let K of $){if(typeof K.complete_votes==="number"&&typeof K.total_members==="number"&&K.total_members>0&&K.complete_votes===K.total_members)X+=1;if(K.verdict==="COMPLETE")q+=1}z.unanimous_rate=Math.round(X/$.length*1e4)/1e4,z.approval_rate=Math.round(q/$.length*1e4)/1e4}if(Z>0)z.iteration_success_rate=Math.round(Q/Z*1e4)/1e4;return z}function C0($){let Q=[],Z=m$($,"metrics","efficiency"),z=m$($,"council"),X=g$(Z)?S0(Z):[];if(!g$(Z))Q.push("no .loki/metrics/efficiency/ dir (efficiency KPIs zeroed)");else if(X.length===0)Q.push(".loki/metrics/efficiency/ exists but no iteration files found");let q=o3(z);if(!g$(z))Q.push("no .loki/council/ dir (accuracy KPIs zeroed)");else if(q.length===0)Q.push(".loki/council/ exists but no round-N.json files found");let K=s3(X),W=K.status_breakdown.success??0,V=r3(q,W,K.iteration_count);return{schema_version:1,generated_at:new Date().toISOString(),loki_dir:$,efficiency:K,accuracy:V,notes:Q}}function b0($){return JSON.stringify($,null,2)}function h0($){let Q=[];Q.push(`Loki Mode KPIs (snapshot at ${$.generated_at})`),Q.push(`Source: ${$.loki_dir}`),Q.push(""),Q.push("Efficiency"),Q.push(` Iterations: ${$.efficiency.iteration_count}`),Q.push(` Total cost USD: ${$.efficiency.total_cost_usd}`),Q.push(` Avg cost per iter: ${$.efficiency.avg_cost_per_iteration??"n/a"}`),Q.push(` Total input tokens: ${$.efficiency.total_input_tokens}`),Q.push(` Total output tokens: ${$.efficiency.total_output_tokens}`),Q.push(` Total duration (ms): ${$.efficiency.total_duration_ms}`),Q.push(` Avg duration / iter: ${$.efficiency.avg_duration_ms_per_iteration??"n/a"}`);let Z=Object.entries($.efficiency.model_breakdown).sort((q,K)=>q[0].localeCompare(K[0]));if(Z.length>0)Q.push(` Model breakdown: ${Z.map(([q,K])=>`${q}=${K}`).join(", ")}`);let z=Object.entries($.efficiency.phase_breakdown).sort((q,K)=>q[0].localeCompare(K[0]));if(z.length>0)Q.push(` Phase breakdown: ${z.map(([q,K])=>`${q}=${K}`).join(", ")}`);let X=Object.entries($.efficiency.status_breakdown).sort((q,K)=>q[0].localeCompare(K[0]));if(X.length>0)Q.push(` Status breakdown: ${X.map(([q,K])=>`${q}=${K}`).join(", ")}`);if(Q.push(""),Q.push("Accuracy"),Q.push(` Council rounds: ${$.accuracy.council_rounds}`),Q.push(` Unanimous rate: ${$.accuracy.unanimous_rate??"n/a"}`),Q.push(` Approval rate: ${$.accuracy.approval_rate??"n/a"}`),Q.push(` Iter success rate: ${$.accuracy.iteration_success_rate??"n/a"}`),$.notes.length>0){Q.push(""),Q.push("Notes");for(let q of $.notes)Q.push(` - ${q}`)}return Q.push(""),Q.push("See also: loki trust (trust trajectory across runs)"),Q.join(`
|
|
425
|
+
`)}var y0=L(()=>{D0()});var Y1={};b(Y1,{runKpis:()=>i3});function i3($,Q={}){if(Q.aliasOf)X1(Q.aliasOf,"report kpis",$);let Z=!1;for(let X of $){if(X==="--help"||X==="-h"||X==="help")return process.stdout.write(t3),0;if(X==="--json"){Z=!0;continue}if(X==="-q"||X==="--quiet")continue;return process.stderr.write(`loki kpis: unknown arg: ${X}
|
|
424
426
|
Run 'loki kpis --help' for usage.
|
|
425
|
-
`),1}let z=
|
|
426
|
-
`:
|
|
427
|
+
`),1}let z=C0(P());return process.stdout.write(Z?b0(z)+`
|
|
428
|
+
`:h0(z)+`
|
|
427
429
|
`),0}var t3=`loki report kpis -- accuracy + efficiency KPI snapshot (v7.5.28 MVP)
|
|
428
430
|
|
|
429
431
|
Usage:
|
|
@@ -445,13 +447,13 @@ iteration success rate.
|
|
|
445
447
|
This is the Phase K MVP -- read-only derivation. Per-iteration
|
|
446
448
|
emission, dashboard panel, and the loki-bench harness are deferred
|
|
447
449
|
follow-ups (see project_v7_5_18_arc_status.md).
|
|
448
|
-
`;var M1=L(()=>{
|
|
449
|
-
`)}Q.push("Is the agent earning autonomy on this repo?");for(let X of f$)if($.axes[X])Q.push(
|
|
450
|
-
`)}var
|
|
450
|
+
`;var M1=L(()=>{y0();C();K1()});var v0={};b(v0,{delegateToBash:()=>Q6});import{resolve as e3}from"path";async function Q6($){let Q=e3(h,"autonomy","loki"),Z=Bun.spawn({cmd:[Q,...$],stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,LOKI_LEGACY_BASH:"1"}}),z=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},$6);try{return await Z.exited}finally{clearTimeout(z)}}var $6=3600000;var g0=L(()=>{C()});import{existsSync as Z6,mkdirSync as z6,readdirSync as X6,readFileSync as K6,statSync as q6,writeFileSync as J6}from"fs";import{join as I$}from"path";function T1($){return $&&typeof $==="object"?$:{}}function X$($){return Math.round($*1e4)/1e4}function G6($){let Q=String($??"").trim().toUpperCase();if(!Q)return null;for(let Z of f0)if(Q.startsWith(Z))return!0;return!1}function B6($){let Q=G6($.final_verdict);if(Q!==null)return Q?1:0;let Z=$.reviewers;if(Array.isArray(Z)&&Z.length>0){let z=0,X=0;for(let q of Z){if(!q||typeof q!=="object")continue;X+=1;let K=String(q.vote??"").trim().toUpperCase();if(f0.some((W)=>K.startsWith(W)))z+=1}if(X>0)return z===X?1:0}return null}function Y6($){let Q=Number($.total),Z=Number($.passed);if(!Number.isFinite(Q)||!Number.isFinite(Z))return null;if(Q<=0)return null;return Math.max(0,Math.min(1,Z/Q))}function M6($){let Q;if($&&typeof $==="object")Q=$.count;else Q=$;let Z=Number(Q);if(!Number.isFinite(Z)||Z<0)return null;return Z}function T6($){let Q=T1($.council);for(let Z of[Q.interventions,$.interventions]){let z=Number(Z);if(Number.isFinite(z)&&z>=0)return z}return null}function O6($){let Q=I$($,"proofs"),Z=[];if(!Z6(Q))return Z;let z;try{z=X6(Q).sort()}catch{return Z}for(let X of z){let q=I$(Q,X);try{if(!q6(q).isDirectory())continue}catch{continue}let K=null;try{K=JSON.parse(K6(I$(q,"proof.json"),"utf8"))}catch{continue}if(!K||typeof K!=="object")continue;Z.push({run_id:String(K.run_id??X),generated_at:typeof K.generated_at==="string"?K.generated_at:null,council_pass_rate:B6(T1(K.council)),gate_pass_rate:Y6(T1(K.quality_gates)),iterations:M6(K.iterations),interventions:T6(K)})}return Z.sort((X,q)=>{let K=X.generated_at===null?1:0,W=q.generated_at===null?1:0;if(K!==W)return K-W;return(X.generated_at??"").localeCompare(q.generated_at??"")}),Z}function m0($){return $.reduce((Q,Z)=>Q+Z,0)/$.length}function A6($,Q){let Z=W6[$],z=U6[$],X=H6[$],q=Q.filter((M)=>M!==null),K=q.length;if(K===0)return{axis:$,label:X,available:!1,higher_is_better:Z,note:"no runs recorded this metric"};if(K<2)return{axis:$,label:X,available:!0,higher_is_better:Z,data_points:K,latest:X$(q[K-1]),direction:"flat",improving:null,delta:0,earlier_mean:X$(q[0]),later_mean:X$(q[K-1]),insufficient:!0,note:"not enough history yet (need 2+ runs with this metric)"};let W=Math.floor(K/2),V=q.slice(0,W),U=q.slice(K-W),H=m0(V),B=m0(U),G=B-H,Y;if(Math.abs(G)<=z)Y="flat";else if(G>0)Y="up";else Y="down";let O;if(Y==="flat")O=null;else O=Y==="up"===Z;return{axis:$,label:X,available:!0,higher_is_better:Z,data_points:K,latest:X$(q[K-1]),direction:Y,improving:O,delta:X$(G),earlier_mean:X$(H),later_mean:X$(B),insufficient:!1}}function u0($){let Q=O6($),Z=Q.map((V)=>({run_id:V.run_id,generated_at:V.generated_at,council_pass_rate:V.council_pass_rate,gate_pass_rate:V.gate_pass_rate,iterations:V.iterations,interventions:V.interventions})),z={};for(let V of f$)z[V]=A6(V,Q.map((U)=>U[V]));let X=Q.length<2,q=f$.filter((V)=>z[V].available&&z[V].improving===!0),K=f$.filter((V)=>z[V].available&&z[V].improving===!1),W=[];if(X)W.push(`not enough history yet: ${Q.length} run(s) recorded, need 2+ to show a trend`);if(!z.interventions.available)W.push("intervention trend unavailable: no per-run intervention count in proof.json yet (axis lights up automatically once recorded)");return{schema_version:V6,generated_at:new Date().toISOString(),loki_dir:$,runs_count:Q.length,insufficient:X,axes:z,improving_count:q.length,regressing_count:K.length,improving_axes:q,regressing_axes:K,series:Z,notes:W}}function c0($){return JSON.stringify($,null,2)}function p0($,Q){let Z=I$($,"metrics"),z=I$(Z,"trust-trajectory.json");try{return z6(Z,{recursive:!0}),J6(z,JSON.stringify(Q,null,2)),z}catch{return null}}function w6($){if($==="up")return"up";if($==="down")return"down";return"flat"}function _6($){let Q=$.label??$.axis;if(!$.available)return` ${(Q+":").padEnd(26)} no data`;let Z;if($.insufficient)Z="(need 2+ runs)";else if($.improving===!0)Z="improving";else if($.improving===!1)Z="regressing";else Z="stable";let z=$.higher_is_better?"higher better":"lower better",X=$.latest??"n/a";return` ${(Q+":").padEnd(26)} ${w6($.direction).padEnd(5)} latest=${String(X).padEnd(7)} ${Z.padEnd(11)} [${z}]`}function l0($){let Q=[];if(Q.push(`Loki Mode Trust Trajectory (snapshot at ${$.generated_at})`),Q.push(`Source: ${$.loki_dir}`),Q.push(`Runs analyzed: ${$.runs_count}`),Q.push(""),$.insufficient){if(Q.push("Not enough history yet."),Q.push("Trust trajectory needs 2+ recorded runs to show a direction."),Q.push("Each `loki start` run writes a proof-of-run; come back after the next run."),$.notes.length>0){Q.push(""),Q.push("Notes");for(let X of $.notes)Q.push(` - ${X}`)}return Q.join(`
|
|
451
|
+
`)}Q.push("Is the agent earning autonomy on this repo?");for(let X of f$)if($.axes[X])Q.push(_6($.axes[X]));Q.push("");let{improving_count:Z,regressing_count:z}=$;if(Z&&!z)Q.push(`Overall: trending more trustworthy (${Z} axis improving).`);else if(z&&!Z)Q.push(`Overall: trust regressing (${z} axis regressing). Review recent runs.`);else if(Z||z)Q.push(`Overall: mixed (${Z} improving / ${z} regressing).`);else Q.push("Overall: stable.");if($.notes.length>0){Q.push(""),Q.push("Notes");for(let X of $.notes)Q.push(` - ${X}`)}return Q.join(`
|
|
452
|
+
`)}var V6=1,f$,W6,U6,H6,f0;var d0=L(()=>{f$=["council_pass_rate","gate_pass_rate","iterations","interventions"],W6={council_pass_rate:!0,gate_pass_rate:!0,iterations:!1,interventions:!1},U6={council_pass_rate:0.01,gate_pass_rate:0.01,iterations:0.25,interventions:0.25},H6={council_pass_rate:"Council pass rate",gate_pass_rate:"Gate pass rate",iterations:"Iterations to completion",interventions:"Human interventions"},f0=["APPROVE","APPROVED","COMPLETE","PASS","PASSED"]});var o0={};b(o0,{runTrust:()=>L6});function L6($){let Q=!1;for(let X of $){if(X==="--help"||X==="-h"||X==="help")return process.stdout.write(I6),0;if(X==="--json"){Q=!0;continue}return process.stderr.write(`loki trust: unknown arg: ${X}
|
|
451
453
|
Run 'loki trust --help' for usage.
|
|
452
|
-
`),1}let Z=P(),z=
|
|
453
|
-
`:
|
|
454
|
-
`),0}var
|
|
454
|
+
`),1}let Z=P(),z=u0(Z);return p0(Z,z),process.stdout.write(Q?c0(z)+`
|
|
455
|
+
`:l0(z)+`
|
|
456
|
+
`),0}var I6=`loki trust -- visible trust trajectory (R4)
|
|
455
457
|
|
|
456
458
|
Usage:
|
|
457
459
|
loki trust Pretty-print the per-project trust trajectory
|
|
@@ -467,30 +469,30 @@ Shows whether the agent is earning autonomy on THIS repo over time:
|
|
|
467
469
|
Derived read-only from proof-of-run history in .loki/proofs/. With fewer
|
|
468
470
|
than 2 recorded runs it reports "not enough history yet" rather than a
|
|
469
471
|
fabricated trend. Complements 'loki kpis' (single-run snapshot).
|
|
470
|
-
`;var
|
|
471
|
-
`)}async function
|
|
472
|
-
`),Q}catch(Z){if(Q!==null){try{L$(Q)}catch{}try{t0($)}catch{}}if(Z?.code==="EEXIST")return null;throw Z}}function
|
|
473
|
-
`)}),
|
|
472
|
+
`;var n0=L(()=>{d0();C()});import{closeSync as L$,fstatSync as P6,fsyncSync as a0,lstatSync as j6,mkdirSync as s0,openSync as c$,readSync as F6,renameSync as k6,rmSync as r0,statSync as R6,unlinkSync as t0,writeSync as i0}from"fs";import{dirname as O1}from"path";function A1($,Q){s0(O1($),{recursive:!0});let Z=`${$}.tmp.${process.pid}.${++E6}`,z=c$(Z,"w");try{i0(z,Q),a0(z)}finally{L$(z)}k6(Z,$),x6($)}function x6($){let Q=null;try{Q=c$(O1($),"r"),a0(Q)}catch{}finally{if(Q!==null)try{L$(Q)}catch{}}}function P$($,Q){A1($,`${JSON.stringify(Q,null,2)}
|
|
473
|
+
`)}async function e0($,Q){let Z=u$.get($)??Promise.resolve(),z=()=>{},X=new Promise((K)=>{z=K}),q=Z.catch(()=>{}).then(()=>X);u$.set($,q);try{return await Z.catch(()=>{}),await Q()}finally{if(z(),u$.get($)===q)u$.delete($)}}function S6($){return`${$}.lock`}function D6($){if(!Number.isFinite($)||$<=0)return!1;try{return process.kill($,0),!0}catch(Q){return Q?.code==="EPERM"}}function C6($){let Q=null;try{return s0(O1($),{recursive:!0}),Q=c$($,"wx"),i0(Q,`${process.pid}
|
|
474
|
+
`),Q}catch(Z){if(Q!==null){try{L$(Q)}catch{}try{t0($)}catch{}}if(Z?.code==="EEXIST")return null;throw Z}}function b6($,Q){let Z;try{Z=j6($)}catch{return!0}if(Z.isSymbolicLink())try{return t0($),!0}catch{return!1}let z;try{z=c$($,"r")}catch{return!0}try{let X=P6(z);if(Date.now()-X.mtimeMs<Q)return!1;let K=NaN;try{let W=Buffer.alloc(64),V=F6(z,W,0,64,0);K=Number.parseInt(W.subarray(0,V).toString("utf-8").trim(),10)}catch{}if(Number.isFinite(K)&&D6(K))return!1;try{if(R6($).mtimeMs>X.mtimeMs)return!1}catch{return!0}try{r0($,{force:!0})}catch{}return!0}finally{try{L$(z)}catch{}}}function j$($,Q,Z={}){let z=Z.timeoutMs??1e4,X=Z.pollMs??25,q=Z.staleMs??30000,K=S6($),W=Date.now()+z,V=null,U=0,H=new Int32Array(new SharedArrayBuffer(4));while(V===null){if(V=C6(K),V!==null)break;if(Date.now()>W)throw Error(`withFileLockSync: timed out after ${z}ms acquiring ${K}`);if(b6(K,q))continue;let B=Math.min(X*2**Math.min(U,4),N6);U+=1,Atomics.wait(H,0,0,B)}try{return Q()}finally{try{L$(V)}catch{}try{r0(K,{force:!0})}catch{}}}var E6=0,u$,N6=50;var F$=L(()=>{u$=new Map});import{existsSync as K$,mkdirSync as Y$,copyFileSync as zQ,readFileSync as I1,readdirSync as h6,statSync as y6,writeFileSync as v6,renameSync as XQ,appendFileSync as KQ,rmSync as g6}from"fs";import{join as m,dirname as p$}from"path";function f6($){let Q=QQ.then($,$);return QQ=Q.catch((Z)=>{console.warn("[checkpoint] serialized op rejected:",Z);return}),Q}function o($){return m($,"state","checkpoints")}function qQ($){return m(o($),"index.jsonl")}async function u6($){let Q=await F(["git","rev-parse","HEAD"],{cwd:$,timeoutMs:5000});if(Q.exitCode!==0)return"no-git";return Q.stdout.trim()||"no-git"}async function c6($){let Q=await F(["git","branch","--show-current"],{cwd:$,timeoutMs:5000});if(Q.exitCode!==0)return"unknown";return Q.stdout.trim()||"unknown"}async function p6($){let Q=await F(["git","diff","--quiet"],{cwd:$,timeoutMs:5000}),Z=await F(["git","diff","--cached","--quiet"],{cwd:$,timeoutMs:5000}),z=Q.exitCode===1,X=Z.exitCode===1;return z||X}function l6($){let Q=m($,"state","orchestrator.json");if(!K$(Q))return"unknown";try{let z=JSON.parse(I1(Q,"utf-8")).currentPhase;return typeof z==="string"&&z.length>0?z:"unknown"}catch{return"unknown"}}function o6($,Q){for(let Z of d6){let z=m($,Z);if(!K$(z))continue;let X=m(Q,Z);Y$(p$(X),{recursive:!0});try{zQ(z,X)}catch{}}}function VQ($,Q){Y$(p$($),{recursive:!0});let Z=`${$}.tmp.${process.pid}.${++JQ}`;v6(Z,Q),XQ(Z,$)}function n6($){return JSON.stringify($,null,2)}function WQ($){return`{${[`"id": ${JSON.stringify($.id)}`,`"ts": ${JSON.stringify($.ts)}`,`"iter": ${JSON.stringify($.iter)}`,`"task": ${JSON.stringify($.task)}`,`"sha": ${JSON.stringify($.sha)}`].join(", ")}}`}async function a6($){return f6(()=>s6($))}async function s6($){let Q=$.lokiDirOverride??P(),Z=process.cwd(),z=o(Q);if(Y$(z,{recursive:!0}),!$.forceCreate){if(!await p6(Z))return{created:!1,reason:"no uncommitted changes"}}let X=await u6(Z),q=await c6(Z),K=$.iteration??Number.parseInt(process.env.ITERATION_COUNT??"0",10),W=$.epochOverride??Math.floor(Date.now()/1000),V=`cp-${K}-${W}`,U=m(z,V);Y$(U,{recursive:!0}),o6(Q,U);let H=new Date().toISOString().replace(/\.\d{3}Z$/,"Z"),B=($.taskDescription??"task completed").slice(0,m6),G=$.provider??process.env.PROVIDER_NAME??"claude",Y={id:V,timestamp:H,iteration:K,task_id:$.taskId??"unknown",task_description:B,git_sha:X,git_branch:q,provider:G,phase:l6(Q)};VQ(m(U,"metadata.json"),n6(Y));let O={id:Y.id,ts:Y.timestamp,iter:Y.iteration,task:Y.task_description,sha:Y.git_sha},M=qQ(Q);return j$(M,()=>{KQ(M,`${WQ(O)}
|
|
475
|
+
`)}),r6(Q),{created:!0,id:V,metadata:Y,dir:U}}function L1($){let Q=o($);if(!K$(Q))return[];return h6(Q).filter((Z)=>Z.startsWith("cp-")).filter((Z)=>{try{return y6(m(Q,Z)).isDirectory()}catch{return!1}})}function P1($){return[...$].sort((Q,Z)=>{let z=ZQ(Q),X=ZQ(Z);return z-X})}function ZQ($){let Q=$.split("-");if(Q.length<3)return 0;let Z=Q[Q.length-1],z=Number.parseInt(Z??"0",10);return Number.isFinite(z)?z:0}function r6($){let Q=L1($);if(Q.length<=$Q)return;let Z=P1(Q),z=Z.slice(0,Z.length-$Q);for(let X of z)try{g6(m(o($),X),{recursive:!0,force:!0})}catch{}t6($)}function t6($){let Q=P1(L1($)),Z=[];for(let q of Q){let K=m(o($),q,"metadata.json"),W=m(o($),q);if(!K$(K)){w1($,W,"missing_field","metadata.json");continue}try{let V=JSON.parse(I1(K,"utf-8")),U=HQ(V,K);if(!U.ok){w1($,W,U.reason,U.field);continue}let H=U.value;Z.push(WQ({id:H.id,ts:H.timestamp,iter:H.iteration,task:H.task_description??"",sha:H.git_sha}))}catch{w1($,W,"invalid_type","metadata.json")}}let z=qQ($),X=Z.length>0?`${Z.join(`
|
|
474
476
|
`)}
|
|
475
|
-
`:"";
|
|
476
|
-
`)})}catch{}}function j1($){let Q=$??P(),Z=P1(L1(Q)),z=[];for(let X of Z){let q=
|
|
477
|
+
`:"";VQ(z,X)}function w1($,Q,Z,z){let X=m($,"events.jsonl"),q={timestamp:new Date().toISOString(),type:"checkpoint.metadata.dropped",checkpoint_dir:Q,reason:Z,field:z};try{Y$(p$(X),{recursive:!0}),j$(X,()=>{KQ(X,`${JSON.stringify(q)}
|
|
478
|
+
`)})}catch{}}function j1($){let Q=$??P(),Z=P1(L1(Q)),z=[];for(let X of Z){let q=UQ(Q,X);if(q)z.push(q)}return z}function UQ($,Q){let Z=m(o($),Q,"metadata.json");if(!K$(Z))return null;try{let z=JSON.parse(I1(Z,"utf-8"));return i6(z,Z)}catch{return null}}function i6($,Q){let Z=HQ($,Q);return Z.ok?Z.value:null}function HQ($,Q){if($===null||typeof $!=="object")return console.warn(`[checkpoint] invalid metadata at ${Q}: not an object`),{ok:!1,reason:"invalid_type",field:"<root>"};let Z=$,z=["id","timestamp","task_id","task_description","git_sha","git_branch","provider","phase"];for(let X of z){if(!(X in Z))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "${X}" missing`),{ok:!1,reason:"missing_field",field:X};if(typeof Z[X]!=="string")return console.warn(`[checkpoint] invalid metadata at ${Q}: field "${X}" not a string`),{ok:!1,reason:"invalid_type",field:X}}if(!Object.prototype.hasOwnProperty.call(Z,"iteration"))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "iteration" missing`),{ok:!1,reason:"missing_field",field:"iteration"};if(typeof Z.iteration!=="number"||!Number.isFinite(Z.iteration))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "iteration" not a finite number`),{ok:!1,reason:"invalid_type",field:"iteration"};for(let X of $7){let q=Z[X];if(e6.test(q))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "${X}" contains control characters`),{ok:!1,reason:"control_chars",field:X}}return{ok:!0,value:{id:Z.id,timestamp:Z.timestamp,iteration:Z.iteration,task_id:Z.task_id,task_description:Z.task_description,git_sha:Z.git_sha,git_branch:Z.git_branch,provider:Z.provider,phase:Z.phase}}}function F1($,Q){if(!Q7.test($))throw new GQ($);let Z=Q??P(),z=m(o(Z),$);if(!K$(z))throw new _1($);let X=UQ(Z,$);if(!X)throw new _1($);return X}function BQ($,Q){let Z=F1($,Q),z=Q??P(),X=m(o(z),$),q=[];for(let K of Z7){let W=m(X,K);if(!K$(W))continue;q.push({from:W,to:m(z,K)})}return{id:$,metadata:Z,restore:q}}function z7($){let Q=[],Z=0;for(let z of $.restore)try{Y$(p$(z.to),{recursive:!0});let X=`${z.to}.tmp.${process.pid}.${++JQ}`;zQ(z.from,X),XQ(X,z.to),Z+=1}catch(X){Q.push(`${z.from} -> ${z.to}: ${X.message}`)}return{restored:Z,errors:Q}}async function YQ($,Q,Z=!1){let z=null;try{let q=await a6({taskDescription:`pre-rollback snapshot (before restoring ${$.id})`,taskId:"rollback",forceCreate:!0,lokiDirOverride:Q});if(q.created)z=q.id}catch(q){let K=q instanceof Error?q.message:String(q);if(!Z)throw Error("pre-rollback snapshot failed ("+K+"); aborting rollback to preserve current state. Re-run with force to roll back anyway without a safety snapshot.");console.warn("[checkpoint] pre-rollback snapshot failed; proceeding due to force:",K)}let X=z7($);return{preRollbackSnapshotId:z,restored:X.restored,errors:X.errors}}var $Q=50,m6=200,QQ,d6,JQ=0,e6,$7,Q7,_1,GQ,Z7;var MQ=L(()=>{C();d();F$();QQ=Promise.resolve();d6=["state/orchestrator.json","autonomy-state.json","queue/pending.json","queue/completed.json","queue/in-progress.json","queue/current-task.json","CONTINUITY.md"];e6=/[\x00-\x08\x0a-\x1f\x7f-\x9f]/,$7=["id","task_id","git_sha","git_branch","provider","phase"];Q7=/^[a-zA-Z0-9_-]+$/;_1=class _1 extends Error{id;constructor($){super(`Checkpoint not found: ${$}`);this.id=$;this.name="CheckpointNotFoundError"}};GQ=class GQ extends Error{id;constructor($){super(`Invalid checkpoint ID: must be alphanumeric, hyphens, underscores only (got: ${$})`);this.id=$;this.name="InvalidCheckpointIdError"}};Z7=["state/orchestrator.json","queue/pending.json","queue/completed.json","queue/in-progress.json","queue/current-task.json","CONTINUITY.md"]});var AQ={};b(AQ,{runRollback:()=>X7});async function X7($){let Q=$[0],Z=$.slice(1);if(Q===void 0||Q==="help"||Q==="--help"||Q==="-h")return process.stdout.write(TQ),Q===void 0?1:0;switch(Q){case"list":{let z=[...j1()].reverse();if(z.length===0)return process.stdout.write(`${_}No checkpoints found.${J}
|
|
477
479
|
`),0;process.stdout.write(`${k}Checkpoints${J} (${z.length}, newest first):
|
|
478
480
|
`);for(let X of z)process.stdout.write(` ${I}${X.id}${J} iter=${X.iteration} ${X.git_branch||"(no branch)"}@${(X.git_sha||"").slice(0,7)} ${X.timestamp}
|
|
479
481
|
`);return 0}case"show":{let z=Z[0];if(!z)return process.stderr.write(`${T}Missing checkpoint id.${J} Use \`loki rollback list\`.
|
|
480
482
|
`),2;try{let X=F1(z);return process.stdout.write(`${JSON.stringify(X,null,2)}
|
|
481
483
|
`),0}catch(X){return process.stderr.write(`${T}Failed to read checkpoint:${J} ${X.message}
|
|
482
484
|
`),1}}case"to":{let z=Z[0];if(!z)return process.stderr.write(`${T}Missing checkpoint id.${J} Use \`loki rollback list\`.
|
|
483
|
-
`),2;return await
|
|
485
|
+
`),2;return await OQ(z,Z.includes("--force"))}case"latest":{let z=j1(),X=z[z.length-1];if(!X)return process.stderr.write(`${T}No checkpoints found to roll back to.${J}
|
|
484
486
|
`),1;return process.stdout.write(`Rolling back to latest checkpoint: ${I}${X.id}${J}
|
|
485
|
-
`),await
|
|
486
|
-
`),process.stderr.write(
|
|
487
|
+
`),await OQ(X.id,Z.includes("--force"))}default:return process.stderr.write(`Unknown subcommand: ${Q}
|
|
488
|
+
`),process.stderr.write(TQ),2}}async function OQ($,Q=!1){let Z;try{Z=BQ($)}catch(X){return process.stderr.write(`${T}Cannot plan rollback:${J} ${X.message}
|
|
487
489
|
`),1}if(Z.restore.length===0)return process.stdout.write(`${_}Checkpoint ${$} has no restorable state files; nothing to do.${J}
|
|
488
|
-
`),0;let z;try{z=await
|
|
490
|
+
`),0;let z;try{z=await YQ(Z,void 0,Q)}catch(X){return process.stderr.write(`${T}Rollback aborted:${J} ${X.message}
|
|
489
491
|
`),1}if(z.errors.length>0){for(let X of z.errors)process.stderr.write(`${T}restore error:${J} ${X}
|
|
490
492
|
`);return process.stderr.write(`${T}Partial rollback: ${z.restored}/${Z.restore.length} files restored.${J}
|
|
491
493
|
`),1}if(process.stdout.write(`${S}Rolled back ${z.restored}/${Z.restore.length} state files from ${$}.${J}
|
|
492
494
|
`),z.preRollbackSnapshotId)process.stdout.write(`Saved your prior state as ${I}${z.preRollbackSnapshotId}${J}; undo this rollback with \`loki rollback to ${z.preRollbackSnapshotId}\`.
|
|
493
|
-
`);return process.stdout.write("Run `loki start` to resume from the restored state.\n"),0}var
|
|
495
|
+
`);return process.stdout.write("Run `loki start` to resume from the restored state.\n"),0}var TQ=`Usage: loki rollback <subcommand>
|
|
494
496
|
|
|
495
497
|
Subcommands:
|
|
496
498
|
list List checkpoints (newest first)
|
|
@@ -511,22 +513,22 @@ to the checkpoint's snapshot (if one was anchored at checkpoint time):
|
|
|
511
513
|
git stash apply refs/loki/cp/<id>
|
|
512
514
|
|
|
513
515
|
Re-run \`loki start\` to resume from the restored state.
|
|
514
|
-
`;var
|
|
515
|
-
`),0;let Q=[];try{Q=
|
|
516
|
+
`;var wQ=L(()=>{MQ();c()});function K7(){return process.env.LOKI_TIER||"oss"}function _Q($){let Q=K7();if(Q==="oss")return{allowed:!0,notes:[]};if(!process.env.LOKI_LICENSE_KEY)return{allowed:!1,notes:[`${_}LOKI_TIER='${Q}' requested but no LOKI_LICENSE_KEY set.${J}`,`Hosted/enterprise license verification is not available yet (capability: ${$}).`,"OSS users: leave LOKI_TIER unset (or 'oss') -- everything stays free."]};return{allowed:!0,notes:[`${_}LOKI_LICENSE_KEY set but the verification backend is not available yet (R9 seam).${J}`]}}var IQ=L(()=>{c()});var PQ={};b(PQ,{runProof:()=>L7});import{existsSync as q$,readdirSync as q7,readFileSync as LQ,mkdtempSync as J7,copyFileSync as V7,rmSync as W7}from"fs";import{join as n,resolve as U7}from"path";import{tmpdir as H7}from"os";import{createInterface as G7}from"readline";import{readFile as B7}from"fs/promises";function a($){return $&&typeof $==="object"?$:{}}function p($){return $===void 0||$===null?"-":String($)}function M$(){return n(P(),"proofs")}function k1($){let Q=n(M$(),$,"proof.json");if(!q$(Q))return null;try{return JSON.parse(LQ(Q,"utf8"))}catch{return{}}}function $$($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function M7(){let $=M$();if(!q$($))return process.stdout.write(`${_}No proofs found.${J} Run 'loki start' to generate one.
|
|
517
|
+
`),0;let Q=[];try{Q=q7($,{withFileTypes:!0}).filter((z)=>z.isDirectory()).map((z)=>z.name).sort()}catch{Q=[]}let Z=[];for(let z of Q){let X=n($,z,"proof.json");if(!q$(X))continue;let q={};try{q=JSON.parse(LQ(X,"utf8"))}catch{q={}}let K=p(q.run_id),W=p(q.generated_at),V=a(q.honesty).headline,U=p(V??a(q.council).final_verdict),H=p(a(q.cost).usd),B=p(a(q.files_changed).count);Z.push(`${$$(K,26)} ${$$(W,20)} ${$$(U,18)} ${$$(H,9)} ${B}`)}if(Z.length===0)return process.stdout.write(`${_}No proofs found.${J} Run 'loki start' to generate one.
|
|
516
518
|
`),0;process.stdout.write(`${$$("RUN_ID",26)} ${$$("GENERATED_AT",20)} ${$$("VERDICT",18)} ${$$("COST_USD",9)} FILES
|
|
517
519
|
`);for(let z of Z)process.stdout.write(`${z}
|
|
518
|
-
`);return 0}function
|
|
520
|
+
`);return 0}function T7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
519
521
|
`),2;let Q=k1($);if(Q===null)return process.stderr.write(`${T}Proof not found: ${$}${J}
|
|
520
522
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
521
523
|
`),1;return process.stdout.write(`${JSON.stringify(Q,null,2)}
|
|
522
|
-
`),0}async function
|
|
524
|
+
`),0}async function O7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
523
525
|
`),2;let Q=n(M$(),$,"index.html");if(!q$(Q))return process.stderr.write(`${T}Proof page not found: ${$}/index.html${J}
|
|
524
526
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
525
527
|
`),1;process.stdout.write(`${S}Opening proof: ${Q}${J}
|
|
526
528
|
`);for(let Z of["open","xdg-open","start"])try{if((await F([Z,Q],{timeoutMs:5000})).exitCode===0)return 0}catch{}return process.stdout.write(`
|
|
527
529
|
Could not detect browser opener.
|
|
528
530
|
`),process.stdout.write(`Please open in browser: ${Q}
|
|
529
|
-
`),0}function
|
|
531
|
+
`),0}function A7($){return new Promise((Q)=>{let Z=G7({input:process.stdin,output:process.stdout});Z.question($,(z)=>{Z.close();let X=z.trim().toLowerCase();Q(X==="y"||X==="yes")})})}async function w7($,Q,Z){let z=_Q("hosted_publish");for(let G of z.notes)process.stderr.write(`${G}
|
|
530
532
|
`);let X=process.env.LOKI_HOSTED_ENDPOINT||"";if(!X)return process.stderr.write(`${_}Hosted publishing backend not available.${J}
|
|
531
533
|
`),process.stderr.write(`There is no official Loki hosted service yet (R9 ships the seam, not a live backend).
|
|
532
534
|
`),process.stderr.write(`To publish to your own hosted endpoint, set LOKI_HOSTED_ENDPOINT to its URL.
|
|
@@ -537,7 +539,7 @@ Could not detect browser opener.
|
|
|
537
539
|
`),process.stdout.write(` endpoint: ${X}
|
|
538
540
|
`),process.stdout.write(` payload: ${Q} (already redacted by the generator)
|
|
539
541
|
|
|
540
|
-
`);let K;try{K=await
|
|
542
|
+
`);let K;try{K=await B7(Q)}catch{return process.stderr.write(`${T}Could not read proof page: ${Q}${J}
|
|
541
543
|
`),1}let W={"Content-Type":"text/html","X-Loki-Proof-Id":$},V=process.env.LOKI_LICENSE_KEY||"";if(V)W.Authorization=`Bearer ${V}`;let U;try{U=await fetch(X,{method:"POST",headers:W,body:new Uint8Array(K)})}catch(G){return process.stderr.write(`${T}Failed to reach hosted endpoint: ${String(G.message||G)}${J}
|
|
542
544
|
`),process.stderr.write(`Check LOKI_HOSTED_ENDPOINT or publish to a gist: loki proof share ${$}
|
|
543
545
|
`),1}let H=await U.text();if(!U.ok){if(process.stderr.write(`${T}Hosted endpoint returned HTTP ${U.status}.${J}
|
|
@@ -547,11 +549,11 @@ Could not detect browser opener.
|
|
|
547
549
|
`),1}let B="";try{let G=JSON.parse(H);if(G&&typeof G==="object"){let Y=G.url??G.public_url;if(typeof Y==="string")B=Y}}catch{}if(B)process.stdout.write(`${S}Published: ${B}${J}
|
|
548
550
|
`);else process.stdout.write(`${S}Published to ${X} (HTTP ${U.status}).${J}
|
|
549
551
|
`),process.stdout.write(`The endpoint did not return a 'url' field; check your endpoint's response.
|
|
550
|
-
`);return 0}async function
|
|
552
|
+
`);return 0}async function _7($){let Q="",Z=!1,z="--public",X=!1;for(let M of $)if(M==="--yes"||M==="-y")Z=!0;else if(M==="--private")z="";else if(M==="--public")z="--public";else if(M==="--hosted")X=!0;else if(M.startsWith("-"))return process.stderr.write(`${T}Unknown option: ${M}${J}
|
|
551
553
|
`),1;else Q=M;if(!Q)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
552
554
|
`),2;let q=n(M$(),Q,"index.html");if(!q$(q))return process.stderr.write(`${T}Proof page not found: ${Q}/index.html${J}
|
|
553
555
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
554
|
-
`),1;if(X)return
|
|
556
|
+
`),1;if(X)return w7(Q,q,n(M$(),Q,"proof.json"));if((await F(["gh","--version"],{timeoutMs:5000})).exitCode!==0)return process.stderr.write(`${T}gh CLI not found${J}
|
|
555
557
|
`),process.stderr.write(`Install the GitHub CLI to publish a proof:
|
|
556
558
|
`),process.stderr.write(` brew install gh # macOS
|
|
557
559
|
`),process.stderr.write(` sudo apt install gh # Ubuntu/Debian
|
|
@@ -569,18 +571,18 @@ Could not detect browser opener.
|
|
|
569
571
|
`)}if(process.stdout.write(`
|
|
570
572
|
${_}Secrets, API keys, tokens, env values, and absolute paths have already been stripped by the generator.${J}
|
|
571
573
|
|
|
572
|
-
`),!Z){if(!await
|
|
573
|
-
`),0}let H=
|
|
574
|
-
`);let G=`Loki Mode proof-of-run ${Q}`,Y=["gh","gist","create",B,"--desc",G];if(z!=="")Y.push(z);let O=await F(Y,{timeoutMs:60000});try{
|
|
574
|
+
`),!Z){if(!await A7(`Publish this proof to a ${V} gist? [y/N] `))return process.stdout.write(`Aborted. Nothing was published.
|
|
575
|
+
`),0}let H=J7(n(H7(),"loki-proof-")),B=n(H,"index.html");V7(q,B),process.stdout.write(`Uploading proof page...
|
|
576
|
+
`);let G=`Loki Mode proof-of-run ${Q}`,Y=["gh","gist","create",B,"--desc",G];if(z!=="")Y.push(z);let O=await F(Y,{timeoutMs:60000});try{W7(H,{recursive:!0,force:!0})}catch{}if(O.exitCode!==0)return process.stderr.write(`${T}Failed to create gist${J}
|
|
575
577
|
`),process.stderr.write(`${O.stdout}${O.stderr}
|
|
576
578
|
`),1;return process.stdout.write(`${S}Shared: ${O.stdout.trim()}${J}
|
|
577
|
-
`),0}async function
|
|
579
|
+
`),0}async function I7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
578
580
|
`),2;let Q=n(M$(),$,"proof.json");if(!q$(Q))return process.stderr.write(`${T}Proof not found: ${$}${J}
|
|
579
581
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
580
|
-
`),1;let Z=
|
|
581
|
-
`),2;let z=process.env.TARGET_DIR||".",X=await F(["python3",Z,Q,z],{timeoutMs:30000});if(X.stdout)process.stdout.write(X.stdout);if(X.stderr)process.stderr.write(X.stderr);return X.exitCode}async function
|
|
582
|
+
`),1;let Z=U7(h,"autonomy","lib","proof-verify.py");if(!q$(Z))return process.stderr.write(`${T}Verifier not found (autonomy/lib/proof-verify.py).${J}
|
|
583
|
+
`),2;let z=process.env.TARGET_DIR||".",X=await F(["python3",Z,Q,z],{timeoutMs:30000});if(X.stdout)process.stdout.write(X.stdout);if(X.stderr)process.stderr.write(X.stderr);return X.exitCode}async function L7($){let Q=$[0],Z=$.slice(1);if(Q===void 0||Q==="help"||Q==="--help"||Q==="-h")return process.stdout.write(Y7),Q===void 0?1:0;switch(Q){case"list":return M7();case"show":return T7(Z[0]);case"verify":return I7(Z[0]);case"open":return O7(Z[0]);case"share":return _7(Z);default:return process.stderr.write(`${T}Unknown subcommand: ${Q}${J}
|
|
582
584
|
`),process.stderr.write(`Run 'loki proof --help' for usage.
|
|
583
|
-
`),1}}var
|
|
585
|
+
`),1}}var Y7;var jQ=L(()=>{C();d();c();IQ();Y7=`${k}loki proof${J} - inspect and share proof-of-run artifacts
|
|
584
586
|
|
|
585
587
|
Usage: loki proof <subcommand> [args]
|
|
586
588
|
|
|
@@ -597,17 +599,17 @@ Options for 'share':
|
|
|
597
599
|
--hosted Publish to LOKI_HOSTED_ENDPOINT (open-core seam; no official backend yet)
|
|
598
600
|
|
|
599
601
|
Proofs are generated automatically at run completion (LOKI_PROOF=0 to opt out).
|
|
600
|
-
`});var
|
|
602
|
+
`});var NQ={};b(NQ,{runCrash:()=>S7});import{existsSync as kQ,readdirSync as P7,readFileSync as j7}from"fs";import{join as RQ}from"path";function k$($){return $===void 0||$===null?"-":String($)}function l$($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function EQ(){return RQ(P(),"crash")}function R1(){let $=EQ();if(!kQ($))return[];try{return P7($,{withFileTypes:!0}).filter((Q)=>Q.isFile()&&Q.name.endsWith(".json")).map((Q)=>Q.name.slice(0,-5)).sort()}catch{return[]}}function k7($){if($.length===0)return!1;if($.includes("/")||$.includes("\\"))return!1;if($.includes(".."))return!1;return!0}function d$($){if(!k7($))return null;let Q=RQ(EQ(),`${$}.json`);if(!kQ(Q))return null;try{return JSON.parse(j7(Q,"utf8"))}catch{return{}}}function R7(){let $=R1();if($.length===0)return process.stdout.write(`${_}No crash reports found.${J} Nothing has been captured in .loki/crash/.
|
|
601
603
|
`),0;process.stdout.write(`${l$("ID",40)} ${l$("CAPTURED_AT",22)} ERROR_CLASS
|
|
602
604
|
`);for(let Q of $){let Z=d$(Q)??{},z=k$(Z.fingerprint),X=k$(Z.captured_at),q=k$(Z.error_class),K=z!=="-"?z:Q;process.stdout.write(`${l$(K,40)} ${l$(X,22)} ${q}
|
|
603
605
|
`)}return process.stdout.write(`
|
|
604
606
|
${$.length} report(s). Run 'loki crash show <id>' to inspect, 'loki crash submit' to get a prefilled GitHub issue URL.
|
|
605
|
-
`),0}function
|
|
606
|
-
`),2;let Q=
|
|
607
|
+
`),0}function xQ($){let Q=d$($);if(Q!==null)return{id:$,report:Q};for(let Z of R1()){let z=d$(Z);if(z&&String(z.fingerprint??"")===$)return{id:Z,report:z}}return null}function E7($){if(!$)return process.stderr.write(`${T}Missing crash id.${J} Use 'loki crash' to list reports.
|
|
608
|
+
`),2;let Q=xQ($);if(Q===null)return process.stderr.write(`${T}Crash report not found: ${$}${J}
|
|
607
609
|
`),process.stderr.write(`Use 'loki crash' to see available reports.
|
|
608
610
|
`),1;return process.stdout.write(`${JSON.stringify(Q.report,null,2)}
|
|
609
|
-
`),0}function
|
|
610
|
-
`),W=new URLSearchParams({title:X,body:K});return`${
|
|
611
|
+
`),0}function x7($){let Q=k$($.error_class),Z=k$($.fingerprint),z=Z!=="-"?Z.slice(0,12):"unknown",X=`crash: ${Q} (${z})`,K=["Anonymous crash report captured by Loki Mode (scrubbed, whitelist-only).","","Scrubbed payload:","```json",JSON.stringify($,null,2),"```","","Nothing was sent automatically. This issue is submitted manually by me."].join(`
|
|
612
|
+
`),W=new URLSearchParams({title:X,body:K});return`${F7}?${W.toString()}`}function N7($){let Q;if($){if(Q=xQ($),Q===null)return process.stderr.write(`${T}Crash report not found: ${$}${J}
|
|
611
613
|
`),process.stderr.write(`Use 'loki crash' to see available reports.
|
|
612
614
|
`),1}else{let Z=R1();if(Z.length===0)return process.stdout.write(`${_}No crash reports found.${J} Nothing to submit.
|
|
613
615
|
`),0;let z=Z[Z.length-1],X=d$(z)??{};Q={id:z,report:X}}return process.stdout.write(`${k}Scrubbed payload (this is the ENTIRE report):${J}
|
|
@@ -616,12 +618,12 @@ ${$.length} report(s). Run 'loki crash show <id>' to inspect, 'loki crash submit
|
|
|
616
618
|
`),process.stdout.write(`${_}Nothing is sent automatically in this version.${J} Loki Mode never transmits crash data on its own.
|
|
617
619
|
`),process.stdout.write(`To submit manually, open this prefilled GitHub issue and review it first:
|
|
618
620
|
|
|
619
|
-
`),process.stdout.write(` ${I}${
|
|
621
|
+
`),process.stdout.write(` ${I}${x7(Q.report)}${J}
|
|
620
622
|
|
|
621
623
|
`),process.stdout.write(`${S}The payload above is exactly what the URL contains.${J}
|
|
622
624
|
`),process.stdout.write(`See docs/PRIVACY.md for what is and is not collected.
|
|
623
|
-
`),0}async function
|
|
624
|
-
`),process.stdout.write(
|
|
625
|
+
`),0}async function S7($){let Q=$[0];switch(Q){case void 0:case"list":return R7();case"--help":case"-h":case"help":return process.stdout.write(FQ),0;case"show":return E7($[1]);case"submit":return N7($[1]);default:return process.stderr.write(`${T}Unknown crash subcommand: ${Q}${J}
|
|
626
|
+
`),process.stdout.write(FQ),2}}var F7="https://github.com/asklokesh/loki-mode/issues/new",FQ;var SQ=L(()=>{C();c();FQ=`${k}loki crash${J} - inspect and manually submit local crash reports
|
|
625
627
|
|
|
626
628
|
Usage: loki crash [subcommand] [args]
|
|
627
629
|
|
|
@@ -633,15 +635,15 @@ Subcommands:
|
|
|
633
635
|
|
|
634
636
|
Crash reports are anonymous, scrubbed, and stored locally only. Nothing is
|
|
635
637
|
sent automatically in this version. See docs/PRIVACY.md.
|
|
636
|
-
`});var
|
|
638
|
+
`});var hQ={};b(hQ,{runWiki:()=>y7});import{existsSync as E1,readFileSync as DQ}from"fs";import{join as x1,resolve as D7}from"path";function b7(){return x1(process.cwd(),".loki","wiki")}function h7($){let Q="";for(let X of $){if(X==="--help"||X==="-h")return process.stdout.write(`Usage: loki wiki show [section]
|
|
637
639
|
Sections: architecture, modules, data-flow
|
|
638
640
|
`),0;if(X.startsWith("-"))return process.stderr.write(`${T}Unknown option: ${X}${J}
|
|
639
|
-
`),1;Q=X}let Z=
|
|
640
|
-
`),1;if(Q){if(!
|
|
641
|
+
`),1;Q=X}let Z=b7();if(!E1(Z))return process.stderr.write(`${_}No wiki found. Run 'loki wiki generate' first.${J}
|
|
642
|
+
`),1;if(Q){if(!C7.has(Q))return process.stderr.write(`${T}No such section: ${Q} (try: architecture, modules, data-flow)${J}
|
|
641
643
|
`),1;let X=x1(Z,`${Q}.md`);if(!E1(X))return process.stderr.write(`${T}Section not generated: ${Q}${J}
|
|
642
|
-
`),1;return process.stdout.write(
|
|
643
|
-
`),1;return process.stdout.write(
|
|
644
|
-
`),process.stdout.write(
|
|
644
|
+
`),1;return process.stdout.write(DQ(X,"utf8")),0}let z=x1(Z,"index.md");if(!E1(z))return process.stderr.write(`${T}Wiki index not found. Run 'loki wiki generate'.${J}
|
|
645
|
+
`),1;return process.stdout.write(DQ(z,"utf8")),0}async function bQ($,Q){let Z=D7(h,"autonomy","loki"),z=3600000,X=Bun.spawn({cmd:[Z,"wiki",$,...Q],stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,LOKI_LEGACY_BASH:"1"}}),q=setTimeout(()=>{try{X.kill("SIGKILL")}catch{}},3600000);try{return await X.exited}finally{clearTimeout(q)}}async function y7($){let Q=$[0],Z=$.slice(1);switch(Q){case void 0:case"help":case"--help":case"-h":return process.stdout.write(CQ),0;case"show":return h7(Z);case"generate":return bQ("generate",Z);case"ask":return bQ("ask",Z);default:return process.stderr.write(`${T}Unknown wiki command: ${Q}${J}
|
|
646
|
+
`),process.stdout.write(CQ),1}}var CQ,C7;var yQ=L(()=>{C();c();CQ=`${k}loki wiki${J} - Auto-generated, cited codebase wiki + Q&A
|
|
645
647
|
|
|
646
648
|
Usage: loki wiki <command> [options]
|
|
647
649
|
|
|
@@ -657,8 +659,8 @@ Examples:
|
|
|
657
659
|
loki wiki generate
|
|
658
660
|
loki wiki show architecture
|
|
659
661
|
loki wiki ask "how does the cli dispatch commands"
|
|
660
|
-
`,
|
|
661
|
-
`)}function
|
|
662
|
+
`,C7=new Set(["architecture","modules","data-flow"])});var S1={};b(S1,{renderFindingsForPrompt:()=>u7,loadPreviousFindings:()=>N1,findLatestReviewDir:()=>uQ,_parseReviewerOutputForTests:()=>c7});import{existsSync as gQ,readFileSync as vQ,readdirSync as mQ,statSync as v7}from"fs";import{join as o$}from"path";function f7($){let Q=$.toLowerCase();if(Q==="critical")return"Critical";if(Q==="high")return"High";if(Q==="medium")return"Medium";return"Low"}function fQ($,Q,Z,z){let X=[],q=$.split(/\r?\n/);for(let K of q){let W=K.trim();if(W.length===0)continue;let V=W.replace(/^[-*]\s*/,""),U=g7.exec(V);if(!U||!U[1]||!U[2])continue;let H=f7(U[1]),B=U[2].trim(),G=m7.exec(B),Y=G&&G[1]?G[1]:null,O=G&&G[2]?Number.parseInt(G[2],10):null;X.push({reviewId:Z,iteration:z,reviewer:Q,severity:H,description:B,file:Y,line:Number.isFinite(O)?O:null,raw:W})}return X}function uQ($,Q){let Z=o$($,"quality","reviews");if(!gQ(Z))return null;let z;try{z=mQ(Z)}catch{return null}let X=Q===void 0?z.filter((W)=>W.startsWith("review-")):z.filter((W)=>W.endsWith(`-${Q}`)&&W.startsWith("review-"));if(X.length===0)return null;X.sort();let q=X[X.length-1];if(!q)return null;let K=o$(Z,q);try{if(!v7(K).isDirectory())return null}catch{return null}return K}function N1($,Q){let Z=uQ($,Q);if(Z===null)return{reviewDir:null,reviewId:null,iteration:null,findings:[]};let z=null,X=null,q=o$(Z,"aggregate.json");if(gQ(q))try{let U=vQ(q,"utf-8"),H=JSON.parse(U);if(typeof H.review_id==="string")z=H.review_id;if(typeof H.iteration==="number")X=H.iteration}catch{}let K;try{K=mQ(Z)}catch{return{reviewDir:Z,reviewId:z,iteration:X,findings:[]}}let W=new Set(["diff.txt","files.txt","anti-sycophancy.txt"]),V=[];for(let U of K){if(!U.endsWith(".txt"))continue;if(W.has(U))continue;if(U.endsWith("-prompt.txt"))continue;let H=U.replace(/\.txt$/,""),B;try{B=vQ(o$(Z,U),"utf-8")}catch{continue}V.push(...fQ(B,H,z??"",X??-1))}return{reviewDir:Z,reviewId:z,iteration:X,findings:V}}function u7($){if($.length===0)return"";let Q=["Critical","High","Medium","Low"],Z=new Map;for(let X of Q)Z.set(X,[]);for(let X of $){let q=Z.get(X.severity);if(q)q.push(X)}let z=[];z.push("PREVIOUS REVIEWER FINDINGS (must address each, or supply counter-evidence in .loki/state/counter-evidence-<iter>.json):");for(let X of Q){let q=Z.get(X)??[];if(q.length===0)continue;z.push(` [${X}] (${q.length}):`);for(let K of q){let W=K.file?` (${K.file}${K.line!==null?":"+K.line:""})`:"";z.push(` - ${K.description}${W} -- via ${K.reviewer}`)}}return z.join(`
|
|
663
|
+
`)}function c7($,Q,Z="review-test",z=0){return fQ($,Q,Z,z)}var g7,m7;var n$=L(()=>{g7=/\[(Critical|High|Medium|Low)\]\s*(.+)/i,m7=/([\w.\-/]+\.[a-zA-Z]+):(\d+)/});import{existsSync as p7}from"fs";import{join as l7}from"path";async function cQ($,Q){let Z=l7($,"memory");if(!p7(Z))return{stored:!1,reason:"memory dir not initialized"};let z=Math.max(0,Math.floor(Q.durationSeconds??0)),X={_LOKI_PROJECT_DIR:h,_LOKI_TARGET_DIR:process.cwd(),_LOKI_TASK_ID:Q.taskId,_LOKI_OUTCOME:Q.outcome,_LOKI_PHASE:Q.phase,_LOKI_GOAL:Q.goal,_LOKI_DURATION:String(z),_LOKI_LOKI_DIR:$},K=await z$(`
|
|
662
664
|
import os, sys
|
|
663
665
|
project = os.environ.get('_LOKI_PROJECT_DIR', '')
|
|
664
666
|
loki = os.environ.get('_LOKI_LOKI_DIR', '.loki')
|
|
@@ -685,25 +687,25 @@ try:
|
|
|
685
687
|
print('OK')
|
|
686
688
|
except Exception as e:
|
|
687
689
|
print('ERR:' + str(e))
|
|
688
|
-
`,{env:X,timeoutMs:15000});if(K.exitCode===127)return{stored:!1,reason:"python3 not found"};let W=K.stdout.trim();if(W==="OK")return{stored:!0,reason:"stored"};if(W.startsWith("ERR:"))return{stored:!1,reason:W.replace(/^ERR:/,"")};return{stored:!1,reason:K.stderr.trim()||"unknown"}}var
|
|
689
|
-
`)}async function
|
|
690
|
-
`)}function
|
|
691
|
-
`),process.stderr.write(C1),2}}async function
|
|
690
|
+
`,{env:X,timeoutMs:15000});if(K.exitCode===127)return{stored:!1,reason:"python3 not found"};let W=K.stdout.trim();if(W==="OK")return{stored:!0,reason:"stored"};if(W.startsWith("ERR:"))return{stored:!1,reason:W.replace(/^ERR:/,"")};return{stored:!1,reason:K.stderr.trim()||"unknown"}}var pQ=L(()=>{V$();C()});var nQ={};b(nQ,{loadLearnings:()=>D1,appendLearning:()=>R$,appendFromGateFailure:()=>i7});import{existsSync as d7,readFileSync as o7}from"fs";import{join as lQ}from"path";import{createHash as n7}from"crypto";function dQ($){return lQ($,a7)}function s7($){if($===null||typeof $!=="object")return!1;let Q=$;return typeof Q.id==="string"&&typeof Q.timestamp==="string"&&typeof Q.iteration==="number"&&typeof Q.trigger==="string"&&typeof Q.rootCause==="string"&&typeof Q.fix==="string"&&typeof Q.preventInFuture==="string"&&typeof Q.evidence==="object"&&Q.evidence!==null}function oQ($){if(!d7($))return{version:1,learnings:[]};try{let Q=o7($,"utf-8"),Z=JSON.parse(Q);if(Z.version===1&&Array.isArray(Z.learnings))return{version:1,learnings:Z.learnings.filter(s7)}}catch{}return{version:1,learnings:[]}}function r7($,Q,Z){return n7("sha256").update(`${$} ${Q} ${Z??""}`).digest("hex").slice(0,16)}async function R$($,Q,Z={}){let z=r7(Q.trigger,Q.rootCause,Q.evidence.file),X=new Date().toISOString(),q={id:z,timestamp:X,...Q},K=dQ($);if(await e0(K,()=>{j$(K,()=>{let V=oQ(K),U=V.learnings.findIndex((H)=>H.id===z);if(U>=0){let H=V.learnings[U];V.learnings[U]={...H,timestamp:X,iteration:q.iteration}}else V.learnings.push(q);P$(K,V)})}),Z.episodeBridge!==null&&(Z.episodeBridge!==void 0||process.env.LOKI_AUTO_LEARNINGS_EPISODE==="1")){let V=Z.episodeBridge??cQ,U=Z.bridgeFailureLog??t7;try{let H=await V($,{taskId:`learning-${z}`,outcome:"failure",phase:"VERIFY",goal:`${Q.trigger}: ${Q.rootCause}`});if(H&&!H.stored){if(!new Set(["memory dir not initialized","stub"]).has(H.reason))U(`episode_bridge skipped: ${H.reason}`)}}catch(H){U(`episode_bridge threw: ${H.message}`)}}return q}function t7($){process.stderr.write(`[learnings_writer] ${$}
|
|
691
|
+
`)}async function i7($,Q,Z,z={}){let X=`[${Z.severity}] ${Z.description}`;return R$($,{iteration:Q,trigger:"gate_failure",rootCause:X,fix:"pending: dev agent must address in next iteration or supply counter-evidence",preventInFuture:"if this finding recurs, lower its severity threshold or add a regression test",evidence:{reviewId:Z.reviewId,file:Z.file??void 0,line:Z.line??void 0,severity:Z.severity,reviewer:Z.reviewer}},z)}function D1($){return oQ(dQ($))}var a7;var a$=L(()=>{F$();pQ();a7=lQ("state","relevant-learnings.json")});var sQ={};b(sQ,{runOverrideCouncil:()=>XZ,recordOverrideOutcome:()=>KZ,loadCounterEvidence:()=>zZ,canonicalFindingId:()=>s$,DEFAULT_OVERRIDE_JUDGES:()=>aQ});import{existsSync as e7,readFileSync as $Z}from"fs";import{join as QZ}from"path";function zZ($,Q){let Z=QZ($,"state",`counter-evidence-${Q}.json`);if(!e7(Z))return null;try{let z=$Z(Z,"utf-8"),X=JSON.parse(z);if(typeof X.iteration!=="number")return null;let q=Array.isArray(X.evidence)?X.evidence:[],K=[];for(let W of q){if(typeof W!=="object"||W===null)continue;let V=W;if(typeof V.findingId!=="string")continue;if(typeof V.claim!=="string")continue;let U=V.proofType;if(typeof U!=="string"||!ZZ.has(U))continue;let H=U,B=Array.isArray(V.artifacts)?V.artifacts:[];K.push({findingId:V.findingId,claim:V.claim,proofType:H,artifacts:B.filter((G)=>typeof G==="string")})}return{iteration:X.iteration,evidence:K}}catch{return null}}async function XZ($,Q,Z,z={}){let X=z.judges??aQ,q=new Set,K=new Set,W={},V=new Map;for(let H of Q.evidence)V.set(H.findingId,H);let U=new Map;for(let H of $){let B=s$(H);U.set(B,(U.get(B)??0)+1)}for(let H of $){let B=s$(H);if((U.get(B)??0)>1){K.add(B);continue}let G=V.get(B);if(!G){K.add(B);continue}let Y=await Promise.all(X.map((M)=>Z({finding:H,evidence:G,judge:M})));if(W[B]=Y,Y.filter((M)=>M.verdict==="APPROVE_OVERRIDE").length>=2)q.add(B);else K.add(B)}return{approvedFindingIds:q,rejectedFindingIds:K,votes:W}}function s$($){let Q=$.raw.slice(0,80).replace(/\s+/g," ").trim();return`${$.reviewer}::${Q}`}async function KZ($,Q,Z,z,X={}){let q={episodeBridge:X.episodeBridge===void 0?null:X.episodeBridge};for(let K of z){let W=s$(K);if(Z.approvedFindingIds.has(W))await R$($,{iteration:Q,trigger:"override_approved",rootCause:`[${K.severity}] ${K.description}`,fix:"override council approved counter-evidence; finding lifted",preventInFuture:"if this reviewer/file pair recurs, narrow the reviewer's selector OR add a baseline doc",evidence:{findingId:W,reviewId:K.reviewId,file:K.file??void 0,line:K.line??void 0,severity:K.severity,reviewer:K.reviewer}},q);else if(Z.rejectedFindingIds.has(W))await R$($,{iteration:Q,trigger:"override_rejected",rootCause:`[${K.severity}] ${K.description}`,fix:"override council rejected -- dev agent must fix the finding",preventInFuture:"address this finding in the next iteration",evidence:{findingId:W,reviewId:K.reviewId,file:K.file??void 0,line:K.line??void 0,severity:K.severity,reviewer:K.reviewer}},q)}}var ZZ,aQ;var rQ=L(()=>{a$();ZZ=new Set(["file-exists","test-passes","grep-miss","reviewer-misread","duplicate-code-path","out-of-scope"]);aQ=["judge-primary","judge-secondary","judge-tertiary"]});var iQ={};b(iQ,{writeEscalationHandoff:()=>YZ,renderHandoff:()=>tQ,readLatestHandoff:()=>MZ});import{existsSync as qZ,readdirSync as JZ,readFileSync as VZ}from"fs";import{join as r$}from"path";function WZ(){return new Date().toISOString()}function UZ($){let Q=$.file?` (${$.file}${$.line!==null?":"+$.line:""})`:"";return` - [${$.severity}] ${$.description}${Q} -- ${$.reviewer}`}function HZ($){let Q=$.evidence,Z=Q.file?` ${Q.file}${Q.line!==void 0?":"+Q.line:""}`:"";return` - **${$.trigger}** (iter ${$.iteration})${Z}: ${$.rootCause}`}function tQ($,Q,Z){let z=[];if(z.push(`# Loki escalation handoff -- ${WZ()}`),z.push(""),z.push(`Gate **${$.gateName}** has failed ${$.consecutiveFailures} consecutive times at iteration ${$.iteration}.`),z.push(""),z.push(`Reason: ${$.detail}`),z.push(""),Q.length>0){z.push(`## Outstanding findings (${Q.length})`),z.push("");for(let X of Q)z.push(UZ(X));z.push("")}else z.push("## Outstanding findings"),z.push(""),z.push("(no per-finding records captured -- gate failed without populating reviewer outputs)"),z.push("");if(Z.length>0){z.push(`## Recent learnings (${Math.min(Z.length,10)})`),z.push("");for(let X of Z.slice(-10))z.push(HZ(X));z.push("")}return z.push("## What the human must decide"),z.push(""),z.push("- Fix the finding? Address it in the code, then `rm .loki/PAUSE` to resume. A code_review BLOCK is NOT lifted by self-supplied counter-evidence -- the gated agent authors that file, so it cannot self-certify a trust-gate finding away."),z.push('- Override after your own review? You (the operator) are the escape path: review the finding and, if you accept it, `rm .loki/PAUSE` to resume. To direct the agent on resume, `echo "instructions" > .loki/HUMAN_INPUT.md` first.'),z.push("- Disable a gate? Set `LOKI_GATE_<NAME>=false` in env (see skills/quality-gates.md)."),z.push("- Tweak escalation? Set `LOKI_GATE_PAUSE_LIMIT` or `LOKI_GATE_ESCALATE_LIMIT`."),z.push("- Roll back? Switch to `LOKI_LEGACY_BASH=1` and re-run; the bash route does not consult this handoff doc."),z.push(""),z.push("To resume: fix the findings (or, after your own review, accept them), then `rm .loki/PAUSE`."),z.join(`
|
|
692
|
+
`)}function BZ($,Q){A1($,Q)}function YZ($,Q,Z={}){let z=Z.findings??N1($,Q.iteration).findings,X=Z.learnings??D1($).learnings,q=tQ(Q,z,X),K=(Z.now?.()??new Date).toISOString().replace(/[-:.]/g,""),W=r$($,"escalations"),V=++GZ,U=r$(W,`handoff-${K}-${process.pid}-${V}-${Q.gateName}.md`);return BZ(U,q),{path:U,bytes:q.length}}function MZ($){let Q=r$($,"escalations");if(!qZ(Q))return null;let Z;try{Z=JZ(Q).filter((q)=>q.endsWith(".md"))}catch{return null}if(Z.length===0)return null;Z.sort();let z=Z[Z.length-1];if(!z)return null;let X=r$(Q,z);try{return{path:X,body:VZ(X,"utf-8")}}catch{return null}}var GZ=0;var eQ=L(()=>{F$();n$();a$()});var Q8={};b(Q8,{runInternalPhase1Hooks:()=>IZ,_resolveForTests:()=>_Z,_internalPhase1HooksHelp:()=>FZ,__testAppendHook:()=>$8});import{existsSync as TZ,mkdirSync as OZ,readdirSync as AZ,statSync as wZ}from"fs";import{join as E$,resolve as _Z}from"path";async function IZ($){let[Q,...Z]=$;switch(Q){case void 0:case"help":case"--help":case"-h":return process.stdout.write(C1),Q===void 0?1:0;case"reflect":return LZ(Z);case"override":return PZ(Z);case"handoff":return jZ(Z);default:return process.stderr.write(`Unknown subcommand: ${Q}
|
|
693
|
+
`),process.stderr.write(C1),2}}async function LZ($){let Q=b1($[0]);if(Q===null)return process.stderr.write(`reflect: missing or invalid <iter>
|
|
692
694
|
`),2;let Z=P();try{let X=(await Promise.resolve().then(() => (n$(),S1))).loadPreviousFindings(Z,Q);if(X.findings.length===0)return process.stdout.write(`reflect: no findings for iter ${Q} (nothing to do)
|
|
693
|
-
`),0;let q=E$(Z,"state");
|
|
695
|
+
`),0;let q=E$(Z,"state");OZ(q,{recursive:!0}),P$(E$(q,`findings-${Q}.json`),{review_id:X.reviewId,iteration:Q,findings:X.findings});let K=await Promise.resolve().then(() => (a$(),nQ)),W=0,V=0;if(process.env.LOKI_AUTO_LEARNINGS!=="0"){let H=X.findings.filter((G)=>G.severity==="Critical"||G.severity==="High"),B=$8.fn??K.appendFromGateFailure;for(let G of H)try{await B(Z,Q,G,{episodeBridge:null}),W+=1}catch(Y){V+=1,process.stderr.write(`reflect: learning append failed for finding ${G.reviewer}/${G.severity}: ${Y.message}
|
|
694
696
|
`)}if(V>0&&W===0)return process.stderr.write(`reflect: all ${V} learning appends failed (iter ${Q})
|
|
695
697
|
`),1}let U=V>0?` (${V} failed)`:"";return process.stdout.write(`reflect: persisted ${X.findings.length} findings + ${W} learnings${U} (iter ${Q})
|
|
696
698
|
`),0}catch(z){return process.stderr.write(`reflect: ${z.message}
|
|
697
|
-
`),1}}async function
|
|
698
|
-
`),2;let Z=P();try{let z=await Promise.resolve().then(() => (
|
|
699
|
+
`),1}}async function PZ($){let Q=b1($[0]);if(Q===null)return process.stderr.write(`override: missing or invalid <iter>
|
|
700
|
+
`),2;let Z=P();try{let z=await Promise.resolve().then(() => (rQ(),sQ)),X=z.loadCounterEvidence(Z,Q);if(X===null||X.evidence.length===0)return process.stdout.write(`override: no counter-evidence for iter ${Q} (skip)
|
|
699
701
|
`),0;let K=(await Promise.resolve().then(() => (n$(),S1))).loadPreviousFindings(Z,Q),W=K.findings.filter((O)=>O.severity==="Critical"||O.severity==="High");if(W.length===0)return process.stdout.write(`override: no blocking findings for iter ${Q} (skip)
|
|
700
|
-
`),0;let V=async(O)=>{return{judge:O.judge,verdict:"REJECT_OVERRIDE",reasoning:`[stub] proofType=${O.evidence.proofType}: self-supplied counter-evidence cannot lift a trust-gate BLOCK on the agent-authored route. Fix the finding, or use the human-escape path (rm .loki/PAUSE; optionally .loki/HUMAN_INPUT.md). The only adjudicated override is the Bun-route real-LLM judge.`}},U=await z.runOverrideCouncil(W,X,V);await z.recordOverrideOutcome(Z,Q,U,W);let H=E$(Z,"quality","reviews");if(
|
|
702
|
+
`),0;let V=async(O)=>{return{judge:O.judge,verdict:"REJECT_OVERRIDE",reasoning:`[stub] proofType=${O.evidence.proofType}: self-supplied counter-evidence cannot lift a trust-gate BLOCK on the agent-authored route. Fix the finding, or use the human-escape path (rm .loki/PAUSE; optionally .loki/HUMAN_INPUT.md). The only adjudicated override is the Bun-route real-LLM judge.`}},U=await z.runOverrideCouncil(W,X,V);await z.recordOverrideOutcome(Z,Q,U,W);let H=E$(Z,"quality","reviews");if(TZ(H))try{let O=AZ(H).filter((R)=>R.startsWith("review-")).sort(),M=O[O.length-1];if(M&&wZ(E$(H,M)).isDirectory())P$(E$(H,M,`override-${Q}.json`),{review_id:K.reviewId,iteration:Q,approved_finding_ids:Array.from(U.approvedFindingIds),rejected_finding_ids:Array.from(U.rejectedFindingIds),votes:U.votes})}catch{}let B=U.approvedFindingIds.size,G=U.rejectedFindingIds.size;if(G===0&&B>0)process.stdout.write(`override: LIFTED -- ${B} approved, ${G} rejected
|
|
701
703
|
`);else process.stdout.write(`override: BLOCKED -- ${B} approved, ${G} rejected
|
|
702
704
|
`);return 0}catch(z){return process.stderr.write(`override: ${z.message}
|
|
703
|
-
`),1}}async function
|
|
704
|
-
`),2;let X=P();try{let K=(await Promise.resolve().then(() => (
|
|
705
|
+
`),1}}async function jZ($){let Q=$[0],Z=Number.parseInt($[1]??"0",10),z=b1($[2]);if(!Q||!Number.isFinite(Z)||z===null)return process.stderr.write(`handoff: usage: handoff <gate> <consecutive-failures> <iter>
|
|
706
|
+
`),2;let X=P();try{let K=(await Promise.resolve().then(() => (eQ(),iQ))).writeEscalationHandoff(X,{gateName:Q,iteration:z,consecutiveFailures:Z,detail:`${Q} hit PAUSE_LIMIT (${Z} consecutive failures)`});return process.stdout.write(`handoff: wrote ${K.path} (${K.bytes}B)
|
|
705
707
|
`),0}catch(q){return process.stderr.write(`handoff: ${q.message}
|
|
706
|
-
`),1}}function b1($){if($===void 0)return null;let Q=Number.parseInt($,10);return Number.isFinite(Q)&&Q>=0?Q:null}var
|
|
708
|
+
`),1}}function b1($){if($===void 0)return null;let Q=Number.parseInt($,10);return Number.isFinite(Q)&&Q>=0?Q:null}var $8,C1=`loki internal phase1-hooks <subcommand>
|
|
707
709
|
|
|
708
710
|
Subcommands:
|
|
709
711
|
reflect <iter> Persist structured findings + auto-learnings.
|
|
@@ -712,9 +714,9 @@ Subcommands:
|
|
|
712
714
|
|
|
713
715
|
This command is invoked by autonomy/run.sh between iterations. Users
|
|
714
716
|
should not run it directly -- run \`loki start\` instead.
|
|
715
|
-
`,
|
|
717
|
+
`,FZ;var Z8=L(()=>{C();F$();$8={fn:null};FZ=C1});$1();C();import{mkdirSync as Y8,readFileSync as M8,writeFileSync as T8}from"fs";import{dirname as O8,resolve as A8}from"path";var w8="https://registry.npmjs.org/loki-mode/latest",_8=86400000,I8=1500;function L8(){return A8(T$(),"cache","update-check.json")}function O$($){let Q=/^(\d+)\.(\d+)\.(\d+)$/.exec($.trim());if(!Q)return null;return[Number(Q[1]),Number(Q[2]),Number(Q[3])]}function P8($,Q){let Z=O$($),z=O$(Q);if(!Z||!z)return!1;let[X,q,K]=Z,[W,V,U]=z;if(X!==W)return X>W;if(q!==V)return q>V;return K>U}function j8(){if(process.env.LOKI_NO_UPDATE_CHECK==="1")return!0;if(process.env.CI)return!0;if(!process.stdout.isTTY)return!0;return!1}function F8($){try{let Q=M8($,"utf-8"),Z=JSON.parse(Q);if(typeof Z.checkedAt==="number"&&typeof Z.latest==="string"&&O$(Z.latest)!==null)return{checkedAt:Z.checkedAt,latest:Z.latest}}catch{}return null}function k8($,Q){try{Y8(O8($),{recursive:!0}),T8($,JSON.stringify(Q),"utf-8")}catch{}}async function R8(){try{let $=await fetch(w8,{signal:AbortSignal.timeout(I8),headers:{accept:"application/json"}});if(!$.ok)return null;let Q=await $.json();if(typeof Q.version==="string"&&O$(Q.version)!==null)return Q.version}catch{}return null}async function E8($=Date.now(),Q=R8,Z=L8()){let z=F8(Z);if(z&&$-z.checkedAt<_8)return z.latest;let X=await Q();if(X===null)return null;return k8(Z,{checkedAt:$,latest:X}),X}async function g1($,Q={}){try{if(j8())return;if(O$($)===null)return;let Z=await E8(Q.now,Q.fetcher,Q.cacheFile);if(Z===null)return;if(!P8(Z,$))return;(Q.write??((X)=>process.stderr.write(X)))(`A newer Loki Mode is available: ${Z} (you have ${$}). Update: bun install -g loki-mode (or npm i -g loki-mode)
|
|
716
718
|
`)}catch{}}async function m1(){let $=N$();return process.stdout.write(`Loki Mode v${$}
|
|
717
|
-
`),await g1($),0}d();c();C();import{readFileSync as
|
|
719
|
+
`),await g1($),0}d();c();C();import{readFileSync as C8,existsSync as b8}from"fs";import{resolve as h8}from"path";var y8=["claude","codex","cline","aider"];function p1(){let $=h8(P(),"state","provider");if(!b8($))return"";try{return C8($,"utf-8").trim()}catch{return""}}function v8($,Q){return $||Q||process.env.LOKI_PROVIDER||"claude"}function g8($){let Q=p1(),Z=v8($,Q);switch(process.stdout.write(`${k}Current Provider${J}
|
|
718
720
|
`),process.stdout.write(`
|
|
719
721
|
`),process.stdout.write(`${I}Provider:${J} ${Z}
|
|
720
722
|
`),Z){case"claude":process.stdout.write(`${S}Status:${J} Full features (subagents, parallel, MCP)
|
|
@@ -725,12 +727,12 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
725
727
|
`);return process.stdout.write(`
|
|
726
728
|
`),process.stdout.write(`Switch provider: ${I}loki provider set <name>${J}
|
|
727
729
|
`),process.stdout.write(`Available: ${I}loki provider list${J}
|
|
728
|
-
`),0}async function
|
|
730
|
+
`),0}async function m8(){let Q=p1()||process.env.LOKI_PROVIDER||"claude";process.stdout.write(`${k}Available Providers${J}
|
|
729
731
|
`),process.stdout.write(`
|
|
730
|
-
`);let Z=await Promise.all(
|
|
732
|
+
`);let Z=await Promise.all(y8.map(async(q)=>[q,await f(q)!==null])),z=new Map;for(let[q,K]of Z)z.set(q,K?`${S}installed${J}`:`${T}not installed${J}`);let X=[["claude","claude - Claude Code (Anthropic) "],["codex","codex - Codex CLI (OpenAI) "],["cline","cline - Cline (multi-provider) "],["aider","aider - Aider (terminal pair prog) "]];for(let[q,K]of X){let W=Q===q?` ${I}(current)${J}`:"";process.stdout.write(` ${K} ${z.get(q)}${W}
|
|
731
733
|
`)}return process.stdout.write(`
|
|
732
734
|
`),process.stdout.write(`Set provider: ${I}loki provider set <name>${J}
|
|
733
|
-
`),0}function
|
|
735
|
+
`),0}function f8(){return process.stdout.write(`${k}Loki Mode Provider Management${J}
|
|
734
736
|
`),process.stdout.write(`
|
|
735
737
|
`),process.stdout.write(`Usage: loki provider <command>
|
|
736
738
|
`),process.stdout.write(`
|
|
@@ -748,8 +750,8 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
748
750
|
`),process.stdout.write(` loki provider list
|
|
749
751
|
`),process.stdout.write(` loki provider info codex
|
|
750
752
|
`),process.stdout.write(` loki provider models
|
|
751
|
-
`),0}async function l1($){let Q=$[0]??"show",Z=$.slice(1);switch(Q){case"show":case"current":return
|
|
752
|
-
`))if(z.includes('"description"'))Z++;return Z}catch{return 0}}async function
|
|
753
|
+
`),0}async function l1($){let Q=$[0]??"show",Z=$.slice(1);switch(Q){case"show":case"current":return g8(Z[0]);case"list":return m8();case"set":case"info":case"models":return u8(["provider",Q,...Z]);default:return f8()}}async function u8($){let{run:Q}=await Promise.resolve().then(() => (d(),c1)),{resolve:Z}=await import("path"),{REPO_ROOT:z}=await Promise.resolve().then(() => (C(),v1)),X=Z(z,"autonomy","loki"),q=await Q([X,...$],{env:{LOKI_LEGACY_BASH:"1"},timeoutMs:3600000});return process.stdout.write(q.stdout),process.stderr.write(q.stderr),q.exitCode}c();C();V$();import{existsSync as d1,readFileSync as p8}from"fs";import{resolve as W$}from"path";import{mkdir as l8}from"fs/promises";var w$=W$(T$(),"learnings");function Z1($){if(!d1($))return 0;try{let Q=p8($,"utf-8"),Z=0;for(let z of Q.split(`
|
|
754
|
+
`))if(z.includes('"description"'))Z++;return Z}catch{return 0}}async function d8(){await l8(w$,{recursive:!0});let $=Z1(W$(w$,"patterns.jsonl")),Q=Z1(W$(w$,"mistakes.jsonl")),Z=Z1(W$(w$,"successes.jsonl"));return process.stdout.write(`${k}Cross-Project Learnings${J}
|
|
753
755
|
`),process.stdout.write(`
|
|
754
756
|
`),process.stdout.write(` Patterns: ${S}${$}${J}
|
|
755
757
|
`),process.stdout.write(` Mistakes: ${_}${Q}${J}
|
|
@@ -758,7 +760,7 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
758
760
|
`),process.stdout.write(`Location: ${w$}
|
|
759
761
|
`),process.stdout.write(`
|
|
760
762
|
`),process.stdout.write(`Use 'loki memory show <type>' to view entries
|
|
761
|
-
`),0}async function
|
|
763
|
+
`),0}async function o8($){if($){let z=`
|
|
762
764
|
try:
|
|
763
765
|
from memory.layers import IndexLayer
|
|
764
766
|
layer = IndexLayer('.loki/memory')
|
|
@@ -770,10 +772,10 @@ except Exception as e:
|
|
|
770
772
|
print(f'Error: {e}')
|
|
771
773
|
`.trim(),X=await z$(z,{cwd:h});return process.stdout.write(X.stdout),0}let Q=W$(P(),"memory","index.json");if(!d1(Q))return process.stdout.write(`No index found
|
|
772
774
|
`),0;let Z=await z$(`import json, sys; sys.stdout.write(json.dumps(json.load(open(${JSON.stringify(Q)})), indent=4) + "\\n")`);if(Z.exitCode!==0)return process.stdout.write(`No index found
|
|
773
|
-
`),0;return process.stdout.write(Z.stdout),0}async function o1($){switch($[0]??"list"){case"list":case"ls":return
|
|
774
|
-
`)){let K=q.replace(/\r$/,"");if(K==="TELEMETRY_DISABLED=true")Q=!0;if(K==="TELEMETRY_ENABLED=true")Z=!0}}}catch{}if(Q)return!1;if($==="on"||Z)return!0;return!1}var S$=!1;function
|
|
775
|
+
`),0;return process.stdout.write(Z.stdout),0}async function o1($){switch($[0]??"list"){case"list":case"ls":return d8();case"index":return o8($[1]==="rebuild");default:{let Z=W$(h,"autonomy","loki"),z=3600000,X=Bun.spawn({cmd:[Z,"memory",...$],stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,LOKI_LEGACY_BASH:"1"}}),q=setTimeout(()=>{try{X.kill("SIGKILL")}catch{}},3600000);try{return await X.exited}finally{clearTimeout(q)}}}}C();V$();d();import{resolve as n8,join as a8}from"path";import{existsSync as z1,readFileSync as s8}from"fs";import{homedir as r8}from"os";import{spawnSync as r1}from"child_process";var t1=3000;function t8(){let $=(process.env.LOKI_TELEMETRY??"").toLowerCase();if($==="off")return!1;if(process.env.LOKI_TELEMETRY_DISABLED==="true")return!1;if(process.env.DO_NOT_TRACK==="1")return!1;let Q=!1,Z=!1;try{let z=a8(r8(),".loki","config");if(z1(z)){let X=s8(z,"utf8");for(let q of X.split(`
|
|
776
|
+
`)){let K=q.replace(/\r$/,"");if(K==="TELEMETRY_DISABLED=true")Q=!0;if(K==="TELEMETRY_ENABLED=true")Z=!0}}}catch{}if(Q)return!1;if($==="on"||Z)return!0;return!1}var S$=!1;function i8(){return n8(h,"autonomy","lib","crash_capture.py")}function e8($,Q){let Z=[$,"--error-class",Q.errorClass,"--message",Q.message];if(Q.stack!==void 0)Z.push("--stack",Q.stack);if(Q.rarvPhase!==void 0)Z.push("--rarv-phase",Q.rarvPhase);if(Q.exitCode!==void 0)Z.push("--exit-code",String(Q.exitCode));if(Q.frictionKind!==void 0)Z.push("--friction-kind",Q.frictionKind);return Z.push("--target-dir",Q.targetDir??process.cwd()),Z}function $3(){if(z1("/opt/homebrew/bin/python3.12"))return"/opt/homebrew/bin/python3.12";for(let Q of["python3.12","python3"])try{let Z=r1("sh",["-c",`command -v ${Q}`],{timeout:t1,encoding:"utf8"});if(Z.status===0){let z=(Z.stdout||"").trim();if(z)return z}}catch{}return null}function n1($){try{if(!t8())return;let Q=i8();if(!z1(Q))return;let Z=$3();if(!Z)return;let z=e8(Q,$);r1(Z,z,{timeout:t1,stdio:"ignore"})}catch{}}function a1($,Q){if($ instanceof Error){let z={errorClass:$.name&&$.name.length>0?$.name:Q,message:$.message};if($.stack)z.stack=$.stack;return z}return{errorClass:Q,message:String($)}}var s1=!1;function i1(){if(s1)return;s1=!0,process.on("uncaughtException",($)=>{if(!S$){S$=!0;let Q=a1($,"UncaughtException");n1({errorClass:Q.errorClass,message:Q.message,...Q.stack!==void 0?{stack:Q.stack}:{},exitCode:1})}try{process.stderr.write(`${$&&$.stack||String($)}
|
|
775
777
|
`)}catch{}process.exit(1)}),process.on("unhandledRejection",($)=>{if(!S$){S$=!0;let Q=a1($,"UnhandledRejection");n1({errorClass:Q.errorClass,message:Q.message,...Q.stack!==void 0?{stack:Q.stack}:{},exitCode:1})}try{let Q=$ instanceof Error?$.stack||$.message:String($);process.stderr.write(`Unhandled promise rejection: ${Q}
|
|
776
|
-
`)}catch{}process.exit(1)})}var
|
|
778
|
+
`)}catch{}process.exit(1)})}var z8=`Loki Mode (TypeScript port, Phase 2 of bash->Bun migration)
|
|
777
779
|
|
|
778
780
|
Usage: loki <command> [args...]
|
|
779
781
|
|
|
@@ -795,12 +797,12 @@ Phase 2 ported (Bun-native, fast):
|
|
|
795
797
|
|
|
796
798
|
All other commands fall through to the bash CLI (autonomy/loki).
|
|
797
799
|
Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
798
|
-
`;function
|
|
799
|
-
`)}async function
|
|
800
|
+
`;function kZ(){let $=process.env.LOKI_LEGACY_BASH;if($===void 0)return;let Q=$.trim().toLowerCase();if(Q!=="1"&&Q!=="true"&&Q!=="yes"&&Q!=="on")return;if(process.env.LOKI_SUPPRESS_BUN_DIRECT_WARN==="1")return;process.stderr.write(`warning: LOKI_LEGACY_BASH is set, but you are running the Bun runtime directly (src/cli.ts). The env var only takes effect via the bin/loki shim, which dispatches between Bun and bash. Behavior is unchanged; this message is informational.
|
|
801
|
+
`)}async function RZ($){kZ();let Q=$[0],Z=$.slice(1);switch(Q){case void 0:case"help":case"--help":case"-h":return process.stdout.write(z8),0;case"version":case"--version":case"-v":return await m1();case"provider":return l1(Z);case"memory":return o1(Z);case"status":{let{runStatus:z}=await Promise.resolve().then(() => (V0(),J0));return z(Z)}case"stats":{let{runStats:z}=await Promise.resolve().then(() => (M0(),Y0));return z(Z)}case"doctor":{let{runDoctor:z}=await Promise.resolve().then(() => (F0(),j0));return z(Z)}case"kpis":{let{runKpis:z}=await Promise.resolve().then(() => (M1(),Y1));return z(Z,{aliasOf:"kpis"})}case"report":{if(Z.find((q)=>!q.startsWith("-"))==="kpis"){let{runKpis:q}=await Promise.resolve().then(() => (M1(),Y1)),K=!1,W=Z.filter((V)=>{if(!K&&V==="kpis")return K=!0,!1;return!0});return q(W)}let{delegateToBash:X}=await Promise.resolve().then(() => (g0(),v0));return X(["report",...Z])}case"trust":{let{runTrust:z}=await Promise.resolve().then(() => (n0(),o0));return z(Z)}case"rollback":{let{runRollback:z}=await Promise.resolve().then(() => (wQ(),AQ));return z(Z)}case"proof":case"receipt":{let{runProof:z}=await Promise.resolve().then(() => (jQ(),PQ));return z(Z)}case"crash":{let{runCrash:z}=await Promise.resolve().then(() => (SQ(),NQ));return z(Z)}case"wiki":{let{runWiki:z}=await Promise.resolve().then(() => (yQ(),hQ));return z(Z)}case"internal":{let z=Z[0];if(!z||z==="--help"||z==="-h"||z==="help"){let q=["loki internal -- runtime hooks driven by autonomy/run.sh","","Subcommands:"," phase1-hooks Persist structured findings, run override council,"," append learnings, and write the escalation handoff"," doc once per iteration. Driven by run.sh; not"," intended for direct invocation.","","Phase 1 (RARV-C closure) env vars:"," LOKI_INJECT_FINDINGS=1 Persist structured reviewer findings to"," .loki/state/findings-<iter>.json so the"," next iteration can address them."," LOKI_OVERRIDE_COUNCIL=1 Allow a 3-LLM override panel to lift a"," BLOCK when counter-evidence is presented."," See LOKI_OVERRIDE_JUDGES (csv),"," LOKI_OVERRIDE_PANEL_SIZE,"," LOKI_OVERRIDE_REAL_JUDGE."," LOKI_AUTO_LEARNINGS=1 Append failure rootcauses to"," .loki/state/relevant-learnings.json via"," the episodic memory bridge."," LOKI_HANDOFF_MD=1 Write a structured human handoff doc to"," .loki/escalations/<ts>.md before PAUSE.","","All four are default-on as of v7.5.3. Set to 0 to disable.","Reference: CHANGELOG.md (search 'Phase 1') and skills/healing.md.","","These commands are wired into the autonomous loop and may change","without notice. Do not script against them.",""].join(`
|
|
800
802
|
`);return process.stdout.write(`${q}
|
|
801
|
-
`),0}if(z==="phase1-hooks"){let{runInternalPhase1Hooks:q}=await Promise.resolve().then(() => (
|
|
803
|
+
`),0}if(z==="phase1-hooks"){let{runInternalPhase1Hooks:q}=await Promise.resolve().then(() => (Z8(),Q8));return q(Z.slice(1))}return process.stderr.write(`Unknown internal subcommand: ${z}
|
|
802
804
|
`),process.stderr.write(`Run 'loki internal --help' for the supported list.
|
|
803
805
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
804
|
-
`),process.stderr.write(
|
|
806
|
+
`),process.stderr.write(z8),2}}i1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var EZ=await RZ(Bun.argv.slice(2));process.exit(EZ);
|
|
805
807
|
|
|
806
|
-
//# debugId=
|
|
808
|
+
//# debugId=48A34AFD97DA2FEB64756E2164756E21
|
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": "7.104.
|
|
4
|
+
"version": "7.104.2",
|
|
5
5
|
"description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 8 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -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": "7.104.
|
|
5
|
+
"version": "7.104.2",
|
|
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",
|