loki-mode 10.5.34 → 10.6.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 (73) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/trigger-server.py +24 -0
  4. package/bin/loki +4 -4
  5. package/dashboard/__init__.py +1 -1
  6. package/docs/INSTALLATION.md +1 -1
  7. package/docs/v10/BOARD.md +1 -0
  8. package/docs/v10/CONTROL-PLANE.md +102 -0
  9. package/docs/v10/DECISIONS.md +30 -0
  10. package/docs/v10/LEGACY-REMOVAL.md +101 -0
  11. package/docs/v10/OPERATING-MODEL.md +1 -1
  12. package/docs/v10/PROGRESS.md +13 -0
  13. package/loki-ts/dist/loki.js +2 -2
  14. package/mcp/__init__.py +1 -1
  15. package/package.json +8 -2
  16. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  17. package/web-app/dist/assets/{AdminPage-CEw59Cx0.js → AdminPage-B8LTaWIa.js} +1 -1
  18. package/web-app/dist/assets/{Avatar-CXd7G2uw.js → Avatar-BbxCTNns.js} +1 -1
  19. package/web-app/dist/assets/{Badge-SNwpbVfd.js → Badge-DIjrBQFC.js} +1 -1
  20. package/web-app/dist/assets/{Button-C6aGc2pY.js → Button-LgRYqCHv.js} +1 -1
  21. package/web-app/dist/assets/{CockpitPage-BcQbFHMz.js → CockpitPage-BgEdvdXX.js} +1 -1
  22. package/web-app/dist/assets/{ComparePage-CXfn6H-J.js → ComparePage-BPttVkSu.js} +1 -1
  23. package/web-app/dist/assets/{ErrorBoundary-CaGNFbbH.js → ErrorBoundary-DCPrb7ec.js} +1 -1
  24. package/web-app/dist/assets/{EvidenceReceiptPanel-bPAsdqka.js → EvidenceReceiptPanel-BLqfCaoK.js} +1 -1
  25. package/web-app/dist/assets/{GitHubIssuesPanel-DRiymrVm.js → GitHubIssuesPanel-Ch61Yw6v.js} +1 -1
  26. package/web-app/dist/assets/{GitHubPRsPanel-s541H5KI.js → GitHubPRsPanel-Cju9OEP1.js} +1 -1
  27. package/web-app/dist/assets/{HomePage-CN8_ol02.js → HomePage-BSt5tg3Z.js} +2 -2
  28. package/web-app/dist/assets/{LoginPage-DT557A5a.js → LoginPage-Cj9xl0pH.js} +1 -1
  29. package/web-app/dist/assets/{MagicPage-Zae7_7ax.js → MagicPage-CyfrX553.js} +1 -1
  30. package/web-app/dist/assets/{MetricsPage-Bx4KkCGZ.js → MetricsPage-Ck6jFgAN.js} +1 -1
  31. package/web-app/dist/assets/{NotFoundPage-IKXpKLQi.js → NotFoundPage-CA_HlCgz.js} +1 -1
  32. package/web-app/dist/assets/{ProjectPage-DD9SaYR9.js → ProjectPage-BkpztOmm.js} +3 -3
  33. package/web-app/dist/assets/{ProjectsPage-3gh-k6d0.js → ProjectsPage-urTkLe8m.js} +1 -1
  34. package/web-app/dist/assets/{SettingsPage-CSrsQWfF.js → SettingsPage-COvHhevh.js} +1 -1
  35. package/web-app/dist/assets/{ShowcasePage--iJJsEM7.js → ShowcasePage-BNIiqhqk.js} +1 -1
  36. package/web-app/dist/assets/{SystemSettingsPage-DTITTTRP.js → SystemSettingsPage-CBPa5u-v.js} +1 -1
  37. package/web-app/dist/assets/{TeamsPage-DueiUphA.js → TeamsPage-DuuHXfkP.js} +1 -1
  38. package/web-app/dist/assets/{TemplatesPage-BC59NBVY.js → TemplatesPage-C8tRhU8-.js} +1 -1
  39. package/web-app/dist/assets/{TerminalOutput-Lg79WAdo.js → TerminalOutput-BOL99fiQ.js} +1 -1
  40. package/web-app/dist/assets/{activity-DFPp5cwI.js → activity-92O1sR3_.js} +1 -1
  41. package/web-app/dist/assets/{bell-Dos83dJ_.js → bell-CeWSKe4w.js} +1 -1
  42. package/web-app/dist/assets/{bot-BpvsFlSf.js → bot-n8nzxbS2.js} +1 -1
  43. package/web-app/dist/assets/{check-BJ40bgL4.js → check-C-8ho0t2.js} +1 -1
  44. package/web-app/dist/assets/{chevron-left-Rumv3O1P.js → chevron-left-D4UQrt8-.js} +1 -1
  45. package/web-app/dist/assets/{circle-alert-DVrRaJyC.js → circle-alert-BnxgnWHv.js} +1 -1
  46. package/web-app/dist/assets/{clock-BqNrxAWL.js → clock-DgbJFbcN.js} +1 -1
  47. package/web-app/dist/assets/{cloud-Byol2PKg.js → cloud-BSEYN8y8.js} +1 -1
  48. package/web-app/dist/assets/{code-xml-BP8i3xZH.js → code-xml-CFYOlC1u.js} +1 -1
  49. package/web-app/dist/assets/{database-BedSSWj2.js → database-DNJ4cz62.js} +1 -1
  50. package/web-app/dist/assets/{dollar-sign-BS8_S1W0.js → dollar-sign-DZ1zEfep.js} +1 -1
  51. package/web-app/dist/assets/{file-code-corner-dsmdTS7W.js → file-code-corner-D9vIN2Ru.js} +1 -1
  52. package/web-app/dist/assets/{file-plus-gf5DDnBC.js → file-plus-B4TugJYw.js} +1 -1
  53. package/web-app/dist/assets/{globe-6CVCcWN0.js → globe-BPNU50l7.js} +1 -1
  54. package/web-app/dist/assets/{hammer-CF2_M3Xz.js → hammer-CwVF_APh.js} +1 -1
  55. package/web-app/dist/assets/{index-xqjdd8CW.js → index-DnAhEaY4.js} +3 -3
  56. package/web-app/dist/assets/{layers-spb5cYTT.js → layers-DNBXP7Gs.js} +1 -1
  57. package/web-app/dist/assets/{loader-circle-a5qrA7Dl.js → loader-circle-bh-SWjhS.js} +1 -1
  58. package/web-app/dist/assets/{lock-B4-6MCIB.js → lock-CpbXWrBs.js} +1 -1
  59. package/web-app/dist/assets/{package-Cn62Lu5E.js → package-3NG8Vkod.js} +1 -1
  60. package/web-app/dist/assets/{plus-B1yous3j.js → plus-C1DPukhG.js} +1 -1
  61. package/web-app/dist/assets/{refresh-cw-Cy418vYC.js → refresh-cw-Cgl65iQ2.js} +1 -1
  62. package/web-app/dist/assets/{rotate-ccw-CGktNxN4.js → rotate-ccw-BS5sMMYV.js} +1 -1
  63. package/web-app/dist/assets/{scroll-text-C97gY2NG.js → scroll-text-BpvzZAZR.js} +1 -1
  64. package/web-app/dist/assets/{server-BFP4sNN3.js → server-DSLFedy_.js} +1 -1
  65. package/web-app/dist/assets/{shield-alert-CmM7wIvE.js → shield-alert-BlG8AkvF.js} +1 -1
  66. package/web-app/dist/assets/{thumbs-up-Qz1Mzhzi.js → thumbs-up-BJcYgjRU.js} +1 -1
  67. package/web-app/dist/assets/{trash-2-D5n8O-BG.js → trash-2-CScLwgFk.js} +1 -1
  68. package/web-app/dist/assets/{trending-down-C9J_yIll.js → trending-down-BPRGGG_g.js} +1 -1
  69. package/web-app/dist/assets/{trending-up-BT7svddv.js → trending-up-BpLBFaZo.js} +1 -1
  70. package/web-app/dist/assets/{upload-Dyv0ClcL.js → upload-LgGE0PEa.js} +1 -1
  71. package/web-app/dist/assets/{usePolling-0oAkpFZj.js → usePolling-0W4sMm7u.js} +1 -1
  72. package/web-app/dist/assets/{user-K6ImWht9.js → user-D4KBUK1Z.js} +1 -1
  73. package/web-app/dist/index.html +1 -1
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: An autonomous software factory that knows what it is supposed to deliver, and proves it did. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v10.5.34
6
+ # Loki Mode v10.6.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -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
- **v10.5.34 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
473
+ **v10.6.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 10.5.34
1
+ 10.6.0
@@ -42,6 +42,7 @@ import os
42
42
  import queue
43
43
  import re
44
44
  import secrets
45
+ import signal
45
46
  import socket
46
47
  import socketserver
47
48
  import subprocess
@@ -373,6 +374,9 @@ def _reap_child(proc):
373
374
  abandoning the child (which would leave a zombie until this process exits),
374
375
  a one-shot daemon thread blocks on wait() until the child finishes. Errors
375
376
  are swallowed because the only goal is to drain the child's exit status.
377
+
378
+ Daemon threads must not write to stdout to avoid blocking the interpreter
379
+ shutdown with closed-pipe issues; logging goes to stderr only.
376
380
  """
377
381
  try:
378
382
  proc.wait()
@@ -1418,4 +1422,24 @@ def main():
1418
1422
 
1419
1423
 
1420
1424
  if __name__ == "__main__":
1425
+ # ponytail: SIGPIPE handler for piped output. When stdout is a pipe and the
1426
+ # reader closes early (e.g., `| head`), Python tries to write to a closed
1427
+ # pipe, raising BrokenPipeError. The default handler raises; SIG_DFL
1428
+ # silently closes. Guarded with hasattr for portability (Windows has no SIGPIPE).
1429
+ if hasattr(signal, "SIGPIPE"):
1430
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
1431
+
1421
1432
  main()
1433
+
1434
+ # ponytail: flush stdout/stderr inside try/except BrokenPipeError before
1435
+ # exit, then call os._exit() to avoid daemon thread cleanup during
1436
+ # interpreter shutdown. This prevents the "could not acquire lock for
1437
+ # <stdout> at interpreter shutdown" error when stdout is a closed pipe
1438
+ # (e.g., piped to `head`, a hook timeout, or a killed parent).
1439
+ # Only in __main__, never inside main(), so tests/callers can import main().
1440
+ try:
1441
+ sys.stdout.flush()
1442
+ sys.stderr.flush()
1443
+ except BrokenPipeError:
1444
+ pass
1445
+ os._exit(0)
package/bin/loki CHANGED
@@ -244,8 +244,8 @@ if [ "${LOKI_LEGACY_BASH:-0}" = "1" ] || [ "${LOKI_LEGACY_BASH:-}" = "true" ]; t
244
244
  fi
245
245
 
246
246
  # Loki 10 bun resolver: bun on PATH, then an npm-installed @oven/bun-* optional
247
- # dependency under REPO_ROOT (postinstall moves it to node_modules/bun/bin/bun.exe;
248
- # under --ignore-scripts it stays in @oven/bun-<os>-<arch>). A candidate counts only if `--version` exits 0
247
+ # dependency under REPO_ROOT (the per-platform packages ship the binary and have no
248
+ # install scripts; node_modules/bun/bin/bun.exe is a legacy fallback). A candidate counts only if `--version` exits 0
249
249
  # within 2s. Prints the path, or nothing.
250
250
  _loki_bun_probe() {
251
251
  local c="$1" t p w rc
@@ -263,7 +263,7 @@ _loki_bun() {
263
263
  local c
264
264
  c=$(command -v bun 2>/dev/null || true)
265
265
  if [ -n "$c" ] && _loki_bun_probe "$c"; then printf '%s\n' "$c"; return 0; fi
266
- for c in "$REPO_ROOT/node_modules/bun/bin/bun.exe" "$REPO_ROOT"/node_modules/@oven/bun-*/bin/bun; do
266
+ for c in "$REPO_ROOT"/node_modules/@oven/bun-*/bin/bun "$REPO_ROOT"/node_modules/@oven/bun-*/bin/bun.exe "$REPO_ROOT/node_modules/bun/bin/bun.exe"; do
267
267
  [ -x "$c" ] && _loki_bun_probe "$c" && { printf '%s\n' "$c"; return 0; }
268
268
  done
269
269
  return 0
@@ -271,7 +271,7 @@ _loki_bun() {
271
271
  # Reason text for the fallback notice: missing, or failed to start, exit N.
272
272
  _loki_bun_why() {
273
273
  local c rc
274
- for c in "$REPO_ROOT/node_modules/bun/bin/bun.exe" "$REPO_ROOT"/node_modules/@oven/bun-*/bin/bun; do
274
+ for c in "$REPO_ROOT"/node_modules/@oven/bun-*/bin/bun "$REPO_ROOT"/node_modules/@oven/bun-*/bin/bun.exe "$REPO_ROOT/node_modules/bun/bin/bun.exe"; do
275
275
  [ -x "$c" ] || continue
276
276
  _loki_bun_probe "$c"; rc=$?
277
277
  echo "failed to start, exit $rc"; return 0
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "10.5.34"
10
+ __version__ = "10.6.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -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:** v10.5.34
5
+ **Version:** v10.6.0
6
6
 
7
7
  ---
8
8
 
package/docs/v10/BOARD.md CHANGED
@@ -618,6 +618,7 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
618
618
  | D50-F2r | D50-F2 rework, honest label only: label a test value change only on the expected side of an assert comparison or a parametrize expected value, only when the old or new value appears in the task text; wording 'assertion value changed (not shown to be required by the task): file:line old -> new' and keep the 'weakened test' line beside it; exclude control flow, range, tolerances, approx kwargs, decorators | loki-ts/src/e10ext classifier, engine10 verify and seal wiring, tests, dist | probes C D E F G H K from the F2 review all keep 'weakened test'; A labelled only when 5 appears in the task; verdict PARTIAL in every case | HIGH | building@2026-10-01T13:50Z r3 (r2 38d8ffe7 REJECTED: tolerance column never read in the body passes as expected; token boundaries let -25 match 25; required: seal re-check on the committed blob with verify counts) | none |
619
619
  | D50-F2-S3 | humanize-174 lift: let the implement brief edit an existing assertion only when the task text states the new expected value; verdict stays PARTIAL, never VERIFIED (moat). CTO call needed first: does a PARTIAL spec-required test edit count as the right outcome, and does the brief license weaken the append-only rule (context.ts:23) | loki-ts/src/e10ext/context.ts, verify and wall policy, eval fixture through implement | humanize-174 fixture through implement ends with code fixed and the spec value assertion changed, PARTIAL with an honest note | HIGH | ready (D53 ruled 12:39Z: VERIFIED allowed when the new literal is verbatim in the issue, the edit changes only that literal in an existing assert, and Wall plus other tests pass; PARTIAL never scores completed; red bypass tests for tolerance, if True to False, deleted assert, literal not in issue) | needs D50-F2r |
620
620
  | D50-F4b | D50-F4 hardening from the opus review (non-blocking): validate base from the worker-written event log as ^[0-9a-f]{40,64}$ before any git call, and skip the backstop when log.verify() fails | loki-ts/src/engine10/supervisor.ts or e10ext/commit_filter.ts, tests | a base of --output=x is refused with no git call; a tampered log runs no backstop | MEDIUM | ready@2026-10-01T13:50Z | none |
621
+ | NPM-LAG | CORRECTED 16:14Z: v10.5.34 (ceb6942a) was accepted by npm at 15:37Z with the notice that it was being processed, and appeared in the registry only at 16:05:58Z (about 29 min; gitHead ceb6942a correct). Not a lost publish, a long npm processing delay, while the Release run already showed success. Guard: publish-npm, post-release-smoke and promote wait up to 45 min for the version (registry, no cache) before declaring it missing, and promote re-triggers when it appears, so a delay is never read as a failure or a pass (10.5.34 smoke failed ETARGET during the lag and skipped promote; rerun 16:30Z); train-cycle merges origin/main back into local main after each release (it stalled at 16:20Z with local main behind its own release) and waits on previous version visible; the release captain (train-cycle.sh) refuses the next release while the previous version is missing from npm | .github/workflows/release.yml publish-npm, scripts/train-cycle.sh, tests | a stubbed npm that never lists the version fails the step; train-cycle logs PREV_NOT_ON_NPM and waits | MEDIUM | ready@2026-10-01T16:14Z | none |
621
622
  | D53-Q1 | CTO call before D50-F2-S3: under D53(a) a bug-report task ('Expected 200, got 404') lets a test change to the buggy value pass the literal-only gate; only Wall coverage of that behaviour stops it. Options: require the new literal to sit on the expected side of an expected/should phrase in the task, or require Wall coverage of the edited assertion | docs/v10/DECISIONS.md D53 | ruling recorded | HIGH | released@2026-10-01T14:20Z (ruled in DECISIONS D53 amendment: literal must be the EXPECTED value in the acceptance criteria with a source span; Wall must cover the behaviour; unclassifiable stays PARTIAL) | none |
622
623
  | D50-F4 | aiq-52 diagnosis: on FAILED, backstopCommit runs git add -A and re-stages the commit stage's exclusions (pre-existing dirt, Wall files, stray lockfiles), so a PR with only setup dirt is pushed. Backstop applies the same exclusions; nothing left means no commit and no PR | loki-ts/src/engine10/supervisor.ts, e10ext helper, tests, dist | preexisting-dirty fixture with FAILED: HEAD equals base and no PR; with a run edit the backstop commit holds only that edit; Wall and stray lockfile never committed | HIGH | merged@2026-10-01T13:50Z 8364a03e (ed8caedf, opus APPROVE r2: filter fixture shows no token, hooks, fsmonitor, textconv or ext-diff with the supervisor env; train/61) | none |
623
624
  | D50-F5 | aiq-52 lift: already_done.ts findEvidence misses compound task keywords (searchbar vs search-command); add deterministic compound-token matching and a same-stem source plus referencing-test category pair; confirmation still must cite a real hit | loki-ts/src/e10ext/already_done.ts, tests, dist | aiq-52-shaped fixture yields a candidate; unrelated keyword, source without referencing test and short prefix yield none | HIGH | building@2026-10-01T13:50Z r3 (r2 f4aa8cc9 REJECTED: derivational suffixes, authorization vs author.ts, productivity vs product.ts; import detection counts strings, comments and docstrings) | none |
@@ -0,0 +1,102 @@
1
+ # Loki Control Plane (D56)
2
+
3
+ Architect design, 2026-10-01, base 1dfc87103. Design only. Flag: `LOKI_CONTROL=1` until acceptance (slice CP-17).
4
+
5
+ ## 1. Goal
6
+ 1. One service plus one UI, `loki control`, replaces dashboard/, dashboard-ui/ and engine10/dashboard. Zero config locally; deployed once for hundreds of runs.
7
+ 2. Stateless processes, all state in one DB (SQLite by default, Postgres via DATABASE_URL), self-healing, horizontally scalable on Postgres.
8
+ 3. Every number is folded from ingested run events. A panel with no data says "no data ingested", never 0.
9
+
10
+ ## 2. Data sources today
11
+ | Source | Where | Status |
12
+ |---|---|---|
13
+ | Run event log, append-only JSONL, envelope `{v,seq,ts,run,type,stage,data}` | engine10/events.ts:11-23 (validate), :54-89 (single writer), types.ts:26-43 (26 types) | REAL. The spool. |
14
+ | Folded run state: verdict, stages, cost (usd null when any session unpriced) | events.ts:106-140 `fold()`, :143-152 `partialCost()` | REAL. Reuse as is. |
15
+ | Run start data: task_source, issue_ref, provider, model, deep, cap_s, branch, origin_repo | supervisor.ts:194, cli data at supervisor.ts:331-334 | REAL |
16
+ | PR URL | `pr.opened {url,draft,existing}` supervisor.ts:233; `run.completed.pr_url` supervisor.ts:252 | REAL (opened only) |
17
+ | PR merged, issue closed | nowhere | MISSING. No event records merge or close. |
18
+ | Cost per session: usd, tokens, cache tokens, model, source | `cost` event session.ts:127-130 | REAL |
19
+ | Receipt and NOT PROVEN | receipt.json, schema types.ts:139-181; `receipt.sealed {path,receipt_sha256,signed,verdict,not_proven}` stages/seal.ts:292; `run.completed.not_proven` supervisor.ts:252 | REAL |
20
+ | Backlog queue (queued, running, BUDGET_STOP) | autonomy/lib/backlog.py:194-257, in memory only | MISSING from any durable store |
21
+ | Workspace group state | `~/.loki/workspaces/<ws>/<group>/group.json`, docs/v10/D51-PHASE-B.md | NOT BUILT (design only) |
22
+ | engine10 dashboard | engine10/dashboard/server.ts:30-57 (fold-based), routes :116-125 | REAL, but one repo, one process, 127.0.0.1 |
23
+ | Python dashboard, 168 routes | dashboard/server.py (13,171 lines); cost reads `.loki/metrics/efficiency` server.py:7869 | REAL but legacy: reads run.sh state that v10 runs never write |
24
+ | Pricing table | dashboard/server.py:7748, :8582 ("Unverified placeholder rate") | INVENTED |
25
+ | dashboard-ui /api/v2 activity, agents/leaderboard, cost/breakdown, memory/graph, pipeline/status, providers/health | dashboard-ui/index.js:100-105, issue #203 | INVENTED (no server route) |
26
+ | Secret redaction | util/redact.ts:4-14 `redactSecrets`; seal.ts:30 `sanitizeReason`; output.ts:79 Reason line | REAL. Reuse. |
27
+
28
+ ## 3. Data model (Drizzle, one schema for SQLite and Postgres)
29
+ - `sources(id PK, host_hash, repo_path_hash, origin_repo, first_seen, last_seen)`. id = sha256(hostname + "\0" + realpath(repo)) truncated to 16 hex, computed by the shipper. No raw paths or hostnames stored.
30
+ - `events(source_id, run_id, seq, PK(source_id, run_id, seq), ts, type, stage, data JSON, line_sha256, received_at)`. Index (run_id, seq), (type, ts).
31
+ - `runs(source_id, run_id, PK(source_id, run_id), origin_repo, issue_ref, task_source, provider, model, started_at, ended_at, verdict, outcome, pr_url, pr_draft, cost_usd NULL, partial_usd, measured_sessions, total_sessions, input_tokens, output_tokens, wall_s, last_seq, last_event_at, tampered, conflict)`. A projection, rebuilt from `events` by `fold()` on every ingest batch for the touched runs; never written any other way.
32
+ - `receipts(source_id, run_id, PK, receipt_sha256, verdict, not_proven JSON, body JSON)`.
33
+ - `work_items(origin_repo, kind 'issue'|'pr', number, PK(origin_repo, kind, number), state, url, observed_at, run_id NULL)`. Fed only by `work.observed` events (CP-12).
34
+ - Event id = `source_id:run_id:seq`. Same id and same line_sha256 is a no-op (idempotent retry). Same id with a different hash returns 409, sets `runs.conflict = 1` and never overwrites.
35
+ - Derived views (SQL, not tables): in-progress = started, no run.completed, last_event_at within 10 min; stale = same but older (heartbeat lost); per-day cost; verdict counts; issue to PR join on (origin_repo, issue_ref).
36
+ - Seal verification stays with `loki verify` on local files: the shipper redacts, so stored bytes may differ from events.jsonl.
37
+
38
+ ## 4. API (Hono, JSON, prefix /v1)
39
+ - `POST /v1/ingest {source, run_id, events[]}`: at most 500 events or 1 MB, each validated with `validateEnvelope()` (events.ts:11), redacted again server-side with `redactSecrets`. Returns `{accepted, duplicate, conflict, last_seq}`.
40
+ - `PUT /v1/runs/:source/:run/receipt`: receipt.json; 400 unless its receipt_sha256 matches a received `receipt.sealed` event.
41
+ - Reads: `GET /v1/runs?repo=&verdict=&provider=&since=&cursor=`, `/v1/runs/:source/:run` (summary + timeline), `/v1/runs/:source/:run/events?after_seq=`, `/v1/stats`, `/v1/costs?group=day|repo|model`, `/v1/compare?ids=`, `/v1/work`, `/v1/backlog`.
42
+ - `GET /health` (process up; `{service:"loki-control", version, install_path, pid}`, the P0-DASH-STATIC identity); `GET /ready` (DB reachable and migrations at head, else 503).
43
+ - Auth: binds 127.0.0.1 by default with no token. A non-loopback bind refuses to start unless `LOKI_CONTROL_TOKEN` is set; then every /v1 call needs `Authorization: Bearer`. Ingest and read share the token in v1.
44
+
45
+ ## 5. Shipper and spool
46
+ - events.jsonl is the spool. The shipper never writes to it (the supervisor treats outside writes as tamper). Its acked cursor lives in `.loki/runs/<id>/ship.json {acked_seq, url}`, written atomically.
47
+ - Started by the supervisor next to the log (one hook line at supervisor.ts:194), it uses `tail()` (events.ts:155), batches up to 200 events or 1 s, and POSTs. Backoff 1, 2, 4 ... 60 s with jitter. It never blocks or fails the run: on supervisor exit it flushes for at most 5 s, then leaves the rest for replay.
48
+ - Every string in `data` goes through `redactSecrets` before sending.
49
+ - Replay: `loki control backfill [--repo DIR]` and every `loki` start ship each run whose ship.json acked_seq is below its last seq. Backfill of old .loki/runs uses the same code path.
50
+
51
+ ## 6. Local auto-start and reuse
52
+ - With LOKI_CONTROL=1 and no LOKI_CONTROL_URL, `loki` reads `~/.loki/control/instance.json {pid, port, version, install_path, db}`.
53
+ - Reuse only when `/health` reports the same version and install_path and `/` returns HTML (the 10.5.34 P0-DASH-STATIC rule). Otherwise start a fresh one on a free port; never kill a process you did not record.
54
+ - A dead pid or failed probe means restart, then replay. The DB defaults to `~/.loki/control/control.db`. Tests always pass a temp HOME, an ephemeral port and `LOKI_NO_BROWSER=1`, and stop by recorded PID.
55
+
56
+ ## 7. Deploy
57
+ - One image: `oven/bun` base, the service plus built UI assets, `bun packages/control-plane/dist/server.js`. Probes: liveness /health, readiness /ready.
58
+ - Helm chart `deploy/helm/loki-control`: replicas 1 with SQLite on a PVC (single writer, documented); replicas N only with DATABASE_URL. Migrations run on boot under a Postgres advisory lock. No in-process pub/sub: the UI polls with a cursor, so any replica serves any request.
59
+ - Clients set `LOKI_CONTROL_URL` and `LOKI_CONTROL_TOKEN`; containers and Helm runs of `loki start` ship the same way.
60
+
61
+ ## 8. Migration and deletion
62
+ 1. Build in packages/control-plane/ behind LOKI_CONTROL=1. The old UIs keep running; old-dashboard bug work is retired (D56.6).
63
+ 2. Acceptance (CP-17): real runs in, correct counts out, on SQLite and Postgres; first-run gate passes with the flag on.
64
+ 3. Flip the default. One release later, delete dashboard/, dashboard-ui/, engine10/dashboard/ (and its registry.ts:19 line), `loki dashboard` becomes an alias of `loki control`, and the dashboard tests are removed (CP-18).
65
+
66
+ ## 9. v0 (ships in 1 to 2 hours on a D46 train)
67
+ CP-00 corpus, then CP-01, CP-02 and CP-03 in parallel, then CP-04 to wire them: SQLite service with ingest, the shipper with backfill, and a UI with the Runs list and detail, all behind the flag.
68
+
69
+ ## 10. Slices
70
+ Rules for every card: file sets do not overlap; only CP-02 touches supervisor.ts and registry.ts, only CP-04 touches autonomy/loki and root package.json. Every Wall check feeds the CP-00 corpus through the real ingest path and asserts exact counts, starting the service on an ephemeral port with a temp DB under LOKI_RUN_TMP. Any new tests/*.sh needs runner registration, a shard row, `timeout -k` and shellcheck.
71
+
72
+ | ID | Scope and file set | Wall check (fixture in, counts out) | Tier | Deps |
73
+ |---|---|---|---|---|
74
+ | CP-00 | Corpus: events.jsonl and receipts written by the real supervisor under the engine10 e2e fake sessions (VERIFIED, PARTIAL, FAILED, BLOCKED, cap.hit, tampered, unpriced cost, resumed). `packages/control-plane/test/fixtures/runs/` + `EXPECTED.json` | EXPECTED.json counts equal a direct `fold()` over each file | LOW | none |
75
+ | CP-01 | **Parallel A.** Service + DB: `src/server/{app,ingest,runs}.ts`, `src/db/{schema,migrate}.ts`, `drizzle/`, `package.json` | ingest corpus twice: run count, verdict counts, cost_usd (null where expected), duplicate=all on 2nd pass; changed line gives 409 | MEDIUM | CP-00 |
76
+ | CP-02 | **Parallel B.** Shipper + backfill: `src/shipper/{ship,backfill}.ts`, hook `loki-ts/src/engine10/ship_hook.ts`, one line each in supervisor.ts and registry.ts | backfill corpus into a CP-01 stub server; kill mid-batch, rerun: every event exactly once; redacted token never appears in the posted body; ship.json advances | MEDIUM | CP-00 |
77
+ | CP-03 | **Parallel C.** UI: `ui/` (Vite, React, Tailwind), Runs list with filters, run detail timeline, receipt and NOT PROVEN panel; empty states | build, render against section 4 JSON captured from the corpus: row count, verdict badges and NOT PROVEN items match EXPECTED.json; empty DB shows "no runs ingested" | MEDIUM | CP-00 |
78
+ | CP-04 | Wire: service serves `ui/dist`; `loki control [serve,backfill,status]` in autonomy/loki + loki-ts cli; bundle into the npm package (`files[]`) | `npm pack` tarball contains server and UI; `loki control serve` + backfill corpus: /v1/runs count = corpus | MEDIUM | 01,02,03 |
79
+ | CP-05 | Local lifecycle: `src/local/lifecycle.ts` (instance.json, reuse rule, restart, replay) | stale-version instance not reused; dead pid restarted and replayed; never touches unrecorded pid | MEDIUM | CP-04 |
80
+ | CP-06 | Auth and bind: `src/server/auth.ts` | non-loopback bind without token exits non-zero; wrong token 401 on ingest and read; loopback no token 200 | HIGH | CP-01 |
81
+ | CP-07 | Postgres: `src/db/pg.ts`, advisory-lock migrations | with DATABASE_URL: two instances ingest corpus concurrently, counts equal SQLite run | MEDIUM | CP-01 |
82
+ | CP-08 | Receipts: `src/server/receipts.ts` + `ui/src/receipt/` | receipt PUT accepted only with matching sealed hash; NOT PROVEN items equal receipt.json | MEDIUM | 01,03 |
83
+ | CP-09 | Overview: `src/server/stats.ts`, `ui/src/overview/` | totals, verdict split, in-progress and stale counts equal EXPECTED.json | LOW | 01,03 |
84
+ | CP-10 | Costs: `src/server/costs.ts`, `ui/src/costs/` | per-day and per-model usd; unpriced run shows partial "N of M sessions", never 0 | MEDIUM | 01,03 |
85
+ | CP-11 | Compare: `src/server/compare.ts`, `ui/src/compare/` | two runs: stage times, cost, verdict, not_proven diff match fixtures | LOW | 01,03 |
86
+ | CP-12 | Work: issues to PRs; `loki control sync` turns `gh pr view`/`gh issue view` on the client into `work.observed` events (no token on the server). `src/sync/`, `src/server/work.ts`, `ui/src/work/` | open, merged, blocked, pending counts from fixture gh JSON; without sync the panel says "merge state not ingested" | MEDIUM | 01,03 |
87
+ | CP-13 | Backlog: backlog.py writes envelope events (`backlog.queued`, `backlog.dispatched`, `backlog.stopped`) to `.loki/backlog/<batch>/events.jsonl`; backfill ships it. `autonomy/lib/backlog.py`, `src/server/backlog.ts`, `ui/src/backlog/` | 5-issue fixture batch: queued, running, done and BUDGET_STOP counts | MEDIUM | 02,03 |
88
+ | CP-14 | Live: cursor polling `ui/src/live/`, `?after_seq=` | append 3 events to a fixture run while open: detail shows them within 2 polls | LOW | 01,03 |
89
+ | CP-15 | Deploy: `packages/control-plane/Dockerfile`, `deploy/helm/loki-control/` | image boots, /ready 200 after migrations; `helm template` renders probes; replicas>1 without DATABASE_URL fails render | MEDIUM | CP-07 |
90
+ | CP-16 | Self-heal: /ready gating, stale-run derivation, replay on boot | DB file removed while up: /ready 503, recovers; stale run flagged after heartbeat gap | LOW | 01,05 |
91
+ | CP-17 | Acceptance + flag flip | full corpus and one real first-run demo run on SQLite and Postgres: every view's counts equal EXPECTED.json | HIGH | all above |
92
+ | CP-18 | Delete dashboard/, dashboard-ui/, engine10/dashboard/, their tests and references | `rg` finds no imports; local-ci fast tier green; first-run gate opens the control UI | HIGH | CP-17 + 1 release |
93
+
94
+ Dependencies to add (none present today; web-app/package.json pins react 19, vite 6, tailwind 3, so align): hono, drizzle-orm, drizzle-kit (dev), react, react-dom, vite, @vitejs/plugin-react, tailwindcss. SQLite uses built-in `bun:sqlite`. Postgres uses drizzle's `bun-sql` driver if the pinned drizzle-orm exports it, otherwise `postgres` is the one extra. No hard blocker found: Bun is already the runtime (bin/loki:94).
95
+
96
+ ## 11. Open questions
97
+ 1. Merge state source: client-side `loki control sync` (chosen default, no server secret) versus a GitHub webhook or App into the service. Webhooks need a public endpoint and a secret.
98
+ 2. Legacy run.sh runs (`LOKI_ENGINE=legacy`) write no events.jsonl. Proposed: not shown. Confirm.
99
+ 3. web-app/ is a fourth UI (Purple Lab, already deprecated). In scope for deletion or not?
100
+ 4. Retention: keep events forever, or prune `heartbeat` after N days?
101
+ 5. One shared token for ingest and read, or separate ingest-only tokens per team (D54 scale, team budgets)?
102
+ 6. Workspaces: once D51 Phase B lands, should group.json also be shipped as envelope events, the same way as backlog (CP-13)?
@@ -449,3 +449,33 @@ Loki's definition: "autonomous software factory that runs with the knowledge of
449
449
  2. Out of scope for v1 (frozen unless a bug blocks v1): loki modernize, new verification features, the gaming matrix, extra dashboards, extra providers, certifications, new engines. Verification is bug-fix only.
450
450
  3. Amendment 15:05Z, the founder's words: "I want sellable product but I don't need to sell right now, don't price anything, everything is still free to use". There is no paid edition and no pricing anywhere; remove "paid", "Team edition", "commercial editions" and "pricing TBD" from docs, README, CLI help and UI. No feature gating, license keys or upgrade prompts in code. LICENSE is untouched (FOUNDER-QUEUE row 7).
451
451
  4. Order: P0 first-run bugs, first run end to end with a recorded demo, PR body and cost cap, D51 Phase B, D51 Phase C. D50 continues only where it raises completion or merge rate. Every release note leads with the user-visible v1 change.
452
+
453
+ ## D55 (CTO, 2026-10-01; reversible via repo variable LOKI_E160_REUSE=0): a push to main reuses a train's verdict for the identical SHA
454
+ 1. Rule (E-160, scripts/ci/train-verdict-reuse.sh). A push to refs/heads/main skips the heavy jobs only when ALL hold: LOKI_E160_REUSE is not 0; the workflow-runs listing for the SHA has total_count of 100 or less; among completed push runs of the same workflow file, other than this run, whose head_branch starts with train/, there is at least one success and no failure, timed_out or startup_failure (cancelled, skipped and neutral count for nothing); and, for Tests only, BEFORE is not all zeros and the BEFORE...SHA compare succeeded, lists fewer than 300 files and touches none of loki-ts/bun.lock, requirements-test.txt, dashboard-ui/package-lock.json. Any parse or API error means reuse=false and the full suite runs. The newest success by created_at is recorded (run id, attempt, branch) in the step summary and a notice; attempts above 1 are accepted.
455
+ 2. Wiring. test.yml: the version-bump-gate skip output is true when either the S-132 gate or the reuse step says so. bun-parity, coverage, first-run-gate and security-audit get a first job train-reuse; every other job needs it and runs under `!cancelled() && needs.train-reuse.outputs.reuse != 'true'`. security-audit sast (CodeQL) is never gated: it always runs on main. coverage and first-run-gate take test.yml's concurrency block (per-ref with cancel for pull_request and train/**, per-SHA without cancel on main).
456
+ 3. Rationale: D28 and D46 item 4 (same SHA means same tree means same workflow YAML). required-ci, train-cycle, the pulse and the version-bump gate already read the train run by head_sha, so no gate gains new trust. Dependency lockfiles are excluded because a fast-forward from an older main can change resolved dependencies that the train run did not see.
457
+ ## D56 (founder, relayed 15:40Z; numbered D56 because D55 is the E-160 CTO ruling): the Loki Control Plane replaces the dashboards
458
+ 1. One service plus one UI, `loki control`, replaces dashboard/, dashboard-ui/ and engine10/dashboard. It runs locally with zero config or is deployed once for many runs. It is stateless and horizontally scalable, keeps all state in a DB (SQLite locally, Postgres via DATABASE_URL), and is self-healing (/health, /ready, migrations on boot, spool replay, CLI restart of a dead local instance, k8s probes, version-checked reuse).
459
+ 2. Stack: TypeScript on Bun with Hono and Drizzle; React, Vite and Tailwind built into static assets served by the same service; one container image.
460
+ 3. Ingest: engine10 ships batched events with idempotent ids to LOKI_CONTROL_URL, with retry; the run's own events.jsonl is the spool. `loki control backfill` imports existing runs.
461
+ 4. Every number comes from ingested events; no placeholders or invented data; an empty panel says so. Localhost-only by default, token auth when bound non-local, no secrets in events.
462
+ 5. Built in packages/control-plane/ behind LOKI_CONTROL=1 until it passes its acceptance tests (real runs in, correct counts out), then the default flips and the old UIs are deleted. v0 (service, SQLite, ingest, shipper, Runs list and detail) ships on D46 trains first; the other views follow train by train.
463
+ 6. Design: docs/v10/CONTROL-PLANE.md (architect slice in progress). Old-dashboard bug work is retired, except the P0 that shipped in 10.5.34.
464
+ ## D55 (CTO, 2026-10-01; reversible via repo variable LOKI_E160_REUSE=0): a push to main reuses a train's verdict for the identical SHA
465
+ 1. Rule (E-160, scripts/ci/train-verdict-reuse.sh). A push to refs/heads/main skips the heavy jobs only when ALL hold: LOKI_E160_REUSE is not 0; the workflow-runs listing for the SHA has total_count of 100 or less; among completed push runs of the same workflow file, other than this run, whose head_branch starts with train/, there is at least one success and no failure, timed_out or startup_failure (cancelled, skipped and neutral count for nothing); and, for Tests only, BEFORE is not all zeros and the BEFORE...SHA compare succeeded, lists fewer than 300 files and touches none of loki-ts/bun.lock, requirements-test.txt, dashboard-ui/package-lock.json. Any parse or API error means reuse=false and the full suite runs. The newest success by created_at is recorded (run id, attempt, branch) in the step summary and a notice; attempts above 1 are accepted.
466
+ 2. Wiring. test.yml: the version-bump-gate skip output is true when either the S-132 gate or the reuse step says so. bun-parity, coverage, first-run-gate and security-audit get a first job train-reuse; every other job needs it and runs under `!cancelled() && needs.train-reuse.outputs.reuse != 'true'`. security-audit sast (CodeQL) is never gated: it always runs on main. coverage and first-run-gate take test.yml's concurrency block (per-ref with cancel for pull_request and train/**, per-SHA without cancel on main).
467
+ 3. Rationale: D28 and D46 item 4 (same SHA means same tree means same workflow YAML). required-ci, train-cycle, the pulse and the version-bump gate already read the train run by head_sha, so no gate gains new trust. Dependency lockfiles are excluded because a fast-forward from an older main can change resolved dependencies that the train run did not see.
468
+
469
+ ## D57 (founder, relayed 16:50Z; "faster" 16:52Z): remove everything legacy, v10 only
470
+ 1. The founder's words: "completely eliminate, deprecate and delete everything legacy, just v10 is enough since our user base so far is super low and we don't have to support anything from legacy". Supersedes the E-35 deprecation, `loki legacy` as an escape hatch, and the legacy leg of the promote gate.
471
+ 2. Wave 1 (10.6.0, minor bump because it breaks the legacy path, within 1 to 2 trains): every entry point routes to v10; `loki legacy`, LOKI_ENGINE and the legacy fallback are removed; when bun cannot run, loki prints a plain error with the one-line fix and exits non-zero (never runs legacy); promote gate leg 2 asserts that error and exit code; README, docs, wiki, CLI help and CHANGELOG say v10 only, with the migration note "legacy removed in 10.6.0; use loki \"<task>\", loki owner/repo#N, loki backlog".
472
+ 3. Wave 2 (following trains): delete legacy code, tests, CI jobs and fixtures in parallel slices, one directory each, every slice independently green (v10 suite, Bun Parity, first-run gate, moat on v10). Anything v10, loki-seal or the Control Plane imports at runtime is kept or ported, never deleted blind. The Python dashboard goes only once Control Plane v0 is the default (D56). Lines deleted are tracked in METRICS.
473
+ 4. Guard: a test fails if any shipped file references run.sh, LOKI_ENGINE or `loki legacy` outside CHANGELOG and the migration note.
474
+ 5. Inventory: docs/v10/LEGACY-REMOVAL.md (architect, 20 minutes, routing and docs surface first).
475
+ 6. D57 product calls (founder delegation, ruled by autonomy-dev-dc, relayed 17:19Z; reversible): (a) PRD and spec start (`loki start ./prd.md`, `--openspec`) have no legacy path; `loki <file>` and `loki "<task>"` read an existing .md, .txt or .yaml file as the task and spec text for one v10 run; greenfield multi-phase PRD builds are dropped (out of D54 v1). (b) `loki quickstart` and templates are removed; first run is `loki` (UI) or `loki "<task>"`; `npx loki-mode tour` stays only if it has no legacy dependency. (c) `loki modernize` already runs on v10 (M-08): code kept, hidden from help and docs as experimental (D54 freeze). (d) The MCP server and the legacy loki-mode Claude Code plugin are removed if they front legacy; only MCP tools that call v10 directly survive; loki-seal stays the only marketplace plugin. (e) Council, gates, RARV, swarms, agent types, voice, grill, BMAD, OpenSpec and Mirofish adapters, `loki heal`, `loki migrate`, and Jira sync if legacy-only are deleted with their docs. (f) Anything else with no v10 equivalent is deleted unless it is in D54 v1 scope; when unsure, it is listed in LEGACY-REMOVAL.md as "deleted, no v10 equivalent" without asking.
476
+
477
+ ## D58 (founder, relayed 17:40Z: "are we even of any use at all for users now?"): basics first, freeze the rest
478
+ 1. Overrides D46 release-rate chasing, D48 and INTEL until all five basics pass. Release count is not the metric until then; pass or fail per basic is reported every hour.
479
+ 2. The five basics, staffed together: (1) `loki start <owner/repo#N | "task" | file>` runs v10 and no user entry point ever invokes legacy (D57 W1-ROUTE); (2) no test binds 57374-57399, the CLI prints and opens the bound port, and Control Plane v0 shows a live run (stage, elapsed time, files touched, PR link); (3) v10 scope control: the committed diff contains only files the task needs, unrelated source edits are reverted, never committed, and listed in NOT PROVEN; (4) install is clean, with no npm allow-scripts warning (BUN-OPT); (5) the real-repo acceptance gate passes before `latest` moves.
480
+ 3. Real-repo gate: from a clean `npm i -g` in a throwaway HOME, `loki start <real issue> --no-pr` on 3 real repos: asklokesh/augmentiq#52 (cloned, no push; expected ALREADY_SATISFIED in under 60s with no diff; 10.5.35 v10 already does this in 24s at $0.07, while legacy ran 18+ minutes and touched 19 files), plus 2 public eval-corpus repos with real open issues that need a change, so the PR path is covered. Pass: v10 engine, 15 minutes or less, diff limited to relevant files, tests green, receipt verifies, dashboard shows the run. Wall time, cost and diff stat per repo go in METRICS. Any failure keeps `latest` where it is.
481
+ 4. D57 Wave 2 deletions continue only as part of basic 1.
@@ -0,0 +1,101 @@
1
+ # Legacy removal inventory (D57)
2
+
3
+ Architect inventory, 2026-10-01, base `main` 80cdb7193. Product calls are D57 item 6 (a to f); nothing here is an open question. "No v10 equivalent" rows are deleted per 6(f) unless named in D54 v1 scope. Evidence is a grep or a file:line; anything not proven unused is KEEP-CHECK, never delete.
4
+
5
+ ## 1. Routing surface (Wave 1, builders already on it)
6
+
7
+ Entry point: package.json `bin.loki = bin/loki`. `BASH_CLI=autonomy/loki` (bin/loki:33). Every `exec "$BASH_CLI"` below is a legacy route.
8
+
9
+ | Where | Legacy behavior | v10 replacement |
10
+ |---|---|---|
11
+ | bin/loki:81, 92, 115 | bad LOKI_TS_ENTRY, BUN_FROM_SOURCE miss, no dist and no src: exec bash | plain error, exit non-zero |
12
+ | bin/loki:242-243 | LOKI_LEGACY_BASH=1 forces bash for every command | delete the knob |
13
+ | bin/loki:300-309 | `modernize` without `--to` goes to bash (heal, migrate) | v10 modernize only, hidden (6c); `heal`, `migrate` deleted (6e) |
14
+ | bin/loki:313-319 | `loki legacy <args>` re-execs with LOKI_ENGINE=legacy | delete; migration note |
15
+ | bin/loki:325-326 | `LOKI_ENGINE` switch, default v10, any other value skips v10 | delete the variable, v10 unconditional |
16
+ | bin/loki:331-342 | status, verify, dashboard, keys reach v10 only with explicit LOKI_ENGINE=v10; bare `verify` picks newest of e10 run vs legacy proof | always engine10 status/verify/keys; dashboard goes to `loki control` once D56 flips |
17
+ | bin/loki:344 | bare `loki` and any flag-first call go to bash | engine10 usage (engine10/cli.ts USAGE) |
18
+ | bin/loki:347-352 | `loki quick --no-pr`, `quick --help` (flag-first) go to legacy quick | `quick <flags> <task>` maps to engine10 `--no-pr`; flags passed through |
19
+ | bin/loki:360 | any one-word argument goes to bash (start, init, stop, config, backlog...) | per-command table below |
20
+ | bin/loki:364-371 | unsupported LOKI_PROVIDER (opencode etc.) falls to legacy | plain error naming claude, codex, cline, aider |
21
+ | bin/loki:372-384 | no working bun: "Running the legacy engine instead" | D57 item 2: print the one-line fix, exit non-zero |
22
+ | bin/loki:388 | error text says "set LOKI_ENGINE=legacy" | drop that hint |
23
+ | bin/loki:397-399 | no bun on PATH: exec bash for everything | same no-bun error as 372-384 |
24
+ | bin/loki:474-477 | `start` with LOKI_SDK_LOOP: v8 Bun loop, diverts to bash for --parallel, --github, --issue, --openspec, --bmad-project, --mirofish*, --sandbox, opencode | `loki <file>` / `loki "<task>"` (6a); issue refs already v10 |
25
+ | bin/loki:492-507 | `trust detail`, `doctor --airgap` exec bash | trust: delete (verification frozen, D54); doctor --airgap: KEEP-CHECK (D54 "your infrastructure"), port to Bun doctor |
26
+ | bin/loki:532-554, 596 | Bun allowlist (version, status, stats, doctor, provider, memory, rollback, internal, kpis, trust, proof, receipt, wiki, crash) runs v8 Bun commands, not engine10 | keep version, doctor; status goes engine10; rest deleted |
27
+ | bin/loki:599 | catch-all `*` exec bash | engine10 run (task) or "unknown command" |
28
+ | loki-ts/src/cli.ts:7, 38-39, 18 | help says "falls through to bash", LOKI_LEGACY_BASH | rewrite help to engine10 USAGE |
29
+ | loki-ts/src/cli.ts:149 | `report` delegates to bash (util/bash_delegate.ts) | delete with report |
30
+ | loki-ts/src/cli.ts:209-231, 295, 313 | `internal` hooks driven by run.sh; `start` (v8 loop); bench to benchmarks/bench/run.sh | delete internal and start; bench KEEP-CHECK (dev tool, not shipped CLI) |
31
+ | loki-ts/src/engine10/cli.ts:3, 28 | comments and USAGE say "LOKI_ENGINE=v10" | drop the phrase |
32
+
33
+ One-word bash commands (autonomy/loki main(), line 21621) and their fate:
34
+ - PORT (v10 scope, hosted in bash today): `backlog` (cmd_backlog autonomy/loki:12875, runs autonomy/lib/backlog.py; D57 migration note depends on it), `config` / `config validate` / `config schema` (D51 loki.yaml), `doctor --airgap`. These must move to Bun before autonomy/loki is deleted. Wave 1 keeps routing them to bash explicitly by name, not via the catch-all.
35
+ - REPLACED: `start <prd>` / `run` / `--openspec` (6a, `loki <file>`), `issue`, `github`, `import` (issue refs), `status`, `verify`, `keys` (engine10), `dashboard`, `web` (`loki control`, D56).
36
+ - DELETED, decided: `quickstart`, `template` (6b); `council`, `grill`, `voice`, `heal`, `migrate`, `agent`, swarm/RARV surfaces (6e). `tour`/`demo` kept only if legacy-free; today they run bash (DELETED unless reimplemented).
37
+ - DELETED, no v10 equivalent (6f): init, stop, cleanup, pause, steer, resume, why, next, stats, monitor, welcome, docker, preview, deploy, ship, open, logs, serve, api, sandbox, notify, watch, cockpit, export, assets, reset, memory, compound, checkpoint, rollback, dogfood, projects, enterprise, secrets, sentrux, setup-skill, self-update, watchdog, audit, compliance, review, ultracode, optimize, spec, intent, mcp, cluster, worktree, state, metrics, cost, estimate, trust, syslog, telemetry, remote, trigger, plan, failover, analyze, onboard, explain, docs, wiki, magic, ci, test, report, crash, share, proof, outcomes, secure, own, context, code, kpis.
38
+ - KEEP-CHECK against D54 v1 "cost and control, scale, audit log, team budgets": `cost`, `audit`, `plan` (cmd_plan carries D5x refs), `self-update`, `provider`. Confirm with PM before deleting; default delete per 6(f) if no v1 owner claims them in one train.
39
+
40
+ ## 2. Docs and help surface (Wave 1)
41
+
42
+ `grep -rlE "run.sh|LOKI_ENGINE|loki legacy|legacy engine"` counts (files / mentions):
43
+ - Root: README.md 19, SKILL.md 10, ARCHITECTURE.md 9, COMPONENTS.md 4, AGENTS.md 2, CONTRIBUTING.md 2, TESTING.md 2, CLAUDE.md 1, SETUP.md 1, Dockerfile 1.
44
+ - docs/: 109 files, 1200 mentions. Shipped (package.json `docs/**/*.md`). Heaviest: v10/BOARD.md 72, BUG-AUDIT-v6.61.0.md 61, ONE-RUN-AUDIT.md 44, BRANCH-LIFECYCLE-PLAN.md 44, CONFIG-FILE-PLAN.md 41, architecture/STATE-MACHINES.md 33, test-scenarios/edge-cases.md 32, v10/ENGINE.md 30, V8-AGENT-SDK-PLAN.md 28, dev/project-structure.md 14. Most are legacy plans: delete, not edit. Keep docs/v10/ (internal records; exclude from `files`).
45
+ - wiki/: 6 files, 13 mentions (Quality-Gates, Enterprise-Features, Enterprise, Contributing, Checkpoints, API-Reference). Quality-Gates and Checkpoints are legacy features: delete pages.
46
+ - skills/ 9 files 33, references/ 7 files 16, vscode-extension/ 3 files 4, integrations/ 2 files 3, templates/ 1 file 2, agent-skills/ 1, packages/loki-seal 4 files 4 (wording only; loki-seal stays).
47
+ - CLI help: autonomy/loki help (goes with the file), loki-ts/src/cli.ts HELP, engine10/cli.ts USAGE, bin/loki error strings (lines 81, 92, 382, 388).
48
+ - completions/_loki, completions/loki.bash: 0 pattern hits but list every bash command; regenerate from the v10 command list.
49
+ - website/: 0 hits.
50
+
51
+ ## 3. Directory classification
52
+
53
+ Evidence: `grep -rn autonomy/|providers/` over loki-ts/src/engine10, packages/control-plane, packages/loki-seal; engine10 relative imports.
54
+
55
+ | Area | Verdict | Evidence |
56
+ |---|---|---|
57
+ | autonomy/run.sh, autonomy/loki, most of autonomy/lib (69 files) | DELETE | no engine10 import; 133k lines in autonomy/ |
58
+ | autonomy/issue-providers.sh | KEEP | engine10/fetch_issue.ts:24 |
59
+ | autonomy/lib/engine10-push.sh, lib/secret-scan.sh | KEEP | stages/pr.ts:24, stages/deep.ts:52-53 |
60
+ | autonomy/lib/modernize/ | KEEP (hidden, 6c) | engine10/modernize via util/python.ts |
61
+ | autonomy/lib/backlog.py | PORT | cmd_backlog; migration note |
62
+ | autonomy/lib/cost-summary.py, app-runner.sh | KEEP-CHECK | named in engine10 comments only (cost.ts:9, deep.ts:102) |
63
+ | autonomy/telemetry.sh, lib/sdk-mode.sh | PORT then delete | sourced by bin/loki:42, 230-238 |
64
+ | providers/*.sh, models.sh | DELETE | ported to loki-ts runner/providers.ts |
65
+ | providers/model_catalog.json | KEEP | engine10/sizing.ts:58 |
66
+ | loki-ts/src/runner, commands, providers (v8 loop) | PORT subset | engine10 imports runner/github_token, types, retry_class, providers, budget; providers/claude_flags, mcp_config; delete the rest |
67
+ | council/, quality gates scripts, swarm/, agents/ | DELETE (6e) | no engine10 refs |
68
+ | dashboard/ (Python) | KEEP until D56 flip, then DELETE | D57 item 3 |
69
+ | dashboard-ui/ | KEEP until D56 flip, then DELETE | same |
70
+ | engine10/dashboard | KEEP until D56 flip | engine10/cli.ts TABLE |
71
+ | web-app/ (Purple Lab) | DELETE | no engine10 or CP ref; 55k lines |
72
+ | mcp/ | DELETE (6d) | mcp/server.py has 0 engine10 calls; loki-ts refs are v8 runner only |
73
+ | skills/, SKILL.md, plugins/, claude/hooks, .claude-plugin | DELETE (6d legacy plugin) | SKILL.md: replace with a v10 stub only if release scripts require it (KEEP-CHECK scripts/ grep) |
74
+ | templates/ | DELETE (6b) | |
75
+ | Dockerfile, helm/, deploy/ | KEEP, PORT entrypoint | D54 v1 scope (container, Helm); Dockerfile has 1 legacy mention |
76
+ | memory/, events/, learning/, magic/, lokistore/, api/, state/, src/ | DELETE, KEEP-CHECK first | in `files`; no engine10 import found |
77
+ | tests/ | 417 of 1186 files reference autonomy/run.sh or autonomy/loki: DELETE with their owner. 16 reference engine10: KEEP |
78
+ | tests/moat/p2, p3, p4 | PORT first | reference autonomy/run.sh; moat must run on v10 |
79
+ | CI: promote.yml:122-146 leg 2 `--engine legacy` | PORT (Wave 1) | assert the no-bun error and exit code |
80
+ | CI: test.yml legacy shards, check-phase6-ready.yml, parity-drift.yml, bun-parity.yml | DELETE with their suites; bun-parity is a Wall check, redefine as v10 Bun suite first |
81
+
82
+ ## 4. Wave 2 slices (safe order, one area each)
83
+
84
+ Wall check for every slice: v10 suite, Bun Parity (redefined in W2-01), first-run gate, moat on v10, all green.
85
+ 1. W2-01 tests/moat port to v10 + redefine Bun Parity as the v10 Bun suite (adds ~300, deletes ~200).
86
+ 2. W2-02 PORT backlog, config, doctor --airgap to Bun (adds ~600).
87
+ 3. W2-03 web-app/ delete (~55k).
88
+ 4. W2-04 templates/, quickstart, tour/demo (~4k).
89
+ 5. W2-05 council, gates scripts, swarm, agents, grill, voice (~10k).
90
+ 6. W2-06 mcp/ + skills/ + plugins/ + SKILL.md + claude/hooks (~16k).
91
+ 7. W2-07 memory/, learning/, magic/, lokistore/, events/, api/, state/, src/ after KEEP-CHECK (~25k).
92
+ 8. W2-08 legacy tests/ (417 files, ~120k) and their CI shards.
93
+ 9. W2-09 loki-ts v8 runner/commands not imported by engine10 (~15k).
94
+ 10. W2-10 providers/*.sh (~3k).
95
+ 11. W2-11 autonomy/run.sh, autonomy/loki, autonomy/lib except KEEP rows (~125k). Last code slice; depends on 01, 02, 08, 09.
96
+ 12. W2-12 legacy docs/ plans and wiki pages (~1000 mentions).
97
+ 13. W2-13 dashboard/ + dashboard-ui/ (~113k), only after D56 default flip.
98
+
99
+ ## 5. Guard spec (D57 item 4)
100
+
101
+ New test `tests/test-no-legacy-refs.sh`: for every path in `npm pack --dry-run --json` output (the shipped set) plus README.md and wiki/, fail on `autonomy/run\.sh`, a bare `\brun\.sh\b` not preceded by `moat/` or `bench/`, `LOKI_ENGINE`, `LOKI_LEGACY_BASH`, or `loki legacy`. Exclusions: CHANGELOG.md and docs/MIGRATION-10.6.md (the migration note) only. Positive control: the test plants one hit in a temp copy and must go red (loki-verify). Phase in: advisory after Wave 1, blocking after W2-11.
@@ -29,7 +29,7 @@ The CEO is Lokesh Mure (Loki), the founder. Everyone else is an agent. The compa
29
29
 
30
30
  ## Release pipeline
31
31
  - Tier A fast gate on every change (target 60-120s): syntax checks, changed-file shellcheck, diff-selected tests, moat suite split per property. It is feedback, not release authority.
32
- - Tier B full verification on every main commit (target 5-6 min, hard 10 min per job, never cancelled on main).
32
+ - Tier B: every main commit has a full Tier B verdict on its exact tree, run on main or on the train that produced it (D55); never cancelled on main.
33
33
  - Release = a lookup: publish a commit whose tree already has a Tier B pass. A VERSION-only bump reuses its parent's verdict. Target: 2 min from verified to npm.
34
34
  - Trains: the Release Manager batches merged slices; one push per train; releases when verified; the next train opens immediately. Never hold a train for one HIGH slice.
35
35
  - If Tier B fails on main: stop releases, open a P0 fix-forward slice. Never unpublish; npm deprecate is allowed.
@@ -1885,3 +1885,16 @@ The swarm is stopped: .loki/V10-STOP exists, the loop has no wake-ups, and the c
1885
1885
  - D50-F5 r3 built (845c1c52, compound-token evidence for aiq-52). D50-F2r r3 (the D53 gate classifier) is building: r2 still let an unread tolerance column and sign-adjacent tokens through. Both go to one batched opus re-review.
1886
1886
  - D53-Q1 for the CTO: under D53(a), a bug-report task can license a test change to the buggy value.
1887
1887
  - Pace: the peer's live /usage showed 36% at 13:30Z, about 4x the pace budget. Capped at about 4 engineers, no new opus except moat or latest-moving reviews, haiku for mechanical work.
1888
+
1889
+ ## 2026-10-01T15:15Z v10.5.33 latest; train/64 in CI; reds dropped per D46 rule 2
1890
+ - Releases per hour (D46 amendment target 6): 1 in the trailing hour (v10.5.33 at 14:57Z, npm gitHead 95049844, auto-promoted to latest). The automated captain (train-cycle.sh) is merged locally for train/65 and is not yet running live.
1891
+ - v10.5.33: D50-F4 (a failed run never opens a PR of the user's pre-existing changes; backstop with the worker env and --no-filters).
1892
+ - train/62 red on tsc (D50-F2r TS2532): F2r dropped, re-landed as F2r4 with a typecheck fix. train/63 red: RC-AUTO (Linux fixture default branch master) and PY-ABORT (os._exit in main() killed pytest workers) dropped and re-landed as RC-AUTO2 and PY-ABORT2. The new rule from two incidents: every loki-ts slice runs bun run typecheck; bun test does not typecheck.
1893
+ - train/64 (b9b7c8a3) in CI: P0 dashboard fix (founder-reported: loki start showed the frontend-not-found JSON; test suites had leaked dashboards into the real HOME and reuse trusted them; now reuse needs same version, package and HTML, LISTEN-only port check, built-in HTML fallback, first-run gate checks GET /), D54 no-pricing sweep, D50-F5, D50-F2r4.
1894
+ - D54 product scope recorded (docs/PRODUCT.md, free, no editions); OPEN ITEMS ledger re-ranked; D50-W1 and D53-Q1 ruled.
1895
+
1896
+ ## 2026-10-01T16:35Z releases automated; npm processing lag; Control Plane v0 near
1897
+ - Releases per hour: 1 in the trailing hour. v10.5.34 (P0 dashboard fix, ceb6942a) published 15:37Z but npm made it visible only at 16:05:58Z (about 29 min); its Post-Release Smoke failed ETARGET during the lag, so promote skipped. Smoke re-run 16:31Z; a green smoke fires the normal two-leg promote. v10.5.35 (c7f80c0b) was cut automatically by train-cycle.sh at 15:50Z (its first automatic release; it also promoted train/65 at 15:40Z); npm still processing at 16:30Z.
1898
+ - NPM-LAG guard row: publish, smoke and promote wait up to 45 min for the version and re-trigger promote; train-cycle merges origin/main back after each release (it stalled at 16:20Z, merged by hand as cc3e1392).
1899
+ - E-160 (D55, train verdict reuse on main; CodeQL always runs; kill switch LOKI_E160_REUSE=0) merged locally after an opus APPROVE.
1900
+ - D56 Control Plane: design (docs/v10/CONTROL-PLANE.md, 19 slices), CP-00 corpus, CP-01 service (Hono, Drizzle, bun:sqlite; idempotent ingest, 409 on conflict, fold-derived runs), CP-02 shipper (no-op unless LOKI_CONTROL_URL; exactly-once backfill; redaction) and CP-03 UI (runs list and detail; unpriced never shown as 0) merged locally. CP-04 (wire loki control, packaging, CI, test isolation) and BUN-OPT (npm 11 allow-scripts warning: per-platform @oven/bun packages) building.
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var vr=Object.create;var{getPrototypeOf:hr,defineProperty:nG,getOwnPropertyNames:gr}=Object;var mr=Object.prototype.hasOwnProperty;function ur($){return this[$]}var pr,dr,cr=($,Z,Q)=>{var X=$!=null&&typeof $==="object";if(X){var J=Z?pr??=new WeakMap:dr??=new WeakMap,K=J.get($);if(K)return K}Q=$!=null?vr(hr($)):{};let Y=Z||!$||!$.__esModule?nG(Q,"default",{value:$,enumerable:!0}):Q;for(let V of gr($))if(!mr.call(Y,V))nG(Y,V,{get:ur.bind($,V),enumerable:!0});if(X)J.set($,Y);return Y};var IK=($,Z)=>()=>(Z||$((Z={exports:{}}).exports,Z),Z.exports);var lr=($)=>$;function ir($,Z){this[$]=lr.bind(null,Z)}var R0=($,Z)=>{for(var Q in Z)nG($,Q,{get:Z[Q],enumerable:!0,configurable:!0,set:ir.bind(Z,Q)})};var v=($,Z)=>()=>($&&(Z=$($=0)),Z);var b4=import.meta.require;var VI={};R0(VI,{lokiDir:()=>T0,homeLokiDir:()=>m7,findRepoRootForVersion:()=>rG,REPO_ROOT:()=>i0});import{resolve as y4,dirname as sG}from"path";import{fileURLToPath as ar}from"url";import{existsSync as FK}from"fs";import{homedir as or}from"os";function nr(){let $=YI;for(let Z=0;Z<6;Z++){if(FK(y4($,"VERSION"))&&FK(y4($,"autonomy/run.sh")))return $;let Q=sG($);if(Q===$)break;$=Q}return y4(YI,"..","..","..")}function rG($){let Z=$;for(let Q=0;Q<6;Q++){if(FK(y4(Z,"VERSION"))&&FK(y4(Z,"autonomy/run.sh")))return Z;let X=sG(Z);if(X===Z)break;Z=X}return y4($,"..","..","..")}function T0(){return process.env.LOKI_DIR??y4(process.cwd(),".loki")}function m7(){return y4(or(),".loki")}var YI,i0;var J8=v(()=>{YI=sG(ar(import.meta.url));i0=nr()});import{readFileSync as sr}from"fs";import{resolve as rr,dirname as tr}from"path";import{fileURLToPath as er}from"url";function _4(){if(u7!==null)return u7;let $="10.5.34";if(typeof $==="string"&&$.length>0)return u7=$,u7;try{let Z=tr(er(import.meta.url)),Q=rG(Z);u7=sr(rr(Q,"VERSION"),"utf-8").trim()}catch{u7="unknown"}return u7}var u7=null;var g$=v(()=>{J8()});var UI={};R0(UI,{runOrThrow:()=>Ot,run:()=>I0,readStreamCapped:()=>DK,commandVersion:()=>Mt,commandExists:()=>O9,ShellError:()=>eG,MAX_STDOUT_BYTES:()=>BI});async function DK($,Z=BI){let Q=$.getReader(),X=new TextDecoder,J="",K=0;try{while(K<Z){let{done:Y,value:V}=await Q.read();if(Y)break;if(!V)continue;if(K+=V.byteLength,K>Z){let z=V.byteLength-(K-Z);J+=X.decode(V.subarray(0,z),{stream:!0});break}J+=X.decode(V,{stream:!0})}J+=X.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return J}async function I0($,Z={}){let Q=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:Z.env?{...process.env,...Z.env}:process.env,cwd:Z.cwd}),X,J;if(Z.timeoutMs&&Z.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}J=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},Z.timeoutMs);try{let[K,Y,V]=await Promise.all([DK(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:K,stderr:Y,exitCode:V}}finally{if(X)clearTimeout(X);if(J)clearTimeout(J)}}async function Ot($,Z={}){let Q=await I0($,Z);if(Q.exitCode!==0)throw new eG(`command failed (${Q.exitCode}): ${$.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function O9($){let Z=Nt($),Q=await I0(["sh","-c",`command -v ${Z}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Nt($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function Mt($,Z="--version"){if(!await O9($))return null;let X=await I0([$,Z],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var BI=16777216,eG;var J9=v(()=>{eG=class eG extends Error{message;exitCode;stdout;stderr;constructor($,Z,Q,X){super($);this.message=$;this.exitCode=Z;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function f4($){return jt?"":$}var jt,k0,P8,p0,zQ8,K8,L8,K9,d;var o5=v(()=>{jt=(process.env.NO_COLOR??"").length>0;k0=f4("\x1B[0;31m"),P8=f4("\x1B[0;32m"),p0=f4("\x1B[1;33m"),zQ8=f4("\x1B[0;34m"),K8=f4("\x1B[0;36m"),L8=f4("\x1B[1m"),K9=f4("\x1B[2m"),d=f4("\x1B[0m")});import{accessSync as Pt,constants as Et,existsSync as kt,statSync as xt}from"fs";async function n5(){if(m$!==void 0)return m$;let $="/opt/homebrew/bin/python3.12";if(kt($))return m$=$,$;let Z=await O9("python3.12");if(Z)return m$=Z,Z;let Q=await O9("python3");return m$=Q,Q}async function I6($,Z={}){let Q=await n5();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return I0([Q,"-c",$],Z)}async function MI(){let $=(process.env.PATH??"").split(":").filter((Z)=>Z.startsWith("/"));for(let Z of[...bt,...$.map((Q)=>`${Q}/python3`)])try{if(!xt(Z).isFile())continue;if(Pt(Z,Et.X_OK),(await I0([Z,"-I","-S","-c",""],{timeoutMs:1e4})).exitCode===0)return Z}catch{}return null}var m$,St,bt;var F6=v(()=>{J9();St=["/usr/bin/python3","/bin/python3"],bt=St});var _I={};R0(_I,{runStatus:()=>Je});import{existsSync as Y9,readFileSync as W2,readdirSync as wI,statSync as PI}from"fs";import{resolve as u8,basename as nt}from"path";import{homedir as st}from"os";function EI($){let Z=Math.trunc($);if(Z>=1e6)return`${(Math.trunc(Z/1e6*10)/10).toFixed(1)}M`;if(Z>=1000)return`${(Math.trunc(Z/1000*10)/10).toFixed(1)}K`;return String(Z)}function kI($,Z,Q){if(Z===0)return null;let X=Math.trunc($*100/Z),J=Math.trunc($*wK/Z);if(J>wK)J=wK;let K=wK-J,Y=P8;if(X>=80)Y=k0;else if(X>=50)Y=p0;let V="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,K)),z=EI($),W=EI(Z);return` ${L8}${Q}${d} ${Y}[${V}]${d} ${X}% (${z} / ${W})`}async function tt(){if(await O9("jq"))return!0;return process.stdout.write(`${k0}Error: jq is required but not installed.${d}
2
+ var vr=Object.create;var{getPrototypeOf:hr,defineProperty:nG,getOwnPropertyNames:gr}=Object;var mr=Object.prototype.hasOwnProperty;function ur($){return this[$]}var pr,dr,cr=($,Z,Q)=>{var X=$!=null&&typeof $==="object";if(X){var J=Z?pr??=new WeakMap:dr??=new WeakMap,K=J.get($);if(K)return K}Q=$!=null?vr(hr($)):{};let Y=Z||!$||!$.__esModule?nG(Q,"default",{value:$,enumerable:!0}):Q;for(let V of gr($))if(!mr.call(Y,V))nG(Y,V,{get:ur.bind($,V),enumerable:!0});if(X)J.set($,Y);return Y};var IK=($,Z)=>()=>(Z||$((Z={exports:{}}).exports,Z),Z.exports);var lr=($)=>$;function ir($,Z){this[$]=lr.bind(null,Z)}var R0=($,Z)=>{for(var Q in Z)nG($,Q,{get:Z[Q],enumerable:!0,configurable:!0,set:ir.bind(Z,Q)})};var v=($,Z)=>()=>($&&(Z=$($=0)),Z);var b4=import.meta.require;var VI={};R0(VI,{lokiDir:()=>T0,homeLokiDir:()=>m7,findRepoRootForVersion:()=>rG,REPO_ROOT:()=>i0});import{resolve as y4,dirname as sG}from"path";import{fileURLToPath as ar}from"url";import{existsSync as FK}from"fs";import{homedir as or}from"os";function nr(){let $=YI;for(let Z=0;Z<6;Z++){if(FK(y4($,"VERSION"))&&FK(y4($,"autonomy/run.sh")))return $;let Q=sG($);if(Q===$)break;$=Q}return y4(YI,"..","..","..")}function rG($){let Z=$;for(let Q=0;Q<6;Q++){if(FK(y4(Z,"VERSION"))&&FK(y4(Z,"autonomy/run.sh")))return Z;let X=sG(Z);if(X===Z)break;Z=X}return y4($,"..","..","..")}function T0(){return process.env.LOKI_DIR??y4(process.cwd(),".loki")}function m7(){return y4(or(),".loki")}var YI,i0;var J8=v(()=>{YI=sG(ar(import.meta.url));i0=nr()});import{readFileSync as sr}from"fs";import{resolve as rr,dirname as tr}from"path";import{fileURLToPath as er}from"url";function _4(){if(u7!==null)return u7;let $="10.6.0";if(typeof $==="string"&&$.length>0)return u7=$,u7;try{let Z=tr(er(import.meta.url)),Q=rG(Z);u7=sr(rr(Q,"VERSION"),"utf-8").trim()}catch{u7="unknown"}return u7}var u7=null;var g$=v(()=>{J8()});var UI={};R0(UI,{runOrThrow:()=>Ot,run:()=>I0,readStreamCapped:()=>DK,commandVersion:()=>Mt,commandExists:()=>O9,ShellError:()=>eG,MAX_STDOUT_BYTES:()=>BI});async function DK($,Z=BI){let Q=$.getReader(),X=new TextDecoder,J="",K=0;try{while(K<Z){let{done:Y,value:V}=await Q.read();if(Y)break;if(!V)continue;if(K+=V.byteLength,K>Z){let z=V.byteLength-(K-Z);J+=X.decode(V.subarray(0,z),{stream:!0});break}J+=X.decode(V,{stream:!0})}J+=X.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return J}async function I0($,Z={}){let Q=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:Z.env?{...process.env,...Z.env}:process.env,cwd:Z.cwd}),X,J;if(Z.timeoutMs&&Z.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}J=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},Z.timeoutMs);try{let[K,Y,V]=await Promise.all([DK(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:K,stderr:Y,exitCode:V}}finally{if(X)clearTimeout(X);if(J)clearTimeout(J)}}async function Ot($,Z={}){let Q=await I0($,Z);if(Q.exitCode!==0)throw new eG(`command failed (${Q.exitCode}): ${$.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function O9($){let Z=Nt($),Q=await I0(["sh","-c",`command -v ${Z}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Nt($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function Mt($,Z="--version"){if(!await O9($))return null;let X=await I0([$,Z],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var BI=16777216,eG;var J9=v(()=>{eG=class eG extends Error{message;exitCode;stdout;stderr;constructor($,Z,Q,X){super($);this.message=$;this.exitCode=Z;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function f4($){return jt?"":$}var jt,k0,P8,p0,zQ8,K8,L8,K9,d;var o5=v(()=>{jt=(process.env.NO_COLOR??"").length>0;k0=f4("\x1B[0;31m"),P8=f4("\x1B[0;32m"),p0=f4("\x1B[1;33m"),zQ8=f4("\x1B[0;34m"),K8=f4("\x1B[0;36m"),L8=f4("\x1B[1m"),K9=f4("\x1B[2m"),d=f4("\x1B[0m")});import{accessSync as Pt,constants as Et,existsSync as kt,statSync as xt}from"fs";async function n5(){if(m$!==void 0)return m$;let $="/opt/homebrew/bin/python3.12";if(kt($))return m$=$,$;let Z=await O9("python3.12");if(Z)return m$=Z,Z;let Q=await O9("python3");return m$=Q,Q}async function I6($,Z={}){let Q=await n5();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return I0([Q,"-c",$],Z)}async function MI(){let $=(process.env.PATH??"").split(":").filter((Z)=>Z.startsWith("/"));for(let Z of[...bt,...$.map((Q)=>`${Q}/python3`)])try{if(!xt(Z).isFile())continue;if(Pt(Z,Et.X_OK),(await I0([Z,"-I","-S","-c",""],{timeoutMs:1e4})).exitCode===0)return Z}catch{}return null}var m$,St,bt;var F6=v(()=>{J9();St=["/usr/bin/python3","/bin/python3"],bt=St});var _I={};R0(_I,{runStatus:()=>Je});import{existsSync as Y9,readFileSync as W2,readdirSync as wI,statSync as PI}from"fs";import{resolve as u8,basename as nt}from"path";import{homedir as st}from"os";function EI($){let Z=Math.trunc($);if(Z>=1e6)return`${(Math.trunc(Z/1e6*10)/10).toFixed(1)}M`;if(Z>=1000)return`${(Math.trunc(Z/1000*10)/10).toFixed(1)}K`;return String(Z)}function kI($,Z,Q){if(Z===0)return null;let X=Math.trunc($*100/Z),J=Math.trunc($*wK/Z);if(J>wK)J=wK;let K=wK-J,Y=P8;if(X>=80)Y=k0;else if(X>=50)Y=p0;let V="=".repeat(Math.max(0,J))+" ".repeat(Math.max(0,K)),z=EI($),W=EI(Z);return` ${L8}${Q}${d} ${Y}[${V}]${d} ${X}% (${z} / ${W})`}async function tt(){if(await O9("jq"))return!0;return process.stdout.write(`${k0}Error: jq is required but not installed.${d}
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)
@@ -1732,4 +1732,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
1732
1732
  `),2}case"start":{let{runStart:X}=await Promise.resolve().then(() => (Ta(),Ca));return X(Q)}case"engine10":{let{runEngine10:X}=await Promise.resolve().then(() => (Da(),Fa)),{registryLoader:J}=await Promise.resolve().then(() => (BG(),Pr));return X(Q,J)}default:return process.stderr.write(`Unknown command: ${Z}
1733
1733
  `),process.stderr.write(Er),2}}DI();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var cZ8=await dZ8(Bun.argv.slice(2));process.exit(cZ8);
1734
1734
 
1735
- //# debugId=323B6E6CE8FA8B68506831D39560F47C
1735
+ //# debugId=04D96E8C2728FDDAA7A5E66BCFB0644A
package/mcp/__init__.py CHANGED
@@ -75,4 +75,4 @@ try:
75
75
  except ImportError:
76
76
  __all__ = ['mcp']
77
77
 
78
- __version__ = '10.5.34'
78
+ __version__ = '10.6.0'
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": "10.5.34",
4
+ "version": "10.6.0",
5
5
  "description": "An autonomous software factory that knows what it is supposed to deliver, and proves it did.",
6
6
  "keywords": [
7
7
  "agent",
@@ -135,7 +135,13 @@
135
135
  ],
136
136
  "optionalDependencies": {
137
137
  "@anthropic-ai/claude-agent-sdk": "0.3.283",
138
- "bun": "1.4.2",
138
+ "@oven/bun-darwin-aarch64": "1.4.2",
139
+ "@oven/bun-darwin-x64": "1.4.2",
140
+ "@oven/bun-linux-aarch64": "1.4.2",
141
+ "@oven/bun-linux-aarch64-musl": "1.4.2",
142
+ "@oven/bun-linux-x64": "1.4.2",
143
+ "@oven/bun-linux-x64-musl": "1.4.2",
144
+ "@oven/bun-windows-x64": "1.4.2",
139
145
  "@opentelemetry/api": "^1.9.1",
140
146
  "@opentelemetry/exporter-trace-otlp-http": "^0.221.0",
141
147
  "@opentelemetry/sdk-trace-base": "^2.10.0",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "loki-mode",
4
4
  "displayName": "Loki Mode",
5
- "version": "10.5.34",
5
+ "version": "10.6.0",
6
6
  "description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
7
7
  "author": {
8
8
  "name": "Autonomi",
@@ -1,4 +1,4 @@
1
- import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-xqjdd8CW.js";import{B as C}from"./Button-C6aGc2pY.js";import{T as $e}from"./trending-up-BT7svddv.js";import{C as z}from"./clock-BqNrxAWL.js";import{A as Be,U as ue,M as De}from"./Avatar-CXd7G2uw.js";import{A as J}from"./activity-DFPp5cwI.js";import{R as pe}from"./refresh-cw-Cy418vYC.js";import{G as ze}from"./globe-6CVCcWN0.js";import{C as Le}from"./chevron-left-Rumv3O1P.js";import{C as je}from"./check-BJ40bgL4.js";import{D as Y}from"./dollar-sign-BS8_S1W0.js";import{U as Te}from"./user-K6ImWht9.js";import{D as Me}from"./database-BedSSWj2.js";import{L as Ue}from"./lock-B4-6MCIB.js";import{S as Re}from"./scroll-text-C97gY2NG.js";import{S as Ie}from"./shield-alert-CmM7wIvE.js";/**
1
+ import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-DnAhEaY4.js";import{B as C}from"./Button-LgRYqCHv.js";import{T as $e}from"./trending-up-BpLBFaZo.js";import{C as z}from"./clock-DgbJFbcN.js";import{A as Be,U as ue,M as De}from"./Avatar-BbxCTNns.js";import{A as J}from"./activity-92O1sR3_.js";import{R as pe}from"./refresh-cw-Cgl65iQ2.js";import{G as ze}from"./globe-BPNU50l7.js";import{C as Le}from"./chevron-left-D4UQrt8-.js";import{C as je}from"./check-C-8ho0t2.js";import{D as Y}from"./dollar-sign-DZ1zEfep.js";import{U as Te}from"./user-D4KBUK1Z.js";import{D as Me}from"./database-DNJ4cz62.js";import{L as Ue}from"./lock-CpbXWrBs.js";import{S as Re}from"./scroll-text-BpvzZAZR.js";import{S as Ie}from"./shield-alert-BlG8AkvF.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as l,j as s}from"./index-xqjdd8CW.js";/**
1
+ import{c as l,j as s}from"./index-DnAhEaY4.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{j as e}from"./index-xqjdd8CW.js";import{C as r}from"./clock-BqNrxAWL.js";import{C as a}from"./circle-alert-DVrRaJyC.js";import{C as l}from"./check-BJ40bgL4.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
1
+ import{j as e}from"./index-DnAhEaY4.js";import{C as r}from"./clock-DgbJFbcN.js";import{C as a}from"./circle-alert-BnxgnWHv.js";import{C as l}from"./check-C-8ho0t2.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
@@ -1 +1 @@
1
- import{r as p,j as t}from"./index-xqjdd8CW.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
1
+ import{r as p,j as t}from"./index-DnAhEaY4.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
@@ -1,4 +1,4 @@
1
- import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-xqjdd8CW.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-CaGNFbbH.js";import{C as qe,F as Ge,M as Ue,H as Ke,a as We,G as Ve,T as Qe}from"./thumbs-up-Qz1Mzhzi.js";import{C as oe}from"./check-BJ40bgL4.js";import{C as Ye}from"./clock-BqNrxAWL.js";import{D as Xe}from"./dollar-sign-BS8_S1W0.js";import{U as Ze}from"./upload-Dyv0ClcL.js";import{L as V}from"./loader-circle-a5qrA7Dl.js";/**
1
+ import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-DnAhEaY4.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-DCPrb7ec.js";import{C as qe,F as Ge,M as Ue,H as Ke,a as We,G as Ve,T as Qe}from"./thumbs-up-BJcYgjRU.js";import{C as oe}from"./check-C-8ho0t2.js";import{C as Ye}from"./clock-DgbJFbcN.js";import{D as Xe}from"./dollar-sign-DZ1zEfep.js";import{U as Ze}from"./upload-LgGE0PEa.js";import{L as V}from"./loader-circle-bh-SWjhS.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.