@hachej/boring-workspace 0.1.40 → 0.1.42
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 +26 -261
- package/dist/{FileTree-DNIzusWa.js → FileTree-CVsvICGP.js} +1 -1
- package/dist/MarkdownEditor-BvaGmzWP.js +582 -0
- package/dist/{WorkspaceLoadingState-EratTJfG.js → WorkspaceLoadingState-yp4vNmrT.js} +21 -22
- package/dist/{WorkspaceProvider-uuxyAx3i.js → WorkspaceProvider-DkZAxsYo.js} +2902 -2741
- package/dist/app-front.d.ts +5 -0
- package/dist/app-front.js +221 -217
- package/dist/app-server.d.ts +2 -2
- package/dist/app-server.js +23 -5
- package/dist/{createInMemoryBridge-DSjZ9efK.d.ts → createInMemoryBridge-siFWq_R_.d.ts} +8 -0
- package/dist/plugin.d.ts +4 -2
- package/dist/server.d.ts +3 -3
- package/dist/server.js +23 -5
- package/dist/shared.d.ts +1 -1
- package/dist/{surface-obE7YwJk.d.ts → surface-DmIalUmP.d.ts} +2 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.js +1 -1
- package/dist/workspace.css +112 -16
- package/dist/workspace.d.ts +8 -2
- package/dist/workspace.js +5 -5
- package/docs/INTERFACES.md +1 -1
- package/docs/PLUGIN_STRUCTURE.md +3 -3
- package/docs/PLUGIN_SYSTEM.md +46 -4
- package/docs/README.md +85 -22
- package/package.json +4 -4
- package/dist/MarkdownEditor-DhVfKSAq.js +0 -549
- /package/docs/plans/{ASK_USER_QUESTIONS_PLUGIN_SPEC.md → archive/ASK_USER_QUESTIONS_PLUGIN_SPEC.md} +0 -0
- /package/docs/plans/{FULL_PAGE_PANEL_ROUTE_SPEC.md → archive/FULL_PAGE_PANEL_ROUTE_SPEC.md} +0 -0
- /package/docs/plans/{GENERIC_EXPLORER_PLUGIN_PLAN.md → archive/GENERIC_EXPLORER_PLUGIN_PLAN.md} +0 -0
- /package/docs/plans/{PANE_TO_AGENT_CHAT_ACTIONS_SPEC.md → archive/PANE_TO_AGENT_CHAT_ACTIONS_SPEC.md} +0 -0
- /package/docs/plans/{PLUGIN_OUTPUTS_ISOLATION_PLAN.md → archive/PLUGIN_OUTPUTS_ISOLATION_PLAN.md} +0 -0
- /package/docs/plans/{README.md → archive/README.md} +0 -0
- /package/docs/plans/{UI_BRIDGE_OWNERSHIP_REFACTOR.md → archive/UI_BRIDGE_OWNERSHIP_REFACTOR.md} +0 -0
package/README.md
CHANGED
|
@@ -7,56 +7,37 @@
|
|
|
7
7
|
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
The workspace UI, layout, plugin, and bridge layer for boring-ui apps. It gives you
|
|
11
|
+
an IDE-style workbench — Dockview panes, a plugin system that contributes panels,
|
|
12
|
+
tabs, commands, catalogs, and surface resolvers, and a typed agent-to-browser
|
|
13
|
+
bridge. You write the domain logic; the workspace handles the chrome. The app shell
|
|
14
|
+
injects the chat component and owns auth, routing, and persistence.
|
|
11
15
|
|
|
12
16
|
```bash
|
|
13
17
|
pnpm add @hachej/boring-workspace
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
## TL;DR
|
|
19
|
-
|
|
20
|
-
**The Problem**: Agent apps need more than a chat window. You want file trees, editors, data tables, custom panes, keyboard shortcuts — but wiring all that chrome yourself means fighting layout engines, managing panel lifecycles, and building bridges between backend commands and frontend actions.
|
|
21
|
-
|
|
22
|
-
**The Solution**: `@hachej/boring-workspace` gives you a complete IDE-style workbench with a plugin system that contributes panes, tabs, commands, catalogs, surface resolvers, and React context. The agent backend talks to the UI through a typed pubsub bus. You write the domain logic; the workspace handles the chrome.
|
|
23
|
-
|
|
24
|
-
### Why Use @hachej/boring-workspace?
|
|
25
|
-
|
|
26
|
-
| Feature | What It Does |
|
|
27
|
-
|---------|--------------|
|
|
28
|
-
| **Plugin system** | Contribute panels, left-tabs, commands, catalogs, surface resolvers, and React bindings through a single manifest |
|
|
29
|
-
| **Dockview layout** | Split, resize, drag, and dock panels — VS Code–style behavior out of the box |
|
|
30
|
-
| **Auto code-splitting** | Lazy panels (`() => import(...)`) are automatically wrapped in `React.lazy + Suspense + ErrorBoundary` |
|
|
31
|
-
| **Typed UI bridge** | Agent calls `exec_ui({ kind: "openFile", params })` → panel opens in the workbench. SSE + HTTP fallback. |
|
|
32
|
-
| **Surface resolver** | Map agent-emitted `SurfaceOpenRequest` to panel opens — domain-specific routing without hardcoding panel IDs |
|
|
33
|
-
| **Built-in plugins** | File tree, editor, command palette, session management — ready on mount |
|
|
34
|
-
| **Composable** | Three levels: full layout (`IdeLayout`), provider + layout primitives, or headless hooks — pick what you need |
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Quick Example
|
|
20
|
+
## Usage
|
|
39
21
|
|
|
40
22
|
```tsx
|
|
41
23
|
import { WorkspaceProvider, IdeLayout } from "@hachej/boring-workspace"
|
|
42
24
|
import { ChatPanel } from "@hachej/boring-agent"
|
|
43
25
|
|
|
44
|
-
// Full shell — plug in your chat and plugins
|
|
45
26
|
function App() {
|
|
46
27
|
return (
|
|
47
|
-
<WorkspaceProvider chatPanel={ChatPanel} workspaceId="default" plugins={[
|
|
28
|
+
<WorkspaceProvider chatPanel={ChatPanel} workspaceId="default" plugins={[myPlugin]}>
|
|
48
29
|
<IdeLayout />
|
|
49
30
|
</WorkspaceProvider>
|
|
50
31
|
)
|
|
51
32
|
}
|
|
52
33
|
```
|
|
53
34
|
|
|
54
|
-
Add a panel
|
|
35
|
+
Add a panel with a plugin:
|
|
55
36
|
|
|
56
37
|
```ts
|
|
57
38
|
import { definePlugin } from "@hachej/boring-workspace/plugin"
|
|
58
39
|
|
|
59
|
-
export const
|
|
40
|
+
export const myPlugin = definePlugin({
|
|
60
41
|
id: "my-panel",
|
|
61
42
|
label: "My Panel",
|
|
62
43
|
panels: [
|
|
@@ -70,255 +51,39 @@ export const myPanelPlugin = definePlugin({
|
|
|
70
51
|
})
|
|
71
52
|
```
|
|
72
53
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
# pnpm
|
|
79
|
-
pnpm add @hachej/boring-workspace
|
|
80
|
-
|
|
81
|
-
# npm
|
|
82
|
-
npm install @hachej/boring-workspace
|
|
83
|
-
|
|
84
|
-
# from source
|
|
85
|
-
git clone https://github.com/hachej/boring-ui.git
|
|
86
|
-
cd boring-ui && pnpm install
|
|
87
|
-
pnpm --filter @hachej/boring-workspace build
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## Architecture
|
|
93
|
-
|
|
94
|
-
### Plugin System
|
|
54
|
+
`WorkspaceProvider` requires `chatPanel` and `workspaceId`; `plugins`, `apiBaseUrl`,
|
|
55
|
+
`authHeaders`, and `layoutPreferences` are optional. Lazy panel factories
|
|
56
|
+
(`() => import(...)`) are auto-wrapped in `React.lazy + Suspense + ErrorBoundary` —
|
|
57
|
+
do not set `lazy: true`.
|
|
95
58
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
WorkspaceProvider
|
|
100
|
-
├── bootstrap(plugins)
|
|
101
|
-
│ ├── registry.register(panel outputs)
|
|
102
|
-
│ ├── registry.register(left-tab outputs)
|
|
103
|
-
│ └── registry.register(command outputs)
|
|
104
|
-
│
|
|
105
|
-
├── DockviewShell
|
|
106
|
-
│ ├── registry.getComponents() → lazy-wrapped panels
|
|
107
|
-
│ └── DockviewReact (layout chrome)
|
|
108
|
-
│
|
|
109
|
-
├── UiBridgeClient
|
|
110
|
-
│ ├── SSE command stream
|
|
111
|
-
│ └── HTTP poll fallback
|
|
112
|
-
│
|
|
113
|
-
└── Layout (IdeLayout / ChatLayout / ResponsiveDockviewShell)
|
|
114
|
-
```
|
|
59
|
+
## Package surfaces
|
|
115
60
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
POST /api/v1/ui/commands ──► UiBridge dispatches
|
|
122
|
-
{ kind, params } │ ├── openFile
|
|
123
|
-
│ ├── openPanel
|
|
124
|
-
│ └── showNotification
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Agent plugins emit `UiCommand` values on the server. The workbench has a typed event bus that dispatches them to the right handler.
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
POST /api/v1/ui/commands
|
|
131
|
-
{ kind: "openFile", params: { path: "src/index.ts" } }
|
|
132
|
-
|
|
133
|
-
↓
|
|
134
|
-
|
|
135
|
-
UiBridgeClient receives → dispatches to FileTree plugin → expands node + focuses editor
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Built-in Plugins
|
|
139
|
-
|
|
140
|
-
| Plugin | What It Adds |
|
|
141
|
-
|--------|-------------|
|
|
142
|
-
| Filesystem plugin | File tree (left tab), editor (center panel), file navigation |
|
|
143
|
-
| Chat plugin | Integrates the injected `ChatPanel` into the layout |
|
|
144
|
-
| Command palette | `⌘K`-driven search across commands, panels, and surfaces |
|
|
145
|
-
| Session plugin | Lightweight session toolbar (current session, dropdown, new chat) |
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Package Surfaces
|
|
150
|
-
|
|
151
|
-
| Import | Environment | What You Get |
|
|
152
|
-
|--------|-------------|--------------|
|
|
153
|
-
| `@hachej/boring-workspace` | Browser | `WorkspaceProvider`, `IdeLayout`, built-in layout primitives |
|
|
154
|
-
| `@hachej/boring-workspace/plugin` | Browser | `definePlugin()` and browser-safe plugin authoring types |
|
|
155
|
-
| `@hachej/boring-workspace/server` | Node | `defineServerPlugin()`, server routes, UI tools, Pi package helpers |
|
|
61
|
+
| Import | Environment | What you get |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `@hachej/boring-workspace` | Browser | `WorkspaceProvider`, `IdeLayout`, `ChatLayout`, layout primitives |
|
|
64
|
+
| `@hachej/boring-workspace/plugin` | Browser | `definePlugin()` and browser-safe authoring types |
|
|
65
|
+
| `@hachej/boring-workspace/server` | Node | `defineServerPlugin()`, server routes, UI tools, Pi helpers |
|
|
156
66
|
| `@hachej/boring-workspace/shared` | Any | `PaneProps`, `SurfaceOpenRequest`, `UiCommand`, plugin types |
|
|
157
67
|
| `@hachej/boring-workspace/events` | Any | Typed event bus for bridge communication |
|
|
158
|
-
| `@hachej/boring-workspace/charts` | Browser | Recharts wrappers
|
|
68
|
+
| `@hachej/boring-workspace/charts` | Browser | Recharts wrappers |
|
|
159
69
|
| `@hachej/boring-workspace/testing` | Browser | Test utilities and mock providers |
|
|
160
70
|
| `@hachej/boring-workspace/app/front` | Browser | App composition: `WorkspaceAgentFront` |
|
|
161
71
|
| `@hachej/boring-workspace/app/server` | Node | App composition: `createWorkspaceAgentServer` |
|
|
162
72
|
| `@hachej/boring-workspace/globals.css` | Browser | Global CSS for the workspace chrome |
|
|
163
73
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
## Plugin Output Types
|
|
167
|
-
|
|
168
|
-
| Output Type | Contributed Surface | Example |
|
|
169
|
-
|-------------|--------------------|---------|
|
|
170
|
-
| `panel` | Center/right/bottom pane | Code editor, data table, settings page |
|
|
171
|
-
| `left-tab` | Persistent sidebar tab | File tree, data catalog, status panel |
|
|
172
|
-
| `command` | Command palette entry | "Toggle dark mode", "Format files" |
|
|
173
|
-
| `catalog` | Searchable data explorer | Customer list with faceted filters |
|
|
174
|
-
| `surface-resolver` | Maps `exec_ui` → panel | `openFile` → editor panel with path |
|
|
175
|
-
| `binding` | React context in provider tree | Theme, auth, workspace-scoped state |
|
|
176
|
-
| `provider` | Binding + `apiBaseUrl` injection | Server-side plugin config passed to front |
|
|
177
|
-
| `agent-tool` | Static agent tool via server plugin | `deploy`, `test`, `lint` commands |
|
|
178
|
-
|
|
179
|
-
### Writing a Plugin
|
|
180
|
-
|
|
181
|
-
```ts
|
|
182
|
-
import { definePlugin } from "@hachej/boring-workspace/plugin"
|
|
183
|
-
import type { PaneProps } from "@hachej/boring-workspace"
|
|
184
|
-
|
|
185
|
-
export const statusPlugin = definePlugin({
|
|
186
|
-
id: "build-status",
|
|
187
|
-
label: "Build Status",
|
|
188
|
-
leftTabs: [
|
|
189
|
-
{
|
|
190
|
-
id: "build-status-tab",
|
|
191
|
-
title: "Build",
|
|
192
|
-
panelId: "build-status-tab",
|
|
193
|
-
component: () => import("./StatusTab").then(m => ({ default: m.StatusTab })),
|
|
194
|
-
},
|
|
195
|
-
],
|
|
196
|
-
panels: [
|
|
197
|
-
{
|
|
198
|
-
id: "build-details",
|
|
199
|
-
label: "Build Details",
|
|
200
|
-
placement: "bottom",
|
|
201
|
-
component: () => import("./BuildDetails").then(m => ({ default: m.BuildDetails })),
|
|
202
|
-
},
|
|
203
|
-
],
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
// Panel components receive PaneProps<T>:
|
|
207
|
-
function StatusTab({ params, api, containerApi }: PaneProps<{}>) {
|
|
208
|
-
// params — data when panel is opened
|
|
209
|
-
// api — DockviewPanelApi (close, setTitle, …)
|
|
210
|
-
// containerApi — DockviewApi (addPanel, layout, …)
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Server Plugins
|
|
74
|
+
## Documentation
|
|
215
75
|
|
|
216
|
-
|
|
76
|
+
See [`docs/README.md`](./docs/README.md) for the architecture overview, key
|
|
77
|
+
abstractions, and architectural decisions. From there:
|
|
217
78
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
export const statusServerPlugin = defineServerPlugin({
|
|
222
|
-
id: "build-status",
|
|
223
|
-
agentTools: [buildTool], // Agent tools
|
|
224
|
-
routes: async (app) => { // Fastify plugin function
|
|
225
|
-
app.register(statusRoutes, { prefix: "/build-status" })
|
|
226
|
-
},
|
|
227
|
-
provisioning: {
|
|
228
|
-
templateDirs: [
|
|
229
|
-
{ id: "build-status-seed", path: seedBuildDir, target: "." },
|
|
230
|
-
],
|
|
231
|
-
},
|
|
232
|
-
})
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## Configuration
|
|
238
|
-
|
|
239
|
-
### WorkspaceProvider Props
|
|
240
|
-
|
|
241
|
-
```tsx
|
|
242
|
-
<WorkspaceProvider
|
|
243
|
-
chatPanel={ChatPanel} // Required: React component for chat
|
|
244
|
-
workspaceId={id} // Required: workspace identifier
|
|
245
|
-
plugins={[pluginA, pluginB]} // Optional: extend with custom plugins
|
|
246
|
-
apiBaseUrl="http://localhost:3000" // Optional: backend URL
|
|
247
|
-
authHeaders={...} // Optional: auth for HTTP requests
|
|
248
|
-
layoutPreferences={...} // Optional: initial Dockview layout JSON
|
|
249
|
-
/>
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
## How @hachej/boring-workspace Compares
|
|
255
|
-
|
|
256
|
-
| Feature | @hachej/boring-workspace | VS Code (Theia) | Custom layout |
|
|
257
|
-
|---------|--------------------------|-----------------|---------------|
|
|
258
|
-
| Panel layout | ✅ Dockview, drag/drop/split | ✅ Tabbed | ⚠️ Build yourself |
|
|
259
|
-
| Plugin system | ✅ Panels + tabs + commands + catalogs | ✅ Extension API | ❌ DIY |
|
|
260
|
-
| Agent bridge | ✅ Typed UiBridge pubsub | ❌ Not agent-native | ❌ DIY |
|
|
261
|
-
| Code splitting | ✅ Auto-detects lazy factories | ⚠️ Require-based | ⚠️ Manual |
|
|
262
|
-
| Setup time | ✅ ~10 lines | ❌ Heavy framework | ❌ Weeks |
|
|
263
|
-
|
|
264
|
-
**When to use @hachej/boring-workspace:**
|
|
265
|
-
- Building an agent-powered IDE with customizable panes
|
|
266
|
-
- You need plugins to add panels without touching the shell
|
|
267
|
-
- You want the agent to open things (files, data, charts) in the workbench
|
|
268
|
-
|
|
269
|
-
**When it might not fit:**
|
|
270
|
-
- You just want a chat box (use `@hachej/boring-agent` standalone)
|
|
271
|
-
- You need a full VS Code replacement (no language server protocol support)
|
|
272
|
-
- You want to control every pixel of the layout (use Dockview directly)
|
|
273
|
-
|
|
274
|
-
---
|
|
275
|
-
|
|
276
|
-
## Troubleshooting
|
|
277
|
-
|
|
278
|
-
| Error | Cause | Fix |
|
|
279
|
-
|-------|-------|-----|
|
|
280
|
-
| `Panel not found: <id>` | Plugin not registered | Check `plugins` prop on `WorkspaceProvider` |
|
|
281
|
-
| Blank panel / white screen | Lazy component threw | Check `PluginErrorBoundary` — inspect console |
|
|
282
|
-
| `UiBridge not connected` | Backend not running | Verify `apiBaseUrl` and backend endpoint |
|
|
283
|
-
| Commands not arriving | SSE blocked by proxy | Use `?poll=true` on `/api/v1/ui/commands/next` |
|
|
284
|
-
| Plugin not loading | Missing `definePlugin` wrapper or `boring.front` manifest entry | Package front plugins must default-export `definePlugin({ ... })` and declare `boring.front` |
|
|
285
|
-
| Duplicate panel IDs | Two plugins register same ID | Rename one panel's `id` field |
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
|
|
289
|
-
## Limitations
|
|
290
|
-
|
|
291
|
-
- **Plugin panels share the same registry** — name collisions between plugins cause the last-registered panel to win. Namespace your IDs.
|
|
292
|
-
- **No code editor language server** — The editor ships CodeMirror6 with syntax highlighting but no LSP. Semantic features (go-to-definition, rename) are not available.
|
|
293
|
-
- **Rich text editor is TipTap-based** — It's included but opt-in via peer dependencies. Not all TipTap extensions are wired up.
|
|
294
|
-
- **Frontend code must not value-import `@hachej/boring-agent`** — Package-neutral workspace code stays agent-free. Use the `chatPanel` injection pattern instead.
|
|
295
|
-
- **Layout state persistence is the shell's job** — Workspace doesn't save/restore layouts between sessions. The shell owns `layoutPreferences`.
|
|
296
|
-
|
|
297
|
-
---
|
|
298
|
-
|
|
299
|
-
## FAQ
|
|
300
|
-
|
|
301
|
-
**Q: What's the difference between a `panel` and a `left-tab`?**
|
|
302
|
-
A: `panel` opens in the main Dockview area (center/right/bottom). `left-tab` is a persistent sidebar element that stays docked to the left. Users open panels programmatically; left-tabs are always visible.
|
|
303
|
-
|
|
304
|
-
**Q: How do I lazy-load a panel?**
|
|
305
|
-
A: Pass a zero-arg arrow function `() => import("./Pane").then(m => ({ default: m.Pane }))`. The registry auto-detects this pattern and wraps it in `React.lazy + Suspense`. Don't set `lazy: true`.
|
|
306
|
-
|
|
307
|
-
**Q: Can the agent open my plugin's panel?**
|
|
308
|
-
A: Yes. Register a `surface-resolver` that maps the agent's `SurfaceOpenRequest` to your panel ID. Then the agent can use `exec_ui` to open it.
|
|
309
|
-
|
|
310
|
-
**Q: Why can't frontend workspace code import from `@hachej/boring-agent`?**
|
|
311
|
-
A: The workspace package stays package-neutral so it can be used without the agent. The `chatPanel` prop injects the agent's UI, keeping the dependency inverted.
|
|
312
|
-
|
|
313
|
-
**Q: What's `surface-resolver` for?**
|
|
314
|
-
A: It decouples agent-side "open X" requests from frontend panel IDs. The agent says `{ kind: "open-series", seriesId: "GDPC1" }`, and the surface resolver maps that to `{ panelId: "series-chart", params: { seriesId: "GDPC1" } }`.
|
|
79
|
+
- [`docs/PLUGIN_SYSTEM.md`](./docs/PLUGIN_SYSTEM.md) — normative plugin/agent layer spec.
|
|
80
|
+
- [`docs/PLUGIN_STRUCTURE.md`](./docs/PLUGIN_STRUCTURE.md) — plugin layout quick reference.
|
|
81
|
+
- [`docs/INTERFACES.md`](./docs/INTERFACES.md) — package boundaries and ownership rules.
|
|
315
82
|
|
|
316
83
|
---
|
|
317
84
|
|
|
318
85
|
*About Contributions:* Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via `gh` and independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.
|
|
319
86
|
|
|
320
|
-
---
|
|
321
|
-
|
|
322
87
|
## License
|
|
323
88
|
|
|
324
89
|
MIT
|
|
@@ -2,7 +2,7 @@ import { jsx as c, jsxs as z } from "react/jsx-runtime";
|
|
|
2
2
|
import { useRef as D, useEffect as A, useMemo as M, useCallback as w, createContext as S, useContext as $ } from "react";
|
|
3
3
|
import { Tree as E } from "react-arborist";
|
|
4
4
|
import { FolderOpenIcon as J, FolderIcon as K, ChevronRightIcon as U, Loader2Icon as V } from "lucide-react";
|
|
5
|
-
import { L as X } from "./WorkspaceProvider-
|
|
5
|
+
import { L as X } from "./WorkspaceProvider-DkZAxsYo.js";
|
|
6
6
|
import { EmptyState as Y, Input as Z } from "@hachej/boring-ui-kit";
|
|
7
7
|
import { c as N } from "./utils-B6yFEsav.js";
|
|
8
8
|
import { createDragDropManager as y } from "dnd-core";
|