loki-mode 7.115.0 → 7.116.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 +51 -2
- package/autonomy/verify.sh +35 -0
- 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.116.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.116.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.116.0
|
package/autonomy/run.sh
CHANGED
|
@@ -1668,7 +1668,7 @@ _loki_trust_run_id() {
|
|
|
1668
1668
|
# Args: $1 = the new phase value (REASONING, BUILDING, VERIFYING, COMPLETED, etc.)
|
|
1669
1669
|
_advance_current_phase() {
|
|
1670
1670
|
local new_phase="${1:?phase required}"
|
|
1671
|
-
local loki_dir="${LOKI_DIR:-${TARGET_DIR:-.}
|
|
1671
|
+
local loki_dir="${LOKI_DIR:-${TARGET_DIR:-.}/.loki}"
|
|
1672
1672
|
local orch="$loki_dir/state/orchestrator.json"
|
|
1673
1673
|
[ -f "$orch" ] || return 0
|
|
1674
1674
|
# Values are passed via argv (not interpolated into the source) so a phase or
|
|
@@ -9159,6 +9159,51 @@ sys.stdout.write(t.strip())
|
|
|
9159
9159
|
details="cargo test: $(echo "$output" | tail -3 | tr '\n' ' ')"
|
|
9160
9160
|
fi
|
|
9161
9161
|
|
|
9162
|
+
# node --test (built-in Node test runner) -- config-less fallback (task #79).
|
|
9163
|
+
# Node's built-in runner (stable since Node 18) runs *.test.{js,mjs,cjs}
|
|
9164
|
+
# with ZERO config and NO package.json. A deliverable of slug.js +
|
|
9165
|
+
# slug.test.js (a real, passing suite) previously fell straight through to
|
|
9166
|
+
# runner="none" and recorded verification_gap="source_without_tests" -- a
|
|
9167
|
+
# FALSE-NEGATIVE trust defect (symmetric to fake-green): genuinely-correct,
|
|
9168
|
+
# fully-tested work read as NOT VERIFIED. This branch fires ONLY as a
|
|
9169
|
+
# fallback below every explicit-framework path (vitest/jest/mocha/scripts.test
|
|
9170
|
+
# via package.json, monorepo, pytest, go, cargo all gate on
|
|
9171
|
+
# test_runner=="none"), so package.json-with-jest still selects jest. It runs
|
|
9172
|
+
# only when node is on PATH AND *.test.{js,mjs,cjs} files exist at root or
|
|
9173
|
+
# under test/ or tests/. A failing suite records test_passed=false (never
|
|
9174
|
+
# swallowed); absence of node or test files falls through to the honest
|
|
9175
|
+
# "none"/inconclusive path below (never fabricates a pass).
|
|
9176
|
+
if [ "$test_runner" = "none" ] && command -v node &>/dev/null; then
|
|
9177
|
+
local _nt_files=()
|
|
9178
|
+
local _nt_f
|
|
9179
|
+
# Root-level test files (maxdepth 1) plus test/ and tests/ dirs, skipping
|
|
9180
|
+
# vendored trees so we never walk node_modules.
|
|
9181
|
+
while IFS= read -r _nt_f; do
|
|
9182
|
+
[ -n "$_nt_f" ] && _nt_files+=("$_nt_f")
|
|
9183
|
+
done < <(find "${TARGET_DIR:-.}" -maxdepth 1 -type f \
|
|
9184
|
+
\( -name '*.test.js' -o -name '*.test.mjs' -o -name '*.test.cjs' \) \
|
|
9185
|
+
2>/dev/null)
|
|
9186
|
+
for _nt_dir in test tests; do
|
|
9187
|
+
[ -d "${TARGET_DIR:-.}/$_nt_dir" ] || continue
|
|
9188
|
+
while IFS= read -r _nt_f; do
|
|
9189
|
+
[ -n "$_nt_f" ] && _nt_files+=("$_nt_f")
|
|
9190
|
+
done < <(find "${TARGET_DIR:-.}/$_nt_dir" -maxdepth 3 -type f \
|
|
9191
|
+
\( -name '*.test.js' -o -name '*.test.mjs' -o -name '*.test.cjs' \) \
|
|
9192
|
+
-not -path '*/node_modules/*' 2>/dev/null)
|
|
9193
|
+
done
|
|
9194
|
+
if [ "${#_nt_files[@]}" -gt 0 ]; then
|
|
9195
|
+
test_runner="node-test"
|
|
9196
|
+
local output
|
|
9197
|
+
# Pass matched files explicitly (node --test globbing is
|
|
9198
|
+
# Node-version-sensitive); quote each so paths with spaces survive.
|
|
9199
|
+
output=$(cd "${TARGET_DIR:-.}" && timeout "${LOKI_GATE_TIMEOUT:-300}" \
|
|
9200
|
+
node --test "${_nt_files[@]}" 2>&1) || test_passed=false
|
|
9201
|
+
# tail -14 so node's TAP summary block (# tests / # pass N / # fail N,
|
|
9202
|
+
# ~10 lines) survives truncation for the best-effort count parse below.
|
|
9203
|
+
details="node --test: $(echo "$output" | tail -14 | tr '\n' ' ')"
|
|
9204
|
+
fi
|
|
9205
|
+
fi
|
|
9206
|
+
|
|
9162
9207
|
if [ "$test_runner" = "none" ]; then
|
|
9163
9208
|
log_info "Test coverage: no test runner detected, recording inconclusive (not pass)"
|
|
9164
9209
|
# v7.41.x fail-open fix: previously this wrote pass:true, so a project
|
|
@@ -9258,6 +9303,10 @@ TREOF
|
|
|
9258
9303
|
local _tr_passed_n _tr_failed_n
|
|
9259
9304
|
_tr_passed_n=$(printf '%s' "$details" | grep -oE '[0-9]+ passed' | grep -oE '[0-9]+' | head -1)
|
|
9260
9305
|
_tr_failed_n=$(printf '%s' "$details" | grep -oE '[0-9]+ failed' | grep -oE '[0-9]+' | head -1)
|
|
9306
|
+
# node --test emits TAP-ish "# pass N" / "# fail N" summary lines, which the
|
|
9307
|
+
# "N passed"/"N failed" pattern above does not match. Fall back to those.
|
|
9308
|
+
[ -n "$_tr_passed_n" ] || _tr_passed_n=$(printf '%s' "$details" | grep -oE '# pass [0-9]+' | grep -oE '[0-9]+' | head -1)
|
|
9309
|
+
[ -n "$_tr_failed_n" ] || _tr_failed_n=$(printf '%s' "$details" | grep -oE '# fail [0-9]+' | grep -oE '[0-9]+' | head -1)
|
|
9261
9310
|
[ -n "$_tr_passed_n" ] || _tr_passed_n=null
|
|
9262
9311
|
[ -n "$_tr_failed_n" ] || _tr_failed_n=null
|
|
9263
9312
|
|
|
@@ -19316,7 +19365,7 @@ main() {
|
|
|
19316
19365
|
# engine's own is_completed() recognise this session as terminal. Write the
|
|
19317
19366
|
# file-system COMPLETED marker (checked by is_completed() in the main loop).
|
|
19318
19367
|
_advance_current_phase "COMPLETED"
|
|
19319
|
-
local loki_dir="${LOKI_DIR:-${TARGET_DIR:-.}
|
|
19368
|
+
local loki_dir="${LOKI_DIR:-${TARGET_DIR:-.}/.loki}"
|
|
19320
19369
|
echo "Session completed at $(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$loki_dir/COMPLETED" 2>/dev/null || true
|
|
19321
19370
|
|
|
19322
19371
|
# Finish-and-own (v7.88.0): write a plain-English ownership handoff
|
package/autonomy/verify.sh
CHANGED
|
@@ -383,6 +383,41 @@ verify_gate_tests() {
|
|
|
383
383
|
fi
|
|
384
384
|
fi
|
|
385
385
|
|
|
386
|
+
# node --test (built-in Node runner) -- config-less fallback (task #79).
|
|
387
|
+
# Node's built-in test runner (stable since Node 18) runs
|
|
388
|
+
# *.test.{js,mjs,cjs} with ZERO config and NO package.json, so a real
|
|
389
|
+
# passing suite (slug.js + slug.test.js, no package.json) previously fell
|
|
390
|
+
# through to runner="none" -> tests "skipped" -- a FALSE-NEGATIVE on the
|
|
391
|
+
# verdict surface (symmetric to fake-green). This branch fires ONLY below
|
|
392
|
+
# the explicit-framework paths (vitest/jest/mocha via package.json all set
|
|
393
|
+
# runner above), so package.json-with-jest still selects jest. Runs only
|
|
394
|
+
# when node is on PATH AND *.test.{js,mjs,cjs} exist at root or under
|
|
395
|
+
# test/ or tests/. A FAILING run records fail (never swallowed); absence of
|
|
396
|
+
# node or test files falls through to the honest "skipped" path below.
|
|
397
|
+
if [ "$runner" = "none" ] && command -v node >/dev/null 2>&1; then
|
|
398
|
+
local _nt_files=()
|
|
399
|
+
local _nt_f _nt_dir
|
|
400
|
+
while IFS= read -r _nt_f; do
|
|
401
|
+
[ -n "$_nt_f" ] && _nt_files+=("$_nt_f")
|
|
402
|
+
done < <(find "$tree" -maxdepth 1 -type f \
|
|
403
|
+
\( -name '*.test.js' -o -name '*.test.mjs' -o -name '*.test.cjs' \) \
|
|
404
|
+
2>/dev/null)
|
|
405
|
+
for _nt_dir in test tests; do
|
|
406
|
+
[ -d "$tree/$_nt_dir" ] || continue
|
|
407
|
+
while IFS= read -r _nt_f; do
|
|
408
|
+
[ -n "$_nt_f" ] && _nt_files+=("$_nt_f")
|
|
409
|
+
done < <(find "$tree/$_nt_dir" -maxdepth 3 -type f \
|
|
410
|
+
\( -name '*.test.js' -o -name '*.test.mjs' -o -name '*.test.cjs' \) \
|
|
411
|
+
-not -path '*/node_modules/*' 2>/dev/null)
|
|
412
|
+
done
|
|
413
|
+
if [ "${#_nt_files[@]}" -gt 0 ]; then
|
|
414
|
+
runner="node-test"
|
|
415
|
+
# Pass matched files explicitly (node --test globbing is
|
|
416
|
+
# Node-version-sensitive); quote each so paths with spaces survive.
|
|
417
|
+
out="$(cd "$tree" && timeout "$timeout_s" node --test "${_nt_files[@]}" 2>&1)" || rc=$?
|
|
418
|
+
fi
|
|
419
|
+
fi
|
|
420
|
+
|
|
386
421
|
if [ "$runner" = "none" ]; then
|
|
387
422
|
_verify_add_gate "tests" "skipped" "" "no test framework detected" "true"
|
|
388
423
|
return 0
|
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.116.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.116.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=30F27BA7342E3CAE64756E2164756E21
|
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.116.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.116.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",
|