loki-mode 11.55.2 → 11.56.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.
Files changed (70) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/mcp-config.sh +131 -0
  4. package/dashboard/__init__.py +1 -1
  5. package/docs/CLI-REFERENCE.md +1 -1
  6. package/docs/INSTALLATION.md +1 -1
  7. package/docs/v10/FAILURE-CLASSES.md +12 -0
  8. package/loki-ts/dist/loki.js +420 -420
  9. package/mcp/__init__.py +1 -1
  10. package/package.json +2 -2
  11. package/packages/control-plane/dist/server.js +4 -1
  12. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  13. package/state/manager.ts +57 -14
  14. package/web-app/dist/assets/{AdminPage-Cq1bWFPJ.js → AdminPage-CmBpiMau.js} +1 -1
  15. package/web-app/dist/assets/{Avatar-DmLQK54Y.js → Avatar-DKMbfUD3.js} +1 -1
  16. package/web-app/dist/assets/{Badge-EDrJvqAV.js → Badge-BWnU7YEI.js} +1 -1
  17. package/web-app/dist/assets/{Button-BTayfRNs.js → Button-DySbWiB2.js} +1 -1
  18. package/web-app/dist/assets/{CockpitPage-DDxKaKAy.js → CockpitPage-DGn5dhOE.js} +1 -1
  19. package/web-app/dist/assets/{ComparePage-BEgcZF7Q.js → ComparePage-CWN21Av-.js} +1 -1
  20. package/web-app/dist/assets/{ErrorBoundary-DH7gH8tH.js → ErrorBoundary-BHRZHMSw.js} +1 -1
  21. package/web-app/dist/assets/{EvidenceReceiptPanel-BZrWS10j.js → EvidenceReceiptPanel-HZLbQdCW.js} +1 -1
  22. package/web-app/dist/assets/{GitHubIssuesPanel-TYn02Fhe.js → GitHubIssuesPanel-B9bjy9TY.js} +1 -1
  23. package/web-app/dist/assets/{GitHubPRsPanel-C9w7zI6N.js → GitHubPRsPanel-CXExgqa1.js} +1 -1
  24. package/web-app/dist/assets/{HomePage-Ct9msy_p.js → HomePage-C6T4CLSu.js} +2 -2
  25. package/web-app/dist/assets/{LoginPage-WRpEJmns.js → LoginPage-D0ikzScF.js} +1 -1
  26. package/web-app/dist/assets/{MagicPage-DJiL6WqU.js → MagicPage-BAOn7PDD.js} +1 -1
  27. package/web-app/dist/assets/{MetricsPage-2CMKR2Sq.js → MetricsPage-CeH7REnD.js} +1 -1
  28. package/web-app/dist/assets/{NotFoundPage-Cq2cofyE.js → NotFoundPage-hRysg98x.js} +1 -1
  29. package/web-app/dist/assets/{ProjectPage-CJjNZdid.js → ProjectPage-CTnLYbKK.js} +3 -3
  30. package/web-app/dist/assets/{ProjectsPage-7ApVblSL.js → ProjectsPage-DfV2rDNy.js} +1 -1
  31. package/web-app/dist/assets/{SettingsPage-D5YSUgYn.js → SettingsPage-PDKi8rW-.js} +1 -1
  32. package/web-app/dist/assets/{ShowcasePage-BORv96H6.js → ShowcasePage-DAXMeHi2.js} +1 -1
  33. package/web-app/dist/assets/{SystemSettingsPage-DAcoP_xM.js → SystemSettingsPage-w4wEFQ-w.js} +1 -1
  34. package/web-app/dist/assets/{TeamsPage-Dw032JqQ.js → TeamsPage-M2T8vLDC.js} +1 -1
  35. package/web-app/dist/assets/{TemplatesPage-BG6bVuMJ.js → TemplatesPage-tWDJLI_1.js} +1 -1
  36. package/web-app/dist/assets/{TerminalOutput-BB69c1HU.js → TerminalOutput-E9vOt7lb.js} +1 -1
  37. package/web-app/dist/assets/{activity-TmFvslmE.js → activity-pkruUWrS.js} +1 -1
  38. package/web-app/dist/assets/{bell-BU2erY_i.js → bell-QWwy_DqT.js} +1 -1
  39. package/web-app/dist/assets/{bot-DMpSqrIl.js → bot-EkuURDPq.js} +1 -1
  40. package/web-app/dist/assets/{check-B6QVSMTJ.js → check-gjOQFxmN.js} +1 -1
  41. package/web-app/dist/assets/{chevron-left-CPeGOhGt.js → chevron-left-CCsNBJRT.js} +1 -1
  42. package/web-app/dist/assets/{circle-alert-Cwtuu2Xr.js → circle-alert-tbh0eotU.js} +1 -1
  43. package/web-app/dist/assets/{clock-CwRw08oZ.js → clock-jAqMaUbM.js} +1 -1
  44. package/web-app/dist/assets/{cloud-DGl4zUQq.js → cloud-BkzP_2O3.js} +1 -1
  45. package/web-app/dist/assets/{code-xml-CJ-Q1knR.js → code-xml-BO_XLft5.js} +1 -1
  46. package/web-app/dist/assets/{database-z-xWVQ5b.js → database-BEYnSD3y.js} +1 -1
  47. package/web-app/dist/assets/{dollar-sign-Cvd44aa9.js → dollar-sign-DCS-4ENC.js} +1 -1
  48. package/web-app/dist/assets/{file-code-corner-D14LpiMK.js → file-code-corner-CC-AAFuP.js} +1 -1
  49. package/web-app/dist/assets/{file-plus-ttJnTDT_.js → file-plus-DARaysVE.js} +1 -1
  50. package/web-app/dist/assets/{globe-DuP7Cua6.js → globe-BChKv8f3.js} +1 -1
  51. package/web-app/dist/assets/{hammer-CYq2GDHm.js → hammer-NDAi7rpO.js} +1 -1
  52. package/web-app/dist/assets/{index-CT2oE8Kl.js → index-CfqkxH90.js} +3 -3
  53. package/web-app/dist/assets/{layers-Bc8WbT9k.js → layers-eMnPES9D.js} +1 -1
  54. package/web-app/dist/assets/{loader-circle-d2mz7LEV.js → loader-circle-BPBq3q2l.js} +1 -1
  55. package/web-app/dist/assets/{lock-Ck5Mh1rN.js → lock-Duh0wVt3.js} +1 -1
  56. package/web-app/dist/assets/{package-BQ9Z6lZq.js → package-DFF4Bb2P.js} +1 -1
  57. package/web-app/dist/assets/{plus-CM2G1mBi.js → plus-Dlr8W3yV.js} +1 -1
  58. package/web-app/dist/assets/{refresh-cw-C-UsEISU.js → refresh-cw-DgxH4bSy.js} +1 -1
  59. package/web-app/dist/assets/{rotate-ccw-BUVkLdye.js → rotate-ccw-DU-Os9wC.js} +1 -1
  60. package/web-app/dist/assets/{scroll-text-C4dsalAn.js → scroll-text-S4t8mHDF.js} +1 -1
  61. package/web-app/dist/assets/{server-C-PwNJQZ.js → server-SN6JNCdM.js} +1 -1
  62. package/web-app/dist/assets/{shield-alert-xlj61qF3.js → shield-alert-CIBehVkH.js} +1 -1
  63. package/web-app/dist/assets/{thumbs-up-hqfY-fuM.js → thumbs-up-CJ4n3c2X.js} +1 -1
  64. package/web-app/dist/assets/{trash-2-DeJLxH-E.js → trash-2-BKj6RtAL.js} +1 -1
  65. package/web-app/dist/assets/{trending-down-DZ8saztL.js → trending-down-DGQkEa36.js} +1 -1
  66. package/web-app/dist/assets/{trending-up-eNGjwokM.js → trending-up-CNbeB3P5.js} +1 -1
  67. package/web-app/dist/assets/{upload-Dno5mkwT.js → upload-BcCti89m.js} +1 -1
  68. package/web-app/dist/assets/{usePolling-CS6DDczq.js → usePolling-6qsv_mtm.js} +1 -1
  69. package/web-app/dist/assets/{user-CmMF5dGD.js → user-7N9sAvJt.js} +1 -1
  70. package/web-app/dist/index.html +1 -1
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Runs an autonomous software factory that knows what it is supposed to deliver and proves it did, with a signed receipt. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v11.55.2
6
+ # Loki Mode v11.56.0
7
7
 
8
8
  **Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
9
9
 
@@ -476,4 +476,4 @@ Implemented, planned and deprecated items, with the version each landed in: `ski
476
476
 
477
477
  ---
478
478
 
479
- **v11.55.2 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
479
+ **v11.56.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.55.2
1
+ 11.56.0
@@ -27,6 +27,11 @@
27
27
  # element to satisfy Claude's variadic flag.
28
28
  # Returns 0 on success, 1 if the bundle
29
29
  # emission fails.
30
+ # loki_mcp_launch_for -- emit the per-provider MCP launch as one compact JSON
31
+ # object {"argv":[..],"env":{..}[,"reason":".."]}
32
+ # for claude|codex|opencode|cline|aider. Mirror of
33
+ # mcpLaunchFor in loki-ts/src/providers/mcp_config.ts;
34
+ # tests/providers parity test reads both.
30
35
  #
31
36
  # No side effects beyond writing .loki/mcp-config.json (idempotent;
32
37
  # regenerated each call).
@@ -183,3 +188,129 @@ loki_mcp_config_argv() {
183
188
  fi
184
189
  return 0
185
190
  }
191
+
192
+ # ---------- Per-provider MCP launch (CW-10) ----------
193
+ # Usage: loki_mcp_launch_for <provider> [target_dir]
194
+ # claude: the pre-CW-10 --mcp-config paths, unchanged. codex: `-c mcp_servers.*`
195
+ # overrides. opencode: env OPENCODE_CONFIG_CONTENT. cline/aider/unknown: empty
196
+ # launch plus a reason. Servers for codex/opencode: Loki bundle, project
197
+ # <target_dir>/.mcp.json only when LOKI_MCP_PROJECT=1, ~/.claude/mcp.json overlay;
198
+ # bundle wins a name collision, then project over overlay. `${...}` stays literal.
199
+ loki_mcp_launch_for() {
200
+ local provider="${1:-}" target="${2:-${TARGET_DIR:-.}}"
201
+ local claude_argv="" user_path="" project_path="" lsp_detected=0 lsp_bin cline_ver="unknown" line
202
+ case "$provider" in
203
+ claude)
204
+ claude_argv=$(TARGET_DIR="$target" loki_mcp_config_argv) || return 1
205
+ ;;
206
+ codex | opencode)
207
+ TARGET_DIR="$target" loki_mcp_config_path >/dev/null || return 1
208
+ user_path=$(loki_user_mcp_config_path)
209
+ if [ "${LOKI_MCP_PROJECT:-}" = "1" ]; then
210
+ project_path="${target}/.mcp.json"
211
+ fi
212
+ for lsp_bin in typescript-language-server pyright-langserver pylsp gopls rust-analyzer jdtls; do
213
+ if command -v "$lsp_bin" >/dev/null 2>&1; then
214
+ lsp_detected=1
215
+ break
216
+ fi
217
+ done
218
+ ;;
219
+ cline)
220
+ if command -v cline >/dev/null 2>&1; then
221
+ line=$(cline --version 2>/dev/null | head -n 1) || line=""
222
+ line="${line#"${line%%[![:space:]]*}"}"
223
+ line="${line%"${line##*[![:space:]]}"}"
224
+ [ -n "$line" ] && cline_ver="$line"
225
+ fi
226
+ ;;
227
+ esac
228
+ _MCP_PROVIDER="$provider" _MCP_CLAUDE_ARGV="$claude_argv" _MCP_USER="$user_path" _MCP_PROJECT="$project_path" _MCP_LSP="$lsp_detected" _MCP_CLINE_VER="$cline_ver" python3 -c '
229
+ import json, os, re
230
+ prov = os.environ["_MCP_PROVIDER"]
231
+ NAME = re.compile(r"^[A-Za-z0-9_-]+$")
232
+ MAXB = 1024 * 1024
233
+
234
+ def norm(raw):
235
+ out = {}
236
+ if not isinstance(raw, dict):
237
+ return out
238
+ for name, e in raw.items():
239
+ if not NAME.match(name) or not isinstance(e, dict):
240
+ continue
241
+ cmd = e.get("command")
242
+ if not isinstance(cmd, str) or not cmd:
243
+ continue
244
+ args = e.get("args", [])
245
+ if not isinstance(args, list) or not all(isinstance(a, str) for a in args):
246
+ continue
247
+ env = e.get("env", {})
248
+ if not isinstance(env, dict) or not all(isinstance(v, str) for v in env.values()):
249
+ continue
250
+ out[name] = {"command": cmd, "args": args, "env": env}
251
+ return out
252
+
253
+ def load(p):
254
+ if not p:
255
+ return {}
256
+ try:
257
+ if not os.path.isfile(p) or os.path.getsize(p) > MAXB:
258
+ return {}
259
+ with open(p, encoding="utf-8") as h:
260
+ v = json.load(h)
261
+ return norm(v.get("mcpServers")) if isinstance(v, dict) else {}
262
+ except (OSError, ValueError):
263
+ return {}
264
+
265
+ def dumps(v):
266
+ return json.dumps(v, ensure_ascii=False, separators=(",", ":"))
267
+
268
+ def servers():
269
+ merged = {}
270
+ merged.update(load(os.environ["_MCP_USER"]))
271
+ merged.update(load(os.environ["_MCP_PROJECT"]))
272
+ bundle = {"loki-mode": {"command": "python3", "args": ["-m", "mcp.server"]}}
273
+ if os.environ["_MCP_LSP"] == "1":
274
+ bundle["lsp-proxy"] = {"command": "python3", "args": ["-m", "mcp.lsp_proxy"]}
275
+ merged.update(norm(bundle))
276
+ ordered = {k: merged[k] for k in bundle}
277
+ for k, v in merged.items():
278
+ if k not in ordered:
279
+ ordered[k] = v
280
+ return ordered
281
+
282
+ res = {"argv": [], "env": {}}
283
+ if prov == "claude":
284
+ res["argv"] = ["--mcp-config"] + os.environ["_MCP_CLAUDE_ARGV"].split()
285
+ elif prov == "codex":
286
+ skipped = []
287
+ for n, s in servers().items():
288
+ names = [k for k in s["env"] if NAME.match(k)]
289
+ if any(k in res["env"] and res["env"][k] != s["env"][k] for k in names):
290
+ skipped.append(n)
291
+ continue
292
+ res["argv"] += ["-c", "mcp_servers.%s.command=%s" % (n, dumps(s["command"]))]
293
+ res["argv"] += ["-c", "mcp_servers.%s.args=%s" % (n, dumps(s["args"]))]
294
+ if names:
295
+ for k in names:
296
+ res["env"][k] = s["env"][k]
297
+ res["argv"] += ["-c", "mcp_servers.%s.env_vars=%s" % (n, dumps(names))]
298
+ if skipped:
299
+ res["reason"] = "mcp: skipped %s (env name conflict)" % ",".join(skipped)
300
+ elif prov == "opencode":
301
+ mcp = {}
302
+ for n, s in servers().items():
303
+ e = {"type": "local", "command": [s["command"]] + s["args"], "enabled": True}
304
+ if s["env"]:
305
+ e["environment"] = s["env"]
306
+ mcp[n] = e
307
+ res["env"] = {"OPENCODE_CONFIG_CONTENT": dumps({"mcp": mcp})}
308
+ elif prov == "cline":
309
+ res["reason"] = "mcp: unsupported (cline %s)" % os.environ["_MCP_CLINE_VER"]
310
+ elif prov == "aider":
311
+ res["reason"] = "mcp: unsupported (aider has no MCP support)"
312
+ else:
313
+ res["reason"] = "mcp: unsupported (provider %s)" % prov
314
+ print(dumps(res))
315
+ '
316
+ }
@@ -7,6 +7,6 @@ Modules:
7
7
  control: Session control helpers (status, atomic writes, origin check)
8
8
  """
9
9
 
10
- __version__ = "11.55.2"
10
+ __version__ = "11.56.0"
11
11
 
12
12
  __all__ = ["__version__"]
@@ -1,6 +1,6 @@
1
1
  # CLI reference
2
2
 
3
- Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.55.2. Do not edit by hand.
3
+ Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.56.0. Do not edit by hand.
4
4
  Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for the full inventory.
5
5
 
6
6
  | Command | Description |
@@ -2,7 +2,7 @@
2
2
 
3
3
  Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
4
4
 
5
- **Version:** v11.55.2
5
+ **Version:** v11.56.0
6
6
 
7
7
  **Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
8
8
 
@@ -1443,3 +1443,15 @@ L0 review rule (ENGINE-LAWS.md L0): a fix that adds an `if` or a regex about the
1443
1443
  - Siblings swept: all 14 literals in loki-ts/tests, replaced in one change; per-test `, N)` timeouts are explicit single-test budgets and are not in this class.
1444
1444
  - Mechanism: loki-ts/tests/preload.ts exports `setLoadAwareTimeout(baseMs)`: baseMs times clamp(ceil(2 * loadavg1 / cpus), 1, 10). `LOKI_TEST_TIMEOUT_SCALE` (positive number, capped at 10) replaces the factor; `LOKI_TEST_TIMEOUT_MS` is a floor that wins when larger. A guard in loki-ts/tests/util fails on any direct `setDefaultTimeout(` call in tests.
1445
1445
  - Fixture: loki-ts/tests/util/test_timeout_guard.test.ts tests FC-TEST-TIMEOUT-OVERRIDES-CLI, including a subprocess run through the real setLoadAwareTimeout path (env knob lifts the budget, a real hang still times out).
1446
+
1447
+ - Siblings swept: every registered MCP tool and resource, via the runtime-derived guard in tests/mcp/test_phase1_tools.py (seeds this cache with the marker; the observer now also sees os.scandir, os.stat, Path.iterdir and glob); the JS mirror declares its fields in src/protocols and counts them in tests/protocols/mcp-server.test.js.
1448
+ - Mechanism: part 1 (this change) moves loki_verify_fast findings under untrusted_content via _UNTRUSTED_FIELDS. The verdict-suppression half is open in #319 (cache entries must be authenticated or re-derived, then the row is closed).
1449
+ - Fixture: tests/mcp/test_phase1_tools.py test_stored_text_appears_only_inside_untrusted_content (red with loki_verify_fast trusted: leaks ['loki_verify_fast']; green after).
1450
+
1451
+ ## FC-STATE-MANAGER-ROOT-IGNORED A process-wide state manager singleton ignored its lokiDir after first use, and a per-root cache would grow without bound
1452
+ - User-visible vs raw: user-visible. getStateManager({ lokiDir }) for a second .loki directory returned the first directory's manager, so reads and writes for run B landed in run A's state; a long-lived process serving many roots would have leaked one open watcher per root once keyed naively.
1453
+ - Law: a keyed accessor honours its key on every call; a cache that holds OS resources is bounded and releases what it evicts.
1454
+ - Cause (measured): state/manager.ts kept one module-level defaultManager and created it from the first call's options only.
1455
+ - Siblings swept: state/manager.py get_state_manager has the same single-default shape and is to follow the same keying rule (separate branch); no other TS caller passes arguments to getStateManager.
1456
+ - Mechanism: one per-root cache in state/manager.ts keyed by the (st_dev, st_ino) of the .loki directory (symlinks and case spellings share a manager), capped by LOKI_STATE_MANAGER_MAX (default 8), least recently used evicted and stop()ped.
1457
+ - Fixture: loki-ts/tests/state_manager.test.ts (under loki-ts so bun and CI discover it). Red on origin/main (2 fail), green after (5 pass or 4 pass and 1 skip on a case-sensitive volume); mutations: no eviction, eviction without stop, path-string key, constant key, no LRU touch each go red.