@hachej/boring-ui-cli 0.1.24 → 0.1.26

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 (152) hide show
  1. package/dist/server/cli.js +465 -44
  2. package/dist/server/pluginDiscovery.js +36 -0
  3. package/dist/server/pluginFrontRuntime.js +1458 -0
  4. package/package.json +7 -7
  5. package/public/assets/DebugDrawer-kRj0QGoh.js +1 -0
  6. package/public/assets/_baseUniq-BaoahSEi.js +1 -0
  7. package/public/assets/angular-ts-BrjP3tb8.js +1 -1
  8. package/public/assets/angular-ts-BwZT4LLn.js +1 -1
  9. package/public/assets/apl-CORt7UWP.js +1 -1
  10. package/public/assets/apl-dKokRX4l.js +1 -1
  11. package/public/assets/arc-BGT9Yoor.js +1 -0
  12. package/public/assets/architectureDiagram-Q4EWVU46-8Fsx8Bw5.js +36 -0
  13. package/public/assets/astro-CbQHKStN.js +1 -1
  14. package/public/assets/astro-HNnZUWAn.js +1 -1
  15. package/public/assets/blade-BjGOyj-B.js +1 -1
  16. package/public/assets/blade-D4QpJJKB.js +1 -1
  17. package/public/assets/{blockDiagram-DXYQGD6D-DEkkj6Fh.js → blockDiagram-DXYQGD6D-CSD_8P6t.js} +5 -5
  18. package/public/assets/{c4Diagram-AHTNJAMY-CEZo72O7.js → c4Diagram-AHTNJAMY-BANFpiWc.js} +1 -1
  19. package/public/assets/channel-BdMajkgC.js +1 -0
  20. package/public/assets/{chunk-4BX2VUAB-kct9rMc4.js → chunk-4BX2VUAB-DwXbCZ7y.js} +1 -1
  21. package/public/assets/{chunk-4TB4RGXK-przR2bht.js → chunk-4TB4RGXK-Dk2hp0kY.js} +3 -3
  22. package/public/assets/{chunk-55IACEB6-BtFWJCbx.js → chunk-55IACEB6-CFeiGe8t.js} +1 -1
  23. package/public/assets/{chunk-EDXVE4YY-wnitHF3B.js → chunk-EDXVE4YY-B0SJv4ej.js} +1 -1
  24. package/public/assets/{chunk-FMBD7UC4-8PDhdiie.js → chunk-FMBD7UC4-BakGwea6.js} +1 -1
  25. package/public/assets/{chunk-OYMX7WX6-TDftW5K8.js → chunk-OYMX7WX6-Dq0T_fTM.js} +2 -2
  26. package/public/assets/{chunk-QZHKN3VN-B5vnQXaM.js → chunk-QZHKN3VN-B5OglTTC.js} +1 -1
  27. package/public/assets/{chunk-YZCP3GAM-CGg2izn8.js → chunk-YZCP3GAM-NDaB-kfw.js} +1 -1
  28. package/public/assets/classDiagram-6PBFFD2Q-B-lcy3NJ.js +1 -0
  29. package/public/assets/classDiagram-v2-HSJHXN6E-B-lcy3NJ.js +1 -0
  30. package/public/assets/clone-CQaScT6j.js +1 -0
  31. package/public/assets/cobol-nBiQ_Alo.js +1 -1
  32. package/public/assets/cobol-nwyudZeR.js +1 -1
  33. package/public/assets/{cose-bilkent-S5V4N54A-CjXKbjHV.js → cose-bilkent-S5V4N54A-C_XiHCxn.js} +1 -1
  34. package/public/assets/crystal-DNxU26gB.js +1 -1
  35. package/public/assets/crystal-tKQVLTB8.js +1 -1
  36. package/public/assets/{dagre-KV5264BT-D-wBcwT7.js → dagre-KV5264BT-DeKC0ZTS.js} +2 -2
  37. package/public/assets/diagram-5BDNPKRD-BI21qA6c.js +10 -0
  38. package/public/assets/diagram-G4DWMVQ6-DXlN6VCm.js +24 -0
  39. package/public/assets/diagram-MMDJMWI5-BCJkUUZU.js +43 -0
  40. package/public/assets/diagram-TYMM5635-C-KOEBZV.js +24 -0
  41. package/public/assets/edge-BkV0erSs.js +1 -1
  42. package/public/assets/edge-FbVlp4U3.js +1 -1
  43. package/public/assets/elixir-CDX3lj18.js +1 -1
  44. package/public/assets/elixir-CkH2-t6x.js +1 -1
  45. package/public/assets/{erDiagram-SMLLAGMA-CUWacc8b.js → erDiagram-SMLLAGMA-_vucZwTa.js} +2 -2
  46. package/public/assets/erb-B12qg9BL.js +1 -1
  47. package/public/assets/erb-BYCe7drp.js +1 -1
  48. package/public/assets/{flowDiagram-DWJPFMVM-DVIhUX7Z.js → flowDiagram-DWJPFMVM-CWye_WgN.js} +4 -4
  49. package/public/assets/{ganttDiagram-T4ZO3ILL-g3ncLabH.js → ganttDiagram-T4ZO3ILL-Cg6T_N_V.js} +3 -3
  50. package/public/assets/gitGraphDiagram-UUTBAWPF-CI6tYFw1.js +106 -0
  51. package/public/assets/glimmer-js-ByusRIyA.js +1 -1
  52. package/public/assets/glimmer-js-Rg0-pVw9.js +1 -1
  53. package/public/assets/glimmer-ts-BfAWNZQY.js +1 -1
  54. package/public/assets/glimmer-ts-U6CK756n.js +1 -1
  55. package/public/assets/{graph-CDl50skT.js → graph-Ci4pDE3A.js} +1 -1
  56. package/public/assets/hack-CaT9iCJl.js +1 -1
  57. package/public/assets/hack-i7_Ulhet.js +1 -1
  58. package/public/assets/haml-B8DHNrY2.js +1 -1
  59. package/public/assets/haml-D5jkg6IW.js +1 -1
  60. package/public/assets/handlebars-BL8al0AC.js +1 -1
  61. package/public/assets/handlebars-BpdQsYii.js +1 -1
  62. package/public/assets/highlighted-body-OFNGDK62-xGLlGy3l.js +1 -0
  63. package/public/assets/html-GMplVEZG.js +1 -1
  64. package/public/assets/html-derivative-BFtXZ54Q.js +1 -1
  65. package/public/assets/html-derivative-DlHx6ybY.js +1 -1
  66. package/public/assets/html-pp8916En.js +1 -1
  67. package/public/assets/index-BNz332Xu.js +1669 -0
  68. package/public/assets/index-D5qFagsx.css +1 -0
  69. package/public/assets/infoDiagram-42DDH7IO-CigcPMhk.js +2 -0
  70. package/public/assets/{ishikawaDiagram-UXIWVN3A-BbjR1GdS.js → ishikawaDiagram-UXIWVN3A-CDZTRajH.js} +4 -4
  71. package/public/assets/jinja-4LBKfQ-Z.js +1 -1
  72. package/public/assets/jinja-f2NsQr07.js +1 -1
  73. package/public/assets/{journeyDiagram-VCZTEJTY-DJHw1u4a.js → journeyDiagram-VCZTEJTY-C9MHFDJ6.js} +4 -4
  74. package/public/assets/just-Cw27pwNe.js +1 -1
  75. package/public/assets/just-VxiPbLrw.js +1 -1
  76. package/public/assets/{kanban-definition-6JOO6SKY-agbEFS20.js → kanban-definition-6JOO6SKY-Hpr02Gir.js} +7 -7
  77. package/public/assets/{layout-BtrYpvUW.js → layout-uDkQb6eL.js} +1 -1
  78. package/public/assets/{linear-C4IQ6Sya.js → linear-D9bVI_aq.js} +1 -1
  79. package/public/assets/liquid-C0sCDyMI.js +1 -1
  80. package/public/assets/liquid-DYVedYrR.js +1 -1
  81. package/public/assets/marko-CnJfTvn9.js +1 -1
  82. package/public/assets/marko-DjSrsDqO.js +1 -1
  83. package/public/assets/mdc-BMNejdWA.js +1 -1
  84. package/public/assets/mdc-DTYItulj.js +1 -1
  85. package/public/assets/{min-DDWmdqiX.js → min-T0CPelcS.js} +1 -1
  86. package/public/assets/{mindmap-definition-QFDTVHPH-By9_uC_s.js → mindmap-definition-QFDTVHPH-BxDJYpMb.js} +8 -8
  87. package/public/assets/nim-BIad80T-.js +1 -1
  88. package/public/assets/nim-CVrawwO9.js +1 -1
  89. package/public/assets/perl-C0TMdlhV.js +1 -1
  90. package/public/assets/perl-NvoQZIq0.js +1 -1
  91. package/public/assets/php-Dhbhpdrm.js +1 -1
  92. package/public/assets/php-R6g_5hLQ.js +1 -1
  93. package/public/assets/pieDiagram-DEJITSTG-C214NdS2.js +30 -0
  94. package/public/assets/pug-CGlum2m_.js +1 -1
  95. package/public/assets/pug-DKIMFp6K.js +1 -1
  96. package/public/assets/{quadrantDiagram-34T5L4WZ-BszNW2Gc.js → quadrantDiagram-34T5L4WZ-B4hldTdV.js} +3 -3
  97. package/public/assets/razor-BDqjjVU7.js +1 -1
  98. package/public/assets/razor-Uh8Bk_45.js +1 -1
  99. package/public/assets/{requirementDiagram-MS252O5E-fdyCkRN5.js → requirementDiagram-MS252O5E-Cv-IZSGz.js} +1 -1
  100. package/public/assets/rst-BrH8l1NY.js +1 -1
  101. package/public/assets/rst-CRjBmOyv.js +1 -1
  102. package/public/assets/ruby-Dw2BHqvy.js +1 -1
  103. package/public/assets/ruby-Wjq7vjNf.js +1 -1
  104. package/public/assets/{sankeyDiagram-XADWPNL6-tg2HOfl2.js → sankeyDiagram-XADWPNL6-C52Wx9t_.js} +2 -2
  105. package/public/assets/{sequenceDiagram-FGHM5R23-GF78cQ5y.js → sequenceDiagram-FGHM5R23-C9gRx_I2.js} +5 -5
  106. package/public/assets/soy-8wufbnw4.js +1 -1
  107. package/public/assets/soy-Brmx7dQM.js +1 -1
  108. package/public/assets/{stateDiagram-FHFEXIEX-C709lyuE.js → stateDiagram-FHFEXIEX-BVweWFAE.js} +1 -1
  109. package/public/assets/stateDiagram-v2-QKLJ7IA2-CftkpTOS.js +1 -0
  110. package/public/assets/svelte-C_ipcX3V.js +1 -1
  111. package/public/assets/svelte-Cy7k_4gC.js +1 -1
  112. package/public/assets/templ-DhtptRzy.js +1 -1
  113. package/public/assets/templ-P3uqSqPl.js +1 -1
  114. package/public/assets/{timeline-definition-GMOUNBTQ-D2y-83yP.js → timeline-definition-GMOUNBTQ-Boc8Q03t.js} +3 -3
  115. package/public/assets/ts-tags-DQrlYJgV.js +1 -1
  116. package/public/assets/ts-tags-zn1MmPIZ.js +1 -1
  117. package/public/assets/twig-DNn4PbVi.js +1 -1
  118. package/public/assets/twig-xg9kU7Mw.js +1 -1
  119. package/public/assets/vennDiagram-DHZGUBPP-BE8XjSYZ.js +34 -0
  120. package/public/assets/vue-D2xRrEX4.js +1 -1
  121. package/public/assets/vue-DN_0RTcg.js +1 -1
  122. package/public/assets/vue-vine-BoDAl6tE.js +1 -1
  123. package/public/assets/vue-vine-CQOfvN7w.js +1 -1
  124. package/public/assets/{wardley-RL74JXVD-NEg4mPyC.js → wardley-RL74JXVD-MQjS4K_T.js} +1 -1
  125. package/public/assets/{wardleyDiagram-NUSXRM2D-BbXAj99t.js → wardleyDiagram-NUSXRM2D-CKUw97nD.js} +2 -2
  126. package/public/assets/{xychartDiagram-5P7HB3ND-C8Y3cC5f.js → xychartDiagram-5P7HB3ND-OkP2T3uc.js} +3 -3
  127. package/public/index.html +2 -2
  128. package/templates/front-canonical.tsx +4 -2
  129. package/public/assets/CodeEditor-DQqOn4xz-BnYIpEQ0.js +0 -31
  130. package/public/assets/FileTree-DjPzfDMq-jOFMfLV-.js +0 -21
  131. package/public/assets/MarkdownEditor-BbSy0bLV-_8qFqqna.js +0 -254
  132. package/public/assets/_baseUniq-DysFpiFw.js +0 -1
  133. package/public/assets/arc-D0sqkACA.js +0 -1
  134. package/public/assets/architectureDiagram-Q4EWVU46-DnyELkA2.js +0 -36
  135. package/public/assets/channel-Ci4DEwaO.js +0 -1
  136. package/public/assets/classDiagram-6PBFFD2Q-0PAZNzgC.js +0 -1
  137. package/public/assets/classDiagram-v2-HSJHXN6E-0PAZNzgC.js +0 -1
  138. package/public/assets/clone-_lPYOTLf.js +0 -1
  139. package/public/assets/diagram-5BDNPKRD-Ch4e4G6h.js +0 -10
  140. package/public/assets/diagram-G4DWMVQ6-a_PPD1uY.js +0 -24
  141. package/public/assets/diagram-MMDJMWI5-D9Lkv8IB.js +0 -43
  142. package/public/assets/diagram-TYMM5635-BlfaVidf.js +0 -24
  143. package/public/assets/gitGraphDiagram-UUTBAWPF-DpPqglKx.js +0 -106
  144. package/public/assets/highlighted-body-OFNGDK62-BcVhfY0-.js +0 -1
  145. package/public/assets/index-C9S_GD0T.js +0 -1330
  146. package/public/assets/index-CrFvzn5a.js +0 -9
  147. package/public/assets/index-Css1pwyY.css +0 -1
  148. package/public/assets/index-Vcq4gwWv.js +0 -1
  149. package/public/assets/infoDiagram-42DDH7IO-COfGVlDB.js +0 -2
  150. package/public/assets/pieDiagram-DEJITSTG-DfzJSvMR.js +0 -30
  151. package/public/assets/stateDiagram-v2-QKLJ7IA2-BbgcVrKo.js +0 -1
  152. package/public/assets/vennDiagram-DHZGUBPP-BOsWwU4c.js +0 -34
@@ -15,6 +15,11 @@ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:pat
15
15
  import { fileURLToPath } from "node:url";
16
16
  import { parseArgs } from "node:util";
17
17
  import { createLocalWorkspaceRegistry } from "./localWorkspaces.js";
18
+ import {
19
+ createCliPluginAssetManager,
20
+ getGlobalPiExtensionsRoot,
21
+ resolveCliBoringPluginDirs
22
+ } from "./pluginDiscovery.js";
18
23
  const MODE_MAP = {
19
24
  "local": "direct",
20
25
  // no sandbox, full network access
@@ -98,11 +103,18 @@ async function provisionCliWorkspaceRuntime(opts) {
98
103
  if (!adapter) {
99
104
  throw new Error(`runtime mode ${opts.mode} does not support workspace provisioning`);
100
105
  }
101
- return await agent.provisionWorkspaceRuntime({
106
+ const result = await agent.provisionWorkspaceRuntime({
102
107
  plugins: [createBoringUiCliRuntimePlugin(), ...opts.plugins ?? []],
103
108
  adapter,
104
109
  runtimeLayout
105
110
  });
111
+ return {
112
+ ...result,
113
+ env: {
114
+ ...result.env,
115
+ BORING_AGENT_WORKSPACE_LOCAL_PLUGIN_ROOTS: opts.mode === "direct" || opts.mode === "local" ? "1" : "0"
116
+ }
117
+ };
106
118
  }
107
119
  function ensureFrontendBuilt(publicDir) {
108
120
  if (existsSync(join(publicDir, "index.html"))) return;
@@ -138,7 +150,7 @@ const HELP_TEXT = [
138
150
  "Options:",
139
151
  " -p, --port <port> HTTP port (default: 5200)",
140
152
  " --host <host> Listen host (default: 0.0.0.0)",
141
- " -m, --mode <mode> local-sandbox or local (default: local-sandbox)",
153
+ " -m, --mode <mode> local-sandbox or local (default: local)",
142
154
  " -h, --help Show this help"
143
155
  ].join("\n");
144
156
  const AUTH_GUIDE = [
@@ -162,10 +174,174 @@ async function checkAuth() {
162
174
  const registry = ModelRegistry.create(authStorage);
163
175
  return registry.getAvailable().length;
164
176
  }
177
+ const FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID = "folder";
178
+ const RUNTIME_PLUGIN_TRUST_LABEL = "Trusted local runtime plugins";
179
+ const RUNTIME_PLUGIN_TRUST_DESCRIPTION = "Loads plugin UI code from trusted local Pi extension roots through the CLI-owned runtime module host.";
180
+ function createRuntimePluginDiagnosticsStore() {
181
+ const byWorkspace = /* @__PURE__ */ new Map();
182
+ function upsert(workspaceId, pluginId) {
183
+ const workspace = byWorkspace.get(workspaceId) ?? /* @__PURE__ */ new Map();
184
+ byWorkspace.set(workspaceId, workspace);
185
+ const existing = workspace.get(pluginId) ?? {
186
+ workspaceId,
187
+ pluginId,
188
+ recent: []
189
+ };
190
+ workspace.set(pluginId, existing);
191
+ return existing;
192
+ }
193
+ return {
194
+ record(diagnostic) {
195
+ if (!diagnostic.workspaceId || !diagnostic.pluginId) return;
196
+ const entry = upsert(diagnostic.workspaceId, diagnostic.pluginId);
197
+ const now = Date.now();
198
+ entry.lastDiagnostic = diagnostic;
199
+ entry.recent = [...entry.recent, diagnostic].slice(-12);
200
+ if (diagnostic.revision !== void 0) entry.revision = diagnostic.revision;
201
+ if (diagnostic.requestedPath) entry.lastRequestedPath = diagnostic.requestedPath;
202
+ if (diagnostic.resolvedPath) entry.lastResolvedPath = diagnostic.resolvedPath;
203
+ const details = diagnostic.details ?? {};
204
+ if (typeof details.rootDir === "string") entry.rootDir = details.rootDir;
205
+ if (typeof details.entryUrl === "string") entry.entryUrl = details.entryUrl;
206
+ if (typeof diagnostic.requestedPath === "string") entry.frontEntrySubpath = diagnostic.requestedPath;
207
+ if (diagnostic.stage === "track" && diagnostic.outcome === "tracked") {
208
+ entry.lastErrorCode = void 0;
209
+ entry.lastErrorMessage = void 0;
210
+ entry.lastErrorStage = void 0;
211
+ }
212
+ if (diagnostic.stage === "cache") entry.lastRequestAt = now;
213
+ if (diagnostic.stage === "transform" && diagnostic.outcome === "served") {
214
+ entry.lastTransformAt = now;
215
+ entry.lastTransformDurationMs = diagnostic.durationMs;
216
+ }
217
+ if (diagnostic.stage === "serve" && diagnostic.outcome === "served") {
218
+ entry.lastServeAt = now;
219
+ entry.lastServeDurationMs = diagnostic.durationMs;
220
+ entry.lastErrorCode = void 0;
221
+ entry.lastErrorMessage = void 0;
222
+ entry.lastErrorStage = void 0;
223
+ }
224
+ if (diagnostic.outcome === "rejected") {
225
+ entry.lastRejectedAt = now;
226
+ entry.lastErrorCode = diagnostic.code;
227
+ entry.lastErrorMessage = diagnostic.msg;
228
+ entry.lastErrorStage = diagnostic.stage;
229
+ }
230
+ if (diagnostic.stage === "cleanup" && diagnostic.outcome === "disposed") {
231
+ entry.lastDisposedAt = now;
232
+ }
233
+ },
234
+ snapshot(workspaceId) {
235
+ return [...byWorkspace.get(workspaceId)?.values() ?? []].map((entry) => ({ ...entry, recent: [...entry.recent] })).sort((a, b) => a.pluginId.localeCompare(b.pluginId));
236
+ },
237
+ disposeWorkspace(workspaceId) {
238
+ byWorkspace.delete(workspaceId);
239
+ }
240
+ };
241
+ }
242
+ function syncRuntimeHostFromPluginEvents(runtimeHost, workspaceId, events) {
243
+ for (const event of events) {
244
+ if (event.type === "boring.plugin.unload" || event.type === "boring.plugin.load" && !event.frontTarget) {
245
+ runtimeHost.untrackPlugin(workspaceId, event.id);
246
+ }
247
+ }
248
+ }
249
+ function buildRuntimePluginDiagnosticsResponse(args) {
250
+ const byPlugin = /* @__PURE__ */ new Map();
251
+ for (const plugin of args.loaded) {
252
+ byPlugin.set(plugin.id, {
253
+ id: plugin.id,
254
+ ...plugin.version ? { version: plugin.version } : {},
255
+ ...plugin.rootDir ? { rootDir: plugin.rootDir } : {},
256
+ ...plugin.frontPath ? { frontPath: plugin.frontPath } : {},
257
+ ...plugin.frontTarget ? { frontTarget: plugin.frontTarget } : {},
258
+ ...plugin.revision !== void 0 ? { serverLoadedRevision: plugin.revision } : {}
259
+ });
260
+ }
261
+ for (const error of args.errors) {
262
+ const current = byPlugin.get(error.id) ?? { id: error.id };
263
+ byPlugin.set(error.id, {
264
+ ...current,
265
+ serverError: error.message
266
+ });
267
+ }
268
+ for (const hostEntry of args.host) {
269
+ const current = byPlugin.get(hostEntry.pluginId) ?? { id: hostEntry.pluginId };
270
+ byPlugin.set(hostEntry.pluginId, {
271
+ ...current,
272
+ ...current.rootDir ? {} : hostEntry.rootDir ? { rootDir: hostEntry.rootDir } : {},
273
+ ...current.frontPath ? {} : hostEntry.frontEntrySubpath ? { frontPath: hostEntry.frontEntrySubpath } : {},
274
+ ...current.frontTarget ? {} : hostEntry.entryUrl ? { frontTarget: { kind: "native", entryUrl: hostEntry.entryUrl, revision: hostEntry.revision ?? 0, trust: "local-trusted-native" } } : {},
275
+ host: hostEntry
276
+ });
277
+ }
278
+ return {
279
+ workspaceId: args.workspaceId,
280
+ plugins: [...byPlugin.values()].sort((a, b) => a.id.localeCompare(b.id))
281
+ };
282
+ }
283
+ async function createFolderModeApp(opts) {
284
+ const workspaceRoot = resolve(opts.workspaceRoot);
285
+ const projectName = opts.projectName ?? (basename(workspaceRoot) || "workspace");
286
+ const [{ createWorkspaceAgentServer, readWorkspacePluginPackageRuntimePlugins }, { createPluginFrontRuntimeHost }] = await Promise.all([
287
+ import("@hachej/boring-workspace/app/server"),
288
+ import("./pluginFrontRuntime.js")
289
+ ]);
290
+ const diagnosticsStore = createRuntimePluginDiagnosticsStore();
291
+ const runtimeHost = await createPluginFrontRuntimeHost({
292
+ onDiagnostic: (diagnostic) => diagnosticsStore.record(diagnostic)
293
+ });
294
+ const runtimeProvisioning = await provisionCliWorkspaceRuntime({
295
+ workspaceRoot,
296
+ mode: opts.mode,
297
+ provisionWorkspace: opts.provisionWorkspace,
298
+ plugins: readWorkspacePluginPackageRuntimePlugins(resolveCliBoringPluginDirs(workspaceRoot))
299
+ });
300
+ const app = await createWorkspaceAgentServer({
301
+ workspaceRoot,
302
+ mode: opts.mode,
303
+ logger: false,
304
+ provisionWorkspace: false,
305
+ runtimeProvisioning,
306
+ additionalBoringPluginDirs: [getGlobalPiExtensionsRoot()],
307
+ boringPluginFrontTargetResolver: runtimeHost.createFrontTargetResolver(FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID),
308
+ boringPluginIncludeLegacyFrontUrl: false
309
+ });
310
+ await runtimeHost.registerRoutes(app);
311
+ const folderAssetManager = app.__boringAssetManager;
312
+ const closeFolderRuntimeCleanup = folderAssetManager?.subscribe((event) => {
313
+ syncRuntimeHostFromPluginEvents(runtimeHost, FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID, [event]);
314
+ });
315
+ if (closeFolderRuntimeCleanup) {
316
+ app.addHook("onClose", async () => {
317
+ closeFolderRuntimeCleanup();
318
+ });
319
+ }
320
+ app.get("/api/v1/runtime-plugin-diagnostics", async () => {
321
+ const manager = app.__boringAssetManager;
322
+ return buildRuntimePluginDiagnosticsResponse({
323
+ workspaceId: FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID,
324
+ loaded: manager?.inspectLoaded() ?? [],
325
+ errors: manager?.getErrors() ?? [],
326
+ host: diagnosticsStore.snapshot(FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID)
327
+ });
328
+ });
329
+ app.get("/api/v1/workspace/meta", async () => ({
330
+ workspaceRoot,
331
+ projectName,
332
+ version: CLI_VERSION,
333
+ runtimePluginFrontLoadingEnabled: true,
334
+ runtimePluginTrustLabel: RUNTIME_PLUGIN_TRUST_LABEL,
335
+ runtimePluginTrustDescription: RUNTIME_PLUGIN_TRUST_DESCRIPTION,
336
+ runtimePluginDiagnosticsEnabled: true
337
+ }));
338
+ return app;
339
+ }
165
340
  async function startFolderMode(opts) {
166
341
  const workspaceRoot = process.env.BORING_AGENT_WORKSPACE_ROOT ?? resolve(opts.folderArg ?? process.cwd());
167
342
  const projectName = basename(resolve(workspaceRoot)) || "workspace";
168
343
  const modelCount = await checkAuth();
344
+ const url = `http://localhost:${opts.port}`;
169
345
  console.log(`
170
346
  ${projectName}`);
171
347
  console.log(` workspace ${workspaceRoot}`);
@@ -173,40 +349,39 @@ ${projectName}`);
173
349
  console.log(` port ${opts.port}`);
174
350
  console.log(` host ${opts.host}`);
175
351
  if (modelCount === 0) console.log(AUTH_GUIDE);
176
- const runtimeProvisioning = await provisionCliWorkspaceRuntime({
177
- workspaceRoot,
178
- mode: opts.mode
179
- });
180
- const { createWorkspaceAgentServer } = await import("@hachej/boring-workspace/app/server");
181
- const app = await createWorkspaceAgentServer({
352
+ console.log(`
353
+ starting ${url} \u2026`);
354
+ const app = await createFolderModeApp({
182
355
  workspaceRoot,
183
356
  mode: opts.mode,
184
- logger: false,
185
- provisionWorkspace: false,
186
- runtimeProvisioning
357
+ projectName
187
358
  });
188
- app.get("/api/v1/workspace/meta", async () => ({
189
- workspaceRoot,
190
- projectName,
191
- version: CLI_VERSION
192
- }));
193
359
  await registerStatic(app, opts.publicDir);
194
360
  await app.listen({ port: opts.port, host: opts.host });
195
- console.log(`
196
- http://localhost:${opts.port}
361
+ console.log(` ${url} ready
197
362
  `);
198
- openBrowser(`http://localhost:${opts.port}`);
363
+ openBrowser(url);
199
364
  }
200
- async function startWorkspacesMode(opts) {
201
- const [workspaceAppServer, workspaceServer, agentServer, fastifyModule] = await Promise.all([
365
+ async function createWorkspacesModeApp(opts) {
366
+ const [workspaceAppServer, workspaceServer, agentServer, fastifyModule, { createPluginFrontRuntimeHost }] = await Promise.all([
202
367
  import("@hachej/boring-workspace/app/server"),
203
368
  import("@hachej/boring-workspace/server"),
204
369
  import("@hachej/boring-agent/server"),
205
- import("fastify")
370
+ import("fastify"),
371
+ import("./pluginFrontRuntime.js")
206
372
  ]);
207
- const registry = createLocalWorkspaceRegistry();
373
+ const registry = createLocalWorkspaceRegistry(opts.registryPath);
208
374
  const app = fastifyModule.default({ logger: false, bodyLimit: 16 * 1024 * 1024 });
375
+ const diagnosticsStore = createRuntimePluginDiagnosticsStore();
376
+ const runtimeHost = await createPluginFrontRuntimeHost({
377
+ onDiagnostic: (diagnostic) => diagnosticsStore.record(diagnostic)
378
+ });
379
+ await runtimeHost.registerRoutes(app);
209
380
  const bridges = /* @__PURE__ */ new Map();
381
+ const workspaceEventClosers = /* @__PURE__ */ new Map();
382
+ const pluginRuntimes = /* @__PURE__ */ new Map();
383
+ const pluginPiSnapshots = /* @__PURE__ */ new Map();
384
+ const runtimeProvisioningByWorkspace = /* @__PURE__ */ new Map();
210
385
  function getBridge(workspaceId) {
211
386
  let bridge = bridges.get(workspaceId);
212
387
  if (!bridge) {
@@ -224,6 +399,65 @@ async function startWorkspacesMode(opts) {
224
399
  async function workspaceFromRequest(request) {
225
400
  return await requireWorkspace(resolveWorkspaceIdFromRequest(request));
226
401
  }
402
+ function pluginRuntimeKey(workspace) {
403
+ return `${workspace.id}:${workspace.path}`;
404
+ }
405
+ function syncLoadedPluginPiSnapshot(workspace, manager) {
406
+ pluginPiSnapshots.set(pluginRuntimeKey(workspace), manager.inspectLoadedPiSnapshot());
407
+ }
408
+ function getOrCreatePluginRuntime(workspace) {
409
+ const key = pluginRuntimeKey(workspace);
410
+ let runtime = pluginRuntimes.get(key);
411
+ if (!runtime) {
412
+ const manager = createCliPluginAssetManager(workspace.path, {
413
+ frontTargetResolver: runtimeHost.createFrontTargetResolver(workspace.id),
414
+ includeLegacyFrontUrl: false
415
+ });
416
+ runtime = {
417
+ manager,
418
+ ensureLoaded: manager.load().then(() => {
419
+ syncLoadedPluginPiSnapshot(workspace, manager);
420
+ })
421
+ };
422
+ pluginRuntimes.set(key, runtime);
423
+ }
424
+ return runtime;
425
+ }
426
+ async function getLoadedPluginRuntime(workspace) {
427
+ const runtime = getOrCreatePluginRuntime(workspace);
428
+ await runtime.ensureLoaded;
429
+ return runtime;
430
+ }
431
+ function getLoadedPluginPiSnapshot(workspace) {
432
+ return pluginPiSnapshots.get(pluginRuntimeKey(workspace)) ?? {
433
+ additionalSkillPaths: [],
434
+ packages: [],
435
+ extensionPaths: []
436
+ };
437
+ }
438
+ async function disposeWorkspaceRuntime(workspace) {
439
+ for (const close of workspaceEventClosers.get(workspace.id) ?? []) {
440
+ try {
441
+ close();
442
+ } catch {
443
+ }
444
+ }
445
+ workspaceEventClosers.delete(workspace.id);
446
+ const runtimeKey = pluginRuntimeKey(workspace);
447
+ pluginRuntimes.delete(runtimeKey);
448
+ pluginPiSnapshots.delete(runtimeKey);
449
+ runtimeProvisioningByWorkspace.delete(workspace.id);
450
+ bridges.delete(workspace.id);
451
+ diagnosticsStore.disposeWorkspace(workspace.id);
452
+ await runtimeHost.disposeWorkspace(workspace.id);
453
+ }
454
+ function reloadDiagnostics(scan) {
455
+ return scan.errors.map((error) => ({
456
+ source: "workspaces-plugin-manager",
457
+ message: error.message,
458
+ pluginId: error.id
459
+ }));
460
+ }
227
461
  app.get("/api/v1/local-workspaces", async () => ({
228
462
  workspaces: await registry.list()
229
463
  }));
@@ -243,10 +477,12 @@ async function startWorkspacesMode(opts) {
243
477
  });
244
478
  }
245
479
  });
246
- app.delete("/api/v1/local-workspaces/:id", async (request) => {
480
+ app.delete("/api/v1/local-workspaces/:id", async (request, reply) => {
247
481
  const { id } = request.params;
482
+ const workspace = await registry.get(id);
248
483
  await registry.remove(id);
249
- return { ok: true };
484
+ if (workspace) await disposeWorkspaceRuntime(workspace);
485
+ return reply.send({ ok: true });
250
486
  });
251
487
  app.get("/api/v1/workspaces", async () => ({
252
488
  workspaces: (await registry.list()).map(toCoreWorkspace)
@@ -260,20 +496,50 @@ async function startWorkspacesMode(opts) {
260
496
  await app.register(agentServer.registerAgentRoutes, {
261
497
  mode: opts.mode,
262
498
  systemPromptAppend: workspaceAppServer.buildWorkspaceContextPrompt(),
499
+ getSystemPromptDynamic: async ({ workspaceId }) => {
500
+ const workspace = await requireWorkspace(workspaceId);
501
+ await getLoadedPluginRuntime(workspace);
502
+ return getLoadedPluginPiSnapshot(workspace).systemPromptAppend;
503
+ },
263
504
  getWorkspaceId: async (request) => (await workspaceFromRequest(request)).id,
264
505
  getWorkspaceRoot: async (workspaceId) => (await requireWorkspace(workspaceId)).path,
265
506
  getSessionNamespace: async ({ workspaceId }) => `local-workspace-${workspaceId}`,
266
- provisionRuntime: async ({ workspaceRoot, runtimeMode, runtimeLayout, provisioningAdapter }) => {
267
- return await provisionCliWorkspaceRuntime({
507
+ provisionRuntime: async ({ workspaceId, workspaceRoot, runtimeMode, runtimeLayout, provisioningAdapter }) => {
508
+ if (runtimeProvisioningByWorkspace.has(workspaceId)) {
509
+ return runtimeProvisioningByWorkspace.get(workspaceId);
510
+ }
511
+ const provisioned = await provisionCliWorkspaceRuntime({
268
512
  workspaceRoot,
269
513
  mode: runtimeMode,
514
+ provisionWorkspace: opts.provisionWorkspace,
270
515
  adapter: provisioningAdapter,
271
- runtimeLayout
516
+ runtimeLayout,
517
+ plugins: workspaceAppServer.readWorkspacePluginPackageRuntimePlugins(resolveCliBoringPluginDirs(workspaceRoot))
272
518
  });
519
+ runtimeProvisioningByWorkspace.set(workspaceId, provisioned);
520
+ return provisioned;
521
+ },
522
+ beforeReload: async ({ workspaceId }) => {
523
+ const workspace = await requireWorkspace(workspaceId);
524
+ const runtime = await getLoadedPluginRuntime(workspace);
525
+ const scan = await runtime.manager.load();
526
+ syncLoadedPluginPiSnapshot(workspace, runtime.manager);
527
+ syncRuntimeHostFromPluginEvents(runtimeHost, workspaceId, scan.events);
528
+ return {
529
+ restart_warnings: workspaceServer.collectRestartWarnings(scan.events),
530
+ diagnostics: reloadDiagnostics(scan)
531
+ };
532
+ },
533
+ getPi: async ({ workspaceId, workspaceRoot }) => {
534
+ const workspace = await requireWorkspace(workspaceId);
535
+ await getLoadedPluginRuntime(workspace);
536
+ return {
537
+ additionalSkillPaths: [join(workspaceRoot, ".agents", "skills")],
538
+ packages: [],
539
+ extensionPaths: [],
540
+ getHotReloadableResources: () => getLoadedPluginPiSnapshot(workspace)
541
+ };
273
542
  },
274
- getPi: async ({ workspaceRoot }) => ({
275
- additionalSkillPaths: [join(workspaceRoot, ".agents", "skills")]
276
- }),
277
543
  getExtraTools: async ({ workspaceId, workspaceRoot, workspaceFsCapability }) => [
278
544
  ...workspaceServer.createWorkspaceUiTools(getBridge(workspaceId), {
279
545
  workspaceRoot: workspaceFsCapability === "strong" ? workspaceRoot : void 0
@@ -283,23 +549,127 @@ async function startWorkspacesMode(opts) {
283
549
  await app.register(workspaceServer.uiRoutes, {
284
550
  getBridge: async (request) => getBridge((await workspaceFromRequest(request)).id)
285
551
  });
552
+ app.get("/api/v1/runtime-plugin-diagnostics", async (request) => {
553
+ const workspace = await workspaceFromRequest(request);
554
+ const runtime = await getLoadedPluginRuntime(workspace);
555
+ return buildRuntimePluginDiagnosticsResponse({
556
+ workspaceId: workspace.id,
557
+ loaded: runtime.manager.inspectLoaded(),
558
+ errors: runtime.manager.getErrors(),
559
+ host: diagnosticsStore.snapshot(workspace.id)
560
+ });
561
+ });
562
+ app.get("/api/v1/agent-plugins", async (request) => {
563
+ const workspace = await workspaceFromRequest(request);
564
+ const runtime = await getLoadedPluginRuntime(workspace);
565
+ return runtime.manager.list();
566
+ });
567
+ app.get("/api/v1/agent-plugins/:id/error", async (request, reply) => {
568
+ const workspace = await workspaceFromRequest(request);
569
+ const runtime = await getLoadedPluginRuntime(workspace);
570
+ const { id } = request.params;
571
+ const error = runtime.manager.getError(id);
572
+ if (error == null) return reply.code(404).send({ error: "not_found" });
573
+ return reply.type("text/plain").send(error);
574
+ });
575
+ app.get("/api/v1/agent-plugins/events", async (request, reply) => {
576
+ const workspace = await workspaceFromRequest(request);
577
+ const runtime = await getLoadedPluginRuntime(workspace);
578
+ const manager = runtime.manager;
579
+ reply.hijack();
580
+ const res = reply.raw;
581
+ res.statusCode = 200;
582
+ res.setHeader("Content-Type", "text/event-stream");
583
+ res.setHeader("Cache-Control", "no-cache, no-transform");
584
+ res.setHeader("Connection", "keep-alive");
585
+ res.setHeader("X-Accel-Buffering", "no");
586
+ res.flushHeaders?.();
587
+ const write = (eventName, payload) => {
588
+ try {
589
+ res.write(`event: ${eventName}
590
+ `);
591
+ res.write(`data: ${JSON.stringify(payload)}
592
+
593
+ `);
594
+ } catch {
595
+ }
596
+ };
597
+ const liveQueue = [];
598
+ let replaying = true;
599
+ const unsubscribe = manager.subscribe((event) => {
600
+ if (event.type === "boring.plugin.unload" || event.type === "boring.plugin.load" && !event.frontTarget) {
601
+ runtimeHost.untrackPlugin(workspace.id, event.id);
602
+ }
603
+ const payload = {
604
+ ...event,
605
+ workspaceId: workspace.id,
606
+ replay: false
607
+ };
608
+ if (replaying) {
609
+ liveQueue.push({ eventName: event.type, payload });
610
+ return;
611
+ }
612
+ write(event.type, payload);
613
+ });
614
+ for (const plugin of manager.list()) {
615
+ write("boring.plugin.load", {
616
+ type: "boring.plugin.load",
617
+ id: plugin.id,
618
+ boring: plugin.boring,
619
+ version: plugin.version,
620
+ revision: plugin.revision,
621
+ ...plugin.frontTarget ? { frontTarget: plugin.frontTarget } : {},
622
+ workspaceId: workspace.id,
623
+ replay: true
624
+ });
625
+ }
626
+ write("boring.plugin.replay-complete", {
627
+ type: "boring.plugin.replay-complete",
628
+ workspaceId: workspace.id,
629
+ replay: true
630
+ });
631
+ replaying = false;
632
+ for (const event of liveQueue) write(event.eventName, event.payload);
633
+ const heartbeat = setInterval(() => {
634
+ try {
635
+ res.write(": heartbeat\n\n");
636
+ } catch {
637
+ }
638
+ }, 25e3);
639
+ const closeStream = () => {
640
+ clearInterval(heartbeat);
641
+ unsubscribe();
642
+ workspaceEventClosers.get(workspace.id)?.delete(closeStream);
643
+ try {
644
+ res.end();
645
+ } catch {
646
+ }
647
+ };
648
+ const closers = workspaceEventClosers.get(workspace.id) ?? /* @__PURE__ */ new Set();
649
+ closers.add(closeStream);
650
+ workspaceEventClosers.set(workspace.id, closers);
651
+ request.raw.on("close", closeStream);
652
+ });
286
653
  app.get("/api/v1/workspace/meta", async () => ({
287
654
  projectName: "Boring UI",
288
655
  workspacesMode: true,
289
- version: CLI_VERSION
656
+ version: CLI_VERSION,
657
+ runtimePluginFrontLoadingEnabled: true,
658
+ runtimePluginTrustLabel: RUNTIME_PLUGIN_TRUST_LABEL,
659
+ runtimePluginTrustDescription: RUNTIME_PLUGIN_TRUST_DESCRIPTION,
660
+ runtimePluginDiagnosticsEnabled: true
290
661
  }));
662
+ return app;
663
+ }
664
+ async function startWorkspacesMode(opts) {
665
+ const app = await createWorkspacesModeApp({ mode: opts.mode });
666
+ const registry = createLocalWorkspaceRegistry();
291
667
  await registerStatic(app, opts.publicDir);
292
668
  await app.listen({ port: opts.port, host: opts.host });
293
669
  const initialWorkspace = (await registry.list()).find((workspace) => workspace.available);
294
670
  const initialUrl = initialWorkspace ? `http://localhost:${opts.port}/workspace/${encodeURIComponent(initialWorkspace.id)}` : `http://localhost:${opts.port}`;
295
- console.log(`
296
- Boring UI`);
297
671
  console.log(` workspaces ${registry.path}`);
298
- console.log(` mode ${opts.cliMode}`);
299
- console.log(` port ${opts.port}`);
300
- console.log(` host ${opts.host}`);
301
- console.log(`
302
- ${initialUrl}
672
+ console.log(` ${initialUrl} ready
303
673
  `);
304
674
  if (await checkAuth() === 0) console.log(AUTH_GUIDE);
305
675
  openBrowser(initialUrl);
@@ -457,6 +827,7 @@ async function runCli(options) {
457
827
  mode: { type: "string", short: "m" },
458
828
  name: { type: "string", short: "n" },
459
829
  path: { type: "string" },
830
+ json: { type: "boolean" },
460
831
  help: { type: "boolean", short: "h" }
461
832
  },
462
833
  allowPositionals: true,
@@ -468,12 +839,26 @@ async function runCli(options) {
468
839
  }
469
840
  const port = Number(args.port ?? process.env.PORT) || 5200;
470
841
  const host = args.host ?? process.env.HOST ?? "0.0.0.0";
471
- const rawMode = args.mode ?? process.env.BORING_MODE ?? "local-sandbox";
472
- if (!(rawMode in MODE_MAP)) {
473
- throw new Error(`invalid --mode "${rawMode}". Valid options: ${Object.keys(MODE_MAP).join(", ")}`);
842
+ const rawMode = args.mode ?? process.env.BORING_MODE;
843
+ let cliMode;
844
+ let mode;
845
+ if (rawMode) {
846
+ if (!(rawMode in MODE_MAP)) {
847
+ throw new Error(`invalid --mode "${rawMode}". Valid options: ${Object.keys(MODE_MAP).join(", ")}`);
848
+ }
849
+ cliMode = rawMode;
850
+ mode = MODE_MAP[cliMode];
851
+ } else {
852
+ const agent = await import("@hachej/boring-agent/server");
853
+ const detected = agent.autoDetectMode();
854
+ if (detected === "local") {
855
+ cliMode = "local-sandbox";
856
+ mode = "local";
857
+ } else {
858
+ cliMode = "local";
859
+ mode = "direct";
860
+ }
474
861
  }
475
- const cliMode = rawMode;
476
- const mode = MODE_MAP[cliMode];
477
862
  const base = {
478
863
  publicDir: options.publicDir,
479
864
  port,
@@ -496,6 +881,10 @@ async function runCli(options) {
496
881
  });
497
882
  return;
498
883
  }
884
+ if (positionals[0] === "plugin-status") {
885
+ handlePluginStatusCommand({ json: args.json === true });
886
+ return;
887
+ }
499
888
  if (positionals[0] === "scaffold-plugin") {
500
889
  await handleScaffoldPluginCommand({ positionals });
501
890
  return;
@@ -512,6 +901,32 @@ async function runCli(options) {
512
901
  function defaultWorkspaceRoot() {
513
902
  return process.env.BORING_AGENT_WORKSPACE_ROOT ?? process.cwd();
514
903
  }
904
+ function workspaceLocalPluginRootsEnabled() {
905
+ const raw = process.env.BORING_AGENT_WORKSPACE_LOCAL_PLUGIN_ROOTS;
906
+ if (raw == null || raw.trim() === "") return true;
907
+ return !["0", "false", "no", "off"].includes(raw.trim().toLowerCase());
908
+ }
909
+ function buildPluginStatus() {
910
+ const workspaceRoot = resolve(defaultWorkspaceRoot());
911
+ const enabled = workspaceLocalPluginRootsEnabled();
912
+ return {
913
+ workspaceLocalPluginRoots: enabled,
914
+ workspaceRoot,
915
+ extensionsDir: join(workspaceRoot, ".pi", "extensions"),
916
+ reloadSupported: enabled,
917
+ ...enabled ? {} : {
918
+ reason: "This runtime writes to a remote sandbox; host-side plugin discovery cannot load .pi/extensions from there."
919
+ }
920
+ };
921
+ }
922
+ function handlePluginStatusCommand(opts) {
923
+ const status = buildPluginStatus();
924
+ if (opts.json) {
925
+ console.log(JSON.stringify(status, null, 2));
926
+ return;
927
+ }
928
+ console.log(status.workspaceLocalPluginRoots ? `workspace-local plugin roots enabled: ${status.extensionsDir}` : `workspace-local plugin roots disabled: ${status.reason}`);
929
+ }
515
930
  async function handleVerifyPluginCommand(opts) {
516
931
  const maybeName = opts.positionals[1];
517
932
  const maybeWorkspace = opts.positionals[2];
@@ -542,6 +957,10 @@ async function handleScaffoldPluginCommand(opts) {
542
957
  if (!name) {
543
958
  throw new Error("usage: boring-ui scaffold-plugin <name> [workspace]");
544
959
  }
960
+ const status = buildPluginStatus();
961
+ if (!status.workspaceLocalPluginRoots) {
962
+ throw new Error(`${status.reason} Do not scaffold into .pi/extensions in this runtime.`);
963
+ }
545
964
  const workspaceRoot = resolve(opts.positionals[2] ?? defaultWorkspaceRoot());
546
965
  const { scaffoldPlugin } = await import("./scaffoldPlugin.js");
547
966
  const result = scaffoldPlugin({ name, workspaceRoot });
@@ -563,6 +982,8 @@ async function handleScaffoldPluginCommand(opts) {
563
982
  }
564
983
  export {
565
984
  createBoringUiCliRuntimePlugin,
985
+ createFolderModeApp,
986
+ createWorkspacesModeApp,
566
987
  provisionCliWorkspaceRuntime,
567
988
  registerStatic,
568
989
  resolveBoringUiCliPackageRoot,
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { homedir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+ import {
5
+ BoringPluginAssetManager
6
+ } from "@hachej/boring-workspace/server";
7
+ import {
8
+ readWorkspacePluginPackagePiSnapshot
9
+ } from "@hachej/boring-workspace/app/server";
10
+ function getGlobalPiExtensionsRoot(options = {}) {
11
+ return resolve(options.globalRoot ?? join(homedir(), ".pi", "agent", "extensions"));
12
+ }
13
+ function resolveCliBoringPluginDirs(workspaceRoot, options = {}) {
14
+ const roots = [
15
+ getGlobalPiExtensionsRoot(options),
16
+ resolve(workspaceRoot, ".pi", "extensions")
17
+ ];
18
+ return [...new Set(roots)];
19
+ }
20
+ function readCliPluginPiSnapshot(workspaceRoot, options = {}) {
21
+ return readWorkspacePluginPackagePiSnapshot(resolveCliBoringPluginDirs(workspaceRoot, options));
22
+ }
23
+ function createCliPluginAssetManager(workspaceRoot, options = {}) {
24
+ return new BoringPluginAssetManager({
25
+ pluginDirs: resolveCliBoringPluginDirs(workspaceRoot, options),
26
+ errorRoot: resolve(workspaceRoot, ".boring-agent", "plugin-errors"),
27
+ frontTargetResolver: options.frontTargetResolver,
28
+ includeLegacyFrontUrl: options.includeLegacyFrontUrl
29
+ });
30
+ }
31
+ export {
32
+ createCliPluginAssetManager,
33
+ getGlobalPiExtensionsRoot,
34
+ readCliPluginPiSnapshot,
35
+ resolveCliBoringPluginDirs
36
+ };