@hachej/boring-workspace 0.1.0
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/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/CodeEditor-DQqOn4xz.js +266 -0
- package/dist/CommandPalette-aM61U-b0.js +5229 -0
- package/dist/FileTree-DRq_bfue.js +245 -0
- package/dist/MarkdownEditor-DjiHxnRv.js +349 -0
- package/dist/WorkspaceLoadingState-By0dZoPD.js +568 -0
- package/dist/agent-tool-NvxKfist.d.ts +28 -0
- package/dist/app-front.d.ts +485 -0
- package/dist/app-front.js +452 -0
- package/dist/app-server.d.ts +53 -0
- package/dist/app-server.js +769 -0
- package/dist/bootstrapServer-BRUqUpVW.d.ts +66 -0
- package/dist/boring-workspace.css +1 -0
- package/dist/charts.d.ts +114 -0
- package/dist/charts.js +143 -0
- package/dist/events.d.ts +178 -0
- package/dist/events.js +88 -0
- package/dist/explorer-DtLUnuah.d.ts +129 -0
- package/dist/panel-DnvDNQac.js +6 -0
- package/dist/server.d.ts +84 -0
- package/dist/server.js +811 -0
- package/dist/shared.d.ts +113 -0
- package/dist/shared.js +11 -0
- package/dist/testing-e2e.d.ts +68 -0
- package/dist/testing-e2e.js +45 -0
- package/dist/testing.d.ts +464 -0
- package/dist/testing.js +10984 -0
- package/dist/utils-B6yFEsav.js +8 -0
- package/dist/workspace.css +5780 -0
- package/dist/workspace.d.ts +2119 -0
- package/dist/workspace.js +1884 -0
- package/docs/INTERFACES.md +58 -0
- package/docs/PLUGIN_STRUCTURE.md +162 -0
- package/docs/README.md +19 -0
- package/docs/bridge.md +135 -0
- package/docs/panels.md +102 -0
- package/docs/plans/GENERIC_EXPLORER_PLUGIN_PLAN.md +455 -0
- package/docs/plans/MACRO_PLUGIN_GENERIC_HELPERS_AUDIT.md +962 -0
- package/docs/plans/PLUGIN_OUTPUTS_ISOLATION_PLAN.md +301 -0
- package/docs/plans/README.md +9 -0
- package/docs/plans/UI_BRIDGE_OWNERSHIP_REFACTOR.md +303 -0
- package/docs/plans/archive/CODE_OWNERSHIP_CLEANUP_PLAN.md +387 -0
- package/docs/plans/archive/COMMAND_PALETTE_REGISTRY.md +814 -0
- package/docs/plans/archive/DECLARATIVE_LAYOUT_MIGRATION.md +277 -0
- package/docs/plans/archive/PLUGIN_MODEL.md +3674 -0
- package/docs/plans/archive/SRC_FOLDER_REORG_PLAN.md +307 -0
- package/docs/plans/archive/UNIFIED_EVENT_BUS.md +647 -0
- package/docs/plans/archive/WORKSPACE_V2_PLAN.md +2489 -0
- package/docs/plugins.md +158 -0
- package/package.json +164 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
# Generic Explorer Plugin Plan
|
|
2
|
+
|
|
3
|
+
Last updated: 2026-05-01
|
|
4
|
+
|
|
5
|
+
Status: draft plan. No code has moved yet.
|
|
6
|
+
|
|
7
|
+
## Problem
|
|
8
|
+
|
|
9
|
+
Workspace currently has a good generic `DataExplorer` primitive under
|
|
10
|
+
`src/front/components/DataExplorer`. The data-catalog-specific legacy wrappers
|
|
11
|
+
under `src/front/components/data-catalog` have been removed; data catalog behavior
|
|
12
|
+
now lives only in `dataCatalogPlugin`. Feret v2 shows the next requirement: not
|
|
13
|
+
just flat/faceted database rows, but mixed project trees with
|
|
14
|
+
filesystem rows, virtual DB rows, section filters, friendly labels, and domain
|
|
15
|
+
open routing.
|
|
16
|
+
|
|
17
|
+
We need a cleaner ownership model:
|
|
18
|
+
|
|
19
|
+
- `front/` contains only workspace host, chrome, registries, bridge, layout,
|
|
20
|
+
design primitives, and truly generic helpers.
|
|
21
|
+
- `plugins/` owns domain panes, domain data, domain catalogs, domain surface
|
|
22
|
+
resolvers, and reusable plugin-level feature families.
|
|
23
|
+
- Generic explorer behavior should be reusable by many plugins without making
|
|
24
|
+
filesystem depend on data catalog or data catalog depend on filesystem.
|
|
25
|
+
|
|
26
|
+
## Decision
|
|
27
|
+
|
|
28
|
+
Create a dedicated generic explorer plugin/family:
|
|
29
|
+
|
|
30
|
+
```txt
|
|
31
|
+
packages/workspace/src/plugins/explorerPlugin/
|
|
32
|
+
index.tsx
|
|
33
|
+
constants.ts
|
|
34
|
+
types.ts
|
|
35
|
+
Explorer.tsx
|
|
36
|
+
ExplorerPane.tsx
|
|
37
|
+
createExplorerOutputs.ts
|
|
38
|
+
adapters.ts
|
|
39
|
+
useExplorerState.ts
|
|
40
|
+
__tests__/
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This plugin is not a domain plugin. It is a reusable feature plugin that owns
|
|
44
|
+
explorer panes and explorer row contracts. This adds a third plugin category:
|
|
45
|
+
workspace-owned feature plugins. They live under `src/plugins/` because they
|
|
46
|
+
emit panes/outputs and own a feature contract, but they do not encode an app
|
|
47
|
+
domain like files, data catalog, or Feret. Domain plugins compose it:
|
|
48
|
+
|
|
49
|
+
```txt
|
|
50
|
+
dataCatalogPlugin -> uses explorerPlugin for generic explorer rendering
|
|
51
|
+
filesystemPlugin -> may use explorerPlugin for project/friendly trees later
|
|
52
|
+
Feret app plugin -> uses explorerPlugin directly for Project Tree and Data/Feret
|
|
53
|
+
future domain plugin -> uses explorerPlugin for symbols/docs/jobs/issues/etc.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Do **not** put generic explorer under `dataCatalogPlugin`. That would make other
|
|
57
|
+
domains depend on a data-catalog name and blur ownership.
|
|
58
|
+
|
|
59
|
+
## Target Package Shape
|
|
60
|
+
|
|
61
|
+
```txt
|
|
62
|
+
src/front/
|
|
63
|
+
bridge/ # workspace bridge client/dispatcher only
|
|
64
|
+
chrome/ # shell chrome panes: chat host, artifact surface, workbench left
|
|
65
|
+
components/
|
|
66
|
+
ui/ # shadcn-style primitives
|
|
67
|
+
CommandPalette.tsx # generic workspace command/catalog UI
|
|
68
|
+
ErrorChip.tsx
|
|
69
|
+
PanelErrorBoundary.tsx
|
|
70
|
+
WorkspaceLoadingState.tsx
|
|
71
|
+
recent/ # generic recent command/catalog state
|
|
72
|
+
dock/ # dockview shell/chrome
|
|
73
|
+
events/ # cross-cutting event bus
|
|
74
|
+
hooks/ # generic workspace hooks
|
|
75
|
+
layout/ # generic layouts/top bar
|
|
76
|
+
lib/ # generic utils/validation
|
|
77
|
+
plugin/ # registry consumers/inspector/error boundary
|
|
78
|
+
provider/ # WorkspaceProvider
|
|
79
|
+
registry/ # registries and core registrations
|
|
80
|
+
store/ # layout/workspace UI store only
|
|
81
|
+
testing/
|
|
82
|
+
theme/
|
|
83
|
+
toast/
|
|
84
|
+
|
|
85
|
+
src/plugins/
|
|
86
|
+
explorerPlugin/ # generic explorer feature family
|
|
87
|
+
dataCatalogPlugin/ # data catalog specialization
|
|
88
|
+
filesystemPlugin/ # files/editors/tree specialization
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Explorer Plugin API Shape
|
|
92
|
+
|
|
93
|
+
### Row model
|
|
94
|
+
|
|
95
|
+
The current `ExplorerRow` is useful but too flat for Feret project trees. Keep
|
|
96
|
+
flat rows as the base, then add tree/section nodes.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
export type ExplorerBadge = {
|
|
100
|
+
code: string;
|
|
101
|
+
tooltip?: string;
|
|
102
|
+
tone?: "neutral" | "info" | "success" | "warning" | "danger";
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export type ExplorerFilterConfig = {
|
|
106
|
+
key: string;
|
|
107
|
+
label: string;
|
|
108
|
+
order?: string[];
|
|
109
|
+
formatValue?: (value: string) => string;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export type DragPayload = { mimeType: string; value: string };
|
|
113
|
+
|
|
114
|
+
export type ExplorerItemRow<RowKind extends string = string> = {
|
|
115
|
+
kind?: "item";
|
|
116
|
+
/** Domain/type discriminant used by app plugins for routing. */
|
|
117
|
+
rowKind?: RowKind;
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
subtitle?: string;
|
|
121
|
+
group?: string;
|
|
122
|
+
leading?: ExplorerBadge;
|
|
123
|
+
trailing?: ExplorerBadge[];
|
|
124
|
+
meta?: string;
|
|
125
|
+
icon?: React.ComponentType<{ className?: string }>;
|
|
126
|
+
payload?: Record<string, unknown>;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export type ExplorerSectionNode = {
|
|
130
|
+
kind: "section";
|
|
131
|
+
id: string;
|
|
132
|
+
title: string;
|
|
133
|
+
subtitle?: string;
|
|
134
|
+
filters?: ExplorerFilterConfig[];
|
|
135
|
+
count?: number;
|
|
136
|
+
defaultExpanded?: boolean;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export type ExplorerFolderNode = {
|
|
140
|
+
kind: "folder";
|
|
141
|
+
id: string;
|
|
142
|
+
title: string;
|
|
143
|
+
subtitle?: string;
|
|
144
|
+
count?: number;
|
|
145
|
+
defaultExpanded?: boolean;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export type ExplorerNode =
|
|
149
|
+
| ExplorerItemRow
|
|
150
|
+
| ExplorerSectionNode
|
|
151
|
+
| ExplorerFolderNode;
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Flat adapter
|
|
155
|
+
|
|
156
|
+
Keep the current adapter semantics for global catalogs and data tabs.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
export type ExplorerSearchArgs = {
|
|
160
|
+
query: string;
|
|
161
|
+
filters: Record<string, string[]>;
|
|
162
|
+
group?: { key: string; value: string };
|
|
163
|
+
limit: number;
|
|
164
|
+
offset: number;
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export type ExplorerSearchResult = {
|
|
169
|
+
items: ExplorerItemRow[];
|
|
170
|
+
total: number;
|
|
171
|
+
hasMore: boolean;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export type ExplorerFacetValue = { value: string; count: number };
|
|
175
|
+
export type ExplorerFacets = Record<string, ExplorerFacetValue[]>;
|
|
176
|
+
export type ExplorerFacetsArgs = {
|
|
177
|
+
filters: Record<string, string[]>;
|
|
178
|
+
signal?: AbortSignal;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export type ExplorerFlatAdapter = {
|
|
182
|
+
search(args: ExplorerSearchArgs): Promise<ExplorerSearchResult>;
|
|
183
|
+
fetchFacets?(args: ExplorerFacetsArgs): Promise<ExplorerFacets>;
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Tree adapter
|
|
188
|
+
|
|
189
|
+
Add tree/provider support for Feret Project Tree and future friendly project
|
|
190
|
+
views.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
export type ExplorerTreeArgs = {
|
|
194
|
+
query: string;
|
|
195
|
+
/** Global tree filters, if the host exposes any. */
|
|
196
|
+
filters: Record<string, string[]>;
|
|
197
|
+
/** Filters scoped to the parent/section being loaded. */
|
|
198
|
+
scopedFilters?: Record<string, string[]>;
|
|
199
|
+
parentId?: string;
|
|
200
|
+
limit: number;
|
|
201
|
+
offset: number;
|
|
202
|
+
signal?: AbortSignal;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export type ExplorerTreeResult = {
|
|
206
|
+
nodes: ExplorerNode[];
|
|
207
|
+
total?: number;
|
|
208
|
+
hasMore?: boolean;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export type ExplorerTreeAdapter = {
|
|
212
|
+
roots(args: ExplorerTreeArgs): Promise<ExplorerTreeResult>;
|
|
213
|
+
children(
|
|
214
|
+
parentId: string,
|
|
215
|
+
args: ExplorerTreeArgs,
|
|
216
|
+
): Promise<ExplorerTreeResult>;
|
|
217
|
+
fetchNodeFacets?(
|
|
218
|
+
nodeId: string,
|
|
219
|
+
args: ExplorerFacetsArgs,
|
|
220
|
+
): Promise<ExplorerFacets>;
|
|
221
|
+
};
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Component/pane outputs
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
type ExplorerBaseProps = {
|
|
228
|
+
facets?: ExplorerFilterConfig[];
|
|
229
|
+
groupBy?: string;
|
|
230
|
+
onActivate?: (row: ExplorerItemRow) => void;
|
|
231
|
+
getDragPayload?: (row: ExplorerItemRow) => DragPayload | null | undefined;
|
|
232
|
+
emptyState?: React.ReactNode;
|
|
233
|
+
searchPlaceholder?: string;
|
|
234
|
+
query?: string;
|
|
235
|
+
searchable?: boolean;
|
|
236
|
+
className?: string;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export type ExplorerProps =
|
|
240
|
+
| (ExplorerBaseProps & {
|
|
241
|
+
mode?: "flat";
|
|
242
|
+
flatAdapter: ExplorerFlatAdapter;
|
|
243
|
+
treeAdapter?: never;
|
|
244
|
+
})
|
|
245
|
+
| (ExplorerBaseProps & {
|
|
246
|
+
mode: "tree";
|
|
247
|
+
treeAdapter: ExplorerTreeAdapter;
|
|
248
|
+
flatAdapter?: never;
|
|
249
|
+
})
|
|
250
|
+
| (ExplorerBaseProps & {
|
|
251
|
+
/** Auto means: use tree when only treeAdapter is provided, else flat. */
|
|
252
|
+
mode: "auto";
|
|
253
|
+
flatAdapter?: ExplorerFlatAdapter;
|
|
254
|
+
treeAdapter?: ExplorerTreeAdapter;
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
export type CreateExplorerOutputsOptions = ExplorerProps & {
|
|
258
|
+
id: string;
|
|
259
|
+
label: string;
|
|
260
|
+
leftTabId?: string;
|
|
261
|
+
includeLeftTab?: boolean;
|
|
262
|
+
panelId?: string;
|
|
263
|
+
includePanel?: boolean;
|
|
264
|
+
/** Existing workspace core panel config source type. */
|
|
265
|
+
source?: PanelConfig["source"];
|
|
266
|
+
};
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`createExplorerOutputs()` emits generic left-tab/panel outputs only. It does not
|
|
270
|
+
emit data-catalog catalogs or data-catalog surface resolvers.
|
|
271
|
+
|
|
272
|
+
Implementation must validate adapter/mode combinations at runtime too:
|
|
273
|
+
|
|
274
|
+
- `flat` requires `flatAdapter`.
|
|
275
|
+
- `tree` requires `treeAdapter`.
|
|
276
|
+
- `auto` chooses `tree` only when `treeAdapter` exists and `flatAdapter` does
|
|
277
|
+
not; otherwise it chooses `flat`.
|
|
278
|
+
- missing adapters throw a development-facing invariant error rather than
|
|
279
|
+
rendering an empty explorer. The `auto` union may be tightened to require at
|
|
280
|
+
least one adapter during implementation; runtime validation remains required
|
|
281
|
+
either way.
|
|
282
|
+
|
|
283
|
+
## Data Catalog After Refactor
|
|
284
|
+
|
|
285
|
+
`dataCatalogPlugin` becomes a specialization that composes explorer outputs:
|
|
286
|
+
|
|
287
|
+
```txt
|
|
288
|
+
dataCatalogPlugin/
|
|
289
|
+
index.tsx # createDataCatalogPlugin, appendDataCatalogOutputs
|
|
290
|
+
constants.ts
|
|
291
|
+
types.ts
|
|
292
|
+
catalogs.ts # data catalog catalog config helpers
|
|
293
|
+
surfaceResolver.ts
|
|
294
|
+
openVisualization.ts
|
|
295
|
+
hooks.ts
|
|
296
|
+
server/
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Responsibilities:
|
|
300
|
+
|
|
301
|
+
- choose data-catalog defaults: labels, empty state, search placeholder
|
|
302
|
+
- register `CatalogConfig`
|
|
303
|
+
- default `onSelect` posts `openSurface`
|
|
304
|
+
- create row visualization panel/resolver when requested
|
|
305
|
+
- provide server agent tool helpers for querying a catalog adapter
|
|
306
|
+
|
|
307
|
+
Non-responsibilities:
|
|
308
|
+
|
|
309
|
+
- own generic explorer rendering
|
|
310
|
+
- own generic explorer row state machine
|
|
311
|
+
- own filesystem/project tree behavior
|
|
312
|
+
|
|
313
|
+
Legacy `src/front/components/data-catalog` is removed. Consumers should use
|
|
314
|
+
`createDataCatalogPlugin()` / `appendDataCatalogOutputs()` or compose
|
|
315
|
+
`DataExplorer` directly until it moves to `explorerPlugin`.
|
|
316
|
+
|
|
317
|
+
## Feret v2 Requirements Driving Explorer Plugin
|
|
318
|
+
|
|
319
|
+
Feret needs two explorer usages.
|
|
320
|
+
|
|
321
|
+
### Data/Feret tab
|
|
322
|
+
|
|
323
|
+
Flat/faceted data explorer:
|
|
324
|
+
|
|
325
|
+
- DB/API-backed ingredient/document/formulation rows
|
|
326
|
+
- search input
|
|
327
|
+
- category/status/supplier facets
|
|
328
|
+
- row badges and cost/status metadata
|
|
329
|
+
- open row into domain pane
|
|
330
|
+
- drag ingredients into formulation builder later
|
|
331
|
+
|
|
332
|
+
This maps to `ExplorerFlatAdapter`.
|
|
333
|
+
|
|
334
|
+
### Feret Project Tree
|
|
335
|
+
|
|
336
|
+
Mixed tree explorer:
|
|
337
|
+
|
|
338
|
+
- real markdown/source files
|
|
339
|
+
- virtual DB rows: ingredient, formulation, process, scenario
|
|
340
|
+
- sections: Brief, Sources, Ingredients, Formulations, Notes, Reports
|
|
341
|
+
- section-local filters
|
|
342
|
+
- friendly labels hiding technical paths/extensions
|
|
343
|
+
- click routing by row type:
|
|
344
|
+
- markdown -> filesystem markdown editor/open file
|
|
345
|
+
- source file -> source preview/extraction review
|
|
346
|
+
- ingredient -> ingredient detail pane
|
|
347
|
+
- formulation -> formulation builder/detail pane
|
|
348
|
+
|
|
349
|
+
This maps to `ExplorerTreeAdapter` plus row `payload`/`kind` routing controlled
|
|
350
|
+
by the Feret app plugin. Section-local filters must stay scoped: the explorer
|
|
351
|
+
state tracks active filters per section/folder id and passes them to
|
|
352
|
+
`children(parentId, { scopedFilters })` rather than flattening them into global
|
|
353
|
+
filters.
|
|
354
|
+
|
|
355
|
+
## Current Component Ownership Audit
|
|
356
|
+
|
|
357
|
+
| Current location | Decision | Rationale |
|
|
358
|
+
| --------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
359
|
+
| `front/components/DataExplorer/*` | Move to `plugins/explorerPlugin/*` | Generic feature family, but pane-capable and adapter-owned; multiple plugins depend on it. |
|
|
360
|
+
| `front/components/data-catalog/*` | Removed | Data-catalog naming is domain-ish; real data catalog behavior is plugin-owned already. |
|
|
361
|
+
| `front/components/CommandPalette.tsx` | Keep in `front/components` | Generic workspace chrome over command/catalog registries, not a domain plugin. |
|
|
362
|
+
| `front/components/recent/*` | Keep in `front/components` for now | Generic command/catalog recent state used by CommandPalette. Could become `commandPalette` subfolder later. |
|
|
363
|
+
| `front/components/ErrorChip.tsx` | Keep generic | Generic error UI primitive. |
|
|
364
|
+
| `front/components/PanelErrorBoundary.tsx` | Keep generic | Generic plugin/panel safety boundary. |
|
|
365
|
+
| `front/components/WorkspaceLoadingState.tsx` | Keep generic | Generic shell loading UI. |
|
|
366
|
+
| `front/components/SessionList.tsx` | Re-evaluate after checking package-root consumers and whether it is only used by `SessionBrowser` | If it is just session chrome, consolidate under `front/chrome/session-list`; if consumers need a standalone primitive, keep a re-exported primitive. |
|
|
367
|
+
| `@boring/ui/*` | Keep generic | Design primitives only. |
|
|
368
|
+
| `front/chrome/artifact-surface/*` | Keep in front chrome | Core workspace surface host, not plugin domain. |
|
|
369
|
+
| `front/chrome/chat/*` | Keep in front chrome | Chat host injection point, not agent/plugin domain. |
|
|
370
|
+
| `front/chrome/empty-pane/*` | Keep or move to core chrome | Generic shell fallback. Not a domain plugin. |
|
|
371
|
+
| `front/chrome/session-list/*` | Keep in front chrome, maybe consolidate `SessionList` here | Session chrome is host-level. |
|
|
372
|
+
| `front/chrome/workbench-left/*` | Keep in front chrome | Renders plugin left-tabs; host chrome. |
|
|
373
|
+
| `plugins/filesystemPlugin/front/file-tree/*` | Keep in filesystem plugin for now | File-specific tree, path behavior, events, and open-file routing are domain-owned. May reuse explorer tree later. |
|
|
374
|
+
| `plugins/filesystemPlugin/front/code-editor/*` | Keep in filesystem plugin | File editor domain and file data hooks. |
|
|
375
|
+
| `plugins/filesystemPlugin/front/markdown-editor/*` | Keep in filesystem plugin | File editor domain and file data hooks. |
|
|
376
|
+
| `plugins/filesystemPlugin/front/empty-file-panel/*` | Keep in filesystem plugin | File-specific empty panel. |
|
|
377
|
+
| `plugins/dataCatalogPlugin/front/*` | Keep plugin-owned, but import explorer from `explorerPlugin` | Domain specialization. |
|
|
378
|
+
|
|
379
|
+
## Public API Migration
|
|
380
|
+
|
|
381
|
+
Avoid breaking current consumers in the first pass.
|
|
382
|
+
|
|
383
|
+
1. Add `plugins/explorerPlugin` and re-export explorer APIs from old package
|
|
384
|
+
root names:
|
|
385
|
+
- `DataExplorer` stays exported, but source moves.
|
|
386
|
+
- `ExplorerRow`, `ExplorerAdapter`, `FacetConfig`, etc. stay exported with
|
|
387
|
+
compatibility aliases.
|
|
388
|
+
2. Keep `front/components/DataExplorer/index.ts` as a thin deprecated re-export
|
|
389
|
+
for one release if internal import churn is high.
|
|
390
|
+
3. `DataCatalog` and `DataCatalogPane` root exports are removed now; use data catalog plugin helpers instead.
|
|
391
|
+
4. Move app/plugin imports to `plugins/explorerPlugin` or package-root exports.
|
|
392
|
+
|
|
393
|
+
## Implementation Beads
|
|
394
|
+
|
|
395
|
+
### Bead 1 — Explorer plugin skeleton
|
|
396
|
+
|
|
397
|
+
- Add `src/plugins/explorerPlugin` with current `DataExplorer` code moved mostly
|
|
398
|
+
intact.
|
|
399
|
+
- Export compatibility aliases.
|
|
400
|
+
- Update internal imports from `front/components/DataExplorer` to
|
|
401
|
+
`plugins/explorerPlugin`.
|
|
402
|
+
- Tests: current DataExplorer tests pass unchanged after path update.
|
|
403
|
+
|
|
404
|
+
### Bead 2 — Data catalog plugin composition
|
|
405
|
+
|
|
406
|
+
- Change `dataCatalogPlugin` to import explorer APIs from `explorerPlugin`.
|
|
407
|
+
- Split data catalog helpers into `catalogs.ts` if useful.
|
|
408
|
+
- Keep `front/components/data-catalog` removed; do not add compatibility wrappers back.
|
|
409
|
+
- Tests: dataCatalogPlugin tests and public API tests.
|
|
410
|
+
|
|
411
|
+
### Bead 3 — Tree adapter design
|
|
412
|
+
|
|
413
|
+
- Add `ExplorerTreeAdapter`, `ExplorerNode`, section/folder node types.
|
|
414
|
+
- Add tree state hook or extend explorer state carefully, including per-section
|
|
415
|
+
filter maps that flow into `ExplorerTreeArgs.scopedFilters`.
|
|
416
|
+
- Do not rewrite filesystem tree yet.
|
|
417
|
+
- Tests: adapter contract, expansion, per-node loading, abort handling.
|
|
418
|
+
|
|
419
|
+
### Bead 4 — Feret project tree spike
|
|
420
|
+
|
|
421
|
+
- In Feret v2/app playground, build a project tree using `ExplorerTreeAdapter`.
|
|
422
|
+
- Prove mixed rows and section filters.
|
|
423
|
+
- Keep row activation domain-owned by Feret plugin.
|
|
424
|
+
- Output is either a shippable Feret integration PR or a plan update with the
|
|
425
|
+
gaps found during the spike.
|
|
426
|
+
|
|
427
|
+
### Bead 5 — Optional filesystem reuse
|
|
428
|
+
|
|
429
|
+
- Evaluate whether filesystem tree should remain custom or wrap explorer tree.
|
|
430
|
+
- Decision trigger: after the Feret project tree spike, compare required file
|
|
431
|
+
tree behavior (path validation, file events, expand-to-file, selection, editor
|
|
432
|
+
lifecycle) against explorer tree behavior.
|
|
433
|
+
- Exit criteria: record either `keep custom filesystem tree` or `migrate
|
|
434
|
+
filesystem tree to explorer tree` before the legacy data-catalog removal bead.
|
|
435
|
+
- Only migrate if benefits outweigh loss of file-tree-specific behavior.
|
|
436
|
+
|
|
437
|
+
## Non-goals
|
|
438
|
+
|
|
439
|
+
- Do not make every visual component a plugin. `@boring/ui`, layout,
|
|
440
|
+
chrome hosts, registries, bridge, and provider stay front-owned.
|
|
441
|
+
- Do not force filesystem to depend on data catalog.
|
|
442
|
+
- Do not rewrite file tree in the first bead.
|
|
443
|
+
- Do not remove public exports without an explicit breaking cleanup bead.
|
|
444
|
+
- Do not allow reverse imports from `explorerPlugin` into domain plugins. Add or
|
|
445
|
+
extend invariant lint so allowed direction is domain plugin -> explorerPlugin,
|
|
446
|
+
never explorerPlugin -> dataCatalogPlugin/filesystemPlugin/app plugins.
|
|
447
|
+
|
|
448
|
+
## Acceptance Criteria
|
|
449
|
+
|
|
450
|
+
- `front/` contains only generic host/chrome/primitives after migration.
|
|
451
|
+
- Domain-named components do not live under `front/components`.
|
|
452
|
+
- Explorer APIs are reusable by data catalog, filesystem, and Feret without
|
|
453
|
+
cross-domain plugin imports.
|
|
454
|
+
- Existing public API remains source-compatible until an approved breaking bead.
|
|
455
|
+
- Feret Project Tree requirements are representable without forking explorer UI.
|