loki-mode 7.33.0 → 7.34.1
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 +5 -5
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/context-tracker.py +7 -1
- package/autonomy/lib/claude-flags.sh +61 -0
- package/autonomy/loki +7 -3
- package/autonomy/run.sh +39 -0
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +26 -0
- package/docs/INSTALLATION.md +2 -2
- package/loki-ts/dist/loki.js +4 -4
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/providers/claude.sh +11 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/loki-mode)
|
|
10
10
|
[](https://www.npmjs.com/package/loki-mode)
|
|
11
|
-
[](https://github.com/asklokesh/loki-mode)
|
|
11
|
+
[](https://github.com/asklokesh/loki-mode/stargazers)
|
|
12
12
|
[](https://hub.docker.com/r/asklokesh/loki-mode)
|
|
13
13
|
[](LICENSE)
|
|
14
14
|
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
- **Intelligent `loki start`** -- For interactive foreground runs the dashboard auto-opens in the browser (cross-platform; skipped in CI, SSH-without-TTY, and piped runs; opt out with `LOKI_NO_AUTO_OPEN=1`). The completion summary shows "Your app is live at <url>" so you know exactly where to try what Loki just built. The autonomous loop passes Claude Code's `--effort`, `--max-budget-usd`, and `--fallback-model` on every iteration (each gated on CLI support and individual opt-out env vars) for better long-run unattended execution (v7.25.0).
|
|
37
37
|
- **Cross-project memory** -- Episodic/semantic/procedural memory with vector search; knowledge learned on one project surfaces on the next (v5.15.0+, see `memory/engine.py`)
|
|
38
38
|
- **Self-hosted and private** -- Your keys, your infrastructure, no data leaves your network
|
|
39
|
-
- **Legacy system healing** -- `loki heal` archaeology/stabilize/isolate/modernize/validate phases (v6.67.0, see `skills/healing.md`)
|
|
39
|
+
- **Legacy system healing** -- `loki modernize heal` archaeology/stabilize/isolate/modernize/validate phases (v6.67.0, see `skills/healing.md`)
|
|
40
40
|
- **MCP server** -- 34 tools (including ChromaDB code search) plus 3 resources and 2 prompts (`mcp/server.py`, with magic tools registered from `mcp/magic_tools.py` and the managed-memory tool from `mcp/managed_tools.py`). Of the 34, 33 are always available; `loki_memory_redact` is registered but only succeeds when `LOKI_MANAGED_AGENTS=true` and `LOKI_MANAGED_MEMORY=true`. Launch with `loki mcp` (bootstraps the Python MCP SDK on first run).
|
|
41
41
|
- **Full-stack output** -- Source code, tests, Docker Compose stacks (multi-service with healthchecks), CI/CD pipelines, audit logs
|
|
42
42
|
- **Provider-agnostic** -- runs on Claude, Codex, Cline, or Aider with automatic failover (`loki-ts/src/runner/providers.ts`); no vendor lock-in. Gemini CLI deprecated v7.5.18; Antigravity CLI coming soon.
|
|
@@ -366,17 +366,17 @@ Status legend: "E2E-verified" means we run real spec-to-code builds on it oursel
|
|
|
366
366
|
|---------|-------------|
|
|
367
367
|
| `loki start [PRD]` | Start with optional PRD file (also accepts an issue ref; replaces deprecated `loki run`). Auto-opens the dashboard in the browser for interactive runs and passes native `--effort`/`--max-budget-usd`/`--fallback-model` for resilience (v7.25.0) |
|
|
368
368
|
| `loki stop` | Stop execution |
|
|
369
|
-
| `loki heal <path>` | Legacy system healing (archaeology, stabilize, isolate, modernize, validate -- v6.67.0) |
|
|
369
|
+
| `loki modernize heal <path>` | Legacy system healing (archaeology, stabilize, isolate, modernize, validate -- v6.67.0; was: `loki heal`) |
|
|
370
370
|
| `loki pause` / `resume` | Pause/resume after current session |
|
|
371
371
|
| `loki status` | Show current status |
|
|
372
372
|
| `loki dashboard` | Open web dashboard |
|
|
373
|
-
| `loki preview`
|
|
373
|
+
| `loki preview` | Print running app URL and open in browser (Live App Preview, v7.24.0; was: `loki open`) |
|
|
374
374
|
| `loki web` | Launch Purple Lab web UI |
|
|
375
375
|
| `loki doctor` | Check environment and dependencies |
|
|
376
376
|
| `loki plan [PRD]` | Pre-execution analysis: complexity, cost, iterations |
|
|
377
377
|
| `loki review [--staged\|--diff]` | AI-powered code review with severity filtering |
|
|
378
378
|
| `loki test [--file\|--dir\|--changed]` | AI test generation (8 languages, 9 frameworks) |
|
|
379
|
-
| `loki onboard [path]` | Project analysis and CLAUDE.md generation |
|
|
379
|
+
| `loki analyze onboard [path]` | Project analysis and CLAUDE.md generation (was: `loki onboard`) |
|
|
380
380
|
| `loki import` | Import GitHub issues as tasks |
|
|
381
381
|
| `loki ci` | CI/CD quality gate integration |
|
|
382
382
|
| `loki failover` | Cross-provider auto-failover management |
|
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.
|
|
6
|
+
# Loki Mode v7.34.1
|
|
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.
|
|
401
|
+
**v7.34.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.34.1
|
|
@@ -304,7 +304,13 @@ def update_tracking(loki_dir, iteration, window_size, provider="claude",
|
|
|
304
304
|
if result["new_offset"] == last_offset:
|
|
305
305
|
return # Nothing new
|
|
306
306
|
|
|
307
|
-
# Update session ID and offset
|
|
307
|
+
# Update session ID and offset.
|
|
308
|
+
# v7.34.0 Phase 1: when LOKI_SESSION_STAMP=1, run.sh passes a
|
|
309
|
+
# per-iteration --session-id, so claude names the JSONL after that uuid
|
|
310
|
+
# and jsonl_path.stem is that uuid rather than a claude-minted one. This
|
|
311
|
+
# is just a string label for the tracking record; any value (uuid or
|
|
312
|
+
# otherwise) is fine here, so no reconcile/parse is needed and there is
|
|
313
|
+
# no crash path from the id differing.
|
|
308
314
|
tracking["session_id"] = jsonl_path.stem
|
|
309
315
|
tracking["updated_at"] = datetime.now(timezone.utc).isoformat()
|
|
310
316
|
offset_file.write_text(str(result["new_offset"]))
|
|
@@ -226,3 +226,64 @@ loki_review_guard_denylist() {
|
|
|
226
226
|
# global-flag-before-subcommand evasion of the bare git-mutation rules.
|
|
227
227
|
printf '%s' "Edit,Write,NotebookEdit,Bash(git commit:*),Bash(git reset:*),Bash(git push:*),Bash(git checkout:*),Bash(git clean:*),Bash(git rm:*),Bash(git stash:*),Bash(git -C:*),Bash(git --git-dir:*),Bash(git -c:*)"
|
|
228
228
|
}
|
|
229
|
+
|
|
230
|
+
# ---------- v7.34.0 Claude session-id stamping (Phase 1, correlation-only) -----
|
|
231
|
+
# Derive a deterministic per-run UUID from the existing trust-run-id so the same
|
|
232
|
+
# run always maps to the same claude session UUID, and the bash + Bun routes
|
|
233
|
+
# produce BYTE-IDENTICAL uuids for the same run id. We use RFC-4122 UUIDv5
|
|
234
|
+
# (SHA-1 over a stable namespace + the name). The namespace below is a fixed,
|
|
235
|
+
# Loki-specific constant; never change it (changing it re-keys every run's uuid).
|
|
236
|
+
# The TS mirror is loki-ts/src/providers/claude_flags.ts claudeSessionUuid().
|
|
237
|
+
#
|
|
238
|
+
# Phase 1 is correlation-only: the uuid is written to a metadata file and (only
|
|
239
|
+
# when LOKI_SESSION_STAMP=1) emitted as a PER-ITERATION --session-id on the main
|
|
240
|
+
# loop. It NEVER pins one id across the run (that is Phase 2 continuity, which
|
|
241
|
+
# would accumulate transcript and compete with Loki's own injected memory).
|
|
242
|
+
LOKI_CLAUDE_SESSION_NS="b6f3c7a2-9d41-5e8b-9c2a-3f7d6e1a4b50"
|
|
243
|
+
|
|
244
|
+
# UUIDv5 over the Loki session namespace + an arbitrary name string. Pure
|
|
245
|
+
# (stdout only), deterministic, no side effects. Uses python3 (always present on
|
|
246
|
+
# the bash route; every other helper here already depends on it). Emits empty on
|
|
247
|
+
# any failure so the caller degrades to metadata-only without breaking the run.
|
|
248
|
+
_loki_uuid5() {
|
|
249
|
+
local name="${1:-}"
|
|
250
|
+
[ -z "$name" ] && return 0
|
|
251
|
+
command -v python3 >/dev/null 2>&1 || return 0
|
|
252
|
+
LOKI_CLAUDE_SESSION_NS="$LOKI_CLAUDE_SESSION_NS" _LOKI_UUID5_NAME="$name" \
|
|
253
|
+
python3 - <<'UUID5_PY' 2>/dev/null || true
|
|
254
|
+
import os, uuid
|
|
255
|
+
ns = uuid.UUID(os.environ["LOKI_CLAUDE_SESSION_NS"])
|
|
256
|
+
print(uuid.uuid5(ns, os.environ["_LOKI_UUID5_NAME"]))
|
|
257
|
+
UUID5_PY
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
# The stable per-run claude session UUID: UUIDv5 of the trust-run-id. Same run
|
|
261
|
+
# id -> same uuid, on every route. Emits empty when no run id is resolvable.
|
|
262
|
+
_loki_claude_session_uuid() {
|
|
263
|
+
local run_id="${1:-${LOKI_TRUST_RUN_ID:-}}"
|
|
264
|
+
[ -z "$run_id" ] && return 0
|
|
265
|
+
_loki_uuid5 "$run_id"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# The PER-ITERATION session UUID emitted on the main loop when LOKI_SESSION_STAMP=1.
|
|
269
|
+
# UUIDv5 of "<run-id>:<iteration>", so every iteration gets a DISTINCT, deterministic
|
|
270
|
+
# id. This is deliberately NOT the stable per-run uuid: a single pinned id reused
|
|
271
|
+
# across iterations would make claude RESUME (accumulate transcript), which is
|
|
272
|
+
# Phase 2 continuity, explicitly out of scope here. Distinct-per-iteration keeps
|
|
273
|
+
# each iteration a fresh stateless session (byte-identical default behavior to
|
|
274
|
+
# v7.33 except for the added correlation flag).
|
|
275
|
+
_loki_claude_iteration_session_uuid() {
|
|
276
|
+
local run_id="${1:-${LOKI_TRUST_RUN_ID:-}}"
|
|
277
|
+
local iteration="${2:-${ITERATION_COUNT:-0}}"
|
|
278
|
+
[ -z "$run_id" ] && return 0
|
|
279
|
+
_loki_uuid5 "${run_id}:${iteration}"
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
# Predicate: emit the per-iteration --session-id ARGV flag? CONSERVATIVE DEFAULT
|
|
283
|
+
# is OFF (metadata-file-only) so the default claude argv stays byte-identical to
|
|
284
|
+
# v7.33 (the UX-monotonicity requirement). Opt IN with LOKI_SESSION_STAMP=1.
|
|
285
|
+
# Gated on CLI support so an older claude degrades gracefully (no flag emitted).
|
|
286
|
+
loki_session_stamp_enabled() {
|
|
287
|
+
[ "${LOKI_SESSION_STAMP:-0}" = "1" ] || return 1
|
|
288
|
+
loki_claude_flag_supported "--session-id"
|
|
289
|
+
}
|
package/autonomy/loki
CHANGED
|
@@ -685,7 +685,7 @@ show_help() {
|
|
|
685
685
|
echo " modernize [cmd] Legacy modernization: heal|migrate"
|
|
686
686
|
echo ""
|
|
687
687
|
echo "Config:"
|
|
688
|
-
echo " config [cmd] Manage configuration
|
|
688
|
+
echo " config [cmd] Manage configuration (show|init|edit|path|set|get)"
|
|
689
689
|
echo " doctor [--json] Check system prerequisites and skill symlinks"
|
|
690
690
|
echo ""
|
|
691
691
|
echo " version Show version"
|
|
@@ -2888,8 +2888,8 @@ cmd_status() {
|
|
|
2888
2888
|
fi
|
|
2889
2889
|
|
|
2890
2890
|
echo ""
|
|
2891
|
-
echo -e "${DIM} Tip: loki context show - detailed token breakdown${NC}"
|
|
2892
|
-
echo -e "${DIM} Tip: loki code overview
|
|
2891
|
+
echo -e "${DIM} Tip: loki analyze context show - detailed token breakdown${NC}"
|
|
2892
|
+
echo -e "${DIM} Tip: loki analyze code overview - codebase intelligence${NC}"
|
|
2893
2893
|
}
|
|
2894
2894
|
|
|
2895
2895
|
# JSON output for loki status --json
|
|
@@ -8697,8 +8697,12 @@ cmd_api() {
|
|
|
8697
8697
|
|
|
8698
8698
|
# Parse --host/--port (the old code ignored them, so `loki serve --port X`
|
|
8699
8699
|
# silently bound 57374 and `--host 0.0.0.0` was dropped).
|
|
8700
|
+
# A trailing --help/-h on any subcommand (e.g. `loki api start --help`)
|
|
8701
|
+
# short-circuits to the help text instead of being swallowed and starting
|
|
8702
|
+
# the server (#574).
|
|
8700
8703
|
while [ $# -gt 0 ]; do
|
|
8701
8704
|
case "$1" in
|
|
8705
|
+
--help|-h) subcommand="help"; break ;;
|
|
8702
8706
|
--port) port="${2:-$port}"; shift 2 ;;
|
|
8703
8707
|
--port=*) port="${1#*=}"; shift ;;
|
|
8704
8708
|
--host) host="${2:-$host}"; shift 2 ;;
|
package/autonomy/run.sh
CHANGED
|
@@ -12324,6 +12324,26 @@ except Exception:
|
|
|
12324
12324
|
LOKI_TRUST_RUN_ID="$(_loki_trust_run_id --new)"
|
|
12325
12325
|
export LOKI_TRUST_RUN_ID
|
|
12326
12326
|
record_trust_event_bash "run_start" "start_sha=${_LOKI_RUN_START_SHA:-}" 2>/dev/null || true
|
|
12327
|
+
|
|
12328
|
+
# v7.34.0 Phase 1 (correlation-only): write a deterministic claude
|
|
12329
|
+
# session UUID derived from the trust-run-id to .loki/state/claude-session.json.
|
|
12330
|
+
# mode is "stamp" (Phase 1); Phase 2 continuity is a separate, opt-in arc.
|
|
12331
|
+
# Best-effort: the helper is in scope via providers/claude.sh sourcing
|
|
12332
|
+
# claude-flags.sh; if absent (e.g. non-claude provider, no python3) we
|
|
12333
|
+
# skip silently and never fail the run. The dashboard reads this file to
|
|
12334
|
+
# surface it for correlating the run with its Claude session JSONL.
|
|
12335
|
+
if type _loki_claude_session_uuid >/dev/null 2>&1; then
|
|
12336
|
+
local _loki_session_uuid
|
|
12337
|
+
_loki_session_uuid="$(_loki_claude_session_uuid "$LOKI_TRUST_RUN_ID")"
|
|
12338
|
+
if [ -n "$_loki_session_uuid" ]; then
|
|
12339
|
+
local _loki_session_created
|
|
12340
|
+
_loki_session_created="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
12341
|
+
mkdir -p ".loki/state" 2>/dev/null || true
|
|
12342
|
+
printf '{"run_id":"%s","claude_session_uuid":"%s","mode":"stamp","created_at":"%s"}\n' \
|
|
12343
|
+
"$LOKI_TRUST_RUN_ID" "$_loki_session_uuid" "$_loki_session_created" \
|
|
12344
|
+
> ".loki/state/claude-session.json" 2>/dev/null || true
|
|
12345
|
+
fi
|
|
12346
|
+
fi
|
|
12327
12347
|
fi
|
|
12328
12348
|
|
|
12329
12349
|
# Notify dashboard of active project directory (for AI Chat cross-directory usage)
|
|
@@ -12719,6 +12739,20 @@ except Exception as exc:
|
|
|
12719
12739
|
&& loki_claude_flag_supported "--include-partial-messages"; then
|
|
12720
12740
|
_loki_claude_argv+=("--include-partial-messages")
|
|
12721
12741
|
fi
|
|
12742
|
+
# v7.34.0 Phase 1 (correlation-only): per-iteration --session-id. OPT-IN
|
|
12743
|
+
# via LOKI_SESSION_STAMP=1 (CONSERVATIVE DEFAULT is OFF so the default
|
|
12744
|
+
# argv stays byte-identical to v7.33 -- the UX-monotonicity requirement).
|
|
12745
|
+
# The id is a DISTINCT, deterministic UUIDv5 of "<run-id>:<iteration>",
|
|
12746
|
+
# never one pinned id across the run: a reused id would make claude RESUME
|
|
12747
|
+
# and accumulate transcript (Phase 2 continuity, out of scope). This keeps
|
|
12748
|
+
# each iteration a fresh stateless session while making its ~/.claude
|
|
12749
|
+
# JSONL name predictable for dashboard correlation. Gated on CLI support.
|
|
12750
|
+
if type loki_session_stamp_enabled >/dev/null 2>&1 \
|
|
12751
|
+
&& loki_session_stamp_enabled; then
|
|
12752
|
+
local _loki_iter_session_uuid
|
|
12753
|
+
_loki_iter_session_uuid="$(_loki_claude_iteration_session_uuid "${LOKI_TRUST_RUN_ID:-}" "$ITERATION_COUNT")"
|
|
12754
|
+
[ -n "$_loki_iter_session_uuid" ] && _loki_claude_argv+=("--session-id" "$_loki_iter_session_uuid")
|
|
12755
|
+
fi
|
|
12722
12756
|
# ---- Bash<->Bun invocation-flag convergence ledger (v7.25.0) ----------
|
|
12723
12757
|
# The fixture corpus covers build_prompt/stats output, NOT this claude
|
|
12724
12758
|
# argv, so drift here is invisible to parity tests. Keep this ledger
|
|
@@ -12729,8 +12763,13 @@ except Exception as exc:
|
|
|
12729
12763
|
# today.
|
|
12730
12764
|
# Bash argv (canonical, live): --dangerously-skip-permissions --model M
|
|
12731
12765
|
# [--append-system-prompt] [--setting-sources] [--include-partial-messages]
|
|
12766
|
+
# [--session-id UUID (only when LOKI_SESSION_STAMP=1, v7.34.0)]
|
|
12732
12767
|
# [--effort] [--max-budget-usd] [--fallback-model] -p PROMPT
|
|
12733
12768
|
# --output-format stream-json --verbose
|
|
12769
|
+
# v7.34.0: --session-id is emitted ONLY on this MAIN loop, only under
|
|
12770
|
+
# LOKI_SESSION_STAMP=1, as a per-iteration distinct UUIDv5; the DEFAULT
|
|
12771
|
+
# argv (knob unset) is byte-identical to v7.33. Bun mirror lives in
|
|
12772
|
+
# loki-ts/src/runner/providers.ts (sessionStampArgv).
|
|
12734
12773
|
# Bun buildAutoFlags also emits: --exclude-dynamic-system-prompt-sections
|
|
12735
12774
|
# (cost-only), --mcp-config (bash gets MCP via --setting-sources +
|
|
12736
12775
|
# .mcp.json discovery; a how-difference, likely behavior-equivalent),
|
package/dashboard/__init__.py
CHANGED
package/dashboard/server.py
CHANGED
|
@@ -387,6 +387,11 @@ class StatusResponse(BaseModel):
|
|
|
387
387
|
mode: str = ""
|
|
388
388
|
provider: str = "claude"
|
|
389
389
|
current_task: str = ""
|
|
390
|
+
# v7.34.0 Phase 1: the deterministic per-run Claude session UUID derived from
|
|
391
|
+
# the trust-run-id (read from .loki/state/claude-session.json). Surfaced so a
|
|
392
|
+
# user can correlate the run with its Claude session JSONL (in ~/.claude/projects). Empty when
|
|
393
|
+
# the run predates this field or no claude session was stamped.
|
|
394
|
+
claude_session_id: str = ""
|
|
390
395
|
# Concurrent sessions (v6.4.0)
|
|
391
396
|
sessions: list[SessionInfo] = []
|
|
392
397
|
|
|
@@ -954,6 +959,26 @@ async def get_status() -> StatusResponse:
|
|
|
954
959
|
pending_tasks = 0
|
|
955
960
|
running_agents = 0
|
|
956
961
|
|
|
962
|
+
# v7.34.0 Phase 1: the deterministic per-run Claude session UUID, written at
|
|
963
|
+
# run-start by run.sh (correlation-only). Best-effort read; empty when the
|
|
964
|
+
# file is absent (run predates the field, or a non-claude provider).
|
|
965
|
+
claude_session_id = ""
|
|
966
|
+
claude_session_file = loki_dir / "state" / "claude-session.json"
|
|
967
|
+
if claude_session_file.exists():
|
|
968
|
+
try:
|
|
969
|
+
_cs = _safe_json_read(claude_session_file, {})
|
|
970
|
+
# Guard against a syntactically-valid non-object JSON (array, string,
|
|
971
|
+
# number) that would make .get() raise AttributeError, AND a
|
|
972
|
+
# non-string VALUE that would fail StatusResponse's str validation
|
|
973
|
+
# (both -> 500). The normal writer (run.sh) always emits an object
|
|
974
|
+
# with a string uuid, so this only triggers on external file
|
|
975
|
+
# corruption, but /api/status must never 500 on it.
|
|
976
|
+
if isinstance(_cs, dict):
|
|
977
|
+
_v = _cs.get("claude_session_uuid", "")
|
|
978
|
+
claude_session_id = _v if isinstance(_v, str) else ""
|
|
979
|
+
except (json.JSONDecodeError, OSError, KeyError, AttributeError):
|
|
980
|
+
pass
|
|
981
|
+
|
|
957
982
|
# Read dashboard state (with retry for concurrent writes)
|
|
958
983
|
_has_dashboard_state = False
|
|
959
984
|
if state_file.exists():
|
|
@@ -1206,6 +1231,7 @@ async def get_status() -> StatusResponse:
|
|
|
1206
1231
|
mode=mode,
|
|
1207
1232
|
provider=provider,
|
|
1208
1233
|
current_task=current_task,
|
|
1234
|
+
claude_session_id=claude_session_id,
|
|
1209
1235
|
sessions=active_session_list,
|
|
1210
1236
|
)
|
|
1211
1237
|
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -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.
|
|
5
|
+
**Version:** v7.34.1
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -534,7 +534,7 @@ Loki Mode uses two network ports for different services:
|
|
|
534
534
|
LOKI_DASHBOARD_PORT=57374 loki dashboard start
|
|
535
535
|
|
|
536
536
|
# API port (default: 57374)
|
|
537
|
-
loki
|
|
537
|
+
loki api start --port 57374 # was: loki serve
|
|
538
538
|
```
|
|
539
539
|
|
|
540
540
|
### CORS Configuration
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -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.
|
|
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.34.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}
|
|
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)
|
|
@@ -42,8 +42,8 @@ var n6=Object.defineProperty;var a6=($)=>$;function s6($,Q){this[$]=a6.bind(null
|
|
|
42
42
|
`)}let J=D($,"state","context-usage.json");if(v(J)){let B=a1(J,"window_size",200000),O=a1(J,"used_tokens",0),M=0;if(B>0)M=Math.floor(O*100/B);process.stdout.write(`${w}Context:${q} ${M}% (${O} / ${B} tokens)
|
|
43
43
|
`)}let G=[D($,"dashboard","dashboard.pid"),D(NQ(),".loki","dashboard","dashboard.pid")].find((B)=>v(B))??"";if(G&&v(G)){let B=R$(G);if(B!==null&&k$(B)){let O=D(G,".."),M=(_,k)=>{let u=D(O,_);try{return v(u)?U$(u,"utf-8").trim()||k:k}catch{return k}},x=M("scheme","http"),N=M("host","127.0.0.1"),b=M("port",process.env.LOKI_DASHBOARD_PORT||"57374");if(N==="0.0.0.0")N="127.0.0.1";process.stdout.write(`${w}Dashboard:${q} ${x}://${N}:${b}/
|
|
44
44
|
`)}}return await hQ($),process.stdout.write(`
|
|
45
|
-
`),process.stdout.write(`${y} Tip: loki context show - detailed token breakdown${q}
|
|
46
|
-
`),process.stdout.write(`${y} Tip: loki code overview
|
|
45
|
+
`),process.stdout.write(`${y} Tip: loki analyze context show - detailed token breakdown${q}
|
|
46
|
+
`),process.stdout.write(`${y} Tip: loki analyze code overview - codebase intelligence${q}
|
|
47
47
|
`),0}async function hQ($){let Q=D($,"state"),Z=yQ(Q),z=D(Q,"relevant-learnings.json"),X=D($,"escalations"),W=Z.length>0,K=v(z),U=v(X);if(!W&&!K&&!U)return;if(process.stdout.write(`
|
|
48
48
|
${w}Phase 1 artifacts:${q}
|
|
49
49
|
`),W){let V=Z[Z.length-1],H=s1(V);if(H&&Array.isArray(H.findings)){let J={Critical:0,High:0,Medium:0,Low:0};for(let G of H.findings){let B=String(G.severity??"");if(B in J)J[B]=(J[B]??0)+1}let Y=Object.entries(J).filter(([,G])=>G>0).map(([G,B])=>`${B} ${G.toLowerCase()}`).join(", ");process.stdout.write(` Findings (iter ${H.iteration??"?"}): ${Y||"none"} -- ${H.findings.length} total
|
|
@@ -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=
|
|
792
|
+
//# debugId=F6F45F7E10405C2564756E2164756E21
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.34.1",
|
|
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",
|
package/providers/claude.sh
CHANGED
|
@@ -247,6 +247,17 @@ _loki_build_claude_auto_flags() {
|
|
|
247
247
|
&& loki_claude_flag_supported "--include-partial-messages"; then
|
|
248
248
|
_LOKI_CLAUDE_AUTO_FLAGS+=("--include-partial-messages")
|
|
249
249
|
fi
|
|
250
|
+
|
|
251
|
+
# --no-session-persistence (v7.34.0): boolean flag that disables Claude's
|
|
252
|
+
# own session persistence (it would otherwise write transcript JSONL under
|
|
253
|
+
# ~/.claude/projects). OPT-IN only via LOKI_NO_SESSION_PERSIST=1; DEFAULT OFF
|
|
254
|
+
# so this is zero behavior change (the flag is never emitted unless the user
|
|
255
|
+
# asks for it). Useful for ephemeral/CI runs that do not want on-disk
|
|
256
|
+
# transcripts. Gated on CLI support so an older claude degrades gracefully.
|
|
257
|
+
if [ "${LOKI_NO_SESSION_PERSIST:-0}" = "1" ] \
|
|
258
|
+
&& loki_claude_flag_supported "--no-session-persistence"; then
|
|
259
|
+
_LOKI_CLAUDE_AUTO_FLAGS+=("--no-session-persistence")
|
|
260
|
+
fi
|
|
250
261
|
}
|
|
251
262
|
|
|
252
263
|
# The system-prompt text that authorizes autonomous operation and resolves
|