@blackbelt-technology/pi-agent-dashboard 0.4.0 → 0.4.2

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 (129) hide show
  1. package/AGENTS.md +104 -35
  2. package/README.md +390 -494
  3. package/docs/architecture.md +423 -20
  4. package/package.json +11 -8
  5. package/packages/extension/package.json +11 -4
  6. package/packages/extension/src/__tests__/ask-user-schema-discriminator.test.ts +141 -0
  7. package/packages/extension/src/__tests__/ask-user-tool.test.ts +91 -15
  8. package/packages/extension/src/__tests__/bridge-entry-id-pi-070.test.ts +174 -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__/multiselect-dashboard-routing.test.ts +203 -0
  12. package/packages/extension/src/__tests__/multiselect-list.test.ts +137 -0
  13. package/packages/extension/src/__tests__/multiselect-polyfill.test.ts +92 -0
  14. package/packages/extension/src/__tests__/no-session-replacement-calls.test.ts +99 -0
  15. package/packages/extension/src/__tests__/no-tui-multiselect-arm-regression.test.ts +81 -0
  16. package/packages/extension/src/__tests__/openspec-activity-detector.test.ts +37 -0
  17. package/packages/extension/src/__tests__/ui-decorators.test.ts +309 -0
  18. package/packages/extension/src/__tests__/ui-modules.test.ts +293 -0
  19. package/packages/extension/src/ask-user-tool.ts +170 -61
  20. package/packages/extension/src/bridge.ts +199 -19
  21. package/packages/extension/src/multiselect-decode.ts +40 -0
  22. package/packages/extension/src/multiselect-list.ts +146 -0
  23. package/packages/extension/src/multiselect-polyfill.ts +73 -0
  24. package/packages/extension/src/server-launcher.ts +15 -3
  25. package/packages/extension/src/ui-modules.ts +272 -0
  26. package/packages/server/package.json +11 -5
  27. package/packages/server/src/__tests__/auto-attach.test.ts +61 -8
  28. package/packages/server/src/__tests__/browse-endpoint.test.ts +295 -19
  29. package/packages/server/src/__tests__/cli-bootstrap.test.ts +36 -0
  30. package/packages/server/src/__tests__/directory-service-refresh-force.test.ts +163 -0
  31. package/packages/server/src/__tests__/directory-service-specs-mtime.test.ts +315 -0
  32. package/packages/server/src/__tests__/directory-service-toctou.test.ts +303 -0
  33. package/packages/server/src/__tests__/directory-service.test.ts +174 -0
  34. package/packages/server/src/__tests__/fixtures/fork-jsonl-roundtrip.jsonl +8 -0
  35. package/packages/server/src/__tests__/fork-jsonl-roundtrip.test.ts +49 -0
  36. package/packages/server/src/__tests__/installed-package-enricher.test.ts +225 -0
  37. package/packages/server/src/__tests__/package-manager-wrapper-move.test.ts +414 -0
  38. package/packages/server/src/__tests__/package-routes.test.ts +136 -3
  39. package/packages/server/src/__tests__/package-source-helpers.test.ts +101 -0
  40. package/packages/server/src/__tests__/pending-attach-registry.test.ts +123 -0
  41. package/packages/server/src/__tests__/pending-resume-intent-registry.test.ts +138 -0
  42. package/packages/server/src/__tests__/pi-core-checker.test.ts +73 -30
  43. package/packages/server/src/__tests__/pi-gateway-consume-pending-attach.test.ts +112 -0
  44. package/packages/server/src/__tests__/pi-version-skew.test.ts +72 -0
  45. package/packages/server/src/__tests__/post-install-openspec-refresh.test.ts +180 -0
  46. package/packages/server/src/__tests__/post-install-rescan.test.ts +134 -0
  47. package/packages/server/src/__tests__/proposal-attach-naming.test.ts +79 -0
  48. package/packages/server/src/__tests__/restart-helper.test.ts +34 -6
  49. package/packages/server/src/__tests__/session-action-handler-spawn-with-attach.test.ts +108 -0
  50. package/packages/server/src/__tests__/session-order-manager.test.ts +55 -0
  51. package/packages/server/src/__tests__/session-order-reboot.test.ts +242 -0
  52. package/packages/server/src/__tests__/session-scanner.test.ts +44 -0
  53. package/packages/server/src/__tests__/subscription-handler.test.ts +40 -0
  54. package/packages/server/src/__tests__/translate-path-source.test.ts +77 -0
  55. package/packages/server/src/__tests__/ui-decorators-replay.test.ts +209 -0
  56. package/packages/server/src/__tests__/ui-modules-replay.test.ts +221 -0
  57. package/packages/server/src/browse.ts +118 -13
  58. package/packages/server/src/browser-gateway.ts +19 -0
  59. package/packages/server/src/browser-handlers/__tests__/session-meta-handler.test.ts +183 -0
  60. package/packages/server/src/browser-handlers/directory-handler.ts +7 -1
  61. package/packages/server/src/browser-handlers/handler-context.ts +15 -0
  62. package/packages/server/src/browser-handlers/session-action-handler.ts +29 -3
  63. package/packages/server/src/browser-handlers/session-meta-handler.ts +46 -12
  64. package/packages/server/src/browser-handlers/subscription-handler.ts +46 -1
  65. package/packages/server/src/cli.ts +61 -15
  66. package/packages/server/src/directory-service.ts +156 -15
  67. package/packages/server/src/event-wiring.ts +111 -10
  68. package/packages/server/src/installed-package-enricher.ts +143 -0
  69. package/packages/server/src/package-manager-wrapper.ts +305 -8
  70. package/packages/server/src/package-source-helpers.ts +104 -0
  71. package/packages/server/src/pending-attach-registry.ts +112 -0
  72. package/packages/server/src/pending-resume-intent-registry.ts +107 -0
  73. package/packages/server/src/pi-core-checker.ts +9 -14
  74. package/packages/server/src/pi-gateway.ts +14 -0
  75. package/packages/server/src/pi-version-skew.ts +12 -1
  76. package/packages/server/src/proposal-attach-naming.ts +47 -0
  77. package/packages/server/src/restart-helper.ts +13 -2
  78. package/packages/server/src/routes/file-routes.ts +29 -3
  79. package/packages/server/src/routes/package-routes.ts +72 -3
  80. package/packages/server/src/routes/plugin-config-routes.ts +129 -0
  81. package/packages/server/src/routes/system-routes.ts +2 -0
  82. package/packages/server/src/server.ts +339 -10
  83. package/packages/server/src/session-api.ts +30 -5
  84. package/packages/server/src/session-order-manager.ts +22 -0
  85. package/packages/server/src/session-scanner.ts +10 -1
  86. package/packages/shared/package.json +9 -2
  87. package/packages/shared/src/__tests__/browser-protocol-types.test.ts +59 -0
  88. package/packages/shared/src/__tests__/config-plugins.test.ts +68 -0
  89. package/packages/shared/src/__tests__/extension-ui-module-shape.test.ts +265 -0
  90. package/packages/shared/src/__tests__/no-hardcoded-node-modules-paths.test.ts +176 -0
  91. package/packages/shared/src/__tests__/no-raw-node-import.test.ts +146 -0
  92. package/packages/shared/src/__tests__/no-raw-openspec-status-in-skills.test.ts +81 -0
  93. package/packages/shared/src/__tests__/node-spawn.test.ts +210 -0
  94. package/packages/shared/src/__tests__/openspec-design-evidence.test.ts +288 -0
  95. package/packages/shared/src/__tests__/openspec-effective-status-script.test.ts +174 -0
  96. package/packages/shared/src/__tests__/openspec-poller-design-override.test.ts +225 -0
  97. package/packages/shared/src/__tests__/openspec-poller-specs-override.test.ts +284 -0
  98. package/packages/shared/src/__tests__/openspec-specs-evidence.test.ts +144 -0
  99. package/packages/shared/src/__tests__/platform/is-appimage-self-hit.test.ts +164 -0
  100. package/packages/shared/src/__tests__/plugin-bridge-register-extended.test.ts +72 -0
  101. package/packages/shared/src/__tests__/plugin-bridge-register.test.ts +113 -0
  102. package/packages/shared/src/__tests__/plugin-config-update-protocol.test.ts +41 -0
  103. package/packages/shared/src/__tests__/recommended-extensions.test.ts +5 -1
  104. package/packages/shared/src/__tests__/resolve-tool-cli.test.ts +105 -0
  105. package/packages/shared/src/__tests__/spawn-session-attach-proposal.test.ts +47 -0
  106. package/packages/shared/src/__tests__/state-replay-entry-id.test.ts +69 -0
  107. package/packages/shared/src/__tests__/tool-registry-strategies-appimage.test.ts +118 -0
  108. package/packages/shared/src/browser-protocol.ts +110 -4
  109. package/packages/shared/src/config.ts +45 -0
  110. package/packages/shared/src/dashboard-plugin/index.ts +11 -0
  111. package/packages/shared/src/dashboard-plugin/manifest-types.ts +58 -0
  112. package/packages/shared/src/dashboard-plugin/plugin-status.ts +26 -0
  113. package/packages/shared/src/dashboard-plugin/slot-props.ts +92 -0
  114. package/packages/shared/src/dashboard-plugin/slot-types.ts +151 -0
  115. package/packages/shared/src/openspec-activity-detector.ts +18 -22
  116. package/packages/shared/src/openspec-design-evidence.ts +109 -0
  117. package/packages/shared/src/openspec-poller.ts +117 -3
  118. package/packages/shared/src/openspec-specs-evidence.ts +79 -0
  119. package/packages/shared/src/platform/binary-lookup.ts +96 -1
  120. package/packages/shared/src/platform/index.ts +1 -0
  121. package/packages/shared/src/platform/node-spawn.ts +154 -0
  122. package/packages/shared/src/plugin-bridge-register.ts +139 -0
  123. package/packages/shared/src/protocol.ts +79 -2
  124. package/packages/shared/src/recommended-extensions.ts +7 -1
  125. package/packages/shared/src/rest-api.ts +68 -3
  126. package/packages/shared/src/state-replay.ts +20 -1
  127. package/packages/shared/src/tool-registry/definitions.ts +92 -0
  128. package/packages/shared/src/tool-registry/strategies.ts +17 -3
  129. package/packages/shared/src/types.ts +160 -0
package/README.md CHANGED
@@ -6,191 +6,164 @@
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
- - **Custom LLM providers** — Add OpenAI-compatible, Anthropic-compatible, or Google Generative AI endpoints (Settings → Providers → LLM Providers). Each card has a **Test** button that pings the provider's `/models` endpoint to verify your base URL + API key combination before saving. Adding, editing, or removing a provider takes effect live in every running pi session — no restart required.
33
- - **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.
34
- - **OpenSpec integration** — Browse specs, view archive history, manage changes, and create new changes from the session sidebar
35
- - **Diff viewer** — Side-by-side and unified diff views with file tree navigation for reviewing agent changes
36
- - **Editor integration** — Open files in your preferred editor (VS Code, Cursor, etc.) directly from tool call cards
37
- - **Markdown preview** — Rendered markdown views with search, mermaid diagrams, and syntax highlighting
38
- - **Network discovery** — mDNS-based auto-discovery of other dashboard servers on the local network; connect to known remote servers
39
-
40
- ## Architecture
41
-
42
- ```mermaid
43
- graph LR
44
- subgraph "Per pi session"
45
- B[Bridge Extension]
46
- end
47
-
48
- subgraph "Dashboard Server (Node.js)"
49
- PG[Pi Gateway :9999]
50
- BG[Browser Gateway :8000]
51
- HTTP[HTTP / Static Files]
52
- MEM[(In-Memory Store)]
53
- JSON[(JSON Files)]
54
- end
55
-
56
- subgraph "Browser"
57
- UI[React Web Client]
58
- end
59
-
60
- B <-->|WebSocket| PG
61
- UI <-->|WebSocket| BG
62
- UI -->|HTTP| HTTP
63
- PG --- MEM
64
- PG --- JSON
65
- BG --- MEM
66
- ```
16
+ ## Table of contents
67
17
 
68
- The system has three components:
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)
69
31
 
70
- | Component | Location | Role |
71
- |-----------|----------|------|
72
- | **Bridge Extension** | `packages/extension/` | Runs in every pi session. Forwards events, relays commands, auto-starts server, hosts PromptBus. |
73
- | **Dashboard Server** | `packages/server/` | Aggregates events in-memory, persists metadata to JSON, serves the web client, manages terminals. |
74
- | **Web Client** | `packages/client/` | React + Tailwind UI with real-time WebSocket updates. |
75
- | **Shared** | `packages/shared/` | TypeScript types, protocols, and utilities shared across all packages. |
76
-
77
- See [docs/architecture.md](docs/architecture.md) for detailed data flows, reconnection logic, and persistence model.
32
+ ---
78
33
 
79
- ## Getting Started
34
+ ## Quickstart
80
35
 
81
- There are three ways to use the dashboard, from simplest to most flexible:
36
+ Three install paths, pick one:
82
37
 
83
- ### Option A: Electron Desktop App (standalone — no prerequisites)
38
+ ### A Electron desktop app (no prerequisites)
84
39
 
85
- 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):
86
41
 
87
42
  | Platform | Download |
88
43
  |----------|----------|
89
- | **macOS** (Apple Silicon) | `.dmg` (arm64) |
90
- | **macOS** (Intel) | `.dmg` (x64) |
91
- | **Linux** (x64) | `.deb` or `.AppImage` |
92
- | **Linux** (ARM64) | `.deb` |
93
- | **Windows** (x64) | `.exe` (NSIS installer), `.zip`, or portable `.exe` |
94
- | **Windows** (ARM64) | `.zip` or portable `.exe` |
95
-
96
- On first launch, a setup wizard guides you through:
97
-
98
- 1. **Choose a mode:**
99
- - **Standalone** — Bundles Node.js and auto-installs pi + dashboard + openspec into `~/.pi-dashboard/`. No Node.js, npm, or build tools needed.
100
- - **Power User** — Uses your existing system-installed pi and dashboard.
101
- 2. **Configure an API key** — Enter your Anthropic/OpenAI key or sign in via browser-based OAuth.
102
- 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.
103
- 4. **Done** — The app discovers or spawns a dashboard server automatically.
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` |
104
47
 
105
- > **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.
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**.
106
49
 
107
- ### Option B: pi Package (recommended for CLI users)
108
-
109
- 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 **≥ 22.18.0** (or ≥ 24.3.0). Older Node 22.x / 24.x builds are affected by [nodejs/node#58515](https://github.com/nodejs/node/issues/58515) which crashes Fastify at startup.
50
+ ### B pi package (recommended for CLI users)
110
51
 
111
52
  ```bash
112
53
  pi install npm:@blackbelt-technology/pi-agent-dashboard
113
54
  pi
114
55
  ```
115
56
 
116
- 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:
117
58
 
118
59
  ```
119
60
  🌐 Dashboard started at http://localhost:8000
120
61
  ```
121
62
 
122
- 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.
123
64
 
124
- ### Option C: Local development install
65
+ ### C From source (contributors)
125
66
 
126
67
  ```bash
127
68
  git clone https://github.com/BlackBeltTechnology/pi-agent-dashboard.git
128
69
  cd pi-agent-dashboard
129
70
  npm install
130
- 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
131
73
  ```
132
74
 
133
- ## Recommended extensions
134
-
135
- The dashboard integrates tightly with a small, curated set of pi extensions
136
- — for custom tool rendering, the Flow dashboard, and anthropic-messages
137
- protocol compatibility. The wizard's Recommended-extensions step installs
138
- them in one go; the **Packages** tab and a top-of-page **banner** keep
139
- them discoverable afterwards.
140
-
141
- | Extension | Source | Status | Unlocks |
142
- |---|---|---|---|
143
- | `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. |
144
- | `@tintinweb/pi-subagents` | `npm:@tintinweb/pi-subagents` | strongly suggested | `Agent` tool card UI, subagent activity badge, `get_subagent_result` / `steer_subagent` renderers. |
145
- | `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. |
146
- | `pi-web-access` | `npm:pi-web-access` | strongly suggested | `web_search`, `code_search`, `fetch_content`, `get_search_content`. |
147
- | `pi-agent-browser` | `npm:pi-agent-browser` | optional | `browser` tool (open, snapshot, click, screenshot). |
148
-
149
- Authoritative source of truth: `packages/shared/src/recommended-extensions.ts`.
150
- Descriptions, versions, and installed-state are enriched live at runtime via
151
- `GET /api/packages/recommended` (falling back to offline descriptions on
152
- network failure).
153
-
154
- ### GitHub SSH notes
155
-
156
- The `pi-flows` and `pi-anthropic-messages` entries install via `pi install
157
- git@github.com:…` (SSH). If your system doesn't have a GitHub SSH key
158
- configured the clone will fail with a "Permission denied (publickey)"
159
- error. Set up a key by following
160
- [GitHub's SSH docs](https://docs.github.com/en/authentication/connecting-to-github-with-ssh),
161
- or substitute the equivalent HTTPS URL in the manifest if your fork is
162
- public.
163
-
164
- ### Quick test (without installing)
165
-
166
75
  To try the extension in a single pi session without registering it:
167
76
 
168
77
  ```bash
169
78
  pi -e /path/to/pi-agent-dashboard/packages/extension/src/bridge.ts
170
79
  ```
171
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, syntax highlighting, and safe handling for raw HTML `ref` attributes
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. Multiselect uses the bus-routed browser path exclusively (the dashboard `MultiselectRenderer` dialog) since pi 0.70's RPC mode has no working terminal-overlay primitive. First-response-wins semantics with cross-adapter dismissal.
105
+ - **Extension UI System (Phase 1)** — extensions can declare slash-command-triggered modal UIs as data, without authoring React or importing an SDK. Listen on `pi.events.on("ui:list-modules", probe)` and push descriptors into `probe.modules`; the dashboard renders `table` / `grid` / `form` views with row actions, optional confirm-dialog gates, and MDI icons. Modules survive reconnect via the server-side cache; in pure-pi mode descriptors stay dormant. See `openspec/specs/extension-ui-system/spec.md` for the protocol contract.
106
+ - **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.
107
+ - **OpenSpec integration** — browse specs, view archive history, manage changes, create new changes from the sidebar
108
+ - **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.
109
+ - **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.
110
+ - **Package management** — browse, install, update, remove, and **move** pi packages between global and project scopes from a single rich-row UI used in both Settings and Pi Resources. Install dialog exposes a Local/Global radio when launched from a per-folder context. Search the npm registry for pi-package extensions/skills/themes; install from npm or git URL. Active sessions auto-reload after changes.
111
+
112
+ **Dev tools**
113
+ - **Integrated terminal** — full browser-based terminal emulator (xterm.js + node-pty) with ANSI colors, scrollback, and keep-alive
114
+ - **Diff viewer** — side-by-side and unified diff views with file tree navigation
115
+ - **Editor integration** — open files in VS Code, Cursor, etc. directly from tool call cards
116
+
117
+ **Networking & distribution**
118
+ - **Network discovery** — mDNS-based auto-discovery of other dashboard servers on the local network
119
+ - **Zrok tunnel** — optional persistent public URL via reserved shares (see [Configuration → Tunnel](#tunnel-zrok))
120
+
121
+ ---
122
+
172
123
  ## Prerequisites
173
124
 
174
- Only needed for Option B/C (the Electron app handles everything automatically).
125
+ **Only needed for Quickstart paths B and C.** The Electron app (path A) bundles everything in standalone mode.
175
126
 
176
127
  | Requirement | Why | Install |
177
128
  |-------------|-----|---------|
178
- | **[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` |
179
- | **Node.js ≥ 22.18.0** | Runtime for the dashboard server (older 22.x / 24.x affected by [nodejs/node#58515](https://github.com/nodejs/node/issues/58515)) | [nodejs.org](https://nodejs.org/) |
180
- | **C++ build tools** | Required by `node-pty` native addon for terminal emulation | Xcode CLI Tools (macOS) / `build-essential` (Linux) |
129
+ | **[pi](https://github.com/badlogic/pi-mono)** | The AI coding agent the dashboard monitors | `npm i -g @mariozechner/pi-coding-agent` |
130
+ | **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/) |
131
+ | **C++ build tools** | Required by `node-pty` native addon for the integrated terminal | Xcode CLI Tools (macOS) / `build-essential` (Linux) |
181
132
 
182
- ### Optional tools
133
+ Optional:
183
134
 
184
135
  | Tool | Purpose | When needed |
185
136
  |------|---------|-------------|
186
- | **tmux** | Spawn new pi sessions from the browser in a tmux window | When `spawnStrategy` is `"tmux"` |
187
- | **[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) |
137
+ | **tmux** | Spawn new pi sessions in a tmux window | When `spawnStrategy` is `"tmux"` |
138
+ | **[zrok](https://zrok.io/)** | Public tunnel with persistent URLs | When `tunnel.enabled` is `true` (default) |
139
+
140
+ ---
188
141
 
189
142
  ## Configuration
190
143
 
191
- Config file: **`~/.pi/dashboard/config.json`** (auto-created with defaults on first run)
144
+ - **Config file:** `~/.pi/dashboard/config.json` (auto-created with defaults on first run)
145
+ - **Tool overrides (machine-local):** `~/.pi/dashboard/tool-overrides.json` — see [Tool overrides](#tool-overrides)
146
+ - **Settings UI:** click the ⚙ gear icon in the sidebar header to edit all fields from the browser
147
+
148
+ ### Precedence & keys
149
+
150
+ CLI flags → environment variables → config file → built-in defaults.
192
151
 
193
- Tool path overrides (optional, machine-local): **`~/.pi/dashboard/tool-overrides.json`** see [Tool resolution & overrides](#tool-resolution--overrides) below.
152
+ | CLI flag | Env var | Config key | Default | Description |
153
+ |----------|---------|------------|---------|-------------|
154
+ | `--port` | `PI_DASHBOARD_PORT` | `port` | `8000` | HTTP + browser WebSocket port |
155
+ | `--pi-port` | `PI_DASHBOARD_PI_PORT` | `piPort` | `9999` | Pi extension WebSocket port |
156
+ | `--dev` | — | — | `false` | Development mode (proxy to Vite) |
157
+ | `--no-tunnel` | — | `tunnel.enabled` | `true` | Disable zrok tunnel |
158
+ | — | — | `autoStart` | `true` | Bridge auto-starts server if not running |
159
+ | — | — | `autoShutdown` | `false` | Server shuts down when idle |
160
+ | — | — | `shutdownIdleSeconds` | `300` | Seconds idle before auto-shutdown |
161
+ | — | — | `spawnStrategy` | `"headless"` | Session spawn mode: `"headless"` or `"tmux"` |
162
+ | — | — | `devBuildOnReload` | `false` | Rebuild client + restart server on `/reload` |
163
+
164
+ The bridge also honours `PI_DASHBOARD_URL=ws://host:port` to point at a remote server instead of localhost.
165
+
166
+ ### Minimal `config.json`
194
167
 
195
168
  ```json
196
169
  {
@@ -211,22 +184,56 @@ Tool path overrides (optional, machine-local): **`~/.pi/dashboard/tool-overrides
211
184
  }
212
185
  ```
213
186
 
214
- **OpenSpec background polling** (`openspec` block):
187
+ ### Authentication (optional)
188
+
189
+ OAuth2 authentication guards external (tunnel) access. Localhost is always unguarded.
190
+
191
+ ```json
192
+ {
193
+ "auth": {
194
+ "secret": "auto-generated-if-omitted",
195
+ "providers": {
196
+ "github": { "clientId": "...", "clientSecret": "..." },
197
+ "google": { "clientId": "...", "clientSecret": "..." },
198
+ "keycloak": { "clientId": "...", "clientSecret": "...", "issuerUrl": "https://keycloak.example.com/realms/myrealm" }
199
+ },
200
+ "allowedUsers": ["octocat", "user@example.com", "*@company.com"]
201
+ }
202
+ }
203
+ ```
204
+
205
+ | Key | Required | Description |
206
+ |-----|----------|-------------|
207
+ | `auth.secret` | No | JWT signing secret (auto-generated if omitted) |
208
+ | `auth.providers` | Yes | Map of provider → `{ clientId, clientSecret, issuerUrl? }` |
209
+ | `auth.allowedUsers` | No | Allowlist: usernames, emails, or `*@domain` wildcards. Empty = allow all |
210
+
211
+ **Supported providers:** `github`, `google`, `keycloak`, `oidc` (generic OIDC with `issuerUrl`).
212
+
213
+ **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).
214
+
215
+ ### Tunnel (zrok)
216
+
217
+ 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.
218
+
219
+ ### OpenSpec background polling
220
+
221
+ Tune how often the server polls known directories for OpenSpec updates (`openspec` block):
215
222
 
216
223
  | Key | Default | Range | Description |
217
224
  |-----|---------|-------|-------------|
218
- | `pollIntervalSeconds` | `30` | `5–3600` | How often each known directory is polled for OpenSpec updates |
219
- | `maxConcurrentSpawns` | `3` | `1–16` | Cap on concurrent `openspec` CLI invocations across all directories |
220
- | `changeDetection` | `"mtime"` | `"mtime" \| "always"` | `mtime` skips re-polling unchanged proposals (near-zero steady-state cost); `always` polls unconditionally |
221
- | `jitterSeconds` | `5` | `0–60` | Per-directory phase offset so polls don't all align on the same tick |
225
+ | `pollIntervalSeconds` | `30` | `5–3600` | How often each known directory is polled |
226
+ | `maxConcurrentSpawns` | `3` | `1–16` | Cap on concurrent `openspec` CLI invocations |
227
+ | `changeDetection` | `"mtime"` | `"mtime" \| "always"` | `mtime` skips unchanged proposals; `always` polls unconditionally |
228
+ | `jitterSeconds` | `5` | `0–60` | Per-directory phase offset so polls don't align on the same tick |
222
229
 
223
230
  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.
224
231
 
225
- ### Tool resolution & overrides
232
+ ### Tool overrides
226
233
 
227
- 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 of which strategies were tried and why each succeeded or failed.
234
+ 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.
228
235
 
229
- **Inspecting and overriding** — Settings → General → **Tools** shows every resolved tool, its source, and the trail. You can set a per-tool override path, rescan a single tool or all of them, and export the full diagnostic report for bug reports.
236
+ **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.
230
237
 
231
238
  **Overrides file** — `~/.pi/dashboard/tool-overrides.json`:
232
239
 
@@ -240,241 +247,216 @@ The dashboard resolves every external tool it calls (`pi`, `pi-coding-agent`, `o
240
247
  }
241
248
  ```
242
249
 
243
- The file is deliberately separate from `config.json` so machine-specific paths don't follow a dotfiles sync to another host. Invalid overrides (path doesn't exist) are recorded in the diagnostic trail and the registry falls through to the next strategy automatically.
244
-
245
- **Troubleshooting** — if the dashboard says it can't find `pi`, `openspec`, `npm`, or any other tool, 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.
250
+ 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.
246
251
 
247
- **Troubleshooting: sessions don't group under my pinned folder** — since v0.3+, session grouping uses OS-aware path equality (`platform/paths.ts`). Sessions group correctly under a pinned folder even when the path stored on pin and the path reported by the session differ in trailing separator, separator style, or case (on Windows and macOS). 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 behavior, not a bug. If the paths really are the same filesystem, file an issue with both the pinned path (visible in Settings → Tools → Export diagnostics) and the session `cwd` as reported in `/api/sessions`.
252
+ ---
248
253
 
249
- ### Windows session durability
254
+ ## Usage
250
255
 
251
- **Behavior change**: Since the `consolidate-windows-spawn-and-platform-handlers` release, pi sessions on Windows now **survive dashboard server restart**, matching macOS/Linux behavior. Previously, killing or restarting the dashboard process (Task Manager, Ctrl+C, `/api/restart`, crash) would terminate 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 — the Windows equivalent of Unix PGID detachment.
256
+ ### Auto-start (default)
252
257
 
253
- 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` via the REST API).
258
+ 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`.
254
259
 
255
- **Recommended: install Windows Terminal** (`wt.exe`) for tabbed interactive sessions on Windows 10/11. The dashboard prefers `wt` when available (new tab in an existing WT window, respects your default profile — cmd / PowerShell / WSL / whatever), and falls back to WSL tmux and then headless mode when absent. Windows Terminal is bundled with Windows 11; on Windows 10 install it from the Microsoft Store (search for "Windows Terminal").
260
+ ### Daemon mode
256
261
 
257
- **Troubleshooting: Windows Terminal tab doesn't appear** — 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.
262
+ ```bash
263
+ pi-dashboard start # background daemon (production)
264
+ pi-dashboard start --dev # dev mode (proxy to Vite, fallback to production build)
265
+ pi-dashboard stop # stop daemon (also kills stale port holders)
266
+ pi-dashboard restart # restart (production)
267
+ pi-dashboard restart --dev # restart in dev mode
268
+ pi-dashboard status # daemon status
269
+ ```
258
270
 
259
- ### Authentication (Optional)
271
+ Daemon stdout/stderr is logged to `~/.pi/dashboard/server.log` (append mode with timestamped headers per start).
260
272
 
261
- Add an `auth` section to enable OAuth2 authentication for external (tunnel) access. Localhost is always unguarded.
273
+ ### Manual server start
262
274
 
263
- ```json
264
- {
265
- "auth": {
266
- "secret": "auto-generated-if-omitted",
267
- "providers": {
268
- "github": {
269
- "clientId": "your-github-client-id",
270
- "clientSecret": "your-github-client-secret"
271
- },
272
- "google": {
273
- "clientId": "your-google-client-id",
274
- "clientSecret": "your-google-client-secret"
275
- },
276
- "keycloak": {
277
- "clientId": "your-keycloak-client-id",
278
- "clientSecret": "your-keycloak-client-secret",
279
- "issuerUrl": "https://keycloak.example.com/realms/myrealm"
280
- }
281
- },
282
- "allowedUsers": ["octocat", "user@example.com", "*@company.com"]
283
- }
284
- }
275
+ ```bash
276
+ npx tsx packages/server/src/cli.ts
277
+ npx tsx packages/server/src/cli.ts --port 8000 --pi-port 9999
278
+ npx tsx packages/server/src/cli.ts --dev # proxy to Vite dev server
285
279
  ```
286
280
 
287
- | Key | Required | Description |
288
- |-----|----------|-------------|
289
- | `auth.secret` | No | JWT signing secret (auto-generated if omitted) |
290
- | `auth.providers` | Yes | Map of provider name → `{ clientId, clientSecret, issuerUrl? }` |
291
- | `auth.allowedUsers` | No | User allowlist: usernames, emails, or `*@domain` wildcards. Empty = allow all |
281
+ ### Graceful restart via API
292
282
 
293
- **Supported providers:** `github`, `google`, `keycloak`, `oidc` (generic OIDC with `issuerUrl`).
283
+ ```bash
284
+ # Restart in the same mode
285
+ curl -X POST http://localhost:8000/api/restart
294
286
 
295
- **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).
287
+ # Switch to dev / production
288
+ curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":true}'
289
+ curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":false}'
296
290
 
297
- **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.
291
+ # Check current mode
292
+ curl -s http://localhost:8000/api/health | jq .mode
293
+ ```
298
294
 
299
- **Precedence:** CLI flags environment variables config file built-in defaults.
295
+ 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).
300
296
 
301
- | CLI Flag | Env Var | Config Key | Default | Description |
302
- |----------|---------|------------|---------|-------------|
303
- | `--port` | `PI_DASHBOARD_PORT` | `port` | `8000` | HTTP + Browser WebSocket port |
304
- | `--pi-port` | `PI_DASHBOARD_PI_PORT` | `piPort` | `9999` | Pi extension WebSocket port |
305
- | `--dev` | — | — | `false` | Development mode (proxy to Vite) |
306
- | `--no-tunnel` | — | `tunnel.enabled` | `true` | Disable zrok tunnel |
307
- | — | — | `autoStart` | `true` | Bridge auto-starts server if not running |
308
- | — | — | `autoShutdown` | `false` | Server shuts down when idle |
309
- | — | — | `shutdownIdleSeconds` | `300` | Seconds idle before auto-shutdown |
310
- | — | — | `spawnStrategy` | `"headless"` | Session spawn mode: `"headless"` or `"tmux"` |
311
- | — | — | `devBuildOnReload` | `false` | Rebuild client + restart server on `/reload` |
297
+ ### Dev mode with production fallback
312
298
 
313
- ### Override the server URL
299
+ 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/`:
314
300
 
315
- By default the bridge connects to `ws://localhost:{piPort}`. To point at a remote server:
301
+ - `pi-dashboard start --dev` **always works** no 502 errors
302
+ - Start/stop Vite independently without restarting the dashboard
303
+ - Start Vite later and refresh the browser to get HMR
316
304
 
317
- ```bash
318
- PI_DASHBOARD_URL=ws://192.168.1.100:9999 pi
305
+ ### Dev build on reload
306
+
307
+ Set `"devBuildOnReload": true` in `config.json` for a one-command full-stack refresh:
308
+
309
+ ```
310
+ /reload → build client → stop server → reload extension → auto-start fresh server
319
311
  ```
320
312
 
321
- ## Installation Methods
313
+ > Blocks pi for ~2–5s during the build. The server shutdown affects all connected sessions — they auto-reconnect when one restarts the server.
322
314
 
323
- ### Electron Desktop App (standalone)
315
+ ### Session spawning
324
316
 
325
- 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).
317
+ **Headless** (default)runs pi as a background process with no terminal attached. Interaction through the web UI.
326
318
 
327
- ### From npm (recommended for CLI users)
319
+ **tmux** runs pi inside a tmux session named `pi-dashboard`, each spawned session as a new window:
328
320
 
329
321
  ```bash
330
- # pi
331
- pi install npm:@blackbelt-technology/pi-agent-dashboard
332
-
333
- # Oh My Pi
334
- omp install npm:@blackbelt-technology/pi-agent-dashboard
322
+ tmux attach -t pi-dashboard # attach
323
+ tmux list-windows -t pi-dashboard # list windows
324
+ # inside tmux: Ctrl-b n / p / w # next / prev / picker
335
325
  ```
336
326
 
337
- > 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.
327
+ Switch with `"spawnStrategy": "tmux"` in `~/.pi/dashboard/config.json`.
338
328
 
339
- ### Local development install
329
+ ### Keyboard shortcuts in chat input
340
330
 
341
- ```bash
342
- cd /path/to/pi-agent-dashboard
343
- npm install
331
+ Bash-style history recall and per-session draft persistence:
344
332
 
345
- # Global install
346
- pi install /path/to/pi-agent-dashboard
333
+ | Key | Action |
334
+ |-----|--------|
335
+ | `Enter` | Send the prompt |
336
+ | `Shift+Enter` | Insert a newline |
337
+ | `ArrowUp` | Recall previous user prompt (caret on first line, no dropdown open). Repeat to walk back |
338
+ | `ArrowDown` | Walk forward through history (caret on last line). Past the newest entry, restores the in-progress draft |
339
+ | `Escape` | Restore in-progress draft and exit history mode; also cancels pending prompt / dismisses dropdown |
340
+ | `Tab` / `Enter` in dropdown | Accept the highlighted `/command` or `@file` suggestion |
347
341
 
348
- # Or project-local only
349
- pi install -l /path/to/pi-agent-dashboard
350
- ```
342
+ 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.
351
343
 
352
- Pi reads the `pi.extensions` field from `package.json` and loads the bridge extension automatically.
344
+ ---
353
345
 
354
- ### Manual settings entry
346
+ ## Recommended extensions
355
347
 
356
- Add the package path directly to your settings file:
348
+ 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.
357
349
 
358
- **Global** (`~/.pi/agent/settings.json`):
359
- ```json
360
- {
361
- "packages": ["/path/to/pi-agent-dashboard"]
362
- }
363
- ```
350
+ | Extension | Source | Status | Unlocks |
351
+ |---|---|---|---|
352
+ | `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. |
353
+ | `@tintinweb/pi-subagents` | `npm:@tintinweb/pi-subagents` | strongly suggested | `Agent` tool card UI, subagent activity badge, `get_subagent_result` / `steer_subagent` renderers |
354
+ | `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 |
355
+ | `pi-web-access` | `npm:pi-web-access` | strongly suggested | `web_search`, `code_search`, `fetch_content`, `get_search_content` |
356
+ | `pi-agent-browser` | `npm:pi-agent-browser` | optional | `browser` tool (open, snapshot, click, screenshot) |
364
357
 
365
- **Project-local** (`.pi/settings.json`):
366
- ```json
367
- {
368
- "packages": ["/path/to/pi-agent-dashboard"]
369
- }
370
- ```
358
+ Authoritative source: `packages/shared/src/recommended-extensions.ts`. Descriptions, versions, and installed-state are enriched live via `GET /api/packages/recommended` (offline fallback).
371
359
 
372
- ### Removing
360
+ ---
373
361
 
374
- ```bash
375
- pi remove /path/to/pi-agent-dashboard
376
- ```
362
+ ## Troubleshooting
377
363
 
378
- ## Usage
364
+ ### Dashboard server doesn't start
379
365
 
380
- ### Auto-start (default)
366
+ If `pi` launches but the dashboard never becomes reachable, inspect the launch log:
381
367
 
382
- The bridge extension **automatically starts the dashboard server** when pi launches if it's not already running. No separate terminal needed.
368
+ ```bash
369
+ cat ~/.pi/dashboard/server.log # Linux / macOS
370
+ type %USERPROFILE%\.pi\dashboard\server.log # Windows
371
+ ```
383
372
 
384
- To disable: set `"autoStart": false` in `~/.pi/dashboard/config.json`.
373
+ The log is append-mode with timestamped headers per start attempt, so previous crashes are preserved. Common issues:
385
374
 
386
- ### Manual server start
375
+ - **`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.
376
+ - **`Cannot find pi's TypeScript loader`** — pi is not installed globally. Run `npm install -g @mariozechner/pi-coding-agent`.
377
+ - **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+.
387
378
 
388
- ```bash
389
- npx tsx packages/server/src/cli.ts
390
- npx tsx packages/server/src/cli.ts --port 8000 --pi-port 9999
391
- npx tsx packages/server/src/cli.ts --dev # proxy to Vite dev server
392
- ```
379
+ ### Port already in use
393
380
 
394
- ### Daemon mode
381
+ - **Windows:** `netstat -ano | findstr :8000` then `taskkill /F /PID <pid>`
382
+ - **Unix:** `lsof -t -i :8000 | xargs kill`
383
+ - Or change `port` in `~/.pi/dashboard/config.json`.
395
384
 
396
- ```bash
397
- pi-dashboard start # Start as background daemon (production)
398
- pi-dashboard start --dev # Start in dev mode (proxy to Vite, fallback to production build)
399
- pi-dashboard stop # Stop running daemon (also kills stale port holders)
400
- pi-dashboard restart # Restart daemon (production)
401
- pi-dashboard restart --dev # Restart in dev mode
402
- pi-dashboard status # Show daemon status
403
- ```
385
+ ### UI is empty or stuck after switching servers
404
386
 
405
- Daemon stdout/stderr is logged to `~/.pi/dashboard/server.log` for crash diagnosis.
387
+ 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.
406
388
 
407
- ### Keyboard shortcuts in chat input
389
+ 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.
408
390
 
409
- The chat input supports bash-style history recall and per-session draft persistence:
391
+ 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.
410
392
 
411
- | Key | Action |
412
- |-----|--------|
413
- | `Enter` | Send the prompt. |
414
- | `Shift+Enter` | Insert a newline. |
415
- | `ArrowUp` | Recall the previous user prompt (only when the caret is on the first line and no autocomplete dropdown is open). Repeat to walk further back. |
416
- | `ArrowDown` | Walk forward through history (only when the caret is on the last line). Past the newest entry, restores the in-progress draft. |
417
- | `Escape` | While navigating history, restore the in-progress draft and exit history mode. Also cancels a pending prompt or dismisses the autocomplete dropdown. |
418
- | `Tab` / `Enter` in dropdown | Accept the highlighted `/command` or `@file` suggestion. |
393
+ ### Windows: sessions die when the dashboard restarts
419
394
 
420
- Drafts (typed-but-unsent text) are persisted per session in `localStorage` under `chat-draft:<sessionId>` and survive navigation (Settings, OpenSpec preview, file diffs, ...) as well as full page reloads. Drafts never leak between sessions.
395
+ 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.
421
396
 
422
- ### Graceful restart via API
397
+ 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`).
423
398
 
424
- Restart without CLI useful from scripts, other sessions, or the dashboard skill:
399
+ ### Windows Terminal tab doesn't appear
425
400
 
426
- ```bash
427
- # Restart in same mode (preserves current dev/prod)
428
- curl -X POST http://localhost:8000/api/restart
401
+ 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.
429
402
 
430
- # Switch to dev mode
431
- curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":true}'
403
+ 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.
432
404
 
433
- # Switch to production mode
434
- curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":false}'
405
+ ### Sessions don't group under my pinned folder
435
406
 
436
- # Check current mode
437
- curl -s http://localhost:8000/api/health | jq .mode
438
- ```
407
+ 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).
439
408
 
440
- 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`.
409
+ 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`.
441
410
 
442
- ### Dev mode with production fallback
411
+ ### Tool not found (pi / openspec / npm / …)
443
412
 
444
- 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:
413
+ 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.
445
414
 
446
- - `pi-dashboard start --dev` **always works** — no 502 errors
447
- - Start/stop Vite independently without restarting the dashboard
448
- - Seamless transition: start Vite later and refresh the browser to get HMR
415
+ ### Recommended extensions: "Permission denied (publickey)"
449
416
 
450
- ### Session spawning
417
+ `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.
451
418
 
452
- The dashboard can spawn new pi sessions from the browser. Two strategies are available:
419
+ ---
453
420
 
454
- **Headless** (default) — Runs pi as a background process with no terminal attached. Interaction happens entirely through the dashboard web UI.
421
+ ## Architecture
455
422
 
456
- **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:
423
+ ```mermaid
424
+ graph LR
425
+ subgraph "Per pi session"
426
+ B[Bridge Extension]
427
+ end
457
428
 
458
- ```bash
459
- # Attach to the pi-dashboard tmux session
460
- tmux attach -t pi-dashboard
429
+ subgraph "Dashboard Server (Node.js)"
430
+ PG[Pi Gateway :9999]
431
+ BG[Browser Gateway :8000]
432
+ HTTP[HTTP / Static Files]
433
+ MEM[(In-Memory Store)]
434
+ JSON[(JSON Files)]
435
+ end
461
436
 
462
- # List all windows (each is a spawned pi session)
463
- tmux list-windows -t pi-dashboard
437
+ subgraph "Browser"
438
+ UI[React Web Client]
439
+ end
464
440
 
465
- # Switch between windows inside tmux
466
- Ctrl-b n # next window
467
- Ctrl-b p # previous window
468
- Ctrl-b w # interactive window picker
441
+ B <-->|WebSocket| PG
442
+ UI <-->|WebSocket| BG
443
+ UI -->|HTTP| HTTP
444
+ PG --- MEM
445
+ PG --- JSON
446
+ BG --- MEM
469
447
  ```
470
448
 
471
- To switch strategy, set `spawnStrategy` in `~/.pi/dashboard/config.json`:
449
+ | Component | Location | Role |
450
+ |-----------|----------|------|
451
+ | **Bridge Extension** | `packages/extension/` | Runs in every pi session. Forwards events, relays commands, auto-starts server, hosts PromptBus. |
452
+ | **Dashboard Server** | `packages/server/` | Aggregates events in-memory, persists metadata to JSON, serves the web client, manages terminals. |
453
+ | **Web Client** | `packages/client/` | React + Tailwind UI with real-time WebSocket updates. |
454
+ | **Shared** | `packages/shared/` | TypeScript types, protocols, and utilities shared across all packages. |
455
+ | **Plugin Runtime** | `packages/dashboard-plugin-runtime/` | Plugin loader, slot registry, slot consumers, plugin context API, and Vite plugin. |
472
456
 
473
- ```json
474
- {
475
- "spawnStrategy": "tmux"
476
- }
477
- ```
457
+ First-party features can live as separate monorepo packages by declaring a `pi-dashboard-plugin` field in their `package.json`. The Vite plugin auto-discovers these manifests at build time and generates a static registry (`packages/client/src/generated/plugin-registry.tsx`) using named imports for tree-shaking. During server startup, `loadServerEntries()` dynamic-imports each plugin's server entry and invokes `registerPlugin(ctx: ServerPluginContext)`. See [docs/architecture.md](docs/architecture.md#plugin-architecture) for the full plugin data flow.
458
+
459
+ See [docs/architecture.md](docs/architecture.md) for detailed data flows, reconnection logic, and persistence model.
478
460
 
479
461
  ### Auto-start flow
480
462
 
@@ -493,15 +475,25 @@ flowchart TD
493
475
 
494
476
  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`.
495
477
 
496
- ### Dev build on reload
478
+ ---
497
479
 
498
- Set `"devBuildOnReload": true` in `config.json` for a one-command full-stack refresh:
480
+ ## Monitoring
499
481
 
482
+ The health endpoint provides server and agent process metrics:
483
+
484
+ ```bash
485
+ curl -s http://localhost:8000/api/health | jq
500
486
  ```
501
- /reload → build client → stop server → reload extension → auto-start fresh server
502
- ```
503
487
 
504
- > **Note:** Blocks pi for ~2–5s during the build. The server shutdown affects all connected sessions — they auto-reconnect when one restarts the server.
488
+ Returns:
489
+ - `mode` — `"dev"` or `"production"`
490
+ - `server.rss`, `server.heapUsed`, `server.heapTotal` — server memory
491
+ - `server.activeSessions`, `server.totalSessions` — session counts
492
+ - `agents[]` — per-agent metrics (CPU%, RSS, heap, event loop max delay, system load)
493
+
494
+ Agent metrics are collected every 15s via heartbeats and include `eventLoopMaxMs` — useful for diagnosing connection drops during long-running operations.
495
+
496
+ ---
505
497
 
506
498
  ## Development
507
499
 
@@ -536,8 +528,6 @@ pi -e packages/extension/src/bridge.ts # or just `pi` if installed
536
528
 
537
529
  ### Deploy after changes
538
530
 
539
- The `pi-dashboard` command is available globally when the package is installed. After making changes, restart the appropriate components:
540
-
541
531
  ```bash
542
532
  # After client changes (production mode)
543
533
  npm run build
@@ -547,142 +537,15 @@ curl -X POST http://localhost:8000/api/restart
547
537
  curl -X POST http://localhost:8000/api/restart
548
538
 
549
539
  # After bridge extension changes
550
- npm run reload # Reload all connected pi sessions
540
+ npm run reload
551
541
 
552
542
  # Full rebuild (e.g., after pulling updates)
553
543
  npm run build
554
544
  curl -X POST http://localhost:8000/api/restart
555
545
  npm run reload
556
-
557
- # Switch between dev and production mode
558
- curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":true}'
559
- curl -X POST http://localhost:8000/api/restart -H 'Content-Type: application/json' -d '{"dev":false}'
560
- ```
561
-
562
- ### Project Structure
563
-
564
- The project is a monorepo with npm workspaces:
565
-
566
- ```
567
- packages/
568
- ├── shared/ # Shared TypeScript types & utilities
569
- │ └── src/
570
- │ ├── protocol.ts # Extension ↔ Server messages
571
- │ ├── browser-protocol.ts # Server ↔ Browser messages (incl. PromptBus types)
572
- │ ├── types.ts # Data models
573
- │ ├── config.ts # Shared config loader
574
- │ ├── rest-api.ts # REST API types
575
- │ ├── session-meta.ts # Session metadata sidecar (.meta.json) read/write
576
- │ ├── state-replay.ts # Event synthesis on reconnect
577
- │ ├── stats-extractor.ts # Token/cost stats extraction
578
- │ ├── server-identity.ts # Server detection & identity
579
- │ ├── mdns-discovery.ts # mDNS network auto-discovery
580
- │ └── openspec-poller.ts # OpenSpec change data polling
581
- ├── extension/ # Bridge extension (runs in pi)
582
- │ └── src/
583
- │ ├── bridge.ts # Main extension entry
584
- │ ├── connection.ts # WebSocket with reconnection
585
- │ ├── event-forwarder.ts # Event mapping
586
- │ ├── flow-event-wiring.ts # pi-flows event forwarding
587
- │ ├── prompt-bus.ts # PromptBus — unified prompt routing with adapters
588
- │ ├── dashboard-default-adapter.ts # Default PromptBus adapter for dashboard UI
589
- │ ├── prompt-expander.ts # Prompt template expansion from disk
590
- │ ├── provider-register.ts # Provider auth registration & sync
591
- │ ├── model-tracker.ts # Model selection tracking
592
- │ ├── source-detector.ts # Session source detection (via .meta.json sidecar)
593
- │ ├── command-handler.ts # Command relay
594
- │ ├── server-probe.ts # TCP probe for server detection
595
- │ ├── server-auto-start.ts # Auto-start logic on session launch
596
- │ ├── server-launcher.ts # Spawn server as detached process
597
- │ ├── session-sync.ts # Session history sync
598
- │ ├── process-metrics.ts # Agent process CPU/memory metrics
599
- │ ├── process-scanner.ts # Running process detection
600
- │ ├── git-info.ts # Git branch/remote/PR detection
601
- │ ├── git-link-builder.ts # GitHub/GitLab permalink generation
602
- │ └── dev-build.ts # Dev build-on-reload helper
603
- ├── server/ # Dashboard server
604
- │ └── src/
605
- │ ├── cli.ts # CLI entry (start/stop/restart/status)
606
- │ ├── server.ts # HTTP + WebSocket server
607
- │ ├── pi-gateway.ts # Extension WebSocket gateway
608
- │ ├── browser-gateway.ts # Browser WebSocket gateway
609
- │ ├── memory-event-store.ts # In-memory event buffer (LRU, per-session cap, truncation)
610
- │ ├── memory-session-manager.ts # In-memory session registry
611
- │ ├── preferences-store.ts # User prefs: hidden sessions, pinned dirs
612
- │ ├── meta-persistence.ts # Session metadata persistence
613
- │ ├── session-order-manager.ts # Per-cwd session ordering
614
- │ ├── session-discovery.ts # Session file scanning & loading
615
- │ ├── process-manager.ts # tmux/headless session spawning
616
- │ ├── headless-pid-registry.ts # Track headless process PIDs
617
- │ ├── editor-registry.ts # Available editor detection
618
- │ ├── editor-manager.ts # Editor launch & file opening
619
- │ ├── provider-auth-storage.ts # Provider credential persistence
620
- │ ├── provider-auth-handlers.ts # OAuth flow handlers
621
- │ ├── npm-search-proxy.ts # npm registry search proxy
622
- │ ├── package-manager-wrapper.ts # pi package install/remove
623
- │ ├── pending-fork-registry.ts # Flow fork decision persistence
624
- │ ├── tunnel.ts # Zrok tunnel with reserved shares
625
- │ ├── terminal-manager.ts # Browser terminal sessions (xterm.js + node-pty)
626
- │ ├── server-pid.ts # PID file for daemon management
627
- │ ├── auth.ts # OAuth2 authentication
628
- │ └── json-store.ts # Atomic JSON file helpers
629
- ├── client/ # React web client
630
- │ └── src/
631
- │ ├── App.tsx
632
- │ ├── hooks/ # WebSocket hooks, mobile detection
633
- │ ├── lib/ # Event reducer, command filter
634
- │ └── components/ # UI components
635
- │ ├── FlowDashboard.tsx # Live flow execution view
636
- │ ├── FlowAgentCard.tsx # Per-agent status cards
637
- │ ├── FlowGraph.tsx # DAG visualization
638
- │ ├── FlowArchitect.tsx # Flow designer UI
639
- │ ├── FlowSummary.tsx # Post-flow result summary
640
- │ ├── DiffView.tsx # Side-by-side diff viewer
641
- │ ├── TerminalView.tsx # Browser terminal emulator
642
- │ ├── PackageBrowser.tsx # Package search & install
643
- │ ├── ProviderAuthSection.tsx # Provider sign-in UI
644
- │ ├── SettingsPanel.tsx # Config editor
645
- │ └── ... # 80+ components
646
- └── electron/ # Electron desktop app wrapper
647
- ├── src/main.ts
648
- ├── scripts/
649
- └── resources/
650
- ```
651
-
652
- ## Monitoring
653
-
654
- The health endpoint provides server and agent process metrics:
655
-
656
- ```bash
657
- curl -s http://localhost:8000/api/health | jq
658
546
  ```
659
547
 
660
- Returns:
661
- - `mode` — `"dev"` or `"production"`
662
- - `server.rss`, `server.heapUsed`, `server.heapTotal` — server memory
663
- - `server.activeSessions`, `server.totalSessions` — session counts
664
- - `agents[]` — per-agent metrics (CPU%, RSS, heap, event loop max delay, system load)
665
-
666
- Agent metrics are collected every 15s via heartbeats and include `eventLoopMaxMs` — useful for diagnosing connection drops during long-running operations.
667
-
668
- ### Troubleshooting: dashboard server doesn't start
669
-
670
- If `pi` launches but the dashboard never becomes reachable (no `http://localhost:8000`, no `🌐 Dashboard started` notification), inspect the launch log:
671
-
672
- ```bash
673
- cat ~/.pi/dashboard/server.log # Linux / macOS
674
- type %USERPROFILE%\.pi\dashboard\server.log # Windows
675
- ```
676
-
677
- The log is opened in append mode and prefixed with a timestamped header on every start attempt, so previous crashes are preserved. Common issues:
678
-
679
- - **`ERR_UNSUPPORTED_ESM_URL_SCHEME` on Windows** — fixed in pi-agent-dashboard 0.2.10+; upgrade the package.
680
- - **`Port 8000 is occupied by another service`** — another process is bound to the port. On Windows: `netstat -ano | findstr :8000` then `taskkill /F /PID <pid>`. On Unix: `lsof -t -i :8000 | xargs kill`. Or change `port` in `~/.pi/dashboard/config.json`.
681
- - **`Cannot find pi's TypeScript loader`** — pi is not installed globally. Run `npm install -g @mariozechner/pi-coding-agent`.
682
-
683
- The `POST /api/restart` endpoint and `pi-dashboard restart` command work identically on Windows, macOS, and Linux (no `sh`/`lsof`/`curl` dependency).
684
-
685
- ## Extension UI Events
548
+ ### Extension UI events
686
549
 
687
550
  Your own extensions can broadcast UI events to the dashboard:
688
551
 
@@ -696,40 +559,40 @@ pi.events.emit("dashboard:ui", {
696
559
 
697
560
  Supported methods: `confirm`, `select`, `input`, `notify`.
698
561
 
699
- ## Electron Desktop App
700
-
701
- 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.
702
-
703
- The Electron app supports two modes:
562
+ ### Project structure
704
563
 
705
- | Mode | Description |
706
- |------|-------------|
707
- | **Standalone** | Bundles Node.js, auto-installs pi + dashboard into `~/.pi-dashboard/`. Zero prerequisites. |
708
- | **Power User** | Detects and uses your existing system pi + dashboard install. |
564
+ Monorepo with npm workspaces — top-level layout only. See [AGENTS.md](AGENTS.md) for the full file-by-file index.
709
565
 
710
- Features: first-run setup wizard, auto-update checker, system tray, splash screen, VM detection (disables GPU acceleration), mDNS server discovery, and version compatibility checks.
566
+ ```
567
+ packages/
568
+ ├── shared/ # Shared TypeScript types, protocols, config, session-meta helpers
569
+ ├── extension/ # Bridge extension (runs inside pi) — WS client, PromptBus, event forwarding, auto-start
570
+ ├── server/ # Dashboard server — HTTP + dual WebSocket gateways, in-memory store, terminals, auth, tunnel
571
+ ├── client/ # React + Tailwind web client — 80+ components, hooks, event reducer
572
+ └── electron/ # Electron desktop wrapper — wizard, system tray, auto-update, bundled Node.js
573
+ ```
711
574
 
712
- ### Building from Source
575
+ ---
713
576
 
714
- > **Prerequisites for building:** Node.js 22.12+, platform-specific tools handled by Electron Forge automatically.
577
+ ## Building the Electron app
715
578
 
716
- ### Building for Your Platform
579
+ > **Prerequisites:** Node.js 22.12+; platform-specific tools handled by Electron Forge automatically.
717
580
 
718
- The easiest way — one command that handles everything (client build, Node.js bundling, installer creation):
581
+ ### Native build (current platform)
719
582
 
720
583
  ```bash
721
- npm run electron:build # Build for current platform & arch
722
- npm run electron:build -- --arch x64 # Override architecture
723
- npm run electron:build -- --skip-client # Skip client rebuild
584
+ npm run electron:build # Build for current platform & arch
585
+ npm run electron:build -- --arch x64 # Override architecture
586
+ npm run electron:build -- --skip-client # Skip client rebuild
724
587
  ```
725
588
 
726
589
  Or step by step:
727
590
 
728
591
  ```bash
729
- npm run build # Build web client
592
+ npm run build # Build web client
730
593
  cd packages/electron
731
- bash scripts/download-node.sh # Download Node.js for bundling
732
- npm run make # Build installer
594
+ bash scripts/download-node.sh # Download Node.js for bundling
595
+ npm run make # Build installer
733
596
  ```
734
597
 
735
598
  Output by platform:
@@ -738,25 +601,22 @@ Output by platform:
738
601
  |----------|--------|----------|
739
602
  | macOS | `.dmg` | `packages/electron/out/make/` |
740
603
  | Linux | `.deb` + `.AppImage` | `packages/electron/out/make/` |
741
- | Windows | `.exe` (NSIS installer) + `.zip` + portable `.exe` | `packages/electron/out/make/` |
604
+ | Windows | `.exe` (NSIS) + `.zip` + portable `.exe` | `packages/electron/out/make/` |
742
605
 
743
- ### Cross-Platform Builds (via Docker)
606
+ ### Cross-platform builds (Docker)
744
607
 
745
- From macOS or Linux, you can build installers for **all platforms** using Docker:
608
+ From macOS or Linux, build installers for all platforms:
746
609
 
747
610
  ```bash
748
- npm run electron:build -- --all # macOS (native) + Linux + Windows (Docker)
749
- npm run electron:build -- --linux # Linux .deb + .AppImage only
750
- npm run electron:build -- --windows # Windows .exe (NSIS) only
611
+ npm run electron:build -- --all # macOS (native) + Linux + Windows (Docker)
612
+ npm run electron:build -- --linux # Linux .deb + .AppImage only
613
+ npm run electron:build -- --windows # Windows .exe (NSIS) only
751
614
  npm run electron:build -- --linux --windows # Both, skip native
752
615
  ```
753
616
 
754
- Docker builds use a Node 22 Debian container with NSIS installed for Windows cross-compilation.
755
- All output goes to `packages/electron/out/make/`.
756
-
757
- > **Note:** Native builds (no flags) build for the current platform only. Docker is required for `--linux`, `--windows`, and `--all`.
617
+ Docker builds use a Node 22 Debian container with NSIS installed for Windows cross-compilation. Output goes to `packages/electron/out/make/`.
758
618
 
759
- ### Development Mode
619
+ ### Electron dev mode
760
620
 
761
621
  ```bash
762
622
  # Start the dashboard server and Vite dev server first
@@ -768,7 +628,7 @@ cd packages/electron
768
628
  npm run start:dev
769
629
  ```
770
630
 
771
- ### Regenerating Icons
631
+ ### Regenerating icons
772
632
 
773
633
  All platform icon variants are generated from the master icon at `packages/electron/resources/icon.png`:
774
634
 
@@ -777,9 +637,31 @@ cd packages/electron
777
637
  npm run icons # Generates .icns (macOS), .ico (Windows), and resized PNGs
778
638
  ```
779
639
 
780
- ### CI Builds & GitHub Releases
640
+ ---
641
+
642
+ ## CI/CD & releasing
643
+
644
+ See [`docs/release-process.md`](docs/release-process.md) for the full cut-a-release workflow.
645
+
646
+ ### Continuous integration
781
647
 
782
- The release workflow (`.github/workflows/publish.yml`) builds Electron installers for **all platforms** on every version tag (`v*`):
648
+ Every push to `develop` and every pull request against `develop` triggers [`ci.yml`](.github/workflows/ci.yml):
649
+
650
+ 1. `npm ci` — install dependencies
651
+ 2. `npm run lint` — type check
652
+ 3. `npm test` — run tests
653
+ 4. `npm run build` — build web client
654
+
655
+ ### Releasing
656
+
657
+ The publish workflow ([`publish.yml`](.github/workflows/publish.yml)) triggers on `v*` tags:
658
+
659
+ ```bash
660
+ npm version patch # or minor / major
661
+ git push --follow-tags
662
+ ```
663
+
664
+ This runs CI, publishes to npm with `--provenance` for supply-chain transparency, and builds Electron installers for all platforms on native runners:
783
665
 
784
666
  | Runner | Platform | Outputs |
785
667
  |--------|----------|---------|
@@ -789,37 +671,51 @@ The release workflow (`.github/workflows/publish.yml`) builds Electron installer
789
671
  | `windows-latest` | Windows x64 | `.exe` (NSIS) + `.zip` + portable |
790
672
  | `windows-latest` | Windows arm64 | `.zip` + portable (x64 Node.js via WoW64) |
791
673
 
792
- 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.
674
+ All artifacts are uploaded to a **draft GitHub Release**. Release notes are extracted automatically from the matching `## [<version>]` section of [`CHANGELOG.md`](CHANGELOG.md).
793
675
 
794
- ## CI/CD
676
+ ### Trusted Publisher (OIDC) setup
795
677
 
796
- ### Continuous Integration
678
+ 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.
797
679
 
798
- Every push to `develop` and every pull request against `develop` triggers the CI workflow (`.github/workflows/ci.yml`):
680
+ **Requirements** (already configured in [`publish.yml`](.github/workflows/publish.yml)):
799
681
 
800
- 1. `npm ci` — install dependencies
801
- 2. `npm run lint` — type check
802
- 3. `npm test` run tests
803
- 4. `npm run build` build web client
682
+ ```yaml
683
+ permissions:
684
+ contents: write # draft GitHub Release + tag push
685
+ id-token: write # OIDC token exchange with the npm registry
686
+ environment: npm-publish
687
+ ```
804
688
 
805
- ### Releasing to npm
689
+ Trusted Publishing requires **npm CLI ≥ 11.5.1**. The workflow upgrades npm automatically (`npm install -g npm@latest`) before publishing.
806
690
 
807
- The publish workflow (`.github/workflows/publish.yml`) triggers on `v*` tags:
691
+ **One-time npm-side setup** — repeat once per published package (five scoped workspaces; `@blackbelt-technology/pi-dashboard-electron` is private and skipped):
808
692
 
809
- ```bash
810
- npm version patch # or minor / major
811
- git push --follow-tags
812
- ```
693
+ | Package |
694
+ |---|
695
+ | `@blackbelt-technology/pi-agent-dashboard` (root) |
696
+ | `@blackbelt-technology/pi-dashboard-shared` |
697
+ | `@blackbelt-technology/pi-dashboard-extension` |
698
+ | `@blackbelt-technology/pi-dashboard-server` |
699
+ | `@blackbelt-technology/pi-dashboard-web` |
700
+
701
+ For each:
702
+
703
+ 1. Go to [npmjs.com](https://www.npmjs.com/) → the package → **Settings** → **Trusted Publisher** → **GitHub Actions**
704
+ 2. Fill in:
705
+ - **Organization or user:** `BlackBeltTechnology`
706
+ - **Repository:** `pi-agent-dashboard`
707
+ - **Workflow filename:** `publish.yml` *(filename only, not the full path)*
708
+ - **Environment name:** `npm-publish` *(must match the `environment:` field in the workflow)*
709
+ 3. Save
813
710
 
814
- This runs CI checks, then publishes to npm with `--provenance` for supply chain transparency.
711
+ **GitHub Environment (recommended)** configures an optional human-approval gate on every release:
815
712
 
816
- ### npm Token Setup
713
+ 1. GitHub repo → **Settings** → **Environments** → **New environment** → name `npm-publish`
714
+ 2. Optionally add **required reviewers** and/or **deployment branch/tag protection rules** (e.g. restrict to `v*` tags)
817
715
 
818
- The publish workflow requires an `NPM_TOKEN` secret in the GitHub repository:
716
+ No secrets to rotate, no tokens to leak.
819
717
 
820
- 1. Generate a token at [npmjs.com](https://www.npmjs.com/) → Access Tokens → Generate New Token (Granular Access Token)
821
- 2. Grant publish access to `@blackbelt-technology` packages
822
- 3. Add it as a repository secret: GitHub repo → Settings → Secrets and variables → Actions → New repository secret → Name: `NPM_TOKEN`
718
+ ---
823
719
 
824
720
  ## License
825
721