@hachej/boring-workspace 0.1.13 → 0.1.16

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 (34) hide show
  1. package/README.md +270 -42
  2. package/dist/CommandPalette-NOEOVkN2.js +5714 -0
  3. package/dist/{FileTree-BVfqs3rR.js → FileTree-Dl-qUAB0.js} +9 -9
  4. package/dist/MarkdownEditor-yc6mFsnI.js +533 -0
  5. package/dist/{WorkspaceLoadingState-BjZGQLS_.js → WorkspaceLoadingState-CSZfENWe.js} +145 -124
  6. package/dist/agent-tool-DEtfQPVB.d.ts +100 -0
  7. package/dist/app-front.d.ts +79 -67
  8. package/dist/app-front.js +253 -241
  9. package/dist/app-server.d.ts +17 -12
  10. package/dist/app-server.js +80 -10
  11. package/dist/{bootstrapServer-BRUqUpVW.d.ts → bootstrapServer-BreQ9QBc.d.ts} +8 -2
  12. package/dist/server.d.ts +10 -32
  13. package/dist/server.js +22 -127
  14. package/dist/shared.d.ts +1 -2
  15. package/dist/testing.d.ts +0 -63
  16. package/dist/testing.js +2248 -2401
  17. package/dist/workspace.css +1616 -974
  18. package/dist/workspace.d.ts +111 -450
  19. package/dist/workspace.js +417 -1635
  20. package/docs/INTERFACES.md +2 -2
  21. package/docs/PLUGIN_STRUCTURE.md +1 -1
  22. package/docs/plans/ASK_USER_QUESTIONS_PLUGIN_SPEC.md +131 -263
  23. package/docs/plans/GENERIC_EXPLORER_PLUGIN_PLAN.md +29 -27
  24. package/docs/plans/MACRO_PLUGIN_GENERIC_HELPERS_AUDIT.md +12 -12
  25. package/docs/plans/PANE_TO_AGENT_CHAT_ACTIONS_SPEC.md +366 -0
  26. package/docs/plans/README.md +2 -0
  27. package/docs/plans/archive/PLUGIN_MODEL.md +14 -14
  28. package/docs/plans/archive/SRC_FOLDER_REORG_PLAN.md +2 -3
  29. package/docs/plans/archive/WORKSPACE_V2_PLAN.md +1 -1
  30. package/package.json +3 -6
  31. package/dist/CommandPalette-Dme9em28.js +0 -5506
  32. package/dist/MarkdownEditor-CcCDF65H.js +0 -502
  33. package/dist/agent-tool-NvxKfist.d.ts +0 -28
  34. package/dist/explorer-DtLUnuah.d.ts +0 -129
@@ -320,7 +320,7 @@ createDataCatalogPreset({
320
320
  });
321
321
  ```
322
322
 
323
- Owner: `dataCatalogPlugin`, not macro.
323
+ Owner: the `@hachej/boring-data-catalog` package, not macro.
324
324
 
325
325
  2. **Drag payload helper**
326
326
 
@@ -328,7 +328,7 @@ Owner: `dataCatalogPlugin`, not macro.
328
328
  getDragPayload: createTextDragPayload("text/series-id", (row) => row.id);
329
329
  ```
330
330
 
331
- Owner: future `explorerPlugin` or `DataExplorer/adapters`.
331
+ Owner: the future `@hachej/boring-data-explorer` package or `DataExplorer/adapters`.
332
332
 
333
333
  3. **Facet config helper**
334
334
 
@@ -406,8 +406,8 @@ Also extract generic query helper:
406
406
  toQueryString(params: Record<string, string | number | string[] | undefined>): string
407
407
  ```
408
408
 
409
- Owner: `explorerPlugin/adapters.ts` once created. Temporary owner can be
410
- `front/components/DataExplorer/adapters.ts`.
409
+ Owner: `@hachej/boring-data-explorer/adapters.ts` once created. Temporary owner can be
410
+ `@hachej/boring-data-explorer/front` adapter helpers.
411
411
 
412
412
  Risk: don't overfit response shape. Keep mapper hooks explicit.
413
413
 
@@ -563,7 +563,7 @@ surfaceResolverOutputs(resolvers): PluginOutput[]
563
563
  ```
564
564
 
565
565
  Owner: `front/registry/surfaceResolverHelpers.ts` or future
566
- `plugins/explorerPlugin/surface.ts`. Since these helpers are not explorer-only,
566
+ `@hachej/boring-data-explorer` surface helpers. Since these helpers are not explorer-only,
567
567
  prefer `front/registry` or a new `front/surface` module.
568
568
 
569
569
  ### `data/macroSeriesData.ts`
@@ -662,7 +662,7 @@ createOpenSurfacePrompt({
662
662
  });
663
663
  ```
664
664
 
665
- Owner: workspace server UI-control or dataCatalogPlugin server utilities.
665
+ Owner: workspace server UI-control or data catalog package server utilities.
666
666
 
667
667
  3. **Provisioning type**
668
668
 
@@ -851,16 +851,16 @@ Better integration opportunities:
851
851
  plugin composition.
852
852
  3. `createRestExplorerAdapter()` for `/catalog` + `/facets` endpoints.
853
853
  4. `createOpenSurfaceRowHandler()` for catalog row activation.
854
- 5. Future `explorerPlugin` owns explorer primitives and adapter helpers;
855
- `dataCatalogPlugin` composes them.
854
+ 5. The future `@hachej/boring-data-explorer` package owns explorer primitives and adapter helpers;
855
+ the `@hachej/boring-data-catalog` package composes them.
856
856
 
857
- Do not make macro depend directly on a future `explorerPlugin` if
858
- `dataCatalogPlugin` can provide the right data-catalog specialization. Macro
857
+ Do not make macro depend directly on a future `@hachej/boring-data-explorer` package if
858
+ the `@hachej/boring-data-catalog` package can provide the right data-catalog specialization. Macro
859
859
  should depend on the highest-level appropriate abstraction:
860
860
 
861
861
  ```txt
862
- macro series catalog -> dataCatalogPlugin plugin/factory
863
- macro custom project/tree explorer -> explorerPlugin plugin/factory
862
+ macro series catalog -> data catalog package plugin/factory
863
+ macro custom project/tree explorer -> data explorer package plugin/factory
864
864
  macro chart/deck panels -> macro-owned panels
865
865
  ```
866
866
 
@@ -0,0 +1,366 @@
1
+ # Pane to Agent Chat Actions Spec
2
+
3
+ Last updated: 2026-05-08
4
+
5
+ ## Summary
6
+
7
+ Add a first-class way for Workspace panes/plugins to send a message into the
8
+ active visible agent chat without bypassing `ChatPanel` and `useAgentChat()`.
9
+
10
+ This is separate from the `ask_user` Questions submit path. `ask_user` answers
11
+ resolve a blocked tool through the Questions browser -> server command channel.
12
+ Pane-to-agent chat actions are for user-triggered conversational messages such
13
+ as "Analyze this chart", "Explain this result", or "Ask the agent about this
14
+ pane".
15
+
16
+ ## Problem
17
+
18
+ Today panes cannot cleanly send a message into the active agent session.
19
+
20
+ Current flow:
21
+
22
+ - `ChatPanel` owns `sendMessage` privately through `useAgentChat()`.
23
+ - `useAgentChat()` wraps AI SDK `useChat()` and posts to
24
+ `POST /api/v1/agent/chat` with `{ sessionId, message, model, thinkingLevel,
25
+ attachments }`.
26
+ - `ChatPanel.handleSubmit()` delegates to AI SDK `sendMessage()` and does not
27
+ expose that foreground-chat path to panes.
28
+ - While chat is submitted/streaming, the current composer behavior is owned by
29
+ `ChatPanel`; this plan does not invent a separate follow-up endpoint.
30
+ - `WorkspaceAgentFront` / `ChatPanelHost` wrap chat for stream data events,
31
+ artifact opening, and agent -> UI commands.
32
+ - Existing Workspace UI bridge is agent/server -> pane commands. It is not a
33
+ pane -> active chat message API.
34
+
35
+ A pane can technically call `/api/v1/agent/chat` directly, but that is the wrong
36
+ integration for foreground chat UX because it bypasses:
37
+
38
+ - visible user bubble state
39
+ - AI SDK `useChat()` state
40
+ - current session selection
41
+ - model/thinking-level selection
42
+ - request headers
43
+ - attachment handling and composer validation
44
+ - streaming/busy state
45
+ - history/persistence expectations
46
+
47
+ Direct HTTP is acceptable only for intentionally headless/background agent jobs,
48
+ not for "send this as a message in the current chat".
49
+
50
+ ## Goals
51
+
52
+ - Let panes/plugins send a message into the active visible agent chat.
53
+ - Preserve `ChatPanel` as the owner of foreground chat send behavior.
54
+ - Preserve current session, model, thinking level, request headers, attachments,
55
+ visible bubbles, busy-state behavior, and persistence behavior.
56
+ - Expose a stable Workspace-facing hook/helper for panes.
57
+ - Support plugin/module-graph boundaries with an event fallback.
58
+ - Keep Workspace base front/shared code package-neutral where required; app/front
59
+ composition may import documented `@boring/agent/front` APIs.
60
+
61
+ ## Non-goals
62
+
63
+ - Replacing `useAgentChat()` or changing the agent chat transport.
64
+ - Making panes call `/api/v1/agent/chat` directly for foreground chat.
65
+ - Implementing a new follow-up queue or `/followup` route in v1.
66
+ - Using this path for `ask_user` form submission.
67
+ - Background/headless agent jobs.
68
+ - Multi-agent routing or sending to arbitrary non-active sessions in v1.
69
+
70
+ ## Architecture
71
+
72
+ Use both an imperative controller and a browser event helper:
73
+
74
+ 1. `ChatPanel` exposes an `AgentChatController` that wraps its existing visible
75
+ composer send path.
76
+ 2. Workspace app/front composition stores the active controller near
77
+ `WorkspaceAgentFront`.
78
+ 3. Panes call a stable hook/helper such as `useAgentActions().sendMessage(...)`.
79
+ 4. Plugins that cannot reliably share React context may call
80
+ `postAgentMessage(...)`, which dispatches a browser event caught by the same
81
+ Workspace app/front bridge and forwarded to the active controller.
82
+
83
+ ## Export/API placement
84
+
85
+ - `AgentChatController`, `AgentChatControllerRegistration`, and
86
+ `AgentChatMessageInput` should be exported as **types** from
87
+ `@boring/agent/front`.
88
+ - `useAgentActions()`, `AgentActionsProvider`, and `postAgentMessage()` should be
89
+ exported from `@boring/workspace/app/front` because they are part of the
90
+ Workspace + Agent composition layer.
91
+ - Base Workspace front/shared code must not value-import `@boring/agent`.
92
+ - If a package-neutral Workspace type is needed, keep it structurally typed and
93
+ free of agent value imports.
94
+
95
+ Intended imports:
96
+
97
+ ```ts
98
+ import type { AgentChatMessageInput } from "@boring/agent/front"
99
+ import { useAgentActions, postAgentMessage } from "@boring/workspace/app/front"
100
+ ```
101
+
102
+ ## Contracts
103
+
104
+ ### Agent chat controller
105
+
106
+ ```ts
107
+ export interface AgentChatAttachmentInput {
108
+ filename?: string
109
+ mediaType: string
110
+ url: string
111
+ }
112
+
113
+ export interface AgentChatMessageInput {
114
+ text: string
115
+ files?: AgentChatAttachmentInput[]
116
+ metadata?: Record<string, unknown>
117
+ allowSlashCommands?: boolean
118
+ }
119
+
120
+ export interface AgentChatControllerRegistration {
121
+ controllerId: string
122
+ sessionId: string
123
+ controller: AgentChatController
124
+ }
125
+
126
+ export interface AgentChatController {
127
+ sendAgentMessage(input: AgentChatMessageInput): Promise<void>
128
+ canSendAgentMessage(): boolean
129
+ }
130
+ ```
131
+
132
+ `ChatPanel` owns the implementation. It should expose the controller through a
133
+ prop such as:
134
+
135
+ ```ts
136
+ interface ChatPanelProps {
137
+ onControllerReady?: (registration: AgentChatControllerRegistration | null) => void
138
+ }
139
+ ```
140
+
141
+ Lifecycle rules:
142
+
143
+ - `ChatPanel` calls `onControllerReady(registration)` when mounted and ready.
144
+ - `ChatPanel` calls `onControllerReady(null)` on unmount or when the active
145
+ controller becomes invalid.
146
+ - Workspace stores the active controller by `controllerId` and `sessionId`.
147
+ - Unregister clears the active controller only when `controllerId` matches the
148
+ currently registered controller. An old unmount must not clear a newer active
149
+ controller.
150
+ - `ChatPanel` re-registers when `sessionId`, request headers, model,
151
+ thinking-level, or the underlying send callback changes.
152
+ - The controller method delegates to the same path as user composer submit.
153
+ - If chat is submitted/streaming, default v1 behavior rejects with
154
+ `AGENT_CHAT_BUSY` and `canSendAgentMessage()` returns false. Runtimes with an
155
+ explicit native follow-up capability may route busy-time user messages through
156
+ their documented follow-up path instead of rejecting.
157
+ - Workspace attention blockers override native follow-up. If a pending
158
+ `ask_user`/Questions blocker exists for the active session,
159
+ `canSendAgentMessage()` returns false and `sendAgentMessage()` rejects/blocks;
160
+ the message must not be converted into a hidden follow-up because the active
161
+ tool expects a structured form answer.
162
+ - It must not create a separate hidden chat stream.
163
+
164
+ ### Promise semantics
165
+
166
+ `sendAgentMessage()` / `sendMessage()` promises resolve when the message is
167
+ accepted into the visible ChatPanel send path and local user-message handling has
168
+ completed. They do **not** wait for the assistant response stream to finish.
169
+
170
+ Promise rejection is for immediate failures only:
171
+
172
+ - invalid input
173
+ - no active controller
174
+ - stale controller
175
+ - chat busy/submitted/streaming
176
+ - synchronous failure while enqueueing/sending
177
+
178
+ Async model/network failures after the message is accepted surface through the
179
+ existing chat error UI and optional notifications. They are not guaranteed to
180
+ reject the original pane promise.
181
+
182
+ ### Workspace agent actions
183
+
184
+ Workspace app/front exposes a provider/hook for panes:
185
+
186
+ ```ts
187
+ export interface AgentActions {
188
+ sendMessage(input: AgentChatMessageInput): Promise<void>
189
+ canSendMessage(): boolean
190
+ }
191
+
192
+ export function useAgentActions(): AgentActions
193
+ ```
194
+
195
+ Behavior:
196
+
197
+ - If no active controller exists, `sendMessage` rejects with
198
+ `AGENT_CHAT_CONTROLLER_UNAVAILABLE` and may show a workspace notification.
199
+ - If the active controller changes between call start and dispatch,
200
+ `sendMessage` rejects with `AGENT_CHAT_CONTROLLER_STALE`.
201
+ - If chat is busy/submitted/streaming, `sendMessage` rejects with
202
+ `AGENT_CHAT_BUSY`.
203
+ - `canSendMessage()` returns false when no active chat controller is registered
204
+ or when the active controller reports busy/unavailable.
205
+ - The hook sends to the active visible chat session only.
206
+
207
+ ### Event fallback
208
+
209
+ For plugin/module graph safety, expose a same-window browser event helper:
210
+
211
+ ```ts
212
+ export const AGENT_MESSAGE_EVENT = "boring:agent-message"
213
+
214
+ export interface PostAgentMessageInput {
215
+ workspaceId?: string
216
+ text: string
217
+ metadata?: Record<string, unknown>
218
+ allowSlashCommands?: boolean
219
+ }
220
+
221
+ export function postAgentMessage(input: PostAgentMessageInput): boolean {
222
+ return globalThis.dispatchEvent(new CustomEvent(AGENT_MESSAGE_EVENT, { detail: input }))
223
+ }
224
+ ```
225
+
226
+ Event fallback is fire-and-forget. The boolean only means the browser event was
227
+ dispatched to at least one same-window listener; it is not delivery confirmation.
228
+ Use `useAgentActions()` when the caller needs promise feedback.
229
+
230
+ Workspace app/front listens for `AGENT_MESSAGE_EVENT`, validates the payload, and
231
+ forwards it to the active `AgentChatController`.
232
+
233
+ Event rules:
234
+
235
+ - Event fallback v1 is text + metadata only. Attachments are allowed through the
236
+ hook/controller path, not global events.
237
+ - The event is for trusted same-origin plugin code only. It is not a security
238
+ boundary.
239
+ - The event is same-window only and does not cross tabs by default.
240
+ - `workspaceId` routes events when multiple Workspace shells are mounted in one
241
+ window. If omitted and more than one active controller exists, Workspace
242
+ rejects/ignores the event as ambiguous and may show a notification.
243
+ - Invalid payloads are ignored with a developer-facing warning.
244
+ - If no controller is active, Workspace shows a non-fatal notification such as
245
+ "No active agent chat is available."
246
+ - Event sends are subject to the same busy-state rejection and debounce/rate
247
+ limiting as hook sends.
248
+
249
+ ## Pane usage
250
+
251
+ Preferred React usage:
252
+
253
+ ```tsx
254
+ function ChartPane({ chartId }: { chartId: string }) {
255
+ const agent = useAgentActions()
256
+
257
+ return (
258
+ <Button
259
+ disabled={!agent.canSendMessage()}
260
+ onClick={() =>
261
+ agent.sendMessage({
262
+ text: `Analyze this chart: ${chartId}`,
263
+ metadata: { source: "chart-pane", chartId },
264
+ })
265
+ }
266
+ >
267
+ Ask agent
268
+ </Button>
269
+ )
270
+ }
271
+ ```
272
+
273
+ Event fallback:
274
+
275
+ ```ts
276
+ postAgentMessage({
277
+ text: "Explain the selected result",
278
+ metadata: { source: "results-pane" },
279
+ })
280
+ ```
281
+
282
+ Do not call `/api/v1/agent/chat` directly from panes for visible chat UX. Use the
283
+ hook or event helper so the visible chat owner remains `ChatPanel`.
284
+
285
+ ## Error handling
286
+
287
+ Add or reuse stable Workspace/app-front error codes for:
288
+
289
+ - `AGENT_CHAT_CONTROLLER_UNAVAILABLE`
290
+ - `AGENT_CHAT_CONTROLLER_STALE`
291
+ - `AGENT_CHAT_BUSY`
292
+ - `AGENT_CHAT_MESSAGE_INVALID`
293
+ - `AGENT_CHAT_SEND_FAILED`
294
+ - `AGENT_CHAT_AMBIGUOUS_WORKSPACE`
295
+
296
+ Errors should be surfaced as non-fatal UI notifications and promise rejections
297
+ from `sendMessage()` when the caller uses the hook/controller path. Event path
298
+ errors are notification/log only.
299
+
300
+ ## Security and validation
301
+
302
+ - Panes can only send to the active visible chat session in v1.
303
+ - The server remains responsible for authorization on chat requests; this plan
304
+ does not weaken existing auth.
305
+ - Client-side validation should use exported constants shared with the composer
306
+ where possible.
307
+ - Suggested v1 limits:
308
+ - `text.trim().length >= 1` unless files are present
309
+ - max message length matches server/chat composer limits
310
+ - max attachments: 20
311
+ - max attachment size: 5 MiB when size is knowable
312
+ - allowed attachment URL schemes: `blob:`, `data:`, or same-origin URLs only
313
+ - max attachment URL/string byte length to prevent giant data-url bypasses
314
+ - metadata is JSON-serializable, max depth 4, max serialized bytes 4096
315
+ - `metadata` is client-side advisory only in v1. It is not sent to the server or
316
+ agent unless the caller explicitly includes it in `text`.
317
+ - Event helper payloads must be runtime-validated before forwarding.
318
+ - Pane-originated messages bypass slash-command parsing by default. Set
319
+ `allowSlashCommands: true` only when the caller intentionally wants composer
320
+ slash-command behavior.
321
+
322
+ ## Relationship to `ask_user`
323
+
324
+ This plan does not change `ask_user` answer submission.
325
+
326
+ - `ask_user` answer path:
327
+ `Questions pane -> Questions browser/server command -> AskUserCoordinator`
328
+ - pane-to-agent chat action path:
329
+ `pane -> AgentChatController -> ChatPanel/useAgentChat -> visible chat`
330
+
331
+ Do not use pane-to-agent chat actions to submit generated form answers. Use it
332
+ only when the user intentionally wants to send a conversational message to the
333
+ agent.
334
+
335
+ ## Acceptance criteria
336
+
337
+ - `ChatPanel` exposes an `AgentChatController` lifecycle callback or equivalent
338
+ controller ref.
339
+ - Workspace app/front stores the active controller by `controllerId`/`sessionId`
340
+ and exposes `useAgentActions()`.
341
+ - `postAgentMessage()` event helper forwards text-only messages to the active
342
+ controller when unambiguous.
343
+ - Pane calls produce visible user messages in the active chat.
344
+ - Pane calls reject/disable while chat is submitted/streaming with
345
+ `AGENT_CHAT_BUSY` in v1.
346
+ - Pane calls preserve model/thinking-level/session/request-header behavior by
347
+ delegating to `ChatPanel` internals.
348
+ - Calling from a pane when no active controller exists fails gracefully with a
349
+ stable error/notification.
350
+ - Plugin author docs/templates mention: foreground chat uses
351
+ `useAgentActions()` / `postAgentMessage()`; direct HTTP is only for
352
+ background/headless jobs.
353
+ - Tests cover:
354
+ - controller registration/unregistration
355
+ - old unregister cannot clear newer controller
356
+ - session switch re-registers and stale controller rejects
357
+ - hook-based send
358
+ - event-based send
359
+ - busy/submitted/streaming rejection
360
+ - promise resolves on local accept/enqueue, not assistant completion
361
+ - unavailable controller path
362
+ - invalid event payload rejection
363
+ - multiple Workspace shells / ambiguous event routing
364
+ - attachment count/URL/size validation on hook path
365
+ - metadata size/depth validation
366
+ - slash-command bypass by default and opt-in behavior
@@ -2,6 +2,8 @@
2
2
 
3
3
  Active ownership records live in this folder.
4
4
 
5
+ - `ASK_USER_QUESTIONS_PLUGIN_SPEC.md` - blocking ask-user tool + Questions workspace plugin spec.
6
+ - `PANE_TO_AGENT_CHAT_ACTIONS_SPEC.md` - pane/plugin to active agent chat action bridge spec.
5
7
  - `GENERIC_EXPLORER_PLUGIN_PLAN.md` - generic explorer plugin shape and front/plugin ownership audit.
6
8
  - `MACRO_PLUGIN_GENERIC_HELPERS_AUDIT.md` - macro plugin audit for reusable explorer/surface/event helper extraction.
7
9
  - `PLUGIN_OUTPUTS_ISOLATION_PLAN.md` - plugin ownership and isolation plan.
@@ -11,7 +11,7 @@
11
11
  > are superseded by generic `surface-resolver` outputs. Workspace core owns
12
12
  > only the resolver registry and `openSurface` dispatch. Filesystem path/glob
13
13
  > mapping lives in `plugins/filesystemPlugin/surfaceResolver.ts`; data catalog
14
- > row-to-visualization mapping lives in `plugins/dataCatalogPlugin`.
14
+ > row-to-visualization mapping now lives in `@hachej/boring-data-catalog`.
15
15
 
16
16
  Prior status (v7.6): round-5 review patches — Step 0 sequencing (move workspace into v7.5 layout BEFORE Phase 1, not after); split plugin entrypoints (index.ts client + server.ts per plugin); strict type-only imports for cross-folder Plugin refs; cleanup pack (uiBridge dedup, EmptyFilePanel relocation, A/B parallelism tightened, TL;DR scrub, tsconfig excludes, pi-tools-migration catch-up). **Meta-rule: when files move, they go DIRECTLY to final v7.6 destinations — no intermediate placements.**
17
17
 
@@ -588,10 +588,10 @@ Use Fastify's `inject()` for in-process testing; no port binding.
588
588
  Dropping `data: DataPaneConfig` from `<ChatCenteredShell>` removed
589
589
  the one-liner ergonomics for hosts that just want a simple data
590
590
  tab with their adapter (gemini P2). Restore them via the reusable
591
- data catalog plugin factory exported from `@boring/workspace`:
591
+ data catalog plugin factory now exported from `@hachej/boring-data-catalog/front`:
592
592
 
593
593
  ```ts
594
- import { createDataCatalogPlugin } from "@boring/workspace"
594
+ import { createDataCatalogPlugin } from "@hachej/boring-data-catalog/front"
595
595
  import { myAdapter } from "./adapter"
596
596
 
597
597
  export const dataPlugin = createDataCatalogPlugin({
@@ -746,7 +746,7 @@ type changes. The plan does NOT delete `chatSuggestions` from
746
746
  |---|---|---|
747
747
  | **`filesystemPlugin`** | UI-only: a Files catalog (cmd palette); FileTree panel registration as `placement: 'left-tab'`; CodeEditor + MarkdownEditor panel registrations (with `filePatterns`). **No `agentTools` field** — file tools are harness substrate (see §"Tools belong with the harness, not the plugin"). | Hosts that want a chat-only UI (no file tree, no code editor opening on file click) can opt out. When excluded: file UI disappears; LLM file tools STAY (controlled separately by `disableDefaultFileTools` on `createAgentApp`). |
748
748
 
749
- **v6 had a `dataCatalogPlugin` second default; v6.2 cuts it.**
749
+ **v6 had a data catalog plugin second default; v6.2 cuts it.**
750
750
  Reason (codex round-3 P1): with `recentKind` cut and no other
751
751
  filter, a generic "Data" tab couldn't unambiguously pick *which*
752
752
  catalog to display when multiple plugins contribute catalogs (e.g.,
@@ -1269,7 +1269,7 @@ agent tools and catalogs but leave a dead Files tab in the UI.
1269
1269
  Phase 1 step 5c retrofits `WorkbenchLeftPane` to query
1270
1270
  `PanelRegistry` for `placement: 'left-tab'`, sorted by
1271
1271
  registration order. `filesystemPlugin` contributes the Files tab;
1272
- `dataCatalogPlugin` contributes the Data tab.
1272
+ the data catalog plugin contributes the Data tab.
1273
1273
  `excludeDefaults: ['filesystem']` truly removes the tab.
1274
1274
 
1275
1275
  (`'right-tab'` is reserved in the contract but no Phase 1 component
@@ -1533,7 +1533,7 @@ model**.
1533
1533
  │ @boring/workspace │
1534
1534
  │ • Plugin contract (definePlugin, factories) │
1535
1535
  │ • Registries (Panel / Command / Catalog) │
1536
- │ • Default plugins (filesystemPlugin, dataCatalogPlugin) │
1536
+ │ • Default plugins (filesystemPlugin; data catalog is now external) │
1537
1537
  │ • UI bridge core (moved from @boring/agent) │
1538
1538
  │ • Substrate routes /api/v1/{ui,files,tree,files/search} │
1539
1539
  │ • Event bus + WorkspaceEventMap │
@@ -1655,7 +1655,7 @@ packages/workspace/
1655
1655
  │ │ └── defaults/
1656
1656
  │ │ ├── filesystemPlugin.ts (imports filesystemAgentTools
1657
1657
  │ │ │ from @boring/agent)
1658
- │ │ └── dataCatalogPlugin.ts
1658
+ │ │ └── dataCatalogPlugin.ts (historical; now external package)
1659
1659
  │ ├── registry/
1660
1660
  │ │ ├── PanelRegistry.ts [EXISTS — retrofitted:
1661
1661
  │ │ │ subscribable, path-aware
@@ -1878,7 +1878,7 @@ restructure; subsequent phases assume the v7.6 layout exists.
1878
1878
  │ registered by createAgentApp via pi-tools-migration's │
1879
1879
  │ buildFilesystemAgentTools(bundle) — NOT the plugin's job. │
1880
1880
  │ │
1881
- │ (v6 had dataCatalogPlugin as a second default; v6.2 cuts │
1881
+ │ (v6 had a data catalog plugin as a second default; v6.2 cuts │
1882
1882
  │ it — plugins that want a workbench data tab contribute │
1883
1883
  │ their own left-tab panel.) │
1884
1884
  │ │
@@ -1930,7 +1930,7 @@ restructure; subsequent phases assume the v7.6 layout exists.
1930
1930
  │ was the original justification for the retrofit. │
1931
1931
  │ - Drop `data: DataPaneConfig` prop. Hosts that want a │
1932
1932
  │ workbench data tab register their own left-tab panel │
1933
- │ or compose the reusable `createDataCatalogPlugin(opts)` │
1933
+ │ or compose `createDataCatalogPlugin(opts)` from `@hachej/boring-data-catalog/front`
1934
1934
  │ / `appendDataCatalogOutputs(...)` helpers. │
1935
1935
  │ - Drop `extraPanels` prop. Panels come from PanelRegistry; │
1936
1936
  │ new optional `allowedPanels?: string[]` for gating. │
@@ -2056,7 +2056,7 @@ export const makeMacroServerPlugin = (): Plugin =>
2056
2056
  component is `DataExplorer` configured with macro's adapter and
2057
2057
  `onActivate` that calls `surface.openPanel({ component:
2058
2058
  "chart-canvas", … })`. This replaces the v5 dataPaneConfig wiring
2059
- without needing a default `dataCatalogPlugin`. The catalog
2059
+ without needing a default data catalog plugin. The catalog
2060
2060
  (`seriesCatalog`) stays separate — it's what powers the cmd palette
2061
2061
  search; the panel is what shows the workbench browser.
2062
2062
 
@@ -2417,7 +2417,7 @@ apps/boring-macro-v2/src/plugin/ ← macroPlugin lives here
2417
2417
  - `src/components/chat/` (whole folder; Phase A + C + G)
2418
2418
  - Top-level `src/panes/{code-editor, markdown-editor, file-tree}/` — moved INTO
2419
2419
  `src/plugin/defaults/filesystemPlugin/` (panes/sidebar split per role) by j9p7.9
2420
- - `src/panes/data-catalog/` — orphaned (dataCatalogPlugin was cut in v6.2);
2420
+ - `src/panes/data-catalog/` — orphaned (the data catalog plugin was cut in v6.2);
2421
2421
  audit during j9p7.30: delete if no consumer, otherwise re-home as a primitive
2422
2422
  in `components/` for plugin authors who want a generic data-tab implementation
2423
2423
  - `src/panes/EmptyPane.tsx` (loose) — moved to `chrome/EmptyPane.tsx`
@@ -3417,7 +3417,7 @@ simple hosts.** A host that just wants "a data tab with my
3417
3417
  adapter" had a one-liner; v6.2's "register your own left-tab
3418
3418
  panel" makes it ~10 lines. **Fix:** use
3419
3419
  `createDataCatalogPlugin` for standalone data catalog plugins, or
3420
- `appendDataCatalogOutputs` when an app plugin needs to install
3420
+ `appendDataCatalogOutputs` from `@hachej/boring-data-catalog/front` when an app plugin needs to install
3421
3421
  the data catalog as part of a domain plugin. Macro uses the latter
3422
3422
  so chart/deck behavior stays in the macro app.
3423
3423
 
@@ -3474,7 +3474,7 @@ by `createWorkspaceAgentApp` rather than evaluated at module load.
3474
3474
  `data` prop.** With `recentKind` cut and multiple registered
3475
3475
  catalogs (filesystem's Files + macro's Series), nothing in the
3476
3476
  spec said which one fills the generic Data tab. **Fix:** drop
3477
- `dataCatalogPlugin` from defaults entirely. There is no generic
3477
+ the data catalog plugin from defaults entirely. There is no generic
3478
3478
  Data tab; plugins that want a workbench data tab register their
3479
3479
  own `placement: 'left-tab'` panel (e.g., macro's `macroSeriesPanel`
3480
3480
  which internally renders DataExplorer with the macro adapter +
@@ -3516,7 +3516,7 @@ rolled back.
3516
3516
 
3517
3517
  ### Net impact (v6.1 → v6.2)
3518
3518
 
3519
- - One default plugin removed (`dataCatalogPlugin`).
3519
+ - One default plugin removed (the data catalog plugin; now external).
3520
3520
  - Two factory shapes formalized (`createFilesystemAgentTools(deps)`
3521
3521
  and `makeFilesystemPlugin(deps)`).
3522
3522
  - Macro example honors client/server split.
@@ -87,7 +87,7 @@ src/
87
87
  │ │ ├── defaultEditorPanels.ts ← MOVED from panes/ (3 apps consume via barrel — keep)
88
88
  │ │ └── __tests__/
89
89
  │ │
90
- │ └── dataCatalogPlugin/ (reusable data catalog outputs + hooks)
90
+ │ └── (moved out) data catalog package: `@hachej/boring-data-catalog`
91
91
 
92
92
  ├── server/ (existing)
93
93
  └── shared/ (existing)
@@ -108,8 +108,7 @@ plugin with hardcoded data.
108
108
 
109
109
  `DataCatalog` belongs alongside `DataExplorer` in `front/components/` — both are
110
110
  presentational peers. Move `panes/data-catalog/*` → `front/components/data-catalog/*`.
111
- Apps install data catalog outputs through `createDataCatalogPlugin` or
112
- `appendDataCatalogOutputs`.
111
+ Apps install data catalog outputs through `@hachej/boring-data-catalog/front` (`createDataCatalogPlugin` or `appendDataCatalogOutputs`).
113
112
 
114
113
  ---
115
114
 
@@ -21,7 +21,7 @@ Use this section as the live handoff ledger while executing this plan.
21
21
  - Current source uses generic `surface-resolver` plugin outputs plus the
22
22
  `openSurface` UI command. Filesystem path matching belongs to
23
23
  `plugins/filesystemPlugin/surfaceResolver.ts`; data catalog row opening
24
- belongs to `plugins/dataCatalogPlugin`.
24
+ belongs to the extracted `@hachej/boring-data-catalog` package.
25
25
 
26
26
  ### Pass 2 — Full milestone verification (2026-04-24)
27
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-workspace",
3
- "version": "0.1.13",
3
+ "version": "0.1.16",
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.",
@@ -119,14 +119,12 @@
119
119
  "fastify": "^5.3.3",
120
120
  "lowlight": "^3.3.0",
121
121
  "lucide-react": "^1.8.0",
122
- "micromatch": "^4.0.8",
123
- "radix-ui": "^1.4.3",
124
122
  "react-arborist": "^3.4.0",
125
123
  "tailwind-merge": "^2.0.0",
126
124
  "zod": "^3.23.0",
127
125
  "zustand": "^5.0.0",
128
- "@hachej/boring-agent": "0.1.13",
129
- "@hachej/boring-ui-kit": "0.1.13"
126
+ "@hachej/boring-agent": "0.1.16",
127
+ "@hachej/boring-ui-kit": "0.1.16"
130
128
  },
131
129
  "devDependencies": {
132
130
  "@tailwindcss/postcss": "^4.0.0",
@@ -134,7 +132,6 @@
134
132
  "@testing-library/jest-dom": "^6.9.1",
135
133
  "@testing-library/react": "^16.3.2",
136
134
  "@testing-library/user-event": "^14.6.1",
137
- "@types/micromatch": "^4.0.10",
138
135
  "@types/node": "^22.15.3",
139
136
  "@types/react": "^19.0.0",
140
137
  "@types/react-dom": "^19.0.0",