loki-mode 8.18.0 → 8.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/own-render.py +37 -1
- package/autonomy/lib/proof-generator.py +23 -0
- 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.
|
|
6
|
+
# Loki Mode v8.19.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.
|
|
472
|
+
**v8.19.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
8.
|
|
1
|
+
8.19.0
|
|
@@ -319,6 +319,24 @@ def _section_is_it_working(proof, run_id=None):
|
|
|
319
319
|
lines.append("This means Loki is NOT telling you it is ready to ship. Here is "
|
|
320
320
|
"what was not verified:")
|
|
321
321
|
lines.append("")
|
|
322
|
+
# Gates the operator switched off. This is the FIRST gap listed, because a
|
|
323
|
+
# run blocked only by disabled gates has headline VERIFIED and an EMPTY
|
|
324
|
+
# degraded list -- so without this the owner was told "no specific gaps were
|
|
325
|
+
# itemized" when the reason was precise and already known.
|
|
326
|
+
#
|
|
327
|
+
# It also resolves a contradiction the owner could see on the page: the
|
|
328
|
+
# verdict line reads VERIFIED while the section refuses to call it ready.
|
|
329
|
+
# Naming the skipped gates is what makes those two statements consistent.
|
|
330
|
+
_qg = (proof or {}).get("quality_gates") or {}
|
|
331
|
+
_off = _qg.get("disabled_phases")
|
|
332
|
+
_off = [str(x).strip() for x in _off] if isinstance(_off, list) else []
|
|
333
|
+
_trust_off = sorted(n for n in _off
|
|
334
|
+
if n.lower() in ("code_review", "security",
|
|
335
|
+
"unit_tests", "e2e_tests"))
|
|
336
|
+
if _trust_off:
|
|
337
|
+
lines.append("- These checks were switched OFF for this run, so they "
|
|
338
|
+
"never ran: %s" % ", ".join(_trust_off))
|
|
339
|
+
|
|
322
340
|
if isinstance(degraded, list) and degraded:
|
|
323
341
|
for d in degraded:
|
|
324
342
|
if isinstance(d, dict):
|
|
@@ -330,7 +348,7 @@ def _section_is_it_working(proof, run_id=None):
|
|
|
330
348
|
lines.append("- %s%s" % (item, tail))
|
|
331
349
|
else:
|
|
332
350
|
lines.append("- %s" % str(d))
|
|
333
|
-
|
|
351
|
+
elif not _trust_off:
|
|
334
352
|
lines.append("- (no specific gaps were itemized, but the verdict above is "
|
|
335
353
|
"not a clean pass)")
|
|
336
354
|
lines.append("")
|
|
@@ -480,6 +498,24 @@ def _section_still_to_do(proof, completion):
|
|
|
480
498
|
# Anything not verified (degraded items) is also a to-do.
|
|
481
499
|
honesty = (proof or {}).get("honesty") or {}
|
|
482
500
|
degraded = honesty.get("degraded") or []
|
|
501
|
+
# Gates the operator switched off. This is the FIRST gap listed, because a
|
|
502
|
+
# run blocked only by disabled gates has headline VERIFIED and an EMPTY
|
|
503
|
+
# degraded list -- so without this the owner was told "no specific gaps were
|
|
504
|
+
# itemized" when the reason was precise and already known.
|
|
505
|
+
#
|
|
506
|
+
# It also resolves a contradiction the owner could see on the page: the
|
|
507
|
+
# verdict line reads VERIFIED while the section refuses to call it ready.
|
|
508
|
+
# Naming the skipped gates is what makes those two statements consistent.
|
|
509
|
+
_qg = (proof or {}).get("quality_gates") or {}
|
|
510
|
+
_off = _qg.get("disabled_phases")
|
|
511
|
+
_off = [str(x).strip() for x in _off] if isinstance(_off, list) else []
|
|
512
|
+
_trust_off = sorted(n for n in _off
|
|
513
|
+
if n.lower() in ("code_review", "security",
|
|
514
|
+
"unit_tests", "e2e_tests"))
|
|
515
|
+
if _trust_off:
|
|
516
|
+
lines.append("- These checks were switched OFF for this run, so they "
|
|
517
|
+
"never ran: %s" % ", ".join(_trust_off))
|
|
518
|
+
|
|
483
519
|
if isinstance(degraded, list) and degraded:
|
|
484
520
|
for d in degraded:
|
|
485
521
|
if isinstance(d, dict):
|
|
@@ -1256,6 +1256,29 @@ def _build_proof(args, loki_dir, target_dir, repo_root):
|
|
|
1256
1256
|
# signed record.
|
|
1257
1257
|
degraded = _compute_degraded(facts)
|
|
1258
1258
|
headline = _compute_headline(facts, degraded)
|
|
1259
|
+
|
|
1260
|
+
# Trust gates the operator switched off are a gap in the proof of done, and
|
|
1261
|
+
# the honesty ledger exists so "a reader sees exactly what was NOT verified
|
|
1262
|
+
# rather than inferring it from silence". Measured through the real
|
|
1263
|
+
# generator: a run with code review and security disabled listed only
|
|
1264
|
+
# "build" as its gap, while two correctness checks had not run at all.
|
|
1265
|
+
#
|
|
1266
|
+
# Appended AFTER the headline is computed, deliberately. Feeding these into
|
|
1267
|
+
# _compute_headline would change what "Verified" MEANS, and this file
|
|
1268
|
+
# already records that as a trust-semantics decision for the council and
|
|
1269
|
+
# founder rather than an inference (see the FV-2 note on the functional
|
|
1270
|
+
# fact). This is the record half: the gap becomes visible without the
|
|
1271
|
+
# verdict silently moving under anyone.
|
|
1272
|
+
_dis = (quality_gates or {}).get("disabled_phases") if isinstance(quality_gates, dict) else None
|
|
1273
|
+
_dis = [str(x).strip() for x in _dis] if isinstance(_dis, list) else []
|
|
1274
|
+
for _name in sorted(n for n in _dis
|
|
1275
|
+
if n.lower() in ("code_review", "security",
|
|
1276
|
+
"unit_tests", "e2e_tests")):
|
|
1277
|
+
degraded.append({
|
|
1278
|
+
"item": _name,
|
|
1279
|
+
"status": "disabled",
|
|
1280
|
+
"reason": "switched off for this run, so the check never ran",
|
|
1281
|
+
})
|
|
1259
1282
|
honesty = {
|
|
1260
1283
|
"headline": headline,
|
|
1261
1284
|
"degraded": degraded,
|
package/dashboard/__init__.py
CHANGED
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var h_=Object.create;var{getPrototypeOf:v_,defineProperty:rK,getOwnPropertyNames:g_}=Object;var m_=Object.prototype.hasOwnProperty;function u_(Z){return this[Z]}var p_,d_,c_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?p_??=new WeakMap:d_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?h_(v_(Z)):{};let K=X||!Z||!Z.__esModule?rK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of g_(Z))if(!m_.call(K,$))rK(K,$,{get:u_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var qQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var l_=(Z)=>Z;function i_(Z,X){this[Z]=l_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)rK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:i_.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:()=>P4,findRepoRootForVersion:()=>eK,REPO_ROOT:()=>r0});import{resolve as n7,dirname as tK}from"path";import{fileURLToPath as a_}from"url";import{existsSync as GQ}from"fs";import{homedir as s_}from"os";function n_(){let Z=RO;for(let X=0;X<6;X++){if(GQ(n7(Z,"VERSION"))&&GQ(n7(Z,"autonomy/run.sh")))return Z;let Q=tK(Z);if(Q===Z)break;Z=Q}return n7(RO,"..","..","..")}function eK(Z){let X=Z;for(let Q=0;Q<6;Q++){if(GQ(n7(X,"VERSION"))&&GQ(n7(X,"autonomy/run.sh")))return X;let Y=tK(X);if(Y===X)break;X=Y}return n7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??n7(process.cwd(),".loki")}function P4(){return n7(s_(),".loki")}var RO,r0;var G8=p(()=>{RO=tK(a_(import.meta.url));r0=n_()});import{readFileSync as o_}from"fs";import{resolve as r_,dirname as t_}from"path";import{fileURLToPath as e_}from"url";function f3(){if(h5!==null)return h5;let Z="8.
|
|
2
|
+
var h_=Object.create;var{getPrototypeOf:v_,defineProperty:rK,getOwnPropertyNames:g_}=Object;var m_=Object.prototype.hasOwnProperty;function u_(Z){return this[Z]}var p_,d_,c_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?p_??=new WeakMap:d_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?h_(v_(Z)):{};let K=X||!Z||!Z.__esModule?rK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of g_(Z))if(!m_.call(K,$))rK(K,$,{get:u_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var qQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var l_=(Z)=>Z;function i_(Z,X){this[Z]=l_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)rK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:i_.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:()=>P4,findRepoRootForVersion:()=>eK,REPO_ROOT:()=>r0});import{resolve as n7,dirname as tK}from"path";import{fileURLToPath as a_}from"url";import{existsSync as GQ}from"fs";import{homedir as s_}from"os";function n_(){let Z=RO;for(let X=0;X<6;X++){if(GQ(n7(Z,"VERSION"))&&GQ(n7(Z,"autonomy/run.sh")))return Z;let Q=tK(Z);if(Q===Z)break;Z=Q}return n7(RO,"..","..","..")}function eK(Z){let X=Z;for(let Q=0;Q<6;Q++){if(GQ(n7(X,"VERSION"))&&GQ(n7(X,"autonomy/run.sh")))return X;let Y=tK(X);if(Y===X)break;X=Y}return n7(Z,"..","..","..")}function j0(){return process.env.LOKI_DIR??n7(process.cwd(),".loki")}function P4(){return n7(s_(),".loki")}var RO,r0;var G8=p(()=>{RO=tK(a_(import.meta.url));r0=n_()});import{readFileSync as o_}from"fs";import{resolve as r_,dirname as t_}from"path";import{fileURLToPath as e_}from"url";function f3(){if(h5!==null)return h5;let Z="8.19.0";if(typeof Z==="string"&&Z.length>0)return h5=Z,h5;try{let X=t_(e_(import.meta.url)),Q=eK(X);h5=o_(r_(Q,"VERSION"),"utf-8").trim()}catch{h5="unknown"}return h5}var h5=null;var HQ=p(()=>{G8()});var bO={};l0(bO,{runOrThrow:()=>Of,run:()=>E0,readStreamCapped:()=>UQ,commandVersion:()=>Af,commandExists:()=>X9,ShellError:()=>Z$,MAX_STDOUT_BYTES:()=>yO});async function UQ(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([UQ(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 Of(Z,X={}){let Q=await E0(Z,X);if(Q.exitCode!==0)throw new Z$(`command failed (${Q.exitCode}): ${Z.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function X9(Z){let X=Lf(Z),Q=await E0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Lf(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function Af(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,Z$;var x9=p(()=>{Z$=class Z$ 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 jf?"":Z}var jf,L0,k8,p0,ZV0,i0,H8,Q9,v;var S6=p(()=>{jf=(process.env.NO_COLOR??"").length>0;L0=o7("\x1B[0;31m"),k8=o7("\x1B[0;32m"),p0=o7("\x1B[1;33m"),ZV0=o7("\x1B[0;34m"),i0=o7("\x1B[0;36m"),H8=o7("\x1B[1m"),Q9=o7("\x1B[2m"),v=o7("\x1B[0m")});import{existsSync as xf}from"fs";async function E7(){if(k4!==void 0)return k4;let Z="/opt/homebrew/bin/python3.12";if(xf(Z))return k4=Z,Z;let X=await X9("python3.12");if(X)return k4=X,X;let Q=await X9("python3");return k4=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 k4;var r7=p(()=>{x9()});var ZL={};l0(ZL,{runStatus:()=>Yh});import{existsSync as Y9,readFileSync as v3,readdirSync as iO,statSync as aO}from"fs";import{resolve as h8,basename as sf}from"path";import{homedir as nf}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*NQ/X);if(J>NQ)J=NQ;let z=NQ-J,K=k8;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` ${H8}${Q}${v} ${K}[${$}]${v} ${Y}% (${W} / ${V})`}async function rf(){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)
|
|
@@ -1222,4 +1222,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
1222
1222
|
`),2}case"start":{let{runStart:Y}=await Promise.resolve().then(() => (b_(),y_));return Y(Q)}default:return process.stderr.write(`Unknown command: ${X}
|
|
1223
1223
|
`),process.stderr.write(__),2}}cO();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var fW0=await _W0(Bun.argv.slice(2));process.exit(fW0);
|
|
1224
1224
|
|
|
1225
|
-
//# debugId=
|
|
1225
|
+
//# debugId=CB16F7FA4924CA0B64756E2164756E21
|
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.
|
|
4
|
+
"version": "8.19.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.
|
|
5
|
+
"version": "8.19.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",
|