@alisio/server 0.1.0-alpha.1 → 0.1.0-alpha.3

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 (129) hide show
  1. package/dist/host/dir-listing.d.ts +20 -0
  2. package/dist/host/dir-listing.js +119 -0
  3. package/dist/host/folder-picker.d.ts +95 -0
  4. package/dist/host/folder-picker.js +273 -0
  5. package/dist/host/workspace-host.d.ts +10 -2
  6. package/dist/host/workspace-host.js +45 -10
  7. package/dist/http/errors.js +6 -0
  8. package/dist/index.d.ts +7 -0
  9. package/dist/index.js +16 -2
  10. package/dist/routes/commands.js +3 -1
  11. package/dist/routes/files.js +3 -1
  12. package/dist/routes/folders.d.ts +17 -0
  13. package/dist/routes/folders.js +44 -0
  14. package/dist/routes/health.d.ts +3 -0
  15. package/dist/routes/health.js +4 -3
  16. package/dist/routes/sessions.js +2 -0
  17. package/dist/routes/side-questions.d.ts +12 -0
  18. package/dist/routes/side-questions.js +61 -0
  19. package/dist/routes/workspaces.d.ts +4 -1
  20. package/dist/routes/workspaces.js +23 -2
  21. package/dist/web/alisio-wordmark.png +0 -0
  22. package/dist/web/assets/BtwPanel-CfrlNsqD.css +1 -0
  23. package/dist/web/assets/BtwPanel-CtK6nL1k.js +1 -0
  24. package/dist/web/assets/SettingsModal-B69hjOh0.js +1 -0
  25. package/dist/web/assets/SettingsModal-DuS6eVxB.css +1 -0
  26. package/dist/web/assets/{abnfDiagram-VCTEODGH-Ct0-FsLe.js → abnfDiagram-VCTEODGH-W77lnbMi.js} +1 -1
  27. package/dist/web/assets/architecture-7GRP2DOG-D1ya7AUe.js +1 -0
  28. package/dist/web/assets/{architectureDiagram-5GKGNRK7-BvjnUlvj.js → architectureDiagram-5GKGNRK7-C6PBbaeo.js} +1 -1
  29. package/dist/web/assets/{blockDiagram-I7D4REHJ-CBHCj2Mn.js → blockDiagram-I7D4REHJ-C1PBdOkX.js} +1 -1
  30. package/dist/web/assets/{c4Diagram-7LVT6UL2-9I13K7Yy.js → c4Diagram-7LVT6UL2-C1siIqaQ.js} +1 -1
  31. package/dist/web/assets/channel-BKu2fpj-.js +1 -0
  32. package/dist/web/assets/{chunk-4HAMMTFA-Du4xf36t.js → chunk-4HAMMTFA-fteNd3-U.js} +1 -1
  33. package/dist/web/assets/{chunk-75Z2AOVW-93KpRXCT.js → chunk-75Z2AOVW-D1wpTnTM.js} +1 -1
  34. package/dist/web/assets/{chunk-DU6HZSFF-DP6dsL6K.js → chunk-DU6HZSFF-D67lp4wj.js} +1 -1
  35. package/dist/web/assets/{chunk-F27PBJKO-CxLLRIN4.js → chunk-F27PBJKO-o5VRPsdh.js} +1 -1
  36. package/dist/web/assets/{chunk-GMAD6QVW-BGv500CR.js → chunk-GMAD6QVW-Cj6iihx3.js} +1 -1
  37. package/dist/web/assets/{chunk-GVQU2GXP-BmXv3St8.js → chunk-GVQU2GXP-B_GDBHrL.js} +1 -1
  38. package/dist/web/assets/{chunk-IMKFNOWR-tmbCLM1n.js → chunk-IMKFNOWR-BtOT8hYb.js} +1 -1
  39. package/dist/web/assets/{chunk-L3NEJ4N5-BULbKNtl.js → chunk-L3NEJ4N5-C7JXpbh_.js} +1 -1
  40. package/dist/web/assets/{chunk-OSK3NFVY-DyvADXPn.js → chunk-OSK3NFVY-DCVpP_Rf.js} +1 -1
  41. package/dist/web/assets/{chunk-P2QGCYS3-YhA2sAhR.js → chunk-P2QGCYS3-pltljbMq.js} +1 -1
  42. package/dist/web/assets/{chunk-POPQ4Y6H-BLr1KktA.js → chunk-POPQ4Y6H-DsTguJIh.js} +1 -1
  43. package/dist/web/assets/{chunk-PWAF6VOD-DJCZC9ie.js → chunk-PWAF6VOD-CPzNIjNy.js} +1 -1
  44. package/dist/web/assets/{chunk-SHT3W25Y-B8xH9z5t.js → chunk-SHT3W25Y-QvVe8iDd.js} +1 -1
  45. package/dist/web/assets/{chunk-SVP7TREG-DxynkM9y.js → chunk-SVP7TREG-B-hStYeg.js} +1 -1
  46. package/dist/web/assets/{chunk-TICWLB2K-CZPXqwaW.js → chunk-TICWLB2K-Cn8kFuzV.js} +1 -1
  47. package/dist/web/assets/classDiagram-ZZMXUADV-YRQXLjhB.js +1 -0
  48. package/dist/web/assets/classDiagram-v2-VYDZK3BY-YRQXLjhB.js +1 -0
  49. package/dist/web/assets/{cynefin-OW5HDTMX-rct1-Bf_.js → cynefin-OW5HDTMX-CTCpFxz5.js} +1 -1
  50. package/dist/web/assets/{cynefinDiagram-5FMLGOSQ-CuBJbnvx.js → cynefinDiagram-5FMLGOSQ-Ccwq_del.js} +1 -1
  51. package/dist/web/assets/{dagre-GXQ25YYZ-w8zs2moB.js → dagre-GXQ25YYZ-DVldPe6v.js} +1 -1
  52. package/dist/web/assets/{diagram-S7CK7UJ4-BMBhFewM.js → diagram-S7CK7UJ4-C-a0JpHd.js} +1 -1
  53. package/dist/web/assets/{diagram-UQ7AKVKN-C7BN6534.js → diagram-UQ7AKVKN-CfDM8Y6F.js} +1 -1
  54. package/dist/web/assets/{diagram-VSXAHHWV-Dd8_wR6U.js → diagram-VSXAHHWV-ByLzrjJF.js} +1 -1
  55. package/dist/web/assets/{diagram-VX7I27RA-DR3aOC1b.js → diagram-VX7I27RA-D-gnUcwL.js} +1 -1
  56. package/dist/web/assets/{diagram-Z3DM3KII-5aBBRZ2Z.js → diagram-Z3DM3KII-B-riDjw6.js} +1 -1
  57. package/dist/web/assets/{ebnfDiagram-PWID7BFC-46Gc2APT.js → ebnfDiagram-PWID7BFC-9MyJsI3c.js} +1 -1
  58. package/dist/web/assets/{engine-CknQqOvU.js → engine-D40yLY_U.js} +4 -4
  59. package/dist/web/assets/{erDiagram-RLTQ6QDP-CNfUFQmD.js → erDiagram-RLTQ6QDP-N799CZm7.js} +1 -1
  60. package/dist/web/assets/eventmodeling-NTZA5JFV-BxVDr6Nm.js +1 -0
  61. package/dist/web/assets/flowDiagram-HODETNUW-DJ_RarP5.js +1 -0
  62. package/dist/web/assets/{ganttDiagram-EL5Y4UJY-B1RLLE0F.js → ganttDiagram-EL5Y4UJY-MVcwyLgI.js} +1 -1
  63. package/dist/web/assets/{gitGraph-4MIJSDKK-DmzdoCuA.js → gitGraph-4MIJSDKK-CK2nHEiv.js} +1 -1
  64. package/dist/web/assets/{gitGraphDiagram-WWUBYQGX-DN5-fMOS.js → gitGraphDiagram-WWUBYQGX-DKZy0hvy.js} +1 -1
  65. package/dist/web/assets/{highlight-C1LfZ1aI.js → highlight-C8FwCbLq.js} +1 -1
  66. package/dist/web/assets/index-CGOgNFx5.css +1 -0
  67. package/dist/web/assets/index-CMMMNWOn.js +75 -0
  68. package/dist/web/assets/{info-A6RAGUB7-CebZRx1l.js → info-A6RAGUB7-B7bsZFto.js} +1 -1
  69. package/dist/web/assets/{infoDiagram-27XIBGKW-BeY-irSX.js → infoDiagram-27XIBGKW-BOmlRrC_.js} +1 -1
  70. package/dist/web/assets/{ishikawaDiagram-5VMMS53U-Djn1dIqp.js → ishikawaDiagram-5VMMS53U-C9BfTY4y.js} +1 -1
  71. package/dist/web/assets/{journeyDiagram-3NMN7TZE-CV_b2MnE.js → journeyDiagram-3NMN7TZE-BBhEKs-j.js} +1 -1
  72. package/dist/web/assets/jsxRuntime-DnBCdh_Z.js +1 -0
  73. package/dist/web/assets/{kanban-definition-UXKFOSKX-CXTukynL.js → kanban-definition-UXKFOSKX-CRs3tvoC.js} +1 -1
  74. package/dist/web/assets/{line-DIt63x6x.js → line-B3IfyWYt.js} +1 -1
  75. package/dist/web/assets/{mermaid-parser.core-UsYAxtjN.js → mermaid-parser.core-OzvFg3MX.js} +3 -3
  76. package/dist/web/assets/{mindmap-definition-YA3MSWOX-G0K_7S5N.js → mindmap-definition-YA3MSWOX-CzqJfERM.js} +1 -1
  77. package/dist/web/assets/{packet-AYTQ26CC-D3_L-O-_.js → packet-AYTQ26CC-B0aiVtYc.js} +1 -1
  78. package/dist/web/assets/{pegDiagram-XKGWAZYB-BoSJtVsR.js → pegDiagram-XKGWAZYB-DTvoRl0E.js} +1 -1
  79. package/dist/web/assets/{pie-WAS4IAKB-DUARjLYc.js → pie-WAS4IAKB-DSgmxs5B.js} +1 -1
  80. package/dist/web/assets/{pieDiagram-E7YTZNPT-DaFXBymx.js → pieDiagram-E7YTZNPT-DNKsEHsO.js} +1 -1
  81. package/dist/web/assets/{quadrantDiagram-AXDQQJYC-DvJJGxS3.js → quadrantDiagram-AXDQQJYC-DZCyyT-7.js} +1 -1
  82. package/dist/web/assets/{radar-RG4KPBEZ-CoTA2z0h.js → radar-RG4KPBEZ-Br1zOmaV.js} +1 -1
  83. package/dist/web/assets/{railroad-74A4TZTK-D22_YeTS.js → railroad-74A4TZTK-BZWaWLI9.js} +1 -1
  84. package/dist/web/assets/railroad-abnf-HS5TGJTU-CovjZS2M.js +1 -0
  85. package/dist/web/assets/railroad-ebnf-LZEXJU2U-4XWWCoEA.js +1 -0
  86. package/dist/web/assets/railroad-peg-WCYAUIDC-ByQJEDvc.js +1 -0
  87. package/dist/web/assets/{railroadDiagram-O6MQD6OU-Cxnojv6Q.js → railroadDiagram-O6MQD6OU-BD4wMWFZ.js} +1 -1
  88. package/dist/web/assets/{requirementDiagram-BXWQKSXE-gW2PlZJn.js → requirementDiagram-BXWQKSXE-Bkq6uo8T.js} +1 -1
  89. package/dist/web/assets/{sankeyDiagram-P5KCCOFB-DcoJ0sYw.js → sankeyDiagram-P5KCCOFB-BD7DSO0l.js} +1 -1
  90. package/dist/web/assets/{sequenceDiagram-WJ2MYXX4-kRLbkAfp.js → sequenceDiagram-WJ2MYXX4-ySuq8V_9.js} +1 -1
  91. package/dist/web/assets/{stateDiagram-D77RDMKH-CEWdwxTm.js → stateDiagram-D77RDMKH-eMKYJ2yD.js} +1 -1
  92. package/dist/web/assets/stateDiagram-v2-MP3YSRHH-DIjhulyn.js +1 -0
  93. package/dist/web/assets/{swimlanes-42K2YHIH-oyoSxsbH.js → swimlanes-42K2YHIH-DVi1lTr7.js} +1 -1
  94. package/dist/web/assets/swimlanesDiagram-VR7AAH4N-DwPzD4HF.js +8 -0
  95. package/dist/web/assets/{timeline-definition-24CTP7MA-D97QYUq5.js → timeline-definition-24CTP7MA-Cuny1pIj.js} +1 -1
  96. package/dist/web/assets/{treeView-Q6P3EWNA-FwhRnXTt.js → treeView-Q6P3EWNA-qn0ZK8wv.js} +1 -1
  97. package/dist/web/assets/{treemap-WGGIJYW6-ByFNzzzU.js → treemap-WGGIJYW6-D2zgkQxn.js} +1 -1
  98. package/dist/web/assets/{vennDiagram-4TSXK5OY-CcqjaQy9.js → vennDiagram-4TSXK5OY-BPCM2sqH.js} +1 -1
  99. package/dist/web/assets/{view-BQZA99Bp.js → view-BSs9O8KC.js} +1 -1
  100. package/dist/web/assets/{view-CS-jPsy6.js → view-BuAv5SLI.js} +2 -2
  101. package/dist/web/assets/{view-DzlpughI.js → view-D00dIkJS.js} +1 -1
  102. package/dist/web/assets/{view-NDb0VvVU.js → view-D5ngm6EH.js} +1 -1
  103. package/dist/web/assets/{view-C9vvQ0AK.js → view-DI_PrZPK.js} +1 -1
  104. package/dist/web/assets/{view-CYRKKlxP.js → view-Dxls51Hk.js} +1 -1
  105. package/dist/web/assets/{view-0zE8CdnP.js → view-MPMg9bfD.js} +1 -1
  106. package/dist/web/assets/{view-DE2OI6Vv.js → view-niy0QSE1.js} +1 -1
  107. package/dist/web/assets/{wardley-WFR3VGLG-Bt4CePrl.js → wardley-WFR3VGLG-BTUkNa-6.js} +1 -1
  108. package/dist/web/assets/{wardleyDiagram-VM6X3IG4-CcgXimi3.js → wardleyDiagram-VM6X3IG4-Bxj-CZyy.js} +1 -1
  109. package/dist/web/assets/{xychartDiagram-S5SC5T6Z-0Jx20wNz.js → xychartDiagram-S5SC5T6Z-DrxQEmlK.js} +1 -1
  110. package/dist/web/favicon.png +0 -0
  111. package/dist/web/index.html +5 -4
  112. package/dist/web/logo-64.png +0 -0
  113. package/package.json +3 -3
  114. package/dist/web/assets/SettingsModal-Dj5G3JIz.js +0 -1
  115. package/dist/web/assets/SettingsModal-YCahs6O5.css +0 -1
  116. package/dist/web/assets/architecture-7GRP2DOG-B5Qnm7io.js +0 -1
  117. package/dist/web/assets/channel-B-TykkBN.js +0 -1
  118. package/dist/web/assets/classDiagram-ZZMXUADV-B6LKfKSk.js +0 -1
  119. package/dist/web/assets/classDiagram-v2-VYDZK3BY-B6LKfKSk.js +0 -1
  120. package/dist/web/assets/eventmodeling-NTZA5JFV-Dx_J4ait.js +0 -1
  121. package/dist/web/assets/flowDiagram-HODETNUW-Bs7QheBl.js +0 -1
  122. package/dist/web/assets/index-CGolUSWa.js +0 -75
  123. package/dist/web/assets/index-vUqwyH-2.css +0 -1
  124. package/dist/web/assets/jsxRuntime-D9k5B_Bf.js +0 -1
  125. package/dist/web/assets/railroad-abnf-HS5TGJTU-Mvl9LvJX.js +0 -1
  126. package/dist/web/assets/railroad-ebnf-LZEXJU2U-hvVPkAs6.js +0 -1
  127. package/dist/web/assets/railroad-peg-WCYAUIDC-XX_5aYEK.js +0 -1
  128. package/dist/web/assets/stateDiagram-v2-MP3YSRHH-DZ8dTBXf.js +0 -1
  129. package/dist/web/assets/swimlanesDiagram-VR7AAH4N-McbEeiYz.js +0 -8
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { type ServerResponse } from "node:http";
2
+ import { type FolderPicker } from "./host/folder-picker.ts";
2
3
  import { type ServerAppOptions } from "./host/workspace-host.ts";
3
4
  import { type Logger } from "./log.ts";
4
5
  export { isLoopbackHost } from "./auth/guard.ts";
5
6
  export { ApprovalBridge } from "./bridges/approval-bridge.ts";
6
7
  export { InteractionBridge } from "./bridges/interaction-bridge.ts";
8
+ export { createNativePicker, type FolderPicker, type PickerStrategy, selectPicker, } from "./host/folder-picker.ts";
7
9
  export { type Application, type OpenWorkspace, type ServerAppOptions, WorkspaceHost, workspaceId, } from "./host/workspace-host.ts";
8
10
  export { HttpError } from "./http/errors.ts";
9
11
  export { contentSecurityPolicy, PLACEHOLDER_HTML } from "./http/static.ts";
@@ -46,6 +48,11 @@ export interface ServerOptions {
46
48
  approvalGraceMs?: number;
47
49
  /** Deny an approval after this long even when watched (default 10 min; 0 = no limit). */
48
50
  approvalTimeoutMs?: number;
51
+ /**
52
+ * Native folder dialog for "Open a workspace" (default: detected for this OS). Injectable for
53
+ * tests. Always off when the server is bound for remote access.
54
+ */
55
+ folderPicker?: FolderPicker;
49
56
  }
50
57
  export interface RunningServer {
51
58
  host: string;
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { BlobStore, SQLiteStore, stateHome } from "@alisio/core";
9
9
  import { AuthGuard, isLoopbackHost } from "./auth/guard.js";
10
10
  import { ApprovalBridge } from "./bridges/approval-bridge.js";
11
11
  import { InteractionBridge } from "./bridges/interaction-bridge.js";
12
+ import { createNativePicker } from "./host/folder-picker.js";
12
13
  import { RunScheduler } from "./host/run-scheduler.js";
13
14
  import { SessionService } from "./host/sessions.js";
14
15
  import { WorkspaceHost, workspaceId } from "./host/workspace-host.js";
@@ -21,18 +22,21 @@ import { registerBlobRoutes } from "./routes/blobs.js";
21
22
  import { registerCommandRoutes } from "./routes/commands.js";
22
23
  import { registerEventRoutes } from "./routes/events.js";
23
24
  import { registerFileRoutes } from "./routes/files.js";
25
+ import { registerFolderRoutes } from "./routes/folders.js";
24
26
  import { registerHealthRoutes } from "./routes/health.js";
25
27
  import { registerManagementRoutes, WorkspaceRecycler } from "./routes/management.js";
26
28
  import { registerPromptRoutes } from "./routes/prompts.js";
27
29
  import { registerProviderRoutes } from "./routes/providers.js";
28
30
  import { registerSessionViewRoutes } from "./routes/session-views.js";
29
31
  import { registerSessionRoutes } from "./routes/sessions.js";
32
+ import { registerSideQuestionRoutes } from "./routes/side-questions.js";
30
33
  import { registerWorkspaceRoutes } from "./routes/workspaces.js";
31
34
  import { SseHub } from "./sse/hub.js";
32
35
  import { InflightTracker } from "./sse/inflight.js";
33
36
  export { isLoopbackHost } from "./auth/guard.js";
34
37
  export { ApprovalBridge } from "./bridges/approval-bridge.js";
35
38
  export { InteractionBridge } from "./bridges/interaction-bridge.js";
39
+ export { createNativePicker, selectPicker, } from "./host/folder-picker.js";
36
40
  export { WorkspaceHost, workspaceId, } from "./host/workspace-host.js";
37
41
  export { HttpError } from "./http/errors.js";
38
42
  export { contentSecurityPolicy, PLACEHOLDER_HTML } from "./http/static.js";
@@ -186,18 +190,27 @@ export async function startServer(options = {}) {
186
190
  pendingApprovals: approvals?.size ?? 0,
187
191
  sseDropped: hub.dropped,
188
192
  });
193
+ // The dialog and the directory browser act on the server machine as the server user: only for
194
+ // loopback, where the viewer is that user at that machine.
195
+ const loopback = isLoopbackHost(host);
196
+ const picker = loopback ? (options.folderPicker ?? createNativePicker()) : undefined;
197
+ const pickerAbort = new AbortController();
189
198
  registerHealthRoutes(router, {
190
199
  version: options.version ?? "dev",
191
- remote: !isLoopbackHost(host),
200
+ remote: !loopback,
192
201
  stats,
202
+ nativePicker: async () => !!picker && (await picker.available()),
203
+ folderBrowser: loopback,
193
204
  });
194
- registerWorkspaceRoutes(router, { workspaces, catalog });
205
+ registerFolderRoutes(router, { picker, browser: loopback, signal: pickerAbort.signal });
206
+ registerWorkspaceRoutes(router, { workspaces, catalog, scheduler });
195
207
  registerSessionRoutes(router, { catalog, workspaces, sessions, scheduler });
196
208
  registerSessionViewRoutes(router, { catalog, sessions });
197
209
  registerFileRoutes(router, { workspaces, catalog, sessions });
198
210
  registerBlobRoutes(router, { blobs });
199
211
  registerPromptRoutes(router, { sessions, scheduler });
200
212
  registerCommandRoutes(router, { sessions, scheduler, workspaces });
213
+ registerSideQuestionRoutes(router, { sessions });
201
214
  registerApprovalRoutes(router, { approvals, interactions });
202
215
  const management = {
203
216
  workspaces,
@@ -322,6 +335,7 @@ export async function startServer(options = {}) {
322
335
  const began = Date.now();
323
336
  closing = true;
324
337
  clearInterval(sweeper);
338
+ pickerAbort.abort();
325
339
  const settling = scheduler.shutdown(2_000);
326
340
  approvals?.denyAll();
327
341
  interactions?.cancelAll();
@@ -81,7 +81,9 @@ export function registerCommandRoutes(router, ctx) {
81
81
  throw error;
82
82
  return fail(error);
83
83
  }
84
- sessions.notify(session.id);
84
+ // A `/btw` side question changes nothing the session summary shows.
85
+ if (descriptor.name !== "btw")
86
+ sessions.notify(session.id);
85
87
  return { body: outcome };
86
88
  async function run() {
87
89
  if (!descriptor)
@@ -30,7 +30,9 @@ export async function confine(root, path, mustExist = true) {
30
30
  }
31
31
  catch (error) {
32
32
  if (errno(error) === "ENOENT")
33
- throw new HttpError("not_found", "Workspace not found");
33
+ throw new HttpError("workspace_missing", `Workspace folder not found: ${root}`, {
34
+ path: root,
35
+ });
34
36
  throw new HttpError("path_outside_workspace", "The path is outside the workspace");
35
37
  }
36
38
  let real = target;
@@ -0,0 +1,17 @@
1
+ import type { FolderPicker } from "../host/folder-picker.ts";
2
+ import type { Router } from "../http/router.ts";
3
+ export interface FolderRouteOptions {
4
+ /** Native dialog; `undefined` when disabled (remote bind). */
5
+ picker: FolderPicker | undefined;
6
+ /** In-app folder browser (directory names of the server user); loopback only. */
7
+ browser: boolean;
8
+ /** Aborted on shutdown: closes an open dialog. */
9
+ signal: AbortSignal;
10
+ }
11
+ /**
12
+ * `POST /api/workspaces/pick` (native OS folder dialog on the server's desktop) and
13
+ * `GET /api/fs/dirs` (subdirectory names for the in-app browser). Both only exist for a loopback
14
+ * server: the dialog opens on the machine running `alisio serve`, and the browser exposes the
15
+ * server user's directory names (the same trust as the loopback CLI).
16
+ */
17
+ export declare function registerFolderRoutes(router: Router, options: FolderRouteOptions): void;
@@ -0,0 +1,44 @@
1
+ import { stat } from "node:fs/promises";
2
+ import { isAbsolute } from "node:path";
3
+ import { listDirectories } from "../host/dir-listing.js";
4
+ import { readJson } from "../http/body.js";
5
+ import { HttpError } from "../http/errors.js";
6
+ import { is, validate } from "../schemas.js";
7
+ const TITLE = "Open a workspace — Alisio";
8
+ /**
9
+ * `POST /api/workspaces/pick` (native OS folder dialog on the server's desktop) and
10
+ * `GET /api/fs/dirs` (subdirectory names for the in-app browser). Both only exist for a loopback
11
+ * server: the dialog opens on the machine running `alisio serve`, and the browser exposes the
12
+ * server user's directory names (the same trust as the loopback CLI).
13
+ */
14
+ export function registerFolderRoutes(router, options) {
15
+ router.post("/api/workspaces/pick", async ({ req }) => {
16
+ const { start } = validate(await readJson(req), {
17
+ start: { check: is.nonEmpty(4096) },
18
+ });
19
+ if (!options.picker || !(await options.picker.available()))
20
+ throw new HttpError("picker_unavailable", "No native folder dialog on this server");
21
+ if (start !== undefined) {
22
+ const valid = isAbsolute(start) &&
23
+ (await stat(start).then((s) => s.isDirectory(), () => false));
24
+ if (!valid)
25
+ throw new HttpError("validation_failed", "Invalid start directory", { fields: ["start"] });
26
+ }
27
+ const outcome = await options.picker.pick({
28
+ title: TITLE,
29
+ ...(start ? { start } : {}),
30
+ signal: options.signal,
31
+ });
32
+ return { body: outcome };
33
+ });
34
+ router.get("/api/fs/dirs", async ({ url }) => {
35
+ if (!options.browser)
36
+ throw new HttpError("picker_unavailable", "The folder browser is only available on loopback");
37
+ return {
38
+ body: await listDirectories({
39
+ path: url.searchParams.get("path"),
40
+ hidden: url.searchParams.get("hidden") === "true",
41
+ }),
42
+ };
43
+ });
44
+ }
@@ -15,4 +15,7 @@ export declare function registerHealthRoutes(router: Router, options: {
15
15
  version: string;
16
16
  remote: boolean;
17
17
  stats: () => ServerStats;
18
+ /** A native folder dialog can be opened (detected once, lazily). */
19
+ nativePicker?: () => Promise<boolean>;
20
+ folderBrowser?: boolean;
18
21
  }): void;
@@ -4,7 +4,7 @@ import { HttpError } from "../http/errors.js";
4
4
  export const PROTOCOL_VERSION = 1;
5
5
  /** `/api/health` (unauthenticated), `/api/ready` and `/api/metrics`. */
6
6
  export function registerHealthRoutes(router, options) {
7
- router.get("/api/health", () => {
7
+ router.get("/api/health", async () => {
8
8
  const body = {
9
9
  name: "alisio",
10
10
  version: options.version,
@@ -13,12 +13,13 @@ export function registerHealthRoutes(router, options) {
13
13
  sse: true,
14
14
  websocket: false,
15
15
  multiWorkspace: true,
16
- // Uploads (`POST /api/blobs`) arrive in phase 4.
17
- attachments: false,
16
+ attachments: true,
18
17
  uiBlocks: [...UI_BLOCK_KINDS],
19
18
  mcpApps: false,
20
19
  automation: false,
21
20
  remote: options.remote,
21
+ nativePicker: (await options.nativePicker?.()) ?? false,
22
+ folderBrowser: options.folderBrowser ?? false,
22
23
  },
23
24
  };
24
25
  return { body };
@@ -60,6 +60,8 @@ export function registerSessionRoutes(router, ctx) {
60
60
  : await ctx.workspaces.pathOf(input.workspace);
61
61
  if (!path)
62
62
  throw new HttpError("not_found", "Workspace not found");
63
+ if (ctx.workspaces.archived(path))
64
+ throw new HttpError("workspace_archived", `Workspace ${path} is archived; unarchive it to start new sessions`, { path });
63
65
  const opened = await ctx.workspaces.openPath(path);
64
66
  let created;
65
67
  try {
@@ -0,0 +1,12 @@
1
+ import type { SessionService } from "../host/sessions.ts";
2
+ import type { Router } from "../http/router.ts";
3
+ /**
4
+ * `/btw` side questions (tool-less answers about a session outside its conversation):
5
+ * `GET /api/sessions/:sid/btw` lists the session's side questions (oldest first),
6
+ * `POST /api/sessions/:sid/btw {question}` answers one, and `POST .../btw/cancel` cancels the
7
+ * session's in-flight ones. A client that closes the request also cancels it. Side questions
8
+ * never produce durable events, messages or runs, and never wait for the session to be idle.
9
+ */
10
+ export declare function registerSideQuestionRoutes(router: Router, ctx: {
11
+ sessions: SessionService;
12
+ }): void;
@@ -0,0 +1,61 @@
1
+ import { SIDE_QUESTION_MAX_CHARS } from "@alisio/core";
2
+ import { readJson } from "../http/body.js";
3
+ import { HttpError } from "../http/errors.js";
4
+ import { is, validate } from "../schemas.js";
5
+ /**
6
+ * `/btw` side questions (tool-less answers about a session outside its conversation):
7
+ * `GET /api/sessions/:sid/btw` lists the session's side questions (oldest first),
8
+ * `POST /api/sessions/:sid/btw {question}` answers one, and `POST .../btw/cancel` cancels the
9
+ * session's in-flight ones. A client that closes the request also cancels it. Side questions
10
+ * never produce durable events, messages or runs, and never wait for the session to be idle.
11
+ */
12
+ export function registerSideQuestionRoutes(router, ctx) {
13
+ const { sessions } = ctx;
14
+ const inflight = new Map();
15
+ router.get("/api/sessions/:sid/btw", async ({ params }) => {
16
+ const session = sessions.get(params.sid ?? "");
17
+ const opened = await sessions.app(session);
18
+ return { body: opened.app.sideQuestions.history(session.id) };
19
+ });
20
+ router.post("/api/sessions/:sid/btw", async ({ req, res, params }) => {
21
+ const session = sessions.get(params.sid ?? "");
22
+ const input = validate(await readJson(req), {
23
+ question: { check: is.nonEmpty(SIDE_QUESTION_MAX_CHARS), required: true },
24
+ });
25
+ const opened = await sessions.app(session);
26
+ const controller = new AbortController();
27
+ // The client went away before the answer: stop the provider call.
28
+ const onClose = () => {
29
+ if (!res.writableFinished)
30
+ controller.abort(new Error("Side question cancelled"));
31
+ };
32
+ res.on("close", onClose);
33
+ const running = inflight.get(session.id) ?? new Set();
34
+ running.add(controller);
35
+ inflight.set(session.id, running);
36
+ try {
37
+ const entry = await opened.app.sideQuestions.ask(session.id, input.question, {
38
+ signal: controller.signal,
39
+ });
40
+ return { body: entry };
41
+ }
42
+ catch (error) {
43
+ if (controller.signal.aborted)
44
+ throw new HttpError("cancelled", "Side question cancelled");
45
+ throw new HttpError("provider_unavailable", error instanceof Error ? error.message : "Side question failed");
46
+ }
47
+ finally {
48
+ res.off("close", onClose);
49
+ running.delete(controller);
50
+ if (!running.size)
51
+ inflight.delete(session.id);
52
+ }
53
+ });
54
+ router.post("/api/sessions/:sid/btw/cancel", async ({ params }) => {
55
+ const session = sessions.get(params.sid ?? "");
56
+ const running = [...(inflight.get(session.id) ?? [])];
57
+ for (const controller of running)
58
+ controller.abort(new Error("Side question cancelled"));
59
+ return { body: { cancelled: running.length > 0 } };
60
+ });
61
+ }
@@ -1,7 +1,10 @@
1
+ import type { SQLiteStore } from "@alisio/core";
2
+ import type { RunScheduler } from "../host/run-scheduler.ts";
1
3
  import type { WorkspaceHost } from "../host/workspace-host.ts";
2
4
  import type { Router } from "../http/router.ts";
3
5
  /** `GET/POST /api/workspaces`, `PATCH /api/workspaces/:wid`. */
4
6
  export declare function registerWorkspaceRoutes(router: Router, ctx: {
5
7
  workspaces: WorkspaceHost;
6
- catalog: import("@alisio/core").SQLiteStore;
8
+ catalog: SQLiteStore;
9
+ scheduler: RunScheduler;
7
10
  }): void;
@@ -4,7 +4,15 @@ import { HttpError } from "../http/errors.js";
4
4
  import { is, validate } from "../schemas.js";
5
5
  /** `GET/POST /api/workspaces`, `PATCH /api/workspaces/:wid`. */
6
6
  export function registerWorkspaceRoutes(router, ctx) {
7
- router.get("/api/workspaces", async () => ({ body: await ctx.workspaces.list() }));
7
+ router.get("/api/workspaces", async ({ url }) => {
8
+ // Same semantics as `GET /api/sessions`: archived ones are hidden unless asked for.
9
+ const archived = url.searchParams.get("archived") ?? "false";
10
+ if (archived !== "true" && archived !== "false" && archived !== "all")
11
+ throw new HttpError("validation_failed", "Invalid query parameter", {
12
+ fields: ["archived"],
13
+ });
14
+ return { body: await ctx.workspaces.list(archived) };
15
+ });
8
16
  router.post("/api/workspaces", async ({ req }) => {
9
17
  const { path } = validate(await readJson(req), {
10
18
  path: { check: is.nonEmpty(4096), required: true },
@@ -12,6 +20,9 @@ export function registerWorkspaceRoutes(router, ctx) {
12
20
  if (!isAbsolute(path))
13
21
  throw new HttpError("validation_failed", "path must be absolute", { fields: ["path"] });
14
22
  const canonical = await ctx.workspaces.canonical(path);
23
+ // Opening a folder explicitly is the user asking for it back: it leaves the archive.
24
+ if (ctx.workspaces.archived(canonical))
25
+ ctx.catalog.recordWorkspace(canonical, { archived: false });
15
26
  const opened = await ctx.workspaces.openPath(canonical);
16
27
  return { body: await ctx.workspaces.info(opened.path) };
17
28
  });
@@ -19,13 +30,23 @@ export function registerWorkspaceRoutes(router, ctx) {
19
30
  const patch = validate(await readJson(req), {
20
31
  label: { check: is.nullableString(200) },
21
32
  pinned: { check: is.boolean() },
33
+ archived: { check: is.boolean() },
22
34
  });
23
- const path = await ctx.workspaces.pathOf(params.wid ?? "");
35
+ const id = params.wid ?? "";
36
+ const path = await ctx.workspaces.pathOf(id);
24
37
  if (!path)
25
38
  throw new HttpError("not_found", "Workspace not found");
39
+ if (patch.archived) {
40
+ if (ctx.scheduler.busyWorkspace(id))
41
+ throw new HttpError("runs_active", "Wait for the workspace's runs to finish, then archive it");
42
+ // Sessions are kept (and stay readable); only the idle application is released.
43
+ await ctx.workspaces.close(id);
44
+ }
45
+ // Upserts: a workspace known only from its sessions gets a row here.
26
46
  ctx.catalog.recordWorkspace(path, {
27
47
  ...(patch.label !== undefined ? { label: patch.label?.trim() || null } : {}),
28
48
  ...(patch.pinned !== undefined ? { pinned: patch.pinned } : {}),
49
+ ...(patch.archived !== undefined ? { archived: patch.archived } : {}),
29
50
  });
30
51
  return { body: await ctx.workspaces.info(path) };
31
52
  });
Binary file
@@ -0,0 +1 @@
1
+ ._panel_ses4f_2{z-index:40;border:1px solid var(--border-strong);border-radius:var(--radius-lg);background:var(--panel);width:min(520px,100vw - 32px);max-height:min(62vh,640px);box-shadow:var(--shadow);animation:_rise_ses4f_1 .16s var(--ease);outline:none;flex-direction:column;display:flex;position:fixed;bottom:132px;right:24px}._panel_ses4f_2:focus-visible{box-shadow:var(--shadow), var(--focus)}@keyframes _rise_ses4f_1{0%{opacity:0;transform:translateY(6px)}}@media (prefers-reduced-motion:reduce){._panel_ses4f_2{animation:none}}@media (max-width:720px){._panel_ses4f_2{width:auto;max-height:calc(100dvh - 250px);bottom:176px;left:16px;right:16px}}._head_ses4f_46{border-bottom:1px solid var(--border);align-items:center;gap:8px;padding:12px 12px 10px 14px;display:flex}._badge_ses4f_54{border-radius:var(--radius-sm);background:var(--accent-soft);color:var(--accent);font:600 12px var(--mono);flex:none;padding:3px 7px}._titles_ses4f_63{flex:1;min-width:0}._title_ses4f_63{white-space:nowrap;margin:0;font-size:.95rem;font-weight:600}._eyebrow_ses4f_75{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;margin:1px 0 0;font-size:12px;overflow:hidden}._nav_ses4f_84{align-items:center;gap:2px;display:flex}._position_ses4f_90{min-width:3.2em;font:12px var(--mono);color:var(--muted);text-align:center}._flip_ses4f_97{transform:rotate(180deg)}._body_ses4f_101{padding:12px 16px 14px;overflow-y:auto}._question_ses4f_106{border-left:3px solid var(--accent);white-space:pre-wrap;overflow-wrap:anywhere;margin:0 0 10px;padding-left:10px;font-weight:600}._answer_ses4f_115{overflow-wrap:anywhere}._pending_ses4f_119{color:var(--muted);align-items:center;gap:10px;display:flex}._spinner_ses4f_126{border:2px solid var(--border-strong);border-top-color:var(--accent);border-radius:50%;width:16px;height:16px}._cancel_ses4f_134{border:1px solid var(--border-strong);border-radius:var(--radius-sm);color:var(--text);cursor:pointer;background:0 0;margin-left:auto;padding:4px 12px}._cancel_ses4f_134:hover{background:var(--hover)}._error_ses4f_148{border-radius:var(--radius-sm);background:var(--danger-soft);color:var(--danger);margin:0;padding:8px 10px}._usage_ses4f_156 code{font-family:var(--mono);color:var(--accent-strong)}._usage_ses4f_156 p{color:var(--muted);margin:6px 0 0}._foot_ses4f_166{border-top:1px solid var(--border);font:12px var(--mono);color:var(--faint);padding:8px 16px 10px}
@@ -0,0 +1 @@
1
+ import{_ as e,a as t,b as n,p as r,t as i}from"./jsxRuntime-DnBCdh_Z.js";import{C as a,E as o,T as s,_ as c,d as l,h as u,o as d,p as f,w as p}from"./index-CMMMNWOn.js";var m={panel:`_panel_ses4f_2`,rise:`_rise_ses4f_1`,head:`_head_ses4f_46`,badge:`_badge_ses4f_54`,titles:`_titles_ses4f_63`,title:`_title_ses4f_63`,eyebrow:`_eyebrow_ses4f_75`,nav:`_nav_ses4f_84`,position:`_position_ses4f_90`,flip:`_flip_ses4f_97`,body:`_body_ses4f_101`,question:`_question_ses4f_106`,answer:`_answer_ses4f_115`,pending:`_pending_ses4f_119`,spinner:`_spinner_ses4f_126`,cancel:`_cancel_ses4f_134`,error:`_error_ses4f_148`,usage:`_usage_ses4f_156`,foot:`_foot_ses4f_166`},h=e=>e instanceof HTMLElement&&(e.isContentEditable||[`INPUT`,`TEXTAREA`,`SELECT`].includes(e.tagName));function g(){let g=u.value,_=r(null);if(e(()=>{_.current?.focus()},[g?.sessionId,g?.pending?.question]),e(()=>{let e=e=>{let t=u.value;t&&!e.defaultPrevented&&(e.key===`Escape`?(e.preventDefault(),c()):(e.key===`ArrowLeft`||e.key===`ArrowRight`)&&!h(e.target)&&!e.altKey&&!e.ctrlKey&&!e.metaKey&&(e.preventDefault(),u.value=o(t,e.key===`ArrowLeft`?-1:1)))};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[]),!g)return null;let v=p(g),y=s(g),b=g.pending?.question??g.error?.question??v?.question,x=e=>{u.value&&(u.value=o(u.value,e))};return i(`aside`,{ref:_,class:m.panel,role:`dialog`,"aria-modal":`false`,"aria-labelledby":`btw-title`,tabIndex:-1,children:[i(`header`,{class:m.head,children:[i(`span`,{class:m.badge,"aria-hidden":`true`,children:`btw`}),i(`div`,{class:m.titles,children:[i(`h2`,{id:`btw-title`,class:m.title,children:t(`btw.title`)}),i(`p`,{class:m.eyebrow,children:t(`btw.subtitle`)})]}),g.entries.length&&!g.usage?i(`nav`,{class:m.nav,"aria-label":t(`btw.history`),children:[i(`button`,{type:`button`,class:`icon-btn`,"aria-label":t(`btw.earlier`),title:t(`btw.earlier`),disabled:!y.earlier,onClick:()=>x(-1),children:i(f,{name:`chevronRight`,size:16,class:m.flip})}),i(`span`,{class:m.position,"aria-live":`polite`,children:v?t(`btw.position`,{n:g.index+1,total:g.entries.length}):``}),i(`button`,{type:`button`,class:`icon-btn`,"aria-label":t(`btw.later`),title:t(`btw.later`),disabled:!y.later,onClick:()=>x(1),children:i(f,{name:`chevronRight`,size:16})})]}):null,v?i(l,{text:()=>v.answer,label:t(`btw.copy`)}):null,i(`button`,{type:`button`,class:`icon-btn`,"aria-label":t(`common.close`),title:t(`common.close`),onClick:()=>c(),children:i(f,{name:`x`,size:16})})]}),i(`div`,{class:m.body,children:g.usage?i(`div`,{class:m.usage,children:[i(`code`,{children:a}),i(`p`,{children:t(`btw.usage`)})]}):i(n,{children:[b?i(`p`,{class:m.question,children:b}):null,g.pending?i(`div`,{class:m.pending,role:`status`,children:[i(`span`,{class:`${m.spinner} spin`,"aria-hidden":`true`}),i(`span`,{children:t(`btw.thinking`)}),i(`button`,{type:`button`,class:m.cancel,onClick:()=>c(),children:t(`common.cancel`)})]}):g.error?i(`p`,{class:m.error,role:`alert`,children:g.error.message}):v?i(`div`,{class:m.answer,children:i(d,{text:v.answer})}):null]})}),v?i(`footer`,{class:m.foot,children:[t(`btw.tokens`,{model:v.model,input:v.usage.input.toLocaleString(),output:v.usage.output.toLocaleString()}),v.truncated?` · ${t(`btw.truncated`)}`:``]}):null]})}export{g as BtwPanel};
@@ -0,0 +1 @@
1
+ import{_ as e,a as t,b as n,g as r,i,n as a,p as o,r as s,t as c}from"./jsxRuntime-DnBCdh_Z.js";import{S as l,a as u,b as d,d as f,g as p,i as m,m as h,p as g,r as _,t as v,v as y,x as b,y as x}from"./index-CMMMNWOn.js";var S={backdrop:`_backdrop_wp9h7_1`,dialog:`_dialog_wp9h7_11`,nav:`_nav_wp9h7_23`,heading:`_heading_wp9h7_29`,navItem:`_navItem_wp9h7_35`,content:`_content_wp9h7_58`,topBar:`_topBar_wp9h7_64`,outline:`_outline_wp9h7_77`,popover:`_popover_wp9h7_91`,popoverHead:`_popoverHead_wp9h7_104`,paths:`_paths_wp9h7_110`,pathRow:`_pathRow_wp9h7_118`,path:`_path_wp9h7_110`,intro:`_intro_wp9h7_135`,pageTitle:`_pageTitle_wp9h7_139`,lead:`_lead_wp9h7_145`,about:`_about_wp9h7_151`,aboutLogo:`_aboutLogo_wp9h7_155`,aboutDescription:`_aboutDescription_wp9h7_162`,aboutAttribution:`_aboutAttribution_wp9h7_171`,aboutLink:`_aboutLink_wp9h7_177`,scope:`_scope_wp9h7_188`,sectionTitle:`_sectionTitle_wp9h7_197`,fieldset:`_fieldset_wp9h7_203`,legend:`_legend_wp9h7_209`,choices:`_choices_wp9h7_214`,choice:`_choice_wp9h7_214`,note:`_note_wp9h7_240`,cardText:`_cardText_wp9h7_247`,facts:`_facts_wp9h7_248`,errorText:`_errorText_wp9h7_254`,tabs:`_tabs_wp9h7_259`,tab:`_tab_wp9h7_259`,search:`_search_wp9h7_281`,listTitle:`_listTitle_wp9h7_307`,count:`_count_wp9h7_313`,grid:`_grid_wp9h7_319`,card:`_card_wp9h7_247`,cardHead:`_cardHead_wp9h7_339`,cardName:`_cardName_wp9h7_351`,chevron:`_chevron_wp9h7_361`,cardBody:`_cardBody_wp9h7_366`,diagnostic:`_diagnostic_wp9h7_393`,toggleRow:`_toggleRow_wp9h7_399`,pill:`_pill_wp9h7_409`,pillDot:`_pillDot_wp9h7_437`,switch:`_switch_wp9h7_444`,knob:`_knob_wp9h7_468`,rows:`_rows_wp9h7_484`,row:`_row_wp9h7_484`,rowMain:`_rowMain_wp9h7_510`,rowTitle:`_rowTitle_wp9h7_515`,rowActions:`_rowActions_wp9h7_526`,meta:`_meta_wp9h7_533`,linkButton:`_linkButton_wp9h7_539`,instructions:`_instructions_wp9h7_550`,primary:`_primary_wp9h7_561`,secondary:`_secondary_wp9h7_562`,banner:`_banner_wp9h7_587`,confirm:`_confirm_wp9h7_602`,confirmTitle:`_confirmTitle_wp9h7_610`,checkRow:`_checkRow_wp9h7_619`,actions:`_actions_wp9h7_627`,callout:`_callout_wp9h7_633`,stack:`_stack_wp9h7_643`,settingList:`_settingList_wp9h7_648`,settingRow:`_settingRow_wp9h7_655`,settingLabel:`_settingLabel_wp9h7_664`,settingKey:`_settingKey_wp9h7_671`,input:`_input_wp9h7_677`,credential:`_credential_wp9h7_693`,credentialForm:`_credentialForm_wp9h7_704`,profileForm:`_profileForm_wp9h7_716`,formRow:`_formRow_wp9h7_726`,addButton:`_addButton_wp9h7_738`},C=e=>e instanceof Error?e.message:String(e);function w(){let e=y.value;if(e)return{id:e.workspaceId,path:e.workspace};let t=l.value.workspaces[0];return t?{id:t.id,path:t.path}:void 0}function T(t,n,i=[]){let[a,o]=r({loading:!!t}),[s,c]=r(0),l=i.map(e=>p.value[e]??0).join(`,`);return e(()=>{if(!t){o({loading:!1});return}let e=!0;return o(e=>({...e,loading:!0})),t().then(t=>e&&o({data:t,loading:!1}),t=>e&&o({error:C(t),loading:!1})),()=>{e=!1}},[...n,l,s]),{...a,reload:()=>c(e=>e+1),set:e=>o({data:e,loading:!1})}}function E(e){return c(`button`,{type:`button`,role:`switch`,class:S.switch,"aria-checked":e.checked,"aria-label":e.label,"aria-busy":e.busy||void 0,disabled:e.disabled||e.busy,onClick:()=>e.onChange(!e.checked),children:c(`span`,{class:S.knob})})}function D(e){return c(`span`,{class:S.pill,"data-tone":e.tone,children:[e.tone===`ok`?c(`span`,{class:S.pillDot,"aria-hidden":`true`}):null,e.children]})}function O(e){return c(`fieldset`,{class:S.fieldset,children:[c(`legend`,{class:S.legend,children:e.legend}),c(`div`,{class:S.choices,children:e.options.map(t=>c(`label`,{class:S.choice,children:[c(`input`,{type:`radio`,name:e.legend,checked:e.value===t.id,onChange:()=>e.onChange(t.id)}),c(`span`,{children:t.label})]},t.id))})]})}function k(e){return e.error?c(`p`,{class:S.errorText,role:`alert`,children:e.error}):e.loading?c(`p`,{class:S.note,children:t(`common.loading`)}):e.empty?c(`p`,{class:S.note,children:t(e.empty)}):null}function A(e){return c(`header`,{class:S.intro,children:[c(`h3`,{class:S.pageTitle,children:e.title}),e.body?c(`p`,{class:S.lead,children:e.body}):null,e.workspace?c(`p`,{class:S.scope,title:e.workspace,children:t(`settings.workspace`,{path:e.workspace})}):null]})}function j(e){return c(`label`,{class:S.search,children:[c(`svg`,{width:`17`,height:`17`,viewBox:`0 0 24 24`,"aria-hidden":`true`,focusable:`false`,children:c(`path`,{d:`M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14ZM20 20l-4-4`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.8`,"stroke-linecap":`round`})}),c(`input`,{type:`search`,placeholder:e.label,"aria-label":e.label,value:e.value,onInput:t=>e.onInput(t.target.value)})]})}var M=`https://github.com/GustavoGutierrez/alisio`;function N(){return c(`section`,{class:S.about,children:[c(A,{title:t(`settings.about`)}),c(`img`,{class:S.aboutLogo,src:`/alisio-wordmark.png`,alt:`Alisio`,width:320,height:150}),c(`p`,{class:S.aboutDescription,children:t(`about.description`)}),c(`p`,{class:S.aboutAttribution,children:`Gustavo Gutiérrez · Bogotá, Colombia`}),c(`a`,{class:S.aboutLink,href:M,target:`_blank`,rel:`noopener noreferrer`,"aria-label":t(`about.repositoryLabel`),children:[c(g,{name:`github`,size:19}),t(`about.repository`)]})]})}function P(){let e=w(),[i,a]=r(),o=T(e?()=>h.agents(e.id):void 0,[e?.id],[`agents`,`plugins`]),s=y.value,l=s?.agent??o.data?.find(e=>e.default)?.id;return c(n,{children:[c(A,{title:t(`settings.agents`),body:t(`agents.lead`),workspace:e?.path}),c(k,{loading:o.loading&&!o.data,error:o.error,empty:e?void 0:`settings.noWorkspace`}),c(`ul`,{class:S.rows,children:(o.data??[]).map(e=>c(`li`,{class:S.row,"data-current":e.id===l,children:[c(`div`,{class:S.rowMain,children:[c(`div`,{class:S.rowTitle,children:[c(`span`,{class:S.cardName,children:e.name}),c(D,{tone:`off`,children:t(`agents.source.${e.source}`)}),e.readOnly?c(D,{tone:`warn`,children:t(`agents.readOnly`)}):null,e.default?c(D,{tone:`ok`,children:t(`agents.default`)}):null]}),c(`p`,{class:S.cardText,children:e.description}),e.model?c(`p`,{class:S.meta,children:t(`agents.model`,{model:e.model})}):null,e.instructions?c(n,{children:[c(`button`,{type:`button`,class:S.linkButton,"aria-expanded":i===e.id,onClick:()=>a(i===e.id?void 0:e.id),children:[c(g,{name:i===e.id?`chevronDown`:`chevronRight`,size:14}),t(`agents.instructions`)]}),i===e.id?c(`pre`,{class:S.instructions,children:e.instructions}):null]}):null]}),c(`div`,{class:S.rowActions,children:s&&!s.parentId?e.id===l?c(`span`,{class:S.meta,children:t(`agents.inUse`)}):c(`button`,{type:`button`,class:S.secondary,onClick:()=>void x({agent:e.id}),children:t(`agents.use`)}):null})]},e.id))})]})}function F(){return c(n,{children:[c(A,{title:t(`settings.appearance`),body:t(`appearance.lead`)}),c(O,{legend:t(`settings.theme`),value:u.value,options:[`dark`,`light`,`system`].map(e=>({id:e,label:t(`theme.${e}`)})),onChange:m}),c(O,{legend:t(`settings.density`),value:v.value,options:[`compact`,`detailed`].map(e=>({id:e,label:t(`density.${e}`)})),onChange:_})]})}var I=/^(tui|agents)\./;function L(e){let{setting:n}=e,[i,a]=r(),[o,s]=r(!1),l=async t=>{s(!0);try{await e.onSave(t),a(void 0)}finally{s(!1)}},u=t(`setting.${n.key}`),d=`setting-${n.key}`,f=()=>{if(i!==void 0){if(n.kind===`number`){let e=Number(i);if(i.trim()===``||!Number.isFinite(e))return a(void 0);l(e)}else l(i.trim()===``?null:i)}};return c(`li`,{class:S.settingRow,children:[c(`label`,{class:S.settingLabel,for:d,children:[c(`span`,{children:u}),c(`code`,{class:S.settingKey,children:n.key})]}),n.kind===`boolean`?c(E,{checked:n.value===!0,label:u,disabled:e.disabled,busy:o,onChange:e=>void l(e)}):n.kind===`enum`?c(`select`,{id:d,class:S.input,disabled:e.disabled||o,value:typeof n.value==`string`?n.value:``,onChange:e=>{let t=e.target.value;l(t===``?null:t)},children:[c(`option`,{value:``,children:t(`settings.default`)}),(n.options??[]).map(e=>c(`option`,{value:e,children:e},e))]}):c(`input`,{id:d,class:S.input,type:n.kind===`number`?`number`:`text`,disabled:e.disabled||o,value:i??(n.value===void 0?``:String(n.value)),onInput:e=>a(e.target.value),onBlur:f,onKeyDown:e=>{e.key===`Enter`&&f(),e.key===`Escape`&&i!==void 0&&(e.stopPropagation(),a(void 0))}})]})}function R(){let e=w(),r=T(e?()=>h.settings(e.id):void 0,[e?.id]),o=async(t,n)=>{if(e&&r.data)try{await h.setSetting(e.id,t,n),r.set({...r.data,settings:r.data.settings.map(e=>e.key===t?{...e,...n===null?{value:void 0}:{value:n}}:e)})}catch(e){throw b(C(e)),e}},l=(r.data?.settings??[]).filter(e=>!I.test(e.key));return c(n,{children:[c(A,{title:t(`settings.general`)}),c(O,{legend:t(`settings.language`),value:s.value,options:a.map(e=>({id:e,label:t(`language.${e}`)})),onChange:i}),c(`h4`,{class:S.sectionTitle,children:t(`settings.agentSettings`)}),c(`p`,{class:S.note,children:[t(`settings.agentSettingsLead`),r.data?c(n,{children:[` `,c(`code`,{children:r.data.settingsPath})]}):null]}),c(k,{loading:r.loading&&!r.data,error:r.error,empty:e?void 0:`settings.noWorkspace`}),r.data?.readOnly?c(`p`,{class:S.note,children:t(`settings.readOnly`)}):null,c(`ul`,{class:S.settingList,children:l.map(e=>c(L,{setting:e,disabled:!!r.data?.readOnly,onSave:t=>o(e.key,t)},e.key))})]})}var z={connected:`ok`,connecting:`warn`,failed:`danger`,"needs-authentication":`warn`,"restart-required":`warn`};function B(e){let[n,i]=r(!1);return c(`div`,{class:S.confirm,role:`alertdialog`,"aria-labelledby":`mcp-consent-title`,children:[c(`h4`,{id:`mcp-consent-title`,class:S.confirmTitle,children:[c(g,{name:`alert`,size:17}),t(`mcp.consentTitle`)]}),c(`p`,{class:S.cardText,children:t(`mcp.consentBody`)}),c(`label`,{class:S.checkRow,children:[c(`input`,{type:`checkbox`,checked:n,onChange:e=>i(e.target.checked)}),c(`span`,{children:t(`mcp.remember`)})]}),c(`div`,{class:S.actions,children:[c(`button`,{type:`button`,class:S.secondary,onClick:e.onCancel,children:t(`common.cancel`)}),c(`button`,{type:`button`,class:S.primary,onClick:()=>e.onGrant(n),children:t(`mcp.grant`)})]})]})}function V(){let e=w(),[i,a]=r(!1),[o,s]=r(),l=T(e?()=>h.mcp(e.id):void 0,[e?.id],[`mcp`]),u=l.data,d=e=>{u&&l.set({...u,servers:u.servers.map(t=>t.name===e.name?e:t)})},f=async(t,n,r)=>{if(e){s(t.name);try{let i=await h.setMcp(e.id,t.name,n,r);d(i),r&&i.status!==`connected`&&i.diagnostic&&b(i.diagnostic)}catch(e){b(C(e))}finally{s(void 0)}}},p=async t=>{if(e){a(!1);try{l.set(await h.mcpConsent(e.id,t))}catch(e){b(C(e))}}},m=u?.permission===`granted`;return c(n,{children:[c(A,{title:t(`settings.mcp`),body:t(`mcp.lead`),workspace:e?.path}),u?c(`div`,{class:S.banner,"data-tone":m?`ok`:`warn`,children:[c(`span`,{children:u.permission===`read-only`?t(`mcp.readOnly`):m?u.persisted?t(`mcp.grantedPersisted`):t(`mcp.granted`):t(`mcp.notGranted`)}),u.permission===`not-granted`&&!i?c(`button`,{type:`button`,class:S.primary,onClick:()=>a(!0),children:t(`mcp.grant`)}):null]}):null,i?c(B,{onCancel:()=>a(!1),onGrant:e=>void p(e)}):null,c(k,{loading:l.loading&&!u,error:l.error,empty:e?u&&!u.servers.length?`mcp.none`:void 0:`settings.noWorkspace`}),c(`ul`,{class:S.rows,children:(u?.servers??[]).map(e=>c(`li`,{class:S.row,children:[c(`div`,{class:S.rowMain,children:[c(`div`,{class:S.rowTitle,children:[c(`span`,{class:S.cardName,children:e.displayName}),c(D,{tone:z[e.status]??`off`,children:t(`mcp.status`,{status:e.status})})]}),c(`p`,{class:S.meta,children:t(`mcp.meta`,{transport:e.transport,source:e.source,tools:e.counts.tools,resources:e.counts.resources,prompts:e.counts.prompts})}),e.diagnostic?c(`p`,{class:S.diagnostic,children:e.diagnostic}):null]}),c(`div`,{class:S.rowActions,children:[e.enabled&&e.status!==`connected`?c(`button`,{type:`button`,class:S.secondary,disabled:!m||o===e.name,title:m?void 0:t(`mcp.needsGrant`),onClick:()=>void f(e,!0,!0),children:t(`mcp.connect`)}):null,c(E,{checked:e.enabled,label:t(`plugins.enableNamed`,{name:e.displayName}),disabled:u?.permission===`read-only`,busy:o===e.name,onChange:t=>void f(e,t,!1)})]})]},e.name))})]})}var H={apiKey:`API key`,bearerToken:`Bearer token`};function U(e){return e.configured?e.source===`env`?t(`models.credential.env`):e.tail?t(`models.credential.storedTail`,{tail:e.tail}):t(`models.credential.stored`):t(`models.credential.missing`)}function W(e){let[n,i]=r(``),[a,o]=r(!1),s=H[e.field]??e.field,l=`cred-${e.profile}-${e.field}`,u=async()=>{let r=n.trim();if(r){o(!0);try{let n=await h.setCredentials(e.profile,{[e.field]:r});e.onChange({...n,source:`file`}),i(``),b(t(`models.credential.saved`))}catch(e){b(C(e))}finally{o(!1)}}},d=async()=>{o(!0);try{await h.deleteCredentials(e.profile),e.onChange({configured:!1})}catch(e){b(C(e))}finally{o(!1)}};return c(`div`,{class:S.credential,children:[c(`label`,{for:l,class:S.settingLabel,children:[c(`span`,{children:s}),c(`span`,{class:S.meta,"data-configured":e.status.configured,children:U(e.status)})]}),c(`form`,{class:S.credentialForm,onSubmit:e=>{e.preventDefault(),u()},children:[c(`input`,{id:l,class:S.input,type:`password`,autocomplete:`off`,spellcheck:!1,placeholder:e.status.configured?t(`models.credential.replace`):t(`models.credential.enter`),value:n,disabled:a,onInput:e=>i(e.target.value)}),c(`button`,{type:`submit`,class:S.primary,disabled:a||!n.trim(),children:t(`models.credential.save`)}),e.status.configured&&e.status.source===`file`?c(`button`,{type:`button`,class:S.secondary,disabled:a,onClick:()=>void d(),children:t(`models.credential.remove`)}):null]})]})}function G(e){let[n,i]=r(e.initial?.name??``),[a,o]=r(e.initial?.provider??e.types[0]?.id??``),[s,l]=r(e.initial?.model??``),[u,d]=r(e.initial?.values??{}),[f,p]=r(!1),m=(e.types.find(e=>e.id===a)?.fields??[]).filter(e=>e.kind!==`secret`),g=(e,t)=>u[e]??t,_=async()=>{p(!0);try{let t={};for(let e of m){let n=g(e.key,e.defaultValue);n!==void 0&&n!==``&&(t[e.key]=n)}e.onSaved(await h.saveProfile(e.workspace,n.trim(),{provider:a,values:t,model:s}))}catch(e){b(C(e))}finally{p(!1)}};return c(`form`,{class:S.profileForm,onSubmit:e=>{e.preventDefault(),_()},children:[c(`label`,{class:S.formRow,children:[c(`span`,{children:t(`models.form.name`)}),c(`input`,{class:S.input,required:!0,pattern:`[A-Za-z0-9][A-Za-z0-9._\\-]{0,63}`,disabled:!!e.initial,value:n,onInput:e=>i(e.target.value)})]}),c(`label`,{class:S.formRow,children:[c(`span`,{children:t(`models.form.type`)}),c(`select`,{class:S.input,value:a,onChange:e=>o(e.target.value),children:e.types.map(e=>c(`option`,{value:e.id,children:e.name},e.id))})]}),m.map(e=>c(`label`,{class:S.formRow,title:e.description,children:[c(`span`,{children:e.label}),e.kind===`select`?c(`select`,{class:S.input,value:String(g(e.key,e.defaultValue)??``),onChange:t=>d({...u,[e.key]:t.target.value}),children:(e.options??[]).map(e=>c(`option`,{value:e.value,children:e.label},e.value))}):e.kind===`boolean`?c(`input`,{type:`checkbox`,checked:g(e.key,e.defaultValue)===!0,onChange:t=>d({...u,[e.key]:t.target.checked})}):c(`input`,{class:S.input,type:e.kind===`url`?`url`:`text`,required:e.required,value:String(g(e.key,e.defaultValue)??``),onInput:t=>d({...u,[e.key]:t.target.value})})]},e.key)),c(`label`,{class:S.formRow,children:[c(`span`,{children:t(`models.form.model`)}),c(`input`,{class:S.input,required:!0,value:s,onInput:e=>l(e.target.value)})]}),c(`p`,{class:S.note,children:t(`models.form.secretsNote`)}),c(`div`,{class:S.actions,children:[c(`button`,{type:`button`,class:S.secondary,onClick:e.onCancel,children:t(`common.cancel`)}),c(`button`,{type:`submit`,class:S.primary,disabled:f,children:t(`models.form.save`)})]})]})}function K(e){let{profile:i,overview:a}=e,[o,s]=r(!1),[l,u]=r(i.model),[d,f]=r(!1),p=a.types.find(e=>e.id===i.provider),m=a.current?.profile===i.name,_=async()=>{f(!0);try{let{changed:n}=await h.activateProvider(e.workspace,i.name,l);b(n?t(`models.activated`,{name:i.name}):t(`models.unchanged`)),e.onActivated()}catch(e){b(C(e))}finally{f(!1)}},v=e.catalog?.models??[];return c(`li`,{class:S.row,"data-current":m,children:c(`div`,{class:S.rowMain,children:[c(`div`,{class:S.rowTitle,children:[c(`span`,{class:S.cardName,children:i.name}),c(D,{tone:`off`,children:p?.name??i.provider}),i.active?c(D,{tone:`ok`,children:t(`models.activeGlobal`)}):null,m?c(D,{tone:`ok`,children:t(`models.current`)}):null,c(`button`,{type:`button`,class:S.linkButton,"aria-expanded":o,onClick:()=>s(!o),children:[c(g,{name:`edit`,size:14}),t(`models.edit`)]})]}),o?c(G,{types:a.types,initial:i,workspace:e.workspace,onCancel:()=>s(!1),onSaved:t=>{s(!1),e.onChange(t)}}):c(`dl`,{class:S.facts,children:[c(`dt`,{children:t(`models.form.model`)}),c(`dd`,{children:i.model}),Object.entries(i.values).map(([e,t])=>c(n,{children:[c(`dt`,{children:p?.fields.find(t=>t.key===e)?.label??e}),c(`dd`,{children:String(t)})]},e))]}),Object.entries(i.credentials).map(([t,n])=>c(W,{profile:i.name,field:t,status:n,onChange:n=>e.onChange({...i,credentials:{...i.credentials,[t]:n}})},t)),c(`form`,{class:S.credentialForm,onSubmit:e=>{e.preventDefault(),_()},children:[v.length?c(`select`,{class:S.input,"aria-label":t(`models.form.model`),value:l,onChange:e=>u(e.target.value),children:[v.some(e=>e.id===l)?null:c(`option`,{value:l,children:l}),v.map(e=>c(`option`,{value:e.id,children:e.name??e.id},e.id))]}):c(`input`,{class:S.input,"aria-label":t(`models.form.model`),value:l,onInput:e=>u(e.target.value)}),c(`button`,{type:`submit`,class:S.secondary,disabled:d||!l.trim(),children:t(`models.activate`)}),e.catalog?.unavailable?c(`span`,{class:S.meta,children:t(`composer.modelsUnavailable`)}):null]})]})})}function q(){let e=w(),[i,a]=r(!1),o=T(e?()=>h.providers(e.id):void 0,[e?.id],[`models`]),s=T(e?()=>h.providerModels(e.id).catch(()=>[]):void 0,[e?.id],[`models`]),l=o.data,u=e=>{if(!l)return;let t=l.profiles.some(t=>t.name===e.name);o.set({...l,profiles:t?l.profiles.map(t=>t.name===e.name?e:t):[...l.profiles,e]})};return c(n,{children:[c(A,{title:t(`settings.models`),body:t(`models.lead`),workspace:e?.path}),l?.current?c(`p`,{class:S.banner,"data-tone":`ok`,children:t(`models.running`,{provider:l.current.provider,model:l.current.model,profile:l.current.profile??`—`})}):null,c(k,{loading:o.loading&&!l,error:o.error,empty:e?l&&!l.profiles.length?`models.none`:void 0:`settings.noWorkspace`}),c(`ul`,{class:S.rows,children:(l?.profiles??[]).map(t=>c(K,{profile:t,overview:l,catalog:s.data?.find(e=>e.profile===t.name),workspace:e?.id??``,onChange:u,onActivated:()=>o.reload()},t.name))}),e&&l?.types.length?i?c(G,{types:l.types,workspace:e.id,onCancel:()=>a(!1),onSaved:e=>{a(!1),u(e)}}):c(`button`,{type:`button`,class:`${S.secondary} ${S.addButton}`,onClick:()=>a(!0),children:t(`models.add`)}):null]})}var J={active:`ok`,inactive:`off`,failed:`danger`,"restart-required":`warn`};function Y(e){return e.status===`failed`?t(`plugins.status.failed`):e.status===`restart-required`?t(`plugins.status.restart`):e.enabled?t(`plugins.status.enabled`):t(`plugins.status.disabled`)}function X(e){let{plugin:i}=e,[a,o]=r(!1),s=`plugin-${i.id}`;return c(`li`,{class:S.card,"data-open":a,children:[c(`button`,{type:`button`,class:S.cardHead,"aria-expanded":a,"aria-controls":s,onClick:()=>o(!a),children:[c(`span`,{class:S.cardName,title:i.name,children:i.name}),c(D,{tone:J[i.status],children:Y(i)}),c(g,{name:a?`chevronDown`:`chevronRight`,size:16,class:S.chevron})]}),a?c(`div`,{id:s,class:S.cardBody,children:[i.description?c(`p`,{class:S.cardText,children:i.description}):null,c(`dl`,{class:S.facts,children:[c(`dt`,{children:t(`plugins.id`)}),c(`dd`,{children:c(`code`,{children:i.id})}),i.version?c(n,{children:[c(`dt`,{children:t(`plugins.version`)}),c(`dd`,{children:i.version})]}):null,c(`dt`,{children:t(`plugins.source`)}),c(`dd`,{children:i.builtin?t(`plugins.builtin`):i.source}),i.categories.length?c(n,{children:[c(`dt`,{children:t(`plugins.categories`)}),c(`dd`,{children:i.categories.join(`, `)})]}):null,c(`dt`,{children:t(`plugins.tools`)}),c(`dd`,{children:i.tools.length?i.tools.join(`, `):`—`}),c(`dt`,{children:t(`plugins.commands`)}),c(`dd`,{children:i.commands.length?i.commands.map(e=>`/${e}`).join(`, `):`—`})]}),i.diagnostic?c(`p`,{class:S.diagnostic,children:i.diagnostic}):null,c(`div`,{class:S.toggleRow,children:[c(`span`,{children:t(`plugins.enable`)}),c(E,{checked:i.enabled,label:t(`plugins.enableNamed`,{name:i.name}),disabled:!i.manageable,busy:e.busy,onChange:e.onToggle})]})]}):null]})}function Z(){let e=w(),[i,a]=r(`list`),[o,s]=r(``),[l,u]=r(),d=T(e?()=>h.plugins(e.id):void 0,[e?.id],[`plugins`]),f=T(e&&i===`configuration`?()=>h.settings(e.id):void 0,[e?.id,i]),p=async(n,r)=>{if(e){u(n.id);try{let i=await h.setPlugin(e.id,n.id,r);d.set((d.data??[]).map(e=>e.id===i.id?i:e)),i.status===`restart-required`&&b(t(`plugins.deferred`))}catch(e){b(C(e))}finally{u(void 0)}}},m=o.trim().toLowerCase(),_=(d.data??[]).filter(e=>!m||e.name.toLowerCase().includes(m)||e.id.toLowerCase().includes(m)||e.description.toLowerCase().includes(m));return c(n,{children:[c(A,{title:t(`settings.plugins`),body:t(`plugins.lead`),workspace:e?.path}),c(`div`,{class:S.tabs,role:`tablist`,children:[`configuration`,`list`].map(e=>c(`button`,{type:`button`,role:`tab`,class:S.tab,"aria-selected":i===e,onClick:()=>a(e),children:t(e===`list`?`plugins.tab.list`:`plugins.tab.configuration`)},e))}),i===`configuration`?c(`div`,{class:S.stack,children:[c(`p`,{class:S.callout,children:[c(g,{name:`shield`,size:16}),c(`span`,{children:t(`plugins.notSandboxed`)})]}),c(`p`,{class:S.note,children:t(`plugins.howToInstall`)}),c(`p`,{class:S.note,children:t(`plugins.applyNote`)}),f.data?c(`p`,{class:S.note,children:[t(`plugins.projectFile`),` `,c(`code`,{children:f.data.configPath})]}):null]}):c(n,{children:[c(j,{value:o,label:t(`plugins.search`),onInput:s}),c(`h4`,{class:S.listTitle,children:[t(`plugins.tab.list`),` `,c(`span`,{class:S.count,children:_.length})]}),c(k,{loading:d.loading&&!d.data,error:d.error,empty:e?d.data&&!_.length?`plugins.none`:void 0:`settings.noWorkspace`}),c(`ul`,{class:S.grid,children:_.map(e=>c(X,{plugin:e,busy:l===e.id,onToggle:t=>void p(e,t)},e.id))})]})]})}function Q(){let e=w(),[i,a]=r(``),[o,s]=r(),l=T(e?()=>h.skills(e.id):void 0,[e?.id],[`skills`]),u=async(t,n)=>{if(e){s(t.id);try{let r=await h.setSkill(e.id,t.id,n);l.set((l.data??[]).map(e=>e.id===r.id&&e.effective?r:e))}catch(e){b(C(e))}finally{s(void 0)}}},d=i.trim().toLowerCase(),f=(l.data??[]).filter(e=>!d||e.displayId.toLowerCase().includes(d)||e.description.toLowerCase().includes(d));return c(n,{children:[c(A,{title:t(`settings.skills`),body:t(`skills.lead`),workspace:e?.path}),c(j,{value:i,label:t(`skills.search`),onInput:a}),c(k,{loading:l.loading&&!l.data,error:l.error,empty:e?l.data&&!f.length?`skills.none`:void 0:`settings.noWorkspace`}),c(`ul`,{class:S.rows,children:f.map(e=>c(`li`,{class:S.row,"data-muted":!e.effective,children:[c(`div`,{class:S.rowMain,children:[c(`div`,{class:S.rowTitle,children:[c(`span`,{class:S.cardName,children:e.displayId}),c(D,{tone:e.enabled&&e.effective?`ok`:`off`,children:e.effective?e.enabled?t(`plugins.status.enabled`):t(`plugins.status.disabled`):t(`skills.shadowed`)})]}),c(`p`,{class:S.cardText,children:e.description}),c(`p`,{class:S.meta,children:[t(`skills.meta`,{scope:e.owner?`${e.scope} · ${e.owner.name}`:e.scope,tokens:e.approximateTokens}),e.shadowedBy?` · ${t(`skills.shadowedBy`,{id:e.shadowedBy})}`:``,e.locked?` · ${t(`skills.locked`)}`:``]})]}),c(E,{checked:e.enabled,label:t(`plugins.enableNamed`,{name:e.displayId}),disabled:!e.effective||!e.manageable||e.locked,busy:o===e.id,onChange:t=>void u(e,t)})]},`${e.id}:${e.source}`))})]})}var $=[{id:`general`,icon:`settings`},{id:`models`,icon:`database`},{id:`plugins`,icon:`sliders`},{id:`skills`,icon:`book`},{id:`mcp`,icon:`plug`},{id:`agents`,icon:`users`},{id:`appearance`,icon:`palette`},{id:`about`,icon:`info`}],ee=`button:not(:disabled), input:not(:disabled), select:not(:disabled), [tabindex='0']`;function te(e){let n=w(),r=T(n?()=>h.settings(n.id):void 0,[n?.id]),i=r.data?[{label:t(`config.effective`),path:r.data.configPath},{label:t(`config.settings`),path:r.data.settingsPath},{label:t(`config.providers`),path:r.data.providersPath}]:[];return c(`div`,{class:S.popover,role:`dialog`,"aria-label":t(`config.open`),children:[c(`div`,{class:S.popoverHead,children:[c(`strong`,{children:t(`config.open`)}),c(`button`,{type:`button`,class:`icon-btn`,"aria-label":t(`common.close`),onClick:e.onClose,children:c(g,{name:`x`,size:16})})]}),c(`p`,{class:S.note,children:t(`config.lead`)}),n?null:c(`p`,{class:S.note,children:t(`settings.noWorkspace`)}),r.error?c(`p`,{class:S.errorText,children:r.error}):null,c(`ul`,{class:S.paths,children:i.map(e=>c(`li`,{children:[c(`span`,{class:S.meta,children:e.label}),c(`span`,{class:S.pathRow,children:[c(`code`,{class:S.path,children:e.path}),c(f,{text:()=>e.path,label:t(`config.copy`)})]})]},e.label))}),r.data&&!r.data.trusted?c(`p`,{class:S.note,children:t(`config.untrusted`)}):null]})}function ne(){let[n,i]=r(`general`),[a,s]=r(!1),l=o(null);e(()=>{let e=document.activeElement;return l.current?.querySelector(`nav button`)?.focus(),()=>e?.focus()},[]);let u=()=>{d.value=!1};return c(`div`,{class:S.backdrop,onMouseDown:e=>{e.target===e.currentTarget&&u()},children:c(`div`,{ref:l,class:S.dialog,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`settings-title`,onKeyDown:e=>{if(e.key===`Escape`&&(a?s(!1):u()),e.key===`Tab`){let t=[...l.current?.querySelectorAll(ee)??[]],n=t[0],r=t.at(-1);e.shiftKey&&document.activeElement===n?(e.preventDefault(),r?.focus()):!e.shiftKey&&document.activeElement===r&&(e.preventDefault(),n?.focus())}},children:[c(`nav`,{class:S.nav,"aria-label":t(`settings.title`),children:[c(`h2`,{id:`settings-title`,class:S.heading,children:t(`settings.title`)}),$.map(({id:e,icon:r})=>c(`button`,{type:`button`,class:S.navItem,"aria-current":n===e?`page`:void 0,onClick:()=>i(e),children:[c(g,{name:r,size:17}),t(`settings.${e}`)]},e))]}),c(`div`,{class:S.content,children:[c(`div`,{class:S.topBar,children:[c(`button`,{type:`button`,class:S.outline,"aria-expanded":a,onClick:()=>s(!a),children:t(`config.open`)}),c(`button`,{type:`button`,class:`icon-btn`,"aria-label":t(`common.close`),onClick:u,children:c(g,{name:`x`,size:18})})]}),a?c(te,{onClose:()=>s(!1)}):null,c(n===`general`?R:n===`models`?q:n===`plugins`?Z:n===`skills`?Q:n===`mcp`?V:n===`agents`?P:n===`appearance`?F:N,{})]})]})})}export{ne as SettingsModal};
@@ -0,0 +1 @@
1
+ ._backdrop_wp9h7_1{z-index:80;background:#0000008c;place-items:center;padding:16px;display:grid;position:fixed;inset:0}._dialog_wp9h7_11{border:1px solid var(--border);background:var(--panel);width:min(1040px,100%);height:min(760px,92vh);box-shadow:var(--shadow);border-radius:22px;grid-template-columns:230px 1fr;display:grid;overflow:hidden}._nav_wp9h7_23{border-right:1px solid var(--border);padding:26px 14px;overflow-y:auto}._heading_wp9h7_29{margin:0 10px 18px;font-size:20px;font-weight:600}._navItem_wp9h7_35{border-radius:var(--radius);text-align:left;background:0 0;border:0;align-items:center;gap:10px;width:100%;height:40px;padding:0 12px;font-size:15px;display:flex}._navItem_wp9h7_35:hover{background:var(--hover)}._navItem_wp9h7_35[aria-current=page]{background:var(--raised);font-weight:550}._content_wp9h7_58{padding:20px 32px 32px;position:relative;overflow-y:auto}._topBar_wp9h7_64{z-index:2;background:var(--panel);justify-content:flex-end;align-items:center;gap:8px;margin:-20px -32px 0;padding:16px 20px 8px;display:flex;position:sticky;top:-20px}._outline_wp9h7_77{border:1px solid var(--border-strong);background:0 0;border-radius:999px;height:34px;padding:0 16px;font-size:14px}._outline_wp9h7_77:hover,._outline_wp9h7_77[aria-expanded=true]{background:var(--hover)}._popover_wp9h7_91{z-index:3;border:1px solid var(--border);border-radius:var(--radius);background:var(--raised);width:min(560px,100% - 48px);box-shadow:var(--shadow);padding:14px 16px;position:absolute;top:56px;right:24px}._popoverHead_wp9h7_104{justify-content:space-between;align-items:center;display:flex}._paths_wp9h7_110{gap:10px;margin:8px 0 0;padding:0;list-style:none;display:grid}._pathRow_wp9h7_118{align-items:center;gap:6px;display:flex}._path_wp9h7_110{border-radius:var(--radius-sm);background:var(--code-bg);min-width:0;font-family:var(--mono);overflow-wrap:anywhere;flex:1;padding:6px 8px;font-size:12.5px}._intro_wp9h7_135{margin-bottom:18px}._pageTitle_wp9h7_139{margin:0 0 6px;font-size:22px;font-weight:600}._lead_wp9h7_145{color:var(--muted);margin:0;font-size:15px}._about_wp9h7_151{min-height:calc(100% - 42px)}._aboutLogo_wp9h7_155{width:min(480px,100%);height:auto;margin:36px auto 26px;display:block}._aboutDescription_wp9h7_162{max-width:62ch;color:var(--muted);text-align:center;margin:0 auto;font-size:16px;line-height:1.6}._aboutAttribution_wp9h7_171{text-align:center;margin:18px 0 0;font-weight:550}._aboutLink_wp9h7_177{width:-moz-fit-content;width:fit-content;color:var(--accent-strong);justify-content:center;align-items:center;gap:8px;margin:18px auto 0;font-weight:550;display:flex}._scope_wp9h7_188{color:var(--faint);text-overflow:ellipsis;white-space:nowrap;margin:6px 0 0;font-size:12.5px;overflow:hidden}._sectionTitle_wp9h7_197{margin:26px 0 6px;font-size:15px;font-weight:600}._fieldset_wp9h7_203{border:0;margin:0 0 22px;padding:0}._legend_wp9h7_209{margin-bottom:10px;font-weight:550}._choices_wp9h7_214{flex-wrap:wrap;gap:8px;display:flex}._choice_wp9h7_214{border:1px solid var(--border);cursor:pointer;border-radius:999px;align-items:center;gap:8px;padding:8px 14px;display:inline-flex}._choice_wp9h7_214:has(input:checked){border-color:var(--accent);background:var(--accent-soft)}._choice_wp9h7_214 input{accent-color:var(--accent);margin:0}._note_wp9h7_240{max-width:64ch;color:var(--muted);font-size:14px}._note_wp9h7_240 code,._cardText_wp9h7_247 code,._facts_wp9h7_248 code{font-family:var(--mono);overflow-wrap:anywhere;font-size:12.5px}._errorText_wp9h7_254{color:var(--danger);font-size:14px}._tabs_wp9h7_259{border-bottom:1px solid var(--border);gap:28px;margin-bottom:18px;display:flex}._tab_wp9h7_259{color:var(--muted);background:0 0;border:0;border-bottom:2px solid #0000;margin-bottom:-1px;padding:10px 2px;font-size:15px}._tab_wp9h7_259[aria-selected=true]{border-bottom-color:var(--text);color:var(--text)}._search_wp9h7_281{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);height:44px;color:var(--muted);align-items:center;gap:10px;padding:0 14px;display:flex}._search_wp9h7_281 input{min-width:0;color:var(--text);background:0 0;border:0;outline:0;flex:1;font-size:15px}._search_wp9h7_281:focus-within{border-color:var(--accent)}._listTitle_wp9h7_307{margin:18px 0 12px;font-size:15px;font-weight:600}._count_wp9h7_313{color:var(--muted);margin-left:6px;font-weight:400}._grid_wp9h7_319{grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:12px;margin:0;padding:0;list-style:none;display:grid}._card_wp9h7_247{border:1px solid var(--border);background:var(--surface);border-radius:14px}._card_wp9h7_247[data-open=true]{border-color:var(--border-strong)}._cardHead_wp9h7_339{text-align:left;background:0 0;border:0;align-items:center;gap:10px;width:100%;min-height:60px;padding:10px 14px 10px 18px;display:flex}._cardName_wp9h7_351{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:16px;font-weight:600;overflow:hidden}._chevron_wp9h7_361{color:var(--muted);flex:none}._cardBody_wp9h7_366{padding:0 18px 14px}._cardText_wp9h7_247{color:var(--muted);margin:4px 0 8px;font-size:14px}._facts_wp9h7_248{grid-template-columns:max-content 1fr;gap:4px 12px;margin:8px 0;font-size:13px;display:grid}._facts_wp9h7_248 dt{color:var(--faint)}._facts_wp9h7_248 dd{overflow-wrap:anywhere;margin:0}._diagnostic_wp9h7_393{color:var(--warn);margin:6px 0;font-size:13px}._toggleRow_wp9h7_399{border-top:1px solid var(--border);justify-content:space-between;align-items:center;margin-top:10px;padding-top:10px;font-size:14px;display:flex}._pill_wp9h7_409{background:var(--raised);color:var(--muted);white-space:nowrap;border-radius:8px;flex:none;align-items:center;gap:6px;padding:3px 10px;font-size:13px;display:inline-flex}._pill_wp9h7_409[data-tone=ok]{background:color-mix(in srgb, var(--ok) 14%, transparent);color:var(--ok)}._pill_wp9h7_409[data-tone=warn]{background:color-mix(in srgb, var(--warn) 14%, transparent);color:var(--warn)}._pill_wp9h7_409[data-tone=danger]{background:var(--danger-soft);color:var(--danger)}._pillDot_wp9h7_437{background:currentColor;border-radius:50%;width:7px;height:7px}._switch_wp9h7_444{border:1px solid var(--border-strong);background:var(--raised);border-radius:999px;flex:none;width:40px;height:22px;padding:0;position:relative}._switch_wp9h7_444[aria-checked=true]{border-color:var(--accent);background:var(--accent)}._switch_wp9h7_444:disabled{opacity:.45}._switch_wp9h7_444[aria-busy=true]{opacity:.7}._knob_wp9h7_468{background:var(--text);width:16px;height:16px;transition:transform .15s var(--ease);border-radius:50%;position:absolute;top:2px;left:2px}._switch_wp9h7_444[aria-checked=true] ._knob_wp9h7_468{background:var(--accent-contrast);transform:translate(18px)}._rows_wp9h7_484{gap:10px;margin:14px 0 0;padding:0;list-style:none;display:grid}._row_wp9h7_484{border:1px solid var(--border);background:var(--surface);border-radius:14px;align-items:flex-start;gap:16px;padding:14px 16px;display:flex}._row_wp9h7_484[data-muted=true]{opacity:.7}._row_wp9h7_484[data-current=true]{border-color:var(--accent)}._rowMain_wp9h7_510{flex:1;min-width:0}._rowTitle_wp9h7_515{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._rowTitle_wp9h7_515 ._cardName_wp9h7_351{flex:0 auto}._rowActions_wp9h7_526{flex:none;align-items:center;gap:10px;display:flex}._meta_wp9h7_533{color:var(--faint);margin:2px 0 0;font-size:12.5px}._linkButton_wp9h7_539{color:var(--accent-strong);background:0 0;border:0;align-items:center;gap:4px;padding:2px 0;font-size:13px;display:inline-flex}._instructions_wp9h7_550{border-radius:var(--radius-sm);background:var(--code-bg);white-space:pre-wrap;max-height:260px;margin:6px 0 0;padding:10px 12px;font-size:12.5px;overflow:auto}._primary_wp9h7_561,._secondary_wp9h7_562{border-radius:var(--radius);white-space:nowrap;height:34px;padding:0 14px;font-size:14px}._primary_wp9h7_561{background:var(--accent);color:var(--accent-contrast);border:0;font-weight:550}._secondary_wp9h7_562{border:1px solid var(--border-strong);background:0 0}._primary_wp9h7_561:disabled,._secondary_wp9h7_562:disabled{opacity:.5}._banner_wp9h7_587{border:1px solid var(--border);border-radius:var(--radius);justify-content:space-between;align-items:center;gap:12px;padding:10px 14px;font-size:14px;display:flex}._banner_wp9h7_587[data-tone=warn]{border-color:color-mix(in srgb, var(--warn) 40%, var(--border))}._confirm_wp9h7_602{border:1px solid color-mix(in srgb, var(--warn) 45%, var(--border));border-radius:var(--radius);background:var(--surface);margin-top:12px;padding:14px 16px}._confirmTitle_wp9h7_610{color:var(--warn);align-items:center;gap:8px;margin:0 0 6px;font-size:15px;display:flex}._checkRow_wp9h7_619{align-items:center;gap:8px;margin:8px 0;font-size:14px;display:flex}._actions_wp9h7_627{justify-content:flex-end;gap:8px;display:flex}._callout_wp9h7_633{border:1px solid color-mix(in srgb, var(--warn) 40%, var(--border));border-radius:var(--radius);color:var(--text);gap:10px;padding:12px 14px;font-size:14px;display:flex}._stack_wp9h7_643{gap:4px;display:grid}._settingList_wp9h7_648{margin:8px 0 0;padding:0;list-style:none;display:grid}._settingRow_wp9h7_655{border-bottom:1px solid var(--border);justify-content:space-between;align-items:center;gap:16px;padding:10px 0;display:flex}._settingLabel_wp9h7_664{gap:2px;min-width:0;font-size:14px;display:grid}._settingKey_wp9h7_671{color:var(--faint);font-family:var(--mono);font-size:12px}._input_wp9h7_677{border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface);width:200px;height:34px;color:var(--text);padding:0 10px;font-size:14px}._input_wp9h7_677:focus{border-color:var(--accent);outline:0}._credential_wp9h7_693{border-top:1px solid var(--border);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 16px;margin-top:10px;padding-top:10px;display:flex}._credentialForm_wp9h7_704{flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px;display:flex}._meta_wp9h7_533[data-configured=true]{color:var(--ok)}._profileForm_wp9h7_716{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);gap:10px;margin:12px 0;padding:14px 16px;display:grid}._formRow_wp9h7_726{justify-content:space-between;align-items:center;gap:16px;font-size:14px;display:flex}._formRow_wp9h7_726 ._input_wp9h7_677{width:min(320px,60%)}._addButton_wp9h7_738{margin-top:14px}@media (max-width:760px){._dialog_wp9h7_11{grid-template-rows:auto 1fr;grid-template-columns:1fr;height:94vh}._nav_wp9h7_23{border-right:0;border-bottom:1px solid var(--border);gap:4px;padding:12px;display:flex;overflow-x:auto}._heading_wp9h7_29{display:none}._navItem_wp9h7_35{flex:none;width:auto}._content_wp9h7_58{padding:16px}._topBar_wp9h7_64{margin:-16px -16px 0}._grid_wp9h7_319{grid-template-columns:1fr}._settingRow_wp9h7_655,._row_wp9h7_484{flex-wrap:wrap}}
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-UsYAxtjN.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-B6xuSHsQ.js";import"./chunk-DU6HZSFF-DP6dsL6K.js";import{n as i,r as a,t as o}from"./chunk-SVP7TREG-DxynkM9y.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./engine-CknQqOvU.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
1
+ import{m as e,t}from"./mermaid-parser.core-OzvFg3MX.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-B6xuSHsQ.js";import"./chunk-DU6HZSFF-D67lp4wj.js";import{n as i,r as a,t as o}from"./chunk-SVP7TREG-B-hStYeg.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./engine-D40yLY_U.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
@@ -0,0 +1 @@
1
+ import"./chunk-FOHPRMQF-DzxwRta7.js";import{M as e}from"./mermaid-parser.core-OzvFg3MX.js";export{e as createArchitectureServices};