loki-mode 7.91.1 → 7.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v7.91.1
6
+ # Loki Mode v7.93.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -408,4 +408,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
408
408
 
409
409
  ---
410
410
 
411
- **v7.91.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
411
+ **v7.93.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 7.91.1
1
+ 7.93.0
package/autonomy/loki CHANGED
@@ -313,6 +313,112 @@ get_version() {
313
313
  fi
314
314
  }
315
315
 
316
+ # Stale-install nudge (bash route; mirrors loki-ts/src/util/update_check.ts).
317
+ # Best-effort, fail-silent, and adds zero latency on the hot path:
318
+ # - skipped entirely on non-TTY / CI / LOKI_NO_UPDATE_CHECK=1;
319
+ # - result cached in ~/.loki/cache/update-check-bash.json for >= 24h, so the
320
+ # network is hit at most once a day (separate file from the Bun cache, which
321
+ # stores millisecond timestamps; this file stores Unix seconds);
322
+ # - the registry fetch has a hard 1.5s timeout and is fully fail-silent;
323
+ # - the hint goes to STDERR so stdout stays byte-identical for scripts and the
324
+ # bash<->Bun parity tests.
325
+ # We never fabricate a version: the hint prints only when a real check (or a
326
+ # fresh cache from one) reports a strictly newer stable semver.
327
+ _loki_update_cache_path() {
328
+ echo "$HOME/.loki/cache/update-check-bash.json"
329
+ }
330
+
331
+ # _loki_semver_newer <latest> <current> -> 0 (true) iff latest is strictly newer.
332
+ # Rejects anything that is not a plain MAJOR.MINOR.PATCH (e.g. "unknown",
333
+ # prereleases): on any unparseable input it returns 1 (never nudge).
334
+ _loki_semver_newer() {
335
+ local latest="$1" current="$2"
336
+ case "$latest" in
337
+ [0-9]*.[0-9]*.[0-9]*) ;;
338
+ *) return 1 ;;
339
+ esac
340
+ case "$current" in
341
+ [0-9]*.[0-9]*.[0-9]*) ;;
342
+ *) return 1 ;;
343
+ esac
344
+ # Reject prerelease / build suffixes (anything past the third number).
345
+ case "$latest" in *[!0-9.]*) return 1 ;; esac
346
+ case "$current" in *[!0-9.]*) return 1 ;; esac
347
+ local l_maj l_min l_pat c_maj c_min c_pat
348
+ IFS='.' read -r l_maj l_min l_pat _ <<EOF
349
+ $latest
350
+ EOF
351
+ IFS='.' read -r c_maj c_min c_pat _ <<EOF
352
+ $current
353
+ EOF
354
+ # Default any empty component to 0 (defensive).
355
+ l_maj=${l_maj:-0}; l_min=${l_min:-0}; l_pat=${l_pat:-0}
356
+ c_maj=${c_maj:-0}; c_min=${c_min:-0}; c_pat=${c_pat:-0}
357
+ if [ "$l_maj" -ne "$c_maj" ]; then [ "$l_maj" -gt "$c_maj" ]; return; fi
358
+ if [ "$l_min" -ne "$c_min" ]; then [ "$l_min" -gt "$c_min" ]; return; fi
359
+ [ "$l_pat" -gt "$c_pat" ]
360
+ }
361
+
362
+ # maybe_print_update_hint: print the one-line update nudge to stderr if (and
363
+ # only if) a successful, non-fabricated check reports a strictly newer release.
364
+ # Never blocks, never slows the command, never touches stdout. Always returns 0.
365
+ maybe_print_update_hint() {
366
+ # Opt-out / non-interactive / CI: do nothing, touch neither disk nor network.
367
+ [ "${LOKI_NO_UPDATE_CHECK:-}" = "1" ] && return 0
368
+ [ -n "${CI:-}" ] && return 0
369
+ [ ! -t 1 ] && return 0
370
+
371
+ local current
372
+ current=$(get_version)
373
+ case "$current" in
374
+ [0-9]*.[0-9]*.[0-9]*) ;;
375
+ *) return 0 ;; # "unknown" or non-semver -> never nudge
376
+ esac
377
+
378
+ local cache_file latest=""
379
+ cache_file=$(_loki_update_cache_path)
380
+
381
+ # Fast path: a fresh (< 24h) cache means zero network.
382
+ if [ -f "$cache_file" ]; then
383
+ local checked_at now age
384
+ checked_at=$(sed -n 's/.*"checkedAt"[[:space:]]*:[[:space:]]*\([0-9]\{1,\}\).*/\1/p' "$cache_file" 2>/dev/null | head -1)
385
+ latest=$(sed -n 's/.*"latest"[[:space:]]*:[[:space:]]*"\([0-9][0-9.]*\)".*/\1/p' "$cache_file" 2>/dev/null | head -1)
386
+ if [ -n "$checked_at" ] && [ -n "$latest" ]; then
387
+ now=$(date +%s 2>/dev/null || echo 0)
388
+ age=$(( now - checked_at ))
389
+ if [ "$age" -ge 0 ] && [ "$age" -lt 86400 ]; then
390
+ if _loki_semver_newer "$latest" "$current"; then
391
+ printf 'A newer loki-mode is available (%s). Update: bun install -g loki-mode\n' "$latest" >&2
392
+ fi
393
+ return 0
394
+ fi
395
+ fi
396
+ latest="" # stale cache -> fall through to a fresh fetch
397
+ fi
398
+
399
+ # Cache miss/stale: query the registry. Hard timeout, fail-silent.
400
+ if command -v curl >/dev/null 2>&1; then
401
+ latest=$(curl -fsS --max-time 1.5 "https://registry.npmjs.org/loki-mode/latest" 2>/dev/null \
402
+ | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([0-9][0-9.]*\)".*/\1/p' | head -1)
403
+ fi
404
+ # No usable result -> print nothing, write nothing (never fabricate).
405
+ case "$latest" in
406
+ [0-9]*.[0-9]*.[0-9]*) ;;
407
+ *) return 0 ;;
408
+ esac
409
+
410
+ # Persist the fresh result (best-effort; a non-writable HOME must not break).
411
+ local now2
412
+ now2=$(date +%s 2>/dev/null || echo 0)
413
+ ( mkdir -p "$(dirname "$cache_file")" 2>/dev/null \
414
+ && printf '{"checkedAt":%s,"latest":"%s"}\n' "$now2" "$latest" > "$cache_file" 2>/dev/null ) || true
415
+
416
+ if _loki_semver_newer "$latest" "$current"; then
417
+ printf 'A newer loki-mode is available (%s). Update: bun install -g loki-mode\n' "$latest" >&2
418
+ fi
419
+ return 0
420
+ }
421
+
316
422
  # Ensure dashboard Python venv with all deps installed.
317
423
  # Uses ~/.loki/dashboard-venv (persistent, writable, survives npm/brew upgrades).
318
424
  # Sets DASHBOARD_PYTHON to the venv python3 path on success.
@@ -717,11 +823,11 @@ show_help() {
717
823
  echo ""
718
824
  echo "Usage: loki <command> [options]"
719
825
  echo ""
720
- echo "New here? Try one of these first:"
826
+ echo "New here? Try these in order:"
721
827
  echo " loki doctor Check your setup is ready (a few seconds)"
722
- echo " loki quick \"add a health endpoint\" One small task, start to finish"
723
- echo " loki demo Build a sample todo app end to end (real run)"
828
+ echo " loki quickstart Guided first build from your idea (no PRD needed)"
724
829
  echo " loki start ./prd.md Build from a spec (PRD file, GitHub issue, or no arg)"
830
+ echo " quickstart = guided first build; quick = one small task (3 iters max)."
725
831
  echo " Docs: https://github.com/asklokesh/loki-mode | Report a problem: loki crash"
726
832
  echo ""
727
833
  # CLI consolidation (Phase A): the front page presents ~17 canonical
@@ -778,11 +884,11 @@ show_help() {
778
884
  echo " version Show version"
779
885
  echo " help Show this help ('loki help aliases' for old names)"
780
886
  echo ""
781
- echo "More commands (ship, grill, spec, deploy, cleanup, init, watch, demo, web, api,"
782
- echo "logs, github, import, council, proof, audit, compliance, agent, template,"
783
- echo "magic, docs, wiki, ci, test, bench, secrets, telemetry, crash, worktree,"
784
- echo "failover, monitor, remote, ...) are dispatchable and documented via"
785
- echo "'loki <command> --help'."
887
+ echo "More commands (the most useful; many more are dispatchable):"
888
+ echo " Advanced: ship, deploy, init, web"
889
+ echo " Cloud + CI: github, import, ci"
890
+ echo " Debugging: logs, crash, cleanup"
891
+ echo "...run 'loki help <name>' for any command."
786
892
  echo ""
787
893
  echo "Aliases (deprecated): older command names still work; they print a"
788
894
  echo "one-line pointer to stderr and never alter --json output. See the full"
@@ -804,19 +910,8 @@ show_help() {
804
910
  echo " --bmad-project PATH Use BMAD Method project artifacts as input"
805
911
  echo " --openspec PATH Use OpenSpec change directory as input"
806
912
  echo ""
807
- echo "Options for 'run' (v6.0.0):"
808
- echo " --dry-run Preview generated PRD without starting"
809
- echo " --no-start Generate PRD but don't start execution"
810
- echo " --output FILE Save PRD to custom path"
811
- echo " --provider NAME AI provider: claude (default), codex, cline, aider"
812
- echo " --parallel Enable parallel mode with git worktrees"
813
- echo " --budget USD Set cost budget limit"
814
- echo ""
815
- echo "Progressive Isolation (for 'run'):"
816
- echo " --worktree, -w Git worktree isolation (separate branch)"
817
- echo " --pr Auto-create PR after completion (implies --worktree)"
818
- echo " --ship Auto-merge after PR (implies --pr)"
819
- echo " --detach, -d Run in background (implies --worktree)"
913
+ echo "Deprecated alias 'run': 'loki run <issue-ref>' still works as an alias"
914
+ echo "for 'loki start'. See its options with 'loki run --help'."
820
915
  echo ""
821
916
  echo "Examples:"
822
917
  echo ""
@@ -941,11 +1036,11 @@ show_landing() {
941
1036
  echo ""
942
1037
  echo -e "First time here? ${CYAN}loki doctor${NC} checks your setup (an AI provider CLI is required)."
943
1038
  echo ""
944
- echo "Get started:"
1039
+ echo "Get started (in order):"
1040
+ echo -e " ${CYAN}loki doctor${NC} Check your setup is ready (a few seconds)"
945
1041
  echo -e " ${CYAN}loki quickstart${NC} Guided first build from your idea (no PRD needed)"
946
1042
  echo -e " ${CYAN}loki start ./prd.md${NC} Build from a spec (PRD file, GitHub issue, or no arg)"
947
- echo -e " ${CYAN}loki demo${NC} Build a sample todo app end to end (real run)"
948
- echo -e " ${CYAN}loki dashboard start${NC} Start the live run monitor (then: loki dashboard open)"
1043
+ echo " quickstart = guided first build; quick = one small task (3 iters max)."
949
1044
  echo ""
950
1045
  echo -e "Need help? ${CYAN}loki help${NC} lists every command."
951
1046
  echo "Tip: preview cost and scope before building: loki plan <your-prd.md>"
@@ -3408,7 +3503,8 @@ cmd_why() {
3408
3503
  fi
3409
3504
 
3410
3505
  if [ "$as_json" = "1" ]; then
3411
- _LOKI_WHY_STATE="$state_file" _LOKI_WHY_COMPLETION="$completion_file" python3 - <<'WHYJSON'
3506
+ _LOKI_WHY_STATE="$state_file" _LOKI_WHY_COMPLETION="$completion_file" \
3507
+ _LOKI_WHY_LAST_ERROR="$loki_dir/state/LAST_ERROR.json" python3 - <<'WHYJSON'
3412
3508
  import json, os
3413
3509
  def load(p):
3414
3510
  try:
@@ -3416,7 +3512,8 @@ def load(p):
3416
3512
  except Exception: return {}
3417
3513
  state = load(os.environ.get("_LOKI_WHY_STATE", ""))
3418
3514
  comp = load(os.environ.get("_LOKI_WHY_COMPLETION", ""))
3419
- print(json.dumps({"state": state, "completion": comp}, indent=2))
3515
+ last_error = load(os.environ.get("_LOKI_WHY_LAST_ERROR", ""))
3516
+ print(json.dumps({"state": state, "completion": comp, "last_error": last_error}, indent=2))
3420
3517
  WHYJSON
3421
3518
  return 0
3422
3519
  fi
@@ -3428,6 +3525,7 @@ WHYJSON
3428
3525
  _why_head_sha="$(git rev-parse HEAD 2>/dev/null || echo "")"
3429
3526
  _LOKI_WHY_STATE="$state_file" _LOKI_WHY_COMPLETION="$completion_file" \
3430
3527
  _LOKI_WHY_HEAD_SHA="$_why_head_sha" \
3528
+ _LOKI_WHY_LAST_ERROR="$loki_dir/state/LAST_ERROR.json" \
3431
3529
  _LOKI_WHY_HANDOFFS="$loki_dir/memory/handoffs" python3 - <<'WHYTXT'
3432
3530
  import json, os, glob
3433
3531
  def load(p):
@@ -3519,6 +3617,28 @@ print()
3519
3617
  print(f" What happened: {meaning}")
3520
3618
  print(f" What to do : {action}")
3521
3619
 
3620
+ # Surface the structured per-iteration error record, if one exists at
3621
+ # .loki/state/LAST_ERROR.json (the run.sh writer that produces it ships in the
3622
+ # SAME v7.92.0 release; on an older engine the file is simply absent and this
3623
+ # block stays dormant - never fabricated). run.sh clears it at the start of every
3624
+ # fresh run, so a present record belongs to the CURRENT run. We still only show it
3625
+ # when THIS run's outcome is itself a failure - never beside a success verdict
3626
+ # (that would be a fake-green-adjacent lie) - using the same SUCCESS set below.
3627
+ SUCCESS_STATUSES = {"council_approved", "completion_promise_fulfilled", "complete", "completed"}
3628
+ le = {}
3629
+ try:
3630
+ with open(os.environ.get("_LOKI_WHY_LAST_ERROR", "")) as f:
3631
+ le = json.load(f)
3632
+ except Exception:
3633
+ le = {}
3634
+ if isinstance(le, dict) and le.get("error_class") and status not in SUCCESS_STATUSES:
3635
+ print()
3636
+ _it = le.get("iteration")
3637
+ _it_s = f" (iteration {_it})" if _it not in (None, "") else ""
3638
+ print(f" Last error : {le.get('error_class')}{_it_s}")
3639
+ if le.get("brief"):
3640
+ print(f" {le.get('brief')}")
3641
+
3522
3642
  # Surface the latest structured handoff (already-captured context), honestly.
3523
3643
  hd = sorted(glob.glob(os.path.join(os.environ.get("_LOKI_WHY_HANDOFFS",""), "*.md")))
3524
3644
  if hd:
@@ -10104,6 +10224,9 @@ except Exception:
10104
10224
  echo ""
10105
10225
  echo "Next: loki quickstart (guided first build from your idea, no PRD needed)"
10106
10226
  echo " or loki demo (builds a sample todo app end to end) or loki start ./prd.md"
10227
+ # Best-effort stale-install nudge (stderr only; never blocks; off on
10228
+ # non-TTY/CI). Reached only on the human-readable path (--json returns above).
10229
+ maybe_print_update_hint
10107
10230
  return 0
10108
10231
  }
10109
10232
 
@@ -10476,6 +10599,9 @@ cmd_version() {
10476
10599
  ;;
10477
10600
  esac
10478
10601
  echo "Loki Mode v$(get_version)"
10602
+ # Best-effort stale-install nudge (stderr only; never blocks; off on
10603
+ # non-TTY/CI). Mirrors the Bun route's update check for parity.
10604
+ maybe_print_update_hint
10479
10605
  }
10480
10606
 
10481
10607
  # Secrets / credential management
@@ -16704,7 +16830,8 @@ main() {
16704
16830
  if _suggestion=$(_suggest_command "$command"); then
16705
16831
  echo "Did you mean 'loki ${_suggestion}'?" >&2
16706
16832
  fi
16707
- echo "Run 'loki help' for usage." >&2
16833
+ # Always point to the full command list, even with no near-miss match.
16834
+ echo "Run 'loki help' to see every command." >&2
16708
16835
  exit 1
16709
16836
  ;;
16710
16837
  esac
@@ -69,8 +69,15 @@ _po_non_interactive() {
69
69
  # successful install. Inherited stdio; Loki never handles credentials.
70
70
  _po_run_login() {
71
71
  # claude must actually be on PATH for login to make sense.
72
+ # If the install succeeded but the binary is not yet resolvable, npm's
73
+ # global bin is almost certainly not on PATH. Print the exact copy-paste
74
+ # fix. We print the literal $(npm config get prefix) form (single-quoted,
75
+ # NOT executed here) so the user runs it in their own shell and so this
76
+ # post-install path makes no extra npm invocation.
72
77
  if ! command -v claude >/dev/null 2>&1; then
73
- printf "%sInstalled, but 'claude' is not on your PATH yet. You may need to restart your shell or add npm's global bin to PATH (npm config get prefix). Run 'loki doctor' to recheck.%s\n" "$_PO_YELLOW" "$_PO_NC"
78
+ printf "%sInstalled, but 'claude' is not on your PATH yet. Add npm's global bin to your shell:%s\n" "$_PO_YELLOW" "$_PO_NC"
79
+ printf ' export PATH="$(npm config get prefix)/bin:$PATH"\n'
80
+ printf "Then restart your shell (or source your rc) and run: loki doctor\n"
74
81
  return 0
75
82
  fi
76
83