@hachej/boring-ui-cli 0.1.30 → 0.1.32

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 (92) hide show
  1. package/README.md +7 -4
  2. package/dist/server/cli.js +35 -233
  3. package/dist/server/pluginFrontRuntime.js +183 -23
  4. package/package.json +7 -6
  5. package/public/assets/DebugDrawer-DB9C3tZz.js +1 -0
  6. package/public/assets/{_baseUniq-2WvYsyyQ.js → _baseUniq-BHrtLO8W.js} +1 -1
  7. package/public/assets/{arc-BfQMEcaD.js → arc-BTJHwuiF.js} +1 -1
  8. package/public/assets/architectureDiagram-Q4EWVU46-CJMeSZx6.js +36 -0
  9. package/public/assets/{blockDiagram-DXYQGD6D-BwO0KFc4.js → blockDiagram-DXYQGD6D-D_iRmbs0.js} +5 -5
  10. package/public/assets/{c4Diagram-AHTNJAMY-3ZfOXc8v.js → c4Diagram-AHTNJAMY-DqJK-oCk.js} +1 -1
  11. package/public/assets/channel-t1oMFJWT.js +1 -0
  12. package/public/assets/{chunk-4BX2VUAB-CRl1YiJJ.js → chunk-4BX2VUAB-DBqhw0eR.js} +1 -1
  13. package/public/assets/{chunk-4TB4RGXK-DrpTwphl.js → chunk-4TB4RGXK-BEbQ9ff5.js} +2 -2
  14. package/public/assets/chunk-55IACEB6-sdAV4otZ.js +1 -0
  15. package/public/assets/{chunk-EDXVE4YY-BC7-AFdu.js → chunk-EDXVE4YY-BGeNOj7f.js} +1 -1
  16. package/public/assets/{chunk-FMBD7UC4-DsK26d_T.js → chunk-FMBD7UC4-DwD_gBy0.js} +1 -1
  17. package/public/assets/{chunk-OYMX7WX6-BeikaWZm.js → chunk-OYMX7WX6-CjMCkDF3.js} +1 -1
  18. package/public/assets/{chunk-QZHKN3VN-BwxHokKH.js → chunk-QZHKN3VN-Cot2XaAR.js} +1 -1
  19. package/public/assets/{chunk-YZCP3GAM-BbZ8wRWB.js → chunk-YZCP3GAM-CGX-4Jvn.js} +1 -1
  20. package/public/assets/classDiagram-6PBFFD2Q-BgSBQBOf.js +1 -0
  21. package/public/assets/classDiagram-v2-HSJHXN6E-BgSBQBOf.js +1 -0
  22. package/public/assets/clone-BBHYjbBI.js +1 -0
  23. package/public/assets/{cose-bilkent-S5V4N54A-C3HWuNVz.js → cose-bilkent-S5V4N54A-CDntEO8X.js} +1 -1
  24. package/public/assets/{dagre-KV5264BT-DOVky5l9.js → dagre-KV5264BT-ZOVUZI--.js} +2 -2
  25. package/public/assets/diagram-5BDNPKRD-LdjTY2br.js +10 -0
  26. package/public/assets/diagram-G4DWMVQ6-BWxGregh.js +24 -0
  27. package/public/assets/diagram-MMDJMWI5-CxtOYZMd.js +43 -0
  28. package/public/assets/diagram-TYMM5635-ChD56z2q.js +24 -0
  29. package/public/assets/{erDiagram-SMLLAGMA-wZ_XblND.js → erDiagram-SMLLAGMA-B8zSJysM.js} +2 -2
  30. package/public/assets/{flowDiagram-DWJPFMVM-of3iiuJI.js → flowDiagram-DWJPFMVM-Dqqy7UJT.js} +1 -1
  31. package/public/assets/{ganttDiagram-T4ZO3ILL-CiIxc0v4.js → ganttDiagram-T4ZO3ILL-Dn_EJlMH.js} +1 -1
  32. package/public/assets/gitGraphDiagram-UUTBAWPF-BVuaJiec.js +106 -0
  33. package/public/assets/{graph-CandW0gD.js → graph-Dj5mmSf2.js} +1 -1
  34. package/public/assets/highlighted-body-OFNGDK62-Cn9lWz0x.js +1 -0
  35. package/public/assets/index-Ciaf_ynY.css +1 -0
  36. package/public/assets/{index-CtdAhKdF.js → index-CrmEpxcy.js} +423 -398
  37. package/public/assets/{infoDiagram-42DDH7IO-B4MJKAr8.js → infoDiagram-42DDH7IO-DawFXMLo.js} +1 -1
  38. package/public/assets/{ishikawaDiagram-UXIWVN3A-Bl2J6bvs.js → ishikawaDiagram-UXIWVN3A-DBxt-riO.js} +4 -4
  39. package/public/assets/{journeyDiagram-VCZTEJTY-JYysqMwv.js → journeyDiagram-VCZTEJTY-D50mNLlL.js} +4 -4
  40. package/public/assets/{kanban-definition-6JOO6SKY-B0wB13fQ.js → kanban-definition-6JOO6SKY-CFBUjJCs.js} +6 -6
  41. package/public/assets/{layout-DYl8UnAo.js → layout-DEdejLi9.js} +1 -1
  42. package/public/assets/{linear-Dj3asvOm.js → linear-BXKtVmEh.js} +1 -1
  43. package/public/assets/{min-Cbw7dpzS.js → min-DY1T79Si.js} +1 -1
  44. package/public/assets/{mindmap-definition-QFDTVHPH-DLl-2gHB.js → mindmap-definition-QFDTVHPH-DbCBDJgc.js} +9 -9
  45. package/public/assets/pieDiagram-DEJITSTG-DYgefMzu.js +30 -0
  46. package/public/assets/{quadrantDiagram-34T5L4WZ-CqkG9t9_.js → quadrantDiagram-34T5L4WZ-552sDLt-.js} +2 -2
  47. package/public/assets/{requirementDiagram-MS252O5E-D_SkRDmv.js → requirementDiagram-MS252O5E-DNzvM72W.js} +1 -1
  48. package/public/assets/{sankeyDiagram-XADWPNL6-BoQxjHkJ.js → sankeyDiagram-XADWPNL6-DKy6TNHm.js} +6 -6
  49. package/public/assets/{sequenceDiagram-FGHM5R23-BDGOIizo.js → sequenceDiagram-FGHM5R23-BQCY2Zf9.js} +5 -5
  50. package/public/assets/{stateDiagram-FHFEXIEX-SYaFpYZC.js → stateDiagram-FHFEXIEX-D7T4Km3f.js} +1 -1
  51. package/public/assets/stateDiagram-v2-QKLJ7IA2-CYjKpaa0.js +1 -0
  52. package/public/assets/{timeline-definition-GMOUNBTQ-DKLze3x4.js → timeline-definition-GMOUNBTQ-CqlaVFMe.js} +8 -8
  53. package/public/assets/{vennDiagram-DHZGUBPP-SSE-F6n3.js → vennDiagram-DHZGUBPP-D4C7VzEp.js} +5 -5
  54. package/public/assets/{wardley-RL74JXVD-S0ICuT1a.js → wardley-RL74JXVD-BYxilceB.js} +1 -1
  55. package/public/assets/{wardleyDiagram-NUSXRM2D-DMA7ZjAO.js → wardleyDiagram-NUSXRM2D-B5Zztop3.js} +2 -2
  56. package/public/assets/{xychartDiagram-5P7HB3ND-CZZ9juBQ.js → xychartDiagram-5P7HB3ND-CAK4X6lJ.js} +4 -4
  57. package/public/index.html +2 -2
  58. package/dist/server/scaffoldPlugin.js +0 -72
  59. package/dist/server/verifyPlugin.js +0 -235
  60. package/public/assets/DebugDrawer-C-v1B1vW.js +0 -1
  61. package/public/assets/architectureDiagram-Q4EWVU46-Bj_s6upX.js +0 -36
  62. package/public/assets/channel-DLeWkql2.js +0 -1
  63. package/public/assets/chunk-55IACEB6-D5vTVeAc.js +0 -1
  64. package/public/assets/classDiagram-6PBFFD2Q-CVe-3aSj.js +0 -1
  65. package/public/assets/classDiagram-v2-HSJHXN6E-CVe-3aSj.js +0 -1
  66. package/public/assets/clone-Dkncs6zh.js +0 -1
  67. package/public/assets/diagram-5BDNPKRD-DnAM93VO.js +0 -10
  68. package/public/assets/diagram-G4DWMVQ6-CcYjwbKm.js +0 -24
  69. package/public/assets/diagram-MMDJMWI5-B6xlqXbp.js +0 -43
  70. package/public/assets/diagram-TYMM5635-B9ak5QMP.js +0 -24
  71. package/public/assets/gitGraphDiagram-UUTBAWPF-IAJs2Nmr.js +0 -106
  72. package/public/assets/highlighted-body-OFNGDK62-DAnjqfIm.js +0 -1
  73. package/public/assets/index-iIIavXI3.css +0 -1
  74. package/public/assets/pieDiagram-DEJITSTG-CMC6SqWn.js +0 -30
  75. package/public/assets/stateDiagram-v2-QKLJ7IA2-BmucXGxE.js +0 -1
  76. package/templates/front-canonical.tsx +0 -64
  77. package/templates/package-canonical.json +0 -19
  78. package/templates/plugin/README.md +0 -64
  79. package/templates/plugin/package.json +0 -67
  80. package/templates/plugin/src/front/__tests__/samplePlugin.test.ts +0 -53
  81. package/templates/plugin/src/front/index.ts +0 -45
  82. package/templates/plugin/src/front/panels.tsx +0 -8
  83. package/templates/plugin/src/front/surfaceResolver.ts +0 -19
  84. package/templates/plugin/src/server/index.ts +0 -29
  85. package/templates/plugin/src/shared/constants.ts +0 -2
  86. package/templates/plugin/src/shared/index.ts +0 -2
  87. package/templates/plugin/src/shared/types.ts +0 -3
  88. package/templates/plugin/src/test-setup.ts +0 -43
  89. package/templates/plugin/tsconfig.json +0 -23
  90. package/templates/plugin/tsup.config.ts +0 -21
  91. package/templates/plugin/vitest.config.ts +0 -20
  92. package/templates/server-canonical.ts +0 -42
package/README.md CHANGED
@@ -92,14 +92,17 @@ pnpm --filter @hachej/boring-ui-cli build
92
92
  npx ./packages/cli/dist/index.js
93
93
  ```
94
94
 
95
- ### Scaffold a Plugin
95
+ ### Plugins
96
+
97
+ Plugin authoring operations live in the dedicated plugin CLI:
96
98
 
97
99
  ```bash
98
- boring-ui plugin create my-plugin --path plugins
100
+ boring-ui-plugin create my-package-plugin --path plugins
101
+ boring-ui-plugin scaffold my-runtime-plugin "$BORING_AGENT_WORKSPACE_ROOT"
102
+ boring-ui-plugin verify my-runtime-plugin "$BORING_AGENT_WORKSPACE_ROOT"
103
+ boring-ui-plugin test my-runtime-plugin
99
104
  ```
100
105
 
101
- This copies the bundled plugin template from `templates/plugin/`, renames the sample identifiers, and creates `plugins/my-plugin`.
102
-
103
106
  ---
104
107
 
105
108
  ## Authentication
@@ -1,17 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { execSync } from "node:child_process";
3
3
  import {
4
- cpSync,
5
4
  existsSync,
6
- mkdirSync,
7
- readdirSync,
8
- readFileSync,
9
- renameSync,
10
- statSync,
11
- writeFileSync
5
+ readFileSync
12
6
  } from "node:fs";
13
7
  import { createRequire } from "node:module";
14
- import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
8
+ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
15
9
  import { fileURLToPath } from "node:url";
16
10
  import { parseArgs } from "node:util";
17
11
  import { createLocalWorkspaceRegistry } from "./localWorkspaces.js";
@@ -27,7 +21,7 @@ const MODE_MAP = {
27
21
  // bwrap isolated, no network (Linux only)
28
22
  };
29
23
  const require2 = createRequire(import.meta.url);
30
- const CLI_PACKAGE_NAME = "@hachej/boring-ui-cli";
24
+ const PLUGIN_CLI_PACKAGE_NAME = "@hachej/boring-ui-plugin-cli";
31
25
  const CLI_VERSION = (() => {
32
26
  try {
33
27
  const pkg = require2("../../package.json");
@@ -81,16 +75,30 @@ function resolveBoringUiCliPackageRoot() {
81
75
  const __dirname = dirname(fileURLToPath(import.meta.url));
82
76
  return resolve(__dirname, "..", "..");
83
77
  }
84
- function createBoringUiCliRuntimePlugin(packageRoot = resolveBoringUiCliPackageRoot()) {
78
+ function isUsableBoringUiPluginCliPackageRoot(candidate) {
79
+ try {
80
+ const pkg = JSON.parse(readFileSync(join(candidate, "package.json"), "utf8"));
81
+ return pkg.name === PLUGIN_CLI_PACKAGE_NAME && existsSync(join(candidate, "dist", "bin.js"));
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+ function resolveBoringUiPluginCliPackageRoot() {
87
+ const cliRoot = resolveBoringUiCliPackageRoot();
88
+ const candidate = resolve(cliRoot, "..", "plugin-cli");
89
+ return isUsableBoringUiPluginCliPackageRoot(candidate) ? candidate : null;
90
+ }
91
+ function createBoringUiCliRuntimePlugin() {
92
+ const useLocal = process.env.BORING_USE_LOCAL_PACKAGES === "1";
93
+ const packageRoot = useLocal ? resolveBoringUiPluginCliPackageRoot() : null;
85
94
  return {
86
- id: "boring-ui-cli-runtime",
95
+ id: "boring-ui-plugin-cli-runtime",
87
96
  provisioning: {
88
97
  nodePackages: [{
89
- id: "boring-ui-cli",
90
- packageName: CLI_PACKAGE_NAME,
91
- packageRoot,
92
- version: CLI_VERSION,
93
- expectedBins: ["boring-ui"]
98
+ id: "boring-ui-plugin-cli",
99
+ packageName: PLUGIN_CLI_PACKAGE_NAME,
100
+ ...packageRoot ? { packageRoot } : { version: CLI_VERSION },
101
+ expectedBins: ["boring-ui-plugin"]
94
102
  }]
95
103
  }
96
104
  };
@@ -124,6 +132,8 @@ function ensureFrontendBuilt(publicDir) {
124
132
  }
125
133
  async function registerStatic(app, publicDir) {
126
134
  ensureFrontendBuilt(publicDir);
135
+ const { default: fastifyCompress } = await import("@fastify/compress");
136
+ await app.register(fastifyCompress, { global: true, encodings: ["br", "gzip"], threshold: 1024 });
127
137
  const { default: fastifyStatic } = await import("@fastify/static");
128
138
  await app.register(fastifyStatic, {
129
139
  root: publicDir,
@@ -142,10 +152,6 @@ const HELP_TEXT = [
142
152
  "Commands:",
143
153
  " boring-ui [workspace] Start the workspace UI for a folder",
144
154
  " boring-ui workspaces <subcommand> Manage saved local workspaces",
145
- " boring-ui scaffold-plugin <name> [workspace]",
146
- " Scaffold a hot-reloadable plugin",
147
- " boring-ui verify-plugin [name] [workspace]",
148
- " Validate plugin manifests/files",
149
155
  "",
150
156
  "Options:",
151
157
  " -p, --port <port> HTTP port (default: 5200)",
@@ -327,6 +333,7 @@ async function createFolderModeApp(opts) {
327
333
  });
328
334
  });
329
335
  app.get("/api/v1/workspace/meta", async () => ({
336
+ workspaceId: "default",
330
337
  workspaceRoot,
331
338
  projectName,
332
339
  version: CLI_VERSION,
@@ -547,6 +554,7 @@ async function createWorkspacesModeApp(opts) {
547
554
  ]
548
555
  });
549
556
  await app.register(workspaceServer.uiRoutes, {
557
+ getWorkspaceId: async (request) => (await workspaceFromRequest(request)).id,
550
558
  getBridge: async (request) => getBridge((await workspaceFromRequest(request)).id)
551
559
  });
552
560
  app.get("/api/v1/runtime-plugin-diagnostics", async (request) => {
@@ -674,109 +682,6 @@ async function startWorkspacesMode(opts) {
674
682
  if (await checkAuth() === 0) console.log(AUTH_GUIDE);
675
683
  openBrowser(initialUrl);
676
684
  }
677
- function findRepoRoot(from) {
678
- let current = from;
679
- while (true) {
680
- if (existsSync(join(current, "pnpm-workspace.yaml"))) return current;
681
- const parent = dirname(current);
682
- if (parent === current) return null;
683
- current = parent;
684
- }
685
- }
686
- function walkDir(dir, base, out = []) {
687
- for (const entry of readdirSync(dir)) {
688
- if (entry === "node_modules" || entry === ".git" || entry === "dist") continue;
689
- const fullPath = join(dir, entry);
690
- const stat = statSync(fullPath);
691
- if (stat.isDirectory()) {
692
- walkDir(fullPath, base, out);
693
- continue;
694
- }
695
- out.push(relative(base, fullPath));
696
- }
697
- return out;
698
- }
699
- function replaceInFile(filePath, replacements) {
700
- let content = readFileSync(filePath, "utf8");
701
- for (const [from, to] of Object.entries(replacements)) {
702
- content = content.replaceAll(from, to);
703
- }
704
- writeFileSync(filePath, content, "utf8");
705
- }
706
- async function handlePluginCommand(opts) {
707
- const subcommand = opts.positionals[1];
708
- if (subcommand !== "create") {
709
- console.log("Usage: boring-ui plugin create <name> [--path <dir>]");
710
- console.log("");
711
- console.log("Scaffold a new plugin from the template.");
712
- console.log("");
713
- console.log("Arguments:");
714
- console.log(" <name> Plugin name (e.g. my-plugin)");
715
- console.log(" --path Parent directory for the new plugin (default: plugins/)");
716
- return;
717
- }
718
- const name = opts.positionals[2];
719
- if (!name) throw new Error("usage: boring-ui plugin create <name>");
720
- const __dirname = dirname(fileURLToPath(import.meta.url));
721
- const packageRoot = resolve(__dirname, "..", "..");
722
- const templateDir = join(packageRoot, "templates", "plugin");
723
- if (!existsSync(templateDir)) {
724
- throw new Error(
725
- `Plugin template not found at ${templateDir}.
726
- This build may not include the plugin template.`
727
- );
728
- }
729
- const repoRoot = findRepoRoot(process.cwd());
730
- const customPath = opts.args.path;
731
- const targetParent = customPath ? resolve(customPath) : join(repoRoot ?? process.cwd(), "plugins");
732
- const targetDir = join(targetParent, name);
733
- if (existsSync(targetDir)) {
734
- throw new Error(`Directory already exists: ${targetDir}`);
735
- }
736
- const id = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "");
737
- if (!id) throw new Error(`invalid plugin name: ${name}`);
738
- const symbolBase = id.replace(/-plugin$/, "") || id;
739
- const pascalBase = symbolBase.split(/[-_]+/).map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1)).join("");
740
- const camelBase = pascalBase.charAt(0).toLowerCase() + pascalBase.slice(1);
741
- const upperBase = symbolBase.replace(/-/g, "_").toUpperCase();
742
- console.log(`Scaffolding plugin "${id}" at ${targetDir}`);
743
- mkdirSync(targetParent, { recursive: true });
744
- cpSync(templateDir, targetDir, { recursive: true });
745
- const files = walkDir(targetDir, targetDir);
746
- const pkgName = `@hachej/boring-${id}`;
747
- for (const file of files) {
748
- const fullPath = join(targetDir, file);
749
- replaceInFile(fullPath, {
750
- "@hachej/boring-plugin-template": pkgName,
751
- "sample-plugin": id,
752
- "sample-panel": `${id}-panel`,
753
- "sample.open": `${id}.open`,
754
- "sample:": `${id}:`,
755
- '"sample"': `"${id}"`,
756
- "SAMPLE": upperBase,
757
- "Sample": pascalBase,
758
- "sampleSurfaceResolver": `${camelBase}SurfaceResolver`,
759
- "samplePanel": `${camelBase}Panel`
760
- });
761
- if (file.includes("samplePlugin")) {
762
- const newFile = file.replace(/samplePlugin/g, `${camelBase}Plugin`);
763
- const oldPath = join(targetDir, file);
764
- const newPath = join(targetDir, newFile);
765
- if (oldPath !== newPath) {
766
- mkdirSync(dirname(newPath), { recursive: true });
767
- renameSync(oldPath, newPath);
768
- }
769
- }
770
- }
771
- console.log("");
772
- console.log(`\u2713 Created plugin \`${id}\` at ${relative(process.cwd(), targetDir)}`);
773
- console.log("");
774
- console.log("Next steps:");
775
- console.log(` cd ${relative(process.cwd(), targetDir)}`);
776
- console.log(" pnpm install");
777
- console.log(` pnpm --filter ${pkgName} typecheck`);
778
- console.log(` pnpm --filter ${pkgName} test`);
779
- }
780
685
  async function handleWorkspacesCommand(opts) {
781
686
  const registry = createLocalWorkspaceRegistry();
782
687
  const subcommand = opts.positionals[1];
@@ -828,6 +733,10 @@ async function runCli(options) {
828
733
  name: { type: "string", short: "n" },
829
734
  path: { type: "string" },
830
735
  json: { type: "boolean" },
736
+ url: { type: "string" },
737
+ workspace: { type: "string" },
738
+ "panel-id": { type: "string" },
739
+ "timeout-ms": { type: "string" },
831
740
  help: { type: "boolean", short: "h" }
832
741
  },
833
742
  allowPositionals: true,
@@ -849,15 +758,8 @@ async function runCli(options) {
849
758
  cliMode = rawMode;
850
759
  mode = MODE_MAP[cliMode];
851
760
  } 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
- }
761
+ cliMode = "local";
762
+ mode = "direct";
861
763
  }
862
764
  const base = {
863
765
  publicDir: options.publicDir,
@@ -866,13 +768,6 @@ async function runCli(options) {
866
768
  cliMode,
867
769
  mode
868
770
  };
869
- if (positionals[0] === "plugin") {
870
- await handlePluginCommand({
871
- positionals,
872
- args: { path: args.path }
873
- });
874
- return;
875
- }
876
771
  if (positionals[0] === "workspaces") {
877
772
  await handleWorkspacesCommand({
878
773
  ...base,
@@ -881,105 +776,11 @@ async function runCli(options) {
881
776
  });
882
777
  return;
883
778
  }
884
- if (positionals[0] === "plugin-status") {
885
- handlePluginStatusCommand({ json: args.json === true });
886
- return;
887
- }
888
- if (positionals[0] === "scaffold-plugin") {
889
- await handleScaffoldPluginCommand({ positionals });
890
- return;
891
- }
892
- if (positionals[0] === "verify-plugin") {
893
- await handleVerifyPluginCommand({ positionals });
894
- return;
895
- }
896
779
  await startFolderMode({
897
780
  ...base,
898
781
  folderArg: positionals[0]
899
782
  });
900
783
  }
901
- function defaultWorkspaceRoot() {
902
- return process.env.BORING_AGENT_WORKSPACE_ROOT ?? process.cwd();
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
- }
930
- async function handleVerifyPluginCommand(opts) {
931
- const maybeName = opts.positionals[1];
932
- const maybeWorkspace = opts.positionals[2];
933
- const looksLikePath = maybeName && (maybeName.includes("/") || maybeName.startsWith("."));
934
- const name = looksLikePath ? void 0 : maybeName;
935
- const workspaceRoot = resolve(maybeWorkspace ?? (looksLikePath ? maybeName : defaultWorkspaceRoot()));
936
- const { findHintForError, formatVerifyResult, verifyPlugin } = await import("./verifyPlugin.js");
937
- const result = verifyPlugin({ workspaceRoot, ...name ? { name } : {} });
938
- console.log(formatVerifyResult(result));
939
- if (!result.ok) {
940
- const hints = [];
941
- for (const outcome of result.outcomes) {
942
- for (const err of outcome.errors) {
943
- const hint = findHintForError(err);
944
- if (hint) hints.push(` hint (${outcome.id}): ${hint}`);
945
- }
946
- }
947
- if (hints.length > 0) {
948
- console.log("");
949
- console.log("Suggestions:");
950
- for (const hint of hints) console.log(hint);
951
- }
952
- process.exit(1);
953
- }
954
- }
955
- async function handleScaffoldPluginCommand(opts) {
956
- const name = opts.positionals[1];
957
- if (!name) {
958
- throw new Error("usage: boring-ui scaffold-plugin <name> [workspace]");
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
- }
964
- const workspaceRoot = resolve(opts.positionals[2] ?? defaultWorkspaceRoot());
965
- const { scaffoldPlugin } = await import("./scaffoldPlugin.js");
966
- const result = scaffoldPlugin({ name, workspaceRoot });
967
- console.log(`scaffolded ${name}`);
968
- console.log(` dir ${result.pluginDir}`);
969
- for (const file of result.filesCreated) {
970
- console.log(` + ${file}`);
971
- }
972
- console.log("");
973
- console.log("Next steps:");
974
- console.log(` 1. edit front/index.tsx for UI panels/commands/resolvers`);
975
- console.log(` 2. add pi.extensions / skills for hot-reloadable agent behavior`);
976
- console.log(` 3. bash \`boring-ui verify-plugin\` \u2014 confirms manifests + files are valid`);
977
- console.log(` 4. ask the user: /reload`);
978
- console.log("");
979
- console.log("Advanced server integration:");
980
- console.log(" boring.server is boot-time/static composition only. It is NOT hot-registered");
981
- console.log(" by /reload for .pi/extensions user plugins; use Pi extensions for agent tools.");
982
- }
983
784
  export {
984
785
  createBoringUiCliRuntimePlugin,
985
786
  createFolderModeApp,
@@ -987,5 +788,6 @@ export {
987
788
  provisionCliWorkspaceRuntime,
988
789
  registerStatic,
989
790
  resolveBoringUiCliPackageRoot,
791
+ resolveBoringUiPluginCliPackageRoot,
990
792
  runCli
991
793
  };