loki-mode 8.76.0 → 8.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md 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 v8.76.0
6
+ # Loki Mode v8.77.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -469,4 +469,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
469
469
 
470
470
  ---
471
471
 
472
- **v8.76.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
472
+ **v8.77.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 8.76.0
1
+ 8.77.0
package/autonomy/loki CHANGED
@@ -1040,7 +1040,8 @@ show_help() {
1040
1040
  echo " agent analyze api assets audit bench checkpoint (cp) ci cleanup"
1041
1041
  echo " cluster cockpit code compliance completions compound config context (ctx)"
1042
1042
  echo " cost council crash dashboard demo deploy docker docs doctor dogfood"
1043
- echo " enterprise explain export failover github grill heal help import init"
1043
+ echo " enterprise estimate explain export failover github grill heal help"
1044
+ echo " import init"
1044
1045
  echo " issue kpis logs magic mcp memory metrics migrate modernize monitor"
1045
1046
  echo " next notify onboard open optimize otel own (handoff) pause plan preview"
1046
1047
  echo " projects proof (receipt) provider quick quickstart rc remote report reset"
@@ -19158,6 +19159,9 @@ main() {
19158
19159
  _deprecated_alias cost "report cost" "$@"
19159
19160
  cmd_report cost "$@"
19160
19161
  ;;
19162
+ estimate)
19163
+ cmd_estimate "$@"
19164
+ ;;
19161
19165
  trust)
19162
19166
  cmd_trust "$@"
19163
19167
  ;;
@@ -25310,9 +25314,92 @@ cmd_trust_metrics() {
25310
25314
  # for the current-run aggregate (single source of truth) and reads .loki/proofs/
25311
25315
  # for persistent per-run history. Honest: prints "not recorded" when cost was
25312
25316
  # never collected, never a fabricated $0.00.
25317
+ # Forward cost projection. Wraps tools/estimate-run.py.
25318
+ #
25319
+ # --iterations is REQUIRED by that tool by design: no multi-run history exists
25320
+ # to derive a horizon from, so projecting a total without one would be guessing
25321
+ # at the single number the operator asked for. We surface that requirement here
25322
+ # rather than inventing a default, for the same reason cost reports UNKNOWN
25323
+ # instead of $0.00 -- an unearned number is worse than an absent one.
25324
+ cmd_estimate() {
25325
+ local iterations=""
25326
+ local show_json=false
25327
+
25328
+ while [[ $# -gt 0 ]]; do
25329
+ case "$1" in
25330
+ --help|-h)
25331
+ echo -e "${BOLD}loki estimate${NC} - Project what a run is likely to cost"
25332
+ echo ""
25333
+ echo "Usage: loki estimate --iterations N [--json]"
25334
+ echo ""
25335
+ echo "Projects a run cost from this workspace's MEASURED history in"
25336
+ echo ".loki/metrics/efficiency/. With no measured history there is no"
25337
+ echo "basis, and it says so rather than returning a fabricated number."
25338
+ echo ""
25339
+ echo "Options:"
25340
+ echo " --iterations N REQUIRED. How many iterations to project."
25341
+ echo " No multi-run history exists to derive a horizon"
25342
+ echo " from, so there is no honest default."
25343
+ echo " --json Machine-readable JSON output"
25344
+ echo " --help, -h Show this help"
25345
+ echo ""
25346
+ echo "Examples:"
25347
+ echo " loki estimate --iterations 10"
25348
+ echo " loki estimate --iterations 25 --json"
25349
+ echo ""
25350
+ echo "See also: loki cost --detail (what a run ALREADY spent)"
25351
+ return 0
25352
+ ;;
25353
+ --json) show_json=true; shift ;;
25354
+ --iterations) iterations="${2:-}"; shift 2 || shift ;;
25355
+ --iterations=*) iterations="${1#*=}"; shift ;;
25356
+ *) echo -e "${RED}Unknown option: $1${NC}" >&2; echo "Run 'loki estimate --help' for usage." >&2; return 1 ;;
25357
+ esac
25358
+ done
25359
+
25360
+ if [ -z "$iterations" ]; then
25361
+ echo -e "${RED}--iterations is required${NC}" >&2
25362
+ echo "" >&2
25363
+ echo "No multi-run history exists to derive a horizon from, so there is no" >&2
25364
+ echo "honest default for how many iterations to project. Say how many you" >&2
25365
+ echo "expect and the projection is scaled from measured per-iteration cost." >&2
25366
+ echo "" >&2
25367
+ echo " loki estimate --iterations 10" >&2
25368
+ echo "" >&2
25369
+ echo "Run 'loki estimate --help' for usage." >&2
25370
+ return 1
25371
+ fi
25372
+
25373
+ case "$iterations" in
25374
+ ''|*[!0-9]*)
25375
+ echo -e "${RED}--iterations must be a positive whole number (got: $iterations)${NC}" >&2
25376
+ return 1
25377
+ ;;
25378
+ esac
25379
+
25380
+ local estimate_py="$SKILL_DIR/tools/estimate-run.py"
25381
+ if ! command -v python3 >/dev/null 2>&1; then
25382
+ echo -e "${RED}python3 is required for 'loki estimate'${NC}" >&2
25383
+ echo "Install python3 and re-run." >&2
25384
+ return 1
25385
+ fi
25386
+ if [ ! -f "$estimate_py" ]; then
25387
+ echo -e "${RED}Estimate tool not found: $estimate_py${NC}" >&2
25388
+ echo "Your install looks incomplete. Reinstall: loki self-update" >&2
25389
+ return 1
25390
+ fi
25391
+
25392
+ # Same workspace derivation as 'loki cost --detail': the tool takes the
25393
+ # workspace and appends .loki itself, while LOKI_DIR is the .loki path.
25394
+ local est_args=("$(dirname "${LOKI_DIR:-.loki}")" "--iterations" "$iterations")
25395
+ [ "$show_json" = "true" ] && est_args+=("--json")
25396
+ python3 "$estimate_py" "${est_args[@]}"
25397
+ }
25398
+
25313
25399
  cmd_cost() {
25314
25400
  local show_json=false
25315
25401
  local last_n=0
25402
+ local detail=false
25316
25403
 
25317
25404
  while [[ $# -gt 0 ]]; do
25318
25405
  case "$1" in
@@ -25328,23 +25415,67 @@ cmd_cost() {
25328
25415
  echo "Options:"
25329
25416
  echo " --json Machine-readable JSON output"
25330
25417
  echo " --last N Show only the last N runs in history (default: all)"
25418
+ echo " --detail Per-iteration breakdown: cache hit ratio, cost trend,"
25419
+ echo " and the measured/found ratio (autonomy/lib/cost-summary.py)"
25331
25420
  echo " --help, -h Show this help"
25332
25421
  echo ""
25333
25422
  echo "Examples:"
25334
25423
  echo " loki cost # Cost summary + budget status"
25335
25424
  echo " loki cost --json # Machine-readable output"
25336
25425
  echo " loki cost --last 10 # Last 10 runs of history"
25426
+ echo " loki cost --detail # Per-iteration cache + trend breakdown"
25427
+ echo " loki cost --detail --json # Same, machine-readable"
25337
25428
  echo ""
25338
25429
  echo "Budget cap: set LOKI_BUDGET_LIMIT (USD). Warns at 80%, stops at 100%."
25430
+ echo ""
25431
+ echo "An unmeasured iteration reads UNKNOWN and is excluded from totals."
25432
+ echo "Unmeasured is never reported as \$0.00 -- that would be indistinguishable"
25433
+ echo "from a real measurement of zero."
25339
25434
  exit 0
25340
25435
  ;;
25341
25436
  --json) show_json=true; shift ;;
25437
+ --detail) detail=true; shift ;;
25342
25438
  --last) last_n="${2:-0}"; shift 2 ;;
25343
25439
  --last=*) last_n="${1#*=}"; shift ;;
25344
25440
  *) echo -e "${RED}Unknown option: $1${NC}" >&2; echo "Run 'loki cost --help' for usage." >&2; exit 1 ;;
25345
25441
  esac
25346
25442
  done
25347
25443
 
25444
+ # --detail routes to the per-run summarizer, which reports what the budget
25445
+ # view cannot: cache hit ratio, cost trend, and the measured/found ratio.
25446
+ # It reuses the SAME honesty predicate (efficiency_cost.record_is_measured),
25447
+ # so both views agree on what counts as measured.
25448
+ if [ "$detail" = "true" ]; then
25449
+ # --last filters per-RUN history, which this view does not show (it
25450
+ # breaks down the iterations of ONE run). Rejecting is the honest
25451
+ # move: silently discarding it would make the filter look applied.
25452
+ if [ "$last_n" != "0" ]; then
25453
+ echo -e "${RED}--last is not supported with --detail${NC}" >&2
25454
+ echo "--detail breaks down the iterations of the current run, not per-run history." >&2
25455
+ echo "Use 'loki cost --last N' for the per-run history view." >&2
25456
+ return 1
25457
+ fi
25458
+ local cost_summary_py="$SKILL_DIR/autonomy/lib/cost-summary.py"
25459
+ if ! command -v python3 >/dev/null 2>&1; then
25460
+ echo -e "${RED}python3 is required for 'loki cost --detail'${NC}" >&2
25461
+ echo "Install python3, or run 'loki cost' for the budget view." >&2
25462
+ return 1
25463
+ fi
25464
+ if [ ! -f "$cost_summary_py" ]; then
25465
+ echo -e "${RED}Cost summary tool not found: $cost_summary_py${NC}" >&2
25466
+ echo "Your install looks incomplete. Reinstall: loki self-update" >&2
25467
+ return 1
25468
+ fi
25469
+ # cost-summary.py takes the WORKSPACE (it appends .loki itself), while
25470
+ # LOKI_DIR is the .loki path and is genuinely relocatable
25471
+ # (autonomy/serve.sh exports a non-default). Derive the parent so
25472
+ # --detail describes the same workspace the budget view does.
25473
+ local ws_args=("$(dirname "${LOKI_DIR:-.loki}")")
25474
+ [ "$show_json" = "true" ] && ws_args+=("--json")
25475
+ python3 "$cost_summary_py" "${ws_args[@]}"
25476
+ return $?
25477
+ fi
25478
+
25348
25479
  local loki_dir="${LOKI_DIR:-.loki}"
25349
25480
 
25350
25481
  if ! command -v python3 &>/dev/null; then
package/completions/_loki CHANGED
@@ -179,7 +179,8 @@ function _loki_commands {
179
179
  'web:Start the web dashboard'
180
180
  'plan:Preview the build plan for a spec'
181
181
  'report:Reporting commands (cost, kpis, share)'
182
- 'cost:Show cost of recent runs'
182
+ 'cost:Show cost of recent runs (--detail for cache + trend)'
183
+ 'estimate:Project run cost (requires --iterations N)'
183
184
  'kpis:Key performance indicators'
184
185
  'stats:Session statistics'
185
186
  'preview:Open the running app preview'
@@ -5,7 +5,7 @@ _loki_completion() {
5
5
  _init_completion || return
6
6
 
7
7
  # Main subcommands (must match autonomy/loki main case statement)
8
- local main_commands="start quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt explain plan report cost kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash open otel preview quickstart rc rollback self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help"
8
+ local main_commands="start quick monitor demo tour welcome init stop pause resume steer status next ship dashboard web serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets cockpit secure own handoff doctor watchdog audit metrics syslog onboard share proof receipt explain plan report cost estimate kpis stats test ci watch telemetry agent context ctx code run export review optimize heal modernize migrate cluster worktree wt trigger failover remote deploy docker mcp magic assets analyze compliance crash open otel preview quickstart rc rollback self-update sentrux setup-skill spec state template trust trust-metrics ultracode update verify voice why wiki bench cleanup logs grill docs cp version completions help"
9
9
 
10
10
  # 1. If we are on the first argument (subcommand)
11
11
  if [[ $cword -eq 1 ]]; then
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "8.76.0"
10
+ __version__ = "8.77.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var m_=Object.create;var{getPrototypeOf:u_,defineProperty:eK,getOwnPropertyNames:p_}=Object;var d_=Object.prototype.hasOwnProperty;function c_(Z){return this[Z]}var l_,i_,a_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?l_??=new WeakMap:i_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?m_(u_(Z)):{};let K=X||!Z||!Z.__esModule?eK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of p_(Z))if(!d_.call(K,$))eK(K,$,{get:c_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var HQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var s_=(Z)=>Z;function n_(Z,X){this[Z]=s_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)eK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:n_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var e0=import.meta.require;var kO={};l0(kO,{lokiDir:()=>j0,homeLokiDir:()=>R4,findRepoRootForVersion:()=>X$,REPO_ROOT:()=>i0});import{resolve as n7,dirname as Z$}from"path";import{fileURLToPath as o_}from"url";import{existsSync as UQ}from"fs";import{homedir as r_}from"os";function t_(){let Z=RO;for(let X=0;X<6;X++){if(UQ(n7(Z,"VERSION"))&&UQ(n7(Z,"autonomy/run.sh")))return Z;let Q=Z$(Z);if(Q===Z)break;Z=Q}return n7(RO,"..","..","..")}function X$(Z){let X=Z;for(let Q=0;Q<6;Q++){if(UQ(n7(X,"VERSION"))&&UQ(n7(X,"autonomy/run.sh")))return X;let Y=Z$(X);if(Y===X)break;X=Y}return n7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??n7(process.cwd(),".loki")}function R4(){return n7(r_(),".loki")}var RO,i0;var H8=p(()=>{RO=Z$(o_(import.meta.url));i0=t_()});import{readFileSync as e_}from"fs";import{resolve as Zf,dirname as Xf}from"path";import{fileURLToPath as Qf}from"url";function h3(){if(h5!==null)return h5;let Z="8.76.0";if(typeof Z==="string"&&Z.length>0)return h5=Z,h5;try{let X=Xf(Qf(import.meta.url)),Q=X$(X);h5=e_(Zf(Q,"VERSION"),"utf-8").trim()}catch{h5="unknown"}return h5}var h5=null;var BQ=p(()=>{H8()});var bO={};l0(bO,{runOrThrow:()=>jf,run:()=>E0,readStreamCapped:()=>NQ,commandVersion:()=>Tf,commandExists:()=>X9,ShellError:()=>Q$,MAX_STDOUT_BYTES:()=>yO});async function NQ(Z,X=yO){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([NQ(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 jf(Z,X={}){let Q=await E0(Z,X);if(Q.exitCode!==0)throw new Q$(`command failed (${Q.exitCode}): ${Z.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function X9(Z){let X=Mf(Z),Q=await E0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Mf(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function Tf(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 yO=16777216,Q$;var x9=p(()=>{Q$=class Q$ 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 o7(Z){return wf?"":Z}var wf,L0,F8,p0,zV0,a0,W8,Q9,v;var S6=p(()=>{wf=(process.env.NO_COLOR??"").length>0;L0=o7("\x1B[0;31m"),F8=o7("\x1B[0;32m"),p0=o7("\x1B[1;33m"),zV0=o7("\x1B[0;34m"),a0=o7("\x1B[0;36m"),W8=o7("\x1B[1m"),Q9=o7("\x1B[2m"),v=o7("\x1B[0m")});import{existsSync as bf}from"fs";async function E7(){if(x4!==void 0)return x4;let Z="/opt/homebrew/bin/python3.12";if(bf(Z))return x4=Z,Z;let X=await X9("python3.12");if(X)return x4=X,X;let Q=await X9("python3");return x4=Q,Q}async function Y7(Z,X={}){let Q=await E7();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return E0([Q,"-c",Z],X)}var x4;var r7=p(()=>{x9()});var ZL={};l0(ZL,{runStatus:()=>Kh});import{existsSync as Y9,readFileSync as g3,readdirSync as iO,statSync as aO}from"fs";import{resolve as h8,basename as rf}from"path";import{homedir as tf}from"os";function sO(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 nO(Z,X,Q){if(X===0)return null;let Y=Math.trunc(Z*100/X),J=Math.trunc(Z*LQ/X);if(J>LQ)J=LQ;let z=LQ-J,K=F8;if(Y>=80)K=L0;else if(Y>=50)K=p0;let $="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,z)),W=sO(Z),V=sO(X);return` ${W8}${Q}${v} ${K}[${$}]${v} ${Y}% (${W} / ${V})`}async function Zh(){if(await X9("jq"))return!0;return process.stdout.write(`${L0}Error: jq is required but not installed.${v}
2
+ var m_=Object.create;var{getPrototypeOf:u_,defineProperty:eK,getOwnPropertyNames:p_}=Object;var d_=Object.prototype.hasOwnProperty;function c_(Z){return this[Z]}var l_,i_,a_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?l_??=new WeakMap:i_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?m_(u_(Z)):{};let K=X||!Z||!Z.__esModule?eK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of p_(Z))if(!d_.call(K,$))eK(K,$,{get:c_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var HQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var s_=(Z)=>Z;function n_(Z,X){this[Z]=s_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)eK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:n_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var e0=import.meta.require;var kO={};l0(kO,{lokiDir:()=>j0,homeLokiDir:()=>R4,findRepoRootForVersion:()=>X$,REPO_ROOT:()=>i0});import{resolve as n7,dirname as Z$}from"path";import{fileURLToPath as o_}from"url";import{existsSync as UQ}from"fs";import{homedir as r_}from"os";function t_(){let Z=RO;for(let X=0;X<6;X++){if(UQ(n7(Z,"VERSION"))&&UQ(n7(Z,"autonomy/run.sh")))return Z;let Q=Z$(Z);if(Q===Z)break;Z=Q}return n7(RO,"..","..","..")}function X$(Z){let X=Z;for(let Q=0;Q<6;Q++){if(UQ(n7(X,"VERSION"))&&UQ(n7(X,"autonomy/run.sh")))return X;let Y=Z$(X);if(Y===X)break;X=Y}return n7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??n7(process.cwd(),".loki")}function R4(){return n7(r_(),".loki")}var RO,i0;var H8=p(()=>{RO=Z$(o_(import.meta.url));i0=t_()});import{readFileSync as e_}from"fs";import{resolve as Zf,dirname as Xf}from"path";import{fileURLToPath as Qf}from"url";function h3(){if(h5!==null)return h5;let Z="8.77.0";if(typeof Z==="string"&&Z.length>0)return h5=Z,h5;try{let X=Xf(Qf(import.meta.url)),Q=X$(X);h5=e_(Zf(Q,"VERSION"),"utf-8").trim()}catch{h5="unknown"}return h5}var h5=null;var BQ=p(()=>{H8()});var bO={};l0(bO,{runOrThrow:()=>jf,run:()=>E0,readStreamCapped:()=>NQ,commandVersion:()=>Tf,commandExists:()=>X9,ShellError:()=>Q$,MAX_STDOUT_BYTES:()=>yO});async function NQ(Z,X=yO){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([NQ(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 jf(Z,X={}){let Q=await E0(Z,X);if(Q.exitCode!==0)throw new Q$(`command failed (${Q.exitCode}): ${Z.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function X9(Z){let X=Mf(Z),Q=await E0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Mf(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function Tf(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 yO=16777216,Q$;var x9=p(()=>{Q$=class Q$ 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 o7(Z){return wf?"":Z}var wf,L0,F8,p0,zV0,a0,W8,Q9,v;var S6=p(()=>{wf=(process.env.NO_COLOR??"").length>0;L0=o7("\x1B[0;31m"),F8=o7("\x1B[0;32m"),p0=o7("\x1B[1;33m"),zV0=o7("\x1B[0;34m"),a0=o7("\x1B[0;36m"),W8=o7("\x1B[1m"),Q9=o7("\x1B[2m"),v=o7("\x1B[0m")});import{existsSync as bf}from"fs";async function E7(){if(x4!==void 0)return x4;let Z="/opt/homebrew/bin/python3.12";if(bf(Z))return x4=Z,Z;let X=await X9("python3.12");if(X)return x4=X,X;let Q=await X9("python3");return x4=Q,Q}async function Y7(Z,X={}){let Q=await E7();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return E0([Q,"-c",Z],X)}var x4;var r7=p(()=>{x9()});var ZL={};l0(ZL,{runStatus:()=>Kh});import{existsSync as Y9,readFileSync as g3,readdirSync as iO,statSync as aO}from"fs";import{resolve as h8,basename as rf}from"path";import{homedir as tf}from"os";function sO(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 nO(Z,X,Q){if(X===0)return null;let Y=Math.trunc(Z*100/X),J=Math.trunc(Z*LQ/X);if(J>LQ)J=LQ;let z=LQ-J,K=F8;if(Y>=80)K=L0;else if(Y>=50)K=p0;let $="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,z)),W=sO(Z),V=sO(X);return` ${W8}${Q}${v} ${K}[${$}]${v} ${Y}% (${W} / ${V})`}async function Zh(){if(await X9("jq"))return!0;return process.stdout.write(`${L0}Error: jq is required but not installed.${v}
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)
@@ -1232,4 +1232,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
1232
1232
  `),2}case"start":{let{runStart:Y}=await Promise.resolve().then(() => (h_(),f_));return Y(Q)}default:return process.stderr.write(`Unknown command: ${X}
1233
1233
  `),process.stderr.write(v_),2}}cO();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var uW0=await mW0(Bun.argv.slice(2));process.exit(uW0);
1234
1234
 
1235
- //# debugId=D8F84559349944B064756E2164756E21
1235
+ //# debugId=C4360B4BD01881AA64756E2164756E21
package/mcp/__init__.py CHANGED
@@ -75,4 +75,4 @@ try:
75
75
  except ImportError:
76
76
  __all__ = ['mcp']
77
77
 
78
- __version__ = '8.76.0'
78
+ __version__ = '8.77.0'
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.76.0",
4
+ "version": "8.77.0",
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.76.0",
5
+ "version": "8.77.0",
6
6
  "description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
7
7
  "author": {
8
8
  "name": "Autonomi",