loki-mode 8.0.1 → 8.0.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 +63 -3
- package/dashboard/__init__.py +1 -1
- package/loki-ts/dist/loki.js +2 -2
- 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 v8.0.
|
|
6
|
+
# Loki Mode v8.0.2
|
|
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.0.
|
|
472
|
+
**v8.0.2 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
8.0.
|
|
1
|
+
8.0.2
|
package/autonomy/loki
CHANGED
|
@@ -3896,6 +3896,8 @@ WHYJSON
|
|
|
3896
3896
|
_LOKI_WHY_LAST_ERROR="$loki_dir/state/LAST_ERROR.json" \
|
|
3897
3897
|
_LOKI_WHY_UNCERTAINTY="$loki_dir/signals/UNCERTAINTY_ESCALATION" \
|
|
3898
3898
|
_LOKI_WHY_CONVERGENCE="$loki_dir/council/convergence.log" \
|
|
3899
|
+
_LOKI_WHY_GATE="$loki_dir/signals/GATE_ESCALATION.json" \
|
|
3900
|
+
_LOKI_WHY_TARGET="${TARGET_DIR:-$(dirname "$loki_dir")}" \
|
|
3899
3901
|
_LOKI_WHY_HANDOFFS="$loki_dir/memory/handoffs" python3 - <<'WHYTXT'
|
|
3900
3902
|
import json, os, glob
|
|
3901
3903
|
def load(p):
|
|
@@ -3953,6 +3955,11 @@ GUIDE = {
|
|
|
3953
3955
|
"If no build is active it likely crashed; in durable mode (LOKI_DURABLE_STATE=1) a restart resumes, else loki start re-runs."),
|
|
3954
3956
|
"exited": ("The build process exited mid-iteration (likely a crash, kill, or empty provider output).",
|
|
3955
3957
|
"Read .loki/logs/ for the last error; if nothing is running it crashed -- re-run with loki start, or loki resume in durable mode."),
|
|
3958
|
+
# A real terminal state that had no entry, so `loki why` answered the one
|
|
3959
|
+
# question it exists to answer with "No diagnosis mapping for this status".
|
|
3960
|
+
"inconclusive_spec_contradiction": (
|
|
3961
|
+
"Loki could not reconcile parts of the spec, so it stopped rather than guess.",
|
|
3962
|
+
"The specific contradictions are in .loki/assumptions/ledger.md -- resolve them in the spec, then re-run."),
|
|
3956
3963
|
}
|
|
3957
3964
|
meaning, action = GUIDE.get(status, ("No diagnosis mapping for this status; see the raw fields below.",
|
|
3958
3965
|
"Check loki status and .loki/logs/ for detail."))
|
|
@@ -3979,13 +3986,66 @@ if iters is not None:
|
|
|
3979
3986
|
print(f" Iterations : {iters}")
|
|
3980
3987
|
if comp.get("branch"):
|
|
3981
3988
|
print(f" Branch : {comp['branch']}{comp_label}")
|
|
3982
|
-
|
|
3983
|
-
|
|
3989
|
+
_fc = comp.get("files_changed")
|
|
3990
|
+
if _fc is not None:
|
|
3991
|
+
if _fc == 0:
|
|
3992
|
+
# A recorded 0 is NOT trustworthy on its own: a greenfield run whose
|
|
3993
|
+
# baseline never resolved records 0 while having committed real work.
|
|
3994
|
+
# Saying "0 files" flatly told users nothing was built on a run that
|
|
3995
|
+
# produced 9 files and 1300 insertions. Re-derive from git, and only
|
|
3996
|
+
# claim zero when git agrees.
|
|
3997
|
+
_real = None
|
|
3998
|
+
try:
|
|
3999
|
+
import subprocess as _sp
|
|
4000
|
+
_tgt = os.environ.get("_LOKI_WHY_TARGET") or "."
|
|
4001
|
+
_base = (comp.get("start_sha") or "").strip()
|
|
4002
|
+
if not _base or _base == "HEAD":
|
|
4003
|
+
_base = _sp.run(["git", "-C", _tgt, "hash-object", "-t", "tree", os.devnull],
|
|
4004
|
+
capture_output=True, text=True, timeout=10).stdout.strip()
|
|
4005
|
+
if _base:
|
|
4006
|
+
_o = _sp.run(["git", "-C", _tgt, "diff", "--shortstat", f"{_base}..HEAD",
|
|
4007
|
+
"--", ".", ":(exclude).loki/"],
|
|
4008
|
+
capture_output=True, text=True, timeout=15).stdout.strip()
|
|
4009
|
+
if _o:
|
|
4010
|
+
_real = _o
|
|
4011
|
+
except Exception:
|
|
4012
|
+
_real = None
|
|
4013
|
+
if _real:
|
|
4014
|
+
print(f" Changes : {_real} (re-derived; the run record said 0)")
|
|
4015
|
+
else:
|
|
4016
|
+
print(f" Changes : none recorded (the run did not resolve a baseline)")
|
|
4017
|
+
else:
|
|
4018
|
+
print(f" Changes : {_fc} files (+{comp.get('insertions',0)}/-{comp.get('deletions',0)}){comp_label}")
|
|
3984
4019
|
if comp.get("pr_url"):
|
|
3985
4020
|
print(f" PR : {comp['pr_url']}{comp_label}")
|
|
4021
|
+
|
|
4022
|
+
# Name the gate that actually stopped the run. Without this the user is told to
|
|
4023
|
+
# "resume", which the run's own pause notice warns will stop at the same gate.
|
|
4024
|
+
_gate = load(os.environ.get("_LOKI_WHY_GATE", "")) or {}
|
|
4025
|
+
_gname = str(_gate.get("gate", "") or "").strip()
|
|
4026
|
+
if _gname:
|
|
4027
|
+
_gc, _gt = _gate.get("count"), _gate.get("threshold")
|
|
4028
|
+
_detail = f"{_gname} (failed {_gc} times, threshold {_gt})" if isinstance(_gc, int) and isinstance(_gt, int) else _gname
|
|
4029
|
+
print(f" Blocked by : {_detail}")
|
|
4030
|
+
|
|
3986
4031
|
print()
|
|
3987
4032
|
print(f" What happened: {meaning}")
|
|
3988
|
-
|
|
4033
|
+
if _gname:
|
|
4034
|
+
print(f" What to do : Read the {_gname} findings and fix what they name, then resume.")
|
|
4035
|
+
print(f" Resuming unchanged will stop at the same gate again.")
|
|
4036
|
+
_art = str(_gate.get("latest_artifact", "") or "")
|
|
4037
|
+
if _art:
|
|
4038
|
+
# Make the pointer relative to the workspace. The recorded value is an
|
|
4039
|
+
# absolute path from the machine that ran the build -- on the preserved
|
|
4040
|
+
# run it names a /var/folders temp dir that no longer exists, so the one
|
|
4041
|
+
# actionable pointer in the whole notice led nowhere. Anchor on
|
|
4042
|
+
# ".loki/" so it works even when the run happened elsewhere.
|
|
4043
|
+
_i = _art.find(".loki/")
|
|
4044
|
+
if _i != -1:
|
|
4045
|
+
_art = _art[_i:]
|
|
4046
|
+
print(f" Findings: {_art}")
|
|
4047
|
+
else:
|
|
4048
|
+
print(f" What to do : {action}")
|
|
3989
4049
|
|
|
3990
4050
|
# RUN-25 iter 22b/iter 23 (Wave D #6): when a run is PAUSED / live and actually
|
|
3991
4051
|
# STUCK, name the REAL stall reason instead of the generic "resume". The runner
|
package/dashboard/__init__.py
CHANGED
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var k_=Object.create;var{getPrototypeOf:x_,defineProperty:oK,getOwnPropertyNames:S_}=Object;var y_=Object.prototype.hasOwnProperty;function b_(Z){return this[Z]}var __,f_,h_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?__??=new WeakMap:f_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?k_(x_(Z)):{};let K=X||!Z||!Z.__esModule?oK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of S_(Z))if(!y_.call(K,$))oK(K,$,{get:b_.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 v_=(Z)=>Z;function g_(Z,X){this[Z]=v_.bind(null,X)}var c0=(Z,X)=>{for(var Q in X)oK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:g_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var t0=import.meta.require;var EO={};c0(EO,{lokiDir:()=>j0,homeLokiDir:()=>I4,findRepoRootForVersion:()=>tK,REPO_ROOT:()=>Q8});import{resolve as s7,dirname as rK}from"path";import{fileURLToPath as m_}from"url";import{existsSync as qQ}from"fs";import{homedir as u_}from"os";function p_(){let Z=DO;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(DO,"..","..","..")}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(u_(),".loki")}var DO,Q8;var G8=p(()=>{DO=rK(m_(import.meta.url));Q8=p_()});import{readFileSync as d_}from"fs";import{resolve as c_,dirname as l_}from"path";import{fileURLToPath as i_}from"url";function _3(){if(f5!==null)return f5;let Z="8.0.
|
|
2
|
+
var k_=Object.create;var{getPrototypeOf:x_,defineProperty:oK,getOwnPropertyNames:S_}=Object;var y_=Object.prototype.hasOwnProperty;function b_(Z){return this[Z]}var __,f_,h_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?__??=new WeakMap:f_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?k_(x_(Z)):{};let K=X||!Z||!Z.__esModule?oK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of S_(Z))if(!y_.call(K,$))oK(K,$,{get:b_.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 v_=(Z)=>Z;function g_(Z,X){this[Z]=v_.bind(null,X)}var c0=(Z,X)=>{for(var Q in X)oK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:g_.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var t0=import.meta.require;var EO={};c0(EO,{lokiDir:()=>j0,homeLokiDir:()=>I4,findRepoRootForVersion:()=>tK,REPO_ROOT:()=>Q8});import{resolve as s7,dirname as rK}from"path";import{fileURLToPath as m_}from"url";import{existsSync as qQ}from"fs";import{homedir as u_}from"os";function p_(){let Z=DO;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(DO,"..","..","..")}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(u_(),".loki")}var DO,Q8;var G8=p(()=>{DO=rK(m_(import.meta.url));Q8=p_()});import{readFileSync as d_}from"fs";import{resolve as c_,dirname as l_}from"path";import{fileURLToPath as i_}from"url";function _3(){if(f5!==null)return f5;let Z="8.0.2";if(typeof Z==="string"&&Z.length>0)return f5=Z,f5;try{let X=l_(i_(import.meta.url)),Q=tK(X);f5=d_(c_(Q,"VERSION"),"utf-8").trim()}catch{f5="unknown"}return f5}var f5=null;var GQ=p(()=>{G8()});var kO={};c0(kO,{runOrThrow:()=>Wf,run:()=>D0,readStreamCapped:()=>HQ,commandVersion:()=>qf,commandExists:()=>H9,ShellError:()=>eK,MAX_STDOUT_BYTES:()=>RO});async function HQ(Z,X=RO){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 D0(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 Wf(Z,X={}){let Q=await D0(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 H9(Z){let X=Vf(Z),Q=await D0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Vf(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function qf(Z,X="--version"){if(!await H9(Z))return null;let Y=await D0([Z,X],{timeoutMs:5000});if(Y.exitCode!==0)return null;return((Y.stdout||Y.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var RO=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 Gf?"":Z}var Gf,M0,k8,l0,gW0,a0,H8,X9,g;var S6=p(()=>{Gf=(process.env.NO_COLOR??"").length>0;M0=n7("\x1B[0;31m"),k8=n7("\x1B[0;32m"),l0=n7("\x1B[1;33m"),gW0=n7("\x1B[0;34m"),a0=n7("\x1B[0;36m"),H8=n7("\x1B[1m"),X9=n7("\x1B[2m"),g=n7("\x1B[0m")});import{existsSync as wf}from"fs";async function F7(){if(R4!==void 0)return R4;let Z="/opt/homebrew/bin/python3.12";if(wf(Z))return R4=Z,Z;let X=await H9("python3.12");if(X)return R4=X,X;let Q=await H9("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 D0([Q,"-c",Z],X)}var R4;var o7=p(()=>{k9()});var oO={};c0(oO,{runStatus:()=>of});import{existsSync as Q9,readFileSync as h3,readdirSync as pO,statSync as dO}from"fs";import{resolve as h8,basename as mf}from"path";import{homedir as uf}from"os";function cO(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 lO(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=cO(Z),V=cO(X);return` ${H8}${Q}${g} ${K}[${$}]${g} ${Y}% (${W} / ${V})`}async function df(){if(await H9("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)
|
|
@@ -1203,4 +1203,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
1203
1203
|
`),2}case"start":{let{runStart:Y}=await Promise.resolve().then(() => (I_(),E_));return Y(Q)}default:return process.stderr.write(`Unknown command: ${X}
|
|
1204
1204
|
`),process.stderr.write(P_),2}}mO();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var TW0=await MW0(Bun.argv.slice(2));process.exit(TW0);
|
|
1205
1205
|
|
|
1206
|
-
//# debugId=
|
|
1206
|
+
//# debugId=0B4A1F7E210B77BE64756E2164756E21
|
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": "8.0.
|
|
4
|
+
"version": "8.0.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": "8.0.
|
|
5
|
+
"version": "8.0.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",
|