loki-mode 9.22.7 → 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 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.7
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.7 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
473
+ **v9.22.8 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 9.22.7
1
+ 9.22.8
@@ -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 [ ! -f "$preview_path" ] || [ ! -r "$preview_path" ] || [ -L "$preview_path" ]; then
513
- printf 'Preview path is not a readable regular non-symlink file: %s\n' "$preview_path" >&2
514
- return 2
515
- fi
516
- local preview_size
517
- preview_size=$(wc -c < "$preview_path" 2>/dev/null | tr -d '[:space:]') || return 2
518
- case "$preview_size" in
519
- ""|*[!0-9]*) return 2;;
520
- esac
521
- if [ "$preview_size" -eq 0 ] || [ "$preview_size" -gt 1048576 ]; then
522
- printf 'Preview JSON must be between 1 byte and 1 MiB.\n' >&2
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
- python3 - "$preview_path" <<'PY'
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
- flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0)
537
- descriptor = os.open(path, flags)
538
- try:
539
- metadata = os.fstat(descriptor)
540
- if not stat.S_ISREG(metadata.st_mode) or metadata.st_size < 1 or metadata.st_size > 1048576:
541
- raise ValueError("unsafe preview")
542
- raw = os.read(descriptor, 1048577)
543
- finally:
544
- os.close(descriptor)
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 a saved JSON preview; requires explicit --yes\n'
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'
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "9.22.7"
10
+ __version__ = "9.22.8"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -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.
@@ -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.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}
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=D32CF1FDB032F37F64756E2164756E21
1241
+ //# debugId=B93D9505D257E3EF64756E2164756E21
package/mcp/__init__.py CHANGED
@@ -75,4 +75,4 @@ try:
75
75
  except ImportError:
76
76
  __all__ = ['mcp']
77
77
 
78
- __version__ = '9.22.7'
78
+ __version__ = '9.22.8'
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.7",
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.7",
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",