@puredesktop/create-app 1.0.0-beta.2 → 2.1.1
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/bin/create-puredesktop-app.mjs +308 -77
- package/package.json +2 -2
- package/template/README.md +39 -296
- package/template/docs/README.md +31 -0
- package/template/docs/agent.md +58 -0
- package/template/docs/app-lifecycle.md +60 -0
- package/template/docs/bridge/README.md +79 -0
- package/template/docs/bridge/dialog.md +56 -0
- package/template/docs/bridge/fs.md +95 -0
- package/template/docs/bridge/network.md +38 -0
- package/template/docs/bridge/settings.md +63 -0
- package/template/docs/bridge/storage.md +48 -0
- package/template/docs/plugin-manifest.md +108 -0
- package/template/docs/theme-vars.md +138 -0
- package/template/docs/tool-handlers.md +124 -0
- package/template/docs/ui-and-components.md +59 -0
- package/template/package.json +4 -4
- package/template/plugin.json +1 -1
- package/template/scripts/validate-puredesktop-app.mjs +66 -1
- package/template/src/App.tsx +2 -2
- package/template/src/bridge/platformBridge.ts +62 -15
package/template/README.md
CHANGED
|
@@ -1,313 +1,56 @@
|
|
|
1
|
-
# {{APP_TITLE}}
|
|
2
|
-
|
|
3
|
-
Vite + React plugin app for **PureScience Desktop**, scaffolded with `@puredesktop/create-app`.
|
|
4
|
-
|
|
5
|
-
## Dev in the shell
|
|
6
|
-
|
|
7
|
-
1. `npm install`
|
|
8
|
-
2. `npm run dev` — serves at `http://localhost:{{APP_PORT}}` (must match `plugin.json`)
|
|
9
|
-
3. In PureScience Desktop: **File → Register App…**
|
|
10
|
-
- Entrypoint URL: `http://localhost:{{APP_PORT}}`
|
|
11
|
-
- Permissions: **Network**, **Settings**, **Agents**
|
|
12
|
-
|
|
13
|
-
## Dev in the browser (optional)
|
|
14
|
-
|
|
15
|
-
Open the Vite URL directly. The app runs in standalone dev mode without the shell bridge.
|
|
16
|
-
|
|
17
|
-
## Build & deploy
|
|
1
|
+
# {{APP_TITLE}}
|
|
18
2
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
npm run build
|
|
22
|
-
npm run puredesktop:check
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Deploy the `dist/` folder to HTTPS, then register that URL in PureScience Desktop.
|
|
26
|
-
|
|
27
|
-
Run `npm run puredesktop:check` after every production build. It checks the
|
|
28
|
-
same package facts PureScience Desktop needs before registration:
|
|
29
|
-
|
|
30
|
-
- `plugin.json` is valid and has the required app identity fields.
|
|
31
|
-
- non-local URL entrypoints include the `network` permission.
|
|
32
|
-
- `dist/` exists.
|
|
33
|
-
- `agents.md` is matched by the `agents` permission.
|
|
34
|
-
- `app.usePureDesktopAiPanel` is `true`.
|
|
35
|
-
- `package.json` has the required scripts and dependencies.
|
|
36
|
-
- declared `app.agents.tools` have names, descriptions, schemas, source
|
|
37
|
-
handlers, and built output.
|
|
38
|
-
|
|
39
|
-
## Project layout
|
|
40
|
-
|
|
41
|
-
- `src/App.tsx` — bridge + boot gates, always wraps `AppFrame`
|
|
42
|
-
- `src/components/AppShell.tsx` — your UI starts here
|
|
43
|
-
- `src/bridge/platformBridge.ts` — only file that calls `bridge.call`
|
|
44
|
-
- `plugin.json` — catalog metadata and dev entrypoint port
|
|
45
|
-
- `agents.md` — app-scoped assistant prompt used by PureDesktop agent sessions
|
|
46
|
-
|
|
47
|
-
## PureDesktop app rules
|
|
48
|
-
|
|
49
|
-
Every generated app must keep these files aligned:
|
|
50
|
-
|
|
51
|
-
- `plugin.json` `app.slug` must match `src/constants.ts`.
|
|
52
|
-
- `plugin.json` `entrypoint.url` must match the Vite dev port.
|
|
53
|
-
- `plugin.json` `app.usePureDesktopAiPanel` must stay `true` for now. The
|
|
54
|
-
shell PureDesktop AI panel owns the agent UI.
|
|
55
|
-
- `agents.md` must exist at the package root for app-scoped sessions.
|
|
56
|
-
- `plugin.json` `permissions` must include every bridge capability the app uses:
|
|
57
|
-
`settings` for app settings, `filesystem` for files/storage/dialog/catalog
|
|
58
|
-
file opens, `network` for hosted URLs and network/OAuth/vision calls,
|
|
59
|
-
`assets` for asset library calls, `render` for print/render calls, and
|
|
60
|
-
`agents` for agent sessions, tools, credentials, context, or screen capture.
|
|
61
|
-
- Keep all direct `bridge.call(...)` usage inside `src/bridge/platformBridge.ts`
|
|
62
|
-
or a local bridge helper owned by that folder.
|
|
63
|
-
- Keep `AppFrame` around every return path in `src/App.tsx`, including loading
|
|
64
|
-
and error states.
|
|
65
|
-
|
|
66
|
-
## Required package.json shape
|
|
67
|
-
|
|
68
|
-
Keep these scripts:
|
|
69
|
-
|
|
70
|
-
```json
|
|
71
|
-
{
|
|
72
|
-
"scripts": {
|
|
73
|
-
"dev": "vite",
|
|
74
|
-
"build": "vite build",
|
|
75
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
76
|
-
"puredesktop:check": "node scripts/validate-puredesktop-app.mjs"
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Keep these runtime dependencies:
|
|
82
|
-
|
|
83
|
-
- `@puredesktop/puredesktop-ui-bridge`
|
|
84
|
-
- `react`
|
|
85
|
-
- `react-dom`
|
|
86
|
-
- `styled-components`
|
|
87
|
-
|
|
88
|
-
Keep these dev dependencies:
|
|
89
|
-
|
|
90
|
-
- `@vitejs/plugin-react-swc`
|
|
91
|
-
- `typescript`
|
|
92
|
-
- `vite`
|
|
93
|
-
|
|
94
|
-
## Required plugin.json shape
|
|
3
|
+
Vite + React plugin app for **PureDesktop**, scaffolded with
|
|
4
|
+
`@puredesktop/create-app`.
|
|
95
5
|
|
|
96
|
-
|
|
6
|
+
## Start
|
|
97
7
|
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"id": "{{PLUGIN_ID}}",
|
|
102
|
-
"name": "{{APP_TITLE}}",
|
|
103
|
-
"permissions": ["network", "settings", "agents"],
|
|
104
|
-
"entrypoint": {
|
|
105
|
-
"kind": "dev-url",
|
|
106
|
-
"url": "http://localhost:{{APP_PORT}}"
|
|
107
|
-
},
|
|
108
|
-
"app": {
|
|
109
|
-
"id": "plugin.{{APP_SLUG}}",
|
|
110
|
-
"slug": "{{APP_SLUG}}",
|
|
111
|
-
"name": "{{APP_TITLE}}",
|
|
112
|
-
"navigationLabel": "{{APP_TITLE}}",
|
|
113
|
-
"productName": "pure.{{APP_SLUG}}",
|
|
114
|
-
"kind": "{{APP_SLUG}}",
|
|
115
|
-
"description": "{{APP_TITLE}} - built with PureScience Desktop.",
|
|
116
|
-
"usePureDesktopAiPanel": true
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
When the app exposes tools to its app agent, add tool schemas under
|
|
122
|
-
`app.agents.tools` and keep the top-level `agents` permission:
|
|
123
|
-
|
|
124
|
-
```json
|
|
125
|
-
{
|
|
126
|
-
"app": {
|
|
127
|
-
"agents": {
|
|
128
|
-
"tools": [
|
|
129
|
-
{
|
|
130
|
-
"name": "listItems",
|
|
131
|
-
"description": "List the current items with ids, titles, status, and next action.",
|
|
132
|
-
"inputSchema": {
|
|
133
|
-
"type": "object",
|
|
134
|
-
"properties": {
|
|
135
|
-
"status": {
|
|
136
|
-
"type": "string",
|
|
137
|
-
"description": "Optional status filter."
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
"additionalProperties": false
|
|
141
|
-
},
|
|
142
|
-
"requiresApproval": false
|
|
143
|
-
}
|
|
144
|
-
]
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Required app agent
|
|
151
|
-
|
|
152
|
-
Every app has an app agent:
|
|
153
|
-
|
|
154
|
-
1. Keep `agents` in top-level `plugin.json` permissions.
|
|
155
|
-
2. Keep root-level `agents.md` next to `plugin.json`.
|
|
156
|
-
3. Keep `app.usePureDesktopAiPanel` set to `true`.
|
|
157
|
-
4. Run `npm run typecheck`, `npm run build`, and `npm run puredesktop:check`.
|
|
158
|
-
|
|
159
|
-
Add tool handlers when the manifest declares `app.agents.tools`.
|
|
160
|
-
|
|
161
|
-
Create a stable tool-name catalog:
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
// src/agents/catalog.ts
|
|
165
|
-
export const APP_AGENT_TOOL_NAMES = ['listItems'] as const
|
|
8
|
+
```bash
|
|
9
|
+
npm install
|
|
10
|
+
npm run dev
|
|
166
11
|
```
|
|
167
12
|
|
|
168
|
-
|
|
13
|
+
The dev server runs at `http://localhost:{{APP_PORT}}`, matching
|
|
14
|
+
`plugin.json`.
|
|
169
15
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
import {
|
|
173
|
-
agentToolErrorContent,
|
|
174
|
-
formatAgentToolJson,
|
|
175
|
-
readAgentToolStringArg,
|
|
176
|
-
} from '@puredesktop/puredesktop-ui-bridge/bridge/agentToolHelpers'
|
|
177
|
-
import { APP_AGENT_TOOL_NAMES } from './agents/catalog'
|
|
16
|
+
In PureDesktop, register the app from **File -> Register App...** with the same
|
|
17
|
+
entrypoint URL.
|
|
178
18
|
|
|
179
|
-
|
|
180
|
-
usePlatformAgentTools({
|
|
181
|
-
ready,
|
|
182
|
-
tools: APP_AGENT_TOOL_NAMES,
|
|
183
|
-
handlers: {
|
|
184
|
-
async listItems(ctx) {
|
|
185
|
-
const status = readAgentToolStringArg(ctx.arguments, 'status')
|
|
186
|
-
try {
|
|
187
|
-
return {
|
|
188
|
-
content: formatAgentToolJson({
|
|
189
|
-
items: [],
|
|
190
|
-
status: status || null,
|
|
191
|
-
}),
|
|
192
|
-
}
|
|
193
|
-
} catch (error) {
|
|
194
|
-
return agentToolErrorContent(
|
|
195
|
-
error instanceof Error ? error.message : String(error),
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
})
|
|
19
|
+
## Build
|
|
201
20
|
|
|
202
|
-
|
|
203
|
-
|
|
21
|
+
```bash
|
|
22
|
+
npm run typecheck
|
|
23
|
+
npm run build
|
|
24
|
+
npm run puredesktop:check
|
|
204
25
|
```
|
|
205
26
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
external-effect tools should use `requiresApproval: true`.
|
|
210
|
-
|
|
211
|
-
## Design baseline
|
|
212
|
-
|
|
213
|
-
Build quiet, dense, legible work software. Make the main work object visible
|
|
214
|
-
quickly and directly actionable. Use platform components and `--platform-*`
|
|
215
|
-
CSS variables before adding local styling. Keep one source of truth for each
|
|
216
|
-
object and avoid persistent chrome that competes with the work.
|
|
27
|
+
`puredesktop:check` verifies the package facts the shell needs before
|
|
28
|
+
registration: manifest shape, entrypoint, permissions, `agents.md`, build output,
|
|
29
|
+
and declared app agent tools.
|
|
217
30
|
|
|
218
|
-
##
|
|
31
|
+
## Project Layout
|
|
219
32
|
|
|
220
|
-
|
|
221
|
-
|
|
33
|
+
- `plugin.json`: app identity, permissions, entrypoint, routing, and agent tool
|
|
34
|
+
declarations.
|
|
35
|
+
- `agents.md`: app-scoped assistant prompt.
|
|
36
|
+
- `src/App.tsx`: bridge and boot gates wrapped in `AppFrame`.
|
|
37
|
+
- `src/bridge/platformBridge.ts`: local app bridge exports.
|
|
38
|
+
- `src/hooks/useAppBoot.ts`: boot data loading after bridge readiness.
|
|
39
|
+
- `src/components/AppShell.tsx`: first app-owned UI surface.
|
|
40
|
+
- `docs/`: builder-facing app, bridge, agent, and tool-handler docs.
|
|
222
41
|
|
|
223
|
-
|
|
224
|
-
--platform-mode
|
|
42
|
+
## Builder Docs
|
|
225
43
|
|
|
226
|
-
|
|
227
|
-
--platform-colors-surface
|
|
228
|
-
--platform-colors-surface-hover
|
|
229
|
-
--platform-colors-surface-active
|
|
230
|
-
--platform-colors-elevated
|
|
231
|
-
--platform-colors-text
|
|
232
|
-
--platform-colors-text-secondary
|
|
233
|
-
--platform-colors-text-disabled
|
|
234
|
-
--platform-colors-text-inverse
|
|
235
|
-
--platform-colors-accent
|
|
236
|
-
--platform-colors-accent-hover
|
|
237
|
-
--platform-colors-accent-muted
|
|
238
|
-
--platform-colors-border
|
|
239
|
-
--platform-colors-border-strong
|
|
240
|
-
--platform-colors-divider
|
|
241
|
-
--platform-colors-danger
|
|
242
|
-
--platform-colors-text-danger
|
|
243
|
-
--platform-colors-warning
|
|
244
|
-
--platform-colors-success
|
|
245
|
-
--platform-colors-info
|
|
246
|
-
--platform-colors-semantic-blue
|
|
247
|
-
--platform-colors-semantic-blue-text
|
|
248
|
-
--platform-colors-semantic-blue-muted
|
|
249
|
-
--platform-colors-semantic-blue-border
|
|
250
|
-
--platform-colors-semantic-orange
|
|
251
|
-
--platform-colors-semantic-orange-text
|
|
252
|
-
--platform-colors-semantic-orange-muted
|
|
253
|
-
--platform-colors-semantic-orange-border
|
|
254
|
-
--platform-colors-semantic-green
|
|
255
|
-
--platform-colors-semantic-green-text
|
|
256
|
-
--platform-colors-semantic-green-muted
|
|
257
|
-
--platform-colors-semantic-green-border
|
|
258
|
-
--platform-colors-semantic-red
|
|
259
|
-
--platform-colors-semantic-red-text
|
|
260
|
-
--platform-colors-semantic-red-muted
|
|
261
|
-
--platform-colors-semantic-red-border
|
|
262
|
-
--platform-colors-focus
|
|
263
|
-
--platform-colors-selection
|
|
264
|
-
--platform-colors-app-viewport
|
|
265
|
-
--platform-colors-chrome-titlebar
|
|
266
|
-
--platform-colors-chrome-tab-strip
|
|
44
|
+
Read [docs/README.md](./docs/README.md) before changing app structure.
|
|
267
45
|
|
|
268
|
-
|
|
269
|
-
--platform-typography-font-family-content
|
|
270
|
-
--platform-typography-font-family-mono
|
|
271
|
-
--platform-typography-font-size-base
|
|
272
|
-
--platform-typography-font-size-xs
|
|
273
|
-
--platform-typography-font-size-sm
|
|
274
|
-
--platform-typography-font-size-lg
|
|
275
|
-
--platform-typography-font-size-xl
|
|
276
|
-
--platform-typography-line-height-base
|
|
277
|
-
--platform-typography-line-height-tight
|
|
278
|
-
--platform-typography-font-weight-normal
|
|
279
|
-
--platform-typography-font-weight-medium
|
|
280
|
-
--platform-typography-font-weight-bold
|
|
46
|
+
Bridge helper docs live in [docs/bridge/README.md](./docs/bridge/README.md).
|
|
281
47
|
|
|
282
|
-
|
|
283
|
-
--platform-spacing-sm
|
|
284
|
-
--platform-spacing-md
|
|
285
|
-
--platform-spacing-lg
|
|
286
|
-
--platform-spacing-xl
|
|
287
|
-
--platform-spacing-xxl
|
|
288
|
-
|
|
289
|
-
--platform-radius-sm
|
|
290
|
-
--platform-radius-md
|
|
291
|
-
--platform-radius-lg
|
|
292
|
-
--platform-radius-full
|
|
293
|
-
|
|
294
|
-
--platform-shadow-sm
|
|
295
|
-
--platform-shadow-md
|
|
296
|
-
--platform-shadow-lg
|
|
297
|
-
|
|
298
|
-
--platform-transition-fast
|
|
299
|
-
--platform-transition-base
|
|
300
|
-
--platform-transition-slow
|
|
301
|
-
|
|
302
|
-
--platform-z-index-zi-app-base
|
|
303
|
-
--platform-z-index-zi-app-sidebar
|
|
304
|
-
--platform-z-index-zi-app-chrome
|
|
305
|
-
--platform-z-index-zi-app-viewport-toolbar
|
|
306
|
-
--platform-z-index-zi-app-menus
|
|
307
|
-
--platform-z-index-zi-app-toast
|
|
308
|
-
--platform-z-index-zi-app-modal
|
|
309
|
-
```
|
|
48
|
+
## Core Rules
|
|
310
49
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
for
|
|
50
|
+
- `plugin.json` `app.slug` matches `src/constants.ts` `APP_SLUG`.
|
|
51
|
+
- `plugin.json` `entrypoint.url` matches the Vite dev port.
|
|
52
|
+
- `app.usePureDesktopAiPanel` stays `true` for shell-owned agent UI.
|
|
53
|
+
- `agents.md` stays at the package root for app-scoped sessions.
|
|
54
|
+
- Bridge calls stay inside `src/bridge/platformBridge.ts` or files owned by
|
|
55
|
+
`src/bridge/`.
|
|
56
|
+
- `AppFrame` wraps every `src/App.tsx` return path.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# PureDesktop App Builder Docs
|
|
2
|
+
|
|
3
|
+
This folder is the builder-facing contract for generated PureDesktop apps.
|
|
4
|
+
|
|
5
|
+
A generated app is a Vite + React application rendered by PureDesktop inside a
|
|
6
|
+
workspace iframe. The app owns its UI, state, domain logic, and optional tool
|
|
7
|
+
handlers. The shell owns discovery, tabs, bridge permissions, filesystem and OS
|
|
8
|
+
services, agent sessions, and app registration.
|
|
9
|
+
|
|
10
|
+
Read these in order when building or repairing an app:
|
|
11
|
+
|
|
12
|
+
1. [App lifecycle](./app-lifecycle.md)
|
|
13
|
+
2. [Plugin manifest](./plugin-manifest.md)
|
|
14
|
+
3. [Bridge helpers](./bridge/README.md)
|
|
15
|
+
4. [App agent](./agent.md)
|
|
16
|
+
5. [Tool handlers](./tool-handlers.md)
|
|
17
|
+
6. [UI and components](./ui-and-components.md)
|
|
18
|
+
7. [Theme CSS variables](./theme-vars.md)
|
|
19
|
+
|
|
20
|
+
Key files in this scaffold:
|
|
21
|
+
|
|
22
|
+
- `plugin.json`: app identity, entrypoint, permissions, file routing, and agent
|
|
23
|
+
tool declarations.
|
|
24
|
+
- `agents.md`: app-scoped assistant instructions used by shell agent sessions.
|
|
25
|
+
- `src/App.tsx`: bridge readiness, boot loading, and `AppFrame` wrapper.
|
|
26
|
+
- `src/bridge/platformBridge.ts`: local app bridge surface.
|
|
27
|
+
- `src/hooks/useAppBoot.ts`: app boot data loading after the bridge is ready.
|
|
28
|
+
- `src/components/AppShell.tsx`: first app-owned UI surface.
|
|
29
|
+
- `scripts/validate-puredesktop-app.mjs`: registration and tool scaffold check.
|
|
30
|
+
|
|
31
|
+
Use `npm run puredesktop:check` after `npm run build` before registration.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# App Agent
|
|
2
|
+
|
|
3
|
+
Every generated app has an app-scoped assistant that runs in the shell agent
|
|
4
|
+
drawer. The app does not render its own agent chat UI by default.
|
|
5
|
+
|
|
6
|
+
## Source Files
|
|
7
|
+
|
|
8
|
+
- `agents.md`: app-scoped assistant prompt.
|
|
9
|
+
- `plugin.json` `app.agents.tools`: tool schemas exposed to the agent.
|
|
10
|
+
- `src/agents/*`: generated app-owned tool catalog and handlers when tools
|
|
11
|
+
exist.
|
|
12
|
+
- `src/hooks/useAppAgentTools.ts`: generated runtime registration hook when
|
|
13
|
+
tools exist.
|
|
14
|
+
|
|
15
|
+
## How The Agent Uses App Tools
|
|
16
|
+
|
|
17
|
+
1. The shell reads `plugin.json` and includes declared app tools in the app
|
|
18
|
+
agent's available tools.
|
|
19
|
+
2. The app iframe loads and registers runtime handlers with
|
|
20
|
+
`usePlatformAgentTools`.
|
|
21
|
+
3. The agent calls a declared tool during a shell-managed session.
|
|
22
|
+
4. The shell routes the invocation to the app iframe.
|
|
23
|
+
5. The app handler returns compact text or JSON.
|
|
24
|
+
6. The bridge helper completes the tool call back to the shell.
|
|
25
|
+
7. The shell resumes the agent session.
|
|
26
|
+
|
|
27
|
+
The app owns the handler implementation. The shell owns session state,
|
|
28
|
+
approvals, routing, and completion.
|
|
29
|
+
|
|
30
|
+
When `plugin.json` contains `app.agents.tools`, the create-app generator writes
|
|
31
|
+
the initial catalog, handler map, and registration hook. The generated handlers
|
|
32
|
+
return explicit not-implemented tool errors until the app replaces them with real
|
|
33
|
+
domain behavior.
|
|
34
|
+
|
|
35
|
+
## agents.md
|
|
36
|
+
|
|
37
|
+
Keep `agents.md` grounded in the app's real UI and data. Mention the app's work
|
|
38
|
+
objects, read-first workflow, write safety rules, and expected concise output.
|
|
39
|
+
|
|
40
|
+
Example:
|
|
41
|
+
|
|
42
|
+
```md
|
|
43
|
+
# {{APP_TITLE}} Agent
|
|
44
|
+
|
|
45
|
+
You are the app-scoped assistant for {{APP_TITLE}}.
|
|
46
|
+
|
|
47
|
+
Help the user understand, review, and act on the work inside this app. Stay
|
|
48
|
+
grounded in the app UI and data. Prefer concise answers, concrete next actions,
|
|
49
|
+
and safe tool use.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Approval Policy
|
|
53
|
+
|
|
54
|
+
Set `requiresApproval` on each manifest tool. Read-only inspection tools usually
|
|
55
|
+
set `false`. Destructive, external-effect, or broad write tools set `true`.
|
|
56
|
+
|
|
57
|
+
The shell drawer displays approvals and resumes the same session after the user
|
|
58
|
+
approves or rejects.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# App Lifecycle
|
|
2
|
+
|
|
3
|
+
A PureDesktop app is loaded into an iframe by the shell. The shell discovers the
|
|
4
|
+
app from `plugin.json`, opens a workspace tab, loads the entrypoint URL or built
|
|
5
|
+
static bundle, then establishes the bridge handshake with the iframe.
|
|
6
|
+
|
|
7
|
+
## Registration To Render
|
|
8
|
+
|
|
9
|
+
1. The shell scans installed app folders for `plugin.json`.
|
|
10
|
+
2. The catalog creates one app entry from `plugin.json` `app.slug`.
|
|
11
|
+
3. Opening the app creates a workspace tab.
|
|
12
|
+
4. The tab renders the app entrypoint in an iframe.
|
|
13
|
+
5. The iframe starts React from `src/main.tsx`.
|
|
14
|
+
6. `src/App.tsx` calls `usePlatformBridge()`.
|
|
15
|
+
7. The bridge client sends a handshake to the shell parent window.
|
|
16
|
+
8. The shell replies with `ready` metadata, including `pluginId`, `appSlug`,
|
|
17
|
+
allowed method names, theme CSS, and optional viewport resource.
|
|
18
|
+
9. The app boot hook loads app settings and other startup data.
|
|
19
|
+
10. The app renders inside `AppFrame`.
|
|
20
|
+
|
|
21
|
+
## App.tsx Contract
|
|
22
|
+
|
|
23
|
+
`src/App.tsx` is the orchestration boundary. Keep it thin:
|
|
24
|
+
|
|
25
|
+
- call `usePlatformBridge()`;
|
|
26
|
+
- allow standalone browser dev mode when needed;
|
|
27
|
+
- call the app boot hook after the bridge is ready;
|
|
28
|
+
- render loading and error states inside `AppFrame`;
|
|
29
|
+
- render the app shell inside `AppFrame` after boot succeeds.
|
|
30
|
+
|
|
31
|
+
The template already follows this shape.
|
|
32
|
+
|
|
33
|
+
## Viewport Resources
|
|
34
|
+
|
|
35
|
+
When the shell opens a file or app resource into a tab, the bridge ready metadata
|
|
36
|
+
can include:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
{
|
|
40
|
+
viewport: {
|
|
41
|
+
tabId: string
|
|
42
|
+
resource: { path: string; name: string; kind: string } | null
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
File-centric apps use `usePlatformViewportResource(ready, meta)` from the bridge
|
|
48
|
+
React helpers. This handles cold opens and warm `resource.open` events without
|
|
49
|
+
duplicating event wiring in screens.
|
|
50
|
+
|
|
51
|
+
## Standalone Dev
|
|
52
|
+
|
|
53
|
+
The template supports browser-only development with:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
window.parent === window
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Standalone mode is for UI iteration. Production app behavior runs inside the
|
|
60
|
+
shell iframe and uses shell bridge permissions.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Platform Bridge Helpers
|
|
2
|
+
|
|
3
|
+
The bridge is the app iframe's RPC channel to the PureDesktop shell.
|
|
4
|
+
|
|
5
|
+
The generated app runs in an iframe. It cannot call shell internals directly.
|
|
6
|
+
Instead, app code imports helpers from `src/bridge/platformBridge.ts`. That
|
|
7
|
+
local bridge module wraps the package bridge client from
|
|
8
|
+
`@puredesktop/puredesktop-ui-bridge`.
|
|
9
|
+
|
|
10
|
+
## Runtime Boundary
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
App iframe -> bridge helper -> postMessage -> shell renderer -> shell handler
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The shell validates the app origin, method name, and `plugin.json` permissions
|
|
17
|
+
before running a handler.
|
|
18
|
+
|
|
19
|
+
## Ready Handshake
|
|
20
|
+
|
|
21
|
+
`src/App.tsx` uses `usePlatformBridge()` to wait for the shell:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
const { ready, error, meta } = usePlatformBridge()
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The shell ready payload includes:
|
|
28
|
+
|
|
29
|
+
- `pluginId`: plugin package identity.
|
|
30
|
+
- `appSlug`: app API scope.
|
|
31
|
+
- `methods`: bridge methods available in this shell.
|
|
32
|
+
- `theme`: injected theme CSS.
|
|
33
|
+
- `viewport`: optional tab resource opened into the app.
|
|
34
|
+
|
|
35
|
+
Call bridge helpers after `ready` is true. The template boot hook follows that
|
|
36
|
+
pattern.
|
|
37
|
+
|
|
38
|
+
## Local Bridge Module
|
|
39
|
+
|
|
40
|
+
`src/bridge/platformBridge.ts` is the app's bridge boundary. Components and
|
|
41
|
+
feature code import from that local file:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { fetchAppSettings, networkFetch } from '../bridge/platformBridge'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Keep request-shape knowledge in this bridge folder. Component code calls
|
|
48
|
+
domain-named helpers.
|
|
49
|
+
|
|
50
|
+
## Helper Domains
|
|
51
|
+
|
|
52
|
+
- [Dialog](./dialog.md)
|
|
53
|
+
- [Filesystem](./fs.md)
|
|
54
|
+
- [Network](./network.md)
|
|
55
|
+
- [Settings](./settings.md)
|
|
56
|
+
- [Storage](./storage.md)
|
|
57
|
+
|
|
58
|
+
## Permissions
|
|
59
|
+
|
|
60
|
+
Bridge calls are gated by top-level `plugin.json` `permissions`.
|
|
61
|
+
|
|
62
|
+
| Permission | Helper domains |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `settings` | settings and preferences |
|
|
65
|
+
| `filesystem` | filesystem, dialogs, storage, file routing |
|
|
66
|
+
| `network` | network requests and OAuth-style flows |
|
|
67
|
+
| `render` | print and render helpers |
|
|
68
|
+
| `assets` | asset library helpers |
|
|
69
|
+
| `agents` | agent sessions, agent tools, credentials |
|
|
70
|
+
|
|
71
|
+
## Events
|
|
72
|
+
|
|
73
|
+
The bridge also delivers shell events into the iframe. Common app events include
|
|
74
|
+
theme changes, viewport resource opens, render progress, filesystem watch
|
|
75
|
+
changes, agent run events, and app tool invocations.
|
|
76
|
+
|
|
77
|
+
Use the package React hooks when they exist. For example,
|
|
78
|
+
`usePlatformViewportResource(ready, meta)` handles file opens without manual
|
|
79
|
+
event wiring.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Dialog
|
|
2
|
+
|
|
3
|
+
Permission: `filesystem`
|
|
4
|
+
|
|
5
|
+
Dialog helpers open shell-native file and folder pickers.
|
|
6
|
+
|
|
7
|
+
Import from the generated app bridge:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {
|
|
11
|
+
openPlatformFileDialog,
|
|
12
|
+
openPlatformFolderDialog,
|
|
13
|
+
openPlatformImageDialog,
|
|
14
|
+
savePlatformFolderDialog,
|
|
15
|
+
} from '../../src/bridge/platformBridge'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## openPlatformFolderDialog
|
|
19
|
+
|
|
20
|
+
Opens a folder picker.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
const folderPath = await openPlatformFolderDialog()
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Returns the selected absolute folder path, or `null` when cancelled.
|
|
27
|
+
|
|
28
|
+
## savePlatformFolderDialog
|
|
29
|
+
|
|
30
|
+
Opens a folder picker configured for choosing a parent directory.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
const parentPath = await savePlatformFolderDialog()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Returns the selected absolute folder path, or `null` when cancelled.
|
|
37
|
+
|
|
38
|
+
## openPlatformImageDialog
|
|
39
|
+
|
|
40
|
+
Opens an image file picker.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
const imagePath = await openPlatformImageDialog()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Returns the selected absolute image path, or `null` when cancelled.
|
|
47
|
+
|
|
48
|
+
## openPlatformFileDialog
|
|
49
|
+
|
|
50
|
+
Opens a text/document file picker.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const filePath = await openPlatformFileDialog()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Returns the selected absolute file path, or `null` when cancelled.
|