@hachej/boring-workspace 0.1.36 → 0.1.37

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/dist/app-front.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { jsx as f, jsxs as ye, Fragment as ce } from "react/jsx-runtime";
2
2
  import { useEffect as A, useSyncExternalStore as vr, useMemo as C, useState as O, useCallback as w, useRef as j, useLayoutEffect as Sr } from "react";
3
3
  import { PiChatPanel as br, usePiSessions as yr } from "@hachej/boring-agent/front";
4
- import { aj as Pr, at as qe, au as bn, av as yn, aw as Pn, ax as An, ay as ze, az as pt, aA as ht, aB as En, aC as Ar, aD as He, aE as Er, U as un, aF as wr, q as Tr, aG as Nr, u as wn, aH as Dr, ag as Rr, aI as _r } from "./WorkspaceProvider-CpK401MG.js";
5
- import { T as Lr, C as Or, r as dn, w as xr, W as fn } from "./WorkspaceLoadingState-C664sU-y.js";
4
+ import { aj as Pr, at as qe, au as bn, av as yn, aw as Pn, ax as An, ay as ze, az as pt, aA as ht, aB as En, aC as Ar, aD as He, aE as Er, U as un, aF as wr, q as Tr, aG as Nr, u as wn, aH as Dr, ag as Rr, aI as _r } from "./WorkspaceProvider-CX_4aV6Z.js";
5
+ import { T as Lr, C as Or, r as dn, w as xr, W as fn } from "./WorkspaceLoadingState-C-whZTne.js";
6
6
  import { Sun as Mr, Moon as Cr } from "lucide-react";
7
7
  import { IconButton as Wr, ErrorState as Fr } from "@hachej/boring-ui-kit";
8
8
  function Gr() {
@@ -1,8 +1,8 @@
1
1
  import { PiPackageSource, PiExtensionFactory, CreateAgentAppOptions, ProvisionWorkspaceRuntimeOptions } from '@hachej/boring-agent/server';
2
2
  export { PiPackageSource as WorkspacePiPackageSource } from '@hachej/boring-agent/server';
3
3
  import { FastifyInstance } from 'fastify';
4
- import { W as WorkspaceServerPlugin, S as ServerBootstrapOptions, B as BoringPluginSourceInput, a as BoringPluginFrontTargetResolver, b as WorkspaceProvisioningContribution, c as WorkspaceRouteContribution, d as createInMemoryBridge } from './createInMemoryBridge-e7QdNLSA.js';
5
- export { e as ServerWorkspaceRuntimeProvisioningInput } from './createInMemoryBridge-e7QdNLSA.js';
4
+ import { W as WorkspaceServerPlugin, S as ServerBootstrapOptions, B as BoringPluginSourceInput, a as BoringPluginFrontTargetResolver, b as WorkspaceProvisioningContribution, c as WorkspaceRouteContribution, d as createInMemoryBridge } from './createInMemoryBridge-DSjZ9efK.js';
5
+ export { e as ServerWorkspaceRuntimeProvisioningInput } from './createInMemoryBridge-DSjZ9efK.js';
6
6
  import './manifest-C2vVgH_e.js';
7
7
  import './agent-tool-CB0RQyx9.js';
8
8
  import './ui-bridge-LeBuZqfA.js';
@@ -90,14 +90,6 @@ interface CreateWorkspaceAgentServerOptions extends WorkspaceAgentCreateOptions,
90
90
  force?: boolean;
91
91
  };
92
92
  validateUiPaths?: boolean;
93
- /**
94
- * Whether the canonical agent reload refreshes discovered package plugins.
95
- * When true, chat `/reload` refreshes package front/Pi metadata and reports
96
- * static-server restart warnings; dir-source server entries are re-imported
97
- * for diagnostics only. When false, initial static discovery still runs, but
98
- * dynamic Pi/system-prompt refresh is disabled. Defaults to true.
99
- */
100
- pluginHotReload?: boolean;
101
93
  /**
102
94
  * App-default plugin packages (by npm name OR absolute filesystem path).
103
95
  * Each entry is resolved at boot, registered as a Pi package (so Pi sees
@@ -113,28 +105,12 @@ interface CreateWorkspaceAgentServerOptions extends WorkspaceAgentCreateOptions,
113
105
  */
114
106
  defaultPluginPackages?: string[];
115
107
  /**
116
- * Absolute path to the app's `package.json`. When passed, the workspace
117
- * reads `package.json#boring.defaultPluginPackages: string[]` from it
118
- * and merges those entries with anything passed in
119
- * `defaultPluginPackages`. Relative entries in package.json resolve
120
- * against the package.json's own directory.
121
- *
122
- * Example app `package.json`:
123
- *
124
- * {
125
- * "name": "my-app",
126
- * "boring": {
127
- * "defaultPluginPackages": [
128
- * "@hachej/boring-ask-user",
129
- * "./src/plugins/playgroundDataCatalog"
130
- * ]
131
- * }
132
- * }
133
- *
134
- * Lets apps declare their plugin set in the canonical app manifest
135
- * instead of inside the server boot path.
108
+ * The host app's package root. Anchors npm-name resolution of
109
+ * `defaultPluginPackages` at the app's own node_modules (in addition to a
110
+ * walk-up from `workspaceRoot`). Pass when the workspace root does not
111
+ * live under the app directory.
136
112
  */
137
- appPackageJsonPath?: string;
113
+ appRoot?: string;
138
114
  /** Additional plugin collection roots to scan alongside workspace .pi/extensions and package/plugin-derived roots. */
139
115
  additionalBoringPluginDirs?: BoringPluginSourceInput[];
140
116
  /**
@@ -152,8 +128,6 @@ interface CreateWorkspaceAgentServerOptions extends WorkspaceAgentCreateOptions,
152
128
  installPluginAuthoring?: boolean;
153
129
  /** Optional host-owned front-target override for boring plugin list/event payloads. */
154
130
  boringPluginFrontTargetResolver?: BoringPluginFrontTargetResolver;
155
- /** Preserve legacy `/@fs/...` frontUrl payloads alongside frontTarget. Defaults to true. */
156
- boringPluginIncludeLegacyFrontUrl?: boolean;
157
131
  }
158
132
  declare const PLUGIN_AUTHORING_PROVISIONING_IDS: Set<string>;
159
133
  declare function omitPluginAuthoringProvisioning(plugins: WorkspaceRuntimeProvisioningInput[]): WorkspaceRuntimeProvisioningInput[];
@@ -191,15 +165,27 @@ declare function createWorkspaceAgentServer(opts?: CreateWorkspaceAgentServerOpt
191
165
 
192
166
  interface ResolveDefaultWorkspacePluginPackagePathsOptions {
193
167
  workspaceRoot?: string;
168
+ /**
169
+ * Internal plugin packages, listed explicitly in host boot code — npm
170
+ * package names (resolved via require.resolve) or absolute directory
171
+ * paths. Mirrors the front side, where internal plugins are statically
172
+ * imported in the app: both sides declare the same explicit list.
173
+ */
194
174
  defaultPluginPackages?: string[];
195
- appPackageJsonPath?: string;
175
+ /**
176
+ * Directory whose node_modules anchors npm-name resolution (the host
177
+ * package's own root). Defaults to walking up from `workspaceRoot`,
178
+ * then from this module's location.
179
+ */
180
+ anchorDir?: string;
196
181
  }
197
182
  /**
198
- * Resolve app-default plugin package declarations exactly once for app hosts.
199
- * This is shared by standalone workspace-agent and core composition so both
200
- * read `package.json#boring.defaultPluginPackages` with the same relative-path
201
- * and package-name semantics.
183
+ * Resolve each entry in `defaultPluginPackages` to an absolute package
184
+ * directory. Accepts either an npm-style name (resolved via
185
+ * `require.resolve('<name>/package.json')`) or an absolute filesystem
186
+ * path. THROWS on unresolved entries — a typo or missing dependency
187
+ * is an app boot-time error, not something to silently drop.
202
188
  */
203
- declare function resolveDefaultWorkspacePluginPackagePaths({ workspaceRoot, defaultPluginPackages, appPackageJsonPath, }?: ResolveDefaultWorkspacePluginPackagePathsOptions): string[];
189
+ declare function resolveDefaultWorkspacePluginPackagePaths({ workspaceRoot, defaultPluginPackages, anchorDir, }?: ResolveDefaultWorkspacePluginPackagePathsOptions): string[];
204
190
 
205
191
  export { type CollectWorkspaceAgentServerPluginsOptions, type CreateWorkspaceAgentServerOptions, type DirPluginEntry, PLUGIN_AUTHORING_PROVISIONING_IDS, type PluginResolveContext, type ResolveDefaultWorkspacePluginPackagePathsOptions, type WorkspaceAgentPiOptions, type WorkspaceAgentServerPluginCollection, type WorkspaceAgentServerPluginContext, type WorkspacePluginEntry, type WorkspacePluginPackagePiSnapshot, WorkspaceProvisioningContribution, WorkspaceRouteContribution, type WorkspaceRuntimeProvisioningInput, buildWorkspaceContextPrompt, collectWorkspaceAgentServerPlugins, createWorkspaceAgentServer, hasDirServerPlugin, omitPluginAuthoringProvisioning, provisionWorkspaceAgentServer, readWorkspacePluginPackagePiSnapshot, readWorkspacePluginPackageRuntimePlugins, resolveDefaultWorkspacePluginPackagePaths, resolveOnePluginEntry };
@@ -8,7 +8,7 @@ import {
8
8
  resolveMode,
9
9
  VERCEL_SANDBOX_WORKSPACE_ROOT
10
10
  } from "@hachej/boring-agent/server";
11
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
11
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
12
12
  import { dirname as dirname7, isAbsolute as isAbsolute5, join as join7, resolve as resolve7 } from "path";
13
13
  import { homedir } from "os";
14
14
  import { createRequire as createRequire4 } from "module";
@@ -987,7 +987,6 @@ var BoringPluginAssetManager = class {
987
987
  pluginDirs;
988
988
  errorRoot;
989
989
  frontTargetResolver;
990
- includeLegacyFrontUrl;
991
990
  loaded = /* @__PURE__ */ new Map();
992
991
  revisions = /* @__PURE__ */ new Map();
993
992
  listeners = /* @__PURE__ */ new Set();
@@ -998,7 +997,6 @@ var BoringPluginAssetManager = class {
998
997
  this.pluginDirs = options.pluginDirs;
999
998
  this.errorRoot = options.errorRoot ?? join4(process.cwd(), ".pi", "extensions");
1000
999
  this.frontTargetResolver = options.frontTargetResolver;
1001
- this.includeLegacyFrontUrl = options.includeLegacyFrontUrl ?? true;
1002
1000
  }
1003
1001
  /**
1004
1002
  * Replace the scanned source roots. Lets hosts re-resolve discovery inputs
@@ -1016,6 +1014,17 @@ var BoringPluginAssetManager = class {
1016
1014
  list() {
1017
1015
  return [...this.loaded.values()].map((plugin) => this.toListEntry(plugin));
1018
1016
  }
1017
+ /**
1018
+ * Plugins whose front lifecycle the SSE channel owns. Internal plugins are
1019
+ * app code — their front is statically bundled by the host app and must
1020
+ * never be re-imported through the hot-reload pipeline (a second module
1021
+ * instance would carry a fresh React context identity, breaking
1022
+ * provider ↔ panel lookups). They are loaded server-side (routes, agent
1023
+ * tools, Pi snapshot) but excluded from SSE replay and live events.
1024
+ */
1025
+ listExternal() {
1026
+ return [...this.loaded.values()].filter((plugin) => plugin.source.kind === "external").map((plugin) => this.toListEntry(plugin));
1027
+ }
1019
1028
  getError(pluginId) {
1020
1029
  const path = this.errorPath(pluginId);
1021
1030
  if (!path || !existsSync4(path)) return null;
@@ -1092,9 +1101,7 @@ ${prompts.join("\n\n")}` } : {}
1092
1101
  } catch {
1093
1102
  }
1094
1103
  }
1095
- const event = { type: "boring.plugin.unload", id, revision };
1096
- events.push(event);
1097
- this.emit(event);
1104
+ this.record(events, { type: "boring.plugin.unload", id, revision }, previous?.source);
1098
1105
  }
1099
1106
  for (const plugin of nextPlugins) {
1100
1107
  try {
@@ -1125,22 +1132,18 @@ ${prompts.join("\n\n")}` } : {}
1125
1132
  boring: plugin.boring,
1126
1133
  version: plugin.version,
1127
1134
  revision,
1128
- ...this.frontUrlPayload(plugin.frontUrl),
1129
1135
  ...frontTarget ? { frontTarget } : {},
1130
1136
  ...requiresRestart.length > 0 ? { requiresRestart } : {}
1131
1137
  };
1132
- events.push(event);
1133
- this.emit(event);
1138
+ this.record(events, event, plugin.source);
1134
1139
  } catch (error) {
1135
1140
  const revision = this.bumpRevision(plugin.id);
1136
1141
  const message = error instanceof Error ? error.stack ?? error.message : String(error);
1137
1142
  this.writeError(plugin.id, message);
1138
- const event = { type: "boring.plugin.error", id: plugin.id, revision, message };
1139
1143
  const loadError = { id: plugin.id, revision, message };
1140
1144
  this.lastErrors.set(plugin.id, loadError);
1141
1145
  errors.push(loadError);
1142
- events.push(event);
1143
- this.emit(event);
1146
+ this.record(events, { type: "boring.plugin.error", id: plugin.id, revision, message }, plugin.source);
1144
1147
  }
1145
1148
  }
1146
1149
  return { loaded: this.list(), events, errors };
@@ -1173,16 +1176,14 @@ Plugin dir: ${error.pluginDir}`;
1173
1176
  ...plugin.pi ? { pi: plugin.pi } : {},
1174
1177
  version: plugin.version,
1175
1178
  revision: plugin.revision,
1176
- ...this.frontUrlPayload(plugin.frontUrl),
1177
1179
  ...plugin.frontTarget ? { frontTarget: plugin.frontTarget } : {}
1178
1180
  };
1179
1181
  }
1180
- frontUrlPayload(frontUrl) {
1181
- if (!this.includeLegacyFrontUrl || !frontUrl) return {};
1182
- return { frontUrl };
1183
- }
1184
1182
  resolveFrontTarget(plugin, revision) {
1185
- if (!plugin.frontPath || !this.frontTargetResolver) return void 0;
1183
+ if (!plugin.frontPath) return void 0;
1184
+ if (!this.frontTargetResolver) {
1185
+ return plugin.frontUrl ? { kind: "module-url", entryUrl: plugin.frontUrl, revision } : void 0;
1186
+ }
1186
1187
  const frontEntrySubpath = typeof plugin.boring.front === "string" ? plugin.boring.front.replace(/^\.\//, "") : normalizePluginSubpath(plugin.rootDir, plugin.frontPath);
1187
1188
  const frontTarget = this.frontTargetResolver(plugin, {
1188
1189
  revision,
@@ -1191,6 +1192,16 @@ Plugin dir: ${error.pluginDir}`;
1191
1192
  if (!frontTarget) return void 0;
1192
1193
  return { ...frontTarget, revision };
1193
1194
  }
1195
+ /**
1196
+ * Append to the load result's events array and emit on the SSE channel —
1197
+ * unless the source is internal. Internal plugins are app code: their
1198
+ * events stay in the load result (for /reload diagnostics and restart
1199
+ * warnings) but never reach SSE subscribers (see listExternal).
1200
+ */
1201
+ record(events, event, source) {
1202
+ events.push(event);
1203
+ if (source?.kind !== "internal") this.emit(event);
1204
+ }
1194
1205
  emit(event) {
1195
1206
  for (const listener of [...this.listeners]) {
1196
1207
  try {
@@ -1275,14 +1286,13 @@ async function boringPluginRoutes(app, opts) {
1275
1286
  }
1276
1287
  write(event.type, payload);
1277
1288
  });
1278
- for (const plugin of manager.list()) {
1289
+ for (const plugin of manager.listExternal()) {
1279
1290
  write("boring.plugin.load", {
1280
1291
  type: "boring.plugin.load",
1281
1292
  id: plugin.id,
1282
1293
  boring: plugin.boring,
1283
1294
  version: plugin.version,
1284
1295
  revision: plugin.revision,
1285
- ...plugin.frontUrl ? { frontUrl: plugin.frontUrl } : {},
1286
1296
  ...plugin.frontTarget ? { frontTarget: plugin.frontTarget } : {},
1287
1297
  replay: true
1288
1298
  });
@@ -1882,31 +1892,18 @@ async function rebuildServerPlugins(opts) {
1882
1892
  }
1883
1893
 
1884
1894
  // src/app/server/defaultPluginPackages.ts
1885
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1895
+ import { existsSync as existsSync6 } from "fs";
1886
1896
  import { createRequire as createRequire3 } from "module";
1887
1897
  import { dirname as dirname6, isAbsolute as isAbsolute3, join as join6 } from "path";
1888
- function readAppManifestDefaultPlugins(appPackageJsonPath) {
1889
- if (!appPackageJsonPath || !existsSync6(appPackageJsonPath)) return [];
1890
- let pkg;
1891
- try {
1892
- pkg = JSON.parse(readFileSync5(appPackageJsonPath, "utf8"));
1893
- } catch {
1894
- return [];
1895
- }
1896
- const entries = pkg.boring?.defaultPluginPackages;
1897
- if (!Array.isArray(entries)) return [];
1898
- const pkgDir = dirname6(appPackageJsonPath);
1899
- return entries.filter((e) => typeof e === "string").map((entry) => {
1900
- if (entry.startsWith("./") || entry.startsWith("../")) {
1901
- return join6(pkgDir, entry);
1902
- }
1903
- return entry;
1904
- });
1905
- }
1906
- function resolveDefaultPluginPackagePaths(workspaceRoot, defaultPluginPackages) {
1898
+ function resolveDefaultWorkspacePluginPackagePaths({
1899
+ workspaceRoot = process.cwd(),
1900
+ defaultPluginPackages = [],
1901
+ anchorDir
1902
+ } = {}) {
1907
1903
  if (defaultPluginPackages.length === 0) return [];
1908
- const require5 = createRequire3(join6(workspaceRoot, "package.json"));
1909
- const requireFromHere = createRequire3(import.meta.url);
1904
+ const requireFromAnchor = anchorDir ? createRequire3(join6(anchorDir, "package.json")) : null;
1905
+ const requireFromWorkspace = createRequire3(join6(workspaceRoot, "package.json"));
1906
+ const resolvers = [requireFromAnchor, requireFromWorkspace].filter((req) => req !== null);
1910
1907
  const resolved = [];
1911
1908
  for (const entry of defaultPluginPackages) {
1912
1909
  if (isAbsolute3(entry)) {
@@ -1919,32 +1916,22 @@ function resolveDefaultPluginPackagePaths(workspaceRoot, defaultPluginPackages)
1919
1916
  continue;
1920
1917
  }
1921
1918
  let resolvedPath = null;
1922
- try {
1923
- resolvedPath = dirname6(require5.resolve(`${entry}/package.json`));
1924
- } catch {
1919
+ for (const req of resolvers) {
1925
1920
  try {
1926
- resolvedPath = dirname6(requireFromHere.resolve(`${entry}/package.json`));
1921
+ resolvedPath = dirname6(req.resolve(`${entry}/package.json`));
1922
+ break;
1927
1923
  } catch {
1928
- throw new Error(
1929
- `defaultPluginPackages: cannot resolve "${entry}" \u2014 install it as a dep of the app (or workspace root) so require.resolve can find its package.json. Pass an absolute path instead if the package lives outside node_modules.`
1930
- );
1931
1924
  }
1932
1925
  }
1926
+ if (!resolvedPath) {
1927
+ throw new Error(
1928
+ `defaultPluginPackages: cannot resolve "${entry}" \u2014 install it as a dep of the app so require.resolve can find its package.json. Pass an absolute path instead if the package lives outside node_modules.`
1929
+ );
1930
+ }
1933
1931
  resolved.push(resolvedPath);
1934
1932
  }
1935
1933
  return resolved;
1936
1934
  }
1937
- function resolveDefaultWorkspacePluginPackagePaths({
1938
- workspaceRoot = process.cwd(),
1939
- defaultPluginPackages = [],
1940
- appPackageJsonPath
1941
- } = {}) {
1942
- const manifestPluginPackages = readAppManifestDefaultPlugins(appPackageJsonPath);
1943
- return resolveDefaultPluginPackagePaths(workspaceRoot, [
1944
- ...manifestPluginPackages,
1945
- ...defaultPluginPackages
1946
- ]);
1947
- }
1948
1935
 
1949
1936
  // src/server/bridge/createInMemoryBridge.ts
1950
1937
  var MAX_PENDING_COMMANDS = 1e3;
@@ -2622,7 +2609,7 @@ function resolveWorkspacePackageRoot() {
2622
2609
  ];
2623
2610
  for (const candidate of candidates) {
2624
2611
  try {
2625
- const pkg = JSON.parse(readFileSync6(join7(candidate, "package.json"), "utf8"));
2612
+ const pkg = JSON.parse(readFileSync5(join7(candidate, "package.json"), "utf8"));
2626
2613
  if (pkg.name === "@hachej/boring-workspace") return candidate;
2627
2614
  } catch {
2628
2615
  }
@@ -2632,7 +2619,7 @@ function resolveWorkspacePackageRoot() {
2632
2619
  function readPackageVersion(packageRoot) {
2633
2620
  if (!packageRoot) return void 0;
2634
2621
  try {
2635
- const pkg = JSON.parse(readFileSync6(join7(packageRoot, "package.json"), "utf8"));
2622
+ const pkg = JSON.parse(readFileSync5(join7(packageRoot, "package.json"), "utf8"));
2636
2623
  return typeof pkg.version === "string" && pkg.version.length > 0 ? pkg.version : void 0;
2637
2624
  } catch {
2638
2625
  return void 0;
@@ -2649,7 +2636,7 @@ function resolveBoringPiPackageRoot() {
2649
2636
  ];
2650
2637
  for (const candidate of candidates) {
2651
2638
  try {
2652
- const pkg = JSON.parse(readFileSync6(join7(candidate, "package.json"), "utf8"));
2639
+ const pkg = JSON.parse(readFileSync5(join7(candidate, "package.json"), "utf8"));
2653
2640
  if (pkg.name === "@hachej/boring-pi") return candidate;
2654
2641
  } catch {
2655
2642
  }
@@ -2662,7 +2649,7 @@ function resolveBoringPiPackageRoot() {
2662
2649
  }
2663
2650
  function isUsableBoringUiPluginCliPackageRoot(candidate) {
2664
2651
  try {
2665
- const pkg = JSON.parse(readFileSync6(join7(candidate, "package.json"), "utf8"));
2652
+ const pkg = JSON.parse(readFileSync5(join7(candidate, "package.json"), "utf8"));
2666
2653
  return pkg.name === "@hachej/boring-ui-plugin-cli" && existsSync7(join7(candidate, "dist", "bin.js"));
2667
2654
  } catch {
2668
2655
  return false;
@@ -2800,7 +2787,7 @@ function resolveLocalPiPackageSource(settingsDir, source) {
2800
2787
  function readPiSettingsBoringPluginSources(settingsPath, workspaceId) {
2801
2788
  let raw;
2802
2789
  try {
2803
- raw = JSON.parse(readFileSync6(settingsPath, "utf8"));
2790
+ raw = JSON.parse(readFileSync5(settingsPath, "utf8"));
2804
2791
  } catch {
2805
2792
  return [];
2806
2793
  }
@@ -2920,11 +2907,10 @@ async function createWorkspaceAgentServer(opts = {}) {
2920
2907
  const ctx = { workspaceRoot, bridge };
2921
2908
  const defaultPluginPackagePaths = resolveDefaultWorkspacePluginPackagePaths({
2922
2909
  workspaceRoot,
2923
- appPackageJsonPath: opts.appPackageJsonPath,
2924
- defaultPluginPackages: opts.defaultPluginPackages
2910
+ defaultPluginPackages: opts.defaultPluginPackages,
2911
+ anchorDir: opts.appRoot
2925
2912
  });
2926
- const pluginHotReload = opts.pluginHotReload ?? true;
2927
- const defaultPluginDirEntries = defaultPluginPackagePaths.map((dir) => ({ dir, hotReload: pluginHotReload })).filter((entry) => hasDirServerPlugin(entry));
2913
+ const defaultPluginDirEntries = defaultPluginPackagePaths.map((dir) => ({ dir, hotReload: true })).filter((entry) => hasDirServerPlugin(entry));
2928
2914
  const allPluginEntries = [
2929
2915
  ...defaultPluginDirEntries,
2930
2916
  ...opts.plugins ?? []
@@ -2958,7 +2944,7 @@ async function createWorkspaceAgentServer(opts = {}) {
2958
2944
  return boringPluginDirs;
2959
2945
  };
2960
2946
  refreshBoringPluginDirs();
2961
- const staticPluginPackagePiSnapshot = pluginHotReload ? emptyPackageJsonPiSnapshot() : readWorkspacePluginPackagePiSnapshot(refreshBoringPluginDirs());
2947
+ const staticPluginPackagePiSnapshot = emptyPackageJsonPiSnapshot();
2962
2948
  const staticPiSkillPaths = [
2963
2949
  ...baseStaticPiSkillPaths,
2964
2950
  ...staticPluginPackagePiSnapshot.additionalSkillPaths
@@ -2971,12 +2957,11 @@ async function createWorkspaceAgentServer(opts = {}) {
2971
2957
  ...baseStaticPiExtensionPaths,
2972
2958
  ...staticPluginPackagePiSnapshot.extensionPaths
2973
2959
  ];
2974
- const getHotReloadablePiResources = pluginHotReload ? () => readWorkspacePluginPackagePiSnapshot(refreshBoringPluginDirs()) : void 0;
2960
+ const getHotReloadablePiResources = () => readWorkspacePluginPackagePiSnapshot(refreshBoringPluginDirs());
2975
2961
  const boringAssetManager = new BoringPluginAssetManager({
2976
2962
  pluginDirs: boringPluginDirs,
2977
2963
  errorRoot: join7(workspaceRoot, ".pi", "extensions"),
2978
- frontTargetResolver: opts.boringPluginFrontTargetResolver,
2979
- includeLegacyFrontUrl: opts.boringPluginIncludeLegacyFrontUrl
2964
+ frontTargetResolver: opts.boringPluginFrontTargetResolver
2980
2965
  });
2981
2966
  const runtimeBackendRegistry = new RuntimeBackendRegistry();
2982
2967
  const buildRuntimeProvisioningInputs = () => {
@@ -3044,19 +3029,17 @@ async function createWorkspaceAgentServer(opts = {}) {
3044
3029
  beforeReload: async () => {
3045
3030
  let restart_warnings = [];
3046
3031
  let diagnostics = [];
3047
- if (pluginHotReload) {
3048
- refreshBoringPluginDirs();
3049
- const scan = await boringAssetManager.load();
3050
- const backendReload = await runtimeBackendRegistry.reloadFromLoadedPlugins(boringAssetManager.inspectLoaded());
3051
- restart_warnings = collectRestartWarnings(scan.events);
3052
- const scanDiagnostics = scan.errors.map((error) => ({
3053
- source: `boring plugin asset scan (${error.id})`,
3054
- message: error.message,
3055
- pluginId: error.id
3056
- }));
3057
- const rebuild = await rebuildPlugins();
3058
- diagnostics = [...scanDiagnostics, ...backendReload.diagnostics, ...rebuild.diagnostics];
3059
- }
3032
+ refreshBoringPluginDirs();
3033
+ const scan = await boringAssetManager.load();
3034
+ const backendReload = await runtimeBackendRegistry.reloadFromLoadedPlugins(boringAssetManager.inspectLoaded());
3035
+ restart_warnings = collectRestartWarnings(scan.events);
3036
+ const scanDiagnostics = scan.errors.map((error) => ({
3037
+ source: `boring plugin asset scan (${error.id})`,
3038
+ message: error.message,
3039
+ pluginId: error.id
3040
+ }));
3041
+ const rebuild = await rebuildPlugins();
3042
+ diagnostics = [...scanDiagnostics, ...backendReload.diagnostics, ...rebuild.diagnostics];
3060
3043
  await runRuntimeProvisioning();
3061
3044
  const callerResult = await opts.beforeReload?.();
3062
3045
  const callerRestartWarnings = callerResult && typeof callerResult === "object" ? callerResult.restart_warnings ?? [] : [];
@@ -3079,7 +3062,7 @@ async function createWorkspaceAgentServer(opts = {}) {
3079
3062
  extensionFactories: pluginCollection.agentOptions.pi?.extensionFactories,
3080
3063
  getHotReloadableResources: getHotReloadablePiResources
3081
3064
  },
3082
- systemPromptDynamic: pluginHotReload ? () => aggregatePluginPrompts(boringAssetManager) : void 0
3065
+ systemPromptDynamic: () => aggregatePluginPrompts(boringAssetManager)
3083
3066
  });
3084
3067
  refreshBoringPluginDirs();
3085
3068
  await boringAssetManager.load();
@@ -1 +1 @@
1
- .dv-shell{--dv-background-color: var(--background);--dv-paneview-header-border-color: var(--border);--dv-tabs-and-actions-container-font-size: .8125rem;--dv-tabs-and-actions-container-height: 52px;--dv-tab-close-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E");--dv-group-view-background-color: var(--background);--dv-tabs-and-actions-container-background-color: var(--background);--dv-activegroup-visiblepanel-tab-background-color: var(--background);--dv-activegroup-hiddenpanel-tab-background-color: var(--muted);--dv-inactivegroup-visiblepanel-tab-background-color: var(--background);--dv-inactivegroup-hiddenpanel-tab-background-color: var(--muted);--dv-activegroup-visiblepanel-tab-color: var(--foreground);--dv-activegroup-hiddenpanel-tab-color: var(--muted-foreground);--dv-inactivegroup-visiblepanel-tab-color: var(--foreground);--dv-inactivegroup-hiddenpanel-tab-color: var(--muted-foreground);--dv-tab-divider-color: transparent;--dv-drag-over-background-color: oklch(from var(--accent) l c h / .3);--dv-drag-over-border-color: var(--accent);--dv-separator-border: var(--border);color:var(--foreground);background-color:var(--background)}.dv-shell .dv-tabs-and-actions-container,.dv-shell .tabs-and-actions-container{background-color:var(--background)!important;border-bottom:1px solid oklch(from var(--border) l c h / .4);padding:6px 8px 0;gap:4px;align-items:flex-end}.dv-shell .dv-tabs-container,.dv-shell .tab-container{background-color:transparent!important;gap:4px;align-self:stretch;display:flex;align-items:flex-end}.workbench-dockview .dv-shell .dv-tabs-and-actions-container,.workbench-dockview .dv-shell .tabs-and-actions-container,.workbench-dockview .dv-tabs-and-actions-container,.workbench-dockview .tabs-and-actions-container{height:44px!important}.workbench-dockview[data-collapsed-sources=true] .dv-tabs-and-actions-container,.workbench-dockview[data-collapsed-sources=true] .tabs-and-actions-container{padding-left:44px!important}.workbench-dockview .dv-tabs-and-actions-container,.workbench-dockview .tabs-and-actions-container{padding-right:44px!important}.dv-shell .dv-tab,.dv-shell .tab{color:var(--muted-foreground)!important;background-color:transparent!important;border:1px solid transparent;border-top-left-radius:8px;border-top-right-radius:8px;transition:color .18s cubic-bezier(.22,1,.36,1),background-color .18s cubic-bezier(.22,1,.36,1),border-color .18s cubic-bezier(.22,1,.36,1);min-width:120px;max-width:220px;padding:0;height:34px;align-self:end;font-size:12.5px;letter-spacing:-.01em}.dv-shell .dv-tab:hover,.dv-shell .tab:hover{color:var(--foreground)!important;background-color:oklch(from var(--foreground) l c h / .04)!important}.dv-shell .dv-tab>*,.dv-shell .tab>*{width:100%;height:100%}.dv-shell .dv-tab.dv-active-tab,.dv-shell .tab.active-tab{color:var(--foreground)!important;background-color:var(--background)!important;border-color:oklch(from var(--border) l c h / .5);border-bottom-color:var(--background);margin-bottom:-1px;position:relative;z-index:1;font-weight:500}.dv-shell .dv-tab.dv-active-tab:before,.dv-shell .tab.active-tab:before{content:"";position:absolute;left:10px;right:10px;top:-1px;height:2px;background:var(--accent);border-radius:0 0 2px 2px;opacity:0;transition:opacity .2s cubic-bezier(.22,1,.36,1)}.dv-shell .dv-tab.dv-active-tab:hover:before,.dv-shell .tab.active-tab:hover:before{opacity:.7}.dv-shell .sash-container .sash,.dv-shell .dv-sash-container .dv-sash{transition:background-color .2s}.dv-shell .sash-container .sash:hover,.dv-shell .sash-container .sash.active,.dv-shell .dv-sash-container .dv-sash:hover,.dv-shell .dv-sash-container .dv-sash.dv-active{background-color:var(--primary);transition-delay:.15s}.dv-shell .drop-target-dropzone>.drop-target-selection,.dv-shell .dv-drop-target-dropzone>.dv-drop-target-selection{background-color:oklch(from var(--primary) l c h / .15);border:2px dashed var(--primary);border-radius:calc(var(--radius) - 2px)}.dv-shell .watermark,.dv-shell .dv-watermark{color:var(--muted-foreground)}.dv-shell,.dv-shell .dv-dockview,.dv-shell .dv-groupview,.dv-shell .groupview,.dv-shell .groupview>.content-container,.dv-shell .dv-view-container,.dv-shell .view-container{background-color:var(--background)}.dv-shell .dv-groupview,.dv-shell .groupview{color:var(--foreground)}.dv-shell .right-actions-container,.dv-shell .left-actions-container,.dv-shell .dv-right-actions-container,.dv-shell .dv-left-actions-container{color:var(--muted-foreground);display:flex;align-items:center;align-self:stretch}.dv-shell .right-actions-container:hover,.dv-shell .left-actions-container:hover,.dv-shell .dv-right-actions-container:hover,.dv-shell .dv-left-actions-container:hover{color:var(--foreground)}.dv-shell .dv-drag-image{opacity:.85;border:1px solid var(--border);border-radius:calc(var(--radius) - 2px);box-shadow:0 4px 12px #00000026}.dv-chat-stage{--dv-tabs-and-actions-container-height: 32px;--dv-tabs-and-actions-container-font-size: .75rem;--dv-activegroup-visiblepanel-tab-background-color: transparent;--dv-activegroup-hiddenpanel-tab-background-color: transparent;--dv-inactivegroup-visiblepanel-tab-background-color: transparent;--dv-inactivegroup-hiddenpanel-tab-background-color: transparent}.dv-shell.dv-chat-stage .dv-tabs-and-actions-container{border-bottom:none;padding:0;gap:0;align-items:stretch}.dv-shell.dv-chat-stage .dv-tabs-and-actions-container.dv-single-tab .dv-tabs-container{width:100%}.dv-shell.dv-chat-stage .dv-tab,.dv-shell.dv-chat-stage .dv-tab.dv-active-tab{width:100%;height:100%;min-width:0;max-width:none;flex:1 1 auto;align-self:stretch;margin-bottom:0;padding:0;border:none;border-radius:0;background-color:transparent!important}.dv-shell.dv-chat-stage .dv-tab.dv-active-tab:before{content:none}.dv-chat-stage .dv-default-tab-action{display:none}.dv-chat-stage .dv-groupview{position:relative}.dv-chat-stage .dv-groupview:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:40;pointer-events:none;background:transparent;transition:background-color .22s cubic-bezier(.22,1,.36,1),box-shadow .22s cubic-bezier(.22,1,.36,1)}[data-boring-workspace-part=chat-pane-stage][data-multi-pane=true] .dv-groupview:not(.dv-active-group):after{background:oklch(from var(--foreground) l c h / .035)}
1
+ .dv-shell{--dv-background-color: var(--background);--dv-paneview-header-border-color: var(--border);--dv-tabs-and-actions-container-font-size: .8125rem;--dv-tabs-and-actions-container-height: 52px;--dv-tab-close-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E");--dv-group-view-background-color: var(--background);--dv-tabs-and-actions-container-background-color: var(--background);--dv-activegroup-visiblepanel-tab-background-color: var(--background);--dv-activegroup-hiddenpanel-tab-background-color: var(--muted);--dv-inactivegroup-visiblepanel-tab-background-color: var(--background);--dv-inactivegroup-hiddenpanel-tab-background-color: var(--muted);--dv-activegroup-visiblepanel-tab-color: var(--foreground);--dv-activegroup-hiddenpanel-tab-color: var(--muted-foreground);--dv-inactivegroup-visiblepanel-tab-color: var(--foreground);--dv-inactivegroup-hiddenpanel-tab-color: var(--muted-foreground);--dv-tab-divider-color: transparent;--dv-drag-over-background-color: oklch(from var(--accent) l c h / .3);--dv-drag-over-border-color: var(--accent);--dv-separator-border: var(--border);color:var(--foreground);background-color:var(--background)}.dv-shell .dv-tabs-and-actions-container,.dv-shell .tabs-and-actions-container{background-color:var(--background)!important;border-bottom:1px solid oklch(from var(--border) l c h / .4);padding:6px 8px 0;gap:4px;align-items:flex-end}.dv-shell .dv-tabs-container,.dv-shell .tab-container{background-color:transparent!important;gap:4px;align-self:stretch;display:flex;align-items:flex-end}.workbench-dockview .dv-shell .dv-tabs-and-actions-container,.workbench-dockview .dv-shell .tabs-and-actions-container,.workbench-dockview .dv-tabs-and-actions-container,.workbench-dockview .tabs-and-actions-container{height:44px!important}.workbench-dockview[data-collapsed-sources=true] .dv-tabs-and-actions-container,.workbench-dockview[data-collapsed-sources=true] .tabs-and-actions-container{padding-left:44px!important}.workbench-dockview .dv-tabs-and-actions-container,.workbench-dockview .tabs-and-actions-container{padding-right:44px!important}.dv-shell .dv-tab,.dv-shell .tab{color:var(--muted-foreground)!important;background-color:transparent!important;border:1px solid transparent;border-top-left-radius:8px;border-top-right-radius:8px;transition:color .18s cubic-bezier(.22,1,.36,1),background-color .18s cubic-bezier(.22,1,.36,1),border-color .18s cubic-bezier(.22,1,.36,1);min-width:120px;max-width:220px;padding:0;height:34px;align-self:end;font-size:12.5px;letter-spacing:-.01em}.dv-shell .dv-tab:hover,.dv-shell .tab:hover{color:var(--foreground)!important;background-color:oklch(from var(--foreground) l c h / .04)!important}.dv-shell .dv-tab>*,.dv-shell .tab>*{width:100%;height:100%}.dv-shell .dv-tab.dv-active-tab,.dv-shell .tab.active-tab{color:var(--foreground)!important;background-color:var(--background)!important;border-color:oklch(from var(--border) l c h / .5);border-bottom-color:var(--background);margin-bottom:-1px;position:relative;z-index:1;font-weight:500}.dv-shell .dv-tab.dv-active-tab:before,.dv-shell .tab.active-tab:before{content:"";position:absolute;left:10px;right:10px;top:-1px;height:2px;background:var(--accent);border-radius:0 0 2px 2px;opacity:0;transition:opacity .2s cubic-bezier(.22,1,.36,1)}.dv-shell .dv-tab.dv-active-tab:hover:before,.dv-shell .tab.active-tab:hover:before{opacity:.7}.dv-shell{--dv-sash-color: transparent;--dv-active-sash-color: transparent;--dv-active-sash-transition-delay: 0s}.dv-shell .sash-container .sash,.dv-shell .dv-sash-container .dv-sash{transition:box-shadow .16s cubic-bezier(.22,1,.36,1),background-color .16s cubic-bezier(.22,1,.36,1)}.dv-shell .dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash{width:12px;margin-left:-4px}.dv-shell .dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash{height:12px;margin-top:-4px}.dv-shell .dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash:hover,.dv-shell .dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash:active{box-shadow:inset 0 0 0 1px oklch(from var(--primary) l c h / .45),inset 5px 0 oklch(from var(--primary) l c h / .35),inset 6px 0 oklch(from var(--primary) l c h / .35)}.dv-shell .dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash:hover,.dv-shell .dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash:active{box-shadow:inset 0 0 0 1px oklch(from var(--primary) l c h / .45),inset 0 5px oklch(from var(--primary) l c h / .35),inset 0 6px oklch(from var(--primary) l c h / .35)}.dv-shell .drop-target-dropzone>.drop-target-selection,.dv-shell .dv-drop-target-dropzone>.dv-drop-target-selection{background-color:oklch(from var(--primary) l c h / .15);border:2px dashed var(--primary);border-radius:calc(var(--radius) - 2px)}.dv-shell .watermark,.dv-shell .dv-watermark{color:var(--muted-foreground)}.dv-shell,.dv-shell .dv-dockview,.dv-shell .dv-groupview,.dv-shell .groupview,.dv-shell .groupview>.content-container,.dv-shell .dv-view-container,.dv-shell .view-container{background-color:var(--background)}.dv-shell .dv-groupview,.dv-shell .groupview{color:var(--foreground)}.dv-shell .right-actions-container,.dv-shell .left-actions-container,.dv-shell .dv-right-actions-container,.dv-shell .dv-left-actions-container{color:var(--muted-foreground);display:flex;align-items:center;align-self:stretch}.dv-shell .right-actions-container:hover,.dv-shell .left-actions-container:hover,.dv-shell .dv-right-actions-container:hover,.dv-shell .dv-left-actions-container:hover{color:var(--foreground)}.dv-shell .dv-drag-image{opacity:.85;border:1px solid var(--border);border-radius:calc(var(--radius) - 2px);box-shadow:0 4px 12px #00000026}.dv-chat-stage{--dv-tabs-and-actions-container-height: 32px;--dv-tabs-and-actions-container-font-size: .75rem;--dv-activegroup-visiblepanel-tab-background-color: transparent;--dv-activegroup-hiddenpanel-tab-background-color: transparent;--dv-inactivegroup-visiblepanel-tab-background-color: transparent;--dv-inactivegroup-hiddenpanel-tab-background-color: transparent}.dv-shell.dv-chat-stage .dv-tabs-and-actions-container{border-bottom:none;padding:0;gap:0;align-items:stretch}.dv-shell.dv-chat-stage .dv-tabs-and-actions-container.dv-single-tab .dv-tabs-container{width:100%}.dv-shell.dv-chat-stage .dv-tab,.dv-shell.dv-chat-stage .dv-tab.dv-active-tab{width:100%;height:100%;min-width:0;max-width:none;flex:1 1 auto;align-self:stretch;margin-bottom:0;padding:0;border:none;border-radius:0;background-color:transparent!important}.dv-shell.dv-chat-stage .dv-tab.dv-active-tab:before{content:none}.dv-chat-stage .dv-default-tab-action{display:none}.dv-chat-stage .dv-groupview{position:relative}.dv-chat-stage .dv-groupview:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:40;pointer-events:none;background:transparent;transition:background-color .22s cubic-bezier(.22,1,.36,1),box-shadow .22s cubic-bezier(.22,1,.36,1)}[data-boring-workspace-part=chat-pane-stage][data-multi-pane=true] .dv-groupview:not(.dv-active-group):after{background:oklch(from var(--foreground) l c h / .035)}
@@ -18,14 +18,23 @@ interface BoringPluginNativeFrontTarget$1 {
18
18
  revision: number;
19
19
  trust: BoringPluginNativeFrontTargetTrust$1;
20
20
  }
21
- type BoringPluginFrontTarget$1 = BoringPluginNativeFrontTarget$1;
21
+ /**
22
+ * Plugin front served as a plain browser module URL — the Vite-dev transport
23
+ * (`/@fs/...`). Hosts running a Vite dev server let Vite transform the entry;
24
+ * the CLI's runtime host mints `native` targets instead.
25
+ */
26
+ interface BoringPluginModuleUrlFrontTarget {
27
+ kind: "module-url";
28
+ entryUrl: string;
29
+ revision: number;
30
+ }
31
+ type BoringPluginFrontTarget$1 = BoringPluginNativeFrontTarget$1 | BoringPluginModuleUrlFrontTarget;
22
32
  type BoringPluginEvent$1 = {
23
33
  type: "boring.plugin.load";
24
34
  id: string;
25
35
  boring: BoringPackageBoringField;
26
36
  version: string;
27
37
  revision: number;
28
- frontUrl?: string;
29
38
  frontTarget?: BoringPluginFrontTarget$1;
30
39
  } | {
31
40
  type: "boring.plugin.unload";
@@ -43,7 +52,6 @@ interface BoringPluginListEntry$1 {
43
52
  pi?: BoringPackagePiField;
44
53
  version: string;
45
54
  revision: number;
46
- frontUrl?: string;
47
55
  frontTarget?: BoringPluginFrontTarget$1;
48
56
  }
49
57
 
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { f as WorkspaceServerPluginAsset, g as BoringServerPluginManifest, B as BoringPluginSourceInput, a as BoringPluginFrontTargetResolver, h as BoringPluginListEntry, i as BoringPluginFrontTarget, j as BoringPluginSource, k as BoringPluginEvent, P as PluginRestartSurface } from './createInMemoryBridge-e7QdNLSA.js';
2
- export { l as BoringPluginFrontTargetResolverContext, m as BoringPluginNativeFrontTarget, n as BoringPluginNativeFrontTargetTrust, o as BoringPluginSourceKind, S as ServerBootstrapOptions, p as ServerBootstrapResult, b as WorkspaceProvisioningContribution, c as WorkspaceRouteContribution, W as WorkspaceServerPlugin, q as bootstrapServer, d as createInMemoryBridge, r as defineServerPlugin, v as validateServerPlugin } from './createInMemoryBridge-e7QdNLSA.js';
1
+ import { f as WorkspaceServerPluginAsset, g as BoringServerPluginManifest, B as BoringPluginSourceInput, a as BoringPluginFrontTargetResolver, h as BoringPluginListEntry, i as BoringPluginFrontTarget, j as BoringPluginSource, k as BoringPluginEvent, P as PluginRestartSurface } from './createInMemoryBridge-DSjZ9efK.js';
2
+ export { l as BoringPluginFrontTargetResolverContext, m as BoringPluginNativeFrontTarget, n as BoringPluginNativeFrontTargetTrust, o as BoringPluginSourceKind, S as ServerBootstrapOptions, p as ServerBootstrapResult, b as WorkspaceProvisioningContribution, c as WorkspaceRouteContribution, W as WorkspaceServerPlugin, q as bootstrapServer, d as createInMemoryBridge, r as defineServerPlugin, v as validateServerPlugin } from './createInMemoryBridge-DSjZ9efK.js';
3
3
  import { FastifyRequest, FastifyInstance } from 'fastify';
4
4
  import { U as UiBridge } from './ui-bridge-LeBuZqfA.js';
5
5
  export { C as CommandResult, a as UiCommand, b as UiState } from './ui-bridge-LeBuZqfA.js';
@@ -189,15 +189,11 @@ interface BoringPluginAssetManagerOptions {
189
189
  */
190
190
  errorRoot?: string;
191
191
  /**
192
- * Optional host-owned runtime front-target resolver. When omitted, list/event
193
- * payloads preserve the existing `frontUrl` (`/@fs/...`) fallback only.
192
+ * Optional host-owned runtime front-target resolver (the CLI's runtime
193
+ * module host mints `native` targets). When omitted, plugins with a front
194
+ * entry get a `module-url` target pointing at the Vite-dev `/@fs/...` URL.
194
195
  */
195
196
  frontTargetResolver?: BoringPluginFrontTargetResolver;
196
- /**
197
- * Keep legacy `/@fs/...` frontUrl payloads alongside frontTarget. Defaults
198
- * to true for back-compat; packaged CLI folder/workspaces mode can disable it.
199
- */
200
- includeLegacyFrontUrl?: boolean;
201
197
  }
202
198
  interface LoadBoringAssetsError {
203
199
  id: string;
@@ -230,7 +226,6 @@ declare class BoringPluginAssetManager {
230
226
  private pluginDirs;
231
227
  private readonly errorRoot;
232
228
  private readonly frontTargetResolver?;
233
- private readonly includeLegacyFrontUrl;
234
229
  private readonly loaded;
235
230
  private readonly revisions;
236
231
  private readonly listeners;
@@ -248,6 +243,15 @@ declare class BoringPluginAssetManager {
248
243
  setPluginDirs(pluginDirs: BoringPluginSourceInput[]): void;
249
244
  preflight(): BoringPluginPreflightResult;
250
245
  list(): BoringPluginListEntry[];
246
+ /**
247
+ * Plugins whose front lifecycle the SSE channel owns. Internal plugins are
248
+ * app code — their front is statically bundled by the host app and must
249
+ * never be re-imported through the hot-reload pipeline (a second module
250
+ * instance would carry a fresh React context identity, breaking
251
+ * provider ↔ panel lookups). They are loaded server-side (routes, agent
252
+ * tools, Pi snapshot) but excluded from SSE replay and live events.
253
+ */
254
+ listExternal(): BoringPluginListEntry[];
251
255
  getError(pluginId: string): string | null;
252
256
  getErrors(): LoadBoringAssetsError[];
253
257
  inspectLoaded(): LoadedBoringPluginInspection[];
@@ -259,8 +263,14 @@ declare class BoringPluginAssetManager {
259
263
  private collectPreflightErrors;
260
264
  private bumpRevision;
261
265
  private toListEntry;
262
- private frontUrlPayload;
263
266
  private resolveFrontTarget;
267
+ /**
268
+ * Append to the load result's events array and emit on the SSE channel —
269
+ * unless the source is internal. Internal plugins are app code: their
270
+ * events stay in the load result (for /reload diagnostics and restart
271
+ * warnings) but never reach SSE subscribers (see listExternal).
272
+ */
273
+ private record;
264
274
  private emit;
265
275
  private errorPath;
266
276
  private writeError;
@@ -368,10 +378,18 @@ declare class RuntimeBackendRegistry {
368
378
  private closeOnce;
369
379
  }
370
380
 
381
+ /**
382
+ * Minimal dispatch surface the gateway needs. RuntimeBackendRegistry satisfies
383
+ * it directly; multi-workspace hosts can pass a facade that routes the request
384
+ * to a per-workspace registry by `request.workspaceId`.
385
+ */
386
+ interface RuntimeBackendDispatcher {
387
+ dispatch(request: RuntimeBackendDispatchRequest): Promise<RuntimeBackendDispatchResponse>;
388
+ }
371
389
  interface RuntimeBackendGatewayOptions {
372
- registry: RuntimeBackendRegistry;
390
+ registry: RuntimeBackendDispatcher;
373
391
  defaultWorkspaceId?: string;
374
392
  }
375
393
  declare function runtimeBackendGateway(app: FastifyInstance, opts: RuntimeBackendGatewayOptions): Promise<void>;
376
394
 
377
- export { BoringPluginAssetManager, BoringPluginEvent, BoringPluginFrontTarget, BoringPluginFrontTargetResolver, BoringPluginListEntry, type BoringPluginScanResult, BoringPluginSource, BoringPluginSourceInput, BoringServerPluginManifest, type PluginRestartWarning, type RuntimeBackendDiagnostic, type RuntimeBackendDispatchRequest, type RuntimeBackendDispatchResponse, RuntimeBackendError, type RuntimeBackendGatewayOptions, RuntimeBackendRegistry, type RuntimeBackendReloadResult, UiBridge, type UiRoutesOptions, WorkspaceServerPluginAsset, aggregatePluginPrompts, boringPluginRoutes, buildBoringSystemPrompt, collectRestartWarnings, createExecUiTool, createGetUiStateTool, createWorkspaceUiTools, definePluginAsset, pluginFileSignature, preflightBoringPlugins, readBoringPlugins, readPluginSignatureCache, resolvePluginAssetPath, runtimeBackendGateway, scanBoringPlugins, uiRoutes, writePluginSignatureCache };
395
+ export { BoringPluginAssetManager, BoringPluginEvent, BoringPluginFrontTarget, BoringPluginFrontTargetResolver, BoringPluginListEntry, type BoringPluginScanResult, BoringPluginSource, BoringPluginSourceInput, BoringServerPluginManifest, type PluginRestartWarning, type RuntimeBackendDiagnostic, type RuntimeBackendDispatchRequest, type RuntimeBackendDispatchResponse, type RuntimeBackendDispatcher, RuntimeBackendError, type RuntimeBackendGatewayOptions, RuntimeBackendRegistry, type RuntimeBackendReloadResult, UiBridge, type UiRoutesOptions, WorkspaceServerPluginAsset, aggregatePluginPrompts, boringPluginRoutes, buildBoringSystemPrompt, collectRestartWarnings, createExecUiTool, createGetUiStateTool, createWorkspaceUiTools, definePluginAsset, pluginFileSignature, preflightBoringPlugins, readBoringPlugins, readPluginSignatureCache, resolvePluginAssetPath, runtimeBackendGateway, scanBoringPlugins, uiRoutes, writePluginSignatureCache };