@hachej/boring-workspace 0.1.12 → 0.1.14
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.
- package/README.md +270 -42
- package/dist/CommandPalette-NOEOVkN2.js +5714 -0
- package/dist/{FileTree-BVfqs3rR.js → FileTree-Dl-qUAB0.js} +9 -9
- package/dist/MarkdownEditor-yc6mFsnI.js +533 -0
- package/dist/{WorkspaceLoadingState-CPQBxYFG.js → WorkspaceLoadingState-CSZfENWe.js} +178 -157
- package/dist/agent-tool-DEtfQPVB.d.ts +100 -0
- package/dist/app-front.d.ts +79 -67
- package/dist/app-front.js +253 -241
- package/dist/app-server.d.ts +17 -12
- package/dist/app-server.js +105 -23
- package/dist/{bootstrapServer-BRUqUpVW.d.ts → bootstrapServer-BreQ9QBc.d.ts} +8 -2
- package/dist/server.d.ts +13 -35
- package/dist/server.js +39 -137
- package/dist/shared.d.ts +1 -2
- package/dist/testing.d.ts +0 -63
- package/dist/testing.js +2248 -2401
- package/dist/workspace.css +1616 -977
- package/dist/workspace.d.ts +111 -450
- package/dist/workspace.js +417 -1635
- package/docs/INTERFACES.md +2 -2
- package/docs/PLUGIN_STRUCTURE.md +1 -1
- package/docs/plans/ASK_USER_QUESTIONS_PLUGIN_SPEC.md +131 -263
- package/docs/plans/GENERIC_EXPLORER_PLUGIN_PLAN.md +29 -27
- package/docs/plans/MACRO_PLUGIN_GENERIC_HELPERS_AUDIT.md +12 -12
- package/docs/plans/PANE_TO_AGENT_CHAT_ACTIONS_SPEC.md +366 -0
- package/docs/plans/README.md +2 -0
- package/docs/plans/archive/PLUGIN_MODEL.md +14 -14
- package/docs/plans/archive/SRC_FOLDER_REORG_PLAN.md +2 -3
- package/docs/plans/archive/WORKSPACE_V2_PLAN.md +1 -1
- package/package.json +3 -6
- package/dist/CommandPalette-Dme9em28.js +0 -5506
- package/dist/MarkdownEditor-CcCDF65H.js +0 -502
- package/dist/agent-tool-NvxKfist.d.ts +0 -28
- package/dist/explorer-DtLUnuah.d.ts +0 -129
package/dist/server.js
CHANGED
|
@@ -93,7 +93,11 @@ function uiRoutes(app, opts, done) {
|
|
|
93
93
|
async (request, reply) => {
|
|
94
94
|
const body = request.body;
|
|
95
95
|
const bridge = await resolveBridge(request);
|
|
96
|
-
await bridge.
|
|
96
|
+
const current = await bridge.getState() ?? {};
|
|
97
|
+
const preserved = Object.fromEntries(
|
|
98
|
+
(opts.preserveStateKeys ?? []).filter((key) => !(key in body.state) && key in current).map((key) => [key, current[key]])
|
|
99
|
+
);
|
|
100
|
+
await bridge.setState({ ...body.state, ...preserved });
|
|
97
101
|
return reply.code(204).send();
|
|
98
102
|
}
|
|
99
103
|
);
|
|
@@ -162,7 +166,7 @@ data: ${JSON.stringify({ v: UI_BRIDGE_PROTOCOL_VERSION })}
|
|
|
162
166
|
|
|
163
167
|
// src/server/ui-control/tools/uiTools.ts
|
|
164
168
|
import { access } from "fs/promises";
|
|
165
|
-
import { resolve, isAbsolute, relative } from "path";
|
|
169
|
+
import { resolve, isAbsolute, relative, win32 } from "path";
|
|
166
170
|
function makeError(message) {
|
|
167
171
|
return {
|
|
168
172
|
content: [{ type: "text", text: message }],
|
|
@@ -174,9 +178,15 @@ function getPathParam(kind, params) {
|
|
|
174
178
|
const raw = kind === "navigateToLine" ? params.file : params.path;
|
|
175
179
|
return typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
176
180
|
}
|
|
181
|
+
function isPathAbsolute(filePath) {
|
|
182
|
+
return isAbsolute(filePath) || win32.isAbsolute(filePath);
|
|
183
|
+
}
|
|
184
|
+
function isOutsideWorkspaceRel(rel) {
|
|
185
|
+
return rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isPathAbsolute(rel);
|
|
186
|
+
}
|
|
177
187
|
function validatePathSyntax(relPath, workspaceRoot) {
|
|
178
188
|
const rootHint = workspaceRoot ? ` (${workspaceRoot})` : "";
|
|
179
|
-
if (
|
|
189
|
+
if (isPathAbsolute(relPath)) {
|
|
180
190
|
return {
|
|
181
191
|
ok: false,
|
|
182
192
|
reason: `path "${relPath}" is absolute \u2014 pass a path relative to the workspace root${rootHint}.`
|
|
@@ -198,7 +208,7 @@ async function validatePath(workspaceRoot, relPath) {
|
|
|
198
208
|
if (!syntax.ok) return syntax;
|
|
199
209
|
const resolved = resolve(workspaceRoot, relPath);
|
|
200
210
|
const rel = relative(workspaceRoot, resolved);
|
|
201
|
-
if (
|
|
211
|
+
if (isOutsideWorkspaceRel(rel)) {
|
|
202
212
|
return {
|
|
203
213
|
ok: false,
|
|
204
214
|
reason: `path "${relPath}" escapes the workspace root (${workspaceRoot}).`
|
|
@@ -301,13 +311,14 @@ function createExecUiTool(uiBridge, opts = {}) {
|
|
|
301
311
|
" auto-opens if collapsed. Path must be relative to the",
|
|
302
312
|
" workspace root (e.g. `src/foo.ts`, not `foo.ts` if it",
|
|
303
313
|
" lives under src/).",
|
|
304
|
-
" Recovery on file-not-found:
|
|
305
|
-
"
|
|
306
|
-
" exist. On that error,
|
|
307
|
-
" grep) to locate the file,
|
|
308
|
-
" openFile AGAIN using the EXACT path
|
|
309
|
-
" give up and don't switch to the read
|
|
310
|
-
" until openFile succeeds or no candidate
|
|
314
|
+
" Recovery on file-not-found: when the server has local",
|
|
315
|
+
" filesystem access, this tool stat-checks the path and",
|
|
316
|
+
" returns an error if it doesn't exist. On that error,",
|
|
317
|
+
" immediately call find (or grep) to locate the file,",
|
|
318
|
+
" then call exec_ui openFile AGAIN using the EXACT path",
|
|
319
|
+
" returned \u2014 don't give up and don't switch to the read",
|
|
320
|
+
" tool. Repeat until openFile succeeds or no candidate",
|
|
321
|
+
" is found.",
|
|
311
322
|
" Example: {kind:'openFile', params:{path:'README.md'}}",
|
|
312
323
|
"",
|
|
313
324
|
" openPanel params: { id: string, component: string,",
|
|
@@ -326,11 +337,11 @@ function createExecUiTool(uiBridge, opts = {}) {
|
|
|
326
337
|
" \u2014 Open a plugin-owned target through the workspace",
|
|
327
338
|
" surface resolver registry. Use this when a plugin",
|
|
328
339
|
" defines the mapping from domain target to panel",
|
|
329
|
-
" component, for example a
|
|
340
|
+
" component, for example a catalog row.",
|
|
330
341
|
" Example: {kind:'openSurface', params:{",
|
|
331
|
-
" kind:'
|
|
342
|
+
" kind:'my-plugin.open-row',",
|
|
332
343
|
" target:'orders_daily',",
|
|
333
|
-
" meta:{catalogId:'
|
|
344
|
+
" meta:{catalogId:'my-plugin'}}}",
|
|
334
345
|
"",
|
|
335
346
|
" closePanel params: { id: string }",
|
|
336
347
|
" closeWorkbenchLeftPane params: {}",
|
|
@@ -592,6 +603,11 @@ function validateServerPlugin(plugin) {
|
|
|
592
603
|
if (plugin.routes !== void 0 && typeof plugin.routes !== "function") {
|
|
593
604
|
fail(plugin.id, "routes must be a Fastify plugin function when provided");
|
|
594
605
|
}
|
|
606
|
+
if (plugin.preservedUiStateKeys !== void 0) {
|
|
607
|
+
if (!Array.isArray(plugin.preservedUiStateKeys) || plugin.preservedUiStateKeys.some((key) => typeof key !== "string" || key.length === 0)) {
|
|
608
|
+
fail(plugin.id, "preservedUiStateKeys must be a non-empty string array when provided");
|
|
609
|
+
}
|
|
610
|
+
}
|
|
595
611
|
if (plugin.provisioning !== void 0) {
|
|
596
612
|
validateProvisioning(plugin.id, plugin.provisioning);
|
|
597
613
|
}
|
|
@@ -647,6 +663,10 @@ function composeServerPlugins(options) {
|
|
|
647
663
|
...options.plugins.map((plugin) => plugin.routes),
|
|
648
664
|
options.routes
|
|
649
665
|
]);
|
|
666
|
+
const preservedUiStateKeys = [.../* @__PURE__ */ new Set([
|
|
667
|
+
...options.plugins.flatMap((plugin) => plugin.preservedUiStateKeys ?? []),
|
|
668
|
+
...options.preservedUiStateKeys ?? []
|
|
669
|
+
])];
|
|
650
670
|
return defineServerPlugin({
|
|
651
671
|
id: options.id,
|
|
652
672
|
...options.label !== void 0 ? { label: options.label } : {},
|
|
@@ -654,7 +674,8 @@ function composeServerPlugins(options) {
|
|
|
654
674
|
...systemPrompt ? { systemPrompt } : {},
|
|
655
675
|
...agentTools.length > 0 ? { agentTools } : {},
|
|
656
676
|
...provisioning ? { provisioning } : {},
|
|
657
|
-
...routes ? { routes } : {}
|
|
677
|
+
...routes ? { routes } : {},
|
|
678
|
+
...preservedUiStateKeys.length > 0 ? { preservedUiStateKeys } : {}
|
|
658
679
|
});
|
|
659
680
|
}
|
|
660
681
|
|
|
@@ -686,145 +707,26 @@ function bootstrapServer(options) {
|
|
|
686
707
|
const piPackages = collectPiPackages(finalPlugins);
|
|
687
708
|
const provisioningContributions = finalPlugins.filter((p) => p.provisioning).map((p) => ({ id: p.id, provisioning: p.provisioning }));
|
|
688
709
|
const routeContributions = finalPlugins.filter((p) => p.routes).map((p) => ({ id: p.id, routes: p.routes }));
|
|
710
|
+
const preservedUiStateKeys = [...new Set(finalPlugins.flatMap((p) => p.preservedUiStateKeys ?? []))];
|
|
689
711
|
return {
|
|
690
712
|
registered: finalPlugins.map((p) => p.id),
|
|
691
713
|
systemPromptAppend,
|
|
692
714
|
piPackages,
|
|
693
715
|
agentTools,
|
|
694
716
|
provisioningContributions,
|
|
695
|
-
routeContributions
|
|
696
|
-
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// src/plugins/dataCatalogPlugin/shared/constants.ts
|
|
700
|
-
var DATA_CATALOG_PLUGIN_ID = "data-catalog";
|
|
701
|
-
var DATA_CATALOG_DEFAULT_TOOL_NAME = "query_data_catalog";
|
|
702
|
-
var DATA_CATALOG_ROW_SURFACE_KIND = "data-catalog.open-row";
|
|
703
|
-
|
|
704
|
-
// src/plugins/dataCatalogPlugin/server/index.ts
|
|
705
|
-
function textResult(text, details) {
|
|
706
|
-
return { content: [{ type: "text", text }], details };
|
|
707
|
-
}
|
|
708
|
-
function errorResult(text) {
|
|
709
|
-
return { content: [{ type: "text", text }], isError: true };
|
|
710
|
-
}
|
|
711
|
-
function clampLimit(value, fallback, max) {
|
|
712
|
-
const numeric = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
|
|
713
|
-
if (!Number.isFinite(numeric)) return fallback;
|
|
714
|
-
return Math.max(1, Math.min(max, Math.floor(numeric)));
|
|
715
|
-
}
|
|
716
|
-
function normalizeLimitOptions(options) {
|
|
717
|
-
const rawMax = options.maxLimit ?? 50;
|
|
718
|
-
const maxLimit = typeof rawMax === "number" && Number.isFinite(rawMax) ? Math.max(1, Math.floor(rawMax)) : 50;
|
|
719
|
-
const rawDefault = options.defaultLimit ?? 20;
|
|
720
|
-
const defaultLimit = typeof rawDefault === "number" && Number.isFinite(rawDefault) ? Math.max(1, Math.min(maxLimit, Math.floor(rawDefault))) : Math.min(20, maxLimit);
|
|
721
|
-
return { defaultLimit, maxLimit };
|
|
722
|
-
}
|
|
723
|
-
function formatBadge(row) {
|
|
724
|
-
const parts = [
|
|
725
|
-
row.leading?.code,
|
|
726
|
-
...(row.trailing ?? []).map((badge) => badge.code),
|
|
727
|
-
row.meta
|
|
728
|
-
].filter(Boolean);
|
|
729
|
-
return parts.length > 0 ? ` [${parts.join(", ")}]` : "";
|
|
730
|
-
}
|
|
731
|
-
function formatDataCatalogSearchResult(query, result) {
|
|
732
|
-
if (result.items.length === 0) {
|
|
733
|
-
return `No ${query ? `results for "${query}"` : "catalog results"}.`;
|
|
734
|
-
}
|
|
735
|
-
const lines = result.items.map((row) => {
|
|
736
|
-
const subtitle = row.subtitle ? ` \u2014 ${row.subtitle}` : "";
|
|
737
|
-
return `${row.id}: ${row.title}${subtitle}${formatBadge(row)}`;
|
|
738
|
-
});
|
|
739
|
-
const total = Number.isFinite(result.total) ? result.total : result.items.length;
|
|
740
|
-
return `Found ${total} results (showing ${result.items.length}):
|
|
741
|
-
|
|
742
|
-
${lines.join("\n")}`;
|
|
743
|
-
}
|
|
744
|
-
function createDataCatalogAgentTool(options) {
|
|
745
|
-
const name = options.name ?? DATA_CATALOG_DEFAULT_TOOL_NAME;
|
|
746
|
-
const label = options.label ?? "data catalog";
|
|
747
|
-
const { defaultLimit, maxLimit } = normalizeLimitOptions(options);
|
|
748
|
-
return {
|
|
749
|
-
name,
|
|
750
|
-
description: `Search the ${label}. Use this before opening data visualizations or asking for a specific dataset.`,
|
|
751
|
-
parameters: {
|
|
752
|
-
type: "object",
|
|
753
|
-
properties: {
|
|
754
|
-
query: {
|
|
755
|
-
type: "string",
|
|
756
|
-
description: "Search keywords for datasets, series, tables, or metrics."
|
|
757
|
-
},
|
|
758
|
-
limit: {
|
|
759
|
-
type: "number",
|
|
760
|
-
description: `Maximum number of results. Default ${defaultLimit}, max ${maxLimit}.`,
|
|
761
|
-
minimum: 1,
|
|
762
|
-
maximum: maxLimit
|
|
763
|
-
}
|
|
764
|
-
},
|
|
765
|
-
required: ["query"],
|
|
766
|
-
additionalProperties: false
|
|
767
|
-
},
|
|
768
|
-
async execute(params, ctx) {
|
|
769
|
-
const query = String(params.query ?? "").trim();
|
|
770
|
-
if (!query) return errorResult("query is required");
|
|
771
|
-
const limit = clampLimit(params.limit, defaultLimit, maxLimit);
|
|
772
|
-
try {
|
|
773
|
-
const result = await options.adapter.search({
|
|
774
|
-
query,
|
|
775
|
-
filters: {},
|
|
776
|
-
limit,
|
|
777
|
-
offset: 0,
|
|
778
|
-
signal: ctx.abortSignal
|
|
779
|
-
});
|
|
780
|
-
return textResult(formatDataCatalogSearchResult(query, result), result);
|
|
781
|
-
} catch (error) {
|
|
782
|
-
return errorResult(error instanceof Error ? error.message : String(error));
|
|
783
|
-
}
|
|
784
|
-
}
|
|
717
|
+
routeContributions,
|
|
718
|
+
preservedUiStateKeys
|
|
785
719
|
};
|
|
786
720
|
}
|
|
787
|
-
function createDataCatalogSkillPrompt(options = {}) {
|
|
788
|
-
const label = options.label ?? "data catalog";
|
|
789
|
-
const toolName = options.toolName ?? DATA_CATALOG_DEFAULT_TOOL_NAME;
|
|
790
|
-
const surfaceKind = options.surfaceKind ?? DATA_CATALOG_ROW_SURFACE_KIND;
|
|
791
|
-
const guidance = options.guidance?.trim();
|
|
792
|
-
return [
|
|
793
|
-
"## Data Catalog Plugin",
|
|
794
|
-
"",
|
|
795
|
-
`Use \`${toolName}\` to search the ${label} before referencing datasets, series, tables, or metrics.`,
|
|
796
|
-
`When you need to show a catalog row to the user, use the workspace UI bridge \`openSurface\` command with \`{ kind: '${surfaceKind}', target: row.id, meta: { catalogId, row } }\` so the client plugin resolver chooses the panel.`,
|
|
797
|
-
guidance ? "" : void 0,
|
|
798
|
-
guidance || void 0
|
|
799
|
-
].filter((line) => line !== void 0).join("\n");
|
|
800
|
-
}
|
|
801
|
-
function createDataCatalogServerPlugin(options) {
|
|
802
|
-
const tool = createDataCatalogAgentTool(options);
|
|
803
|
-
return defineServerPlugin({
|
|
804
|
-
id: options.id ?? DATA_CATALOG_PLUGIN_ID,
|
|
805
|
-
label: options.label ?? "Data Catalog",
|
|
806
|
-
agentTools: [tool],
|
|
807
|
-
systemPrompt: createDataCatalogSkillPrompt({
|
|
808
|
-
label: options.label,
|
|
809
|
-
toolName: tool.name,
|
|
810
|
-
surfaceKind: options.surfaceKind,
|
|
811
|
-
guidance: options.guidance
|
|
812
|
-
})
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
721
|
export {
|
|
816
722
|
ServerPluginError,
|
|
817
723
|
bootstrapServer,
|
|
818
724
|
composeServerPlugins,
|
|
819
|
-
createDataCatalogAgentTool,
|
|
820
|
-
createDataCatalogServerPlugin,
|
|
821
|
-
createDataCatalogSkillPrompt,
|
|
822
725
|
createExecUiTool,
|
|
823
726
|
createGetUiStateTool,
|
|
824
727
|
createInMemoryBridge,
|
|
825
728
|
createWorkspaceUiTools,
|
|
826
729
|
defineServerPlugin,
|
|
827
|
-
formatDataCatalogSearchResult,
|
|
828
730
|
uiRoutes,
|
|
829
731
|
validateServerPlugin
|
|
830
732
|
};
|
package/dist/shared.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export { C as CommandResult,
|
|
1
|
+
export { A as AgentTool, C as CommandResult, J as JSONSchema, T as ToolExecContext, c as ToolResult, U as UiBridge, a as UiCommand, b as UiState } from './agent-tool-DEtfQPVB.js';
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
3
|
import { DockviewPanelApi, DockviewApi } from 'dockview-react';
|
|
4
|
-
export { A as AgentTool, J as JSONSchema, T as ToolExecContext, a as ToolResult } from './agent-tool-NvxKfist.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Shared panel and command types — no runtime deps beyond React/dockview.
|
package/dist/testing.d.ts
CHANGED
|
@@ -8,12 +8,6 @@ import { ReactNode } from 'react';
|
|
|
8
8
|
import { RenderOptions } from '@testing-library/react';
|
|
9
9
|
import { RenderResult } from '@testing-library/react';
|
|
10
10
|
|
|
11
|
-
declare type Badge = {
|
|
12
|
-
/** 1–4 char mono code rendered as a chip. */
|
|
13
|
-
code: string;
|
|
14
|
-
tooltip?: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
11
|
/**
|
|
18
12
|
* Land on the app with a clean localStorage so persistence-sensitive tests
|
|
19
13
|
* start from defaults. Pre-opens the workbench surface unless told
|
|
@@ -135,8 +129,6 @@ export declare interface CreateMockRegistryOptions {
|
|
|
135
129
|
capabilities?: Record<string, boolean>;
|
|
136
130
|
}
|
|
137
131
|
|
|
138
|
-
export declare function createMockSeriesAdapter(): ExplorerAdapter;
|
|
139
|
-
|
|
140
132
|
export declare function createMockSessions(opts?: CreateMockSessionsOptions): MockSessionsStore;
|
|
141
133
|
|
|
142
134
|
export declare interface CreateMockSessionsOptions {
|
|
@@ -146,8 +138,6 @@ export declare interface CreateMockSessionsOptions {
|
|
|
146
138
|
activeId?: string;
|
|
147
139
|
}
|
|
148
140
|
|
|
149
|
-
export declare function createMockTablesAdapter(): ExplorerAdapter;
|
|
150
|
-
|
|
151
141
|
declare interface DynamicPaneConfig {
|
|
152
142
|
id: string;
|
|
153
143
|
component: string;
|
|
@@ -155,39 +145,6 @@ declare interface DynamicPaneConfig {
|
|
|
155
145
|
title?: string;
|
|
156
146
|
}
|
|
157
147
|
|
|
158
|
-
declare type ExplorerAdapter = {
|
|
159
|
-
search(args: SearchArgs): Promise<SearchResult>;
|
|
160
|
-
/** Optional. When omitted, the explorer renders flat (no facet popover). */
|
|
161
|
-
fetchFacets?(args: FacetsArgs): Promise<Facets>;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
declare type ExplorerRow = {
|
|
165
|
-
id: string;
|
|
166
|
-
title: string;
|
|
167
|
-
/** Optional muted second line (truncates with title). */
|
|
168
|
-
subtitle?: string;
|
|
169
|
-
/** Group key — must match one of the facet values for `groupBy`. */
|
|
170
|
-
group?: string;
|
|
171
|
-
/** Leading mono chip (e.g. type code, frequency). */
|
|
172
|
-
leading?: Badge;
|
|
173
|
-
/** Trailing mono chips for status flags (e.g. [D] derived, [LIVE]). */
|
|
174
|
-
trailing?: Badge[];
|
|
175
|
-
/** Right-aligned plain text for numeric metadata (e.g. "1.2M", "2.4s"). */
|
|
176
|
-
meta?: string;
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
declare type Facets = Record<string, FacetValue[]>;
|
|
180
|
-
|
|
181
|
-
declare type FacetsArgs = {
|
|
182
|
-
filters: Record<string, string[]>;
|
|
183
|
-
signal?: AbortSignal;
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
declare type FacetValue = {
|
|
187
|
-
value: string;
|
|
188
|
-
count: number;
|
|
189
|
-
};
|
|
190
|
-
|
|
191
148
|
export declare interface MockBridgeState {
|
|
192
149
|
openPanels: PanelState[];
|
|
193
150
|
activeFile: string | null;
|
|
@@ -363,26 +320,6 @@ export declare type RenderPaneResult = RenderResult & {
|
|
|
363
320
|
registry: PanelRegistry;
|
|
364
321
|
};
|
|
365
322
|
|
|
366
|
-
declare type SearchArgs = {
|
|
367
|
-
query: string;
|
|
368
|
-
filters: Record<string, string[]>;
|
|
369
|
-
/** Scope to a single group's value (only set when paginating inside a group). */
|
|
370
|
-
group?: {
|
|
371
|
-
key: string;
|
|
372
|
-
value: string;
|
|
373
|
-
};
|
|
374
|
-
limit: number;
|
|
375
|
-
offset: number;
|
|
376
|
-
signal?: AbortSignal;
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
declare type SearchResult = {
|
|
380
|
-
items: ExplorerRow[];
|
|
381
|
-
/** Total count for the current scope (query + filters + optional group). */
|
|
382
|
-
total: number;
|
|
383
|
-
hasMore: boolean;
|
|
384
|
-
};
|
|
385
|
-
|
|
386
323
|
declare interface SessionItem {
|
|
387
324
|
id: string;
|
|
388
325
|
title: string;
|