@puredesktop/create-app 2.1.9 → 2.1.10

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.
@@ -20,10 +20,10 @@ if (packageJson) {
20
20
  validatePackageJson(packageJson)
21
21
  }
22
22
 
23
- if (manifest) {
24
- validateManifest(manifest)
25
- await validateBridgePermissionUsage(manifest)
26
- }
23
+ if (manifest) {
24
+ validateManifest(manifest)
25
+ await validateBridgePermissionUsage(manifest)
26
+ }
27
27
 
28
28
  if (await isDirectory(distPath)) {
29
29
  info.push('dist folder is present for static registration.')
@@ -136,7 +136,7 @@ function validateManifest(manifest) {
136
136
  if (errors.length === 0) info.push('plugin.json is valid.')
137
137
  }
138
138
 
139
- function validateEntrypoint(entrypoint, permissions) {
139
+ function validateEntrypoint(entrypoint, permissions) {
140
140
  if (!isPlainObject(entrypoint)) {
141
141
  errors.push('entrypoint is required.')
142
142
  return
@@ -170,47 +170,47 @@ function validateEntrypoint(entrypoint, permissions) {
170
170
  }
171
171
  return
172
172
  }
173
- errors.push(`Unsupported entrypoint kind: ${String(entrypoint.kind ?? '') || '(missing)'}.`)
174
- }
175
-
176
- async function validateBridgePermissionUsage(manifest) {
177
- const permissions = Array.isArray(manifest.permissions) ? manifest.permissions : []
178
- const sourceText = await readProjectText(join(ROOT, 'src'))
179
- const requirements = [
180
- {
181
- permission: 'filesystem',
182
- hints: [
183
- '/bridge/storage',
184
- '/bridge/fs',
185
- '/bridge/dialog',
186
- '/bridge/react/usePlatformJsonStore',
187
- ],
188
- },
189
- {
190
- permission: 'settings',
191
- hints: [
192
- '/bridge/appSettings',
193
- '/bridge/preferences',
194
- '/bridge/react/usePlatformAppSettings',
195
- '/bridge/react/usePlatformPreferences',
196
- ],
197
- },
198
- {
199
- permission: 'network',
200
- hints: ['/bridge/network', '/bridge/vision'],
201
- },
202
- ]
203
-
204
- for (const requirement of requirements) {
205
- if (permissions.includes(requirement.permission)) continue
206
- if (!requirement.hints.some(hint => sourceText.includes(hint))) continue
207
- errors.push(
208
- `Source imports ${requirement.permission}-gated bridge helpers, so plugin.json must include the ${requirement.permission} permission.`,
209
- )
210
- }
211
- }
212
-
213
- async function validateAgentTools(manifest, distPath) {
173
+ errors.push(`Unsupported entrypoint kind: ${String(entrypoint.kind ?? '') || '(missing)'}.`)
174
+ }
175
+
176
+ async function validateBridgePermissionUsage(manifest) {
177
+ const permissions = Array.isArray(manifest.permissions) ? manifest.permissions : []
178
+ const sourceText = await readProjectText(join(ROOT, 'src'))
179
+ const requirements = [
180
+ {
181
+ permission: 'filesystem',
182
+ hints: [
183
+ '/bridge/storage',
184
+ '/bridge/fs',
185
+ '/bridge/dialog',
186
+ '/bridge/react/usePlatformJsonStore',
187
+ ],
188
+ },
189
+ {
190
+ permission: 'settings',
191
+ hints: [
192
+ '/bridge/appSettings',
193
+ '/bridge/preferences',
194
+ '/bridge/react/usePlatformAppSettings',
195
+ '/bridge/react/usePlatformPreferences',
196
+ ],
197
+ },
198
+ {
199
+ permission: 'network',
200
+ hints: ['/bridge/network', '/bridge/vision'],
201
+ },
202
+ ]
203
+
204
+ for (const requirement of requirements) {
205
+ if (permissions.includes(requirement.permission)) continue
206
+ if (!requirement.hints.some(hint => sourceText.includes(hint))) continue
207
+ errors.push(
208
+ `Source imports ${requirement.permission}-gated bridge helpers, so plugin.json must include the ${requirement.permission} permission.`,
209
+ )
210
+ }
211
+ }
212
+
213
+ async function validateAgentTools(manifest, distPath) {
214
214
  const tools = manifest.app?.agents?.tools ?? []
215
215
  if (!Array.isArray(tools) || tools.length === 0) {
216
216
  info.push('No app agent tools declared.')
@@ -1,10 +1,10 @@
1
1
  import { AppFrame } from '@puredesktop/puredesktop-ui-bridge/components/common/containers/AppFrame'
2
2
  import { EmptyState } from '@puredesktop/puredesktop-ui-bridge/components/common/feedback/EmptyState'
3
3
  import { usePlatformBridge } from '@puredesktop/puredesktop-ui-bridge/bridge/react/usePlatformBridge'
4
- import { AppShell } from './components/AppShell'
5
- import { isStandaloneDevMode } from './bridge/platformBridge'
6
- import { APP_TITLE } from './constants'
7
- import { useAppBoot } from './hooks/useAppBoot'
4
+ import { AppShell } from './components/AppShell'
5
+ import { isStandaloneDevMode } from './bridge/platformBridge'
6
+ import { APP_TITLE } from './constants'
7
+ import { useAppBoot } from './hooks/useAppBoot'
8
8
 
9
9
  export function App(): React.ReactElement {
10
10
  const { error: bridgeError, ready } = usePlatformBridge()
@@ -14,7 +14,7 @@ export function App(): React.ReactElement {
14
14
 
15
15
  if (bridgeError && !standaloneDev) {
16
16
  return (
17
- <AppFrame>
17
+ <AppFrame hideWordmark>
18
18
  <EmptyState
19
19
  tone="error"
20
20
  title="Bridge unavailable"
@@ -26,10 +26,10 @@ export function App(): React.ReactElement {
26
26
 
27
27
  if (!bootReady || !boot) {
28
28
  return (
29
- <AppFrame>
29
+ <AppFrame hideWordmark>
30
30
  <EmptyState
31
31
  tone={bootError ? 'error' : 'neutral'}
32
- title={bootError ? 'Boot failed' : APP_TITLE}
32
+ title={bootError ? 'Boot failed' : APP_TITLE}
33
33
  message={
34
34
  bootError
35
35
  ? bootError.message
@@ -43,7 +43,7 @@ export function App(): React.ReactElement {
43
43
  }
44
44
 
45
45
  return (
46
- <AppFrame>
46
+ <AppFrame hideWordmark>
47
47
  <AppShell settings={boot.settings} />
48
48
  </AppFrame>
49
49
  )
@@ -1,11 +1,11 @@
1
- import type { AppSettings } from '../types'
2
- import { APP_TITLE } from '../constants'
3
- import { StarterWorkspace } from './StarterWorkspace'
4
-
5
- export interface AppShellProps {
6
- settings: AppSettings
7
- }
8
-
9
- export function AppShell({ settings }: AppShellProps): React.ReactElement {
10
- return <StarterWorkspace appName={APP_TITLE} settings={settings} />
11
- }
1
+ import type { AppSettings } from '../types'
2
+ import { APP_TITLE } from '../constants'
3
+ import { StarterWorkspace } from './StarterWorkspace'
4
+
5
+ export interface AppShellProps {
6
+ settings: AppSettings
7
+ }
8
+
9
+ export function AppShell({ settings }: AppShellProps): React.ReactElement {
10
+ return <StarterWorkspace appName={APP_TITLE} settings={settings} />
11
+ }
@@ -1,154 +1,154 @@
1
- import styled from 'styled-components'
2
- import { Heading } from '@puredesktop/puredesktop-ui-bridge/components/common/typography/Heading'
3
- import { Text } from '@puredesktop/puredesktop-ui-bridge/components/common/typography/Text'
4
- import {
5
- readConfiguredSettingCount,
6
- starterMilestones,
7
- } from '../lib/starterWorkspace'
8
- import type { AppSettings } from '../types'
9
-
10
- const Root = styled.div`
11
- display: flex;
12
- min-height: 100%;
13
- width: 100%;
14
- align-items: center;
15
- justify-content: center;
16
- padding: var(--platform-spacing-xxl);
17
- color: var(--platform-colors-text);
18
- background:
19
- linear-gradient(
20
- 135deg,
21
- color-mix(in srgb, var(--platform-colors-accent) 6%, transparent),
22
- transparent 42%
23
- ),
24
- var(--platform-colors-bg);
25
- `
26
-
27
- const Panel = styled.section`
28
- display: grid;
29
- width: min(760px, 100%);
30
- gap: var(--platform-spacing-xl);
31
- `
32
-
33
- const Header = styled.header`
34
- display: grid;
35
- gap: var(--platform-spacing-sm);
36
- `
37
-
38
- const MilestoneGrid = styled.div`
39
- display: grid;
40
- grid-template-columns: repeat(3, minmax(0, 1fr));
41
- gap: var(--platform-spacing-md);
42
-
43
- @media (max-width: 720px) {
44
- grid-template-columns: 1fr;
45
- }
46
- `
47
-
48
- const Milestone = styled.article`
49
- display: grid;
50
- gap: var(--platform-spacing-sm);
51
- min-width: 0;
52
- padding: var(--platform-spacing-lg);
53
- border: 1px solid var(--platform-colors-border);
54
- background: var(--platform-colors-surface);
55
- box-shadow: var(--platform-shadow-sm);
56
- `
57
-
58
- const PulseTrack = styled.div`
59
- position: relative;
60
- overflow: hidden;
61
- height: 3px;
62
- background: var(--platform-colors-border);
63
- `
64
-
65
- const Pulse = styled.div`
66
- position: absolute;
67
- inset: 0 auto 0 0;
68
- width: 44%;
69
- background: var(--platform-colors-accent);
70
- animation: starter-pulse 1600ms ease-in-out infinite;
71
-
72
- @keyframes starter-pulse {
73
- 0% {
74
- transform: translateX(-100%);
75
- opacity: 0.35;
76
- }
77
-
78
- 45%,
79
- 60% {
80
- opacity: 1;
81
- }
82
-
83
- 100% {
84
- transform: translateX(230%);
85
- opacity: 0.35;
86
- }
87
- }
88
- `
89
-
90
- const MetaRow = styled.div`
91
- display: flex;
92
- flex-wrap: wrap;
93
- gap: var(--platform-spacing-sm);
94
- `
95
-
96
- const MetaPill = styled.span`
97
- padding: 4px 8px;
98
- border: 1px solid var(--platform-colors-border);
99
- background: var(--platform-colors-surface);
100
- color: var(--platform-colors-text-secondary);
101
- font-size: var(--platform-typography-font-size-xs);
102
- font-weight: var(--platform-typography-font-weight-medium);
103
- `
104
-
105
- interface StarterWorkspaceProps {
106
- appName: string
107
- settings: AppSettings
108
- }
109
-
110
- export function StarterWorkspace({
111
- appName,
112
- settings,
113
- }: StarterWorkspaceProps): React.ReactElement {
114
- const settingCount = readConfiguredSettingCount(settings)
115
-
116
- return (
117
- <Root>
118
- <Panel aria-label={`${appName} starter workspace`}>
119
- <Header>
120
- <Text size="sm" tone="secondary">
121
- PureDesktop app workspace
122
- </Text>
123
- <Heading level={1}>{appName}</Heading>
124
- <Text tone="secondary">
125
- This workspace is ready. The first build step will replace this
126
- starter screen with the product experience.
127
- </Text>
128
- </Header>
129
-
130
- <MilestoneGrid>
131
- {starterMilestones.map(milestone => (
132
- <Milestone key={milestone.id}>
133
- <Text size="sm" weight="medium">
134
- {milestone.title}
135
- </Text>
136
- <Text size="sm" tone="secondary">
137
- {milestone.detail}
138
- </Text>
139
- <PulseTrack aria-hidden="true">
140
- <Pulse />
141
- </PulseTrack>
142
- </Milestone>
143
- ))}
144
- </MilestoneGrid>
145
-
146
- <MetaRow>
147
- <MetaPill>{settingCount} setting key(s)</MetaPill>
148
- <MetaPill>Theme active</MetaPill>
149
- <MetaPill>Shell connected</MetaPill>
150
- </MetaRow>
151
- </Panel>
152
- </Root>
153
- )
154
- }
1
+ import styled from 'styled-components'
2
+ import { Heading } from '@puredesktop/puredesktop-ui-bridge/components/common/typography/Heading'
3
+ import { Text } from '@puredesktop/puredesktop-ui-bridge/components/common/typography/Text'
4
+ import {
5
+ readConfiguredSettingCount,
6
+ starterMilestones,
7
+ } from '../lib/starterWorkspace'
8
+ import type { AppSettings } from '../types'
9
+
10
+ const Root = styled.div`
11
+ display: flex;
12
+ min-height: 100%;
13
+ width: 100%;
14
+ align-items: center;
15
+ justify-content: center;
16
+ padding: var(--platform-spacing-xxl);
17
+ color: var(--platform-colors-text);
18
+ background:
19
+ linear-gradient(
20
+ 135deg,
21
+ color-mix(in srgb, var(--platform-colors-accent) 6%, transparent),
22
+ transparent 42%
23
+ ),
24
+ var(--platform-colors-bg);
25
+ `
26
+
27
+ const Panel = styled.section`
28
+ display: grid;
29
+ width: min(760px, 100%);
30
+ gap: var(--platform-spacing-xl);
31
+ `
32
+
33
+ const Header = styled.header`
34
+ display: grid;
35
+ gap: var(--platform-spacing-sm);
36
+ `
37
+
38
+ const MilestoneGrid = styled.div`
39
+ display: grid;
40
+ grid-template-columns: repeat(3, minmax(0, 1fr));
41
+ gap: var(--platform-spacing-md);
42
+
43
+ @media (max-width: 720px) {
44
+ grid-template-columns: 1fr;
45
+ }
46
+ `
47
+
48
+ const Milestone = styled.article`
49
+ display: grid;
50
+ gap: var(--platform-spacing-sm);
51
+ min-width: 0;
52
+ padding: var(--platform-spacing-lg);
53
+ border: 1px solid var(--platform-colors-border);
54
+ background: var(--platform-colors-surface);
55
+ box-shadow: var(--platform-shadow-sm);
56
+ `
57
+
58
+ const PulseTrack = styled.div`
59
+ position: relative;
60
+ overflow: hidden;
61
+ height: 3px;
62
+ background: var(--platform-colors-border);
63
+ `
64
+
65
+ const Pulse = styled.div`
66
+ position: absolute;
67
+ inset: 0 auto 0 0;
68
+ width: 44%;
69
+ background: var(--platform-colors-accent);
70
+ animation: starter-pulse 1600ms ease-in-out infinite;
71
+
72
+ @keyframes starter-pulse {
73
+ 0% {
74
+ transform: translateX(-100%);
75
+ opacity: 0.35;
76
+ }
77
+
78
+ 45%,
79
+ 60% {
80
+ opacity: 1;
81
+ }
82
+
83
+ 100% {
84
+ transform: translateX(230%);
85
+ opacity: 0.35;
86
+ }
87
+ }
88
+ `
89
+
90
+ const MetaRow = styled.div`
91
+ display: flex;
92
+ flex-wrap: wrap;
93
+ gap: var(--platform-spacing-sm);
94
+ `
95
+
96
+ const MetaPill = styled.span`
97
+ padding: 4px 8px;
98
+ border: 1px solid var(--platform-colors-border);
99
+ background: var(--platform-colors-surface);
100
+ color: var(--platform-colors-text-secondary);
101
+ font-size: var(--platform-typography-font-size-xs);
102
+ font-weight: var(--platform-typography-font-weight-medium);
103
+ `
104
+
105
+ interface StarterWorkspaceProps {
106
+ appName: string
107
+ settings: AppSettings
108
+ }
109
+
110
+ export function StarterWorkspace({
111
+ appName,
112
+ settings,
113
+ }: StarterWorkspaceProps): React.ReactElement {
114
+ const settingCount = readConfiguredSettingCount(settings)
115
+
116
+ return (
117
+ <Root>
118
+ <Panel aria-label={`${appName} starter workspace`}>
119
+ <Header>
120
+ <Text size="sm" tone="secondary">
121
+ PureDesktop app workspace
122
+ </Text>
123
+ <Heading level={1}>{appName}</Heading>
124
+ <Text tone="secondary">
125
+ This workspace is ready. The first build step will replace this
126
+ starter screen with the product experience.
127
+ </Text>
128
+ </Header>
129
+
130
+ <MilestoneGrid>
131
+ {starterMilestones.map(milestone => (
132
+ <Milestone key={milestone.id}>
133
+ <Text size="sm" weight="medium">
134
+ {milestone.title}
135
+ </Text>
136
+ <Text size="sm" tone="secondary">
137
+ {milestone.detail}
138
+ </Text>
139
+ <PulseTrack aria-hidden="true">
140
+ <Pulse />
141
+ </PulseTrack>
142
+ </Milestone>
143
+ ))}
144
+ </MilestoneGrid>
145
+
146
+ <MetaRow>
147
+ <MetaPill>{settingCount} setting key(s)</MetaPill>
148
+ <MetaPill>Theme active</MetaPill>
149
+ <MetaPill>Shell connected</MetaPill>
150
+ </MetaRow>
151
+ </Panel>
152
+ </Root>
153
+ )
154
+ }
@@ -1,2 +1,2 @@
1
- export const APP_SLUG = '{{APP_SLUG}}'
2
- export const APP_TITLE = '{{APP_TITLE}}'
1
+ export const APP_SLUG = '{{APP_SLUG}}'
2
+ export const APP_TITLE = '{{APP_TITLE}}'
@@ -1,29 +1,29 @@
1
- import type { AppSettings } from '../types'
2
-
3
- export interface StarterMilestone {
4
- detail: string
5
- id: string
6
- title: string
7
- }
8
-
9
- export const starterMilestones: StarterMilestone[] = [
10
- {
11
- detail: 'The starter screen is temporary and ready to be replaced by product UI.',
12
- id: 'boot',
13
- title: 'Workspace ready',
14
- },
15
- {
16
- detail: 'PureDesktop styling is loaded so early screens match the shell.',
17
- id: 'composition',
18
- title: 'Theme active',
19
- },
20
- {
21
- detail: 'Settings and shell capabilities are available through the app bridge.',
22
- id: 'domain',
23
- title: 'Shell connected',
24
- },
25
- ]
26
-
27
- export function readConfiguredSettingCount(settings: AppSettings): number {
28
- return Object.keys(settings).length
29
- }
1
+ import type { AppSettings } from '../types'
2
+
3
+ export interface StarterMilestone {
4
+ detail: string
5
+ id: string
6
+ title: string
7
+ }
8
+
9
+ export const starterMilestones: StarterMilestone[] = [
10
+ {
11
+ detail: 'The starter screen is temporary and ready to be replaced by product UI.',
12
+ id: 'boot',
13
+ title: 'Workspace ready',
14
+ },
15
+ {
16
+ detail: 'PureDesktop styling is loaded so early screens match the shell.',
17
+ id: 'composition',
18
+ title: 'Theme active',
19
+ },
20
+ {
21
+ detail: 'Settings and shell capabilities are available through the app bridge.',
22
+ id: 'domain',
23
+ title: 'Shell connected',
24
+ },
25
+ ]
26
+
27
+ export function readConfiguredSettingCount(settings: AppSettings): number {
28
+ return Object.keys(settings).length
29
+ }
@@ -16,16 +16,16 @@ function devServerFromManifest(metaUrl) {
16
16
  }
17
17
  }
18
18
 
19
- export default defineConfig({
20
- plugins: [
21
- react({
22
- plugins: [
23
- ['@swc/plugin-styled-components', { displayName: true, fileName: true }],
24
- ],
25
- }),
26
- ],
27
- optimizeDeps: {
28
- include: ['react-dom'],
29
- },
30
- server: devServerFromManifest(import.meta.url),
31
- })
19
+ export default defineConfig({
20
+ plugins: [
21
+ react({
22
+ plugins: [
23
+ ['@swc/plugin-styled-components', { displayName: true, fileName: true }],
24
+ ],
25
+ }),
26
+ ],
27
+ optimizeDeps: {
28
+ include: ['react-dom'],
29
+ },
30
+ server: devServerFromManifest(import.meta.url),
31
+ })