@geastack/cli 0.1.3 → 0.1.5
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 +11 -10
- package/docs/ESP32-WAVESHARE-AMOLED-QUICKSTART.md +11 -10
- package/docs/SPEC.md +1 -1
- package/package.json +1 -1
- package/src/create-geastack.mjs +29 -8
- package/src/gea.mjs +9 -1
package/README.md
CHANGED
|
@@ -9,23 +9,24 @@ keeping target-specific build logic behind stable backend contracts.
|
|
|
9
9
|
## Commands
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
|
|
12
|
+
npm install --global @geastack/cli
|
|
13
|
+
gea create my-panel
|
|
13
14
|
cd my-panel
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
25
26
|
|
|
26
27
|
```mermaid
|
|
27
28
|
flowchart TD
|
|
28
|
-
create["
|
|
29
|
+
create["gea create my-app"] --> identity["Resolve app identity<br/>argument, optional --id, optional --name"]
|
|
29
30
|
identity --> starter{"Starter app?"}
|
|
30
31
|
|
|
31
32
|
starter -->|"Counter starter"| counter["Copy bundled minimal JSX counter"]
|
|
@@ -30,7 +30,8 @@ You do not clone GeaStack.
|
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
32
|
npm login
|
|
33
|
-
|
|
33
|
+
npm install --global @geastack/cli
|
|
34
|
+
gea create my-app
|
|
34
35
|
cd my-app
|
|
35
36
|
```
|
|
36
37
|
|
|
@@ -45,12 +46,12 @@ When the wizard asks what to create, choose:
|
|
|
45
46
|
|
|
46
47
|
For the fastest first flash, choose `Counter starter`.
|
|
47
48
|
|
|
48
|
-
That creates a tiny JSX app
|
|
49
|
+
That creates a tiny JSX app and installs all of its project dependencies.
|
|
49
50
|
|
|
50
51
|
## 3. Set Up The Board
|
|
51
52
|
|
|
52
53
|
```sh
|
|
53
|
-
|
|
54
|
+
gea setup
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
Choose:
|
|
@@ -82,7 +83,7 @@ If ESP-IDF was installed, the CLI prints this for future shells:
|
|
|
82
83
|
. "$HOME/esp/esp-idf/export.sh"
|
|
83
84
|
```
|
|
84
85
|
|
|
85
|
-
You do not need to run that before every command unless `
|
|
86
|
+
You do not need to run that before every command unless `gea doctor` says ESP-IDF is not active.
|
|
86
87
|
|
|
87
88
|
If the wizard finds a connected serial device, pick it. If no board is plugged in yet, that is fine; you can provide the port later.
|
|
88
89
|
|
|
@@ -93,13 +94,13 @@ The wizard writes the board config into your app at `.gea/boards.json` and initi
|
|
|
93
94
|
Flash and open the serial monitor:
|
|
94
95
|
|
|
95
96
|
```sh
|
|
96
|
-
|
|
97
|
+
gea flash --board amoled --monitor
|
|
97
98
|
```
|
|
98
99
|
|
|
99
100
|
If you need to specify the serial port manually:
|
|
100
101
|
|
|
101
102
|
```sh
|
|
102
|
-
|
|
103
|
+
gea flash --board amoled --port /dev/cu.usbmodemXXXX --monitor
|
|
103
104
|
```
|
|
104
105
|
|
|
105
106
|
## Rich Examples
|
|
@@ -109,10 +110,10 @@ The bundled starter is intentionally tiny. Rich examples live in the GeaStack ex
|
|
|
109
110
|
For example:
|
|
110
111
|
|
|
111
112
|
```sh
|
|
112
|
-
|
|
113
|
+
gea create watch-demo --starter example --example watch
|
|
113
114
|
cd watch-demo
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
gea setup
|
|
116
|
+
gea flash --board amoled --monitor
|
|
116
117
|
```
|
|
117
118
|
|
|
118
119
|
The CLI owns the example catalog, so the user does not need to clone the examples repo.
|
|
@@ -122,7 +123,7 @@ The CLI owns the example catalog, so the user does not need to clone the example
|
|
|
122
123
|
Run:
|
|
123
124
|
|
|
124
125
|
```sh
|
|
125
|
-
|
|
126
|
+
gea doctor
|
|
126
127
|
```
|
|
127
128
|
|
|
128
129
|
Most first-run issues are one of:
|
package/docs/SPEC.md
CHANGED
package/package.json
CHANGED
package/src/create-geastack.mjs
CHANGED
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
formatStarterChoice
|
|
16
16
|
} from './starter-catalog.mjs'
|
|
17
17
|
|
|
18
|
+
const cliVersion = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version
|
|
19
|
+
|
|
18
20
|
export async function runCreateGeastack(argv, io = {}) {
|
|
19
21
|
const parsed = parseArgs(argv)
|
|
20
22
|
const stdout = io.stdout || console.log
|
|
@@ -38,13 +40,19 @@ export async function runCreateGeastack(argv, io = {}) {
|
|
|
38
40
|
const ctx = createContext(parsed, env, cwd)
|
|
39
41
|
const displayName = option(parsed, 'name', titleFromId(appId))
|
|
40
42
|
const coreDependency = option(parsed, 'core-dependency') || '^0.1.4'
|
|
41
|
-
const cliDependency = option(parsed, 'cli-dependency') ||
|
|
43
|
+
const cliDependency = option(parsed, 'cli-dependency') || `^${cliVersion}`
|
|
42
44
|
const starter = await resolveStarter(ctx, parsed, io)
|
|
45
|
+
const entry = projectRelativePath(option(parsed, 'entry') || starter.starter?.entry || starter.example?.entry || 'index.tsx', 'entry')
|
|
46
|
+
if (option(parsed, 'entry') && starter.kind !== 'empty') {
|
|
47
|
+
fail('--entry can only be used with --starter empty.', ExitCode.usage)
|
|
48
|
+
}
|
|
43
49
|
|
|
44
50
|
fs.mkdirSync(targetDir, { recursive: true })
|
|
45
51
|
if (starter.kind === 'empty') {
|
|
46
|
-
|
|
47
|
-
fs.
|
|
52
|
+
const entryPath = path.join(targetDir, entry)
|
|
53
|
+
fs.mkdirSync(path.dirname(entryPath), { recursive: true })
|
|
54
|
+
fs.writeFileSync(entryPath, indexTsx(displayName))
|
|
55
|
+
fs.writeFileSync(path.join(path.dirname(entryPath), 'styles.css'), stylesCss())
|
|
48
56
|
} else if (starter.kind === 'bundled') {
|
|
49
57
|
copyStarterFiles(starter.starter.root, targetDir)
|
|
50
58
|
} else if (starter.kind === 'example') {
|
|
@@ -69,12 +77,14 @@ export async function runCreateGeastack(argv, io = {}) {
|
|
|
69
77
|
appId,
|
|
70
78
|
displayName,
|
|
71
79
|
targets,
|
|
80
|
+
entry,
|
|
81
|
+
bleOta: flag(parsed, 'ble-ota'),
|
|
72
82
|
coreDependency,
|
|
73
83
|
cliDependency,
|
|
74
84
|
sourcePackage,
|
|
75
85
|
sourceManifest
|
|
76
86
|
}))
|
|
77
|
-
ensureFile(path.join(targetDir, 'index.html'), () => indexHtml(displayName))
|
|
87
|
+
ensureFile(path.join(targetDir, 'index.html'), () => indexHtml(displayName, entry))
|
|
78
88
|
fs.mkdirSync(path.join(targetDir, '.gea'), { recursive: true })
|
|
79
89
|
writeJson(path.join(targetDir, '.gea', 'boards.json'), {})
|
|
80
90
|
ensureJson(path.join(targetDir, 'tsconfig.json'), tsconfigJson)
|
|
@@ -203,14 +213,15 @@ function targetManifestFromObject(targets = {}) {
|
|
|
203
213
|
}
|
|
204
214
|
}
|
|
205
215
|
|
|
206
|
-
function packageJson({ appId, displayName, targets, coreDependency, cliDependency, sourcePackage = {}, sourceManifest = {} }) {
|
|
216
|
+
function packageJson({ appId, displayName, targets, entry, bleOta, coreDependency, cliDependency, sourcePackage = {}, sourceManifest = {} }) {
|
|
207
217
|
const geaManifest = {
|
|
208
218
|
...sourceManifest,
|
|
209
219
|
id: appId,
|
|
210
220
|
name: displayName,
|
|
211
|
-
entry
|
|
221
|
+
entry,
|
|
212
222
|
targets
|
|
213
223
|
}
|
|
224
|
+
if (bleOta) geaManifest.ota = { ...(geaManifest.ota || {}), ble: true }
|
|
214
225
|
if (!geaManifest.runtime || geaManifest.runtime === 'gea') delete geaManifest.runtime
|
|
215
226
|
|
|
216
227
|
return {
|
|
@@ -299,7 +310,7 @@ h1 {
|
|
|
299
310
|
`
|
|
300
311
|
}
|
|
301
312
|
|
|
302
|
-
function indexHtml(displayName) {
|
|
313
|
+
function indexHtml(displayName, entry = 'index.tsx') {
|
|
303
314
|
return `<!doctype html>
|
|
304
315
|
<html lang="en">
|
|
305
316
|
<head>
|
|
@@ -309,7 +320,7 @@ function indexHtml(displayName) {
|
|
|
309
320
|
</head>
|
|
310
321
|
<body>
|
|
311
322
|
<div id="app"></div>
|
|
312
|
-
<script type="module" src="
|
|
323
|
+
<script type="module" src="/${entry}"></script>
|
|
313
324
|
</body>
|
|
314
325
|
</html>
|
|
315
326
|
`
|
|
@@ -398,6 +409,14 @@ function normalizeStarter(value) {
|
|
|
398
409
|
return normalized
|
|
399
410
|
}
|
|
400
411
|
|
|
412
|
+
function projectRelativePath(value, label) {
|
|
413
|
+
const normalized = path.posix.normalize(String(value || '').replaceAll('\\', '/')).replace(/^\.\//, '')
|
|
414
|
+
if (!normalized || normalized === '.' || normalized === '..' || normalized.startsWith('../') || path.posix.isAbsolute(normalized)) {
|
|
415
|
+
fail(`--${label} must be a path inside the project.`, ExitCode.usage)
|
|
416
|
+
}
|
|
417
|
+
return normalized
|
|
418
|
+
}
|
|
419
|
+
|
|
401
420
|
function readPackageJson(targetDir) {
|
|
402
421
|
const packagePath = path.join(targetDir, 'package.json')
|
|
403
422
|
if (!exists(packagePath)) return {}
|
|
@@ -422,6 +441,8 @@ Options:
|
|
|
422
441
|
--examples-repo <git-url-or-local-path>
|
|
423
442
|
--examples-ref <git-ref>
|
|
424
443
|
--targets web,esp32,rp2350,geaos,macos,ios,android
|
|
444
|
+
--entry <relative-path>
|
|
445
|
+
--ble-ota
|
|
425
446
|
--core-dependency <specifier>
|
|
426
447
|
--cli-dependency <specifier>
|
|
427
448
|
--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 = '
|
|
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]
|