@hachej/boring-workspace 0.1.12 → 0.1.13

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.
@@ -1,10 +1,10 @@
1
- import { jsxs as d, jsx as o, Fragment as H } from "react/jsx-runtime";
2
- import { useCallback as b, useMemo as A, useEffect as S, useState as V, Suspense as X, useRef as q } from "react";
1
+ import { jsxs as d, jsx as a, Fragment as H } from "react/jsx-runtime";
2
+ import { useCallback as p, useMemo as D, useEffect as S, useState as V, Suspense as U, useRef as q } from "react";
3
3
  import { LoadingState as Z, ResizeHandle as G, IconButton as $, Button as J, Kbd as Q } from "@hachej/boring-ui-kit";
4
4
  import { c as g } from "./utils-B6yFEsav.js";
5
- import { $ as Y, a6 as ee, E as te, am as ne, ak as re, u as oe } from "./CommandPalette-Dme9em28.js";
6
- import { Search as ae, Plus as ie } from "lucide-react";
7
- function be(e, t, r = !0) {
5
+ import { $ as Y, a6 as ee, E as te, am as ne, ak as re, u as ae } from "./CommandPalette-Dme9em28.js";
6
+ import { Search as oe, Plus as ie } from "lucide-react";
7
+ function pe(e, t, r = !0) {
8
8
  if (!r || typeof window > "u") return t;
9
9
  try {
10
10
  const n = window.localStorage.getItem(e);
@@ -49,8 +49,8 @@ function ve(e = {}) {
49
49
  surfaceParams: l,
50
50
  sidebar: s,
51
51
  sidebarParams: w
52
- } = e, p = [];
53
- return t && p.push({
52
+ } = e, b = [];
53
+ return t && b.push({
54
54
  id: "nav",
55
55
  position: "left",
56
56
  panel: t,
@@ -58,13 +58,13 @@ function ve(e = {}) {
58
58
  locked: !0,
59
59
  hideHeader: !0,
60
60
  constraints: { minWidth: 60, maxWidth: 60 }
61
- }), p.push({
61
+ }), b.push({
62
62
  id: "center",
63
63
  position: "center",
64
64
  panel: n,
65
65
  params: i,
66
66
  hideHeader: !0
67
- }), s && p.push({
67
+ }), s && b.push({
68
68
  id: "sidebar",
69
69
  position: "left",
70
70
  panel: s,
@@ -73,7 +73,7 @@ function ve(e = {}) {
73
73
  collapsible: !0,
74
74
  collapsedWidth: 40,
75
75
  constraints: { minWidth: 200, maxWidthViewportRatio: 0.5 }
76
- }), c && p.push({
76
+ }), c && b.push({
77
77
  id: "surface",
78
78
  position: "right",
79
79
  panel: c,
@@ -81,45 +81,45 @@ function ve(e = {}) {
81
81
  hideHeader: !0,
82
82
  dynamic: !0,
83
83
  placeholder: "empty"
84
- }), { version: "2.0", groups: p };
84
+ }), { version: "2.0", groups: b };
85
85
  }
86
86
  function xe(e) {
87
- const t = e.nav !== null, r = e.surface !== void 0, n = !!e.surface, i = e.nav || "session-list", c = e.center ?? "chat", l = e.surface || "artifact-surface", s = ce(), [w, p] = j(
87
+ const t = e.nav !== null, r = e.surface !== void 0, n = !!e.surface, i = e.nav || "session-list", c = e.center ?? "chat", l = e.surface || "artifact-surface", s = ce(), [w, b] = E(
88
88
  e.storageKey ? `${e.storageKey}:drawerWidth` : void 0,
89
89
  260
90
- ), [T, U] = j(
90
+ ), [T, X] = E(
91
91
  e.storageKey ? `${e.storageKey}:surfaceWidth` : void 0,
92
92
  680
93
- ), f = Y(), W = C(w, 200, 360), M = Math.max(480, Math.floor(s * 0.72)), P = C(T, 480, M), z = N(e.centerParams, "getSurface"), I = N(e.centerParams, "isWorkbenchOpen"), O = N(e.centerParams, "openWorkbench"), u = R(e.navParams, "onClose"), h = R(e.surfaceParams, "onClose"), B = R(e.navParams, "onCreate"), v = t ? !!u : !!e.onOpenNav, x = n ? !!h : !!e.onOpenSurface, y = b(() => {
94
- var a;
93
+ ), f = Y(), W = C(w, 200, 360), M = Math.max(480, Math.floor(s * 0.72)), P = C(T, 480, M), z = N(e.centerParams, "getSurface"), I = N(e.centerParams, "isWorkbenchOpen"), O = N(e.centerParams, "openWorkbench"), u = R(e.navParams, "onClose"), h = R(e.surfaceParams, "onClose"), B = R(e.navParams, "onCreate"), v = t ? !!u : !!e.onOpenNav, x = n ? !!h : !!e.onOpenSurface, y = p(() => {
94
+ var o;
95
95
  if (t) {
96
96
  u == null || u();
97
97
  return;
98
98
  }
99
- (a = e.onOpenNav) == null || a.call(e);
100
- }, [u, t, e.onOpenNav]), k = b(() => {
101
- var a;
99
+ (o = e.onOpenNav) == null || o.call(e);
100
+ }, [u, t, e.onOpenNav]), k = p(() => {
101
+ var o;
102
102
  if (n) {
103
103
  h == null || h();
104
104
  return;
105
105
  }
106
- (a = e.onOpenSurface) == null || a.call(e);
107
- }, [h, e.onOpenSurface, n]), _ = b(() => {
108
- t && (u == null || u()), n && (h == null || h()), D(), de();
106
+ (o = e.onOpenSurface) == null || o.call(e);
107
+ }, [h, e.onOpenSurface, n]), _ = p(() => {
108
+ t && (u == null || u()), n && (h == null || h()), A(), de();
109
109
  }, [u, h, t, n]);
110
110
  return ee({
111
- shortcuts: A(() => {
112
- const a = [];
113
- return v && a.push({ key: "1", mod: !0, handler: y }), x && a.push({ key: "2", mod: !0, handler: k }), c === "chat" && a.push({ key: "Escape", allowInEditable: !0, handler: _ }), a;
111
+ shortcuts: D(() => {
112
+ const o = [];
113
+ return v && o.push({ key: "1", mod: !0, handler: y }), x && o.push({ key: "2", mod: !0, handler: k }), c === "chat" && o.push({ key: "Escape", allowInEditable: !0, handler: _ }), o;
114
114
  }, [v, x, c, _, y, k])
115
115
  }), S(() => {
116
- const a = "workspace:chat-layout", m = "agent:chat-layout";
117
- return f.unregisterByPluginId(a), f.unregisterByPluginId(m), f.registerCommand({
116
+ const o = "workspace:chat-layout", m = "agent:chat-layout";
117
+ return f.unregisterByPluginId(o), f.unregisterByPluginId(m), f.registerCommand({
118
118
  id: "workspace:open-session-history",
119
119
  title: t ? "Close Session History" : "Open Session History",
120
120
  keywords: ["sessions", "history", "drawer", t ? "close" : "open"],
121
121
  shortcut: "⌘1",
122
- pluginId: a,
122
+ pluginId: o,
123
123
  when: () => v,
124
124
  run: y
125
125
  }), f.registerCommand({
@@ -127,7 +127,7 @@ function xe(e) {
127
127
  title: n ? "Close Workbench" : "Open Workbench",
128
128
  keywords: ["surface", "artifacts", "sources", "workbench", n ? "close" : "open"],
129
129
  shortcut: "⌘2",
130
- pluginId: a,
130
+ pluginId: o,
131
131
  when: () => x,
132
132
  run: k
133
133
  }), c === "chat" && f.registerCommand({
@@ -143,7 +143,7 @@ function xe(e) {
143
143
  pluginId: m,
144
144
  run: B
145
145
  }), () => {
146
- f.unregisterByPluginId(a), f.unregisterByPluginId(m);
146
+ f.unregisterByPluginId(o), f.unregisterByPluginId(m);
147
147
  };
148
148
  }, [
149
149
  f,
@@ -165,13 +165,13 @@ function xe(e) {
165
165
  k
166
166
  ]), S(() => {
167
167
  if (!z || !I || !O) return;
168
- const a = {
168
+ const o = {
169
169
  surface: z,
170
170
  isWorkbenchOpen: I,
171
171
  openWorkbench: O
172
172
  };
173
173
  return te.on(ne.uiCommand, ({ command: m }) => {
174
- re(m, a);
174
+ re(m, o);
175
175
  });
176
176
  }, [z, I, O]), /* @__PURE__ */ d(
177
177
  "div",
@@ -199,7 +199,7 @@ function xe(e) {
199
199
  willChange: "width"
200
200
  },
201
201
  children: [
202
- /* @__PURE__ */ o(
202
+ /* @__PURE__ */ a(
203
203
  "div",
204
204
  {
205
205
  className: g(
@@ -207,15 +207,15 @@ function xe(e) {
207
207
  "transition-opacity duration-[200ms] ease-[cubic-bezier(0.22,1,0.36,1)]",
208
208
  t ? "opacity-100" : "opacity-0"
209
209
  ),
210
- children: /* @__PURE__ */ o(L, { id: i, params: e.navParams })
210
+ children: /* @__PURE__ */ a(L, { id: i, params: e.navParams })
211
211
  }
212
212
  ),
213
- t ? /* @__PURE__ */ o(
214
- E,
213
+ t ? /* @__PURE__ */ a(
214
+ K,
215
215
  {
216
216
  side: "drawer-right",
217
217
  ariaLabel: "Resize sessions drawer",
218
- onResize: (a) => p((m) => C(m + a, 200, 360))
218
+ onResize: (o) => b((m) => C(m + o, 200, 360))
219
219
  }
220
220
  ) : null
221
221
  ]
@@ -228,9 +228,9 @@ function xe(e) {
228
228
  "aria-label": "Chat stage",
229
229
  className: "relative h-full min-h-0 min-w-0 flex-1 overflow-hidden bg-background",
230
230
  children: [
231
- /* @__PURE__ */ o(L, { id: c, params: e.centerParams }),
232
- !t && e.onOpenNav ? /* @__PURE__ */ o(
233
- K,
231
+ /* @__PURE__ */ a(L, { id: c, params: e.centerParams }),
232
+ !t && e.onOpenNav ? /* @__PURE__ */ a(
233
+ j,
234
234
  {
235
235
  side: "left",
236
236
  icon: "sessions",
@@ -239,8 +239,8 @@ function xe(e) {
239
239
  hint: "⌘1"
240
240
  }
241
241
  ) : null,
242
- !n && e.onOpenSurface ? /* @__PURE__ */ o(
243
- K,
242
+ !n && e.onOpenSurface ? /* @__PURE__ */ a(
243
+ j,
244
244
  {
245
245
  side: "right",
246
246
  icon: "workbench",
@@ -271,7 +271,7 @@ function xe(e) {
271
271
  willChange: "width"
272
272
  },
273
273
  children: [
274
- /* @__PURE__ */ o(
274
+ /* @__PURE__ */ a(
275
275
  "div",
276
276
  {
277
277
  className: g(
@@ -279,15 +279,15 @@ function xe(e) {
279
279
  "transition-opacity duration-[200ms] ease-[cubic-bezier(0.22,1,0.36,1)]",
280
280
  n ? "opacity-100" : "opacity-0"
281
281
  ),
282
- children: /* @__PURE__ */ o(L, { id: l, params: e.surfaceParams })
282
+ children: /* @__PURE__ */ a(L, { id: l, params: e.surfaceParams })
283
283
  }
284
284
  ),
285
- n ? /* @__PURE__ */ o(
286
- E,
285
+ n ? /* @__PURE__ */ a(
286
+ K,
287
287
  {
288
288
  side: "surface-left",
289
289
  ariaLabel: "Resize workbench",
290
- onResize: (a) => U((m) => C(m - a, 480, M))
290
+ onResize: (o) => X((m) => C(m - o, 480, M))
291
291
  }
292
292
  ) : null
293
293
  ]
@@ -300,14 +300,14 @@ function xe(e) {
300
300
  function C(e, t, r) {
301
301
  return Math.max(t, Math.min(r, e));
302
302
  }
303
- function j(e, t) {
303
+ function E(e, t) {
304
304
  const [r, n] = V(
305
305
  () => e ? F(e, t) : t
306
306
  );
307
307
  S(() => {
308
308
  n(e ? F(e, t) : t);
309
309
  }, [e, t]);
310
- const i = b(
310
+ const i = p(
311
311
  (c) => {
312
312
  n((l) => {
313
313
  const s = typeof c == "function" ? c(l) : c;
@@ -325,17 +325,17 @@ function ce() {
325
325
  return window.addEventListener("resize", r), () => window.removeEventListener("resize", r);
326
326
  }, []), e;
327
327
  }
328
- function E({ side: e, ariaLabel: t, onResize: r }) {
329
- const n = q(null), i = b((s) => {
328
+ function K({ side: e, ariaLabel: t, onResize: r }) {
329
+ const n = q(null), i = p((s) => {
330
330
  s.preventDefault(), n.current = s.clientX, s.currentTarget.setPointerCapture(s.pointerId), document.body.style.cursor = "col-resize", document.body.style.userSelect = "none";
331
- }, []), c = b((s) => {
331
+ }, []), c = p((s) => {
332
332
  if (n.current === null) return;
333
333
  const w = s.clientX - n.current;
334
334
  n.current = s.clientX, r(w);
335
- }, [r]), l = b((s) => {
335
+ }, [r]), l = p((s) => {
336
336
  n.current !== null && (n.current = null, s.currentTarget.releasePointerCapture(s.pointerId), document.body.style.cursor = "", document.body.style.userSelect = "");
337
337
  }, []);
338
- return /* @__PURE__ */ o(
338
+ return /* @__PURE__ */ a(
339
339
  G,
340
340
  {
341
341
  "aria-label": t,
@@ -361,7 +361,7 @@ function N(e, t) {
361
361
  function R(e, t) {
362
362
  return N(e, t);
363
363
  }
364
- function D() {
364
+ function A() {
365
365
  if (typeof document > "u") return;
366
366
  const e = document.querySelector(
367
367
  '[data-boring-agent] textarea[name="message"], textarea[name="message"]'
@@ -370,12 +370,12 @@ function D() {
370
370
  }
371
371
  function de() {
372
372
  typeof window > "u" || window.requestAnimationFrame(() => {
373
- D(), window.setTimeout(D, 320);
373
+ A(), window.setTimeout(A, 320);
374
374
  });
375
375
  }
376
376
  function L({ id: e, params: t }) {
377
- const r = oe(), i = A(() => r.getComponents(), [r])[e], c = A(() => le(e), [e]);
378
- return i ? /* @__PURE__ */ o(X, { fallback: /* @__PURE__ */ o(Z, { centered: !0 }), children: /* @__PURE__ */ o(
377
+ const r = ae(), i = D(() => r.getComponents(), [r])[e], c = D(() => le(e), [e]);
378
+ return i ? /* @__PURE__ */ a(U, { fallback: /* @__PURE__ */ a(Z, { centered: !0 }), children: /* @__PURE__ */ a(
379
379
  i,
380
380
  {
381
381
  params: t,
@@ -420,14 +420,14 @@ function le(e) {
420
420
  } })
421
421
  };
422
422
  }
423
- function K({
423
+ function j({
424
424
  side: e,
425
425
  icon: t,
426
426
  onClick: r,
427
427
  label: n,
428
428
  hint: i
429
429
  }) {
430
- return /* @__PURE__ */ o(
430
+ return /* @__PURE__ */ a(
431
431
  $,
432
432
  {
433
433
  type: "button",
@@ -444,9 +444,9 @@ function K({
444
444
  "focus-visible:ring-ring/40"
445
445
  ),
446
446
  children: t === "sessions" ? /* @__PURE__ */ d("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
447
- /* @__PURE__ */ o("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "1.8" }),
448
- /* @__PURE__ */ o("path", { d: "M12 7v5l3.2 2", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
449
- ] }) : /* @__PURE__ */ o("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ o("path", { d: "M3 7.5 A1.5 1.5 0 0 1 4.5 6 h4 l2 2 h9 A1.5 1.5 0 0 1 21 9.5 V17.5 A1.5 1.5 0 0 1 19.5 19 H4.5 A1.5 1.5 0 0 1 3 17.5 Z", stroke: "currentColor", strokeWidth: "1.8", strokeLinejoin: "round" }) })
447
+ /* @__PURE__ */ a("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "1.8" }),
448
+ /* @__PURE__ */ a("path", { d: "M12 7v5l3.2 2", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
449
+ ] }) : /* @__PURE__ */ a("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ a("path", { d: "M3 7.5 A1.5 1.5 0 0 1 4.5 6 h4 l2 2 h9 A1.5 1.5 0 0 1 21 9.5 V17.5 A1.5 1.5 0 0 1 19.5 19 H4.5 A1.5 1.5 0 0 1 3 17.5 Z", stroke: "currentColor", strokeWidth: "1.8", strokeLinejoin: "round" }) })
450
450
  }
451
451
  );
452
452
  }
@@ -465,26 +465,26 @@ function ye({
465
465
  {
466
466
  "data-boring-workspace-part": "topbar",
467
467
  className: g(
468
- "relative flex items-center justify-between gap-3 px-4",
468
+ "relative flex items-center justify-between gap-2 px-3",
469
469
  "bg-background border-b border-[color:oklch(from_var(--border)_l_c_h/0.4)]",
470
470
  l
471
471
  ),
472
- style: { height: 52 },
472
+ style: { height: 40 },
473
473
  "aria-label": "App top bar",
474
474
  children: [
475
- /* @__PURE__ */ o("div", { className: "flex min-w-0 flex-1 items-center gap-2.5", children: i ?? /* @__PURE__ */ d(H, { children: [
476
- /* @__PURE__ */ o(
477
- "div",
475
+ /* @__PURE__ */ a("div", { className: "flex min-w-0 flex-1 items-center gap-2.5", children: i ?? /* @__PURE__ */ d(H, { children: [
476
+ /* @__PURE__ */ a(
477
+ "img",
478
478
  {
479
- "aria-hidden": "true",
480
- className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-foreground text-[12px] font-semibold text-background",
481
- children: e.charAt(0).toUpperCase()
479
+ src: "https://chatgpt.com/backend-api/estuary/content?id=file_000000006a4471f4b8411fcbfde271c6&ts=493962&p=fs&cid=1&sig=b406cfec61d387bdedd898858283b389f31ad2bd3eb7a358a6d1efa23e9afa83&v=0",
480
+ alt: e,
481
+ className: "h-6 w-6 shrink-0 rounded-md"
482
482
  }
483
483
  ),
484
- /* @__PURE__ */ o("span", { className: "truncate text-[13px] font-medium tracking-tight text-foreground", children: e }),
484
+ /* @__PURE__ */ a("span", { className: "truncate text-[12px] font-medium tracking-tight text-foreground", children: e }),
485
485
  t && /* @__PURE__ */ d(H, { children: [
486
- /* @__PURE__ */ o("span", { "aria-hidden": "true", className: "text-muted-foreground/30", children: "/" }),
487
- /* @__PURE__ */ o("span", { className: "truncate text-[13px] font-normal text-muted-foreground", children: t })
486
+ /* @__PURE__ */ a("span", { "aria-hidden": "true", className: "text-muted-foreground/30", children: "/" }),
487
+ /* @__PURE__ */ a("span", { className: "truncate text-[12px] font-normal text-muted-foreground", children: t })
488
488
  ] })
489
489
  ] }) }),
490
490
  /* @__PURE__ */ d(
@@ -494,18 +494,18 @@ function ye({
494
494
  variant: "ghost",
495
495
  size: "sm",
496
496
  onClick: r,
497
- className: "group h-7 gap-1.5 px-1.5 text-[12.5px] text-muted-foreground/60 hover:bg-transparent hover:text-foreground focus-visible:text-foreground",
497
+ className: "group h-6 gap-1 px-1.5 text-[12px] text-muted-foreground/60 hover:bg-transparent hover:text-foreground focus-visible:text-foreground",
498
498
  "aria-label": "Search catalogs and commands",
499
499
  title: "Command palette (⌘K)",
500
500
  children: [
501
- /* @__PURE__ */ o(ae, { className: "h-3.5 w-3.5 shrink-0 opacity-70", strokeWidth: 1.75 }),
502
- /* @__PURE__ */ o("span", { className: "font-normal tracking-tight", children: "Search" }),
503
- /* @__PURE__ */ o(Q, { className: "ml-1 border-0 bg-transparent p-0 text-[10px] shadow-none group-hover:text-muted-foreground", children: "⌘K" })
501
+ /* @__PURE__ */ a(oe, { className: "h-3 w-3 shrink-0 opacity-70", strokeWidth: 1.75 }),
502
+ /* @__PURE__ */ a("span", { className: "font-normal tracking-tight", children: "Search" }),
503
+ /* @__PURE__ */ a(Q, { className: "ml-1 border-0 bg-transparent p-0 text-[10px] shadow-none group-hover:text-muted-foreground", children: "⌘K" })
504
504
  ]
505
505
  }
506
506
  ),
507
507
  /* @__PURE__ */ d("div", { className: "flex flex-1 shrink-0 items-center justify-end gap-1", children: [
508
- n && /* @__PURE__ */ o(
508
+ n && /* @__PURE__ */ a(
509
509
  $,
510
510
  {
511
511
  type: "button",
@@ -514,7 +514,7 @@ function ye({
514
514
  onClick: n,
515
515
  "aria-label": "New chat",
516
516
  title: "New chat",
517
- children: /* @__PURE__ */ o(ie, { className: "h-4 w-4" })
517
+ children: /* @__PURE__ */ a(ie, { className: "h-4 w-4" })
518
518
  }
519
519
  ),
520
520
  s
@@ -530,7 +530,7 @@ function ke({
530
530
  fullscreen: n = !0,
531
531
  className: i
532
532
  }) {
533
- return /* @__PURE__ */ o(
533
+ return /* @__PURE__ */ a(
534
534
  "section",
535
535
  {
536
536
  role: "status",
@@ -542,7 +542,7 @@ function ke({
542
542
  i
543
543
  ),
544
544
  children: /* @__PURE__ */ d("div", { className: "flex w-full max-w-sm flex-col items-center gap-5 text-center", children: [
545
- /* @__PURE__ */ o("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg border border-border bg-card text-foreground", children: /* @__PURE__ */ o(
545
+ /* @__PURE__ */ a("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg border border-border bg-card text-foreground", children: /* @__PURE__ */ a(
546
546
  "span",
547
547
  {
548
548
  "aria-hidden": "true",
@@ -550,10 +550,10 @@ function ke({
550
550
  }
551
551
  ) }),
552
552
  /* @__PURE__ */ d("div", { className: "space-y-2", children: [
553
- /* @__PURE__ */ o("h2", { className: "text-base font-medium text-foreground", children: e }),
554
- t ? /* @__PURE__ */ o("p", { className: "text-sm leading-6 text-muted-foreground", children: t }) : null
553
+ /* @__PURE__ */ a("h2", { className: "text-base font-medium text-foreground", children: e }),
554
+ t ? /* @__PURE__ */ a("p", { className: "text-sm leading-6 text-muted-foreground", children: t }) : null
555
555
  ] }),
556
- r ? /* @__PURE__ */ o("p", { className: "text-xs font-medium text-muted-foreground/80", children: r }) : null
556
+ r ? /* @__PURE__ */ a("p", { className: "text-xs font-medium text-muted-foreground/80", children: r }) : null
557
557
  ] })
558
558
  }
559
559
  );
@@ -563,6 +563,6 @@ export {
563
563
  ye as T,
564
564
  ke as W,
565
565
  ve as b,
566
- be as r,
566
+ pe as r,
567
567
  we as w
568
568
  };
package/dist/app-front.js CHANGED
@@ -2,7 +2,7 @@ import { jsx as d, jsxs as Te, Fragment as x } from "react/jsx-runtime";
2
2
  import { useSyncExternalStore as ze, useMemo as v, useRef as K, useState as X, useEffect as y, useCallback as P } from "react";
3
3
  import { ChatPanel as Fe, useSessions as Ge } from "@hachej/boring-agent/front";
4
4
  import { aj as ke, q as Ye, ak as Qe, u as Xe, al as Ze } from "./CommandPalette-Dme9em28.js";
5
- import { T as He, C as qe, r as Ee, w as et, W as $e } from "./WorkspaceLoadingState-CPQBxYFG.js";
5
+ import { T as He, C as qe, r as Ee, w as et, W as $e } from "./WorkspaceLoadingState-BjZGQLS_.js";
6
6
  function tt() {
7
7
  const e = `s${Date.now()}`;
8
8
  return {
@@ -28,9 +28,9 @@ interface CreateWorkspaceAgentServerOptions extends WorkspaceAgentCreateOptions,
28
28
  };
29
29
  /**
30
30
  * Whether exec_ui should stat-check file paths against the workspaceRoot
31
- * before queueing the command. Defaults to true in direct/local mode and
32
- * false in vercel-sandbox (where workspace files live inside the microVM,
33
- * not on the host server running this Fastify process).
31
+ * before queueing the command. Defaults to true only for local host-backed
32
+ * modes (direct/local). Remote sandbox modes should leave this false because
33
+ * workspace files may not exist on the host server running Fastify.
34
34
  */
35
35
  validateUiPaths?: boolean;
36
36
  }
@@ -1,7 +1,9 @@
1
1
  // src/app/server/createWorkspaceAgentServer.ts
2
2
  import {
3
+ autoDetectMode,
3
4
  createAgentApp,
4
- provisionRuntimeWorkspace
5
+ provisionRuntimeWorkspace,
6
+ resolveMode
5
7
  } from "@hachej/boring-agent/server";
6
8
  import { join } from "path";
7
9
 
@@ -49,7 +51,7 @@ function createInMemoryBridge() {
49
51
 
50
52
  // src/server/ui-control/tools/uiTools.ts
51
53
  import { access } from "fs/promises";
52
- import { resolve, isAbsolute, relative } from "path";
54
+ import { resolve, isAbsolute, relative, win32 } from "path";
53
55
  function makeError(message) {
54
56
  return {
55
57
  content: [{ type: "text", text: message }],
@@ -61,9 +63,15 @@ function getPathParam(kind, params) {
61
63
  const raw = kind === "navigateToLine" ? params.file : params.path;
62
64
  return typeof raw === "string" && raw.length > 0 ? raw : void 0;
63
65
  }
66
+ function isPathAbsolute(filePath) {
67
+ return isAbsolute(filePath) || win32.isAbsolute(filePath);
68
+ }
69
+ function isOutsideWorkspaceRel(rel) {
70
+ return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isPathAbsolute(rel);
71
+ }
64
72
  function validatePathSyntax(relPath, workspaceRoot) {
65
73
  const rootHint = workspaceRoot ? ` (${workspaceRoot})` : "";
66
- if (isAbsolute(relPath)) {
74
+ if (isPathAbsolute(relPath)) {
67
75
  return {
68
76
  ok: false,
69
77
  reason: `path "${relPath}" is absolute \u2014 pass a path relative to the workspace root${rootHint}.`
@@ -85,7 +93,7 @@ async function validatePath(workspaceRoot, relPath) {
85
93
  if (!syntax.ok) return syntax;
86
94
  const resolved = resolve(workspaceRoot, relPath);
87
95
  const rel = relative(workspaceRoot, resolved);
88
- if (rel.startsWith("..") || isAbsolute(rel)) {
96
+ if (isOutsideWorkspaceRel(rel)) {
89
97
  return {
90
98
  ok: false,
91
99
  reason: `path "${relPath}" escapes the workspace root (${workspaceRoot}).`
@@ -188,13 +196,14 @@ function createExecUiTool(uiBridge, opts = {}) {
188
196
  " auto-opens if collapsed. Path must be relative to the",
189
197
  " workspace root (e.g. `src/foo.ts`, not `foo.ts` if it",
190
198
  " lives under src/).",
191
- " Recovery on file-not-found: this tool stat-checks the",
192
- " path server-side and returns an error if it doesn't",
193
- " exist. On that error, immediately call find (or",
194
- " grep) to locate the file, then call exec_ui",
195
- " openFile AGAIN using the EXACT path returned \u2014 don't",
196
- " give up and don't switch to the read tool. Repeat",
197
- " until openFile succeeds or no candidate is found.",
199
+ " Recovery on file-not-found: when the server has local",
200
+ " filesystem access, this tool stat-checks the path and",
201
+ " returns an error if it doesn't exist. On that error,",
202
+ " immediately call find (or grep) to locate the file,",
203
+ " then call exec_ui openFile AGAIN using the EXACT path",
204
+ " returned \u2014 don't give up and don't switch to the read",
205
+ " tool. Repeat until openFile succeeds or no candidate",
206
+ " is found.",
198
207
  " Example: {kind:'openFile', params:{path:'README.md'}}",
199
208
  "",
200
209
  " openPanel params: { id: string, component: string,",
@@ -747,7 +756,9 @@ async function provisionWorkspaceAgentServer(opts) {
747
756
  async function createWorkspaceAgentServer(opts = {}) {
748
757
  const workspaceRoot = opts.workspaceRoot ?? process.cwd();
749
758
  const bridge = createInMemoryBridge();
750
- const validateUiPaths = opts.validateUiPaths ?? opts.mode !== "vercel-sandbox";
759
+ const resolvedMode = opts.runtimeModeAdapter?.id ?? opts.mode ?? autoDetectMode();
760
+ const workspaceFsCapability = opts.runtimeModeAdapter ? opts.runtimeModeAdapter.workspaceFsCapability ?? "best-effort" : resolveMode(resolvedMode).workspaceFsCapability ?? "best-effort";
761
+ const validateUiPaths = opts.validateUiPaths ?? workspaceFsCapability === "strong";
751
762
  const uiTools = createWorkspaceUiTools(bridge, {
752
763
  workspaceRoot: validateUiPaths ? workspaceRoot : void 0
753
764
  });
@@ -761,6 +772,7 @@ async function createWorkspaceAgentServer(opts = {}) {
761
772
  }
762
773
  const app = await createAgentApp({
763
774
  ...opts,
775
+ mode: resolvedMode,
764
776
  workspaceRoot,
765
777
  extraTools: [
766
778
  ...opts.extraTools ?? [],
@@ -768,7 +780,7 @@ async function createWorkspaceAgentServer(opts = {}) {
768
780
  ...pluginCollection.agentOptions.extraTools ?? []
769
781
  ],
770
782
  systemPromptAppend: [
771
- opts.mode !== "vercel-sandbox" ? buildWorkspaceContextPrompt() : void 0,
783
+ workspaceFsCapability === "strong" ? buildWorkspaceContextPrompt() : void 0,
772
784
  pluginCollection.agentOptions.systemPromptAppend
773
785
  ].filter(Boolean).join("\n\n") || void 0,
774
786
  resourceLoaderOptions: pluginCollection.agentOptions.resourceLoaderOptions
package/dist/server.d.ts CHANGED
@@ -21,9 +21,9 @@ interface ExecUiToolOptions {
21
21
  * tool stat-checks the resolved path before queueing the UI command and
22
22
  * returns an error to the agent if the file is missing or escapes the
23
23
  * root — so the model gets immediate feedback instead of the frontend
24
- * silently no-op'ing on a wrong path. When omitted, paths are passed
25
- * through unvalidated (back-compat for callers without server-side
26
- * filesystem access).
24
+ * silently no-op'ing on a wrong path. When omitted (for example, remote
25
+ * sandbox filesystems the host cannot stat), path syntax is still validated
26
+ * but existence is left to the frontend/remote filesystem.
27
27
  */
28
28
  workspaceRoot?: string;
29
29
  /**
package/dist/server.js CHANGED
@@ -162,7 +162,7 @@ data: ${JSON.stringify({ v: UI_BRIDGE_PROTOCOL_VERSION })}
162
162
 
163
163
  // src/server/ui-control/tools/uiTools.ts
164
164
  import { access } from "fs/promises";
165
- import { resolve, isAbsolute, relative } from "path";
165
+ import { resolve, isAbsolute, relative, win32 } from "path";
166
166
  function makeError(message) {
167
167
  return {
168
168
  content: [{ type: "text", text: message }],
@@ -174,9 +174,15 @@ function getPathParam(kind, params) {
174
174
  const raw = kind === "navigateToLine" ? params.file : params.path;
175
175
  return typeof raw === "string" && raw.length > 0 ? raw : void 0;
176
176
  }
177
+ function isPathAbsolute(filePath) {
178
+ return isAbsolute(filePath) || win32.isAbsolute(filePath);
179
+ }
180
+ function isOutsideWorkspaceRel(rel) {
181
+ return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isPathAbsolute(rel);
182
+ }
177
183
  function validatePathSyntax(relPath, workspaceRoot) {
178
184
  const rootHint = workspaceRoot ? ` (${workspaceRoot})` : "";
179
- if (isAbsolute(relPath)) {
185
+ if (isPathAbsolute(relPath)) {
180
186
  return {
181
187
  ok: false,
182
188
  reason: `path "${relPath}" is absolute \u2014 pass a path relative to the workspace root${rootHint}.`
@@ -198,7 +204,7 @@ async function validatePath(workspaceRoot, relPath) {
198
204
  if (!syntax.ok) return syntax;
199
205
  const resolved = resolve(workspaceRoot, relPath);
200
206
  const rel = relative(workspaceRoot, resolved);
201
- if (rel.startsWith("..") || isAbsolute(rel)) {
207
+ if (isOutsideWorkspaceRel(rel)) {
202
208
  return {
203
209
  ok: false,
204
210
  reason: `path "${relPath}" escapes the workspace root (${workspaceRoot}).`
@@ -301,13 +307,14 @@ function createExecUiTool(uiBridge, opts = {}) {
301
307
  " auto-opens if collapsed. Path must be relative to the",
302
308
  " workspace root (e.g. `src/foo.ts`, not `foo.ts` if it",
303
309
  " lives under src/).",
304
- " Recovery on file-not-found: this tool stat-checks the",
305
- " path server-side and returns an error if it doesn't",
306
- " exist. On that error, immediately call find (or",
307
- " grep) to locate the file, then call exec_ui",
308
- " openFile AGAIN using the EXACT path returned \u2014 don't",
309
- " give up and don't switch to the read tool. Repeat",
310
- " until openFile succeeds or no candidate is found.",
310
+ " Recovery on file-not-found: when the server has local",
311
+ " filesystem access, this tool stat-checks the path and",
312
+ " returns an error if it doesn't exist. On that error,",
313
+ " immediately call find (or grep) to locate the file,",
314
+ " then call exec_ui openFile AGAIN using the EXACT path",
315
+ " returned \u2014 don't give up and don't switch to the read",
316
+ " tool. Repeat until openFile succeeds or no candidate",
317
+ " is found.",
311
318
  " Example: {kind:'openFile', params:{path:'README.md'}}",
312
319
  "",
313
320
  " openPanel params: { id: string, component: string,",
@@ -1868,9 +1868,6 @@
1868
1868
  .w-6 {
1869
1869
  width: calc(var(--spacing) * 6);
1870
1870
  }
1871
- .w-7 {
1872
- width: calc(var(--spacing) * 7);
1873
- }
1874
1871
  .w-9 {
1875
1872
  width: calc(var(--spacing) * 9);
1876
1873
  }
package/dist/workspace.js CHANGED
@@ -10,7 +10,7 @@ import { EmptyState as Ie, Toolbar as ot, Popover as me, PopoverTrigger as ge, P
10
10
  import { Toaster as Ma, dismissToast as Da, toast as Ra } from "@hachej/boring-ui-kit";
11
11
  import { c as H } from "./utils-B6yFEsav.js";
12
12
  import { d as Re } from "./panel-DnvDNQac.js";
13
- import { C as Fa, T as La, W as za, b as qa } from "./WorkspaceLoadingState-CPQBxYFG.js";
13
+ import { C as Fa, T as La, W as za, b as qa } from "./WorkspaceLoadingState-BjZGQLS_.js";
14
14
  import { C as Ba, c as Aa } from "./CodeEditor-DQqOn4xz.js";
15
15
  import { FileTree as Ka } from "./FileTree-BVfqs3rR.js";
16
16
  import { MarkdownEditor as ja } from "./MarkdownEditor-CcCDF65H.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-workspace",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Workspace UI, plugin, and bridge package for composing chat, files, catalogs, editors, and app-specific panes.",
@@ -125,8 +125,8 @@
125
125
  "tailwind-merge": "^2.0.0",
126
126
  "zod": "^3.23.0",
127
127
  "zustand": "^5.0.0",
128
- "@hachej/boring-agent": "0.1.12",
129
- "@hachej/boring-ui-kit": "0.1.12"
128
+ "@hachej/boring-agent": "0.1.13",
129
+ "@hachej/boring-ui-kit": "0.1.13"
130
130
  },
131
131
  "devDependencies": {
132
132
  "@tailwindcss/postcss": "^4.0.0",