loki-mode 8.2.0 → 8.3.1

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/README.md CHANGED
@@ -15,12 +15,67 @@ _The free, source-available autonomous coding agent by [Autonomi](https://www.au
15
15
 
16
16
  [Website](https://www.autonomi.dev/) | [Documentation](wiki/Home.md) | [Installation](docs/INSTALLATION.md) | [Changelog](CHANGELOG.md) | [Purple Lab -- deprecated v7.44.0](#purple-lab)
17
17
 
18
- **Current release: v8.2.0**
18
+ **Current release: v8.3.1**
19
19
 
20
20
  </div>
21
21
 
22
22
  ---
23
23
 
24
+ ## See the receipt before you install anything
25
+
26
+ Every agent claims it finished. Ours hands you an artifact you can check:
27
+
28
+ ```bash
29
+ npx loki-mode tour # no install, no API key, no spend, no network
30
+ ```
31
+
32
+ That prints a real Evidence Receipt from a past build. Note what it says:
33
+
34
+ ```
35
+ Headline: VERIFIED WITH GAPS
36
+
37
+ | Fact | Value |
38
+ | Files changed | 8 |
39
+ | Diff sha256 | c2be6fff3e774c387f276277b25fc424f07b667… |
40
+ | Tests | verified (node-test) |
41
+ | Build | not_run |
42
+ | Security | findings |
43
+ | Cost | $10.3218 |
44
+ ```
45
+
46
+ **"WITH GAPS" is the point.** Build was not run. Security has findings. The
47
+ receipt says so on its own front page, and separates deterministic FACTS -- the
48
+ diff hash, the test result, the cost -- from AI ASSESSMENTS, because only four
49
+ of the eight quality gates are agent-independent and a receipt that implied
50
+ otherwise would be marketing.
51
+
52
+ Recompute the diff hash yourself and check it matches. That is the whole idea:
53
+ you are not asked to trust the agent's self-report.
54
+
55
+ Self-reported completion is the failure users actually hit. A survey of the
56
+ open issue trackers of seven coding harnesses (OpenHands, Cline, Aider,
57
+ SWE-agent, Roo-Code, OpenCode, Continue) found the recurring complaint is the
58
+ agent silently not doing the work -- "always stuck at Preparing write"
59
+ ([opencode#11112](https://github.com/anomalyco/opencode/issues/11112), 76
60
+ comments), "Continue not making changes to code"
61
+ ([continue#7143](https://github.com/continuedev/continue/issues/7143)), "Agent
62
+ does not execute functions"
63
+ ([continue#5696](https://github.com/continuedev/continue/issues/5696)). None of
64
+ those seven publishes a machine-checkable completion artifact.
65
+
66
+ We have not audited the closed-source products (Cursor, Devin, Replit Agent)
67
+ feature by feature, so treat this as "unclaimed as far as we can verify" rather
68
+ than a proven first. The receipt stands on its own either way: run the tour and
69
+ check the hash.
70
+
71
+ **Evaluating this against something else?** [docs/EVALUATING.md](docs/EVALUATING.md)
72
+ puts a runnable command next to every claim we make, and states plainly what we
73
+ do not have (no enterprise case studies, no independent benchmark placement, and
74
+ generation is not air-gapped). It ends with the one question worth asking any
75
+ agent vendor, including us.
76
+
77
+ ---
78
+
24
79
  > **How it works:** Drop a spec -- a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief. Loki Mode classifies complexity (`run.sh:detect_complexity()`), assembles an agent team from 41 specialized agent roles across 8 domains - prompt-defined specifications the orchestrator adopts per phase, with parallel review (blind council) and optional worktree streams on Claude Code, sequential on other providers - and runs autonomous RARV cycles (Reason - Act - Reflect - Verify, see `run.sh:run_autonomous()`) with 8 quality gates (see `skills/quality-gates.md`). Code is not "done" until it passes automated verification. Output is a Git repo with source, tests, configs, and audit logs.
25
80
 
26
81
  ---
package/VERSION CHANGED
@@ -1 +1 @@
1
- 8.2.0
1
+ 8.3.1
package/autonomy/loki CHANGED
@@ -10772,6 +10772,15 @@ cmd_doctor() {
10772
10772
 
10773
10773
  local pass_count=0
10774
10774
  local fail_count=0
10775
+ # FUNNEL FIX (v8.2.x): collect the NAME + FIX of every hard failure, not just
10776
+ # a count. A first-time user on a bare machine sees 15 warnings (sentrux, GPG
10777
+ # signing, bash 4, Bun, python3.12, truecolor, inline-image probe -- all
10778
+ # OPTIONAL) around 2 real blockers, then a summary that says only "Some
10779
+ # required prerequisites are missing" without naming them. That is the point
10780
+ # where someone closes the terminal. Naming the blockers and their exact
10781
+ # install command turns a wall of yellow into a two-line to-do.
10782
+ local _doctor_blockers=""
10783
+ _doctor_block() { _doctor_blockers="${_doctor_blockers}\n - $1"; }
10775
10784
  local warn_count=0
10776
10785
 
10777
10786
  # Helper: check command exists and optionally check version
@@ -10784,6 +10793,7 @@ cmd_doctor() {
10784
10793
  if ! command -v "$cmd" &> /dev/null; then
10785
10794
  if [ "$required" = "required" ]; then
10786
10795
  echo -e " ${RED}FAIL${NC} $name - not found"
10796
+ _doctor_block "$name is not installed"
10787
10797
  fail_count=$((fail_count + 1))
10788
10798
  elif [ "$required" = "recommended" ]; then
10789
10799
  echo -e " ${YELLOW}WARN${NC} $name - not found (recommended)"
@@ -10849,6 +10859,7 @@ cmd_doctor() {
10849
10859
  { [ "$cur_major" -eq "$min_major" ] 2>/dev/null && [ "$cur_minor" -lt "$min_minor" ] 2>/dev/null; }; then
10850
10860
  if [ "$required" = "required" ]; then
10851
10861
  echo -e " ${RED}FAIL${NC} $name$version_display - requires >= $min_version"
10862
+ _doctor_block "$name must be >= $min_version"
10852
10863
  fail_count=$((fail_count + 1))
10853
10864
  else
10854
10865
  echo -e " ${YELLOW}WARN${NC} $name$version_display - recommended >= $min_version"
@@ -10920,6 +10931,7 @@ cmd_doctor() {
10920
10931
  else
10921
10932
  echo -e " ${RED}FAIL${NC} No AI provider CLI installed -- at least one is required"
10922
10933
  echo -e " ${YELLOW}Install: npm install -g @anthropic-ai/claude-code${NC}"
10934
+ _doctor_block "No AI provider CLI. Fix: npm install -g @anthropic-ai/claude-code"
10923
10935
  fail_count=$((fail_count + 1))
10924
10936
  # v7.29.0: on a TTY (non-json), append the consent-gated install offer.
10925
10937
  # In report mode the helper is a no-op on non-TTY/CI, so the doctor
@@ -11024,6 +11036,7 @@ except Exception:
11024
11036
  _target=$(readlink "$sdir" 2>/dev/null || echo "unknown")
11025
11037
  echo -e " ${RED}FAIL${NC} $sname ${DIM}(broken symlink -> $_target)${NC}"
11026
11038
  echo -e " ${YELLOW}Fix: loki setup-skill${NC}"
11039
+ _doctor_block "$sname is a broken symlink. Fix: loki setup-skill"
11027
11040
  fail_count=$((fail_count + 1))
11028
11041
  else
11029
11042
  echo -e " ${YELLOW}WARN${NC} $sname ${DIM}(not found - run 'loki setup-skill')${NC}"
@@ -11187,6 +11200,7 @@ except Exception:
11187
11200
  if [ -n "$disk_avail" ] && [ "$disk_avail" -gt 0 ] 2>/dev/null; then
11188
11201
  if [ "$disk_avail" -lt 1 ]; then
11189
11202
  echo -e " ${RED}FAIL${NC} Disk space: ${disk_avail}GB available (need >= 1GB)"
11203
+ _doctor_block "Free up disk: ${disk_avail}GB available, need >= 1GB"
11190
11204
  fail_count=$((fail_count + 1))
11191
11205
  elif [ "$disk_avail" -lt 5 ]; then
11192
11206
  echo -e " ${YELLOW}WARN${NC} Disk space: ${disk_avail}GB available (low)"
@@ -11289,8 +11303,11 @@ except Exception:
11289
11303
  echo ""
11290
11304
 
11291
11305
  if [ "$fail_count" -gt 0 ]; then
11292
- echo -e "${RED}Some required prerequisites are missing.${NC}"
11293
- echo "Install missing dependencies and run 'loki doctor' again."
11306
+ echo -e "${RED}Blocking ($fail_count). Everything else above is optional.${NC}"
11307
+ printf '%b\n' "$_doctor_blockers"
11308
+ echo ""
11309
+ echo "Then re-run: loki doctor"
11310
+ echo "Meanwhile 'loki tour' works right now -- no provider, no key, no spend."
11294
11311
  return 1
11295
11312
  elif [ "$warn_count" -gt 0 ]; then
11296
11313
  echo -e "${YELLOW}All required checks passed with some warnings.${NC}"
@@ -19104,7 +19121,7 @@ $(cat "$f" 2>/dev/null)
19104
19121
 
19105
19122
  # --- Tally results ---
19106
19123
  local count_critical=0 count_high=0 count_medium=0 count_low=0 count_info=0
19107
- for f in "${findings[@]}"; do
19124
+ for f in "${findings[@]+"${findings[@]}"}"; do
19108
19125
  local sev
19109
19126
  sev=$(echo "$f" | cut -d'|' -f3)
19110
19127
  case "$sev" in
@@ -19126,7 +19143,7 @@ $(cat "$f" 2>/dev/null)
19126
19143
  if [ "$review_format" = "json" ]; then
19127
19144
  local json_findings="["
19128
19145
  local first=true
19129
- for f in "${findings[@]}"; do
19146
+ for f in "${findings[@]+"${findings[@]}"}"; do
19130
19147
  local f_file f_line f_sev f_cat f_finding f_suggestion
19131
19148
  f_file=$(echo "$f" | cut -d'|' -f1)
19132
19149
  f_line=$(echo "$f" | cut -d'|' -f2)
@@ -19155,7 +19172,7 @@ $(cat "$f" 2>/dev/null)
19155
19172
  # Group by severity
19156
19173
  for sev_name in CRITICAL HIGH MEDIUM LOW INFO; do
19157
19174
  local printed_header=false
19158
- for f in "${findings[@]}"; do
19175
+ for f in "${findings[@]+"${findings[@]}"}"; do
19159
19176
  local f_sev
19160
19177
  f_sev=$(echo "$f" | cut -d'|' -f3)
19161
19178
  [ "$f_sev" != "$sev_name" ] && continue
@@ -30081,7 +30098,7 @@ TEST_SUGGEST_PY
30081
30098
 
30082
30099
  # --- Tally findings ---
30083
30100
  local count_critical=0 count_high=0 count_medium=0 count_low=0 count_info=0
30084
- for f in "${findings[@]}"; do
30101
+ for f in "${findings[@]+"${findings[@]}"}"; do
30085
30102
  local sev
30086
30103
  sev=$(echo "$f" | cut -d'|' -f3)
30087
30104
  case "$sev" in
@@ -30097,7 +30114,7 @@ TEST_SUGGEST_PY
30097
30114
  # Determine exit code based on --fail-on threshold
30098
30115
  local exit_code=0
30099
30116
  if [ "$fail_threshold" -lt 99 ]; then
30100
- for f in "${findings[@]}"; do
30117
+ for f in "${findings[@]+"${findings[@]}"}"; do
30101
30118
  local sev sev_num
30102
30119
  sev=$(echo "$f" | cut -d'|' -f3)
30103
30120
  sev_num=$(_ci_sev_level "$sev")
@@ -30117,7 +30134,7 @@ TEST_SUGGEST_PY
30117
30134
  if [ "$ci_format" = "json" ]; then
30118
30135
  # JSON output via python for proper escaping
30119
30136
  export LOKI_CI_JSON_FINDINGS=""
30120
- for f in "${findings[@]}"; do
30137
+ for f in "${findings[@]+"${findings[@]}"}"; do
30121
30138
  LOKI_CI_JSON_FINDINGS+="${f}"$'\n'
30122
30139
  done
30123
30140
  export LOKI_CI_JSON_META="ci_env=${ci_env}|pr=${ci_pr_number}|ts=${report_timestamp}|files=${file_count}|exit=${exit_code}"
@@ -30199,7 +30216,7 @@ CI_JSON_OUT
30199
30216
  echo ""
30200
30217
  for sev_name in CRITICAL HIGH MEDIUM LOW INFO; do
30201
30218
  local has_sev=false
30202
- for f in "${findings[@]}"; do
30219
+ for f in "${findings[@]+"${findings[@]}"}"; do
30203
30220
  local f_sev
30204
30221
  f_sev=$(echo "$f" | cut -d'|' -f3)
30205
30222
  [ "$f_sev" != "$sev_name" ] && continue
@@ -30259,7 +30276,7 @@ for t in tests:
30259
30276
  else
30260
30277
  for sev_name in CRITICAL HIGH MEDIUM LOW INFO; do
30261
30278
  local printed_header=false
30262
- for f in "${findings[@]}"; do
30279
+ for f in "${findings[@]+"${findings[@]}"}"; do
30263
30280
  local f_sev
30264
30281
  f_sev=$(echo "$f" | cut -d'|' -f3)
30265
30282
  [ "$f_sev" != "$sev_name" ] && continue
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "8.2.0"
10
+ __version__ = "8.3.1"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -1,6 +1,13 @@
1
1
  # Autonomous Coding Agents Comparison (2025-2026)
2
2
 
3
- > Last Updated: January 25, 2026 (v2.36.9)
3
+ > **STALE. Last updated January 25, 2026 against v2.36.9; the current release is
4
+ > v8.2.0.** Roughly six months and thirty releases of drift, and every cell in
5
+ > the grids below is a subjective grade assigned by the vendor being graded --
6
+ > which is exactly the kind of comparison a serious evaluator discounts.
7
+ >
8
+ > For claims you can actually check, see **[EVALUATING.md](EVALUATING.md)**: a
9
+ > runnable command next to every assertion, plus an explicit list of what we do
10
+ > not have. This file is kept for historical reference only.
4
11
  >
5
12
  > A comprehensive comparison of Loki Mode against major autonomous coding agents and AI IDEs in the market.
6
13
  > Deep-dive comparisons validated by Opus feedback loops.
@@ -0,0 +1,142 @@
1
+ # Evaluating Loki Mode
2
+
3
+ For someone deciding whether to trust an autonomous coding agent with a real
4
+ codebase. Every claim below has a command next to it. Run them; do not take our
5
+ word for it.
6
+
7
+ We have deliberately not written a feature grid scoring ourselves against ten
8
+ competitors. Those grids are written by the vendor being scored, the criteria
9
+ are chosen by the vendor, and no reader can check a single cell. This page only
10
+ makes claims you can falsify in a terminal.
11
+
12
+ ---
13
+
14
+ ## 1. The agent hands you a receipt, and it admits what it did not verify
15
+
16
+ ```bash
17
+ npx loki-mode tour # no install, no API key, no spend, no network
18
+ ```
19
+
20
+ Output includes:
21
+
22
+ ```
23
+ Headline: VERIFIED WITH GAPS
24
+
25
+ | Files changed | 8 |
26
+ | Diff sha256 | c2be6fff3e774c387f276277b25fc424f07b667… |
27
+ | Tests | verified (node-test) |
28
+ | Build | not_run |
29
+ | Security | findings |
30
+ | Cost | $10.3218 |
31
+ ```
32
+
33
+ **What to notice:** the headline is not "SUCCESS". Build was not run. Security
34
+ has findings. The receipt says so on its own front page.
35
+
36
+ **Why that is the product.** Every coding agent reports its own completion, and
37
+ self-reporting is the thing they are structurally worst at. The receipt
38
+ separates deterministic FACTS (diff hash, test result, cost) from AI
39
+ ASSESSMENTS, because only four of our eight quality gates are agent-independent
40
+ and a receipt implying otherwise would be marketing.
41
+
42
+ **Check it yourself:** recompute the diff sha256 over the same range and confirm
43
+ it matches. If it does not, the receipt is worthless and you should not use us.
44
+
45
+ ---
46
+
47
+ ## 2. Verification runs air-gapped
48
+
49
+ Deterministic verification makes zero network calls, so it runs inside a
50
+ perimeter on code that may never leave the building.
51
+
52
+ ```bash
53
+ bash tests/test-airgap-verify.sh
54
+ ```
55
+
56
+ That test blackholes every proxy variable, strips the environment, and asserts a
57
+ real verdict still comes back. Measured: **8.43 ms**.
58
+
59
+ **Scope, stated honestly:** verification is air-gapped. **Generation is not.**
60
+ Every provider we ship calls a hosted API, and local-weight generation needs
61
+ models you would supply. We are not claiming the generation half, and any vendor
62
+ who claims a fully air-gapped LLM agent without shipping weights is worth a
63
+ second question.
64
+
65
+ ---
66
+
67
+ ## 3. On an existing codebase, the read-only path is genuinely read-only
68
+
69
+ Brownfield is the harder problem, and the reason to distrust an agent near it is
70
+ obvious. So the entry point writes nothing:
71
+
72
+ ```bash
73
+ loki modernize heal ./your-repo --assess
74
+ git status # clean. no scratch files, no .loki/, no commits.
75
+ ```
76
+
77
+ **Enforced, not promised:**
78
+
79
+ ```bash
80
+ bash tests/test-brownfield-assess-readonly.sh
81
+ ```
82
+
83
+ That test hashes every file before and after, compares HEAD, and requires a
84
+ clean working tree. It is content-addressed, so it does not care *how* a write
85
+ might happen.
86
+
87
+ ---
88
+
89
+ ## 4. The harness is model-invariant (and we do not overclaim it)
90
+
91
+ ```bash
92
+ cat benchmarks/results/cross-model-eval.json
93
+ ```
94
+
95
+ - **Claimed:** the same gates run, the same acceptance is checked, and the same
96
+ receipt semantics apply regardless of which model is behind it.
97
+ - **Explicitly NOT claimed:** identical quality or identical speed across
98
+ models. That is not deliverable and we do not assert it.
99
+
100
+ Measured runs are in that file with wall-clock and iteration counts. Two runs is
101
+ two runs; it is not a benchmark suite, and the file says so.
102
+
103
+ ---
104
+
105
+ ## 5. Verification is fast enough to embed
106
+
107
+ ```bash
108
+ python3 autonomy/lib/fast_verify.py --path . --diff-base HEAD~1
109
+ ```
110
+
111
+ Measured on this repository, 1,932 tracked source files: **11,040 ms before,
112
+ 19 ms diff-scoped** (298 ms cold, 87 ms warm). That is the difference between a
113
+ check you run at the end and a check something else can call as a dependency.
114
+
115
+ ---
116
+
117
+ ## What we do not have
118
+
119
+ Stating this plainly, because you will find it out anyway and it is cheaper for
120
+ both of us if you find it here.
121
+
122
+ - **No published enterprise case studies.** We have adoption signal (fork ratio
123
+ well above the norm for a tool this size) but no named enterprise references.
124
+ - **No independent third-party benchmark placement.** The SWE-bench Verified
125
+ leaderboard is months stale and every entry on it is self-reported, ours would
126
+ be too.
127
+ - **No audit of the closed-source products.** We have verified that seven open
128
+ harnesses (OpenHands, Cline, Aider, SWE-agent, Roo-Code, OpenCode, Continue)
129
+ publish no machine-checkable completion artifact. Cursor, Devin, Replit Agent
130
+ and Claude Code we have **not** audited feature by feature, so treat the
131
+ receipt as "unclaimed as far as we can verify", not as a proven first.
132
+ - **Generation is not air-gapped.** See section 2.
133
+
134
+ ---
135
+
136
+ ## The one question worth asking any agent vendor
137
+
138
+ > When your agent says it finished, what artifact can I check that does not come
139
+ > from the agent's own narrative?
140
+
141
+ Ours is the Evidence Receipt, and section 1 is a two-minute test of whether the
142
+ answer holds up. Ask the same question everywhere else.
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var S_=Object.create;var{getPrototypeOf:y_,defineProperty:oK,getOwnPropertyNames:b_}=Object;var __=Object.prototype.hasOwnProperty;function f_(Z){return this[Z]}var h_,v_,g_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?h_??=new WeakMap:v_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?S_(y_(Z)):{};let K=X||!Z||!Z.__esModule?oK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of b_(Z))if(!__.call(K,$))oK(K,$,{get:f_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var VQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var m_=(Z)=>Z;function u_(Z,X){this[Z]=m_.bind(null,X)}var c0=(Z,X)=>{for(var Q in X)oK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:u_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var t0=import.meta.require;var IO={};c0(IO,{lokiDir:()=>j0,homeLokiDir:()=>I4,findRepoRootForVersion:()=>tK,REPO_ROOT:()=>Q8});import{resolve as s7,dirname as rK}from"path";import{fileURLToPath as p_}from"url";import{existsSync as qQ}from"fs";import{homedir as d_}from"os";function c_(){let Z=EO;for(let X=0;X<6;X++){if(qQ(s7(Z,"VERSION"))&&qQ(s7(Z,"autonomy/run.sh")))return Z;let Q=rK(Z);if(Q===Z)break;Z=Q}return s7(EO,"..","..","..")}function tK(Z){let X=Z;for(let Q=0;Q<6;Q++){if(qQ(s7(X,"VERSION"))&&qQ(s7(X,"autonomy/run.sh")))return X;let Y=rK(X);if(Y===X)break;X=Y}return s7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??s7(process.cwd(),".loki")}function I4(){return s7(d_(),".loki")}var EO,Q8;var G8=p(()=>{EO=rK(p_(import.meta.url));Q8=c_()});import{readFileSync as l_}from"fs";import{resolve as i_,dirname as a_}from"path";import{fileURLToPath as s_}from"url";function _3(){if(f5!==null)return f5;let Z="8.2.0";if(typeof Z==="string"&&Z.length>0)return f5=Z,f5;try{let X=a_(s_(import.meta.url)),Q=tK(X);f5=l_(i_(Q,"VERSION"),"utf-8").trim()}catch{f5="unknown"}return f5}var f5=null;var GQ=p(()=>{G8()});var xO={};c0(xO,{runOrThrow:()=>qf,run:()=>E0,readStreamCapped:()=>HQ,commandVersion:()=>Hf,commandExists:()=>X9,ShellError:()=>eK,MAX_STDOUT_BYTES:()=>kO});async function HQ(Z,X=kO){let Q=Z.getReader(),Y=new TextDecoder,J="",z=0;try{while(z<X){let{done:K,value:$}=await Q.read();if(K)break;if(!$)continue;if(z+=$.byteLength,z>X){let W=$.byteLength-(z-X);J+=Y.decode($.subarray(0,W),{stream:!0});break}J+=Y.decode($,{stream:!0})}J+=Y.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return J}async function E0(Z,X={}){let Q=Bun.spawn({cmd:[...Z],stdout:"pipe",stderr:"pipe",env:X.env?{...process.env,...X.env}:process.env,cwd:X.cwd}),Y,J;if(X.timeoutMs&&X.timeoutMs>0)Y=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}J=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},X.timeoutMs);try{let[z,K,$]=await Promise.all([HQ(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:z,stderr:K,exitCode:$}}finally{if(Y)clearTimeout(Y);if(J)clearTimeout(J)}}async function qf(Z,X={}){let Q=await E0(Z,X);if(Q.exitCode!==0)throw new eK(`command failed (${Q.exitCode}): ${Z.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function X9(Z){let X=Gf(Z),Q=await E0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Gf(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function Hf(Z,X="--version"){if(!await X9(Z))return null;let Y=await E0([Z,X],{timeoutMs:5000});if(Y.exitCode!==0)return null;return((Y.stdout||Y.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var kO=16777216,eK;var k9=p(()=>{eK=class eK extends Error{message;exitCode;stdout;stderr;constructor(Z,X,Q,Y){super(Z);this.message=Z;this.exitCode=X;this.stdout=Q;this.stderr=Y;this.name="ShellError"}}});function n7(Z){return Uf?"":Z}var Uf,M0,k8,l0,dW0,a0,H8,Q9,g;var S6=p(()=>{Uf=(process.env.NO_COLOR??"").length>0;M0=n7("\x1B[0;31m"),k8=n7("\x1B[0;32m"),l0=n7("\x1B[1;33m"),dW0=n7("\x1B[0;34m"),a0=n7("\x1B[0;36m"),H8=n7("\x1B[1m"),Q9=n7("\x1B[2m"),g=n7("\x1B[0m")});import{existsSync as Ff}from"fs";async function F7(){if(R4!==void 0)return R4;let Z="/opt/homebrew/bin/python3.12";if(Ff(Z))return R4=Z,Z;let X=await X9("python3.12");if(X)return R4=X,X;let Q=await X9("python3");return R4=Q,Q}async function D7(Z,X={}){let Q=await F7();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return E0([Q,"-c",Z],X)}var R4;var o7=p(()=>{k9()});var rO={};c0(rO,{runStatus:()=>tf});import{existsSync as Y9,readFileSync as h3,readdirSync as dO,statSync as cO}from"fs";import{resolve as h8,basename as pf}from"path";import{homedir as df}from"os";function lO(Z){let X=Math.trunc(Z);if(X>=1e6)return`${(Math.trunc(X/1e6*10)/10).toFixed(1)}M`;if(X>=1000)return`${(Math.trunc(X/1000*10)/10).toFixed(1)}K`;return String(X)}function iO(Z,X,Q){if(X===0)return null;let Y=Math.trunc(Z*100/X),J=Math.trunc(Z*BQ/X);if(J>BQ)J=BQ;let z=BQ-J,K=k8;if(Y>=80)K=M0;else if(Y>=50)K=l0;let $="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,z)),W=lO(Z),V=lO(X);return` ${H8}${Q}${g} ${K}[${$}]${g} ${Y}% (${W} / ${V})`}async function lf(){if(await X9("jq"))return!0;return process.stdout.write(`${M0}Error: jq is required but not installed.${g}
2
+ var S_=Object.create;var{getPrototypeOf:y_,defineProperty:oK,getOwnPropertyNames:b_}=Object;var __=Object.prototype.hasOwnProperty;function f_(Z){return this[Z]}var h_,v_,g_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?h_??=new WeakMap:v_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?S_(y_(Z)):{};let K=X||!Z||!Z.__esModule?oK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of b_(Z))if(!__.call(K,$))oK(K,$,{get:f_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var VQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var m_=(Z)=>Z;function u_(Z,X){this[Z]=m_.bind(null,X)}var c0=(Z,X)=>{for(var Q in X)oK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:u_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var t0=import.meta.require;var IO={};c0(IO,{lokiDir:()=>j0,homeLokiDir:()=>I4,findRepoRootForVersion:()=>tK,REPO_ROOT:()=>Q8});import{resolve as s7,dirname as rK}from"path";import{fileURLToPath as p_}from"url";import{existsSync as qQ}from"fs";import{homedir as d_}from"os";function c_(){let Z=EO;for(let X=0;X<6;X++){if(qQ(s7(Z,"VERSION"))&&qQ(s7(Z,"autonomy/run.sh")))return Z;let Q=rK(Z);if(Q===Z)break;Z=Q}return s7(EO,"..","..","..")}function tK(Z){let X=Z;for(let Q=0;Q<6;Q++){if(qQ(s7(X,"VERSION"))&&qQ(s7(X,"autonomy/run.sh")))return X;let Y=rK(X);if(Y===X)break;X=Y}return s7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??s7(process.cwd(),".loki")}function I4(){return s7(d_(),".loki")}var EO,Q8;var G8=p(()=>{EO=rK(p_(import.meta.url));Q8=c_()});import{readFileSync as l_}from"fs";import{resolve as i_,dirname as a_}from"path";import{fileURLToPath as s_}from"url";function _3(){if(f5!==null)return f5;let Z="8.3.1";if(typeof Z==="string"&&Z.length>0)return f5=Z,f5;try{let X=a_(s_(import.meta.url)),Q=tK(X);f5=l_(i_(Q,"VERSION"),"utf-8").trim()}catch{f5="unknown"}return f5}var f5=null;var GQ=p(()=>{G8()});var xO={};c0(xO,{runOrThrow:()=>qf,run:()=>E0,readStreamCapped:()=>HQ,commandVersion:()=>Hf,commandExists:()=>X9,ShellError:()=>eK,MAX_STDOUT_BYTES:()=>kO});async function HQ(Z,X=kO){let Q=Z.getReader(),Y=new TextDecoder,J="",z=0;try{while(z<X){let{done:K,value:$}=await Q.read();if(K)break;if(!$)continue;if(z+=$.byteLength,z>X){let W=$.byteLength-(z-X);J+=Y.decode($.subarray(0,W),{stream:!0});break}J+=Y.decode($,{stream:!0})}J+=Y.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return J}async function E0(Z,X={}){let Q=Bun.spawn({cmd:[...Z],stdout:"pipe",stderr:"pipe",env:X.env?{...process.env,...X.env}:process.env,cwd:X.cwd}),Y,J;if(X.timeoutMs&&X.timeoutMs>0)Y=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}J=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},X.timeoutMs);try{let[z,K,$]=await Promise.all([HQ(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:z,stderr:K,exitCode:$}}finally{if(Y)clearTimeout(Y);if(J)clearTimeout(J)}}async function qf(Z,X={}){let Q=await E0(Z,X);if(Q.exitCode!==0)throw new eK(`command failed (${Q.exitCode}): ${Z.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function X9(Z){let X=Gf(Z),Q=await E0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Gf(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function Hf(Z,X="--version"){if(!await X9(Z))return null;let Y=await E0([Z,X],{timeoutMs:5000});if(Y.exitCode!==0)return null;return((Y.stdout||Y.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var kO=16777216,eK;var k9=p(()=>{eK=class eK extends Error{message;exitCode;stdout;stderr;constructor(Z,X,Q,Y){super(Z);this.message=Z;this.exitCode=X;this.stdout=Q;this.stderr=Y;this.name="ShellError"}}});function n7(Z){return Uf?"":Z}var Uf,M0,k8,l0,dW0,a0,H8,Q9,g;var S6=p(()=>{Uf=(process.env.NO_COLOR??"").length>0;M0=n7("\x1B[0;31m"),k8=n7("\x1B[0;32m"),l0=n7("\x1B[1;33m"),dW0=n7("\x1B[0;34m"),a0=n7("\x1B[0;36m"),H8=n7("\x1B[1m"),Q9=n7("\x1B[2m"),g=n7("\x1B[0m")});import{existsSync as Ff}from"fs";async function F7(){if(R4!==void 0)return R4;let Z="/opt/homebrew/bin/python3.12";if(Ff(Z))return R4=Z,Z;let X=await X9("python3.12");if(X)return R4=X,X;let Q=await X9("python3");return R4=Q,Q}async function D7(Z,X={}){let Q=await F7();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return E0([Q,"-c",Z],X)}var R4;var o7=p(()=>{k9()});var rO={};c0(rO,{runStatus:()=>tf});import{existsSync as Y9,readFileSync as h3,readdirSync as dO,statSync as cO}from"fs";import{resolve as h8,basename as pf}from"path";import{homedir as df}from"os";function lO(Z){let X=Math.trunc(Z);if(X>=1e6)return`${(Math.trunc(X/1e6*10)/10).toFixed(1)}M`;if(X>=1000)return`${(Math.trunc(X/1000*10)/10).toFixed(1)}K`;return String(X)}function iO(Z,X,Q){if(X===0)return null;let Y=Math.trunc(Z*100/X),J=Math.trunc(Z*BQ/X);if(J>BQ)J=BQ;let z=BQ-J,K=k8;if(Y>=80)K=M0;else if(Y>=50)K=l0;let $="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,z)),W=lO(Z),V=lO(X);return` ${H8}${Q}${g} ${K}[${$}]${g} ${Y}% (${W} / ${V})`}async function lf(){if(await X9("jq"))return!0;return process.stdout.write(`${M0}Error: jq is required but not installed.${g}
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)
@@ -1206,4 +1206,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
1206
1206
  `),2}case"start":{let{runStart:Y}=await Promise.resolve().then(() => (R_(),P_));return Y(Q)}default:return process.stderr.write(`Unknown command: ${X}
1207
1207
  `),process.stderr.write(k_),2}}uO();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var DW0=await FW0(Bun.argv.slice(2));process.exit(DW0);
1208
1208
 
1209
- //# debugId=BF5245603E575A0964756E2164756E21
1209
+ //# debugId=56EE84E87CC3B43564756E2164756E21
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": "8.2.0",
4
+ "version": "8.3.1",
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": "8.2.0",
5
+ "version": "8.3.1",
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",