@hachej/boring-ui-cli 0.1.36 → 0.1.38

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 (64) hide show
  1. package/dist/server/cli.js +19 -580
  2. package/dist/server/modeApps.js +642 -0
  3. package/dist/server/pluginDiscovery.js +25 -4
  4. package/dist/server/pluginFrontRuntime.js +67 -17
  5. package/package.json +6 -5
  6. package/public/assets/{DebugDrawer-DC7YYrof.js → DebugDrawer-DnJihn7d.js} +1 -1
  7. package/public/assets/{_baseUniq-DWcImnmH.js → _baseUniq-Css5uykF.js} +1 -1
  8. package/public/assets/{arc-DDLmX1AG.js → arc-CnfZXaWe.js} +1 -1
  9. package/public/assets/{architectureDiagram-Q4EWVU46-B38ghbjL.js → architectureDiagram-Q4EWVU46-BANSd98t.js} +1 -1
  10. package/public/assets/{blockDiagram-DXYQGD6D-Bp07F26G.js → blockDiagram-DXYQGD6D-Cd6iEbZF.js} +1 -1
  11. package/public/assets/{c4Diagram-AHTNJAMY-Dcu6Qx6c.js → c4Diagram-AHTNJAMY-9WJupXFB.js} +1 -1
  12. package/public/assets/channel-Cn1SBioe.js +1 -0
  13. package/public/assets/{chunk-4BX2VUAB-DC5-ge26.js → chunk-4BX2VUAB-DEE8UItM.js} +1 -1
  14. package/public/assets/{chunk-4TB4RGXK-WI3HSrJ9.js → chunk-4TB4RGXK-Bf4S3aFF.js} +1 -1
  15. package/public/assets/{chunk-55IACEB6-DphRtKl9.js → chunk-55IACEB6-rumvIfCQ.js} +1 -1
  16. package/public/assets/{chunk-EDXVE4YY-VsnZ7w9d.js → chunk-EDXVE4YY-B41LsR8o.js} +1 -1
  17. package/public/assets/{chunk-FMBD7UC4-DU-cVjgu.js → chunk-FMBD7UC4-Cq0MvVHl.js} +1 -1
  18. package/public/assets/{chunk-OYMX7WX6-B1l0Dpt4.js → chunk-OYMX7WX6-AEfKb-L7.js} +1 -1
  19. package/public/assets/{chunk-QZHKN3VN-38IXLFlx.js → chunk-QZHKN3VN-BnF9Mgjw.js} +1 -1
  20. package/public/assets/{chunk-YZCP3GAM-eY6KeIEv.js → chunk-YZCP3GAM-CVhtG4Yd.js} +1 -1
  21. package/public/assets/classDiagram-6PBFFD2Q-B7iAGzAt.js +1 -0
  22. package/public/assets/classDiagram-v2-HSJHXN6E-B7iAGzAt.js +1 -0
  23. package/public/assets/clone-CKRPa4Cx.js +1 -0
  24. package/public/assets/{cose-bilkent-S5V4N54A-YEoqfW_D.js → cose-bilkent-S5V4N54A-BAlza9SS.js} +1 -1
  25. package/public/assets/{dagre-KV5264BT-B45m1NxI.js → dagre-KV5264BT-DXC-wg6w.js} +1 -1
  26. package/public/assets/{diagram-5BDNPKRD-B5ZXQlWh.js → diagram-5BDNPKRD-DQ_JZ2v6.js} +1 -1
  27. package/public/assets/{diagram-G4DWMVQ6-C1ynjN78.js → diagram-G4DWMVQ6-BV1_oXdH.js} +1 -1
  28. package/public/assets/{diagram-MMDJMWI5-D4hAUvca.js → diagram-MMDJMWI5-CBT9iuoD.js} +1 -1
  29. package/public/assets/{diagram-TYMM5635-B3agZWj-.js → diagram-TYMM5635-2gLQa-5c.js} +1 -1
  30. package/public/assets/{erDiagram-SMLLAGMA-CH2AxsAT.js → erDiagram-SMLLAGMA-BlACgWIF.js} +1 -1
  31. package/public/assets/{flowDiagram-DWJPFMVM-DDgdNECT.js → flowDiagram-DWJPFMVM-C3a4Cakw.js} +1 -1
  32. package/public/assets/{ganttDiagram-T4ZO3ILL-CzvQW97t.js → ganttDiagram-T4ZO3ILL-BvO6eI9n.js} +1 -1
  33. package/public/assets/{gitGraphDiagram-UUTBAWPF-DcQZPPMD.js → gitGraphDiagram-UUTBAWPF-CNRpcuUc.js} +1 -1
  34. package/public/assets/{graph-CD4bwX_-.js → graph-BGcM9Vra.js} +1 -1
  35. package/public/assets/{highlighted-body-OFNGDK62-CiM51uH6.js → highlighted-body-OFNGDK62-DFAlA8ty.js} +1 -1
  36. package/public/assets/{index-BXEu5C8e.js → index-DuQz_ooq.js} +471 -466
  37. package/public/assets/index-o6MvaI3V.css +1 -0
  38. package/public/assets/{infoDiagram-42DDH7IO-nwmufYgw.js → infoDiagram-42DDH7IO-tqWZWhv9.js} +1 -1
  39. package/public/assets/{ishikawaDiagram-UXIWVN3A-CAAuAFim.js → ishikawaDiagram-UXIWVN3A-BSrhE5rT.js} +1 -1
  40. package/public/assets/{journeyDiagram-VCZTEJTY-jPt0NUc6.js → journeyDiagram-VCZTEJTY-p4zWU15s.js} +1 -1
  41. package/public/assets/{kanban-definition-6JOO6SKY-BkWE1oIv.js → kanban-definition-6JOO6SKY-Bh1g0QjZ.js} +1 -1
  42. package/public/assets/{layout-DVywqgnM.js → layout-gyEZgedN.js} +1 -1
  43. package/public/assets/{linear-D5rTUKEy.js → linear-D_hzHorE.js} +1 -1
  44. package/public/assets/{min-CGxxs3H9.js → min-DuaweV_G.js} +1 -1
  45. package/public/assets/{mindmap-definition-QFDTVHPH-C5Bv0ezi.js → mindmap-definition-QFDTVHPH-Bd9cPaCZ.js} +1 -1
  46. package/public/assets/{pieDiagram-DEJITSTG-C4KdtVZ8.js → pieDiagram-DEJITSTG-BtC28nvk.js} +1 -1
  47. package/public/assets/{quadrantDiagram-34T5L4WZ-Cz9vL8Q6.js → quadrantDiagram-34T5L4WZ-D4l6_MzD.js} +1 -1
  48. package/public/assets/{requirementDiagram-MS252O5E-B80rbkJK.js → requirementDiagram-MS252O5E-C1iUHr18.js} +1 -1
  49. package/public/assets/{sankeyDiagram-XADWPNL6-Cn-nZLaG.js → sankeyDiagram-XADWPNL6-OVDB_8ZR.js} +1 -1
  50. package/public/assets/{sequenceDiagram-FGHM5R23-A6IunKM0.js → sequenceDiagram-FGHM5R23-BDavACVC.js} +1 -1
  51. package/public/assets/{stateDiagram-FHFEXIEX-BR6MAf9n.js → stateDiagram-FHFEXIEX-q8RwQFTP.js} +1 -1
  52. package/public/assets/stateDiagram-v2-QKLJ7IA2-BoiN-2KM.js +1 -0
  53. package/public/assets/{timeline-definition-GMOUNBTQ-4cDx4FT9.js → timeline-definition-GMOUNBTQ-y0_Knxi9.js} +1 -1
  54. package/public/assets/{vennDiagram-DHZGUBPP-_CpmLhQd.js → vennDiagram-DHZGUBPP-DbnSIyoN.js} +1 -1
  55. package/public/assets/{wardley-RL74JXVD-CSa4wbmw.js → wardley-RL74JXVD-CIj9kuqP.js} +1 -1
  56. package/public/assets/{wardleyDiagram-NUSXRM2D-DY8-GDoy.js → wardleyDiagram-NUSXRM2D--fILgFoZ.js} +1 -1
  57. package/public/assets/{xychartDiagram-5P7HB3ND-Dbdvqxtm.js → xychartDiagram-5P7HB3ND-YFiXEsiS.js} +1 -1
  58. package/public/index.html +2 -2
  59. package/public/assets/channel-DqOmgrq9.js +0 -1
  60. package/public/assets/classDiagram-6PBFFD2Q-Fjgbctha.js +0 -1
  61. package/public/assets/classDiagram-v2-HSJHXN6E-Fjgbctha.js +0 -1
  62. package/public/assets/clone-CpoJL_n1.js +0 -1
  63. package/public/assets/index-hl1JXpgN.css +0 -1
  64. package/public/assets/stateDiagram-v2-QKLJ7IA2-75t4kRUE.js +0 -1
@@ -1,64 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import { execSync } from "node:child_process";
3
3
  import {
4
- existsSync,
5
- readFileSync
4
+ existsSync
6
5
  } from "node:fs";
7
- import { createRequire } from "node:module";
8
- import { basename, dirname, isAbsolute, join, resolve } from "node:path";
9
- import { fileURLToPath } from "node:url";
6
+ import { basename, join, resolve } from "node:path";
10
7
  import { parseArgs } from "node:util";
11
8
  import { createLocalWorkspaceRegistry } from "./localWorkspaces.js";
12
- const MODE_MAP = {
13
- "local": "direct",
14
- // no sandbox, full network access
15
- "local-sandbox": "local"
16
- // bwrap isolated, no network (Linux only)
17
- };
18
- const require2 = createRequire(import.meta.url);
19
- const PLUGIN_CLI_PACKAGE_NAME = "@hachej/boring-ui-plugin-cli";
20
- const CLI_VERSION = (() => {
21
- try {
22
- const pkg = require2("../../package.json");
23
- return pkg.version ?? "0.0.0";
24
- } catch {
25
- return "0.0.0";
26
- }
27
- })();
28
- function httpError(message, statusCode) {
29
- const error = new Error(message);
30
- error.statusCode = statusCode;
31
- return error;
32
- }
33
- function firstString(value) {
34
- if (typeof value === "string") return value;
35
- if (!Array.isArray(value)) return void 0;
36
- return value.find((item) => typeof item === "string");
37
- }
38
- function resolveWorkspaceIdFromRequest(request) {
39
- const headers = request.headers ?? {};
40
- const headerValue = headers["x-boring-workspace-id"] ?? Object.entries(headers).find(([key]) => key.toLowerCase() === "x-boring-workspace-id")?.[1];
41
- const query = request.query;
42
- const raw = firstString(headerValue) ?? firstString(query?.workspaceId) ?? "";
43
- const workspaceId = raw.trim();
44
- if (!workspaceId) throw httpError("workspace id is required", 400);
45
- if (workspaceId.includes("\0") || workspaceId.includes("/") || workspaceId.includes("\\") || workspaceId.includes("..") || isAbsolute(workspaceId)) {
46
- throw httpError("invalid workspace id", 400);
47
- }
48
- return workspaceId;
49
- }
50
- function toCoreWorkspace(workspace) {
51
- return {
52
- id: workspace.id,
53
- name: workspace.name,
54
- slug: workspace.id,
55
- isDefault: false,
56
- createdAt: workspace.createdAt,
57
- updatedAt: workspace.updatedAt,
58
- unavailable: !workspace.available,
59
- path: workspace.path
60
- };
61
- }
9
+ import {
10
+ MODE_MAP,
11
+ createFolderModeApp,
12
+ createWorkspacesModeApp
13
+ } from "./modeApps.js";
14
+ import {
15
+ createBoringUiCliRuntimePlugin,
16
+ createFolderModeApp as createFolderModeApp2,
17
+ createWorkspacesModeApp as createWorkspacesModeApp2,
18
+ provisionCliWorkspaceRuntime as provisionCliWorkspaceRuntime2,
19
+ resolveBoringUiPluginCliPackageRoot
20
+ } from "./modeApps.js";
21
+ import { resolveBoringUiCliPackageRoot as resolveBoringUiCliPackageRoot2 } from "./pluginDiscovery.js";
62
22
  function openBrowser(url) {
63
23
  try {
64
24
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -66,59 +26,6 @@ function openBrowser(url) {
66
26
  } catch {
67
27
  }
68
28
  }
69
- function resolveBoringUiCliPackageRoot() {
70
- const __dirname = dirname(fileURLToPath(import.meta.url));
71
- return resolve(__dirname, "..", "..");
72
- }
73
- function isUsableBoringUiPluginCliPackageRoot(candidate) {
74
- try {
75
- const pkg = JSON.parse(readFileSync(join(candidate, "package.json"), "utf8"));
76
- return pkg.name === PLUGIN_CLI_PACKAGE_NAME && existsSync(join(candidate, "dist", "bin.js"));
77
- } catch {
78
- return false;
79
- }
80
- }
81
- function resolveBoringUiPluginCliPackageRoot() {
82
- const cliRoot = resolveBoringUiCliPackageRoot();
83
- const candidate = resolve(cliRoot, "..", "plugin-cli");
84
- return isUsableBoringUiPluginCliPackageRoot(candidate) ? candidate : null;
85
- }
86
- function createBoringUiCliRuntimePlugin() {
87
- const useLocal = process.env.BORING_USE_LOCAL_PACKAGES === "1";
88
- const packageRoot = useLocal ? resolveBoringUiPluginCliPackageRoot() : null;
89
- return {
90
- id: "boring-ui-plugin-cli-runtime",
91
- provisioning: {
92
- nodePackages: [{
93
- id: "boring-ui-plugin-cli",
94
- packageName: PLUGIN_CLI_PACKAGE_NAME,
95
- ...packageRoot ? { packageRoot } : { version: CLI_VERSION },
96
- expectedBins: ["boring-ui-plugin"]
97
- }]
98
- }
99
- };
100
- }
101
- async function provisionCliWorkspaceRuntime(opts) {
102
- if (opts.provisionWorkspace === false) return void 0;
103
- const agent = await import("@hachej/boring-agent/server");
104
- const runtimeLayout = opts.runtimeLayout ?? agent.getBoringAgentRuntimePaths(opts.workspaceRoot);
105
- const adapter = opts.adapter ?? opts.modeAdapter?.createProvisioningAdapter?.(runtimeLayout) ?? agent.resolveMode(opts.mode).createProvisioningAdapter?.(runtimeLayout);
106
- if (!adapter) {
107
- throw new Error(`runtime mode ${opts.mode} does not support workspace provisioning`);
108
- }
109
- const result = await agent.provisionWorkspaceRuntime({
110
- plugins: [createBoringUiCliRuntimePlugin(), ...opts.plugins ?? []],
111
- adapter,
112
- runtimeLayout
113
- });
114
- return {
115
- ...result,
116
- env: {
117
- ...result.env,
118
- BORING_AGENT_WORKSPACE_LOCAL_PLUGIN_ROOTS: opts.mode === "direct" || opts.mode === "local" ? "1" : "0"
119
- }
120
- };
121
- }
122
29
  function ensureFrontendBuilt(publicDir) {
123
30
  if (existsSync(join(publicDir, "index.html"))) return;
124
31
  console.error("\nError: boring-ui frontend not found.");
@@ -176,172 +83,6 @@ async function checkAuth() {
176
83
  const registry = ModelRegistry.create(authStorage);
177
84
  return registry.getAvailable().length;
178
85
  }
179
- const FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID = "folder";
180
- const RUNTIME_PLUGIN_TRUST_LABEL = "Trusted local runtime plugins";
181
- const RUNTIME_PLUGIN_TRUST_DESCRIPTION = "Loads plugin UI code from trusted local Pi extension roots through the CLI-owned runtime module host.";
182
- function createRuntimePluginDiagnosticsStore() {
183
- const byWorkspace = /* @__PURE__ */ new Map();
184
- function upsert(workspaceId, pluginId) {
185
- const workspace = byWorkspace.get(workspaceId) ?? /* @__PURE__ */ new Map();
186
- byWorkspace.set(workspaceId, workspace);
187
- const existing = workspace.get(pluginId) ?? {
188
- workspaceId,
189
- pluginId,
190
- recent: []
191
- };
192
- workspace.set(pluginId, existing);
193
- return existing;
194
- }
195
- return {
196
- record(diagnostic) {
197
- if (!diagnostic.workspaceId || !diagnostic.pluginId) return;
198
- const entry = upsert(diagnostic.workspaceId, diagnostic.pluginId);
199
- const now = Date.now();
200
- entry.lastDiagnostic = diagnostic;
201
- entry.recent = [...entry.recent, diagnostic].slice(-12);
202
- if (diagnostic.revision !== void 0) entry.revision = diagnostic.revision;
203
- if (diagnostic.requestedPath) entry.lastRequestedPath = diagnostic.requestedPath;
204
- if (diagnostic.resolvedPath) entry.lastResolvedPath = diagnostic.resolvedPath;
205
- const details = diagnostic.details ?? {};
206
- if (typeof details.rootDir === "string") entry.rootDir = details.rootDir;
207
- if (typeof details.entryUrl === "string") entry.entryUrl = details.entryUrl;
208
- if (typeof diagnostic.requestedPath === "string") entry.frontEntrySubpath = diagnostic.requestedPath;
209
- if (diagnostic.stage === "track" && diagnostic.outcome === "tracked") {
210
- entry.lastErrorCode = void 0;
211
- entry.lastErrorMessage = void 0;
212
- entry.lastErrorStage = void 0;
213
- }
214
- if (diagnostic.stage === "cache") entry.lastRequestAt = now;
215
- if (diagnostic.stage === "transform" && diagnostic.outcome === "served") {
216
- entry.lastTransformAt = now;
217
- entry.lastTransformDurationMs = diagnostic.durationMs;
218
- }
219
- if (diagnostic.stage === "serve" && diagnostic.outcome === "served") {
220
- entry.lastServeAt = now;
221
- entry.lastServeDurationMs = diagnostic.durationMs;
222
- entry.lastErrorCode = void 0;
223
- entry.lastErrorMessage = void 0;
224
- entry.lastErrorStage = void 0;
225
- }
226
- if (diagnostic.outcome === "rejected") {
227
- entry.lastRejectedAt = now;
228
- entry.lastErrorCode = diagnostic.code;
229
- entry.lastErrorMessage = diagnostic.msg;
230
- entry.lastErrorStage = diagnostic.stage;
231
- }
232
- if (diagnostic.stage === "cleanup" && diagnostic.outcome === "disposed") {
233
- entry.lastDisposedAt = now;
234
- }
235
- },
236
- snapshot(workspaceId) {
237
- return [...byWorkspace.get(workspaceId)?.values() ?? []].map((entry) => ({ ...entry, recent: [...entry.recent] })).sort((a, b) => a.pluginId.localeCompare(b.pluginId));
238
- },
239
- disposeWorkspace(workspaceId) {
240
- byWorkspace.delete(workspaceId);
241
- }
242
- };
243
- }
244
- function syncRuntimeHostFromPluginEvents(runtimeHost, workspaceId, events) {
245
- for (const event of events) {
246
- if (event.type === "boring.plugin.unload" || event.type === "boring.plugin.load" && !event.frontTarget) {
247
- runtimeHost.untrackPlugin(workspaceId, event.id);
248
- }
249
- }
250
- }
251
- function buildRuntimePluginDiagnosticsResponse(args) {
252
- const byPlugin = /* @__PURE__ */ new Map();
253
- for (const plugin of args.loaded) {
254
- byPlugin.set(plugin.id, {
255
- id: plugin.id,
256
- ...plugin.version ? { version: plugin.version } : {},
257
- ...plugin.rootDir ? { rootDir: plugin.rootDir } : {},
258
- ...plugin.frontPath ? { frontPath: plugin.frontPath } : {},
259
- ...plugin.frontTarget ? { frontTarget: plugin.frontTarget } : {},
260
- ...plugin.revision !== void 0 ? { serverLoadedRevision: plugin.revision } : {}
261
- });
262
- }
263
- for (const error of args.errors) {
264
- const current = byPlugin.get(error.id) ?? { id: error.id };
265
- byPlugin.set(error.id, {
266
- ...current,
267
- serverError: error.message
268
- });
269
- }
270
- for (const hostEntry of args.host) {
271
- const current = byPlugin.get(hostEntry.pluginId) ?? { id: hostEntry.pluginId };
272
- byPlugin.set(hostEntry.pluginId, {
273
- ...current,
274
- ...current.rootDir ? {} : hostEntry.rootDir ? { rootDir: hostEntry.rootDir } : {},
275
- ...current.frontPath ? {} : hostEntry.frontEntrySubpath ? { frontPath: hostEntry.frontEntrySubpath } : {},
276
- ...current.frontTarget ? {} : hostEntry.entryUrl ? { frontTarget: { kind: "native", entryUrl: hostEntry.entryUrl, revision: hostEntry.revision ?? 0, trust: "local-trusted-native" } } : {},
277
- host: hostEntry
278
- });
279
- }
280
- return {
281
- workspaceId: args.workspaceId,
282
- plugins: [...byPlugin.values()].sort((a, b) => a.id.localeCompare(b.id))
283
- };
284
- }
285
- async function createFolderModeApp(opts) {
286
- const workspaceRoot = resolve(opts.workspaceRoot);
287
- const projectName = opts.projectName ?? (basename(workspaceRoot) || "workspace");
288
- const [{ createWorkspaceAgentServer, readWorkspacePluginPackageRuntimePlugins }, { createPluginFrontRuntimeHost }, pluginDiscovery] = await Promise.all([
289
- import("@hachej/boring-workspace/app/server"),
290
- import("./pluginFrontRuntime.js"),
291
- import("./pluginDiscovery.js")
292
- ]);
293
- const diagnosticsStore = createRuntimePluginDiagnosticsStore();
294
- const runtimeHost = await createPluginFrontRuntimeHost({
295
- onDiagnostic: (diagnostic) => diagnosticsStore.record(diagnostic)
296
- });
297
- const pluginDirs = pluginDiscovery.resolveCliBoringPluginDirs(workspaceRoot);
298
- const runtimeProvisioning = await provisionCliWorkspaceRuntime({
299
- workspaceRoot,
300
- mode: opts.mode,
301
- provisionWorkspace: opts.provisionWorkspace,
302
- plugins: readWorkspacePluginPackageRuntimePlugins(pluginDirs)
303
- });
304
- const app = await createWorkspaceAgentServer({
305
- workspaceRoot,
306
- mode: opts.mode,
307
- logger: false,
308
- provisionWorkspace: false,
309
- runtimeProvisioning,
310
- additionalBoringPluginDirs: pluginDirs,
311
- boringPluginFrontTargetResolver: runtimeHost.createFrontTargetResolver(FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID),
312
- boringPluginIncludeLegacyFrontUrl: false
313
- });
314
- await runtimeHost.registerRoutes(app);
315
- const folderAssetManager = app.__boringAssetManager;
316
- const closeFolderRuntimeCleanup = folderAssetManager?.subscribe((event) => {
317
- syncRuntimeHostFromPluginEvents(runtimeHost, FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID, [event]);
318
- });
319
- if (closeFolderRuntimeCleanup) {
320
- app.addHook("onClose", async () => {
321
- closeFolderRuntimeCleanup();
322
- });
323
- }
324
- app.get("/api/v1/runtime-plugin-diagnostics", async () => {
325
- const manager = app.__boringAssetManager;
326
- return buildRuntimePluginDiagnosticsResponse({
327
- workspaceId: FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID,
328
- loaded: manager?.inspectLoaded() ?? [],
329
- errors: manager?.getErrors() ?? [],
330
- host: diagnosticsStore.snapshot(FOLDER_RUNTIME_PLUGIN_WORKSPACE_ID)
331
- });
332
- });
333
- app.get("/api/v1/workspace/meta", async () => ({
334
- workspaceId: "default",
335
- workspaceRoot,
336
- projectName,
337
- version: CLI_VERSION,
338
- runtimePluginFrontLoadingEnabled: true,
339
- runtimePluginTrustLabel: RUNTIME_PLUGIN_TRUST_LABEL,
340
- runtimePluginTrustDescription: RUNTIME_PLUGIN_TRUST_DESCRIPTION,
341
- runtimePluginDiagnosticsEnabled: true
342
- }));
343
- return app;
344
- }
345
86
  async function startFolderMode(opts) {
346
87
  const workspaceRoot = process.env.BORING_AGENT_WORKSPACE_ROOT ?? resolve(opts.folderArg ?? process.cwd());
347
88
  const projectName = basename(resolve(workspaceRoot)) || "workspace";
@@ -367,308 +108,6 @@ ${projectName}`);
367
108
  `);
368
109
  openBrowser(url);
369
110
  }
370
- async function createWorkspacesModeApp(opts) {
371
- const [workspaceAppServer, workspaceServer, agentServer, fastifyModule, { createPluginFrontRuntimeHost }, pluginDiscovery] = await Promise.all([
372
- import("@hachej/boring-workspace/app/server"),
373
- import("@hachej/boring-workspace/server"),
374
- import("@hachej/boring-agent/server"),
375
- import("fastify"),
376
- import("./pluginFrontRuntime.js"),
377
- import("./pluginDiscovery.js")
378
- ]);
379
- const registry = createLocalWorkspaceRegistry(opts.registryPath);
380
- const app = fastifyModule.default({ logger: false, bodyLimit: 16 * 1024 * 1024 });
381
- const diagnosticsStore = createRuntimePluginDiagnosticsStore();
382
- const runtimeHost = await createPluginFrontRuntimeHost({
383
- onDiagnostic: (diagnostic) => diagnosticsStore.record(diagnostic)
384
- });
385
- await runtimeHost.registerRoutes(app);
386
- const bridges = /* @__PURE__ */ new Map();
387
- const workspaceEventClosers = /* @__PURE__ */ new Map();
388
- const pluginRuntimes = /* @__PURE__ */ new Map();
389
- const pluginPiSnapshots = /* @__PURE__ */ new Map();
390
- const runtimeProvisioningByWorkspace = /* @__PURE__ */ new Map();
391
- function getBridge(workspaceId) {
392
- let bridge = bridges.get(workspaceId);
393
- if (!bridge) {
394
- bridge = workspaceServer.createInMemoryBridge();
395
- bridges.set(workspaceId, bridge);
396
- }
397
- return bridge;
398
- }
399
- async function requireWorkspace(workspaceId) {
400
- const workspace = await registry.get(workspaceId);
401
- if (!workspace) throw httpError("unknown workspace", 404);
402
- if (!workspace.available) throw httpError("workspace folder unavailable", 409);
403
- return workspace;
404
- }
405
- async function workspaceFromRequest(request) {
406
- return await requireWorkspace(resolveWorkspaceIdFromRequest(request));
407
- }
408
- function pluginRuntimeKey(workspace) {
409
- return `${workspace.id}:${workspace.path}`;
410
- }
411
- function syncLoadedPluginPiSnapshot(workspace, manager) {
412
- pluginPiSnapshots.set(pluginRuntimeKey(workspace), manager.inspectLoadedPiSnapshot());
413
- }
414
- function getOrCreatePluginRuntime(workspace) {
415
- const key = pluginRuntimeKey(workspace);
416
- let runtime = pluginRuntimes.get(key);
417
- if (!runtime) {
418
- const manager = pluginDiscovery.createCliPluginAssetManager(workspace.path, {
419
- frontTargetResolver: runtimeHost.createFrontTargetResolver(workspace.id),
420
- includeLegacyFrontUrl: false
421
- });
422
- runtime = {
423
- manager,
424
- ensureLoaded: manager.load().then(() => {
425
- syncLoadedPluginPiSnapshot(workspace, manager);
426
- })
427
- };
428
- pluginRuntimes.set(key, runtime);
429
- }
430
- return runtime;
431
- }
432
- async function getLoadedPluginRuntime(workspace) {
433
- const runtime = getOrCreatePluginRuntime(workspace);
434
- await runtime.ensureLoaded;
435
- return runtime;
436
- }
437
- function getLoadedPluginPiSnapshot(workspace) {
438
- return pluginPiSnapshots.get(pluginRuntimeKey(workspace)) ?? {
439
- additionalSkillPaths: [],
440
- packages: [],
441
- extensionPaths: []
442
- };
443
- }
444
- async function disposeWorkspaceRuntime(workspace) {
445
- for (const close of workspaceEventClosers.get(workspace.id) ?? []) {
446
- try {
447
- close();
448
- } catch {
449
- }
450
- }
451
- workspaceEventClosers.delete(workspace.id);
452
- const runtimeKey = pluginRuntimeKey(workspace);
453
- pluginRuntimes.delete(runtimeKey);
454
- pluginPiSnapshots.delete(runtimeKey);
455
- runtimeProvisioningByWorkspace.delete(workspace.id);
456
- bridges.delete(workspace.id);
457
- diagnosticsStore.disposeWorkspace(workspace.id);
458
- await runtimeHost.disposeWorkspace(workspace.id);
459
- }
460
- function reloadDiagnostics(scan) {
461
- return scan.errors.map((error) => ({
462
- source: "workspaces-plugin-manager",
463
- message: error.message,
464
- pluginId: error.id
465
- }));
466
- }
467
- app.get("/api/v1/local-workspaces", async () => ({
468
- workspaces: await registry.list()
469
- }));
470
- app.post("/api/v1/local-workspaces", async (request, reply) => {
471
- const body = request.body;
472
- if (typeof body?.path !== "string" || !body.path.trim()) {
473
- return reply.code(400).send({ error: "workspace path is required" });
474
- }
475
- try {
476
- const workspace = await registry.add(body.path, {
477
- name: typeof body.name === "string" ? body.name : void 0
478
- });
479
- return { workspace };
480
- } catch (error) {
481
- return reply.code(400).send({
482
- error: error instanceof Error ? error.message : "unable to add workspace"
483
- });
484
- }
485
- });
486
- app.delete("/api/v1/local-workspaces/:id", async (request, reply) => {
487
- const { id } = request.params;
488
- const workspace = await registry.get(id);
489
- await registry.remove(id);
490
- if (workspace) await disposeWorkspaceRuntime(workspace);
491
- return reply.send({ ok: true });
492
- });
493
- app.get("/api/v1/workspaces", async () => ({
494
- workspaces: (await registry.list()).map(toCoreWorkspace)
495
- }));
496
- app.get("/api/v1/workspaces/:id", async (request, reply) => {
497
- const { id } = request.params;
498
- const workspace = await registry.get(id);
499
- if (!workspace) return reply.code(404).send({ error: "workspace not found" });
500
- return { workspace: toCoreWorkspace(workspace), role: "owner" };
501
- });
502
- await app.register(agentServer.registerAgentRoutes, {
503
- mode: opts.mode,
504
- systemPromptAppend: workspaceAppServer.buildWorkspaceContextPrompt(),
505
- getSystemPromptDynamic: async ({ workspaceId }) => {
506
- const workspace = await requireWorkspace(workspaceId);
507
- await getLoadedPluginRuntime(workspace);
508
- return getLoadedPluginPiSnapshot(workspace).systemPromptAppend;
509
- },
510
- getWorkspaceId: async (request) => (await workspaceFromRequest(request)).id,
511
- getWorkspaceRoot: async (workspaceId) => (await requireWorkspace(workspaceId)).path,
512
- getSessionNamespace: async ({ workspaceId }) => `local-workspace-${workspaceId}`,
513
- provisionRuntime: async ({ workspaceId, workspaceRoot, runtimeMode, runtimeLayout, provisioningAdapter }) => {
514
- if (runtimeProvisioningByWorkspace.has(workspaceId)) {
515
- return runtimeProvisioningByWorkspace.get(workspaceId);
516
- }
517
- const provisioned = await provisionCliWorkspaceRuntime({
518
- workspaceRoot,
519
- mode: runtimeMode,
520
- provisionWorkspace: opts.provisionWorkspace,
521
- adapter: provisioningAdapter,
522
- runtimeLayout,
523
- plugins: workspaceAppServer.readWorkspacePluginPackageRuntimePlugins(pluginDiscovery.resolveCliBoringPluginDirs(workspaceRoot))
524
- });
525
- runtimeProvisioningByWorkspace.set(workspaceId, provisioned);
526
- return provisioned;
527
- },
528
- beforeReload: async ({ workspaceId }) => {
529
- const workspace = await requireWorkspace(workspaceId);
530
- const runtime = await getLoadedPluginRuntime(workspace);
531
- runtime.manager.setPluginDirs(pluginDiscovery.resolveCliBoringPluginDirs(workspace.path));
532
- const scan = await runtime.manager.load();
533
- syncLoadedPluginPiSnapshot(workspace, runtime.manager);
534
- syncRuntimeHostFromPluginEvents(runtimeHost, workspaceId, scan.events);
535
- return {
536
- restart_warnings: workspaceServer.collectRestartWarnings(scan.events),
537
- diagnostics: reloadDiagnostics(scan)
538
- };
539
- },
540
- getPi: async ({ workspaceId, workspaceRoot }) => {
541
- const workspace = await requireWorkspace(workspaceId);
542
- await getLoadedPluginRuntime(workspace);
543
- return {
544
- additionalSkillPaths: [join(workspaceRoot, ".agents", "skills")],
545
- packages: [],
546
- extensionPaths: [],
547
- getHotReloadableResources: () => getLoadedPluginPiSnapshot(workspace)
548
- };
549
- },
550
- getExtraTools: async ({ workspaceId, workspaceRoot, workspaceFsCapability }) => [
551
- ...workspaceServer.createWorkspaceUiTools(getBridge(workspaceId), {
552
- workspaceRoot: workspaceFsCapability === "strong" ? workspaceRoot : void 0
553
- })
554
- ]
555
- });
556
- await app.register(workspaceServer.uiRoutes, {
557
- getWorkspaceId: async (request) => (await workspaceFromRequest(request)).id,
558
- getBridge: async (request) => getBridge((await workspaceFromRequest(request)).id)
559
- });
560
- app.get("/api/v1/runtime-plugin-diagnostics", async (request) => {
561
- const workspace = await workspaceFromRequest(request);
562
- const runtime = await getLoadedPluginRuntime(workspace);
563
- return buildRuntimePluginDiagnosticsResponse({
564
- workspaceId: workspace.id,
565
- loaded: runtime.manager.inspectLoaded(),
566
- errors: runtime.manager.getErrors(),
567
- host: diagnosticsStore.snapshot(workspace.id)
568
- });
569
- });
570
- app.get("/api/v1/agent-plugins", async (request) => {
571
- const workspace = await workspaceFromRequest(request);
572
- const runtime = await getLoadedPluginRuntime(workspace);
573
- return runtime.manager.list();
574
- });
575
- app.get("/api/v1/agent-plugins/:id/error", async (request, reply) => {
576
- const workspace = await workspaceFromRequest(request);
577
- const runtime = await getLoadedPluginRuntime(workspace);
578
- const { id } = request.params;
579
- const error = runtime.manager.getError(id);
580
- if (error == null) return reply.code(404).send({ error: "not_found" });
581
- return reply.type("text/plain").send(error);
582
- });
583
- app.get("/api/v1/agent-plugins/events", async (request, reply) => {
584
- const workspace = await workspaceFromRequest(request);
585
- const runtime = await getLoadedPluginRuntime(workspace);
586
- const manager = runtime.manager;
587
- reply.hijack();
588
- const res = reply.raw;
589
- res.statusCode = 200;
590
- res.setHeader("Content-Type", "text/event-stream");
591
- res.setHeader("Cache-Control", "no-cache, no-transform");
592
- res.setHeader("Connection", "keep-alive");
593
- res.setHeader("X-Accel-Buffering", "no");
594
- res.flushHeaders?.();
595
- const write = (eventName, payload) => {
596
- try {
597
- res.write(`event: ${eventName}
598
- `);
599
- res.write(`data: ${JSON.stringify(payload)}
600
-
601
- `);
602
- } catch {
603
- }
604
- };
605
- const liveQueue = [];
606
- let replaying = true;
607
- const unsubscribe = manager.subscribe((event) => {
608
- if (event.type === "boring.plugin.unload" || event.type === "boring.plugin.load" && !event.frontTarget) {
609
- runtimeHost.untrackPlugin(workspace.id, event.id);
610
- }
611
- const payload = {
612
- ...event,
613
- workspaceId: workspace.id,
614
- replay: false
615
- };
616
- if (replaying) {
617
- liveQueue.push({ eventName: event.type, payload });
618
- return;
619
- }
620
- write(event.type, payload);
621
- });
622
- for (const plugin of manager.list()) {
623
- write("boring.plugin.load", {
624
- type: "boring.plugin.load",
625
- id: plugin.id,
626
- boring: plugin.boring,
627
- version: plugin.version,
628
- revision: plugin.revision,
629
- ...plugin.frontTarget ? { frontTarget: plugin.frontTarget } : {},
630
- workspaceId: workspace.id,
631
- replay: true
632
- });
633
- }
634
- write("boring.plugin.replay-complete", {
635
- type: "boring.plugin.replay-complete",
636
- workspaceId: workspace.id,
637
- replay: true
638
- });
639
- replaying = false;
640
- for (const event of liveQueue) write(event.eventName, event.payload);
641
- const heartbeat = setInterval(() => {
642
- try {
643
- res.write(": heartbeat\n\n");
644
- } catch {
645
- }
646
- }, 25e3);
647
- const closeStream = () => {
648
- clearInterval(heartbeat);
649
- unsubscribe();
650
- workspaceEventClosers.get(workspace.id)?.delete(closeStream);
651
- try {
652
- res.end();
653
- } catch {
654
- }
655
- };
656
- const closers = workspaceEventClosers.get(workspace.id) ?? /* @__PURE__ */ new Set();
657
- closers.add(closeStream);
658
- workspaceEventClosers.set(workspace.id, closers);
659
- request.raw.on("close", closeStream);
660
- });
661
- app.get("/api/v1/workspace/meta", async () => ({
662
- projectName: "Boring UI",
663
- workspacesMode: true,
664
- version: CLI_VERSION,
665
- runtimePluginFrontLoadingEnabled: true,
666
- runtimePluginTrustLabel: RUNTIME_PLUGIN_TRUST_LABEL,
667
- runtimePluginTrustDescription: RUNTIME_PLUGIN_TRUST_DESCRIPTION,
668
- runtimePluginDiagnosticsEnabled: true
669
- }));
670
- return app;
671
- }
672
111
  async function startWorkspacesMode(opts) {
673
112
  const app = await createWorkspacesModeApp({ mode: opts.mode });
674
113
  const registry = createLocalWorkspaceRegistry();
@@ -787,11 +226,11 @@ async function runCli(options) {
787
226
  }
788
227
  export {
789
228
  createBoringUiCliRuntimePlugin,
790
- createFolderModeApp,
791
- createWorkspacesModeApp,
792
- provisionCliWorkspaceRuntime,
229
+ createFolderModeApp2 as createFolderModeApp,
230
+ createWorkspacesModeApp2 as createWorkspacesModeApp,
231
+ provisionCliWorkspaceRuntime2 as provisionCliWorkspaceRuntime,
793
232
  registerStatic,
794
- resolveBoringUiCliPackageRoot,
233
+ resolveBoringUiCliPackageRoot2 as resolveBoringUiCliPackageRoot,
795
234
  resolveBoringUiPluginCliPackageRoot,
796
235
  runCli
797
236
  };