loki-mode 9.22.6 → 9.22.7
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/issue-providers.sh +82 -11
- package/dashboard/__init__.py +1 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v9.22.
|
|
6
|
+
# Loki Mode v9.22.7
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
470
470
|
|
|
471
471
|
---
|
|
472
472
|
|
|
473
|
-
**v9.22.
|
|
473
|
+
**v9.22.7 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
9.22.
|
|
1
|
+
9.22.7
|
|
@@ -190,20 +190,91 @@ fetch_github_issue() {
|
|
|
190
190
|
}
|
|
191
191
|
fi
|
|
192
192
|
|
|
193
|
-
# Normalize to common format
|
|
194
|
-
|
|
193
|
+
# Normalize to common format only after binding the returned identity to the
|
|
194
|
+
# exact issue requested. A syntactically valid substituted response must not
|
|
195
|
+
# be allowed to seed an issue context or early journey plan.
|
|
196
|
+
_LOKI_REPO_REF="$repo_ref" _LOKI_ISSUE_NUMBER="$number" python3 -c "
|
|
195
197
|
import json, sys, os
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
from urllib.parse import urlsplit
|
|
199
|
+
|
|
200
|
+
repo_ref = os.environ.get('_LOKI_REPO_REF', '')
|
|
201
|
+
expected_number = os.environ.get('_LOKI_ISSUE_NUMBER', '')
|
|
202
|
+
|
|
203
|
+
def refuse(reason):
|
|
204
|
+
raise SystemExit(f'Error: GitHub issue identity mismatch: {reason}')
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
data = json.loads(sys.stdin.read())
|
|
208
|
+
except (json.JSONDecodeError, UnicodeDecodeError):
|
|
209
|
+
refuse('response is not valid JSON')
|
|
210
|
+
if not isinstance(data, dict):
|
|
211
|
+
refuse('response root is not an object')
|
|
212
|
+
if not repo_ref or repo_ref.count('/') != 1 or not all(repo_ref.split('/')):
|
|
213
|
+
refuse('requested repository could not be resolved')
|
|
214
|
+
if not expected_number.isdigit():
|
|
215
|
+
refuse('requested issue number is invalid')
|
|
216
|
+
expected_number_normalized = str(int(expected_number))
|
|
217
|
+
|
|
218
|
+
returned_number = data.get('number')
|
|
219
|
+
url = data.get('url')
|
|
220
|
+
if type(returned_number) is not int or returned_number != int(expected_number):
|
|
221
|
+
refuse(f'expected issue {expected_number_normalized}, received {returned_number!r}')
|
|
222
|
+
if not isinstance(url, str):
|
|
223
|
+
refuse('response URL is not a string')
|
|
224
|
+
if any(character.isspace() or ord(character) < 32 or ord(character) == 127 for character in url):
|
|
225
|
+
refuse('response URL contains whitespace or control characters')
|
|
226
|
+
|
|
227
|
+
expected_path = f'/{repo_ref}/issues/{expected_number_normalized}'
|
|
228
|
+
try:
|
|
229
|
+
parsed_url = urlsplit(url)
|
|
230
|
+
parsed_hostname = parsed_url.hostname
|
|
231
|
+
parsed_port = parsed_url.port
|
|
232
|
+
except ValueError:
|
|
233
|
+
refuse(f'expected https://github.com{expected_path}, received {url!r}')
|
|
234
|
+
if (
|
|
235
|
+
parsed_url.scheme != 'https'
|
|
236
|
+
or (parsed_hostname or '').lower() != 'github.com'
|
|
237
|
+
or parsed_url.username is not None
|
|
238
|
+
or parsed_url.password is not None
|
|
239
|
+
or parsed_port is not None
|
|
240
|
+
or parsed_url.query
|
|
241
|
+
or parsed_url.fragment
|
|
242
|
+
or parsed_url.path.rstrip('/').casefold() != expected_path.casefold()
|
|
243
|
+
):
|
|
244
|
+
refuse(f'expected https://github.com{expected_path}, received {url!r}')
|
|
245
|
+
|
|
246
|
+
labels = data.get('labels', [])
|
|
247
|
+
author = data.get('author') or {}
|
|
248
|
+
if not isinstance(labels, list) or any(not isinstance(label, dict) for label in labels):
|
|
249
|
+
refuse('response labels are not an array of objects')
|
|
250
|
+
if not isinstance(author, dict):
|
|
251
|
+
refuse('response author is not an object')
|
|
252
|
+
scalar_fields = {
|
|
200
253
|
'title': data.get('title', ''),
|
|
201
254
|
'body': data.get('body', '') or '',
|
|
202
|
-
'
|
|
203
|
-
'author':
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
255
|
+
'createdAt': data.get('createdAt', ''),
|
|
256
|
+
'author.login': author.get('login', ''),
|
|
257
|
+
}
|
|
258
|
+
for field, value in scalar_fields.items():
|
|
259
|
+
if not isinstance(value, str):
|
|
260
|
+
refuse(f'response {field} is not a string')
|
|
261
|
+
label_names = []
|
|
262
|
+
for label in labels:
|
|
263
|
+
name = label.get('name', '')
|
|
264
|
+
if not isinstance(name, str):
|
|
265
|
+
refuse('response label name is not a string')
|
|
266
|
+
label_names.append(name)
|
|
267
|
+
|
|
268
|
+
print(json.dumps({
|
|
269
|
+
'provider': 'github',
|
|
270
|
+
'number': returned_number,
|
|
271
|
+
'title': scalar_fields['title'],
|
|
272
|
+
'body': scalar_fields['body'],
|
|
273
|
+
'labels': label_names,
|
|
274
|
+
'author': scalar_fields['author.login'],
|
|
275
|
+
'url': url,
|
|
276
|
+
'created_at': scalar_fields['createdAt'],
|
|
277
|
+
'repo': repo_ref
|
|
207
278
|
}))
|
|
208
279
|
" <<< "$issue_json"
|
|
209
280
|
}
|
package/dashboard/__init__.py
CHANGED
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var l_=Object.create;var{getPrototypeOf:i_,defineProperty:eK,getOwnPropertyNames:a_}=Object;var n_=Object.prototype.hasOwnProperty;function s_(Z){return this[Z]}var o_,r_,t_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?o_??=new WeakMap:r_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?l_(i_(Z)):{};let K=X||!Z||!Z.__esModule?eK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of a_(Z))if(!n_.call(K,$))eK(K,$,{get:s_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var HQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var e_=(Z)=>Z;function Zf(Z,X){this[Z]=e_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)eK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:Zf.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var t0=import.meta.require;var bO={};l0(bO,{lokiDir:()=>A0,homeLokiDir:()=>R4,findRepoRootForVersion:()=>X$,REPO_ROOT:()=>i0});import{resolve as s7,dirname as Z$}from"path";import{fileURLToPath as Xf}from"url";import{existsSync as UQ}from"fs";import{homedir as Qf}from"os";function Yf(){let Z=yO;for(let X=0;X<6;X++){if(UQ(s7(Z,"VERSION"))&&UQ(s7(Z,"autonomy/run.sh")))return Z;let Q=Z$(Z);if(Q===Z)break;Z=Q}return s7(yO,"..","..","..")}function X$(Z){let X=Z;for(let Q=0;Q<6;Q++){if(UQ(s7(X,"VERSION"))&&UQ(s7(X,"autonomy/run.sh")))return X;let Y=Z$(X);if(Y===X)break;X=Y}return s7(Z,"..","..","..")}function A0(){return process.env.LOKI_DIR??s7(process.cwd(),".loki")}function R4(){return s7(Qf(),".loki")}var yO,i0;var V8=p(()=>{yO=Z$(Xf(import.meta.url));i0=Yf()});import{readFileSync as Jf}from"fs";import{resolve as zf,dirname as Kf}from"path";import{fileURLToPath as $f}from"url";function h3(){if(h5!==null)return h5;let Z="9.22.
|
|
2
|
+
var l_=Object.create;var{getPrototypeOf:i_,defineProperty:eK,getOwnPropertyNames:a_}=Object;var n_=Object.prototype.hasOwnProperty;function s_(Z){return this[Z]}var o_,r_,t_=(Z,X,Q)=>{var Y=Z!=null&&typeof Z==="object";if(Y){var J=X?o_??=new WeakMap:r_??=new WeakMap,z=J.get(Z);if(z)return z}Q=Z!=null?l_(i_(Z)):{};let K=X||!Z||!Z.__esModule?eK(Q,"default",{value:Z,enumerable:!0}):Q;for(let $ of a_(Z))if(!n_.call(K,$))eK(K,$,{get:s_.bind(Z,$),enumerable:!0});if(Y)J.set(Z,K);return K};var HQ=(Z,X)=>()=>(X||Z((X={exports:{}}).exports,X),X.exports);var e_=(Z)=>Z;function Zf(Z,X){this[Z]=e_.bind(null,X)}var l0=(Z,X)=>{for(var Q in X)eK(Z,Q,{get:X[Q],enumerable:!0,configurable:!0,set:Zf.bind(X,Q)})};var p=(Z,X)=>()=>(Z&&(X=Z(Z=0)),X);var t0=import.meta.require;var bO={};l0(bO,{lokiDir:()=>A0,homeLokiDir:()=>R4,findRepoRootForVersion:()=>X$,REPO_ROOT:()=>i0});import{resolve as s7,dirname as Z$}from"path";import{fileURLToPath as Xf}from"url";import{existsSync as UQ}from"fs";import{homedir as Qf}from"os";function Yf(){let Z=yO;for(let X=0;X<6;X++){if(UQ(s7(Z,"VERSION"))&&UQ(s7(Z,"autonomy/run.sh")))return Z;let Q=Z$(Z);if(Q===Z)break;Z=Q}return s7(yO,"..","..","..")}function X$(Z){let X=Z;for(let Q=0;Q<6;Q++){if(UQ(s7(X,"VERSION"))&&UQ(s7(X,"autonomy/run.sh")))return X;let Y=Z$(X);if(Y===X)break;X=Y}return s7(Z,"..","..","..")}function A0(){return process.env.LOKI_DIR??s7(process.cwd(),".loki")}function R4(){return s7(Qf(),".loki")}var yO,i0;var V8=p(()=>{yO=Z$(Xf(import.meta.url));i0=Yf()});import{readFileSync as Jf}from"fs";import{resolve as zf,dirname as Kf}from"path";import{fileURLToPath as $f}from"url";function h3(){if(h5!==null)return h5;let Z="9.22.7";if(typeof Z==="string"&&Z.length>0)return h5=Z,h5;try{let X=Kf($f(import.meta.url)),Q=X$(X);h5=Jf(zf(Q,"VERSION"),"utf-8").trim()}catch{h5="unknown"}return h5}var h5=null;var BQ=p(()=>{V8()});var vO={};l0(vO,{runOrThrow:()=>Ff,run:()=>E0,readStreamCapped:()=>NQ,commandVersion:()=>Ef,commandExists:()=>X9,ShellError:()=>Q$,MAX_STDOUT_BYTES:()=>hO});async function NQ(Z,X=hO){let Q=Z.getReader(),Y=new TextDecoder,J="",z=0;try{while(z<X){let{done:K,value:$}=await Q.read();if(K)break;if(!$)continue;if(z+=$.byteLength,z>X){let V=$.byteLength-(z-X);J+=Y.decode($.subarray(0,V),{stream:!0});break}J+=Y.decode($,{stream:!0})}J+=Y.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return J}async function E0(Z,X={}){let Q=Bun.spawn({cmd:[...Z],stdout:"pipe",stderr:"pipe",env:X.env?{...process.env,...X.env}:process.env,cwd:X.cwd}),Y,J;if(X.timeoutMs&&X.timeoutMs>0)Y=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}J=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},X.timeoutMs);try{let[z,K,$]=await Promise.all([NQ(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:z,stderr:K,exitCode:$}}finally{if(Y)clearTimeout(Y);if(J)clearTimeout(J)}}async function Ff(Z,X={}){let Q=await E0(Z,X);if(Q.exitCode!==0)throw new Q$(`command failed (${Q.exitCode}): ${Z.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function X9(Z){let X=Df(Z),Q=await E0(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Df(Z){if(!/^[A-Za-z0-9._/-]+$/.test(Z))throw Error(`refused to shell-escape suspect token: ${Z}`);return Z}async function Ef(Z,X="--version"){if(!await X9(Z))return null;let Y=await E0([Z,X],{timeoutMs:5000});if(Y.exitCode!==0)return null;return((Y.stdout||Y.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var hO=16777216,Q$;var x9=p(()=>{Q$=class Q$ extends Error{message;exitCode;stdout;stderr;constructor(Z,X,Q,Y){super(Z);this.message=Z;this.exitCode=X;this.stdout=Q;this.stderr=Y;this.name="ShellError"}}});function o7(Z){return Pf?"":Z}var Pf,L0,F8,_0,MW0,a0,W8,Q9,h;var S6=p(()=>{Pf=(process.env.NO_COLOR??"").length>0;L0=o7("\x1B[0;31m"),F8=o7("\x1B[0;32m"),_0=o7("\x1B[1;33m"),MW0=o7("\x1B[0;34m"),a0=o7("\x1B[0;36m"),W8=o7("\x1B[1m"),Q9=o7("\x1B[2m"),h=o7("\x1B[0m")});import{existsSync as gf}from"fs";async function P7(){if(x4!==void 0)return x4;let Z="/opt/homebrew/bin/python3.12";if(gf(Z))return x4=Z,Z;let X=await X9("python3.12");if(X)return x4=X,X;let Q=await X9("python3");return x4=Q,Q}async function z7(Z,X={}){let Q=await P7();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return E0([Q,"-c",Z],X)}var x4;var r7=p(()=>{x9()});var JA={};l0(JA,{runStatus:()=>Gh});import{existsSync as Y9,readFileSync as g3,readdirSync as oO,statSync as rO}from"fs";import{resolve as h8,basename as Qh}from"path";import{homedir as Yh}from"os";function tO(Z){let X=Math.trunc(Z);if(X>=1e6)return`${(Math.trunc(X/1e6*10)/10).toFixed(1)}M`;if(X>=1000)return`${(Math.trunc(X/1000*10)/10).toFixed(1)}K`;return String(X)}function eO(Z,X,Q){if(X===0)return null;let Y=Math.trunc(Z*100/X),J=Math.trunc(Z*AQ/X);if(J>AQ)J=AQ;let z=AQ-J,K=F8;if(Y>=80)K=L0;else if(Y>=50)K=_0;let $="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,z)),V=tO(Z),W=tO(X);return` ${W8}${Q}${h} ${K}[${$}]${h} ${Y}% (${V} / ${W})`}async function zh(){if(await X9("jq"))return!0;return process.stdout.write(`${L0}Error: jq is required but not installed.${h}
|
|
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)
|
|
@@ -1238,4 +1238,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
1238
1238
|
`),2}case"start":{let{runStart:Y}=await Promise.resolve().then(() => (p_(),u_));return Y(Q)}default:return process.stderr.write(`Unknown command: ${X}
|
|
1239
1239
|
`),process.stderr.write(d_),2}}nO();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var QW0=await XW0(Bun.argv.slice(2));process.exit(QW0);
|
|
1240
1240
|
|
|
1241
|
-
//# debugId=
|
|
1241
|
+
//# debugId=D32CF1FDB032F37F64756E2164756E21
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "9.22.
|
|
4
|
+
"version": "9.22.7",
|
|
5
5
|
"description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 8 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "loki-mode",
|
|
4
4
|
"displayName": "Loki Mode",
|
|
5
|
-
"version": "9.22.
|
|
5
|
+
"version": "9.22.7",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|