loki-mode 7.119.0 → 7.120.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/run.sh +49 -0
- package/autonomy/verify.sh +23 -1
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +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 v7.
|
|
6
|
+
# Loki Mode v7.120.0
|
|
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.
|
|
411
|
+
**v7.120.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.120.0
|
package/autonomy/run.sh
CHANGED
|
@@ -9317,6 +9317,21 @@ _loki_zero_tests_executed() {
|
|
|
9317
9317
|
fi
|
|
9318
9318
|
return 1
|
|
9319
9319
|
;;
|
|
9320
|
+
unittest)
|
|
9321
|
+
# #139: `python3 -m unittest discover` on ZERO discovered tests prints
|
|
9322
|
+
# "Ran 0 tests" + "NO TESTS RAN". Depending on the Python version it
|
|
9323
|
+
# exits 5 (newer, already not-pass) OR 0 (older = a silent fake-green,
|
|
9324
|
+
# the #82/#89 trap). POSITIVE detection so it is inconclusive on BOTH:
|
|
9325
|
+
# a "Ran 0 tests" line (authoritative), or the "NO TESTS RAN" banner,
|
|
9326
|
+
# AND no ran-count >= 1. A real run prints "Ran N test(s)" with N>=1
|
|
9327
|
+
# and "OK"/"FAILED", so it is never downgraded. Verified live: zero ->
|
|
9328
|
+
# "Ran 0 tests"/"NO TESTS RAN"; one -> "Ran 1 test"/"OK".
|
|
9329
|
+
if printf '%s' "$_zt_out" | grep -qE '^Ran 0 tests' 2>/dev/null \
|
|
9330
|
+
|| printf '%s' "$_zt_out" | grep -qE '^NO TESTS RAN$' 2>/dev/null; then
|
|
9331
|
+
return 0
|
|
9332
|
+
fi
|
|
9333
|
+
return 1
|
|
9334
|
+
;;
|
|
9320
9335
|
*)
|
|
9321
9336
|
# Unknown/unparseable runner -> never claim zero-tests (safe default).
|
|
9322
9337
|
return 1
|
|
@@ -9483,6 +9498,17 @@ sys.stdout.write(t.strip())
|
|
|
9483
9498
|
-print -quit 2>/dev/null | grep -q .; then
|
|
9484
9499
|
has_python_project=true
|
|
9485
9500
|
fi
|
|
9501
|
+
elif find "${TARGET_DIR:-.}" -maxdepth 2 -type f \
|
|
9502
|
+
\( -name 'test_*.py' -o -name '*_test.py' \) \
|
|
9503
|
+
-not -path '*/.loki/*' -not -path '*/.git/*' -not -path '*/node_modules/*' \
|
|
9504
|
+
-not -path '*/.venv/*' -not -path '*/venv/*' \
|
|
9505
|
+
-print -quit 2>/dev/null | grep -q .; then
|
|
9506
|
+
# #139: a ROOT-LEVEL (or shallow) test_*.py / *_test.py with NO tests/
|
|
9507
|
+
# dir and NO config file. The founder's invoice CLI had exactly this
|
|
9508
|
+
# shape (test_invoice_cli.py at the root) -> was missed -> tests read
|
|
9509
|
+
# "not run" on a genuinely-passing 16-test unittest suite. This is the
|
|
9510
|
+
# same false-negative class as #79 (validated work reads as unvalidated).
|
|
9511
|
+
has_python_project=true
|
|
9486
9512
|
fi
|
|
9487
9513
|
if [ "$has_python_project" = "true" ] && command -v pytest &>/dev/null; then
|
|
9488
9514
|
test_runner="pytest"
|
|
@@ -9499,6 +9525,29 @@ sys.stdout.write(t.strip())
|
|
|
9499
9525
|
[ "$pytest_exit" -ne 0 ] && test_passed=false
|
|
9500
9526
|
details="pytest: $(echo "$output" | tail -5 | tr '\n' ' ')"
|
|
9501
9527
|
fi
|
|
9528
|
+
elif [ "$has_python_project" = "true" ] && command -v python3 &>/dev/null; then
|
|
9529
|
+
# #139: pytest ABSENT but a Python test suite exists. stdlib unittest
|
|
9530
|
+
# discovery runs test_*.py with ZERO third-party deps -- so a legit
|
|
9531
|
+
# unittest suite (the invoice CLI's 16 tests) is verified instead of
|
|
9532
|
+
# silently read as "not run". The zero-test guard (unittest case) makes
|
|
9533
|
+
# a zero-discovery run inconclusive, NOT a fake-green pass (unittest
|
|
9534
|
+
# prints "NO TESTS RAN" and exits 0 -- the #82/#89 trap, guarded).
|
|
9535
|
+
test_runner="unittest"
|
|
9536
|
+
local output unittest_exit _ut_to
|
|
9537
|
+
_ut_to="${LOKI_PYTEST_TIMEOUT:-${LOKI_GATE_TIMEOUT:-300}}"
|
|
9538
|
+
local _ut_cmd=(timeout "${_ut_to}s")
|
|
9539
|
+
command -v gtimeout &>/dev/null && _ut_cmd=(gtimeout "${_ut_to}s")
|
|
9540
|
+
command -v timeout &>/dev/null || command -v gtimeout &>/dev/null || _ut_cmd=()
|
|
9541
|
+
output=$(cd "${TARGET_DIR:-.}" && "${_ut_cmd[@]}" python3 -m unittest discover -p 'test_*.py' 2>&1)
|
|
9542
|
+
unittest_exit=$?
|
|
9543
|
+
if [ "$unittest_exit" -eq 124 ]; then
|
|
9544
|
+
test_passed=false
|
|
9545
|
+
log_warn "unittest gate timed out after ${_ut_to}s (exit 124)"
|
|
9546
|
+
details="unittest: TIMED OUT after ${_ut_to}s -- $(echo "$output" | tail -3 | tr '\n' ' ')"
|
|
9547
|
+
else
|
|
9548
|
+
[ "$unittest_exit" -ne 0 ] && test_passed=false
|
|
9549
|
+
details="unittest: $(echo "$output" | tail -5 | tr '\n' ' ')"
|
|
9550
|
+
fi
|
|
9502
9551
|
fi
|
|
9503
9552
|
fi
|
|
9504
9553
|
|
package/autonomy/verify.sh
CHANGED
|
@@ -350,6 +350,18 @@ _verify_zero_tests_executed() {
|
|
|
350
350
|
fi
|
|
351
351
|
return 1
|
|
352
352
|
;;
|
|
353
|
+
unittest)
|
|
354
|
+
# #139: `python3 -m unittest discover` on ZERO discovered tests prints
|
|
355
|
+
# "Ran 0 tests" + "NO TESTS RAN". On older Python it EXITS 0 (a silent
|
|
356
|
+
# fake-green), on newer it exits 5 (already not-pass). POSITIVE detection
|
|
357
|
+
# so it is inconclusive on BOTH. A real run prints "Ran N test(s)" (N>=1)
|
|
358
|
+
# + "OK"/"FAILED" -> never downgraded. Mirrors run.sh's guard exactly.
|
|
359
|
+
if printf '%s' "$_zt_out" | grep -qE '^Ran 0 tests' 2>/dev/null \
|
|
360
|
+
|| printf '%s' "$_zt_out" | grep -qE '^NO TESTS RAN$' 2>/dev/null; then
|
|
361
|
+
return 0
|
|
362
|
+
fi
|
|
363
|
+
return 1
|
|
364
|
+
;;
|
|
353
365
|
*)
|
|
354
366
|
return 1
|
|
355
367
|
;;
|
|
@@ -421,9 +433,19 @@ verify_gate_tests() {
|
|
|
421
433
|
if command -v pytest >/dev/null 2>&1; then
|
|
422
434
|
runner="pytest"
|
|
423
435
|
out="$(cd "$tree" && timeout "$timeout_s" pytest --tb=short 2>&1)" || rc=$?
|
|
436
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
437
|
+
# #139 parity: pytest ABSENT but a Python suite exists -> run it with
|
|
438
|
+
# stdlib unittest (zero third-party deps) instead of going blindly
|
|
439
|
+
# inconclusive. A real passing test_*.py suite is now VERIFIED here
|
|
440
|
+
# too, matching run.sh's enforce_test_coverage. Zero-discovery is
|
|
441
|
+
# handled below (unittest exits 5 on newer Python = fail-not-pass, or
|
|
442
|
+
# a "Ran 0 tests" line detected by the zero-test guard on the run.sh
|
|
443
|
+
# mirror) so this never green-washes an empty suite.
|
|
444
|
+
runner="unittest"
|
|
445
|
+
out="$(cd "$tree" && timeout "$timeout_s" python3 -m unittest discover -p 'test_*.py' 2>&1)" || rc=$?
|
|
424
446
|
else
|
|
425
447
|
# Applicable but cannot run -> inconclusive (Entanglement 2).
|
|
426
|
-
_verify_add_gate "tests" "inconclusive" "pytest" "python project detected but pytest
|
|
448
|
+
_verify_add_gate "tests" "inconclusive" "pytest" "python project detected but no pytest/python3 on PATH" "true"
|
|
427
449
|
return 0
|
|
428
450
|
fi
|
|
429
451
|
fi
|
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.
|
|
5
|
+
**Version:** v7.120.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var q8=Object.defineProperty;var J8=($)=>$;function V8($,Q){this[$]=J8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)q8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:V8.bind(Q,Z)})};var P=($,Q)=>()=>($&&(Q=$($=0)),Q);var J$=import.meta.require;var m1={};b(m1,{lokiDir:()=>j,homeLokiDir:()=>T$,findRepoRootForVersion:()=>$1,REPO_ROOT:()=>h});import{resolve as t,dirname as e$}from"path";import{fileURLToPath as W8}from"url";import{existsSync as N$}from"fs";import{homedir as H8}from"os";function G8(){let $=v1;for(let Q=0;Q<6;Q++){if(N$(t($,"VERSION"))&&N$(t($,"autonomy/run.sh")))return $;let Z=e$($);if(Z===$)break;$=Z}return t(v1,"..","..","..")}function $1($){let Q=$;for(let Z=0;Z<6;Z++){if(N$(t(Q,"VERSION"))&&N$(t(Q,"autonomy/run.sh")))return Q;let z=e$(Q);if(z===Q)break;Q=z}return t($,"..","..","..")}function j(){return process.env.LOKI_DIR??t(process.cwd(),".loki")}function T$(){return t(H8(),".loki")}var v1,h;var C=P(()=>{v1=e$(W8(import.meta.url));h=G8()});import{readFileSync as U8}from"fs";import{resolve as Y8,dirname as B8}from"path";import{fileURLToPath as M8}from"url";function S$(){if(Q$!==null)return Q$;let $="7.
|
|
2
|
+
var q8=Object.defineProperty;var J8=($)=>$;function V8($,Q){this[$]=J8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)q8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:V8.bind(Q,Z)})};var P=($,Q)=>()=>($&&(Q=$($=0)),Q);var J$=import.meta.require;var m1={};b(m1,{lokiDir:()=>j,homeLokiDir:()=>T$,findRepoRootForVersion:()=>$1,REPO_ROOT:()=>h});import{resolve as t,dirname as e$}from"path";import{fileURLToPath as W8}from"url";import{existsSync as N$}from"fs";import{homedir as H8}from"os";function G8(){let $=v1;for(let Q=0;Q<6;Q++){if(N$(t($,"VERSION"))&&N$(t($,"autonomy/run.sh")))return $;let Z=e$($);if(Z===$)break;$=Z}return t(v1,"..","..","..")}function $1($){let Q=$;for(let Z=0;Z<6;Z++){if(N$(t(Q,"VERSION"))&&N$(t(Q,"autonomy/run.sh")))return Q;let z=e$(Q);if(z===Q)break;Q=z}return t($,"..","..","..")}function j(){return process.env.LOKI_DIR??t(process.cwd(),".loki")}function T$(){return t(H8(),".loki")}var v1,h;var C=P(()=>{v1=e$(W8(import.meta.url));h=G8()});import{readFileSync as U8}from"fs";import{resolve as Y8,dirname as B8}from"path";import{fileURLToPath as M8}from"url";function S$(){if(Q$!==null)return Q$;let $="7.120.0";if(typeof $==="string"&&$.length>0)return Q$=$,Q$;try{let Q=B8(M8(import.meta.url)),Z=$1(Q);Q$=U8(Y8(Z,"VERSION"),"utf-8").trim()}catch{Q$="unknown"}return Q$}var Q$=null;var Q1=P(()=>{C()});var p1={};b(p1,{runOrThrow:()=>S8,run:()=>R,readStreamCapped:()=>c1,commandVersion:()=>C8,commandExists:()=>u,ShellError:()=>Z1,MAX_STDOUT_BYTES:()=>u1});async function c1($,Q=u1){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 R($,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([c1(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 S8($,Q={}){let Z=await R($,Q);if(Z.exitCode!==0)throw new Z1(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function u($){let Q=D8($),Z=await R(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function D8($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function C8($,Q="--version"){if(!await u($))return null;let z=await R([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var u1=16777216,Z1;var o=P(()=>{Z1=class Z1 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 r($){return b8?"":$}var b8,M,S,_,tZ,L,k,y,J;var p=P(()=>{b8=(process.env.NO_COLOR??"").length>0;M=r("\x1B[0;31m"),S=r("\x1B[0;32m"),_=r("\x1B[1;33m"),tZ=r("\x1B[0;34m"),L=r("\x1B[0;36m"),k=r("\x1B[1m"),y=r("\x1B[2m"),J=r("\x1B[0m")});import{existsSync as l8}from"fs";async function Z$(){if(A$!==void 0)return A$;let $="/opt/homebrew/bin/python3.12";if(l8($))return A$=$,$;let Q=await u("python3.12");if(Q)return A$=Q,Q;let Z=await u("python3");return A$=Z,Z}async function z$($,Q={}){let Z=await Z$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return R([Z,"-c",$],Q)}var A$;var V$=P(()=>{o()});var V0={};b(V0,{runStatus:()=>U3});import{existsSync as v,readFileSync as H$,readdirSync as $0,statSync as Q0}from"fs";import{resolve as D,basename as z3}from"path";import{homedir as X3}from"os";function Z0($){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($*C$/Q);if(X>C$)X=C$;let q=C$-X,K=S;if(z>=80)K=M;else if(z>=50)K=_;let W="=".repeat(Math.max(0,X))+" ".repeat(Math.max(0,q)),V=Z0($),H=Z0(Q);return` ${k}${Z}${J} ${K}[${W}]${J} ${z}% (${V} / ${H})`}async function q3(){if(await u("jq"))return!0;return process.stdout.write(`${M}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)
|
|
@@ -814,4 +814,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
814
814
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
815
815
|
`),process.stderr.write(K8),2}}e1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var SZ=await NZ(Bun.argv.slice(2));process.exit(SZ);
|
|
816
816
|
|
|
817
|
-
//# debugId=
|
|
817
|
+
//# debugId=4C6F828B3BD8743B64756E2164756E21
|
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.
|
|
4
|
+
"version": "7.120.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": "7.
|
|
5
|
+
"version": "7.120.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",
|