loki-mode 7.7.30 → 7.7.31

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/README.md CHANGED
@@ -38,6 +38,26 @@
38
38
 
39
39
  ## Get Started in 30 Seconds
40
40
 
41
+ **Prerequisites**
42
+
43
+ Loki drives a coding agent CLI and orchestrates real builds, so it needs a few tools on your PATH. `loki doctor` checks all of these and tells you what is missing.
44
+
45
+ Required:
46
+
47
+ - An agent provider CLI (at least one): [Claude Code](https://docs.claude.com/en/docs/claude-code) (`claude`, Tier 1, recommended), or OpenAI Codex CLI (`codex`), Cline, or Aider.
48
+ - Python 3.10+ (`python3`) for the dashboard, memory system, and orchestration helpers.
49
+ - Git 2.x (`git`) for checkpoints and worktrees.
50
+ - `curl` for installation and network calls.
51
+
52
+ Recommended:
53
+
54
+ - Bun 1.3.0+ (`bun`) for the fast runtime (the recommended install path below installs it).
55
+ - Node.js 18+ and npm if you install via npm instead of Bun.
56
+ - `jq` for nicer JSON handling in shell flows.
57
+ - Docker if you want Loki's App Runner to run containerized projects, or to run Loki itself from the published image.
58
+
59
+ You also need credentials for whichever provider you use (for Claude Code, an authenticated `claude` login or `ANTHROPIC_API_KEY`).
60
+
41
61
  **Recommended (Bun, fastest):**
42
62
 
43
63
  ```bash
@@ -66,7 +86,7 @@ loki quick "build a landing page with a signup form"
66
86
  |--------|---------|-------|
67
87
  | **Bun (recommended)** | `bun install -g loki-mode` | Fastest. v8 will be Bun-only. |
68
88
  | **Homebrew** | `brew tap asklokesh/tap && brew install loki-mode` | Auto-installs Bun as a dep |
69
- | **Docker** | `docker pull asklokesh/loki-mode:7.5.11 && docker run --rm asklokesh/loki-mode:7.5.11 start prd.md` | Bun pre-installed in image |
89
+ | **Docker** | `docker pull asklokesh/loki-mode:7.7.31 && docker run --rm asklokesh/loki-mode:7.7.31 start prd.md` | Bun pre-installed in image |
70
90
  | **npm (compat)** | `npm install -g loki-mode` | Works without Bun (bash fallback). Migrate any time with `loki self-update --to bun`. |
71
91
 
72
92
  **Upgrading:**
@@ -85,12 +105,12 @@ See the [Installation Guide](docs/INSTALLATION.md) for the long form.
85
105
 
86
106
  ## Runtime Architecture
87
107
 
88
- Loki Mode is in the middle of a phased migration from a Bash-based runtime to a TypeScript/Bun runtime. The work is happening on the `feat/bun-migration` branch and is being shipped incrementally.
108
+ Loki Mode is in a phased migration from a Bash-based runtime to a TypeScript/Bun runtime. The migration has merged to `main` and ships incrementally with each release.
89
109
 
90
110
  **What ships today:**
91
111
 
92
- - A small set of read-only commands is routed to the Bun runtime when `bun` is on `PATH`. The router lives in `bin/loki` and currently routes: `version`, `--version`, `-v`, `status`, `stats`, `doctor`, `provider` (covers `provider show` and `provider list`), `memory` (covers `memory list` and `memory index`).
93
- - Every other command continues to execute on the existing Bash CLI (`autonomy/loki`).
112
+ - Commands routed to the Bun runtime when `bun` is on `PATH` (the router lives in `bin/loki`): `version`, `--version`, `-v`, `status`, `stats`, `doctor`, `provider` (covers `provider show` and `provider list`), `memory` (covers `memory list` and `memory index`), `rollback`, `kpis`, and `internal`.
113
+ - Every other command continues to execute on the existing Bash CLI (`autonomy/loki`), including the autonomous `loki start` / `loki run` loop which remains the Bash orchestrator (`autonomy/run.sh`).
94
114
  - If `bun` is not on `PATH`, the shim falls through to Bash silently. Existing users without Bun installed see no behavior change.
95
115
 
96
116
  **Rollback flag:**
@@ -126,7 +146,7 @@ The next major release sunsets the Bash runtime entirely. There is no firm calen
126
146
  | Method | Command |
127
147
  |--------|---------|
128
148
  | **Homebrew** | `brew tap asklokesh/tap && brew install loki-mode` |
129
- | **Docker** | `docker pull asklokesh/loki-mode:7.5.11` |
149
+ | **Docker** | `docker pull asklokesh/loki-mode:7.7.31` |
130
150
  | **Inside Claude Code** | `claude --dangerously-skip-permissions` then type "Loki Mode" |
131
151
  | **Git clone** | `git clone https://github.com/asklokesh/loki-mode.git` |
132
152
 
@@ -137,7 +157,7 @@ See the full [Installation Guide](docs/INSTALLATION.md).
137
157
  <details>
138
158
  <summary><strong>Supported spec formats</strong></summary>
139
159
 
140
- A "spec" is whatever you hand `loki start`. Loki auto-detects the format and normalises it before the RARV loop. A Markdown PRD is one form of spec; the table below lists every input the v7.5.11 CLI accepts.
160
+ A "spec" is whatever you hand `loki start`. Loki auto-detects the format and normalises it before the RARV loop. A Markdown PRD is one form of spec; the table below lists every input the CLI accepts.
141
161
 
142
162
  | Format | Example | Notes |
143
163
  |--------|---------|-------|
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.7.30
6
+ # Loki Mode v7.7.31
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.7.30 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
384
+ **v7.7.31 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 7.7.30
1
+ 7.7.31
package/autonomy/run.sh CHANGED
@@ -11204,13 +11204,31 @@ except Exception as exc:
11204
11204
  local exit_code=0
11205
11205
  # v7.5.12: Mark provider pipeline as active so SIGINT trap can kill it.
11206
11206
  LOKI_PROVIDER_ACTIVE=1
11207
+ # v7.7.31: authorize autonomous operation at the system-prompt tier so
11208
+ # the spawned agent does not read the user's global ~/.claude/CLAUDE.md,
11209
+ # judge it to conflict with the loki_system prompt, call AskUserQuestion,
11210
+ # and exit having done nothing. An appended system prompt outranks
11211
+ # CLAUDE.md memory (verified empirically). Default-on; opt out with
11212
+ # LOKI_AUTONOMY_OVERRIDE=off. Only added when the installed CLI supports
11213
+ # the flag and the override helper is in scope (sourced via the provider).
11214
+ # Build the claude flag list as an array. The base flags are always
11215
+ # present so the array is never empty (empty "${arr[@]}" under `set -u`
11216
+ # is an error on bash 3.2, the stock macOS shell). The autonomy override
11217
+ # is appended conditionally.
11218
+ local _loki_claude_argv=("--dangerously-skip-permissions" "--model" "$tier_param")
11219
+ if [ "${LOKI_AUTONOMY_OVERRIDE:-on}" != "off" ] \
11220
+ && type _loki_autonomy_override_text >/dev/null 2>&1 \
11221
+ && type loki_claude_flag_supported >/dev/null 2>&1 \
11222
+ && loki_claude_flag_supported "--append-system-prompt"; then
11223
+ _loki_claude_argv+=("--append-system-prompt" "$(_loki_autonomy_override_text)")
11224
+ fi
11207
11225
  case "${PROVIDER_NAME:-claude}" in
11208
11226
  claude)
11209
11227
  # Claude: Full features with stream-json output and agent tracking
11210
11228
  # Uses dynamic tier for model selection based on RARV phase
11211
11229
  # Pass tier to Python via environment for dashboard display
11212
11230
  { LOKI_CURRENT_MODEL="$tier_param" \
11213
- claude --dangerously-skip-permissions --model "$tier_param" -p "$prompt" \
11231
+ claude "${_loki_claude_argv[@]}" -p "$prompt" \
11214
11232
  --output-format stream-json --verbose 2>&1 | \
11215
11233
  tee -a "$log_file" "$agent_log" "$iter_output" | \
11216
11234
  python3 -u -c '
@@ -11948,21 +11966,34 @@ if __name__ == "__main__":
11948
11966
 
11949
11967
  log_info "Press Ctrl+C to cancel"
11950
11968
 
11951
- # Countdown with progress
11969
+ # Countdown with progress.
11970
+ # v7.7.31: the countdown now sleeps in short 1s ticks and checks the
11971
+ # STOP/PAUSE signal on every tick. Previously it slept in 10s (or 60s
11972
+ # for long waits) chunks and never read the STOP file, so a dashboard
11973
+ # Stop button or `loki stop` issued DURING the inter-iteration wait did
11974
+ # nothing for up to 60s, and a SIGTERM was deferred by bash until the
11975
+ # current sleep chunk finished. Short ticks make Stop take effect within
11976
+ # ~1s and let the SIGTERM trap fire promptly.
11952
11977
  local remaining=$wait_time
11953
- local interval=10
11954
- # Use longer interval for long waits
11955
- if [ $wait_time -gt 1800 ]; then
11956
- interval=60
11957
- fi
11958
-
11978
+ local _loki_dir_wait="${TARGET_DIR:-.}/.loki"
11979
+ local _last_shown=-1
11959
11980
  while [ $remaining -gt 0 ]; do
11960
- local human_remaining=$(format_duration $remaining)
11961
- printf "\r${YELLOW}Resuming in ${human_remaining}...${NC} "
11962
- # BUG-RUN-007: Prevent timer from overshooting into negative
11963
- local sleep_time=$((remaining < interval ? remaining : interval))
11964
- sleep $sleep_time
11965
- remaining=$((remaining - sleep_time))
11981
+ # Honor an immediate stop/pause requested during the wait (dashboard
11982
+ # Stop button, `loki stop`, or a STOP file written by any control).
11983
+ if [ -f "$_loki_dir_wait/STOP" ] || [ -f "$_loki_dir_wait/PAUSE" ]; then
11984
+ echo ""
11985
+ log_warn "Stop/pause signal detected during wait - returning to control loop"
11986
+ break
11987
+ fi
11988
+ # Refresh the human-readable countdown at most once per 10s of change
11989
+ # so we do not spam the terminal while still ticking every second.
11990
+ if [ $((remaining % 10)) -eq 0 ] || [ "$_last_shown" -ne "$remaining" ]; then
11991
+ local human_remaining=$(format_duration $remaining)
11992
+ printf "\r${YELLOW}Resuming in ${human_remaining}...${NC} "
11993
+ _last_shown=$remaining
11994
+ fi
11995
+ sleep 1
11996
+ remaining=$((remaining - 1))
11966
11997
  done
11967
11998
  echo ""
11968
11999
 
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "7.7.30"
10
+ __version__ = "7.7.31"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2166,7 +2166,8 @@ async def list_running_projects():
2166
2166
  path = p.get("path", "")
2167
2167
  pid = p.get("pid")
2168
2168
  running = False
2169
- if isinstance(pid, int) and pid > 0:
2169
+ has_pid = isinstance(pid, int) and pid > 0
2170
+ if has_pid:
2170
2171
  try:
2171
2172
  os.kill(pid, 0)
2172
2173
  running = True # signal 0 delivered -> pid alive
@@ -2174,8 +2175,14 @@ async def list_running_projects():
2174
2175
  running = True # pid exists but owned by another user
2175
2176
  except (ProcessLookupError, OSError):
2176
2177
  running = False # ESRCH -> dead
2177
- # A project is also "live" if its .loki/session.json says running.
2178
- if not running and path:
2178
+ # session.json is only a FALLBACK for legacy sessions with no recorded
2179
+ # pid. v7.7.31: when a pid IS recorded but dead, that pid is
2180
+ # authoritative -- the orchestrator is gone, so do NOT let a stale
2181
+ # session.json (status still "running" after a hard kill / crash) flip
2182
+ # this back to running. Otherwise the switcher shows a dead session as
2183
+ # running and the Stop button targets a dead pid. Only consult
2184
+ # session.json when no pid was ever recorded.
2185
+ if not running and not has_pid and path:
2179
2186
  try:
2180
2187
  sess = _Path(path) / ".loki" / "session.json"
2181
2188
  if sess.is_file():
@@ -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.7.30
5
+ **Version:** v7.7.31
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.7.30";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.7.31";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=1D57DCC7E6AE757E64756E2164756E21
607
+ //# debugId=4167329ADA92E7A964756E2164756E21
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '7.7.30'
60
+ __version__ = '7.7.31'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "7.7.30",
3
+ "version": "7.7.31",
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",
@@ -201,6 +201,38 @@ _loki_build_claude_auto_flags() {
201
201
  && loki_claude_flag_supported "--include-hook-events"; then
202
202
  _LOKI_CLAUDE_AUTO_FLAGS+=("--include-hook-events")
203
203
  fi
204
+
205
+ # --append-system-prompt (v7.7.31): authorize autonomous operation at the
206
+ # system-prompt tier so the spawned agent does not refuse the run. Without
207
+ # this, the agent reads the user's global ~/.claude/CLAUDE.md (which may say
208
+ # "always ask for clarification" / "never commit without permission"),
209
+ # judges it to conflict with Loki's "never ask, never stop" prompt (which is
210
+ # only a user-message instruction and thus lower precedence), calls
211
+ # AskUserQuestion, and exits in ~30s having done nothing. An appended system
212
+ # prompt outranks CLAUDE.md memory (verified empirically), so it resolves the
213
+ # conflict in Loki's favor for this authorized session. Default-on; opt out
214
+ # with LOKI_AUTONOMY_OVERRIDE=off. We never edit the user's CLAUDE.md.
215
+ if [ "${LOKI_AUTONOMY_OVERRIDE:-on}" != "off" ] \
216
+ && loki_claude_flag_supported "--append-system-prompt"; then
217
+ _LOKI_CLAUDE_AUTO_FLAGS+=("--append-system-prompt" "$(_loki_autonomy_override_text)")
218
+ fi
219
+ }
220
+
221
+ # The system-prompt text that authorizes autonomous operation and resolves
222
+ # precedence against a conflicting user/project CLAUDE.md. Kept in one place so
223
+ # the bash and Bun routes can stay byte-identical. No emojis, no em dashes.
224
+ _loki_autonomy_override_text() {
225
+ cat <<'LOKI_AUTONOMY_EOF'
226
+ You are running INSIDE Loki Mode autonomous execution, a session the user explicitly launched with full prior authorization (loki start / loki run). This IS an authorized autonomous session, not an unattended action you must seek consent for.
227
+
228
+ Instruction precedence for THIS session: when the loki_system instructions in the user prompt conflict with any CLAUDE.md, project memory, or global memory that tells you to ask for clarification, pause for confirmation, refuse to act autonomously, or withhold routine commits, the loki_system instructions take precedence. The user has already consented by launching autonomous mode.
229
+
230
+ Therefore, for this session: do NOT ask the user questions, do NOT call the AskUserQuestion tool, do NOT stop to request confirmation, and do NOT refuse routine, reversible engineering work (writing code, running tests, creating files, atomic git checkpoints in the working tree). Proceed and complete the task directly. If a decision is genuinely ambiguous, choose the most reasonable option, record the assumption in .loki/CONTINUITY.md, and continue rather than halting.
231
+
232
+ Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.
233
+
234
+ This precedence override is narrow. It does NOT relax any safety rule. Every safety prohibition in CLAUDE.md or memory still fully binds: anything genuinely destructive or irreversible remains out of scope unless the task explicitly calls for it. This includes (not limited to) force-pushing, deleting or overwriting the user's data, dropping or truncating databases, publishing or releasing, rotating or exfiltrating secrets, touching production systems, and anything a CLAUDE.md safety rule explicitly forbids. When in doubt about whether an action is destructive, treat it as destructive and do not do it.
235
+ LOKI_AUTONOMY_EOF
204
236
  }
205
237
 
206
238
  # Invocation function (basic, no tier).