@puredesktop/create-app 2.1.0 → 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.
@@ -1,26 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Scaffold an external PureScience Desktop plugin app.
3
+ * Scaffold an external PureDesktop plugin app.
4
4
  *
5
- * Published as @puredesktop/create-app npm create @puredesktop/app@latest
5
+ * Published as @puredesktop/create-app -> npm create @puredesktop/app@latest
6
6
  */
7
- import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
7
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
8
8
  import { dirname, join, resolve } from 'node:path'
9
9
  import { fileURLToPath } from 'node:url'
10
10
 
11
- const __dirname = dirname(fileURLToPath(import.meta.url))
12
- const TEMPLATE_DIR = join(__dirname, '..', 'template')
13
- const DEFAULT_UI = '@puredesktop/puredesktop-ui-bridge'
14
- const DEFAULT_UI_VERSION = '2.1.0'
15
-
16
- function usage() {
17
- console.log(`Usage: npm create @puredesktop/app@latest [dir] [options]
11
+ const __dirname = dirname(fileURLToPath(import.meta.url))
12
+ const TEMPLATE_DIR = join(__dirname, '..', 'template')
13
+
14
+ function usage() {
15
+ console.log(`Usage: npm create @puredesktop/app@latest [dir] [options]
18
16
 
19
17
  Options:
20
18
  --name <title> Display name (default: derived from dir)
21
19
  --slug <slug> App slug for settings/bridge (default: dir name)
22
20
  --port <number> Dev server port in plugin.json (default: 5300)
23
- --ui <spec> UI package spec (default: ${DEFAULT_UI}@${DEFAULT_UI_VERSION})
24
21
  --manifest-json-base64 <base64>
25
22
  Structured plugin.json manifest draft for app-builder use
26
23
  --agents-md-base64 <base64>
@@ -29,30 +26,15 @@ Options:
29
26
  Examples:
30
27
  npm create @puredesktop/app@latest my-tool
31
28
  npm create @puredesktop/app@latest my-tool -- --name "My Tool" --slug mytool --port 5310
32
- `)
33
- }
34
-
35
- function uiDependencySpec(spec) {
36
- if (spec.startsWith('file:')) {
37
- return {
38
- name: '@puredesktop/puredesktop-ui-bridge',
39
- version: spec,
40
- }
41
- }
42
- const at = spec.lastIndexOf('@')
43
- if (at > 1) {
44
- return { name: spec.slice(0, at), version: spec.slice(at + 1) }
45
- }
46
- return { name: spec, version: DEFAULT_UI_VERSION }
47
- }
48
-
49
- function parseArgs(argv) {
50
- const positional = []
51
- const options = {
29
+ `)
30
+ }
31
+
32
+ function parseArgs(argv) {
33
+ const positional = []
34
+ const options = {
52
35
  name: '',
53
36
  slug: '',
54
37
  port: 5300,
55
- ui: `${DEFAULT_UI}@${DEFAULT_UI_VERSION}`,
56
38
  manifestJsonBase64: '',
57
39
  agentsMdBase64: '',
58
40
  }
@@ -71,12 +53,8 @@ function parseArgs(argv) {
71
53
  options.slug = argv[++i] ?? ''
72
54
  continue
73
55
  }
74
- if (arg === '--port') {
75
- options.port = Number(argv[++i])
76
- continue
77
- }
78
- if (arg === '--ui') {
79
- options.ui = argv[++i] ?? options.ui
56
+ if (arg === '--port') {
57
+ options.port = Number(argv[++i])
80
58
  continue
81
59
  }
82
60
  if (arg === '--manifest-json-base64') {
@@ -223,6 +201,110 @@ function errorMessage(error) {
223
201
  return error instanceof Error ? error.message : String(error)
224
202
  }
225
203
 
204
+ function readGeneratedManifest(outDir) {
205
+ try {
206
+ return JSON.parse(readFileSync(join(outDir, 'plugin.json'), 'utf8'))
207
+ } catch (error) {
208
+ console.error(`Generated plugin.json could not be read: ${errorMessage(error)}`)
209
+ process.exit(1)
210
+ }
211
+ }
212
+
213
+ function readAgentToolNames(manifest) {
214
+ const tools = manifest?.app?.agents?.tools
215
+ if (!Array.isArray(tools)) return []
216
+ return tools
217
+ .map(tool => (typeof tool?.name === 'string' ? tool.name.trim() : ''))
218
+ .filter(Boolean)
219
+ }
220
+
221
+ function jsonString(value) {
222
+ return JSON.stringify(value)
223
+ }
224
+
225
+ function writeAgentToolScaffold(outDir, appSlug, toolNames) {
226
+ if (toolNames.length === 0) return
227
+
228
+ const agentsDir = join(outDir, 'src', 'agents')
229
+ const handlersDir = join(agentsDir, 'handlers')
230
+ const hooksDir = join(outDir, 'src', 'hooks')
231
+ mkdirSync(handlersDir, { recursive: true })
232
+ mkdirSync(hooksDir, { recursive: true })
233
+
234
+ writeFileSync(
235
+ join(agentsDir, 'catalog.ts'),
236
+ `export const APP_AGENT_TOOL_NAMES = ${JSON.stringify(toolNames, null, 2)} as const
237
+
238
+ export const APP_AGENT_LOG_LABEL = ${jsonString(appSlug)}
239
+ `,
240
+ )
241
+
242
+ const handlerEntries = toolNames
243
+ .map(
244
+ name =>
245
+ ` ${jsonString(name)}: async () => notImplemented(${jsonString(name)}),`,
246
+ )
247
+ .join('\n')
248
+
249
+ writeFileSync(
250
+ join(handlersDir, 'index.ts'),
251
+ `import { agentToolErrorContent } from '@puredesktop/puredesktop-ui-bridge/bridge/agentToolHelpers'
252
+ import type { AgentToolHandler } from '@puredesktop/puredesktop-ui-bridge/bridge/react/usePlatformAgentTools'
253
+
254
+ function notImplemented(toolName: string) {
255
+ return agentToolErrorContent(
256
+ \`Tool "\${toolName}" is declared in plugin.json but its runtime handler has not been implemented yet.\`,
257
+ )
258
+ }
259
+
260
+ export const appAgentHandlers = {
261
+ ${handlerEntries}
262
+ } satisfies Record<string, AgentToolHandler>
263
+ `,
264
+ )
265
+
266
+ writeFileSync(
267
+ join(hooksDir, 'useAppAgentTools.ts'),
268
+ `import { usePlatformAgentTools } from '@puredesktop/puredesktop-ui-bridge/bridge/react/usePlatformAgentTools'
269
+ import { APP_AGENT_LOG_LABEL, APP_AGENT_TOOL_NAMES } from '../agents/catalog'
270
+ import { appAgentHandlers } from '../agents/handlers'
271
+
272
+ export function useAppAgentTools(ready: boolean): void {
273
+ usePlatformAgentTools({
274
+ ready,
275
+ tools: APP_AGENT_TOOL_NAMES,
276
+ logLabel: APP_AGENT_LOG_LABEL,
277
+ handlers: appAgentHandlers,
278
+ })
279
+ }
280
+ `,
281
+ )
282
+
283
+ wireAgentToolHook(outDir)
284
+ }
285
+
286
+ function wireAgentToolHook(outDir) {
287
+ const appPath = join(outDir, 'src', 'App.tsx')
288
+ const source = readFileSync(appPath, 'utf8')
289
+ const importPattern = /import \{ useAppBoot \} from '\.\/hooks\/useAppBoot'\r?\n/
290
+ const callPattern = /( const \{ error: bridgeError, ready \} = usePlatformBridge\(\)\r?\n)/
291
+
292
+ if (!importPattern.test(source) || !callPattern.test(source)) {
293
+ console.error('Generated src/App.tsx does not match the agent tool scaffold insertion points.')
294
+ process.exit(1)
295
+ }
296
+
297
+ const withImport = source.replace(
298
+ importPattern,
299
+ match => `${match}import { useAppAgentTools } from './hooks/useAppAgentTools'\n`,
300
+ )
301
+ const withHook = withImport.replace(
302
+ callPattern,
303
+ (_match, line) => `${line} useAppAgentTools(ready)\n`,
304
+ )
305
+ writeFileSync(appPath, withHook)
306
+ }
307
+
226
308
  function copyTemplate(srcDir, destDir, vars) {
227
309
  for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
228
310
  const srcPath = join(srcDir, entry.name)
@@ -246,7 +328,6 @@ const structuredManifest = options.manifestJsonBase64
246
328
  const structuredAgentsMd = options.agentsMdBase64
247
329
  ? readStructuredAgentsMd(options.agentsMdBase64)
248
330
  : null
249
- const uiDep = uiDependencySpec(options.ui)
250
331
  const dirName = targetDir
251
332
  const structuredSlug = structuredManifest?.app.slug ?? ''
252
333
  const structuredTitle = structuredManifest?.app.name ?? ''
@@ -273,13 +354,11 @@ mkdirSync(outDir, { recursive: true })
273
354
  const vars = {
274
355
  APP_TITLE: title,
275
356
  APP_SLUG: slug,
276
- APP_NAME: slug,
277
- PLUGIN_ID: pluginId,
278
- APP_PORT: String(options.port),
279
- UI_PACKAGE_NAME: uiDep.name,
280
- UI_PACKAGE_VERSION: uiDep.version,
281
- PACKAGE_NAME: `@puredesktop/${slug}`,
282
- }
357
+ APP_NAME: slug,
358
+ PLUGIN_ID: pluginId,
359
+ APP_PORT: String(options.port),
360
+ PACKAGE_NAME: `@puredesktop/${slug}`,
361
+ }
283
362
 
284
363
  copyTemplate(TEMPLATE_DIR, outDir, vars)
285
364
 
@@ -294,8 +373,15 @@ if (structuredAgentsMd) {
294
373
  writeFileSync(join(outDir, 'agents.md'), structuredAgentsMd)
295
374
  }
296
375
 
376
+ const generatedManifest = readGeneratedManifest(outDir)
377
+ writeAgentToolScaffold(
378
+ outDir,
379
+ generatedManifest?.app?.slug ?? slug,
380
+ readAgentToolNames(generatedManifest),
381
+ )
382
+
297
383
  console.log(`
298
- Created ${title} at ${outDir}
384
+ Created ${title} at ${outDir}
299
385
 
300
386
  cd ${dirName}
301
387
  npm install
@@ -306,7 +392,7 @@ Before shipping:
306
392
  npm run build
307
393
  npm run puredesktop:check
308
394
 
309
- Register in PureScience Desktop (File Register App) with:
395
+ Register in PureDesktop (File -> Register App...) with:
310
396
  entrypoint: http://localhost:${options.port}
311
397
  permissions: network, settings, agents
312
398
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@puredesktop/create-app",
3
- "version": "2.1.0",
4
- "description": "Scaffold a PureScience Desktop plugin app (Vite + bridge SDK)",
3
+ "version": "2.1.1",
4
+ "description": "Scaffold a PureDesktop plugin app (Vite + bridge SDK)",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "create-app": "./bin/create-puredesktop-app.mjs",
@@ -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
- ```bash
20
- npm run typecheck
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
- Keep this structure and update values rather than inventing new fields:
6
+ ## Start
97
7
 
98
- ```json
99
- {
100
- "schemaVersion": 1,
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
- Register matching runtime handlers after the bridge is ready:
13
+ The dev server runs at `http://localhost:{{APP_PORT}}`, matching
14
+ `plugin.json`.
169
15
 
170
- ```tsx
171
- import { usePlatformAgentTools } from '@puredesktop/puredesktop-ui-bridge/bridge/react/usePlatformAgentTools'
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
- function AppAgentTools({ ready }: { ready: boolean }) {
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
- return null
203
- }
21
+ ```bash
22
+ npm run typecheck
23
+ npm run build
24
+ npm run puredesktop:check
204
25
  ```
205
26
 
206
- Manifest tool names and handler names must match exactly. Read tools should
207
- return compact JSON with stable ids. Write tools should validate exact targets,
208
- reject ambiguous edits, and return a concise JSON result. Destructive or
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
- ## Platform CSS variables
31
+ ## Project Layout
219
32
 
220
- Theme variables are injected by PureDesktop and follow
221
- `--platform-<domain>-<token>`. Use these before adding app-local variables:
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
- ```text
224
- --platform-mode
42
+ ## Builder Docs
225
43
 
226
- --platform-colors-bg
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
- --platform-typography-font-family
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
- --platform-spacing-xs
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
- Use the plural `--platform-colors-*` prefix for colors. Do not create
312
- `--platform-color-*` variables. App-specific variables should use an app prefix,
313
- for example `--my-app-accent`.
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.