@hachej/boring-ui-cli 0.1.68 → 0.1.70

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 (87) hide show
  1. package/dist/server/localWorkspaces.js +80 -46
  2. package/dist/server/modeApps.js +3 -0
  3. package/dist/server/pluginDiscovery.js +1 -1
  4. package/dist/server/workspacePluginRoutes.js +144 -0
  5. package/package.json +9 -7
  6. package/public/assets/{DebugDrawer-BPhPmF7n.js → DebugDrawer-4lxm6M9r.js} +1 -1
  7. package/public/assets/{DiagramPane-Cb8gdMwJ.js → DiagramPane-GOP7JDAY.js} +4 -4
  8. package/public/assets/architecture-YZFGNWBL-CSlAeBux.js +1 -0
  9. package/public/assets/{architectureDiagram-Q4EWVU46-C2LlQ_Jj.js → architectureDiagram-Q4EWVU46-B_cr9ja0.js} +1 -1
  10. package/public/assets/{blockDiagram-DXYQGD6D-e3vVT5ca.js → blockDiagram-DXYQGD6D-BfAOA2sb.js} +1 -1
  11. package/public/assets/{c4Diagram-AHTNJAMY-CQMGUGZr.js → c4Diagram-AHTNJAMY-l8FhRptb.js} +1 -1
  12. package/public/assets/channel-DLu3hTuZ.js +1 -0
  13. package/public/assets/{chunk-4TB4RGXK-NVc-EkQr.js → chunk-4TB4RGXK-BWfHBTVf.js} +1 -1
  14. package/public/assets/{chunk-5FUZZQ4R-DFs5M0VY.js → chunk-5FUZZQ4R-Ba6XrhVK.js} +1 -1
  15. package/public/assets/{chunk-5PVQY5BW-PKb2UfEn.js → chunk-5PVQY5BW-CJjwZOXY.js} +1 -1
  16. package/public/assets/{chunk-EDXVE4YY-W62DzS3u.js → chunk-EDXVE4YY-BmQF_Jii.js} +1 -1
  17. package/public/assets/{chunk-ENJZ2VHE-B19bR_UY.js → chunk-ENJZ2VHE-CEJhWlbH.js} +1 -1
  18. package/public/assets/{chunk-ICPOFSXX-CbeWjtve.js → chunk-ICPOFSXX-Dwv7Fn2n.js} +2 -2
  19. package/public/assets/{chunk-K5T4RW27-BJPpT0_8.js → chunk-K5T4RW27-DcgWlBQN.js} +1 -1
  20. package/public/assets/{chunk-OYMX7WX6-DDrTbLPP.js → chunk-OYMX7WX6-CCVxUN5K.js} +1 -1
  21. package/public/assets/{chunk-U2HBQHQK-CdUtCuol.js → chunk-U2HBQHQK-Bz2zS-oB.js} +1 -1
  22. package/public/assets/{chunk-X2U36JSP-CJWDEMsp.js → chunk-X2U36JSP-R29_i44a.js} +1 -1
  23. package/public/assets/{chunk-YZCP3GAM-C1MzZAkl.js → chunk-YZCP3GAM-DmMC90jF.js} +1 -1
  24. package/public/assets/{chunk-ZZ45TVLE-CCEhJUTd.js → chunk-ZZ45TVLE--iQbKNdL.js} +1 -1
  25. package/public/assets/classDiagram-6PBFFD2Q-BFerpStM.js +1 -0
  26. package/public/assets/classDiagram-v2-HSJHXN6E-BFerpStM.js +1 -0
  27. package/public/assets/clone-6hC8R7hq.js +1 -0
  28. package/public/assets/{dagre-KV5264BT-DUiFDgw2.js → dagre-KV5264BT-DB2-vx0a.js} +1 -1
  29. package/public/assets/{dagre-DGF0uJBS.js → dagre-v-loQdrj.js} +1 -1
  30. package/public/assets/{diagram-5BDNPKRD-zVwejgnb.js → diagram-5BDNPKRD-CtC2SnI_.js} +1 -1
  31. package/public/assets/{diagram-G4DWMVQ6-TIbsYTBJ.js → diagram-G4DWMVQ6-C1hwuOi-.js} +1 -1
  32. package/public/assets/{diagram-MMDJMWI5-CFsXMMwG.js → diagram-MMDJMWI5-3MgLEV9z.js} +1 -1
  33. package/public/assets/{diagram-TYMM5635-Dy645EM6.js → diagram-TYMM5635-BuCrXn_U.js} +1 -1
  34. package/public/assets/{dist-DAGGreTm.js → dist-MWzh3tWH.js} +1 -1
  35. package/public/assets/{erDiagram-SMLLAGMA-CGqOyENd.js → erDiagram-SMLLAGMA-CYQyjmQb.js} +1 -1
  36. package/public/assets/{flatten-D5sKD-5t.js → flatten-xEDtzclq.js} +1 -1
  37. package/public/assets/{flowDiagram-DWJPFMVM-L6BVbVJK.js → flowDiagram-DWJPFMVM-3X2cDfmk.js} +1 -1
  38. package/public/assets/{ganttDiagram-T4ZO3ILL-BUrmnGiC.js → ganttDiagram-T4ZO3ILL-IbI7mKoq.js} +1 -1
  39. package/public/assets/gitGraph-7Q5UKJZL-CTUp4HOA.js +1 -0
  40. package/public/assets/{gitGraphDiagram-UUTBAWPF-D6R_lj2o.js → gitGraphDiagram-UUTBAWPF-CoXTfAJP.js} +1 -1
  41. package/public/assets/{graphlib-DGfh1co3.js → graphlib-JzRJ1o1K.js} +1 -1
  42. package/public/assets/{highlighted-body-OFNGDK62-Ckfy53pN.js → highlighted-body-OFNGDK62-C2IsLRsw.js} +1 -1
  43. package/public/assets/index-Cns0vbRE.js +861 -0
  44. package/public/assets/info-OMHHGYJF-DjmEzY3l.js +1 -0
  45. package/public/assets/{infoDiagram-42DDH7IO-L3GN3t-A.js → infoDiagram-42DDH7IO-BdBxeF7r.js} +1 -1
  46. package/public/assets/{ishikawaDiagram-UXIWVN3A-CriSwJEC.js → ishikawaDiagram-UXIWVN3A-CR7033B8.js} +1 -1
  47. package/public/assets/{journeyDiagram-VCZTEJTY-CYX--9Wp.js → journeyDiagram-VCZTEJTY-C8aEShQh.js} +1 -1
  48. package/public/assets/{kanban-definition-6JOO6SKY-r_FtVoAw.js → kanban-definition-6JOO6SKY-BFOH-Rts.js} +1 -1
  49. package/public/assets/{line-CR3tMWzH.js → line-CVqLMcG8.js} +1 -1
  50. package/public/assets/mermaid-GHXKKRXX-BQshgTYg.js +1 -0
  51. package/public/assets/{mermaid-parser.core-Ds0FSkVW.js → mermaid-parser.core-DvuoaBUx.js} +2 -2
  52. package/public/assets/{mindmap-definition-QFDTVHPH-CXn15TFt.js → mindmap-definition-QFDTVHPH-DJ_zvfT3.js} +1 -1
  53. package/public/assets/packet-4T2RLAQJ-Dxoy5Yff.js +1 -0
  54. package/public/assets/pie-ZZUOXDRM-B736w5qr.js +1 -0
  55. package/public/assets/{pieDiagram-DEJITSTG-CkClooEG.js → pieDiagram-DEJITSTG-GPlo6pr4.js} +1 -1
  56. package/public/assets/{quadrantDiagram-34T5L4WZ-D6Mc-mAE.js → quadrantDiagram-34T5L4WZ-B8QLb1y0.js} +1 -1
  57. package/public/assets/radar-PYXPWWZC-CoG6en_X.js +1 -0
  58. package/public/assets/{reduce-CSUAx4db.js → reduce-D02udmm3.js} +1 -1
  59. package/public/assets/{requirementDiagram-MS252O5E-4jeIYjL_.js → requirementDiagram-MS252O5E-Cg_LlRc9.js} +1 -1
  60. package/public/assets/{sankeyDiagram-XADWPNL6-DefHsk1L.js → sankeyDiagram-XADWPNL6-CeWpMwXk.js} +1 -1
  61. package/public/assets/{sequenceDiagram-FGHM5R23-BSK4jxQB.js → sequenceDiagram-FGHM5R23-DqoX-g-a.js} +1 -1
  62. package/public/assets/{stateDiagram-FHFEXIEX-CF__r1FS.js → stateDiagram-FHFEXIEX-0ykhWBqF.js} +1 -1
  63. package/public/assets/stateDiagram-v2-QKLJ7IA2-Dc93-eeY.js +1 -0
  64. package/public/assets/{timeline-definition-GMOUNBTQ-PQmHOvTQ.js → timeline-definition-GMOUNBTQ-CmnLEeHt.js} +1 -1
  65. package/public/assets/treeView-SZITEDCU-BA_-6zmu.js +1 -0
  66. package/public/assets/treemap-W4RFUUIX-n6XXeD76.js +1 -0
  67. package/public/assets/{vennDiagram-DHZGUBPP-BKKZxb8t.js → vennDiagram-DHZGUBPP-C3U7v4Bs.js} +1 -1
  68. package/public/assets/wardley-RL74JXVD-BCcuTq98.js +1 -0
  69. package/public/assets/{wardleyDiagram-NUSXRM2D-BwMOKkpM.js → wardleyDiagram-NUSXRM2D-Dc26G64U.js} +1 -1
  70. package/public/assets/{xychartDiagram-5P7HB3ND-DVsnXqW_.js → xychartDiagram-5P7HB3ND-DyW3Gdw9.js} +1 -1
  71. package/public/index.html +9 -9
  72. package/public/assets/architecture-YZFGNWBL-BHB2sWUH.js +0 -1
  73. package/public/assets/channel-DHwtVBRO.js +0 -1
  74. package/public/assets/classDiagram-6PBFFD2Q-DrDFaWlC.js +0 -1
  75. package/public/assets/classDiagram-v2-HSJHXN6E-DrDFaWlC.js +0 -1
  76. package/public/assets/clone-euLbFmGl.js +0 -1
  77. package/public/assets/gitGraph-7Q5UKJZL-nQMAGxnD.js +0 -1
  78. package/public/assets/index-Bp2DjxBi.js +0 -861
  79. package/public/assets/info-OMHHGYJF-CxYJBTrR.js +0 -1
  80. package/public/assets/mermaid-GHXKKRXX-DZG06fPR.js +0 -1
  81. package/public/assets/packet-4T2RLAQJ-f-eHIL1I.js +0 -1
  82. package/public/assets/pie-ZZUOXDRM-Br4NtZeB.js +0 -1
  83. package/public/assets/radar-PYXPWWZC-DJpNuaAh.js +0 -1
  84. package/public/assets/stateDiagram-v2-QKLJ7IA2-CTaYljGy.js +0 -1
  85. package/public/assets/treeView-SZITEDCU-B3Z7Q2r-.js +0 -1
  86. package/public/assets/treemap-W4RFUUIX-CkYHLHQz.js +0 -1
  87. package/public/assets/wardley-RL74JXVD-DwJKtGnx.js +0 -1
@@ -4,6 +4,7 @@ import { existsSync, statSync } from "node:fs";
4
4
  import { mkdir, readFile, realpath, rename, writeFile } from "node:fs/promises";
5
5
  import { homedir } from "node:os";
6
6
  import { basename, dirname, join, resolve } from "node:path";
7
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
7
8
  const DEFAULT_REGISTRY_PATH = resolve(homedir(), ".boring-ui", "workspaces.yaml");
8
9
  function getDefaultLocalWorkspaceRegistryPath() {
9
10
  return process.env.BORING_UI_WORKSPACES_PATH ? resolve(process.env.BORING_UI_WORKSPACES_PATH) : DEFAULT_REGISTRY_PATH;
@@ -15,61 +16,82 @@ function workspaceIdForPath(path) {
15
16
  const hash = createHash("sha1").update(path).digest("hex").slice(0, 8);
16
17
  return `${slugify(basename(path))}-${hash}`;
17
18
  }
18
- function yamlString(value) {
19
- if (/^[a-zA-Z0-9_./:@ -]+$/.test(value) && !value.startsWith(" ") && !value.endsWith(" ")) {
20
- return value;
19
+ function isPlainRecord(value) {
20
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
21
+ const proto = Object.getPrototypeOf(value);
22
+ return proto === Object.prototype || proto === null;
23
+ }
24
+ function cloneJsonLike(value) {
25
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
26
+ if (Array.isArray(value)) return value.map(cloneJsonLike);
27
+ if (isPlainRecord(value)) {
28
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, cloneJsonLike(entry)]));
21
29
  }
22
- return JSON.stringify(value);
30
+ return void 0;
23
31
  }
24
- function unquoteYamlString(value) {
32
+ function parseLegacyTaskProvider(value) {
33
+ if (typeof value !== "string") return void 0;
25
34
  const trimmed = value.trim();
26
- if (!trimmed) return "";
27
- if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
28
- try {
29
- return JSON.parse(trimmed);
30
- } catch {
31
- return trimmed.slice(1, -1);
32
- }
35
+ if (!trimmed || trimmed === "none") return void 0;
36
+ if (trimmed === "github" || trimmed === "github:auto") return { provider: "github", repo: "auto" };
37
+ if (trimmed.startsWith("github:")) {
38
+ const repo = trimmed.slice("github:".length).trim();
39
+ if (/^[^/\s]+\/[^/\s]+$/.test(repo)) return { provider: "github", repo };
33
40
  }
34
- return trimmed;
41
+ return void 0;
35
42
  }
36
- function parseRegistryYaml(content) {
37
- const result = [];
38
- let current = null;
39
- for (const line of content.split(/\r?\n/)) {
40
- const trimmed = line.trim();
41
- if (!trimmed || trimmed.startsWith("#") || trimmed === "version: 1" || trimmed === "workspaces:") continue;
42
- const itemMatch = line.match(/^\s*-\s+id:\s*(.*)$/);
43
- if (itemMatch) {
44
- if (current?.id && current.name && current.path && current.createdAt && current.updatedAt) {
45
- result.push(current);
46
- }
47
- current = { id: unquoteYamlString(itemMatch[1] ?? "") };
48
- continue;
49
- }
50
- const fieldMatch = line.match(/^\s+(name|path|createdAt|updatedAt):\s*(.*)$/);
51
- if (fieldMatch && current) {
52
- current[fieldMatch[1]] = unquoteYamlString(fieldMatch[2] ?? "");
53
- }
43
+ function legacyTaskProviders(record) {
44
+ if (typeof record.taskProviders === "string") {
45
+ const providers = record.taskProviders.split(",").map((entry) => parseLegacyTaskProvider(entry)).filter((entry) => Boolean(entry));
46
+ if (providers.length > 0) return providers;
54
47
  }
55
- if (current?.id && current.name && current.path && current.createdAt && current.updatedAt) {
56
- result.push(current);
48
+ if (Array.isArray(record.taskProviders)) {
49
+ const providers = record.taskProviders.map((entry) => isPlainRecord(entry) && entry.provider === "github" ? { provider: "github", repo: typeof entry.repo === "string" ? entry.repo : "auto" } : void 0).filter((entry) => Boolean(entry));
50
+ if (providers.length > 0) return providers;
57
51
  }
58
- return result;
52
+ const single = parseLegacyTaskProvider(record.taskProvider);
53
+ return single ? [single] : void 0;
54
+ }
55
+ function parsePlugins(value) {
56
+ if (!isPlainRecord(value)) return void 0;
57
+ const entries = Object.entries(value).map(([pluginId, config]) => [pluginId, cloneJsonLike(config)]).filter((entry) => /^[a-zA-Z0-9_-]+$/.test(entry[0]) && isPlainRecord(entry[1]));
58
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
59
+ }
60
+ function parseRegistryYaml(content) {
61
+ const parsed = parseYaml(content);
62
+ if (!isPlainRecord(parsed) || !Array.isArray(parsed.workspaces)) return [];
63
+ return parsed.workspaces.flatMap((entry) => {
64
+ if (!isPlainRecord(entry)) return [];
65
+ const id = typeof entry.id === "string" ? entry.id : "";
66
+ const name = typeof entry.name === "string" ? entry.name : "";
67
+ const path = typeof entry.path === "string" ? entry.path : "";
68
+ const createdAt = typeof entry.createdAt === "string" ? entry.createdAt : "";
69
+ const updatedAt = typeof entry.updatedAt === "string" ? entry.updatedAt : "";
70
+ if (!id || !name || !path || !createdAt || !updatedAt) return [];
71
+ const plugins = parsePlugins(entry.plugins);
72
+ const legacyProviders = legacyTaskProviders(entry);
73
+ return [{
74
+ id,
75
+ name,
76
+ path,
77
+ createdAt,
78
+ updatedAt,
79
+ ...plugins || legacyProviders ? { plugins: { ...plugins ?? {}, ...legacyProviders ? { tasks: { providers: legacyProviders } } : {} } } : {}
80
+ }];
81
+ });
59
82
  }
60
83
  function serializeRegistryYaml(workspaces) {
61
- const lines = ["version: 1", "workspaces:"];
62
- for (const workspace of workspaces) {
63
- lines.push(
64
- ` - id: ${yamlString(workspace.id)}`,
65
- ` name: ${yamlString(workspace.name)}`,
66
- ` path: ${yamlString(workspace.path)}`,
67
- ` createdAt: ${yamlString(workspace.createdAt)}`,
68
- ` updatedAt: ${yamlString(workspace.updatedAt)}`
69
- );
70
- }
71
- return `${lines.join("\n")}
72
- `;
84
+ return stringifyYaml({
85
+ version: 1,
86
+ workspaces: workspaces.map((workspace) => ({
87
+ id: workspace.id,
88
+ name: workspace.name,
89
+ path: workspace.path,
90
+ createdAt: workspace.createdAt,
91
+ updatedAt: workspace.updatedAt,
92
+ ...workspace.plugins && Object.keys(workspace.plugins).length > 0 ? { plugins: workspace.plugins } : {}
93
+ }))
94
+ });
73
95
  }
74
96
  function expandHomePath(input) {
75
97
  if (input === "~") return homedir();
@@ -158,6 +180,18 @@ function createLocalWorkspaceRegistry(path = getDefaultLocalWorkspaceRegistryPat
158
180
  workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
159
181
  await writeStored(workspaces);
160
182
  return withAvailability(workspace);
183
+ },
184
+ async setPluginConfig(id, pluginId, config) {
185
+ const workspaces = await readStored();
186
+ const workspace = workspaces.find((entry) => entry.id === id);
187
+ if (!workspace) throw new Error(`workspace not found: ${id}`);
188
+ workspace.plugins ??= {};
189
+ if (config === null) delete workspace.plugins[pluginId];
190
+ else workspace.plugins[pluginId] = config;
191
+ if (Object.keys(workspace.plugins).length === 0) delete workspace.plugins;
192
+ workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
193
+ await writeStored(workspaces);
194
+ return withAvailability(workspace);
161
195
  }
162
196
  };
163
197
  }
@@ -3,6 +3,7 @@ import { existsSync, readFileSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import { basename, isAbsolute, join, resolve } from "node:path";
5
5
  import { createLocalWorkspaceRegistry } from "./localWorkspaces.js";
6
+ import { registerWorkspacePluginConfigRoutes, registerWorkspaceTaskRoutes } from "./workspacePluginRoutes.js";
6
7
  import { resolveBoringUiCliPackageRoot } from "./pluginDiscovery.js";
7
8
  const MODE_MAP = {
8
9
  "local": "direct",
@@ -514,6 +515,8 @@ async function createWorkspacesModeApp(opts) {
514
515
  if (workspace) await disposeWorkspaceRuntime(workspace);
515
516
  return reply.send({ ok: true });
516
517
  });
518
+ await registerWorkspacePluginConfigRoutes(app, registry);
519
+ await registerWorkspaceTaskRoutes(app, registry);
517
520
  app.get("/api/v1/workspaces", async () => ({
518
521
  workspaces: (await registry.list()).map(toCoreWorkspace)
519
522
  }));
@@ -23,7 +23,7 @@ function getGlobalPiExtensionsRoot(options = {}) {
23
23
  function getGlobalPiAgentRoot(options = {}) {
24
24
  return resolve(options.globalAgentRoot ?? dirname(getGlobalPiExtensionsRoot(options)));
25
25
  }
26
- const CLI_DEFAULT_PLUGIN_PACKAGES = ["@hachej/boring-ask-user", "@hachej/boring-diagram"];
26
+ const CLI_DEFAULT_PLUGIN_PACKAGES = ["@hachej/boring-ask-user", "@hachej/boring-diagram", "@hachej/boring-tasks"];
27
27
  function resolveCliDefaultPluginPackagePaths() {
28
28
  try {
29
29
  return resolveDefaultWorkspacePluginPackagePaths({
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ import { isAbsolute } from "node:path";
3
+ function firstString(value) {
4
+ if (typeof value === "string") return value;
5
+ if (!Array.isArray(value)) return void 0;
6
+ return value.find((item) => typeof item === "string");
7
+ }
8
+ function httpError(message, statusCode = 400) {
9
+ const error = new Error(message);
10
+ error.statusCode = statusCode;
11
+ return error;
12
+ }
13
+ function resolveWorkspaceIdFromRequest(request) {
14
+ const headers = request.headers ?? {};
15
+ const headerValue = headers["x-boring-workspace-id"] ?? Object.entries(headers).find(([key]) => key.toLowerCase() === "x-boring-workspace-id")?.[1];
16
+ const query = request.query;
17
+ const raw = firstString(headerValue) ?? firstString(query?.workspaceId) ?? "";
18
+ const workspaceId = raw.trim();
19
+ if (!workspaceId) throw httpError("workspace id is required", 400);
20
+ if (workspaceId.includes("\0") || workspaceId.includes("/") || workspaceId.includes("\\") || workspaceId.includes("..") || isAbsolute(workspaceId)) {
21
+ throw httpError("invalid workspace id", 400);
22
+ }
23
+ return workspaceId;
24
+ }
25
+ async function requireWorkspace(registry, workspaceId) {
26
+ const workspace = await registry.get(workspaceId);
27
+ if (!workspace) throw httpError("unknown workspace", 404);
28
+ if (!workspace.available) throw httpError("workspace folder unavailable", 409);
29
+ return workspace;
30
+ }
31
+ function taskResponseError(cause) {
32
+ if (cause instanceof Error && "status" in cause && "code" in cause) {
33
+ return { ok: false, code: cause.code, error: cause.message };
34
+ }
35
+ return { ok: false, code: "TASK_SOURCE_ERROR", error: "Task source request failed." };
36
+ }
37
+ function taskStatusFor(cause) {
38
+ const status = cause?.status ?? cause?.statusCode;
39
+ return typeof status === "number" ? status : 500;
40
+ }
41
+ function taskBodyObject(body) {
42
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
43
+ const error = new Error("request body must be an object");
44
+ error.status = 400;
45
+ error.code = "TASK_INVALID_BODY";
46
+ throw error;
47
+ }
48
+ return body;
49
+ }
50
+ function taskStringArray(value) {
51
+ if (value === void 0) return void 0;
52
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string" || entry.length === 0)) {
53
+ const error = new Error("sourceIds must be an array of non-empty strings");
54
+ error.status = 400;
55
+ error.code = "TASK_INVALID_BODY";
56
+ throw error;
57
+ }
58
+ return value;
59
+ }
60
+ function taskRequiredString(body, key) {
61
+ const value = body[key];
62
+ if (typeof value !== "string" || value.length === 0) {
63
+ const error = new Error(`${key} must be a non-empty string`);
64
+ error.status = 400;
65
+ error.code = "TASK_INVALID_BODY";
66
+ throw error;
67
+ }
68
+ return value;
69
+ }
70
+ function isPluginConfig(value) {
71
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
72
+ }
73
+ async function createWorkspaceTaskService(workspace) {
74
+ const tasks = await import("@hachej/boring-tasks/server");
75
+ const registry = tasks.createTaskSourceRegistryFromConfig(workspace.plugins?.tasks, { workspaceRoot: workspace.path });
76
+ return tasks.createTaskSourceService(registry);
77
+ }
78
+ async function registerWorkspacePluginConfigRoutes(app, registry) {
79
+ app.get("/api/v1/local-workspaces/:id/plugin-config/:pluginId", async (request, reply) => {
80
+ const { id, pluginId } = request.params;
81
+ if (!/^[a-zA-Z0-9_-]+$/.test(pluginId)) return reply.code(400).send({ error: "invalid plugin id" });
82
+ const workspace = await registry.get(id);
83
+ if (!workspace) return reply.code(404).send({ error: "workspace not found" });
84
+ return { config: workspace.plugins?.[pluginId] ?? null };
85
+ });
86
+ app.put("/api/v1/local-workspaces/:id/plugin-config/:pluginId", async (request, reply) => {
87
+ const { id, pluginId } = request.params;
88
+ if (!/^[a-zA-Z0-9_-]+$/.test(pluginId)) return reply.code(400).send({ error: "invalid plugin id" });
89
+ const body = request.body;
90
+ const config = body?.config;
91
+ if (config !== null && !isPluginConfig(config)) {
92
+ return reply.code(400).send({ error: "plugin config must be an object or null" });
93
+ }
94
+ try {
95
+ const workspace = await registry.setPluginConfig(id, pluginId, config);
96
+ return { workspace };
97
+ } catch (error) {
98
+ return reply.code(404).send({ error: error instanceof Error ? error.message : "workspace not found" });
99
+ }
100
+ });
101
+ }
102
+ async function registerWorkspaceTaskRoutes(app, registry) {
103
+ const workspaceFromRequest = async (request) => {
104
+ return await requireWorkspace(registry, resolveWorkspaceIdFromRequest(request));
105
+ };
106
+ app.get("/api/boring-tasks/sources", async (request, reply) => {
107
+ try {
108
+ const workspace = await workspaceFromRequest(request);
109
+ const service = await createWorkspaceTaskService(workspace);
110
+ return { ok: true, sources: service.listSources() };
111
+ } catch (cause) {
112
+ return reply.status(taskStatusFor(cause)).send(taskResponseError(cause));
113
+ }
114
+ });
115
+ app.post("/api/boring-tasks/sources/tasks/list", async (request, reply) => {
116
+ try {
117
+ const workspace = await workspaceFromRequest(request);
118
+ const body = request.body === void 0 ? {} : taskBodyObject(request.body);
119
+ const service = await createWorkspaceTaskService(workspace);
120
+ return { ok: true, ...await service.listTasks({ workspaceId: workspace.id, workspaceRoot: workspace.path }, { sourceIds: taskStringArray(body.sourceIds) }) };
121
+ } catch (cause) {
122
+ return reply.status(taskStatusFor(cause)).send(taskResponseError(cause));
123
+ }
124
+ });
125
+ app.post("/api/boring-tasks/sources/tasks/move", async (request, reply) => {
126
+ try {
127
+ const workspace = await workspaceFromRequest(request);
128
+ const body = taskBodyObject(request.body);
129
+ const service = await createWorkspaceTaskService(workspace);
130
+ const task = await service.moveTask({ workspaceId: workspace.id, workspaceRoot: workspace.path }, {
131
+ sourceId: taskRequiredString(body, "sourceId"),
132
+ taskId: taskRequiredString(body, "taskId"),
133
+ statusId: taskRequiredString(body, "statusId")
134
+ });
135
+ return { ok: true, task };
136
+ } catch (cause) {
137
+ return reply.status(taskStatusFor(cause)).send(taskResponseError(cause));
138
+ }
139
+ });
140
+ }
141
+ export {
142
+ registerWorkspacePluginConfigRoutes,
143
+ registerWorkspaceTaskRoutes
144
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-ui-cli",
3
- "version": "0.1.68",
3
+ "version": "0.1.70",
4
4
  "description": "Turn an agent into an app",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,12 +20,14 @@
20
20
  "lucide-react": "^1.21.0",
21
21
  "typescript": "^6.0.3",
22
22
  "vite": "^8.1.0",
23
- "@hachej/boring-agent": "0.1.68",
24
- "@hachej/boring-diagram": "0.1.68",
25
- "@hachej/boring-ask-user": "0.1.68",
26
- "@hachej/boring-ui-kit": "0.1.68",
27
- "@hachej/boring-workspace": "0.1.68",
28
- "@hachej/boring-ui-plugin-cli": "0.1.68"
23
+ "yaml": "^2.9.0",
24
+ "@hachej/boring-ask-user": "0.1.70",
25
+ "@hachej/boring-agent": "0.1.70",
26
+ "@hachej/boring-tasks": "0.1.70",
27
+ "@hachej/boring-diagram": "0.1.70",
28
+ "@hachej/boring-ui-plugin-cli": "0.1.70",
29
+ "@hachej/boring-ui-kit": "0.1.70",
30
+ "@hachej/boring-workspace": "0.1.70"
29
31
  },
30
32
  "devDependencies": {
31
33
  "@tailwindcss/vite": "^4.3.1",
@@ -1 +1 @@
1
- import{s as e}from"./rolldown-runtime-BG2f4sTM.js";import{n as t,t as n}from"./jsx-runtime-CC-kRuLe.js";import{Ct as r,G as i,St as a,Tt as o,d as s,wt as c}from"./createLucideIcon-BpL36Utr.js";import{A as l,C as u,D as d,E as f,O as p,S as m,k as h}from"./index-Bp2DjxBi.js";var g=e(t(),1),_=e(n(),1);function v({value:e,label:t}){let[n,r]=(0,g.useState)(!1);return(0,_.jsx)(i,{type:`button`,variant:`ghost`,size:`icon-xs`,onClick:(0,g.useCallback)(()=>{m(e).then(e=>{e&&(r(!0),window.setTimeout(()=>r(!1),1200))})},[e]),className:`text-muted-foreground/60`,"aria-label":t,title:t,children:n?(0,_.jsx)(l,{className:`h-3 w-3`}):(0,_.jsx)(d,{className:`h-3 w-3`})})}function y({label:e,value:t}){return(0,_.jsxs)(`div`,{className:`rounded-md border border-border/40 bg-muted/20 p-2`,children:[(0,_.jsxs)(`div`,{className:`mb-1 flex items-center justify-between gap-2`,children:[(0,_.jsx)(`span`,{className:`text-[10px] font-medium uppercase tracking-[0.16em] text-muted-foreground`,children:e}),(0,_.jsx)(v,{value:t,label:`Copy ${e}`})]}),(0,_.jsx)(`code`,{className:`block break-all font-mono text-[11px] leading-relaxed text-foreground dark:text-zinc-100`,children:t})]})}function b({sessionId:e}){return(0,_.jsxs)(`div`,{className:`flex flex-col gap-3 overflow-auto p-3 text-[11px] text-muted-foreground dark:text-zinc-300`,children:[(0,_.jsx)(`p`,{className:`text-muted-foreground dark:text-zinc-300`,children:`This web chat is backed by a runtime session. Use the id below for support or debugging.`}),(0,_.jsx)(y,{label:`Runtime session id`,value:e})]})}var x=2500,S=20;function C({apiBaseUrl:e,fetch:t,sessionId:n,requestHeaders:r,storageScope:a}){let[o,s]=(0,g.useState)({kind:`loading`}),[c,l]=(0,g.useState)(0),u=(0,g.useRef)(0),d=(0,g.useCallback)(()=>{u.current=0,l(e=>e+1)},[]);return(0,g.useEffect)(()=>{let i=!1,o=null;return s({kind:`loading`}),(t??globalThis.fetch.bind(globalThis))(j(e,`/api/v1/agent/sessions/${encodeURIComponent(n)}/system-prompt`),{headers:M(r,a)}).then(async e=>{if(i)return;if(e.ok){let t=await e.json();if(typeof t.systemPrompt==`string`){u.current=0,s({kind:`ok`,text:t.systemPrompt});return}}let t=(await e.json().catch(()=>null))?.error?.message??`HTTP ${e.status}`;e.status===404&&u.current<S?(s({kind:`empty`,reason:t}),o=setTimeout(()=>{i||(u.current++,l(e=>e+1))},x)):s(e.status===404?{kind:`empty`,reason:t}:{kind:`error`,reason:t})}).catch(e=>{i||s({kind:`error`,reason:e instanceof Error?e.message:String(e)})}),()=>{i=!0,o&&clearTimeout(o)}},[e,t,n,r,c,a]),(0,_.jsxs)(`div`,{className:`flex flex-col h-full min-h-0`,children:[(0,_.jsxs)(`div`,{className:`shrink-0 flex items-center justify-between px-3 pt-2 pb-1 border-b border-border/40`,children:[(0,_.jsx)(`span`,{className:`text-[10px] text-muted-foreground/80 font-mono`,children:o.kind===`ok`?`${o.text.length.toLocaleString()} chars`:o.kind===`loading`?`loading…`:o.kind===`empty`?`waiting for session · retry ${u.current}/${S}`:`error`}),o.kind!==`loading`&&(0,_.jsx)(i,{type:`button`,variant:`ghost`,size:`icon-xs`,onClick:d,className:`text-muted-foreground/60`,"aria-label":`Refresh system prompt`,children:(0,_.jsx)(f,{className:`h-3 w-3`})})]}),(o.kind===`loading`||o.kind===`empty`)&&(0,_.jsx)(`p`,{className:`text-[11px] text-muted-foreground p-3`,children:o.kind===`loading`?`Loading…`:o.reason}),o.kind===`error`&&(0,_.jsx)(`p`,{className:`text-[11px] text-destructive p-3`,children:o.reason}),o.kind===`ok`&&(0,_.jsx)(`pre`,{className:`flex-1 overflow-auto px-3 py-2 font-mono text-[11px] leading-relaxed text-foreground whitespace-pre-wrap break-words`,children:o.text})]})}function w(e){let t=e,n=t?.type??`?`;if(n===`text`){let e=String(t.text??``);return e.slice(0,80)+(e.length>80?`…`:``)}if(n===`tool-invocation`){let e=t.toolInvocation,n=String(e?.state??``);return`${e?.toolName??`?`}() · ${n}`}if(n===`reasoning`){let e=String(t.text??t.reasoning??``);return e.slice(0,80)+(e.length>80?`…`:``)}return n}function T(e){let t=[];for(let n=0;n<e.length;n++){let r=e[n],i=r,a=i.createdAt?new Date(i.createdAt).toISOString().slice(11,23):null;for(let e=0;e<r.parts.length;e++){let i=r.parts[e];t.push({msgId:r.id,msgIndex:n,role:r.role,time:a,partIndex:e,partType:i?.type??`unknown`,part:i})}}return t}function E({messages:e}){let t=T(e),[n,r]=(0,g.useState)(null),i=(0,g.useRef)(null),a=(0,g.useRef)(t.length);return(0,g.useEffect)(()=>{t.length!==a.current&&(i.current?.scrollIntoView({behavior:`smooth`}),a.current=t.length)},[t.length]),t.length===0?(0,_.jsx)(`p`,{className:`text-[11px] text-muted-foreground p-3`,children:`No messages yet.`}):(0,_.jsxs)(`div`,{className:`flex flex-col h-full min-h-0`,children:[(0,_.jsxs)(`div`,{className:`shrink-0 px-3 pt-2 pb-1 text-[10px] text-muted-foreground/80 font-mono border-b border-border/40`,children:[e.length,` msg · `,t.length,` parts`]}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-auto`,children:[t.map(e=>{let t=`${e.msgId}:${e.partIndex}`,i=n===t;return(0,_.jsxs)(`div`,{className:`border-b border-border/30 last:border-0`,children:[(0,_.jsxs)(s,{type:`button`,variant:`ghost`,onClick:()=>r(i?null:t),className:`h-auto w-full justify-start gap-1.5 rounded-none px-2 py-1.5 text-left`,children:[(0,_.jsx)(`span`,{className:`mt-0.5 shrink-0 text-muted-foreground/40`,children:i?(0,_.jsx)(h,{className:`h-3 w-3`}):(0,_.jsx)(p,{className:`h-3 w-3`})}),(0,_.jsx)(`span`,{className:`font-mono text-[10px] shrink-0 w-20`,children:e.time?(0,_.jsx)(`span`,{className:`text-muted-foreground/60`,children:e.time}):(0,_.jsxs)(`span`,{className:`text-muted-foreground/30`,children:[`m`,e.msgIndex]})}),(0,_.jsx)(`span`,{className:u(`shrink-0 font-mono text-[10px] w-14`,e.role===`user`?`text-accent`:`text-muted-foreground`),children:e.role}),(0,_.jsx)(`span`,{className:`shrink-0 font-mono text-[10px] text-muted-foreground/60 w-24`,children:e.partType}),(0,_.jsx)(`span`,{className:`flex-1 min-w-0 font-mono text-[11px] text-foreground truncate`,children:w(e.part)})]}),i&&(0,_.jsx)(`pre`,{className:`px-3 pb-2 font-mono text-[10px] leading-relaxed text-foreground/80 whitespace-pre-wrap break-words bg-muted/20`,children:JSON.stringify(e.part,null,2)})]},t)}),(0,_.jsx)(`div`,{ref:i})]})]})}var D=[{id:`session`,label:`Session`},{id:`prompt`,label:`System prompt`},{id:`messages`,label:`Messages`}],O=280,k=800;function A({apiBaseUrl:e,fetch:t,sessionId:n,messages:i,requestHeaders:s,storageScope:l,width:d,onWidthChange:f}){let[p,m]=(0,g.useState)(`session`);return(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(`div`,{onMouseDown:(0,g.useCallback)(e=>{e.preventDefault();let t=e.clientX,n=d,r=e=>{let r=t-e.clientX;f(Math.min(k,Math.max(O,n+r)))},i=()=>{window.removeEventListener(`mousemove`,r),window.removeEventListener(`mouseup`,i)};window.addEventListener(`mousemove`,r),window.addEventListener(`mouseup`,i)},[d,f]),className:`w-1 shrink-0 cursor-col-resize hover:bg-accent/40 active:bg-accent/60 transition-colors`,"aria-hidden":!0}),(0,_.jsx)(`aside`,{style:{width:d},className:u(`flex h-full shrink-0 flex-col border-l border-border/60`,`bg-[oklch(from_var(--background)_calc(l-0.01)_c_h)]`),children:(0,_.jsxs)(a,{value:p,onValueChange:e=>m(e),className:`flex flex-col flex-1 min-h-0 overflow-hidden`,children:[(0,_.jsx)(`header`,{className:`flex shrink-0 items-center gap-0 border-b border-border/60 px-1`,children:(0,_.jsx)(c,{variant:`line`,className:`h-auto gap-0 p-0 w-full`,children:D.map(({id:e,label:t})=>(0,_.jsx)(o,{value:e,className:`h-8 flex-none px-3 py-2 text-[11px] font-medium data-[state=active]:after:bg-[color:var(--accent)]`,children:t},e))})}),(0,_.jsx)(r,{value:`session`,forceMount:!0,className:`flex flex-col flex-1 min-h-0 overflow-hidden data-[state=inactive]:hidden`,children:(0,_.jsx)(b,{sessionId:n})}),(0,_.jsx)(r,{value:`prompt`,forceMount:!0,className:`flex flex-col flex-1 min-h-0 overflow-hidden data-[state=inactive]:hidden`,children:(0,_.jsx)(C,{apiBaseUrl:e,fetch:t,sessionId:n,requestHeaders:s,storageScope:l})}),(0,_.jsx)(r,{value:`messages`,forceMount:!0,className:`flex flex-col flex-1 min-h-0 overflow-hidden data-[state=inactive]:hidden`,children:(0,_.jsx)(E,{messages:i})})]})})]})}function j(e,t){return`${e?.replace(/\/$/,``)??``}${t}`}function M(e,t){if(!e&&!t)return;let n={...e??{}},r=Object.keys(n).some(e=>e.toLowerCase()===`x-boring-storage-scope`);return t&&!r&&(n[`x-boring-storage-scope`]=t),n}export{A as DebugDrawer};
1
+ import{s as e}from"./rolldown-runtime-BG2f4sTM.js";import{n as t,t as n}from"./jsx-runtime-CC-kRuLe.js";import{Ct as r,G as i,St as a,Tt as o,d as s,wt as c}from"./createLucideIcon-BpL36Utr.js";import{A as l,C as u,D as d,E as f,O as p,S as m,k as h}from"./index-Cns0vbRE.js";var g=e(t(),1),_=e(n(),1);function v({value:e,label:t}){let[n,r]=(0,g.useState)(!1);return(0,_.jsx)(i,{type:`button`,variant:`ghost`,size:`icon-xs`,onClick:(0,g.useCallback)(()=>{m(e).then(e=>{e&&(r(!0),window.setTimeout(()=>r(!1),1200))})},[e]),className:`text-muted-foreground/60`,"aria-label":t,title:t,children:n?(0,_.jsx)(l,{className:`h-3 w-3`}):(0,_.jsx)(d,{className:`h-3 w-3`})})}function y({label:e,value:t}){return(0,_.jsxs)(`div`,{className:`rounded-md border border-border/40 bg-muted/20 p-2`,children:[(0,_.jsxs)(`div`,{className:`mb-1 flex items-center justify-between gap-2`,children:[(0,_.jsx)(`span`,{className:`text-[10px] font-medium uppercase tracking-[0.16em] text-muted-foreground`,children:e}),(0,_.jsx)(v,{value:t,label:`Copy ${e}`})]}),(0,_.jsx)(`code`,{className:`block break-all font-mono text-[11px] leading-relaxed text-foreground dark:text-zinc-100`,children:t})]})}function b({sessionId:e}){return(0,_.jsxs)(`div`,{className:`flex flex-col gap-3 overflow-auto p-3 text-[11px] text-muted-foreground dark:text-zinc-300`,children:[(0,_.jsx)(`p`,{className:`text-muted-foreground dark:text-zinc-300`,children:`This web chat is backed by a runtime session. Use the id below for support or debugging.`}),(0,_.jsx)(y,{label:`Runtime session id`,value:e})]})}var x=2500,S=20;function C({apiBaseUrl:e,fetch:t,sessionId:n,requestHeaders:r,storageScope:a}){let[o,s]=(0,g.useState)({kind:`loading`}),[c,l]=(0,g.useState)(0),u=(0,g.useRef)(0),d=(0,g.useCallback)(()=>{u.current=0,l(e=>e+1)},[]);return(0,g.useEffect)(()=>{let i=!1,o=null;return s({kind:`loading`}),(t??globalThis.fetch.bind(globalThis))(j(e,`/api/v1/agent/sessions/${encodeURIComponent(n)}/system-prompt`),{headers:M(r,a)}).then(async e=>{if(i)return;if(e.ok){let t=await e.json();if(typeof t.systemPrompt==`string`){u.current=0,s({kind:`ok`,text:t.systemPrompt});return}}let t=(await e.json().catch(()=>null))?.error?.message??`HTTP ${e.status}`;e.status===404&&u.current<S?(s({kind:`empty`,reason:t}),o=setTimeout(()=>{i||(u.current++,l(e=>e+1))},x)):s(e.status===404?{kind:`empty`,reason:t}:{kind:`error`,reason:t})}).catch(e=>{i||s({kind:`error`,reason:e instanceof Error?e.message:String(e)})}),()=>{i=!0,o&&clearTimeout(o)}},[e,t,n,r,c,a]),(0,_.jsxs)(`div`,{className:`flex flex-col h-full min-h-0`,children:[(0,_.jsxs)(`div`,{className:`shrink-0 flex items-center justify-between px-3 pt-2 pb-1 border-b border-border/40`,children:[(0,_.jsx)(`span`,{className:`text-[10px] text-muted-foreground/80 font-mono`,children:o.kind===`ok`?`${o.text.length.toLocaleString()} chars`:o.kind===`loading`?`loading…`:o.kind===`empty`?`waiting for session · retry ${u.current}/${S}`:`error`}),o.kind!==`loading`&&(0,_.jsx)(i,{type:`button`,variant:`ghost`,size:`icon-xs`,onClick:d,className:`text-muted-foreground/60`,"aria-label":`Refresh system prompt`,children:(0,_.jsx)(f,{className:`h-3 w-3`})})]}),(o.kind===`loading`||o.kind===`empty`)&&(0,_.jsx)(`p`,{className:`text-[11px] text-muted-foreground p-3`,children:o.kind===`loading`?`Loading…`:o.reason}),o.kind===`error`&&(0,_.jsx)(`p`,{className:`text-[11px] text-destructive p-3`,children:o.reason}),o.kind===`ok`&&(0,_.jsx)(`pre`,{className:`flex-1 overflow-auto px-3 py-2 font-mono text-[11px] leading-relaxed text-foreground whitespace-pre-wrap break-words`,children:o.text})]})}function w(e){let t=e,n=t?.type??`?`;if(n===`text`){let e=String(t.text??``);return e.slice(0,80)+(e.length>80?`…`:``)}if(n===`tool-invocation`){let e=t.toolInvocation,n=String(e?.state??``);return`${e?.toolName??`?`}() · ${n}`}if(n===`reasoning`){let e=String(t.text??t.reasoning??``);return e.slice(0,80)+(e.length>80?`…`:``)}return n}function T(e){let t=[];for(let n=0;n<e.length;n++){let r=e[n],i=r,a=i.createdAt?new Date(i.createdAt).toISOString().slice(11,23):null;for(let e=0;e<r.parts.length;e++){let i=r.parts[e];t.push({msgId:r.id,msgIndex:n,role:r.role,time:a,partIndex:e,partType:i?.type??`unknown`,part:i})}}return t}function E({messages:e}){let t=T(e),[n,r]=(0,g.useState)(null),i=(0,g.useRef)(null),a=(0,g.useRef)(t.length);return(0,g.useEffect)(()=>{t.length!==a.current&&(i.current?.scrollIntoView({behavior:`smooth`}),a.current=t.length)},[t.length]),t.length===0?(0,_.jsx)(`p`,{className:`text-[11px] text-muted-foreground p-3`,children:`No messages yet.`}):(0,_.jsxs)(`div`,{className:`flex flex-col h-full min-h-0`,children:[(0,_.jsxs)(`div`,{className:`shrink-0 px-3 pt-2 pb-1 text-[10px] text-muted-foreground/80 font-mono border-b border-border/40`,children:[e.length,` msg · `,t.length,` parts`]}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-auto`,children:[t.map(e=>{let t=`${e.msgId}:${e.partIndex}`,i=n===t;return(0,_.jsxs)(`div`,{className:`border-b border-border/30 last:border-0`,children:[(0,_.jsxs)(s,{type:`button`,variant:`ghost`,onClick:()=>r(i?null:t),className:`h-auto w-full justify-start gap-1.5 rounded-none px-2 py-1.5 text-left`,children:[(0,_.jsx)(`span`,{className:`mt-0.5 shrink-0 text-muted-foreground/40`,children:i?(0,_.jsx)(h,{className:`h-3 w-3`}):(0,_.jsx)(p,{className:`h-3 w-3`})}),(0,_.jsx)(`span`,{className:`font-mono text-[10px] shrink-0 w-20`,children:e.time?(0,_.jsx)(`span`,{className:`text-muted-foreground/60`,children:e.time}):(0,_.jsxs)(`span`,{className:`text-muted-foreground/30`,children:[`m`,e.msgIndex]})}),(0,_.jsx)(`span`,{className:u(`shrink-0 font-mono text-[10px] w-14`,e.role===`user`?`text-accent`:`text-muted-foreground`),children:e.role}),(0,_.jsx)(`span`,{className:`shrink-0 font-mono text-[10px] text-muted-foreground/60 w-24`,children:e.partType}),(0,_.jsx)(`span`,{className:`flex-1 min-w-0 font-mono text-[11px] text-foreground truncate`,children:w(e.part)})]}),i&&(0,_.jsx)(`pre`,{className:`px-3 pb-2 font-mono text-[10px] leading-relaxed text-foreground/80 whitespace-pre-wrap break-words bg-muted/20`,children:JSON.stringify(e.part,null,2)})]},t)}),(0,_.jsx)(`div`,{ref:i})]})]})}var D=[{id:`session`,label:`Session`},{id:`prompt`,label:`System prompt`},{id:`messages`,label:`Messages`}],O=280,k=800;function A({apiBaseUrl:e,fetch:t,sessionId:n,messages:i,requestHeaders:s,storageScope:l,width:d,onWidthChange:f}){let[p,m]=(0,g.useState)(`session`);return(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(`div`,{onMouseDown:(0,g.useCallback)(e=>{e.preventDefault();let t=e.clientX,n=d,r=e=>{let r=t-e.clientX;f(Math.min(k,Math.max(O,n+r)))},i=()=>{window.removeEventListener(`mousemove`,r),window.removeEventListener(`mouseup`,i)};window.addEventListener(`mousemove`,r),window.addEventListener(`mouseup`,i)},[d,f]),className:`w-1 shrink-0 cursor-col-resize hover:bg-accent/40 active:bg-accent/60 transition-colors`,"aria-hidden":!0}),(0,_.jsx)(`aside`,{style:{width:d},className:u(`flex h-full shrink-0 flex-col border-l border-border/60`,`bg-[oklch(from_var(--background)_calc(l-0.01)_c_h)]`),children:(0,_.jsxs)(a,{value:p,onValueChange:e=>m(e),className:`flex flex-col flex-1 min-h-0 overflow-hidden`,children:[(0,_.jsx)(`header`,{className:`flex shrink-0 items-center gap-0 border-b border-border/60 px-1`,children:(0,_.jsx)(c,{variant:`line`,className:`h-auto gap-0 p-0 w-full`,children:D.map(({id:e,label:t})=>(0,_.jsx)(o,{value:e,className:`h-8 flex-none px-3 py-2 text-[11px] font-medium data-[state=active]:after:bg-[color:var(--accent)]`,children:t},e))})}),(0,_.jsx)(r,{value:`session`,forceMount:!0,className:`flex flex-col flex-1 min-h-0 overflow-hidden data-[state=inactive]:hidden`,children:(0,_.jsx)(b,{sessionId:n})}),(0,_.jsx)(r,{value:`prompt`,forceMount:!0,className:`flex flex-col flex-1 min-h-0 overflow-hidden data-[state=inactive]:hidden`,children:(0,_.jsx)(C,{apiBaseUrl:e,fetch:t,sessionId:n,requestHeaders:s,storageScope:l})}),(0,_.jsx)(r,{value:`messages`,forceMount:!0,className:`flex flex-col flex-1 min-h-0 overflow-hidden data-[state=inactive]:hidden`,children:(0,_.jsx)(E,{messages:i})})]})})]})}function j(e,t){return`${e?.replace(/\/$/,``)??``}${t}`}function M(e,t){if(!e&&!t)return;let n={...e??{}},r=Object.keys(n).some(e=>e.toLowerCase()===`x-boring-storage-scope`);return t&&!r&&(n[`x-boring-storage-scope`]=t),n}export{A as DebugDrawer};