loki-mode 7.104.0 → 7.104.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +28 -6
- package/autonomy/run.sh +134 -10
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +132 -129
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var X8=Object.defineProperty;var K8=($)=>$;function q8($,Q){this[$]=K8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)X8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:q8.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 r,dirname as i$}from"path";import{fileURLToPath as J8}from"url";import{existsSync as x$}from"fs";import{homedir as V8}from"os";function W8(){let $=y1;for(let Q=0;Q<6;Q++){if(x$(r($,"VERSION"))&&x$(r($,"autonomy/run.sh")))return $;let Z=i$($);if(Z===$)break;$=Z}return r(y1,"..","..","..")}function e$($){let Q=$;for(let Z=0;Z<6;Z++){if(x$(r(Q,"VERSION"))&&x$(r(Q,"autonomy/run.sh")))return Q;let z=i$(Q);if(z===Q)break;Q=z}return r($,"..","..","..")}function P(){return process.env.LOKI_DIR??r(process.cwd(),".loki")}function T$(){return r(V8(),".loki")}var y1,h;var C=L(()=>{y1=i$(J8(import.meta.url));h=W8()});import{readFileSync as U8}from"fs";import{resolve as H8,dirname as G8}from"path";import{fileURLToPath as B8}from"url";function N$(){if(Q$!==null)return Q$;let $="7.104.2";if(typeof $==="string"&&$.length>0)return Q$=$,Q$;try{let Q=G8(B8(import.meta.url)),Z=e$(Q);Q$=U8(H8(Z,"VERSION"),"utf-8").trim()}catch{Q$="unknown"}return Q$}var Q$=null;var $1=L(()=>{C()});var c1={};b(c1,{runOrThrow:()=>x8,run:()=>F,readStreamCapped:()=>u1,commandVersion:()=>S8,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 x8($,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=N8($),Z=await F(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function N8($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function S8($,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 t($){return D8?"":$}var D8,T,S,_,nZ,I,k,y,J;var c=L(()=>{D8=(process.env.NO_COLOR??"").length>0;T=t("\x1B[0;31m"),S=t("\x1B[0;32m"),_=t("\x1B[1;33m"),nZ=t("\x1B[0;34m"),I=t("\x1B[0;36m"),k=t("\x1B[1m"),y=t("\x1B[2m"),J=t("\x1B[0m")});import{existsSync as c8}from"fs";async function Z$(){if(A$!==void 0)return A$;let $="/opt/homebrew/bin/python3.12";if(c8($))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:()=>U3});import{existsSync as v,readFileSync as U$,readdirSync as e1,statSync as $0}from"fs";import{resolve as D,basename as Q3}from"path";import{homedir as Z3}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 X3(){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
|
|
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 K3($){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=Q3(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 q3(){let $=P();if(!await X3())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.
|
|
@@ -19,7 +19,7 @@ var z8=Object.defineProperty;var X8=($)=>$;function K8($,Q){this[$]=X8.bind(null
|
|
|
19
19
|
`);let Q="",Z=D($,"state","provider");if(v(Z))try{Q=U$(Z,"utf-8").trim()}catch{Q=""}let z=Q||process.env.LOKI_PROVIDER||"claude",X="full features";switch(z){case"codex":case"aider":X="degraded mode";break;case"cline":X="near-full mode";break;default:X="full features";break}process.stdout.write(`${I}Provider:${J} ${z} (${X})
|
|
20
20
|
`),process.stdout.write(`${y} Switch with: loki provider set <claude|codex|cline|aider>${J}
|
|
21
21
|
`),process.stdout.write(`
|
|
22
|
-
`);let q=
|
|
22
|
+
`);let q=K3($);if(q.length>0){process.stdout.write(`${S}Active Sessions: ${q.length}${J}
|
|
23
23
|
`);for(let Y of q){let O=Y.indexOf(":"),M=O>=0?Y.slice(0,O):Y,R=O>=0?Y.slice(O+1):"";if(M==="global")process.stdout.write(` ${I}[global]${J} PID ${R}
|
|
24
24
|
`);else process.stdout.write(` ${I}[#${M}]${J} PID ${R}
|
|
25
25
|
`)}process.stdout.write(`
|
|
@@ -35,27 +35,27 @@ 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(
|
|
45
|
-
`)}}return await
|
|
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(Z3(),".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
|
+
`)}}return await J3($),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
|
-
`),0}async function
|
|
48
|
+
`),0}async function J3($){let Q=D($,"state"),Z=V3(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
|
|
54
|
-
`),1;let Q=h,Z=P(),z=process.env.LOKI_DASHBOARD_PORT||"57374",X=process.env.LOKI_PROVIDER||"claude",q=await F([$,"-c",
|
|
55
|
-
`),1;return process.stdout.write(q.stdout),0}async function
|
|
53
|
+
`)}}function V3($){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 W3(){let $=await Z$();if(!$)return process.stderr.write(`{"error": "Failed to generate JSON status. Ensure python3 is available."}
|
|
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
|
+
`),1;return process.stdout.write(q.stdout),0}async function U3($){let Q=[...$];while(Q.length>0){let Z=Q[0];if(Z==="--json")return W3();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}
|
|
57
57
|
`),process.stdout.write(`Usage: loki status [--json]
|
|
58
|
-
`),1}return
|
|
58
|
+
`),1}return q3()}var D$=30,z3=`
|
|
59
59
|
import json, os, sys, time
|
|
60
60
|
|
|
61
61
|
skill_dir = sys.argv[1]
|
|
@@ -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
|
|
334
|
-
`)}function
|
|
335
|
-
Start a session with: loki start <prd>`}}let X=
|
|
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
|
|
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&&G3.has(Q))return!0;for(let Z of $)if(H3.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 H3,G3;var K1=L(()=>{H3=new Set(["--json","-q","--quiet"]),G3=new Set(["json","csv","timeline"])});var Y0={};b(Y0,{runStats:()=>A3,computeStats:()=>B0});import{readdirSync as H0,readFileSync as B3,statSync as G0}from"fs";import{join as i}from"path";function H$($){try{if(!G0($).isFile())return null;return JSON.parse(B3($,"utf-8"))}catch{return null}}function V1($){try{return G0($).isDirectory()}catch{return!1}}function Y3($){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 M3($){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=Y3(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,t$=i($,"quality");if(V1(t$)){let j=[];try{j=H0(t$)}catch{j=[]}for(let x of j){if(!x.endsWith(".json")||x==="gate-failure-count.json")continue;let l=H$(i(t$,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 T3($,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 O3($,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=M3(z);return{exitCode:0,stdout:Q?T3(X,Z):O3(X,Z)}}async function A3($){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 j0={};b(j0,{runDoctor:()=>b3,pythonImportOk:()=>B1,httpReachable:()=>U1,checkTool:()=>_0,checkSkills:()=>I0,checkDisk:()=>G1,buildDoctorJson:()=>P0,_setPythonImportOkForTest:()=>F3});import{existsSync as T0,lstatSync as w3,readFileSync as _3,readlinkSync as I3,statfsSync as L3}from"fs";import{spawnSync as O0}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 A0($){try{let Q=await F([$,"--version"],{timeoutMs:5000}),Z=(Q.stdout||Q.stderr||"").trim();return j3(Z)}catch{return null}}function w0($,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 _0($,Q,Z,z=null){let X=await f(Q),q=X!==null,K=q?await A0(Q):null,W="pass";if(!q)W=Z==="required"?"fail":"warn";else if(z&&K){if(w0(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=L3(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 I0(){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(w3(z).isSymbolicLink()){let W="unknown";try{W=I3(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 L0(){return Promise.all(R3.map(async($)=>{return{...await _0($.jsonName,$.cmd,$.required,$.min??null),displayName:$.displayName}}))}async function E3(){let Q=await f("sentrux")!==null,Z=Q?await A0("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 P0(){let Q=(await L0()).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=_3(`${$}/.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 S3(){try{let Q=(O0("claude",["auth","status"],{encoding:"utf8",timeout:5000}).stdout||"").trim();if(!Q)return"";let Z=JSON.parse(Q);if(Z?.loggedIn===!0)return"yes";if(Z?.loggedIn===!1)return"no";return""}catch{return""}}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&&w0($.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 D3(){process.stdout.write(`${k}loki doctor${J} - Check system prerequisites
|
|
337
337
|
|
|
338
338
|
`),process.stdout.write(`Usage: loki doctor [--json]
|
|
339
339
|
|
|
@@ -342,30 +342,33 @@ 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 C3(){process.stdout.write(`${k}Loki Mode Doctor${J}
|
|
346
346
|
|
|
347
347
|
`),process.stdout.write(`Checking system prerequisites...
|
|
348
348
|
|
|
349
|
-
`);let $={pass:0,fail:0,warn:0},Q=await
|
|
350
|
-
`);for(let w of["node","python3","jq","git","curl"]){let
|
|
351
|
-
`),y$($,
|
|
349
|
+
`);let $={pass:0,fail:0,warn:0},Q=await L0(),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 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))O0("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(` ${
|
|
361
|
-
`)
|
|
360
|
+
`),$.pass++;else if(K){let w=S3();if(w==="yes")process.stdout.write(` ${A("pass")} Claude CLI is logged in (subscription/OAuth login)
|
|
361
|
+
`),$.pass++;else if(w==="no")process.stdout.write(` ${A("warn")} Claude CLI is NOT logged in -- run 'claude login' before a build (it would otherwise stall)
|
|
362
|
+
`),$.warn++;else if(N3())process.stdout.write(` ${A("warn")} Claude login has EXPIRED -- run 'claude login' before a build (it would otherwise stall)
|
|
363
|
+
`),$.warn++;else process.stdout.write(` ${y} -- ${J} ANTHROPIC_API_KEY not set (Claude CLI uses its own login)
|
|
364
|
+
`)}if(V.OPENAI_API_KEY)process.stdout.write(` ${A("pass")} OPENAI_API_KEY is set
|
|
362
365
|
`),$.pass++;else if(W)process.stdout.write(` ${y} -- ${J} OPENAI_API_KEY not set (Codex CLI uses its own login)
|
|
363
366
|
`);if(V.ANTHROPIC_BASE_URL){let w=V.ANTHROPIC_BASE_URL;if(process.stdout.write(` ${A("pass")} ANTHROPIC_BASE_URL: ${w}
|
|
364
367
|
`),$.pass++,!V.LOKI_MODEL_OVERRIDE)process.stdout.write(` ${A("warn")} LOKI_MODEL_OVERRIDE not set -- opus/sonnet/haiku aliases may not resolve on alt-provider
|
|
365
368
|
`),$.warn++;else process.stdout.write(` ${A("pass")} LOKI_MODEL_OVERRIDE: ${V.LOKI_MODEL_OVERRIDE}
|
|
366
369
|
`),$.pass++}process.stdout.write(`
|
|
367
370
|
`),process.stdout.write(`${I}Skills:${J}
|
|
368
|
-
`);for(let w of
|
|
371
|
+
`);for(let w of I0())if(w.status==="pass")process.stdout.write(` ${A("pass")} ${w.name} ${y}${w.path}${J}
|
|
369
372
|
`),$.pass++;else if(w.status==="fail")process.stdout.write(` ${A("fail")} ${w.name} ${y}${w.detail}${J}
|
|
370
373
|
`),process.stdout.write(` ${_}Fix: loki setup-skill${J}
|
|
371
374
|
`),$.fail++;else process.stdout.write(` ${A("warn")} ${w.name} ${y}${w.detail}${J}
|
|
@@ -379,7 +382,7 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
379
382
|
`),$.pass++;else process.stdout.write(` ${A("warn")} sentence-transformers - not installed (loki memory vectors setup)
|
|
380
383
|
`),$.warn++;if(await U1("http://localhost:8100/api/v2/heartbeat"))process.stdout.write(` ${A("pass")} ChromaDB server (port 8100)
|
|
381
384
|
`),$.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"],
|
|
385
|
+
`),$.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
386
|
`),$.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
387
|
`),$.warn++}let G=process.env.LOKI_MIROFISH_URL;if(G)if(await U1(`${G}/health`))process.stdout.write(` ${A("pass")} MiroFish server (${G})
|
|
385
388
|
`),$.pass++;else process.stdout.write(` ${A("warn")} MiroFish - not running (loki start --mirofish-docker <image>)
|
|
@@ -391,7 +394,7 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
391
394
|
`),process.stdout.write(`${I}System:${J}
|
|
392
395
|
`);let Y=Z.get("bash");process.stdout.write(h$(Y)+`
|
|
393
396
|
`),y$($,Y.status);let O=Z.get("bun");if(O)process.stdout.write(h$(O)+`
|
|
394
|
-
`),y$($,O.status);let M=
|
|
397
|
+
`),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
398
|
`),$.warn++;else if(M.status==="fail")process.stdout.write(` ${A("fail")} Disk space: ${R}GB available (need >= 1GB)
|
|
396
399
|
`),$.fail++;else if(M.status==="warn")process.stdout.write(` ${A("warn")} Disk space: ${R}GB available (low)
|
|
397
400
|
`),$.warn++;else process.stdout.write(` ${A("pass")} Disk space: ${R}GB available
|
|
@@ -401,8 +404,8 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
401
404
|
`),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
405
|
`);if(process.env.LOKI_TS_ENTRY)process.stdout.write(` ${A("pass")} LOKI_TS_ENTRY override: ${process.env.LOKI_TS_ENTRY}
|
|
403
406
|
`);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(
|
|
407
|
+
`);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}
|
|
408
|
+
`);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
409
|
`);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
410
|
`)}else process.stdout.write(` ${A("warn")} Python 3 not on PATH -- memory + MCP integrations disabled. The rest of Loki works without them.
|
|
408
411
|
`);if(process.stdout.write(`
|
|
@@ -415,15 +418,15 @@ Start a session with: loki start <prd>`}}let X=Y3(z);return{exitCode:0,stdout:Q?
|
|
|
415
418
|
`);return process.stdout.write(`
|
|
416
419
|
`),process.stdout.write(`Next: loki quickstart (guided first build from your idea, no PRD needed)
|
|
417
420
|
`),process.stdout.write(` or loki demo (builds a sample todo app end to end) or loki start ./prd.md
|
|
418
|
-
`),0}async function
|
|
421
|
+
`),0}async function b3($){let Q=!1;for(let Z of $)if(Z==="--json")Q=!0;else if(Z==="--help"||Z==="-h")return D3(),0;else return process.stderr.write(`${T}Unknown option: ${Z}${J}
|
|
419
422
|
`),process.stderr.write(`Usage: loki doctor [--json]
|
|
420
|
-
`),1;if(Q){let Z=await
|
|
421
|
-
`),0}return
|
|
422
|
-
`)}var
|
|
423
|
+
`),1;if(Q){let Z=await P0();return process.stdout.write(JSON.stringify(Z,null,2)+`
|
|
424
|
+
`),0}return C3()}var P3,v$,k3,R3;var F0=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 E0,mkdirSync as f9,readdirSync as h3,readFileSync as x0,renameSync as u9,writeFileSync as c9}from"fs";import{dirname as y3,join as v3,resolve as g3}from"path";import{fileURLToPath as m3}from"url";function f3(){try{let $=y3(m3(import.meta.url)),Q=g3($,"..","..","data","model-pricing.json");if(!E0(Q))return _$;let z=JSON.parse(x0(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 u3($){return Math.round(($+Number.EPSILON)*1e4)/1e4}function c3($){let Q=($??R0).toLowerCase();return k0[Q]??k0[R0]}function N0($){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=c3(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 u3(Q)}function S0($){if(!E0($))return[];let Q=[],Z;try{Z=h3($)}catch{return[]}for(let z of Z){if(!z.endsWith(".json"))continue;let X=v3($,z);try{let q=x0(X,"utf8"),K=JSON.parse(q);if(K&&typeof K==="object")Q.push(K)}catch{}}return Q}var _$,k0,R0="sonnet";var D0=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}};k0=Object.freeze(f3())});import{existsSync as g$,readdirSync as p3,readFileSync as l3,statSync as d3}from"fs";import{join as m$}from"path";function o3($){let Q=[],Z=m$($,"votes");if(!g$(Z))return Q;let z;try{z=p3(Z)}catch{return Q}for(let X of z){if(!X.startsWith("round-")||!X.endsWith(".json"))continue;try{let q=m$(Z,X);if(!d3(q).isFile())continue;let K=JSON.parse(l3(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 n3(){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 a3(){return{council_rounds:0,unanimous_rate:null,approval_rate:null,iteration_success_rate:null}}function s3($){let Q=n3();if($.length===0)return Q;Q.iteration_count=$.length,Q.total_cost_usd=Math.round(N0($)*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 r3($,Q,Z){let z=a3();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 C0($){let Q=[],Z=m$($,"metrics","efficiency"),z=m$($,"council"),X=g$(Z)?S0(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=o3(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=s3(X),W=K.status_breakdown.success??0,V=r3(q,W,K.iteration_count);return{schema_version:1,generated_at:new Date().toISOString(),loki_dir:$,efficiency:K,accuracy:V,notes:Q}}function b0($){return JSON.stringify($,null,2)}function h0($){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(`
|
|
425
|
+
`)}var y0=L(()=>{D0()});var Y1={};b(Y1,{runKpis:()=>i3});function i3($,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
426
|
Run 'loki kpis --help' for usage.
|
|
424
|
-
`),1}let z=
|
|
425
|
-
`:
|
|
426
|
-
`),0}var
|
|
427
|
+
`),1}let z=C0(P());return process.stdout.write(Z?b0(z)+`
|
|
428
|
+
`:h0(z)+`
|
|
429
|
+
`),0}var t3=`loki report kpis -- accuracy + efficiency KPI snapshot (v7.5.28 MVP)
|
|
427
430
|
|
|
428
431
|
Usage:
|
|
429
432
|
loki report kpis Pretty-print KPI snapshot
|
|
@@ -444,13 +447,13 @@ iteration success rate.
|
|
|
444
447
|
This is the Phase K MVP -- read-only derivation. Per-iteration
|
|
445
448
|
emission, dashboard panel, and the loki-bench harness are deferred
|
|
446
449
|
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
|
|
450
|
+
`;var M1=L(()=>{y0();C();K1()});var v0={};b(v0,{delegateToBash:()=>Q6});import{resolve as e3}from"path";async function Q6($){let Q=e3(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{}},$6);try{return await Z.exited}finally{clearTimeout(z)}}var $6=3600000;var g0=L(()=>{C()});import{existsSync as Z6,mkdirSync as z6,readdirSync as X6,readFileSync as K6,statSync as q6,writeFileSync as J6}from"fs";import{join as I$}from"path";function T1($){return $&&typeof $==="object"?$:{}}function X$($){return Math.round($*1e4)/1e4}function G6($){let Q=String($??"").trim().toUpperCase();if(!Q)return null;for(let Z of f0)if(Q.startsWith(Z))return!0;return!1}function B6($){let Q=G6($.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(f0.some((W)=>K.startsWith(W)))z+=1}if(X>0)return z===X?1:0}return null}function Y6($){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 M6($){let Q;if($&&typeof $==="object")Q=$.count;else Q=$;let Z=Number(Q);if(!Number.isFinite(Z)||Z<0)return null;return Z}function T6($){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 O6($){let Q=I$($,"proofs"),Z=[];if(!Z6(Q))return Z;let z;try{z=X6(Q).sort()}catch{return Z}for(let X of z){let q=I$(Q,X);try{if(!q6(q).isDirectory())continue}catch{continue}let K=null;try{K=JSON.parse(K6(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:B6(T1(K.council)),gate_pass_rate:Y6(T1(K.quality_gates)),iterations:M6(K.iterations),interventions:T6(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 m0($){return $.reduce((Q,Z)=>Q+Z,0)/$.length}function A6($,Q){let Z=W6[$],z=U6[$],X=H6[$],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=m0(V),B=m0(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 u0($){let Q=O6($),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]=A6(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:V6,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 c0($){return JSON.stringify($,null,2)}function p0($,Q){let Z=I$($,"metrics"),z=I$(Z,"trust-trajectory.json");try{return z6(Z,{recursive:!0}),J6(z,JSON.stringify(Q,null,2)),z}catch{return null}}function w6($){if($==="up")return"up";if($==="down")return"down";return"flat"}function _6($){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)} ${w6($.direction).padEnd(5)} latest=${String(X).padEnd(7)} ${Z.padEnd(11)} [${z}]`}function l0($){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(`
|
|
451
|
+
`)}Q.push("Is the agent earning autonomy on this repo?");for(let X of f$)if($.axes[X])Q.push(_6($.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(`
|
|
452
|
+
`)}var V6=1,f$,W6,U6,H6,f0;var d0=L(()=>{f$=["council_pass_rate","gate_pass_rate","iterations","interventions"],W6={council_pass_rate:!0,gate_pass_rate:!0,iterations:!1,interventions:!1},U6={council_pass_rate:0.01,gate_pass_rate:0.01,iterations:0.25,interventions:0.25},H6={council_pass_rate:"Council pass rate",gate_pass_rate:"Gate pass rate",iterations:"Iterations to completion",interventions:"Human interventions"},f0=["APPROVE","APPROVED","COMPLETE","PASS","PASSED"]});var o0={};b(o0,{runTrust:()=>L6});function L6($){let Q=!1;for(let X of $){if(X==="--help"||X==="-h"||X==="help")return process.stdout.write(I6),0;if(X==="--json"){Q=!0;continue}return process.stderr.write(`loki trust: unknown arg: ${X}
|
|
450
453
|
Run 'loki trust --help' for usage.
|
|
451
|
-
`),1}let Z=P(),z=
|
|
452
|
-
`:
|
|
453
|
-
`),0}var
|
|
454
|
+
`),1}let Z=P(),z=u0(Z);return p0(Z,z),process.stdout.write(Q?c0(z)+`
|
|
455
|
+
`:l0(z)+`
|
|
456
|
+
`),0}var I6=`loki trust -- visible trust trajectory (R4)
|
|
454
457
|
|
|
455
458
|
Usage:
|
|
456
459
|
loki trust Pretty-print the per-project trust trajectory
|
|
@@ -466,30 +469,30 @@ Shows whether the agent is earning autonomy on THIS repo over time:
|
|
|
466
469
|
Derived read-only from proof-of-run history in .loki/proofs/. With fewer
|
|
467
470
|
than 2 recorded runs it reports "not enough history yet" rather than a
|
|
468
471
|
fabricated trend. Complements 'loki kpis' (single-run snapshot).
|
|
469
|
-
`;var
|
|
470
|
-
`)}async 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
|
-
`)}),
|
|
472
|
+
`;var n0=L(()=>{d0();C()});import{closeSync as L$,fstatSync as P6,fsyncSync as a0,lstatSync as j6,mkdirSync as s0,openSync as c$,readSync as F6,renameSync as k6,rmSync as r0,statSync as R6,unlinkSync as t0,writeSync as i0}from"fs";import{dirname as O1}from"path";function A1($,Q){s0(O1($),{recursive:!0});let Z=`${$}.tmp.${process.pid}.${++E6}`,z=c$(Z,"w");try{i0(z,Q),a0(z)}finally{L$(z)}k6(Z,$),x6($)}function x6($){let Q=null;try{Q=c$(O1($),"r"),a0(Q)}catch{}finally{if(Q!==null)try{L$(Q)}catch{}}}function P$($,Q){A1($,`${JSON.stringify(Q,null,2)}
|
|
473
|
+
`)}async function e0($,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 S6($){return`${$}.lock`}function D6($){if(!Number.isFinite($)||$<=0)return!1;try{return process.kill($,0),!0}catch(Q){return Q?.code==="EPERM"}}function C6($){let Q=null;try{return s0(O1($),{recursive:!0}),Q=c$($,"wx"),i0(Q,`${process.pid}
|
|
474
|
+
`),Q}catch(Z){if(Q!==null){try{L$(Q)}catch{}try{t0($)}catch{}}if(Z?.code==="EEXIST")return null;throw Z}}function b6($,Q){let Z;try{Z=j6($)}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=P6(z);if(Date.now()-X.mtimeMs<Q)return!1;let K=NaN;try{let W=Buffer.alloc(64),V=F6(z,W,0,64,0);K=Number.parseInt(W.subarray(0,V).toString("utf-8").trim(),10)}catch{}if(Number.isFinite(K)&&D6(K))return!1;try{if(R6($).mtimeMs>X.mtimeMs)return!1}catch{return!0}try{r0($,{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=S6($),W=Date.now()+z,V=null,U=0,H=new Int32Array(new SharedArrayBuffer(4));while(V===null){if(V=C6(K),V!==null)break;if(Date.now()>W)throw Error(`withFileLockSync: timed out after ${z}ms acquiring ${K}`);if(b6(K,q))continue;let B=Math.min(X*2**Math.min(U,4),N6);U+=1,Atomics.wait(H,0,0,B)}try{return Q()}finally{try{L$(V)}catch{}try{r0(K,{force:!0})}catch{}}}var E6=0,u$,N6=50;var F$=L(()=>{u$=new Map});import{existsSync as K$,mkdirSync as Y$,copyFileSync as zQ,readFileSync as I1,readdirSync as h6,statSync as y6,writeFileSync as v6,renameSync as XQ,appendFileSync as KQ,rmSync as g6}from"fs";import{join as m,dirname as p$}from"path";function f6($){let Q=QQ.then($,$);return QQ=Q.catch((Z)=>{console.warn("[checkpoint] serialized op rejected:",Z);return}),Q}function o($){return m($,"state","checkpoints")}function qQ($){return m(o($),"index.jsonl")}async function u6($){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 c6($){let Q=await F(["git","branch","--show-current"],{cwd:$,timeoutMs:5000});if(Q.exitCode!==0)return"unknown";return Q.stdout.trim()||"unknown"}async function p6($){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 l6($){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 o6($,Q){for(let Z of d6){let z=m($,Z);if(!K$(z))continue;let X=m(Q,Z);Y$(p$(X),{recursive:!0});try{zQ(z,X)}catch{}}}function VQ($,Q){Y$(p$($),{recursive:!0});let Z=`${$}.tmp.${process.pid}.${++JQ}`;v6(Z,Q),XQ(Z,$)}function n6($){return JSON.stringify($,null,2)}function WQ($){return`{${[`"id": ${JSON.stringify($.id)}`,`"ts": ${JSON.stringify($.ts)}`,`"iter": ${JSON.stringify($.iter)}`,`"task": ${JSON.stringify($.task)}`,`"sha": ${JSON.stringify($.sha)}`].join(", ")}}`}async function a6($){return f6(()=>s6($))}async function s6($){let Q=$.lokiDirOverride??P(),Z=process.cwd(),z=o(Q);if(Y$(z,{recursive:!0}),!$.forceCreate){if(!await p6(Z))return{created:!1,reason:"no uncommitted changes"}}let X=await u6(Z),q=await c6(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}),o6(Q,U);let H=new Date().toISOString().replace(/\.\d{3}Z$/,"Z"),B=($.taskDescription??"task completed").slice(0,m6),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:l6(Q)};VQ(m(U,"metadata.json"),n6(Y));let O={id:Y.id,ts:Y.timestamp,iter:Y.iteration,task:Y.task_description,sha:Y.git_sha},M=qQ(Q);return j$(M,()=>{KQ(M,`${WQ(O)}
|
|
475
|
+
`)}),r6(Q),{created:!0,id:V,metadata:Y,dir:U}}function L1($){let Q=o($);if(!K$(Q))return[];return h6(Q).filter((Z)=>Z.startsWith("cp-")).filter((Z)=>{try{return y6(m(Q,Z)).isDirectory()}catch{return!1}})}function P1($){return[...$].sort((Q,Z)=>{let z=ZQ(Q),X=ZQ(Z);return z-X})}function ZQ($){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 r6($){let Q=L1($);if(Q.length<=$Q)return;let Z=P1(Q),z=Z.slice(0,Z.length-$Q);for(let X of z)try{g6(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=HQ(V,K);if(!U.ok){w1($,W,U.reason,U.field);continue}let H=U.value;Z.push(WQ({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=qQ($),X=Z.length>0?`${Z.join(`
|
|
473
476
|
`)}
|
|
474
|
-
`:"";
|
|
475
|
-
`)})}catch{}}function
|
|
477
|
+
`:"";VQ(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,()=>{KQ(X,`${JSON.stringify(q)}
|
|
478
|
+
`)})}catch{}}function j1($){let Q=$??P(),Z=P1(L1(Q)),z=[];for(let X of Z){let q=UQ(Q,X);if(q)z.push(q)}return z}function UQ($,Q){let Z=m(o($),Q,"metadata.json");if(!K$(Z))return null;try{let z=JSON.parse(I1(Z,"utf-8"));return i6(z,Z)}catch{return null}}function i6($,Q){let Z=HQ($,Q);return Z.ok?Z.value:null}function HQ($,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 $7){let q=Z[X];if(e6.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(!Q7.test($))throw new GQ($);let Z=Q??P(),z=m(o(Z),$);if(!K$(z))throw new _1($);let X=UQ(Z,$);if(!X)throw new _1($);return X}function BQ($,Q){let Z=F1($,Q),z=Q??P(),X=m(o(z),$),q=[];for(let K of Z7){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}.${++JQ}`;zQ(z.from,X),XQ(X,z.to),Z+=1}catch(X){Q.push(`${z.from} -> ${z.to}: ${X.message}`)}return{restored:Z,errors:Q}}async function YQ($,Q,Z=!1){let z=null;try{let q=await a6({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 $Q=50,m6=200,QQ,d6,JQ=0,e6,$7,Q7,_1,GQ,Z7;var MQ=L(()=>{C();d();F$();QQ=Promise.resolve();d6=["state/orchestrator.json","autonomy-state.json","queue/pending.json","queue/completed.json","queue/in-progress.json","queue/current-task.json","CONTINUITY.md"];e6=/[\x00-\x08\x0a-\x1f\x7f-\x9f]/,$7=["id","task_id","git_sha","git_branch","provider","phase"];Q7=/^[a-zA-Z0-9_-]+$/;_1=class _1 extends Error{id;constructor($){super(`Checkpoint not found: ${$}`);this.id=$;this.name="CheckpointNotFoundError"}};GQ=class GQ extends Error{id;constructor($){super(`Invalid checkpoint ID: must be alphanumeric, hyphens, underscores only (got: ${$})`);this.id=$;this.name="InvalidCheckpointIdError"}};Z7=["state/orchestrator.json","queue/pending.json","queue/completed.json","queue/in-progress.json","queue/current-task.json","CONTINUITY.md"]});var AQ={};b(AQ,{runRollback:()=>X7});async function X7($){let Q=$[0],Z=$.slice(1);if(Q===void 0||Q==="help"||Q==="--help"||Q==="-h")return process.stdout.write(TQ),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
479
|
`),0;process.stdout.write(`${k}Checkpoints${J} (${z.length}, newest first):
|
|
477
480
|
`);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
481
|
`);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=
|
|
482
|
+
`),2;try{let X=F1(z);return process.stdout.write(`${JSON.stringify(X,null,2)}
|
|
480
483
|
`),0}catch(X){return process.stderr.write(`${T}Failed to read checkpoint:${J} ${X.message}
|
|
481
484
|
`),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
|
|
485
|
+
`),2;return await OQ(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
486
|
`),1;return process.stdout.write(`Rolling back to latest checkpoint: ${I}${X.id}${J}
|
|
484
|
-
`),await
|
|
485
|
-
`),process.stderr.write(
|
|
487
|
+
`),await OQ(X.id,Z.includes("--force"))}default:return process.stderr.write(`Unknown subcommand: ${Q}
|
|
488
|
+
`),process.stderr.write(TQ),2}}async function OQ($,Q=!1){let Z;try{Z=BQ($)}catch(X){return process.stderr.write(`${T}Cannot plan rollback:${J} ${X.message}
|
|
486
489
|
`),1}if(Z.restore.length===0)return process.stdout.write(`${_}Checkpoint ${$} has no restorable state files; nothing to do.${J}
|
|
487
|
-
`),0;let z;try{z=await
|
|
490
|
+
`),0;let z;try{z=await YQ(Z,void 0,Q)}catch(X){return process.stderr.write(`${T}Rollback aborted:${J} ${X.message}
|
|
488
491
|
`),1}if(z.errors.length>0){for(let X of z.errors)process.stderr.write(`${T}restore error:${J} ${X}
|
|
489
492
|
`);return process.stderr.write(`${T}Partial rollback: ${z.restored}/${Z.restore.length} files restored.${J}
|
|
490
493
|
`),1}if(process.stdout.write(`${S}Rolled back ${z.restored}/${Z.restore.length} state files from ${$}.${J}
|
|
491
494
|
`),z.preRollbackSnapshotId)process.stdout.write(`Saved your prior state as ${I}${z.preRollbackSnapshotId}${J}; undo this rollback with \`loki rollback to ${z.preRollbackSnapshotId}\`.
|
|
492
|
-
`);return process.stdout.write("Run `loki start` to resume from the restored state.\n"),0}var
|
|
495
|
+
`);return process.stdout.write("Run `loki start` to resume from the restored state.\n"),0}var TQ=`Usage: loki rollback <subcommand>
|
|
493
496
|
|
|
494
497
|
Subcommands:
|
|
495
498
|
list List checkpoints (newest first)
|
|
@@ -510,33 +513,33 @@ to the checkpoint's snapshot (if one was anchored at checkpoint time):
|
|
|
510
513
|
git stash apply refs/loki/cp/<id>
|
|
511
514
|
|
|
512
515
|
Re-run \`loki start\` to resume from the restored state.
|
|
513
|
-
`;var
|
|
514
|
-
`),0;let Q=[];try{Q=
|
|
516
|
+
`;var wQ=L(()=>{MQ();c()});function K7(){return process.env.LOKI_TIER||"oss"}function _Q($){let Q=K7();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 IQ=L(()=>{c()});var PQ={};b(PQ,{runProof:()=>L7});import{existsSync as q$,readdirSync as q7,readFileSync as LQ,mkdtempSync as J7,copyFileSync as V7,rmSync as W7}from"fs";import{join as n,resolve as U7}from"path";import{tmpdir as H7}from"os";import{createInterface as G7}from"readline";import{readFile as B7}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(LQ(Q,"utf8"))}catch{return{}}}function $$($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function M7(){let $=M$();if(!q$($))return process.stdout.write(`${_}No proofs found.${J} Run 'loki start' to generate one.
|
|
517
|
+
`),0;let Q=[];try{Q=q7($,{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(LQ(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
518
|
`),0;process.stdout.write(`${$$("RUN_ID",26)} ${$$("GENERATED_AT",20)} ${$$("VERDICT",18)} ${$$("COST_USD",9)} FILES
|
|
516
519
|
`);for(let z of Z)process.stdout.write(`${z}
|
|
517
|
-
`);return 0}function
|
|
518
|
-
`),2;let Q=
|
|
520
|
+
`);return 0}function T7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
521
|
+
`),2;let Q=k1($);if(Q===null)return process.stderr.write(`${T}Proof not found: ${$}${J}
|
|
519
522
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
520
523
|
`),1;return process.stdout.write(`${JSON.stringify(Q,null,2)}
|
|
521
|
-
`),0}async function
|
|
524
|
+
`),0}async function O7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
522
525
|
`),2;let Q=n(M$(),$,"index.html");if(!q$(Q))return process.stderr.write(`${T}Proof page not found: ${$}/index.html${J}
|
|
523
526
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
524
527
|
`),1;process.stdout.write(`${S}Opening proof: ${Q}${J}
|
|
525
528
|
`);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
529
|
Could not detect browser opener.
|
|
527
530
|
`),process.stdout.write(`Please open in browser: ${Q}
|
|
528
|
-
`),0}function
|
|
531
|
+
`),0}function A7($){return new Promise((Q)=>{let Z=G7({input:process.stdin,output:process.stdout});Z.question($,(z)=>{Z.close();let X=z.trim().toLowerCase();Q(X==="y"||X==="yes")})})}async function w7($,Q,Z){let z=_Q("hosted_publish");for(let G of z.notes)process.stderr.write(`${G}
|
|
529
532
|
`);let X=process.env.LOKI_HOSTED_ENDPOINT||"";if(!X)return process.stderr.write(`${_}Hosted publishing backend not available.${J}
|
|
530
533
|
`),process.stderr.write(`There is no official Loki hosted service yet (R9 ships the seam, not a live backend).
|
|
531
534
|
`),process.stderr.write(`To publish to your own hosted endpoint, set LOKI_HOSTED_ENDPOINT to its URL.
|
|
532
535
|
`),process.stderr.write(`Or publish to a GitHub Gist instead: loki proof share ${$}
|
|
533
|
-
`),1;let q=
|
|
536
|
+
`),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
537
|
`),process.stderr.write(`Regenerate the proof (LOKI_PROOF=1) so the redactor runs, then retry.
|
|
535
538
|
`),1}process.stdout.write(`${k}Publishing proof '${$}' to hosted endpoint${J}
|
|
536
539
|
`),process.stdout.write(` endpoint: ${X}
|
|
537
540
|
`),process.stdout.write(` payload: ${Q} (already redacted by the generator)
|
|
538
541
|
|
|
539
|
-
`);let K;try{K=await
|
|
542
|
+
`);let K;try{K=await B7(Q)}catch{return process.stderr.write(`${T}Could not read proof page: ${Q}${J}
|
|
540
543
|
`),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
544
|
`),process.stderr.write(`Check LOKI_HOSTED_ENDPOINT or publish to a gist: loki proof share ${$}
|
|
542
545
|
`),1}let H=await U.text();if(!U.ok){if(process.stderr.write(`${T}Hosted endpoint returned HTTP ${U.status}.${J}
|
|
@@ -546,11 +549,11 @@ Could not detect browser opener.
|
|
|
546
549
|
`),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
550
|
`);else process.stdout.write(`${S}Published to ${X} (HTTP ${U.status}).${J}
|
|
548
551
|
`),process.stdout.write(`The endpoint did not return a 'url' field; check your endpoint's response.
|
|
549
|
-
`);return 0}async function
|
|
552
|
+
`);return 0}async function _7($){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
553
|
`),1;else Q=M;if(!Q)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
551
554
|
`),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
555
|
`),process.stderr.write(`Use 'loki proof list' to see available proofs.
|
|
553
|
-
`),1;if(X)return
|
|
556
|
+
`),1;if(X)return w7(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
557
|
`),process.stderr.write(`Install the GitHub CLI to publish a proof:
|
|
555
558
|
`),process.stderr.write(` brew install gh # macOS
|
|
556
559
|
`),process.stderr.write(` sudo apt install gh # Ubuntu/Debian
|
|
@@ -561,25 +564,25 @@ Could not detect browser opener.
|
|
|
561
564
|
|
|
562
565
|
`),process.stdout.write(`What will be shared:
|
|
563
566
|
`),process.stdout.write(` - ${q}
|
|
564
|
-
`);let U=
|
|
567
|
+
`);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
568
|
`),process.stdout.write(` - files_changed: ${R}
|
|
566
569
|
`),process.stdout.write(` - council verdict: ${N}
|
|
567
570
|
`),process.stdout.write(` - redaction: applied=${p(g.applied)} rules_version=${p(g.rules_version)} redactions_count=${p(g.redactions_count)}
|
|
568
571
|
`)}if(process.stdout.write(`
|
|
569
572
|
${_}Secrets, API keys, tokens, env values, and absolute paths have already been stripped by the generator.${J}
|
|
570
573
|
|
|
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{
|
|
574
|
+
`),!Z){if(!await A7(`Publish this proof to a ${V} gist? [y/N] `))return process.stdout.write(`Aborted. Nothing was published.
|
|
575
|
+
`),0}let H=J7(n(H7(),"loki-proof-")),B=n(H,"index.html");V7(q,B),process.stdout.write(`Uploading proof page...
|
|
576
|
+
`);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{W7(H,{recursive:!0,force:!0})}catch{}if(O.exitCode!==0)return process.stderr.write(`${T}Failed to create gist${J}
|
|
574
577
|
`),process.stderr.write(`${O.stdout}${O.stderr}
|
|
575
578
|
`),1;return process.stdout.write(`${S}Shared: ${O.stdout.trim()}${J}
|
|
576
|
-
`),0}async function
|
|
579
|
+
`),0}async function I7($){if(!$)return process.stderr.write(`${T}Missing proof id.${J} Use 'loki proof list'.
|
|
577
580
|
`),2;let Q=n(M$(),$,"proof.json");if(!q$(Q))return process.stderr.write(`${T}Proof not found: ${$}${J}
|
|
578
581
|
`),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
|
|
582
|
+
`),1;let Z=U7(h,"autonomy","lib","proof-verify.py");if(!q$(Z))return process.stderr.write(`${T}Verifier not found (autonomy/lib/proof-verify.py).${J}
|
|
583
|
+
`),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 L7($){let Q=$[0],Z=$.slice(1);if(Q===void 0||Q==="help"||Q==="--help"||Q==="-h")return process.stdout.write(Y7),Q===void 0?1:0;switch(Q){case"list":return M7();case"show":return T7(Z[0]);case"verify":return I7(Z[0]);case"open":return O7(Z[0]);case"share":return _7(Z);default:return process.stderr.write(`${T}Unknown subcommand: ${Q}${J}
|
|
581
584
|
`),process.stderr.write(`Run 'loki proof --help' for usage.
|
|
582
|
-
`),1}}var
|
|
585
|
+
`),1}}var Y7;var jQ=L(()=>{C();d();c();IQ();Y7=`${k}loki proof${J} - inspect and share proof-of-run artifacts
|
|
583
586
|
|
|
584
587
|
Usage: loki proof <subcommand> [args]
|
|
585
588
|
|
|
@@ -596,31 +599,31 @@ Options for 'share':
|
|
|
596
599
|
--hosted Publish to LOKI_HOSTED_ENDPOINT (open-core seam; no official backend yet)
|
|
597
600
|
|
|
598
601
|
Proofs are generated automatically at run completion (LOKI_PROOF=0 to opt out).
|
|
599
|
-
`});var
|
|
602
|
+
`});var NQ={};b(NQ,{runCrash:()=>S7});import{existsSync as kQ,readdirSync as P7,readFileSync as j7}from"fs";import{join as RQ}from"path";function k$($){return $===void 0||$===null?"-":String($)}function l$($,Q){return $.length>=Q?$:$+" ".repeat(Q-$.length)}function EQ(){return RQ(P(),"crash")}function R1(){let $=EQ();if(!kQ($))return[];try{return P7($,{withFileTypes:!0}).filter((Q)=>Q.isFile()&&Q.name.endsWith(".json")).map((Q)=>Q.name.slice(0,-5)).sort()}catch{return[]}}function k7($){if($.length===0)return!1;if($.includes("/")||$.includes("\\"))return!1;if($.includes(".."))return!1;return!0}function d$($){if(!k7($))return null;let Q=RQ(EQ(),`${$}.json`);if(!kQ(Q))return null;try{return JSON.parse(j7(Q,"utf8"))}catch{return{}}}function R7(){let $=R1();if($.length===0)return process.stdout.write(`${_}No crash reports found.${J} Nothing has been captured in .loki/crash/.
|
|
600
603
|
`),0;process.stdout.write(`${l$("ID",40)} ${l$("CAPTURED_AT",22)} ERROR_CLASS
|
|
601
604
|
`);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
605
|
`)}return process.stdout.write(`
|
|
603
606
|
${$.length} report(s). Run 'loki crash show <id>' to inspect, 'loki crash submit' to get a prefilled GitHub issue URL.
|
|
604
|
-
`),0}function xQ($){let Q=d$($);if(Q!==null)return{id:$,report:Q};for(let Z of
|
|
607
|
+
`),0}function xQ($){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 E7($){if(!$)return process.stderr.write(`${T}Missing crash id.${J} Use 'loki crash' to list reports.
|
|
605
608
|
`),2;let Q=xQ($);if(Q===null)return process.stderr.write(`${T}Crash report not found: ${$}${J}
|
|
606
609
|
`),process.stderr.write(`Use 'loki crash' to see available reports.
|
|
607
610
|
`),1;return process.stdout.write(`${JSON.stringify(Q.report,null,2)}
|
|
608
|
-
`),0}function
|
|
609
|
-
`),W=new URLSearchParams({title:X,body:K});return`${
|
|
611
|
+
`),0}function x7($){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(`
|
|
612
|
+
`),W=new URLSearchParams({title:X,body:K});return`${F7}?${W.toString()}`}function N7($){let Q;if($){if(Q=xQ($),Q===null)return process.stderr.write(`${T}Crash report not found: ${$}${J}
|
|
610
613
|
`),process.stderr.write(`Use 'loki crash' to see available reports.
|
|
611
|
-
`),1}else{let Z=
|
|
614
|
+
`),1}else{let Z=R1();if(Z.length===0)return process.stdout.write(`${_}No crash reports found.${J} Nothing to submit.
|
|
612
615
|
`),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
616
|
`),process.stdout.write(`${JSON.stringify(Q.report,null,2)}
|
|
614
617
|
|
|
615
618
|
`),process.stdout.write(`${_}Nothing is sent automatically in this version.${J} Loki Mode never transmits crash data on its own.
|
|
616
619
|
`),process.stdout.write(`To submit manually, open this prefilled GitHub issue and review it first:
|
|
617
620
|
|
|
618
|
-
`),process.stdout.write(` ${I}${
|
|
621
|
+
`),process.stdout.write(` ${I}${x7(Q.report)}${J}
|
|
619
622
|
|
|
620
623
|
`),process.stdout.write(`${S}The payload above is exactly what the URL contains.${J}
|
|
621
624
|
`),process.stdout.write(`See docs/PRIVACY.md for what is and is not collected.
|
|
622
|
-
`),0}async function
|
|
623
|
-
`),process.stdout.write(
|
|
625
|
+
`),0}async function S7($){let Q=$[0];switch(Q){case void 0:case"list":return R7();case"--help":case"-h":case"help":return process.stdout.write(FQ),0;case"show":return E7($[1]);case"submit":return N7($[1]);default:return process.stderr.write(`${T}Unknown crash subcommand: ${Q}${J}
|
|
626
|
+
`),process.stdout.write(FQ),2}}var F7="https://github.com/asklokesh/loki-mode/issues/new",FQ;var SQ=L(()=>{C();c();FQ=`${k}loki crash${J} - inspect and manually submit local crash reports
|
|
624
627
|
|
|
625
628
|
Usage: loki crash [subcommand] [args]
|
|
626
629
|
|
|
@@ -632,15 +635,15 @@ Subcommands:
|
|
|
632
635
|
|
|
633
636
|
Crash reports are anonymous, scrubbed, and stored locally only. Nothing is
|
|
634
637
|
sent automatically in this version. See docs/PRIVACY.md.
|
|
635
|
-
`});var
|
|
638
|
+
`});var hQ={};b(hQ,{runWiki:()=>y7});import{existsSync as E1,readFileSync as DQ}from"fs";import{join as x1,resolve as D7}from"path";function b7(){return x1(process.cwd(),".loki","wiki")}function h7($){let Q="";for(let X of $){if(X==="--help"||X==="-h")return process.stdout.write(`Usage: loki wiki show [section]
|
|
636
639
|
Sections: architecture, modules, data-flow
|
|
637
640
|
`),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(
|
|
642
|
-
`),1;return process.stdout.write(
|
|
643
|
-
`),process.stdout.write(
|
|
641
|
+
`),1;Q=X}let Z=b7();if(!E1(Z))return process.stderr.write(`${_}No wiki found. Run 'loki wiki generate' first.${J}
|
|
642
|
+
`),1;if(Q){if(!C7.has(Q))return process.stderr.write(`${T}No such section: ${Q} (try: architecture, modules, data-flow)${J}
|
|
643
|
+
`),1;let X=x1(Z,`${Q}.md`);if(!E1(X))return process.stderr.write(`${T}Section not generated: ${Q}${J}
|
|
644
|
+
`),1;return process.stdout.write(DQ(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}
|
|
645
|
+
`),1;return process.stdout.write(DQ(z,"utf8")),0}async function bQ($,Q){let Z=D7(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 y7($){let Q=$[0],Z=$.slice(1);switch(Q){case void 0:case"help":case"--help":case"-h":return process.stdout.write(CQ),0;case"show":return h7(Z);case"generate":return bQ("generate",Z);case"ask":return bQ("ask",Z);default:return process.stderr.write(`${T}Unknown wiki command: ${Q}${J}
|
|
646
|
+
`),process.stdout.write(CQ),1}}var CQ,C7;var yQ=L(()=>{C();c();CQ=`${k}loki wiki${J} - Auto-generated, cited codebase wiki + Q&A
|
|
644
647
|
|
|
645
648
|
Usage: loki wiki <command> [options]
|
|
646
649
|
|
|
@@ -656,8 +659,8 @@ Examples:
|
|
|
656
659
|
loki wiki generate
|
|
657
660
|
loki wiki show architecture
|
|
658
661
|
loki wiki ask "how does the cli dispatch commands"
|
|
659
|
-
`,
|
|
660
|
-
`)}function
|
|
662
|
+
`,C7=new Set(["architecture","modules","data-flow"])});var S1={};b(S1,{renderFindingsForPrompt:()=>u7,loadPreviousFindings:()=>N1,findLatestReviewDir:()=>uQ,_parseReviewerOutputForTests:()=>c7});import{existsSync as gQ,readFileSync as vQ,readdirSync as mQ,statSync as v7}from"fs";import{join as o$}from"path";function f7($){let Q=$.toLowerCase();if(Q==="critical")return"Critical";if(Q==="high")return"High";if(Q==="medium")return"Medium";return"Low"}function fQ($,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=g7.exec(V);if(!U||!U[1]||!U[2])continue;let H=f7(U[1]),B=U[2].trim(),G=m7.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 uQ($,Q){let Z=o$($,"quality","reviews");if(!gQ(Z))return null;let z;try{z=mQ(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(!v7(K).isDirectory())return null}catch{return null}return K}function N1($,Q){let Z=uQ($,Q);if(Z===null)return{reviewDir:null,reviewId:null,iteration:null,findings:[]};let z=null,X=null,q=o$(Z,"aggregate.json");if(gQ(q))try{let U=vQ(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=mQ(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=vQ(o$(Z,U),"utf-8")}catch{continue}V.push(...fQ(B,H,z??"",X??-1))}return{reviewDir:Z,reviewId:z,iteration:X,findings:V}}function u7($){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(`
|
|
663
|
+
`)}function c7($,Q,Z="review-test",z=0){return fQ($,Q,Z,z)}var g7,m7;var n$=L(()=>{g7=/\[(Critical|High|Medium|Low)\]\s*(.+)/i,m7=/([\w.\-/]+\.[a-zA-Z]+):(\d+)/});import{existsSync as p7}from"fs";import{join as l7}from"path";async function cQ($,Q){let Z=l7($,"memory");if(!p7(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
664
|
import os, sys
|
|
662
665
|
project = os.environ.get('_LOKI_PROJECT_DIR', '')
|
|
663
666
|
loki = os.environ.get('_LOKI_LOKI_DIR', '.loki')
|
|
@@ -684,25 +687,25 @@ try:
|
|
|
684
687
|
print('OK')
|
|
685
688
|
except Exception as e:
|
|
686
689
|
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
|
|
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=
|
|
690
|
+
`,{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 pQ=L(()=>{V$();C()});var nQ={};b(nQ,{loadLearnings:()=>D1,appendLearning:()=>R$,appendFromGateFailure:()=>i7});import{existsSync as d7,readFileSync as o7}from"fs";import{join as lQ}from"path";import{createHash as n7}from"crypto";function dQ($){return lQ($,a7)}function s7($){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 oQ($){if(!d7($))return{version:1,learnings:[]};try{let Q=o7($,"utf-8"),Z=JSON.parse(Q);if(Z.version===1&&Array.isArray(Z.learnings))return{version:1,learnings:Z.learnings.filter(s7)}}catch{}return{version:1,learnings:[]}}function r7($,Q,Z){return n7("sha256").update(`${$} ${Q} ${Z??""}`).digest("hex").slice(0,16)}async function R$($,Q,Z={}){let z=r7(Q.trigger,Q.rootCause,Q.evidence.file),X=new Date().toISOString(),q={id:z,timestamp:X,...Q},K=dQ($);if(await e0(K,()=>{j$(K,()=>{let V=oQ(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??cQ,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] ${$}
|
|
691
|
+
`)}async function i7($,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 oQ(dQ($))}var a7;var a$=L(()=>{F$();pQ();a7=lQ("state","relevant-learnings.json")});var sQ={};b(sQ,{runOverrideCouncil:()=>XZ,recordOverrideOutcome:()=>KZ,loadCounterEvidence:()=>zZ,canonicalFindingId:()=>s$,DEFAULT_OVERRIDE_JUDGES:()=>aQ});import{existsSync as e7,readFileSync as $Z}from"fs";import{join as QZ}from"path";function zZ($,Q){let Z=QZ($,"state",`counter-evidence-${Q}.json`);if(!e7(Z))return null;try{let z=$Z(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"||!ZZ.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 XZ($,Q,Z,z={}){let X=z.judges??aQ,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 KZ($,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 ZZ,aQ;var rQ=L(()=>{a$();ZZ=new Set(["file-exists","test-passes","grep-miss","reviewer-misread","duplicate-code-path","out-of-scope"]);aQ=["judge-primary","judge-secondary","judge-tertiary"]});var iQ={};b(iQ,{writeEscalationHandoff:()=>YZ,renderHandoff:()=>tQ,readLatestHandoff:()=>MZ});import{existsSync as qZ,readdirSync as JZ,readFileSync as VZ}from"fs";import{join as r$}from"path";function WZ(){return new Date().toISOString()}function UZ($){let Q=$.file?` (${$.file}${$.line!==null?":"+$.line:""})`:"";return` - [${$.severity}] ${$.description}${Q} -- ${$.reviewer}`}function HZ($){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 -- ${WZ()}`),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(UZ(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(HZ(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(`
|
|
692
|
+
`)}function BZ($,Q){A1($,Q)}function YZ($,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=r$($,"escalations"),V=++GZ,U=r$(W,`handoff-${K}-${process.pid}-${V}-${Q.gateName}.md`);return BZ(U,q),{path:U,bytes:q.length}}function MZ($){let Q=r$($,"escalations");if(!qZ(Q))return null;let Z;try{Z=JZ(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=r$(Q,z);try{return{path:X,body:VZ(X,"utf-8")}}catch{return null}}var GZ=0;var eQ=L(()=>{F$();n$();a$()});var Q8={};b(Q8,{runInternalPhase1Hooks:()=>IZ,_resolveForTests:()=>_Z,_internalPhase1HooksHelp:()=>FZ,__testAppendHook:()=>$8});import{existsSync as TZ,mkdirSync as OZ,readdirSync as AZ,statSync as wZ}from"fs";import{join as E$,resolve as _Z}from"path";async function IZ($){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 LZ(Z);case"override":return PZ(Z);case"handoff":return jZ(Z);default:return process.stderr.write(`Unknown subcommand: ${Q}
|
|
693
|
+
`),process.stderr.write(C1),2}}async function LZ($){let Q=b1($[0]);if(Q===null)return process.stderr.write(`reflect: missing or invalid <iter>
|
|
694
|
+
`),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)
|
|
695
|
+
`),0;let q=E$(Z,"state");OZ(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$(),nQ)),W=0,V=0;if(process.env.LOKI_AUTO_LEARNINGS!=="0"){let H=X.findings.filter((G)=>G.severity==="Critical"||G.severity==="High"),B=$8.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
696
|
`)}if(V>0&&W===0)return process.stderr.write(`reflect: all ${V} learning appends failed (iter ${Q})
|
|
694
697
|
`),1}let U=V>0?` (${V} failed)`:"";return process.stdout.write(`reflect: persisted ${X.findings.length} findings + ${W} learnings${U} (iter ${Q})
|
|
695
698
|
`),0}catch(z){return process.stderr.write(`reflect: ${z.message}
|
|
696
|
-
`),1}}async function
|
|
697
|
-
`),2;let Z=P();try{let z=await Promise.resolve().then(() => (
|
|
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
|
+
`),1}}async function PZ($){let Q=b1($[0]);if(Q===null)return process.stderr.write(`override: missing or invalid <iter>
|
|
700
|
+
`),2;let Z=P();try{let z=await Promise.resolve().then(() => (rQ(),sQ)),X=z.loadCounterEvidence(Z,Q);if(X===null||X.evidence.length===0)return process.stdout.write(`override: no counter-evidence for iter ${Q} (skip)
|
|
701
|
+
`),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)
|
|
702
|
+
`),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(TZ(H))try{let O=AZ(H).filter((R)=>R.startsWith("review-")).sort(),M=O[O.length-1];if(M&&wZ(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
703
|
`);else process.stdout.write(`override: BLOCKED -- ${B} approved, ${G} rejected
|
|
701
704
|
`);return 0}catch(z){return process.stderr.write(`override: ${z.message}
|
|
702
|
-
`),1}}async function
|
|
703
|
-
`),2;let X=P();try{let K=(await Promise.resolve().then(() => (
|
|
705
|
+
`),1}}async function jZ($){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>
|
|
706
|
+
`),2;let X=P();try{let K=(await Promise.resolve().then(() => (eQ(),iQ))).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
707
|
`),0}catch(q){return process.stderr.write(`handoff: ${q.message}
|
|
705
|
-
`),1}}function
|
|
708
|
+
`),1}}function b1($){if($===void 0)return null;let Q=Number.parseInt($,10);return Number.isFinite(Q)&&Q>=0?Q:null}var $8,C1=`loki internal phase1-hooks <subcommand>
|
|
706
709
|
|
|
707
710
|
Subcommands:
|
|
708
711
|
reflect <iter> Persist structured findings + auto-learnings.
|
|
@@ -711,9 +714,9 @@ Subcommands:
|
|
|
711
714
|
|
|
712
715
|
This command is invoked by autonomy/run.sh between iterations. Users
|
|
713
716
|
should not run it directly -- run \`loki start\` instead.
|
|
714
|
-
`,
|
|
715
|
-
`)}catch{}}async function
|
|
716
|
-
`),await
|
|
717
|
+
`,FZ;var Z8=L(()=>{C();F$();$8={fn:null};FZ=C1});$1();C();import{mkdirSync as Y8,readFileSync as M8,writeFileSync as T8}from"fs";import{dirname as O8,resolve as A8}from"path";var w8="https://registry.npmjs.org/loki-mode/latest",_8=86400000,I8=1500;function L8(){return A8(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 P8($,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 j8(){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 F8($){try{let Q=M8($,"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 k8($,Q){try{Y8(O8($),{recursive:!0}),T8($,JSON.stringify(Q),"utf-8")}catch{}}async function R8(){try{let $=await fetch(w8,{signal:AbortSignal.timeout(I8),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 E8($=Date.now(),Q=R8,Z=L8()){let z=F8(Z);if(z&&$-z.checkedAt<_8)return z.latest;let X=await Q();if(X===null)return null;return k8(Z,{checkedAt:$,latest:X}),X}async function g1($,Q={}){try{if(j8())return;if(O$($)===null)return;let Z=await E8(Q.now,Q.fetcher,Q.cacheFile);if(Z===null)return;if(!P8(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)
|
|
718
|
+
`)}catch{}}async function m1(){let $=N$();return process.stdout.write(`Loki Mode v${$}
|
|
719
|
+
`),await g1($),0}d();c();C();import{readFileSync as C8,existsSync as b8}from"fs";import{resolve as h8}from"path";var y8=["claude","codex","cline","aider"];function p1(){let $=h8(P(),"state","provider");if(!b8($))return"";try{return C8($,"utf-8").trim()}catch{return""}}function v8($,Q){return $||Q||process.env.LOKI_PROVIDER||"claude"}function g8($){let Q=p1(),Z=v8($,Q);switch(process.stdout.write(`${k}Current Provider${J}
|
|
717
720
|
`),process.stdout.write(`
|
|
718
721
|
`),process.stdout.write(`${I}Provider:${J} ${Z}
|
|
719
722
|
`),Z){case"claude":process.stdout.write(`${S}Status:${J} Full features (subagents, parallel, MCP)
|
|
@@ -724,12 +727,12 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
724
727
|
`);return process.stdout.write(`
|
|
725
728
|
`),process.stdout.write(`Switch provider: ${I}loki provider set <name>${J}
|
|
726
729
|
`),process.stdout.write(`Available: ${I}loki provider list${J}
|
|
727
|
-
`),0}async function
|
|
730
|
+
`),0}async function m8(){let Q=p1()||process.env.LOKI_PROVIDER||"claude";process.stdout.write(`${k}Available Providers${J}
|
|
728
731
|
`),process.stdout.write(`
|
|
729
|
-
`);let Z=await Promise.all(
|
|
732
|
+
`);let Z=await Promise.all(y8.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
733
|
`)}return process.stdout.write(`
|
|
731
734
|
`),process.stdout.write(`Set provider: ${I}loki provider set <name>${J}
|
|
732
|
-
`),0}function
|
|
735
|
+
`),0}function f8(){return process.stdout.write(`${k}Loki Mode Provider Management${J}
|
|
733
736
|
`),process.stdout.write(`
|
|
734
737
|
`),process.stdout.write(`Usage: loki provider <command>
|
|
735
738
|
`),process.stdout.write(`
|
|
@@ -747,8 +750,8 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
747
750
|
`),process.stdout.write(` loki provider list
|
|
748
751
|
`),process.stdout.write(` loki provider info codex
|
|
749
752
|
`),process.stdout.write(` loki provider models
|
|
750
|
-
`),0}async function
|
|
751
|
-
`))if(z.includes('"description"'))Z++;return Z}catch{return 0}}async function
|
|
753
|
+
`),0}async function l1($){let Q=$[0]??"show",Z=$.slice(1);switch(Q){case"show":case"current":return g8(Z[0]);case"list":return m8();case"set":case"info":case"models":return u8(["provider",Q,...Z]);default:return f8()}}async function u8($){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 p8}from"fs";import{resolve as W$}from"path";import{mkdir as l8}from"fs/promises";var w$=W$(T$(),"learnings");function Z1($){if(!d1($))return 0;try{let Q=p8($,"utf-8"),Z=0;for(let z of Q.split(`
|
|
754
|
+
`))if(z.includes('"description"'))Z++;return Z}catch{return 0}}async function d8(){await l8(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
755
|
`),process.stdout.write(`
|
|
753
756
|
`),process.stdout.write(` Patterns: ${S}${$}${J}
|
|
754
757
|
`),process.stdout.write(` Mistakes: ${_}${Q}${J}
|
|
@@ -757,7 +760,7 @@ should not run it directly -- run \`loki start\` instead.
|
|
|
757
760
|
`),process.stdout.write(`Location: ${w$}
|
|
758
761
|
`),process.stdout.write(`
|
|
759
762
|
`),process.stdout.write(`Use 'loki memory show <type>' to view entries
|
|
760
|
-
`),0}async function
|
|
763
|
+
`),0}async function o8($){if($){let z=`
|
|
761
764
|
try:
|
|
762
765
|
from memory.layers import IndexLayer
|
|
763
766
|
layer = IndexLayer('.loki/memory')
|
|
@@ -767,12 +770,12 @@ except ImportError:
|
|
|
767
770
|
print('Error: memory.layers module not found')
|
|
768
771
|
except Exception as e:
|
|
769
772
|
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(!
|
|
773
|
+
`.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
774
|
`),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
|
|
774
|
-
`)}catch{}process.exit(1)}),process.on("unhandledRejection",($)=>{if(!S$){S$=!0;let Q=
|
|
775
|
-
`)}catch{}process.exit(1)})}var
|
|
775
|
+
`),0;return process.stdout.write(Z.stdout),0}async function o1($){switch($[0]??"list"){case"list":case"ls":return d8();case"index":return o8($[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 n8,join as a8}from"path";import{existsSync as z1,readFileSync as s8}from"fs";import{homedir as r8}from"os";import{spawnSync as r1}from"child_process";var t1=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=a8(r8(),".loki","config");if(z1(z)){let X=s8(z,"utf8");for(let q of X.split(`
|
|
776
|
+
`)){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 i8(){return n8(h,"autonomy","lib","crash_capture.py")}function e8($,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 $3(){if(z1("/opt/homebrew/bin/python3.12"))return"/opt/homebrew/bin/python3.12";for(let Q of["python3.12","python3"])try{let Z=r1("sh",["-c",`command -v ${Q}`],{timeout:t1,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=i8();if(!z1(Q))return;let Z=$3();if(!Z)return;let z=e8(Q,$);r1(Z,z,{timeout:t1,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($)}
|
|
777
|
+
`)}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}
|
|
778
|
+
`)}catch{}process.exit(1)})}var z8=`Loki Mode (TypeScript port, Phase 2 of bash->Bun migration)
|
|
776
779
|
|
|
777
780
|
Usage: loki <command> [args...]
|
|
778
781
|
|
|
@@ -794,12 +797,12 @@ Phase 2 ported (Bun-native, fast):
|
|
|
794
797
|
|
|
795
798
|
All other commands fall through to the bash CLI (autonomy/loki).
|
|
796
799
|
Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
797
|
-
`;function
|
|
798
|
-
`)}async function
|
|
800
|
+
`;function kZ(){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.
|
|
801
|
+
`)}async function RZ($){kZ();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(() => (F0(),j0));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(() => (g0(),v0));return X(["report",...Z])}case"trust":{let{runTrust:z}=await Promise.resolve().then(() => (n0(),o0));return z(Z)}case"rollback":{let{runRollback:z}=await Promise.resolve().then(() => (wQ(),AQ));return z(Z)}case"proof":case"receipt":{let{runProof:z}=await Promise.resolve().then(() => (jQ(),PQ));return z(Z)}case"crash":{let{runCrash:z}=await Promise.resolve().then(() => (SQ(),NQ));return z(Z)}case"wiki":{let{runWiki:z}=await Promise.resolve().then(() => (yQ(),hQ));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
802
|
`);return process.stdout.write(`${q}
|
|
800
|
-
`),0}if(z==="phase1-hooks"){let{runInternalPhase1Hooks:q}=await Promise.resolve().then(() => (
|
|
803
|
+
`),0}if(z==="phase1-hooks"){let{runInternalPhase1Hooks:q}=await Promise.resolve().then(() => (Z8(),Q8));return q(Z.slice(1))}return process.stderr.write(`Unknown internal subcommand: ${z}
|
|
801
804
|
`),process.stderr.write(`Run 'loki internal --help' for the supported list.
|
|
802
805
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
803
|
-
`),process.stderr.write(
|
|
806
|
+
`),process.stderr.write(z8),2}}i1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var EZ=await RZ(Bun.argv.slice(2));process.exit(EZ);
|
|
804
807
|
|
|
805
|
-
//# debugId=
|
|
808
|
+
//# debugId=48A34AFD97DA2FEB64756E2164756E21
|