@hachej/boring-ui-cli 0.1.25 → 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.
- package/dist/server/cli.js +445 -38
- package/dist/server/pluginDiscovery.js +36 -0
- package/dist/server/pluginFrontRuntime.js +1458 -0
- package/package.json +7 -7
- package/public/assets/DebugDrawer-kRj0QGoh.js +1 -0
- package/public/assets/_baseUniq-BaoahSEi.js +1 -0
- package/public/assets/angular-ts-BrjP3tb8.js +1 -1
- package/public/assets/angular-ts-BwZT4LLn.js +1 -1
- package/public/assets/apl-CORt7UWP.js +1 -1
- package/public/assets/apl-dKokRX4l.js +1 -1
- package/public/assets/arc-BGT9Yoor.js +1 -0
- package/public/assets/architectureDiagram-Q4EWVU46-8Fsx8Bw5.js +36 -0
- package/public/assets/astro-CbQHKStN.js +1 -1
- package/public/assets/astro-HNnZUWAn.js +1 -1
- package/public/assets/blade-BjGOyj-B.js +1 -1
- package/public/assets/blade-D4QpJJKB.js +1 -1
- package/public/assets/{blockDiagram-DXYQGD6D-DEkkj6Fh.js → blockDiagram-DXYQGD6D-CSD_8P6t.js} +5 -5
- package/public/assets/{c4Diagram-AHTNJAMY-CEZo72O7.js → c4Diagram-AHTNJAMY-BANFpiWc.js} +1 -1
- package/public/assets/channel-BdMajkgC.js +1 -0
- package/public/assets/{chunk-4BX2VUAB-kct9rMc4.js → chunk-4BX2VUAB-DwXbCZ7y.js} +1 -1
- package/public/assets/{chunk-4TB4RGXK-przR2bht.js → chunk-4TB4RGXK-Dk2hp0kY.js} +3 -3
- package/public/assets/{chunk-55IACEB6-BtFWJCbx.js → chunk-55IACEB6-CFeiGe8t.js} +1 -1
- package/public/assets/{chunk-EDXVE4YY-wnitHF3B.js → chunk-EDXVE4YY-B0SJv4ej.js} +1 -1
- package/public/assets/{chunk-FMBD7UC4-8PDhdiie.js → chunk-FMBD7UC4-BakGwea6.js} +1 -1
- package/public/assets/{chunk-OYMX7WX6-TDftW5K8.js → chunk-OYMX7WX6-Dq0T_fTM.js} +2 -2
- package/public/assets/{chunk-QZHKN3VN-B5vnQXaM.js → chunk-QZHKN3VN-B5OglTTC.js} +1 -1
- package/public/assets/{chunk-YZCP3GAM-CGg2izn8.js → chunk-YZCP3GAM-NDaB-kfw.js} +1 -1
- package/public/assets/classDiagram-6PBFFD2Q-B-lcy3NJ.js +1 -0
- package/public/assets/classDiagram-v2-HSJHXN6E-B-lcy3NJ.js +1 -0
- package/public/assets/clone-CQaScT6j.js +1 -0
- package/public/assets/cobol-nBiQ_Alo.js +1 -1
- package/public/assets/cobol-nwyudZeR.js +1 -1
- package/public/assets/{cose-bilkent-S5V4N54A-CjXKbjHV.js → cose-bilkent-S5V4N54A-C_XiHCxn.js} +1 -1
- package/public/assets/crystal-DNxU26gB.js +1 -1
- package/public/assets/crystal-tKQVLTB8.js +1 -1
- package/public/assets/{dagre-KV5264BT-D-wBcwT7.js → dagre-KV5264BT-DeKC0ZTS.js} +2 -2
- package/public/assets/diagram-5BDNPKRD-BI21qA6c.js +10 -0
- package/public/assets/diagram-G4DWMVQ6-DXlN6VCm.js +24 -0
- package/public/assets/diagram-MMDJMWI5-BCJkUUZU.js +43 -0
- package/public/assets/diagram-TYMM5635-C-KOEBZV.js +24 -0
- package/public/assets/edge-BkV0erSs.js +1 -1
- package/public/assets/edge-FbVlp4U3.js +1 -1
- package/public/assets/elixir-CDX3lj18.js +1 -1
- package/public/assets/elixir-CkH2-t6x.js +1 -1
- package/public/assets/{erDiagram-SMLLAGMA-CUWacc8b.js → erDiagram-SMLLAGMA-_vucZwTa.js} +2 -2
- package/public/assets/erb-B12qg9BL.js +1 -1
- package/public/assets/erb-BYCe7drp.js +1 -1
- package/public/assets/{flowDiagram-DWJPFMVM-DVIhUX7Z.js → flowDiagram-DWJPFMVM-CWye_WgN.js} +4 -4
- package/public/assets/{ganttDiagram-T4ZO3ILL-g3ncLabH.js → ganttDiagram-T4ZO3ILL-Cg6T_N_V.js} +3 -3
- package/public/assets/gitGraphDiagram-UUTBAWPF-CI6tYFw1.js +106 -0
- package/public/assets/glimmer-js-ByusRIyA.js +1 -1
- package/public/assets/glimmer-js-Rg0-pVw9.js +1 -1
- package/public/assets/glimmer-ts-BfAWNZQY.js +1 -1
- package/public/assets/glimmer-ts-U6CK756n.js +1 -1
- package/public/assets/{graph-CDl50skT.js → graph-Ci4pDE3A.js} +1 -1
- package/public/assets/hack-CaT9iCJl.js +1 -1
- package/public/assets/hack-i7_Ulhet.js +1 -1
- package/public/assets/haml-B8DHNrY2.js +1 -1
- package/public/assets/haml-D5jkg6IW.js +1 -1
- package/public/assets/handlebars-BL8al0AC.js +1 -1
- package/public/assets/handlebars-BpdQsYii.js +1 -1
- package/public/assets/highlighted-body-OFNGDK62-xGLlGy3l.js +1 -0
- package/public/assets/html-GMplVEZG.js +1 -1
- package/public/assets/html-derivative-BFtXZ54Q.js +1 -1
- package/public/assets/html-derivative-DlHx6ybY.js +1 -1
- package/public/assets/html-pp8916En.js +1 -1
- package/public/assets/index-BNz332Xu.js +1669 -0
- package/public/assets/index-D5qFagsx.css +1 -0
- package/public/assets/infoDiagram-42DDH7IO-CigcPMhk.js +2 -0
- package/public/assets/{ishikawaDiagram-UXIWVN3A-BbjR1GdS.js → ishikawaDiagram-UXIWVN3A-CDZTRajH.js} +4 -4
- package/public/assets/jinja-4LBKfQ-Z.js +1 -1
- package/public/assets/jinja-f2NsQr07.js +1 -1
- package/public/assets/{journeyDiagram-VCZTEJTY-DJHw1u4a.js → journeyDiagram-VCZTEJTY-C9MHFDJ6.js} +4 -4
- package/public/assets/just-Cw27pwNe.js +1 -1
- package/public/assets/just-VxiPbLrw.js +1 -1
- package/public/assets/{kanban-definition-6JOO6SKY-agbEFS20.js → kanban-definition-6JOO6SKY-Hpr02Gir.js} +7 -7
- package/public/assets/{layout-BtrYpvUW.js → layout-uDkQb6eL.js} +1 -1
- package/public/assets/{linear-C4IQ6Sya.js → linear-D9bVI_aq.js} +1 -1
- package/public/assets/liquid-C0sCDyMI.js +1 -1
- package/public/assets/liquid-DYVedYrR.js +1 -1
- package/public/assets/marko-CnJfTvn9.js +1 -1
- package/public/assets/marko-DjSrsDqO.js +1 -1
- package/public/assets/mdc-BMNejdWA.js +1 -1
- package/public/assets/mdc-DTYItulj.js +1 -1
- package/public/assets/{min-DDWmdqiX.js → min-T0CPelcS.js} +1 -1
- package/public/assets/{mindmap-definition-QFDTVHPH-By9_uC_s.js → mindmap-definition-QFDTVHPH-BxDJYpMb.js} +8 -8
- package/public/assets/nim-BIad80T-.js +1 -1
- package/public/assets/nim-CVrawwO9.js +1 -1
- package/public/assets/perl-C0TMdlhV.js +1 -1
- package/public/assets/perl-NvoQZIq0.js +1 -1
- package/public/assets/php-Dhbhpdrm.js +1 -1
- package/public/assets/php-R6g_5hLQ.js +1 -1
- package/public/assets/pieDiagram-DEJITSTG-C214NdS2.js +30 -0
- package/public/assets/pug-CGlum2m_.js +1 -1
- package/public/assets/pug-DKIMFp6K.js +1 -1
- package/public/assets/{quadrantDiagram-34T5L4WZ-BszNW2Gc.js → quadrantDiagram-34T5L4WZ-B4hldTdV.js} +3 -3
- package/public/assets/razor-BDqjjVU7.js +1 -1
- package/public/assets/razor-Uh8Bk_45.js +1 -1
- package/public/assets/{requirementDiagram-MS252O5E-fdyCkRN5.js → requirementDiagram-MS252O5E-Cv-IZSGz.js} +1 -1
- package/public/assets/rst-BrH8l1NY.js +1 -1
- package/public/assets/rst-CRjBmOyv.js +1 -1
- package/public/assets/ruby-Dw2BHqvy.js +1 -1
- package/public/assets/ruby-Wjq7vjNf.js +1 -1
- package/public/assets/{sankeyDiagram-XADWPNL6-tg2HOfl2.js → sankeyDiagram-XADWPNL6-C52Wx9t_.js} +2 -2
- package/public/assets/{sequenceDiagram-FGHM5R23-GF78cQ5y.js → sequenceDiagram-FGHM5R23-C9gRx_I2.js} +5 -5
- package/public/assets/soy-8wufbnw4.js +1 -1
- package/public/assets/soy-Brmx7dQM.js +1 -1
- package/public/assets/{stateDiagram-FHFEXIEX-C709lyuE.js → stateDiagram-FHFEXIEX-BVweWFAE.js} +1 -1
- package/public/assets/stateDiagram-v2-QKLJ7IA2-CftkpTOS.js +1 -0
- package/public/assets/svelte-C_ipcX3V.js +1 -1
- package/public/assets/svelte-Cy7k_4gC.js +1 -1
- package/public/assets/templ-DhtptRzy.js +1 -1
- package/public/assets/templ-P3uqSqPl.js +1 -1
- package/public/assets/{timeline-definition-GMOUNBTQ-D2y-83yP.js → timeline-definition-GMOUNBTQ-Boc8Q03t.js} +3 -3
- package/public/assets/ts-tags-DQrlYJgV.js +1 -1
- package/public/assets/ts-tags-zn1MmPIZ.js +1 -1
- package/public/assets/twig-DNn4PbVi.js +1 -1
- package/public/assets/twig-xg9kU7Mw.js +1 -1
- package/public/assets/vennDiagram-DHZGUBPP-BE8XjSYZ.js +34 -0
- package/public/assets/vue-D2xRrEX4.js +1 -1
- package/public/assets/vue-DN_0RTcg.js +1 -1
- package/public/assets/vue-vine-BoDAl6tE.js +1 -1
- package/public/assets/vue-vine-CQOfvN7w.js +1 -1
- package/public/assets/{wardley-RL74JXVD-NEg4mPyC.js → wardley-RL74JXVD-MQjS4K_T.js} +1 -1
- package/public/assets/{wardleyDiagram-NUSXRM2D-BbXAj99t.js → wardleyDiagram-NUSXRM2D-CKUw97nD.js} +2 -2
- package/public/assets/{xychartDiagram-5P7HB3ND-C8Y3cC5f.js → xychartDiagram-5P7HB3ND-OkP2T3uc.js} +3 -3
- package/public/index.html +2 -2
- package/templates/front-canonical.tsx +4 -2
- package/public/assets/CodeEditor-DQqOn4xz-BnYIpEQ0.js +0 -31
- package/public/assets/FileTree-DjPzfDMq-jOFMfLV-.js +0 -21
- package/public/assets/MarkdownEditor-BbSy0bLV-_8qFqqna.js +0 -254
- package/public/assets/_baseUniq-DysFpiFw.js +0 -1
- package/public/assets/arc-D0sqkACA.js +0 -1
- package/public/assets/architectureDiagram-Q4EWVU46-DnyELkA2.js +0 -36
- package/public/assets/channel-Ci4DEwaO.js +0 -1
- package/public/assets/classDiagram-6PBFFD2Q-0PAZNzgC.js +0 -1
- package/public/assets/classDiagram-v2-HSJHXN6E-0PAZNzgC.js +0 -1
- package/public/assets/clone-_lPYOTLf.js +0 -1
- package/public/assets/diagram-5BDNPKRD-Ch4e4G6h.js +0 -10
- package/public/assets/diagram-G4DWMVQ6-a_PPD1uY.js +0 -24
- package/public/assets/diagram-MMDJMWI5-D9Lkv8IB.js +0 -43
- package/public/assets/diagram-TYMM5635-BlfaVidf.js +0 -24
- package/public/assets/gitGraphDiagram-UUTBAWPF-DpPqglKx.js +0 -106
- package/public/assets/highlighted-body-OFNGDK62-BcVhfY0-.js +0 -1
- package/public/assets/index-C9S_GD0T.js +0 -1330
- package/public/assets/index-CrFvzn5a.js +0 -9
- package/public/assets/index-Css1pwyY.css +0 -1
- package/public/assets/index-Vcq4gwWv.js +0 -1
- package/public/assets/infoDiagram-42DDH7IO-COfGVlDB.js +0 -2
- package/public/assets/pieDiagram-DEJITSTG-DfzJSvMR.js +0 -30
- package/public/assets/stateDiagram-v2-QKLJ7IA2-BbgcVrKo.js +0 -1
- package/public/assets/vennDiagram-DHZGUBPP-BOsWwU4c.js +0 -34
package/dist/server/cli.js
CHANGED
|
@@ -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
|
-
|
|
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;
|
|
@@ -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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
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(
|
|
363
|
+
openBrowser(url);
|
|
199
364
|
}
|
|
200
|
-
async function
|
|
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
|
-
|
|
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
|
-
|
|
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(`
|
|
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,
|
|
@@ -510,6 +881,10 @@ async function runCli(options) {
|
|
|
510
881
|
});
|
|
511
882
|
return;
|
|
512
883
|
}
|
|
884
|
+
if (positionals[0] === "plugin-status") {
|
|
885
|
+
handlePluginStatusCommand({ json: args.json === true });
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
513
888
|
if (positionals[0] === "scaffold-plugin") {
|
|
514
889
|
await handleScaffoldPluginCommand({ positionals });
|
|
515
890
|
return;
|
|
@@ -526,6 +901,32 @@ async function runCli(options) {
|
|
|
526
901
|
function defaultWorkspaceRoot() {
|
|
527
902
|
return process.env.BORING_AGENT_WORKSPACE_ROOT ?? process.cwd();
|
|
528
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
|
+
}
|
|
529
930
|
async function handleVerifyPluginCommand(opts) {
|
|
530
931
|
const maybeName = opts.positionals[1];
|
|
531
932
|
const maybeWorkspace = opts.positionals[2];
|
|
@@ -556,6 +957,10 @@ async function handleScaffoldPluginCommand(opts) {
|
|
|
556
957
|
if (!name) {
|
|
557
958
|
throw new Error("usage: boring-ui scaffold-plugin <name> [workspace]");
|
|
558
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
|
+
}
|
|
559
964
|
const workspaceRoot = resolve(opts.positionals[2] ?? defaultWorkspaceRoot());
|
|
560
965
|
const { scaffoldPlugin } = await import("./scaffoldPlugin.js");
|
|
561
966
|
const result = scaffoldPlugin({ name, workspaceRoot });
|
|
@@ -577,6 +982,8 @@ async function handleScaffoldPluginCommand(opts) {
|
|
|
577
982
|
}
|
|
578
983
|
export {
|
|
579
984
|
createBoringUiCliRuntimePlugin,
|
|
985
|
+
createFolderModeApp,
|
|
986
|
+
createWorkspacesModeApp,
|
|
580
987
|
provisionCliWorkspaceRuntime,
|
|
581
988
|
registerStatic,
|
|
582
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
|
+
};
|