loki-mode 7.104.0 → 7.104.1
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/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +105 -104
- 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.104.
|
|
6
|
+
# Loki Mode v7.104.1
|
|
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.104.
|
|
411
|
+
**v7.104.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.104.
|
|
1
|
+
7.104.1
|
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.104.
|
|
5
|
+
**Version:** v7.104.1
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var z8=Object.defineProperty;var X8=($)=>$;function K8($,Q){this[$]=X8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)z8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:K8.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var J$=import.meta.require;var
|
|
2
|
+
var z8=Object.defineProperty;var X8=($)=>$;function K8($,Q){this[$]=X8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)z8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:K8.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var J$=import.meta.require;var v1={};b(v1,{lokiDir:()=>P,homeLokiDir:()=>T$,findRepoRootForVersion:()=>e$,REPO_ROOT:()=>h});import{resolve as t,dirname as i$}from"path";import{fileURLToPath as q8}from"url";import{existsSync as x$}from"fs";import{homedir as J8}from"os";function V8(){let $=y1;for(let Q=0;Q<6;Q++){if(x$(t($,"VERSION"))&&x$(t($,"autonomy/run.sh")))return $;let Z=i$($);if(Z===$)break;$=Z}return t(y1,"..","..","..")}function e$($){let Q=$;for(let Z=0;Z<6;Z++){if(x$(t(Q,"VERSION"))&&x$(t(Q,"autonomy/run.sh")))return Q;let z=i$(Q);if(z===Q)break;Q=z}return t($,"..","..","..")}function P(){return process.env.LOKI_DIR??t(process.cwd(),".loki")}function T$(){return t(J8(),".loki")}var y1,h;var C=L(()=>{y1=i$(q8(import.meta.url));h=V8()});import{readFileSync as W8}from"fs";import{resolve as U8,dirname as H8}from"path";import{fileURLToPath as G8}from"url";function N$(){if(Q$!==null)return Q$;let $="7.104.1";if(typeof $==="string"&&$.length>0)return Q$=$,Q$;try{let Q=H8(G8(import.meta.url)),Z=e$(Q);Q$=W8(U8(Z,"VERSION"),"utf-8").trim()}catch{Q$="unknown"}return Q$}var Q$=null;var $1=L(()=>{C()});var c1={};b(c1,{runOrThrow:()=>E8,run:()=>F,readStreamCapped:()=>u1,commandVersion:()=>N8,commandExists:()=>f,ShellError:()=>Q1,MAX_STDOUT_BYTES:()=>f1});async function u1($,Q=f1){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 F($,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([u1(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 E8($,Q={}){let Z=await F($,Q);if(Z.exitCode!==0)throw new Q1(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function f($){let Q=x8($),Z=await F(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function x8($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function N8($,Q="--version"){if(!await f($))return null;let z=await F([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var f1=16777216,Q1;var d=L(()=>{Q1=class Q1 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 S8?"":$}var S8,T,S,_,oZ,I,k,y,J;var c=L(()=>{S8=(process.env.NO_COLOR??"").length>0;T=r("\x1B[0;31m"),S=r("\x1B[0;32m"),_=r("\x1B[1;33m"),oZ=r("\x1B[0;34m"),I=r("\x1B[0;36m"),k=r("\x1B[1m"),y=r("\x1B[2m"),J=r("\x1B[0m")});import{existsSync as u8}from"fs";async function Z$(){if(A$!==void 0)return A$;let $="/opt/homebrew/bin/python3.12";if(u8($))return A$=$,$;let Q=await f("python3.12");if(Q)return A$=Q,Q;let Z=await f("python3");return A$=Z,Z}async function z$($,Q={}){let Z=await Z$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return F([Z,"-c",$],Q)}var A$;var V$=L(()=>{d()});var J0={};b(J0,{runStatus:()=>W3});import{existsSync as v,readFileSync as U$,readdirSync as e1,statSync as $0}from"fs";import{resolve as D,basename as $3}from"path";import{homedir as Q3}from"os";function Q0($){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($*D$/Q);if(X>D$)X=D$;let q=D$-X,K=S;if(z>=80)K=T;else if(z>=50)K=_;let W="=".repeat(Math.max(0,X))+" ".repeat(Math.max(0,q)),V=Q0($),U=Q0(Q);return` ${k}${Z}${J} ${K}[${W}]${J} ${z}% (${V} / ${U})`}async function z3(){if(await f("jq"))return!0;return process.stdout.write(`${T}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)
|
|
6
6
|
`),process.stdout.write(` yum install jq (RHEL/CentOS)
|
|
7
|
-
`),!1}function C$($){if(!Number.isFinite($)||$<=0)return!1;try{return process.kill($,0),!0}catch{return!1}}function b$($){if(!v($))return null;try{let Q=U$($,"utf-8").trim();if(!Q)return null;let Z=Number.parseInt(Q,10);return Number.isFinite(Z)?Z:null}catch{return null}}function X3($){let Q=[],Z=b$(D($,"loki.pid"));if(Z!==null&&C$(Z))Q.push(`global:${Z}`);let z=D($,"sessions");if(v(z)){let X=[];try{X=
|
|
7
|
+
`),!1}function C$($){if(!Number.isFinite($)||$<=0)return!1;try{return process.kill($,0),!0}catch{return!1}}function b$($){if(!v($))return null;try{let Q=U$($,"utf-8").trim();if(!Q)return null;let Z=Number.parseInt(Q,10);return Number.isFinite(Z)?Z:null}catch{return null}}function X3($){let Q=[],Z=b$(D($,"loki.pid"));if(Z!==null&&C$(Z))Q.push(`global:${Z}`);let z=D($,"sessions");if(v(z)){let X=[];try{X=e1(z)}catch{X=[]}for(let q of X){let K=D(z,q);try{if(!$0(K).isDirectory())continue}catch{continue}let W=D(K,"loki.pid"),V=b$(W);if(V!==null&&C$(V))Q.push(`${q}:${V}`)}}if(v($)){let X=[];try{X=e1($)}catch{X=[]}for(let q of X){if(!q.startsWith("run-")||!q.endsWith(".pid"))continue;let K=D($,q);try{if(!$0(K).isFile())continue}catch{continue}let W=$3(q,".pid").slice(4),V=b$(K);if(V!==null&&C$(V)){if(!Q.some((H)=>H.startsWith(`${W}:`)))Q.push(`${W}:${V}`)}}}return Q}async function z0($,Q){let Z=await F(["jq","-r",$,Q]);if(Z.exitCode!==0)return null;return Z.stdout.trim()}function X0($,Q){try{let Z=U$($,"utf-8"),X=JSON.parse(Z)[Q];if(typeof X==="number"){if(Q==="budget_used"){let q=Math.round(X*100)/100;if(Number.isInteger(q))return String(q);return String(q)}return String(X)}if(X===void 0||X===null)return"0";return String(X)}catch{return"0"}}function K0($,Q,Z){try{let z=U$($,"utf-8"),q=JSON.parse(z)[Q];if(typeof q==="number"&&Number.isFinite(q))return q;return Z}catch{return Z}}async function K3(){let $=P();if(!await z3())return 1;if(!v($))return process.stdout.write(`${k}Loki Mode Status${J}
|
|
8
8
|
`),process.stdout.write(`
|
|
9
9
|
`),process.stdout.write(`${_}No active session found.${J}
|
|
10
10
|
`),process.stdout.write(`Loki Mode has not been initialized in this directory.
|
|
@@ -35,22 +35,22 @@ var z8=Object.defineProperty;var X8=($)=>$;function K8($,Q){this[$]=X8.bind(null
|
|
|
35
35
|
`);let K=D($,"STATUS.txt");if(v(K)){process.stdout.write(`${I}Session Info:${J}
|
|
36
36
|
`);try{process.stdout.write(U$(K,"utf-8"))}catch{}process.stdout.write(`
|
|
37
37
|
`)}let W=D($,"state","orchestrator.json");if(v(W)){process.stdout.write(`${I}Orchestrator State:${J}
|
|
38
|
-
`);let Y=await
|
|
39
|
-
`)}let V=D($,"queue","pending.json");if(v(V)){let Y=await
|
|
40
|
-
`)}let U=D($,"metrics","budget.json");if(v(U)){let Y=
|
|
41
|
-
`);let M=Math.trunc((Number.parseFloat(O)||0)*100),R=Number.parseFloat(Y),N=Number.isFinite(R)&&R!==0?Math.trunc(R*100):100,g=
|
|
38
|
+
`);let Y=await z0('.currentPhase // "unknown"',W);process.stdout.write(`${Y??"unknown"}
|
|
39
|
+
`)}let V=D($,"queue","pending.json");if(v(V)){let Y=await z0('if type == "array" then length elif .tasks then .tasks | length else 0 end',V);process.stdout.write(`${I}Pending Tasks:${J} ${Y??"0"}
|
|
40
|
+
`)}let U=D($,"metrics","budget.json");if(v(U)){let Y=X0(U,"budget_limit"),O=X0(U,"budget_used");if(Y!=="0"){process.stdout.write(`${I}Budget:${J} $${O} / $${Y}
|
|
41
|
+
`);let M=Math.trunc((Number.parseFloat(O)||0)*100),R=Number.parseFloat(Y),N=Number.isFinite(R)&&R!==0?Math.trunc(R*100):100,g=Z0(M,N,"Budget");if(g!==null)process.stdout.write(`${g}
|
|
42
42
|
`)}else process.stdout.write(`${I}Cost:${J} $${O} (no limit)
|
|
43
|
-
`)}let H=D($,"state","context-usage.json");if(v(H)){let Y=
|
|
44
|
-
`)}let G=[D($,"dashboard","dashboard.pid"),D(Q3(),".loki","dashboard","dashboard.pid")].find((Y)=>v(Y))??"";if(G&&v(G)){let Y=b$(G);if(Y!==null&&C$(Y)){let O=D(G,".."),M=(u,w)=>{let
|
|
43
|
+
`)}let H=D($,"state","context-usage.json");if(v(H)){let Y=K0(H,"window_size",200000),O=K0(H,"used_tokens",0),M=Z0(O,Y,"Context");if(M!==null)process.stdout.write(`${M}
|
|
44
|
+
`)}let G=[D($,"dashboard","dashboard.pid"),D(Q3(),".loki","dashboard","dashboard.pid")].find((Y)=>v(Y))??"";if(G&&v(G)){let Y=b$(G);if(Y!==null&&C$(Y)){let O=D(G,".."),M=(u,w)=>{let E=D(O,u);try{return v(E)?U$(E,"utf-8").trim()||w:w}catch{return w}},R=M("scheme","http"),N=M("host","127.0.0.1"),g=M("port",process.env.LOKI_DASHBOARD_PORT||"57374");if(N==="0.0.0.0")N="127.0.0.1";process.stdout.write(`${I}Dashboard:${J} ${R}://${N}:${g}/
|
|
45
45
|
`)}}return await q3($),process.stdout.write(`
|
|
46
46
|
`),process.stdout.write(`${y} Tip: loki analyze context show - detailed token breakdown${J}
|
|
47
47
|
`),process.stdout.write(`${y} Tip: loki analyze code overview - codebase intelligence${J}
|
|
48
48
|
`),0}async function q3($){let Q=D($,"state"),Z=J3(Q),z=D(Q,"relevant-learnings.json"),X=D($,"escalations"),q=Z.length>0,K=v(z),W=v(X);if(!q&&!K&&!W)return;if(process.stdout.write(`
|
|
49
49
|
${I}Phase 1 artifacts:${J}
|
|
50
|
-
`),q){let V=Z[Z.length-1],U=
|
|
51
|
-
`)}}if(K){let V=
|
|
50
|
+
`),q){let V=Z[Z.length-1],U=q0(V);if(U&&Array.isArray(U.findings)){let H={Critical:0,High:0,Medium:0,Low:0};for(let G of U.findings){let Y=String(G.severity??"");if(Y in H)H[Y]=(H[Y]??0)+1}let B=Object.entries(H).filter(([,G])=>G>0).map(([G,Y])=>`${Y} ${G.toLowerCase()}`).join(", ");process.stdout.write(` Findings (iter ${U.iteration??"?"}): ${B||"none"} -- ${U.findings.length} total
|
|
51
|
+
`)}}if(K){let V=q0(z);if(V&&Array.isArray(V.learnings)&&V.learnings.length>0){let U=new Map;for(let B of V.learnings){let G=String(B.trigger??"unknown");U.set(G,(U.get(G)??0)+1)}let H=[...U.entries()].sort((B,G)=>G[1]-B[1]).slice(0,3).map(([B,G])=>`${G} ${B}`).join(", ");process.stdout.write(` Learnings: ${V.learnings.length} total (${H})
|
|
52
52
|
`)}}if(W){let V=0,U="";try{let B=(await import("fs")).readdirSync(X).filter((G)=>G.endsWith(".md"));if(V=B.length,B.length>0)B.sort(),U=B[B.length-1]??""}catch{}if(V>0)process.stdout.write(` Escalations: ${V} handoff doc${V===1?"":"s"} (latest: ${U})
|
|
53
|
-
`)}}function J3($){if(!v($))return[];try{return J$("fs").readdirSync($).filter((z)=>/^findings-\d+\.json$/.test(z)).sort((z,X)=>{let q=Number.parseInt(z.replace(/[^0-9]/g,""),10)||0,K=Number.parseInt(X.replace(/[^0-9]/g,""),10)||0;return q-K}).map((z)=>D($,z))}catch{return[]}}function
|
|
53
|
+
`)}}function J3($){if(!v($))return[];try{return J$("fs").readdirSync($).filter((z)=>/^findings-\d+\.json$/.test(z)).sort((z,X)=>{let q=Number.parseInt(z.replace(/[^0-9]/g,""),10)||0,K=Number.parseInt(X.replace(/[^0-9]/g,""),10)||0;return q-K}).map((z)=>D($,z))}catch{return[]}}function q0($){try{let Q=J$("fs");return JSON.parse(Q.readFileSync($,"utf-8"))}catch{return null}}async function V3(){let $=await Z$();if(!$)return process.stderr.write(`{"error": "Failed to generate JSON status. Ensure python3 is available."}
|
|
54
54
|
`),1;let Q=h,Z=P(),z=process.env.LOKI_DASHBOARD_PORT||"57374",X=process.env.LOKI_PROVIDER||"claude",q=await F([$,"-c",Z3,Q,Z,z,X],{timeoutMs:30000});if(q.exitCode!==0)return process.stderr.write(`{"error": "Failed to generate JSON status. Ensure python3 is available."}
|
|
55
55
|
`),1;return process.stdout.write(q.stdout),0}async function W3($){let Q=[...$];while(Q.length>0){let Z=Q[0];if(Z==="--json")return V3();if(Z==="--help"||Z==="-h")return process.stdout.write(`Usage: loki status [--json]
|
|
56
56
|
`),0;return process.stdout.write(`${T}Unknown flag: ${Z}${J}
|
|
@@ -329,11 +329,11 @@ if os.path.isfile(gate_count_file):
|
|
|
329
329
|
result['phase1'] = phase1
|
|
330
330
|
|
|
331
331
|
print(json.dumps(result, indent=2))
|
|
332
|
-
`;var
|
|
333
|
-
`)}var U3,H3;var K1=L(()=>{U3=new Set(["--json","-q","--quiet"]),H3=new Set(["json","csv","timeline"])});var
|
|
334
|
-
`)}function
|
|
335
|
-
Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?M3(X,Z):T3(X,Z)}}async function O3($){let{emitDeprecatedAlias:Q}=await Promise.resolve().then(() => (K1(),
|
|
336
|
-
`);if(G>0&&N.length>0)N=N.slice(1);N=N.map((g)=>g.trim()).filter((g)=>g.length>0),U=N.slice(-5)}}catch{U=[]}return{errors_log_path:H?V:null,recent_errors:U,recent_error_count:U.length,status:U.length===0?"pass":"warn"}}async function L0(){let Q=(await I0()).map(({displayName:V,...U})=>U),Z=
|
|
332
|
+
`;var V0=L(()=>{d();V$();c();C()});var U0={};b(U0,{emitDeprecatedAlias:()=>X1,deprecatedAliasShouldSuppress:()=>W0});function W0($){let Q=$[0];if(Q!==void 0&&H3.has(Q))return!0;for(let Z of $)if(U3.has(Z))return!0;return!1}function X1($,Q,Z){if(W0(Z))return;process.stderr.write(`note: 'loki ${$}' is now 'loki ${Q}'. The old form still works.
|
|
333
|
+
`)}var U3,H3;var K1=L(()=>{U3=new Set(["--json","-q","--quiet"]),H3=new Set(["json","csv","timeline"])});var Y0={};b(Y0,{runStats:()=>O3,computeStats:()=>B0});import{readdirSync as H0,readFileSync as G3,statSync as G0}from"fs";import{join as i}from"path";function H$($){try{if(!G0($).isFile())return null;return JSON.parse(G3($,"utf-8"))}catch{return null}}function V1($){try{return G0($).isDirectory()}catch{return!1}}function B3($){if(!V1($))return[];try{let Q=H0($).filter((Z)=>Z.startsWith("iteration-")&&Z.endsWith(".json"));return Q.sort(),Q.map((Z)=>i($,Z))}catch{return[]}}function G$($){return Math.trunc($).toLocaleString("en-US")}function q1($){let Q=Math.trunc($);if(Q<60)return`${Q}s`;let Z=Math.trunc(Q/3600),z=Math.trunc(Q%3600/60),X=Q%60;if(Z>0)return`${Z}h ${String(z).padStart(2,"0")}m`;return`${z}m ${String(X).padStart(2,"0")}s`}function e($,Q=0){let Z=Math.pow(10,Q);return Math.round($*Z)/Z}function B$($,Q){return $.toFixed(Q)}function J1($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function Y3($){let Q="N/A",Z=0,z=H$(i($,"state","orchestrator.json"));if(z&&typeof z==="object"){if(typeof z.currentPhase==="string")Q=z.currentPhase;if(typeof z.currentIteration==="number")Z=z.currentIteration}let X=i($,"metrics","efficiency"),q=B3(X),K=[];for(let j of q){let x=H$(j);if(x&&typeof x==="object")K.push(x)}if(K.length>0)Z=Math.max(Z,K.length);let W=K.reduce((j,x)=>j+(x.input_tokens??0),0),V=K.reduce((j,x)=>j+(x.output_tokens??0),0),U=W+V,H=K.reduce((j,x)=>j+(x.cost_usd??0),0),B=K.reduce((j,x)=>j+(x.duration_seconds??0),0),G=0,Y=0,O=H$(i($,"metrics","budget.json"));if(O&&typeof O==="object"){if(typeof O.budget_limit==="number")G=O.budget_limit;if(typeof O.budget_used==="number")Y=O.budget_used}let M=0,R=0,N=H$(i($,"state","quality-gates.json"));if(N&&typeof N==="object"){if(Array.isArray(N)){for(let j of N)if(R+=1,j===!0)M+=1;else if(j&&typeof j==="object"){let x=j;if(x.passed===!0||x.status==="passed")M+=1}}else for(let j of Object.values(N))if(typeof j==="boolean"){if(R+=1,j)M+=1}else if(j&&typeof j==="object"){R+=1;let x=j;if(x.passed===!0||x.status==="passed")M+=1}}let g={},u=H$(i($,"quality","gate-failure-count.json"));if(u&&typeof u==="object"&&!Array.isArray(u)){let j={};for(let[x,l]of Object.entries(u))if(typeof l==="number")j[x]=l;g=j}let w=0,E=0,s=0,r$=i($,"quality");if(V1(r$)){let j=[];try{j=H0(r$)}catch{j=[]}for(let x of j){if(!x.endsWith(".json")||x==="gate-failure-count.json")continue;let l=H$(i(r$,x));if(!l||typeof l!=="object")continue;if(!(("verdict"in l)||("approved"in l)||("reviewers"in l)))continue;w+=1;let h1=(l.verdict??"").toString().toLowerCase();if(l.approved===!0||["approved","approve","pass"].includes(h1))E+=1;else if(["revision","revise","changes_requested","reject"].includes(h1))s+=1}}return{phase:Q,iterationCount:Z,iterations:K,totalInput:W,totalOutput:V,totalTokens:U,totalCost:H,totalDuration:B,budgetLimit:G,budgetUsed:Y,gatesPassed:M,gatesTotal:R,gateFailures:g,reviewsTotal:w,reviewsApproved:E,reviewsRevision:s}}function M3($,Q){let Z=$.iterationCount,z={session:{iterations:Z,duration_seconds:$.totalDuration,phase:$.phase},tokens:{input:$.totalInput,output:$.totalOutput,total:$.totalTokens,cost_usd:e($.totalCost,2)},quality:{gates_passed:$.gatesPassed,gates_total:$.gatesTotal,reviews_total:$.reviewsTotal,reviews_approved:$.reviewsApproved,reviews_revision:$.reviewsRevision,gate_failures:$.gateFailures},efficiency:{avg_tokens_per_iteration:Z>0?e($.totalTokens/Z,0):0,avg_cost_per_iteration:Z>0?e($.totalCost/Z,2):0,avg_duration_per_iteration:Z>0?e($.totalDuration/Z,1):0},budget:{used:e($.budgetUsed,2),limit:$.budgetLimit,percent:$.budgetLimit>0?e($.budgetUsed/$.budgetLimit*100,1):0}};if(Q)z.iterations=$.iterations.map((K,W)=>({number:W+1,input_tokens:K.input_tokens??0,output_tokens:K.output_tokens??0,cost_usd:e(K.cost_usd??0,2),duration_seconds:K.duration_seconds??0}));let X=JSON.stringify(z,null,2);function q(K,W){if(!W)return;let V=new RegExp(`("${K}": )(-?\\d+)(,?)$`,"m");X=X.replace(V,(U,H,B,G)=>`${H}${B}.0${G}`)}if(q("avg_duration_per_iteration",Z>0&&Number.isInteger(z.efficiency.avg_duration_per_iteration)),q("percent",$.budgetLimit>0&&Number.isInteger(z.budget.percent)),q("cost_usd",Z>0&&Number.isInteger(z.tokens.cost_usd)),Q)X=X.replace(/("cost_usd": )(-?\d+)(,?)$/gm,(K,W,V,U)=>`${W}${V}.0${U}`);return X}function T3($,Q){let Z=[];if(Z.push("Loki Mode Session Statistics"),Z.push("============================"),Z.push(""),Z.push("Session"),Z.push(` Iterations completed: ${$.iterationCount}`),Z.push(` Duration: ${q1($.totalDuration)}`),Z.push(` Current phase: ${$.phase}`),Z.push(""),Z.push("Token Usage"),$.iterations.length>0)Z.push(` Input tokens: ${G$($.totalInput)}`),Z.push(` Output tokens: ${G$($.totalOutput)}`),Z.push(` Total tokens: ${G$($.totalTokens)}`),Z.push(` Estimated cost: $${B$($.totalCost,2)}`);else Z.push(" N/A (no iteration metrics found)");if(Z.push(""),Z.push("Quality Gates"),$.gatesTotal>0){let z=Math.round($.gatesPassed/$.gatesTotal*100);Z.push(` Gates passed: ${$.gatesPassed}/${$.gatesTotal} (${z}%)`)}else Z.push(" Gates passed: N/A");if($.reviewsTotal>0){let z=[];if($.reviewsApproved>0)z.push(`${$.reviewsApproved} approved`);if($.reviewsRevision>0)z.push(`${$.reviewsRevision} revision requested`);let X=z.length>0?z.join(", "):"N/A";Z.push(` Code reviews: ${$.reviewsTotal} (${X})`)}if(Object.keys($.gateFailures).length>0){let z=Object.entries($.gateFailures).filter(([,X])=>X>0).map(([X,q])=>`${X} (${q})`);if(z.length>0)Z.push(` Gate failures: ${z.join(", ")}`)}if(Z.push(""),Z.push("Efficiency"),$.iterationCount>0&&$.iterations.length>0){let z=Math.round($.totalTokens/$.iterationCount),X=$.totalCost/$.iterationCount,q=$.totalDuration/$.iterationCount;Z.push(` Avg tokens/iteration: ${G$(z)}`),Z.push(` Avg cost/iteration: $${B$(X,2)}`),Z.push(` Avg duration/iteration: ${q1(q)}`)}else Z.push(" N/A (no iteration metrics found)");if(Z.push(""),Z.push("Budget"),$.budgetLimit>0){let z=e($.budgetUsed/$.budgetLimit*100,1),X=Number.isInteger(z)?`${z}.0`:`${z}`;Z.push(` Used: $${B$($.budgetUsed,2)} / $${B$($.budgetLimit,2)} (${X}%)`)}else if($.budgetUsed>0)Z.push(` Used: $${B$($.budgetUsed,2)} (no limit set)`);else Z.push(" N/A");if(Q&&$.iterations.length>0)Z.push(""),Z.push("Per-Iteration Breakdown"),$.iterations.forEach((z,X)=>{let q=X+1,K=J1(G$(z.input_tokens??0),10),W=J1(G$(z.output_tokens??0),10),V=z.cost_usd??0,U=q1(z.duration_seconds??0),H=J1(`${q}`,3);Z.push(` #${H} input: ${K} output: ${W} cost: $${B$(V,2)} time: ${U}`)});return Z.join(`
|
|
334
|
+
`)}function B0($){let Q=!1,Z=!1;for(let K of $)if(K==="--json")Q=!0;else if(K==="--efficiency")Z=!0;let z=P();if(!V1(z)){if(Q)return{exitCode:0,stdout:'{"error": "No active session"}'};return{exitCode:0,stdout:`${_}No active session found.${J}
|
|
335
|
+
Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?M3(X,Z):T3(X,Z)}}async function O3($){let{emitDeprecatedAlias:Q}=await Promise.resolve().then(() => (K1(),U0));Q("stats","report session",$);let Z=B0($);return console.log(Z.stdout),Z.exitCode}var M0=L(()=>{C();c()});var P0={};b(P0,{runDoctor:()=>C3,pythonImportOk:()=>B1,httpReachable:()=>U1,checkTool:()=>w0,checkSkills:()=>_0,checkDisk:()=>G1,buildDoctorJson:()=>L0,_setPythonImportOkForTest:()=>F3});import{existsSync as T0,lstatSync as A3,readFileSync as w3,readlinkSync as _3,statfsSync as I3}from"fs";import{spawnSync as L3}from"child_process";import{homedir as H1}from"os";import{resolve as W1}from"path";function j3($){let Q=$.match(P3);return Q?Q[1]:null}async function O0($){try{let Q=await F([$,"--version"],{timeoutMs:5000}),Z=(Q.stdout||Q.stderr||"").trim();return j3(Z)}catch{return null}}function A0($,Q){let Z=$.split(".").map((X)=>parseInt(X,10)),z=Q.split(".").map((X)=>parseInt(X,10));while(Z.length<2)Z.push(0);while(z.length<2)z.push(0);for(let X=0;X<2;X++){let q=Z[X]??0,K=z[X]??0;if(Number.isNaN(q)||Number.isNaN(K))return 0;if(q!==K)return q-K}return 0}async function w0($,Q,Z,z=null){let X=await f(Q),q=X!==null,K=q?await O0(Q):null,W="pass";if(!q)W=Z==="required"?"fail":"warn";else if(z&&K){if(A0(K,z)<0)W=Z==="required"?"fail":"warn"}return{name:$,command:Q,found:q,version:K,required:Z,min_version:z,status:W,path:X}}function G1(){let $=null;try{let Z=I3(H1()),z=Number(Z.bavail)*Number(Z.bsize);$=Math.round(z/1073741824*10)/10}catch{$=null}let Q="pass";if($!==null){if($<1)Q="fail";else if($<5)Q="warn"}return{available_gb:$,status:Q}}async function U1($,Q=2000){try{return(await fetch($,{signal:AbortSignal.timeout(Q)})).ok}catch{return!1}}async function B1($,Q=!1){let Z=`import ${$}`,z=Q?30000:5000;if(!Q)return(await z$(Z,{timeoutMs:z})).exitCode===0;let X=await Z$();if(!X)return!1;return(await F([X,"-c",Z],{timeoutMs:z})).exitCode===0}function F3($){v$.fn=$??B1}function _0(){let $=H1();return k3.map(({name:Q,dir:Z})=>{let z=W1($,Z),X=z,q=W1(z,"SKILL.md");if(T0(q))return{name:Q,path:X,status:"pass",detail:""};try{if(A3(z).isSymbolicLink()){let W="unknown";try{W=_3(z)}catch{}return{name:Q,path:X,status:"fail",detail:`(broken symlink -> ${W})`}}}catch{}return{name:Q,path:X,status:"warn",detail:"(not found - run 'loki setup-skill')"}})}async function I0(){return Promise.all(R3.map(async($)=>{return{...await w0($.jsonName,$.cmd,$.required,$.min??null),displayName:$.displayName}}))}async function E3(){let Q=await f("sentrux")!==null,Z=Q?await O0("sentrux"):null;return{found:Q,version:Z,status:Q?"pass":"warn",required:"optional"}}async function x3(){let{openSync:$,statSync:Q,readSync:Z,closeSync:z,existsSync:X}=await import("fs"),{join:q}=await import("path"),K=65536,W=process.env.LOKI_DIR??".loki",V=q(W,"memory",".errors.log"),U=[],H=!1;try{if(X(V)){H=!0;let B=Q(V).size,G=Math.max(0,B-65536),Y=B-G,O=Buffer.alloc(Y),M=$(V,"r");try{Z(M,O,0,Y,G)}finally{z(M)}let N=O.toString("utf-8").split(`
|
|
336
|
+
`);if(G>0&&N.length>0)N=N.slice(1);N=N.map((g)=>g.trim()).filter((g)=>g.length>0),U=N.slice(-5)}}catch{U=[]}return{errors_log_path:H?V:null,recent_errors:U,recent_error_count:U.length,status:U.length===0?"pass":"warn"}}async function L0(){let Q=(await I0()).map(({displayName:V,...U})=>U),Z=G1(),z=await E3(),X=await x3(),q=0,K=0,W=0;for(let V of Q)if(V.status==="pass")q++;else if(V.status==="fail")K++;else W++;if(Z.status==="pass")q++;else if(Z.status==="fail")K++;else W++;return{loki_mode_version:N$(),checks:Q,disk:Z,sentrux:z,memory:X,summary:{passed:q,failed:K,warnings:W,ok:K===0}}}function N3(){try{let $=process.env.CLAUDE_CONFIG_DIR||`${H1()}/.claude`,Q=w3(`${$}/.credentials.json`,"utf8");if(!Q)return!1;let Z=JSON.parse(Q)?.claudeAiOauth?.expiresAt;return typeof Z==="number"&&Z>0&&Z/1000<=Date.now()/1000+60}catch{return!1}}function A($){switch($){case"pass":return`${S}PASS${J}`;case"fail":return`${T}FAIL${J}`;case"warn":return`${_}WARN${J}`}}function h$($){let Q=$.version?` (v${$.version})`:"",Z=$.displayName;if(!$.found){let z=$.required==="required"?"not found":$.required==="recommended"?"not found (recommended)":"not found (optional)";return` ${A($.status)} ${Z} - ${z}`}if($.min_version&&$.version&&A0($.version,$.min_version)<0){let z=$.required==="required"?"requires":"recommended";return` ${A($.status)} ${Z}${Q} - ${z} >= ${$.min_version}`}return` ${A($.status)} ${Z}${Q}`}function y$($,Q){if(Q==="pass")$.pass++;else if(Q==="fail")$.fail++;else $.warn++}function S3(){process.stdout.write(`${k}loki doctor${J} - Check system prerequisites
|
|
337
337
|
|
|
338
338
|
`),process.stdout.write(`Usage: loki doctor [--json]
|
|
339
339
|
|
|
@@ -342,22 +342,23 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
342
342
|
|
|
343
343
|
`),process.stdout.write(`Checks: node, python3, jq, git, curl, bash version,
|
|
344
344
|
`),process.stdout.write(` claude/codex CLIs, and disk space.
|
|
345
|
-
`)}async function
|
|
345
|
+
`)}async function D3(){process.stdout.write(`${k}Loki Mode Doctor${J}
|
|
346
346
|
|
|
347
347
|
`),process.stdout.write(`Checking system prerequisites...
|
|
348
348
|
|
|
349
349
|
`);let $={pass:0,fail:0,warn:0},Q=await I0(),Z=new Map(Q.map((w)=>[w.command,w]));process.stdout.write(`${I}Required:${J}
|
|
350
|
-
`);for(let w of["node","python3","jq","git","curl"]){let
|
|
351
|
-
`),y$($,
|
|
350
|
+
`);for(let w of["node","python3","jq","git","curl"]){let E=Z.get(w);process.stdout.write(h$(E)+`
|
|
351
|
+
`),y$($,E.status)}process.stdout.write(`
|
|
352
352
|
`),process.stdout.write(`${I}AI Providers:${J}
|
|
353
|
-
`);let z=["claude","codex","cline","aider"],X={claude:"npm install -g @anthropic-ai/claude-code",codex:"npm install -g @openai/codex",cline:"npm install -g cline",aider:"pip install aider-chat"},q=!1;for(let w of z){let
|
|
354
|
-
`),!
|
|
355
|
-
`);if(y$($,
|
|
353
|
+
`);let z=["claude","codex","cline","aider"],X={claude:"npm install -g @anthropic-ai/claude-code",codex:"npm install -g @openai/codex",cline:"npm install -g cline",aider:"pip install aider-chat"},q=!1;for(let w of z){let E=Z.get(w);if(process.stdout.write(h$(E)+`
|
|
354
|
+
`),!E.found&&X[w])process.stderr.write(` ${_}Install: ${X[w]}${J}
|
|
355
|
+
`);if(y$($,E.status),E.found)q=!0}if(!q){if(process.stdout.write(` ${A("fail")} No AI provider CLI installed -- at least one is required
|
|
356
356
|
`),process.stdout.write(` ${_}Install: npm install -g @anthropic-ai/claude-code${J}
|
|
357
|
-
`),$.fail++,process.stdout.isTTY){let w=W1(h,"autonomy/provider-offer.sh");if(
|
|
357
|
+
`),$.fail++,process.stdout.isTTY){let w=W1(h,"autonomy/provider-offer.sh");if(T0(w))L3("bash",[w,"report"],{stdio:"inherit"})}}process.stdout.write(`
|
|
358
358
|
`),process.stdout.write(`${I}API Keys:${J}
|
|
359
359
|
`);let K=Z.get("claude")?.found??!1,W=Z.get("codex")?.found??!1,V=process.env;if(V.ANTHROPIC_API_KEY)process.stdout.write(` ${A("pass")} ANTHROPIC_API_KEY is set
|
|
360
|
-
`),$.pass++;else if(K)process.stdout.write(` ${
|
|
360
|
+
`),$.pass++;else if(K)if(N3())process.stdout.write(` ${A("warn")} Claude login has EXPIRED -- run 'claude login' before a build (it would otherwise stall)
|
|
361
|
+
`),$.warn++;else process.stdout.write(` ${y} -- ${J} ANTHROPIC_API_KEY not set (Claude CLI uses its own login)
|
|
361
362
|
`);if(V.OPENAI_API_KEY)process.stdout.write(` ${A("pass")} OPENAI_API_KEY is set
|
|
362
363
|
`),$.pass++;else if(W)process.stdout.write(` ${y} -- ${J} OPENAI_API_KEY not set (Codex CLI uses its own login)
|
|
363
364
|
`);if(V.ANTHROPIC_BASE_URL){let w=V.ANTHROPIC_BASE_URL;if(process.stdout.write(` ${A("pass")} ANTHROPIC_BASE_URL: ${w}
|
|
@@ -379,7 +380,7 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
379
380
|
`),$.pass++;else process.stdout.write(` ${A("warn")} sentence-transformers - not installed (loki memory vectors setup)
|
|
380
381
|
`),$.warn++;if(await U1("http://localhost:8100/api/v2/heartbeat"))process.stdout.write(` ${A("pass")} ChromaDB server (port 8100)
|
|
381
382
|
`),$.pass++;else process.stdout.write(` ${A("warn")} ChromaDB - not running (docker start loki-chroma)
|
|
382
|
-
`),$.warn++;{let w=["pyright-langserver","pylsp","typescript-language-server","gopls","rust-analyzer","jdtls"],
|
|
383
|
+
`),$.warn++;{let w=["pyright-langserver","pylsp","typescript-language-server","gopls","rust-analyzer","jdtls"],E=[];for(let s of w)if(await f(s))E.push(s);if(E.length>0)process.stdout.write(` ${A("pass")} LSP servers detected (${E.length}): ${E.join(", ")}
|
|
383
384
|
`),$.pass++;else process.stdout.write(` ${A("warn")} LSP servers - none on PATH (install for symbol grounding: npm i -g pyright typescript-language-server; brew install gopls)
|
|
384
385
|
`),$.warn++}let G=process.env.LOKI_MIROFISH_URL;if(G)if(await U1(`${G}/health`))process.stdout.write(` ${A("pass")} MiroFish server (${G})
|
|
385
386
|
`),$.pass++;else process.stdout.write(` ${A("warn")} MiroFish - not running (loki start --mirofish-docker <image>)
|
|
@@ -391,7 +392,7 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
391
392
|
`),process.stdout.write(`${I}System:${J}
|
|
392
393
|
`);let Y=Z.get("bash");process.stdout.write(h$(Y)+`
|
|
393
394
|
`),y$($,Y.status);let O=Z.get("bun");if(O)process.stdout.write(h$(O)+`
|
|
394
|
-
`),y$($,O.status);let M=
|
|
395
|
+
`),y$($,O.status);let M=G1(),R=M.available_gb===null?null:Math.floor(M.available_gb);if(R===null)process.stdout.write(` ${A("warn")} Disk space: unable to determine
|
|
395
396
|
`),$.warn++;else if(M.status==="fail")process.stdout.write(` ${A("fail")} Disk space: ${R}GB available (need >= 1GB)
|
|
396
397
|
`),$.fail++;else if(M.status==="warn")process.stdout.write(` ${A("warn")} Disk space: ${R}GB available (low)
|
|
397
398
|
`),$.warn++;else process.stdout.write(` ${A("pass")} Disk space: ${R}GB available
|
|
@@ -401,8 +402,8 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
401
402
|
`),process.env.LOKI_LEGACY_BASH==="1"||process.env.LOKI_LEGACY_BASH==="true")process.stdout.write(` ${A("warn")} LOKI_LEGACY_BASH set: shim routes every command to autonomy/loki (bash)
|
|
402
403
|
`);if(process.env.LOKI_TS_ENTRY)process.stdout.write(` ${A("pass")} LOKI_TS_ENTRY override: ${process.env.LOKI_TS_ENTRY}
|
|
403
404
|
`);if(process.env.BUN_FROM_SOURCE==="1"||process.env.BUN_FROM_SOURCE==="true")process.stdout.write(` ${A("pass")} BUN_FROM_SOURCE set: shim prefers loki-ts/src/ over dist/
|
|
404
|
-
`);let u=await Z$();if(u!==null){let
|
|
405
|
-
`);else if(
|
|
405
|
+
`);let u=await Z$();if(u!==null){let E=(await F([u,"-c","import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')"],{timeoutMs:5000})).stdout.trim();if(E.startsWith("3.12"))process.stdout.write(` ${A("pass")} Python 3.12 (chromadb / sentence-transformers): ${E} at ${u}
|
|
406
|
+
`);else if(E)process.stdout.write(` ${A("warn")} Python 3.12 recommended for memory vector search (chromadb / sentence-transformers); found ${E} at ${u}. Core memory and the rest of Loki work without it. Install: brew install python@3.12 (macOS) or apt install python3.12 (Debian/Ubuntu).
|
|
406
407
|
`);else process.stdout.write(` ${A("warn")} Python 3 found at ${u} but version probe failed; memory vector search (chromadb / sentence-transformers) may not work. The rest of Loki is unaffected.
|
|
407
408
|
`)}else process.stdout.write(` ${A("warn")} Python 3 not on PATH -- memory + MCP integrations disabled. The rest of Loki works without them.
|
|
408
409
|
`);if(process.stdout.write(`
|
|
@@ -415,15 +416,15 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
415
416
|
`);return process.stdout.write(`
|
|
416
417
|
`),process.stdout.write(`Next: loki quickstart (guided first build from your idea, no PRD needed)
|
|
417
418
|
`),process.stdout.write(` or loki demo (builds a sample todo app end to end) or loki start ./prd.md
|
|
418
|
-
`),0}async function
|
|
419
|
+
`),0}async function C3($){let Q=!1;for(let Z of $)if(Z==="--json")Q=!0;else if(Z==="--help"||Z==="-h")return S3(),0;else return process.stderr.write(`${T}Unknown option: ${Z}${J}
|
|
419
420
|
`),process.stderr.write(`Usage: loki doctor [--json]
|
|
420
421
|
`),1;if(Q){let Z=await L0();return process.stdout.write(JSON.stringify(Z,null,2)+`
|
|
421
|
-
`),0}return
|
|
422
|
-
`)}var h0=L(()=>{S0()});var
|
|
422
|
+
`),0}return D3()}var P3,v$,k3,R3;var j0=L(()=>{C();d();V$();c();$1();P3=/(\d+\.\d+(?:\.\d+)*)/;v$={fn:B1};k3=[{name:"Claude Code",dir:".claude/skills/loki-mode"},{name:"Codex CLI",dir:".codex/skills/loki-mode"},{name:"Cline CLI",dir:".cline/skills/loki-mode"},{name:"Aider CLI",dir:".aider/skills/loki-mode"}];R3=[{displayName:"Node.js (>= 18)",jsonName:"Node.js",cmd:"node",required:"required",min:"18.0"},{displayName:"Python 3 (>= 3.8)",jsonName:"Python 3",cmd:"python3",required:"required",min:"3.8"},{displayName:"jq",jsonName:"jq",cmd:"jq",required:"required"},{displayName:"git",jsonName:"git",cmd:"git",required:"required"},{displayName:"curl",jsonName:"curl",cmd:"curl",required:"required"},{displayName:"bash (>= 4.0)",jsonName:"bash",cmd:"bash",required:"recommended",min:"4.0"},{displayName:"Bun (>= 1.3)",jsonName:"Bun",cmd:"bun",required:"recommended",min:"1.3"},{displayName:"Claude CLI",jsonName:"Claude CLI",cmd:"claude",required:"optional"},{displayName:"Codex CLI",jsonName:"Codex CLI",cmd:"codex",required:"optional"},{displayName:"Cline CLI",jsonName:"Cline CLI",cmd:"cline",required:"optional"},{displayName:"Aider CLI",jsonName:"Aider CLI",cmd:"aider",required:"optional"}]});import{existsSync as R0,mkdirSync as m9,readdirSync as b3,readFileSync as E0,renameSync as f9,writeFileSync as u9}from"fs";import{dirname as h3,join as y3,resolve as v3}from"path";import{fileURLToPath as g3}from"url";function m3(){try{let $=h3(g3(import.meta.url)),Q=v3($,"..","..","data","model-pricing.json");if(!R0(Q))return _$;let z=JSON.parse(E0(Q,"utf8")).pricing;if(!z||typeof z!=="object")return _$;let X={};for(let[q,K]of Object.entries(z))if(K!==null&&typeof K==="object"&&typeof K.input==="number"&&typeof K.output==="number")X[q]={input:K.input,output:K.output};for(let q of Object.keys(_$))if(!(q in X))return _$;return X}catch{return _$}}function f3($){return Math.round(($+Number.EPSILON)*1e4)/1e4}function u3($){let Q=($??k0).toLowerCase();return F0[Q]??F0[k0]}function x0($){let Q=0;for(let Z of $){if(typeof Z.cost_usd==="number"&&Number.isFinite(Z.cost_usd)){Q+=Z.cost_usd;continue}let z=u3(Z.model),X=typeof Z.input_tokens==="number"?Z.input_tokens:0,q=typeof Z.output_tokens==="number"?Z.output_tokens:0;Q+=X/1e6*z.input+q/1e6*z.output}return f3(Q)}function N0($){if(!R0($))return[];let Q=[],Z;try{Z=b3($)}catch{return[]}for(let z of Z){if(!z.endsWith(".json"))continue;let X=y3($,z);try{let q=E0(X,"utf8"),K=JSON.parse(q);if(K&&typeof K==="object")Q.push(K)}catch{}}return Q}var _$,F0,k0="sonnet";var S0=L(()=>{C();_$={fable:{input:10,output:50},opus:{input:5,output:25},sonnet:{input:3,output:15},haiku:{input:1,output:5},"gpt-5.3-codex":{input:1.5,output:12}};F0=Object.freeze(m3())});import{existsSync as g$,readdirSync as c3,readFileSync as p3,statSync as l3}from"fs";import{join as m$}from"path";function d3($){let Q=[],Z=m$($,"votes");if(!g$(Z))return Q;let z;try{z=c3(Z)}catch{return Q}for(let X of z){if(!X.startsWith("round-")||!X.endsWith(".json"))continue;try{let q=m$(Z,X);if(!l3(q).isFile())continue;let K=JSON.parse(p3(q,"utf8"));Q.push({iteration:typeof K.iteration==="number"?K.iteration:void 0,verdict:typeof K.verdict==="string"?K.verdict:void 0,complete_votes:typeof K.complete_votes==="number"?K.complete_votes:void 0,total_members:typeof K.total_members==="number"?K.total_members:void 0,threshold:typeof K.threshold==="number"?K.threshold:void 0})}catch{}}return Q}function o3(){return{iteration_count:0,total_cost_usd:0,avg_cost_per_iteration:null,total_input_tokens:0,total_output_tokens:0,total_duration_ms:0,avg_duration_ms_per_iteration:null,model_breakdown:{},phase_breakdown:{},status_breakdown:{}}}function n3(){return{council_rounds:0,unanimous_rate:null,approval_rate:null,iteration_success_rate:null}}function a3($){let Q=o3();if($.length===0)return Q;Q.iteration_count=$.length,Q.total_cost_usd=Math.round(x0($)*1e4)/1e4;for(let Z of $){if(typeof Z.input_tokens==="number")Q.total_input_tokens+=Z.input_tokens;if(typeof Z.output_tokens==="number")Q.total_output_tokens+=Z.output_tokens;let z=Z;if(typeof z.duration_ms==="number")Q.total_duration_ms+=z.duration_ms;if(typeof Z.model==="string")Q.model_breakdown[Z.model]=(Q.model_breakdown[Z.model]??0)+1;if(typeof z.phase==="string")Q.phase_breakdown[z.phase]=(Q.phase_breakdown[z.phase]??0)+1;if(typeof z.status==="string")Q.status_breakdown[z.status]=(Q.status_breakdown[z.status]??0)+1}return Q.avg_cost_per_iteration=Math.round(Q.total_cost_usd/Q.iteration_count*1e4)/1e4,Q.avg_duration_ms_per_iteration=Math.round(Q.total_duration_ms/Q.iteration_count),Q}function s3($,Q,Z){let z=n3();if(z.council_rounds=$.length,$.length>0){let X=0,q=0;for(let K of $){if(typeof K.complete_votes==="number"&&typeof K.total_members==="number"&&K.total_members>0&&K.complete_votes===K.total_members)X+=1;if(K.verdict==="COMPLETE")q+=1}z.unanimous_rate=Math.round(X/$.length*1e4)/1e4,z.approval_rate=Math.round(q/$.length*1e4)/1e4}if(Z>0)z.iteration_success_rate=Math.round(Q/Z*1e4)/1e4;return z}function D0($){let Q=[],Z=m$($,"metrics","efficiency"),z=m$($,"council"),X=g$(Z)?N0(Z):[];if(!g$(Z))Q.push("no .loki/metrics/efficiency/ dir (efficiency KPIs zeroed)");else if(X.length===0)Q.push(".loki/metrics/efficiency/ exists but no iteration files found");let q=d3(z);if(!g$(z))Q.push("no .loki/council/ dir (accuracy KPIs zeroed)");else if(q.length===0)Q.push(".loki/council/ exists but no round-N.json files found");let K=a3(X),W=K.status_breakdown.success??0,V=s3(q,W,K.iteration_count);return{schema_version:1,generated_at:new Date().toISOString(),loki_dir:$,efficiency:K,accuracy:V,notes:Q}}function C0($){return JSON.stringify($,null,2)}function b0($){let Q=[];Q.push(`Loki Mode KPIs (snapshot at ${$.generated_at})`),Q.push(`Source: ${$.loki_dir}`),Q.push(""),Q.push("Efficiency"),Q.push(` Iterations: ${$.efficiency.iteration_count}`),Q.push(` Total cost USD: ${$.efficiency.total_cost_usd}`),Q.push(` Avg cost per iter: ${$.efficiency.avg_cost_per_iteration??"n/a"}`),Q.push(` Total input tokens: ${$.efficiency.total_input_tokens}`),Q.push(` Total output tokens: ${$.efficiency.total_output_tokens}`),Q.push(` Total duration (ms): ${$.efficiency.total_duration_ms}`),Q.push(` Avg duration / iter: ${$.efficiency.avg_duration_ms_per_iteration??"n/a"}`);let Z=Object.entries($.efficiency.model_breakdown).sort((q,K)=>q[0].localeCompare(K[0]));if(Z.length>0)Q.push(` Model breakdown: ${Z.map(([q,K])=>`${q}=${K}`).join(", ")}`);let z=Object.entries($.efficiency.phase_breakdown).sort((q,K)=>q[0].localeCompare(K[0]));if(z.length>0)Q.push(` Phase breakdown: ${z.map(([q,K])=>`${q}=${K}`).join(", ")}`);let X=Object.entries($.efficiency.status_breakdown).sort((q,K)=>q[0].localeCompare(K[0]));if(X.length>0)Q.push(` Status breakdown: ${X.map(([q,K])=>`${q}=${K}`).join(", ")}`);if(Q.push(""),Q.push("Accuracy"),Q.push(` Council rounds: ${$.accuracy.council_rounds}`),Q.push(` Unanimous rate: ${$.accuracy.unanimous_rate??"n/a"}`),Q.push(` Approval rate: ${$.accuracy.approval_rate??"n/a"}`),Q.push(` Iter success rate: ${$.accuracy.iteration_success_rate??"n/a"}`),$.notes.length>0){Q.push(""),Q.push("Notes");for(let q of $.notes)Q.push(` - ${q}`)}return Q.push(""),Q.push("See also: loki trust (trust trajectory across runs)"),Q.join(`
|
|
423
|
+
`)}var h0=L(()=>{S0()});var Y1={};b(Y1,{runKpis:()=>r3});function r3($,Q={}){if(Q.aliasOf)X1(Q.aliasOf,"report kpis",$);let Z=!1;for(let X of $){if(X==="--help"||X==="-h"||X==="help")return process.stdout.write(t3),0;if(X==="--json"){Z=!0;continue}if(X==="-q"||X==="--quiet")continue;return process.stderr.write(`loki kpis: unknown arg: ${X}
|
|
423
424
|
Run 'loki kpis --help' for usage.
|
|
424
425
|
`),1}let z=D0(P());return process.stdout.write(Z?C0(z)+`
|
|
425
426
|
`:b0(z)+`
|
|
426
|
-
`),0}var
|
|
427
|
+
`),0}var t3=`loki report kpis -- accuracy + efficiency KPI snapshot (v7.5.28 MVP)
|
|
427
428
|
|
|
428
429
|
Usage:
|
|
429
430
|
loki report kpis Pretty-print KPI snapshot
|
|
@@ -444,13 +445,13 @@ iteration success rate.
|
|
|
444
445
|
This is the Phase K MVP -- read-only derivation. Per-iteration
|
|
445
446
|
emission, dashboard panel, and the loki-bench harness are deferred
|
|
446
447
|
follow-ups (see project_v7_5_18_arc_status.md).
|
|
447
|
-
`;var
|
|
448
|
-
`)}Q.push("Is the agent earning autonomy on this repo?");for(let X of f$)if($.axes[X])Q.push(
|
|
449
|
-
`)}var
|
|
448
|
+
`;var M1=L(()=>{h0();C();K1()});var y0={};b(y0,{delegateToBash:()=>$6});import{resolve as i3}from"path";async function $6($){let Q=i3(h,"autonomy","loki"),Z=Bun.spawn({cmd:[Q,...$],stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,LOKI_LEGACY_BASH:"1"}}),z=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},e3);try{return await Z.exited}finally{clearTimeout(z)}}var e3=3600000;var v0=L(()=>{C()});import{existsSync as Q6,mkdirSync as Z6,readdirSync as z6,readFileSync as X6,statSync as K6,writeFileSync as q6}from"fs";import{join as I$}from"path";function T1($){return $&&typeof $==="object"?$:{}}function X$($){return Math.round($*1e4)/1e4}function H6($){let Q=String($??"").trim().toUpperCase();if(!Q)return null;for(let Z of m0)if(Q.startsWith(Z))return!0;return!1}function G6($){let Q=H6($.final_verdict);if(Q!==null)return Q?1:0;let Z=$.reviewers;if(Array.isArray(Z)&&Z.length>0){let z=0,X=0;for(let q of Z){if(!q||typeof q!=="object")continue;X+=1;let K=String(q.vote??"").trim().toUpperCase();if(m0.some((W)=>K.startsWith(W)))z+=1}if(X>0)return z===X?1:0}return null}function B6($){let Q=Number($.total),Z=Number($.passed);if(!Number.isFinite(Q)||!Number.isFinite(Z))return null;if(Q<=0)return null;return Math.max(0,Math.min(1,Z/Q))}function Y6($){let Q;if($&&typeof $==="object")Q=$.count;else Q=$;let Z=Number(Q);if(!Number.isFinite(Z)||Z<0)return null;return Z}function M6($){let Q=T1($.council);for(let Z of[Q.interventions,$.interventions]){let z=Number(Z);if(Number.isFinite(z)&&z>=0)return z}return null}function T6($){let Q=I$($,"proofs"),Z=[];if(!Q6(Q))return Z;let z;try{z=z6(Q).sort()}catch{return Z}for(let X of z){let q=I$(Q,X);try{if(!K6(q).isDirectory())continue}catch{continue}let K=null;try{K=JSON.parse(X6(I$(q,"proof.json"),"utf8"))}catch{continue}if(!K||typeof K!=="object")continue;Z.push({run_id:String(K.run_id??X),generated_at:typeof K.generated_at==="string"?K.generated_at:null,council_pass_rate:G6(T1(K.council)),gate_pass_rate:B6(T1(K.quality_gates)),iterations:Y6(K.iterations),interventions:M6(K)})}return Z.sort((X,q)=>{let K=X.generated_at===null?1:0,W=q.generated_at===null?1:0;if(K!==W)return K-W;return(X.generated_at??"").localeCompare(q.generated_at??"")}),Z}function g0($){return $.reduce((Q,Z)=>Q+Z,0)/$.length}function O6($,Q){let Z=V6[$],z=W6[$],X=U6[$],q=Q.filter((M)=>M!==null),K=q.length;if(K===0)return{axis:$,label:X,available:!1,higher_is_better:Z,note:"no runs recorded this metric"};if(K<2)return{axis:$,label:X,available:!0,higher_is_better:Z,data_points:K,latest:X$(q[K-1]),direction:"flat",improving:null,delta:0,earlier_mean:X$(q[0]),later_mean:X$(q[K-1]),insufficient:!0,note:"not enough history yet (need 2+ runs with this metric)"};let W=Math.floor(K/2),V=q.slice(0,W),U=q.slice(K-W),H=g0(V),B=g0(U),G=B-H,Y;if(Math.abs(G)<=z)Y="flat";else if(G>0)Y="up";else Y="down";let O;if(Y==="flat")O=null;else O=Y==="up"===Z;return{axis:$,label:X,available:!0,higher_is_better:Z,data_points:K,latest:X$(q[K-1]),direction:Y,improving:O,delta:X$(G),earlier_mean:X$(H),later_mean:X$(B),insufficient:!1}}function f0($){let Q=T6($),Z=Q.map((V)=>({run_id:V.run_id,generated_at:V.generated_at,council_pass_rate:V.council_pass_rate,gate_pass_rate:V.gate_pass_rate,iterations:V.iterations,interventions:V.interventions})),z={};for(let V of f$)z[V]=O6(V,Q.map((U)=>U[V]));let X=Q.length<2,q=f$.filter((V)=>z[V].available&&z[V].improving===!0),K=f$.filter((V)=>z[V].available&&z[V].improving===!1),W=[];if(X)W.push(`not enough history yet: ${Q.length} run(s) recorded, need 2+ to show a trend`);if(!z.interventions.available)W.push("intervention trend unavailable: no per-run intervention count in proof.json yet (axis lights up automatically once recorded)");return{schema_version:J6,generated_at:new Date().toISOString(),loki_dir:$,runs_count:Q.length,insufficient:X,axes:z,improving_count:q.length,regressing_count:K.length,improving_axes:q,regressing_axes:K,series:Z,notes:W}}function u0($){return JSON.stringify($,null,2)}function c0($,Q){let Z=I$($,"metrics"),z=I$(Z,"trust-trajectory.json");try{return Z6(Z,{recursive:!0}),q6(z,JSON.stringify(Q,null,2)),z}catch{return null}}function A6($){if($==="up")return"up";if($==="down")return"down";return"flat"}function w6($){let Q=$.label??$.axis;if(!$.available)return` ${(Q+":").padEnd(26)} no data`;let Z;if($.insufficient)Z="(need 2+ runs)";else if($.improving===!0)Z="improving";else if($.improving===!1)Z="regressing";else Z="stable";let z=$.higher_is_better?"higher better":"lower better",X=$.latest??"n/a";return` ${(Q+":").padEnd(26)} ${A6($.direction).padEnd(5)} latest=${String(X).padEnd(7)} ${Z.padEnd(11)} [${z}]`}function p0($){let Q=[];if(Q.push(`Loki Mode Trust Trajectory (snapshot at ${$.generated_at})`),Q.push(`Source: ${$.loki_dir}`),Q.push(`Runs analyzed: ${$.runs_count}`),Q.push(""),$.insufficient){if(Q.push("Not enough history yet."),Q.push("Trust trajectory needs 2+ recorded runs to show a direction."),Q.push("Each `loki start` run writes a proof-of-run; come back after the next run."),$.notes.length>0){Q.push(""),Q.push("Notes");for(let X of $.notes)Q.push(` - ${X}`)}return Q.join(`
|
|
449
|
+
`)}Q.push("Is the agent earning autonomy on this repo?");for(let X of f$)if($.axes[X])Q.push(w6($.axes[X]));Q.push("");let{improving_count:Z,regressing_count:z}=$;if(Z&&!z)Q.push(`Overall: trending more trustworthy (${Z} axis improving).`);else if(z&&!Z)Q.push(`Overall: trust regressing (${z} axis regressing). Review recent runs.`);else if(Z||z)Q.push(`Overall: mixed (${Z} improving / ${z} regressing).`);else Q.push("Overall: stable.");if($.notes.length>0){Q.push(""),Q.push("Notes");for(let X of $.notes)Q.push(` - ${X}`)}return Q.join(`
|
|
450
|
+
`)}var J6=1,f$,V6,W6,U6,m0;var l0=L(()=>{f$=["council_pass_rate","gate_pass_rate","iterations","interventions"],V6={council_pass_rate:!0,gate_pass_rate:!0,iterations:!1,interventions:!1},W6={council_pass_rate:0.01,gate_pass_rate:0.01,iterations:0.25,interventions:0.25},U6={council_pass_rate:"Council pass rate",gate_pass_rate:"Gate pass rate",iterations:"Iterations to completion",interventions:"Human interventions"},m0=["APPROVE","APPROVED","COMPLETE","PASS","PASSED"]});var d0={};b(d0,{runTrust:()=>I6});function I6($){let Q=!1;for(let X of $){if(X==="--help"||X==="-h"||X==="help")return process.stdout.write(_6),0;if(X==="--json"){Q=!0;continue}return process.stderr.write(`loki trust: unknown arg: ${X}
|
|
450
451
|
Run 'loki trust --help' for usage.
|
|
451
452
|
`),1}let Z=P(),z=f0(Z);return c0(Z,z),process.stdout.write(Q?u0(z)+`
|
|
452
453
|
`:p0(z)+`
|
|
453
|
-
`),0}var
|
|
454
|
+
`),0}var _6=`loki trust -- visible trust trajectory (R4)
|
|
454
455
|
|
|
455
456
|
Usage:
|
|
456
457
|
loki trust Pretty-print the per-project trust trajectory
|
|
@@ -466,20 +467,20 @@ Shows whether the agent is earning autonomy on THIS repo over time:
|
|
|
466
467
|
Derived read-only from proof-of-run history in .loki/proofs/. With fewer
|
|
467
468
|
than 2 recorded runs it reports "not enough history yet" rather than a
|
|
468
469
|
fabricated trend. Complements 'loki kpis' (single-run snapshot).
|
|
469
|
-
`;var o0=L(()=>{l0();C()});import{closeSync as L$,fstatSync as
|
|
470
|
-
`)}async function i0($,Q){let Z=u$.get($)??Promise.resolve(),z=()=>{},X=new Promise((K)=>{z=K}),q=Z.catch(()=>{}).then(()=>X);u$.set($,q);try{return await Z.catch(()=>{}),await Q()}finally{if(z(),u$.get($)===q)u$.delete($)}}function
|
|
471
|
-
`),Q}catch(Z){if(Q!==null){try{L$(Q)}catch{}try{t0($)}catch{}}if(Z?.code==="EEXIST")return null;throw Z}}function
|
|
472
|
-
`)}),
|
|
470
|
+
`;var o0=L(()=>{l0();C()});import{closeSync as L$,fstatSync as L6,fsyncSync as n0,lstatSync as P6,mkdirSync as a0,openSync as c$,readSync as j6,renameSync as F6,rmSync as s0,statSync as k6,unlinkSync as t0,writeSync as r0}from"fs";import{dirname as O1}from"path";function A1($,Q){a0(O1($),{recursive:!0});let Z=`${$}.tmp.${process.pid}.${++R6}`,z=c$(Z,"w");try{r0(z,Q),n0(z)}finally{L$(z)}F6(Z,$),E6($)}function E6($){let Q=null;try{Q=c$(O1($),"r"),n0(Q)}catch{}finally{if(Q!==null)try{L$(Q)}catch{}}}function P$($,Q){A1($,`${JSON.stringify(Q,null,2)}
|
|
471
|
+
`)}async function i0($,Q){let Z=u$.get($)??Promise.resolve(),z=()=>{},X=new Promise((K)=>{z=K}),q=Z.catch(()=>{}).then(()=>X);u$.set($,q);try{return await Z.catch(()=>{}),await Q()}finally{if(z(),u$.get($)===q)u$.delete($)}}function N6($){return`${$}.lock`}function S6($){if(!Number.isFinite($)||$<=0)return!1;try{return process.kill($,0),!0}catch(Q){return Q?.code==="EPERM"}}function D6($){let Q=null;try{return a0(O1($),{recursive:!0}),Q=c$($,"wx"),r0(Q,`${process.pid}
|
|
472
|
+
`),Q}catch(Z){if(Q!==null){try{L$(Q)}catch{}try{t0($)}catch{}}if(Z?.code==="EEXIST")return null;throw Z}}function C6($,Q){let Z;try{Z=P6($)}catch{return!0}if(Z.isSymbolicLink())try{return t0($),!0}catch{return!1}let z;try{z=c$($,"r")}catch{return!0}try{let X=L6(z);if(Date.now()-X.mtimeMs<Q)return!1;let K=NaN;try{let W=Buffer.alloc(64),V=j6(z,W,0,64,0);K=Number.parseInt(W.subarray(0,V).toString("utf-8").trim(),10)}catch{}if(Number.isFinite(K)&&S6(K))return!1;try{if(k6($).mtimeMs>X.mtimeMs)return!1}catch{return!0}try{s0($,{force:!0})}catch{}return!0}finally{try{L$(z)}catch{}}}function j$($,Q,Z={}){let z=Z.timeoutMs??1e4,X=Z.pollMs??25,q=Z.staleMs??30000,K=N6($),W=Date.now()+z,V=null,U=0,H=new Int32Array(new SharedArrayBuffer(4));while(V===null){if(V=D6(K),V!==null)break;if(Date.now()>W)throw Error(`withFileLockSync: timed out after ${z}ms acquiring ${K}`);if(C6(K,q))continue;let B=Math.min(X*2**Math.min(U,4),x6);U+=1,Atomics.wait(H,0,0,B)}try{return Q()}finally{try{L$(V)}catch{}try{s0(K,{force:!0})}catch{}}}var R6=0,u$,x6=50;var F$=L(()=>{u$=new Map});import{existsSync as K$,mkdirSync as Y$,copyFileSync as ZQ,readFileSync as I1,readdirSync as b6,statSync as h6,writeFileSync as y6,renameSync as zQ,appendFileSync as XQ,rmSync as v6}from"fs";import{join as m,dirname as p$}from"path";function m6($){let Q=$Q.then($,$);return $Q=Q.catch((Z)=>{console.warn("[checkpoint] serialized op rejected:",Z);return}),Q}function o($){return m($,"state","checkpoints")}function KQ($){return m(o($),"index.jsonl")}async function f6($){let Q=await F(["git","rev-parse","HEAD"],{cwd:$,timeoutMs:5000});if(Q.exitCode!==0)return"no-git";return Q.stdout.trim()||"no-git"}async function u6($){let Q=await F(["git","branch","--show-current"],{cwd:$,timeoutMs:5000});if(Q.exitCode!==0)return"unknown";return Q.stdout.trim()||"unknown"}async function c6($){let Q=await F(["git","diff","--quiet"],{cwd:$,timeoutMs:5000}),Z=await F(["git","diff","--cached","--quiet"],{cwd:$,timeoutMs:5000}),z=Q.exitCode===1,X=Z.exitCode===1;return z||X}function p6($){let Q=m($,"state","orchestrator.json");if(!K$(Q))return"unknown";try{let z=JSON.parse(I1(Q,"utf-8")).currentPhase;return typeof z==="string"&&z.length>0?z:"unknown"}catch{return"unknown"}}function d6($,Q){for(let Z of l6){let z=m($,Z);if(!K$(z))continue;let X=m(Q,Z);Y$(p$(X),{recursive:!0});try{ZQ(z,X)}catch{}}}function JQ($,Q){Y$(p$($),{recursive:!0});let Z=`${$}.tmp.${process.pid}.${++qQ}`;y6(Z,Q),zQ(Z,$)}function o6($){return JSON.stringify($,null,2)}function VQ($){return`{${[`"id": ${JSON.stringify($.id)}`,`"ts": ${JSON.stringify($.ts)}`,`"iter": ${JSON.stringify($.iter)}`,`"task": ${JSON.stringify($.task)}`,`"sha": ${JSON.stringify($.sha)}`].join(", ")}}`}async function n6($){return m6(()=>a6($))}async function a6($){let Q=$.lokiDirOverride??P(),Z=process.cwd(),z=o(Q);if(Y$(z,{recursive:!0}),!$.forceCreate){if(!await c6(Z))return{created:!1,reason:"no uncommitted changes"}}let X=await f6(Z),q=await u6(Z),K=$.iteration??Number.parseInt(process.env.ITERATION_COUNT??"0",10),W=$.epochOverride??Math.floor(Date.now()/1000),V=`cp-${K}-${W}`,U=m(z,V);Y$(U,{recursive:!0}),d6(Q,U);let H=new Date().toISOString().replace(/\.\d{3}Z$/,"Z"),B=($.taskDescription??"task completed").slice(0,g6),G=$.provider??process.env.PROVIDER_NAME??"claude",Y={id:V,timestamp:H,iteration:K,task_id:$.taskId??"unknown",task_description:B,git_sha:X,git_branch:q,provider:G,phase:p6(Q)};JQ(m(U,"metadata.json"),o6(Y));let O={id:Y.id,ts:Y.timestamp,iter:Y.iteration,task:Y.task_description,sha:Y.git_sha},M=KQ(Q);return j$(M,()=>{XQ(M,`${VQ(O)}
|
|
473
|
+
`)}),s6(Q),{created:!0,id:V,metadata:Y,dir:U}}function L1($){let Q=o($);if(!K$(Q))return[];return b6(Q).filter((Z)=>Z.startsWith("cp-")).filter((Z)=>{try{return h6(m(Q,Z)).isDirectory()}catch{return!1}})}function P1($){return[...$].sort((Q,Z)=>{let z=QQ(Q),X=QQ(Z);return z-X})}function QQ($){let Q=$.split("-");if(Q.length<3)return 0;let Z=Q[Q.length-1],z=Number.parseInt(Z??"0",10);return Number.isFinite(z)?z:0}function s6($){let Q=L1($);if(Q.length<=e0)return;let Z=P1(Q),z=Z.slice(0,Z.length-e0);for(let X of z)try{v6(m(o($),X),{recursive:!0,force:!0})}catch{}t6($)}function t6($){let Q=P1(L1($)),Z=[];for(let q of Q){let K=m(o($),q,"metadata.json"),W=m(o($),q);if(!K$(K)){w1($,W,"missing_field","metadata.json");continue}try{let V=JSON.parse(I1(K,"utf-8")),U=UQ(V,K);if(!U.ok){w1($,W,U.reason,U.field);continue}let H=U.value;Z.push(VQ({id:H.id,ts:H.timestamp,iter:H.iteration,task:H.task_description??"",sha:H.git_sha}))}catch{w1($,W,"invalid_type","metadata.json")}}let z=KQ($),X=Z.length>0?`${Z.join(`
|
|
473
474
|
`)}
|
|
474
|
-
`:"";JQ(z,X)}function
|
|
475
|
-
`)})}catch{}}function
|
|
475
|
+
`:"";JQ(z,X)}function w1($,Q,Z,z){let X=m($,"events.jsonl"),q={timestamp:new Date().toISOString(),type:"checkpoint.metadata.dropped",checkpoint_dir:Q,reason:Z,field:z};try{Y$(p$(X),{recursive:!0}),j$(X,()=>{XQ(X,`${JSON.stringify(q)}
|
|
476
|
+
`)})}catch{}}function j1($){let Q=$??P(),Z=P1(L1(Q)),z=[];for(let X of Z){let q=WQ(Q,X);if(q)z.push(q)}return z}function WQ($,Q){let Z=m(o($),Q,"metadata.json");if(!K$(Z))return null;try{let z=JSON.parse(I1(Z,"utf-8"));return r6(z,Z)}catch{return null}}function r6($,Q){let Z=UQ($,Q);return Z.ok?Z.value:null}function UQ($,Q){if($===null||typeof $!=="object")return console.warn(`[checkpoint] invalid metadata at ${Q}: not an object`),{ok:!1,reason:"invalid_type",field:"<root>"};let Z=$,z=["id","timestamp","task_id","task_description","git_sha","git_branch","provider","phase"];for(let X of z){if(!(X in Z))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "${X}" missing`),{ok:!1,reason:"missing_field",field:X};if(typeof Z[X]!=="string")return console.warn(`[checkpoint] invalid metadata at ${Q}: field "${X}" not a string`),{ok:!1,reason:"invalid_type",field:X}}if(!Object.prototype.hasOwnProperty.call(Z,"iteration"))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "iteration" missing`),{ok:!1,reason:"missing_field",field:"iteration"};if(typeof Z.iteration!=="number"||!Number.isFinite(Z.iteration))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "iteration" not a finite number`),{ok:!1,reason:"invalid_type",field:"iteration"};for(let X of e6){let q=Z[X];if(i6.test(q))return console.warn(`[checkpoint] invalid metadata at ${Q}: field "${X}" contains control characters`),{ok:!1,reason:"control_chars",field:X}}return{ok:!0,value:{id:Z.id,timestamp:Z.timestamp,iteration:Z.iteration,task_id:Z.task_id,task_description:Z.task_description,git_sha:Z.git_sha,git_branch:Z.git_branch,provider:Z.provider,phase:Z.phase}}}function F1($,Q){if(!$7.test($))throw new HQ($);let Z=Q??P(),z=m(o(Z),$);if(!K$(z))throw new _1($);let X=WQ(Z,$);if(!X)throw new _1($);return X}function GQ($,Q){let Z=F1($,Q),z=Q??P(),X=m(o(z),$),q=[];for(let K of Q7){let W=m(X,K);if(!K$(W))continue;q.push({from:W,to:m(z,K)})}return{id:$,metadata:Z,restore:q}}function Z7($){let Q=[],Z=0;for(let z of $.restore)try{Y$(p$(z.to),{recursive:!0});let X=`${z.to}.tmp.${process.pid}.${++qQ}`;ZQ(z.from,X),zQ(X,z.to),Z+=1}catch(X){Q.push(`${z.from} -> ${z.to}: ${X.message}`)}return{restored:Z,errors:Q}}async function BQ($,Q,Z=!1){let z=null;try{let q=await n6({taskDescription:`pre-rollback snapshot (before restoring ${$.id})`,taskId:"rollback",forceCreate:!0,lokiDirOverride:Q});if(q.created)z=q.id}catch(q){let K=q instanceof Error?q.message:String(q);if(!Z)throw Error("pre-rollback snapshot failed ("+K+"); aborting rollback to preserve current state. Re-run with force to roll back anyway without a safety snapshot.");console.warn("[checkpoint] pre-rollback snapshot failed; proceeding due to force:",K)}let X=Z7($);return{preRollbackSnapshotId:z,restored:X.restored,errors:X.errors}}var e0=50,g6=200,$Q,l6,qQ=0,i6,e6,$7,_1,HQ,Q7;var YQ=L(()=>{C();d();F$();$Q=Promise.resolve();l6=["state/orchestrator.json","autonomy-state.json","queue/pending.json","queue/completed.json","queue/in-progress.json","queue/current-task.json","CONTINUITY.md"];i6=/[\x00-\x08\x0a-\x1f\x7f-\x9f]/,e6=["id","task_id","git_sha","git_branch","provider","phase"];$7=/^[a-zA-Z0-9_-]+$/;_1=class _1 extends Error{id;constructor($){super(`Checkpoint not found: ${$}`);this.id=$;this.name="CheckpointNotFoundError"}};HQ=class HQ extends Error{id;constructor($){super(`Invalid checkpoint ID: must be alphanumeric, hyphens, underscores only (got: ${$})`);this.id=$;this.name="InvalidCheckpointIdError"}};Q7=["state/orchestrator.json","queue/pending.json","queue/completed.json","queue/in-progress.json","queue/current-task.json","CONTINUITY.md"]});var OQ={};b(OQ,{runRollback:()=>z7});async function z7($){let Q=$[0],Z=$.slice(1);if(Q===void 0||Q==="help"||Q==="--help"||Q==="-h")return process.stdout.write(MQ),Q===void 0?1:0;switch(Q){case"list":{let z=[...j1()].reverse();if(z.length===0)return process.stdout.write(`${_}No checkpoints found.${J}
|
|
476
477
|
`),0;process.stdout.write(`${k}Checkpoints${J} (${z.length}, newest first):
|
|
477
478
|
`);for(let X of z)process.stdout.write(` ${I}${X.id}${J} iter=${X.iteration} ${X.git_branch||"(no branch)"}@${(X.git_sha||"").slice(0,7)} ${X.timestamp}
|
|
478
479
|
`);return 0}case"show":{let z=Z[0];if(!z)return process.stderr.write(`${T}Missing checkpoint id.${J} Use \`loki rollback list\`.
|
|
479
|
-
`),2;try{let X=
|
|
480
|
+
`),2;try{let X=F1(z);return process.stdout.write(`${JSON.stringify(X,null,2)}
|
|
480
481
|
`),0}catch(X){return process.stderr.write(`${T}Failed to read checkpoint:${J} ${X.message}
|
|
481
482
|
`),1}}case"to":{let z=Z[0];if(!z)return process.stderr.write(`${T}Missing checkpoint id.${J} Use \`loki rollback list\`.
|
|
482
|
-
`),2;return await TQ(z,Z.includes("--force"))}case"latest":{let z=
|
|
483
|
+
`),2;return await TQ(z,Z.includes("--force"))}case"latest":{let z=j1(),X=z[z.length-1];if(!X)return process.stderr.write(`${T}No checkpoints found to roll back to.${J}
|
|
483
484
|
`),1;return process.stdout.write(`Rolling back to latest checkpoint: ${I}${X.id}${J}
|
|
484
485
|
`),await TQ(X.id,Z.includes("--force"))}default:return process.stderr.write(`Unknown subcommand: ${Q}
|
|
485
486
|
`),process.stderr.write(MQ),2}}async function TQ($,Q=!1){let Z;try{Z=GQ($)}catch(X){return process.stderr.write(`${T}Cannot plan rollback:${J} ${X.message}
|
|
@@ -510,33 +511,33 @@ to the checkpoint's snapshot (if one was anchored at checkpoint time):
|
|
|
510
511
|
git stash apply refs/loki/cp/<id>
|
|
511
512
|
|
|
512
513
|
Re-run \`loki start\` to resume from the restored state.
|
|
513
|
-
`;var AQ=L(()=>{YQ();c()});function
|
|
514
|
-
`),0;let Q=[];try{Q=
|
|
514
|
+
`;var AQ=L(()=>{YQ();c()});function X7(){return process.env.LOKI_TIER||"oss"}function wQ($){let Q=X7();if(Q==="oss")return{allowed:!0,notes:[]};if(!process.env.LOKI_LICENSE_KEY)return{allowed:!1,notes:[`${_}LOKI_TIER='${Q}' requested but no LOKI_LICENSE_KEY set.${J}`,`Hosted/enterprise license verification is not available yet (capability: ${$}).`,"OSS users: leave LOKI_TIER unset (or 'oss') -- everything stays free."]};return{allowed:!0,notes:[`${_}LOKI_LICENSE_KEY set but the verification backend is not available yet (R9 seam).${J}`]}}var _Q=L(()=>{c()});var LQ={};b(LQ,{runProof:()=>I7});import{existsSync as q$,readdirSync as K7,readFileSync as IQ,mkdtempSync as q7,copyFileSync as J7,rmSync as V7}from"fs";import{join as n,resolve as W7}from"path";import{tmpdir as U7}from"os";import{createInterface as H7}from"readline";import{readFile as G7}from"fs/promises";function a($){return $&&typeof $==="object"?$:{}}function p($){return $===void 0||$===null?"-":String($)}function M$(){return n(P(),"proofs")}function k1($){let Q=n(M$(),$,"proof.json");if(!q$(Q))return null;try{return JSON.parse(IQ(Q,"utf8"))}catch{return{}}}function $$($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function Y7(){let $=M$();if(!q$($))return process.stdout.write(`${_}No proofs found.${J} Run 'loki start' to generate one.
|
|
515
|
+
`),0;let Q=[];try{Q=K7($,{withFileTypes:!0}).filter((z)=>z.isDirectory()).map((z)=>z.name).sort()}catch{Q=[]}let Z=[];for(let z of Q){let X=n($,z,"proof.json");if(!q$(X))continue;let q={};try{q=JSON.parse(IQ(X,"utf8"))}catch{q={}}let K=p(q.run_id),W=p(q.generated_at),V=a(q.honesty).headline,U=p(V??a(q.council).final_verdict),H=p(a(q.cost).usd),B=p(a(q.files_changed).count);Z.push(`${$$(K,26)} ${$$(W,20)} ${$$(U,18)} ${$$(H,9)} ${B}`)}if(Z.length===0)return process.stdout.write(`${_}No proofs found.${J} Run 'loki start' to generate one.
|
|
515
516
|
`),0;process.stdout.write(`${$$("RUN_ID",26)} ${$$("GENERATED_AT",20)} ${$$("VERDICT",18)} ${$$("COST_USD",9)} FILES
|
|
516
517
|
`);for(let z of Z)process.stdout.write(`${z}
|
|
517
|
-
`);return 0}function
|
|
518
|
-
`),2;let Q=
|
|
518
|
+
`);return 0}function M7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
519
|
+
`),2;let Q=k1($);if(Q===null)return process.stderr.write(`${T}Proof not found: ${$}${J}
|
|
519
520
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
520
521
|
`),1;return process.stdout.write(`${JSON.stringify(Q,null,2)}
|
|
521
|
-
`),0}async function
|
|
522
|
+
`),0}async function T7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
522
523
|
`),2;let Q=n(M$(),$,"index.html");if(!q$(Q))return process.stderr.write(`${T}Proof page not found: ${$}/index.html${J}
|
|
523
524
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
524
525
|
`),1;process.stdout.write(`${S}Opening proof: ${Q}${J}
|
|
525
526
|
`);for(let Z of["open","xdg-open","start"])try{if((await F([Z,Q],{timeoutMs:5000})).exitCode===0)return 0}catch{}return process.stdout.write(`
|
|
526
527
|
Could not detect browser opener.
|
|
527
528
|
`),process.stdout.write(`Please open in browser: ${Q}
|
|
528
|
-
`),0}function
|
|
529
|
+
`),0}function O7($){return new Promise((Q)=>{let Z=H7({input:process.stdin,output:process.stdout});Z.question($,(z)=>{Z.close();let X=z.trim().toLowerCase();Q(X==="y"||X==="yes")})})}async function A7($,Q,Z){let z=wQ("hosted_publish");for(let G of z.notes)process.stderr.write(`${G}
|
|
529
530
|
`);let X=process.env.LOKI_HOSTED_ENDPOINT||"";if(!X)return process.stderr.write(`${_}Hosted publishing backend not available.${J}
|
|
530
531
|
`),process.stderr.write(`There is no official Loki hosted service yet (R9 ships the seam, not a live backend).
|
|
531
532
|
`),process.stderr.write(`To publish to your own hosted endpoint, set LOKI_HOSTED_ENDPOINT to its URL.
|
|
532
533
|
`),process.stderr.write(`Or publish to a GitHub Gist instead: loki proof share ${$}
|
|
533
|
-
`),1;let q=
|
|
534
|
+
`),1;let q=k1($);if(q){if(a(q.redaction).applied!==!0)return process.stderr.write(`${T}Refusing to publish: proof redaction was not confirmed applied.${J}
|
|
534
535
|
`),process.stderr.write(`Regenerate the proof (LOKI_PROOF=1) so the redactor runs, then retry.
|
|
535
536
|
`),1}process.stdout.write(`${k}Publishing proof '${$}' to hosted endpoint${J}
|
|
536
537
|
`),process.stdout.write(` endpoint: ${X}
|
|
537
538
|
`),process.stdout.write(` payload: ${Q} (already redacted by the generator)
|
|
538
539
|
|
|
539
|
-
`);let K;try{K=await
|
|
540
|
+
`);let K;try{K=await G7(Q)}catch{return process.stderr.write(`${T}Could not read proof page: ${Q}${J}
|
|
540
541
|
`),1}let W={"Content-Type":"text/html","X-Loki-Proof-Id":$},V=process.env.LOKI_LICENSE_KEY||"";if(V)W.Authorization=`Bearer ${V}`;let U;try{U=await fetch(X,{method:"POST",headers:W,body:new Uint8Array(K)})}catch(G){return process.stderr.write(`${T}Failed to reach hosted endpoint: ${String(G.message||G)}${J}
|
|
541
542
|
`),process.stderr.write(`Check LOKI_HOSTED_ENDPOINT or publish to a gist: loki proof share ${$}
|
|
542
543
|
`),1}let H=await U.text();if(!U.ok){if(process.stderr.write(`${T}Hosted endpoint returned HTTP ${U.status}.${J}
|
|
@@ -546,11 +547,11 @@ Could not detect browser opener.
|
|
|
546
547
|
`),1}let B="";try{let G=JSON.parse(H);if(G&&typeof G==="object"){let Y=G.url??G.public_url;if(typeof Y==="string")B=Y}}catch{}if(B)process.stdout.write(`${S}Published: ${B}${J}
|
|
547
548
|
`);else process.stdout.write(`${S}Published to ${X} (HTTP ${U.status}).${J}
|
|
548
549
|
`),process.stdout.write(`The endpoint did not return a 'url' field; check your endpoint's response.
|
|
549
|
-
`);return 0}async function
|
|
550
|
+
`);return 0}async function w7($){let Q="",Z=!1,z="--public",X=!1;for(let M of $)if(M==="--yes"||M==="-y")Z=!0;else if(M==="--private")z="";else if(M==="--public")z="--public";else if(M==="--hosted")X=!0;else if(M.startsWith("-"))return process.stderr.write(`${T}Unknown option: ${M}${J}
|
|
550
551
|
`),1;else Q=M;if(!Q)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
551
552
|
`),2;let q=n(M$(),Q,"index.html");if(!q$(q))return process.stderr.write(`${T}Proof page not found: ${Q}/index.html${J}
|
|
552
553
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
553
|
-
`),1;if(X)return
|
|
554
|
+
`),1;if(X)return A7(Q,q,n(M$(),Q,"proof.json"));if((await F(["gh","--version"],{timeoutMs:5000})).exitCode!==0)return process.stderr.write(`${T}gh CLI not found${J}
|
|
554
555
|
`),process.stderr.write(`Install the GitHub CLI to publish a proof:
|
|
555
556
|
`),process.stderr.write(` brew install gh # macOS
|
|
556
557
|
`),process.stderr.write(` sudo apt install gh # Ubuntu/Debian
|
|
@@ -561,25 +562,25 @@ Could not detect browser opener.
|
|
|
561
562
|
|
|
562
563
|
`),process.stdout.write(`What will be shared:
|
|
563
564
|
`),process.stdout.write(` - ${q}
|
|
564
|
-
`);let U=
|
|
565
|
+
`);let U=k1(Q);if(U){let M=p(a(U.cost).usd),R=p(a(U.files_changed).count),N=p(a(U.council).final_verdict),g=a(U.redaction);process.stdout.write(` - cost.usd: ${M}
|
|
565
566
|
`),process.stdout.write(` - files_changed: ${R}
|
|
566
567
|
`),process.stdout.write(` - council verdict: ${N}
|
|
567
568
|
`),process.stdout.write(` - redaction: applied=${p(g.applied)} rules_version=${p(g.rules_version)} redactions_count=${p(g.redactions_count)}
|
|
568
569
|
`)}if(process.stdout.write(`
|
|
569
570
|
${_}Secrets, API keys, tokens, env values, and absolute paths have already been stripped by the generator.${J}
|
|
570
571
|
|
|
571
|
-
`),!Z){if(!await
|
|
572
|
-
`),0}let H=
|
|
573
|
-
`);let G=`Loki Mode proof-of-run ${Q}`,Y=["gh","gist","create",B,"--desc",G];if(z!=="")Y.push(z);let O=await F(Y,{timeoutMs:60000});try{
|
|
572
|
+
`),!Z){if(!await O7(`Publish this proof to a ${V} gist? [y/N] `))return process.stdout.write(`Aborted. Nothing was published.
|
|
573
|
+
`),0}let H=q7(n(U7(),"loki-proof-")),B=n(H,"index.html");J7(q,B),process.stdout.write(`Uploading proof page...
|
|
574
|
+
`);let G=`Loki Mode proof-of-run ${Q}`,Y=["gh","gist","create",B,"--desc",G];if(z!=="")Y.push(z);let O=await F(Y,{timeoutMs:60000});try{V7(H,{recursive:!0,force:!0})}catch{}if(O.exitCode!==0)return process.stderr.write(`${T}Failed to create gist${J}
|
|
574
575
|
`),process.stderr.write(`${O.stdout}${O.stderr}
|
|
575
576
|
`),1;return process.stdout.write(`${S}Shared: ${O.stdout.trim()}${J}
|
|
576
|
-
`),0}async function
|
|
577
|
+
`),0}async function _7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
577
578
|
`),2;let Q=n(M$(),$,"proof.json");if(!q$(Q))return process.stderr.write(`${T}Proof not found: ${$}${J}
|
|
578
579
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
579
|
-
`),1;let Z=
|
|
580
|
-
`),2;let z=process.env.TARGET_DIR||".",X=await F(["python3",Z,Q,z],{timeoutMs:30000});if(X.stdout)process.stdout.write(X.stdout);if(X.stderr)process.stderr.write(X.stderr);return X.exitCode}async function
|
|
580
|
+
`),1;let Z=W7(h,"autonomy","lib","proof-verify.py");if(!q$(Z))return process.stderr.write(`${T}Verifier not found (autonomy/lib/proof-verify.py).${J}
|
|
581
|
+
`),2;let z=process.env.TARGET_DIR||".",X=await F(["python3",Z,Q,z],{timeoutMs:30000});if(X.stdout)process.stdout.write(X.stdout);if(X.stderr)process.stderr.write(X.stderr);return X.exitCode}async function I7($){let Q=$[0],Z=$.slice(1);if(Q===void 0||Q==="help"||Q==="--help"||Q==="-h")return process.stdout.write(B7),Q===void 0?1:0;switch(Q){case"list":return Y7();case"show":return M7(Z[0]);case"verify":return _7(Z[0]);case"open":return T7(Z[0]);case"share":return w7(Z);default:return process.stderr.write(`${T}Unknown subcommand: ${Q}${J}
|
|
581
582
|
`),process.stderr.write(`Run 'loki proof --help' for usage.
|
|
582
|
-
`),1}}var
|
|
583
|
+
`),1}}var B7;var PQ=L(()=>{C();d();c();_Q();B7=`${k}loki proof${J} - inspect and share proof-of-run artifacts
|
|
583
584
|
|
|
584
585
|
Usage: loki proof <subcommand> [args]
|
|
585
586
|
|
|
@@ -596,31 +597,31 @@ Options for 'share':
|
|
|
596
597
|
--hosted Publish to LOKI_HOSTED_ENDPOINT (open-core seam; no official backend yet)
|
|
597
598
|
|
|
598
599
|
Proofs are generated automatically at run completion (LOKI_PROOF=0 to opt out).
|
|
599
|
-
`});var
|
|
600
|
+
`});var xQ={};b(xQ,{runCrash:()=>N7});import{existsSync as FQ,readdirSync as L7,readFileSync as P7}from"fs";import{join as kQ}from"path";function k$($){return $===void 0||$===null?"-":String($)}function l$($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function RQ(){return kQ(P(),"crash")}function R1(){let $=RQ();if(!FQ($))return[];try{return L7($,{withFileTypes:!0}).filter((Q)=>Q.isFile()&&Q.name.endsWith(".json")).map((Q)=>Q.name.slice(0,-5)).sort()}catch{return[]}}function F7($){if($.length===0)return!1;if($.includes("/")||$.includes("\\"))return!1;if($.includes(".."))return!1;return!0}function d$($){if(!F7($))return null;let Q=kQ(RQ(),`${$}.json`);if(!FQ(Q))return null;try{return JSON.parse(P7(Q,"utf8"))}catch{return{}}}function k7(){let $=R1();if($.length===0)return process.stdout.write(`${_}No crash reports found.${J} Nothing has been captured in .loki/crash/.
|
|
600
601
|
`),0;process.stdout.write(`${l$("ID",40)} ${l$("CAPTURED_AT",22)} ERROR_CLASS
|
|
601
602
|
`);for(let Q of $){let Z=d$(Q)??{},z=k$(Z.fingerprint),X=k$(Z.captured_at),q=k$(Z.error_class),K=z!=="-"?z:Q;process.stdout.write(`${l$(K,40)} ${l$(X,22)} ${q}
|
|
602
603
|
`)}return process.stdout.write(`
|
|
603
604
|
${$.length} report(s). Run 'loki crash show <id>' to inspect, 'loki crash submit' to get a prefilled GitHub issue URL.
|
|
604
|
-
`),0}function
|
|
605
|
-
`),2;let Q=
|
|
605
|
+
`),0}function EQ($){let Q=d$($);if(Q!==null)return{id:$,report:Q};for(let Z of R1()){let z=d$(Z);if(z&&String(z.fingerprint??"")===$)return{id:Z,report:z}}return null}function R7($){if(!$)return process.stderr.write(`${T}Missing crash id.${J} Use 'loki crash' to list reports.
|
|
606
|
+
`),2;let Q=EQ($);if(Q===null)return process.stderr.write(`${T}Crash report not found: ${$}${J}
|
|
606
607
|
`),process.stderr.write(`Use 'loki crash' to see available reports.
|
|
607
608
|
`),1;return process.stdout.write(`${JSON.stringify(Q.report,null,2)}
|
|
608
|
-
`),0}function
|
|
609
|
-
`),W=new URLSearchParams({title:X,body:K});return`${
|
|
609
|
+
`),0}function E7($){let Q=k$($.error_class),Z=k$($.fingerprint),z=Z!=="-"?Z.slice(0,12):"unknown",X=`crash: ${Q} (${z})`,K=["Anonymous crash report captured by Loki Mode (scrubbed, whitelist-only).","","Scrubbed payload:","```json",JSON.stringify($,null,2),"```","","Nothing was sent automatically. This issue is submitted manually by me."].join(`
|
|
610
|
+
`),W=new URLSearchParams({title:X,body:K});return`${j7}?${W.toString()}`}function x7($){let Q;if($){if(Q=EQ($),Q===null)return process.stderr.write(`${T}Crash report not found: ${$}${J}
|
|
610
611
|
`),process.stderr.write(`Use 'loki crash' to see available reports.
|
|
611
|
-
`),1}else{let Z=
|
|
612
|
+
`),1}else{let Z=R1();if(Z.length===0)return process.stdout.write(`${_}No crash reports found.${J} Nothing to submit.
|
|
612
613
|
`),0;let z=Z[Z.length-1],X=d$(z)??{};Q={id:z,report:X}}return process.stdout.write(`${k}Scrubbed payload (this is the ENTIRE report):${J}
|
|
613
614
|
`),process.stdout.write(`${JSON.stringify(Q.report,null,2)}
|
|
614
615
|
|
|
615
616
|
`),process.stdout.write(`${_}Nothing is sent automatically in this version.${J} Loki Mode never transmits crash data on its own.
|
|
616
617
|
`),process.stdout.write(`To submit manually, open this prefilled GitHub issue and review it first:
|
|
617
618
|
|
|
618
|
-
`),process.stdout.write(` ${I}${
|
|
619
|
+
`),process.stdout.write(` ${I}${E7(Q.report)}${J}
|
|
619
620
|
|
|
620
621
|
`),process.stdout.write(`${S}The payload above is exactly what the URL contains.${J}
|
|
621
622
|
`),process.stdout.write(`See docs/PRIVACY.md for what is and is not collected.
|
|
622
|
-
`),0}async function
|
|
623
|
-
`),process.stdout.write(jQ),2}}var
|
|
623
|
+
`),0}async function N7($){let Q=$[0];switch(Q){case void 0:case"list":return k7();case"--help":case"-h":case"help":return process.stdout.write(jQ),0;case"show":return R7($[1]);case"submit":return x7($[1]);default:return process.stderr.write(`${T}Unknown crash subcommand: ${Q}${J}
|
|
624
|
+
`),process.stdout.write(jQ),2}}var j7="https://github.com/asklokesh/loki-mode/issues/new",jQ;var NQ=L(()=>{C();c();jQ=`${k}loki crash${J} - inspect and manually submit local crash reports
|
|
624
625
|
|
|
625
626
|
Usage: loki crash [subcommand] [args]
|
|
626
627
|
|
|
@@ -632,15 +633,15 @@ Subcommands:
|
|
|
632
633
|
|
|
633
634
|
Crash reports are anonymous, scrubbed, and stored locally only. Nothing is
|
|
634
635
|
sent automatically in this version. See docs/PRIVACY.md.
|
|
635
|
-
`});var bQ={};b(bQ,{runWiki:()=>
|
|
636
|
+
`});var bQ={};b(bQ,{runWiki:()=>h7});import{existsSync as E1,readFileSync as SQ}from"fs";import{join as x1,resolve as S7}from"path";function C7(){return x1(process.cwd(),".loki","wiki")}function b7($){let Q="";for(let X of $){if(X==="--help"||X==="-h")return process.stdout.write(`Usage: loki wiki show [section]
|
|
636
637
|
Sections: architecture, modules, data-flow
|
|
637
638
|
`),0;if(X.startsWith("-"))return process.stderr.write(`${T}Unknown option: ${X}${J}
|
|
638
|
-
`),1;Q=X}let Z=
|
|
639
|
-
`),1;if(Q){if(!
|
|
640
|
-
`),1;let X=x1(Z,`${Q}.md`);if(!
|
|
641
|
-
`),1;return process.stdout.write(SQ(X,"utf8")),0}let z=x1(Z,"index.md");if(!
|
|
642
|
-
`),1;return process.stdout.write(SQ(z,"utf8")),0}async function CQ($,Q){let Z=
|
|
643
|
-
`),process.stdout.write(DQ),1}}var DQ,
|
|
639
|
+
`),1;Q=X}let Z=C7();if(!E1(Z))return process.stderr.write(`${_}No wiki found. Run 'loki wiki generate' first.${J}
|
|
640
|
+
`),1;if(Q){if(!D7.has(Q))return process.stderr.write(`${T}No such section: ${Q} (try: architecture, modules, data-flow)${J}
|
|
641
|
+
`),1;let X=x1(Z,`${Q}.md`);if(!E1(X))return process.stderr.write(`${T}Section not generated: ${Q}${J}
|
|
642
|
+
`),1;return process.stdout.write(SQ(X,"utf8")),0}let z=x1(Z,"index.md");if(!E1(z))return process.stderr.write(`${T}Wiki index not found. Run 'loki wiki generate'.${J}
|
|
643
|
+
`),1;return process.stdout.write(SQ(z,"utf8")),0}async function CQ($,Q){let Z=S7(h,"autonomy","loki"),z=3600000,X=Bun.spawn({cmd:[Z,"wiki",$,...Q],stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,LOKI_LEGACY_BASH:"1"}}),q=setTimeout(()=>{try{X.kill("SIGKILL")}catch{}},3600000);try{return await X.exited}finally{clearTimeout(q)}}async function h7($){let Q=$[0],Z=$.slice(1);switch(Q){case void 0:case"help":case"--help":case"-h":return process.stdout.write(DQ),0;case"show":return b7(Z);case"generate":return CQ("generate",Z);case"ask":return CQ("ask",Z);default:return process.stderr.write(`${T}Unknown wiki command: ${Q}${J}
|
|
644
|
+
`),process.stdout.write(DQ),1}}var DQ,D7;var hQ=L(()=>{C();c();DQ=`${k}loki wiki${J} - Auto-generated, cited codebase wiki + Q&A
|
|
644
645
|
|
|
645
646
|
Usage: loki wiki <command> [options]
|
|
646
647
|
|
|
@@ -656,8 +657,8 @@ Examples:
|
|
|
656
657
|
loki wiki generate
|
|
657
658
|
loki wiki show architecture
|
|
658
659
|
loki wiki ask "how does the cli dispatch commands"
|
|
659
|
-
`,
|
|
660
|
-
`)}function
|
|
660
|
+
`,D7=new Set(["architecture","modules","data-flow"])});var S1={};b(S1,{renderFindingsForPrompt:()=>f7,loadPreviousFindings:()=>N1,findLatestReviewDir:()=>fQ,_parseReviewerOutputForTests:()=>u7});import{existsSync as vQ,readFileSync as yQ,readdirSync as gQ,statSync as y7}from"fs";import{join as o$}from"path";function m7($){let Q=$.toLowerCase();if(Q==="critical")return"Critical";if(Q==="high")return"High";if(Q==="medium")return"Medium";return"Low"}function mQ($,Q,Z,z){let X=[],q=$.split(/\r?\n/);for(let K of q){let W=K.trim();if(W.length===0)continue;let V=W.replace(/^[-*]\s*/,""),U=v7.exec(V);if(!U||!U[1]||!U[2])continue;let H=m7(U[1]),B=U[2].trim(),G=g7.exec(B),Y=G&&G[1]?G[1]:null,O=G&&G[2]?Number.parseInt(G[2],10):null;X.push({reviewId:Z,iteration:z,reviewer:Q,severity:H,description:B,file:Y,line:Number.isFinite(O)?O:null,raw:W})}return X}function fQ($,Q){let Z=o$($,"quality","reviews");if(!vQ(Z))return null;let z;try{z=gQ(Z)}catch{return null}let X=Q===void 0?z.filter((W)=>W.startsWith("review-")):z.filter((W)=>W.endsWith(`-${Q}`)&&W.startsWith("review-"));if(X.length===0)return null;X.sort();let q=X[X.length-1];if(!q)return null;let K=o$(Z,q);try{if(!y7(K).isDirectory())return null}catch{return null}return K}function N1($,Q){let Z=fQ($,Q);if(Z===null)return{reviewDir:null,reviewId:null,iteration:null,findings:[]};let z=null,X=null,q=o$(Z,"aggregate.json");if(vQ(q))try{let U=yQ(q,"utf-8"),H=JSON.parse(U);if(typeof H.review_id==="string")z=H.review_id;if(typeof H.iteration==="number")X=H.iteration}catch{}let K;try{K=gQ(Z)}catch{return{reviewDir:Z,reviewId:z,iteration:X,findings:[]}}let W=new Set(["diff.txt","files.txt","anti-sycophancy.txt"]),V=[];for(let U of K){if(!U.endsWith(".txt"))continue;if(W.has(U))continue;if(U.endsWith("-prompt.txt"))continue;let H=U.replace(/\.txt$/,""),B;try{B=yQ(o$(Z,U),"utf-8")}catch{continue}V.push(...mQ(B,H,z??"",X??-1))}return{reviewDir:Z,reviewId:z,iteration:X,findings:V}}function f7($){if($.length===0)return"";let Q=["Critical","High","Medium","Low"],Z=new Map;for(let X of Q)Z.set(X,[]);for(let X of $){let q=Z.get(X.severity);if(q)q.push(X)}let z=[];z.push("PREVIOUS REVIEWER FINDINGS (must address each, or supply counter-evidence in .loki/state/counter-evidence-<iter>.json):");for(let X of Q){let q=Z.get(X)??[];if(q.length===0)continue;z.push(` [${X}] (${q.length}):`);for(let K of q){let W=K.file?` (${K.file}${K.line!==null?":"+K.line:""})`:"";z.push(` - ${K.description}${W} -- via ${K.reviewer}`)}}return z.join(`
|
|
661
|
+
`)}function u7($,Q,Z="review-test",z=0){return mQ($,Q,Z,z)}var v7,g7;var n$=L(()=>{v7=/\[(Critical|High|Medium|Low)\]\s*(.+)/i,g7=/([\w.\-/]+\.[a-zA-Z]+):(\d+)/});import{existsSync as c7}from"fs";import{join as p7}from"path";async function uQ($,Q){let Z=p7($,"memory");if(!c7(Z))return{stored:!1,reason:"memory dir not initialized"};let z=Math.max(0,Math.floor(Q.durationSeconds??0)),X={_LOKI_PROJECT_DIR:h,_LOKI_TARGET_DIR:process.cwd(),_LOKI_TASK_ID:Q.taskId,_LOKI_OUTCOME:Q.outcome,_LOKI_PHASE:Q.phase,_LOKI_GOAL:Q.goal,_LOKI_DURATION:String(z),_LOKI_LOKI_DIR:$},K=await z$(`
|
|
661
662
|
import os, sys
|
|
662
663
|
project = os.environ.get('_LOKI_PROJECT_DIR', '')
|
|
663
664
|
loki = os.environ.get('_LOKI_LOKI_DIR', '.loki')
|
|
@@ -684,25 +685,25 @@ try:
|
|
|
684
685
|
print('OK')
|
|
685
686
|
except Exception as e:
|
|
686
687
|
print('ERR:' + str(e))
|
|
687
|
-
`,{env:X,timeoutMs:15000});if(K.exitCode===127)return{stored:!1,reason:"python3 not found"};let W=K.stdout.trim();if(W==="OK")return{stored:!0,reason:"stored"};if(W.startsWith("ERR:"))return{stored:!1,reason:W.replace(/^ERR:/,"")};return{stored:!1,reason:K.stderr.trim()||"unknown"}}var cQ=L(()=>{V$();C()});var oQ={};b(oQ,{loadLearnings:()=>
|
|
688
|
-
`)}async function
|
|
689
|
-
`)}function
|
|
690
|
-
`),process.stderr.write(
|
|
691
|
-
`),2;let Z=P();try{let X=(await Promise.resolve().then(() => (n$(),
|
|
692
|
-
`),0;let q=
|
|
688
|
+
`,{env:X,timeoutMs:15000});if(K.exitCode===127)return{stored:!1,reason:"python3 not found"};let W=K.stdout.trim();if(W==="OK")return{stored:!0,reason:"stored"};if(W.startsWith("ERR:"))return{stored:!1,reason:W.replace(/^ERR:/,"")};return{stored:!1,reason:K.stderr.trim()||"unknown"}}var cQ=L(()=>{V$();C()});var oQ={};b(oQ,{loadLearnings:()=>D1,appendLearning:()=>R$,appendFromGateFailure:()=>r7});import{existsSync as l7,readFileSync as d7}from"fs";import{join as pQ}from"path";import{createHash as o7}from"crypto";function lQ($){return pQ($,n7)}function a7($){if($===null||typeof $!=="object")return!1;let Q=$;return typeof Q.id==="string"&&typeof Q.timestamp==="string"&&typeof Q.iteration==="number"&&typeof Q.trigger==="string"&&typeof Q.rootCause==="string"&&typeof Q.fix==="string"&&typeof Q.preventInFuture==="string"&&typeof Q.evidence==="object"&&Q.evidence!==null}function dQ($){if(!l7($))return{version:1,learnings:[]};try{let Q=d7($,"utf-8"),Z=JSON.parse(Q);if(Z.version===1&&Array.isArray(Z.learnings))return{version:1,learnings:Z.learnings.filter(a7)}}catch{}return{version:1,learnings:[]}}function s7($,Q,Z){return o7("sha256").update(`${$} ${Q} ${Z??""}`).digest("hex").slice(0,16)}async function R$($,Q,Z={}){let z=s7(Q.trigger,Q.rootCause,Q.evidence.file),X=new Date().toISOString(),q={id:z,timestamp:X,...Q},K=lQ($);if(await i0(K,()=>{j$(K,()=>{let V=dQ(K),U=V.learnings.findIndex((H)=>H.id===z);if(U>=0){let H=V.learnings[U];V.learnings[U]={...H,timestamp:X,iteration:q.iteration}}else V.learnings.push(q);P$(K,V)})}),Z.episodeBridge!==null&&(Z.episodeBridge!==void 0||process.env.LOKI_AUTO_LEARNINGS_EPISODE==="1")){let V=Z.episodeBridge??uQ,U=Z.bridgeFailureLog??t7;try{let H=await V($,{taskId:`learning-${z}`,outcome:"failure",phase:"VERIFY",goal:`${Q.trigger}: ${Q.rootCause}`});if(H&&!H.stored){if(!new Set(["memory dir not initialized","stub"]).has(H.reason))U(`episode_bridge skipped: ${H.reason}`)}}catch(H){U(`episode_bridge threw: ${H.message}`)}}return q}function t7($){process.stderr.write(`[learnings_writer] ${$}
|
|
689
|
+
`)}async function r7($,Q,Z,z={}){let X=`[${Z.severity}] ${Z.description}`;return R$($,{iteration:Q,trigger:"gate_failure",rootCause:X,fix:"pending: dev agent must address in next iteration or supply counter-evidence",preventInFuture:"if this finding recurs, lower its severity threshold or add a regression test",evidence:{reviewId:Z.reviewId,file:Z.file??void 0,line:Z.line??void 0,severity:Z.severity,reviewer:Z.reviewer}},z)}function D1($){return dQ(lQ($))}var n7;var a$=L(()=>{F$();cQ();n7=pQ("state","relevant-learnings.json")});var aQ={};b(aQ,{runOverrideCouncil:()=>zZ,recordOverrideOutcome:()=>XZ,loadCounterEvidence:()=>ZZ,canonicalFindingId:()=>s$,DEFAULT_OVERRIDE_JUDGES:()=>nQ});import{existsSync as i7,readFileSync as e7}from"fs";import{join as $Z}from"path";function ZZ($,Q){let Z=$Z($,"state",`counter-evidence-${Q}.json`);if(!i7(Z))return null;try{let z=e7(Z,"utf-8"),X=JSON.parse(z);if(typeof X.iteration!=="number")return null;let q=Array.isArray(X.evidence)?X.evidence:[],K=[];for(let W of q){if(typeof W!=="object"||W===null)continue;let V=W;if(typeof V.findingId!=="string")continue;if(typeof V.claim!=="string")continue;let U=V.proofType;if(typeof U!=="string"||!QZ.has(U))continue;let H=U,B=Array.isArray(V.artifacts)?V.artifacts:[];K.push({findingId:V.findingId,claim:V.claim,proofType:H,artifacts:B.filter((G)=>typeof G==="string")})}return{iteration:X.iteration,evidence:K}}catch{return null}}async function zZ($,Q,Z,z={}){let X=z.judges??nQ,q=new Set,K=new Set,W={},V=new Map;for(let H of Q.evidence)V.set(H.findingId,H);let U=new Map;for(let H of $){let B=s$(H);U.set(B,(U.get(B)??0)+1)}for(let H of $){let B=s$(H);if((U.get(B)??0)>1){K.add(B);continue}let G=V.get(B);if(!G){K.add(B);continue}let Y=await Promise.all(X.map((M)=>Z({finding:H,evidence:G,judge:M})));if(W[B]=Y,Y.filter((M)=>M.verdict==="APPROVE_OVERRIDE").length>=2)q.add(B);else K.add(B)}return{approvedFindingIds:q,rejectedFindingIds:K,votes:W}}function s$($){let Q=$.raw.slice(0,80).replace(/\s+/g," ").trim();return`${$.reviewer}::${Q}`}async function XZ($,Q,Z,z,X={}){let q={episodeBridge:X.episodeBridge===void 0?null:X.episodeBridge};for(let K of z){let W=s$(K);if(Z.approvedFindingIds.has(W))await R$($,{iteration:Q,trigger:"override_approved",rootCause:`[${K.severity}] ${K.description}`,fix:"override council approved counter-evidence; finding lifted",preventInFuture:"if this reviewer/file pair recurs, narrow the reviewer's selector OR add a baseline doc",evidence:{findingId:W,reviewId:K.reviewId,file:K.file??void 0,line:K.line??void 0,severity:K.severity,reviewer:K.reviewer}},q);else if(Z.rejectedFindingIds.has(W))await R$($,{iteration:Q,trigger:"override_rejected",rootCause:`[${K.severity}] ${K.description}`,fix:"override council rejected -- dev agent must fix the finding",preventInFuture:"address this finding in the next iteration",evidence:{findingId:W,reviewId:K.reviewId,file:K.file??void 0,line:K.line??void 0,severity:K.severity,reviewer:K.reviewer}},q)}}var QZ,nQ;var sQ=L(()=>{a$();QZ=new Set(["file-exists","test-passes","grep-miss","reviewer-misread","duplicate-code-path","out-of-scope"]);nQ=["judge-primary","judge-secondary","judge-tertiary"]});var rQ={};b(rQ,{writeEscalationHandoff:()=>BZ,renderHandoff:()=>tQ,readLatestHandoff:()=>YZ});import{existsSync as KZ,readdirSync as qZ,readFileSync as JZ}from"fs";import{join as t$}from"path";function VZ(){return new Date().toISOString()}function WZ($){let Q=$.file?` (${$.file}${$.line!==null?":"+$.line:""})`:"";return` - [${$.severity}] ${$.description}${Q} -- ${$.reviewer}`}function UZ($){let Q=$.evidence,Z=Q.file?` ${Q.file}${Q.line!==void 0?":"+Q.line:""}`:"";return` - **${$.trigger}** (iter ${$.iteration})${Z}: ${$.rootCause}`}function tQ($,Q,Z){let z=[];if(z.push(`# Loki escalation handoff -- ${VZ()}`),z.push(""),z.push(`Gate **${$.gateName}** has failed ${$.consecutiveFailures} consecutive times at iteration ${$.iteration}.`),z.push(""),z.push(`Reason: ${$.detail}`),z.push(""),Q.length>0){z.push(`## Outstanding findings (${Q.length})`),z.push("");for(let X of Q)z.push(WZ(X));z.push("")}else z.push("## Outstanding findings"),z.push(""),z.push("(no per-finding records captured -- gate failed without populating reviewer outputs)"),z.push("");if(Z.length>0){z.push(`## Recent learnings (${Math.min(Z.length,10)})`),z.push("");for(let X of Z.slice(-10))z.push(UZ(X));z.push("")}return z.push("## What the human must decide"),z.push(""),z.push("- Fix the finding? Address it in the code, then `rm .loki/PAUSE` to resume. A code_review BLOCK is NOT lifted by self-supplied counter-evidence -- the gated agent authors that file, so it cannot self-certify a trust-gate finding away."),z.push('- Override after your own review? You (the operator) are the escape path: review the finding and, if you accept it, `rm .loki/PAUSE` to resume. To direct the agent on resume, `echo "instructions" > .loki/HUMAN_INPUT.md` first.'),z.push("- Disable a gate? Set `LOKI_GATE_<NAME>=false` in env (see skills/quality-gates.md)."),z.push("- Tweak escalation? Set `LOKI_GATE_PAUSE_LIMIT` or `LOKI_GATE_ESCALATE_LIMIT`."),z.push("- Roll back? Switch to `LOKI_LEGACY_BASH=1` and re-run; the bash route does not consult this handoff doc."),z.push(""),z.push("To resume: fix the findings (or, after your own review, accept them), then `rm .loki/PAUSE`."),z.join(`
|
|
690
|
+
`)}function GZ($,Q){A1($,Q)}function BZ($,Q,Z={}){let z=Z.findings??N1($,Q.iteration).findings,X=Z.learnings??D1($).learnings,q=tQ(Q,z,X),K=(Z.now?.()??new Date).toISOString().replace(/[-:.]/g,""),W=t$($,"escalations"),V=++HZ,U=t$(W,`handoff-${K}-${process.pid}-${V}-${Q.gateName}.md`);return GZ(U,q),{path:U,bytes:q.length}}function YZ($){let Q=t$($,"escalations");if(!KZ(Q))return null;let Z;try{Z=qZ(Q).filter((q)=>q.endsWith(".md"))}catch{return null}if(Z.length===0)return null;Z.sort();let z=Z[Z.length-1];if(!z)return null;let X=t$(Q,z);try{return{path:X,body:JZ(X,"utf-8")}}catch{return null}}var HZ=0;var iQ=L(()=>{F$();n$();a$()});var $8={};b($8,{runInternalPhase1Hooks:()=>_Z,_resolveForTests:()=>wZ,_internalPhase1HooksHelp:()=>jZ,__testAppendHook:()=>eQ});import{existsSync as MZ,mkdirSync as TZ,readdirSync as OZ,statSync as AZ}from"fs";import{join as E$,resolve as wZ}from"path";async function _Z($){let[Q,...Z]=$;switch(Q){case void 0:case"help":case"--help":case"-h":return process.stdout.write(C1),Q===void 0?1:0;case"reflect":return IZ(Z);case"override":return LZ(Z);case"handoff":return PZ(Z);default:return process.stderr.write(`Unknown subcommand: ${Q}
|
|
691
|
+
`),process.stderr.write(C1),2}}async function IZ($){let Q=b1($[0]);if(Q===null)return process.stderr.write(`reflect: missing or invalid <iter>
|
|
692
|
+
`),2;let Z=P();try{let X=(await Promise.resolve().then(() => (n$(),S1))).loadPreviousFindings(Z,Q);if(X.findings.length===0)return process.stdout.write(`reflect: no findings for iter ${Q} (nothing to do)
|
|
693
|
+
`),0;let q=E$(Z,"state");TZ(q,{recursive:!0}),P$(E$(q,`findings-${Q}.json`),{review_id:X.reviewId,iteration:Q,findings:X.findings});let K=await Promise.resolve().then(() => (a$(),oQ)),W=0,V=0;if(process.env.LOKI_AUTO_LEARNINGS!=="0"){let H=X.findings.filter((G)=>G.severity==="Critical"||G.severity==="High"),B=eQ.fn??K.appendFromGateFailure;for(let G of H)try{await B(Z,Q,G,{episodeBridge:null}),W+=1}catch(Y){V+=1,process.stderr.write(`reflect: learning append failed for finding ${G.reviewer}/${G.severity}: ${Y.message}
|
|
693
694
|
`)}if(V>0&&W===0)return process.stderr.write(`reflect: all ${V} learning appends failed (iter ${Q})
|
|
694
695
|
`),1}let U=V>0?` (${V} failed)`:"";return process.stdout.write(`reflect: persisted ${X.findings.length} findings + ${W} learnings${U} (iter ${Q})
|
|
695
696
|
`),0}catch(z){return process.stderr.write(`reflect: ${z.message}
|
|
696
|
-
`),1}}async function
|
|
697
|
+
`),1}}async function LZ($){let Q=b1($[0]);if(Q===null)return process.stderr.write(`override: missing or invalid <iter>
|
|
697
698
|
`),2;let Z=P();try{let z=await Promise.resolve().then(() => (sQ(),aQ)),X=z.loadCounterEvidence(Z,Q);if(X===null||X.evidence.length===0)return process.stdout.write(`override: no counter-evidence for iter ${Q} (skip)
|
|
698
|
-
`),0;let K=(await Promise.resolve().then(() => (n$(),
|
|
699
|
-
`),0;let V=async(O)=>{return{judge:O.judge,verdict:"REJECT_OVERRIDE",reasoning:`[stub] proofType=${O.evidence.proofType}: self-supplied counter-evidence cannot lift a trust-gate BLOCK on the agent-authored route. Fix the finding, or use the human-escape path (rm .loki/PAUSE; optionally .loki/HUMAN_INPUT.md). The only adjudicated override is the Bun-route real-LLM judge.`}},U=await z.runOverrideCouncil(W,X,V);await z.recordOverrideOutcome(Z,Q,U,W);let H=
|
|
699
|
+
`),0;let K=(await Promise.resolve().then(() => (n$(),S1))).loadPreviousFindings(Z,Q),W=K.findings.filter((O)=>O.severity==="Critical"||O.severity==="High");if(W.length===0)return process.stdout.write(`override: no blocking findings for iter ${Q} (skip)
|
|
700
|
+
`),0;let V=async(O)=>{return{judge:O.judge,verdict:"REJECT_OVERRIDE",reasoning:`[stub] proofType=${O.evidence.proofType}: self-supplied counter-evidence cannot lift a trust-gate BLOCK on the agent-authored route. Fix the finding, or use the human-escape path (rm .loki/PAUSE; optionally .loki/HUMAN_INPUT.md). The only adjudicated override is the Bun-route real-LLM judge.`}},U=await z.runOverrideCouncil(W,X,V);await z.recordOverrideOutcome(Z,Q,U,W);let H=E$(Z,"quality","reviews");if(MZ(H))try{let O=OZ(H).filter((R)=>R.startsWith("review-")).sort(),M=O[O.length-1];if(M&&AZ(E$(H,M)).isDirectory())P$(E$(H,M,`override-${Q}.json`),{review_id:K.reviewId,iteration:Q,approved_finding_ids:Array.from(U.approvedFindingIds),rejected_finding_ids:Array.from(U.rejectedFindingIds),votes:U.votes})}catch{}let B=U.approvedFindingIds.size,G=U.rejectedFindingIds.size;if(G===0&&B>0)process.stdout.write(`override: LIFTED -- ${B} approved, ${G} rejected
|
|
700
701
|
`);else process.stdout.write(`override: BLOCKED -- ${B} approved, ${G} rejected
|
|
701
702
|
`);return 0}catch(z){return process.stderr.write(`override: ${z.message}
|
|
702
|
-
`),1}}async function
|
|
703
|
+
`),1}}async function PZ($){let Q=$[0],Z=Number.parseInt($[1]??"0",10),z=b1($[2]);if(!Q||!Number.isFinite(Z)||z===null)return process.stderr.write(`handoff: usage: handoff <gate> <consecutive-failures> <iter>
|
|
703
704
|
`),2;let X=P();try{let K=(await Promise.resolve().then(() => (iQ(),rQ))).writeEscalationHandoff(X,{gateName:Q,iteration:z,consecutiveFailures:Z,detail:`${Q} hit PAUSE_LIMIT (${Z} consecutive failures)`});return process.stdout.write(`handoff: wrote ${K.path} (${K.bytes}B)
|
|
704
705
|
`),0}catch(q){return process.stderr.write(`handoff: ${q.message}
|
|
705
|
-
`),1}}function
|
|
706
|
+
`),1}}function b1($){if($===void 0)return null;let Q=Number.parseInt($,10);return Number.isFinite(Q)&&Q>=0?Q:null}var eQ,C1=`loki internal phase1-hooks <subcommand>
|
|
706
707
|
|
|
707
708
|
Subcommands:
|
|
708
709
|
reflect <iter> Persist structured findings + auto-learnings.
|
|
@@ -711,9 +712,9 @@ Subcommands:
|
|
|
711
712
|
|
|
712
713
|
This command is invoked by autonomy/run.sh between iterations. Users
|
|
713
714
|
should not run it directly -- run \`loki start\` instead.
|
|
714
|
-
`,
|
|
715
|
-
`)}catch{}}async function
|
|
716
|
-
`),await
|
|
715
|
+
`,jZ;var Q8=L(()=>{C();F$();eQ={fn:null};jZ=C1});$1();C();import{mkdirSync as B8,readFileSync as Y8,writeFileSync as M8}from"fs";import{dirname as T8,resolve as O8}from"path";var A8="https://registry.npmjs.org/loki-mode/latest",w8=86400000,_8=1500;function I8(){return O8(T$(),"cache","update-check.json")}function O$($){let Q=/^(\d+)\.(\d+)\.(\d+)$/.exec($.trim());if(!Q)return null;return[Number(Q[1]),Number(Q[2]),Number(Q[3])]}function L8($,Q){let Z=O$($),z=O$(Q);if(!Z||!z)return!1;let[X,q,K]=Z,[W,V,U]=z;if(X!==W)return X>W;if(q!==V)return q>V;return K>U}function P8(){if(process.env.LOKI_NO_UPDATE_CHECK==="1")return!0;if(process.env.CI)return!0;if(!process.stdout.isTTY)return!0;return!1}function j8($){try{let Q=Y8($,"utf-8"),Z=JSON.parse(Q);if(typeof Z.checkedAt==="number"&&typeof Z.latest==="string"&&O$(Z.latest)!==null)return{checkedAt:Z.checkedAt,latest:Z.latest}}catch{}return null}function F8($,Q){try{B8(T8($),{recursive:!0}),M8($,JSON.stringify(Q),"utf-8")}catch{}}async function k8(){try{let $=await fetch(A8,{signal:AbortSignal.timeout(_8),headers:{accept:"application/json"}});if(!$.ok)return null;let Q=await $.json();if(typeof Q.version==="string"&&O$(Q.version)!==null)return Q.version}catch{}return null}async function R8($=Date.now(),Q=k8,Z=I8()){let z=j8(Z);if(z&&$-z.checkedAt<w8)return z.latest;let X=await Q();if(X===null)return null;return F8(Z,{checkedAt:$,latest:X}),X}async function g1($,Q={}){try{if(P8())return;if(O$($)===null)return;let Z=await R8(Q.now,Q.fetcher,Q.cacheFile);if(Z===null)return;if(!L8(Z,$))return;(Q.write??((X)=>process.stderr.write(X)))(`A newer Loki Mode is available: ${Z} (you have ${$}). Update: bun install -g loki-mode (or npm i -g loki-mode)
|
|
716
|
+
`)}catch{}}async function m1(){let $=N$();return process.stdout.write(`Loki Mode v${$}
|
|
717
|
+
`),await g1($),0}d();c();C();import{readFileSync as D8,existsSync as C8}from"fs";import{resolve as b8}from"path";var h8=["claude","codex","cline","aider"];function p1(){let $=b8(P(),"state","provider");if(!C8($))return"";try{return D8($,"utf-8").trim()}catch{return""}}function y8($,Q){return $||Q||process.env.LOKI_PROVIDER||"claude"}function v8($){let Q=p1(),Z=y8($,Q);switch(process.stdout.write(`${k}Current Provider${J}
|
|
717
718
|
`),process.stdout.write(`
|
|
718
719
|
`),process.stdout.write(`${I}Provider:${J} ${Z}
|
|
719
720
|
`),Z){case"claude":process.stdout.write(`${S}Status:${J} Full features (subagents, parallel, MCP)
|
|
@@ -724,7 +725,7 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
724
725
|
`);return process.stdout.write(`
|
|
725
726
|
`),process.stdout.write(`Switch provider: ${I}loki provider set <name>${J}
|
|
726
727
|
`),process.stdout.write(`Available: ${I}loki provider list${J}
|
|
727
|
-
`),0}async function g8(){let Q=
|
|
728
|
+
`),0}async function g8(){let Q=p1()||process.env.LOKI_PROVIDER||"claude";process.stdout.write(`${k}Available Providers${J}
|
|
728
729
|
`),process.stdout.write(`
|
|
729
730
|
`);let Z=await Promise.all(h8.map(async(q)=>[q,await f(q)!==null])),z=new Map;for(let[q,K]of Z)z.set(q,K?`${S}installed${J}`:`${T}not installed${J}`);let X=[["claude","claude - Claude Code (Anthropic) "],["codex","codex - Codex CLI (OpenAI) "],["cline","cline - Cline (multi-provider) "],["aider","aider - Aider (terminal pair prog) "]];for(let[q,K]of X){let W=Q===q?` ${I}(current)${J}`:"";process.stdout.write(` ${K} ${z.get(q)}${W}
|
|
730
731
|
`)}return process.stdout.write(`
|
|
@@ -747,7 +748,7 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
747
748
|
`),process.stdout.write(` loki provider list
|
|
748
749
|
`),process.stdout.write(` loki provider info codex
|
|
749
750
|
`),process.stdout.write(` loki provider models
|
|
750
|
-
`),0}async function
|
|
751
|
+
`),0}async function l1($){let Q=$[0]??"show",Z=$.slice(1);switch(Q){case"show":case"current":return v8(Z[0]);case"list":return g8();case"set":case"info":case"models":return f8(["provider",Q,...Z]);default:return m8()}}async function f8($){let{run:Q}=await Promise.resolve().then(() => (d(),c1)),{resolve:Z}=await import("path"),{REPO_ROOT:z}=await Promise.resolve().then(() => (C(),v1)),X=Z(z,"autonomy","loki"),q=await Q([X,...$],{env:{LOKI_LEGACY_BASH:"1"},timeoutMs:3600000});return process.stdout.write(q.stdout),process.stderr.write(q.stderr),q.exitCode}c();C();V$();import{existsSync as d1,readFileSync as c8}from"fs";import{resolve as W$}from"path";import{mkdir as p8}from"fs/promises";var w$=W$(T$(),"learnings");function Z1($){if(!d1($))return 0;try{let Q=c8($,"utf-8"),Z=0;for(let z of Q.split(`
|
|
751
752
|
`))if(z.includes('"description"'))Z++;return Z}catch{return 0}}async function l8(){await p8(w$,{recursive:!0});let $=Z1(W$(w$,"patterns.jsonl")),Q=Z1(W$(w$,"mistakes.jsonl")),Z=Z1(W$(w$,"successes.jsonl"));return process.stdout.write(`${k}Cross-Project Learnings${J}
|
|
752
753
|
`),process.stdout.write(`
|
|
753
754
|
`),process.stdout.write(` Patterns: ${S}${$}${J}
|
|
@@ -767,11 +768,11 @@ except ImportError:
|
|
|
767
768
|
print('Error: memory.layers module not found')
|
|
768
769
|
except Exception as e:
|
|
769
770
|
print(f'Error: {e}')
|
|
770
|
-
`.trim(),X=await z$(z,{cwd:h});return process.stdout.write(X.stdout),0}let Q=W$(P(),"memory","index.json");if(!
|
|
771
|
+
`.trim(),X=await z$(z,{cwd:h});return process.stdout.write(X.stdout),0}let Q=W$(P(),"memory","index.json");if(!d1(Q))return process.stdout.write(`No index found
|
|
771
772
|
`),0;let Z=await z$(`import json, sys; sys.stdout.write(json.dumps(json.load(open(${JSON.stringify(Q)})), indent=4) + "\\n")`);if(Z.exitCode!==0)return process.stdout.write(`No index found
|
|
772
|
-
`),0;return process.stdout.write(Z.stdout),0}async function
|
|
773
|
-
`)){let K=q.replace(/\r$/,"");if(K==="TELEMETRY_DISABLED=true")Q=!0;if(K==="TELEMETRY_ENABLED=true")Z=!0}}}catch{}if(Q)return!1;if($==="on"||Z)return!0;return!1}var S$=!1;function r8(){return o8(h,"autonomy","lib","crash_capture.py")}function i8($,Q){let Z=[$,"--error-class",Q.errorClass,"--message",Q.message];if(Q.stack!==void 0)Z.push("--stack",Q.stack);if(Q.rarvPhase!==void 0)Z.push("--rarv-phase",Q.rarvPhase);if(Q.exitCode!==void 0)Z.push("--exit-code",String(Q.exitCode));if(Q.frictionKind!==void 0)Z.push("--friction-kind",Q.frictionKind);return Z.push("--target-dir",Q.targetDir??process.cwd()),Z}function e8(){if(z1("/opt/homebrew/bin/python3.12"))return"/opt/homebrew/bin/python3.12";for(let Q of["python3.12","python3"])try{let Z=
|
|
774
|
-
`)}catch{}process.exit(1)}),process.on("unhandledRejection",($)=>{if(!S$){S$=!0;let Q=
|
|
773
|
+
`),0;return process.stdout.write(Z.stdout),0}async function o1($){switch($[0]??"list"){case"list":case"ls":return l8();case"index":return d8($[1]==="rebuild");default:{let Z=W$(h,"autonomy","loki"),z=3600000,X=Bun.spawn({cmd:[Z,"memory",...$],stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,LOKI_LEGACY_BASH:"1"}}),q=setTimeout(()=>{try{X.kill("SIGKILL")}catch{}},3600000);try{return await X.exited}finally{clearTimeout(q)}}}}C();V$();d();import{resolve as o8,join as n8}from"path";import{existsSync as z1,readFileSync as a8}from"fs";import{homedir as s8}from"os";import{spawnSync as t1}from"child_process";var r1=3000;function t8(){let $=(process.env.LOKI_TELEMETRY??"").toLowerCase();if($==="off")return!1;if(process.env.LOKI_TELEMETRY_DISABLED==="true")return!1;if(process.env.DO_NOT_TRACK==="1")return!1;let Q=!1,Z=!1;try{let z=n8(s8(),".loki","config");if(z1(z)){let X=a8(z,"utf8");for(let q of X.split(`
|
|
774
|
+
`)){let K=q.replace(/\r$/,"");if(K==="TELEMETRY_DISABLED=true")Q=!0;if(K==="TELEMETRY_ENABLED=true")Z=!0}}}catch{}if(Q)return!1;if($==="on"||Z)return!0;return!1}var S$=!1;function r8(){return o8(h,"autonomy","lib","crash_capture.py")}function i8($,Q){let Z=[$,"--error-class",Q.errorClass,"--message",Q.message];if(Q.stack!==void 0)Z.push("--stack",Q.stack);if(Q.rarvPhase!==void 0)Z.push("--rarv-phase",Q.rarvPhase);if(Q.exitCode!==void 0)Z.push("--exit-code",String(Q.exitCode));if(Q.frictionKind!==void 0)Z.push("--friction-kind",Q.frictionKind);return Z.push("--target-dir",Q.targetDir??process.cwd()),Z}function e8(){if(z1("/opt/homebrew/bin/python3.12"))return"/opt/homebrew/bin/python3.12";for(let Q of["python3.12","python3"])try{let Z=t1("sh",["-c",`command -v ${Q}`],{timeout:r1,encoding:"utf8"});if(Z.status===0){let z=(Z.stdout||"").trim();if(z)return z}}catch{}return null}function n1($){try{if(!t8())return;let Q=r8();if(!z1(Q))return;let Z=e8();if(!Z)return;let z=i8(Q,$);t1(Z,z,{timeout:r1,stdio:"ignore"})}catch{}}function a1($,Q){if($ instanceof Error){let z={errorClass:$.name&&$.name.length>0?$.name:Q,message:$.message};if($.stack)z.stack=$.stack;return z}return{errorClass:Q,message:String($)}}var s1=!1;function i1(){if(s1)return;s1=!0,process.on("uncaughtException",($)=>{if(!S$){S$=!0;let Q=a1($,"UncaughtException");n1({errorClass:Q.errorClass,message:Q.message,...Q.stack!==void 0?{stack:Q.stack}:{},exitCode:1})}try{process.stderr.write(`${$&&$.stack||String($)}
|
|
775
|
+
`)}catch{}process.exit(1)}),process.on("unhandledRejection",($)=>{if(!S$){S$=!0;let Q=a1($,"UnhandledRejection");n1({errorClass:Q.errorClass,message:Q.message,...Q.stack!==void 0?{stack:Q.stack}:{},exitCode:1})}try{let Q=$ instanceof Error?$.stack||$.message:String($);process.stderr.write(`Unhandled promise rejection: ${Q}
|
|
775
776
|
`)}catch{}process.exit(1)})}var Z8=`Loki Mode (TypeScript port, Phase 2 of bash->Bun migration)
|
|
776
777
|
|
|
777
778
|
Usage: loki <command> [args...]
|
|
@@ -794,12 +795,12 @@ Phase 2 ported (Bun-native, fast):
|
|
|
794
795
|
|
|
795
796
|
All other commands fall through to the bash CLI (autonomy/loki).
|
|
796
797
|
Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
797
|
-
`;function
|
|
798
|
-
`)}async function
|
|
798
|
+
`;function FZ(){let $=process.env.LOKI_LEGACY_BASH;if($===void 0)return;let Q=$.trim().toLowerCase();if(Q!=="1"&&Q!=="true"&&Q!=="yes"&&Q!=="on")return;if(process.env.LOKI_SUPPRESS_BUN_DIRECT_WARN==="1")return;process.stderr.write(`warning: LOKI_LEGACY_BASH is set, but you are running the Bun runtime directly (src/cli.ts). The env var only takes effect via the bin/loki shim, which dispatches between Bun and bash. Behavior is unchanged; this message is informational.
|
|
799
|
+
`)}async function kZ($){FZ();let Q=$[0],Z=$.slice(1);switch(Q){case void 0:case"help":case"--help":case"-h":return process.stdout.write(Z8),0;case"version":case"--version":case"-v":return await m1();case"provider":return l1(Z);case"memory":return o1(Z);case"status":{let{runStatus:z}=await Promise.resolve().then(() => (V0(),J0));return z(Z)}case"stats":{let{runStats:z}=await Promise.resolve().then(() => (M0(),Y0));return z(Z)}case"doctor":{let{runDoctor:z}=await Promise.resolve().then(() => (j0(),P0));return z(Z)}case"kpis":{let{runKpis:z}=await Promise.resolve().then(() => (M1(),Y1));return z(Z,{aliasOf:"kpis"})}case"report":{if(Z.find((q)=>!q.startsWith("-"))==="kpis"){let{runKpis:q}=await Promise.resolve().then(() => (M1(),Y1)),K=!1,W=Z.filter((V)=>{if(!K&&V==="kpis")return K=!0,!1;return!0});return q(W)}let{delegateToBash:X}=await Promise.resolve().then(() => (v0(),y0));return X(["report",...Z])}case"trust":{let{runTrust:z}=await Promise.resolve().then(() => (o0(),d0));return z(Z)}case"rollback":{let{runRollback:z}=await Promise.resolve().then(() => (AQ(),OQ));return z(Z)}case"proof":case"receipt":{let{runProof:z}=await Promise.resolve().then(() => (PQ(),LQ));return z(Z)}case"crash":{let{runCrash:z}=await Promise.resolve().then(() => (NQ(),xQ));return z(Z)}case"wiki":{let{runWiki:z}=await Promise.resolve().then(() => (hQ(),bQ));return z(Z)}case"internal":{let z=Z[0];if(!z||z==="--help"||z==="-h"||z==="help"){let q=["loki internal -- runtime hooks driven by autonomy/run.sh","","Subcommands:"," phase1-hooks Persist structured findings, run override council,"," append learnings, and write the escalation handoff"," doc once per iteration. Driven by run.sh; not"," intended for direct invocation.","","Phase 1 (RARV-C closure) env vars:"," LOKI_INJECT_FINDINGS=1 Persist structured reviewer findings to"," .loki/state/findings-<iter>.json so the"," next iteration can address them."," LOKI_OVERRIDE_COUNCIL=1 Allow a 3-LLM override panel to lift a"," BLOCK when counter-evidence is presented."," See LOKI_OVERRIDE_JUDGES (csv),"," LOKI_OVERRIDE_PANEL_SIZE,"," LOKI_OVERRIDE_REAL_JUDGE."," LOKI_AUTO_LEARNINGS=1 Append failure rootcauses to"," .loki/state/relevant-learnings.json via"," the episodic memory bridge."," LOKI_HANDOFF_MD=1 Write a structured human handoff doc to"," .loki/escalations/<ts>.md before PAUSE.","","All four are default-on as of v7.5.3. Set to 0 to disable.","Reference: CHANGELOG.md (search 'Phase 1') and skills/healing.md.","","These commands are wired into the autonomous loop and may change","without notice. Do not script against them.",""].join(`
|
|
799
800
|
`);return process.stdout.write(`${q}
|
|
800
801
|
`),0}if(z==="phase1-hooks"){let{runInternalPhase1Hooks:q}=await Promise.resolve().then(() => (Q8(),$8));return q(Z.slice(1))}return process.stderr.write(`Unknown internal subcommand: ${z}
|
|
801
802
|
`),process.stderr.write(`Run 'loki internal --help' for the supported list.
|
|
802
803
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
803
|
-
`),process.stderr.write(Z8),2}}
|
|
804
|
+
`),process.stderr.write(Z8),2}}i1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var RZ=await kZ(Bun.argv.slice(2));process.exit(RZ);
|
|
804
805
|
|
|
805
|
-
//# debugId=
|
|
806
|
+
//# debugId=52AE4FC24550CB9764756E2164756E21
|
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.104.
|
|
4
|
+
"version": "7.104.1",
|
|
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.104.
|
|
5
|
+
"version": "7.104.1",
|
|
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",
|