dsh-mobilecode 0.11.3 → 0.11.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 +3 -2
- package/lib/client.js +32 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,8 +156,9 @@ card is **Device 1**; co-op docks a second, **Device 2**. It is produced
|
|
|
156
156
|
independently. Each pane grants its own HMAC capability; closing one pane
|
|
157
157
|
never stalls or disturbs the other stream. A presence watcher polls device
|
|
158
158
|
liveness while streaming: if a device is powered off (⏻ off, crash, unplug)
|
|
159
|
-
its pane drops the frozen frame and the Live badge within ~5 s, and
|
|
160
|
-
|
|
159
|
+
its pane drops the frozen frame and the Live badge within ~5 s, and stays
|
|
160
|
+
idle instead of silently grabbing another device — both panes guard against
|
|
161
|
+
the re-grab (0.11.3–4). Both stream
|
|
161
162
|
captions carry the running client version (`· v0.11.x`) so a page refresh is
|
|
162
163
|
visibly proven.
|
|
163
164
|
- **Security**: every stream route sits behind a loopback + trusted-browser
|
package/lib/client.js
CHANGED
|
@@ -190,7 +190,7 @@ window.__ModuleLoader__.load({
|
|
|
190
190
|
// Shown on both stream captions so a refresh visibly proves which client
|
|
191
191
|
// bundle the browser is actually running. Kept in lockstep with
|
|
192
192
|
// package.json by test/client.mjs.
|
|
193
|
-
const MC_VERSION = "0.11.
|
|
193
|
+
const MC_VERSION = "0.11.4";
|
|
194
194
|
// The panel shows cards for platforms the host can actually drive; the
|
|
195
195
|
// server reports its OS in info.os (iOS tooling is darwin-only).
|
|
196
196
|
const fallbackPlatforms = (os) => (os === "darwin" ? ["ios", "android"] : ["android"]);
|
|
@@ -676,7 +676,12 @@ window.__ModuleLoader__.load({
|
|
|
676
676
|
const r = await streamPost("/stream/devices", {});
|
|
677
677
|
setDevices(r.devices);
|
|
678
678
|
setAvds(r.avds ?? []);
|
|
679
|
-
|
|
679
|
+
// Prefer emulators for the welcome auto-pick: a physical
|
|
680
|
+
// serial sorts first in adb order but has no ⏻ off control.
|
|
681
|
+
// (Serial prefix, not the avd field — avdName() can fail.)
|
|
682
|
+
const isEmu = (d) => d.serial.startsWith("emulator-");
|
|
683
|
+
const first = r.devices.find((d) => d.streaming && isEmu(d))?.serial ?? r.devices.find(isEmu)?.serial
|
|
684
|
+
?? r.devices.find((d) => d.streaming)?.serial ?? r.devices[0]?.serial ?? "";
|
|
680
685
|
const cur = serialRef.current;
|
|
681
686
|
if (cur === "") {
|
|
682
687
|
// Auto-stream once per page load (the welcome flow). After
|
|
@@ -870,22 +875,35 @@ window.__ModuleLoader__.load({
|
|
|
870
875
|
const [error, setError] = useState("");
|
|
871
876
|
const live = useLiveStream({ serial, onError: setError });
|
|
872
877
|
const grant = (device) => live.grant(device).then((ok) => { if (ok) setError(""); });
|
|
873
|
-
// Serial mirror for the
|
|
878
|
+
// Serial mirror for the 5s poller + one-shot auto-pick guard: this
|
|
879
|
+
// pane may steal a partner while nothing is picked, but it must NOT
|
|
880
|
+
// silently switch to a third device after its own goes offline.
|
|
874
881
|
const serialRef = useRef(serial);
|
|
875
882
|
serialRef.current = serial;
|
|
883
|
+
const autoPicked = useRef(false);
|
|
876
884
|
|
|
877
885
|
const refresh = async () => {
|
|
878
886
|
try {
|
|
879
887
|
const r = await streamPost("/stream/devices", {});
|
|
880
888
|
setDevices(r.devices);
|
|
881
|
-
|
|
882
|
-
|
|
889
|
+
// Partner candidates: emulators only (serial prefix, not the
|
|
890
|
+
// flaky avd field) — the co-op partner must be killable from
|
|
891
|
+
// the picker, and never Device 1's own serial.
|
|
892
|
+
const others = r.devices.filter((d) => d.serial !== excludeSerial && d.serial.startsWith("emulator-"));
|
|
883
893
|
const cur = serialRef.current;
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
894
|
+
if (cur !== "") {
|
|
895
|
+
// Keep any valid pick — including a manually chosen physical
|
|
896
|
+
// device; only emulators are eligible for auto-pick. A dead
|
|
897
|
+
// or stolen pick clears to the placeholder (never re-grabs).
|
|
898
|
+
if (cur !== excludeSerial && r.devices.some((d) => d.serial === cur)) return;
|
|
899
|
+
autoPicked.current = true;
|
|
900
|
+
setSerial(""); live.reset();
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
if (!autoPicked.current) {
|
|
904
|
+
const next = (others.find((d) => d.streaming) ?? others[0])?.serial ?? "";
|
|
905
|
+
if (next !== "") { autoPicked.current = true; setSerial(next); }
|
|
906
|
+
}
|
|
889
907
|
} catch {
|
|
890
908
|
/* the header keeps the last device list */
|
|
891
909
|
}
|
|
@@ -905,7 +923,10 @@ window.__ModuleLoader__.load({
|
|
|
905
923
|
live.streamUrl !== "" && h("span", { className: "mc-live-badge" }, h("span", { className: "mc-dot on" }), "Live"),
|
|
906
924
|
h("span", { className: "sp" }),
|
|
907
925
|
h("select", { className: "mc-input mc-coop-select", value: serial, onChange: (e) => { setSerial(e.target.value); live.reset(); } },
|
|
908
|
-
|
|
926
|
+
// An honest empty option: a select with no matching option
|
|
927
|
+
// silently DISPLAYS devices[0] while state is still "" —
|
|
928
|
+
// that made the probe read a phantom pick (0.11.4).
|
|
929
|
+
!devices.some((d) => d.serial === serial) && h("option", { value: "" }, devices.length === 0 ? "no device" : "— pick device —"),
|
|
909
930
|
devices.map((d) => h("option", { key: d.serial, value: d.serial }, d.serial + (d.serial === excludeSerial ? " (Device 1)" : d.streaming ? " ●" : ""))),
|
|
910
931
|
),
|
|
911
932
|
),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mobilecode",
|
|
3
3
|
"description": "MobileCode for the dsh web GUI: detect iOS/Android projects, run preview servers, and drive the simulator/emulator from the session — 37 agent tools (device_run, device_screen, device_ui_tree, device_ui_rows, device_tap_row, device_tap_element, device_wait_for, device_scroll_to, device_input, device_batch, device_intent, device_connect, device_pair_qr, device_perf, device_meminfo, device_backtrace, device_display, device_avd_create, device_pair_capture, device_app_info, device_install, device_uninstall, device_reboot, device_log, live screen stream, multimodal screenshots) plus a host-mediated co-op mesh hub (random callsigns, JSON pub/sub, tunable latency/jitter/drop/dup/throttle) so two virtual devices — and the AI watching them — can talk in real time. One classified adb boundary and a Wi-Fi connect/pair QR flow in the Connection settings tab. Hot-pluggable — mounted via the profile bundle list + cordis.patch.yml, no dsh source changes.",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.22.0",
|
|
7
7
|
"engines": {
|