loki-mode 10.8.0 → 10.9.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.
- package/README.md +2 -2
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +16 -31
- package/autonomy/tui.sh +5 -1
- package/dashboard/__init__.py +1 -1
- package/dashboard/api_phases.py +1 -1
- package/dashboard/api_start.py +0 -1
- package/dashboard/server.py +22 -138
- package/docs/COCKPIT-SPEC.md +3 -1
- package/docs/DASHBOARD-9.12-EVIDENCE.md +1 -1
- package/docs/DASHBOARD-ARCHITECTURE.md +13 -11
- package/docs/DASHBOARD_V2_CHECKLIST.md +2 -0
- package/docs/INSTALLATION.md +12 -11
- package/docs/MERGE-DEDUP-MAP.md +1 -1
- package/docs/MERGE-ROUTE-MAP.md +1 -1
- package/docs/MERGE3-PLAN.md +2 -2
- package/docs/R3-COST-OBSERVABILITY-DESIGN.md +2 -2
- package/docs/R4-TRUST-TRAJECTORY-DESIGN.md +1 -1
- package/docs/R5-AUTO-WIKI-DESIGN.md +1 -1
- package/docs/R6-ROLLBACK-CHECKPOINT-PLAN.md +1 -1
- package/docs/RARV-C-100X-PLAN.md +3 -3
- package/docs/SONNET5-DEFAULT-PLAN.md +2 -2
- package/docs/SYNERGY-TASKS.md +1 -1
- package/docs/TOOL-INTEGRATION.md +1 -1
- package/docs/TOP-100-BACKLOG.md +1 -1
- package/docs/alternative-installations.md +1 -1
- package/docs/architecture/ADR-001-runtime-migration.md +1 -1
- package/docs/architecture/DASHBOARD_V2_ARCHITECTURE.md +2 -0
- package/docs/audit-logging.md +2 -0
- package/docs/authentication.md +2 -0
- package/docs/authorization.md +2 -0
- package/docs/certification/02-enterprise-features/lab.md +2 -0
- package/docs/certification/02-enterprise-features/lesson.md +2 -0
- package/docs/certification/04-production-deployment/lab.md +2 -0
- package/docs/certification/04-production-deployment/lesson.md +2 -0
- package/docs/control-plane-migration.md +97 -0
- package/docs/dashboard-guide.md +6 -7
- package/docs/dev/release-checklist.md +9 -11
- package/docs/enterprise/integration-cookbook.md +2 -0
- package/docs/enterprise/migration.md +1 -1
- package/docs/enterprise/performance.md +3 -1
- package/docs/enterprise/sdk-guide.md +2 -0
- package/docs/enterprise/security.md +2 -0
- package/docs/plans/FORGE-AUTONOMOUS-QUEUE.md +2 -2
- package/docs/research-2026-07/OBSERVABILITY-TOOL-SPEC.md +1 -1
- package/docs/retrospectives/v7.5.15-honesty-audit.md +2 -2
- package/docs/test-scenarios/enterprise-scenarios.md +2 -2
- package/docs/v10/ARCHITECT-CUTS.md +9 -9
- package/docs/v10/BACKLOG.md +7 -7
- package/docs/v10/BOARD.md +25 -25
- package/docs/v10/CONTROL-PLANE.md +4 -4
- package/docs/v10/CP-ENTERPRISE-UI.md +66 -66
- package/docs/v10/D51-PHASE-B.md +1 -1
- package/docs/v10/DECISIONS.md +3 -3
- package/docs/v10/DEPS.md +10 -10
- package/docs/v10/FAILURE-CLASSES.md +45 -1
- package/docs/v10/LEGACY-REMOVAL.md +2 -2
- package/docs/v10/SWARM.md +2 -2
- package/loki-ts/dist/cockpit.js +11 -11
- package/loki-ts/dist/loki.js +596 -579
- package/magic/core/design_tokens.py +1 -2
- package/magic/core/generator.py +2 -2
- package/magic/tokens/README.md +1 -3
- package/mcp/__init__.py +1 -1
- package/package.json +2 -7
- package/packages/control-plane/dist/server.js +1683 -843
- package/packages/control-plane/src/server/legacy/routes-audit.ts +50 -0
- package/packages/control-plane/src/server/legacy/routes-control.ts +26 -0
- package/packages/control-plane/src/server/legacy/routes-memory.ts +30 -0
- package/packages/control-plane/src/server/legacy/routes.ts +58 -58
- package/packages/control-plane/src/server/legacy/shim.ts +10 -4
- package/packages/control-plane/src/server/routes/checkpoints.ts +171 -0
- package/packages/control-plane/src/server/routes/index.ts +4 -1
- package/packages/control-plane/src/server/routes/memory.ts +219 -0
- package/packages/control-plane/src/server/routes/session_control.ts +155 -0
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/references/magic-modules-patterns.md +2 -2
- package/skills/factory-operations.md +3 -3
- package/skills/magic-modules.md +1 -1
- package/skills/release-cadence.md +1 -1
- package/tools/audit-docs.py +1 -1
- package/tools/index-codebase.py +1 -1
- package/web-app/dist/assets/{AdminPage-DDDvUz0N.js → AdminPage-DqMnfZrH.js} +1 -1
- package/web-app/dist/assets/{Avatar-Dcdz46i6.js → Avatar-BEof29du.js} +1 -1
- package/web-app/dist/assets/{Badge-BB24cCpK.js → Badge-WD53OL5m.js} +1 -1
- package/web-app/dist/assets/{Button-D0-DmPZL.js → Button-Rzk5flhU.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-CdjpU2JW.js → CockpitPage-Bqz3PCMh.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DT5U0y0d.js → ComparePage-Byo2NzAZ.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-lEHcl0EO.js → ErrorBoundary-BuE0kH3W.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-GpnWvdCr.js → EvidenceReceiptPanel-CKFHOPBx.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-C7VOh1B7.js → GitHubIssuesPanel-Df_kTMqI.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-G_kOuINv.js → GitHubPRsPanel-CouvcKrZ.js} +1 -1
- package/web-app/dist/assets/{HomePage-PqRisOny.js → HomePage-dEpLzj0x.js} +2 -2
- package/web-app/dist/assets/{LoginPage-DU7pFAkf.js → LoginPage-6DVjUND5.js} +1 -1
- package/web-app/dist/assets/{MagicPage-C5JWIWMk.js → MagicPage-BDQ9MOfY.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-CbIGS_qo.js → MetricsPage-CXiJ04G_.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-vU1pvdSt.js → NotFoundPage-BaXhZvyj.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-SsixIPPv.js → ProjectPage-BzE4V7Ti.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-BfQKSR9k.js → ProjectsPage-ipf6TLMX.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-B8YfXAom.js → SettingsPage-BDxkUKN6.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-Ba407f2-.js → ShowcasePage-YQXD72SM.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-DzNQhhBS.js → SystemSettingsPage-Dou7zHS0.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-tqUnpZ15.js → TeamsPage-CQarfcYr.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-ClB5EpI3.js → TemplatesPage-CPi1R8Xj.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-CBvpYfEu.js → TerminalOutput-WiGhWdYD.js} +1 -1
- package/web-app/dist/assets/{activity-C1s0L_X9.js → activity-DOa7ejQA.js} +1 -1
- package/web-app/dist/assets/{bell-DMEiXr73.js → bell-CX-VAlYN.js} +1 -1
- package/web-app/dist/assets/{bot-BF_xIOxu.js → bot-EDXaZmHc.js} +1 -1
- package/web-app/dist/assets/{check-Dv1Ynvrs.js → check-CnBdKk3L.js} +1 -1
- package/web-app/dist/assets/{chevron-left-Ddhsod7S.js → chevron-left-BJ_ydRQW.js} +1 -1
- package/web-app/dist/assets/{circle-alert-OATHUkBZ.js → circle-alert-tz8ufhc_.js} +1 -1
- package/web-app/dist/assets/{clock-C1Ltva07.js → clock-DFBZPSsH.js} +1 -1
- package/web-app/dist/assets/{cloud-B-S4oOy9.js → cloud-uy3p_5Q7.js} +1 -1
- package/web-app/dist/assets/{code-xml-D3Femn_F.js → code-xml-3CbYD9YL.js} +1 -1
- package/web-app/dist/assets/{database-DBSeFgO3.js → database-YiNBXc9c.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-sgDgNuGE.js → dollar-sign-D0wBa4Cv.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-C-MbdZEc.js → file-code-corner-DDdZVZ5v.js} +1 -1
- package/web-app/dist/assets/{file-plus-CCB6yqXv.js → file-plus-D09LTBqt.js} +1 -1
- package/web-app/dist/assets/{globe-DlbrNAj1.js → globe-BirTPwff.js} +1 -1
- package/web-app/dist/assets/{hammer-B-DWm695.js → hammer-DaE5qgnd.js} +1 -1
- package/web-app/dist/assets/{index-Dvny-1SU.js → index-D8t7KnQf.js} +3 -3
- package/web-app/dist/assets/{layers-99qsKpOT.js → layers-DVVrckRY.js} +1 -1
- package/web-app/dist/assets/{loader-circle-ZvZyZl3J.js → loader-circle-2-nMGmcb.js} +1 -1
- package/web-app/dist/assets/{lock-DosGjcxP.js → lock-D0Xj43pC.js} +1 -1
- package/web-app/dist/assets/{package-C-PumesN.js → package-BB7S3egm.js} +1 -1
- package/web-app/dist/assets/{plus-CTYYskTB.js → plus-BLhoMrn3.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-qW2ztTFS.js → refresh-cw-DMc2uPLw.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-ZIKrf-vO.js → rotate-ccw-DM3IP9x7.js} +1 -1
- package/web-app/dist/assets/{scroll-text-BamlXjAT.js → scroll-text-lH2uW7rB.js} +1 -1
- package/web-app/dist/assets/{server-BljXb79I.js → server-BkerZcdR.js} +1 -1
- package/web-app/dist/assets/{shield-alert-Dr6eT9c_.js → shield-alert-B8ohcUfu.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-v3oBXZgU.js → thumbs-up-CTIxLzPD.js} +1 -1
- package/web-app/dist/assets/{trash-2-BOuIrCpi.js → trash-2-C3zIpsH5.js} +1 -1
- package/web-app/dist/assets/{trending-down-Dp7jMCgH.js → trending-down-BTT7wV4Y.js} +1 -1
- package/web-app/dist/assets/{trending-up-CDiur-nP.js → trending-up-BzHdCDvF.js} +1 -1
- package/web-app/dist/assets/{upload-DxIHXhNE.js → upload-HxR34-A8.js} +1 -1
- package/web-app/dist/assets/{usePolling-D2Uu-YZb.js → usePolling-DDj6Fupy.js} +1 -1
- package/web-app/dist/assets/{user-BVWCUAfF.js → user-qH5y9yNy.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/dashboard/static/assets/mermaid.min.js +0 -2030
- package/dashboard/static/cost.html +0 -344
- package/dashboard/static/favicon.svg +0 -5
- package/dashboard/static/index.html +0 -15577
- package/dashboard/static/proofs.html +0 -194
- package/dashboard/static/start.html +0 -131
- package/dashboard/static/trust.html +0 -325
package/README.md
CHANGED
|
@@ -310,7 +310,7 @@ The URL comes from `LOKI_CONTROL_URL`, else `http://127.0.0.1:${LOKI_CONTROL_POR
|
|
|
310
310
|
|
|
311
311
|
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
312
|
|
|
313
|
-
|
|
313
|
+
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
314
|
|
|
315
315
|
Container, Helm and ECS deployment: [docs/control-plane-container.md](docs/control-plane-container.md).
|
|
316
316
|
|
|
@@ -588,7 +588,7 @@ Legacy engine, being removed (these run on the previous engine; `loki --help` st
|
|
|
588
588
|
| `loki stop`, `pause`, `resume` | Control a legacy run |
|
|
589
589
|
| `loki steer "<note>"` | Nudge a legacy run (needs `LOKI_PROMPT_INJECTION=1`) |
|
|
590
590
|
| `loki why`, `loki next` | Explain or continue a legacy run |
|
|
591
|
-
| `loki dashboard` |
|
|
591
|
+
| `loki dashboard` | Open the Control Plane UI (see [docs/control-plane-migration.md](docs/control-plane-migration.md)) |
|
|
592
592
|
| `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
593
|
| `loki modernize heal <path>` | Legacy system healing |
|
|
594
594
|
|
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.
|
|
6
|
+
# Loki Mode v10.9.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
|
|
|
@@ -473,4 +473,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
473
473
|
|
|
474
474
|
---
|
|
475
475
|
|
|
476
|
-
**v10.
|
|
476
|
+
**v10.9.1 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
10.
|
|
1
|
+
10.9.1
|
package/autonomy/loki
CHANGED
|
@@ -2032,12 +2032,11 @@ cmd_ui() {
|
|
|
2032
2032
|
LOKI_DASHBOARD_CORS="http://localhost:$port,http://127.0.0.1:$port" \
|
|
2033
2033
|
cmd_dashboard_start --host 127.0.0.1 --port "$port" >&2 || return 1
|
|
2034
2034
|
fi
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
fi
|
|
2035
|
+
# The classic server is API-only; the UI is the Control Plane.
|
|
2036
|
+
local url="http://127.0.0.1:${port}"
|
|
2037
|
+
echo "loki: the classic dashboard at $url serves the API only (the browser UI moved to the Control Plane)." >&2
|
|
2038
|
+
echo "loki: start the Control Plane UI with: loki ui (needs bun)" >&2
|
|
2039
|
+
echo "$url"
|
|
2041
2040
|
}
|
|
2042
2041
|
|
|
2043
2042
|
# Tight newcomer landing for the bare `loki` invocation (no args).
|
|
@@ -3915,18 +3914,9 @@ cmd_start() {
|
|
|
3915
3914
|
# + cockpit, honoring the card's "open dashboard" promise. The
|
|
3916
3915
|
# cockpit hint is printed by _loki_start_handoff for the Both path.
|
|
3917
3916
|
args+=("--bg")
|
|
3918
|
-
#
|
|
3919
|
-
#
|
|
3920
|
-
|
|
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
|
-
) &
|
|
3917
|
+
# The browser UI is the Control Plane; open it (guarded by
|
|
3918
|
+
# loki_open_url: no-op headless and in tests).
|
|
3919
|
+
( LOKI_UI_NO_CLASSIC=1 cmd_ui 2>/dev/null || true ) &
|
|
3930
3920
|
;;
|
|
3931
3921
|
launch-bg-watch)
|
|
3932
3922
|
# Watch (cockpit only) detaches without opening the browser.
|
|
@@ -7561,7 +7551,7 @@ cmd_dashboard_help() {
|
|
|
7561
7551
|
echo " loki dashboard start --tls-cert cert.pem --tls-key key.pem"
|
|
7562
7552
|
echo " loki dashboard status # Check if running"
|
|
7563
7553
|
echo " loki dashboard url --format json # Get URL as JSON"
|
|
7564
|
-
echo " loki dashboard open #
|
|
7554
|
+
echo " loki dashboard open # Print the Control Plane hint (no browser)"
|
|
7565
7555
|
echo " loki dashboard stop # Stop server"
|
|
7566
7556
|
}
|
|
7567
7557
|
|
|
@@ -7789,7 +7779,7 @@ cmd_dashboard_start() {
|
|
|
7789
7779
|
# a second port.
|
|
7790
7780
|
echo -e "${DIM}Want to submit a spec in the browser? Open the 'Lab' tab in this dashboard.${NC}"
|
|
7791
7781
|
echo ""
|
|
7792
|
-
echo -e "
|
|
7782
|
+
echo -e "Control Plane UI: ${CYAN}loki ui${NC}"
|
|
7793
7783
|
echo -e "Check status: ${CYAN}loki dashboard status${NC}"
|
|
7794
7784
|
echo -e "Stop server: ${CYAN}loki dashboard stop${NC}"
|
|
7795
7785
|
else
|
|
@@ -7907,7 +7897,7 @@ cmd_dashboard_status() {
|
|
|
7907
7897
|
fi
|
|
7908
7898
|
|
|
7909
7899
|
echo ""
|
|
7910
|
-
echo -e "
|
|
7900
|
+
echo -e "Control Plane UI: ${CYAN}loki ui${NC}"
|
|
7911
7901
|
echo -e "Stop server: ${CYAN}loki dashboard stop${NC}"
|
|
7912
7902
|
else
|
|
7913
7903
|
echo -e "${YELLOW}Status: Not running (stale PID file)${NC}"
|
|
@@ -8040,14 +8030,10 @@ cmd_dashboard_open() {
|
|
|
8040
8030
|
|
|
8041
8031
|
local url="${scheme}://${host}:${port}"
|
|
8042
8032
|
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
echo ""
|
|
8048
|
-
echo "Browser not opened (headless, test, or no opener)."
|
|
8049
|
-
echo "Please open in browser: $url"
|
|
8050
|
-
fi
|
|
8033
|
+
# The legacy browser UI was removed; this server is API-only. Never open a
|
|
8034
|
+
# browser here: point at the Control Plane instead.
|
|
8035
|
+
echo -e "${YELLOW}The dashboard server at $url serves the API only; the browser UI is now the Control Plane.${NC}"
|
|
8036
|
+
echo -e "Open the Control Plane with: ${CYAN}loki ui${NC}"
|
|
8051
8037
|
}
|
|
8052
8038
|
|
|
8053
8039
|
# Welcome opener (the "magic opener"). Shows a branded welcome page in the
|
|
@@ -18401,8 +18387,7 @@ print(json.dumps({'id': manifest.id, 'dir': str(pipeline.migration_dir)}))
|
|
|
18401
18387
|
|
|
18402
18388
|
sleep 2
|
|
18403
18389
|
if kill -0 "$migrate_dashboard_pid" 2>/dev/null; then
|
|
18404
|
-
echo -e " Dashboard:
|
|
18405
|
-
loki_open_url "${url_scheme}://127.0.0.1:${dashboard_port}/" 2>/dev/null || true
|
|
18390
|
+
echo -e " Dashboard API: ${CYAN}${url_scheme}://127.0.0.1:${dashboard_port}/${NC} (UI: loki ui)"
|
|
18406
18391
|
echo ""
|
|
18407
18392
|
else
|
|
18408
18393
|
echo -e " ${YELLOW}Dashboard failed to start (check logs)${NC}"
|
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
|
-
|
|
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/dashboard/__init__.py
CHANGED
package/dashboard/api_phases.py
CHANGED
|
@@ -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
|
|
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:
|
package/dashboard/api_start.py
CHANGED
|
@@ -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}$")
|
package/dashboard/server.py
CHANGED
|
@@ -1149,14 +1149,8 @@ app.add_middleware(
|
|
|
1149
1149
|
allow_headers=["Content-Type", "Authorization", "X-Requested-With"],
|
|
1150
1150
|
)
|
|
1151
1151
|
|
|
1152
|
-
# RESPONSE COMPRESSION.
|
|
1153
|
-
#
|
|
1154
|
-
# an 81% reduction. Until now only CORS and the collab WS auth middleware were
|
|
1155
|
-
# registered, so every dashboard load shipped the full 780KB.
|
|
1156
|
-
#
|
|
1157
|
-
# That single fact is the most plausible cause of "the dashboard feels slow":
|
|
1158
|
-
# it is not a rendering problem, it is 630KB of avoidable transfer on first
|
|
1159
|
-
# paint, and it costs one middleware to fix.
|
|
1152
|
+
# RESPONSE COMPRESSION. Large JSON API payloads compress well, and it costs one
|
|
1153
|
+
# middleware. (The legacy single-file UI bundle that motivated it was removed.)
|
|
1160
1154
|
#
|
|
1161
1155
|
# minimum_size=1024 leaves small JSON responses uncompressed, where the CPU
|
|
1162
1156
|
# round-trip outweighs the saving. GZipMiddleware is stdlib-backed and does
|
|
@@ -1360,16 +1354,12 @@ else:
|
|
|
1360
1354
|
app.include_router(api_operator_router)
|
|
1361
1355
|
|
|
1362
1356
|
# D51 Phase A: first-run onboarding + backlog API and its /start page.
|
|
1363
|
-
from .api_start import router as api_start_router
|
|
1357
|
+
from .api_start import router as api_start_router
|
|
1364
1358
|
app.include_router(api_start_router)
|
|
1365
1359
|
from .api_runs_v1 import router as api_runs_v1_router
|
|
1366
1360
|
app.include_router(api_runs_v1_router)
|
|
1367
1361
|
|
|
1368
1362
|
|
|
1369
|
-
@app.get("/start", include_in_schema=False, dependencies=[Depends(auth.require_scope("read"))])
|
|
1370
|
-
async def serve_start_page():
|
|
1371
|
-
return FileResponse(_START_HTML, media_type="text/html")
|
|
1372
|
-
|
|
1373
1363
|
|
|
1374
1364
|
# Phase Merge-4: Mount Purple Lab FastAPI app under /lab/ so it appears as a
|
|
1375
1365
|
# sidebar entry in Dashboard. Same `app` is also wrapped by `standalone_app`
|
|
@@ -11579,49 +11569,11 @@ def optimize_prompts(sessions: int = 10, dry_run: bool = True):
|
|
|
11579
11569
|
|
|
11580
11570
|
from fastapi.responses import FileResponse, HTMLResponse
|
|
11581
11571
|
|
|
11582
|
-
# Find static files in multiple possible locations
|
|
11583
11572
|
DASHBOARD_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
11584
11573
|
PROJECT_ROOT = os.path.dirname(DASHBOARD_DIR)
|
|
11585
11574
|
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
def _static_candidates(skill_dir=None, home=None):
|
|
11589
|
-
"""Static dirs in preference order: package, LOKI_SKILL_DIR, ~/.claude skill, dev build."""
|
|
11590
|
-
skill_dir = os.environ.get("LOKI_SKILL_DIR", "") if skill_dir is None else skill_dir
|
|
11591
|
-
home_skill = os.path.join(home or os.path.expanduser("~"), ".claude", "skills", "loki-mode")
|
|
11592
|
-
cands = [os.path.join(DASHBOARD_DIR, "static")]
|
|
11593
|
-
if skill_dir:
|
|
11594
|
-
cands.append(os.path.join(skill_dir, "dashboard", "static"))
|
|
11595
|
-
cands.append(os.path.join(home_skill, "dashboard", "static"))
|
|
11596
|
-
cands.append(os.path.join(PROJECT_ROOT, "dashboard-ui", "dist"))
|
|
11597
|
-
if skill_dir:
|
|
11598
|
-
cands.append(os.path.join(skill_dir, "dashboard-ui", "dist"))
|
|
11599
|
-
cands.append(os.path.join(home_skill, "dashboard-ui", "dist"))
|
|
11600
|
-
return cands
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
def _pick_static_dir(candidates):
|
|
11604
|
-
"""First candidate that CONTAINS index.html; an empty or partial dir must not win."""
|
|
11605
|
-
for loc in candidates:
|
|
11606
|
-
if os.path.isfile(os.path.join(loc, "index.html")):
|
|
11607
|
-
return loc
|
|
11608
|
-
return None
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
STATIC_LOCATIONS = _static_candidates()
|
|
11612
|
-
STATIC_DIR = _pick_static_dir(STATIC_LOCATIONS)
|
|
11613
|
-
if STATIC_DIR:
|
|
11614
|
-
logger.info("Dashboard frontend served from: %s", STATIC_DIR)
|
|
11615
|
-
else:
|
|
11616
|
-
logger.warning("Dashboard frontend NOT found (looked in %s); serving built-in fallback page", STATIC_LOCATIONS)
|
|
11617
|
-
|
|
11618
|
-
if STATIC_DIR:
|
|
11619
|
-
from fastapi.staticfiles import StaticFiles
|
|
11620
|
-
|
|
11621
|
-
# Check if assets directory exists (built frontend)
|
|
11622
|
-
ASSETS_DIR = os.path.join(STATIC_DIR, "assets")
|
|
11623
|
-
if os.path.isdir(ASSETS_DIR):
|
|
11624
|
-
app.mount("/assets", StaticFiles(directory=ASSETS_DIR), name="assets")
|
|
11575
|
+
DASHBOARD_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
11576
|
+
PROJECT_ROOT = os.path.dirname(DASHBOARD_DIR)
|
|
11625
11577
|
|
|
11626
11578
|
# ---------------------------------------------------------------------------
|
|
11627
11579
|
# Activity Logger & Session Diff
|
|
@@ -11682,75 +11634,29 @@ async def log_activity(entry: dict):
|
|
|
11682
11634
|
return result
|
|
11683
11635
|
|
|
11684
11636
|
|
|
11685
|
-
#
|
|
11686
|
-
|
|
11687
|
-
async def serve_favicon():
|
|
11688
|
-
"""Serve the dashboard favicon."""
|
|
11689
|
-
if STATIC_DIR:
|
|
11690
|
-
favicon_path = os.path.join(STATIC_DIR, "favicon.svg")
|
|
11691
|
-
if os.path.isfile(favicon_path):
|
|
11692
|
-
return FileResponse(favicon_path, media_type="image/svg+xml")
|
|
11693
|
-
return Response(status_code=404)
|
|
11694
|
-
|
|
11695
|
-
|
|
11696
|
-
# Serve the self-contained cost + observability panel (R3). Zero-build
|
|
11697
|
-
# standalone page that fetches /api/cost/timeline. Mirrors the proofs.html
|
|
11698
|
-
# pattern: works without the SPA build.
|
|
11699
|
-
@app.get("/cost", include_in_schema=False, dependencies=[Depends(auth.require_scope("read"))])
|
|
11700
|
-
async def serve_cost_panel():
|
|
11701
|
-
"""Serve the standalone cost + observability HTML panel."""
|
|
11702
|
-
if STATIC_DIR:
|
|
11703
|
-
cost_path = os.path.join(STATIC_DIR, "cost.html")
|
|
11704
|
-
if os.path.isfile(cost_path):
|
|
11705
|
-
return FileResponse(cost_path, media_type="text/html")
|
|
11706
|
-
return Response(status_code=404)
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
# R4: standalone trust-trajectory page that fetches /api/trust/trajectory.
|
|
11710
|
-
# Mirrors the cost.html / /cost pattern: works without the SPA build.
|
|
11711
|
-
@app.get("/trust", include_in_schema=False, dependencies=[Depends(auth.require_scope("read"))])
|
|
11712
|
-
async def serve_trust_panel():
|
|
11713
|
-
"""Serve the standalone trust-trajectory HTML panel."""
|
|
11714
|
-
if STATIC_DIR:
|
|
11715
|
-
trust_path = os.path.join(STATIC_DIR, "trust.html")
|
|
11716
|
-
if os.path.isfile(trust_path):
|
|
11717
|
-
return FileResponse(trust_path, media_type="text/html")
|
|
11718
|
-
return Response(status_code=404)
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
# Serve index.html or standalone HTML for root
|
|
11637
|
+
# The legacy dashboard UI was removed (CPE-24). The Control Plane serves the UI;
|
|
11638
|
+
# this server keeps only the /api/* routes that have no Control Plane home yet.
|
|
11722
11639
|
@app.get("/", include_in_schema=False, dependencies=[Depends(auth.require_scope("read"))])
|
|
11723
11640
|
async def serve_index():
|
|
11724
|
-
"""
|
|
11725
|
-
|
|
11726
|
-
index_candidates = []
|
|
11727
|
-
if STATIC_DIR:
|
|
11728
|
-
index_candidates.append(os.path.join(STATIC_DIR, "index.html"))
|
|
11729
|
-
index_candidates.append(os.path.join(STATIC_DIR, "loki-dashboard-standalone.html"))
|
|
11641
|
+
"""Tell a browser where the UI moved; never serve developer JSON to it."""
|
|
11642
|
+
return HTMLResponse(content=_moved_page(), status_code=410)
|
|
11730
11643
|
|
|
11731
|
-
# Also check dashboard-ui directly for standalone
|
|
11732
|
-
standalone_path = os.path.join(PROJECT_ROOT, "dashboard-ui", "dist", "loki-dashboard-standalone.html")
|
|
11733
|
-
if standalone_path not in index_candidates:
|
|
11734
|
-
index_candidates.append(standalone_path)
|
|
11735
11644
|
|
|
11736
|
-
|
|
11737
|
-
if os.path.isfile(index_path):
|
|
11738
|
-
return FileResponse(index_path, media_type="text/html")
|
|
11739
|
-
|
|
11740
|
-
# No frontend anywhere: a browser must never see developer JSON.
|
|
11741
|
-
return HTMLResponse(content=_fallback_page(), status_code=503)
|
|
11742
|
-
|
|
11743
|
-
|
|
11744
|
-
def _fallback_page() -> str:
|
|
11645
|
+
def _moved_page() -> str:
|
|
11745
11646
|
import html as _html
|
|
11647
|
+
cp = os.environ.get("LOKI_CONTROL_PLANE_URL", "").strip()
|
|
11648
|
+
where = (
|
|
11649
|
+
f'<p>Control Plane: <a href="{_html.escape(cp, quote=True)}">{_html.escape(cp)}</a></p>'
|
|
11650
|
+
if cp.startswith(("http://", "https://"))
|
|
11651
|
+
else "<p>Run <code>loki ui</code> to open the Control Plane.</p>"
|
|
11652
|
+
)
|
|
11746
11653
|
return (
|
|
11747
11654
|
'<!doctype html><html lang="en"><head><meta charset="utf-8">'
|
|
11748
|
-
"<title>Loki Mode
|
|
11655
|
+
"<title>Loki Mode API</title></head>"
|
|
11749
11656
|
'<body style="font-family:system-ui,sans-serif;max-width:40rem;margin:4rem auto;padding:0 1rem">'
|
|
11750
|
-
"<h1>
|
|
11751
|
-
f"<p>
|
|
11752
|
-
"
|
|
11753
|
-
"<p>Reinstall to fix it:</p><pre>npm install -g loki-mode@latest</pre>"
|
|
11657
|
+
"<h1>The dashboard UI moved to the Control Plane</h1>"
|
|
11658
|
+
f"<p>This server (version {_html.escape(str(_version))}) now serves the /api routes only.</p>"
|
|
11659
|
+
f"{where}"
|
|
11754
11660
|
'<p><a href="/docs">API docs</a> | <a href="/health">Health</a></p>'
|
|
11755
11661
|
"</body></html>"
|
|
11756
11662
|
)
|
|
@@ -13099,40 +13005,18 @@ async def post_wiki_ask(req: WikiAskRequest):
|
|
|
13099
13005
|
|
|
13100
13006
|
|
|
13101
13007
|
# ---------------------------------------------------------------------------
|
|
13102
|
-
#
|
|
13103
|
-
# or static asset mounts. This lets the dashboard UI handle client-side routing.
|
|
13008
|
+
# Catch-all: unknown paths are real 404s (the SPA was removed, CPE-24).
|
|
13104
13009
|
# Must be registered LAST so it never shadows an API endpoint.
|
|
13105
13010
|
# ---------------------------------------------------------------------------
|
|
13106
13011
|
@app.get("/{full_path:path}", include_in_schema=False, dependencies=[Depends(auth.require_scope("read"))])
|
|
13107
13012
|
async def serve_spa_catchall(full_path: str):
|
|
13108
|
-
"""
|
|
13109
|
-
|
|
13110
|
-
v7.6.1 B-10 fix: requests under /api/, /lab/api/, or /ws/ that fall through
|
|
13111
|
-
here are missing routes, not SPA navigation. Returning index.html (text/html)
|
|
13112
|
-
silently masks 404s and breaks JSON clients (the dashboard UI's loki-memory-browser
|
|
13113
|
-
pinged /api/learning/metrics expecting JSON and got an HTML SPA on prior
|
|
13114
|
-
failures). Return a JSON 404 instead so clients fail loud.
|
|
13115
|
-
"""
|
|
13116
|
-
# API paths that fell through are real 404s, not SPA routes.
|
|
13013
|
+
"""Return a JSON 404 for API-like paths so JSON clients fail loud, else a bare 404."""
|
|
13117
13014
|
api_like = full_path.startswith("api/") or full_path.startswith("lab/api/") or full_path.startswith("ws/")
|
|
13118
13015
|
if api_like:
|
|
13119
13016
|
return JSONResponse(
|
|
13120
13017
|
status_code=404,
|
|
13121
13018
|
content={"error": "Not Found", "path": f"/{full_path}"},
|
|
13122
13019
|
)
|
|
13123
|
-
if STATIC_DIR:
|
|
13124
|
-
static_root = os.path.realpath(STATIC_DIR)
|
|
13125
|
-
# Try to serve the exact file first (e.g. /vite.svg, /manifest.json)
|
|
13126
|
-
# Use realpath to prevent path traversal attacks
|
|
13127
|
-
candidate = os.path.realpath(os.path.join(STATIC_DIR, full_path))
|
|
13128
|
-
if not candidate.startswith(static_root + os.sep) and candidate != static_root:
|
|
13129
|
-
return Response(status_code=404)
|
|
13130
|
-
if os.path.isfile(candidate):
|
|
13131
|
-
return FileResponse(candidate)
|
|
13132
|
-
# Fall back to index.html for client-side routes
|
|
13133
|
-
index_path = os.path.join(STATIC_DIR, "index.html")
|
|
13134
|
-
if os.path.isfile(index_path):
|
|
13135
|
-
return FileResponse(index_path, media_type="text/html")
|
|
13136
13020
|
return Response(status_code=404)
|
|
13137
13021
|
|
|
13138
13022
|
|
package/docs/COCKPIT-SPEC.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Loki Cockpit (rec #6) - build spec
|
|
2
2
|
|
|
3
|
+
> **Historical:** this describes the classic dashboard, removed in Loki Mode 10.8. The Control Plane is the only UI; see [control-plane-migration.md](control-plane-migration.md).
|
|
4
|
+
|
|
3
5
|
Status: IN BUILD (v7.126.0 target). Design approved via mockup
|
|
4
6
|
(scratchpad/loki-cockpit.html). Grounded in real engine state + Autonomi identity.
|
|
5
7
|
|
|
@@ -59,7 +61,7 @@ No chafa / no headless Chrome hard dependency. Pipeline:
|
|
|
59
61
|
- S3 (render pipeline): SVG-from-state builder + SVG->PNG + terminal-image
|
|
60
62
|
encoder + capability detection + fallback. Tests (encoder byte-shape, detection).
|
|
61
63
|
- S4 (dashboard identity redesign): apply logo/purple/fonts/multi-repo switcher to
|
|
62
|
-
|
|
64
|
+
legacy-ui; rebuild dist. Lightweight gate.
|
|
63
65
|
- S5 (docs + wiki + release): help text, README, wiki, CHANGELOG, 14 version files.
|
|
64
66
|
|
|
65
67
|
## Constraints
|
|
@@ -28,7 +28,7 @@ carries a `reason`, an unmeasured number reads `None` rather than `0`, and
|
|
|
28
28
|
| `source` | 10 of 43 | Most rows cannot be audited back to the file they came from |
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
cd
|
|
31
|
+
cd legacy-ui
|
|
32
32
|
grep -l "freshness_s" components/*.js core/*.js | wc -l # 0
|
|
33
33
|
grep -l "measured" components/*.js core/*.js | wc -l # 0
|
|
34
34
|
```
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Dashboard Architecture: Real-Data, Near-Realtime
|
|
2
2
|
|
|
3
|
+
> **Historical:** this describes the classic dashboard, removed in Loki Mode 10.8. The Control Plane is the only UI; see [control-plane-migration.md](control-plane-migration.md).
|
|
4
|
+
|
|
3
5
|
Design only. No implementation in this document.
|
|
4
6
|
|
|
5
7
|
Status: proposal. Measured against the worktree at
|
|
@@ -41,7 +43,7 @@ brief's number and my measurement disagree, both are shown.
|
|
|
41
43
|
|
|
42
44
|
One correction against myself: my first pass reported `0` aria attributes in the
|
|
43
45
|
built artifact and I nearly wrote that up as a shipped accessibility regression.
|
|
44
|
-
It was a measurement error. `
|
|
46
|
+
It was a measurement error. `legacy-ui-static/index.html` has lines long enough
|
|
45
47
|
(577 chars plus minified runs) that `grep` treated the file as binary and
|
|
46
48
|
suppressed output. With `grep -a` the brief's numbers are confirmed. This is the
|
|
47
49
|
`grep-absence false-green` failure mode: an empty result was an absent
|
|
@@ -178,7 +180,7 @@ machine-checkable instead of a naming habit.
|
|
|
178
180
|
`/api/health/processes`.
|
|
179
181
|
|
|
180
182
|
Built artifact realtime constructs: 9
|
|
181
|
-
(`grep -oaE "new WebSocket|EventSource|setInterval"
|
|
183
|
+
(`grep -oaE "new WebSocket|EventSource|setInterval" legacy-ui-static/index.html | wc -l`).
|
|
182
184
|
The brief's "34 realtime constructs" is not reproducible by any pattern I tried;
|
|
183
185
|
I mark that figure **not independently verified** rather than repeat it.
|
|
184
186
|
|
|
@@ -234,8 +236,8 @@ The bundle is 779,725 bytes raw, 150,341 gzipped
|
|
|
234
236
|
gzip stays; nothing in this design touches it.
|
|
235
237
|
|
|
236
238
|
**Progressive disclosure here cannot mean code-splitting.**
|
|
237
|
-
`
|
|
238
|
-
file with zero runtime dependencies, written to both `
|
|
239
|
+
`legacy-ui/scripts/build-standalone.js` produces a single self-contained
|
|
240
|
+
file with zero runtime dependencies, written to both `legacy-ui-static/` and
|
|
239
241
|
`dist/`. That property is why the dashboard works offline and inside Docker
|
|
240
242
|
without a CDN. Splitting the bundle would trade a real capability for a
|
|
241
243
|
transfer-size win that gzip has already mostly taken (5.2x). So disclosure is
|
|
@@ -265,12 +267,12 @@ Measured on the shipped artifact with `grep -a`:
|
|
|
265
267
|
|
|
266
268
|
| Property | Count | Command |
|
|
267
269
|
|---|---|---|
|
|
268
|
-
| Custom elements registered | 39 | `grep -oa "customElements.define"
|
|
270
|
+
| Custom elements registered | 39 | `grep -oa "customElements.define" legacy-ui-static/index.html \| wc -l` |
|
|
269
271
|
| `aria-*` attributes | 100 | `grep -oa "aria-[a-z]*=" ... \| wc -l` |
|
|
270
272
|
| `aria-` occurrences | 113 | `grep -oa "aria-" ... \| wc -l` |
|
|
271
273
|
| `role="` | 38 | `grep -oa 'role="' ... \| wc -l` |
|
|
272
274
|
| `@media` breakpoints | 13 | `grep -oa "@media" ... \| wc -l` |
|
|
273
|
-
| Component source files | 43 | `ls
|
|
275
|
+
| Component source files | 43 | `ls legacy-ui/components \| grep -v vendor \| wc -l` |
|
|
274
276
|
| Registrations in source | 44 | `grep -roha "customElements.define" components core \| wc -l` |
|
|
275
277
|
|
|
276
278
|
The brief's 113 aria and 41 role are consistent with mine within pattern choice
|
|
@@ -278,7 +280,7 @@ The brief's 113 aria and 41 role are consistent with mine within pattern choice
|
|
|
278
280
|
figure is 43 files carrying 44 registrations, not 46.
|
|
279
281
|
|
|
280
282
|
**One gap worth noting:** source registers 44 custom elements, the shipped
|
|
281
|
-
artifact registers 39. Five components exist in `
|
|
283
|
+
artifact registers 39. Five components exist in `legacy-ui/` and do not reach
|
|
282
284
|
the browser. This is out of scope for this document and I did not chase it, but
|
|
283
285
|
it is recorded here because it means the source tree is not a reliable proxy for
|
|
284
286
|
what ships. All acceptance criteria in section 5 therefore measure the **built
|
|
@@ -369,10 +371,10 @@ Every row is measurable by a command. No aspirational entries.
|
|
|
369
371
|
|---|---|---|---|
|
|
370
372
|
| A1 | No route regression | `grep -cE '^@app\.(get\|post\|put\|delete\|patch\|websocket)' dashboard/server.py` | >= 165 |
|
|
371
373
|
| A2 | api_v2 routes intact | `grep -cE '@router\.(get\|post\|put\|delete)' dashboard/api_v2.py` | >= 24 |
|
|
372
|
-
| A3 | Accessibility not regressed | `grep -oa "aria-"
|
|
373
|
-
| A4 | Roles not regressed | `grep -oa 'role="'
|
|
374
|
-
| A5 | Custom elements not regressed | `grep -oa "customElements.define"
|
|
375
|
-
| A6 | Breakpoints not regressed | `grep -oa "@media"
|
|
374
|
+
| A3 | Accessibility not regressed | `grep -oa "aria-" legacy-ui-static/index.html \| wc -l` | >= 113 |
|
|
375
|
+
| A4 | Roles not regressed | `grep -oa 'role="' legacy-ui-static/index.html \| wc -l` | >= 38 |
|
|
376
|
+
| A5 | Custom elements not regressed | `grep -oa "customElements.define" legacy-ui-static/index.html \| wc -l` | >= 39 |
|
|
377
|
+
| A6 | Breakpoints not regressed | `grep -oa "@media" legacy-ui-static/index.html \| wc -l` | >= 13 |
|
|
376
378
|
| A7 | gzip still active | `grep -c "GZipMiddleware" dashboard/server.py` | >= 1 |
|
|
377
379
|
| A8 | Zero runtime dependencies | Built artifact contains no external script/CDN src | 0 external hosts |
|
|
378
380
|
| A9 | Runs store is written by the engine | Drive the lifecycle writer directly (source `run.sh`, call the phase-boundary function), then `GET /api/v2/runs`. No provider call, no spend | Returns >= 1 record with a real run id |
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Loki Mode Dashboard V2 - Implementation Checklist
|
|
2
2
|
|
|
3
|
+
> **Historical:** this describes the classic dashboard, removed in Loki Mode 10.8. The Control Plane is the only UI; see [control-plane-migration.md](control-plane-migration.md).
|
|
4
|
+
|
|
3
5
|
## Overview
|
|
4
6
|
Enterprise-grade Kanban dashboard with FastAPI backend, cross-project support, and CLI integration.
|
|
5
7
|
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -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
|
+
**Version:** v10.9.1
|
|
6
6
|
|
|
7
7
|
**Engine note:** `loki "<task>"`, `loki owner/repo#N` and `loki quick` run the Loki 10 engine. `loki start` still routes to the legacy engine, which is being removed (planned work resumes 2026-10-07); prefer `loki owner/repo#N`. See [docs/v10/GUIDE.md](v10/GUIDE.md).
|
|
8
8
|
|
|
@@ -294,7 +294,7 @@ trade-offs.
|
|
|
294
294
|
## VS Code Extension (Deprecated)
|
|
295
295
|
|
|
296
296
|
> **DEPRECATED as of v7.2.0.** The Loki Mode VS Code extension is no longer
|
|
297
|
-
> maintained. Use the
|
|
297
|
+
> maintained. Use the Control Plane (`loki dashboard`) instead.
|
|
298
298
|
>
|
|
299
299
|
> The marketplace listing remains for users on v7.2.0 and earlier but will
|
|
300
300
|
> not receive further updates. The `vscode-extension/` source remains in the
|
|
@@ -305,8 +305,8 @@ trade-offs.
|
|
|
305
305
|
### Recommended replacement: the dashboard
|
|
306
306
|
|
|
307
307
|
```bash
|
|
308
|
-
loki dashboard
|
|
309
|
-
#
|
|
308
|
+
loki dashboard
|
|
309
|
+
# Opens the Control Plane (default http://127.0.0.1:47821).
|
|
310
310
|
```
|
|
311
311
|
|
|
312
312
|
The dashboard provides session monitoring, task views, the completion
|
|
@@ -450,7 +450,7 @@ behave exactly like the local `loki` CLI. Auth is auto-detected:
|
|
|
450
450
|
(Max/Pro subscribers need no API key), else an honest error with guidance. It
|
|
451
451
|
also forwards `~/.gitconfig` and `~/.config/gh` (read-only) plus
|
|
452
452
|
`GITHUB_TOKEN`/`GH_TOKEN` if set, so commits and PRs work like local, and
|
|
453
|
-
exposes the
|
|
453
|
+
exposes the API on port 57374. Use `--image IMG` to override the image.
|
|
454
454
|
|
|
455
455
|
`loki docker` is a thin host wrapper around the image; it requires loki and
|
|
456
456
|
Docker installed on the host.
|
|
@@ -459,7 +459,7 @@ Multi-repo + unified dashboard: you can run `loki docker start` in several
|
|
|
459
459
|
different repos at once, exactly like the host CLI. Each repo gets its own
|
|
460
460
|
container (deterministic name `loki-<hash-of-path>`) and its own bind-mounted
|
|
461
461
|
`.loki/` state. Every `loki docker` project registers with the host dashboard,
|
|
462
|
-
so running `loki dashboard` on the host shows ALL your projects in one unified
|
|
462
|
+
so running `loki dashboard` on the host (the Control Plane) shows ALL your projects in one unified
|
|
463
463
|
view, whether they run via local `loki start` or via `loki docker start`. Builds
|
|
464
464
|
run with the dashboard off by default (so concurrent runs do not collide on port
|
|
465
465
|
57374); use the host `loki dashboard`, or `loki docker start --api` for a single
|
|
@@ -775,11 +775,12 @@ Loki Mode uses two network ports for different services:
|
|
|
775
775
|
|
|
776
776
|
| Port | Service | Description |
|
|
777
777
|
|------|---------|-------------|
|
|
778
|
-
| **
|
|
778
|
+
| **47821** | Control Plane UI + API | The only UI, plus the `/v1/*` API. Started by `loki control serve` or `loki dashboard`. See [control-plane-migration.md](control-plane-migration.md). |
|
|
779
|
+
| **57374** | Legacy API (FastAPI) | The classic dashboard UI is removed in 10.8; this port no longer serves a UI. |
|
|
779
780
|
|
|
780
781
|
### When to Use Which Port
|
|
781
782
|
|
|
782
|
-
- **Browser access** (
|
|
783
|
+
- **Browser access** (UI, monitoring): Use the Control Plane, port **47821** -- `http://127.0.0.1:47821`
|
|
783
784
|
- **API calls** (REST, programmatic): Use port **57374** -- `http://localhost:57374`
|
|
784
785
|
- **VS Code extension** (deprecated as of v7.2.0): Connects to API on port **57374** automatically (configurable via `loki.apiPort` setting). No new releases will be published; see the deprecation notice above.
|
|
785
786
|
- The server is started automatically when you run `loki start` or `./autonomy/run.sh`. No manual configuration is needed.
|
|
@@ -787,8 +788,8 @@ Loki Mode uses two network ports for different services:
|
|
|
787
788
|
### Port Configuration
|
|
788
789
|
|
|
789
790
|
```bash
|
|
790
|
-
#
|
|
791
|
-
|
|
791
|
+
# Control Plane port (default: 47821)
|
|
792
|
+
loki control serve --port 47821
|
|
792
793
|
|
|
793
794
|
# API port (default: 57374)
|
|
794
795
|
loki api start --port 57374 # was: loki serve
|
|
@@ -796,7 +797,7 @@ loki api start --port 57374 # was: loki serve
|
|
|
796
797
|
|
|
797
798
|
### CORS Configuration
|
|
798
799
|
|
|
799
|
-
|
|
800
|
+
The Control Plane has no CORS setting and requires a loopback Host header unless it is bound to a non-loopback address with `LOKI_CONTROL_TOKEN` set (see [control-plane-migration.md](control-plane-migration.md)). The `LOKI_DASHBOARD_CORS` variable below applies only to the legacy API server:
|
|
800
801
|
|
|
801
802
|
```bash
|
|
802
803
|
# Allow specific origins
|
package/docs/MERGE-DEDUP-MAP.md
CHANGED
|
@@ -362,7 +362,7 @@ class FileEventDebouncer(FileSystemEventHandler):
|
|
|
362
362
|
### What Was NOT Audited (and Why)
|
|
363
363
|
|
|
364
364
|
1. **Frontend code duplication** (TypeScript/React):
|
|
365
|
-
- Dashboard UI (`
|
|
365
|
+
- Dashboard UI (`legacy-ui/src/`) and Lab UI (`web-app/dist/` or source) likely have overlapping components (session cards, status displays, log viewers).
|
|
366
366
|
- Scope: This audit covers Python backend only. Frontend audit deferred to UI design review in Merge-3 (Vite rebuild).
|
|
367
367
|
|
|
368
368
|
2. **Database schema migrations and compatibility:**
|
package/docs/MERGE-ROUTE-MAP.md
CHANGED
|
@@ -30,7 +30,7 @@ This document is the source-of-truth route-collision analysis for the Purple Lab
|
|
|
30
30
|
| Method | Path | Dashboard purpose | Purple Lab purpose | Resolution |
|
|
31
31
|
|---|---|---|---|---|
|
|
32
32
|
| `GET` | `/health` | Dashboard health check | Purple Lab health check | Single `/health` on Dashboard wins. Lab's becomes `/lab/health`. |
|
|
33
|
-
| `GET` | `/{full_path:path}` | Dashboard SPA catch-all (serves `
|
|
33
|
+
| `GET` | `/{full_path:path}` | Dashboard SPA catch-all (serves `legacy-ui-static/index.html`) | Purple Lab SPA catch-all (serves `web-app/dist/index.html`) | Dashboard catch-all wins at root. Lab's becomes `/lab/{full_path:path}` -- triggered only inside the mount. |
|
|
34
34
|
| `WS` | `/ws` | Dashboard WebSocket bus | Purple Lab WebSocket bus | Dashboard `/ws` wins. Lab's becomes `/lab/ws`. Long term: unify into a single bus (Phase Merge-5). |
|
|
35
35
|
|
|
36
36
|
All three collisions resolve automatically when Lab's FastAPI app is mounted at `/lab` via Starlette `app.mount("/lab", purple_lab_app)`. No code dedup needed in Merge-1 -- the mount provides path isolation.
|