reset-framework-cli 0.2.1 → 1.0.2
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/package.json +4 -4
- package/src/commands/build.js +5 -2
- package/src/commands/dev.js +5 -2
- package/src/commands/init.js +329 -18
- package/src/lib/process.js +41 -0
- package/src/lib/project.js +117 -6
- package/templates/basic/frontend/package.json +1 -1
- package/templates/basic/frontend/tsconfig.app.json +5 -1
- package/templates/basic/frontend/vite.config.ts +10 -1
- package/templates/basic/reset.config.json +26 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reset-framework-cli",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Command-line tooling for Reset Framework.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"node": ">=20.19.0"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@reset-framework/native": "0.2
|
|
15
|
-
"@reset-framework/schema": "0.2
|
|
16
|
-
"@reset-framework/sdk": "0.2
|
|
14
|
+
"@reset-framework/native": "1.0.2",
|
|
15
|
+
"@reset-framework/schema": "1.0.2",
|
|
16
|
+
"@reset-framework/sdk": "1.0.2"
|
|
17
17
|
},
|
|
18
18
|
"bin": {
|
|
19
19
|
"reset-framework-cli": "src/index.js"
|
package/src/commands/build.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { buildFrameworkRuntime } from "../lib/framework.js"
|
|
2
2
|
import { stageMacOSAppBundle } from "../lib/output.js"
|
|
3
|
-
import {
|
|
3
|
+
import { resolvePackageManagerCommand, runCommand } from "../lib/process.js"
|
|
4
4
|
import {
|
|
5
5
|
assertAppProject,
|
|
6
6
|
assertFrameworkInstall,
|
|
7
7
|
loadResetConfig,
|
|
8
8
|
resolveAppOutputPaths,
|
|
9
9
|
resolveAppPaths,
|
|
10
|
+
resolveAppPackageManager,
|
|
10
11
|
resolveConfigPath,
|
|
11
12
|
resolveFrontendDir,
|
|
12
13
|
resolveFrameworkBuildPaths,
|
|
@@ -34,6 +35,7 @@ export async function run(context) {
|
|
|
34
35
|
assertFrameworkInstall(frameworkPaths)
|
|
35
36
|
const config = loadResetConfig(appPaths)
|
|
36
37
|
assertAppProject(appPaths, config)
|
|
38
|
+
const packageManager = resolveAppPackageManager(appPaths, config)
|
|
37
39
|
const outputPaths = resolveAppOutputPaths(appPaths, config)
|
|
38
40
|
const configPath = resolveConfigPath(appPaths)
|
|
39
41
|
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
@@ -49,6 +51,7 @@ export async function run(context) {
|
|
|
49
51
|
printKeyValueTable([
|
|
50
52
|
["Config", configPath],
|
|
51
53
|
["Frontend", frontendDir],
|
|
54
|
+
["Package manager", packageManager],
|
|
52
55
|
["Output", outputPaths.appBundlePath]
|
|
53
56
|
])
|
|
54
57
|
console.log("")
|
|
@@ -82,7 +85,7 @@ export async function run(context) {
|
|
|
82
85
|
const progress = createProgress(steps.length, "Build")
|
|
83
86
|
|
|
84
87
|
if (!skipFrontend) {
|
|
85
|
-
await runCommand(
|
|
88
|
+
await runCommand(resolvePackageManagerCommand(packageManager), ["run", "build"], {
|
|
86
89
|
cwd: frontendDir,
|
|
87
90
|
dryRun
|
|
88
91
|
})
|
package/src/commands/dev.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { buildFrameworkRuntime } from "../lib/framework.js"
|
|
2
2
|
import {
|
|
3
3
|
registerChildCleanup,
|
|
4
|
-
|
|
4
|
+
resolvePackageManagerCommand,
|
|
5
5
|
spawnCommand,
|
|
6
6
|
waitForProcessExit,
|
|
7
7
|
waitForUrl
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
assertFrameworkInstall,
|
|
12
12
|
loadResetConfig,
|
|
13
13
|
resolveAppPaths,
|
|
14
|
+
resolveAppPackageManager,
|
|
14
15
|
resolveConfigPath,
|
|
15
16
|
resolveDevServerOptions,
|
|
16
17
|
resolveFrontendDir,
|
|
@@ -39,6 +40,7 @@ export async function run(context) {
|
|
|
39
40
|
assertFrameworkInstall(frameworkPaths)
|
|
40
41
|
const config = loadResetConfig(appPaths)
|
|
41
42
|
assertAppProject(appPaths, config)
|
|
43
|
+
const packageManager = resolveAppPackageManager(appPaths, config)
|
|
42
44
|
const devServer = resolveDevServerOptions(config)
|
|
43
45
|
const configPath = resolveConfigPath(appPaths)
|
|
44
46
|
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
@@ -54,6 +56,7 @@ export async function run(context) {
|
|
|
54
56
|
printKeyValueTable([
|
|
55
57
|
["Config", configPath],
|
|
56
58
|
["Frontend", frontendDir],
|
|
59
|
+
["Package manager", packageManager],
|
|
57
60
|
["Dev URL", config.frontend.devUrl]
|
|
58
61
|
])
|
|
59
62
|
console.log("")
|
|
@@ -97,7 +100,7 @@ export async function run(context) {
|
|
|
97
100
|
const children = []
|
|
98
101
|
|
|
99
102
|
if (!skipFrontend) {
|
|
100
|
-
const frontendProcess = spawnCommand(
|
|
103
|
+
const frontendProcess = spawnCommand(resolvePackageManagerCommand(packageManager), [
|
|
101
104
|
"run",
|
|
102
105
|
"dev",
|
|
103
106
|
"--",
|
package/src/commands/init.js
CHANGED
|
@@ -3,12 +3,14 @@ import { cp, mkdir, readFile, readdir, writeFile } from "node:fs/promises"
|
|
|
3
3
|
import path from "node:path"
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
captureCommandOutput,
|
|
6
7
|
getInstallCommandArgs,
|
|
7
8
|
resolvePackageManagerCommand,
|
|
8
9
|
runCommand
|
|
9
10
|
} from "../lib/process.js"
|
|
10
11
|
import {
|
|
11
12
|
makeAppMetadata,
|
|
13
|
+
resolveCliDependencySpec,
|
|
12
14
|
resolveFrameworkPaths,
|
|
13
15
|
resolveSdkDependencySpec
|
|
14
16
|
} from "../lib/project.js"
|
|
@@ -172,6 +174,84 @@ function App() {
|
|
|
172
174
|
export default App
|
|
173
175
|
`
|
|
174
176
|
|
|
177
|
+
const rootFrontendRunner = `import { readFileSync } from 'node:fs'
|
|
178
|
+
import path from 'node:path'
|
|
179
|
+
import { spawn } from 'node:child_process'
|
|
180
|
+
|
|
181
|
+
const script = process.argv[2]
|
|
182
|
+
if (!script) {
|
|
183
|
+
throw new Error('Missing frontend script name.')
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const appRoot = process.cwd()
|
|
187
|
+
const config = JSON.parse(readFileSync(path.join(appRoot, 'reset.config.json'), 'utf8'))
|
|
188
|
+
const frontendDir =
|
|
189
|
+
typeof config?.project?.frontendDir === 'string' && config.project.frontendDir.trim() !== ''
|
|
190
|
+
? path.resolve(appRoot, config.project.frontendDir)
|
|
191
|
+
: path.join(appRoot, 'frontend')
|
|
192
|
+
|
|
193
|
+
function resolvePackageManagerCommand() {
|
|
194
|
+
const packageJsonPath = path.join(appRoot, 'package.json')
|
|
195
|
+
const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
196
|
+
const packageManager = typeof manifest.packageManager === 'string' ? manifest.packageManager.trim() : ''
|
|
197
|
+
const name = packageManager.split('@')[0]
|
|
198
|
+
|
|
199
|
+
if (name === 'bun') {
|
|
200
|
+
return process.platform === 'win32' ? 'bun.exe' : 'bun'
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (name === 'pnpm') {
|
|
204
|
+
return process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (name === 'yarn') {
|
|
208
|
+
return process.platform === 'win32' ? 'yarn.cmd' : 'yarn'
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (name === 'npm') {
|
|
212
|
+
return process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const candidates = [
|
|
216
|
+
['bun.lock', process.platform === 'win32' ? 'bun.exe' : 'bun'],
|
|
217
|
+
['bun.lockb', process.platform === 'win32' ? 'bun.exe' : 'bun'],
|
|
218
|
+
['pnpm-lock.yaml', process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'],
|
|
219
|
+
['yarn.lock', process.platform === 'win32' ? 'yarn.cmd' : 'yarn'],
|
|
220
|
+
['package-lock.json', process.platform === 'win32' ? 'npm.cmd' : 'npm']
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
for (const [fileName, command] of candidates) {
|
|
224
|
+
try {
|
|
225
|
+
readFileSync(path.join(appRoot, fileName), 'utf8')
|
|
226
|
+
return command
|
|
227
|
+
} catch {}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const command = resolvePackageManagerCommand()
|
|
234
|
+
const child = spawn(command, ['run', script, '--', ...process.argv.slice(3)], {
|
|
235
|
+
cwd: frontendDir,
|
|
236
|
+
stdio: 'inherit',
|
|
237
|
+
env: process.env
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
child.once('error', (error) => {
|
|
241
|
+
console.error(error)
|
|
242
|
+
process.exit(1)
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
child.once('exit', (code, signal) => {
|
|
246
|
+
if (signal) {
|
|
247
|
+
process.kill(process.pid, signal)
|
|
248
|
+
return
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
process.exit(code ?? 1)
|
|
252
|
+
})
|
|
253
|
+
`
|
|
254
|
+
|
|
175
255
|
export const description = "Scaffold a starter app with an interactive project setup"
|
|
176
256
|
|
|
177
257
|
function listTemplates(templatesDir) {
|
|
@@ -183,15 +263,84 @@ function listTemplates(templatesDir) {
|
|
|
183
263
|
|
|
184
264
|
function getRootGitignore(frontendDir) {
|
|
185
265
|
if (frontendDir === ".") {
|
|
186
|
-
return `.
|
|
187
|
-
|
|
188
|
-
|
|
266
|
+
return `.DS_Store
|
|
267
|
+
Thumbs.db
|
|
268
|
+
.idea/
|
|
269
|
+
.vs/
|
|
270
|
+
.vscode/
|
|
271
|
+
.cache/
|
|
272
|
+
.reset/
|
|
273
|
+
.turbo/
|
|
274
|
+
build/
|
|
275
|
+
coverage/
|
|
276
|
+
dist/
|
|
277
|
+
node_modules/
|
|
278
|
+
npm-debug.log*
|
|
279
|
+
yarn-debug.log*
|
|
280
|
+
yarn-error.log*
|
|
281
|
+
.pnpm-debug.log*
|
|
282
|
+
*.log
|
|
283
|
+
*.zip
|
|
284
|
+
*.tgz
|
|
285
|
+
*.tsbuildinfo
|
|
286
|
+
*.dSYM/
|
|
287
|
+
.env
|
|
288
|
+
.env.*
|
|
289
|
+
.env.local
|
|
290
|
+
.env.*.local
|
|
291
|
+
.eslintcache
|
|
292
|
+
bun.lock
|
|
293
|
+
bun.lockb
|
|
294
|
+
compile_commands.json
|
|
295
|
+
CMakeUserPresets.json
|
|
296
|
+
CMakeCache.txt
|
|
297
|
+
CMakeFiles/
|
|
298
|
+
cmake_install.cmake
|
|
299
|
+
install_manifest.txt
|
|
300
|
+
cmake-build-*/
|
|
301
|
+
Testing/
|
|
302
|
+
scripts/local/
|
|
189
303
|
`
|
|
190
304
|
}
|
|
191
305
|
|
|
192
|
-
return `.
|
|
193
|
-
|
|
194
|
-
|
|
306
|
+
return `.DS_Store
|
|
307
|
+
Thumbs.db
|
|
308
|
+
.idea/
|
|
309
|
+
.vs/
|
|
310
|
+
.vscode/
|
|
311
|
+
.cache/
|
|
312
|
+
.reset/
|
|
313
|
+
.turbo/
|
|
314
|
+
build/
|
|
315
|
+
coverage/
|
|
316
|
+
node_modules/
|
|
317
|
+
${frontendDir}/node_modules/
|
|
318
|
+
${frontendDir}/dist/
|
|
319
|
+
npm-debug.log*
|
|
320
|
+
yarn-debug.log*
|
|
321
|
+
yarn-error.log*
|
|
322
|
+
.pnpm-debug.log*
|
|
323
|
+
*.log
|
|
324
|
+
*.zip
|
|
325
|
+
*.tgz
|
|
326
|
+
*.tsbuildinfo
|
|
327
|
+
*.dSYM/
|
|
328
|
+
.env
|
|
329
|
+
.env.*
|
|
330
|
+
.env.local
|
|
331
|
+
.env.*.local
|
|
332
|
+
.eslintcache
|
|
333
|
+
bun.lock
|
|
334
|
+
bun.lockb
|
|
335
|
+
compile_commands.json
|
|
336
|
+
CMakeUserPresets.json
|
|
337
|
+
CMakeCache.txt
|
|
338
|
+
CMakeFiles/
|
|
339
|
+
cmake_install.cmake
|
|
340
|
+
install_manifest.txt
|
|
341
|
+
cmake-build-*/
|
|
342
|
+
Testing/
|
|
343
|
+
scripts/local/
|
|
195
344
|
`
|
|
196
345
|
}
|
|
197
346
|
|
|
@@ -310,6 +459,91 @@ async function applyFrontendOverrides(frontendDir, options) {
|
|
|
310
459
|
await writeFile(path.join(frontendDir, "vite.config.ts"), standaloneViteConfig, "utf8")
|
|
311
460
|
}
|
|
312
461
|
|
|
462
|
+
function createRootPackageJson(options) {
|
|
463
|
+
const packageManagerVersion = options.packageManagerVersion
|
|
464
|
+
? `${options.packageManager}@${options.packageManagerVersion}`
|
|
465
|
+
: undefined
|
|
466
|
+
|
|
467
|
+
const base = {
|
|
468
|
+
name: options.appName,
|
|
469
|
+
private: true,
|
|
470
|
+
version: "0.1.0",
|
|
471
|
+
description: `${options.productName} desktop app`,
|
|
472
|
+
scripts: {
|
|
473
|
+
dev: "reset-framework-cli dev",
|
|
474
|
+
build: "reset-framework-cli build",
|
|
475
|
+
package: "reset-framework-cli package",
|
|
476
|
+
doctor: "reset-framework-cli doctor"
|
|
477
|
+
},
|
|
478
|
+
devDependencies: {
|
|
479
|
+
"reset-framework-cli": options.cliDependencySpec
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (packageManagerVersion) {
|
|
484
|
+
base.packageManager = packageManagerVersion
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (options.frontendDir !== ".") {
|
|
488
|
+
base.workspaces = [options.frontendDir]
|
|
489
|
+
base.scripts["dev:web"] = "node ./scripts/run-frontend.mjs dev"
|
|
490
|
+
base.scripts["build:web"] = "node ./scripts/run-frontend.mjs build"
|
|
491
|
+
base.scripts["lint:web"] = "node ./scripts/run-frontend.mjs lint"
|
|
492
|
+
base.scripts["preview:web"] = "node ./scripts/run-frontend.mjs preview"
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return base
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function createRootReadme(options) {
|
|
499
|
+
const run = `${options.packageManager} run`
|
|
500
|
+
const webPath = options.frontendDir === "." ? "project root" : `${options.frontendDir}/`
|
|
501
|
+
|
|
502
|
+
return `# ${options.productName}
|
|
503
|
+
|
|
504
|
+
Generated with \`reset-framework-cli\`.
|
|
505
|
+
|
|
506
|
+
## Commands
|
|
507
|
+
|
|
508
|
+
- \`${run} dev\`: start the frontend dev server and native desktop runtime
|
|
509
|
+
- \`${run} build\`: build the frontend and stage the desktop app bundle
|
|
510
|
+
- \`${run} package\`: archive the built desktop app
|
|
511
|
+
- \`${run} doctor\`: inspect the project and framework installation
|
|
512
|
+
|
|
513
|
+
## Web-only commands
|
|
514
|
+
|
|
515
|
+
${options.frontendDir === "." ? `- \`${run} dev:web\`: run the Vite frontend only
|
|
516
|
+
- \`${run} build:web\`: build the frontend only` : `- \`${run} dev:web\`: run the frontend workspace only
|
|
517
|
+
- \`${run} build:web\`: build the frontend workspace only`}
|
|
518
|
+
|
|
519
|
+
## Project files
|
|
520
|
+
|
|
521
|
+
- \`reset.config.json\`: desktop app metadata and runtime configuration
|
|
522
|
+
- \`${webPath}\`: web frontend source
|
|
523
|
+
- \`.reset/\`: generated build output and native runtime cache
|
|
524
|
+
`
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async function writeRootPackageFiles(options) {
|
|
528
|
+
await writeFile(
|
|
529
|
+
path.join(options.targetDir, "README.md"),
|
|
530
|
+
createRootReadme(options),
|
|
531
|
+
"utf8"
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
if (options.frontendDir !== ".") {
|
|
535
|
+
await writeFile(
|
|
536
|
+
path.join(options.targetDir, "package.json"),
|
|
537
|
+
JSON.stringify(createRootPackageJson(options), null, 2) + "\n",
|
|
538
|
+
"utf8"
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
const scriptsDir = path.join(options.targetDir, "scripts")
|
|
542
|
+
await mkdir(scriptsDir, { recursive: true })
|
|
543
|
+
await writeFile(path.join(scriptsDir, "run-frontend.mjs"), rootFrontendRunner, "utf8")
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
313
547
|
async function writeProjectFiles(options) {
|
|
314
548
|
const templateConfig = JSON.parse(await readFile(options.templateConfigPath, "utf8"))
|
|
315
549
|
|
|
@@ -343,6 +577,20 @@ async function writeProjectFiles(options) {
|
|
|
343
577
|
)
|
|
344
578
|
}
|
|
345
579
|
|
|
580
|
+
async function resolvePackageManagerVersion(packageManager) {
|
|
581
|
+
if (packageManager !== "npm" && packageManager !== "pnpm" && packageManager !== "yarn" && packageManager !== "bun") {
|
|
582
|
+
return null
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
try {
|
|
586
|
+
const command = resolvePackageManagerCommand(packageManager)
|
|
587
|
+
const result = await captureCommandOutput(command, ["--version"])
|
|
588
|
+
return typeof result === "string" && result.trim() !== "" ? result.trim() : null
|
|
589
|
+
} catch {
|
|
590
|
+
return null
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
346
594
|
async function collectCreateAppOptions(context, templates) {
|
|
347
595
|
const initialTarget = context.args[0] ?? "my-app"
|
|
348
596
|
const defaultTargetDir = path.resolve(context.cwd, initialTarget)
|
|
@@ -377,8 +625,10 @@ async function collectCreateAppOptions(context, templates) {
|
|
|
377
625
|
templateDir: path.join(frameworkPaths.templatesDir, defaults.templateName),
|
|
378
626
|
templateConfigPath: path.join(frameworkPaths.templatesDir, defaults.templateName, "reset.config.json"),
|
|
379
627
|
sourceFrontendDir: path.join(frameworkPaths.templatesDir, defaults.templateName, "frontend"),
|
|
628
|
+
cliDependencySpec: resolveCliDependencySpec(frameworkPaths),
|
|
380
629
|
sdkDependencySpec: resolveSdkDependencySpec(frameworkPaths),
|
|
381
630
|
packageManager: resolvePackageManagerOption(context),
|
|
631
|
+
packageManagerVersion: await resolvePackageManagerVersion(resolvePackageManagerOption(context)),
|
|
382
632
|
installDependencies: !context.flags["no-install"],
|
|
383
633
|
force: Boolean(context.flags.force)
|
|
384
634
|
}
|
|
@@ -464,6 +714,33 @@ async function collectCreateAppOptions(context, templates) {
|
|
|
464
714
|
defaultValue: true
|
|
465
715
|
})
|
|
466
716
|
|
|
717
|
+
const packageManager = await promptSelect(rl, {
|
|
718
|
+
label: "Package manager",
|
|
719
|
+
defaultValue: resolvePackageManagerOption(context),
|
|
720
|
+
choices: [
|
|
721
|
+
{
|
|
722
|
+
value: "npm",
|
|
723
|
+
label: "npm",
|
|
724
|
+
description: "Wide compatibility and predictable installs."
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
value: "bun",
|
|
728
|
+
label: "bun",
|
|
729
|
+
description: "Fast installs and lets bun run the root desktop scripts."
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
value: "pnpm",
|
|
733
|
+
label: "pnpm",
|
|
734
|
+
description: "Strict dependency graph with workspace support."
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
value: "yarn",
|
|
738
|
+
label: "yarn",
|
|
739
|
+
description: "Classic workspace-based JavaScript package workflow."
|
|
740
|
+
}
|
|
741
|
+
]
|
|
742
|
+
})
|
|
743
|
+
|
|
467
744
|
printSection("Summary")
|
|
468
745
|
printKeyValueTable([
|
|
469
746
|
["Directory", targetDir],
|
|
@@ -472,6 +749,7 @@ async function collectCreateAppOptions(context, templates) {
|
|
|
472
749
|
["App ID", appId],
|
|
473
750
|
["Frontend", frontendDir === "." ? "project root" : `${frontendDir}/`],
|
|
474
751
|
["Styling", styling],
|
|
752
|
+
["Package manager", packageManager],
|
|
475
753
|
["Install", installDependencies ? "yes" : "no"]
|
|
476
754
|
])
|
|
477
755
|
console.log("")
|
|
@@ -494,7 +772,7 @@ async function collectCreateAppOptions(context, templates) {
|
|
|
494
772
|
frontendDir,
|
|
495
773
|
styling,
|
|
496
774
|
installDependencies,
|
|
497
|
-
packageManager
|
|
775
|
+
packageManager
|
|
498
776
|
}
|
|
499
777
|
})
|
|
500
778
|
|
|
@@ -503,7 +781,9 @@ async function collectCreateAppOptions(context, templates) {
|
|
|
503
781
|
templateDir: path.join(frameworkPaths.templatesDir, selected.templateName),
|
|
504
782
|
templateConfigPath: path.join(frameworkPaths.templatesDir, selected.templateName, "reset.config.json"),
|
|
505
783
|
sourceFrontendDir: path.join(frameworkPaths.templatesDir, selected.templateName, "frontend"),
|
|
784
|
+
cliDependencySpec: resolveCliDependencySpec(frameworkPaths),
|
|
506
785
|
sdkDependencySpec: resolveSdkDependencySpec(frameworkPaths),
|
|
786
|
+
packageManagerVersion: await resolvePackageManagerVersion(selected.packageManager),
|
|
507
787
|
force: Boolean(context.flags.force)
|
|
508
788
|
}
|
|
509
789
|
}
|
|
@@ -542,6 +822,7 @@ export async function run(context) {
|
|
|
542
822
|
["App ID", options.appId],
|
|
543
823
|
["Frontend", options.frontendDir === "." ? "project root" : `${options.frontendDir}/`],
|
|
544
824
|
["Styling", options.styling],
|
|
825
|
+
["Package manager", options.packageManager],
|
|
545
826
|
["Install", options.installDependencies ? describeInstallCommand(options.packageManager) : "skipped"]
|
|
546
827
|
])
|
|
547
828
|
|
|
@@ -553,10 +834,16 @@ export async function run(context) {
|
|
|
553
834
|
["plan", "Write README", path.join(options.targetDir, "README.md")],
|
|
554
835
|
["plan", "Write config", path.join(options.targetDir, "reset.config.json")],
|
|
555
836
|
["plan", "Write ignore file", path.join(options.targetDir, ".gitignore")],
|
|
837
|
+
["plan", "Write app package", path.join(options.targetDir, "package.json")],
|
|
556
838
|
["plan", "Write SDK bridge", path.join(targetFrontendDir, "src", "lib", "reset.ts")],
|
|
557
839
|
["plan", "Write Vite config", path.join(targetFrontendDir, "vite.config.ts")],
|
|
558
840
|
["plan", "Write TS config", path.join(targetFrontendDir, "tsconfig.app.json")]
|
|
559
841
|
])
|
|
842
|
+
if (options.frontendDir !== ".") {
|
|
843
|
+
printStatusTable([
|
|
844
|
+
["plan", "Write frontend runner", path.join(options.targetDir, "scripts", "run-frontend.mjs")]
|
|
845
|
+
])
|
|
846
|
+
}
|
|
560
847
|
if (options.styling === "tailwindcss") {
|
|
561
848
|
printStatusTable([
|
|
562
849
|
["plan", "Patch package.json", path.join(targetFrontendDir, "package.json")],
|
|
@@ -566,14 +853,14 @@ export async function run(context) {
|
|
|
566
853
|
}
|
|
567
854
|
if (options.installDependencies) {
|
|
568
855
|
printStatusTable([
|
|
569
|
-
["plan", "Install dependencies", `${describeInstallCommand(options.packageManager)} in ${
|
|
856
|
+
["plan", "Install dependencies", `${describeInstallCommand(options.packageManager)} in ${options.targetDir}`]
|
|
570
857
|
])
|
|
571
858
|
}
|
|
572
859
|
return
|
|
573
860
|
}
|
|
574
861
|
|
|
575
862
|
console.log("")
|
|
576
|
-
const progress = createProgress(options.installDependencies ?
|
|
863
|
+
const progress = createProgress(options.installDependencies ? 6 : 5, "Scaffold")
|
|
577
864
|
|
|
578
865
|
await mkdir(options.targetDir, { recursive: true })
|
|
579
866
|
progress.tick("Prepared project directory")
|
|
@@ -581,20 +868,44 @@ export async function run(context) {
|
|
|
581
868
|
await copyFrontendTemplate(options.sourceFrontendDir, targetFrontendDir, options)
|
|
582
869
|
progress.tick("Copied frontend starter")
|
|
583
870
|
|
|
584
|
-
await cp(path.join(options.templateDir, "README.md"), path.join(options.targetDir, "README.md"), {
|
|
585
|
-
force: options.force
|
|
586
|
-
})
|
|
587
|
-
progress.tick("Wrote project README")
|
|
588
|
-
|
|
589
871
|
await writeProjectFiles(options)
|
|
590
|
-
|
|
872
|
+
await writeRootPackageFiles(options)
|
|
873
|
+
progress.tick("Wrote project files")
|
|
591
874
|
|
|
592
875
|
await applyFrontendOverrides(targetFrontendDir, options)
|
|
593
876
|
progress.tick("Applied frontend package wiring")
|
|
594
877
|
|
|
595
878
|
const packageJsonPath = path.join(targetFrontendDir, "package.json")
|
|
596
879
|
const frontendPackage = JSON.parse(await readFile(packageJsonPath, "utf8"))
|
|
597
|
-
|
|
880
|
+
|
|
881
|
+
if (options.frontendDir === ".") {
|
|
882
|
+
const currentScripts = { ...(frontendPackage.scripts ?? {}) }
|
|
883
|
+
frontendPackage.name = options.appName
|
|
884
|
+
frontendPackage.private = true
|
|
885
|
+
frontendPackage.version = "0.1.0"
|
|
886
|
+
frontendPackage.description = `${options.productName} desktop app`
|
|
887
|
+
frontendPackage.devDependencies = {
|
|
888
|
+
...frontendPackage.devDependencies,
|
|
889
|
+
"reset-framework-cli": options.cliDependencySpec
|
|
890
|
+
}
|
|
891
|
+
frontendPackage.scripts = {
|
|
892
|
+
dev: "reset-framework-cli dev",
|
|
893
|
+
"dev:web": currentScripts.dev ?? "vite",
|
|
894
|
+
build: "reset-framework-cli build",
|
|
895
|
+
"build:web": currentScripts.build ?? "tsc -b && vite build",
|
|
896
|
+
package: "reset-framework-cli package",
|
|
897
|
+
doctor: "reset-framework-cli doctor",
|
|
898
|
+
lint: currentScripts.lint ?? "eslint .",
|
|
899
|
+
preview: currentScripts.preview ?? "vite preview"
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
if (options.packageManagerVersion) {
|
|
903
|
+
frontendPackage.packageManager = `${options.packageManager}@${options.packageManagerVersion}`
|
|
904
|
+
}
|
|
905
|
+
} else {
|
|
906
|
+
frontendPackage.name = `${options.appName}-frontend`
|
|
907
|
+
}
|
|
908
|
+
|
|
598
909
|
await writeFile(packageJsonPath, JSON.stringify(frontendPackage, null, 2) + "\n", "utf8")
|
|
599
910
|
progress.tick("Finalized starter metadata")
|
|
600
911
|
|
|
@@ -603,7 +914,7 @@ export async function run(context) {
|
|
|
603
914
|
resolvePackageManagerCommand(options.packageManager),
|
|
604
915
|
getInstallCommandArgs(options.packageManager),
|
|
605
916
|
{
|
|
606
|
-
cwd:
|
|
917
|
+
cwd: options.targetDir
|
|
607
918
|
}
|
|
608
919
|
)
|
|
609
920
|
progress.tick("Installed frontend dependencies")
|
|
@@ -613,6 +924,6 @@ export async function run(context) {
|
|
|
613
924
|
printSection("Result")
|
|
614
925
|
printStatusTable([
|
|
615
926
|
["done", "Project", options.targetDir],
|
|
616
|
-
["done", "Next step", `cd ${formatTargetForShell(options.targetDir)} &&
|
|
927
|
+
["done", "Next step", `cd ${formatTargetForShell(options.targetDir)} && ${options.packageManager} run dev`]
|
|
617
928
|
])
|
|
618
929
|
}
|
package/src/lib/process.js
CHANGED
|
@@ -82,6 +82,47 @@ export async function runCommand(command, args = [], options = {}) {
|
|
|
82
82
|
})
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
export async function captureCommandOutput(command, args = [], options = {}) {
|
|
86
|
+
const { cwd, env } = options
|
|
87
|
+
|
|
88
|
+
await Promise.resolve()
|
|
89
|
+
|
|
90
|
+
return await new Promise((resolve, reject) => {
|
|
91
|
+
const child = spawn(command, args, {
|
|
92
|
+
cwd,
|
|
93
|
+
env: env ? { ...process.env, ...env } : process.env,
|
|
94
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
let stdout = ""
|
|
98
|
+
let stderr = ""
|
|
99
|
+
|
|
100
|
+
child.stdout?.on("data", (chunk) => {
|
|
101
|
+
stdout += String(chunk)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
child.stderr?.on("data", (chunk) => {
|
|
105
|
+
stderr += String(chunk)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
child.once("error", reject)
|
|
109
|
+
child.once("exit", (code, signal) => {
|
|
110
|
+
if (code === 0) {
|
|
111
|
+
resolve(stdout.trim())
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
reject(
|
|
116
|
+
new Error(
|
|
117
|
+
signal
|
|
118
|
+
? `Command terminated by signal: ${signal}`
|
|
119
|
+
: (stderr.trim() || stdout.trim() || `Command exited with code ${code}`)
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
85
126
|
export function spawnCommand(command, args = [], options = {}) {
|
|
86
127
|
const { cwd, dryRun = false, env } = options
|
|
87
128
|
|
package/src/lib/project.js
CHANGED
|
@@ -88,6 +88,10 @@ function readJsonFile(filePath) {
|
|
|
88
88
|
return JSON.parse(readFileSync(filePath, "utf8"))
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
function fileExists(filePath) {
|
|
92
|
+
return existsSync(filePath)
|
|
93
|
+
}
|
|
94
|
+
|
|
91
95
|
function isPathInside(parentDir, candidatePath) {
|
|
92
96
|
const relative = path.relative(parentDir, candidatePath)
|
|
93
97
|
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
@@ -120,21 +124,44 @@ function resolvePackageInfo(packageName, fallbackRoot) {
|
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
|
|
127
|
+
function resolveWorkspacePackageInfo(packageName, workspaceRoot, fallbackInfo) {
|
|
128
|
+
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
129
|
+
|
|
130
|
+
if (!existsSync(packageJsonPath)) {
|
|
131
|
+
return fallbackInfo
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
packageName: manifest.name ?? packageName,
|
|
138
|
+
packageRoot: workspaceRoot,
|
|
139
|
+
packageJsonPath,
|
|
140
|
+
version: manifest.version ?? fallbackInfo.version,
|
|
141
|
+
localFallback: true
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
123
145
|
export function resolveFrameworkPaths() {
|
|
124
146
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url))
|
|
125
147
|
const cliDir = path.resolve(moduleDir, "../..")
|
|
126
148
|
const packagesDir = path.resolve(cliDir, "..")
|
|
127
|
-
const
|
|
149
|
+
const cliPackageJsonPath = path.join(cliDir, "package.json")
|
|
150
|
+
const cliManifest = readJsonFile(cliPackageJsonPath)
|
|
151
|
+
const nativePackage = resolveWorkspacePackageInfo(
|
|
128
152
|
"@reset-framework/native",
|
|
129
|
-
path.join(packagesDir, "native")
|
|
153
|
+
path.join(packagesDir, "native"),
|
|
154
|
+
resolvePackageInfo("@reset-framework/native", path.join(packagesDir, "native"))
|
|
130
155
|
)
|
|
131
|
-
const sdkPackage =
|
|
156
|
+
const sdkPackage = resolveWorkspacePackageInfo(
|
|
132
157
|
"@reset-framework/sdk",
|
|
133
|
-
path.join(packagesDir, "sdk")
|
|
158
|
+
path.join(packagesDir, "sdk"),
|
|
159
|
+
resolvePackageInfo("@reset-framework/sdk", path.join(packagesDir, "sdk"))
|
|
134
160
|
)
|
|
135
|
-
const schemaPackage =
|
|
161
|
+
const schemaPackage = resolveWorkspacePackageInfo(
|
|
136
162
|
"@reset-framework/schema",
|
|
137
|
-
path.join(packagesDir, "schema")
|
|
163
|
+
path.join(packagesDir, "schema"),
|
|
164
|
+
resolvePackageInfo("@reset-framework/schema", path.join(packagesDir, "schema"))
|
|
138
165
|
)
|
|
139
166
|
const isWorkspaceLayout = [nativePackage, sdkPackage, schemaPackage].every((pkg) =>
|
|
140
167
|
isPathInside(packagesDir, pkg.packageRoot)
|
|
@@ -142,6 +169,13 @@ export function resolveFrameworkPaths() {
|
|
|
142
169
|
|
|
143
170
|
return {
|
|
144
171
|
cliDir,
|
|
172
|
+
cliPackage: {
|
|
173
|
+
packageName: cliManifest.name,
|
|
174
|
+
packageRoot: cliDir,
|
|
175
|
+
packageJsonPath: cliPackageJsonPath,
|
|
176
|
+
version: cliManifest.version ?? "0.0.0",
|
|
177
|
+
localFallback: true
|
|
178
|
+
},
|
|
145
179
|
packagesDir,
|
|
146
180
|
frameworkRoot: nativePackage.packageRoot,
|
|
147
181
|
frameworkPackage: nativePackage,
|
|
@@ -186,6 +220,7 @@ export function resolveFrameworkBuildPaths(appPaths) {
|
|
|
186
220
|
export function resolveAppPaths(appRoot) {
|
|
187
221
|
return {
|
|
188
222
|
appRoot,
|
|
223
|
+
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
189
224
|
frontendDir: path.join(appRoot, "frontend"),
|
|
190
225
|
resetConfigPath: path.join(appRoot, "reset.config.json"),
|
|
191
226
|
legacyResetConfigPath: path.join(appRoot, "frontend", "reset.config.json")
|
|
@@ -254,6 +289,7 @@ export function validateResetConfig(rawConfig) {
|
|
|
254
289
|
const frontend = optionalObject(rawConfig, "frontend")
|
|
255
290
|
const build = optionalObject(rawConfig, "build")
|
|
256
291
|
const project = optionalObject(rawConfig, "project")
|
|
292
|
+
const security = optionalObject(rawConfig, "security")
|
|
257
293
|
const windowConfig = optionalObject(rawConfig, "window")
|
|
258
294
|
|
|
259
295
|
return {
|
|
@@ -276,6 +312,17 @@ export function validateResetConfig(rawConfig) {
|
|
|
276
312
|
},
|
|
277
313
|
build: {
|
|
278
314
|
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
315
|
+
},
|
|
316
|
+
security: {
|
|
317
|
+
permissions: Array.isArray(security.permissions)
|
|
318
|
+
? security.permissions.map((value) => {
|
|
319
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
320
|
+
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return value
|
|
324
|
+
})
|
|
325
|
+
: []
|
|
279
326
|
}
|
|
280
327
|
}
|
|
281
328
|
}
|
|
@@ -355,3 +402,67 @@ export function resolveSdkDependencySpec(frameworkPaths) {
|
|
|
355
402
|
|
|
356
403
|
return `^${frameworkPaths.sdkPackage.version}`
|
|
357
404
|
}
|
|
405
|
+
|
|
406
|
+
export function resolveCliDependencySpec(frameworkPaths) {
|
|
407
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
408
|
+
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return `^${frameworkPaths.cliPackage.version}`
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
415
|
+
if (!fileExists(packageJsonPath)) {
|
|
416
|
+
return null
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
420
|
+
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
421
|
+
if (raw === "") {
|
|
422
|
+
return null
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const [name] = raw.split("@")
|
|
426
|
+
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
427
|
+
return name
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return null
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function detectPackageManagerFromLocks(directory) {
|
|
434
|
+
if (!fileExists(directory)) {
|
|
435
|
+
return null
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
439
|
+
return "bun"
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
443
|
+
return "pnpm"
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
447
|
+
return "yarn"
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
451
|
+
return "npm"
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return null
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function resolveAppPackageManager(appPaths, config) {
|
|
458
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
459
|
+
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
460
|
+
|
|
461
|
+
return (
|
|
462
|
+
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
463
|
+
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
464
|
+
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
465
|
+
detectPackageManagerFromLocks(frontendDir) ??
|
|
466
|
+
"npm"
|
|
467
|
+
)
|
|
468
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"baseUrl": ".",
|
|
4
5
|
"target": "ES2023",
|
|
5
6
|
"useDefineForClassFields": true,
|
|
6
7
|
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
@@ -18,7 +19,10 @@
|
|
|
18
19
|
"noUnusedParameters": true,
|
|
19
20
|
"erasableSyntaxOnly": true,
|
|
20
21
|
"noFallthroughCasesInSwitch": true,
|
|
21
|
-
"noUncheckedSideEffectImports": true
|
|
22
|
+
"noUncheckedSideEffectImports": true,
|
|
23
|
+
"paths": {
|
|
24
|
+
"@reset-framework/sdk": ["../../../../sdk/src/index.d.ts"]
|
|
25
|
+
}
|
|
22
26
|
},
|
|
23
27
|
"include": ["src"]
|
|
24
28
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
2
3
|
import react from '@vitejs/plugin-react'
|
|
4
|
+
import { defineConfig } from 'vite'
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
3
7
|
|
|
4
8
|
export default defineConfig({
|
|
5
9
|
plugins: [react()],
|
|
10
|
+
resolve: {
|
|
11
|
+
alias: {
|
|
12
|
+
'@reset-framework/sdk': path.resolve(__dirname, '../../../../sdk/src/index.js'),
|
|
13
|
+
},
|
|
14
|
+
},
|
|
6
15
|
})
|
|
@@ -25,5 +25,31 @@
|
|
|
25
25
|
},
|
|
26
26
|
"build": {
|
|
27
27
|
"outputDir": ".reset/build"
|
|
28
|
+
},
|
|
29
|
+
"security": {
|
|
30
|
+
"permissions": [
|
|
31
|
+
"app.*",
|
|
32
|
+
"runtime.*",
|
|
33
|
+
"window.*",
|
|
34
|
+
"dialog.*",
|
|
35
|
+
"fs.*",
|
|
36
|
+
"path.*",
|
|
37
|
+
"shell.*",
|
|
38
|
+
"clipboard.*",
|
|
39
|
+
"notification.*",
|
|
40
|
+
"screen.*",
|
|
41
|
+
"storage.*",
|
|
42
|
+
"webview.*",
|
|
43
|
+
"event.*",
|
|
44
|
+
"crypto.*",
|
|
45
|
+
"process.*",
|
|
46
|
+
"power.*",
|
|
47
|
+
"menu.*",
|
|
48
|
+
"tray.*",
|
|
49
|
+
"shortcut.*",
|
|
50
|
+
"protocol.*",
|
|
51
|
+
"updater.*",
|
|
52
|
+
"net.*"
|
|
53
|
+
]
|
|
28
54
|
}
|
|
29
55
|
}
|