@pstdio/workbench 0.7.1 → 0.9.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/README.md +39 -317
- package/dist/extensions.d.ts +1492 -698
- package/dist/extensions.js +1679 -1776
- package/dist/extensions.js.map +1 -1
- package/dist/file-renderer-view-kfJRY3yR.js +515 -0
- package/dist/file-renderer-view-kfJRY3yR.js.map +1 -0
- package/dist/index.d.ts +724 -599
- package/dist/index.js +5151 -2369
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +673 -550
- package/dist/react.js +3585 -3335
- package/dist/react.js.map +1 -1
- package/dist/storage.d.ts +120 -155
- package/dist/storage.js +135 -149
- package/dist/storage.js.map +1 -1
- package/dist/webview-runtime.d.ts +2 -5
- package/dist/webview-runtime.js +3 -3
- package/dist/webview-runtime.js.map +1 -1
- package/dist/workbench-menu-paths-B_QJzcNU.js +12 -0
- package/dist/workbench-menu-paths-B_QJzcNU.js.map +1 -0
- package/dist/workbench-renderers-DmsrBGC7.js +960 -0
- package/dist/workbench-renderers-DmsrBGC7.js.map +1 -0
- package/dist/workspaces-DJwFj8uq.js +1872 -0
- package/dist/workspaces-DJwFj8uq.js.map +1 -0
- package/package.json +6 -41
- package/dist/composition-resolver-types-CWykPyEK.js +0 -241
- package/dist/composition-resolver-types-CWykPyEK.js.map +0 -1
- package/dist/file-renderer-view-B6_iR4EN.js +0 -496
- package/dist/file-renderer-view-B6_iR4EN.js.map +0 -1
- package/dist/file-section-navigation-CfYqVObc.js +0 -30
- package/dist/file-section-navigation-CfYqVObc.js.map +0 -1
- package/dist/icon-B9XolQG8.js +0 -35
- package/dist/icon-B9XolQG8.js.map +0 -1
- package/dist/layout-types-DMoZz38-.js +0 -100
- package/dist/layout-types-DMoZz38-.js.map +0 -1
- package/dist/surface-map-C1pOTUmF.js +0 -52
- package/dist/surface-map-C1pOTUmF.js.map +0 -1
- package/dist/testing.d.ts +0 -2284
- package/dist/testing.js +0 -58
- package/dist/testing.js.map +0 -1
- package/dist/workbench-built-ins-BncLJfQA.js +0 -1175
- package/dist/workbench-built-ins-BncLJfQA.js.map +0 -1
- package/dist/workbench-menu-paths-Bb0ICxeG.js +0 -20
- package/dist/workbench-menu-paths-Bb0ICxeG.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,349 +1,71 @@
|
|
|
1
|
-
# pstdio
|
|
1
|
+
# @pstdio/workbench
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The headless composition model and React shell for Prompt Studio hosts. Extension authors use the [SDK cookbook](https://github.com/pufflyai/prompt-studio/blob/main/.pstdio/docs/extensions/cookbook.md). This guide covers host integration.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Entry points
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
- **Resource**: a typed reference to something the workbench can open or navigate to.
|
|
7
|
+
| Entry point | Purpose |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `@pstdio/workbench` | Core, registries, controllers, and host contribution types |
|
|
10
|
+
| `@pstdio/workbench/react` | Shell, region components, and native renderers |
|
|
11
|
+
| `@pstdio/workbench/storage` | Browser persistence adapters |
|
|
12
|
+
| `@pstdio/workbench/extensions` | Checked extension metadata registration and host adapters |
|
|
13
|
+
| `@pstdio/workbench/webview-runtime` | Guest runtime for webview assets |
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
Install the declared React, React DOM, Chakra, and Emotion peers when using the React integration. Public declaration files include the private contracts they need. Package verification installs built entries outside the repository with full declaration checking.
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
The root, storage, and webview-runtime entries load without React. The React and extensions entries require the declared UI peers. Core Kanban contracts parameterize presentation values without choosing a UI framework. React host authors use `ReactAttributeDescriptor`, `ReactBoardColumnConfig`, and `ReactKanbanRendererContribution` from the React entry for checked cell and icon callbacks.
|
|
19
18
|
|
|
20
|
-
##
|
|
19
|
+
## Ownership
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
- `@pstdio/workbench/react` exports the React shell, view hosts, shared hooks, and `WorkbenchModuleHost` for syncing a dynamic module list into a core.
|
|
24
|
-
- `@pstdio/workbench/storage` exports local-storage-backed layout and panel persistence adapters for hosts that want browser persistence with a namespace and scope.
|
|
25
|
-
- `@pstdio/workbench/extensions` maps checked extension metadata into workbench contributions.
|
|
26
|
-
- `@pstdio/workbench/testing` exports test fixtures and helpers.
|
|
27
|
-
- `@pstdio/workbench/webview-runtime` exports the runtime used inside extension webviews.
|
|
21
|
+
`pageLocations` owns durable navigation. A page transition resolves the page, resource, contextual parent, and mode before publishing location, composition, breadcrumbs, and browser history.
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
A page declares an optional resource constraint separately from Main presentation. `main.kind: "view"` presents its routed resource, with one or many instances. `main.kind: "panels"` presents peer Main panels and an empty view when none remain. `slots` holds page panels. The route continues to own context when a file or auxiliary inspector becomes active.
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
Page slots and mode placements share a static-view or resource-binding item. Static views declare `presence`; bindings declare `kinds`, `view`, `cardinality`, and optional `add`. Main, Side, and Secondary have the same meaning for both owners.
|
|
32
26
|
|
|
33
|
-
|
|
27
|
+
Modes supply shared placements, chrome, and region policy. Page navigation selects a mode. The host composes its default navigation whenever the active mode keeps that chrome. A replacement view or `false` overrides the default. Shared placements retain their identity across pages in the same mode.
|
|
34
28
|
|
|
35
|
-
|
|
29
|
+
Register host React views through the core view registry. Register checked extension metadata through the public extension adapter. Dispose the returned registrations when the owner is removed so its views, placements, and mounted content are released.
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
- Set `singleton: true` for one placement total, such as a tree, sidenav, or status view.
|
|
39
|
-
- Non-singleton Panels default to `reuse: "resource"`: one placement per resource URI, with no-resource opens reusing the Panel placement.
|
|
40
|
-
- Set `reuse: "none"` for scratch, untitled, or transient views where every open should create a new placement.
|
|
31
|
+
## Navigation and closing
|
|
41
32
|
|
|
42
|
-
|
|
33
|
+
Page targets change location. Panel targets open a page slot or mode placement while preserving the route. Its owner must be active. A compound target may contain page and panel steps only; resolve dependent targets against proposed state, then commit once. A failed preparation publishes no location, history, layout, selection, breadcrumb, or placement changes.
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
Commands and external links are standalone actions. A command that performs work and navigates must finish that work before requesting a target. The workbench cannot undo external effects.
|
|
45
36
|
|
|
46
|
-
`
|
|
37
|
+
Use `core.closePlacement(identity)` for owned tab closing. Native tabs and the `placement.close` webview capability use this controller. The host supplies the webview's actual placement identity. Fixed placements reject closing. Closing the last routed resource view follows the page's declared parent. Closing an auxiliary panel preserves location.
|
|
47
38
|
|
|
48
|
-
|
|
39
|
+
## Resource identity
|
|
49
40
|
|
|
50
|
-
|
|
41
|
+
Use the SDK's `ResourceRef` throughout host and extension APIs. Its required fields are `type` and `id`; `label` is presentation. Preserve optional extension and project ownership when forwarding a reference.
|
|
51
42
|
|
|
52
|
-
|
|
53
|
-
- [`foundation`](src/examples/foundation/module.tsx) places one shared renderer in five regions.
|
|
43
|
+
Use `resourceKey(resource)` for identity comparisons and layout indexes. Labels and metadata do not change identity. URI conversion belongs in location and persistence adapters. The default page codec preserves existing type/id locations and includes ownership when supplied.
|
|
54
44
|
|
|
55
|
-
|
|
45
|
+
`core.getPrimaryResource()` and resource providers receive the routed page resource. A workspace collection therefore retains workspace context while its active Main panel edits a file. Selection identifies the file separately.
|
|
56
46
|
|
|
57
|
-
|
|
47
|
+
Tab labels resolve from explicit tab presentation, then resource label, then view title. The close action uses the same label.
|
|
58
48
|
|
|
59
|
-
|
|
49
|
+
## Regions and mounting
|
|
60
50
|
|
|
61
|
-
|
|
51
|
+
Use `shell.setRegionOpen("side" | "secondary" | "sidenav", open)` to hide or show a region. Hiding retains its instances. Mode `regionSettings` owns size, collapsibility, headers, and tab visibility. `mountStrategy: "keep-mounted"` keeps an inactive tab's content mounted; removing its owner disposes it.
|
|
62
52
|
|
|
63
|
-
-
|
|
53
|
+
The side-panel controller owns attached, floating, or closed presentation. `floatingPanels: "hidden"` prevents floating and reattaches an already floating panel. Per-view menu preferences belong to `panelMenuState`; they do not duplicate region visibility.
|
|
64
54
|
|
|
65
|
-
|
|
55
|
+
## Persistence
|
|
66
56
|
|
|
67
|
-
|
|
57
|
+
The browser owns Back/Forward history. Page locations remain version 1. Existing resource locations and stored product data stay valid.
|
|
68
58
|
|
|
69
|
-
|
|
59
|
+
Layout cache version 4 records resource identity keys and the new Main collection model. Old layout entries are ignored. This revision does not invalidate tree state, menu preferences, side-panel presentation, or page locations. Collection page state uses the existing location key to separate workspaces.
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
Shared mode placements have one cache entry per project and mode. Page cache entries exclude them. Closing a shared panel therefore remains closed when another page is restored; switching projects does not restore another project's mode panels.
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
- [`foundation`](src/examples/foundation/module.tsx) adds menu items to header paths.
|
|
63
|
+
## Validation
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
Storybook's core guides describe host integration; extension guides use public SDK declarations. Use the repository's Docker workflow and Playwright for dashboard behavior. The release gates are `bun run validate` and `bun run --cwd scripts verify:packages`.
|
|
77
66
|
|
|
78
|
-
|
|
67
|
+
### Commit and host effects
|
|
79
68
|
|
|
80
|
-
|
|
69
|
+
Page and panel compound targets resolve against proposed state before live state changes. The browser adapter must implement atomic `push` and `replace`: if it throws, its history must remain unchanged. Browser serialization and writing happen before workbench owners publish the final state. A rejected navigation leaves the workbench unchanged.
|
|
81
70
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- Register with `renderers.registerRenderer()`
|
|
85
|
-
- Set `keepAlive: true` on the registration to share one persistent subtree across every Panel that points at the same `rendererId`. The subtree is mounted once into a stable host that is reparented between Panel slots via DOM moves; React state, focus, scroll, and in-flight effects survive region transitions. Kept-alive renderers receive no per-Panel input from `render()`; read the active claim with `useWorkbenchClaim()` from `@pstdio/workbench/react`.
|
|
86
|
-
|
|
87
|
-
#### Examples
|
|
88
|
-
|
|
89
|
-
- [`hello-world`](src/examples/hello-world/module.tsx) uses one renderer per Panel and one placeholder renderer.
|
|
90
|
-
- [`foundation`](src/examples/foundation/module.tsx) reuses one renderer across five Panels through `config`.
|
|
91
|
-
- [`renderer-types`](src/examples/renderer-types/module.tsx) registers React and bridge renderers together.
|
|
92
|
-
- [`keep-alive`](src/examples/keep-alive/module.tsx) shares one keep-alive renderer between attached and floating Side Panel presentations.
|
|
93
|
-
|
|
94
|
-
### Tree renderers
|
|
95
|
-
|
|
96
|
-
A tree renderer handles side-panel navigation, outlines, resource lists, and contextual hierarchies. It exposes body sections through `getBody`, optional footer nodes through `getFooter`, and lazy children through `getChildren`. Nodes can carry resources, descriptions, inline actions, context menus, and `contextValue`. A tree renderer registers a Panel renderer with the same id. Use `layout.registerPanel({ rendererId: <tree id> })` and `layout.openPanel(<tree id>)` to place it in a tree-hosting region.
|
|
97
|
-
|
|
98
|
-
- Register with `renderers.registerTreeRenderer()`
|
|
99
|
-
|
|
100
|
-
#### Examples
|
|
101
|
-
|
|
102
|
-
- [`dashboard`](src/examples/dashboard/modules/shell/project-nav.ts) builds the primary tree with resource-backed nodes, footer entries, and context menus.
|
|
103
|
-
- [`dynamic-modules`](src/examples/dynamic-modules/modules/explorer-module.tsx) adds and removes a tree module at runtime.
|
|
104
|
-
|
|
105
|
-
### Kanban renderers
|
|
106
|
-
|
|
107
|
-
A Notion/Linear-style data workspace registered as a renderer. Kanban renderers contribute the schema (tag definitions, grouping/ordering/display options, filter categories), the rows via `executeQuery(state)` (which receives current settings + filters so backends can push filter/sort/pagination down), and row-mutation callbacks. Like tree renderers, a kanban renderer auto-registers a Panel renderer with the same id, so the workspace is placed via `layout.registerPanel({ rendererId: <kanban renderer id> })` and opened with `layout.openPanel(...)`.
|
|
108
|
-
|
|
109
|
-
- Register with `renderers.registerKanbanRenderer()`
|
|
110
|
-
|
|
111
|
-
#### Examples
|
|
112
|
-
|
|
113
|
-
- [`kanban-renderer`](src/examples/kanban-renderer/module.tsx) shows a schema, mock rows, and renderer-owned controls.
|
|
114
|
-
- [`dashboard`](src/examples/dashboard/modules/tickets/collections/ticket-data.ts) integrates the ticket workspace into the dashboard shell.
|
|
115
|
-
|
|
116
|
-
### Data table renderers
|
|
117
|
-
|
|
118
|
-
A dense, query-driven table backed by `@pstdio/ui/data-table`. Data table renderers keep row ids and resources outside visible values, support declarative column labels, descriptions, icons, statistics and cell renderers, and use the table's local filtering, sorting, column controls, and pagination. They auto-register a Panel renderer with the same id and can be placed in any workbench region.
|
|
119
|
-
|
|
120
|
-
- Register with `renderers.registerDataTableRenderer()`
|
|
121
|
-
- Refresh with `renderers.refreshDataTableRenderer()` or provide a contribution subscription
|
|
122
|
-
- Extensions contribute `dataTableRenderers` and place them explicitly with `panels.<id>.dataTableRenderer`
|
|
123
|
-
|
|
124
|
-
#### Examples
|
|
125
|
-
|
|
126
|
-
- [`data-table-renderer`](src/examples/data-table-renderer/module.tsx) builds a service-health table with statistics, color scales, formatted JSON, navigation, and row actions.
|
|
127
|
-
|
|
128
|
-
### Breadcrumb (TODO: make it a renderer as well)
|
|
129
|
-
|
|
130
|
-
`<WorkbenchBreadcrumbView workbench={workbench} />` is the React view that turns the breadcrumb controller state into a rendered trail. It subscribes to `workbench.breadcrumbs.store`, builds `BreadcrumbItem`s from the controller items, and returns `null` when the trail is empty. The default `Workbench` renders it in the persistent Nav Chrome; a custom `nav` Panel replaces only that trail area. Panel headers do not own breadcrumbs. Resource navigation drives the trail through `ctx.breadcrumbs.setItems(...)`; each call replaces the trail.
|
|
131
|
-
|
|
132
|
-
- Render with `<WorkbenchBreadcrumbView workbench={workbench} />` from `@pstdio/workbench/react`
|
|
133
|
-
- Drive items with `workbench.breadcrumbs.setItems([...])` from the resource navigation controller
|
|
134
|
-
- Set `indicator: "session-status"` when a breadcrumb should show the resource's session completion status
|
|
135
|
-
|
|
136
|
-
#### Examples
|
|
137
|
-
|
|
138
|
-
- [`dashboard`](src/examples/dashboard/shared/resource-sync.ts) updates the breadcrumb trail when the open resource changes.
|
|
139
|
-
- [`onboarding`](src/examples/onboarding/breadcrumb-module.tsx) keeps a three-level trail in sync with page navigation.
|
|
140
|
-
|
|
141
|
-
A typical surface combines both layers: a **renderer** supplies the UI, a **Panel** places it in a region with optional `config`, and `layout.openPanel()` creates the placement the user actually sees. Pick the narrowest contribution that matches what you are adding:
|
|
142
|
-
|
|
143
|
-
- Add a **Panel** to claim a spot in a region for a renderer.
|
|
144
|
-
- Add a **renderer** to supply the React or bridge UI for a Panel or placeholder.
|
|
145
|
-
- Add a **tree renderer** for navigable hierarchy and resource discovery, and place it with a Panel.
|
|
146
|
-
- Add a **placeholder** for region-level empty state, not for normal content.
|
|
147
|
-
|
|
148
|
-
## Resource contributions
|
|
149
|
-
|
|
150
|
-
Resource contributions define typed objects the workbench can open, route, or resolve from product data. They keep trees, navigation, and history speaking the same resource language.
|
|
151
|
-
|
|
152
|
-
### Resource kinds
|
|
153
|
-
|
|
154
|
-
Declare typed things the workbench can open. Resource refs carry `kind`, `uri`, optional `id`, labels, icons, and metadata. Resource kinds make navigation, presenters, and history speak the same language.
|
|
155
|
-
|
|
156
|
-
- Register with `resources.registerKind()`
|
|
157
|
-
- Use the standard icon names for common resources: project `folder-root`, workspace `computer`, worktree `git-pull-request-draft`, ticket `component`, kanban renderer `square-kanban`, settings `settings`.
|
|
158
|
-
|
|
159
|
-
#### Examples
|
|
160
|
-
|
|
161
|
-
- [`renderer-types`](src/examples/renderer-types/module.tsx) defines a module with one resource kind.
|
|
162
|
-
- [`navigation`](src/examples/navigation/module.tsx) uses several resource kinds in routing.
|
|
163
|
-
|
|
164
|
-
### Resource presenters
|
|
165
|
-
|
|
166
|
-
Map a Resource to the Panel instance that presents it. Presenters declare `canOpen(resource)` and return a Panel from `open(resource, input)`. `openResource()` uses the highest-priority presenter, then establishes the returned Panel as the active Location. Direct `layout.openPanel()` calls display supporting Panels without navigating.
|
|
167
|
-
|
|
168
|
-
- Register with `resources.registerPresenter()`
|
|
169
|
-
|
|
170
|
-
#### Examples
|
|
171
|
-
|
|
172
|
-
- [`renderer-types`](src/examples/renderer-types/module.tsx) routes one resource kind to one of two Panels.
|
|
173
|
-
- [`navigation`](src/examples/navigation/module.tsx) uses presenters for parsed navigation targets.
|
|
174
|
-
|
|
175
|
-
### Resource providers
|
|
176
|
-
|
|
177
|
-
Look up resources by kind, uri, or search input. Providers let features resolve resources without knowing where they are stored, which keeps trees and navigation decoupled from product data access.
|
|
178
|
-
|
|
179
|
-
- Register with `resources.registerProvider()`
|
|
180
|
-
|
|
181
|
-
#### Examples
|
|
182
|
-
|
|
183
|
-
- [`dashboard`](src/examples/dashboard/modules/tickets/module.ts) provides ticket resources to the ticket board.
|
|
184
|
-
|
|
185
|
-
## Navigation contributions
|
|
186
|
-
|
|
187
|
-
Navigation contributions turn incoming locations and resolved workbench targets into concrete workbench actions. They keep URL parsing, command dispatch, view opening, and resource routing centralized.
|
|
188
|
-
|
|
189
|
-
### Navigation parsers
|
|
190
|
-
|
|
191
|
-
Turn ingress locations into workbench targets. Parsers convert URLs or location strings into resource, view, command, or compound targets. Compound targets are dispatched transactionally through a checkpoint.
|
|
192
|
-
|
|
193
|
-
- Register with `navigation.registerParser()`
|
|
194
|
-
|
|
195
|
-
#### Examples
|
|
196
|
-
|
|
197
|
-
- [`navigation`](src/examples/navigation/module.tsx) parses URL-like locations into typed targets.
|
|
198
|
-
|
|
199
|
-
### Navigation navigators
|
|
200
|
-
|
|
201
|
-
Custom dispatch behavior for navigation targets. Navigators let modules extend how resolved targets are opened while still using the shared navigation service.
|
|
202
|
-
|
|
203
|
-
- Register with `navigation.registerNavigator()`
|
|
204
|
-
|
|
205
|
-
## Other contributions
|
|
206
|
-
|
|
207
|
-
Supporting contributions make view, layout, resource, and navigation contributions useful. They define actions, persistence, scoping, and preferences without directly owning a workbench region.
|
|
208
|
-
|
|
209
|
-
### Commands
|
|
210
|
-
|
|
211
|
-
Any executable workbench action. Commands are the primitive behind menus, keybindings, tree actions, notification actions, and command palette entries. Handlers can expose `isEnabled()` and execution failures emit `commands.onDidExecuteError`.
|
|
212
|
-
|
|
213
|
-
- Register with `commands.registerCommand()`
|
|
214
|
-
|
|
215
|
-
#### Examples
|
|
216
|
-
|
|
217
|
-
- [`hello-world`](src/examples/hello-world/module.tsx) adds a command that opens a Panel.
|
|
218
|
-
- [`renderer-types`](src/examples/renderer-types/module.tsx) opens different placements with commands.
|
|
219
|
-
|
|
220
|
-
### Keybindings
|
|
221
|
-
|
|
222
|
-
Keyboard access to commands. Keybindings reference command ids and can include a `when` expression such as `project.active && !dialog.open`.
|
|
223
|
-
|
|
224
|
-
- Register with `keybindings.registerKeybinding()`
|
|
225
|
-
|
|
226
|
-
#### Examples
|
|
227
|
-
|
|
228
|
-
- [`foundation`](src/examples/foundation/module.tsx) gates a keybinding with a context key.
|
|
229
|
-
- [`random`](src/examples/random/modules/random-workbench.tsx) pairs keybindings with mode-scoped commands.
|
|
230
|
-
|
|
231
|
-
### Context keys
|
|
232
|
-
|
|
233
|
-
Conditional command, menu, and keybinding behavior. Module contexts create scoped context keys that are cleaned up with the module. Use context keys for current mode, focused surface, selection state, and other workbench-level conditions.
|
|
234
|
-
|
|
235
|
-
- Set through the module context with `context.set()`
|
|
236
|
-
|
|
237
|
-
#### Examples
|
|
238
|
-
|
|
239
|
-
- [`foundation`](src/examples/foundation/module.tsx) sets `foundation.host` to gate menus and keybindings.
|
|
240
|
-
- [`keep-alive`](src/examples/keep-alive/module.tsx) uses a context key to control kept-alive subtree visibility.
|
|
241
|
-
|
|
242
|
-
### Modes
|
|
243
|
-
|
|
244
|
-
Temporary bundles of contributions for workspace modes such as project, settings, review, or dashboard. Activating a mode runs its contribution function; switching modes disposes the previous mode's mode-scoped contributions.
|
|
245
|
-
|
|
246
|
-
- Register with `modes.registerMode()`
|
|
247
|
-
|
|
248
|
-
#### Examples
|
|
249
|
-
|
|
250
|
-
- [`workbench-modes`](src/examples/workbench-modes/modules/project-mode.tsx) switches between mode-scoped bundles.
|
|
251
|
-
- [`dashboard`](src/examples/dashboard/modules/shell/module.tsx) defines the project mode and its navigation surfaces.
|
|
252
|
-
|
|
253
|
-
### Preference schemas
|
|
254
|
-
|
|
255
|
-
Typed settings contributed by a module or runtime extension. Schemas define the shape and default behavior of workbench preferences, while the host can provide scoped persistence.
|
|
256
|
-
|
|
257
|
-
- Register with `preferences.registerSchema()`
|
|
258
|
-
|
|
259
|
-
#### Examples
|
|
260
|
-
|
|
261
|
-
- [`preferences`](src/examples/preferences/module.tsx) registers user and workspace-scoped preference values.
|
|
262
|
-
|
|
263
|
-
### Notifications
|
|
264
|
-
|
|
265
|
-
Toast-style messages from modules or extensions. Notifications can include command-backed actions and are rendered by workbench chrome rather than by individual views.
|
|
266
|
-
|
|
267
|
-
- Show with `notifications.show()`
|
|
268
|
-
|
|
269
|
-
#### Examples
|
|
270
|
-
|
|
271
|
-
- [`dynamic-modules`](src/examples/dynamic-modules/modules/diagnostics-module.tsx) emits toasts from a diagnostics module.
|
|
272
|
-
- [`navigation`](src/examples/navigation/module.tsx) sends a notification from a navigation flow.
|
|
273
|
-
|
|
274
|
-
### Themes
|
|
275
|
-
|
|
276
|
-
The React workbench owns the shared `@pstdio/ui` theme preference system through `WorkbenchThemeProvider`. The available theme set lives on the workbench: `workbench.themes` holds contributed themes, and `useWorkbenchThemePreferences(workbench)` reads the built-in themes plus those. `<Workbench />` feeds that set into its own provider, so a contributed theme appears in the picker only while its contributor stays registered. The workbench also renders the shared `Toaster` viewport for workbench notifications and toast calls from workbench modules. Hosts that render their own chrome (sizing boxes or app-level loading screens) wrap it in `WorkbenchThemeProvider` with the same set so that chrome is themed too. Workbench chrome reads VS Code-compatible color theme tokens such as `editor.background`, `sideBar.background`, `panel.background`, and `editorWidget.background` when extension themes provide them.
|
|
277
|
-
|
|
278
|
-
#### Examples
|
|
279
|
-
|
|
280
|
-
- [`extension-themes`](src/examples/extension-themes/module.tsx) registers extensions as workbench modules that add and remove VS Code-compatible color themes at runtime.
|
|
281
|
-
|
|
282
|
-
### Terminal
|
|
283
|
-
|
|
284
|
-
Terminals are owned by the host. Extensions do not compose their chrome. The `workbench.terminal` controller owns the session registry. Hosts supply a session opener through `workbench.terminal.setSessionOpener(...)`. Production uses a real PTY transport. Stories and the extension testbench use `createScriptedTerminalBridge` from `@pstdio/ui/terminal`. `createWorkbenchTerminalModule()` registers the terminal Panel in the `secondary` region and the `workbench.terminal.open` command. The Panel renders the shared `Terminal` component from `@pstdio/ui/terminal`. Closing the Panel kills its session. Disposing the controller kills every live session.
|
|
285
|
-
|
|
286
|
-
Extension webviews never receive PTY handles. A webview with the `terminal.session` capability uses serializable `open`, `write`, `resize`, `kill`, and `subscribe` operations. The host sends output and exit events over the bridge event channel. `createTerminalSessionBridge(host)` from `@pstdio/sdk/extensions` turns that protocol into a bridge accepted by the `Terminal` component.
|
|
287
|
-
|
|
288
|
-
#### Examples
|
|
289
|
-
|
|
290
|
-
- [`workbench-modes`](src/examples/workbench-modes/module.tsx) opens the host-owned terminal Panel with a scripted backend.
|
|
291
|
-
- [`workbench.stories`](src/examples/workbench.stories.tsx) drives the `HostTerminal` story with `createScriptedTerminalBridge`.
|
|
292
|
-
|
|
293
|
-
Register related contributions inside one **workbench module** so they share ownership and disposal. For example, a ticket collection module usually contributes a resource kind, resource presenter, Panel, renderer, tree renderer, commands, and menu items together.
|
|
294
|
-
|
|
295
|
-
## Nomenclature
|
|
296
|
-
|
|
297
|
-
- **Contribution**: a declarative unit added to a registry, such as a command, menu item, resource kind, Panel, renderer, tree renderer, mode, or KanbanView.
|
|
298
|
-
- **Workbench module**: contribution owner registered with `workbench.registerModule(module)` and removed with `workbench.unregisterModule(moduleId)`. Module disposables are tracked and disposed together. See [Contribution Ownership](https://github.com/pufflyai/prompt-studio/blob/main/.pstdio/docs/references/workbench/contribution-ownership.md).
|
|
299
|
-
- **Runtime extension**: extension metadata from `pstdio-extensions` that a host maps into workbench modules at the trust boundary.
|
|
300
|
-
- **Panel placement**: an opened instance of a Panel contribution in a region. Placements track active Panel, resource URI, title, pinned/closable flags, and placement ownership.
|
|
301
|
-
- **Tree renderer contribution**: a tree-shaped renderer registered under `renderers`. Provides `getBody` (sectioned body), optional `getFooter` (flat footer node list), and `getChildren` (lazy children). Auto-registers a Panel renderer with the same id so Panels place trees through `layout.registerPanel`.
|
|
302
|
-
- **Kanban renderer contribution**: a data-workspace renderer registered under `renderers`. Provides a schema, `executeQuery(state)` rows, and row-mutation callbacks. Auto-registers a Panel renderer with the same id so Panels place the workspace through `layout.registerPanel`. The presentational layer is `<KanbanRenderer>` from `@pstdio/ui`.
|
|
303
|
-
- **Data table renderer contribution**: a dense table renderer registered under `renderers`. Provides query rows, optional column descriptors, navigation, and row actions. Extensions place it through a native view; the presentational layer is `<DataTable>` from `@pstdio/ui/data-table`.
|
|
304
|
-
- **Placeholder**: an empty-state contribution rendered only when a region has no Panel placements. Placeholders do not appear in tabs.
|
|
305
|
-
- **Renderer**: code that turns a Panel placement into UI. The Panel host looks up `rendererId` in `workbench.renderers` and inserts the returned React node.
|
|
306
|
-
- **Resource**: a typed object reference with `kind`, `id`, `uri`, and label metadata.
|
|
307
|
-
- **Resource presenter**: routing logic that maps a resource to a Panel placement.
|
|
308
|
-
- **Command**: an executable action registered in the command registry. Errors raised during execution emit `workbench.commands.onDidExecuteError`.
|
|
309
|
-
- **Menu path**: a stable location where commands are surfaced, such as the command palette, a region header, or a tree node context menu.
|
|
310
|
-
- **Keybinding**: a keyboard shortcut bound to a command, optionally gated by a context expression.
|
|
311
|
-
- **Context key**: boolean or scalar workbench state used by commands, menus, and keybindings to decide when they are active.
|
|
312
|
-
- **Preference schema**: typed settings contributed by workbench modules or runtime extensions.
|
|
313
|
-
- **Mode**: a named bundle of temporary contributions activated through `workbench.modes`. Switching modes disposes the previous mode's activation result.
|
|
314
|
-
- **Tree view section**: a group of nodes inside a tree renderer's `getBody`, with an optional label, optional collapsible flag, and inline actions.
|
|
315
|
-
- **Notification**: a transient workbench message emitted by workbench modules or extensions. Notifications can include command-backed actions and are rendered as workbench toast chrome.
|
|
316
|
-
- **Side Panel**: the project-owned carry surface controlled by `workbench.sidePanel`. It can be `attached`, `floating`, or `closed` while preserving one live host and its resource binding.
|
|
317
|
-
|
|
318
|
-
## Regions overview
|
|
319
|
-
|
|
320
|
-
Workbench regions are named layout targets used by Panel contributions. They describe where a Panel belongs in the workbench; the workbench decides the exact chrome, tabs, resize handles, and visibility behavior.
|
|
321
|
-
|
|
322
|
-
Use `layout.registerPlaceholder()` for a region empty state that should render only after all Panels in that region close. Placeholders are not Panel placements, so they do not affect tab lists.
|
|
323
|
-
|
|
324
|
-
Panels with tabs are paired with a `<panel>-header` region that the workbench renders directly above the panel. Panels placed in a header region use a bottom border by default. Set `headerBorderBottom: false` on a Panel contribution to let that Panel own the header separation.
|
|
325
|
-
|
|
326
|
-
| Region | Workbench location | Typical use |
|
|
327
|
-
| ------------------ | -------------------------------------------- | ------------------------------------------------------------- |
|
|
328
|
-
| `nav` | Nav Chrome across the resource-owned column | Project selector, breadcrumbs, history, resource actions, region controls |
|
|
329
|
-
| `activity` | Optional rail on the leading edge | Top-level mode or workspace switching |
|
|
330
|
-
| `sidenav-header` | Optional header above `sidenav` | Sidenav-local controls that must sit above its scrolling content |
|
|
331
|
-
| `sidenav` | Leading Sidenav | Navigation trees, registries, outlines, resource lists |
|
|
332
|
-
| `main-header` | Header above the Main Panel | Main Panel tabs and controls |
|
|
333
|
-
| `main-left-menu` | Menu inside the Main Panel's leading edge | Contextual navigation and document outlines |
|
|
334
|
-
| `main` | Central Main Panel | Editors, detail pages, dashboards, primary resource views |
|
|
335
|
-
| `main-right-menu` | Menu inside the Main Panel's trailing edge | Inspectors, properties, and contextual details |
|
|
336
|
-
| `secondary-header` | Header above the Secondary Panel | Tabs, add-panel controls, and collapsed-menu controls |
|
|
337
|
-
| `secondary` | Secondary Panel below the Main Panel | Diagnostics, activity, logs, terminals, background task output |
|
|
338
|
-
| `side-header` | Header above the Side Panel | Session tabs and Side Panel controls |
|
|
339
|
-
| `side` | Full-height Side Panel | Assistant sessions and independent secondary workflows |
|
|
340
|
-
| `status` | Full-width Status Bar at the viewport bottom | Compact state, counters, sync status, environment indicators |
|
|
341
|
-
| `overlay` | Layer above the workbench | Modal flows, blocking prompts, transient overlays |
|
|
342
|
-
|
|
343
|
-
The command palette, toast notifications, and resize handles are workbench chrome, not workbench regions. Use the `RegionMap` Storybook story to see the current region placement rendered through the real `Workbench`.
|
|
344
|
-
|
|
345
|
-
## Header actions
|
|
346
|
-
|
|
347
|
-
Each region header renders command-backed actions from two menu paths derived from `headerLeadingMenuPath(region)` and `headerTrailingMenuPath(region)`. Nav Chrome reuses these paths under `workbenchTopHeaderLeadingMenuPath` and `workbenchTopHeaderTrailingMenuPath`. It keeps history, the breadcrumb trail, the trailing breadcrumb-action slot, and Sidenav/Secondary/Side visibility controls mounted in that order. Workbench modules can register commands and add menu actions to those paths without moving navigation into a Panel Header.
|
|
348
|
-
|
|
349
|
-
Runtime extensions should only target documented public slots through descriptors; hosts map those descriptors into workbench modules instead of giving extension packages direct workbench access.
|
|
71
|
+
Cache writes, mode lifecycle hooks, and subscribers are host effects after this boundary. Their exceptions are reported with the owner in the console and do not reject a committed navigation or stop other observers. A full cache can prevent restoration on the next launch, while the current location and panels remain usable. Fix the reported host effect at its source. A hook must clean up its own external effects if it fails before returning its disposables.
|