loki-mode 10.8.0 → 10.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/.github/actions/issue-to-pr/action.yml +2 -2
  2. package/README.md +11 -5
  3. package/SKILL.md +12 -2
  4. package/VERSION +1 -1
  5. package/autonomy/lib/proof-generator.py +1 -0
  6. package/autonomy/loki +55 -40
  7. package/autonomy/receipt_jwt.py +46 -1
  8. package/autonomy/run.sh +1 -1
  9. package/autonomy/telemetry.sh +1 -1
  10. package/autonomy/trigger-server.py +1 -0
  11. package/autonomy/tui.sh +5 -1
  12. package/bin/loki +12 -1
  13. package/bin/loki-postinstall.js +12 -0
  14. package/dashboard/__init__.py +1 -1
  15. package/dashboard/api_phases.py +1 -1
  16. package/dashboard/api_start.py +0 -1
  17. package/dashboard/server.py +22 -138
  18. package/docs/CLI-REFERENCE.md +139 -0
  19. package/docs/COCKPIT-SPEC.md +3 -1
  20. package/docs/DASHBOARD-9.12-EVIDENCE.md +1 -1
  21. package/docs/DASHBOARD-ARCHITECTURE.md +13 -11
  22. package/docs/DASHBOARD_V2_CHECKLIST.md +2 -0
  23. package/docs/INSTALLATION.md +12 -11
  24. package/docs/LOKI-10-BUILD-PROMPT.md +2 -2
  25. package/docs/MERGE-DEDUP-MAP.md +1 -1
  26. package/docs/MERGE-ROUTE-MAP.md +1 -1
  27. package/docs/MERGE3-PLAN.md +2 -2
  28. package/docs/PLANS-INDEX.md +2 -3
  29. package/docs/R3-COST-OBSERVABILITY-DESIGN.md +2 -2
  30. package/docs/R4-TRUST-TRAJECTORY-DESIGN.md +1 -1
  31. package/docs/R5-AUTO-WIKI-DESIGN.md +1 -1
  32. package/docs/R6-ROLLBACK-CHECKPOINT-PLAN.md +1 -1
  33. package/docs/RARV-C-100X-PLAN.md +3 -3
  34. package/docs/SLO.md +3 -3
  35. package/docs/SONNET5-DEFAULT-PLAN.md +2 -2
  36. package/docs/SYNERGY-TASKS.md +1 -1
  37. package/docs/TOOL-INTEGRATION.md +1 -1
  38. package/docs/TOP-100-BACKLOG.md +1 -1
  39. package/docs/alternative-installations.md +2 -2
  40. package/docs/architecture/ADR-001-runtime-migration.md +1 -1
  41. package/docs/architecture/DASHBOARD_V2_ARCHITECTURE.md +2 -0
  42. package/docs/audit-logging.md +2 -0
  43. package/docs/authentication.md +2 -0
  44. package/docs/authorization.md +2 -0
  45. package/docs/bug-fixes/agent-04-memory-fixes.md +1 -1
  46. package/docs/certification/02-enterprise-features/lab.md +2 -0
  47. package/docs/certification/02-enterprise-features/lesson.md +2 -0
  48. package/docs/certification/04-production-deployment/lab.md +2 -0
  49. package/docs/certification/04-production-deployment/lesson.md +2 -0
  50. package/docs/control-plane-migration.md +97 -0
  51. package/docs/dashboard-guide.md +6 -7
  52. package/docs/dev/release-checklist.md +10 -12
  53. package/docs/enterprise/integration-cookbook.md +2 -0
  54. package/docs/enterprise/migration.md +1 -1
  55. package/docs/enterprise/performance.md +3 -1
  56. package/docs/enterprise/sdk-guide.md +2 -0
  57. package/docs/enterprise/security.md +2 -0
  58. package/{.github/workflows/loki-issue-to-pr.yml → docs/examples/loki-issue-to-pr.yml.example} +2 -0
  59. package/docs/{ONE-RUN-AUDIT.md → history/one-run-audit.md} +6 -0
  60. package/docs/{BUG-AUDIT-v6.61.0.md → history/v6.61.0-audit.md} +6 -0
  61. package/docs/{V8-AGENT-SDK-PLAN.md → history/v8-agent-sdk-plan.md} +6 -0
  62. package/docs/{CONFIG-FILE-PLAN.md → history/v8-config-plan.md} +6 -0
  63. package/docs/plans/FORGE-AUTONOMOUS-QUEUE.md +2 -2
  64. package/docs/research-2026-07/OBSERVABILITY-TOOL-SPEC.md +1 -1
  65. package/docs/retrospectives/v7.5.15-honesty-audit.md +2 -2
  66. package/docs/test-scenarios/enterprise-scenarios.md +3 -3
  67. package/docs/v10/ARCHITECT-CUTS.md +9 -9
  68. package/docs/v10/BACKLOG.md +7 -7
  69. package/docs/v10/BOARD.md +28 -25
  70. package/docs/v10/CLI-MODERN.md +190 -0
  71. package/docs/v10/CONTROL-PLANE.md +4 -4
  72. package/docs/v10/CP-ENTERPRISE-UI.md +66 -66
  73. package/docs/v10/D51-PHASE-B.md +1 -1
  74. package/docs/v10/DECISIONS.md +3 -3
  75. package/docs/v10/DEPS.md +148 -169
  76. package/docs/v10/FAILURE-CLASSES.md +63 -1
  77. package/docs/v10/LEGACY-REMOVAL.md +335 -26
  78. package/docs/v10/PROGRESS.md +15 -0
  79. package/docs/v10/SWARM.md +2 -2
  80. package/loki-ts/dist/cockpit.js +11 -11
  81. package/loki-ts/dist/loki.js +1610 -1813
  82. package/magic/core/design_tokens.py +1 -2
  83. package/magic/core/generator.py +2 -2
  84. package/magic/tokens/README.md +1 -3
  85. package/mcp/__init__.py +1 -1
  86. package/package.json +4 -8
  87. package/packages/control-plane/dist/server.js +1956 -1019
  88. package/packages/control-plane/src/db/fixture-cleanup.ts +47 -0
  89. package/packages/control-plane/src/server/app.ts +2 -0
  90. package/packages/control-plane/src/server/integrity.ts +48 -9
  91. package/packages/control-plane/src/server/legacy/routes-audit.ts +50 -0
  92. package/packages/control-plane/src/server/legacy/routes-control.ts +26 -0
  93. package/packages/control-plane/src/server/legacy/routes-memory.ts +30 -0
  94. package/packages/control-plane/src/server/legacy/routes.ts +58 -58
  95. package/packages/control-plane/src/server/legacy/shim.ts +10 -4
  96. package/packages/control-plane/src/server/routes/checkpoints.ts +171 -0
  97. package/packages/control-plane/src/server/routes/index.ts +4 -1
  98. package/packages/control-plane/src/server/routes/memory.ts +219 -0
  99. package/packages/control-plane/src/server/routes/session_control.ts +155 -0
  100. package/packages/control-plane/src/server/routes/stats.ts +16 -5
  101. package/packages/control-plane/src/server/runs.ts +16 -4
  102. package/packages/control-plane/ui/dist/assets/index-NAMkcA9N.js +165 -0
  103. package/packages/control-plane/ui/dist/index.html +1 -1
  104. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  105. package/references/magic-modules-patterns.md +2 -2
  106. package/schemas/status-result.schema.json +13 -22
  107. package/skills/factory-operations.md +3 -3
  108. package/skills/magic-modules.md +1 -1
  109. package/skills/release-cadence.md +6 -6
  110. package/tools/audit-docs.py +1 -1
  111. package/tools/index-codebase.py +1 -1
  112. package/web-app/dist/assets/{AdminPage-DDDvUz0N.js → AdminPage-B8RjG3sy.js} +1 -1
  113. package/web-app/dist/assets/{Avatar-Dcdz46i6.js → Avatar-Dttmvqc-.js} +1 -1
  114. package/web-app/dist/assets/{Badge-BB24cCpK.js → Badge-Bvyp8VrD.js} +1 -1
  115. package/web-app/dist/assets/{Button-D0-DmPZL.js → Button-DtY5ZrZw.js} +1 -1
  116. package/web-app/dist/assets/{CockpitPage-CdjpU2JW.js → CockpitPage-B2gbOwRp.js} +1 -1
  117. package/web-app/dist/assets/{ComparePage-DT5U0y0d.js → ComparePage-CHi5nZTU.js} +1 -1
  118. package/web-app/dist/assets/{ErrorBoundary-lEHcl0EO.js → ErrorBoundary-BUuTj-OQ.js} +1 -1
  119. package/web-app/dist/assets/{EvidenceReceiptPanel-GpnWvdCr.js → EvidenceReceiptPanel-C5aOn4ES.js} +1 -1
  120. package/web-app/dist/assets/{GitHubIssuesPanel-C7VOh1B7.js → GitHubIssuesPanel-isVxxHXb.js} +1 -1
  121. package/web-app/dist/assets/{GitHubPRsPanel-G_kOuINv.js → GitHubPRsPanel-DtDpxyQl.js} +1 -1
  122. package/web-app/dist/assets/{HomePage-PqRisOny.js → HomePage-Casf-LUB.js} +2 -2
  123. package/web-app/dist/assets/{LoginPage-DU7pFAkf.js → LoginPage-DvB78691.js} +1 -1
  124. package/web-app/dist/assets/{MagicPage-C5JWIWMk.js → MagicPage-DU6hmbnC.js} +1 -1
  125. package/web-app/dist/assets/{MetricsPage-CbIGS_qo.js → MetricsPage-DcPwzoS8.js} +1 -1
  126. package/web-app/dist/assets/{NotFoundPage-vU1pvdSt.js → NotFoundPage-Bs6WxAZ8.js} +1 -1
  127. package/web-app/dist/assets/{ProjectPage-SsixIPPv.js → ProjectPage-RBIqC-DJ.js} +3 -3
  128. package/web-app/dist/assets/{ProjectsPage-BfQKSR9k.js → ProjectsPage-CogXD7jM.js} +1 -1
  129. package/web-app/dist/assets/{SettingsPage-B8YfXAom.js → SettingsPage-pAyJAfPt.js} +1 -1
  130. package/web-app/dist/assets/{ShowcasePage-Ba407f2-.js → ShowcasePage-D6bT2bDd.js} +1 -1
  131. package/web-app/dist/assets/{SystemSettingsPage-DzNQhhBS.js → SystemSettingsPage-CE8xiJRh.js} +1 -1
  132. package/web-app/dist/assets/{TeamsPage-tqUnpZ15.js → TeamsPage-wMS55TDT.js} +1 -1
  133. package/web-app/dist/assets/{TemplatesPage-ClB5EpI3.js → TemplatesPage-COJNVQqu.js} +1 -1
  134. package/web-app/dist/assets/{TerminalOutput-CBvpYfEu.js → TerminalOutput-Cc2XASxd.js} +1 -1
  135. package/web-app/dist/assets/{activity-C1s0L_X9.js → activity-C6eHFDjL.js} +1 -1
  136. package/web-app/dist/assets/{bell-DMEiXr73.js → bell-BJpVYj4n.js} +1 -1
  137. package/web-app/dist/assets/{bot-BF_xIOxu.js → bot-BwRVVUQL.js} +1 -1
  138. package/web-app/dist/assets/{check-Dv1Ynvrs.js → check-CGDwoKy8.js} +1 -1
  139. package/web-app/dist/assets/{chevron-left-Ddhsod7S.js → chevron-left-CF2Nilj6.js} +1 -1
  140. package/web-app/dist/assets/{circle-alert-OATHUkBZ.js → circle-alert-D0RyRec1.js} +1 -1
  141. package/web-app/dist/assets/{clock-C1Ltva07.js → clock-xeF3gW0W.js} +1 -1
  142. package/web-app/dist/assets/{cloud-B-S4oOy9.js → cloud-D5Sy69ZZ.js} +1 -1
  143. package/web-app/dist/assets/{code-xml-D3Femn_F.js → code-xml-C6-5Ql9I.js} +1 -1
  144. package/web-app/dist/assets/{database-DBSeFgO3.js → database-BSjG1_z0.js} +1 -1
  145. package/web-app/dist/assets/{dollar-sign-sgDgNuGE.js → dollar-sign-FnDR2QUu.js} +1 -1
  146. package/web-app/dist/assets/{file-code-corner-C-MbdZEc.js → file-code-corner-BiOK9vR6.js} +1 -1
  147. package/web-app/dist/assets/{file-plus-CCB6yqXv.js → file-plus-3WALQDEE.js} +1 -1
  148. package/web-app/dist/assets/{globe-DlbrNAj1.js → globe-vUdUrQqp.js} +1 -1
  149. package/web-app/dist/assets/{hammer-B-DWm695.js → hammer-0VwHUEpa.js} +1 -1
  150. package/web-app/dist/assets/{index-Dvny-1SU.js → index-BMKIwteZ.js} +3 -3
  151. package/web-app/dist/assets/{layers-99qsKpOT.js → layers-C6q8kzST.js} +1 -1
  152. package/web-app/dist/assets/{loader-circle-ZvZyZl3J.js → loader-circle-B4Tz724d.js} +1 -1
  153. package/web-app/dist/assets/{lock-DosGjcxP.js → lock-yxvEA65n.js} +1 -1
  154. package/web-app/dist/assets/{package-C-PumesN.js → package-BpKD0Ot0.js} +1 -1
  155. package/web-app/dist/assets/{plus-CTYYskTB.js → plus-Ibqx_Vo9.js} +1 -1
  156. package/web-app/dist/assets/{refresh-cw-qW2ztTFS.js → refresh-cw-C9auyvi-.js} +1 -1
  157. package/web-app/dist/assets/{rotate-ccw-ZIKrf-vO.js → rotate-ccw-2cEiXm6O.js} +1 -1
  158. package/web-app/dist/assets/{scroll-text-BamlXjAT.js → scroll-text-BPAWML-w.js} +1 -1
  159. package/web-app/dist/assets/{server-BljXb79I.js → server-CZh6B1zx.js} +1 -1
  160. package/web-app/dist/assets/{shield-alert-Dr6eT9c_.js → shield-alert-CivolUIx.js} +1 -1
  161. package/web-app/dist/assets/{thumbs-up-v3oBXZgU.js → thumbs-up-BP9covEH.js} +1 -1
  162. package/web-app/dist/assets/{trash-2-BOuIrCpi.js → trash-2-BCDfTcNx.js} +1 -1
  163. package/web-app/dist/assets/{trending-down-Dp7jMCgH.js → trending-down-5LypivXh.js} +1 -1
  164. package/web-app/dist/assets/{trending-up-CDiur-nP.js → trending-up-DNt4SFdk.js} +1 -1
  165. package/web-app/dist/assets/{upload-DxIHXhNE.js → upload-DBmHbY6y.js} +1 -1
  166. package/web-app/dist/assets/{usePolling-D2Uu-YZb.js → usePolling-DOPZcbUL.js} +1 -1
  167. package/web-app/dist/assets/{user-BVWCUAfF.js → user-BQTJJDCG.js} +1 -1
  168. package/web-app/dist/index.html +1 -1
  169. package/dashboard/static/assets/mermaid.min.js +0 -2030
  170. package/dashboard/static/cost.html +0 -344
  171. package/dashboard/static/favicon.svg +0 -5
  172. package/dashboard/static/index.html +0 -15577
  173. package/dashboard/static/proofs.html +0 -194
  174. package/dashboard/static/start.html +0 -131
  175. package/dashboard/static/trust.html +0 -325
  176. package/docs/BRANCH-LIFECYCLE-PLAN.md +0 -354
  177. package/docs/EXECUTION-COCKPIT-PLAN.md +0 -289
  178. package/packages/control-plane/ui/dist/assets/index-Dbhu244h.js +0 -155
@@ -10,7 +10,7 @@ branding:
10
10
  # must not hold a write token. Run it with `permissions: contents: read,
11
11
  # issues: read` and `actions/checkout` with `persist-credentials: false`, upload
12
12
  # `outputs.patch`, and push and open the PR from a second job that runs no
13
- # agent. .github/workflows/loki-issue-to-pr.yml in asklokesh/loki-mode is the
13
+ # agent. docs/examples/loki-issue-to-pr.yml.example in asklokesh/loki-mode is the
14
14
  # reference. Earlier versions pushed and opened the PR from the same step that
15
15
  # ran the agent; this one does not.
16
16
  #
@@ -247,7 +247,7 @@ runs:
247
247
  echo "patch=$OUT/loki.patch" >> "$GITHUB_OUTPUT"
248
248
  echo "pr_body=$OUT/pr-body.md" >> "$GITHUB_OUTPUT"
249
249
 
250
- echo "::warning::This action does not open the pull request (Rule of Two). Upload outputs.patch and open the PR from a job that holds the write token and runs no agent; see .github/workflows/loki-issue-to-pr.yml in asklokesh/loki-mode."
250
+ echo "::warning::This action does not open the pull request (Rule of Two). Upload outputs.patch and open the PR from a job that holds the write token and runs no agent; see docs/examples/loki-issue-to-pr.yml.example in asklokesh/loki-mode."
251
251
  if [ -n "$RUN_DIR" ]; then
252
252
  echo "Loki 10 receipt under $RUN_DIR/"
253
253
  fi
package/README.md CHANGED
@@ -9,6 +9,12 @@ An autonomous software factory that knows what it is supposed to deliver, and pr
9
9
 
10
10
  [Website](https://www.autonomi.dev/) | [Documentation](wiki/Home.md) | [Installation](docs/INSTALLATION.md) | [Changelog](CHANGELOG.md)
11
11
 
12
+ <!-- generated:facts -->
13
+ The npm badge above tracks the current release; see [CHANGELOG.md](CHANGELOG.md) for release notes.
14
+
15
+ CLI reference: [docs/CLI-REFERENCE.md](docs/CLI-REFERENCE.md) (generated from the command registry).
16
+ <!-- /generated -->
17
+
12
18
  Loki Mode is a free, source-available autonomous coding agent by [Autonomi](https://www.autonomi.dev/). Hand it a PRD, GitHub issue, OpenAPI doc or one-line brief. It derives a delivery contract (the acceptance criteria), builds against it, and ends with a signed Evidence Receipt that states what was proven and what was not. If the contract cannot be derived, it stops and asks one question instead of guessing.
13
19
 
14
20
  Before a build counts as done, a review council selects reviewers from a specialist pool (`agents/types.json`, scored by `run.sh:FOCUS_KEYWORDS`). The bundled MCP server exposes 39 tools over stdio (`mcp/server.py`), including `loki_v10_run`, `loki_v10_status` and `loki_v10_verify` to start a Loki 10 run in the background, read its phase, verdict and cost, and verify its receipt (`BLOCKED` runs report their question). Add it with `claude mcp add loki-mode -- python3 -m mcp.server` from the install directory.
@@ -88,7 +94,7 @@ loki owner/repo#123
88
94
 
89
95
  The v10 engine accepts a quoted multi-word task, a GitHub, GitLab or Jira issue reference, `status`, `verify`, `dashboard`, and other subcommands. Flags (`loki-ts/src/engine10/cli.ts` USAGE): `--no-pr` builds and verifies without opening a pull request, `--deep` requests the deep verify pass and a longer implement budget, `--provider <name>` picks the coding provider, `--max-cost <usd>` sets the per-run cost cap (default $100.00 when an API key is set, no dollar cap on a subscription run where the start line adds `subscription: no dollar cap; usage counts against your plan limits`; or `budgets.per_run` in `loki.yaml`; the flag wins; the start line prints it as `cap $100.00 (default)`; reaching it ends the run BUDGET_STOP, exit 3) (`--json` and `--verbose` are also parsed by the supervisor, see [Quiet output](#quiet-output)). The engine needs Bun; without it the command exits 1 with a message and installation instructions.
90
96
 
91
- **Legacy engine (being removed).** The previous engine still ships in 10.6.6 and is reachable with `LOKI_ENGINE=legacy` or `loki legacy <args>`. `loki start owner/repo#N`, `loki start <issue URL>` and `loki start "<multi-word task>"` run on Loki 10, the same as `loki owner/repo#N` and `loki "<task>"`; `loki start ./prd.md`, a flag-first call and a one-word start stay on the legacy engine. For many issues use `loki backlog owner/repo --all|--label X|--issues N,N` (many issues, N in parallel, each on a `loki/backlog-N` worktree branch) instead. Legacy removal is planned and resumes on 2026-10-07; see [docs/v10/LEGACY-REMOVAL.md](docs/v10/LEGACY-REMOVAL.md). Sections below marked "legacy" describe features that run only on that engine.
97
+ **Legacy engine (being removed).** Migration note: the previous engine is being removed and has no engine switch; use `loki "<task>"` and `loki owner/repo#N`. `loki start owner/repo#N`, `loki start <issue URL>` and `loki start "<multi-word task>"` run on Loki 10, the same as `loki owner/repo#N` and `loki "<task>"`; `loki start ./prd.md`, a flag-first call and a one-word start stay on the legacy engine. For many issues use `loki backlog owner/repo --all|--label X|--issues N,N` (many issues, N in parallel, each on a `loki/backlog-N` worktree branch) instead. Legacy removal is planned and resumes on 2026-10-07; see [docs/v10/LEGACY-REMOVAL.md](docs/v10/LEGACY-REMOVAL.md). Sections below marked "legacy" describe features that run only on that engine.
92
98
 
93
99
  ### The state machine
94
100
 
@@ -154,7 +160,7 @@ The run cap is 900s (2700s with `--deep`, `DEFAULT_CAP_S` and `DEEP_CAP_S` in `t
154
160
 
155
161
  A finished run prints a short summary (see [Quiet output](#quiet-output), which also shows an example) whose `NOT PROVEN` line is never empty by omission: deep checks deferred to the deep-verify pass are always listed there.
156
162
 
157
- `loki status [run-id]` and `loki verify [run-id]` are built on the v10 path (bare `loki verify` follows the newest run, v10 or legacy). `loki dashboard` and `loki status` reach the v10 commands with `LOKI_ENGINE=v10`. Two-way Slack (`loki slack serve`) is on by default and documented in [docs/slack.md](docs/slack.md); outbound notifications use `LOKI_SLACK_WEBHOOK_URL`.
163
+ `loki status [run-id]` and `loki verify [run-id]` are built on the v10 path (bare `loki verify` follows the newest run, v10 or legacy). Two-way Slack (`loki slack serve`) is on by default and documented in [docs/slack.md](docs/slack.md); outbound notifications use `LOKI_SLACK_WEBHOOK_URL`.
158
164
 
159
165
  ## Run from Jira or Linear
160
166
 
@@ -182,7 +188,7 @@ On by default; set `LOKI_CONTRACT=0` to turn it off. It does nothing unless `.lo
182
188
 
183
189
  Both run on your own GitHub Actions minutes; there is no hosted service.
184
190
 
185
- - Issue to PR: copy `.github/workflows/loki-issue-to-pr.yml` into your repository. Label an issue `loki`, or comment `/loki` as an owner, member or collaborator, and it runs `loki owner/repo#N` (the Loki 10 engine) and opens a pull request with an evidence receipt. The agent job holds a read-only token; a separate publish job opens the PR. Set `ANTHROPIC_API_KEY` in repository secrets.
191
+ - Issue to PR: copy `docs/examples/loki-issue-to-pr.yml.example` to `.github/workflows/loki-issue-to-pr.yml` in your repository. Label an issue `loki`, or comment `/loki` as an owner, member or collaborator, and it runs `loki owner/repo#N` (the Loki 10 engine) and opens a pull request with an evidence receipt. The agent job holds a read-only token; a separate publish job opens the PR. Set `ANTHROPIC_API_KEY` in repository secrets.
186
192
  - Nightly backlog: copy `examples/loki-nightly-backlog.yml` into `.github/workflows/`. Its `schedule:` trigger runs `loki backlog owner/repo --label loki`, one Loki 10 run per labeled open issue:
187
193
 
188
194
  ```yaml
@@ -310,7 +316,7 @@ The URL comes from `LOKI_CONTROL_URL`, else `http://127.0.0.1:${LOKI_CONTROL_POR
310
316
 
311
317
  Answering a BLOCKED run: when a run stops on a spec conflict, its run page shows the question and an answer box. Submitting posts to `POST /v1/runs/<source>/<run>/answer` (JSON `{"answer": "..."}`, up to 4000 characters, loopback only) and writes `~/.loki/control/answers/<source>/<run>.answer.txt` (override the directory with `LOKI_CONTROL_ANSWER_DIR`). The page prints the resume command, `loki answer <run>`, which starts a fresh run carrying the task, the question and that file's text (or pass `--text "..."` yourself; with no run id it picks the newest BLOCKED run). A run that is not BLOCKED exits 2.
312
318
 
313
- Set `LOKI_CONTROL_DEFAULT=1` (off by default) to make `loki dashboard`, `loki dashboard start` and `loki dashboard open` start the Control Plane instead of the old dashboard. The old dashboard is unchanged when the flag is unset.
319
+ The Control Plane is the only UI. `loki dashboard`, `loki dashboard start` and `loki dashboard open` open it (starting `loki control serve` if none is running). The classic dashboard UI and its port 57374 are removed in 10.8; see [docs/control-plane-migration.md](docs/control-plane-migration.md) for the route mapping and what is not yet available.
314
320
 
315
321
  Container, Helm and ECS deployment: [docs/control-plane-container.md](docs/control-plane-container.md).
316
322
 
@@ -588,7 +594,7 @@ Legacy engine, being removed (these run on the previous engine; `loki --help` st
588
594
  | `loki stop`, `pause`, `resume` | Control a legacy run |
589
595
  | `loki steer "<note>"` | Nudge a legacy run (needs `LOKI_PROMPT_INJECTION=1`) |
590
596
  | `loki why`, `loki next` | Explain or continue a legacy run |
591
- | `loki dashboard` | Operations UI server (`start\|stop\|status\|url\|open`) |
597
+ | `loki dashboard` | Open the Control Plane UI (see [docs/control-plane-migration.md](docs/control-plane-migration.md)) |
592
598
  | `loki review`, `loki test`, `loki analyze`, `loki memory`, `loki failover`, `loki enterprise`, `loki import`, `loki ci` | Review, test generation, codebase analysis, memory, failover, enterprise, issue import, CI gate |
593
599
  | `loki modernize heal <path>` | Legacy system healing |
594
600
 
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.8.0
6
+ # Loki Mode v10.10.1
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 legacy engine, which still ships and is being removed (`loki start owner/repo#N` still routes to it; prefer `loki owner/repo#N`).
9
9
 
@@ -195,6 +195,16 @@ This protocol governs **skill module** loading -- task-scoped instruction files
195
195
 
196
196
  ---
197
197
 
198
+ ## Command list
199
+
200
+ <!-- generated:commands -->
201
+ Commands (generated from `loki-ts/src/cli/registry.ts`; full reference in `docs/CLI-REFERENCE.md`):
202
+
203
+ `version`, `status`, `doctor`, `provider`, `memory`, `rollback`, `proof`, `wiki`, `control`, `kpis`, `report`, `trust`, `crash`, `contract`, `start`, `slack`, `answer`, `engine10`, `help`, `quick`, `quickstart`, `init`, `template`, `verify`, `keys`, `review`, `dashboard`, `config`, `mcp`, `acp`, `stop`, `pause`, `resume`, `why`, `next`, `logs`, `ship`, `deploy`, `import`, `github`, `issue`, `ci`, `modernize`, `share`, `assets`, `export`, `notify`, `tour`, `welcome`, `onboard`, `setup-skill`, `self-update`, `remote`, `cockpit`, `code`, `context`, `secrets`, `api`, `sandbox`, `docker`, `web`, `preview`, `telemetry`, `syslog`, `explain`, `docs`, `test`, `bench`, `voice`, `own`, `secure`, `compliance`, `enterprise`, `projects`, `audit`, `cost`, `metrics`, `sentrux`, `magic`
204
+ <!-- /generated -->
205
+
206
+ ---
207
+
198
208
  ## Invocation
199
209
 
200
210
  **Legacy entry point (v6.84.0, being removed; for Loki 10 use `loki "<task>"` or `loki owner/repo#N`):** `loki start [SPEC|ISSUE-REF]` auto-detects whether the input is a PRD file, an issue URL, an issue number, or another spec format (e.g. OpenAPI). No need to pick between `loki start` and `loki run` -- the single command handles all cases.
@@ -473,4 +483,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
473
483
 
474
484
  ---
475
485
 
476
- **v10.8.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
486
+ **v10.10.1 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 10.8.0
1
+ 10.10.1
@@ -2406,6 +2406,7 @@ def generate(args):
2406
2406
  job_id=str(redacted.get("run_id") or ""),
2407
2407
  run_id=str(redacted.get("run_id") or ""),
2408
2408
  receipt_hash=digest,
2409
+ verification=verification,
2409
2410
  )
2410
2411
  if _tok:
2411
2412
  verification["attestation"] = _tok
package/autonomy/loki CHANGED
@@ -918,7 +918,7 @@ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
918
918
  import json, sys, hashlib, urllib.request
919
919
  sys.path.insert(0, sys.argv[3])
920
920
  try:
921
- from receipt_jwt import verify_attestation, _CRYPTO_AVAILABLE
921
+ from receipt_jwt import verify_attestation, check_seal_meta, _CRYPTO_AVAILABLE
922
922
  except ImportError:
923
923
  sys.exit(1) # -> "" : cannot check, never a verdict
924
924
  proof = json.load(open(sys.argv[1]))
@@ -966,10 +966,14 @@ if not ok:
966
966
  # receipt. Recompute the digest the same way the receipt records it (with
967
967
  # `verification` stripped) and require the signed claim to match, or a valid
968
968
  # token lifted from a different run would vouch for these bytes.
969
- proof.pop("verification", None)
969
+ _vmeta = proof.pop("verification", None)
970
970
  canon = json.dumps(proof, sort_keys=True, separators=(",", ":")).encode()
971
- print("ok" if claims.get("receipt_sha256") == hashlib.sha256(canon).hexdigest()
972
- else "bad")
971
+ if claims.get("receipt_sha256") != hashlib.sha256(canon).hexdigest():
972
+ print("bad"); sys.exit(0)
973
+ # seal.v2: the verification.* metadata (scope, algo, attestation_kid, ...) is
974
+ # inside the signature; a token that signs different metadata is refused. A
975
+ # legacy seal.v1 token still verifies (its metadata is simply unsigned).
976
+ print("ok" if check_seal_meta(tok, claims, _vmeta)[0] != "bad" else "bad")
973
977
  PY
974
978
  }
975
979
 
@@ -1052,7 +1056,7 @@ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
1052
1056
  import json, sys, os, hashlib, urllib.request
1053
1057
  sys.path.insert(0, sys.argv[3])
1054
1058
  try:
1055
- from receipt_jwt import verify_attestation, _CRYPTO_AVAILABLE
1059
+ from receipt_jwt import verify_attestation, check_seal_meta, _CRYPTO_AVAILABLE
1056
1060
  except ImportError:
1057
1061
  sys.exit(1) # "" : cannot check
1058
1062
  try:
@@ -1117,10 +1121,32 @@ if not ok:
1117
1121
  # A verifying signature is not enough: it must attest to THESE bytes. Recompute
1118
1122
  # the digest the way the receipt records it, so a token lifted from another run
1119
1123
  # cannot vouch for this one.
1120
- proof.pop("verification", None)
1124
+ _vmeta = proof.pop("verification", None)
1121
1125
  canon = json.dumps(proof, sort_keys=True, separators=(",", ":")).encode()
1122
- print("ok" if claims.get("receipt_sha256") == hashlib.sha256(canon).hexdigest()
1123
- else "bad")
1126
+ if claims.get("receipt_sha256") != hashlib.sha256(canon).hexdigest():
1127
+ print("bad"); sys.exit(0)
1128
+ # seal.v2: the verification.* metadata (scope, algo, attestation_kid, ...) is
1129
+ # inside the signature; a token that signs different metadata is refused. A
1130
+ # legacy seal.v1 token still verifies (its metadata is simply unsigned).
1131
+ print("ok" if check_seal_meta(tok, claims, _vmeta)[0] != "bad" else "bad")
1132
+ PY
1133
+ }
1134
+
1135
+ # Prints "legacy" when the receipt's attestation is a seal.v1 token (the
1136
+ # verification.* metadata is NOT inside the signature), else nothing. Callers
1137
+ # append "metadata not signed (legacy seal.v1)" to a VERIFIED line.
1138
+ loki_proof_seal_legacy() {
1139
+ python3 -E - "$1" "${_LOKI_SCRIPT_DIR}" 2>/dev/null <<'PY' || true
1140
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
1141
+ import json, sys
1142
+ sys.path.insert(0, sys.argv[2])
1143
+ from receipt_jwt import _b64url_decode
1144
+ try:
1145
+ tok = json.load(open(sys.argv[1]))["verification"]["attestation"]
1146
+ claims = json.loads(_b64url_decode(tok.split(".")[1]))
1147
+ print("legacy" if "seal" not in claims else "")
1148
+ except Exception:
1149
+ print("")
1124
1150
  PY
1125
1151
  }
1126
1152
 
@@ -2032,12 +2058,11 @@ cmd_ui() {
2032
2058
  LOKI_DASHBOARD_CORS="http://localhost:$port,http://127.0.0.1:$port" \
2033
2059
  cmd_dashboard_start --host 127.0.0.1 --port "$port" >&2 || return 1
2034
2060
  fi
2035
- local url="http://127.0.0.1:${port}/start"
2036
- if [ "${LOKI_HEADLESS:-0}" = "1" ] || [ "${1:-}" = "--no-open" ]; then
2037
- echo "$url"
2038
- else
2039
- loki_open_url "$url" || echo "$url"
2040
- fi
2061
+ # The classic server is API-only; the UI is the Control Plane.
2062
+ local url="http://127.0.0.1:${port}"
2063
+ echo "loki: the classic dashboard at $url serves the API only (the browser UI moved to the Control Plane)." >&2
2064
+ echo "loki: start the Control Plane UI with: loki ui (needs bun)" >&2
2065
+ echo "$url"
2041
2066
  }
2042
2067
 
2043
2068
  # Tight newcomer landing for the bare `loki` invocation (no args).
@@ -3915,18 +3940,9 @@ cmd_start() {
3915
3940
  # + cockpit, honoring the card's "open dashboard" promise. The
3916
3941
  # cockpit hint is printed by _loki_start_handoff for the Both path.
3917
3942
  args+=("--bg")
3918
- # Open the URL the runner PUBLISHES for the port it actually bound
3919
- # or reused (it walks past refused ports); never guess the default
3920
- # 57374, which may be a foreign or stale dashboard. stdout must
3921
- # stay unredirected: loki_open_url checks the TTY.
3922
- local _dfile="${PWD}/.loki/dashboard/url"
3923
- rm -f "$_dfile" 2>/dev/null
3924
- (
3925
- for _ in $(seq 1 120); do
3926
- if [ -s "$_dfile" ]; then loki_open_url "$(head -1 "$_dfile")" 2>/dev/null; exit 0; fi
3927
- sleep 0.5
3928
- done
3929
- ) &
3943
+ # The browser UI is the Control Plane; open it (guarded by
3944
+ # loki_open_url: no-op headless and in tests).
3945
+ ( LOKI_UI_NO_CLASSIC=1 cmd_ui 2>/dev/null || true ) &
3930
3946
  ;;
3931
3947
  launch-bg-watch)
3932
3948
  # Watch (cockpit only) detaches without opening the browser.
@@ -7561,7 +7577,7 @@ cmd_dashboard_help() {
7561
7577
  echo " loki dashboard start --tls-cert cert.pem --tls-key key.pem"
7562
7578
  echo " loki dashboard status # Check if running"
7563
7579
  echo " loki dashboard url --format json # Get URL as JSON"
7564
- echo " loki dashboard open # Open in browser"
7580
+ echo " loki dashboard open # Print the Control Plane hint (no browser)"
7565
7581
  echo " loki dashboard stop # Stop server"
7566
7582
  }
7567
7583
 
@@ -7789,7 +7805,7 @@ cmd_dashboard_start() {
7789
7805
  # a second port.
7790
7806
  echo -e "${DIM}Want to submit a spec in the browser? Open the 'Lab' tab in this dashboard.${NC}"
7791
7807
  echo ""
7792
- echo -e "Open in browser: ${CYAN}loki dashboard open${NC}"
7808
+ echo -e "Control Plane UI: ${CYAN}loki ui${NC}"
7793
7809
  echo -e "Check status: ${CYAN}loki dashboard status${NC}"
7794
7810
  echo -e "Stop server: ${CYAN}loki dashboard stop${NC}"
7795
7811
  else
@@ -7907,7 +7923,7 @@ cmd_dashboard_status() {
7907
7923
  fi
7908
7924
 
7909
7925
  echo ""
7910
- echo -e "Open in browser: ${CYAN}loki dashboard open${NC}"
7926
+ echo -e "Control Plane UI: ${CYAN}loki ui${NC}"
7911
7927
  echo -e "Stop server: ${CYAN}loki dashboard stop${NC}"
7912
7928
  else
7913
7929
  echo -e "${YELLOW}Status: Not running (stale PID file)${NC}"
@@ -8040,14 +8056,10 @@ cmd_dashboard_open() {
8040
8056
 
8041
8057
  local url="${scheme}://${host}:${port}"
8042
8058
 
8043
- echo -e "${GREEN}Opening dashboard: $url${NC}"
8044
-
8045
- # Open in browser (cross-platform, guarded: no-op in tests/CI/non-TTY)
8046
- if ! loki_open_url "$url" 2>/dev/null; then
8047
- echo ""
8048
- echo "Browser not opened (headless, test, or no opener)."
8049
- echo "Please open in browser: $url"
8050
- fi
8059
+ # The legacy browser UI was removed; this server is API-only. Never open a
8060
+ # browser here: point at the Control Plane instead.
8061
+ echo -e "${YELLOW}The dashboard server at $url serves the API only; the browser UI is now the Control Plane.${NC}"
8062
+ echo -e "Open the Control Plane with: ${CYAN}loki ui${NC}"
8051
8063
  }
8052
8064
 
8053
8065
  # Welcome opener (the "magic opener"). Shows a branded welcome page in the
@@ -18401,8 +18413,7 @@ print(json.dumps({'id': manifest.id, 'dir': str(pipeline.migration_dir)}))
18401
18413
 
18402
18414
  sleep 2
18403
18415
  if kill -0 "$migrate_dashboard_pid" 2>/dev/null; then
18404
- echo -e " Dashboard: ${CYAN}${url_scheme}://127.0.0.1:${dashboard_port}/${NC}"
18405
- loki_open_url "${url_scheme}://127.0.0.1:${dashboard_port}/" 2>/dev/null || true
18416
+ echo -e " Dashboard API: ${CYAN}${url_scheme}://127.0.0.1:${dashboard_port}/${NC} (UI: loki ui)"
18406
18417
  echo ""
18407
18418
  else
18408
18419
  echo -e " ${YELLOW}Dashboard failed to start (check logs)${NC}"
@@ -37675,7 +37686,11 @@ print(json.dumps(json.load(open(os.environ['LOKI_PROOF_JSON'])), indent=2))
37675
37686
  _pv_att="$(loki_proof_attestation_check "$pj" "$_pv_jwks")"
37676
37687
  case "$_pv_att" in
37677
37688
  ok)
37678
- echo "attestation: VERIFIED against ${_pv_jwks}" >&2
37689
+ if [ "$(loki_proof_seal_legacy "$pj")" = "legacy" ]; then
37690
+ echo "attestation: VERIFIED against ${_pv_jwks} (metadata not signed (legacy seal.v1): scope, algo and attestation_kid are not covered by the signature)" >&2
37691
+ else
37692
+ echo "attestation: VERIFIED against ${_pv_jwks}" >&2
37693
+ fi
37679
37694
  echo " Proven: these bytes were signed by the holder of a key in that set." >&2
37680
37695
  echo " NOT proven: that the code is correct. A receipt records which checks ran." >&2
37681
37696
  _pv_attestation_field="VERIFIED"
@@ -265,8 +265,49 @@ def build_jwks(private_key=None, retired_public_keys=None) -> dict:
265
265
  return {"keys": keys}
266
266
 
267
267
 
268
+ SEAL_V2 = "seal.v2"
269
+
270
+
271
+ def seal_meta(verification, kid):
272
+ """The verification.* metadata a seal.v2 token signs.
273
+
274
+ Every key of `verification` except the token itself and attestation_kid
275
+ (which is replaced by the signing kid, so a forged kid can never match).
276
+ Any extra key a forger adds (for example gpg_signature) changes this dict
277
+ and so fails the comparison in check_seal_meta.
278
+ """
279
+ meta = {k: v for k, v in (verification or {}).items()
280
+ if k not in ("attestation", "attestation_kid")}
281
+ meta["attestation_kid"] = kid
282
+ return meta
283
+
284
+
285
+ def check_seal_meta(token, claims, verification):
286
+ """Bind verification.* metadata to a verified token. Returns (status, why).
287
+
288
+ status is "v2" (metadata signed and matching), "legacy" (seal.v1 token: the
289
+ metadata is NOT signed, the caller must say so), or "bad" (a seal.v2 token
290
+ whose signed metadata differs from what the receipt now shows).
291
+ """
292
+ if not isinstance(claims, dict) or "seal" not in claims:
293
+ return "legacy", "metadata not signed (legacy seal.v1)"
294
+ if claims.get("seal") != SEAL_V2:
295
+ return "bad", "unknown seal version"
296
+ try:
297
+ kid = json.loads(_b64url_decode(token.split(".")[0])).get("kid", "")
298
+ except Exception:
299
+ return "bad", "malformed token"
300
+ if not isinstance(verification, dict):
301
+ return "bad", "verification block missing"
302
+ if verification.get("attestation_kid") != kid:
303
+ return "bad", "attestation_kid differs from the signing kid"
304
+ if claims.get("meta") != seal_meta(verification, kid):
305
+ return "bad", "verification metadata differs from the signed metadata"
306
+ return "v2", ""
307
+
308
+
268
309
  def sign_attestation(private_key, kid, *, job_id, run_id, receipt_hash,
269
- submitter="", issued_at=None, issuer=""):
310
+ submitter="", issued_at=None, issuer="", verification=None):
270
311
  """Return a compact JWT binding a receipt hash to a job identity.
271
312
 
272
313
  The signed claims are what gpg could never carry: WHICH job produced this
@@ -294,6 +335,10 @@ def sign_attestation(private_key, kid, *, job_id, run_id, receipt_hash,
294
335
  # Optional claims are omitted rather than emitted empty: a present-but-blank
295
336
  # `sub` reads as "an anonymous submitter was recorded" instead of "no
296
337
  # submitter identity was available".
338
+ if verification is not None:
339
+ # seal.v2: the verification.* metadata is inside the signature.
340
+ payload["seal"] = SEAL_V2
341
+ payload["meta"] = seal_meta(verification, kid)
297
342
  if submitter:
298
343
  payload["sub"] = submitter
299
344
  if issuer:
package/autonomy/run.sh CHANGED
@@ -5553,7 +5553,7 @@ except Exception:
5553
5553
  # prompt over IPC; it is left untouched here) explicitly to route around
5554
5554
  # this. The boundary is a CI job that holds
5555
5555
  # no write token and no SSH agent while the agent runs (see
5556
- # .github/workflows/loki-issue-to-pr.yml).
5556
+ # docs/examples/loki-issue-to-pr.yml.example).
5557
5557
  #===============================================================================
5558
5558
  _LOKI_WITHHELD_TOKENS=""
5559
5559
  _LOKI_GIT_CONFIG_COUNT_UNSUPPORTED=""
@@ -168,7 +168,7 @@ _loki_known_command() {
168
168
  case "${1:-}" in
169
169
  --help|--version|-h|-v|agent|analyze|api|assets\
170
170
  |audit|bench|checkpoint|ci|cleanup|cluster|cockpit|code\
171
- |completions|compliance|compound|config|context|control|cost|council|cp\
171
+ |completion|completions|compliance|compound|config|context|control|cost|council|cp\
172
172
  |crash|ctx|dashboard|demo|deploy|docker|docs|doctor\
173
173
  |dogfood|enterprise|explain|export|failover|github|grill|handoff\
174
174
  |heal|help|import|init|internal|issue|kpis|logs\
@@ -1069,6 +1069,7 @@ class WebhookHandler(http.server.BaseHTTPRequestHandler):
1069
1069
  token = sign_attestation(
1070
1070
  self.signing_key, self.signing_kid,
1071
1071
  job_id=job_id, run_id=run_id, receipt_hash=receipt_hash,
1072
+ verification=verification,
1072
1073
  )
1073
1074
  if not token:
1074
1075
  return proof
package/autonomy/tui.sh CHANGED
@@ -24,7 +24,11 @@ TUI_HAS_COLOR=false
24
24
  TUI_COLS=80
25
25
  if [ -t 1 ]; then
26
26
  TUI_HAS_COLOR=true
27
- TUI_COLS=$(tput cols 2>/dev/null || echo 80)
27
+ # FC-10: tput can print 0 or nothing on a pty with no size; fall back to COLUMNS, then 80
28
+ TUI_COLS=$(tput cols 2>/dev/null || true)
29
+ case "$TUI_COLS" in '' | *[!0-9]*) TUI_COLS="${COLUMNS:-80}" ;; esac
30
+ case "$TUI_COLS" in '' | *[!0-9]*) TUI_COLS=80 ;; esac
31
+ [ "$TUI_COLS" -ge 40 ] || TUI_COLS=80
28
32
  fi
29
33
 
30
34
  # Unicode box drawing (degrade to ASCII if terminal doesn't support)
package/bin/loki CHANGED
@@ -115,6 +115,17 @@ else
115
115
  exec "$BASH_CLI" "$@"
116
116
  fi
117
117
 
118
+ # Shell completions install themselves: once per VERSION, on the first interactive
119
+ # run after an install or upgrade (stamp: ~/.loki/completions-version). Never needed
120
+ # by the user; skipped under CI, LOKI_NO_COMPLETIONS=1 and non-TTY stdout. Failure
121
+ # is silent and never blocks the command.
122
+ if [ -t 1 ] && [ -z "${CI:-}" ] && [ "${LOKI_NO_COMPLETIONS:-}" != "1" ] \
123
+ && [ "${1:-}" != "completion" ] && [ "${1:-}" != "__complete" ] \
124
+ && [ "$(cat "${HOME}/.loki/completions-version" 2>/dev/null)" != "$(cat "$REPO_ROOT/VERSION" 2>/dev/null)" ] \
125
+ && command -v bun >/dev/null 2>&1; then
126
+ bun "$BUN_CLI" completion --auto </dev/null || true
127
+ fi
128
+
118
129
  # v7.88.1 covert-path fix (council cF_r2 + cG_r2 sentinel edge): under on-by-default
119
130
  # diagnostics, NO telemetry may egress before the user has seen a disclosure once.
120
131
  # The cmd_start welcome only shows on `loki start`, so a first `loki version`/`doctor`
@@ -567,7 +578,7 @@ fi
567
578
  # Two-token routes (provider show/list, memory list/index) match on the first
568
579
  # token only; the Bun dispatcher handles subcommand routing internally.
569
580
  case "${1:-}" in
570
- version|--version|-v|status|stats|doctor|provider|memory|rollback|internal|kpis|trust|proof|receipt|wiki|crash|control|contract|slack|answer)
581
+ version|--version|-v|status|stats|doctor|provider|memory|rollback|internal|kpis|trust|proof|receipt|wiki|crash|control|contract|slack|answer|completion|__complete)
571
582
  # v7.5.2: rollback added (wires loki-ts/src/commands/rollback.ts).
572
583
  # v7.5.3: internal added for autonomy/run.sh phase1-hooks calls.
573
584
  # v7.5.28: kpis added (Phase K MVP: read-only KPI snapshot).
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ // npm postinstall: install shell completions. Must never fail the install.
3
+ try {
4
+ const { spawnSync } = require("node:child_process");
5
+ const path = require("node:path");
6
+ if (!process.env.CI && process.env.LOKI_NO_COMPLETIONS !== "1") {
7
+ spawnSync(path.join(__dirname, "loki"), ["completion", "--postinstall"], { stdio: "ignore", timeout: 20000 });
8
+ }
9
+ } catch (e) {
10
+ // ignore: completions are a convenience
11
+ }
12
+ process.exit(0);
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "10.8.0"
10
+ __version__ = "10.10.1"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -1,6 +1,6 @@
1
1
  """Read-only phase history for a run, derived from real `phase_change` events.
2
2
 
3
- WHY THIS EXISTS. dashboard-ui/components/loki-session-timeline.js SYNTHESIZED
3
+ WHY THIS EXISTS. The legacy dashboard session timeline (removed in CPE-24) SYNTHESIZED
4
4
  its timeline. It took a scalar status (uptime, current phase, iteration count),
5
5
  rotated a fixed list `['planning','building','testing','reviewing']`, and gave
6
6
  each invented segment a randomized duration:
@@ -37,7 +37,6 @@ from . import auth
37
37
  logger = logging.getLogger(__name__)
38
38
  router = APIRouter(tags=["start"])
39
39
 
40
- START_HTML = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static", "start.html")
41
40
  _LOKI_BIN = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "bin", "loki")
42
41
  _REPO_RE = re.compile(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$")
43
42
  _TOKEN_RE = re.compile(r"^[A-Za-z0-9_\-]{10,255}$")