@blackbelt-technology/pi-agent-dashboard 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +19 -30
- package/README.md +69 -1
- package/docs/architecture.md +89 -165
- package/package.json +11 -7
- package/packages/extension/package.json +2 -2
- package/packages/extension/src/__tests__/bridge-default-model-gate.test.ts +47 -0
- package/packages/extension/src/__tests__/bridge-followup-chat-order.test.ts +215 -0
- package/packages/extension/src/__tests__/bridge-followup-multi-entry.test.ts +202 -0
- package/packages/extension/src/__tests__/bridge-queue-update-forward.test.ts +77 -0
- package/packages/extension/src/__tests__/bridge-retry-ordering.test.ts +148 -0
- package/packages/extension/src/__tests__/bridge-shadow-queue-drain.test.ts +221 -0
- package/packages/extension/src/__tests__/bridge-shadow-queue-gate.test.ts +299 -0
- package/packages/extension/src/__tests__/bridge-shutdown-reset.test.ts +238 -0
- package/packages/extension/src/__tests__/bridge-slash-command-routing.test.ts +127 -31
- package/packages/extension/src/__tests__/command-handler.test.ts +105 -3
- package/packages/extension/src/__tests__/fixtures/usage-limit-error-strings.ts +127 -0
- package/packages/extension/src/__tests__/source-detector.test.ts +15 -0
- package/packages/extension/src/__tests__/usage-limit-orderer.test.ts +12 -0
- package/packages/extension/src/bridge-default-model-gate.ts +32 -0
- package/packages/extension/src/bridge.ts +299 -20
- package/packages/extension/src/command-handler.ts +53 -7
- package/packages/extension/src/dashboard-default-adapter.ts +5 -0
- package/packages/extension/src/prompt-bus.ts +15 -0
- package/packages/extension/src/slash-dispatch.ts +30 -15
- package/packages/extension/src/source-detector.ts +13 -5
- package/packages/extension/src/usage-limit-orderer.ts +18 -1
- package/packages/server/bin/pi-dashboard.mjs +62 -14
- package/packages/server/package.json +9 -5
- package/packages/server/src/__tests__/browser-gateway-register-handler.test.ts +69 -0
- package/packages/server/src/__tests__/cli-env-no-clobber.test.ts +46 -0
- package/packages/server/src/__tests__/cli-no-bootstrap-references.test.ts +69 -0
- package/packages/server/src/__tests__/cli-parse.test.ts +9 -10
- package/packages/server/src/__tests__/cli-version.test.ts +151 -0
- package/packages/server/src/__tests__/directory-service-openspec-enabled.test.ts +9 -0
- package/packages/server/src/__tests__/directory-service-refresh-force.test.ts +9 -0
- package/packages/server/src/__tests__/directory-service-specs-mtime.test.ts +9 -0
- package/packages/server/src/__tests__/directory-service-toctou.test.ts +9 -0
- package/packages/server/src/__tests__/directory-service.test.ts +9 -0
- package/packages/server/src/__tests__/doctor-route.test.ts +53 -0
- package/packages/server/src/__tests__/event-wiring-queue-state.test.ts +156 -0
- package/packages/server/src/__tests__/event-wiring-resume-clear.test.ts +105 -0
- package/packages/server/src/__tests__/health-shape.test.ts +35 -12
- package/packages/server/src/__tests__/installed-package-enricher.test.ts +12 -12
- package/packages/server/src/__tests__/is-activity-event.test.ts +4 -7
- package/packages/server/src/__tests__/package-routes.test.ts +6 -2
- package/packages/server/src/__tests__/pi-changelog-routes.test.ts +10 -13
- package/packages/server/src/__tests__/pi-core-checker.test.ts +2 -2
- package/packages/server/src/__tests__/pi-version-skew.test.ts +3 -2
- package/packages/server/src/__tests__/plugin-activation-routes.test.ts +267 -0
- package/packages/server/src/__tests__/plugin-intent-cache.test.ts +75 -0
- package/packages/server/src/__tests__/preferences-store.test.ts +196 -0
- package/packages/server/src/__tests__/reattach-placement.test.ts +9 -0
- package/packages/server/src/__tests__/recommended-routes.test.ts +2 -2
- package/packages/server/src/__tests__/recovery-server.test.ts +203 -0
- package/packages/server/src/__tests__/session-action-handler-clear-queue.test.ts +153 -0
- package/packages/server/src/__tests__/session-action-handler-headless-reload.test.ts +43 -0
- package/packages/server/src/__tests__/session-order-manager.test.ts +9 -0
- package/packages/server/src/__tests__/session-order-reboot.test.ts +9 -0
- package/packages/server/src/__tests__/session-ordering-integration.test.ts +9 -0
- package/packages/server/src/browser-gateway.ts +83 -5
- package/packages/server/src/browser-handlers/directory-handler.ts +69 -0
- package/packages/server/src/browser-handlers/session-action-handler.ts +89 -0
- package/packages/server/src/browser-handlers/subscription-handler.ts +23 -0
- package/packages/server/src/changelog-parser.ts +1 -1
- package/packages/server/src/cli.ts +68 -250
- package/packages/server/src/event-status-extraction.ts +14 -62
- package/packages/server/src/event-wiring.ts +23 -10
- package/packages/server/src/memory-session-manager.ts +4 -0
- package/packages/server/src/pi-core-checker.ts +1 -1
- package/packages/server/src/pi-dev-version-check.ts +1 -1
- package/packages/server/src/pi-version-skew.ts +24 -46
- package/packages/server/src/plugin-intent-cache.ts +67 -0
- package/packages/server/src/preferences-store.ts +199 -13
- package/packages/server/src/recovery-server.ts +366 -0
- package/packages/server/src/routes/__tests__/manifest-route.test.ts +138 -0
- package/packages/server/src/routes/doctor-routes.ts +26 -21
- package/packages/server/src/routes/manifest-route.ts +162 -0
- package/packages/server/src/routes/openspec-routes.ts +4 -25
- package/packages/server/src/routes/pi-changelog-routes.ts +5 -24
- package/packages/server/src/routes/pi-core-routes.ts +3 -23
- package/packages/server/src/routes/plugin-activation-routes.ts +193 -0
- package/packages/server/src/routes/recommended-routes.ts +21 -0
- package/packages/server/src/routes/system-routes.ts +73 -11
- package/packages/server/src/server.ts +105 -307
- package/packages/server/src/session-api.ts +5 -63
- package/packages/shared/package.json +1 -1
- package/packages/shared/src/__tests__/binary-lookup-resolveJiti.test.ts +28 -0
- package/packages/shared/src/__tests__/binary-lookup-spawn-env.test.ts +61 -0
- package/packages/shared/src/__tests__/binary-lookup.test.ts +16 -0
- package/packages/shared/src/__tests__/bridge-register.test.ts +67 -0
- package/packages/shared/src/__tests__/ci-electron-no-side-effects.test.ts +129 -0
- package/packages/shared/src/__tests__/config.test.ts +40 -0
- package/packages/shared/src/__tests__/dashboard-paths.test.ts +81 -0
- package/packages/shared/src/__tests__/ensure-windows-path.test.ts +112 -0
- package/packages/shared/src/__tests__/intent-types.test.ts +120 -0
- package/packages/shared/src/__tests__/jiti-packages-parity.test.ts +85 -0
- package/packages/shared/src/__tests__/legacy-managed-dir.test.ts +59 -0
- package/packages/shared/src/__tests__/no-direct-child-process.test.ts +12 -0
- package/packages/shared/src/__tests__/no-electron-execpath-spawn.test.ts +149 -0
- package/packages/shared/src/__tests__/no-flow-command-route-claims.test.ts +71 -0
- package/packages/shared/src/__tests__/no-flow-references-in-shell.test.ts +221 -0
- package/packages/shared/src/__tests__/no-managed-dir-reference.test.ts +134 -0
- package/packages/shared/src/__tests__/no-pi-dashboard-version-jiti-gate.test.ts +41 -0
- package/packages/shared/src/__tests__/no-primitive-direct-import.test.ts +235 -0
- package/packages/shared/src/__tests__/no-server-imports-in-resolver.test.ts +53 -0
- package/packages/shared/src/__tests__/node-spawn-jiti-contract.test.ts +54 -101
- package/packages/shared/src/__tests__/node-spawn.test.ts +29 -13
- package/packages/shared/src/__tests__/pi-package-resolver.test.ts +300 -0
- package/packages/shared/src/__tests__/plugin-activation-contracts.test.ts +74 -0
- package/packages/shared/src/__tests__/plugin-bridge-classify-source.test.ts +73 -0
- package/packages/shared/src/__tests__/plugin-bridge-register-extended.test.ts +17 -5
- package/packages/shared/src/__tests__/plugin-bridge-register-packages.test.ts +233 -0
- package/packages/shared/src/__tests__/plugin-bridge-register.test.ts +19 -9
- package/packages/shared/src/__tests__/publish-workflow-contract.test.ts +154 -15
- package/packages/shared/src/__tests__/recommended-extensions.test.ts +28 -10
- package/packages/shared/src/__tests__/resolver-parity-with-scanner.test.ts +76 -0
- package/packages/shared/src/__tests__/server-identity.test.ts +127 -0
- package/packages/shared/src/__tests__/server-launcher.test.ts +35 -0
- package/packages/shared/src/__tests__/source-matching.test.ts +5 -5
- package/packages/shared/src/__tests__/sync-versions-spec.test.ts +76 -0
- package/packages/shared/src/__tests__/tool-registry-definitions.test.ts +50 -2
- package/packages/shared/src/bridge-register.ts +35 -2
- package/packages/shared/src/browser-protocol.ts +176 -2
- package/packages/shared/src/config.ts +12 -0
- package/packages/shared/src/dashboard-paths.ts +69 -0
- package/packages/shared/src/dashboard-plugin/index.ts +2 -0
- package/packages/shared/src/dashboard-plugin/intent-types.ts +93 -0
- package/packages/shared/src/dashboard-plugin/manifest-types.ts +55 -1
- package/packages/shared/src/dashboard-plugin/plugin-status.ts +82 -0
- package/packages/shared/src/dashboard-plugin/slot-props.ts +11 -0
- package/packages/shared/src/dashboard-plugin/slot-types.ts +16 -2
- package/packages/shared/src/dashboard-plugin/ui-primitives.ts +287 -0
- package/packages/shared/src/dashboard-starter.ts +22 -0
- package/packages/shared/src/doctor-core.ts +49 -27
- package/packages/shared/src/launch-source-types.ts +9 -9
- package/packages/shared/src/legacy-managed-dir.ts +97 -0
- package/packages/shared/src/mdns-discovery.ts +4 -1
- package/packages/shared/src/pi-package-resolver.ts +388 -0
- package/packages/shared/src/platform/binary-lookup.ts +27 -3
- package/packages/shared/src/platform/ensure-windows-path.ts +95 -0
- package/packages/shared/src/platform/exec.ts +22 -0
- package/packages/shared/src/platform/node-spawn.ts +42 -41
- package/packages/shared/src/plugin-bridge-register.ts +275 -18
- package/packages/shared/src/protocol.ts +94 -2
- package/packages/shared/src/recommended-extensions.ts +34 -10
- package/packages/shared/src/server-identity.ts +74 -5
- package/packages/shared/src/server-launcher.ts +20 -0
- package/packages/shared/src/source-matching.ts +1 -1
- package/packages/shared/src/tool-registry/__tests__/node-script-toargv-fallback.test.ts +84 -0
- package/packages/shared/src/tool-registry/definitions.ts +91 -7
- package/packages/shared/src/types.ts +12 -8
- package/scripts/maybe-patch-package.cjs +44 -0
- package/packages/server/src/__tests__/bootstrap-install-from-list.test.ts +0 -263
- package/packages/server/src/__tests__/bootstrap-queue.test.ts +0 -120
- package/packages/server/src/__tests__/bootstrap-routes.test.ts +0 -125
- package/packages/server/src/__tests__/bootstrap-state.test.ts +0 -119
- package/packages/server/src/__tests__/cli-bootstrap.test.ts +0 -36
- package/packages/server/src/__tests__/event-status-extraction-flow.test.ts +0 -55
- package/packages/server/src/__tests__/legacy-pi-cleanup.test.ts +0 -149
- package/packages/server/src/__tests__/post-install-openspec-refresh.test.ts +0 -180
- package/packages/server/src/__tests__/post-install-rescan.test.ts +0 -134
- package/packages/server/src/__tests__/system-routes-reextract.test.ts +0 -91
- package/packages/server/src/bootstrap-install-from-list.ts +0 -232
- package/packages/server/src/bootstrap-queue.ts +0 -130
- package/packages/server/src/bootstrap-state.ts +0 -159
- package/packages/server/src/legacy-pi-cleanup.ts +0 -151
- package/packages/server/src/routes/bootstrap-routes.ts +0 -125
- package/packages/shared/src/__tests__/bootstrap/README.md +0 -133
- package/packages/shared/src/__tests__/bootstrap/__snapshots__/cube.test.ts.snap +0 -378
- package/packages/shared/src/__tests__/bootstrap/assertions.ts +0 -136
- package/packages/shared/src/__tests__/bootstrap/cube.test.ts +0 -47
- package/packages/shared/src/__tests__/bootstrap/cube.ts +0 -66
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/a-electron.test.ts.snap +0 -84
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/b-npm-global.test.ts.snap +0 -90
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/c-dev-monorepo.test.ts.snap +0 -34
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/d-overrides.test.ts.snap +0 -20
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/e-stale-partial.test.ts.snap +0 -62
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/f-cwd-variants.test.ts.snap +0 -34
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/g-windows-specifics.test.ts.snap +0 -49
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/j-path-gui-minimal.test.ts.snap +0 -12
- package/packages/shared/src/__tests__/bootstrap/families/a-electron.test.ts +0 -156
- package/packages/shared/src/__tests__/bootstrap/families/b-npm-global.test.ts +0 -157
- package/packages/shared/src/__tests__/bootstrap/families/c-dev-monorepo.test.ts +0 -102
- package/packages/shared/src/__tests__/bootstrap/families/d-overrides.test.ts +0 -76
- package/packages/shared/src/__tests__/bootstrap/families/e-stale-partial.test.ts +0 -94
- package/packages/shared/src/__tests__/bootstrap/families/f-cwd-variants.test.ts +0 -87
- package/packages/shared/src/__tests__/bootstrap/families/g-windows-specifics.test.ts +0 -143
- package/packages/shared/src/__tests__/bootstrap/families/h-home-drift.test.ts +0 -64
- package/packages/shared/src/__tests__/bootstrap/families/i-malformed-settings.test.ts +0 -77
- package/packages/shared/src/__tests__/bootstrap/families/index.ts +0 -19
- package/packages/shared/src/__tests__/bootstrap/families/j-path-gui-minimal.test.ts +0 -61
- package/packages/shared/src/__tests__/bootstrap/families/k-dashboard-absent.test.ts +0 -50
- package/packages/shared/src/__tests__/bootstrap/families/l-instance-coordination.test.ts +0 -272
- package/packages/shared/src/__tests__/bootstrap/fixtures/dev-monorepo.ts +0 -58
- package/packages/shared/src/__tests__/bootstrap/fixtures/electron-layout.ts +0 -84
- package/packages/shared/src/__tests__/bootstrap/fixtures/index.ts +0 -9
- package/packages/shared/src/__tests__/bootstrap/fixtures/managed-install.ts +0 -85
- package/packages/shared/src/__tests__/bootstrap/fixtures/npm-global-layout.ts +0 -122
- package/packages/shared/src/__tests__/bootstrap/fixtures/pi-versions.ts +0 -36
- package/packages/shared/src/__tests__/bootstrap/fixtures/settings-json.ts +0 -39
- package/packages/shared/src/__tests__/bootstrap/harness.smoke.test.ts +0 -220
- package/packages/shared/src/__tests__/bootstrap/harness.ts +0 -413
- package/packages/shared/src/__tests__/bootstrap/scenarios-skipped.ts +0 -125
- package/packages/shared/src/__tests__/bootstrap/scenarios.ts +0 -132
- package/packages/shared/src/__tests__/bootstrap-install-resolve-npm.test.ts +0 -72
- package/packages/shared/src/__tests__/install-managed-node-bootstrap-order.test.ts +0 -68
- package/packages/shared/src/__tests__/install-managed-node.test.ts +0 -192
- package/packages/shared/src/__tests__/installable-list.test.ts +0 -130
- package/packages/shared/src/__tests__/no-installable-list-in-bridge.test.ts +0 -52
- package/packages/shared/src/bootstrap-install.ts +0 -406
- package/packages/shared/src/installable-list.ts +0 -152
- package/packages/shared/src/launch-source-flag.ts +0 -14
|
@@ -99,59 +99,59 @@ export function toFileUrl(pathOrUrl: string): string {
|
|
|
99
99
|
return pathToFileURL(absolute).href;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Detect whether a loader (file:// URL or raw path) is jiti.
|
|
104
|
+
*
|
|
105
|
+
* Mirrors `isTsxLoader`. jiti's hook ships under `jiti/lib/`. Used so
|
|
106
|
+
* `shouldUrlWrapEntry` can refuse to URL-wrap the entry when jiti is
|
|
107
|
+
* the loader on Windows — see the JITI VERSION CONTRACT below.
|
|
108
|
+
*/
|
|
109
|
+
export function isJitiLoader(loader: string | null | undefined): boolean {
|
|
110
|
+
if (!loader) return false;
|
|
111
|
+
const normalized = loader.replace(/\\/g, "/");
|
|
112
|
+
return /\/jiti\//i.test(normalized);
|
|
113
|
+
}
|
|
114
|
+
|
|
102
115
|
/**
|
|
103
116
|
* Decide whether the entry-script position needs `file://` URL wrapping.
|
|
104
117
|
*
|
|
105
118
|
* Rule:
|
|
106
119
|
* - tsx loader: always raw path (tsx rejects file:// entries on every OS)
|
|
107
|
-
* -
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* a relative specifier, producing `<cwd>/file:/...` ENOENT errors.)
|
|
112
|
-
* - non-tsx on Windows: file:// URL
|
|
120
|
+
* - jiti loader: always raw path (jiti misnormalises file:// URL
|
|
121
|
+
* entries on Windows — see the JITI VERSION CONTRACT below)
|
|
122
|
+
* - any loader on POSIX: raw path (no drive-letter / URL-scheme collision)
|
|
123
|
+
* - other / default Node resolver on Windows: file:// URL
|
|
113
124
|
* (Node parses drive letters like `B:` / `A:` as URL schemes in argv
|
|
114
125
|
* before loaders run, throwing ERR_UNSUPPORTED_ESM_URL_SCHEME.
|
|
115
|
-
* Wrapping with `file://` sidesteps the parse.
|
|
126
|
+
* Wrapping with `file://` sidesteps the parse. The drive-letter
|
|
127
|
+
* heuristic in Node catches `C:\…` / `D:\…` etc., which is what
|
|
128
|
+
* jiti relies on for the standalone install layout.)
|
|
116
129
|
*
|
|
117
130
|
* Keeps a `platform` parameter for testability so unit tests on a POSIX
|
|
118
131
|
* host can exercise the Windows branch without mutating `process.platform`.
|
|
119
132
|
*
|
|
120
133
|
* !! JITI VERSION CONTRACT !!
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* `
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
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.
|
|
147
|
-
*
|
|
148
|
-
* If a future change bumps the offline-cacache `pi-coding-agent` pin to
|
|
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:
|
|
152
|
-
* 1. Update the contract (fix the file:// URL handling expectation), OR
|
|
153
|
-
* 2. Add a per-jiti-version branch here, OR
|
|
154
|
-
* 3. Switch the bundled loader to tsx (which has its own contract).
|
|
134
|
+
* jiti — at every version verified on Windows so far, including the
|
|
135
|
+
* current pin `jiti@^2.7.0` shipped under
|
|
136
|
+
* `@earendil-works/pi-coding-agent@0.74.x` — MISHANDLES `file:///`
|
|
137
|
+
* triple-slash URL entries on Windows. Symptom: the entry is rewritten
|
|
138
|
+
* to single-slash `file:/C:/…` and then re-resolved relative to cwd,
|
|
139
|
+
* yielding `Cannot find module 'file:///<cwd>/file:/C:/…/cli.ts'`.
|
|
140
|
+
*
|
|
141
|
+
* This was verified live in a Windows 11 standalone install
|
|
142
|
+
* (Node 22.18.0 + jiti 2.7.0) and is the reason the Windows branch of
|
|
143
|
+
* this function now returns `false` for jiti loaders. Node's own
|
|
144
|
+
* drive-letter heuristic accepts raw `C:\…` argv entries, so the URL
|
|
145
|
+
* wrap is unnecessary for the common standalone-install layout where
|
|
146
|
+
* pi + the dashboard live under `C:\Users\<u>\.pi-dashboard\…`.
|
|
147
|
+
*
|
|
148
|
+
* Earlier baselines (`@mariozechner/pi-coding-agent@0.70.x`,
|
|
149
|
+
* `jiti@2.6.5` in `pi-coding-agent@0.71.x`) exhibited the same or
|
|
150
|
+
* worse breakage; we no longer attempt to special-case any single
|
|
151
|
+
* jiti version. If a future jiti release fixes file:/// handling and
|
|
152
|
+
* we want to URL-wrap again (e.g. to cover `B:` / `A:` drives outside
|
|
153
|
+
* Node's heuristic), narrow the rule here and add a per-version
|
|
154
|
+
* branch — re-verify on real Windows before changing.
|
|
155
155
|
*
|
|
156
156
|
* Locked by `node-spawn-jiti-contract.test.ts`.
|
|
157
157
|
*/
|
|
@@ -160,6 +160,7 @@ export function shouldUrlWrapEntry(
|
|
|
160
160
|
platform: NodeJS.Platform = process.platform,
|
|
161
161
|
): boolean {
|
|
162
162
|
if (isTsxLoader(loader)) return false;
|
|
163
|
+
if (isJitiLoader(loader)) return false;
|
|
163
164
|
return platform === "win32";
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -2,26 +2,47 @@
|
|
|
2
2
|
* Plugin bridge entry management in pi's settings.json.
|
|
3
3
|
*
|
|
4
4
|
* Manages `dashboard-<plugin-id>` keys in a dedicated
|
|
5
|
-
* `dashboardPluginBridges` object inside settings.json
|
|
5
|
+
* `dashboardPluginBridges` object inside settings.json AND mirrors each
|
|
6
|
+
* managed bridge path into the top-level `packages[]` array so
|
|
7
|
+
* pi-coding-agent (which only reads `packages[]`) actually loads the
|
|
8
|
+
* bridge as an extension.
|
|
9
|
+
*
|
|
10
|
+
* See change: fix-pi-flows-end-to-end (Group 1).
|
|
11
|
+
*
|
|
12
|
+
* Ownership tracking:
|
|
13
|
+
* - `dashboardPluginBridges["dashboard-<id>"] = "<absPath>"` — managed key
|
|
14
|
+
* - `_dashboardManagedPackages["<absPath>"] = "<id>"` — ownership map
|
|
15
|
+
* - `packages[]` gains a plain string entry `"<absPath>"` — readable by pi
|
|
6
16
|
*
|
|
7
17
|
* Rules:
|
|
8
|
-
* - Only touches entries under
|
|
9
|
-
* - NEVER modifies user-owned `packages[]` entries
|
|
18
|
+
* - Only touches entries under managed keys / paths.
|
|
19
|
+
* - NEVER modifies user-owned `packages[]` entries (those without an entry
|
|
20
|
+
* in `_dashboardManagedPackages`).
|
|
10
21
|
* - Uses atomic write (tmp + rename) for all updates.
|
|
11
22
|
* - Detects path conflicts (existing entry with mismatched path).
|
|
23
|
+
*
|
|
24
|
+
* Escape hatch: setting `PI_DASHBOARD_DISABLE_PLUGIN_BRIDGE_PACKAGES_WRITE=1`
|
|
25
|
+
* skips the `packages[]` write (rollback parity with pre-change behavior).
|
|
12
26
|
*/
|
|
13
27
|
import fs from "node:fs";
|
|
14
28
|
import path from "node:path";
|
|
15
29
|
import os from "node:os";
|
|
30
|
+
import type { BridgeLoadSource } from "./dashboard-plugin/plugin-status.js";
|
|
16
31
|
|
|
17
32
|
export interface PluginBridgeRegisterOptions {
|
|
18
33
|
homedir?: string;
|
|
34
|
+
/** Override env-driven escape hatch for tests. */
|
|
35
|
+
skipPackagesWrite?: boolean;
|
|
19
36
|
}
|
|
20
37
|
|
|
21
38
|
export type PluginBridgeConflict =
|
|
22
39
|
| { type: "ok" }
|
|
23
40
|
| { type: "conflict"; existingPath: string; newPath: string };
|
|
24
41
|
|
|
42
|
+
const MANAGED_PREFIX = "dashboard-";
|
|
43
|
+
const OWNERSHIP_KEY = "_dashboardManagedPackages";
|
|
44
|
+
const ENV_SKIP = "PI_DASHBOARD_DISABLE_PLUGIN_BRIDGE_PACKAGES_WRITE";
|
|
45
|
+
|
|
25
46
|
function getSettingsPath(homedir?: string): string {
|
|
26
47
|
const home = homedir ?? process.env.HOME ?? process.env.USERPROFILE ?? os.homedir();
|
|
27
48
|
return path.join(home, ".pi", "agent", "settings.json");
|
|
@@ -55,11 +76,95 @@ function getManagedBridges(
|
|
|
55
76
|
return {};
|
|
56
77
|
}
|
|
57
78
|
|
|
58
|
-
|
|
79
|
+
function getOwnershipMap(
|
|
80
|
+
settings: Record<string, unknown>,
|
|
81
|
+
): Record<string, string> {
|
|
82
|
+
const val = settings[OWNERSHIP_KEY];
|
|
83
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
84
|
+
return val as Record<string, string>;
|
|
85
|
+
}
|
|
86
|
+
return {};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getPackages(settings: Record<string, unknown>): unknown[] {
|
|
90
|
+
const val = settings.packages;
|
|
91
|
+
return Array.isArray(val) ? val : [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function packageEntryPath(entry: unknown): string | null {
|
|
95
|
+
if (typeof entry === "string") return entry;
|
|
96
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
97
|
+
const src = (entry as Record<string, unknown>).source;
|
|
98
|
+
if (typeof src === "string") return src;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function shouldSkipPackagesWrite(opts: PluginBridgeRegisterOptions): boolean {
|
|
104
|
+
if (opts.skipPackagesWrite === true) return true;
|
|
105
|
+
if (opts.skipPackagesWrite === false) return false;
|
|
106
|
+
return process.env[ENV_SKIP] === "1";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
110
|
+
// Pure helpers (Task 1.1)
|
|
111
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Ensure `packages[]` contains `bridgePath` and record ownership.
|
|
115
|
+
* No-op when entry already present. Mutates `packages` and `ownership` in place.
|
|
116
|
+
* Returns `true` if a new entry was added.
|
|
117
|
+
*/
|
|
118
|
+
export function ensurePackageEntry(
|
|
119
|
+
packages: unknown[],
|
|
120
|
+
ownership: Record<string, string>,
|
|
121
|
+
bridgePath: string,
|
|
122
|
+
ownerMarker: string,
|
|
123
|
+
): boolean {
|
|
124
|
+
const already = packages.some((e) => packageEntryPath(e) === bridgePath);
|
|
125
|
+
ownership[bridgePath] = ownerMarker; // record ownership regardless
|
|
126
|
+
if (already) return false;
|
|
127
|
+
packages.push(bridgePath);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Remove a managed `packages[]` entry whose ownership matches `ownerMarker`.
|
|
133
|
+
* Leaves user-added entries (no matching ownership record) untouched.
|
|
134
|
+
* Mutates `packages` and `ownership` in place. Returns `true` if removed.
|
|
135
|
+
*/
|
|
136
|
+
export function removePackageEntry(
|
|
137
|
+
packages: unknown[],
|
|
138
|
+
ownership: Record<string, string>,
|
|
139
|
+
ownerMarker: string,
|
|
140
|
+
): boolean {
|
|
141
|
+
const owned = Object.entries(ownership)
|
|
142
|
+
.filter(([, owner]) => owner === ownerMarker)
|
|
143
|
+
.map(([p]) => p);
|
|
144
|
+
if (owned.length === 0) return false;
|
|
145
|
+
let removed = false;
|
|
146
|
+
for (const p of owned) {
|
|
147
|
+
const idx = packages.findIndex((e) => packageEntryPath(e) === p);
|
|
148
|
+
if (idx >= 0) {
|
|
149
|
+
packages.splice(idx, 1);
|
|
150
|
+
removed = true;
|
|
151
|
+
}
|
|
152
|
+
delete ownership[p];
|
|
153
|
+
}
|
|
154
|
+
return removed;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
158
|
+
// Public API (Tasks 1.2, 1.3, 1.4)
|
|
159
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
59
160
|
|
|
60
161
|
/**
|
|
61
162
|
* Register a plugin's bridge entry in pi's settings.json.
|
|
62
163
|
*
|
|
164
|
+
* Writes to BOTH:
|
|
165
|
+
* - `dashboardPluginBridges["dashboard-<pluginId>"]` (forward-compat)
|
|
166
|
+
* - `packages[]` + ownership record (so pi-coding-agent loads the bridge)
|
|
167
|
+
*
|
|
63
168
|
* Returns { type: "conflict", existingPath, newPath } if a
|
|
64
169
|
* `dashboard-<pluginId>` key already exists but points to a different path.
|
|
65
170
|
* In that case the settings.json is NOT modified.
|
|
@@ -74,25 +179,64 @@ export function registerPluginBridge(
|
|
|
74
179
|
const settingsPath = getSettingsPath(opts.homedir);
|
|
75
180
|
const settings = readSettings(settingsPath);
|
|
76
181
|
const managed = getManagedBridges(settings);
|
|
182
|
+
const ownership = getOwnershipMap(settings);
|
|
183
|
+
const packages = getPackages(settings);
|
|
77
184
|
const key = MANAGED_PREFIX + pluginId;
|
|
185
|
+
const ownerMarker = key;
|
|
78
186
|
|
|
79
187
|
const existing = managed[key];
|
|
80
|
-
if (existing) {
|
|
81
|
-
|
|
82
|
-
|
|
188
|
+
if (existing && existing !== bridgePath) {
|
|
189
|
+
// Self-heal: if the existing path no longer resolves on disk (typical
|
|
190
|
+
// after a dev-monorepo → deployed-bundle path change), silently replace.
|
|
191
|
+
// This avoids cosmetic "Bridge path conflict" errors on every restart
|
|
192
|
+
// when the user switches between dev and production launch sources.
|
|
193
|
+
// See change: add-plugin-activation-ui (deployment-fix follow-up).
|
|
194
|
+
let existingStillOnDisk = true;
|
|
195
|
+
try {
|
|
196
|
+
existingStillOnDisk = fs.existsSync(existing);
|
|
197
|
+
} catch {
|
|
198
|
+
existingStillOnDisk = false;
|
|
199
|
+
}
|
|
200
|
+
if (existingStillOnDisk) {
|
|
201
|
+
return { type: "conflict", existingPath: existing, newPath: bridgePath };
|
|
202
|
+
}
|
|
203
|
+
// Strip the stale entry and matching ownership/packages mirrors so the
|
|
204
|
+
// subsequent register block below installs the new path cleanly.
|
|
205
|
+
delete managed[key];
|
|
206
|
+
if (ownership[existing] === ownerMarker) delete ownership[existing];
|
|
207
|
+
const idx = packages.indexOf(existing);
|
|
208
|
+
if (idx >= 0) packages.splice(idx, 1);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let mutated = false;
|
|
212
|
+
if (!managed[key]) {
|
|
213
|
+
managed[key] = bridgePath;
|
|
214
|
+
settings.dashboardPluginBridges = managed;
|
|
215
|
+
mutated = true;
|
|
83
216
|
}
|
|
84
217
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
218
|
+
if (!shouldSkipPackagesWrite(opts)) {
|
|
219
|
+
const ownershipBefore = ownership[bridgePath];
|
|
220
|
+
const added = ensurePackageEntry(packages, ownership, bridgePath, ownerMarker);
|
|
221
|
+
if (added || ownershipBefore !== ownerMarker) {
|
|
222
|
+
mutated = true;
|
|
223
|
+
settings.packages = packages;
|
|
224
|
+
settings[OWNERSHIP_KEY] = ownership;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (mutated) {
|
|
229
|
+
writeSettings(settingsPath, settings);
|
|
230
|
+
console.info(`[plugin-bridge] Registered bridge for plugin "${pluginId}": ${bridgePath}`);
|
|
231
|
+
}
|
|
89
232
|
return { type: "ok" };
|
|
90
233
|
}
|
|
91
234
|
|
|
92
235
|
/**
|
|
93
236
|
* Remove a plugin's bridge entry from pi's settings.json.
|
|
94
|
-
*
|
|
95
|
-
*
|
|
237
|
+
* Removes BOTH the `dashboardPluginBridges` key AND the matching ownership-marked
|
|
238
|
+
* `packages[]` entry. No-op if neither exists.
|
|
239
|
+
* NEVER touches entries without matching ownership.
|
|
96
240
|
*/
|
|
97
241
|
export function deregisterPluginBridge(
|
|
98
242
|
pluginId: string,
|
|
@@ -101,14 +245,29 @@ export function deregisterPluginBridge(
|
|
|
101
245
|
const settingsPath = getSettingsPath(opts.homedir);
|
|
102
246
|
const settings = readSettings(settingsPath);
|
|
103
247
|
const managed = getManagedBridges(settings);
|
|
248
|
+
const ownership = getOwnershipMap(settings);
|
|
249
|
+
const packages = getPackages(settings);
|
|
104
250
|
const key = MANAGED_PREFIX + pluginId;
|
|
251
|
+
const ownerMarker = key;
|
|
252
|
+
|
|
253
|
+
let mutated = false;
|
|
105
254
|
|
|
106
|
-
if (
|
|
255
|
+
if (key in managed) {
|
|
256
|
+
delete managed[key];
|
|
257
|
+
settings.dashboardPluginBridges = managed;
|
|
258
|
+
mutated = true;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (removePackageEntry(packages, ownership, ownerMarker)) {
|
|
262
|
+
settings.packages = packages;
|
|
263
|
+
settings[OWNERSHIP_KEY] = ownership;
|
|
264
|
+
mutated = true;
|
|
265
|
+
}
|
|
107
266
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
267
|
+
if (mutated) {
|
|
268
|
+
writeSettings(settingsPath, settings);
|
|
269
|
+
console.info(`[plugin-bridge] Deregistered bridge for plugin "${pluginId}"`);
|
|
270
|
+
}
|
|
112
271
|
}
|
|
113
272
|
|
|
114
273
|
/**
|
|
@@ -127,6 +286,57 @@ export function registerAllPluginBridges(
|
|
|
127
286
|
return results;
|
|
128
287
|
}
|
|
129
288
|
|
|
289
|
+
/**
|
|
290
|
+
* One-shot reconciliation (Task 1.4): for each entry in
|
|
291
|
+
* `dashboardPluginBridges`, ensure a matching `packages[]` entry exists with
|
|
292
|
+
* the same ownership marker. Heals installs that pre-date the dual-write.
|
|
293
|
+
*
|
|
294
|
+
* Returns a list of `{ pluginId, bridgePath, action }` summaries — `"added"`
|
|
295
|
+
* when a new packages[] entry was inserted, `"already"` when no change needed.
|
|
296
|
+
*/
|
|
297
|
+
export function reconcilePluginBridgePackages(
|
|
298
|
+
opts: PluginBridgeRegisterOptions = {},
|
|
299
|
+
): Array<{ pluginId: string; bridgePath: string; action: "added" | "already" }> {
|
|
300
|
+
if (shouldSkipPackagesWrite(opts)) return [];
|
|
301
|
+
const settingsPath = getSettingsPath(opts.homedir);
|
|
302
|
+
const settings = readSettings(settingsPath);
|
|
303
|
+
const managed = getManagedBridges(settings);
|
|
304
|
+
const ownership = getOwnershipMap(settings);
|
|
305
|
+
const packages = getPackages(settings);
|
|
306
|
+
|
|
307
|
+
const summary: Array<{ pluginId: string; bridgePath: string; action: "added" | "already" }> = [];
|
|
308
|
+
let mutated = false;
|
|
309
|
+
|
|
310
|
+
for (const [key, bridgePath] of Object.entries(managed)) {
|
|
311
|
+
if (!key.startsWith(MANAGED_PREFIX)) continue;
|
|
312
|
+
const pluginId = key.slice(MANAGED_PREFIX.length);
|
|
313
|
+
const ownershipBefore = ownership[bridgePath];
|
|
314
|
+
const added = ensurePackageEntry(packages, ownership, bridgePath, key);
|
|
315
|
+
summary.push({ pluginId, bridgePath, action: added ? "added" : "already" });
|
|
316
|
+
if (added) mutated = true;
|
|
317
|
+
// `ensurePackageEntry` already wrote `ownership[bridgePath] = key`
|
|
318
|
+
// unconditionally. Compare the previous value (`ownershipBefore`) to
|
|
319
|
+
// detect whether persistence is needed for the ownership marker. This
|
|
320
|
+
// fixes a bug where the marker was set in memory but the file write
|
|
321
|
+
// was skipped because the *current* ownership equalled `key`.
|
|
322
|
+
if (ownershipBefore !== key) mutated = true;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (mutated) {
|
|
326
|
+
settings.packages = packages;
|
|
327
|
+
settings[OWNERSHIP_KEY] = ownership;
|
|
328
|
+
writeSettings(settingsPath, settings);
|
|
329
|
+
for (const { pluginId, bridgePath, action } of summary) {
|
|
330
|
+
if (action === "added") {
|
|
331
|
+
console.info(
|
|
332
|
+
`[plugin-bridge] Reconciled packages[] entry for plugin "${pluginId}": ${bridgePath}`,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return summary;
|
|
338
|
+
}
|
|
339
|
+
|
|
130
340
|
/**
|
|
131
341
|
* List all currently managed plugin bridge entries.
|
|
132
342
|
*/
|
|
@@ -137,3 +347,50 @@ export function listManagedBridges(
|
|
|
137
347
|
const settings = readSettings(settingsPath);
|
|
138
348
|
return getManagedBridges(settings);
|
|
139
349
|
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Inspect ownership map (for diagnostics / health).
|
|
353
|
+
*/
|
|
354
|
+
export function listManagedPackageOwnership(
|
|
355
|
+
opts: PluginBridgeRegisterOptions = {},
|
|
356
|
+
): Record<string, string> {
|
|
357
|
+
const settingsPath = getSettingsPath(opts.homedir);
|
|
358
|
+
const settings = readSettings(settingsPath);
|
|
359
|
+
return getOwnershipMap(settings);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Classify where a bridge path is registered in pi's settings.
|
|
364
|
+
*
|
|
365
|
+
* Precedence (intentional — packages[] is what pi actually loads, so it wins
|
|
366
|
+
* even when both keys point at the same path):
|
|
367
|
+
* 1. matching entry in `packages[]` → `"packages[]"`
|
|
368
|
+
* 2. matching value in `dashboardPluginBridges` → `"dashboardPluginBridges"`
|
|
369
|
+
* 3. no match → `"none"`
|
|
370
|
+
*
|
|
371
|
+
* Used by `/api/health.plugins[].bridgeLoadedFrom`. See change:
|
|
372
|
+
* fix-pi-flows-end-to-end (Group 2, task 2.2).
|
|
373
|
+
*/
|
|
374
|
+
export function classifyBridgeSource(
|
|
375
|
+
settings: unknown,
|
|
376
|
+
bridgePath: string,
|
|
377
|
+
): BridgeLoadSource {
|
|
378
|
+
if (!settings || typeof settings !== "object" || Array.isArray(settings)) {
|
|
379
|
+
return "none";
|
|
380
|
+
}
|
|
381
|
+
const s = settings as Record<string, unknown>;
|
|
382
|
+
|
|
383
|
+
const packages = Array.isArray(s.packages) ? s.packages : [];
|
|
384
|
+
for (const entry of packages) {
|
|
385
|
+
if (packageEntryPath(entry) === bridgePath) return "packages[]";
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const bridges = s.dashboardPluginBridges;
|
|
389
|
+
if (bridges && typeof bridges === "object" && !Array.isArray(bridges)) {
|
|
390
|
+
for (const value of Object.values(bridges as Record<string, unknown>)) {
|
|
391
|
+
if (value === bridgePath) return "dashboardPluginBridges";
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return "none";
|
|
396
|
+
}
|
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { DashboardEvent, CommandInfo, FlowInfo, SessionSource, ImageContent, FileEntry, TurnUsage, ContextUsage, ModelInfo, ProviderInfo, PiSessionInfo, OpenSpecPhase, RoleInfo, ExtensionUiModule, DecoratorDescriptor } from "./types.js";
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Bridge -> server: mirror of pi's native steering + follow-up queues, forwarded
|
|
8
|
+
* from pi's `queue_update` event. Server caches the latest snapshot per session
|
|
9
|
+
* in `SessionUiState.pendingQueues` and broadcasts via `session_updated`.
|
|
10
|
+
* See change: add-followup-edit-and-steer-cancel.
|
|
11
|
+
*/
|
|
12
|
+
export interface QueueUpdateToServerMessage {
|
|
13
|
+
type: "queue_update";
|
|
14
|
+
sessionId: string;
|
|
15
|
+
steering: string[];
|
|
16
|
+
followUp: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
6
19
|
// ── Extension → Server ──────────────────────────────────────────────
|
|
7
20
|
|
|
8
21
|
export interface SessionRegisterMessage {
|
|
@@ -372,7 +385,8 @@ export type ExtensionToServerMessage =
|
|
|
372
385
|
| UiDataListMessage
|
|
373
386
|
| ExtUiDecoratorMessage
|
|
374
387
|
| AssetRegisterMessage
|
|
375
|
-
| DispatchExtensionCommandMessage
|
|
388
|
+
| DispatchExtensionCommandMessage
|
|
389
|
+
| QueueUpdateToServerMessage;
|
|
376
390
|
|
|
377
391
|
// ── Server → Extension ──────────────────────────────────────────────
|
|
378
392
|
|
|
@@ -381,6 +395,8 @@ export interface SendPromptToExtensionMessage {
|
|
|
381
395
|
sessionId: string;
|
|
382
396
|
text: string;
|
|
383
397
|
images?: ImageContent[];
|
|
398
|
+
/** Delivery mode: "steer" (after current turn) or "followUp" (after agent finishes). Defaults to "followUp" when absent. See change: add-steering-message. */
|
|
399
|
+
delivery?: "steer" | "followUp";
|
|
384
400
|
}
|
|
385
401
|
|
|
386
402
|
export interface AbortToExtensionMessage {
|
|
@@ -574,6 +590,76 @@ export interface ServerRestartingExtensionMessage {
|
|
|
574
590
|
quiesceMs: number;
|
|
575
591
|
}
|
|
576
592
|
|
|
593
|
+
/**
|
|
594
|
+
* Server -> bridge: clear pi's steering queue for the named session.
|
|
595
|
+
* Bridge calls `pi.clearSteeringQueue()`. Idempotent on empty queue.
|
|
596
|
+
* Pi emits a fresh `queue_update` reflecting the empty array.
|
|
597
|
+
* See change: add-followup-edit-and-steer-cancel.
|
|
598
|
+
*/
|
|
599
|
+
export interface ClearSteeringQueueToExtensionMessage {
|
|
600
|
+
type: "clear_steering_queue";
|
|
601
|
+
sessionId: string;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Server -> bridge: clear pi's follow-up queue for the named session.
|
|
606
|
+
* Bridge calls `pi.clearFollowUpQueue()` and wipes its shadow `bridgeFollowUp[]`.
|
|
607
|
+
* Idempotent on empty queue.
|
|
608
|
+
* See change: add-followup-edit-and-steer-cancel.
|
|
609
|
+
*/
|
|
610
|
+
export interface ClearFollowupSlotToExtensionMessage {
|
|
611
|
+
type: "clear_followup_slot";
|
|
612
|
+
sessionId: string;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Server -> bridge (v1, deprecated): atomic replace of pi's follow-up slot.
|
|
617
|
+
* v2 prefers `edit_followup_entry { index: 0 }`. Bridge accepts both.
|
|
618
|
+
* See change: add-followup-edit-and-steer-cancel.
|
|
619
|
+
*/
|
|
620
|
+
export interface EditFollowupSlotToExtensionMessage {
|
|
621
|
+
type: "edit_followup_slot";
|
|
622
|
+
sessionId: string;
|
|
623
|
+
text: string;
|
|
624
|
+
images?: ImageContent[];
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Server -> bridge (v2): move the follow-up entry at `index` to position 0
|
|
629
|
+
* (head of the queue). Bridge rewrites its shadow + replays via
|
|
630
|
+
* `clearFollowUpQueue` then `sendUserMessage` for each entry in the new
|
|
631
|
+
* order. See change: add-followup-edit-and-steer-cancel.
|
|
632
|
+
*/
|
|
633
|
+
export interface PromoteFollowupEntryToExtensionMessage {
|
|
634
|
+
type: "promote_followup_entry";
|
|
635
|
+
sessionId: string;
|
|
636
|
+
index: number;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Server -> bridge (v2): remove the follow-up entry at `index`. Bridge
|
|
641
|
+
* rewrites its shadow + replays the surviving entries.
|
|
642
|
+
* See change: add-followup-edit-and-steer-cancel.
|
|
643
|
+
*/
|
|
644
|
+
export interface RemoveFollowupEntryToExtensionMessage {
|
|
645
|
+
type: "remove_followup_entry";
|
|
646
|
+
sessionId: string;
|
|
647
|
+
index: number;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Server -> bridge (v2): replace the follow-up entry at `index` with new text.
|
|
652
|
+
* Bridge rewrites its shadow + replays.
|
|
653
|
+
* See change: add-followup-edit-and-steer-cancel.
|
|
654
|
+
*/
|
|
655
|
+
export interface EditFollowupEntryToExtensionMessage {
|
|
656
|
+
type: "edit_followup_entry";
|
|
657
|
+
sessionId: string;
|
|
658
|
+
index: number;
|
|
659
|
+
text: string;
|
|
660
|
+
images?: ImageContent[];
|
|
661
|
+
}
|
|
662
|
+
|
|
577
663
|
export type ServerToExtensionMessage =
|
|
578
664
|
| SendPromptToExtensionMessage
|
|
579
665
|
| AbortToExtensionMessage
|
|
@@ -602,4 +688,10 @@ export type ServerToExtensionMessage =
|
|
|
602
688
|
| RequestRolesMessage
|
|
603
689
|
| UiManagementMessage
|
|
604
690
|
| KillProcessMessage
|
|
605
|
-
| ServerRestartingExtensionMessage
|
|
691
|
+
| ServerRestartingExtensionMessage
|
|
692
|
+
| ClearSteeringQueueToExtensionMessage
|
|
693
|
+
| ClearFollowupSlotToExtensionMessage
|
|
694
|
+
| EditFollowupSlotToExtensionMessage
|
|
695
|
+
| PromoteFollowupEntryToExtensionMessage
|
|
696
|
+
| RemoveFollowupEntryToExtensionMessage
|
|
697
|
+
| EditFollowupEntryToExtensionMessage;
|