@blackbelt-technology/pi-agent-dashboard 0.5.0 → 0.5.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 (201) hide show
  1. package/AGENTS.md +26 -5
  2. package/README.md +49 -7
  3. package/docs/architecture.md +129 -1
  4. package/package.json +15 -15
  5. package/packages/extension/package.json +11 -3
  6. package/packages/extension/src/__tests__/ask-user-tool.test.ts +1 -1
  7. package/packages/extension/src/__tests__/bridge-slash-command-routing.test.ts +362 -0
  8. package/packages/extension/src/__tests__/command-handler.test.ts +78 -8
  9. package/packages/extension/src/__tests__/enrich-model-metadata.test.ts +1 -1
  10. package/packages/extension/src/__tests__/extension-slash-command-detection.test.ts +107 -0
  11. package/packages/extension/src/__tests__/no-tui-multiselect-arm-regression.test.ts +1 -1
  12. package/packages/extension/src/__tests__/prompt-expander.test.ts +110 -1
  13. package/packages/extension/src/__tests__/provider-register-reload.test.ts +74 -0
  14. package/packages/extension/src/__tests__/retry-tracker.test.ts +147 -0
  15. package/packages/extension/src/__tests__/server-launcher-launch.test.ts +78 -0
  16. package/packages/extension/src/__tests__/session-sync.test.ts +72 -0
  17. package/packages/extension/src/__tests__/usage-limit-orderer.test.ts +105 -0
  18. package/packages/extension/src/ask-user-tool.ts +1 -1
  19. package/packages/extension/src/bridge-context.ts +68 -4
  20. package/packages/extension/src/bridge.ts +79 -11
  21. package/packages/extension/src/command-handler.ts +95 -15
  22. package/packages/extension/src/flow-event-wiring.ts +1 -1
  23. package/packages/extension/src/multiselect-list.ts +1 -1
  24. package/packages/extension/src/pi-env.d.ts +16 -9
  25. package/packages/extension/src/prompt-expander.ts +74 -63
  26. package/packages/extension/src/provider-register.ts +16 -9
  27. package/packages/extension/src/retry-tracker.ts +123 -0
  28. package/packages/extension/src/server-launcher.ts +31 -70
  29. package/packages/extension/src/session-sync.ts +10 -1
  30. package/packages/extension/src/slash-dispatch.ts +123 -0
  31. package/packages/extension/src/usage-limit-orderer.ts +76 -0
  32. package/packages/server/bin/pi-dashboard.mjs +84 -0
  33. package/packages/server/package.json +8 -7
  34. package/packages/server/scripts/fix-pty-permissions.cjs +52 -0
  35. package/packages/server/src/__tests__/changelog-fs.test.ts +171 -0
  36. package/packages/server/src/__tests__/changelog-parser.test.ts +220 -0
  37. package/packages/server/src/__tests__/changelog-remote.test.ts +193 -0
  38. package/packages/server/src/__tests__/cli-parse.test.ts +16 -4
  39. package/packages/server/src/__tests__/directory-service-openspec-enabled.test.ts +187 -0
  40. package/packages/server/src/__tests__/directory-service-refresh-force.test.ts +1 -1
  41. package/packages/server/src/__tests__/directory-service-specs-mtime.test.ts +1 -1
  42. package/packages/server/src/__tests__/directory-service-toctou.test.ts +1 -1
  43. package/packages/server/src/__tests__/directory-service.test.ts +2 -2
  44. package/packages/server/src/__tests__/dispatch-extension-command-router.test.ts +178 -0
  45. package/packages/server/src/__tests__/e2e/model-proxy-google-flash.test.ts +184 -0
  46. package/packages/server/src/__tests__/event-wiring-providers-list.test.ts +68 -1
  47. package/packages/server/src/__tests__/fixtures/pi-changelog-slice.md +180 -0
  48. package/packages/server/src/__tests__/fork-empty-session-preflight.test.ts +268 -0
  49. package/packages/server/src/__tests__/headless-pid-registry.test.ts +316 -0
  50. package/packages/server/src/__tests__/is-pi-process.test.ts +1 -1
  51. package/packages/server/src/__tests__/keeper-manager.test.ts +298 -0
  52. package/packages/server/src/__tests__/legacy-pi-cleanup.test.ts +149 -0
  53. package/packages/server/src/__tests__/model-proxy-api-key-routes.test.ts +277 -0
  54. package/packages/server/src/__tests__/model-proxy-auth-gate.test.ts +263 -0
  55. package/packages/server/src/__tests__/model-proxy-multi-user.test.ts +169 -0
  56. package/packages/server/src/__tests__/model-proxy-routes.test.ts +286 -0
  57. package/packages/server/src/__tests__/model-proxy-second-port.test.ts +116 -0
  58. package/packages/server/src/__tests__/openspec-connect-snapshot.test.ts +64 -8
  59. package/packages/server/src/__tests__/openspec-group-broadcast.test.ts +97 -0
  60. package/packages/server/src/__tests__/openspec-group-join.test.ts +80 -0
  61. package/packages/server/src/__tests__/openspec-group-routes.test.ts +370 -0
  62. package/packages/server/src/__tests__/openspec-group-store.test.ts +496 -0
  63. package/packages/server/src/__tests__/package-manager-wrapper-resolve.test.ts +4 -4
  64. package/packages/server/src/__tests__/package-routes.test.ts +1 -1
  65. package/packages/server/src/__tests__/pending-fork-registry.test.ts +48 -24
  66. package/packages/server/src/__tests__/pi-ai-shape.test.ts +147 -0
  67. package/packages/server/src/__tests__/pi-changelog-integration.test.ts +165 -0
  68. package/packages/server/src/__tests__/pi-changelog-routes.test.ts +409 -0
  69. package/packages/server/src/__tests__/pi-core-checker.test.ts +155 -13
  70. package/packages/server/src/__tests__/pi-core-updater-managed-path.test.ts +62 -3
  71. package/packages/server/src/__tests__/pi-core-updater.test.ts +1 -1
  72. package/packages/server/src/__tests__/pi-dashboard-bin-wrapper.test.ts +84 -0
  73. package/packages/server/src/__tests__/pi-dev-version-check.test.ts +184 -0
  74. package/packages/server/src/__tests__/pi-version-skew.test.ts +4 -4
  75. package/packages/server/src/__tests__/process-manager-keeper-spawn.test.ts +206 -0
  76. package/packages/server/src/__tests__/provider-auth-routes.test.ts +12 -4
  77. package/packages/server/src/__tests__/provider-catalogue-cache.test.ts +13 -23
  78. package/packages/server/src/__tests__/provider-routes-recursion-guard.test.ts +131 -0
  79. package/packages/server/src/__tests__/recommended-routes.test.ts +3 -3
  80. package/packages/server/src/__tests__/spawn-correlation-token-integration.test.ts +91 -0
  81. package/packages/server/src/__tests__/spawn-register-watchdog.test.ts +84 -0
  82. package/packages/server/src/__tests__/spawn-token.test.ts +57 -0
  83. package/packages/server/src/__tests__/tunnel-watchdog.test.ts +139 -0
  84. package/packages/server/src/auth-plugin.ts +3 -0
  85. package/packages/server/src/bootstrap-state.ts +10 -0
  86. package/packages/server/src/browser-gateway.ts +27 -10
  87. package/packages/server/src/browser-handlers/handler-context.ts +9 -0
  88. package/packages/server/src/browser-handlers/session-action-handler.ts +128 -19
  89. package/packages/server/src/changelog-fs.ts +167 -0
  90. package/packages/server/src/changelog-parser.ts +321 -0
  91. package/packages/server/src/changelog-remote.ts +134 -0
  92. package/packages/server/src/cli.ts +62 -82
  93. package/packages/server/src/config-api.ts +14 -2
  94. package/packages/server/src/directory-service.ts +106 -4
  95. package/packages/server/src/event-wiring.ts +90 -6
  96. package/packages/server/src/headless-pid-registry.ts +344 -37
  97. package/packages/server/src/legacy-pi-cleanup.ts +151 -0
  98. package/packages/server/src/model-proxy/__tests__/api-key-store.test.ts +142 -0
  99. package/packages/server/src/model-proxy/__tests__/auth-json-contention.test.ts +98 -0
  100. package/packages/server/src/model-proxy/__tests__/concurrency.test.ts +107 -0
  101. package/packages/server/src/model-proxy/__tests__/failed-auth-backoff.test.ts +46 -0
  102. package/packages/server/src/model-proxy/__tests__/recursion-guard.test.ts +61 -0
  103. package/packages/server/src/model-proxy/__tests__/streamer.test.ts +139 -0
  104. package/packages/server/src/model-proxy/api-key-store.ts +87 -0
  105. package/packages/server/src/model-proxy/auth-gate.ts +116 -0
  106. package/packages/server/src/model-proxy/concurrency.ts +76 -0
  107. package/packages/server/src/model-proxy/convert/UPSTREAM.md +13 -0
  108. package/packages/server/src/model-proxy/convert/__tests__/anthropic-in.test.ts +137 -0
  109. package/packages/server/src/model-proxy/convert/__tests__/anthropic-out.test.ts +183 -0
  110. package/packages/server/src/model-proxy/convert/__tests__/openai-in.test.ts +134 -0
  111. package/packages/server/src/model-proxy/convert/__tests__/openai-out.test.ts +166 -0
  112. package/packages/server/src/model-proxy/convert/anthropic-in.ts +129 -0
  113. package/packages/server/src/model-proxy/convert/anthropic-out.ts +173 -0
  114. package/packages/server/src/model-proxy/convert/index.ts +8 -0
  115. package/packages/server/src/model-proxy/convert/openai-in.ts +119 -0
  116. package/packages/server/src/model-proxy/convert/openai-out.ts +151 -0
  117. package/packages/server/src/model-proxy/convert/types.ts +70 -0
  118. package/packages/server/src/model-proxy/failed-auth-backoff.ts +45 -0
  119. package/packages/server/src/model-proxy/internal-auth-storage.ts +146 -0
  120. package/packages/server/src/model-proxy/internal-registry.ts +157 -0
  121. package/packages/server/src/model-proxy/recursion-guard.ts +72 -0
  122. package/packages/server/src/model-proxy/registry-singleton.ts +109 -0
  123. package/packages/server/src/model-proxy/request-log.ts +53 -0
  124. package/packages/server/src/model-proxy/streamer.ts +59 -0
  125. package/packages/server/src/openspec-group-store.ts +490 -0
  126. package/packages/server/src/pending-client-correlations.ts +73 -0
  127. package/packages/server/src/pending-fork-registry.ts +24 -12
  128. package/packages/server/src/pi-core-checker.ts +77 -17
  129. package/packages/server/src/pi-core-updater.ts +16 -6
  130. package/packages/server/src/pi-dev-version-check.ts +145 -0
  131. package/packages/server/src/pi-gateway.ts +4 -0
  132. package/packages/server/src/pi-version-skew.ts +12 -4
  133. package/packages/server/src/process-manager.ts +182 -11
  134. package/packages/server/src/provider-auth-storage.ts +29 -47
  135. package/packages/server/src/provider-catalogue-cache.ts +24 -18
  136. package/packages/server/src/restart-helper.ts +17 -16
  137. package/packages/server/src/routes/bootstrap-routes.ts +37 -0
  138. package/packages/server/src/routes/jj-routes.ts +3 -0
  139. package/packages/server/src/routes/model-proxy-api-key-routes.ts +168 -0
  140. package/packages/server/src/routes/model-proxy-refresh-routes.ts +24 -0
  141. package/packages/server/src/routes/model-proxy-routes.ts +330 -0
  142. package/packages/server/src/routes/openspec-group-routes.ts +231 -0
  143. package/packages/server/src/routes/pi-changelog-routes.ts +194 -0
  144. package/packages/server/src/routes/pi-core-routes.ts +1 -1
  145. package/packages/server/src/routes/provider-auth-routes.ts +8 -1
  146. package/packages/server/src/routes/provider-routes.ts +28 -5
  147. package/packages/server/src/routes/system-routes.ts +44 -2
  148. package/packages/server/src/rpc-keeper/__tests__/fixtures/mock-pi-shim.sh +9 -0
  149. package/packages/server/src/rpc-keeper/__tests__/fixtures/mock-pi.cjs +50 -0
  150. package/packages/server/src/rpc-keeper/__tests__/keeper.test.ts +371 -0
  151. package/packages/server/src/rpc-keeper/dispatch-router.ts +85 -0
  152. package/packages/server/src/rpc-keeper/keeper-manager.ts +364 -0
  153. package/packages/server/src/rpc-keeper/keeper.cjs +313 -0
  154. package/packages/server/src/server.ts +254 -60
  155. package/packages/server/src/session-api.ts +63 -4
  156. package/packages/server/src/session-discovery.ts +1 -1
  157. package/packages/server/src/session-file-reader.ts +1 -1
  158. package/packages/server/src/spawn-register-watchdog.ts +62 -7
  159. package/packages/server/src/spawn-token.ts +20 -0
  160. package/packages/server/src/tunnel-watchdog.ts +230 -0
  161. package/packages/server/src/tunnel.ts +5 -1
  162. package/packages/shared/package.json +1 -1
  163. package/packages/shared/src/__tests__/binary-lookup-resolveJiti.test.ts +228 -0
  164. package/packages/shared/src/__tests__/bootstrap/__snapshots__/cube.test.ts.snap +24 -17
  165. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/a-electron.test.ts.snap +5 -4
  166. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/b-npm-global.test.ts.snap +6 -5
  167. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/c-dev-monorepo.test.ts.snap +1 -0
  168. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/e-stale-partial.test.ts.snap +5 -4
  169. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/f-cwd-variants.test.ts.snap +2 -1
  170. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/g-windows-specifics.test.ts.snap +5 -3
  171. package/packages/shared/src/__tests__/bootstrap/fixtures/dev-monorepo.ts +1 -1
  172. package/packages/shared/src/__tests__/changelog-types.test.ts +78 -0
  173. package/packages/shared/src/__tests__/config-openspec.test.ts +74 -0
  174. package/packages/shared/src/__tests__/model-proxy-config.test.ts +146 -0
  175. package/packages/shared/src/__tests__/no-raw-node-import.test.ts +7 -5
  176. package/packages/shared/src/__tests__/node-spawn-jiti-contract.test.ts +56 -20
  177. package/packages/shared/src/__tests__/node-spawn.test.ts +51 -0
  178. package/packages/shared/src/__tests__/openspec-groups-types.test.ts +135 -0
  179. package/packages/shared/src/__tests__/publish-workflow-contract.test.ts +96 -0
  180. package/packages/shared/src/__tests__/recommended-extensions.test.ts +11 -3
  181. package/packages/shared/src/__tests__/server-launcher.test.ts +227 -0
  182. package/packages/shared/src/__tests__/tool-registry-definitions.test.ts +1 -1
  183. package/packages/shared/src/bootstrap-install.ts +1 -1
  184. package/packages/shared/src/browser-protocol.ts +70 -0
  185. package/packages/shared/src/changelog-types.ts +111 -0
  186. package/packages/shared/src/config.ts +172 -2
  187. package/packages/shared/src/dashboard-plugin/manifest-types.ts +16 -1
  188. package/packages/shared/src/dashboard-plugin/slot-props.ts +8 -0
  189. package/packages/shared/src/dashboard-plugin/slot-types.ts +57 -0
  190. package/packages/shared/src/platform/binary-lookup.ts +204 -0
  191. package/packages/shared/src/platform/node-spawn.ts +71 -26
  192. package/packages/shared/src/protocol.ts +27 -1
  193. package/packages/shared/src/recommended-extensions.ts +18 -0
  194. package/packages/shared/src/rest-api.ts +219 -1
  195. package/packages/shared/src/server-launcher.ts +277 -0
  196. package/packages/shared/src/skill-block-parser.ts +1 -1
  197. package/packages/shared/src/tool-registry/__tests__/pi-ai-registration.test.ts +124 -0
  198. package/packages/shared/src/tool-registry/definitions.ts +15 -3
  199. package/packages/shared/src/types.ts +62 -0
  200. package/packages/shared/src/__tests__/resolve-jiti.test.ts +0 -53
  201. package/packages/shared/src/resolve-jiti.ts +0 -102
@@ -118,29 +118,37 @@ export function toFileUrl(pathOrUrl: string): string {
118
118
  * host can exercise the Windows branch without mutating `process.platform`.
119
119
  *
120
120
  * !! JITI VERSION CONTRACT !!
121
- * The Windows-non-tsx arm assumes the jiti loader is from
122
- * `@mariozechner/pi-coding-agent@0.70.x` (jiti 2.x with the `file:///`
123
- * triple-slash URL handling fix). jiti 2.x correctly handles `file:///`
124
- * URL entries on Windows it was the version we carved this contract
125
- * around in change `fix-windows-entry-script-url`.
126
- *
127
- * Newer jiti versions (e.g. jiti 2.6.5 in `pi-coding-agent@0.71.x`)
128
- * MISBEHAVE on `file:///` entries: they normalize triple-slash to
129
- * single-slash and prepend cwd as if the entry were a relative
130
- * specifier, producing `<cwd>/file:/...` ENOENT errors.
131
- *
132
- * The Electron Windows codepath defends against this version drift by
133
- * resolving jiti from the managed dir's `pi-coding-agent@0.70.0` (the
134
- * version pinned in `packages/electron/offline-packages.json` and
135
- * extracted into `~/.pi-dashboard/` by `installStandalone()` on first
136
- * launch see Defect 1 of change
137
- * `fix-electron-windows-installer-and-server-bootstrap`). Since the
138
- * managed-dir tree is pinned, the contract holds regardless of what
139
- * jiti is on the user's PATH.
121
+ * The Windows-non-tsx arm relies on jiti's `file:///` triple-slash URL
122
+ * handling. Verified-good baselines (must be one of these in the
123
+ * offline cacache):
124
+ * `@earendil-works/pi-coding-agent@0.74.x` (jiti `^2.7.0`) current
125
+ * `@mariozechner/pi-coding-agent@0.70.x` (jiti 2.x) — legacy
126
+ *
127
+ * Both ship a jiti that correctly normalises `file:///` entries on
128
+ * Windows. The contract was originally carved around 0.70.x in change
129
+ * `fix-windows-entry-script-url` and re-anchored at 0.74.x in change
130
+ * `migrate-pi-fork-to-earendil` (E.7).
131
+ *
132
+ * Known-broken (do NOT pin): `pi-coding-agent@0.71.x` shipping
133
+ * `jiti@2.6.5`. That jiti version misnormalises triple-slash to
134
+ * single-slash and prepends cwd as if the entry were a relative
135
+ * specifier, producing `<cwd>/file:/...` ENOENT errors. Keep the
136
+ * 0.71.x / 2.6.5 mention here so contributors recognise the
137
+ * regression pattern if it recurs in a future jiti.
138
+ *
139
+ * The Electron Windows codepath defends against version drift by
140
+ * resolving jiti from the managed dir's pinned `pi-coding-agent`
141
+ * (currently `@earendil-works/pi-coding-agent@0.74.0`, pinned in
142
+ * `packages/electron/offline-packages.json` and extracted into
143
+ * `~/.pi-dashboard/` by `installStandalone()` on first launch — see
144
+ * Defect 1 of change `fix-electron-windows-installer-and-server-bootstrap`).
145
+ * Since the managed-dir tree is pinned, the contract holds regardless
146
+ * of what jiti is on the user's PATH.
140
147
  *
141
148
  * If a future change bumps the offline-cacache `pi-coding-agent` pin to
142
- * a version with a different jiti, RE-VERIFY this contract on Windows
143
- * manually (run a packaged Electron app on Win10 + Win11) and either:
149
+ * a version OUTSIDE the verified baselines, RE-VERIFY this contract on
150
+ * Windows manually (run a packaged Electron app on Win10 + Win11) and
151
+ * either:
144
152
  * 1. Update the contract (fix the file:// URL handling expectation), OR
145
153
  * 2. Add a per-jiti-version branch here, OR
146
154
  * 3. Switch the bundled loader to tsx (which has its own contract).
@@ -169,16 +177,53 @@ export function shouldUrlWrapEntry(
169
177
  * preserved. Does not import `node:child_process` directly (the type
170
178
  * imports above are annotated with the opt-out marker).
171
179
  */
180
+ /**
181
+ * Pure helper: build the bare argv chunk for `node --import <loader>
182
+ * <entry> [...args]` with correct URL-wrapping at both positions.
183
+ *
184
+ * Single source of truth for the `--import` argv shape — used by
185
+ * `spawnNodeScript` (runtime spawn) and by
186
+ * `packages/server/src/restart-helper.ts buildOrchestratorScript`
187
+ * (which embeds the argv into a `node -e` orchestrator script that
188
+ * executes in a fresh process and therefore cannot call
189
+ * `spawnNodeScript` directly).
190
+ *
191
+ * No I/O. The `platform` parameter is passed through to
192
+ * `shouldUrlWrapEntry` for testability.
193
+ *
194
+ * Loader is always URL-wrapped. Entry is URL-wrapped per
195
+ * `shouldUrlWrapEntry(loader, platform)`.
196
+ */
197
+ export function buildNodeImportArgvParts(opts: {
198
+ loader: string;
199
+ entry: string;
200
+ args?: readonly string[];
201
+ platform?: NodeJS.Platform;
202
+ }): string[] {
203
+ const wrapEntry = shouldUrlWrapEntry(opts.loader, opts.platform);
204
+ const parts: string[] = [
205
+ "--import", toFileUrl(opts.loader),
206
+ wrapEntry ? toFileUrl(opts.entry) : opts.entry,
207
+ ];
208
+ if (opts.args && opts.args.length > 0) parts.push(...opts.args);
209
+ return parts;
210
+ }
211
+
172
212
  export function spawnNodeScript(opts: SpawnNodeScriptOptions): ChildProcess {
173
213
  const nodeBin = opts.nodeBin ?? process.execPath;
174
- const wrapEntry = shouldUrlWrapEntry(opts.loader);
175
214
 
176
- const argv: string[] = [];
215
+ let argv: string[];
177
216
  if (opts.loader) {
178
- argv.push("--import", toFileUrl(opts.loader));
217
+ argv = buildNodeImportArgvParts({
218
+ loader: opts.loader,
219
+ entry: opts.entry,
220
+ args: opts.args,
221
+ });
222
+ } else {
223
+ const wrapEntry = shouldUrlWrapEntry(opts.loader);
224
+ argv = [wrapEntry ? toFileUrl(opts.entry) : opts.entry];
225
+ if (opts.args) argv.push(...opts.args);
179
226
  }
180
- argv.push(wrapEntry ? toFileUrl(opts.entry) : opts.entry);
181
- if (opts.args) argv.push(...opts.args);
182
227
 
183
228
  return execSpawn(nodeBin, argv, opts.spawnOptions ?? {});
184
229
  }
@@ -22,6 +22,14 @@ export interface SessionRegisterMessage {
22
22
  eventCount?: number;
23
23
  /** OS process ID of the pi agent — used for force-kill escalation */
24
24
  pid?: number;
25
+ /**
26
+ * Server-minted spawn correlation token. Bridge populates this from
27
+ * `process.env.PI_DASHBOARD_SPAWN_TOKEN` IFF this is the first register
28
+ * for the bridge process (`bc.hasRegisteredOnce === false`). Subsequent
29
+ * registers (reattach, in-process new/fork/resume) omit it.
30
+ * See change: spawn-correlation-token.
31
+ */
32
+ spawnToken?: string;
25
33
  /**
26
34
  * Why the bridge is registering this session. The bridge sets this to
27
35
  * `"spawn"` for the very first `session_register` after process boot
@@ -281,6 +289,23 @@ export interface UiDataListMessage {
281
289
  items: unknown[];
282
290
  }
283
291
 
292
+ // ── RPC keeper: bridge → server slash dispatch ──
293
+ // See change: add-rpc-stdin-dispatch-with-keeper-sidecar.
294
+ //
295
+ // Emitted by `slash-dispatch.ts::tryDispatchExtensionCommand` when the
296
+ // active pi build does NOT expose `pi.dispatchCommand` AND the bridge
297
+ // detects a headless RPC pi (per `isHeadlessRpcSession()`). The server's
298
+ // dispatch-router writes `{type:"prompt", message: command, id: requestId}`
299
+ // to the session's keeper UDS / named pipe and emits the optimistic
300
+ // `command_feedback {status:"completed"}` (or error) to browser subscribers.
301
+ export interface DispatchExtensionCommandMessage {
302
+ type: "dispatch_extension_command";
303
+ sessionId: string;
304
+ command: string;
305
+ /** UUID minted by the bridge so pi's RPC response can be correlated. */
306
+ requestId: string;
307
+ }
308
+
284
309
  // ── Extension UI System (Phase 2: live in-page decorations) ──
285
310
  // See change: add-extension-ui-decorations.
286
311
 
@@ -346,7 +371,8 @@ export type ExtensionToServerMessage =
346
371
  | UiModulesListMessage
347
372
  | UiDataListMessage
348
373
  | ExtUiDecoratorMessage
349
- | AssetRegisterMessage;
374
+ | AssetRegisterMessage
375
+ | DispatchExtensionCommandMessage;
350
376
 
351
377
  // ── Server → Extension ──────────────────────────────────────────────
352
378
 
@@ -165,6 +165,24 @@ export const RECOMMENDED_EXTENSIONS: readonly RecommendedExtension[] = [
165
165
  unlocks: ["browser tool (open, snapshot, click, screenshot)"],
166
166
  toolsRegistered: ["browser"],
167
167
  },
168
+ {
169
+ id: "pi-memory-honcho",
170
+ source: "npm:pi-memory-honcho",
171
+ displayName: "pi-memory-honcho",
172
+ fallbackDescription:
173
+ "Persistent cross-session memory backed by Honcho. Pairs with " +
174
+ "the @blackbelt-technology/pi-dashboard-honcho-plugin dashboard " +
175
+ "plugin which adds a settings panel, per-card actions, and " +
176
+ "optional self-hosted Honcho server lifecycle.",
177
+ status: "optional",
178
+ unlocks: [
179
+ "Honcho memory tools (honcho_search, honcho_context, honcho_profile)",
180
+ "Honcho settings panel (when honcho-plugin is loaded)",
181
+ "Per-card 🧠 status badge + interview/sync/map actions",
182
+ ],
183
+ toolsRegistered: ["honcho_search", "honcho_context", "honcho_profile"],
184
+ autowired: true,
185
+ },
168
186
  ];
169
187
 
170
188
  /**
@@ -5,6 +5,8 @@ import type {
5
5
  DashboardSession,
6
6
  DashboardEvent,
7
7
  ApiResponse,
8
+ OpenSpecGroup,
9
+ OpenSpecGroupsFile,
8
10
  } from "./types.js";
9
11
 
10
12
  export type { ApiResponse } from "./types.js";
@@ -163,8 +165,22 @@ export type MkdirResponse = ApiResponse<MkdirResult>;
163
165
 
164
166
  // ── Tunnel Status ───────────────────────────────────────────────────
165
167
 
168
+ export interface TunnelWatchdogPublicStatus {
169
+ running: boolean;
170
+ intervalMs: number;
171
+ failureThreshold: number;
172
+ probeTimeoutMs: number;
173
+ lastProbeAt: number | null;
174
+ lastSuccessAt: number | null;
175
+ lastFailureAt: number | null;
176
+ lastFailureReason: string | null;
177
+ consecutiveFailures: number;
178
+ lastRecycleAt: number | null;
179
+ recycleCount: number;
180
+ }
181
+
166
182
  export type TunnelStatus =
167
- | { status: "active"; url: string; serverOs: string }
183
+ | { status: "active"; url: string; serverOs: string; watchdog?: TunnelWatchdogPublicStatus }
168
184
  | { status: "inactive"; serverOs: string }
169
185
  | { status: "unavailable"; serverOs: string };
170
186
 
@@ -447,3 +463,205 @@ export interface RescanToolsRequest {
447
463
  export interface SetToolOverrideRequest {
448
464
  path: string;
449
465
  }
466
+
467
+ // ── Model Proxy: wire-protocol types ────────────────────────────────
468
+
469
+ /** OpenAI Chat Completions request shape (subset relevant to the proxy). */
470
+ export interface OpenAIChatCompletionRequest {
471
+ model: string;
472
+ messages: OpenAIChatMessage[];
473
+ stream?: boolean;
474
+ max_tokens?: number;
475
+ temperature?: number;
476
+ top_p?: number;
477
+ tools?: OpenAITool[];
478
+ tool_choice?: string | { type: string; function?: { name: string } };
479
+ stop?: string | string[];
480
+ }
481
+
482
+ export interface OpenAIChatMessage {
483
+ role: "system" | "user" | "assistant" | "tool";
484
+ content?: string | OpenAIContentPart[];
485
+ name?: string;
486
+ tool_calls?: OpenAIToolCall[];
487
+ tool_call_id?: string;
488
+ }
489
+
490
+ export interface OpenAIContentPart {
491
+ type: "text" | "image_url";
492
+ text?: string;
493
+ image_url?: { url: string; detail?: string };
494
+ }
495
+
496
+ export interface OpenAITool {
497
+ type: "function";
498
+ function: { name: string; description?: string; parameters?: Record<string, unknown> };
499
+ }
500
+
501
+ export interface OpenAIToolCall {
502
+ id: string;
503
+ type: "function";
504
+ function: { name: string; arguments: string };
505
+ }
506
+
507
+ export interface OpenAIChatCompletionResponse {
508
+ id: string;
509
+ object: "chat.completion";
510
+ created: number;
511
+ model: string;
512
+ choices: {
513
+ index: number;
514
+ message: { role: "assistant"; content?: string | null; tool_calls?: OpenAIToolCall[] };
515
+ finish_reason: string | null;
516
+ }[];
517
+ usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
518
+ }
519
+
520
+ export interface OpenAIChatCompletionStreamChunk {
521
+ id: string;
522
+ object: "chat.completion.chunk";
523
+ created: number;
524
+ model: string;
525
+ choices: {
526
+ index: number;
527
+ delta: {
528
+ role?: "assistant";
529
+ content?: string | null;
530
+ reasoning_content?: string | null;
531
+ tool_calls?: { index: number; id?: string; type?: "function"; function?: { name?: string; arguments?: string } }[];
532
+ };
533
+ finish_reason: string | null;
534
+ }[];
535
+ }
536
+
537
+ export interface OpenAIModelEntry {
538
+ id: string;
539
+ object: "model";
540
+ created: number;
541
+ owned_by: string;
542
+ "x-pi"?: {
543
+ contextWindow?: number;
544
+ maxTokens?: number;
545
+ reasoning?: boolean;
546
+ cost?: { input?: number; output?: number };
547
+ input?: string[];
548
+ };
549
+ }
550
+
551
+ export interface OpenAIModelsResponse {
552
+ object: "list";
553
+ data: OpenAIModelEntry[];
554
+ }
555
+
556
+ /** Anthropic Messages request shape (subset relevant to the proxy). */
557
+ export interface AnthropicMessagesRequest {
558
+ model: string;
559
+ messages: AnthropicMessage[];
560
+ system?: string | AnthropicContentBlock[];
561
+ max_tokens: number;
562
+ stream?: boolean;
563
+ temperature?: number;
564
+ top_p?: number;
565
+ tools?: AnthropicTool[];
566
+ stop_sequences?: string[];
567
+ }
568
+
569
+ export interface AnthropicMessage {
570
+ role: "user" | "assistant";
571
+ content: string | AnthropicContentBlock[];
572
+ }
573
+
574
+ export interface AnthropicContentBlock {
575
+ type: string;
576
+ text?: string;
577
+ source?: { type: "base64"; media_type: string; data: string };
578
+ [key: string]: unknown;
579
+ }
580
+
581
+ export interface AnthropicTool {
582
+ name: string;
583
+ description?: string;
584
+ input_schema: Record<string, unknown>;
585
+ }
586
+
587
+ export interface AnthropicMessagesResponse {
588
+ id: string;
589
+ type: "message";
590
+ role: "assistant";
591
+ content: AnthropicContentBlock[];
592
+ model: string;
593
+ stop_reason: string | null;
594
+ usage: { input_tokens: number; output_tokens: number };
595
+ }
596
+
597
+ export interface AnthropicMessagesStreamEvent {
598
+ type: string;
599
+ message?: AnthropicMessagesResponse;
600
+ index?: number;
601
+ content_block?: AnthropicContentBlock;
602
+ delta?: { type: string; text?: string; partial_json?: string; thinking?: string; [key: string]: unknown };
603
+ usage?: { output_tokens: number };
604
+ }
605
+
606
+ // ── Model Proxy: API key management ─────────────────────────────────
607
+
608
+ export interface ModelProxyApiKeysCreateRequest {
609
+ label: string;
610
+ scopes?: string[];
611
+ expiresAt?: number;
612
+ }
613
+
614
+ export interface ModelProxyApiKeyEntry {
615
+ id: string;
616
+ label: string;
617
+ createdBy?: string;
618
+ scopes: string[];
619
+ createdAt: number;
620
+ lastUsedAt?: number;
621
+ expiresAt?: number;
622
+ revokedAt?: number;
623
+ hash: string; // redacted to "***" in list responses
624
+ }
625
+
626
+ export type ModelProxyApiKeysListResponse = ApiResponse<{
627
+ keys: ModelProxyApiKeyEntry[];
628
+ revoked: ModelProxyApiKeyEntry[];
629
+ }>;
630
+
631
+ export type ModelProxyApiKeysCreateResponse = ApiResponse<{
632
+ id: string;
633
+ label: string;
634
+ createdBy?: string;
635
+ scopes: string[];
636
+ createdAt: number;
637
+ expiresAt?: number;
638
+ key: string; // cleartext, revealed ONCE
639
+ }>;
640
+
641
+ // ── OpenSpec Change Grouping ────────────────────────────────────────
642
+ // See change: add-openspec-change-grouping (tasks 1.6, 5.x).
643
+ // Endpoints under `/api/openspec/groups[?cwd=…]`.
644
+
645
+ export type GetOpenSpecGroupsResponse = ApiResponse<OpenSpecGroupsFile>;
646
+
647
+ export interface CreateOpenSpecGroupRequest {
648
+ name: string;
649
+ color?: string;
650
+ }
651
+ export type CreateOpenSpecGroupResponse = ApiResponse<OpenSpecGroup>;
652
+
653
+ export interface UpdateOpenSpecGroupRequest {
654
+ name?: string;
655
+ color?: string;
656
+ order?: number;
657
+ }
658
+ export type UpdateOpenSpecGroupResponse = ApiResponse<OpenSpecGroup>;
659
+
660
+ export type DeleteOpenSpecGroupResponse = ApiResponse<void>;
661
+
662
+ export interface SetOpenSpecGroupAssignmentRequest {
663
+ changeName: string;
664
+ /** `null` removes the assignment (change becomes Ungrouped). */
665
+ groupId: string | null;
666
+ }
667
+ export type SetOpenSpecGroupAssignmentResponse = ApiResponse<void>;