@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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -0
  3. package/dist/CodeEditor-DQqOn4xz.js +266 -0
  4. package/dist/CommandPalette-aM61U-b0.js +5229 -0
  5. package/dist/FileTree-DRq_bfue.js +245 -0
  6. package/dist/MarkdownEditor-DjiHxnRv.js +349 -0
  7. package/dist/WorkspaceLoadingState-By0dZoPD.js +568 -0
  8. package/dist/agent-tool-NvxKfist.d.ts +28 -0
  9. package/dist/app-front.d.ts +485 -0
  10. package/dist/app-front.js +452 -0
  11. package/dist/app-server.d.ts +53 -0
  12. package/dist/app-server.js +769 -0
  13. package/dist/bootstrapServer-BRUqUpVW.d.ts +66 -0
  14. package/dist/boring-workspace.css +1 -0
  15. package/dist/charts.d.ts +114 -0
  16. package/dist/charts.js +143 -0
  17. package/dist/events.d.ts +178 -0
  18. package/dist/events.js +88 -0
  19. package/dist/explorer-DtLUnuah.d.ts +129 -0
  20. package/dist/panel-DnvDNQac.js +6 -0
  21. package/dist/server.d.ts +84 -0
  22. package/dist/server.js +811 -0
  23. package/dist/shared.d.ts +113 -0
  24. package/dist/shared.js +11 -0
  25. package/dist/testing-e2e.d.ts +68 -0
  26. package/dist/testing-e2e.js +45 -0
  27. package/dist/testing.d.ts +464 -0
  28. package/dist/testing.js +10984 -0
  29. package/dist/utils-B6yFEsav.js +8 -0
  30. package/dist/workspace.css +5780 -0
  31. package/dist/workspace.d.ts +2119 -0
  32. package/dist/workspace.js +1884 -0
  33. package/docs/INTERFACES.md +58 -0
  34. package/docs/PLUGIN_STRUCTURE.md +162 -0
  35. package/docs/README.md +19 -0
  36. package/docs/bridge.md +135 -0
  37. package/docs/panels.md +102 -0
  38. package/docs/plans/GENERIC_EXPLORER_PLUGIN_PLAN.md +455 -0
  39. package/docs/plans/MACRO_PLUGIN_GENERIC_HELPERS_AUDIT.md +962 -0
  40. package/docs/plans/PLUGIN_OUTPUTS_ISOLATION_PLAN.md +301 -0
  41. package/docs/plans/README.md +9 -0
  42. package/docs/plans/UI_BRIDGE_OWNERSHIP_REFACTOR.md +303 -0
  43. package/docs/plans/archive/CODE_OWNERSHIP_CLEANUP_PLAN.md +387 -0
  44. package/docs/plans/archive/COMMAND_PALETTE_REGISTRY.md +814 -0
  45. package/docs/plans/archive/DECLARATIVE_LAYOUT_MIGRATION.md +277 -0
  46. package/docs/plans/archive/PLUGIN_MODEL.md +3674 -0
  47. package/docs/plans/archive/SRC_FOLDER_REORG_PLAN.md +307 -0
  48. package/docs/plans/archive/UNIFIED_EVENT_BUS.md +647 -0
  49. package/docs/plans/archive/WORKSPACE_V2_PLAN.md +2489 -0
  50. package/docs/plugins.md +158 -0
  51. package/package.json +164 -0
@@ -0,0 +1,277 @@
1
+ # Declarative layout migration — retire ChatCenteredShell, adopt ChatLayout / IdeLayout
2
+
3
+ > **⚠ SUPERSEDED 2026-04-29 — content merged into [PLUGIN_MODEL.md](./PLUGIN_MODEL.md) §"Phase 1.5: Consumer migration".**
4
+ >
5
+ > Per user decision (v7.4 merger): the two plans had substantial scope overlap (macro migration, ChatCenteredShell removal, plugin extraction). Folded into one mega-plan + one epic (boring-ui-v2-j9p7) with a single acceptance gate. Phase 1.5 in PLUGIN_MODEL.md is the canonical reference; phase beads are j9p7.24-29 + j9p7.18-20 (the latter reframed under Phase E).
6
+ >
7
+ > Epic boring-ui-v2-zrby closed as merged.
8
+ >
9
+ > The original content below is preserved as a historical record.
10
+ > ─────────────────────────────────────────────────────────────────
11
+
12
+ **Status:** SUPERSEDED — see PLUGIN_MODEL.md v7.4
13
+ **Owners:** workspace
14
+ **Last updated:** 2026-04-29
15
+ **Preconditions:** plugin model (epic boring-ui-v2-j9p7) — closed
16
+ **Tracked by:** ~~epic boring-ui-v2-zrby~~ → epic boring-ui-v2-j9p7 (Phase 1.5)
17
+
18
+ ## Problem
19
+
20
+ `@boring/workspace` ships two parallel layout systems:
21
+
22
+ 1. **Imperative shell.** `ChatCenteredShell` (29KB) + `SurfaceShell` (23KB) + `ChatTopBar` + `SessionBrowser` + `WorkbenchLeftPane` + `ChatStagePlaceholder`, all living under `src/components/chat/`. Hardcodes the chat panel from `@boring/agent`, the top-bar slots, the session drawer, and the artifact dockview. Apps pass props in; they cannot restructure.
23
+
24
+ 2. **Declarative layouts.** `ChatLayout` + `IdeLayout` + `ResponsiveDockviewShell` in `src/layouts/`. Compose panels by id (e.g. `<ChatLayout nav="session-list" center="chat" surface="artifact-surface" />`). Plugins register panels into the panel registry; the layout config resolves ids → components via dockview.
25
+
26
+ Today every consuming app (`apps/workspace-playground`, `apps/full-app`, `apps/boring-macro-v2`) uses **only the imperative shell**. The declarative layouts have **zero app consumers** — they're tested and exported but never reached.
27
+
28
+ Symptoms:
29
+
30
+ - Two layout systems = drift. New features land in `ChatCenteredShell` because that's what apps use, while `ChatLayout` falls behind and gets stale.
31
+ - Apps cannot extend the layout shape. Adding a fourth pane on the right, splitting the center, or rearranging anything requires forking `ChatCenteredShell`.
32
+ - Plugins (per `PLUGIN_MODEL.md`) are designed to contribute panels by id — but with `ChatCenteredShell` as the entry point, the layout doesn't read panels from the registry; it imports them statically. The plugin model's panel-registration story is blunted.
33
+ - Boring-macro's chart canvas, slide deck, and series-explorer panels currently bolt into `ChatCenteredShell` via custom props and ad-hoc state. They should be a `macroPlugin`.
34
+
35
+ ## Goal
36
+
37
+ Single layout system. The declarative pattern (`ChatLayout` / `IdeLayout` + `ResponsiveDockviewShell` + `TopBar` + `WorkspaceProvider` registering core panels + plugin model wiring) is the canonical entry. The imperative `ChatCenteredShell` is deleted once all consumers migrate. Apps consume one of three tiers, all public:
38
+
39
+ ### Tier 1 — declarative pre-shaped layouts
40
+
41
+ For apps that want a stock chat- or IDE-shaped surface. ~80% of apps.
42
+
43
+ ```tsx
44
+ import { WorkspaceProvider, ChatLayout, TopBar } from "@boring/workspace"
45
+ import { macroPlugin } from "./macro-plugin"
46
+
47
+ <WorkspaceProvider plugins={[macroPlugin]}>
48
+ <TopBar appTitle="Macro" right={<UserMenu />} />
49
+ <ChatLayout
50
+ nav="session-list"
51
+ center="chat"
52
+ sidebar="charts"
53
+ surface="artifact-surface"
54
+ />
55
+ </WorkspaceProvider>
56
+ ```
57
+
58
+ Apps swap panels by changing the `nav` / `center` / `sidebar` / `surface` ids. Plugins register the implementations.
59
+
60
+ ### Tier 2 — custom LayoutConfig with stock chrome
61
+
62
+ For apps that need a non-stock layout shape (split center, multiple right surfaces, custom group constraints) but still want responsive sidebar collapse, dockview integration, and the same `<TopBar>` chrome.
63
+
64
+ ```tsx
65
+ import { WorkspaceProvider, ResponsiveDockviewShell, TopBar, type LayoutConfig } from "@boring/workspace"
66
+
67
+ const myLayout: LayoutConfig = {
68
+ version: "2.0",
69
+ groups: [
70
+ { id: "rail", position: "left", panel: "session-list", locked: true, hideHeader: true },
71
+ { id: "tree", position: "left", panel: "filetree", collapsible: true },
72
+ { id: "center", position: "center", panel: "chat" },
73
+ { id: "split-a", position: "right", panel: "code-editor" },
74
+ { id: "split-b", position: "right", panel: "live-preview" },
75
+ ],
76
+ }
77
+
78
+ <WorkspaceProvider plugins={[chatExperiencePlugin, livePreviewPlugin]}>
79
+ <TopBar appTitle="..." />
80
+ <ResponsiveDockviewShell layout={myLayout} />
81
+ </WorkspaceProvider>
82
+ ```
83
+
84
+ ### Tier 3 — full custom
85
+
86
+ Raw primitives. For apps with bespoke chrome (non-rectangular layout, multiple dockview instances, embedded workspace inside a larger non-workspace shell). Rare.
87
+
88
+ ```tsx
89
+ import {
90
+ WorkspaceProvider,
91
+ DockviewShell,
92
+ useViewportBreakpoint,
93
+ useResponsiveSidebarCollapse,
94
+ useTopBarSlot,
95
+ } from "@boring/workspace"
96
+
97
+ function MyShell() {
98
+ // App fully composes chrome + dockview structure
99
+ }
100
+ ```
101
+
102
+ All three tiers share the SAME core panel registrations (chat, session-list, workbench-left, artifact-surface). The only thing that changes between tiers is how the app shapes the layout around them.
103
+
104
+ ## Substrate vs plugin (architectural commitment)
105
+
106
+ The migration is a chance to clarify what's substrate and what's plugin:
107
+
108
+ - **Substrate** = constitutive workspace panels. Without them, `@boring/workspace` is an empty dockview. Apps cannot opt out — these ARE what the package is. Today: `chat`, `session-list`, `workbench-left`, `artifact-surface`.
109
+ - **Default plugins** = optional capabilities apps can disable via `excludeDefaults: ['filesystem']`. Today: just `filesystemPlugin` (file tree + code editor + markdown editor + filesCatalog).
110
+ - **App plugins** = host-specific contributions. Apps register via `<WorkspaceProvider plugins={[macroPlugin, ...]}>`. Examples: `macroPlugin` (charts + slides + series), future `analyticsPlugin`, etc.
111
+
112
+ There is **no `chatExperiencePlugin`**. Chat is core, not a plugin. The earlier sketch of a "chat experience plugin" bundling these panels was wrong — it conflates substrate with extension.
113
+
114
+ `WorkspaceProvider` registers core panels at mount, before running the plugin bootstrap:
115
+
116
+ ```ts
117
+ function WorkspaceProvider({ plugins, excludeDefaults, children }) {
118
+ const panelRegistry = new PanelRegistry()
119
+ panelRegistry.registerAll(coreWorkspacePanels) // ← substrate, always
120
+ bootstrap({ plugins, defaults: filteredDefaults, registries }) // ← optional + app
121
+ ...
122
+ }
123
+ ```
124
+
125
+ ## File-tree consequences
126
+
127
+ After migration:
128
+
129
+ ```
130
+ src/panes/ ← all registered panels live here
131
+ ├── chat/ ← core
132
+ │ ├── ChatPanel.tsx thin wrapper around @boring/agent's ChatPanel
133
+ │ │ + workspace integrations (auto-open hooks,
134
+ │ │ command-stream consumption, suggestions)
135
+ │ └── definition.ts `definePanel({ id: "chat", ... })`
136
+ ├── session-list/ ← core (was components/chat/SessionBrowser)
137
+ ├── workbench-left/ ← core (was components/chat/WorkbenchLeftPane)
138
+ ├── artifact-surface/ ← core (was components/chat/SurfaceShell)
139
+ ├── code-editor/ existing (filesystem plugin)
140
+ ├── markdown-editor/ existing (filesystem plugin)
141
+ ├── file-tree/ existing (filesystem plugin)
142
+ ├── data-catalog/ existing
143
+ ├── ArtifactSurfacePane.tsx stays — referenced by SurfaceShell impl
144
+ ├── EmptyPane.tsx stays
145
+ └── defaultEditorPanels.ts stays
146
+
147
+ src/layouts/ ← declarative composition + chrome
148
+ ├── ChatLayout.tsx KEEP
149
+ ├── IdeLayout.tsx KEEP
150
+ ├── ResponsiveDockviewShell.tsx KEEP — exported as Tier 2 entry
151
+ ├── TopBar.tsx NEW — was components/chat/ChatTopBar
152
+ └── index.ts
153
+
154
+ src/registry/coreRegistrations.ts NEW — exports `coreWorkspacePanels: PanelConfig[]`
155
+ imported and applied by WorkspaceProvider
156
+
157
+ src/plugin/ unchanged — plugin model machinery
158
+ └── defaults/
159
+ └── filesystemPlugin.ts unchanged — still the only default plugin
160
+
161
+ src/components/ shrinks to genuinely cross-cutting UI
162
+ ├── chat/ GONE — contents moved to panes/, layouts/, bridge/
163
+ ├── ui/ stays (shadcn primitives)
164
+ ├── DataExplorer/ stays (generic data subsystem)
165
+ ├── CommandPalette.tsx stays
166
+ ├── PanelErrorBoundary.tsx stays
167
+ └── SessionList.tsx stays — data-list helper, distinct from
168
+ the SessionBrowser panel that wraps it
169
+
170
+ src/bridge/ (or src/ui-bridge/) absorbs the bridge infrastructure
171
+ ├── (existing bridge code)
172
+ ├── uiCommandStream.ts was components/chat/uiCommandStream.ts
173
+ └── uiCommandDispatcher.ts was components/chat/uiCommandDispatcher.ts
174
+ ```
175
+
176
+ What disappears:
177
+
178
+ - `src/components/chat/` (whole folder)
179
+ - `ChatCenteredShell.tsx` + `ChatShellContext` (`context.ts`)
180
+ - The old `presets.test.tsx` (it tests the layouts in isolation; superseded by the migrated apps' e2e + new layout tests)
181
+ - `src/index.ts` exports for `ChatCenteredShell`, `useChatShell`, `useChatSurface`, `ChatStagePlaceholder` (those are imperative-shell internals)
182
+
183
+ What stays exported (Tier 1 / Tier 2 / Tier 3 surface):
184
+
185
+ ```ts
186
+ // Tier 1
187
+ export { ChatLayout, IdeLayout, buildChatLayout, buildIdeLayout } from "./layouts"
188
+ export type { ChatLayoutProps, IdeLayoutProps } from "./layouts"
189
+ export { TopBar } from "./layouts/TopBar"
190
+
191
+ // Tier 2
192
+ export { ResponsiveDockviewShell } from "./layouts/ResponsiveDockviewShell"
193
+
194
+ // Tier 3 (raw primitives)
195
+ export { DockviewShell } from "./dock" // already exported
196
+ export type { LayoutConfig, GroupConfig } from "./dock"
197
+ export { useViewportBreakpoint, useResponsiveSidebarCollapse } from "./hooks"
198
+ export { useTopBarSlot } from "./components/TopBarSlot"
199
+
200
+ // WorkspaceProvider + plugin model (unchanged)
201
+ export { WorkspaceProvider } from "./WorkspaceProvider"
202
+ export { definePlugin, definePanel, PluginError, ... } from "./plugin"
203
+ export { CatalogRegistry, useCommands, useActivePanels, useCatalogs, ... } from "./plugin"
204
+ ```
205
+
206
+ ## Phase breakdown — 7 child beads
207
+
208
+ A. **Decompose chat shells into per-pane folders + bridge/**
209
+ - `git mv` `components/chat/{SessionBrowser, ChatStagePlaceholder, SurfaceShell, WorkbenchLeftPane}.tsx` into per-pane folders under `panes/`. Each pane gains a `definition.ts` exporting a `PanelConfig`.
210
+ - Create `panes/chat/ChatPanel.tsx` (thin wrapper around `@boring/agent`'s ChatPanel + workspace integrations) + `definition.ts`.
211
+ - `git mv` `components/chat/{uiCommandStream, uiCommandDispatcher}.ts` → `bridge/`.
212
+ - Update internal imports.
213
+ - **Don't touch `ChatCenteredShell.tsx` or `ChatTopBar.tsx` yet** — they stay in `components/chat/` until later beads.
214
+
215
+ B. **Wire core panel registrations in WorkspaceProvider**
216
+ - Create `registry/coreRegistrations.ts` exporting `coreWorkspacePanels: PanelConfig[]` aggregating the 4 core panel defs.
217
+ - `WorkspaceProvider` imports and registers them at mount, BEFORE `bootstrap()` runs.
218
+ - Test: render `WorkspaceProvider` with no plugins; assert the panel registry has the 4 core ids.
219
+
220
+ C. **Lift TopBar chrome + expose ResponsiveDockviewShell**
221
+ - `git mv` `components/chat/ChatTopBar.tsx` → `layouts/TopBar.tsx`. Rename type `ChatTopBarProps` → `TopBarProps`. Update barrel.
222
+ - Export `ResponsiveDockviewShell` from package barrel with jsdoc explaining Tier 2.
223
+ - Add a section to `packages/workspace/README.md` (or `docs/`) documenting the three-tier API.
224
+
225
+ D. **Migrate workspace-playground to ChatLayout (Tier 1, canary)**
226
+ - Rewrite `apps/workspace-playground/src/App.tsx` to use `<WorkspaceProvider>` + `<TopBar>` + `<ChatLayout>`.
227
+ - Confirm e2e tests (`apps/workspace-playground/e2e/*.spec.ts`) still pass.
228
+ - Document any gotchas for the next two app migrations.
229
+
230
+ E. **Migrate boring-macro-v2: ChatLayout + extract macroPlugin**
231
+ - Create `apps/boring-macro-v2/src/macroPlugin.ts` defining the macro-specific panels (chart canvas, slide deck, series explorer) + commands (open_series) + agent tools (execute_sql, macro_search, get_series_data, persist_derived_series).
232
+ - Rewrite `apps/boring-macro-v2/src/front/App.tsx` to use `<ChatLayout>` + `<WorkspaceProvider plugins={[macroPlugin]}>`.
233
+ - Confirm boring-macro e2e tests pass.
234
+
235
+ F. **Migrate full-app to ChatLayout (or IdeLayout if appropriate)**
236
+ - Rewrite `apps/full-app/src/front/main.tsx` to use the appropriate declarative layout.
237
+ - Confirm e2e tests pass.
238
+
239
+ G. **Delete ChatCenteredShell + ChatShellContext + finalize**
240
+ - Once D, E, F are merged: delete `components/chat/ChatCenteredShell.tsx` and `components/chat/context.ts`.
241
+ - Drop the related exports from `src/index.ts`.
242
+ - The `components/chat/` folder is now empty; remove it.
243
+ - Update `WORKSPACE_V2_PLAN.md` and any other doc that references `ChatCenteredShell`.
244
+
245
+ A and B can run in parallel. C depends on A. D, E, F can run in parallel after A+B+C. G depends on D+E+F.
246
+
247
+ ## Test plan
248
+
249
+ - **Per-pane reorg (Phase A):** existing tests follow the moved files; vi.mock paths get updated. No new tests required — the moves are mechanical.
250
+ - **Core panel registration (Phase B):** new test in `WorkspaceProvider.test.tsx` asserting the 4 core panel ids are registered post-mount.
251
+ - **TopBar (Phase C):** existing `ChatTopBar.test.tsx` follows the rename. New test confirming `useTopBarSlot()` integration if not already covered.
252
+ - **App migrations (D/E/F):** existing e2e suites must pass with no expected-snapshot changes (visuals shouldn't shift). If layout pixels shift slightly, regenerate snapshots in the same commit and document.
253
+ - **Tier 2 / Tier 3 public API:** add a jsdoc-extracted snippet test or a small integration test that constructs a custom `LayoutConfig` and renders it through `<ResponsiveDockviewShell>` to prove the export wiring works.
254
+ - **`ChatCenteredShell` removal (Phase G):** the `__tests__` folder for the imperative shell goes with it. Public API test asserts the symbol is gone.
255
+
256
+ ## Risks
257
+
258
+ - **Pixel drift on canary migration.** Tier 1's `<ChatLayout>` may render at slightly different pixel offsets than `<ChatCenteredShell>` (different padding stack, different transition timing on the sidebar). Plan: regenerate visual snapshots when migrating workspace-playground; eyeball the diff for genuine regressions vs cosmetic shifts.
259
+ - **Plugin id collisions.** boring-macro's existing panels might collide with workspace's core panel ids if any name overlaps. Plan: audit during Phase E; rename macro panels to be namespaced (`macro:charts`, `macro:slides`).
260
+ - **boring-macro custom shell logic.** boring-macro's current App.tsx has more glue than the playground (custom session handling, custom topbar variants). Phase E may surface that some of this glue should live in `macroPlugin` (commands), and some should stay app-level (the actual host wiring + auth). Will need careful split.
261
+ - **`uiCommandStream` / `uiCommandDispatcher` re-homing.** These are the workspace's bridge consumers. Today they live in `components/chat/`; they need to move to `bridge/`. They're currently called from inside `ChatCenteredShell`. After A's move + WorkspaceProvider's mount-time wiring, they should be invoked from a `useEffect` inside `WorkspaceProvider` (or a dedicated hook). Confirm the lifecycle is right — the stream must start before the chat panel mounts.
262
+
263
+ ## Out of scope
264
+
265
+ - Adding new panel types beyond the existing core + filesystem + macro sets.
266
+ - Changing the dockview library.
267
+ - Changing `@boring/agent`'s ChatPanel API. Workspace's chat panel is a thin wrapper, not a fork.
268
+ - Changing the plugin model itself (closed under `boring-ui-v2-j9p7`).
269
+ - Tier 2 / Tier 3 reference apps. The escape hatches stay public; we don't ship a demo app that uses them in this epic.
270
+
271
+ ## Ship criteria
272
+
273
+ - All 7 phase beads closed.
274
+ - Three apps run on declarative layouts in production.
275
+ - `ChatCenteredShell` and `ChatShellContext` deleted from the tree.
276
+ - Public API exposes Tier 1 / Tier 2 / Tier 3 entries with jsdoc.
277
+ - A README section in `packages/workspace/` describing the three-tier model with one snippet per tier.