loki-mode 9.22.6 → 9.22.8
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/autonomy/quickstart.sh +39 -23
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +12 -0
- 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.8
|
|
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.8 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
9.22.
|
|
1
|
+
9.22.8
|
|
@@ -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/autonomy/quickstart.sh
CHANGED
|
@@ -509,21 +509,29 @@ json.dump(payload, sys.stdout, separators=(",", ":"), sort_keys=True)
|
|
|
509
509
|
# cmd_quickstart always recomputes and displays the current estimator result.
|
|
510
510
|
_qs_load_preview() {
|
|
511
511
|
local preview_path="$1"
|
|
512
|
-
if [
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
return 2
|
|
512
|
+
if [ "$preview_path" = "-" ]; then
|
|
513
|
+
if [ -t 0 ]; then
|
|
514
|
+
printf 'Preview stdin must be piped; refusing to wait on a terminal.\n' >&2
|
|
515
|
+
return 2
|
|
516
|
+
fi
|
|
517
|
+
else
|
|
518
|
+
if [ ! -f "$preview_path" ] || [ ! -r "$preview_path" ] || [ -L "$preview_path" ]; then
|
|
519
|
+
printf 'Preview path is not a readable regular non-symlink file: %s\n' "$preview_path" >&2
|
|
520
|
+
return 2
|
|
521
|
+
fi
|
|
522
|
+
local preview_size
|
|
523
|
+
preview_size=$(wc -c < "$preview_path" 2>/dev/null | tr -d '[:space:]') || return 2
|
|
524
|
+
case "$preview_size" in
|
|
525
|
+
""|*[!0-9]*) return 2;;
|
|
526
|
+
esac
|
|
527
|
+
if [ "$preview_size" -eq 0 ] || [ "$preview_size" -gt 1048576 ]; then
|
|
528
|
+
printf 'Preview JSON must be between 1 byte and 1 MiB.\n' >&2
|
|
529
|
+
return 2
|
|
530
|
+
fi
|
|
524
531
|
fi
|
|
525
532
|
|
|
526
|
-
|
|
533
|
+
local validator_code=""
|
|
534
|
+
validator_code=$(cat <<'PY'
|
|
527
535
|
import base64
|
|
528
536
|
import json
|
|
529
537
|
import os
|
|
@@ -533,15 +541,20 @@ import sys
|
|
|
533
541
|
|
|
534
542
|
path = sys.argv[1]
|
|
535
543
|
try:
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
544
|
+
if path == "-":
|
|
545
|
+
raw = sys.stdin.buffer.read(1048577)
|
|
546
|
+
if len(raw) < 1 or len(raw) > 1048576:
|
|
547
|
+
raise ValueError("unsafe preview stdin")
|
|
548
|
+
else:
|
|
549
|
+
flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0)
|
|
550
|
+
descriptor = os.open(path, flags)
|
|
551
|
+
try:
|
|
552
|
+
metadata = os.fstat(descriptor)
|
|
553
|
+
if not stat.S_ISREG(metadata.st_mode) or metadata.st_size < 1 or metadata.st_size > 1048576:
|
|
554
|
+
raise ValueError("unsafe preview")
|
|
555
|
+
raw = os.read(descriptor, 1048577)
|
|
556
|
+
finally:
|
|
557
|
+
os.close(descriptor)
|
|
545
558
|
if len(raw) > 1048576:
|
|
546
559
|
raise ValueError("oversized")
|
|
547
560
|
def reject_duplicate_keys(pairs):
|
|
@@ -606,6 +619,8 @@ elif kind == "prd":
|
|
|
606
619
|
else:
|
|
607
620
|
sys.exit(2)
|
|
608
621
|
PY
|
|
622
|
+
)
|
|
623
|
+
python3 -c "$validator_code" "$preview_path"
|
|
609
624
|
}
|
|
610
625
|
|
|
611
626
|
# _qs_help: concise usage for `loki quickstart --help`.
|
|
@@ -625,7 +640,7 @@ _qs_help() {
|
|
|
625
640
|
printf ' --yes, -y Auto-confirm the final build prompt (still shows the plan)\n'
|
|
626
641
|
printf ' --dry-run Preview the selected template and plan; write/start nothing\n'
|
|
627
642
|
printf ' --json With --dry-run, emit one machine-readable JSON object\n'
|
|
628
|
-
printf ' --from-preview F Continue
|
|
643
|
+
printf ' --from-preview F Continue saved JSON from file F (or - for piped stdin); requires --yes\n'
|
|
629
644
|
printf ' --template N Use the exact shipped template N for an IDEA\n'
|
|
630
645
|
printf ' --list-templates List every shipped template and its purpose\n'
|
|
631
646
|
printf ' --help, -h Show this help and exit\n'
|
|
@@ -644,6 +659,7 @@ _qs_help() {
|
|
|
644
659
|
printf ' no file is written, and no build is started. Do not combine with --yes.\n'
|
|
645
660
|
printf ' Add --json for versioned JSON only; --json requires --dry-run.\n'
|
|
646
661
|
printf ' Save that JSON, then continue it with --from-preview FILE --yes.\n'
|
|
662
|
+
printf ' Or pipe it with --from-preview - --yes; terminal stdin is refused.\n'
|
|
647
663
|
printf '\n'
|
|
648
664
|
printf 'Steps:\n'
|
|
649
665
|
printf ' 1. Setup Check for an AI provider for execution (skipped in preview)\n'
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
|
@@ -194,6 +194,18 @@ Use `--dry-run` instead of `--yes` to preview the same template and plan without
|
|
|
194
194
|
provider discovery, file writes, or execution; add `--json` for one versioned
|
|
195
195
|
machine-readable object.
|
|
196
196
|
|
|
197
|
+
For a local pipeline, pass that object to `--from-preview - --yes`. Loki accepts
|
|
198
|
+
at most 1 MiB from non-terminal stdin, revalidates the schema, and recomputes the
|
|
199
|
+
current estimate before the explicitly consented build starts:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
loki quickstart "an internal reporting workspace" --template dashboard --dry-run --json \
|
|
203
|
+
| loki quickstart --from-preview - --yes
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Omit `--yes`, pipe malformed or oversized JSON, or use `-` from a terminal and
|
|
207
|
+
the continuation exits `2` before provider discovery, PRD writes, or execution.
|
|
208
|
+
|
|
197
209
|
Drop a spec -- any artifact that describes what you want built -- and Loki
|
|
198
210
|
Mode takes it from spec to deployed app. Specs can be a markdown PRD, a
|
|
199
211
|
GitHub issue URL, or a YAML feature description.
|
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.8";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=B93D9505D257E3EF64756E2164756E21
|
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.8",
|
|
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.8",
|
|
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",
|