@blackbelt-technology/pi-agent-dashboard 0.3.0 → 0.4.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 (216) hide show
  1. package/AGENTS.md +87 -114
  2. package/README.md +408 -430
  3. package/docs/architecture.md +465 -12
  4. package/package.json +10 -5
  5. package/packages/extension/package.json +14 -4
  6. package/packages/extension/src/__tests__/ask-user-tool.test.ts +40 -8
  7. package/packages/extension/src/__tests__/bridge-entry-id-pi-070.test.ts +174 -0
  8. package/packages/extension/src/__tests__/enrich-model-metadata.test.ts +201 -0
  9. package/packages/extension/src/__tests__/event-forwarder.test.ts +30 -0
  10. package/packages/extension/src/__tests__/fork-entryid-timing.test.ts +64 -76
  11. package/packages/extension/src/__tests__/git-info.test.ts +67 -55
  12. package/packages/extension/src/__tests__/multiselect-list.test.ts +137 -0
  13. package/packages/extension/src/__tests__/no-session-replacement-calls.test.ts +99 -0
  14. package/packages/extension/src/__tests__/openspec-poller.test.ts +101 -96
  15. package/packages/extension/src/__tests__/process-scanner-kill.test.ts +61 -0
  16. package/packages/extension/src/__tests__/provider-register-reload.test.ts +394 -0
  17. package/packages/extension/src/__tests__/server-auto-start.test.ts +95 -4
  18. package/packages/extension/src/__tests__/server-launcher.test.ts +16 -0
  19. package/packages/extension/src/ask-user-tool.ts +5 -4
  20. package/packages/extension/src/bridge.ts +171 -17
  21. package/packages/extension/src/dev-build.ts +1 -1
  22. package/packages/extension/src/git-info.ts +9 -19
  23. package/packages/extension/src/multiselect-list.ts +146 -0
  24. package/packages/extension/src/multiselect-polyfill.ts +43 -0
  25. package/packages/extension/src/pi-env.d.ts +1 -0
  26. package/packages/extension/src/process-scanner.ts +72 -38
  27. package/packages/extension/src/provider-register.ts +304 -16
  28. package/packages/extension/src/server-auto-start.ts +27 -1
  29. package/packages/extension/src/server-launcher.ts +83 -27
  30. package/packages/server/package.json +16 -2
  31. package/packages/server/src/__tests__/bootstrap-queue.test.ts +120 -0
  32. package/packages/server/src/__tests__/bootstrap-routes.test.ts +125 -0
  33. package/packages/server/src/__tests__/bootstrap-state.test.ts +119 -0
  34. package/packages/server/src/__tests__/browse-endpoint.test.ts +17 -0
  35. package/packages/server/src/__tests__/cli-parse.test.ts +11 -0
  36. package/packages/server/src/__tests__/concurrent-launch.test.ts +110 -0
  37. package/packages/server/src/__tests__/config-api.test.ts +68 -0
  38. package/packages/server/src/__tests__/crash-recovery.test.ts +88 -0
  39. package/packages/server/src/__tests__/directory-service.test.ts +234 -8
  40. package/packages/server/src/__tests__/editor-registry.test.ts +28 -15
  41. package/packages/server/src/__tests__/extension-register-appimage.test.ts +5 -1
  42. package/packages/server/src/__tests__/extension-register.test.ts +3 -1
  43. package/packages/server/src/__tests__/find-port-holders.test.ts +94 -0
  44. package/packages/server/src/__tests__/fixtures/fork-jsonl-roundtrip.jsonl +8 -0
  45. package/packages/server/src/__tests__/force-kill-handler.test.ts +57 -8
  46. package/packages/server/src/__tests__/fork-jsonl-roundtrip.test.ts +49 -0
  47. package/packages/server/src/__tests__/home-lock-escape-hatch.test.ts +60 -0
  48. package/packages/server/src/__tests__/home-lock-release.test.ts +85 -0
  49. package/packages/server/src/__tests__/home-lock.test.ts +308 -0
  50. package/packages/server/src/__tests__/is-pi-process.test.ts +36 -0
  51. package/packages/server/src/__tests__/node-guard.test.ts +85 -0
  52. package/packages/server/src/__tests__/package-manager-wrapper-resolve.test.ts +5 -1
  53. package/packages/server/src/__tests__/package-manager-wrapper.test.ts +45 -10
  54. package/packages/server/src/__tests__/pi-version-skew.test.ts +237 -0
  55. package/packages/server/src/__tests__/preferences-store.test.ts +73 -4
  56. package/packages/server/src/__tests__/process-manager.test.ts +45 -18
  57. package/packages/server/src/__tests__/provider-probe.test.ts +287 -0
  58. package/packages/server/src/__tests__/provider-test-route.test.ts +149 -0
  59. package/packages/server/src/__tests__/restart-helper.test.ts +111 -0
  60. package/packages/server/src/__tests__/session-action-handler-headless-reload.test.ts +467 -0
  61. package/packages/server/src/__tests__/session-action-handler-reload-predicate.test.ts +73 -0
  62. package/packages/server/src/__tests__/session-action-handler-spawn-error.test.ts +74 -0
  63. package/packages/server/src/__tests__/terminal-manager.test.ts +41 -1
  64. package/packages/server/src/__tests__/tool-routes.test.ts +277 -0
  65. package/packages/server/src/__tests__/trusted-networks-config.test.ts +19 -0
  66. package/packages/server/src/__tests__/trusted-networks-no-oauth-roundtrip.test.ts +126 -0
  67. package/packages/server/src/__tests__/tunnel-cleanup.test.ts +90 -0
  68. package/packages/server/src/__tests__/tunnel.test.ts +13 -7
  69. package/packages/server/src/__tests__/wsl-tmux-probe-cache.test.ts +44 -0
  70. package/packages/server/src/bootstrap-queue.ts +130 -0
  71. package/packages/server/src/bootstrap-state.ts +131 -0
  72. package/packages/server/src/browse.ts +8 -3
  73. package/packages/server/src/browser-handlers/directory-handler.ts +23 -8
  74. package/packages/server/src/browser-handlers/session-action-handler.ts +213 -79
  75. package/packages/server/src/browser-handlers/session-action-helpers.ts +36 -0
  76. package/packages/server/src/cli.ts +310 -39
  77. package/packages/server/src/config-api.ts +16 -0
  78. package/packages/server/src/directory-service.ts +270 -39
  79. package/packages/server/src/editor-detection.ts +12 -9
  80. package/packages/server/src/editor-manager.ts +19 -4
  81. package/packages/server/src/editor-pid-registry.ts +9 -8
  82. package/packages/server/src/editor-registry.ts +22 -25
  83. package/packages/server/src/git-operations.ts +1 -1
  84. package/packages/server/src/headless-pid-registry.ts +7 -20
  85. package/packages/server/src/home-lock-release.ts +72 -0
  86. package/packages/server/src/home-lock.ts +389 -0
  87. package/packages/server/src/node-guard.ts +52 -0
  88. package/packages/server/src/package-manager-wrapper.ts +207 -47
  89. package/packages/server/src/pi-core-checker.ts +1 -1
  90. package/packages/server/src/pi-core-updater.ts +7 -1
  91. package/packages/server/src/pi-resource-scanner.ts +5 -8
  92. package/packages/server/src/pi-version-skew.ts +207 -0
  93. package/packages/server/src/preferences-store.ts +17 -3
  94. package/packages/server/src/process-manager.ts +403 -222
  95. package/packages/server/src/provider-probe.ts +234 -0
  96. package/packages/server/src/restart-helper.ts +141 -0
  97. package/packages/server/src/routes/bootstrap-routes.ts +88 -0
  98. package/packages/server/src/routes/openspec-routes.ts +25 -1
  99. package/packages/server/src/routes/pi-core-routes.ts +24 -1
  100. package/packages/server/src/routes/provider-auth-routes.ts +8 -8
  101. package/packages/server/src/routes/provider-routes.ts +43 -0
  102. package/packages/server/src/routes/recommended-routes.ts +10 -12
  103. package/packages/server/src/routes/system-routes.ts +20 -33
  104. package/packages/server/src/routes/tool-routes.ts +153 -0
  105. package/packages/server/src/server-pid.ts +5 -9
  106. package/packages/server/src/server.ts +211 -10
  107. package/packages/server/src/session-api.ts +77 -8
  108. package/packages/server/src/session-bootstrap.ts +17 -3
  109. package/packages/server/src/session-diff.ts +21 -21
  110. package/packages/server/src/terminal-manager.ts +61 -20
  111. package/packages/server/src/tunnel.ts +42 -28
  112. package/packages/shared/package.json +10 -3
  113. package/packages/shared/src/__tests__/{tool-resolver.test.ts → binary-lookup.test.ts} +32 -12
  114. package/packages/shared/src/__tests__/bootstrap/README.md +133 -0
  115. package/packages/shared/src/__tests__/bootstrap/__snapshots__/cube.test.ts.snap +370 -0
  116. package/packages/shared/src/__tests__/bootstrap/assertions.ts +136 -0
  117. package/packages/shared/src/__tests__/bootstrap/cube.test.ts +47 -0
  118. package/packages/shared/src/__tests__/bootstrap/cube.ts +66 -0
  119. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/a-electron.test.ts.snap +83 -0
  120. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/b-npm-global.test.ts.snap +89 -0
  121. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/c-dev-monorepo.test.ts.snap +33 -0
  122. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/d-overrides.test.ts.snap +20 -0
  123. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/e-stale-partial.test.ts.snap +61 -0
  124. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/f-cwd-variants.test.ts.snap +33 -0
  125. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/g-windows-specifics.test.ts.snap +46 -0
  126. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/j-path-gui-minimal.test.ts.snap +12 -0
  127. package/packages/shared/src/__tests__/bootstrap/families/a-electron.test.ts +156 -0
  128. package/packages/shared/src/__tests__/bootstrap/families/b-npm-global.test.ts +157 -0
  129. package/packages/shared/src/__tests__/bootstrap/families/c-dev-monorepo.test.ts +102 -0
  130. package/packages/shared/src/__tests__/bootstrap/families/d-overrides.test.ts +76 -0
  131. package/packages/shared/src/__tests__/bootstrap/families/e-stale-partial.test.ts +94 -0
  132. package/packages/shared/src/__tests__/bootstrap/families/f-cwd-variants.test.ts +87 -0
  133. package/packages/shared/src/__tests__/bootstrap/families/g-windows-specifics.test.ts +143 -0
  134. package/packages/shared/src/__tests__/bootstrap/families/h-home-drift.test.ts +64 -0
  135. package/packages/shared/src/__tests__/bootstrap/families/i-malformed-settings.test.ts +77 -0
  136. package/packages/shared/src/__tests__/bootstrap/families/index.ts +19 -0
  137. package/packages/shared/src/__tests__/bootstrap/families/j-path-gui-minimal.test.ts +61 -0
  138. package/packages/shared/src/__tests__/bootstrap/families/k-dashboard-absent.test.ts +50 -0
  139. package/packages/shared/src/__tests__/bootstrap/families/l-instance-coordination.test.ts +272 -0
  140. package/packages/shared/src/__tests__/bootstrap/fixtures/dev-monorepo.ts +58 -0
  141. package/packages/shared/src/__tests__/bootstrap/fixtures/electron-layout.ts +84 -0
  142. package/packages/shared/src/__tests__/bootstrap/fixtures/index.ts +9 -0
  143. package/packages/shared/src/__tests__/bootstrap/fixtures/managed-install.ts +85 -0
  144. package/packages/shared/src/__tests__/bootstrap/fixtures/npm-global-layout.ts +122 -0
  145. package/packages/shared/src/__tests__/bootstrap/fixtures/pi-versions.ts +36 -0
  146. package/packages/shared/src/__tests__/bootstrap/fixtures/settings-json.ts +39 -0
  147. package/packages/shared/src/__tests__/bootstrap/harness.smoke.test.ts +220 -0
  148. package/packages/shared/src/__tests__/bootstrap/harness.ts +413 -0
  149. package/packages/shared/src/__tests__/bootstrap/scenarios-skipped.ts +125 -0
  150. package/packages/shared/src/__tests__/bootstrap/scenarios.ts +132 -0
  151. package/packages/shared/src/__tests__/bridge-register.test.ts +29 -6
  152. package/packages/shared/src/__tests__/config-openspec.test.ts +106 -0
  153. package/packages/shared/src/__tests__/config.test.ts +56 -0
  154. package/packages/shared/src/__tests__/detached-spawn.test.ts +243 -0
  155. package/packages/shared/src/__tests__/managed-paths.test.ts +60 -0
  156. package/packages/shared/src/__tests__/no-direct-child-process.test.ts +112 -0
  157. package/packages/shared/src/__tests__/no-direct-platform-branch.test.ts +174 -0
  158. package/packages/shared/src/__tests__/no-direct-process-kill.test.ts +105 -0
  159. package/packages/shared/src/__tests__/no-hardcoded-node-modules-paths.test.ts +176 -0
  160. package/packages/shared/src/__tests__/no-raw-node-import.test.ts +146 -0
  161. package/packages/shared/src/__tests__/node-spawn.test.ts +210 -0
  162. package/packages/shared/src/__tests__/platform-commands.test.ts +108 -0
  163. package/packages/shared/src/__tests__/platform-exec.test.ts +103 -0
  164. package/packages/shared/src/__tests__/platform-git.test.ts +194 -0
  165. package/packages/shared/src/__tests__/platform-npm.test.ts +137 -0
  166. package/packages/shared/src/__tests__/platform-openspec.test.ts +92 -0
  167. package/packages/shared/src/__tests__/platform-paths.test.ts +284 -0
  168. package/packages/shared/src/__tests__/platform-process-scan.test.ts +55 -0
  169. package/packages/shared/src/__tests__/platform-process.test.ts +160 -0
  170. package/packages/shared/src/__tests__/platform-runner.test.ts +173 -0
  171. package/packages/shared/src/__tests__/platform-shell.test.ts +74 -0
  172. package/packages/shared/src/__tests__/process-identify.test.ts +113 -0
  173. package/packages/shared/src/__tests__/recommended-extensions.test.ts +40 -7
  174. package/packages/shared/src/__tests__/resolve-jiti.test.ts +43 -7
  175. package/packages/shared/src/__tests__/resolve-tool-cli.test.ts +105 -0
  176. package/packages/shared/src/__tests__/semaphore.test.ts +119 -0
  177. package/packages/shared/src/__tests__/spawn-mechanism.test.ts +131 -0
  178. package/packages/shared/src/__tests__/state-replay-entry-id.test.ts +69 -0
  179. package/packages/shared/src/__tests__/tool-registry-definitions.test.ts +239 -0
  180. package/packages/shared/src/__tests__/tool-registry-overrides.test.ts +137 -0
  181. package/packages/shared/src/__tests__/tool-registry-registry.test.ts +343 -0
  182. package/packages/shared/src/bootstrap-install.ts +212 -0
  183. package/packages/shared/src/bridge-register.ts +87 -20
  184. package/packages/shared/src/browser-protocol.ts +71 -1
  185. package/packages/shared/src/config.ts +87 -15
  186. package/packages/shared/src/managed-paths.ts +31 -4
  187. package/packages/shared/src/openspec-poller.ts +63 -46
  188. package/packages/shared/src/{tool-resolver.ts → platform/binary-lookup.ts} +125 -25
  189. package/packages/shared/src/platform/commands.ts +100 -0
  190. package/packages/shared/src/platform/detached-spawn.ts +305 -0
  191. package/packages/shared/src/platform/exec.ts +220 -0
  192. package/packages/shared/src/platform/git.ts +155 -0
  193. package/packages/shared/src/platform/index.ts +16 -0
  194. package/packages/shared/src/platform/node-spawn.ts +154 -0
  195. package/packages/shared/src/platform/npm.ts +162 -0
  196. package/packages/shared/src/platform/openspec.ts +91 -0
  197. package/packages/shared/src/platform/paths.ts +276 -0
  198. package/packages/shared/src/platform/process-identify.ts +126 -0
  199. package/packages/shared/src/platform/process-scan.ts +94 -0
  200. package/packages/shared/src/platform/process.ts +168 -0
  201. package/packages/shared/src/platform/runner.ts +369 -0
  202. package/packages/shared/src/platform/shell.ts +44 -0
  203. package/packages/shared/src/platform/spawn-mechanism.ts +124 -0
  204. package/packages/shared/src/platform/subprocess-adapter.ts +124 -0
  205. package/packages/shared/src/protocol.ts +23 -0
  206. package/packages/shared/src/recommended-extensions.ts +18 -2
  207. package/packages/shared/src/resolve-jiti.ts +62 -3
  208. package/packages/shared/src/rest-api.ts +26 -0
  209. package/packages/shared/src/semaphore.ts +83 -0
  210. package/packages/shared/src/state-replay.ts +9 -0
  211. package/packages/shared/src/tool-registry/definitions.ts +434 -0
  212. package/packages/shared/src/tool-registry/index.ts +56 -0
  213. package/packages/shared/src/tool-registry/overrides.ts +118 -0
  214. package/packages/shared/src/tool-registry/registry.ts +262 -0
  215. package/packages/shared/src/tool-registry/strategies.ts +198 -0
  216. package/packages/shared/src/tool-registry/types.ts +180 -0
package/README.md CHANGED
@@ -1,193 +1,168 @@
1
1
  # PI Dashboard
2
2
 
3
3
  [![CI](https://github.com/BlackBeltTechnology/pi-agent-dashboard/actions/workflows/ci.yml/badge.svg)](https://github.com/BlackBeltTechnology/pi-agent-dashboard/actions/workflows/ci.yml)
4
- [![npm](https://img.shields.io/npm/v/@blackbelt-technology/pi-dashboard)](https://www.npmjs.com/package/@blackbelt-technology/pi-dashboard)
4
+ [![npm](https://img.shields.io/npm/v/@blackbelt-technology/pi-agent-dashboard)](https://www.npmjs.com/package/@blackbelt-technology/pi-agent-dashboard)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
7
  A web-based dashboard for monitoring and interacting with [pi](https://github.com/badlogic/pi-mono) agent sessions from any browser, including mobile.
8
8
 
9
- **Website:** [blackbelttechnology.github.io/pi-agent-dashboard](https://blackbelttechnology.github.io/pi-agent-dashboard) — animated tour, screenshots, and install guide.
9
+ 🌐 **Website & demo:** [blackbelttechnology.github.io/pi-agent-dashboard](https://blackbelttechnology.github.io/pi-agent-dashboard) — animated tour, screenshots, and install guide.
10
+ 📝 **Changelog:** [`CHANGELOG.md`](CHANGELOG.md)
10
11
 
11
- **Changelog:** see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
12
+ > **Note:** This dashboard only works with [pi](https://github.com/badlogic/pi-mono). Oh My Pi is **not** supported.
12
13
 
13
- **Releasing:** see [`docs/release-process.md`](docs/release-process.md) for the cut-a-release workflow.
14
+ ---
14
15
 
15
- ## Features
16
-
17
- - **Real-time session mirroring** — See all active pi sessions with live streaming messages
18
- - **Bidirectional interaction** — Send prompts and commands from the browser
19
- - **Workspace management** — Organize sessions by project folder with pinned directories and drag-to-reorder
20
- - **Command autocomplete** — `/` prefix triggers command dropdown with filtering
21
- - **Session statistics** — Token counts, costs, model info, thinking level, context usage bar
22
- - **Elapsed time tracking** — Live ticking counters on running operations, final duration on completed tool calls and reasoning blocks
23
- - **Mobile-friendly** — Responsive layout with swipe drawer, touch targets, and mobile action menus
24
- - **Session spawning** — Launch new pi sessions from the dashboard (headless by default, or via tmux)
25
- - **PromptBus architecture** — Unified prompt routing with adapters (TUI, dashboard, custom). Interactive dialogs (confirm/select/input/editor/multiselect) survive page refresh and server restart. First-response-wins semantics with cross-adapter dismissal.
26
- - **On-demand session loading** — Browse historical sessions with lazy-loaded content from pi session files
27
- - **Integrated terminal** — Full browser-based terminal emulator (xterm.js + node-pty) with ANSI color support, scrollback, and keep-alive
28
- - **pi-flows integration** — Live flow execution dashboard with agent cards, detail views, flow graph visualization, summary, abort/auto controls. Launch flows and design new ones with the Flow Architect — all from the browser. Fork decisions and subagent dialogs forwarded via PromptBus.
29
- - **Force kill escalation** — Two-click Stop button (in command bar and on running tool cards): first click sends soft abort, second click force-kills the process (SIGTERM → SIGKILL). Session preserved as "ended" for resume/fork. Repeated tool calls (e.g. health check loops) are auto-collapsed with a count badge.
30
- - **Searchable select dialogs** — Keyboard-navigable picker with real-time filtering for OpenSpec changes and flow commands
31
- - **Browser-based provider auth** — Sign in to Anthropic, OpenAI Codex, GitHub Copilot, Gemini CLI, and Antigravity directly from Settings. Enter API keys for other providers. Credentials saved to `~/.pi/agent/auth.json` and live-synced to running sessions.
32
- - **Package management** — Browse, install, update, and remove pi packages from the dashboard. Search the npm registry for pi-package extensions/skills/themes, install from npm or git URL, manage global packages in Settings and local packages per workspace. All active sessions auto-reload after changes.
33
- - **OpenSpec integration** — Browse specs, view archive history, manage changes, and create new changes from the session sidebar
34
- - **Diff viewer** — Side-by-side and unified diff views with file tree navigation for reviewing agent changes
35
- - **Editor integration** — Open files in your preferred editor (VS Code, Cursor, etc.) directly from tool call cards
36
- - **Markdown preview** — Rendered markdown views with search, mermaid diagrams, and syntax highlighting
37
- - **Network discovery** — mDNS-based auto-discovery of other dashboard servers on the local network; connect to known remote servers
38
-
39
- ## Architecture
40
-
41
- ```mermaid
42
- graph LR
43
- subgraph "Per pi session"
44
- B[Bridge Extension]
45
- end
46
-
47
- subgraph "Dashboard Server (Node.js)"
48
- PG[Pi Gateway :9999]
49
- BG[Browser Gateway :8000]
50
- HTTP[HTTP / Static Files]
51
- MEM[(In-Memory Store)]
52
- JSON[(JSON Files)]
53
- end
16
+ ## Table of contents
54
17
 
55
- subgraph "Browser"
56
- UI[React Web Client]
57
- end
58
-
59
- B <-->|WebSocket| PG
60
- UI <-->|WebSocket| BG
61
- UI -->|HTTP| HTTP
62
- PG --- MEM
63
- PG --- JSON
64
- BG --- MEM
65
- ```
66
-
67
- The system has three components:
68
-
69
- | Component | Location | Role |
70
- |-----------|----------|------|
71
- | **Bridge Extension** | `packages/extension/` | Runs in every pi session. Forwards events, relays commands, auto-starts server, hosts PromptBus. |
72
- | **Dashboard Server** | `packages/server/` | Aggregates events in-memory, persists metadata to JSON, serves the web client, manages terminals. |
73
- | **Web Client** | `packages/client/` | React + Tailwind UI with real-time WebSocket updates. |
74
- | **Shared** | `packages/shared/` | TypeScript types, protocols, and utilities shared across all packages. |
18
+ - [Quickstart](#quickstart)
19
+ - [Features](#features)
20
+ - [Prerequisites](#prerequisites)
21
+ - [Configuration](#configuration)
22
+ - [Usage](#usage)
23
+ - [Recommended extensions](#recommended-extensions)
24
+ - [Troubleshooting](#troubleshooting)
25
+ - [Architecture](#architecture)
26
+ - [Monitoring](#monitoring)
27
+ - [Development](#development)
28
+ - [Building the Electron app](#building-the-electron-app)
29
+ - [CI/CD & releasing](#cicd--releasing)
30
+ - [License](#license)
75
31
 
76
- See [docs/architecture.md](docs/architecture.md) for detailed data flows, reconnection logic, and persistence model.
32
+ ---
77
33
 
78
- ## Getting Started
34
+ ## Quickstart
79
35
 
80
- There are three ways to use the dashboard, from simplest to most flexible:
36
+ Three install paths, pick one:
81
37
 
82
- ### Option A: Electron Desktop App (standalone — no prerequisites)
38
+ ### A Electron desktop app (no prerequisites)
83
39
 
84
- Download a pre-built installer from [GitHub Releases](https://github.com/BlackBeltTechnology/pi-agent-dashboard/releases) for your platform:
40
+ Download a pre-built installer from [GitHub Releases](https://github.com/BlackBeltTechnology/pi-agent-dashboard/releases):
85
41
 
86
42
  | Platform | Download |
87
43
  |----------|----------|
88
- | **macOS** (Apple Silicon) | `.dmg` (arm64) |
89
- | **macOS** (Intel) | `.dmg` (x64) |
90
- | **Linux** (x64) | `.deb` or `.AppImage` |
91
- | **Linux** (ARM64) | `.deb` |
92
- | **Windows** (x64) | `.exe` (NSIS installer), `.zip`, or portable `.exe` |
93
- | **Windows** (ARM64) | `.zip` or portable `.exe` |
94
-
95
- On first launch, a setup wizard guides you through:
96
-
97
- 1. **Choose a mode:**
98
- - **Standalone** — Bundles Node.js and auto-installs pi + dashboard + openspec into `~/.pi-dashboard/`. No Node.js, npm, or build tools needed.
99
- - **Power User** — Uses your existing system-installed pi and dashboard.
100
- 2. **Configure an API key** — Enter your Anthropic/OpenAI key or sign in via browser-based OAuth.
101
- 3. **Recommended extensions** — Install the curated set of pi extensions the dashboard is built to work with (see [Recommended extensions](#recommended-extensions) below). You can skip and manage them later from the Packages tab.
102
- 4. **Done** — The app discovers or spawns a dashboard server automatically.
103
-
104
- > **No terminal, no npm, no Node.js required.** The Electron app is fully self-contained in standalone mode. It bundles a Node.js runtime, spawns the dashboard server internally, and manages all dependencies. System tray integration keeps it running in the background.
44
+ | **macOS** (Apple Silicon / Intel) | `.dmg` (arm64 / x64) |
45
+ | **Linux** (x64 / ARM64) | `.deb` or `.AppImage` |
46
+ | **Windows** (x64 / ARM64) | `.exe` (NSIS), `.zip`, or portable `.exe` |
105
47
 
106
- ### Option B: pi Package (recommended for CLI users)
48
+ On first launch a setup wizard walks you through mode selection (standalone vs. power-user), API key / OAuth sign-in, and [recommended extensions](#recommended-extensions). The standalone mode bundles Node.js and auto-installs pi + dashboard + openspec into `~/.pi-dashboard/` — **no terminal, npm, or Node.js required**.
107
49
 
108
- Requires [pi](https://github.com/badlogic/pi-mono) (or [Oh My Pi](https://www.npmjs.com/package/@oh-my-pi/pi-coding-agent)) and Node.js ≥ 20.
50
+ ### B pi package (recommended for CLI users)
109
51
 
110
52
  ```bash
111
- pi install npm:@blackbelt-technology/pi-dashboard
53
+ pi install npm:@blackbelt-technology/pi-agent-dashboard
112
54
  pi
113
55
  ```
114
56
 
115
- The bridge extension auto-starts the dashboard server on first launch. You'll see:
57
+ The bridge extension auto-starts the dashboard server on first launch:
116
58
 
117
59
  ```
118
60
  🌐 Dashboard started at http://localhost:8000
119
61
  ```
120
62
 
121
- Open **http://localhost:8000** in any browser. All active pi sessions appear automatically.
63
+ Open **http://localhost:8000** in any browser. All active pi sessions appear automatically. See [Prerequisites](#prerequisites) for Node.js / build-tool requirements.
122
64
 
123
- ### Option C: Local development install
65
+ ### C From source (contributors)
124
66
 
125
67
  ```bash
126
68
  git clone https://github.com/BlackBeltTechnology/pi-agent-dashboard.git
127
69
  cd pi-agent-dashboard
128
70
  npm install
129
- pi install /path/to/pi-agent-dashboard
71
+ pi install /path/to/pi-agent-dashboard # global
72
+ # or: pi install -l /path/to/pi-agent-dashboard # project-local only
130
73
  ```
131
74
 
132
- ## Recommended extensions
133
-
134
- The dashboard integrates tightly with a small, curated set of pi extensions
135
- — for custom tool rendering, the Flow dashboard, and anthropic-messages
136
- protocol compatibility. The wizard's Recommended-extensions step installs
137
- them in one go; the **Packages** tab and a top-of-page **banner** keep
138
- them discoverable afterwards.
139
-
140
- | Extension | Source | Status | Unlocks |
141
- |---|---|---|---|
142
- | `pi-anthropic-messages` | `git@github.com:BlackBeltTechnology/pi-anthropic-messages.git` | **required** | Tool calls on Claude-model Anthropic OAuth / 9Router `cc/*` / pi-model-proxy providers. Without it, tool calls fall back to Claude Code's built-in `bash_ide` sandbox and fail. |
143
- | `@tintinweb/pi-subagents` | `npm:@tintinweb/pi-subagents` | strongly suggested | `Agent` tool card UI, subagent activity badge, `get_subagent_result` / `steer_subagent` renderers. |
144
- | `pi-flows` | `git@github.com:BlackBeltTechnology/pi-flows.git` | strongly suggested | Flow dashboard, role aliases (`@planning`, `@coding`, …), subagent / flow_write / flow_results / agent_write / ask_user / skill_read / finish tools. |
145
- | `pi-web-access` | `npm:pi-web-access` | strongly suggested | `web_search`, `code_search`, `fetch_content`, `get_search_content`. |
146
- | `pi-agent-browser` | `npm:pi-agent-browser` | optional | `browser` tool (open, snapshot, click, screenshot). |
147
-
148
- Authoritative source of truth: `packages/shared/src/recommended-extensions.ts`.
149
- Descriptions, versions, and installed-state are enriched live at runtime via
150
- `GET /api/packages/recommended` (falling back to offline descriptions on
151
- network failure).
152
-
153
- ### GitHub SSH notes
154
-
155
- The `pi-flows` and `pi-anthropic-messages` entries install via `pi install
156
- git@github.com:…` (SSH). If your system doesn't have a GitHub SSH key
157
- configured the clone will fail with a "Permission denied (publickey)"
158
- error. Set up a key by following
159
- [GitHub's SSH docs](https://docs.github.com/en/authentication/connecting-to-github-with-ssh),
160
- or substitute the equivalent HTTPS URL in the manifest if your fork is
161
- public.
162
-
163
- ### Quick test (without installing)
164
-
165
75
  To try the extension in a single pi session without registering it:
166
76
 
167
77
  ```bash
168
78
  pi -e /path/to/pi-agent-dashboard/packages/extension/src/bridge.ts
169
79
  ```
170
80
 
81
+ Remove with `pi remove /path/to/pi-agent-dashboard`. Alternatively, add the package path directly to `~/.pi/agent/settings.json` (global) or `.pi/settings.json` (project) under `"packages": [...]`.
82
+
83
+ ---
84
+
85
+ ## Features
86
+
87
+ **Sessions & chat**
88
+ - **Real-time session mirroring** — all active pi sessions with live streaming messages
89
+ - **Bidirectional interaction** — send prompts and commands from the browser
90
+ - **Session statistics** — token counts, costs, model info, thinking level, context usage bar
91
+ - **Elapsed time tracking** — live ticking counters on running operations, final duration on completed tool calls and reasoning blocks
92
+ - **Session spawning** — launch new pi sessions from the dashboard (headless by default, or via tmux)
93
+ - **On-demand session loading** — browse historical sessions with lazy-loaded content from pi session files
94
+ - **Force kill escalation** — two-click Stop button; first click sends soft abort, second force-kills (SIGTERM → SIGKILL). Session preserved as "ended" for resume/fork.
95
+
96
+ **Workspace & UI**
97
+ - **Workspace management** — organize sessions by project folder with pinned directories and drag-to-reorder
98
+ - **Command autocomplete** — `/` prefix triggers a filtering dropdown
99
+ - **Mobile-friendly** — responsive layout with swipe drawer, touch targets, and mobile action menus
100
+ - **Markdown preview** — rendered markdown views with search, mermaid diagrams, and syntax highlighting
101
+ - **Searchable select dialogs** — keyboard-navigable picker with real-time filtering (OpenSpec changes, flow commands)
102
+
103
+ **Integrations**
104
+ - **PromptBus architecture** — unified prompt routing with adapters (TUI, dashboard, custom). Interactive dialogs (confirm/select/input/editor/multiselect) survive page refresh and server restart. First-response-wins semantics with cross-adapter dismissal.
105
+ - **pi-flows integration** — live flow execution dashboard with agent cards, detail views, flow graph, summary, abort/auto controls. Launch flows and design new ones with Flow Architect, all from the browser. Fork decisions and subagent dialogs forwarded via PromptBus.
106
+ - **OpenSpec integration** — browse specs, view archive history, manage changes, create new changes from the sidebar
107
+ - **Browser-based provider auth** — sign in to Anthropic, OpenAI Codex, GitHub Copilot, Gemini CLI, and Antigravity from Settings. Enter API keys for other providers. Credentials saved to `~/.pi/agent/auth.json` and live-synced to running sessions.
108
+ - **Custom LLM providers** — add OpenAI-compatible, Anthropic-compatible, or Google Generative AI endpoints (Settings → Providers → LLM Providers). **Test** button verifies the base URL + API key before saving. Adding / editing / removing takes effect live in every running session — no restart.
109
+ - **Package management** — browse, install, update, and remove pi packages. Search the npm registry for pi-package extensions/skills/themes; install from npm or git URL. Active sessions auto-reload after changes.
110
+
111
+ **Dev tools**
112
+ - **Integrated terminal** — full browser-based terminal emulator (xterm.js + node-pty) with ANSI colors, scrollback, and keep-alive
113
+ - **Diff viewer** — side-by-side and unified diff views with file tree navigation
114
+ - **Editor integration** — open files in VS Code, Cursor, etc. directly from tool call cards
115
+
116
+ **Networking & distribution**
117
+ - **Network discovery** — mDNS-based auto-discovery of other dashboard servers on the local network
118
+ - **Zrok tunnel** — optional persistent public URL via reserved shares (see [Configuration → Tunnel](#tunnel-zrok))
119
+
120
+ ---
121
+
171
122
  ## Prerequisites
172
123
 
173
- Only needed for Option B/C (the Electron app handles everything automatically).
124
+ **Only needed for Quickstart paths B and C.** The Electron app (path A) bundles everything in standalone mode.
174
125
 
175
126
  | Requirement | Why | Install |
176
127
  |-------------|-----|---------|
177
- | **[pi](https://github.com/badlogic/pi-mono)** or **[Oh My Pi](https://www.npmjs.com/package/@oh-my-pi/pi-coding-agent)** | The AI coding agent that the dashboard monitors | `npm i -g @mariozechner/pi-coding-agent` |
178
- | **Node.js ≥ 20** | Runtime for the dashboard server | [nodejs.org](https://nodejs.org/) |
179
- | **C++ build tools** | Required by `node-pty` native addon for terminal emulation | Xcode CLI Tools (macOS) / `build-essential` (Linux) |
128
+ | **[pi](https://github.com/badlogic/pi-mono)** | The AI coding agent the dashboard monitors | `npm i -g @mariozechner/pi-coding-agent` |
129
+ | **Node.js ≥ 22.18.0** | Server runtime. Older 22.x / 24.x < 24.3.0 are affected by [nodejs/node#58515](https://github.com/nodejs/node/issues/58515) which crashes Fastify at startup. | [nodejs.org](https://nodejs.org/) |
130
+ | **C++ build tools** | Required by `node-pty` native addon for the integrated terminal | Xcode CLI Tools (macOS) / `build-essential` (Linux) |
180
131
 
181
- ### Optional tools
132
+ Optional:
182
133
 
183
134
  | Tool | Purpose | When needed |
184
135
  |------|---------|-------------|
185
- | **tmux** | Spawn new pi sessions from the browser in a tmux window | When `spawnStrategy` is `"tmux"` |
186
- | **[zrok](https://zrok.io/)** | Expose dashboard over the internet via tunnel (auto-connects on server start). Install with `brew install zrok` (macOS) and run `zrok enable <token>` to enroll — the dashboard reads zrok's own config (`~/.zrok2/environment.json`), no keys are stored in the dashboard. Uses reserved shares for persistent URLs across restarts. | When `tunnel.enabled` is `true` (default) |
136
+ | **tmux** | Spawn new pi sessions in a tmux window | When `spawnStrategy` is `"tmux"` |
137
+ | **[zrok](https://zrok.io/)** | Public tunnel with persistent URLs | When `tunnel.enabled` is `true` (default) |
138
+
139
+ ---
187
140
 
188
141
  ## Configuration
189
142
 
190
- Config file: **`~/.pi/dashboard/config.json`** (auto-created with defaults on first run)
143
+ - **Config file:** `~/.pi/dashboard/config.json` (auto-created with defaults on first run)
144
+ - **Tool overrides (machine-local):** `~/.pi/dashboard/tool-overrides.json` — see [Tool overrides](#tool-overrides)
145
+ - **Settings UI:** click the ⚙ gear icon in the sidebar header to edit all fields from the browser
146
+
147
+ ### Precedence & keys
148
+
149
+ CLI flags → environment variables → config file → built-in defaults.
150
+
151
+ | CLI flag | Env var | Config key | Default | Description |
152
+ |----------|---------|------------|---------|-------------|
153
+ | `--port` | `PI_DASHBOARD_PORT` | `port` | `8000` | HTTP + browser WebSocket port |
154
+ | `--pi-port` | `PI_DASHBOARD_PI_PORT` | `piPort` | `9999` | Pi extension WebSocket port |
155
+ | `--dev` | — | — | `false` | Development mode (proxy to Vite) |
156
+ | `--no-tunnel` | — | `tunnel.enabled` | `true` | Disable zrok tunnel |
157
+ | — | — | `autoStart` | `true` | Bridge auto-starts server if not running |
158
+ | — | — | `autoShutdown` | `false` | Server shuts down when idle |
159
+ | — | — | `shutdownIdleSeconds` | `300` | Seconds idle before auto-shutdown |
160
+ | — | — | `spawnStrategy` | `"headless"` | Session spawn mode: `"headless"` or `"tmux"` |
161
+ | — | — | `devBuildOnReload` | `false` | Rebuild client + restart server on `/reload` |
162
+
163
+ The bridge also honours `PI_DASHBOARD_URL=ws://host:port` to point at a remote server instead of localhost.
164
+
165
+ ### Minimal `config.json`
191
166
 
192
167
  ```json
193
168
  {
@@ -198,32 +173,28 @@ Config file: **`~/.pi/dashboard/config.json`** (auto-created with defaults on fi
198
173
  "shutdownIdleSeconds": 300,
199
174
  "spawnStrategy": "headless",
200
175
  "tunnel": { "enabled": true, "reservedToken": "auto-created-on-first-run" },
201
- "devBuildOnReload": false
176
+ "devBuildOnReload": false,
177
+ "openspec": {
178
+ "pollIntervalSeconds": 30,
179
+ "maxConcurrentSpawns": 3,
180
+ "changeDetection": "mtime",
181
+ "jitterSeconds": 5
182
+ }
202
183
  }
203
184
  ```
204
185
 
205
- ### Authentication (Optional)
186
+ ### Authentication (optional)
206
187
 
207
- Add an `auth` section to enable OAuth2 authentication for external (tunnel) access. Localhost is always unguarded.
188
+ OAuth2 authentication guards external (tunnel) access. Localhost is always unguarded.
208
189
 
209
190
  ```json
210
191
  {
211
192
  "auth": {
212
193
  "secret": "auto-generated-if-omitted",
213
194
  "providers": {
214
- "github": {
215
- "clientId": "your-github-client-id",
216
- "clientSecret": "your-github-client-secret"
217
- },
218
- "google": {
219
- "clientId": "your-google-client-id",
220
- "clientSecret": "your-google-client-secret"
221
- },
222
- "keycloak": {
223
- "clientId": "your-keycloak-client-id",
224
- "clientSecret": "your-keycloak-client-secret",
225
- "issuerUrl": "https://keycloak.example.com/realms/myrealm"
226
- }
195
+ "github": { "clientId": "...", "clientSecret": "..." },
196
+ "google": { "clientId": "...", "clientSecret": "..." },
197
+ "keycloak": { "clientId": "...", "clientSecret": "...", "issuerUrl": "https://keycloak.example.com/realms/myrealm" }
227
198
  },
228
199
  "allowedUsers": ["octocat", "user@example.com", "*@company.com"]
229
200
  }
@@ -233,101 +204,70 @@ Add an `auth` section to enable OAuth2 authentication for external (tunnel) acce
233
204
  | Key | Required | Description |
234
205
  |-----|----------|-------------|
235
206
  | `auth.secret` | No | JWT signing secret (auto-generated if omitted) |
236
- | `auth.providers` | Yes | Map of provider name → `{ clientId, clientSecret, issuerUrl? }` |
237
- | `auth.allowedUsers` | No | User allowlist: usernames, emails, or `*@domain` wildcards. Empty = allow all |
207
+ | `auth.providers` | Yes | Map of provider → `{ clientId, clientSecret, issuerUrl? }` |
208
+ | `auth.allowedUsers` | No | Allowlist: usernames, emails, or `*@domain` wildcards. Empty = allow all |
238
209
 
239
210
  **Supported providers:** `github`, `google`, `keycloak`, `oidc` (generic OIDC with `issuerUrl`).
240
211
 
241
- **Callback URL:** Register `https://<tunnel-url>/auth/callback/<provider>` in your OAuth provider settings. The tunnel URL is stable across restarts (reserved shares are auto-created).
242
-
243
- **Settings UI:** Click the ⚙ gear icon in the sidebar header to open the Settings panel, where all config fields (including auth) can be edited from the browser.
244
-
245
- **Precedence:** CLI flags → environment variables → config file → built-in defaults.
246
-
247
- | CLI Flag | Env Var | Config Key | Default | Description |
248
- |----------|---------|------------|---------|-------------|
249
- | `--port` | `PI_DASHBOARD_PORT` | `port` | `8000` | HTTP + Browser WebSocket port |
250
- | `--pi-port` | `PI_DASHBOARD_PI_PORT` | `piPort` | `9999` | Pi extension WebSocket port |
251
- | `--dev` | — | — | `false` | Development mode (proxy to Vite) |
252
- | `--no-tunnel` | — | `tunnel.enabled` | `true` | Disable zrok tunnel |
253
- | — | — | `autoStart` | `true` | Bridge auto-starts server if not running |
254
- | — | — | `autoShutdown` | `false` | Server shuts down when idle |
255
- | — | — | `shutdownIdleSeconds` | `300` | Seconds idle before auto-shutdown |
256
- | — | — | `spawnStrategy` | `"headless"` | Session spawn mode: `"headless"` or `"tmux"` |
257
- | — | — | `devBuildOnReload` | `false` | Rebuild client + restart server on `/reload` |
258
-
259
- ### Override the server URL
260
-
261
- By default the bridge connects to `ws://localhost:{piPort}`. To point at a remote server:
262
-
263
- ```bash
264
- PI_DASHBOARD_URL=ws://192.168.1.100:9999 pi
265
- ```
266
-
267
- ## Installation Methods
268
-
269
- ### Electron Desktop App (standalone)
212
+ **Callback URL:** register `https://<tunnel-url>/auth/callback/<provider>` in your OAuth provider settings. The tunnel URL is stable across restarts (reserved shares are auto-created).
270
213
 
271
- See [Getting Started — Option A](#option-a-electron-desktop-app-standalone--no-prerequisites) above. Download from [GitHub Releases](https://github.com/BlackBeltTechnology/pi-agent-dashboard/releases).
214
+ ### Tunnel (zrok)
272
215
 
273
- ### From npm (recommended for CLI users)
216
+ The dashboard auto-connects a [zrok](https://zrok.io/) tunnel on start when `tunnel.enabled` is `true`. Install with `brew install zrok` (macOS) and run `zrok enable <token>` to enrol — the dashboard reads zrok's own config (`~/.zrok2/environment.json`), no keys are stored in the dashboard. Reserved shares provide persistent URLs across restarts.
274
217
 
275
- ```bash
276
- # pi
277
- pi install npm:@blackbelt-technology/pi-dashboard
278
-
279
- # Oh My Pi
280
- omp install npm:@blackbelt-technology/pi-dashboard
281
- ```
218
+ ### OpenSpec background polling
282
219
 
283
- > The package is compatible with both [pi](https://github.com/badlogic/pi-mono) and [Oh My Pi](https://www.npmjs.com/package/@oh-my-pi/pi-coding-agent) — no configuration needed.
284
-
285
- ### Local development install
286
-
287
- ```bash
288
- cd /path/to/pi-agent-dashboard
289
- npm install
220
+ Tune how often the server polls known directories for OpenSpec updates (`openspec` block):
290
221
 
291
- # Global install
292
- pi install /path/to/pi-agent-dashboard
222
+ | Key | Default | Range | Description |
223
+ |-----|---------|-------|-------------|
224
+ | `pollIntervalSeconds` | `30` | `5–3600` | How often each known directory is polled |
225
+ | `maxConcurrentSpawns` | `3` | `1–16` | Cap on concurrent `openspec` CLI invocations |
226
+ | `changeDetection` | `"mtime"` | `"mtime" \| "always"` | `mtime` skips unchanged proposals; `always` polls unconditionally |
227
+ | `jitterSeconds` | `5` | `0–60` | Per-directory phase offset so polls don't align on the same tick |
293
228
 
294
- # Or project-local only
295
- pi install -l /path/to/pi-agent-dashboard
296
- ```
229
+ Live-reconfigurable via Settings → Advanced → "Background polling (OpenSpec)" or `PUT /api/config` — no server restart needed. See [docs/architecture.md](docs/architecture.md) for the cost model.
297
230
 
298
- Pi reads the `pi.extensions` field from `package.json` and loads the bridge extension automatically.
231
+ ### Tool overrides
299
232
 
300
- ### Manual settings entry
233
+ The dashboard resolves every external tool it calls (`pi`, `pi-coding-agent`, `openspec`, `npm`, `node`, `tsx`, `git`, `zrok`, `pi-dashboard`) through a single `ToolRegistry`. Each tool has an ordered strategy chain (override → managed install → bare-import / npm-global → PATH search), and every resolution records a diagnostic trail.
301
234
 
302
- Add the package path directly to your settings file:
235
+ **Inspecting and overriding** — Settings → General → **Tools** shows every resolved tool, its source, and the trail. You can set a per-tool override path, rescan individually or all at once, and export the full diagnostic report.
303
236
 
304
- **Global** (`~/.pi/agent/settings.json`):
305
- ```json
306
- {
307
- "packages": ["/path/to/pi-agent-dashboard"]
308
- }
309
- ```
237
+ **Overrides file** `~/.pi/dashboard/tool-overrides.json`:
310
238
 
311
- **Project-local** (`.pi/settings.json`):
312
239
  ```json
313
240
  {
314
- "packages": ["/path/to/pi-agent-dashboard"]
241
+ "version": 1,
242
+ "overrides": {
243
+ "pi": { "path": "C:\\custom\\pi.cmd" },
244
+ "pi-coding-agent": { "path": "D:\\dev\\pi-coding-agent\\dist\\index.js" }
245
+ }
315
246
  }
316
247
  ```
317
248
 
318
- ### Removing
249
+ The file is deliberately separate from `config.json` so machine-specific paths don't follow a dotfiles sync. Invalid overrides (path doesn't exist) are recorded in the trail and the registry falls through to the next strategy automatically.
319
250
 
320
- ```bash
321
- pi remove /path/to/pi-agent-dashboard
322
- ```
251
+ ---
323
252
 
324
253
  ## Usage
325
254
 
326
255
  ### Auto-start (default)
327
256
 
328
- The bridge extension **automatically starts the dashboard server** when pi launches if it's not already running. No separate terminal needed.
257
+ The bridge extension **automatically starts the dashboard server** when pi launches if it's not already running. Disable with `"autoStart": false` in `~/.pi/dashboard/config.json`.
329
258
 
330
- To disable: set `"autoStart": false` in `~/.pi/dashboard/config.json`.
259
+ ### Daemon mode
260
+
261
+ ```bash
262
+ pi-dashboard start # background daemon (production)
263
+ pi-dashboard start --dev # dev mode (proxy to Vite, fallback to production build)
264
+ pi-dashboard stop # stop daemon (also kills stale port holders)
265
+ pi-dashboard restart # restart (production)
266
+ pi-dashboard restart --dev # restart in dev mode
267
+ pi-dashboard status # daemon status
268
+ ```
269
+
270
+ Daemon stdout/stderr is logged to `~/.pi/dashboard/server.log` (append mode with timestamped headers per start).
331
271
 
332
272
  ### Manual server start
333
273
 
@@ -337,76 +277,183 @@ npx tsx packages/server/src/cli.ts --port 8000 --pi-port 9999
337
277
  npx tsx packages/server/src/cli.ts --dev # proxy to Vite dev server
338
278
  ```
339
279
 
340
- ### Daemon mode
341
-
342
- ```bash
343
- pi-dashboard start # Start as background daemon (production)
344
- pi-dashboard start --dev # Start in dev mode (proxy to Vite, fallback to production build)
345
- pi-dashboard stop # Stop running daemon (also kills stale port holders)
346
- pi-dashboard restart # Restart daemon (production)
347
- pi-dashboard restart --dev # Restart in dev mode
348
- pi-dashboard status # Show daemon status
349
- ```
350
-
351
- Daemon stdout/stderr is logged to `~/.pi/dashboard/server.log` for crash diagnosis.
352
-
353
280
  ### Graceful restart via API
354
281
 
355
- Restart without CLI — useful from scripts, other sessions, or the dashboard skill:
356
-
357
282
  ```bash
358
- # Restart in same mode (preserves current dev/prod)
283
+ # Restart in the same mode
359
284
  curl -X POST http://localhost:8000/api/restart
360
285
 
361
- # Switch to dev mode
286
+ # Switch to dev / production
362
287
  curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":true}'
363
-
364
- # Switch to production mode
365
288
  curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":false}'
366
289
 
367
290
  # Check current mode
368
291
  curl -s http://localhost:8000/api/health | jq .mode
369
292
  ```
370
293
 
371
- The restart endpoint waits for the old server to exit, starts the new one, and verifies health. If the new server fails to start, the error is logged to `server.log`.
294
+ The restart endpoint waits for the old server to exit, starts the new one, and verifies health. It works identically on Windows, macOS, and Linux (no `sh` / `lsof` / `curl` dependency).
372
295
 
373
296
  ### Dev mode with production fallback
374
297
 
375
- When started with `--dev`, the server proxies client requests to the Vite dev server for HMR. If Vite is **not running**, the server automatically falls back to serving the production build from `dist/client/`. This means:
298
+ When started with `--dev`, the server proxies client requests to the Vite dev server for HMR. If Vite is **not running**, it automatically falls back to serving the production build from `dist/client/`:
376
299
 
377
300
  - `pi-dashboard start --dev` **always works** — no 502 errors
378
301
  - Start/stop Vite independently without restarting the dashboard
379
- - Seamless transition: start Vite later and refresh the browser to get HMR
302
+ - Start Vite later and refresh the browser to get HMR
380
303
 
381
- ### Session spawning
304
+ ### Dev build on reload
382
305
 
383
- The dashboard can spawn new pi sessions from the browser. Two strategies are available:
306
+ Set `"devBuildOnReload": true` in `config.json` for a one-command full-stack refresh:
384
307
 
385
- **Headless** (default) — Runs pi as a background process with no terminal attached. Interaction happens entirely through the dashboard web UI.
308
+ ```
309
+ /reload → build client → stop server → reload extension → auto-start fresh server
310
+ ```
386
311
 
387
- **tmux** Runs pi inside a tmux session named `pi-dashboard`. Each spawned session opens as a new tmux window. This lets you attach to the terminal when needed:
312
+ > Blocks pi for ~2–5s during the build. The server shutdown affects all connected sessions they auto-reconnect when one restarts the server.
313
+
314
+ ### Session spawning
315
+
316
+ **Headless** (default) — runs pi as a background process with no terminal attached. Interaction through the web UI.
317
+
318
+ **tmux** — runs pi inside a tmux session named `pi-dashboard`, each spawned session as a new window:
388
319
 
389
320
  ```bash
390
- # Attach to the pi-dashboard tmux session
391
- tmux attach -t pi-dashboard
321
+ tmux attach -t pi-dashboard # attach
322
+ tmux list-windows -t pi-dashboard # list windows
323
+ # inside tmux: Ctrl-b n / p / w # next / prev / picker
324
+ ```
325
+
326
+ Switch with `"spawnStrategy": "tmux"` in `~/.pi/dashboard/config.json`.
327
+
328
+ ### Keyboard shortcuts in chat input
329
+
330
+ Bash-style history recall and per-session draft persistence:
331
+
332
+ | Key | Action |
333
+ |-----|--------|
334
+ | `Enter` | Send the prompt |
335
+ | `Shift+Enter` | Insert a newline |
336
+ | `ArrowUp` | Recall previous user prompt (caret on first line, no dropdown open). Repeat to walk back |
337
+ | `ArrowDown` | Walk forward through history (caret on last line). Past the newest entry, restores the in-progress draft |
338
+ | `Escape` | Restore in-progress draft and exit history mode; also cancels pending prompt / dismisses dropdown |
339
+ | `Tab` / `Enter` in dropdown | Accept the highlighted `/command` or `@file` suggestion |
392
340
 
393
- # List all windows (each is a spawned pi session)
394
- tmux list-windows -t pi-dashboard
341
+ Drafts (typed-but-unsent text) are persisted per session in `localStorage` under `chat-draft:<sessionId>` and survive navigation (Settings, OpenSpec preview, diffs, …) and full page reloads. Drafts never leak between sessions.
342
+
343
+ ---
344
+
345
+ ## Recommended extensions
346
+
347
+ The dashboard integrates tightly with a small, curated set of pi extensions — for custom tool rendering, the Flow dashboard, and anthropic-messages protocol compatibility. The Electron wizard installs them in one go; the **Packages** tab and a top-of-page banner keep them discoverable afterwards.
348
+
349
+ | Extension | Source | Status | Unlocks |
350
+ |---|---|---|---|
351
+ | `pi-anthropic-messages` | `git@github.com:BlackBeltTechnology/pi-anthropic-messages.git` | **required** | Tool calls on Claude-model Anthropic OAuth / 9Router `cc/*` / pi-model-proxy providers. Without it, tool calls fall back to Claude Code's built-in `bash_ide` sandbox and fail. |
352
+ | `@tintinweb/pi-subagents` | `npm:@tintinweb/pi-subagents` | strongly suggested | `Agent` tool card UI, subagent activity badge, `get_subagent_result` / `steer_subagent` renderers |
353
+ | `pi-flows` | `git@github.com:BlackBeltTechnology/pi-flows.git` | strongly suggested | Flow dashboard, role aliases (`@planning`, `@coding`, …), subagent / flow_write / flow_results / agent_write / ask_user / skill_read / finish tools |
354
+ | `pi-web-access` | `npm:pi-web-access` | strongly suggested | `web_search`, `code_search`, `fetch_content`, `get_search_content` |
355
+ | `pi-agent-browser` | `npm:pi-agent-browser` | optional | `browser` tool (open, snapshot, click, screenshot) |
395
356
 
396
- # Switch between windows inside tmux
397
- Ctrl-b n # next window
398
- Ctrl-b p # previous window
399
- Ctrl-b w # interactive window picker
357
+ Authoritative source: `packages/shared/src/recommended-extensions.ts`. Descriptions, versions, and installed-state are enriched live via `GET /api/packages/recommended` (offline fallback).
358
+
359
+ ---
360
+
361
+ ## Troubleshooting
362
+
363
+ ### Dashboard server doesn't start
364
+
365
+ If `pi` launches but the dashboard never becomes reachable, inspect the launch log:
366
+
367
+ ```bash
368
+ cat ~/.pi/dashboard/server.log # Linux / macOS
369
+ type %USERPROFILE%\.pi\dashboard\server.log # Windows
400
370
  ```
401
371
 
402
- To switch strategy, set `spawnStrategy` in `~/.pi/dashboard/config.json`:
372
+ The log is append-mode with timestamped headers per start attempt, so previous crashes are preserved. Common issues:
403
373
 
404
- ```json
405
- {
406
- "spawnStrategy": "tmux"
407
- }
374
+ - **`ERR_UNSUPPORTED_ESM_URL_SCHEME` on Windows** — fully fixed in 0.4.0+. The 0.2.10 release wrapped the `--import` loader position as a `file://` URL, but the entry-script position stayed a raw Windows path — which crashed Node on non-`C:` drives (`A:\`, `B:\`, …) because the drive-letter heuristic has gaps there. 0.4.0 routes all four server-spawn call sites through a single `spawnNodeScript` / `toFileUrl` helper that wraps both positions unconditionally, and a repo-level lint test prevents regression. Upgrade the package.
375
+ - **`Cannot find pi's TypeScript loader`** — pi is not installed globally. Run `npm install -g @mariozechner/pi-coding-agent`.
376
+ - **Fastify crash at startup** — you're on Node 22.0.0–22.17.x or 24.1.0–24.2.x which are affected by [nodejs/node#58515](https://github.com/nodejs/node/issues/58515). Upgrade to 22.18+ or 24.3+.
377
+
378
+ ### Port already in use
379
+
380
+ - **Windows:** `netstat -ano | findstr :8000` then `taskkill /F /PID <pid>`
381
+ - **Unix:** `lsof -t -i :8000 | xargs kill`
382
+ - Or change `port` in `~/.pi/dashboard/config.json`.
383
+
384
+ ### UI is empty or stuck after switching servers
385
+
386
+ Since the `safe-server-switch` release, switching servers via the header dropdown is **transactional**: the UI verifies the target through a short-lived staging WebSocket (5 s timeout) **before** clearing state or writing `localStorage`. If the target is unreachable, nothing changes — a toast appears and you stay on the previous server.
387
+
388
+ If the currently-active server drops for more than 3 s, a yellow **“Disconnected from \<host\>. Retrying…”** banner appears at the top with a **Switch server** button — use it to pick a reachable server.
389
+
390
+ You should no longer need to manually `localStorage.removeItem("pi-dashboard-last-server")` to recover from a bad switch. If you still get stuck, please file an issue.
391
+
392
+ ### Windows: sessions die when the dashboard restarts
393
+
394
+ Since the `consolidate-windows-spawn-and-platform-handlers` release, pi sessions on Windows **survive dashboard restart**, matching macOS/Linux behaviour. Previously, killing the dashboard process (Task Manager, Ctrl+C, `/api/restart`, crash) terminated every running pi session because the children were in the server's libuv kill-on-close Job Object. The fix uses `detached: true` so children are excluded from the parent's job.
395
+
396
+ If you previously relied on "closing the dashboard cleans everything up," use the per-session **Force Kill** action instead (or `POST /api/session/:id/force-kill`).
397
+
398
+ ### Windows Terminal tab doesn't appear
399
+
400
+ Install Windows Terminal (`wt.exe`) for tabbed interactive sessions — the dashboard prefers it over WSL tmux / headless when available. Windows 11 ships with it; on Windows 10 install from the Microsoft Store.
401
+
402
+ If `wt.exe` is on PATH but launching does nothing, check **Settings → Apps → Advanced app settings → App execution aliases**. If the "wt" alias is disabled, `wt.exe` is found but can't be executed. Enable the alias or uninstall/reinstall Windows Terminal.
403
+
404
+ ### Sessions don't group under my pinned folder
405
+
406
+ Since v0.3+, session grouping uses OS-aware path equality (`platform/paths.ts`). Sessions group correctly under a pinned folder even across trailing-separator, separator-style, or case differences (on Windows and macOS).
407
+
408
+ If you still see two entries for what should be one folder, the paths are likely on different Windows drives (`A:\Foo` and `B:\Foo` are different filesystems and never merge) — that's correct behaviour. If the paths really are the same filesystem, file an issue with both the pinned path (Settings → Tools → Export diagnostics) and the session `cwd` from `/api/sessions`.
409
+
410
+ ### Tool not found (pi / openspec / npm / …)
411
+
412
+ Open **Settings → General → Tools**, click the chevron next to the failing tool to see the full `tried[]` trail, then either (a) install the missing tool on PATH / in the managed location shown in the trail, or (b) set an explicit override via the row's path input. Hit **Rescan** to pick up the change without a server restart.
413
+
414
+ ### Recommended extensions: "Permission denied (publickey)"
415
+
416
+ `pi-flows` and `pi-anthropic-messages` install via SSH (`git@github.com:…`). If your system has no GitHub SSH key, set one up following [GitHub's SSH docs](https://docs.github.com/en/authentication/connecting-to-github-with-ssh), or substitute the equivalent HTTPS URL in the manifest if your fork is public.
417
+
418
+ ---
419
+
420
+ ## Architecture
421
+
422
+ ```mermaid
423
+ graph LR
424
+ subgraph "Per pi session"
425
+ B[Bridge Extension]
426
+ end
427
+
428
+ subgraph "Dashboard Server (Node.js)"
429
+ PG[Pi Gateway :9999]
430
+ BG[Browser Gateway :8000]
431
+ HTTP[HTTP / Static Files]
432
+ MEM[(In-Memory Store)]
433
+ JSON[(JSON Files)]
434
+ end
435
+
436
+ subgraph "Browser"
437
+ UI[React Web Client]
438
+ end
439
+
440
+ B <-->|WebSocket| PG
441
+ UI <-->|WebSocket| BG
442
+ UI -->|HTTP| HTTP
443
+ PG --- MEM
444
+ PG --- JSON
445
+ BG --- MEM
408
446
  ```
409
447
 
448
+ | Component | Location | Role |
449
+ |-----------|----------|------|
450
+ | **Bridge Extension** | `packages/extension/` | Runs in every pi session. Forwards events, relays commands, auto-starts server, hosts PromptBus. |
451
+ | **Dashboard Server** | `packages/server/` | Aggregates events in-memory, persists metadata to JSON, serves the web client, manages terminals. |
452
+ | **Web Client** | `packages/client/` | React + Tailwind UI with real-time WebSocket updates. |
453
+ | **Shared** | `packages/shared/` | TypeScript types, protocols, and utilities shared across all packages. |
454
+
455
+ See [docs/architecture.md](docs/architecture.md) for detailed data flows, reconnection logic, and persistence model.
456
+
410
457
  ### Auto-start flow
411
458
 
412
459
  ```mermaid
@@ -424,15 +471,25 @@ flowchart TD
424
471
 
425
472
  The server is spawned detached (`child_process.spawn` with `detached: true`, `unref()`), so it outlives the pi session. Duplicate spawn attempts from concurrent pi sessions fail harmlessly with `EADDRINUSE`.
426
473
 
427
- ### Dev build on reload
474
+ ---
428
475
 
429
- Set `"devBuildOnReload": true` in `config.json` for a one-command full-stack refresh:
476
+ ## Monitoring
430
477
 
478
+ The health endpoint provides server and agent process metrics:
479
+
480
+ ```bash
481
+ curl -s http://localhost:8000/api/health | jq
431
482
  ```
432
- /reload → build client → stop server → reload extension → auto-start fresh server
433
- ```
434
483
 
435
- > **Note:** Blocks pi for ~2–5s during the build. The server shutdown affects all connected sessions — they auto-reconnect when one restarts the server.
484
+ Returns:
485
+ - `mode` — `"dev"` or `"production"`
486
+ - `server.rss`, `server.heapUsed`, `server.heapTotal` — server memory
487
+ - `server.activeSessions`, `server.totalSessions` — session counts
488
+ - `agents[]` — per-agent metrics (CPU%, RSS, heap, event loop max delay, system load)
489
+
490
+ Agent metrics are collected every 15s via heartbeats and include `eventLoopMaxMs` — useful for diagnosing connection drops during long-running operations.
491
+
492
+ ---
436
493
 
437
494
  ## Development
438
495
 
@@ -467,8 +524,6 @@ pi -e packages/extension/src/bridge.ts # or just `pi` if installed
467
524
 
468
525
  ### Deploy after changes
469
526
 
470
- The `pi-dashboard` command is available globally when the package is installed. After making changes, restart the appropriate components:
471
-
472
527
  ```bash
473
528
  # After client changes (production mode)
474
529
  npm run build
@@ -478,125 +533,15 @@ curl -X POST http://localhost:8000/api/restart
478
533
  curl -X POST http://localhost:8000/api/restart
479
534
 
480
535
  # After bridge extension changes
481
- npm run reload # Reload all connected pi sessions
536
+ npm run reload
482
537
 
483
538
  # Full rebuild (e.g., after pulling updates)
484
539
  npm run build
485
540
  curl -X POST http://localhost:8000/api/restart
486
541
  npm run reload
487
-
488
- # Switch between dev and production mode
489
- curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":true}'
490
- curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":false}'
491
- ```
492
-
493
- ### Project Structure
494
-
495
- The project is a monorepo with npm workspaces:
496
-
497
- ```
498
- packages/
499
- ├── shared/ # Shared TypeScript types & utilities
500
- │ └── src/
501
- │ ├── protocol.ts # Extension ↔ Server messages
502
- │ ├── browser-protocol.ts # Server ↔ Browser messages (incl. PromptBus types)
503
- │ ├── types.ts # Data models
504
- │ ├── config.ts # Shared config loader
505
- │ ├── rest-api.ts # REST API types
506
- │ ├── session-meta.ts # Session metadata sidecar (.meta.json) read/write
507
- │ ├── state-replay.ts # Event synthesis on reconnect
508
- │ ├── stats-extractor.ts # Token/cost stats extraction
509
- │ ├── server-identity.ts # Server detection & identity
510
- │ ├── mdns-discovery.ts # mDNS network auto-discovery
511
- │ └── openspec-poller.ts # OpenSpec change data polling
512
- ├── extension/ # Bridge extension (runs in pi)
513
- │ └── src/
514
- │ ├── bridge.ts # Main extension entry
515
- │ ├── connection.ts # WebSocket with reconnection
516
- │ ├── event-forwarder.ts # Event mapping
517
- │ ├── flow-event-wiring.ts # pi-flows event forwarding
518
- │ ├── prompt-bus.ts # PromptBus — unified prompt routing with adapters
519
- │ ├── dashboard-default-adapter.ts # Default PromptBus adapter for dashboard UI
520
- │ ├── prompt-expander.ts # Prompt template expansion from disk
521
- │ ├── provider-register.ts # Provider auth registration & sync
522
- │ ├── model-tracker.ts # Model selection tracking
523
- │ ├── source-detector.ts # Session source detection (via .meta.json sidecar)
524
- │ ├── command-handler.ts # Command relay
525
- │ ├── server-probe.ts # TCP probe for server detection
526
- │ ├── server-auto-start.ts # Auto-start logic on session launch
527
- │ ├── server-launcher.ts # Spawn server as detached process
528
- │ ├── session-sync.ts # Session history sync
529
- │ ├── process-metrics.ts # Agent process CPU/memory metrics
530
- │ ├── process-scanner.ts # Running process detection
531
- │ ├── git-info.ts # Git branch/remote/PR detection
532
- │ ├── git-link-builder.ts # GitHub/GitLab permalink generation
533
- │ └── dev-build.ts # Dev build-on-reload helper
534
- ├── server/ # Dashboard server
535
- │ └── src/
536
- │ ├── cli.ts # CLI entry (start/stop/restart/status)
537
- │ ├── server.ts # HTTP + WebSocket server
538
- │ ├── pi-gateway.ts # Extension WebSocket gateway
539
- │ ├── browser-gateway.ts # Browser WebSocket gateway
540
- │ ├── memory-event-store.ts # In-memory event buffer (LRU, per-session cap, truncation)
541
- │ ├── memory-session-manager.ts # In-memory session registry
542
- │ ├── preferences-store.ts # User prefs: hidden sessions, pinned dirs
543
- │ ├── meta-persistence.ts # Session metadata persistence
544
- │ ├── session-order-manager.ts # Per-cwd session ordering
545
- │ ├── session-discovery.ts # Session file scanning & loading
546
- │ ├── process-manager.ts # tmux/headless session spawning
547
- │ ├── headless-pid-registry.ts # Track headless process PIDs
548
- │ ├── editor-registry.ts # Available editor detection
549
- │ ├── editor-manager.ts # Editor launch & file opening
550
- │ ├── provider-auth-storage.ts # Provider credential persistence
551
- │ ├── provider-auth-handlers.ts # OAuth flow handlers
552
- │ ├── npm-search-proxy.ts # npm registry search proxy
553
- │ ├── package-manager-wrapper.ts # pi package install/remove
554
- │ ├── pending-fork-registry.ts # Flow fork decision persistence
555
- │ ├── tunnel.ts # Zrok tunnel with reserved shares
556
- │ ├── terminal-manager.ts # Browser terminal sessions (xterm.js + node-pty)
557
- │ ├── server-pid.ts # PID file for daemon management
558
- │ ├── auth.ts # OAuth2 authentication
559
- │ └── json-store.ts # Atomic JSON file helpers
560
- ├── client/ # React web client
561
- │ └── src/
562
- │ ├── App.tsx
563
- │ ├── hooks/ # WebSocket hooks, mobile detection
564
- │ ├── lib/ # Event reducer, command filter
565
- │ └── components/ # UI components
566
- │ ├── FlowDashboard.tsx # Live flow execution view
567
- │ ├── FlowAgentCard.tsx # Per-agent status cards
568
- │ ├── FlowGraph.tsx # DAG visualization
569
- │ ├── FlowArchitect.tsx # Flow designer UI
570
- │ ├── FlowSummary.tsx # Post-flow result summary
571
- │ ├── DiffView.tsx # Side-by-side diff viewer
572
- │ ├── TerminalView.tsx # Browser terminal emulator
573
- │ ├── PackageBrowser.tsx # Package search & install
574
- │ ├── ProviderAuthSection.tsx # Provider sign-in UI
575
- │ ├── SettingsPanel.tsx # Config editor
576
- │ └── ... # 80+ components
577
- └── electron/ # Electron desktop app wrapper
578
- ├── src/main.ts
579
- ├── scripts/
580
- └── resources/
581
- ```
582
-
583
- ## Monitoring
584
-
585
- The health endpoint provides server and agent process metrics:
586
-
587
- ```bash
588
- curl -s http://localhost:8000/api/health | jq
589
542
  ```
590
543
 
591
- Returns:
592
- - `mode` — `"dev"` or `"production"`
593
- - `server.rss`, `server.heapUsed`, `server.heapTotal` — server memory
594
- - `server.activeSessions`, `server.totalSessions` — session counts
595
- - `agents[]` — per-agent metrics (CPU%, RSS, heap, event loop max delay, system load)
596
-
597
- Agent metrics are collected every 15s via heartbeats and include `eventLoopMaxMs` — useful for diagnosing connection drops during long-running operations.
598
-
599
- ## Extension UI Events
544
+ ### Extension UI events
600
545
 
601
546
  Your own extensions can broadcast UI events to the dashboard:
602
547
 
@@ -610,40 +555,40 @@ pi.events.emit("dashboard:ui", {
610
555
 
611
556
  Supported methods: `confirm`, `select`, `input`, `notify`.
612
557
 
613
- ## Electron Desktop App
614
-
615
- The project includes an Electron wrapper at `packages/electron/` that bundles the dashboard as a **fully standalone native desktop app**. Pre-built installers for all platforms are available on [GitHub Releases](https://github.com/BlackBeltTechnology/pi-agent-dashboard/releases) — see [Getting Started](#getting-started) above.
558
+ ### Project structure
616
559
 
617
- The Electron app supports two modes:
560
+ Monorepo with npm workspaces top-level layout only. See [AGENTS.md](AGENTS.md) for the full file-by-file index.
618
561
 
619
- | Mode | Description |
620
- |------|-------------|
621
- | **Standalone** | Bundles Node.js, auto-installs pi + dashboard into `~/.pi-dashboard/`. Zero prerequisites. |
622
- | **Power User** | Detects and uses your existing system pi + dashboard install. |
623
-
624
- Features: first-run setup wizard, auto-update checker, system tray, splash screen, VM detection (disables GPU acceleration), mDNS server discovery, and version compatibility checks.
562
+ ```
563
+ packages/
564
+ ├── shared/ # Shared TypeScript types, protocols, config, session-meta helpers
565
+ ├── extension/ # Bridge extension (runs inside pi) WS client, PromptBus, event forwarding, auto-start
566
+ ├── server/ # Dashboard server — HTTP + dual WebSocket gateways, in-memory store, terminals, auth, tunnel
567
+ ├── client/ # React + Tailwind web client 80+ components, hooks, event reducer
568
+ └── electron/ # Electron desktop wrapper — wizard, system tray, auto-update, bundled Node.js
569
+ ```
625
570
 
626
- ### Building from Source
571
+ ---
627
572
 
628
- > **Prerequisites for building:** Node.js 22.12+, platform-specific tools handled by Electron Forge automatically.
573
+ ## Building the Electron app
629
574
 
630
- ### Building for Your Platform
575
+ > **Prerequisites:** Node.js 22.12+; platform-specific tools handled by Electron Forge automatically.
631
576
 
632
- The easiest way — one command that handles everything (client build, Node.js bundling, installer creation):
577
+ ### Native build (current platform)
633
578
 
634
579
  ```bash
635
- npm run electron:build # Build for current platform & arch
636
- npm run electron:build -- --arch x64 # Override architecture
637
- npm run electron:build -- --skip-client # Skip client rebuild
580
+ npm run electron:build # Build for current platform & arch
581
+ npm run electron:build -- --arch x64 # Override architecture
582
+ npm run electron:build -- --skip-client # Skip client rebuild
638
583
  ```
639
584
 
640
585
  Or step by step:
641
586
 
642
587
  ```bash
643
- npm run build # Build web client
588
+ npm run build # Build web client
644
589
  cd packages/electron
645
- bash scripts/download-node.sh # Download Node.js for bundling
646
- npm run make # Build installer
590
+ bash scripts/download-node.sh # Download Node.js for bundling
591
+ npm run make # Build installer
647
592
  ```
648
593
 
649
594
  Output by platform:
@@ -652,25 +597,22 @@ Output by platform:
652
597
  |----------|--------|----------|
653
598
  | macOS | `.dmg` | `packages/electron/out/make/` |
654
599
  | Linux | `.deb` + `.AppImage` | `packages/electron/out/make/` |
655
- | Windows | `.exe` (NSIS installer) + `.zip` + portable `.exe` | `packages/electron/out/make/` |
600
+ | Windows | `.exe` (NSIS) + `.zip` + portable `.exe` | `packages/electron/out/make/` |
656
601
 
657
- ### Cross-Platform Builds (via Docker)
602
+ ### Cross-platform builds (Docker)
658
603
 
659
- From macOS or Linux, you can build installers for **all platforms** using Docker:
604
+ From macOS or Linux, build installers for all platforms:
660
605
 
661
606
  ```bash
662
- npm run electron:build -- --all # macOS (native) + Linux + Windows (Docker)
663
- npm run electron:build -- --linux # Linux .deb + .AppImage only
664
- npm run electron:build -- --windows # Windows .exe (NSIS) only
607
+ npm run electron:build -- --all # macOS (native) + Linux + Windows (Docker)
608
+ npm run electron:build -- --linux # Linux .deb + .AppImage only
609
+ npm run electron:build -- --windows # Windows .exe (NSIS) only
665
610
  npm run electron:build -- --linux --windows # Both, skip native
666
611
  ```
667
612
 
668
- Docker builds use a Node 22 Debian container with NSIS installed for Windows cross-compilation.
669
- All output goes to `packages/electron/out/make/`.
613
+ Docker builds use a Node 22 Debian container with NSIS installed for Windows cross-compilation. Output goes to `packages/electron/out/make/`.
670
614
 
671
- > **Note:** Native builds (no flags) build for the current platform only. Docker is required for `--linux`, `--windows`, and `--all`.
672
-
673
- ### Development Mode
615
+ ### Electron dev mode
674
616
 
675
617
  ```bash
676
618
  # Start the dashboard server and Vite dev server first
@@ -682,7 +624,7 @@ cd packages/electron
682
624
  npm run start:dev
683
625
  ```
684
626
 
685
- ### Regenerating Icons
627
+ ### Regenerating icons
686
628
 
687
629
  All platform icon variants are generated from the master icon at `packages/electron/resources/icon.png`:
688
630
 
@@ -691,9 +633,31 @@ cd packages/electron
691
633
  npm run icons # Generates .icns (macOS), .ico (Windows), and resized PNGs
692
634
  ```
693
635
 
694
- ### CI Builds & GitHub Releases
636
+ ---
637
+
638
+ ## CI/CD & releasing
639
+
640
+ See [`docs/release-process.md`](docs/release-process.md) for the full cut-a-release workflow.
641
+
642
+ ### Continuous integration
643
+
644
+ Every push to `develop` and every pull request against `develop` triggers [`ci.yml`](.github/workflows/ci.yml):
645
+
646
+ 1. `npm ci` — install dependencies
647
+ 2. `npm run lint` — type check
648
+ 3. `npm test` — run tests
649
+ 4. `npm run build` — build web client
650
+
651
+ ### Releasing
695
652
 
696
- The release workflow (`.github/workflows/publish.yml`) builds Electron installers for **all platforms** on every version tag (`v*`):
653
+ The publish workflow ([`publish.yml`](.github/workflows/publish.yml)) triggers on `v*` tags:
654
+
655
+ ```bash
656
+ npm version patch # or minor / major
657
+ git push --follow-tags
658
+ ```
659
+
660
+ This runs CI, publishes to npm with `--provenance` for supply-chain transparency, and builds Electron installers for all platforms on native runners:
697
661
 
698
662
  | Runner | Platform | Outputs |
699
663
  |--------|----------|---------|
@@ -703,37 +667,51 @@ The release workflow (`.github/workflows/publish.yml`) builds Electron installer
703
667
  | `windows-latest` | Windows x64 | `.exe` (NSIS) + `.zip` + portable |
704
668
  | `windows-latest` | Windows arm64 | `.zip` + portable (x64 Node.js via WoW64) |
705
669
 
706
- All artifacts are uploaded to a **draft GitHub Release** for review and publishing. The same workflow also publishes the npm package. Release notes for the draft are extracted automatically from the matching `## [<version>]` section of [`CHANGELOG.md`](CHANGELOG.md) — see [`docs/release-process.md`](docs/release-process.md) for the full cut-a-release workflow.
670
+ All artifacts are uploaded to a **draft GitHub Release**. Release notes are extracted automatically from the matching `## [<version>]` section of [`CHANGELOG.md`](CHANGELOG.md).
707
671
 
708
- ## CI/CD
672
+ ### Trusted Publisher (OIDC) setup
709
673
 
710
- ### Continuous Integration
674
+ The publish workflow uses **[npm Trusted Publishers](https://docs.npmjs.com/trusted-publishers)** over OIDC — **no `NPM_TOKEN` secret required**. Short-lived, workflow-scoped credentials are exchanged between GitHub and npm at publish time, and every release carries automatic [npm provenance](https://docs.npmjs.com/generating-provenance-statements) tying the published artifact to the exact workflow run.
711
675
 
712
- Every push to `develop` and every pull request against `develop` triggers the CI workflow (`.github/workflows/ci.yml`):
676
+ **Requirements** (already configured in [`publish.yml`](.github/workflows/publish.yml)):
713
677
 
714
- 1. `npm ci` — install dependencies
715
- 2. `npm run lint` — type check
716
- 3. `npm test` run tests
717
- 4. `npm run build` build web client
678
+ ```yaml
679
+ permissions:
680
+ contents: write # draft GitHub Release + tag push
681
+ id-token: write # OIDC token exchange with the npm registry
682
+ environment: npm-publish
683
+ ```
718
684
 
719
- ### Releasing to npm
685
+ Trusted Publishing requires **npm CLI ≥ 11.5.1**. The workflow upgrades npm automatically (`npm install -g npm@latest`) before publishing.
720
686
 
721
- The publish workflow (`.github/workflows/publish.yml`) triggers on `v*` tags:
687
+ **One-time npm-side setup** — repeat once per published package (five scoped workspaces; `@blackbelt-technology/pi-dashboard-electron` is private and skipped):
722
688
 
723
- ```bash
724
- npm version patch # or minor / major
725
- git push --follow-tags
726
- ```
689
+ | Package |
690
+ |---|
691
+ | `@blackbelt-technology/pi-agent-dashboard` (root) |
692
+ | `@blackbelt-technology/pi-dashboard-shared` |
693
+ | `@blackbelt-technology/pi-dashboard-extension` |
694
+ | `@blackbelt-technology/pi-dashboard-server` |
695
+ | `@blackbelt-technology/pi-dashboard-web` |
696
+
697
+ For each:
698
+
699
+ 1. Go to [npmjs.com](https://www.npmjs.com/) → the package → **Settings** → **Trusted Publisher** → **GitHub Actions**
700
+ 2. Fill in:
701
+ - **Organization or user:** `BlackBeltTechnology`
702
+ - **Repository:** `pi-agent-dashboard`
703
+ - **Workflow filename:** `publish.yml` *(filename only, not the full path)*
704
+ - **Environment name:** `npm-publish` *(must match the `environment:` field in the workflow)*
705
+ 3. Save
727
706
 
728
- This runs CI checks, then publishes to npm with `--provenance` for supply chain transparency.
707
+ **GitHub Environment (recommended)** configures an optional human-approval gate on every release:
729
708
 
730
- ### npm Token Setup
709
+ 1. GitHub repo → **Settings** → **Environments** → **New environment** → name `npm-publish`
710
+ 2. Optionally add **required reviewers** and/or **deployment branch/tag protection rules** (e.g. restrict to `v*` tags)
731
711
 
732
- The publish workflow requires an `NPM_TOKEN` secret in the GitHub repository:
712
+ No secrets to rotate, no tokens to leak.
733
713
 
734
- 1. Generate a token at [npmjs.com](https://www.npmjs.com/) → Access Tokens → Generate New Token (Granular Access Token)
735
- 2. Grant publish access to `@blackbelt-technology` packages
736
- 3. Add it as a repository secret: GitHub repo → Settings → Secrets and variables → Actions → New repository secret → Name: `NPM_TOKEN`
714
+ ---
737
715
 
738
716
  ## License
739
717