@geastack/cli 0.1.3 → 0.1.4

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/README.md CHANGED
@@ -9,16 +9,17 @@ keeping target-specific build logic behind stable backend contracts.
9
9
  ## Commands
10
10
 
11
11
  ```sh
12
- npx @geastack/create-geastack my-panel
12
+ npm install --global @geastack/cli
13
+ gea create my-panel
13
14
  cd my-panel
14
- npx gea doctor
15
- npx gea setup
16
- npx gea dev
17
- npx gea build --target web
18
- npx gea build --target ios
19
- npx gea flash --board amoled --monitor
20
- npx gea monitor --board amoled
21
- npx gea inspect --json
15
+ gea doctor
16
+ gea setup
17
+ gea dev
18
+ gea build --target web
19
+ gea build --target ios
20
+ gea flash --board amoled --monitor
21
+ gea monitor --board amoled
22
+ gea inspect --json
22
23
  ```
23
24
 
24
25
  ## Interactive Menu Map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geastack/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Command-line front door for GeaStack apps, targets, and local toolchains.",
6
6
  "publishConfig": {
@@ -38,13 +38,19 @@ export async function runCreateGeastack(argv, io = {}) {
38
38
  const ctx = createContext(parsed, env, cwd)
39
39
  const displayName = option(parsed, 'name', titleFromId(appId))
40
40
  const coreDependency = option(parsed, 'core-dependency') || '^0.1.4'
41
- const cliDependency = option(parsed, 'cli-dependency') || '^0.1.3'
41
+ const cliDependency = option(parsed, 'cli-dependency') || '^0.1.4'
42
42
  const starter = await resolveStarter(ctx, parsed, io)
43
+ const entry = projectRelativePath(option(parsed, 'entry') || starter.starter?.entry || starter.example?.entry || 'index.tsx', 'entry')
44
+ if (option(parsed, 'entry') && starter.kind !== 'empty') {
45
+ fail('--entry can only be used with --starter empty.', ExitCode.usage)
46
+ }
43
47
 
44
48
  fs.mkdirSync(targetDir, { recursive: true })
45
49
  if (starter.kind === 'empty') {
46
- fs.writeFileSync(path.join(targetDir, 'index.tsx'), indexTsx(displayName))
47
- fs.writeFileSync(path.join(targetDir, 'styles.css'), stylesCss())
50
+ const entryPath = path.join(targetDir, entry)
51
+ fs.mkdirSync(path.dirname(entryPath), { recursive: true })
52
+ fs.writeFileSync(entryPath, indexTsx(displayName))
53
+ fs.writeFileSync(path.join(path.dirname(entryPath), 'styles.css'), stylesCss())
48
54
  } else if (starter.kind === 'bundled') {
49
55
  copyStarterFiles(starter.starter.root, targetDir)
50
56
  } else if (starter.kind === 'example') {
@@ -69,12 +75,14 @@ export async function runCreateGeastack(argv, io = {}) {
69
75
  appId,
70
76
  displayName,
71
77
  targets,
78
+ entry,
79
+ bleOta: flag(parsed, 'ble-ota'),
72
80
  coreDependency,
73
81
  cliDependency,
74
82
  sourcePackage,
75
83
  sourceManifest
76
84
  }))
77
- ensureFile(path.join(targetDir, 'index.html'), () => indexHtml(displayName))
85
+ ensureFile(path.join(targetDir, 'index.html'), () => indexHtml(displayName, entry))
78
86
  fs.mkdirSync(path.join(targetDir, '.gea'), { recursive: true })
79
87
  writeJson(path.join(targetDir, '.gea', 'boards.json'), {})
80
88
  ensureJson(path.join(targetDir, 'tsconfig.json'), tsconfigJson)
@@ -203,14 +211,15 @@ function targetManifestFromObject(targets = {}) {
203
211
  }
204
212
  }
205
213
 
206
- function packageJson({ appId, displayName, targets, coreDependency, cliDependency, sourcePackage = {}, sourceManifest = {} }) {
214
+ function packageJson({ appId, displayName, targets, entry, bleOta, coreDependency, cliDependency, sourcePackage = {}, sourceManifest = {} }) {
207
215
  const geaManifest = {
208
216
  ...sourceManifest,
209
217
  id: appId,
210
218
  name: displayName,
211
- entry: sourceManifest.entry || 'index.tsx',
219
+ entry,
212
220
  targets
213
221
  }
222
+ if (bleOta) geaManifest.ota = { ...(geaManifest.ota || {}), ble: true }
214
223
  if (!geaManifest.runtime || geaManifest.runtime === 'gea') delete geaManifest.runtime
215
224
 
216
225
  return {
@@ -299,7 +308,7 @@ h1 {
299
308
  `
300
309
  }
301
310
 
302
- function indexHtml(displayName) {
311
+ function indexHtml(displayName, entry = 'index.tsx') {
303
312
  return `<!doctype html>
304
313
  <html lang="en">
305
314
  <head>
@@ -309,7 +318,7 @@ function indexHtml(displayName) {
309
318
  </head>
310
319
  <body>
311
320
  <div id="app"></div>
312
- <script type="module" src="/index.tsx"></script>
321
+ <script type="module" src="/${entry}"></script>
313
322
  </body>
314
323
  </html>
315
324
  `
@@ -398,6 +407,14 @@ function normalizeStarter(value) {
398
407
  return normalized
399
408
  }
400
409
 
410
+ function projectRelativePath(value, label) {
411
+ const normalized = path.posix.normalize(String(value || '').replaceAll('\\', '/')).replace(/^\.\//, '')
412
+ if (!normalized || normalized === '.' || normalized === '..' || normalized.startsWith('../') || path.posix.isAbsolute(normalized)) {
413
+ fail(`--${label} must be a path inside the project.`, ExitCode.usage)
414
+ }
415
+ return normalized
416
+ }
417
+
401
418
  function readPackageJson(targetDir) {
402
419
  const packagePath = path.join(targetDir, 'package.json')
403
420
  if (!exists(packagePath)) return {}
@@ -422,6 +439,8 @@ Options:
422
439
  --examples-repo <git-url-or-local-path>
423
440
  --examples-ref <git-ref>
424
441
  --targets web,esp32,rp2350,geaos,macos,ios,android
442
+ --entry <relative-path>
443
+ --ble-ota
425
444
  --core-dependency <specifier>
426
445
  --cli-dependency <specifier>
427
446
  --install / --no-install
package/src/gea.mjs CHANGED
@@ -1,6 +1,8 @@
1
1
  import path from 'node:path'
2
+ import fs from 'node:fs'
2
3
 
3
4
  import { flag, option, parseArgs } from './args.mjs'
5
+ import { runCreateGeastack } from './create-geastack.mjs'
4
6
  import { createChildEnv, createContext } from './context.mjs'
5
7
  import { ExitCode, fail } from './errors.mjs'
6
8
  import { exists, readJson } from './fs-utils.mjs'
@@ -18,7 +20,7 @@ import { runExternal } from './run.mjs'
18
20
  import { runSetupWizard } from './setup-wizard.mjs'
19
21
  import { commandVersion, nodeAtLeast } from './toolchain.mjs'
20
22
 
21
- const version = '0.1.1'
23
+ const version = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version
22
24
 
23
25
  export async function runGea(argv, io = {}) {
24
26
  const parsed = parseArgs(argv)
@@ -35,6 +37,11 @@ export async function runGea(argv, io = {}) {
35
37
  stdout(version)
36
38
  return 0
37
39
  }
40
+ if (command === 'create') {
41
+ const createArgs = argv.slice(1)
42
+ if (option(parsed, 'install') === undefined) createArgs.push('--install')
43
+ return runCreateGeastack(createArgs, io)
44
+ }
38
45
  if (!command || command === 'help' || flag(parsed, 'help')) {
39
46
  stdout(usage())
40
47
  return 0
@@ -422,6 +429,7 @@ function requirePath(filePath, label) {
422
429
 
423
430
  function usage() {
424
431
  return `Usage:
432
+ gea create <name> [--starter counter|empty|example] [--targets <list>]
425
433
  gea doctor [--strict] [--json]
426
434
  gea setup --board <alias>
427
435
  gea dev [app] [--target web] [--port 5181]