loki-mode 7.8.0 → 7.8.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-to-product system. Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product via the RARV-C closure loop, with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v7.8.0
6
+ # Loki Mode v7.8.2
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -381,4 +381,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
381
381
 
382
382
  ---
383
383
 
384
- **v7.8.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
384
+ **v7.8.2 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 7.8.0
1
+ 7.8.2
package/autonomy/loki CHANGED
@@ -911,6 +911,13 @@ cmd_start() {
911
911
  args+=("--parallel")
912
912
  shift
913
913
  ;;
914
+ --regen-prd|--regenerate-prd|--regen)
915
+ # v7.8.1: force a fresh generated PRD on a no-PRD run, overriding
916
+ # the staleness-aware reuse (decide_generated_prd_action in
917
+ # run.sh reads LOKI_PRD_REGEN). Exported so the runner sees it.
918
+ export LOKI_PRD_REGEN=1
919
+ shift
920
+ ;;
914
921
  --bg|--background)
915
922
  args+=("--bg")
916
923
  shift
package/autonomy/run.sh CHANGED
@@ -3973,6 +3973,124 @@ print(json.dumps(data, indent=2))
3973
3973
  }
3974
3974
 
3975
3975
  # Track iteration completion - move task to completed queue
3976
+ # v7.8.1: staleness-aware generated-PRD reuse helpers.
3977
+ # Hash stdin with whatever digest tool is available (mirrors the existing
3978
+ # stat -f%z || stat -c%s dual-probe portability pattern). Echoes a short hash.
3979
+ _loki_hash_stdin() {
3980
+ if command -v shasum >/dev/null 2>&1; then
3981
+ shasum -a 256 | cut -c1-16
3982
+ elif command -v sha256sum >/dev/null 2>&1; then
3983
+ sha256sum | cut -c1-16
3984
+ else
3985
+ cksum | tr -d ' ' | cut -c1-16
3986
+ fi
3987
+ }
3988
+
3989
+ # Compute a cheap, clone-stable signature of the codebase so we can tell whether
3990
+ # it changed since the generated PRD was last written. Git repos: HEAD sha +
3991
+ # dirty flag (.loki/.git churn filtered out). Non-git: a hash of sorted
3992
+ # path+size pairs (size, not mtime, so it is clone-stable). Echoes the signature.
3993
+ compute_codebase_signature() {
3994
+ local dir="${1:-.}"
3995
+ ( cd "$dir" 2>/dev/null || exit 0
3996
+ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
3997
+ local head dirty porcelain
3998
+ head=$(git rev-parse HEAD 2>/dev/null || echo "nohead")
3999
+ porcelain=$(git status --porcelain 2>/dev/null | grep -vE '(^...?\.loki/|/\.loki/| \.loki/|\.git/)' || true)
4000
+ if [ -z "$porcelain" ]; then
4001
+ dirty="clean"
4002
+ else
4003
+ dirty=$(printf '%s' "$porcelain" | _loki_hash_stdin)
4004
+ fi
4005
+ echo "git:${head}:${dirty}"
4006
+ else
4007
+ local listing count
4008
+ listing=$(find . \
4009
+ -type d \( -name .loki -o -name .git -o -name node_modules -o -name dist \
4010
+ -o -name build -o -name .next -o -name target -o -name vendor \
4011
+ -o -name __pycache__ -o -name .venv -o -name venv \) -prune -o \
4012
+ -type f -print 2>/dev/null \
4013
+ | while IFS= read -r f; do
4014
+ local sz
4015
+ sz=$(stat -f%z "$f" 2>/dev/null || stat -c%s "$f" 2>/dev/null || echo 0)
4016
+ printf '%s\t%s\n' "$f" "$sz"
4017
+ done | LC_ALL=C sort)
4018
+ count=$(printf '%s\n' "$listing" | grep -c . || echo 0)
4019
+ echo "files:$(printf '%s' "$listing" | _loki_hash_stdin):${count}"
4020
+ fi
4021
+ )
4022
+ }
4023
+
4024
+ # Decide what to do with a previously generated PRD on a no-PRD run.
4025
+ # Echoes one of: reuse | update | generate. Never fails the run.
4026
+ # - LOKI_PRD_REGEN=1 (or --regen-prd, which sets it) -> generate (force fresh).
4027
+ # - no generated PRD present -> generate (first run).
4028
+ # - generated PRD present, no recorded signature -> update (have a PRD but no
4029
+ # provenance: reconcile incrementally rather than trust-blindly or discard).
4030
+ # - signature matches current codebase -> reuse (unchanged).
4031
+ # - signature differs -> update (codebase changed; update incrementally).
4032
+ decide_generated_prd_action() {
4033
+ local loki_dir="${TARGET_DIR:-.}/.loki"
4034
+ if [ "${LOKI_PRD_REGEN:-}" = "1" ]; then
4035
+ echo "generate"; return 0
4036
+ fi
4037
+ if [ ! -f "$loki_dir/generated-prd.md" ] && [ ! -f "$loki_dir/generated-prd.json" ]; then
4038
+ echo "generate"; return 0
4039
+ fi
4040
+ local sig_file="$loki_dir/state/prd-signature.json"
4041
+ if [ ! -f "$sig_file" ]; then
4042
+ echo "update"; return 0
4043
+ fi
4044
+ local stored current
4045
+ stored=$(LOKI_SIG_FILE="$sig_file" python3 -c "
4046
+ import json, os
4047
+ try:
4048
+ print(json.load(open(os.environ['LOKI_SIG_FILE'])).get('signature',''))
4049
+ except Exception:
4050
+ print('')
4051
+ " 2>/dev/null)
4052
+ [ -z "$stored" ] && { echo "update"; return 0; }
4053
+ current=$(compute_codebase_signature "${TARGET_DIR:-.}")
4054
+ if [ "$stored" = "$current" ]; then
4055
+ echo "reuse"
4056
+ else
4057
+ echo "update"
4058
+ fi
4059
+ }
4060
+
4061
+ # Persist the current codebase signature after a clean no-PRD iteration that has
4062
+ # a generated PRD, so the next run can decide reuse vs update. Best-effort; never
4063
+ # fails the run. Only records on exit_code==0 (do not bless a broken iteration).
4064
+ persist_prd_signature_if_present() {
4065
+ local exit_code="${1:-0}"
4066
+ [ "$exit_code" = "0" ] || return 0
4067
+ # only for no-PRD runs whose generated PRD exists
4068
+ case "${prd_path:-}" in
4069
+ ""|*.loki/generated-prd.md|*.loki/generated-prd.json) ;;
4070
+ *) return 0 ;;
4071
+ esac
4072
+ local loki_dir="${TARGET_DIR:-.}/.loki"
4073
+ [ -f "$loki_dir/generated-prd.md" ] || [ -f "$loki_dir/generated-prd.json" ] || return 0
4074
+ local sig
4075
+ sig=$(compute_codebase_signature "${TARGET_DIR:-.}")
4076
+ [ -n "$sig" ] || return 0
4077
+ mkdir -p "$loki_dir/state" 2>/dev/null || return 0
4078
+ local mode="files"; case "$sig" in git:*) mode="git" ;; esac
4079
+ local tmp="$loki_dir/state/.prd-signature.json.tmp.$$"
4080
+ LOKI_SIG="$sig" LOKI_SIG_MODE="$mode" LOKI_SIG_VER="$(get_version 2>/dev/null || echo unknown)" \
4081
+ python3 -c "
4082
+ import json, os, datetime
4083
+ rec = {
4084
+ 'signature': os.environ['LOKI_SIG'],
4085
+ 'generated_at': datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00','Z'),
4086
+ 'prd_path': '.loki/generated-prd.md',
4087
+ 'mode': os.environ['LOKI_SIG_MODE'],
4088
+ 'loki_version': os.environ['LOKI_SIG_VER'],
4089
+ }
4090
+ print(json.dumps(rec))
4091
+ " > "$tmp" 2>/dev/null && mv -f "$tmp" "$loki_dir/state/prd-signature.json" 2>/dev/null || rm -f "$tmp" 2>/dev/null
4092
+ }
4093
+
3976
4094
  track_iteration_complete() {
3977
4095
  local iteration="$1"
3978
4096
  local exit_code="${2:-0}"
@@ -9586,7 +9704,18 @@ build_prompt() {
9586
9704
  local sdlc_instruction="SDLC_PHASES_ENABLED: [$phases]. Execute ALL enabled phases. Log results to .loki/logs/. See .loki/SKILL.md for phase details. Skill modules at .loki/skills/."
9587
9705
 
9588
9706
  # Codebase Analysis Mode - when no PRD provided
9589
- local analysis_instruction="CODEBASE_ANALYSIS_MODE: No PRD. FIRST: Analyze codebase - scan structure, read package.json/requirements.txt, examine README. THEN: Generate PRD at .loki/generated-prd.md. FINALLY: Execute SDLC phases."
9707
+ # v7.8.1: improved 3-pass instruction. More efficient (no blind full scan)
9708
+ # and more accurate (high-signal files first, fixed PRD section template so
9709
+ # the result is diff-friendly for later incremental updates).
9710
+ local analysis_instruction="CODEBASE_ANALYSIS_MODE: No PRD provided. Reverse-engineer a precise PRD from the existing code in three passes, cheaply and without blind full scans. PASS 1 (orient): list the top two directory levels; read ONLY high-signal manifests that exist (package.json, requirements.txt, pyproject.toml, Cargo.toml, go.mod, pom.xml, build.gradle, composer.json) to identify language, framework, and scripts; read README and any docs index. PASS 2 (locate): from the manifests and conventional layout, identify the entrypoints, the public API or CLI surface, the test directory and runner, and the config or env contract; read those first; skip generated, vendored, and lockfile content; prefer LSP workspace symbols when the lsp-proxy server is available. PASS 3 (write): write .loki/generated-prd.md with these sections: Overview, Detected Stack, Entrypoints and Components, Existing Behavior and Requirements (reverse-engineered, observable), Test and Build Setup, Gaps and TODOs, Out of Scope. Keep it under 200 lines, plain Markdown, no emojis, no em dashes. Do not invent features not evidenced by the code. THEN execute SDLC phases against that PRD."
9711
+
9712
+ # v7.8.1: incremental-update instruction for when a generated PRD already
9713
+ # exists and the codebase changed (GENERATED_PRD_ACTION=update). Reconcile,
9714
+ # do not regenerate, so the PRD stays continuous and the update is cheap.
9715
+ local update_instruction=""
9716
+ if [ "${GENERATED_PRD_ACTION:-}" = "update" ]; then
9717
+ update_instruction="GENERATED_PRD_UPDATE_MODE: A previously generated PRD exists at .loki/generated-prd.md and the codebase has changed since it was written. Do NOT regenerate it from scratch. Read the existing .loki/generated-prd.md first, then reconcile it with the current code: add requirements for new entrypoints, components, or behaviors; remove or mark obsolete requirements whose code was deleted; correct the Detected Stack and Test and Build Setup sections if they drifted. Preserve the existing structure and still-accurate content. Keep edits minimal and evidence-based, under 200 lines, plain Markdown, no emojis, no em dashes. THEN execute SDLC phases against the updated PRD."
9718
+ fi
9590
9719
 
9591
9720
  # Context Memory Instructions (integrated with new memory system)
9592
9721
  local memory_instruction="MEMORY SYSTEM: Relevant context from past sessions is provided below (if any). Your actions will be automatically recorded for future reference. For complex handoffs: create .loki/memory/handoffs/{timestamp}.md. For important decisions: they will be captured in the timeline. Check .loki/CONTINUITY.md for session-level working memory."
@@ -9935,7 +10064,7 @@ except Exception:
9935
10064
  else
9936
10065
  if [ $retry -eq 0 ]; then
9937
10066
  if [ -n "$prd" ]; then
9938
- echo "Loki Mode with PRD at $prd. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $usage_doc_instruction $lsp_grounding_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
10067
+ echo "Loki Mode with PRD at $prd. $update_instruction $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section $rarv_instruction $memory_instruction $usage_doc_instruction $lsp_grounding_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
9939
10068
  else
9940
10069
  echo "Loki Mode. $human_directive $gate_failure_context $queue_tasks $bmad_context $openspec_context $mirofish_context $magic_context $checklist_status $app_runner_info $playwright_info $memory_context_section $analysis_instruction $rarv_instruction $memory_instruction $usage_doc_instruction $lsp_grounding_instruction $completion_instruction $sdlc_instruction $autonomous_suffix"
9941
10070
  fi
@@ -10023,6 +10152,13 @@ except Exception:
10023
10152
  if [ -z "$prd" ]; then
10024
10153
  printf '%s\n' "$analysis_instruction"
10025
10154
  fi
10155
+ # v7.8.1: when reusing a generated PRD whose codebase changed, append the
10156
+ # incremental-update instruction (prd is the generated PRD here, so the
10157
+ # anchor already says "with PRD at .loki/generated-prd.md"). Decided once per
10158
+ # run (GENERATED_PRD_ACTION), so it stays cache-stable across iterations.
10159
+ if [ -n "$update_instruction" ]; then
10160
+ printf '%s\n' "$update_instruction"
10161
+ fi
10026
10162
  printf '</loki_system>\n'
10027
10163
  printf '[CACHE_BREAKPOINT]\n'
10028
10164
 
@@ -10933,13 +11069,33 @@ run_autonomous() {
10933
11069
  if [ -f ".loki/generated-prd.md" ] || [ -f ".loki/generated-prd.json" ]; then
10934
11070
  log_warn "Using user PRD ($found_prd) instead of generated PRD (.loki/generated-prd.md). Remove generated PRD if no longer needed."
10935
11071
  fi
10936
- elif [ -f ".loki/generated-prd.md" ]; then
10937
- log_info "No user PRD found. Using previously generated PRD: .loki/generated-prd.md"
10938
- prd_path=".loki/generated-prd.md"
10939
- elif [ -f ".loki/generated-prd.json" ]; then
10940
- log_info "No user PRD found. Using previously generated PRD: .loki/generated-prd.json"
10941
- prd_path=".loki/generated-prd.json"
11072
+ elif [ -f ".loki/generated-prd.md" ] || [ -f ".loki/generated-prd.json" ]; then
11073
+ # v7.8.1: staleness-aware reuse. Decide reuse|update|generate ONCE
11074
+ # (the decision must be stable across iterations so the cached static
11075
+ # prompt prefix does not change mid-run). reuse/update both point
11076
+ # prd_path at the existing generated PRD; generate (forced via
11077
+ # LOKI_PRD_REGEN) falls through to Codebase Analysis Mode.
11078
+ GENERATED_PRD_ACTION=$(decide_generated_prd_action)
11079
+ export GENERATED_PRD_ACTION
11080
+ local _gen_prd=".loki/generated-prd.md"
11081
+ [ -f ".loki/generated-prd.md" ] || _gen_prd=".loki/generated-prd.json"
11082
+ case "$GENERATED_PRD_ACTION" in
11083
+ reuse)
11084
+ log_info "No user PRD found. Reusing generated PRD (codebase unchanged): $_gen_prd"
11085
+ prd_path="$_gen_prd"
11086
+ ;;
11087
+ update)
11088
+ log_info "No user PRD found. Codebase changed since the generated PRD; will update it incrementally: $_gen_prd"
11089
+ prd_path="$_gen_prd"
11090
+ ;;
11091
+ *)
11092
+ log_info "Regenerating PRD from codebase (forced)"
11093
+ prd_path=""
11094
+ ;;
11095
+ esac
10942
11096
  else
11097
+ GENERATED_PRD_ACTION="generate"
11098
+ export GENERATED_PRD_ACTION
10943
11099
  log_info "No PRD found - will analyze codebase and generate one"
10944
11100
  fi
10945
11101
  fi
@@ -11657,6 +11813,10 @@ if __name__ == "__main__":
11657
11813
 
11658
11814
  # Auto-track iteration completion (for dashboard task queue)
11659
11815
  track_iteration_complete "$ITERATION_COUNT" "$exit_code"
11816
+ # v7.8.1: record the codebase signature after a clean no-PRD iteration
11817
+ # that has a generated PRD, so the next no-PRD run can decide reuse vs
11818
+ # update. Best-effort, never fails the iteration.
11819
+ persist_prd_signature_if_present "$exit_code"
11660
11820
 
11661
11821
  # Sentrux architectural-drift gate diff + finding emission (opt-in, v7.5.15).
11662
11822
  _loki_sentrux_iteration_end "$ITERATION_COUNT" "${TARGET_DIR:-.}"
package/bin/loki CHANGED
@@ -117,6 +117,20 @@ case "${1:-}" in
117
117
  # v7.5.2: rollback added (wires loki-ts/src/commands/rollback.ts).
118
118
  # v7.5.3: internal added for autonomy/run.sh phase1-hooks calls.
119
119
  # v7.5.28: kpis added (Phase K MVP: read-only KPI snapshot).
120
+ #
121
+ # v7.8.2: emit the cli_command product-analytics event for Bun-routed
122
+ # commands. The bash CLI fires this from autonomy/loki main(), but the
123
+ # ported commands above bypass main() entirely, so Bun-routed
124
+ # invocations were invisible to usage analytics. Fire it here, before
125
+ # the exec, so it covers every Bun command exactly once (no
126
+ # double-count: the bash route still emits its own copy in main()).
127
+ # Fire-and-forget, backgrounded, opt-out honored by loki_telemetry
128
+ # itself (LOKI_TELEMETRY_DISABLED / DO_NOT_TRACK). The command token is
129
+ # the subcommand name only -- never args, flags, or paths.
130
+ if command -v curl &>/dev/null && [ -f "$REPO_ROOT/autonomy/telemetry.sh" ]; then
131
+ ( SCRIPT_DIR="$REPO_ROOT/autonomy"; source "$SCRIPT_DIR/telemetry.sh" 2>/dev/null && loki_telemetry "cli_command" "command=${1:-}" 2>/dev/null ) &
132
+ disown 2>/dev/null || true
133
+ fi
120
134
  exec bun "$BUN_CLI" "$@"
121
135
  ;;
122
136
  *)
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "7.8.0"
10
+ __version__ = "7.8.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/). Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v7.8.0
5
+ **Version:** v7.8.2
6
6
 
7
7
  ---
8
8
 
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var _7=Object.defineProperty;var I7=(K)=>K;function P7(K,$){this[K]=I7.bind(null,$)}var v=(K,$)=>{for(var Q in $)_7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:P7.bind($,Q)})};var w=(K,$)=>()=>(K&&($=K(K=0)),$);var t=import.meta.require;var e1={};v(e1,{lokiDir:()=>L,homeLokiDir:()=>k1,findRepoRootForVersion:()=>S1,REPO_ROOT:()=>p});import{resolve as u,dirname as N1}from"path";import{fileURLToPath as L7}from"url";import{existsSync as J1}from"fs";import{homedir as R7}from"os";function E7(){let K=i1;for(let $=0;$<6;$++){if(J1(u(K,"VERSION"))&&J1(u(K,"autonomy/run.sh")))return K;let Q=N1(K);if(Q===K)break;K=Q}return u(i1,"..","..","..")}function S1(K){let $=K;for(let Q=0;Q<6;Q++){if(J1(u($,"VERSION"))&&J1(u($,"autonomy/run.sh")))return $;let X=N1($);if(X===$)break;$=X}return u(K,"..","..","..")}function L(){return process.env.LOKI_DIR??u(process.cwd(),".loki")}function k1(){return u(R7(),".loki")}var i1,p;var g=w(()=>{i1=N1(L7(import.meta.url));p=E7()});import{readFileSync as w7}from"fs";import{resolve as x7,dirname as F7}from"path";import{fileURLToPath as N7}from"url";function G1(){if(o!==null)return o;let K="7.8.0";if(typeof K==="string"&&K.length>0)return o=K,o;try{let $=F7(N7(import.meta.url)),Q=S1($);o=w7(x7(Q,"VERSION"),"utf-8").trim()}catch{o="unknown"}return o}var o=null;var C1=w(()=>{g()});var $0={};v($0,{runOrThrow:()=>S7,run:()=>C,commandVersion:()=>C7,commandExists:()=>b,ShellError:()=>D1});async function C(K,$={}){let Q=Bun.spawn({cmd:[...K],stdout:"pipe",stderr:"pipe",env:$.env?{...process.env,...$.env}:process.env,cwd:$.cwd}),X,Z;if($.timeoutMs&&$.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},$.timeoutMs);try{let[W,z,q]=await Promise.all([new Response(Q.stdout).text(),new Response(Q.stderr).text(),Q.exited]);return{stdout:W,stderr:z,exitCode:q}}finally{if(X)clearTimeout(X);if(Z)clearTimeout(Z)}}async function S7(K,$={}){let Q=await C(K,$);if(Q.exitCode!==0)throw new D1(`command failed (${Q.exitCode}): ${K.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function b(K){let $=k7(K),Q=await C(["sh","-c",`command -v ${$}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function k7(K){if(!/^[A-Za-z0-9._/-]+$/.test(K))throw Error(`refused to shell-escape suspect token: ${K}`);return K}async function C7(K,$="--version"){if(!await b(K))return null;let X=await C([K,$],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var D1;var n=w(()=>{D1=class D1 extends Error{message;exitCode;stdout;stderr;constructor(K,$,Q,X){super(K);this.message=K;this.exitCode=$;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function c(K){return D7?"":K}var D7,F,y,N,A6,A,D,S,H;var a=w(()=>{D7=(process.env.NO_COLOR??"").length>0;F=c("\x1B[0;31m"),y=c("\x1B[0;32m"),N=c("\x1B[1;33m"),A6=c("\x1B[0;34m"),A=c("\x1B[0;36m"),D=c("\x1B[1m"),S=c("\x1B[2m"),H=c("\x1B[0m")});import{existsSync as c7}from"fs";async function i(){if(Z1!==void 0)return Z1;let K="/opt/homebrew/bin/python3.12";if(c7(K))return Z1=K,K;let $=await b("python3.12");if($)return Z1=$,$;let Q=await b("python3");return Z1=Q,Q}async function s(K,$={}){let Q=await i();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return C([Q,"-c",K],$)}var Z1;var z1=w(()=>{n()});var G0={};v(G0,{runStatus:()=>X5});import{existsSync as k,readFileSync as K1,readdirSync as W0,statSync as H0}from"fs";import{resolve as R,basename as a7}from"path";import{homedir as s7}from"os";async function t7(){if(await b("jq"))return!0;return process.stdout.write(`${F}Error: jq is required but not installed.${H}
2
+ var _7=Object.defineProperty;var I7=(K)=>K;function P7(K,$){this[K]=I7.bind(null,$)}var v=(K,$)=>{for(var Q in $)_7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:P7.bind($,Q)})};var w=(K,$)=>()=>(K&&($=K(K=0)),$);var t=import.meta.require;var e1={};v(e1,{lokiDir:()=>L,homeLokiDir:()=>k1,findRepoRootForVersion:()=>S1,REPO_ROOT:()=>p});import{resolve as u,dirname as N1}from"path";import{fileURLToPath as L7}from"url";import{existsSync as J1}from"fs";import{homedir as R7}from"os";function E7(){let K=i1;for(let $=0;$<6;$++){if(J1(u(K,"VERSION"))&&J1(u(K,"autonomy/run.sh")))return K;let Q=N1(K);if(Q===K)break;K=Q}return u(i1,"..","..","..")}function S1(K){let $=K;for(let Q=0;Q<6;Q++){if(J1(u($,"VERSION"))&&J1(u($,"autonomy/run.sh")))return $;let X=N1($);if(X===$)break;$=X}return u(K,"..","..","..")}function L(){return process.env.LOKI_DIR??u(process.cwd(),".loki")}function k1(){return u(R7(),".loki")}var i1,p;var g=w(()=>{i1=N1(L7(import.meta.url));p=E7()});import{readFileSync as w7}from"fs";import{resolve as x7,dirname as F7}from"path";import{fileURLToPath as N7}from"url";function G1(){if(o!==null)return o;let K="7.8.2";if(typeof K==="string"&&K.length>0)return o=K,o;try{let $=F7(N7(import.meta.url)),Q=S1($);o=w7(x7(Q,"VERSION"),"utf-8").trim()}catch{o="unknown"}return o}var o=null;var C1=w(()=>{g()});var $0={};v($0,{runOrThrow:()=>S7,run:()=>C,commandVersion:()=>C7,commandExists:()=>b,ShellError:()=>D1});async function C(K,$={}){let Q=Bun.spawn({cmd:[...K],stdout:"pipe",stderr:"pipe",env:$.env?{...process.env,...$.env}:process.env,cwd:$.cwd}),X,Z;if($.timeoutMs&&$.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},$.timeoutMs);try{let[W,z,q]=await Promise.all([new Response(Q.stdout).text(),new Response(Q.stderr).text(),Q.exited]);return{stdout:W,stderr:z,exitCode:q}}finally{if(X)clearTimeout(X);if(Z)clearTimeout(Z)}}async function S7(K,$={}){let Q=await C(K,$);if(Q.exitCode!==0)throw new D1(`command failed (${Q.exitCode}): ${K.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function b(K){let $=k7(K),Q=await C(["sh","-c",`command -v ${$}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function k7(K){if(!/^[A-Za-z0-9._/-]+$/.test(K))throw Error(`refused to shell-escape suspect token: ${K}`);return K}async function C7(K,$="--version"){if(!await b(K))return null;let X=await C([K,$],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var D1;var n=w(()=>{D1=class D1 extends Error{message;exitCode;stdout;stderr;constructor(K,$,Q,X){super(K);this.message=K;this.exitCode=$;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function c(K){return D7?"":K}var D7,F,y,N,A6,A,D,S,H;var a=w(()=>{D7=(process.env.NO_COLOR??"").length>0;F=c("\x1B[0;31m"),y=c("\x1B[0;32m"),N=c("\x1B[1;33m"),A6=c("\x1B[0;34m"),A=c("\x1B[0;36m"),D=c("\x1B[1m"),S=c("\x1B[2m"),H=c("\x1B[0m")});import{existsSync as c7}from"fs";async function i(){if(Z1!==void 0)return Z1;let K="/opt/homebrew/bin/python3.12";if(c7(K))return Z1=K,K;let $=await b("python3.12");if($)return Z1=$,$;let Q=await b("python3");return Z1=Q,Q}async function s(K,$={}){let Q=await i();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return C([Q,"-c",K],$)}var Z1;var z1=w(()=>{n()});var G0={};v(G0,{runStatus:()=>X5});import{existsSync as k,readFileSync as K1,readdirSync as W0,statSync as H0}from"fs";import{resolve as R,basename as a7}from"path";import{homedir as s7}from"os";async function t7(){if(await b("jq"))return!0;return process.stdout.write(`${F}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)
@@ -604,4 +604,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
604
604
  `),2}default:return process.stderr.write(`Unknown command: ${$}
605
605
  `),process.stderr.write(j7),2}}process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var Z6=await X6(Bun.argv.slice(2));process.exit(Z6);
606
606
 
607
- //# debugId=289BCE83EBB8514D64756E2164756E21
607
+ //# debugId=190D69DBDE66068E64756E2164756E21
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '7.8.0'
60
+ __version__ = '7.8.2'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "7.8.0",
3
+ "version": "7.8.2",
4
4
  "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).",
5
5
  "keywords": [
6
6
  "agent",