@hachej/boring-workspace 0.1.9 → 0.1.12

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.
@@ -2,7 +2,7 @@ import { jsx as i, jsxs as C } from "react/jsx-runtime";
2
2
  import { useRef as w, useEffect as R, useMemo as P, useCallback as x, createContext as H, useContext as L } from "react";
3
3
  import { Tree as q } from "react-arborist";
4
4
  import { FolderOpenIcon as z, FolderIcon as B, ChevronRightIcon as K, Loader2Icon as E } from "lucide-react";
5
- import { K as Y } from "./CommandPalette-CWcgmHpK.js";
5
+ import { K as Y } from "./CommandPalette-Dme9em28.js";
6
6
  import { Input as G } from "@hachej/boring-ui-kit";
7
7
  import { c as v } from "./utils-B6yFEsav.js";
8
8
  const T = /* @__PURE__ */ new Set(), A = H({
@@ -15,7 +15,7 @@ import { TableHeader as tt } from "@tiptap/extension-table-header";
15
15
  import { TableCell as et } from "@tiptap/extension-table-cell";
16
16
  import rt from "@tiptap/extension-image";
17
17
  import { c as y } from "./utils-B6yFEsav.js";
18
- import { an as U, ao as it } from "./CommandPalette-CWcgmHpK.js";
18
+ import { an as U, ao as it } from "./CommandPalette-Dme9em28.js";
19
19
  import { uploadFile as nt } from "@hachej/boring-agent/front";
20
20
  import at from "@tiptap/extension-code-block-lowlight";
21
21
  import { createLowlight as ot, common as lt } from "lowlight";
@@ -2,7 +2,7 @@ import { jsxs as d, jsx as o, Fragment as H } from "react/jsx-runtime";
2
2
  import { useCallback as b, useMemo as A, useEffect as S, useState as V, Suspense as X, 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-CWcgmHpK.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
6
  import { Search as ae, Plus as ie } from "lucide-react";
7
7
  function be(e, t, r = !0) {
8
8
  if (!r || typeof window > "u") return t;
package/dist/app-front.js CHANGED
@@ -1,8 +1,8 @@
1
1
  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
- import { aj as ke, q as Ye, ak as Qe, u as Xe, al as Ze } from "./CommandPalette-CWcgmHpK.js";
5
- import { T as He, C as qe, r as Ee, w as et, W as $e } from "./WorkspaceLoadingState-DV8V-zC2.js";
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";
6
6
  function tt() {
7
7
  const e = `s${Date.now()}`;
8
8
  return {
@@ -61,13 +61,28 @@ function getPathParam(kind, params) {
61
61
  const raw = kind === "navigateToLine" ? params.file : params.path;
62
62
  return typeof raw === "string" && raw.length > 0 ? raw : void 0;
63
63
  }
64
- async function validatePath(workspaceRoot, relPath) {
64
+ function validatePathSyntax(relPath, workspaceRoot) {
65
+ const rootHint = workspaceRoot ? ` (${workspaceRoot})` : "";
65
66
  if (isAbsolute(relPath)) {
66
67
  return {
67
68
  ok: false,
68
- reason: `path "${relPath}" is absolute \u2014 pass a path relative to the workspace root (${workspaceRoot}).`
69
+ reason: `path "${relPath}" is absolute \u2014 pass a path relative to the workspace root${rootHint}.`
69
70
  };
70
71
  }
72
+ if (relPath.includes("\0")) {
73
+ return { ok: false, reason: `path "${relPath}" contains a null byte.` };
74
+ }
75
+ if (relPath.split(/[\\/]+/).includes("..")) {
76
+ return {
77
+ ok: false,
78
+ reason: `path "${relPath}" escapes the workspace root${rootHint}.`
79
+ };
80
+ }
81
+ return { ok: true };
82
+ }
83
+ async function validatePath(workspaceRoot, relPath) {
84
+ const syntax = validatePathSyntax(relPath, workspaceRoot);
85
+ if (!syntax.ok) return syntax;
71
86
  const resolved = resolve(workspaceRoot, relPath);
72
87
  const rel = relative(workspaceRoot, resolved);
73
88
  if (rel.startsWith("..") || isAbsolute(rel)) {
@@ -263,16 +278,20 @@ function createExecUiTool(uiBridge, opts = {}) {
263
278
  return makeError("openSurface: meta must be an object when provided");
264
279
  }
265
280
  }
266
- if (workspaceRoot && PATH_BEARING_KINDS.has(kind)) {
281
+ if (PATH_BEARING_KINDS.has(kind)) {
267
282
  const relPath = getPathParam(kind, cmdParams);
268
283
  if (!relPath) {
269
284
  return makeError(
270
285
  `${kind}: ${kind === "navigateToLine" ? "file" : "path"} param is required`
271
286
  );
272
287
  }
273
- const check = await validatePath(workspaceRoot, relPath);
274
- if (!check.ok) {
275
- return makeError(check.reason);
288
+ const syntax = validatePathSyntax(relPath, workspaceRoot);
289
+ if (!syntax.ok) return makeError(syntax.reason);
290
+ if (workspaceRoot) {
291
+ const check = await validatePath(workspaceRoot, relPath);
292
+ if (!check.ok) {
293
+ return makeError(check.reason);
294
+ }
276
295
  }
277
296
  }
278
297
  try {
package/dist/server.js CHANGED
@@ -174,13 +174,28 @@ 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
- async function validatePath(workspaceRoot, relPath) {
177
+ function validatePathSyntax(relPath, workspaceRoot) {
178
+ const rootHint = workspaceRoot ? ` (${workspaceRoot})` : "";
178
179
  if (isAbsolute(relPath)) {
179
180
  return {
180
181
  ok: false,
181
- reason: `path "${relPath}" is absolute \u2014 pass a path relative to the workspace root (${workspaceRoot}).`
182
+ reason: `path "${relPath}" is absolute \u2014 pass a path relative to the workspace root${rootHint}.`
182
183
  };
183
184
  }
185
+ if (relPath.includes("\0")) {
186
+ return { ok: false, reason: `path "${relPath}" contains a null byte.` };
187
+ }
188
+ if (relPath.split(/[\\/]+/).includes("..")) {
189
+ return {
190
+ ok: false,
191
+ reason: `path "${relPath}" escapes the workspace root${rootHint}.`
192
+ };
193
+ }
194
+ return { ok: true };
195
+ }
196
+ async function validatePath(workspaceRoot, relPath) {
197
+ const syntax = validatePathSyntax(relPath, workspaceRoot);
198
+ if (!syntax.ok) return syntax;
184
199
  const resolved = resolve(workspaceRoot, relPath);
185
200
  const rel = relative(workspaceRoot, resolved);
186
201
  if (rel.startsWith("..") || isAbsolute(rel)) {
@@ -376,16 +391,20 @@ function createExecUiTool(uiBridge, opts = {}) {
376
391
  return makeError("openSurface: meta must be an object when provided");
377
392
  }
378
393
  }
379
- if (workspaceRoot && PATH_BEARING_KINDS.has(kind)) {
394
+ if (PATH_BEARING_KINDS.has(kind)) {
380
395
  const relPath = getPathParam(kind, cmdParams);
381
396
  if (!relPath) {
382
397
  return makeError(
383
398
  `${kind}: ${kind === "navigateToLine" ? "file" : "path"} param is required`
384
399
  );
385
400
  }
386
- const check = await validatePath(workspaceRoot, relPath);
387
- if (!check.ok) {
388
- return makeError(check.reason);
401
+ const syntax = validatePathSyntax(relPath, workspaceRoot);
402
+ if (!syntax.ok) return makeError(syntax.reason);
403
+ if (workspaceRoot) {
404
+ const check = await validatePath(workspaceRoot, relPath);
405
+ if (!check.ok) {
406
+ return makeError(check.reason);
407
+ }
389
408
  }
390
409
  }
391
410
  try {
package/dist/testing.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as ka } from "react/jsx-runtime";
2
2
  import * as Pa from "react";
3
3
  import { createElement as ds, useMemo as Tn, useLayoutEffect as fs, isValidElement as ps, cloneElement as ms, useSyncExternalStore as Ji } from "react";
4
- import { i as vs, q as bs, ai as hs } from "./CommandPalette-CWcgmHpK.js";
4
+ import { i as vs, q as bs, ai as hs } from "./CommandPalette-Dme9em28.js";
5
5
  import { d as ys } from "./panel-DnvDNQac.js";
6
6
  import * as Rs from "react-dom/test-utils";
7
7
  import Ba from "react-dom";
@@ -1913,6 +1913,9 @@
1913
1913
  .max-w-2xl {
1914
1914
  max-width: var(--container-2xl);
1915
1915
  }
1916
+ .max-w-20 {
1917
+ max-width: calc(var(--spacing) * 20);
1918
+ }
1916
1919
  .max-w-\[68ch\] {
1917
1920
  max-width: 68ch;
1918
1921
  }
@@ -509,7 +509,7 @@ export declare interface DataCatalogVisualizationState extends DataCatalogResolv
509
509
  title: string;
510
510
  }
511
511
 
512
- export declare function DataExplorer({ adapter, facets: facetConfigs, groupBy, onActivate, getDragPayload, emptyState, searchPlaceholder, searchable, query, pageSize, debounceMs, className, }: DataExplorerProps): JSX.Element;
512
+ export declare function DataExplorer({ adapter, facets: facetConfigs, groupBy, onActivate, getDragPayload, emptyState, searchPlaceholder, searchable, query, onQueryChange, pageSize, debounceMs, className, }: DataExplorerProps): JSX.Element;
513
513
 
514
514
  export declare type DataExplorerProps = {
515
515
  adapter: ExplorerAdapter;
@@ -532,6 +532,8 @@ export declare type DataExplorerProps = {
532
532
  * Useful when an outer chrome already owns a search box.
533
533
  */
534
534
  query?: string;
535
+ /** Called when the toolbar search changes. Use with `query` for controlled per-tab search. */
536
+ onQueryChange?: (query: string) => void;
535
537
  /** Page size and debounce — passed through to useExplorerState. */
536
538
  pageSize?: number;
537
539
  debounceMs?: number;