@puredesktop/create-app 2.1.8 → 2.1.9
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 +85 -85
- package/package.json +1 -1
|
@@ -18,13 +18,13 @@ Options:
|
|
|
18
18
|
--name <title> Display name (default: derived from dir)
|
|
19
19
|
--slug <slug> App slug for settings/bridge (default: dir name)
|
|
20
20
|
--port <number> Dev server port in plugin.json (default: 5300)
|
|
21
|
-
--manifest-json-
|
|
22
|
-
|
|
23
|
-
--agents-md-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Examples:
|
|
27
|
-
npm create @puredesktop/app@latest my-tool
|
|
21
|
+
--manifest-json-file <path>
|
|
22
|
+
Read structured plugin.json manifest draft from a file
|
|
23
|
+
--agents-md-file <path>
|
|
24
|
+
Read structured agents.md content from a file
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
npm create @puredesktop/app@latest my-tool
|
|
28
28
|
npm create @puredesktop/app@latest my-tool -- --name "My Tool" --slug mytool --port 5310
|
|
29
29
|
`)
|
|
30
30
|
}
|
|
@@ -32,12 +32,12 @@ Examples:
|
|
|
32
32
|
function parseArgs(argv) {
|
|
33
33
|
const positional = []
|
|
34
34
|
const options = {
|
|
35
|
-
name: '',
|
|
36
|
-
slug: '',
|
|
37
|
-
port: 5300,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
35
|
+
name: '',
|
|
36
|
+
slug: '',
|
|
37
|
+
port: 5300,
|
|
38
|
+
manifestJsonFile: '',
|
|
39
|
+
agentsMdFile: '',
|
|
40
|
+
}
|
|
41
41
|
|
|
42
42
|
for (let i = 0; i < argv.length; i += 1) {
|
|
43
43
|
const arg = argv[i]
|
|
@@ -57,14 +57,14 @@ function parseArgs(argv) {
|
|
|
57
57
|
options.port = Number(argv[++i])
|
|
58
58
|
continue
|
|
59
59
|
}
|
|
60
|
-
if (arg === '--manifest-json-
|
|
61
|
-
options.
|
|
62
|
-
continue
|
|
63
|
-
}
|
|
64
|
-
if (arg === '--agents-md-
|
|
65
|
-
options.
|
|
66
|
-
continue
|
|
67
|
-
}
|
|
60
|
+
if (arg === '--manifest-json-file') {
|
|
61
|
+
options.manifestJsonFile = argv[++i] ?? ''
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
if (arg === '--agents-md-file') {
|
|
65
|
+
options.agentsMdFile = argv[++i] ?? ''
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
68
|
if (arg.startsWith('-')) {
|
|
69
69
|
console.error(`Unknown option: ${arg}`)
|
|
70
70
|
usage()
|
|
@@ -97,36 +97,27 @@ function titleCaseFromSlug(slug) {
|
|
|
97
97
|
.join(' ')
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
return normalizeStructuredManifest(manifest, port)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function normalizeStructuredManifest(manifest, port) {
|
|
126
|
-
if (!isPlainObject(manifest)) {
|
|
127
|
-
console.error('--manifest-json-base64 must decode to a manifest object')
|
|
128
|
-
process.exit(1)
|
|
129
|
-
}
|
|
100
|
+
function readStructuredManifestFile(path, port) {
|
|
101
|
+
const text = readUtf8File(path, '--manifest-json-file')
|
|
102
|
+
return readStructuredManifestText(text, port, '--manifest-json-file')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function readStructuredManifestText(text, port, label) {
|
|
106
|
+
let manifest
|
|
107
|
+
try {
|
|
108
|
+
manifest = JSON.parse(text)
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(`${label} must contain JSON: ${errorMessage(error)}`)
|
|
111
|
+
process.exit(1)
|
|
112
|
+
}
|
|
113
|
+
return normalizeStructuredManifest(manifest, port, label)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function normalizeStructuredManifest(manifest, port, label) {
|
|
117
|
+
if (!isPlainObject(manifest)) {
|
|
118
|
+
console.error(`${label} must contain a manifest object`)
|
|
119
|
+
process.exit(1)
|
|
120
|
+
}
|
|
130
121
|
if (manifest.schemaVersion !== 1) {
|
|
131
122
|
console.error('manifest.schemaVersion must be 1')
|
|
132
123
|
process.exit(1)
|
|
@@ -161,14 +152,31 @@ function normalizeStructuredManifest(manifest, port) {
|
|
|
161
152
|
})
|
|
162
153
|
}
|
|
163
154
|
|
|
164
|
-
function
|
|
165
|
-
const text =
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
155
|
+
function readStructuredAgentsMdFile(path) {
|
|
156
|
+
const text = readUtf8File(path, '--agents-md-file')
|
|
157
|
+
return readStructuredAgentsMdText(text, '--agents-md-file')
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function readStructuredAgentsMdText(text, label) {
|
|
161
|
+
if (!text.trim()) {
|
|
162
|
+
console.error(`${label} must contain non-empty agents.md content`)
|
|
163
|
+
process.exit(1)
|
|
164
|
+
}
|
|
165
|
+
return text.endsWith('\n') ? text : `${text}\n`
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function readUtf8File(path, label) {
|
|
169
|
+
if (typeof path !== 'string' || !path.trim()) {
|
|
170
|
+
console.error(`${label} requires a file path`)
|
|
171
|
+
process.exit(1)
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
return readFileSync(resolve(path), 'utf8')
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error(`${label} could not be read: ${errorMessage(error)}`)
|
|
177
|
+
process.exit(1)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
172
180
|
|
|
173
181
|
function requiredString(value, label) {
|
|
174
182
|
const text = typeof value === 'string' ? value.trim() : ''
|
|
@@ -183,15 +191,7 @@ function isPlainObject(value) {
|
|
|
183
191
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
|
184
192
|
}
|
|
185
193
|
|
|
186
|
-
function
|
|
187
|
-
if (typeof value !== 'string' || !value.trim()) return false
|
|
188
|
-
const normalized = value.trim()
|
|
189
|
-
if (!/^[A-Za-z0-9+/]+={0,2}$/u.test(normalized)) return false
|
|
190
|
-
if (normalized.length % 4 !== 0) return false
|
|
191
|
-
return Buffer.from(normalized, 'base64').toString('base64') === normalized
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function stripUndefinedProperties(value) {
|
|
194
|
+
function stripUndefinedProperties(value) {
|
|
195
195
|
return Object.fromEntries(
|
|
196
196
|
Object.entries(value).filter(([, entry]) => entry !== undefined),
|
|
197
197
|
)
|
|
@@ -321,24 +321,24 @@ function copyTemplate(srcDir, destDir, vars) {
|
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
-
const { targetDir, options } = parseArgs(process.argv.slice(2))
|
|
325
|
-
const structuredManifest = options.
|
|
326
|
-
?
|
|
327
|
-
: null
|
|
328
|
-
const structuredAgentsMd = options.
|
|
329
|
-
?
|
|
330
|
-
: null
|
|
324
|
+
const { targetDir, options } = parseArgs(process.argv.slice(2))
|
|
325
|
+
const structuredManifest = options.manifestJsonFile
|
|
326
|
+
? readStructuredManifestFile(options.manifestJsonFile, options.port)
|
|
327
|
+
: null
|
|
328
|
+
const structuredAgentsMd = options.agentsMdFile
|
|
329
|
+
? readStructuredAgentsMdFile(options.agentsMdFile)
|
|
330
|
+
: null
|
|
331
331
|
const dirName = targetDir
|
|
332
|
-
const structuredSlug = structuredManifest?.app.slug ?? ''
|
|
333
|
-
const structuredTitle = structuredManifest?.app.name ?? ''
|
|
334
|
-
if (structuredManifest && options.slug && options.slug !== structuredSlug) {
|
|
335
|
-
console.error('--slug must match manifest.app.slug when
|
|
336
|
-
process.exit(1)
|
|
337
|
-
}
|
|
338
|
-
if (structuredManifest && options.name && options.name !== structuredTitle) {
|
|
339
|
-
console.error('--name must match manifest.app.name when
|
|
340
|
-
process.exit(1)
|
|
341
|
-
}
|
|
332
|
+
const structuredSlug = structuredManifest?.app.slug ?? ''
|
|
333
|
+
const structuredTitle = structuredManifest?.app.name ?? ''
|
|
334
|
+
if (structuredManifest && options.slug && options.slug !== structuredSlug) {
|
|
335
|
+
console.error('--slug must match manifest.app.slug when a structured manifest is used')
|
|
336
|
+
process.exit(1)
|
|
337
|
+
}
|
|
338
|
+
if (structuredManifest && options.name && options.name !== structuredTitle) {
|
|
339
|
+
console.error('--name must match manifest.app.name when a structured manifest is used')
|
|
340
|
+
process.exit(1)
|
|
341
|
+
}
|
|
342
342
|
const slug = structuredSlug || options.slug || slugify(dirName) || 'my-app'
|
|
343
343
|
const title = structuredTitle || options.name || titleCaseFromSlug(slug) || 'My App'
|
|
344
344
|
const pluginId = structuredManifest?.id ?? slug
|