loki-mode 7.32.1 → 7.32.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 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, 11 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v7.32.1
6
+ # Loki Mode v7.32.2
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -398,4 +398,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
398
398
 
399
399
  ---
400
400
 
401
- **v7.32.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
401
+ **v7.32.2 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 7.32.1
1
+ 7.32.2
package/autonomy/loki CHANGED
@@ -711,6 +711,7 @@ show_help() {
711
711
  echo " --no-dashboard Disable web dashboard"
712
712
  echo " --sandbox Run in Docker sandbox for isolation"
713
713
  echo " --skip-memory Skip loading memory context at startup"
714
+ echo " --fresh-prd Regenerate the PRD from the codebase (no-PRD runs; ignores the reusable generated PRD)"
714
715
  echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
715
716
  echo " --budget USD Set cost budget limit (display in dashboard/status)"
716
717
  echo " --bmad-project PATH Use BMAD Method project artifacts as input"
@@ -1030,6 +1031,9 @@ cmd_start() {
1030
1031
  echo " --api Start dashboard API server alongside the build"
1031
1032
  echo " --sandbox Run in Docker sandbox"
1032
1033
  echo " --skip-memory Skip loading memory context at startup"
1034
+ echo " --fresh-prd Regenerate the PRD from the codebase on a no-PRD run"
1035
+ echo " (ignores the reusable generated PRD; aliases: --regen-prd,"
1036
+ echo " --regenerate-prd, --regen, or LOKI_PRD_REGEN=1)"
1033
1037
  echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
1034
1038
  echo " --budget USD Cost budget limit (auto-pause when exceeded)"
1035
1039
  echo " --bmad-project PATH Use BMAD Method project artifacts as input"
@@ -1142,10 +1146,12 @@ cmd_start() {
1142
1146
  args+=("--parallel")
1143
1147
  shift
1144
1148
  ;;
1145
- --regen-prd|--regenerate-prd|--regen)
1149
+ --regen-prd|--regenerate-prd|--regen|--fresh-prd)
1146
1150
  # v7.8.1: force a fresh generated PRD on a no-PRD run, overriding
1147
1151
  # the staleness-aware reuse (decide_generated_prd_action in
1148
1152
  # run.sh reads LOKI_PRD_REGEN). Exported so the runner sees it.
1153
+ # --fresh-prd is the documented alias surfaced in the reuse
1154
+ # disclosure line ("pass --fresh-prd to regenerate").
1149
1155
  export LOKI_PRD_REGEN=1
1150
1156
  shift
1151
1157
  ;;
@@ -1820,13 +1826,30 @@ cmd_start() {
1820
1826
  echo -e "${YELLOW}Warning: No PRD file specified. Auto-confirming (CI mode).${NC}"
1821
1827
  else
1822
1828
  echo -e "${YELLOW}No PRD file specified.${NC}"
1823
- echo "Loki Mode will analyze the existing codebase and generate"
1824
- echo "a PRD automatically. No requirements document needed."
1829
+ # v7.8.1+: the runner (run_autonomous -> decide_generated_prd_action)
1830
+ # makes the real reuse|update|generate decision. Here we only adjust
1831
+ # the TTY prompt wording so it does not falsely claim "generate" when
1832
+ # a previously generated PRD already exists. --regen-prd / --fresh-prd
1833
+ # (LOKI_PRD_REGEN=1) always forces a fresh generation.
1834
+ local _prompt_q="Generate PRD from codebase and start? [Y/n] "
1835
+ if [ "${LOKI_PRD_REGEN:-}" = "1" ]; then
1836
+ echo "Loki Mode will regenerate the PRD from the codebase (forced)."
1837
+ _prompt_q="Regenerate PRD from codebase (forced) and start? [Y/n] "
1838
+ elif [ -f ".loki/generated-prd.md" ] || [ -f ".loki/generated-prd.json" ]; then
1839
+ echo "A previously generated PRD exists. Loki Mode will reuse it"
1840
+ echo "if the codebase is unchanged, update it incrementally if it"
1841
+ echo "changed, or use it as-is if you hand-edited it. Pass"
1842
+ echo "--fresh-prd to regenerate from scratch."
1843
+ _prompt_q="Continue with the existing generated PRD and start? [Y/n] "
1844
+ else
1845
+ echo "Loki Mode will analyze the existing codebase and generate"
1846
+ echo "a PRD automatically. No requirements document needed."
1847
+ fi
1825
1848
  echo ""
1826
1849
  # v7.5.3 UX: rephrased + default flipped from N to Y. The pre-v7.5.3
1827
1850
  # "Continue? [y/N]" with default-N caused users to accidentally
1828
1851
  # cancel by hitting Enter after reading the explanation.
1829
- echo -e "Generate PRD from codebase and start? [Y/n] \c"
1852
+ echo -e "$_prompt_q\c"
1830
1853
  read -r confirm
1831
1854
  if [[ "$confirm" =~ ^[Nn] ]]; then
1832
1855
  echo "Aborted. Usage: loki start <path-to-prd.md>"
package/autonomy/run.sh CHANGED
@@ -4575,10 +4575,30 @@ compute_codebase_signature() {
4575
4575
  )
4576
4576
  }
4577
4577
 
4578
+ # Content hash of the generated PRD file itself (NOT the codebase). Used to
4579
+ # detect that a user hand-edited the generated PRD: when the file no longer
4580
+ # matches the prd_sha Loki recorded after it last wrote the file, the PRD is
4581
+ # user-owned and must be used as-is, never silently overwritten. Echoes "" when
4582
+ # no generated PRD file is present.
4583
+ _loki_prd_file_hash() {
4584
+ local loki_dir="${1:-.}/.loki"
4585
+ local f=""
4586
+ if [ -f "$loki_dir/generated-prd.md" ]; then
4587
+ f="$loki_dir/generated-prd.md"
4588
+ elif [ -f "$loki_dir/generated-prd.json" ]; then
4589
+ f="$loki_dir/generated-prd.json"
4590
+ fi
4591
+ [ -n "$f" ] || { echo ""; return 0; }
4592
+ _loki_hash_stdin < "$f"
4593
+ }
4594
+
4578
4595
  # Decide what to do with a previously generated PRD on a no-PRD run.
4579
- # Echoes one of: reuse | update | generate. Never fails the run.
4580
- # - LOKI_PRD_REGEN=1 (or --regen-prd, which sets it) -> generate (force fresh).
4596
+ # Echoes one of: reuse | update | generate | user_owned. Never fails the run.
4597
+ # Precedence: force-regen > user_owned (hand-edited) > reuse/update > generate.
4598
+ # - LOKI_PRD_REGEN=1 (or --regen-prd/--fresh-prd, which set it) -> generate.
4581
4599
  # - no generated PRD present -> generate (first run).
4600
+ # - generated PRD present but its content hash differs from the recorded
4601
+ # prd_sha -> user_owned (the user hand-edited it; use as-is, do not rewrite).
4582
4602
  # - generated PRD present, no recorded signature -> update (have a PRD but no
4583
4603
  # provenance: reconcile incrementally rather than trust-blindly or discard).
4584
4604
  # - signature matches current codebase -> reuse (unchanged).
@@ -4595,15 +4615,31 @@ decide_generated_prd_action() {
4595
4615
  if [ ! -f "$sig_file" ]; then
4596
4616
  echo "update"; return 0
4597
4617
  fi
4598
- local stored current
4618
+ local stored stored_prd_sha current cur_prd_sha
4599
4619
  stored=$(LOKI_SIG_FILE="$sig_file" python3 -c "
4600
4620
  import json, os
4601
4621
  try:
4602
4622
  print(json.load(open(os.environ['LOKI_SIG_FILE'])).get('signature',''))
4603
4623
  except Exception:
4604
4624
  print('')
4625
+ " 2>/dev/null)
4626
+ stored_prd_sha=$(LOKI_SIG_FILE="$sig_file" python3 -c "
4627
+ import json, os
4628
+ try:
4629
+ print(json.load(open(os.environ['LOKI_SIG_FILE'])).get('prd_sha',''))
4630
+ except Exception:
4631
+ print('')
4605
4632
  " 2>/dev/null)
4606
4633
  [ -z "$stored" ] && { echo "update"; return 0; }
4634
+ # Hand-edit detection (precedence above reuse/update): if we recorded a
4635
+ # prd_sha and the file no longer matches it, the user edited it themselves.
4636
+ # Treat as user-owned: use as-is, never regenerate over their changes.
4637
+ if [ -n "$stored_prd_sha" ]; then
4638
+ cur_prd_sha=$(_loki_prd_file_hash "${TARGET_DIR:-.}")
4639
+ if [ -n "$cur_prd_sha" ] && [ "$cur_prd_sha" != "$stored_prd_sha" ]; then
4640
+ echo "user_owned"; return 0
4641
+ fi
4642
+ fi
4607
4643
  current=$(compute_codebase_signature "${TARGET_DIR:-.}")
4608
4644
  if [ "$stored" = "$current" ]; then
4609
4645
  echo "reuse"
@@ -4618,6 +4654,12 @@ except Exception:
4618
4654
  persist_prd_signature_if_present() {
4619
4655
  local exit_code="${1:-0}"
4620
4656
  [ "$exit_code" = "0" ] || return 0
4657
+ # Hand-edited (user-owned) PRD: do NOT rewrite the signature. Re-hashing the
4658
+ # user's edited file would re-baseline its content as the new prd_sha, so the
4659
+ # next run would fall through to plain reuse with the wrong (non-user-owned)
4660
+ # disclosure. Preserve the prior Loki-authored prd_sha/generated_at so every
4661
+ # subsequent run keeps detecting user_owned until --fresh-prd forces a regen.
4662
+ [ "${GENERATED_PRD_ACTION:-}" = "user_owned" ] && return 0
4621
4663
  # only for no-PRD runs whose generated PRD exists
4622
4664
  case "${prd_path:-}" in
4623
4665
  ""|*.loki/generated-prd.md|*.loki/generated-prd.json) ;;
@@ -4630,17 +4672,38 @@ persist_prd_signature_if_present() {
4630
4672
  [ -n "$sig" ] || return 0
4631
4673
  mkdir -p "$loki_dir/state" 2>/dev/null || return 0
4632
4674
  local mode="files"; case "$sig" in git:*) mode="git" ;; esac
4675
+ # Record the content hash of the PRD file Loki just wrote so a later
4676
+ # hand-edit by the user is detectable (decide_generated_prd_action). This
4677
+ # runs AFTER the agent's own PRD writes, so Loki's updates are not mistaken
4678
+ # for user edits.
4679
+ local prd_sha; prd_sha=$(_loki_prd_file_hash "${TARGET_DIR:-.}")
4633
4680
  local tmp="$loki_dir/state/.prd-signature.json.tmp.$$"
4681
+ # Preserve generated_at when the codebase signature is unchanged so the
4682
+ # reuse disclosure ("generated on <date>") stays honest across reuse runs;
4683
+ # only stamp a new date when the PRD content actually changed (sig differs).
4634
4684
  LOKI_SIG="$sig" LOKI_SIG_MODE="$mode" LOKI_SIG_VER="$(get_version 2>/dev/null || echo unknown)" \
4685
+ LOKI_PRD_SHA="$prd_sha" LOKI_SIG_FILE="$loki_dir/state/prd-signature.json" \
4635
4686
  python3 -c "
4636
4687
  import json, os, datetime
4688
+ sig = os.environ['LOKI_SIG']
4689
+ prev = {}
4690
+ try:
4691
+ prev = json.load(open(os.environ['LOKI_SIG_FILE']))
4692
+ except Exception:
4693
+ prev = {}
4694
+ prev_at = prev.get('generated_at') if isinstance(prev, dict) else None
4695
+ if prev_at and prev.get('signature') == sig:
4696
+ generated_at = prev_at
4697
+ else:
4698
+ generated_at = datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00','Z')
4637
4699
  rec = {
4638
- 'signature': os.environ['LOKI_SIG'],
4639
- 'generated_at': datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00','Z'),
4700
+ 'signature': sig,
4701
+ 'generated_at': generated_at,
4640
4702
  'prd_path': '.loki/generated-prd.md',
4703
+ 'prd_sha': os.environ.get('LOKI_PRD_SHA',''),
4641
4704
  'mode': os.environ['LOKI_SIG_MODE'],
4642
4705
  'loki_version': os.environ['LOKI_SIG_VER'],
4643
- }
4706
+ }
4644
4707
  print(json.dumps(rec))
4645
4708
  " > "$tmp" 2>/dev/null && mv -f "$tmp" "$loki_dir/state/prd-signature.json" 2>/dev/null || rm -f "$tmp" 2>/dev/null
4646
4709
  }
@@ -12014,13 +12077,35 @@ run_autonomous() {
12014
12077
  export GENERATED_PRD_ACTION
12015
12078
  local _gen_prd=".loki/generated-prd.md"
12016
12079
  [ -f ".loki/generated-prd.md" ] || _gen_prd=".loki/generated-prd.json"
12080
+ # Date the generated PRD was last written (for an honest disclosure).
12081
+ local _prd_date=""
12082
+ if [ -f ".loki/state/prd-signature.json" ]; then
12083
+ _prd_date=$(LOKI_SIG_FILE=".loki/state/prd-signature.json" python3 -c "
12084
+ import json, os
12085
+ try:
12086
+ d = json.load(open(os.environ['LOKI_SIG_FILE'])).get('generated_at','')
12087
+ print((d or '')[:10])
12088
+ except Exception:
12089
+ print('')
12090
+ " 2>/dev/null)
12091
+ fi
12017
12092
  case "$GENERATED_PRD_ACTION" in
12018
12093
  reuse)
12019
- log_info "No user PRD found. Reusing generated PRD (codebase unchanged): $_gen_prd"
12094
+ if [ -n "$_prd_date" ]; then
12095
+ log_info "Reusing the PRD last generated or updated on $_prd_date; pass --fresh-prd to regenerate ($_gen_prd)"
12096
+ else
12097
+ log_info "Reusing the generated PRD (codebase unchanged); pass --fresh-prd to regenerate ($_gen_prd)"
12098
+ fi
12099
+ prd_path="$_gen_prd"
12100
+ ;;
12101
+ user_owned)
12102
+ # The user hand-edited the generated PRD. Use it as-is (never
12103
+ # overwrite their edits); distinct disclosure from a clean reuse.
12104
+ log_info "Using your hand-edited PRD as-is ($_gen_prd); pass --fresh-prd to regenerate from the codebase"
12020
12105
  prd_path="$_gen_prd"
12021
12106
  ;;
12022
12107
  update)
12023
- log_info "No user PRD found. Codebase changed since the generated PRD; will update it incrementally: $_gen_prd"
12108
+ log_info "No user PRD found. Codebase changed since the generated PRD; will update it incrementally ($_gen_prd); pass --fresh-prd to regenerate from scratch"
12024
12109
  prd_path="$_gen_prd"
12025
12110
  ;;
12026
12111
  *)
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "7.32.1"
10
+ __version__ = "7.32.2"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v7.32.1
5
+ **Version:** v7.32.2
6
6
 
7
7
  ---
8
8
 
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var n6=Object.defineProperty;var a6=($)=>$;function s6($,Q){this[$]=a6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)n6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:s6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var S1={};h(S1,{lokiDir:()=>P,homeLokiDir:()=>o$,findRepoRootForVersion:()=>d$,REPO_ROOT:()=>m});import{resolve as n,dirname as l$}from"path";import{fileURLToPath as t6}from"url";import{existsSync as P$}from"fs";import{homedir as r6}from"os";function i6(){let $=N1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=l$($);if(Z===$)break;$=Z}return n(N1,"..","..","..")}function d$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=l$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o$(){return n(r6(),".loki")}var N1,m;var C=L(()=>{N1=l$(t6(import.meta.url));m=i6()});import{readFileSync as e6}from"fs";import{resolve as $Q,dirname as QQ}from"path";import{fileURLToPath as ZQ}from"url";function F$(){if($$!==null)return $$;let $="7.32.1";if(typeof $==="string"&&$.length>0)return $$=$,$$;try{let Q=QQ(ZQ(import.meta.url)),Z=d$(Q);$$=e6($Q(Z,"VERSION"),"utf-8").trim()}catch{$$="unknown"}return $$}var $$=null;var n$=L(()=>{C()});var C1={};h(C1,{runOrThrow:()=>zQ,run:()=>j,commandVersion:()=>KQ,commandExists:()=>f,ShellError:()=>a$});async function j($,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[W,K,U]=await Promise.all([new Response(Z.stdout).text(),new Response(Z.stderr).text(),Z.exited]);return{stdout:W,stderr:K,exitCode:U}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function zQ($,Q={}){let Z=await j($,Q);if(Z.exitCode!==0)throw new a$(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function f($){let Q=XQ($),Z=await j(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function XQ($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function KQ($,Q="--version"){if(!await f($))return null;let z=await j([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var a$;var d=L(()=>{a$=class a$ 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 a($){return WQ?"":$}var WQ,T,S,I,TZ,w,R,y,q;var c=L(()=>{WQ=(process.env.NO_COLOR??"").length>0;T=a("\x1B[0;31m"),S=a("\x1B[0;32m"),I=a("\x1B[1;33m"),TZ=a("\x1B[0;34m"),w=a("\x1B[0;36m"),R=a("\x1B[1m"),y=a("\x1B[2m"),q=a("\x1B[0m")});import{existsSync as TQ}from"fs";async function Q$(){if(B$!==void 0)return B$;let $="/opt/homebrew/bin/python3.12";if(TQ($))return B$=$,$;let Q=await f("python3.12");if(Q)return B$=Q,Q;let Z=await f("python3");return B$=Z,Z}async function Z$($,Q={}){let Z=await Q$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return j([Z,"-c",$],Q)}var B$;var W$=L(()=>{d()});var t1={};h(t1,{runStatus:()=>gQ});import{existsSync as v,readFileSync as U$,readdirSync as l1,statSync as d1}from"fs";import{resolve as D,basename as xQ}from"path";import{homedir as NQ}from"os";async function DQ(){if(await f("jq"))return!0;return process.stdout.write(`${T}Error: jq is required but not installed.${q}
2
+ var n6=Object.defineProperty;var a6=($)=>$;function s6($,Q){this[$]=a6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)n6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:s6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var S1={};h(S1,{lokiDir:()=>P,homeLokiDir:()=>o$,findRepoRootForVersion:()=>d$,REPO_ROOT:()=>m});import{resolve as n,dirname as l$}from"path";import{fileURLToPath as t6}from"url";import{existsSync as P$}from"fs";import{homedir as r6}from"os";function i6(){let $=N1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=l$($);if(Z===$)break;$=Z}return n(N1,"..","..","..")}function d$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=l$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o$(){return n(r6(),".loki")}var N1,m;var C=L(()=>{N1=l$(t6(import.meta.url));m=i6()});import{readFileSync as e6}from"fs";import{resolve as $Q,dirname as QQ}from"path";import{fileURLToPath as ZQ}from"url";function F$(){if($$!==null)return $$;let $="7.32.2";if(typeof $==="string"&&$.length>0)return $$=$,$$;try{let Q=QQ(ZQ(import.meta.url)),Z=d$(Q);$$=e6($Q(Z,"VERSION"),"utf-8").trim()}catch{$$="unknown"}return $$}var $$=null;var n$=L(()=>{C()});var C1={};h(C1,{runOrThrow:()=>zQ,run:()=>j,commandVersion:()=>KQ,commandExists:()=>f,ShellError:()=>a$});async function j($,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[W,K,U]=await Promise.all([new Response(Z.stdout).text(),new Response(Z.stderr).text(),Z.exited]);return{stdout:W,stderr:K,exitCode:U}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function zQ($,Q={}){let Z=await j($,Q);if(Z.exitCode!==0)throw new a$(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function f($){let Q=XQ($),Z=await j(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function XQ($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function KQ($,Q="--version"){if(!await f($))return null;let z=await j([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var a$;var d=L(()=>{a$=class a$ 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 a($){return WQ?"":$}var WQ,T,S,I,TZ,w,R,y,q;var c=L(()=>{WQ=(process.env.NO_COLOR??"").length>0;T=a("\x1B[0;31m"),S=a("\x1B[0;32m"),I=a("\x1B[1;33m"),TZ=a("\x1B[0;34m"),w=a("\x1B[0;36m"),R=a("\x1B[1m"),y=a("\x1B[2m"),q=a("\x1B[0m")});import{existsSync as TQ}from"fs";async function Q$(){if(B$!==void 0)return B$;let $="/opt/homebrew/bin/python3.12";if(TQ($))return B$=$,$;let Q=await f("python3.12");if(Q)return B$=Q,Q;let Z=await f("python3");return B$=Z,Z}async function Z$($,Q={}){let Z=await Q$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return j([Z,"-c",$],Q)}var B$;var W$=L(()=>{d()});var t1={};h(t1,{runStatus:()=>gQ});import{existsSync as v,readFileSync as U$,readdirSync as l1,statSync as d1}from"fs";import{resolve as D,basename as xQ}from"path";import{homedir as NQ}from"os";async function DQ(){if(await f("jq"))return!0;return process.stdout.write(`${T}Error: jq is required but not installed.${q}
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)
@@ -789,4 +789,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
789
789
  `),2}default:return process.stderr.write(`Unknown command: ${Q}
790
790
  `),process.stderr.write(o6),2}}p1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var ZZ=await QZ(Bun.argv.slice(2));process.exit(ZZ);
791
791
 
792
- //# debugId=CD523BB6FF38AC8F64756E2164756E21
792
+ //# debugId=F7A4FD0C7A94555A64756E2164756E21
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '7.32.1'
60
+ __version__ = '7.32.2'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "loki-mode",
3
3
  "mcpName": "io.github.asklokesh/loki-mode",
4
- "version": "7.32.1",
4
+ "version": "7.32.2",
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 11 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
6
6
  "keywords": [
7
7
  "agent",