@solidrt/cli 0.0.53 → 0.0.55
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/AGENTS.md +3 -1
- package/agents/debugging.md +31 -8
- package/dist/console.srtapp +3881 -3525
- package/dist/demos/3d/the-third-dimension/the-third-dimension.srt.js +540 -397
- package/dist/demos/components/gallery/gallery.srt.js +922 -646
- package/dist/server.js +23 -25
- package/package.json +7 -7
- package/src/android/docs.md +5 -2
- package/src/android/main.ts +135 -86
- package/src/client/docs.md +3 -1
- package/src/client/main.ts +6 -9
- package/src/init/main.ts +1 -1
- package/src/init/scaffold/AGENTS.md +4 -2
- package/src/init/scaffold/package.json +6 -6
- package/src/mcp/main.ts +13 -7
- package/src/server/control.ts +9 -2
- package/src/server/docs.md +2 -0
- package/src/server/main.ts +6 -12
- package/src/types/control.d.ts +5 -0
- /package/src/{init → lib}/prompt.ts +0 -0
package/dist/server.js
CHANGED
|
@@ -705,7 +705,7 @@ ${stderr.trim()}`;
|
|
|
705
705
|
return null;
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
-
// ../../node_modules/.bun/@jridgewell+sourcemap-codec@1.
|
|
708
|
+
// ../../node_modules/.bun/@jridgewell+sourcemap-codec@1.6.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
|
|
709
709
|
var comma = 44;
|
|
710
710
|
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
711
711
|
var intToChar = new Uint8Array(64);
|
|
@@ -715,7 +715,7 @@ for (let i = 0;i < chars.length; i++) {
|
|
|
715
715
|
intToChar[i] = c;
|
|
716
716
|
charToInt[c] = i;
|
|
717
717
|
}
|
|
718
|
-
function decodeInteger(reader
|
|
718
|
+
function decodeInteger(reader) {
|
|
719
719
|
let value = 0;
|
|
720
720
|
let shift = 0;
|
|
721
721
|
let integer2 = 0;
|
|
@@ -725,12 +725,10 @@ function decodeInteger(reader, relative) {
|
|
|
725
725
|
value |= (integer2 & 31) << shift;
|
|
726
726
|
shift += 5;
|
|
727
727
|
} while (integer2 & 32);
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
}
|
|
733
|
-
return relative + value;
|
|
728
|
+
return value;
|
|
729
|
+
}
|
|
730
|
+
function decodeSign(num) {
|
|
731
|
+
return num & 1 ? -2147483648 | -(num >>> 1) : num >>> 1;
|
|
734
732
|
}
|
|
735
733
|
function hasMoreVlq(reader, max) {
|
|
736
734
|
if (reader.pos >= max)
|
|
@@ -772,16 +770,16 @@ function decode(mappings) {
|
|
|
772
770
|
genColumn = 0;
|
|
773
771
|
while (reader.pos < semi) {
|
|
774
772
|
let seg;
|
|
775
|
-
genColumn
|
|
773
|
+
genColumn += decodeSign(decodeInteger(reader));
|
|
776
774
|
if (genColumn < lastCol)
|
|
777
775
|
sorted = false;
|
|
778
776
|
lastCol = genColumn;
|
|
779
777
|
if (hasMoreVlq(reader, semi)) {
|
|
780
|
-
sourcesIndex
|
|
781
|
-
sourceLine
|
|
782
|
-
sourceColumn
|
|
778
|
+
sourcesIndex += decodeSign(decodeInteger(reader));
|
|
779
|
+
sourceLine += decodeSign(decodeInteger(reader));
|
|
780
|
+
sourceColumn += decodeSign(decodeInteger(reader));
|
|
783
781
|
if (hasMoreVlq(reader, semi)) {
|
|
784
|
-
namesIndex
|
|
782
|
+
namesIndex += decodeSign(decodeInteger(reader));
|
|
785
783
|
seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];
|
|
786
784
|
} else {
|
|
787
785
|
seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];
|
|
@@ -1083,6 +1081,7 @@ function clientList(withAddress = false) {
|
|
|
1083
1081
|
os: info.os,
|
|
1084
1082
|
kernel: info.kernel,
|
|
1085
1083
|
videoDriver: info.videoDriver,
|
|
1084
|
+
refreshRate: info.refreshRate,
|
|
1086
1085
|
gpu: info.gpu,
|
|
1087
1086
|
...withAddress ? { address: ws.remoteAddr ?? null } : {}
|
|
1088
1087
|
}));
|
|
@@ -1335,8 +1334,14 @@ async function handleControl(req, path, query) {
|
|
|
1335
1334
|
return handleQuery(query, "snapshot", extra);
|
|
1336
1335
|
}
|
|
1337
1336
|
case "/__control__/gpu": {
|
|
1337
|
+
let extra = {};
|
|
1338
1338
|
let label = query.get("label");
|
|
1339
|
-
|
|
1339
|
+
if (label !== undefined)
|
|
1340
|
+
extra.label = label;
|
|
1341
|
+
let draw = parseInt(query.get("draw") ?? "", 10);
|
|
1342
|
+
if (Number.isFinite(draw))
|
|
1343
|
+
extra.draw = draw;
|
|
1344
|
+
return handleQuery(query, "gpu", extra);
|
|
1340
1345
|
}
|
|
1341
1346
|
case "/__control__/debug": {
|
|
1342
1347
|
if (req.method !== "POST")
|
|
@@ -3765,6 +3770,7 @@ function onOpen(ws) {
|
|
|
3765
3770
|
os: null,
|
|
3766
3771
|
kernel: null,
|
|
3767
3772
|
videoDriver: null,
|
|
3773
|
+
refreshRate: null,
|
|
3768
3774
|
gpu: null
|
|
3769
3775
|
});
|
|
3770
3776
|
console.log(`[cli] Client connected ${ws.remoteAddr ?? "unknown"}`);
|
|
@@ -3777,8 +3783,6 @@ function onClose(ws) {
|
|
|
3777
3783
|
let info = state.clients.get(ws);
|
|
3778
3784
|
state.clients.delete(ws);
|
|
3779
3785
|
console.log(`[cli] Client disconnected: ${info?.platform ?? "unknown"}`);
|
|
3780
|
-
if (config.client && localClientExited && state.clients.size === 0)
|
|
3781
|
-
shutdown();
|
|
3782
3786
|
}
|
|
3783
3787
|
function onMessage(ws, msg) {
|
|
3784
3788
|
try {
|
|
@@ -3801,6 +3805,7 @@ function onMessage(ws, msg) {
|
|
|
3801
3805
|
os: text(data.os),
|
|
3802
3806
|
kernel: text(data.kernel),
|
|
3803
3807
|
videoDriver: text(data.videoDriver),
|
|
3808
|
+
refreshRate: typeof data.refreshRate === "number" ? data.refreshRate : null,
|
|
3804
3809
|
gpu: data.gpu && typeof data.gpu === "object" ? { vendor: text(data.gpu.vendor) ?? "", renderer: text(data.gpu.renderer) ?? "", version: text(data.gpu.version) ?? "" } : null
|
|
3805
3810
|
});
|
|
3806
3811
|
console.log(`[cli] Client info ${ws.remoteAddr ?? "unknown"} ${data.platform} (${data.version})`);
|
|
@@ -3870,7 +3875,6 @@ var keepalive = setInterval(() => {
|
|
|
3870
3875
|
var shuttingDown = false;
|
|
3871
3876
|
var stopRepl = () => {};
|
|
3872
3877
|
var localClient = null;
|
|
3873
|
-
var localClientExited = false;
|
|
3874
3878
|
var signalOffs = ["SIGINT", "SIGTERM"].map((signal) => onSignal(signal, () => {
|
|
3875
3879
|
shutdown();
|
|
3876
3880
|
}));
|
|
@@ -3924,13 +3928,7 @@ if (config.client) {
|
|
|
3924
3928
|
pump(child.stderr, (line) => console.error(line));
|
|
3925
3929
|
child.status().then(() => {
|
|
3926
3930
|
localClient = null;
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
return;
|
|
3930
|
-
if (state.clients.size === 0) {
|
|
3931
|
-
shutdown();
|
|
3932
|
-
} else {
|
|
3933
|
-
console.log(`[cli] Local client exited, ${state.clients.size} remote client(s) still connected`);
|
|
3934
|
-
}
|
|
3931
|
+
if (!shuttingDown)
|
|
3932
|
+
console.log("[cli] Local client exited; the server keeps running (srt client reattaches)");
|
|
3935
3933
|
});
|
|
3936
3934
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidrt/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.55",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"funding": "https://github.com/sponsors/wellawaretech",
|
|
6
6
|
"author": "Antoine van Wel",
|
|
@@ -24,22 +24,22 @@
|
|
|
24
24
|
"@jridgewell/remapping": "^2.3.0",
|
|
25
25
|
"@jridgewell/trace-mapping": "^0.3.25",
|
|
26
26
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
27
|
-
"@solidjs/babel-plugin": "2.0.0-rc.
|
|
27
|
+
"@solidjs/babel-plugin": "2.0.0-rc.4",
|
|
28
28
|
"bonjour-service": "^1.4.0",
|
|
29
29
|
"qrcode-generator": "^2.0.4",
|
|
30
30
|
"zod": "^4.4.3"
|
|
31
31
|
},
|
|
32
32
|
"optionalDependencies": {
|
|
33
|
-
"@solidrt/darwin-arm64": "0.0.
|
|
34
|
-
"@solidrt/linux-arm64-gnu": "0.0.
|
|
35
|
-
"@solidrt/linux-x64-gnu": "0.0.
|
|
36
|
-
"@solidrt/win32-x64-msvc": "0.0.
|
|
33
|
+
"@solidrt/darwin-arm64": "0.0.55",
|
|
34
|
+
"@solidrt/linux-arm64-gnu": "0.0.55",
|
|
35
|
+
"@solidrt/linux-x64-gnu": "0.0.55",
|
|
36
|
+
"@solidrt/win32-x64-msvc": "0.0.55"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"typescript": "^7"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@solidrt/flux-types": "0.0.
|
|
42
|
+
"@solidrt/flux-types": "0.0.55",
|
|
43
43
|
"@types/babel__core": "^7.20.5",
|
|
44
44
|
"@types/bun": "latest"
|
|
45
45
|
}
|
package/src/android/docs.md
CHANGED
|
@@ -8,8 +8,11 @@ file) in the current directory, or `--port`. A running instance is restarted
|
|
|
8
8
|
so it picks the server up. The command then waits a few seconds for the
|
|
9
9
|
client to appear on the server and reports its client id. The server must
|
|
10
10
|
run with `--lan` so the device can reach it; an emulator reaches a loopback
|
|
11
|
-
server through its host alias.
|
|
12
|
-
|
|
11
|
+
server through its host alias. Without a running server the client starts
|
|
12
|
+
on its own, into the launcher (`--port` must name a live server). With several
|
|
13
|
+
devices connected a terminal asks which ones (all preselected, so enter
|
|
14
|
+
launches on every device); `--device` picks one by serial or unique prefix
|
|
15
|
+
(a script must).
|
|
13
16
|
|
|
14
17
|
`--install` installs (or updates) the client first, from the
|
|
15
18
|
`@solidrt/android-<abi>` dev dependency matching the device's ABI; the
|
package/src/android/main.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { networkInterfaces } from "node:os"
|
|
|
3
3
|
import { resolve } from "node:path"
|
|
4
4
|
import { androidPackageVersion, resolveApk, ANDROID_PKG_MAP } from "../lib/artifacts"
|
|
5
5
|
import { values, port } from "../lib/args"
|
|
6
|
+
import { CLI_VERSION } from "../lib/project"
|
|
7
|
+
import { multiselect } from "../lib/prompt"
|
|
6
8
|
import { resolveByPort, resolveFromCwd } from "../lib/registry"
|
|
7
9
|
import type { LiveRecord } from "../types/registry"
|
|
8
10
|
|
|
@@ -97,14 +99,19 @@ function devServerAddress(adb: string, target: string, server: LiveRecord): stri
|
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
// The dev server the device should dial: --port picks a local server by
|
|
100
|
-
// port, otherwise the project (or file) in the current
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
// port (and must exist), otherwise the project (or file) in the current
|
|
103
|
+
// directory, or none: the client then starts on its own, into the launcher.
|
|
104
|
+
async function resolveServer(): Promise<LiveRecord | null> {
|
|
105
|
+
if (port !== undefined) {
|
|
106
|
+
let resolved = await resolveByPort(port)
|
|
107
|
+
if (!resolved.ok) {
|
|
108
|
+
console.error(resolved.message)
|
|
109
|
+
process.exit(1)
|
|
110
|
+
}
|
|
111
|
+
return resolved.record
|
|
106
112
|
}
|
|
107
|
-
|
|
113
|
+
let resolved = await resolveFromCwd(process.cwd())
|
|
114
|
+
return resolved.ok ? resolved.record : null
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
// Serials of connected, authorized devices (excludes offline/unauthorized).
|
|
@@ -132,25 +139,39 @@ function deviceAbi(adb: string, target: string): string {
|
|
|
132
139
|
return res.stdout.toString().trim()
|
|
133
140
|
}
|
|
134
141
|
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
// One line per connected device with the ABI its APK build would target;
|
|
143
|
+
// the picker shows the same lines, so this is for the cases without one.
|
|
144
|
+
function printDeviceStatus(devices: string[], abiByDevice: Map<string, string>) {
|
|
145
|
+
for (let d of devices) console.log(`${d} - ${abiByDevice.get(d)}`)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// A published CLI version (x.y.z): the release action publishes the CLI and
|
|
149
|
+
// the android packages at one version, so that is the one to pin. A checkout
|
|
150
|
+
// reports a git describe (or the 0.0.0 placeholder), which npm does not have.
|
|
151
|
+
let RELEASE_VERSION = /^\d+\.\d+\.\d+$/
|
|
152
|
+
|
|
153
|
+
// The APK for `abi`, adding the project's @solidrt/android-<abi> dev
|
|
154
|
+
// dependency in the cwd first when it is not installed. ABIs without a
|
|
155
|
+
// published package (e.g. x86) only resolve through SRT_HOME.
|
|
156
|
+
function ensureApk(abi: string): string {
|
|
157
|
+
let apk = resolveApk(abi)
|
|
158
|
+
if (apk) return apk
|
|
159
|
+
let pkg = ANDROID_PKG_MAP[abi]
|
|
160
|
+
if (!pkg) {
|
|
161
|
+
console.error(`Could not find a SolidRT-Go APK for ABI "${abi}".`)
|
|
162
|
+
process.exit(1)
|
|
148
163
|
}
|
|
149
|
-
let
|
|
150
|
-
|
|
151
|
-
|
|
164
|
+
let spec = RELEASE_VERSION.test(CLI_VERSION) && CLI_VERSION !== "0.0.0" ? `${pkg}@${CLI_VERSION}` : pkg
|
|
165
|
+
console.log(`[cli] Adding dev dependency ${spec}`)
|
|
166
|
+
let add = Bun.spawnSync(["bun", "add", "-d", spec], { cwd: process.cwd(), stdout: "inherit", stderr: "inherit" })
|
|
167
|
+
if (add.exitCode !== 0) {
|
|
168
|
+
console.error(`Could not add ${spec}; retry with bun add -d ${spec}`)
|
|
169
|
+
process.exit(1)
|
|
152
170
|
}
|
|
153
|
-
|
|
171
|
+
apk = resolveApk(abi)
|
|
172
|
+
if (apk) return apk
|
|
173
|
+
console.error(`${pkg} is installed but carries no solidrt-go.apk for ABI "${abi}".`)
|
|
174
|
+
process.exit(1)
|
|
154
175
|
}
|
|
155
176
|
|
|
156
177
|
// The versionName of the client installed on `target`, null when none is.
|
|
@@ -171,25 +192,31 @@ async function connectedClients(server: LiveRecord): Promise<Client[]> {
|
|
|
171
192
|
}
|
|
172
193
|
}
|
|
173
194
|
|
|
174
|
-
// The
|
|
175
|
-
|
|
176
|
-
|
|
195
|
+
// The Android clients that appear beyond `before`: all of them once `count`
|
|
196
|
+
// have, else whatever showed up within ~10 s.
|
|
197
|
+
async function waitForClients(server: LiveRecord, before: Set<number>, count: number): Promise<Client[]> {
|
|
198
|
+
let fresh: Client[] = []
|
|
199
|
+
for (let attempt = 0; attempt < 20 && fresh.length < count; attempt++) {
|
|
177
200
|
await sleep(500)
|
|
178
|
-
|
|
179
|
-
if (fresh) return fresh
|
|
201
|
+
fresh = (await connectedClients(server)).filter((c) => c.platform === "android" && !before.has(c.id))
|
|
180
202
|
}
|
|
181
|
-
return
|
|
203
|
+
return fresh
|
|
182
204
|
}
|
|
183
205
|
|
|
184
|
-
|
|
206
|
+
type Device = { target: string; abi: string }
|
|
207
|
+
|
|
208
|
+
// Resolve the target devices (serial and ABI). With --device, treat the
|
|
185
209
|
// value as a serial prefix and require it to match exactly one connected
|
|
186
|
-
// device; without it, use the sole connected device
|
|
187
|
-
//
|
|
188
|
-
|
|
210
|
+
// device; without it, use the sole connected device, or pick any number of
|
|
211
|
+
// several on a terminal (all preselected: enter means every device). Exits
|
|
212
|
+
// with a clear message on any ambiguity.
|
|
213
|
+
async function resolveTargets(adb: string): Promise<Device[]> {
|
|
189
214
|
let devices = listDevices(adb)
|
|
190
|
-
let abiByDevice =
|
|
215
|
+
let abiByDevice = new Map(devices.map((d) => [d, deviceAbi(adb, d)]))
|
|
216
|
+
let device = (target: string): Device => ({ target, abi: abiByDevice.get(target)! })
|
|
191
217
|
|
|
192
218
|
if (values.device) {
|
|
219
|
+
printDeviceStatus(devices, abiByDevice)
|
|
193
220
|
let prefix = values.device
|
|
194
221
|
let matches = devices.filter((d) => d.startsWith(prefix))
|
|
195
222
|
if (matches.length > 1) {
|
|
@@ -201,86 +228,108 @@ function resolveTarget(adb: string): { target: string; abi: string } {
|
|
|
201
228
|
console.error(`No connected device matches --device "${prefix}".`)
|
|
202
229
|
process.exit(1)
|
|
203
230
|
}
|
|
204
|
-
return
|
|
231
|
+
return [device(match)]
|
|
205
232
|
}
|
|
206
233
|
|
|
207
234
|
if (devices.length > 1) {
|
|
208
|
-
|
|
209
|
-
|
|
235
|
+
// The prompt's non-TTY default is no way to pick devices, so a script has
|
|
236
|
+
// to say which.
|
|
237
|
+
if (!process.stdin.isTTY) {
|
|
238
|
+
printDeviceStatus(devices, abiByDevice)
|
|
239
|
+
console.error("Pick one with --device <serial or prefix>.")
|
|
240
|
+
process.exit(1)
|
|
241
|
+
}
|
|
242
|
+
let picked = await multiselect(
|
|
243
|
+
"Pick devices",
|
|
244
|
+
devices.map((d) => ({ label: `${d} - ${abiByDevice.get(d)}`, value: d, checked: true })),
|
|
245
|
+
)
|
|
246
|
+
if (picked.length === 0) {
|
|
247
|
+
console.error("No device picked.")
|
|
248
|
+
process.exit(1)
|
|
249
|
+
}
|
|
250
|
+
return picked.map(device)
|
|
210
251
|
}
|
|
252
|
+
printDeviceStatus(devices, abiByDevice)
|
|
211
253
|
let [only] = devices
|
|
212
254
|
if (!only) {
|
|
213
255
|
console.error("No authorized Android device found. Enable USB debugging and check `adb devices`.")
|
|
214
256
|
process.exit(1)
|
|
215
257
|
}
|
|
216
|
-
return
|
|
258
|
+
return [device(only)]
|
|
217
259
|
}
|
|
218
260
|
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
// up on the dev server. The client is not a child process here: its lifecycle
|
|
223
|
-
// is the WS connect/disconnect the server sees.
|
|
224
|
-
export async function main() {
|
|
225
|
-
let server = await resolveServer()
|
|
226
|
-
let adb = requireAdb()
|
|
227
|
-
|
|
228
|
-
let { target, abi } = resolveTarget(adb)
|
|
229
|
-
|
|
261
|
+
// Install the client on `target` (on --install), else check that one is there
|
|
262
|
+
// and note when its version is not the one the project's package carries.
|
|
263
|
+
async function prepare(adb: string, { target, abi }: Device) {
|
|
230
264
|
if (values.install) {
|
|
231
|
-
let apk =
|
|
232
|
-
if (!apk) {
|
|
233
|
-
console.error(`Could not find a SolidRT-Go APK for ABI "${abi}".`)
|
|
234
|
-
let pkg = ANDROID_PKG_MAP[abi]
|
|
235
|
-
if (pkg) console.error(`Add it with: bun add -d ${pkg}`)
|
|
236
|
-
process.exit(1)
|
|
237
|
-
}
|
|
265
|
+
let apk = ensureApk(abi)
|
|
238
266
|
console.log(`[cli] Installing SolidRT-Go on ${target}`)
|
|
239
267
|
let install = Bun.spawn([adb, "-s", target, "install", "-r", apk], { stdout: "pipe", stderr: "pipe" })
|
|
240
268
|
if ((await install.exited) !== 0) {
|
|
241
269
|
console.error("adb install failed:\n" + (await new Response(install.stderr).text()))
|
|
242
270
|
process.exit(1)
|
|
243
271
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
let expected = androidPackageVersion(abi)
|
|
251
|
-
if (expected !== null && expected !== installed) {
|
|
252
|
-
console.log(
|
|
253
|
-
`[cli] Installed client is ${installed}; the project's ${ANDROID_PKG_MAP[abi]} is ${expected} (srt android --install updates it)`,
|
|
254
|
-
)
|
|
255
|
-
}
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
let installed = installedVersion(adb, target)
|
|
275
|
+
if (installed === null) {
|
|
276
|
+
console.error(`No SolidRT-Go client on ${target}; install one with srt android --install`)
|
|
277
|
+
process.exit(1)
|
|
256
278
|
}
|
|
279
|
+
let expected = androidPackageVersion(abi)
|
|
280
|
+
if (expected !== null && expected !== installed) {
|
|
281
|
+
console.log(
|
|
282
|
+
`[cli] Installed client is ${installed}; the project's ${ANDROID_PKG_MAP[abi]} is ${expected} (srt android --install updates it)`,
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
257
286
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
287
|
+
// Launch the client on `target`, handing it the dev-server address to dial as
|
|
288
|
+
// a launch-intent extra that MainActivity forwards to native argv
|
|
289
|
+
// (--dev-server); the client auto-connects to it. Replaces adb reverse, which
|
|
290
|
+
// never worked over wireless adb. -S stops a running instance first: a
|
|
291
|
+
// delivered intent does not reach one, so without it the client would keep
|
|
292
|
+
// whatever server it had. With no server there is no extra to pass.
|
|
293
|
+
async function launch(adb: string, { target }: Device, server: LiveRecord | null) {
|
|
294
|
+
let devServer = server ? devServerAddress(adb, target, server) : null
|
|
265
295
|
let launchArgs = [adb, "-s", target, "shell", "am", "start", "-S", "-n", PACKAGE_ACTIVITY]
|
|
266
296
|
if (devServer) {
|
|
267
|
-
console.log(`[cli] Client will dial dev server at ${devServer}`)
|
|
297
|
+
console.log(`[cli] Client on ${target} will dial dev server at ${devServer}`)
|
|
268
298
|
launchArgs.push("--es", "srt_dev_server", devServer)
|
|
269
|
-
} else {
|
|
270
|
-
console.log(
|
|
299
|
+
} else if (server) {
|
|
300
|
+
console.log(`[cli] Could not resolve a host address for ${target}; client will need a manual/QR connect`)
|
|
271
301
|
}
|
|
272
|
-
|
|
273
302
|
let start = Bun.spawn(launchArgs, { stdout: "pipe", stderr: "pipe" })
|
|
274
303
|
if ((await start.exited) !== 0) {
|
|
275
304
|
console.error("adb start failed:\n" + (await new Response(start.stderr).text()))
|
|
276
305
|
process.exit(1)
|
|
277
306
|
}
|
|
307
|
+
console.log(`[cli] Launched SolidRT-Go on ${target}`)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Launch the Android client on the connected devices over adb (installing it
|
|
311
|
+
// first on --install), then wait briefly for them to show up on the dev
|
|
312
|
+
// server. The clients are not child processes here: their lifecycle is the
|
|
313
|
+
// WS connect/disconnect the server sees.
|
|
314
|
+
export async function main() {
|
|
315
|
+
let server = await resolveServer()
|
|
316
|
+
let adb = requireAdb()
|
|
317
|
+
|
|
318
|
+
let devices = await resolveTargets(adb)
|
|
319
|
+
for (let device of devices) await prepare(adb, device)
|
|
320
|
+
|
|
321
|
+
let before = new Set(server ? (await connectedClients(server)).map((c) => c.id) : [])
|
|
322
|
+
for (let device of devices) await launch(adb, device, server)
|
|
323
|
+
if (!server) return
|
|
278
324
|
|
|
279
|
-
console.log(
|
|
280
|
-
let
|
|
281
|
-
|
|
325
|
+
console.log("[cli] Waiting for the client(s) to connect to the dev server...")
|
|
326
|
+
let clients = await waitForClients(server, before, devices.length)
|
|
327
|
+
for (let client of clients) {
|
|
282
328
|
console.log(`[cli] Client ${client.id} connected (${client.platform}, ${client.version})`)
|
|
283
|
-
} else {
|
|
284
|
-
console.log(`[cli] No connection after 10 s. The server must run with --lan and the device must reach this machine.`)
|
|
285
329
|
}
|
|
286
|
-
|
|
330
|
+
if (clients.length < devices.length) {
|
|
331
|
+
console.log(
|
|
332
|
+
`[cli] ${devices.length - clients.length} of ${devices.length} not connected after 10 s. The server must run with --lan and the device must reach this machine.`,
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
}
|
package/src/client/docs.md
CHANGED
|
@@ -6,4 +6,6 @@ The client half of [srt run](../server/docs.md), on its own. Without flags
|
|
|
6
6
|
it attaches to the dev server of the project (or file) in the current
|
|
7
7
|
directory; `--port` picks a local server by port and `--server` names any
|
|
8
8
|
address, which is how a second machine joins a server started with `--lan`.
|
|
9
|
-
|
|
9
|
+
Without a running server the client starts on its own, into the launcher
|
|
10
|
+
(`--port` and `--server` must name a live server). A phone or tablet is
|
|
11
|
+
[srt android](../android/docs.md).
|
package/src/client/main.ts
CHANGED
|
@@ -4,13 +4,14 @@ import { resolveFromCwd } from "../lib/registry"
|
|
|
4
4
|
|
|
5
5
|
// Standalone solidrt-go client (no dev server of its own). Without flags it
|
|
6
6
|
// attaches to the dev server of the project (or file) in the current
|
|
7
|
-
// directory, resolved from the registry
|
|
8
|
-
//
|
|
7
|
+
// directory, resolved from the registry, and starts on its own (into the
|
|
8
|
+
// launcher) when there is none; --port picks a local server by port and
|
|
9
|
+
// --server names any address, and those must exist. A device is `srt android`.
|
|
9
10
|
export async function main() {
|
|
10
11
|
let runner = requireBinary("solidrt-go")
|
|
11
12
|
let args: string[] = [...clientStorageArgs()]
|
|
12
13
|
if (values.size) args.push("--size", values.size)
|
|
13
|
-
let address: string
|
|
14
|
+
let address: string | null
|
|
14
15
|
if (values.server) {
|
|
15
16
|
if (!values.server.includes(":")) {
|
|
16
17
|
console.error(`--server needs host:port (got "${values.server}"); dev servers have no fixed port`)
|
|
@@ -21,13 +22,9 @@ export async function main() {
|
|
|
21
22
|
address = `127.0.0.1:${port}`
|
|
22
23
|
} else {
|
|
23
24
|
let resolved = await resolveFromCwd(process.cwd())
|
|
24
|
-
|
|
25
|
-
console.error(resolved.message)
|
|
26
|
-
process.exit(1)
|
|
27
|
-
}
|
|
28
|
-
address = `127.0.0.1:${resolved.record.port}`
|
|
25
|
+
address = resolved.ok ? `127.0.0.1:${resolved.record.port}` : null
|
|
29
26
|
}
|
|
30
|
-
args.push("--dev-server", address)
|
|
27
|
+
if (address) args.push("--dev-server", address)
|
|
31
28
|
let exit = await run(runner, args)
|
|
32
29
|
process.exit(exit)
|
|
33
30
|
}
|
package/src/init/main.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cp, mkdir, readFile, readdir, writeFile } from "node:fs/promises"
|
|
2
2
|
import { basename, dirname, join, resolve } from "node:path"
|
|
3
3
|
import { source, values } from "../lib/args"
|
|
4
|
-
import { multiselect, note, text } from "
|
|
4
|
+
import { multiselect, note, text } from "../lib/prompt"
|
|
5
5
|
|
|
6
6
|
const DEFAULT_NAME = "solidrt-app"
|
|
7
7
|
|
|
@@ -90,8 +90,10 @@ platform-wide and bite in every app:
|
|
|
90
90
|
|
|
91
91
|
## Run / verify
|
|
92
92
|
|
|
93
|
-
- FIRST check whether a dev server and
|
|
94
|
-
build against those; do not start a second `srt run`
|
|
93
|
+
- FIRST check whether a dev server and its clients (possibly several) are
|
|
94
|
+
already running and build against those; do not start a second `srt run`
|
|
95
|
+
when one is up. `reload` reaches every connected client; the per-client
|
|
96
|
+
tools are listed in debugging.md.
|
|
95
97
|
- The dev loop (reload, logs, snapshots, the holds on reload-on-save and on
|
|
96
98
|
the user's input), typechecking, headless rendering and the MCP tools:
|
|
97
99
|
node_modules/@solidrt/cli/AGENTS.md and its agents/debugging.md. Read it
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
"android": "srt android"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@solidrt/core": "0.0.
|
|
14
|
-
"@solidrt/components": "0.0.
|
|
15
|
-
"@solidrt/2d": "0.0.
|
|
16
|
-
"@solidrt/3d": "0.0.
|
|
13
|
+
"@solidrt/core": "0.0.55",
|
|
14
|
+
"@solidrt/components": "0.0.55",
|
|
15
|
+
"@solidrt/2d": "0.0.55",
|
|
16
|
+
"@solidrt/3d": "0.0.55"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@solidrt/cli": "0.0.
|
|
20
|
-
"@solidrt/flux-types": "0.0.
|
|
19
|
+
"@solidrt/cli": "0.0.55",
|
|
20
|
+
"@solidrt/flux-types": "0.0.55",
|
|
21
21
|
"typescript": "^7"
|
|
22
22
|
}
|
|
23
23
|
}
|