@solidrt/cli 0.0.18 → 0.0.19

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidrt/cli",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "license": "MIT",
5
5
  "author": "Antoine van Wel",
6
6
  "type": "module",
@@ -22,12 +22,12 @@
22
22
  "qrcode-generator": "^2.0.4"
23
23
  },
24
24
  "optionalDependencies": {
25
- "@solidrt/darwin-arm64": "0.0.18",
26
- "@solidrt/linux-x64-gnu": "0.0.18",
27
- "@solidrt/win32-x64-msvc": "0.0.18"
25
+ "@solidrt/darwin-arm64": "0.0.19",
26
+ "@solidrt/linux-x64-gnu": "0.0.19",
27
+ "@solidrt/win32-x64-msvc": "0.0.19"
28
28
  },
29
29
  "peerDependencies": {
30
- "@solidrt/core": "0.0.18",
30
+ "@solidrt/core": "0.0.19",
31
31
  "typescript": "^6"
32
32
  },
33
33
  "devDependencies": {
@@ -5,58 +5,68 @@ runtime. No DOM, no HTML, no CSS cascade. If you are an AI assistant, read this
5
5
  before writing or editing code here.
6
6
 
7
7
  Authoritative references ship inside the installed packages - read them:
8
- - node_modules/solid-js/CHEATSHEET.md - SolidJS 2.0 reactivity/control-flow model
9
- - node_modules/@solidrt/core/AGENTS.md - element/prop/reactivity model
10
- - node_modules/@solidrt/core/examples/ - single-concept usage patterns to copy (see its README.md index)
11
- - node_modules/@solidrt/cli/AGENTS.md - running, bundling, headless verify
8
+ - node_modules/solid-js/CHEATSHEET.md - SolidJS 2.0 reactivity/control-flow model
9
+ - node_modules/@solidrt/components/AGENTS.md - the component vocabulary; build UI from these
10
+ - node_modules/@solidrt/components/README.md - full prop tables for every component
11
+ - node_modules/@solidrt/core/AGENTS.md - the underlying element/prop/reactivity model
12
+ - node_modules/@solidrt/core/examples/ - single-concept usage patterns to copy (see its README.md index)
13
+ - node_modules/@solidrt/cli/AGENTS.md - running, bundling, headless verify
12
14
  - node_modules/@solidrt/core/src/types.d.ts and jsx-runtime.d.ts - source of truth
13
15
 
14
16
  <!-- Claude Code auto-imports these; other tools read the paths above. -->
15
17
  @./node_modules/solid-js/CHEATSHEET.md
18
+ @./node_modules/@solidrt/components/AGENTS.md
16
19
  @./node_modules/@solidrt/core/AGENTS.md
17
20
  @./node_modules/@solidrt/cli/AGENTS.md
18
21
 
19
22
  ## The things assistants get wrong (this is not React/DOM)
20
23
 
21
24
  1. This is SolidJS 2.0 (see CHEATSHEET.md for the reactivity/control-flow
22
- model), rendering through a custom Rust runtime instead of the DOM. Import
23
- the whole authoring surface from @solidrt/core - it re-exports the
24
- substrate so you do not have to know which package a symbol lives in:
25
- render plus the window/paint/event APIs alongside the standard reactive
26
- primitives and control-flow components.
27
- 2. Host elements are lowercase intrinsics: window, view, text, rect, oval, path,
28
- texture, audio (+ d- variants). No div/span/img/button.
29
- 3. render(() => <App/>) once, top level. The root MUST be <window> or it throws.
30
- 4. Containers (window, view) DO NOT PAINT. Background = a draw primitive child
31
- placed behind the content, e.g. <d-rect color="..." />.
32
- 5. Paint color is the color prop (a CSS color string). No fill/stroke/background
33
- prop. Outline: drawStyle="stroke" + strokeWidth.
34
- 6. No onClick/onPress. A button is a <view>/<rect> with onPointerDown.
35
- 7. d- prefix = detached from layout: a plain element is laid out by Taffy, a
36
- d-element you position with x/y (omit to fill the parent = how backgrounds
37
- work). A detached node cannot have attached (regular, Taffy-laid-out)
38
- children - everything under a d-element must itself be detached. Nesting a
39
- plain <view>/<text> inside a d-element is an error.
40
- 8. Per-frame animation: onFrame((tick, frame) => {}) is the native hook
41
- (runtime-paced, auto-cleans). requestAnimationFrame(t => {}) exists as a
42
- web-standard one-shot but is not the preferred animation driver.
43
- 9. Reactive window state: prefer the accessors windowSize(), safeArea(),
44
- displayScale(), windowFocused(), keyboardHeight() from @solidrt/core over the
45
- onResize / onLayout callbacks for reading layout and window state.
46
- 10. Device/GPU via subpath imports: @solidrt/core/camera, /microphone, /gpu.
47
- Images: createImage(src) from @solidrt/core (reactive load -> texture id);
48
- raw decodeImage + createTexture (from /gpu) are the primitives underneath.
49
- 11. tsconfig needs jsx:"preserve" + jsxImportSource:"@solidrt/core". Solid peer
50
- deps are pinned betas - do not bump them casually.
51
- 12. Use ASCII characters whenever possible in code and text - for example, no
25
+ model), rendering through a custom Rust runtime instead of the DOM. Build
26
+ UI from @solidrt/components (Window, View, Text, Image, TextInput,
27
+ ScrollView, Pressable, Button, SafeArea, theme/setTheme) - it is the
28
+ higher-level, batteries-included vocabulary and is where most app code
29
+ should live.
30
+ 2. Most components split their props into two objects: `layout={{...}}` for
31
+ anything that feeds the layout engine (flex/grid, sizing, padding/margin,
32
+ position; font fields for Text) and `style={{...}}` for paint-only
33
+ properties that never relayout (`backgroundColor`, `borderColor`,
34
+ `borderWidth`, `borderRadius`, `color`, and the transform `x`/`y`/
35
+ `rotate`/`scale`). Event handlers (`onPointerDown`, `onKeyDown`, ...) are
36
+ top-level props, not inside `layout`/`style`.
37
+ 3. `render(() => <App/>)` once, top level. The root MUST be a `<Window>`
38
+ (from @solidrt/components) or the core `<window>` - it throws otherwise.
39
+ 4. `Window`/`View` do not paint on their own; they only paint when you set
40
+ `style.backgroundColor`/`borderColor` etc - there is no separate
41
+ background element to place by hand.
42
+ 5. There is no onClick/onPress on host elements. Use `Pressable`/`Button`
43
+ from components (`onPress`), or `onPointerDown` on a `View` for anything
44
+ custom.
45
+ 6. Reactive window state: prefer the accessors windowSize(), safeArea(),
46
+ displayScale(), windowFocused(), keyboardHeight() (re-exported from
47
+ @solidrt/core) over onResize/onLayout callbacks for reading layout and
48
+ window state. SafeArea (the component) is usually the simpler fix for
49
+ avoiding notches/system UI.
50
+ 7. Per-frame animation: onFrame((tick, frame) => {}) is the native hook
51
+ (runtime-paced, auto-cleans), re-exported from @solidrt/core.
52
+ requestAnimationFrame(t => {}) exists as a web-standard one-shot but is
53
+ not the preferred animation driver.
54
+ 8. Reach for @solidrt/core directly only for what components doesn't wrap:
55
+ raw host intrinsics and the `d-` (detached, non-layout) primitives like
56
+ `d-rect`/`d-path`/`d-oval` for vector art or perf-sensitive positioned
57
+ drawing, device/GPU subpath imports (@solidrt/core/camera, /microphone,
58
+ /gpu), gradients (createLinearGradient/createRadialGradient), and
59
+ createImage/decodeImage for images below the `Image` component's level.
60
+ Components and core primitives compose freely in the same tree - a
61
+ components-based app can drop to a `<d-path>` for one custom shape without
62
+ giving up `View`/`Text` everywhere else.
63
+ 9. tsconfig needs jsx:"preserve" + jsxImportSource:"@solidrt/core" (still
64
+ true even when you build almost entirely with @solidrt/components -
65
+ components are plain functions returning core JSX). Solid peer deps are
66
+ pinned betas - do not bump them casually.
67
+ 10. Use ASCII characters whenever possible in code and text - for example, no
52
68
  em-dashes (use a hyphen), no smart/curly quotes, no unicode symbols.
53
- 13. Mind the safe area. safeArea() from @solidrt/core is a reactive accessor
54
- returning { top, left, right, bottom } insets (like CSS
55
- env(safe-area-inset-*)). It is fine to place content outside the safe-area
56
- zone (e.g. full-bleed backgrounds), just be aware it may not be visible and
57
- cannot be interacted with (touch gestures). Keep interactive or essential
58
- content inside the safe area by padding the edges.
59
- 14. Prefer let over const. Use const only for real constants - a single fixed
69
+ 11. Prefer let over const. Use const only for real constants - a single fixed
60
70
  string or number value - and name those in ALL_CAPS.
61
71
 
62
72
  ## Run / verify
@@ -65,4 +75,4 @@ Authoritative references ship inside the installed packages - read them:
65
75
  - bunx srt bundle src/index.tsx - exit 0 means it compiles
66
76
  - bunx srt record src/index.tsx --size 480x640 --duration 1 --fps 2 - headless
67
77
  render to PNG frames (proves it renders; see the cli AGENTS.md for where the
68
- frames land)
78
+ frames land)
@@ -4,10 +4,13 @@
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "srt run src/index.tsx",
7
- "bundle": "srt bundle src/index.tsx"
7
+ "server": "srt server",
8
+ "client": "srt client",
9
+ "android": "srt client --android"
8
10
  },
9
11
  "dependencies": {
10
- "@solidrt/core": "0.0.18"
12
+ "@solidrt/core": "0.0.19",
13
+ "@solidrt/components": "0.0.19"
11
14
  },
12
15
  "devDependencies": {
13
16
  "@solidrt/cli": "0.0.0",
@@ -1,25 +1,66 @@
1
- import { render } from "@solidrt/core"
1
+ import { render, For, onFrame, createSignal, createLinearGradient } from "@solidrt/core"
2
+ import { View, Window } from "@solidrt/components"
3
+
4
+ const FADE = 360
5
+
6
+ let SEGMENTS = [
7
+ { base: 0, light: "#3f5494", dark: "#162b6c", d: "M50.000 50.000 L28.330 50.000 C28.330 48.810 27.695 47.711 26.665 47.116 C25.635 46.521 24.365 46.521 23.335 47.116 C22.305 47.711 21.670 48.810 21.670 50.000 L0.000 50.000 L50.000 0.000 L50.000 9.170 C48.810 9.170 47.711 9.805 47.116 10.835 C46.521 11.865 46.521 13.135 47.116 14.165 C47.711 15.195 48.810 15.830 50.000 15.830 L50.000 25.000 L50.000 34.170 C48.810 34.170 47.711 34.805 47.116 35.835 C46.521 36.865 46.521 38.135 47.116 39.165 C47.711 40.195 48.810 40.830 50.000 40.830 L50.000 50.000 Z" },
8
+ { base: 90, light: "#547ebf", dark: "#2b5696", d: "M50.000 50.000 L50.000 59.170 C48.810 59.170 47.711 59.805 47.116 60.835 C46.521 61.865 46.521 63.135 47.116 64.165 C47.711 65.195 48.810 65.830 50.000 65.830 L50.000 75.000 L50.000 84.170 C48.810 84.170 47.711 84.805 47.116 85.835 C46.521 86.865 46.521 88.135 47.116 89.165 C47.711 90.195 48.810 90.830 50.000 90.830 L50.000 100.000 L0.000 50.000 L21.670 50.000 C21.670 48.810 22.305 47.711 23.335 47.116 C24.365 46.521 25.635 46.521 26.665 47.116 C27.695 47.711 28.330 48.810 28.330 50.000 L50.000 50.000 Z" },
9
+ { base: 180, light: "#7ea9ea", dark: "#5681c1", d: "M50.000 25.000 L50.000 15.830 C48.810 15.830 47.711 15.195 47.116 14.165 C46.521 13.135 46.521 11.865 47.116 10.835 C47.711 9.805 48.810 9.170 50.000 9.170 L50.000 0.000 L75.000 25.000 L65.830 25.000 C65.830 26.190 65.195 27.289 64.165 27.884 C63.135 28.479 61.865 28.479 60.835 27.884 C59.805 27.289 59.170 26.190 59.170 25.000 L50.000 25.000 Z" },
10
+ { base: 270, light: "#547ebf", dark: "#2b5696", d: "M50.000 25.000 L59.170 25.000 C59.170 26.190 59.805 27.289 60.835 27.884 C61.865 28.479 63.135 28.479 64.165 27.884 C65.195 27.289 65.830 26.190 65.830 25.000 L75.000 25.000 L75.000 34.170 C73.810 34.170 72.711 34.805 72.116 35.835 C71.521 36.865 71.521 38.135 72.116 39.165 C72.711 40.195 73.810 40.830 75.000 40.830 L75.000 50.000 L65.830 50.000 C65.830 48.810 65.195 47.711 64.165 47.116 C63.135 46.521 61.865 46.521 60.835 47.116 C59.805 47.711 59.170 48.810 59.170 50.000 L50.000 50.000 L50.000 40.830 C48.810 40.830 47.711 40.195 47.116 39.165 C46.521 38.135 46.521 36.865 47.116 35.835 C47.711 34.805 48.810 34.170 50.000 34.170 L50.000 25.000 Z" },
11
+ { base: 360, light: "#7ea9ea", dark: "#5681c1", d: "M50.000 50.000 L59.170 50.000 C59.170 48.810 59.805 47.711 60.835 47.116 C61.865 46.521 63.135 46.521 64.165 47.116 C65.195 47.711 65.830 48.810 65.830 50.000 L75.000 50.000 L64.855 60.145 C64.013 59.304 62.787 58.976 61.638 59.283 C60.489 59.591 59.591 60.489 59.283 61.638 C58.976 62.787 59.304 64.013 60.145 64.855 L50.000 75.000 L50.000 65.830 C48.810 65.830 47.711 65.195 47.116 64.165 C46.521 63.135 46.521 61.865 47.116 60.835 C47.711 59.805 48.810 59.170 50.000 59.170 L50.000 50.000 Z" },
12
+ { base: 450, light: "#3f5494", dark: "#162b6c", d: "M75.000 50.000 L75.000 59.170 C73.810 59.170 72.711 59.805 72.116 60.835 C71.521 61.865 71.521 63.135 72.116 64.165 C72.711 65.195 73.810 65.830 75.000 65.830 L75.000 75.000 L50.000 100.000 L50.000 90.830 C48.810 90.830 47.711 90.195 47.116 89.165 C46.521 88.135 46.521 86.865 47.116 85.835 C47.711 84.805 48.810 84.170 50.000 84.170 L50.000 75.000 L60.145 64.855 C59.304 64.013 58.976 62.787 59.283 61.638 C59.591 60.489 60.489 59.591 61.638 59.283 C62.787 58.976 64.013 59.304 64.855 60.145 L75.000 50.000 Z" },
13
+ { base: 540, light: "#7ea9ea", dark: "#5681c1", d: "M100.000 50.000 L75.000 75.000 L75.000 65.830 C73.810 65.830 72.711 65.195 72.116 64.165 C71.521 63.135 71.521 61.865 72.116 60.835 C72.711 59.805 73.810 59.170 75.000 59.170 L75.000 50.000 L75.000 40.830 C73.810 40.830 72.711 40.195 72.116 39.165 C71.521 38.135 71.521 36.865 72.116 35.835 C72.711 34.805 73.810 34.170 75.000 34.170 L75.000 25.000 L100.000 50.000 Z" },
14
+ ]
15
+
16
+ let LAST = SEGMENTS[SEGMENTS.length - 1].base
17
+ let IN_DONE = LAST + FADE
18
+ let CYCLE = IN_DONE + LAST + FADE
19
+
20
+ let clamp = (x: number) => (x < 0 ? 0 : x > 1 ? 1 : x)
21
+ let ease = (t: number) => 1 - (1 - t) * (1 - t)
22
+ let byte = (x: number) => Math.round(Math.max(0, Math.min(255, x))).toString(16).padStart(2, "0")
23
+
24
+ let fill = (seg: (typeof SEGMENTS)[number], a: number) =>
25
+ createLinearGradient(0, 0, 1, 1, [
26
+ { offset: 0, color: seg.light + byte(a * 255) },
27
+ { offset: 1, color: seg.dark + byte(a * 255) },
28
+ ])
2
29
 
3
30
  function Icon() {
31
+ let [clock, setClock] = createSignal(0)
32
+ let start = -1
33
+ onFrame((t) => (start < 0 && (start = t), setClock((t - start) % CYCLE)))
4
34
  return (
5
- <view width={100} height={100} scale={3}>
6
- <d-path d="M50 50L0 50L50 0Z" color="#1a3380" />
7
- <d-path d="M50 50L50 100L0 50Z" color="#3366b3" />
8
- <d-path d="M50 25L50 0L75 25Z" color="#6699e6" />
9
- <d-path d="M50 25L75 25L75 50L50 50Z" color="#3366b3" />
10
- <d-path d="M50 50L75 50L50 75Z" color="#6699e6" />
11
- <d-path d="M75 50L75 75L50 100L50 75Z" color="#1a3380" />
12
- <d-path d="M100 50L75 75L75 25Z" color="#6699e6" />
13
- </view>
35
+ <View layout={{ width: 100, height: 100 }} style={{ scale: 3 }}>
36
+ <For each={SEGMENTS}>
37
+ {(seg) => {
38
+ let a = () => {
39
+ let t = clock(), end = IN_DONE + seg.base + FADE
40
+ if (t < seg.base || t >= end) return 0
41
+ return ease(Math.min(clamp((t - seg.base) / FADE), clamp((end - t) / FADE)))
42
+ }
43
+ return <d-path d={seg.d} color={fill(seg, a())} />
44
+ }}
45
+ </For>
46
+ </View>
14
47
  )
15
48
  }
16
49
 
17
50
  function App() {
51
+ let backgroundColor = createLinearGradient(0, 0, 1, 1, [
52
+ { offset: 0, color: "#080b16" },
53
+ { offset: 1, color: "#1d2a52" },
54
+ ])
55
+
18
56
  return (
19
- <window alignItems="center" justifyContent="center">
57
+ <Window
58
+ layout={{ alignItems: "center", justifyContent: "center" }}
59
+ style={{ backgroundColor }}
60
+ >
20
61
  <Icon />
21
- </window>
62
+ </Window>
22
63
  )
23
64
  }
24
65
 
25
- render(() => <App />)
66
+ render(() => <App />)
@@ -33,12 +33,12 @@ export async function runInitCommand() {
33
33
  process.exit(1)
34
34
  }
35
35
 
36
- console.log(`>> scaffolding SolidRT project in ${resolve(dir)}`)
36
+ console.log(`>> Scaffolding SolidRT project in ${resolve(dir)}`)
37
37
  for (let { from, to } of TEMPLATE_FILES) {
38
38
  let dest = join(dir, to)
39
39
  await mkdir(dirname(dest), { recursive: true })
40
40
  await writeFile(dest, await readFile(join(SCAFFOLD_DIR, from)))
41
- console.log(` write ${to}`)
41
+ console.log(` Write ${to}`)
42
42
  }
43
43
 
44
44
  // The scaffold package.json carries a placeholder name; set it from the
@@ -50,18 +50,18 @@ export async function runInitCommand() {
50
50
 
51
51
  // Deps are declared in scaffold/package.json (Solid peers resolve via
52
52
  // @solidrt/core's peerDependencies), so a plain install is enough.
53
- console.log("\n>> installing dependencies")
53
+ console.log("\n>> Installing dependencies")
54
54
  let install = Bun.spawnSync(["bun", "install"], {
55
55
  cwd: dir,
56
56
  stdout: "inherit",
57
57
  stderr: "inherit",
58
58
  })
59
59
  if (install.exitCode !== 0) {
60
- console.error("\n!! dependency install failed; retry with `bun install` in the project")
60
+ console.error("\n!! Dependency install failed; retry with `bun install` in the project")
61
61
  process.exit(1)
62
62
  }
63
63
 
64
64
  let prefix = dir === "." ? "" : `cd ${dir} && `
65
- console.log(`\n>> done. next:\n ${prefix}bunx srt run src/index.tsx\n`)
65
+ console.log(`\n>> Done. Next:\n ${prefix}bun run dev\n`)
66
66
  process.exit()
67
67
  }
@@ -65,11 +65,43 @@ function listDevices(adb: string): string[] {
65
65
  .filter((s): s is string => Boolean(s))
66
66
  }
67
67
 
68
- // Resolve the target device serial. With --device, treat the value as a serial
69
- // prefix and require it to match exactly one connected device; without it, use
70
- // the sole connected device. Exits with a clear message on any ambiguity.
71
- function resolveTarget(adb: string): string {
68
+ // Primary ABI of the connected device (e.g. "arm64-v8a", "armeabi-v7a"), used
69
+ // to pick the matching APK -- a fat (multi-ABI) APK reports its 64-bit ABI
70
+ // here and still installs fine, so this only matters for single-ABI builds.
71
+ function deviceAbi(adb: string, target: string): string {
72
+ let res = Bun.spawnSync([adb, "-s", target, "shell", "getprop", "ro.product.cpu.abi"], {
73
+ stdout: "pipe",
74
+ stderr: "pipe",
75
+ })
76
+ return res.stdout.toString().trim()
77
+ }
78
+
79
+ // Always shown up front, regardless of how many devices are connected or
80
+ // whether --device narrows it down: one line per device with the ABI its APK
81
+ // build would target, then a dev-dependency hint for each ABI that isn't
82
+ // resolvable locally yet. Returns the device->abi map so callers don't have
83
+ // to re-query it.
84
+ function printDeviceStatus(adb: string, devices: string[]): Map<string, string> {
85
+ let abiByDevice = new Map<string, string>()
86
+ let missingAbis = new Set<string>()
87
+ for (let d of devices) {
88
+ let abi = deviceAbi(adb, d)
89
+ abiByDevice.set(d, abi)
90
+ print(`${d} - ${abi}`)
91
+ if (!resolveApk(abi)) missingAbis.add(abi)
92
+ }
93
+ let missingPkgs = [...missingAbis].map((abi) => ANDROID_PKG_MAP[abi]).filter((pkg): pkg is string => Boolean(pkg))
94
+ if (missingPkgs.length > 0) print(`Add dev dependencies with: bun add -d ${missingPkgs.join(" ")}`)
95
+ return abiByDevice
96
+ }
97
+
98
+ // Resolve the target device serial (and its ABI). With --device, treat the
99
+ // value as a serial prefix and require it to match exactly one connected
100
+ // device; without it, use the sole connected device. Exits with a clear
101
+ // message on any ambiguity.
102
+ function resolveTarget(adb: string): { target: string; abi: string } {
72
103
  let devices = listDevices(adb)
104
+ let abiByDevice = printDeviceStatus(adb, devices)
73
105
 
74
106
  if (values.device) {
75
107
  let prefix = values.device
@@ -80,14 +112,14 @@ function resolveTarget(adb: string): string {
80
112
  }
81
113
  let [match] = matches
82
114
  if (!match) {
83
- console.error(`No connected device matches --device "${prefix}". Connected: ${devices.join(", ") || "none"}`)
115
+ console.error(`No connected device matches --device "${prefix}".`)
84
116
  process.exit(1)
85
117
  }
86
- return match
118
+ return { target: match, abi: abiByDevice.get(match)! }
87
119
  }
88
120
 
89
121
  if (devices.length > 1) {
90
- console.error(`Multiple devices connected (${devices.join(", ")}); pick one with --device <serial or prefix>.`)
122
+ console.error("Pick one with --device <serial or prefix>.")
91
123
  process.exit(1)
92
124
  }
93
125
  let [only] = devices
@@ -95,18 +127,7 @@ function resolveTarget(adb: string): string {
95
127
  console.error("No authorized Android device found. Enable USB debugging and check `adb devices`.")
96
128
  process.exit(1)
97
129
  }
98
- return only
99
- }
100
-
101
- // Primary ABI of the connected device (e.g. "arm64-v8a", "armeabi-v7a"), used
102
- // to pick the matching APK -- a fat (multi-ABI) APK reports its 64-bit ABI
103
- // here and still installs fine, so this only matters for single-ABI builds.
104
- function deviceAbi(adb: string, target: string): string {
105
- let res = Bun.spawnSync([adb, "-s", target, "shell", "getprop", "ro.product.cpu.abi"], {
106
- stdout: "pipe",
107
- stderr: "pipe",
108
- })
109
- return res.stdout.toString().trim()
130
+ return { target: only, abi: abiByDevice.get(only)! }
110
131
  }
111
132
 
112
133
  // Install + launch the Android client on a connected device over adb, passing it
@@ -116,16 +137,13 @@ function deviceAbi(adb: string, target: string): string {
116
137
  export async function spawnAndroidClient() {
117
138
  let adb = requireAdb()
118
139
 
119
- let target = resolveTarget(adb)
120
- let abi = deviceAbi(adb, target)
140
+ let { target, abi } = resolveTarget(adb)
121
141
 
122
142
  let apk = resolveApk(abi)
123
143
  if (!apk) {
124
144
  console.error(`Could not find a SolidRT-Go APK for ABI "${abi}".`)
125
145
  let pkg = ANDROID_PKG_MAP[abi]
126
146
  if (pkg) console.error(`Add it with: bun add -d ${pkg}`)
127
- let target = abi === "armeabi-v7a" ? "make dist-android-armeabi-v7a" : "make dist-android"
128
- console.error(`Or build one locally (from lattice/): ${target}`)
129
147
  process.exit(1)
130
148
  }
131
149