loki-mode 9.22.11 → 9.23.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.
Files changed (93) hide show
  1. package/SKILL.md +3 -3
  2. package/VERSION +1 -1
  3. package/autonomy/lib/claude-flags.sh +69 -5
  4. package/autonomy/lib/contract-scaffold/scaffold.sh +1 -1
  5. package/autonomy/lib/mcp-config.sh +27 -4
  6. package/autonomy/loki +324 -74
  7. package/autonomy/run.sh +120 -39
  8. package/autonomy/verify.sh +16 -3
  9. package/bin/loki +25 -1
  10. package/dashboard/__init__.py +1 -1
  11. package/dashboard/control.py +88 -4
  12. package/dashboard/server.py +50 -48
  13. package/docs/INSTALLATION.md +2 -2
  14. package/docs/RARV-C-100X-PLAN.md +9 -1
  15. package/docs/enterprise/performance.md +51 -9
  16. package/docs/exit-codes.md +4 -0
  17. package/loki-ts/dist/cockpit.js +1 -1
  18. package/loki-ts/dist/loki.js +634 -549
  19. package/loki-ts/package.json +2 -2
  20. package/mcp/__init__.py +1 -1
  21. package/package.json +6 -5
  22. package/plugins/loki-mode/.claude-plugin/plugin.json +2 -3
  23. package/providers/loader.sh +2 -2
  24. package/providers/model_catalog.json +26 -8
  25. package/providers/models.sh +1 -1
  26. package/providers/opencode.sh +1 -1
  27. package/skills/providers.md +42 -14
  28. package/tools/normalize-package-permissions.mjs +34 -0
  29. package/web-app/dist/assets/{AdminPage-DLhWX6si.js → AdminPage-PyyVXg4b.js} +1 -1
  30. package/web-app/dist/assets/{Avatar-CqyDcUxl.js → Avatar-CTUlr_Xf.js} +1 -1
  31. package/web-app/dist/assets/{Badge-BKGSt1n2.js → Badge-BQeXvmg8.js} +1 -1
  32. package/web-app/dist/assets/{Button-DuuKHXre.js → Button-Dc6-P6pz.js} +1 -1
  33. package/web-app/dist/assets/{CockpitPage-DdClYERC.js → CockpitPage-BspOJ3Fv.js} +1 -1
  34. package/web-app/dist/assets/{ComparePage-CUWlqBxv.js → ComparePage-CFXIM--Z.js} +1 -1
  35. package/web-app/dist/assets/{ErrorBoundary-RwfGKyRJ.js → ErrorBoundary-C7vQYDW9.js} +1 -1
  36. package/web-app/dist/assets/{EvidenceReceiptPanel-CzIgk9sg.js → EvidenceReceiptPanel-CqjsjTOs.js} +1 -1
  37. package/web-app/dist/assets/{GitHubIssuesPanel-CsXVKuyJ.js → GitHubIssuesPanel-DyuNDMgD.js} +1 -1
  38. package/web-app/dist/assets/{GitHubPRsPanel-CYRp1eKS.js → GitHubPRsPanel-BtAq20xF.js} +1 -1
  39. package/web-app/dist/assets/{HomePage-CVJcI5pQ.js → HomePage-BuVFOrO8.js} +1 -1
  40. package/web-app/dist/assets/{LoginPage-BBJNV9Qb.js → LoginPage-CuhhrxGb.js} +1 -1
  41. package/web-app/dist/assets/{MagicPage-CIi9P8jK.js → MagicPage-D2KZPX3F.js} +1 -1
  42. package/web-app/dist/assets/{MetricsPage-Bm34ipiy.js → MetricsPage-DFEYJl9z.js} +1 -1
  43. package/web-app/dist/assets/{NotFoundPage-DpTbcC2P.js → NotFoundPage-CTnnaWlL.js} +1 -1
  44. package/web-app/dist/assets/{ProjectPage-CY2SMGx9.js → ProjectPage-uJFaoM8-.js} +55 -55
  45. package/web-app/dist/assets/{ProjectsPage-DSrXUUKJ.js → ProjectsPage-8lKAOBIW.js} +1 -1
  46. package/web-app/dist/assets/{SettingsPage-jvDyOqYi.js → SettingsPage-D1BBd5qy.js} +1 -1
  47. package/web-app/dist/assets/{ShowcasePage-C8tFWKau.js → ShowcasePage-CmQ0n8iO.js} +1 -1
  48. package/web-app/dist/assets/{SystemSettingsPage-DH4FTH3K.js → SystemSettingsPage-CSHaVyuD.js} +1 -1
  49. package/web-app/dist/assets/{TeamsPage-C1fQYauF.js → TeamsPage-BS0TtVUa.js} +1 -1
  50. package/web-app/dist/assets/{TemplatesPage-CSTFt-4P.js → TemplatesPage-C2zPnnf2.js} +1 -1
  51. package/web-app/dist/assets/{TerminalOutput-Cu4NsyN6.js → TerminalOutput-Dle1klqq.js} +1 -1
  52. package/web-app/dist/assets/{activity-CtjsDzmh.js → activity-DQp5U9f9.js} +1 -1
  53. package/web-app/dist/assets/{bell-C5es1xAs.js → bell-BqkTmgL7.js} +1 -1
  54. package/web-app/dist/assets/{bot-DE04U5Lc.js → bot-DILhaIGH.js} +1 -1
  55. package/web-app/dist/assets/{check-DSKKA9EU.js → check-BC9x7oPm.js} +1 -1
  56. package/web-app/dist/assets/{chevron-left-DJ13W5AR.js → chevron-left--yqvAfjx.js} +1 -1
  57. package/web-app/dist/assets/{circle-alert-CS0BfqAd.js → circle-alert-DOH6PcgZ.js} +1 -1
  58. package/web-app/dist/assets/{clock-D1Y5nruk.js → clock-DKSDFsE6.js} +1 -1
  59. package/web-app/dist/assets/{cloud-nU6LBoZL.js → cloud-DRBU3JYs.js} +1 -1
  60. package/web-app/dist/assets/{code-xml-BZfvIdFo.js → code-xml-D2LqszR9.js} +1 -1
  61. package/web-app/dist/assets/{copy-CK_2O1Xv.js → copy-BKW4U4Qr.js} +1 -1
  62. package/web-app/dist/assets/{database-DJiwznAm.js → database-D7ceedlh.js} +1 -1
  63. package/web-app/dist/assets/{dollar-sign-pO20A3QY.js → dollar-sign-D0A47egY.js} +1 -1
  64. package/web-app/dist/assets/{file-code-corner-Besy6vek.js → file-code-corner-CH_Qbtjo.js} +1 -1
  65. package/web-app/dist/assets/{file-plus-DeaswxYY.js → file-plus-CUNMjHk9.js} +1 -1
  66. package/web-app/dist/assets/{folder-open-cr1UvQLI.js → folder-open-CQ_SVq94.js} +1 -1
  67. package/web-app/dist/assets/{git-commit-horizontal-BLxnfbSn.js → git-commit-horizontal-DQUBe0oD.js} +1 -1
  68. package/web-app/dist/assets/{globe-DrhG1NfX.js → globe-gZnaGg8N.js} +1 -1
  69. package/web-app/dist/assets/{hammer-CeZtPBfE.js → hammer-BhJC5DMK.js} +1 -1
  70. package/web-app/dist/assets/{index-CLvjO22Z.js → index-BMmYYws0.js} +2 -2
  71. package/web-app/dist/assets/{layers-fldADzyE.js → layers-glXeoUbJ.js} +1 -1
  72. package/web-app/dist/assets/{lightbulb-CznOfsPb.js → lightbulb-gXn8H0Lf.js} +1 -1
  73. package/web-app/dist/assets/{loader-circle---lPB1Fs.js → loader-circle-Do2ke8xm.js} +1 -1
  74. package/web-app/dist/assets/{lock-D5jVF-tO.js → lock-Bgplb1_n.js} +1 -1
  75. package/web-app/dist/assets/{mail-D7HkLnlW.js → mail-j4Lo8hfB.js} +1 -1
  76. package/web-app/dist/assets/{minus-C-dT19Ct.js → minus-dhrzKSK5.js} +1 -1
  77. package/web-app/dist/assets/{package-Cm9B-cKE.js → package-CInWQQ97.js} +1 -1
  78. package/web-app/dist/assets/{plus-CQwOffLD.js → plus-BpYvoLlZ.js} +1 -1
  79. package/web-app/dist/assets/{refresh-cw-CvWJZLbN.js → refresh-cw-F6koqEgF.js} +1 -1
  80. package/web-app/dist/assets/{rotate-ccw-C2Q1LYgM.js → rotate-ccw-CQ2W5S8f.js} +1 -1
  81. package/web-app/dist/assets/{save-BP0MvpoQ.js → save-DMCYGm06.js} +1 -1
  82. package/web-app/dist/assets/{server-4i4VZXix.js → server-Bj8EX4Z1.js} +1 -1
  83. package/web-app/dist/assets/{shield-alert-D2_bgb7j.js → shield-alert-CiYuulCU.js} +1 -1
  84. package/web-app/dist/assets/{thumbs-up-vACbzeXj.js → thumbs-up-BqEh1puP.js} +1 -1
  85. package/web-app/dist/assets/{trash-2-EYjdESLs.js → trash-2-CCwouZJJ.js} +1 -1
  86. package/web-app/dist/assets/{trending-down-BWBdcvE3.js → trending-down-Cx1vhE4o.js} +1 -1
  87. package/web-app/dist/assets/{trending-up-Bix6V_-Y.js → trending-up-BUhVYJ2T.js} +1 -1
  88. package/web-app/dist/assets/{upload-B7hh6ERF.js → upload-D5IsZeFM.js} +1 -1
  89. package/web-app/dist/assets/{usePolling-b_e-k-IN.js → usePolling-CJbfhFcH.js} +1 -1
  90. package/web-app/dist/assets/{user-pmjZKWEg.js → user-BRLhezsD.js} +1 -1
  91. package/web-app/dist/index.html +1 -1
  92. package/web-app/requirements.txt +1 -0
  93. package/web-app/server.py +160 -31
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 v9.22.11
6
+ # Loki Mode v9.23.1
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -434,7 +434,7 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
434
434
 
435
435
  | Feature | Added | Notes |
436
436
  |---------|-------|-------|
437
- | Multi-provider support (4 providers) | v5.0.0 | claude, codex, cline, aider -- see `providers/` |
437
+ | Multi-provider support (5 providers) | v5.0.0 | claude, codex, cline, aider, opencode -- see `providers/` |
438
438
  | CONTINUITY.md working memory | v5.35.0 | Auto-managed by run.sh, updated each iteration |
439
439
  | Quality gates 3-reviewer system | v5.35.0 | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
440
440
  | Memory System (episodic/semantic/procedural) | v5.15.0 | Full implementation in `memory/` |
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
470
470
 
471
471
  ---
472
472
 
473
- **v9.22.11 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
473
+ **v9.23.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 9.22.11
1
+ 9.23.1
@@ -762,10 +762,12 @@ loki_caveman_suppress_env() {
762
762
  # this so the operator is never surprised.
763
763
  #
764
764
  # HARDENING: the npx call is forced non-interactive (--non-interactive, plus
765
- # </dev/null so no stdin read can ever block) and time-bounded (timeout when
766
- # available) so a stalled network or an unexpected prompt can never hang a user's
767
- # first `loki start`. caveman's installer is already auto-non-interactive without
768
- # a TTY, but we belt-and-suspenders it.
765
+ # </dev/null so no stdin read can ever block), time-bounded, and run from a
766
+ # disposable directory. The upstream installer may create project-local agent
767
+ # files while wiring its global Claude hook; isolating its cwd prevents those
768
+ # files, lockfiles, or compiled Python cache entries from polluting the user's
769
+ # feature branch and proof diff. caveman's installer is already auto-
770
+ # non-interactive without a TTY, but we belt-and-suspenders it.
769
771
  loki_caveman_bootstrap() {
770
772
  [ "${LOKI_CAVEMAN:-1}" = "0" ] && return 1
771
773
  [ "${LOKI_CAVEMAN_AUTO_BOOTSTRAP:-1}" = "0" ] && return 1
@@ -796,7 +798,19 @@ loki_caveman_bootstrap() {
796
798
  if command -v timeout >/dev/null 2>&1; then
797
799
  _cm_runner="timeout 120 npx"
798
800
  fi
799
- if CAVEMAN_REF="v${ver}" $_cm_runner -y "github:JuliusBrussee/caveman#v${ver}" -- --non-interactive >/dev/null 2>&1 </dev/null; then
801
+ local bootstrap_tmp=""
802
+ bootstrap_tmp="$(mktemp -d "${TMPDIR:-/tmp}/loki-caveman-bootstrap.XXXXXX")" || {
803
+ printf '%s\n' "[caveman] could not allocate an isolated bootstrap directory; run proceeds uncompressed." >&2
804
+ mkdir -p "$marker_dir" 2>/dev/null && : > "$marker" 2>/dev/null || true
805
+ return 1
806
+ }
807
+ local bootstrap_rc=1
808
+ (
809
+ cd "$bootstrap_tmp" || exit 1
810
+ CAVEMAN_REF="v${ver}" $_cm_runner -y "github:JuliusBrussee/caveman#v${ver}" -- --non-interactive >/dev/null 2>&1 </dev/null
811
+ ) && bootstrap_rc=0
812
+ rm -rf -- "$bootstrap_tmp" 2>/dev/null || true
813
+ if [ "$bootstrap_rc" -eq 0 ]; then
800
814
  mkdir -p "$marker_dir" 2>/dev/null && : > "$marker" 2>/dev/null || true
801
815
  if _loki_caveman_installed; then
802
816
  printf '%s\n' "[caveman] installed v${ver}." >&2
@@ -882,3 +896,53 @@ except Exception:
882
896
  pass
883
897
  RESUME_UUID_PY
884
898
  }
899
+
900
+ # ---------- v9.23.0 subagent fleet capacity (Claude Code 2.1.217 defaults) ----------
901
+ # WHY THIS EXISTS. Claude Code 2.1.217 changed two subagent defaults, and both
902
+ # silently degrade a fan-out harness rather than failing loudly:
903
+ #
904
+ # "Changed subagents to no longer spawn nested subagents by default; set
905
+ # CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH to allow deeper nesting"
906
+ # "Added a cap on concurrently-running subagents (default 20, override with
907
+ # CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS) so one message can't fan out
908
+ # unbounded background agents"
909
+ # -- https://github.com/anthropics/claude-code/releases/tag/v2.1.217
910
+ #
911
+ # The spawn-depth default dropped from 5 to 1 (mirrored in Agent SDK 0.3.217).
912
+ # Loki's documented SDLC fleet pattern dispatches an agent that itself delegates
913
+ # (skills/model-selection.md), so at depth 1 the second level never spawns: the
914
+ # fleet quietly collapses to a single tier and the run still reports success.
915
+ # That is the dangerous shape -- no error, just less work done than claimed.
916
+ #
917
+ # We set the depth EXPLICITLY rather than relying on any default, in either
918
+ # direction. 2 is the depth Loki actually uses (orchestrator -> dev/reviewer
919
+ # agent -> its own helpers); we do not raise it further, because unbounded
920
+ # nesting is the runaway the upstream default exists to prevent.
921
+ #
922
+ # Concurrency is left at the upstream default of 20 unless the operator raises
923
+ # it: the council (3 reviewers) and dev fleet (3-5) both sit well under it, and
924
+ # a harness that silently raises a safety cap on every user's machine is the
925
+ # wrong trade. We export it only when the operator asked for more, so the value
926
+ # shows up in a diff rather than being an invisible default.
927
+ #
928
+ # Both are opt-out via LOKI_SUBAGENT_CAPACITY=0 and honor a pre-set value from
929
+ # the environment, so an operator's own export always wins.
930
+ loki_export_subagent_capacity() {
931
+ [ "${LOKI_SUBAGENT_CAPACITY:-1}" = "0" ] && return 0
932
+
933
+ if [ -z "${CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH:-}" ]; then
934
+ export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH="${LOKI_SUBAGENT_SPAWN_DEPTH:-2}"
935
+ fi
936
+
937
+ # Only exported when explicitly requested; no silent raise of the cap.
938
+ if [ -n "${LOKI_SUBAGENT_CONCURRENCY:-}" ] && \
939
+ [ -z "${CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS:-}" ]; then
940
+ export CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS="$LOKI_SUBAGENT_CONCURRENCY"
941
+ fi
942
+ return 0
943
+ }
944
+
945
+ # Applied at SOURCE time, like the caveman default-off export above: the whole
946
+ # subprocess tree inherits it, so every subcall site gets the same capacity
947
+ # without each one having to remember to call this.
948
+ loki_export_subagent_capacity
@@ -137,7 +137,7 @@ cat > "$OUT/tsconfig.json" <<'JSON'
137
137
  "compilerOptions": {
138
138
  "strict": true, "noEmit": true, "jsx": "react-jsx",
139
139
  "module": "ESNext", "moduleResolution": "Bundler",
140
- "target": "ES2022", "lib": ["ES2022", "DOM"], "skipLibCheck": true
140
+ "target": "ES2022", "lib": ["ES2022", "DOM", "DOM.Iterable"], "skipLibCheck": true
141
141
  },
142
142
  "include": ["src"]
143
143
  }
@@ -17,7 +17,7 @@
17
17
  # Returns 0 on success, 1 only if the dir
18
18
  # cannot be created or the file cannot be
19
19
  # written.
20
- # loki_user_mcp_config_path -- emit absolute path to ~/.claude/mcp.json
20
+ # loki_user_mcp_config_path -- emit a bounded, current-schema ~/.claude/mcp.json
21
21
  # if present + readable, else empty. Always
22
22
  # returns 0.
23
23
  # loki_mcp_config_argv -- emit one space-separated string of paths
@@ -127,12 +127,35 @@ print(os.path.abspath(os.environ['_MCP_OUT']))
127
127
  }
128
128
 
129
129
  # ---------- User overlay path ----------
130
- # Echoes ~/.claude/mcp.json if it exists and is readable, else empty.
131
- # Always returns 0 -- a missing overlay is a normal state, not an error.
130
+ # Echoes ~/.claude/mcp.json only when it is valid JSON with the current Claude
131
+ # Code top-level `mcpServers` object. Older files using `servers` are not valid
132
+ # inputs to `claude --mcp-config`: passing one makes Claude refuse before the
133
+ # first provider turn. Ignore those files with an actionable warning so Loki's
134
+ # own valid bundle can still start the run.
135
+ # The 1 MiB bound prevents a local overlay from turning provider startup into an
136
+ # unbounded read. Always returns 0 -- a missing/invalid overlay is recoverable,
137
+ # not fatal.
132
138
  loki_user_mcp_config_path() {
133
139
  local user_path="${HOME}/.claude/mcp.json"
134
140
  if [ -f "$user_path" ] && [ -r "$user_path" ]; then
135
- printf '%s' "$user_path"
141
+ if _LOKI_USER_MCP="$user_path" python3 -c "
142
+ import json, os, sys
143
+ try:
144
+ path = os.environ['_LOKI_USER_MCP']
145
+ if os.path.getsize(path) > 1024 * 1024:
146
+ sys.exit(1)
147
+ with open(path, encoding='utf-8') as handle:
148
+ value = json.load(handle)
149
+ except (OSError, ValueError):
150
+ sys.exit(1)
151
+ sys.exit(0 if isinstance(value, dict) and isinstance(value.get('mcpServers'), dict) else 1)
152
+ " 2>/dev/null; then
153
+ printf '%s' "$user_path"
154
+ else
155
+ printf '%s\n' \
156
+ 'loki: ignoring ~/.claude/mcp.json: Claude Code requires a top-level "mcpServers" object; update or remove the legacy/invalid file.' \
157
+ >&2
158
+ fi
136
159
  fi
137
160
  return 0
138
161
  }