sootsim 0.1.183 → 0.1.185
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 +22 -19
- package/dist-cli/bin.js +6 -6
- package/dist-cli/chunks/{agent-AFAFZKMT.js → agent-VF756RZU.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-MV5WGYCS.js → agent-wrapper-IAFL7ROV.js} +2 -2
- package/dist-cli/chunks/{app-fonts-ERD5J644.js → app-fonts-VWLEC7ZA.js} +2 -2
- package/dist-cli/chunks/{assert-IBMYHSKD.js → assert-I55QVGG7.js} +2 -2
- package/dist-cli/chunks/beta-X6YPQVZH.js +2 -0
- package/dist-cli/chunks/{camera-Y6XUIEAP.js → camera-CYYBJH7W.js} +2 -2
- package/dist-cli/chunks/{chunk-XGVVYY6P.js → chunk-2T73IGB2.js} +2 -2
- package/dist-cli/chunks/{chunk-BTIARV2B.js → chunk-4NUQVW5P.js} +17 -4
- package/dist-cli/chunks/{chunk-FODJBAWY.js → chunk-4OUQAR34.js} +1 -1
- package/dist-cli/chunks/{chunk-RQDJPT6N.js → chunk-7OAUPGLN.js} +2 -2
- package/dist-cli/chunks/{chunk-BYKEWDZO.js → chunk-ARNLQPMQ.js} +4 -4
- package/dist-cli/chunks/{chunk-AP22KA3Q.js → chunk-BI56RR3G.js} +1 -1
- package/dist-cli/chunks/{chunk-WN6XO6JV.js → chunk-BMCBPMTC.js} +1 -1
- package/dist-cli/chunks/{chunk-64EKAMA3.js → chunk-C3UEINOZ.js} +2 -2
- package/dist-cli/chunks/{chunk-VSDVOOWG.js → chunk-C63EVPDN.js} +2 -2
- package/dist-cli/chunks/{chunk-CD3KUHS3.js → chunk-CYBRFHPU.js} +2 -2
- package/dist-cli/chunks/chunk-DZLBZGHN.js +62 -0
- package/dist-cli/chunks/{chunk-QP4W3SGO.js → chunk-E5DE33BU.js} +1 -1
- package/dist-cli/chunks/{chunk-WV7QBUFY.js → chunk-EXFB33AZ.js} +2 -2
- package/dist-cli/chunks/{chunk-QF6RJQ2U.js → chunk-FHJTTB3W.js} +2 -2
- package/dist-cli/chunks/{chunk-UXHEGFHQ.js → chunk-FUHXL6BW.js} +1 -1
- package/dist-cli/chunks/{chunk-WOOWTKM7.js → chunk-FY6DJGOS.js} +1 -1
- package/dist-cli/chunks/{chunk-YSTCZI6L.js → chunk-GX6MKIFC.js} +1 -1
- package/dist-cli/chunks/{chunk-JR7LKXPB.js → chunk-HQG4DRQ3.js} +1 -1
- package/dist-cli/chunks/chunk-IGJHME3T.js +1 -0
- package/dist-cli/chunks/{chunk-C7BIPAXT.js → chunk-IJP257WP.js} +1 -1
- package/dist-cli/chunks/chunk-JRL7PFNZ.js +463 -0
- package/dist-cli/chunks/{chunk-7SP7PFUR.js → chunk-K2THZIVC.js} +1 -1
- package/dist-cli/chunks/chunk-KOKIECMB.js +118 -0
- package/dist-cli/chunks/{chunk-IJMDXS7N.js → chunk-LI4RLX6B.js} +1 -1
- package/dist-cli/chunks/{chunk-3JW7SSYR.js → chunk-LJ3SOZBF.js} +2 -2
- package/dist-cli/chunks/{chunk-6TNJLDAQ.js → chunk-M3P67TBN.js} +1 -1
- package/dist-cli/chunks/{chunk-OIFGVAV2.js → chunk-MADEJDFD.js} +1 -1
- package/dist-cli/chunks/{chunk-RC3FKTYP.js → chunk-NL5IFN4T.js} +2 -2
- package/dist-cli/chunks/chunk-OAHGYDJR.js +13 -0
- package/dist-cli/chunks/{chunk-RQXZANGL.js → chunk-PDLQWZN4.js} +1 -1
- package/dist-cli/chunks/{chunk-KSV6H2IC.js → chunk-PIUKLO3W.js} +1 -1
- package/dist-cli/chunks/{chunk-FO3RPGBR.js → chunk-PKZNXDUJ.js} +2 -2
- package/dist-cli/chunks/{chunk-N2EXJ7HK.js → chunk-QQ4NSPAD.js} +2 -2
- package/dist-cli/chunks/{chunk-W3G5M4UB.js → chunk-QTFCJYBF.js} +3 -3
- package/dist-cli/chunks/{chunk-CPZNH3B3.js → chunk-R4KLD4P4.js} +3 -3
- package/dist-cli/chunks/chunk-SL6565MR.js +1 -0
- package/dist-cli/chunks/{chunk-QQDPEM7F.js → chunk-TFZO277G.js} +1 -1
- package/dist-cli/chunks/{chunk-4FVYQIRB.js → chunk-TNHF6BON.js} +1 -1
- package/dist-cli/chunks/{chunk-L3FPLPA4.js → chunk-TUF6EPCQ.js} +2 -2
- package/dist-cli/chunks/chunk-V4M2R6FZ.js +2 -0
- package/dist-cli/chunks/{chunk-6GCEDCO5.js → chunk-V5JEPE3P.js} +2 -2
- package/dist-cli/chunks/{chunk-PY4P54SD.js → chunk-WBY4JJ2K.js} +2 -2
- package/dist-cli/chunks/{chunk-RAEIXWER.js → chunk-WEJKLJ4B.js} +2 -2
- package/dist-cli/chunks/{chunk-SGWTX6CO.js → chunk-X4KS33ZC.js} +2 -2
- package/dist-cli/chunks/{chunk-HW65ZTXM.js → chunk-XU5EMZ4B.js} +2 -2
- package/dist-cli/chunks/cli-version-ICHQMND6.js +2 -0
- package/dist-cli/chunks/{compat-ZTFIQOVI.js → compat-ZJA3N4ZT.js} +3 -3
- package/dist-cli/chunks/{control-XWU7LZWC.js → control-CZFSYSYG.js} +2 -2
- package/dist-cli/chunks/{cpu-profile-3F2OQNCM.js → cpu-profile-ACSQMVXY.js} +2 -2
- package/dist-cli/chunks/daemon-337B4P3B.js +2 -0
- package/dist-cli/chunks/{debug-7MIHREPG.js → debug-W2ZOVTQO.js} +3 -3
- package/dist-cli/chunks/{detox-CDYD54PS.js → detox-ANJO6T27.js} +2 -2
- package/dist-cli/chunks/{device-H53IDQ67.js → device-KPPN4KYD.js} +2 -2
- package/dist-cli/chunks/{diagnose-YWSZCFPG.js → diagnose-5PEJYGES.js} +2 -2
- package/dist-cli/chunks/drivers-MSDIFHBD.js +2 -0
- package/dist-cli/chunks/electron-U456QLSQ.js +19 -0
- package/dist-cli/chunks/flow-JL3SC6HC.js +2 -0
- package/dist-cli/chunks/help-PA4RTR5X.js +2 -0
- package/dist-cli/chunks/{hints-BYH6BMHP.js → hints-MBBQLMQU.js} +2 -2
- package/dist-cli/chunks/{home-paths-AXKOJS62.js → home-paths-KQKYP2SE.js} +2 -2
- package/dist-cli/chunks/{inspect-TGQU6MZQ.js → inspect-ZP5SM4EW.js} +62 -62
- package/dist-cli/chunks/{install-desktop-AOJACCWA.js → install-desktop-OR6ZJ43X.js} +4 -4
- package/dist-cli/chunks/{keys-RC6SP7XY.js → keys-JSQMBUE7.js} +2 -2
- package/dist-cli/chunks/{login-EQDNEJFU.js → login-DVMWAI3G.js} +4 -4
- package/dist-cli/chunks/{logout-QEDUWSSY.js → logout-RIVPFE5N.js} +2 -2
- package/dist-cli/chunks/{maestro-6SVETVRL.js → maestro-TX6FPTVH.js} +8 -6
- package/dist-cli/chunks/optional-demo-registry-ONYG6DUI.js +2 -0
- package/dist-cli/chunks/{preview-UNXWRROE.js → preview-3AD7WNA6.js} +2 -2
- package/dist-cli/chunks/{profile-UBHQS25I.js → profile-HY55VFNR.js} +2 -2
- package/dist-cli/chunks/{react-THVP5NZX.js → react-HDRCKCKV.js} +2 -2
- package/dist-cli/chunks/{record-SOACBRM3.js → record-HW4C7QYN.js} +2 -2
- package/dist-cli/chunks/runtime-RHHPW5WO.js +2 -0
- package/dist-cli/chunks/{screenshot-MJKWIVV6.js → screenshot-XFR3QN5T.js} +2 -2
- package/dist-cli/chunks/{screenshot-mode-RP67FQSA.js → screenshot-mode-Y5CVO267.js} +2 -2
- package/dist-cli/chunks/{screenshots-LWDOE4RD.js → screenshots-RKUL2ZZT.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-RUXUL5GO.js → screenshots-capture-RVNF75ZD.js} +8 -8
- package/dist-cli/chunks/{serve-TMMMRVTI.js → serve-QMRYLWL5.js} +2 -2
- package/dist-cli/chunks/setup-ELNJS7AI.js +97 -0
- package/dist-cli/chunks/{skills-P3HEQGPB.js → skills-GPSJYS4W.js} +2 -2
- package/dist-cli/chunks/{slides-MICILFXO.js → slides-OCFNPIFG.js} +2 -2
- package/dist-cli/chunks/store-MBKDUQEQ.js +2 -0
- package/dist-cli/chunks/telemetry-46XXIUEE.js +2 -0
- package/dist-cli/chunks/{telemetry-7ZVCPD7R.js → telemetry-KFZQUFG5.js} +2 -2
- package/dist-cli/chunks/{test-NT7SGPG5.js → test-Z2HZXCZM.js} +3 -3
- package/dist-cli/chunks/{three-mode-6ADYURNM.js → three-mode-NKJFCDYS.js} +2 -2
- package/dist-cli/chunks/{timeline-JZNPRKEH.js → timeline-PRGQMQRR.js} +2 -2
- package/dist-cli/chunks/upgrade-3NW7JRRX.js +4 -0
- package/dist-cli/chunks/upload-QVDVJ6ZK.js +2 -0
- package/dist-cli/chunks/{version-GS2J6SFA.js → version-FDTZRIYT.js} +2 -2
- package/dist-cli/chunks/{web-J2XC4OK4.js → web-4N5QQEQJ.js} +2 -2
- package/dist-cli/chunks/{what-happened-O5MCMYJL.js → what-happened-IX2RRCOS.js} +2 -2
- package/dist-cli/chunks/{whoami-Z2Y2X2DN.js → whoami-QZ42FYYF.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +218 -47
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.cjs +1 -1
- package/skills/soot.md +2 -2
- package/skills/sootsim-setup.md +7 -6
- package/dist-cli/chunks/beta-T7Z7WSTK.js +0 -2
- package/dist-cli/chunks/chunk-4HJKPRWO.js +0 -463
- package/dist-cli/chunks/chunk-77GTIGLV.js +0 -1
- package/dist-cli/chunks/chunk-B3W63SZA.js +0 -13
- package/dist-cli/chunks/chunk-D7ZB6A5T.js +0 -2
- package/dist-cli/chunks/chunk-F6DIP2WH.js +0 -62
- package/dist-cli/chunks/chunk-MBR6TG2P.js +0 -118
- package/dist-cli/chunks/chunk-NLI4YQOY.js +0 -1
- package/dist-cli/chunks/cli-version-P4SZNBPQ.js +0 -2
- package/dist-cli/chunks/daemon-CUQB4QAP.js +0 -2
- package/dist-cli/chunks/drivers-RRCIIDGS.js +0 -2
- package/dist-cli/chunks/electron-UPH35PTF.js +0 -18
- package/dist-cli/chunks/flow-ZDJI7ICC.js +0 -2
- package/dist-cli/chunks/help-U5QGSMDR.js +0 -2
- package/dist-cli/chunks/optional-demo-registry-KXYBVP4S.js +0 -2
- package/dist-cli/chunks/runtime-BAS2IZFB.js +0 -2
- package/dist-cli/chunks/setup-WYKWQPJW.js +0 -77
- package/dist-cli/chunks/store-7CIU7X6W.js +0 -2
- package/dist-cli/chunks/telemetry-LVBDBPPV.js +0 -2
- package/dist-cli/chunks/upgrade-K6V3HYCU.js +0 -4
- package/dist-cli/chunks/upload-Q2ZFKOSR.js +0 -2
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.185 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -15834,6 +15834,25 @@ function readyProbeHasContent(probe) {
|
|
|
15834
15834
|
function readyProbeHasTargetContent(probe) {
|
|
15835
15835
|
return probe.targets > 0;
|
|
15836
15836
|
}
|
|
15837
|
+
function isShellCommandUnavailable(error) {
|
|
15838
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15839
|
+
return message.includes("call target not found: SootSim.bridges.mainShell") || message.includes("test bridge unavailable before app-in-worker boot");
|
|
15840
|
+
}
|
|
15841
|
+
async function getShellState(bridge, readyTimeoutMs = 0) {
|
|
15842
|
+
const deadline = Date.now() + Math.max(0, readyTimeoutMs);
|
|
15843
|
+
while (true) {
|
|
15844
|
+
try {
|
|
15845
|
+
return await bridge.send({
|
|
15846
|
+
type: "call",
|
|
15847
|
+
path: "SootSim.bridges.mainShell.getState",
|
|
15848
|
+
args: []
|
|
15849
|
+
});
|
|
15850
|
+
} catch (error) {
|
|
15851
|
+
if (!isShellCommandUnavailable(error) || Date.now() >= deadline) throw error;
|
|
15852
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
15853
|
+
}
|
|
15854
|
+
}
|
|
15855
|
+
}
|
|
15837
15856
|
var LAYOUT_GET_NATIVE_EVAL, WAIT_READY_PROBE, READY_CONTENT_NODE_FLOOR, READY_NODE_STABLE_MS;
|
|
15838
15857
|
var init_core = __esm({
|
|
15839
15858
|
"cli/commands/inspect/core.ts"() {
|
|
@@ -16104,6 +16123,32 @@ var init_settling = __esm({
|
|
|
16104
16123
|
}
|
|
16105
16124
|
});
|
|
16106
16125
|
|
|
16126
|
+
// cli/commands/inspect/shared.ts
|
|
16127
|
+
function sleep(ms) {
|
|
16128
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
16129
|
+
}
|
|
16130
|
+
async function callShellCommand(bridge, method, ...args) {
|
|
16131
|
+
return callInBridgeWrite(bridge, `SootSim.bridges.mainShell.${method}`, ...args);
|
|
16132
|
+
}
|
|
16133
|
+
async function callShellCommandWhenReady(bridge, method, readyTimeoutMs, ...args) {
|
|
16134
|
+
const deadline = Date.now() + Math.max(0, readyTimeoutMs);
|
|
16135
|
+
while (true) {
|
|
16136
|
+
try {
|
|
16137
|
+
return await callShellCommand(bridge, method, ...args);
|
|
16138
|
+
} catch (error) {
|
|
16139
|
+
if (!isShellCommandUnavailable(error) || Date.now() >= deadline) throw error;
|
|
16140
|
+
await sleep(50);
|
|
16141
|
+
}
|
|
16142
|
+
}
|
|
16143
|
+
}
|
|
16144
|
+
var init_shared = __esm({
|
|
16145
|
+
"cli/commands/inspect/shared.ts"() {
|
|
16146
|
+
"use strict";
|
|
16147
|
+
init_ws_bridge();
|
|
16148
|
+
init_core();
|
|
16149
|
+
}
|
|
16150
|
+
});
|
|
16151
|
+
|
|
16107
16152
|
// cli/maestro-js.ts
|
|
16108
16153
|
function executeSyncHttp(url, method, params) {
|
|
16109
16154
|
if (params?.multipartForm) {
|
|
@@ -16675,9 +16720,33 @@ __export(bridge_flow_runner_exports, {
|
|
|
16675
16720
|
resolveFlowScreenshotPath: () => resolveFlowScreenshotPath,
|
|
16676
16721
|
resolveFlowScreenshotPathWithMode: () => resolveFlowScreenshotPathWithMode
|
|
16677
16722
|
});
|
|
16678
|
-
function
|
|
16723
|
+
function sleep2(ms) {
|
|
16679
16724
|
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
16680
16725
|
}
|
|
16726
|
+
function isObjectRecord(value) {
|
|
16727
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
16728
|
+
}
|
|
16729
|
+
function readStringKey(value, key) {
|
|
16730
|
+
if (!isObjectRecord(value)) return null;
|
|
16731
|
+
const raw = value[key];
|
|
16732
|
+
return typeof raw === "string" && raw.length > 0 ? raw : null;
|
|
16733
|
+
}
|
|
16734
|
+
function readBooleanKey(value, key) {
|
|
16735
|
+
if (!isObjectRecord(value)) return false;
|
|
16736
|
+
return value[key] === true;
|
|
16737
|
+
}
|
|
16738
|
+
function readRecentShellAppId(state) {
|
|
16739
|
+
if (!state) return null;
|
|
16740
|
+
const recentApps = state.recentApps;
|
|
16741
|
+
if (Array.isArray(recentApps)) {
|
|
16742
|
+
for (const app of recentApps) {
|
|
16743
|
+
const id = readStringKey(app, "id");
|
|
16744
|
+
if (id) return id;
|
|
16745
|
+
}
|
|
16746
|
+
}
|
|
16747
|
+
const bindings = state.surfaceBindings;
|
|
16748
|
+
return readStringKey(bindings, "app:one") || readStringKey(bindings, "app:two") || null;
|
|
16749
|
+
}
|
|
16681
16750
|
function resolveFlowScreenshotPath(screenshotDir, name) {
|
|
16682
16751
|
return resolveFlowScreenshotPathWithMode(screenshotDir, name, {
|
|
16683
16752
|
mode: "dir"
|
|
@@ -16761,6 +16830,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
16761
16830
|
init_app_state_reset();
|
|
16762
16831
|
init_core();
|
|
16763
16832
|
init_settling();
|
|
16833
|
+
init_shared();
|
|
16764
16834
|
init_maestro_js();
|
|
16765
16835
|
init_recording_access();
|
|
16766
16836
|
DEFAULT_TIMEOUT = 1e4;
|
|
@@ -16909,7 +16979,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
16909
16979
|
` [flow] waiting for app to be ready\u2026 (${Math.round(elapsed / 1e3)}s)`
|
|
16910
16980
|
);
|
|
16911
16981
|
}
|
|
16912
|
-
await
|
|
16982
|
+
await sleep2(500);
|
|
16913
16983
|
}
|
|
16914
16984
|
if (lastError?.message.startsWith("app failed to load:")) {
|
|
16915
16985
|
throw lastError;
|
|
@@ -16992,7 +17062,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
16992
17062
|
const maxMs = Math.max(0, Math.round(opts.maxMs));
|
|
16993
17063
|
if (maxMs <= 0) return;
|
|
16994
17064
|
if (!opts.smart) {
|
|
16995
|
-
await
|
|
17065
|
+
await sleep2(maxMs);
|
|
16996
17066
|
return;
|
|
16997
17067
|
}
|
|
16998
17068
|
const result = await waitForSootsimIdle({
|
|
@@ -17202,7 +17272,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17202
17272
|
if (!direct2?.ok) {
|
|
17203
17273
|
await this.tap(point.x, point.y);
|
|
17204
17274
|
}
|
|
17205
|
-
await
|
|
17275
|
+
await sleep2(300);
|
|
17206
17276
|
return;
|
|
17207
17277
|
}
|
|
17208
17278
|
const TAP_WAIT_DEADLINE_MS = 5e3;
|
|
@@ -17210,7 +17280,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17210
17280
|
const deadline = Date.now() + TAP_WAIT_DEADLINE_MS;
|
|
17211
17281
|
let element = await this.findElement({ text: opts.text, id: opts.id });
|
|
17212
17282
|
while (!element && Date.now() < deadline) {
|
|
17213
|
-
await
|
|
17283
|
+
await sleep2(TAP_WAIT_POLL_MS);
|
|
17214
17284
|
element = await this.findElement({ text: opts.text, id: opts.id });
|
|
17215
17285
|
}
|
|
17216
17286
|
if (element) {
|
|
@@ -17228,9 +17298,9 @@ var init_bridge_flow_runner = __esm({
|
|
|
17228
17298
|
type: tapTarget?.target?.type ?? current.type ?? null
|
|
17229
17299
|
});
|
|
17230
17300
|
if (hit?.hit === true) {
|
|
17231
|
-
await
|
|
17301
|
+
await sleep2(300);
|
|
17232
17302
|
if (!current.isTextInput) return;
|
|
17233
|
-
if (await this.waitForFocusedTextInput(600)) return;
|
|
17303
|
+
if (await this.waitForFocusedTextInput(600, current)) return;
|
|
17234
17304
|
continue;
|
|
17235
17305
|
}
|
|
17236
17306
|
break;
|
|
@@ -17238,14 +17308,14 @@ var init_bridge_flow_runner = __esm({
|
|
|
17238
17308
|
}
|
|
17239
17309
|
const direct = await this.activatePressTarget(opts);
|
|
17240
17310
|
if (direct?.ok) {
|
|
17241
|
-
await
|
|
17311
|
+
await sleep2(300);
|
|
17242
17312
|
return;
|
|
17243
17313
|
}
|
|
17244
17314
|
throw new Error(`tapOn: element not found: ${JSON.stringify(opts)}`);
|
|
17245
17315
|
}
|
|
17246
17316
|
async tapAtCoords(x, y) {
|
|
17247
17317
|
await this.tap(x, y);
|
|
17248
|
-
await
|
|
17318
|
+
await sleep2(300);
|
|
17249
17319
|
}
|
|
17250
17320
|
async doubleTapAtCoords(x, y, gapMs = 80) {
|
|
17251
17321
|
const waitMs = Math.max(0, Math.round(gapMs));
|
|
@@ -17262,7 +17332,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17262
17332
|
return !!second && second.hit !== false
|
|
17263
17333
|
})()`);
|
|
17264
17334
|
if (!ok) throw new Error(`doubleTapAtCoords failed at (${x}, ${y})`);
|
|
17265
|
-
await
|
|
17335
|
+
await sleep2(300);
|
|
17266
17336
|
}
|
|
17267
17337
|
async assertVisible(target) {
|
|
17268
17338
|
const opts = typeof target === "string" ? { text: target } : target;
|
|
@@ -17270,7 +17340,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17270
17340
|
if (await this.isElementVisible(opts)) {
|
|
17271
17341
|
return;
|
|
17272
17342
|
}
|
|
17273
|
-
await
|
|
17343
|
+
await sleep2(200);
|
|
17274
17344
|
}
|
|
17275
17345
|
const found = await this.findElement(opts);
|
|
17276
17346
|
const detail = found ? ` (matched node at y=${Math.round(found.absolutePosition.y)} h=${Math.round(found.layout.height)} \u2014 off-screen)` : " (no matching node in tree)";
|
|
@@ -17289,29 +17359,48 @@ var init_bridge_flow_runner = __esm({
|
|
|
17289
17359
|
return !!(element && element.absolutePosition.y + element.layout.height > 0 && element.absolutePosition.y < SCREEN_H);
|
|
17290
17360
|
}
|
|
17291
17361
|
async inputText(text) {
|
|
17292
|
-
await this.waitForFocusedTextInput()
|
|
17362
|
+
if (!await this.waitForFocusedTextInput()) {
|
|
17363
|
+
throw new Error(
|
|
17364
|
+
"inputText: no focused TextInput; tap the input and wait for focus before typing"
|
|
17365
|
+
);
|
|
17366
|
+
}
|
|
17293
17367
|
await this.bridge.send({
|
|
17294
17368
|
type: "keyboard",
|
|
17295
17369
|
simId: this.opts.simId,
|
|
17296
17370
|
action: "type",
|
|
17297
17371
|
text
|
|
17298
17372
|
});
|
|
17299
|
-
await
|
|
17373
|
+
await sleep2(200);
|
|
17300
17374
|
}
|
|
17301
17375
|
// poll for a focused text input. returns true once getFocusedNode reports a
|
|
17302
17376
|
// node (focus landed), false if the budget elapses. callers use it both as a
|
|
17303
17377
|
// tap-focus confirmation (tapOn retry) and a pre-type barrier (inputText).
|
|
17304
|
-
|
|
17378
|
+
focusedTextInputMatches(focused, expected) {
|
|
17379
|
+
if (!expected) return true;
|
|
17380
|
+
if (typeof expected.nodeId === "number" && typeof focused.nodeId === "number" && expected.nodeId === focused.nodeId) {
|
|
17381
|
+
return true;
|
|
17382
|
+
}
|
|
17383
|
+
const expectedTestID = expected.testID ?? null;
|
|
17384
|
+
const focusedTestID = focused.testID ?? null;
|
|
17385
|
+
if (expectedTestID && focusedTestID && expectedTestID === focusedTestID) {
|
|
17386
|
+
return true;
|
|
17387
|
+
}
|
|
17388
|
+
const expectedId = expected.id ?? null;
|
|
17389
|
+
const focusedId = focused.id ?? null;
|
|
17390
|
+
if (expectedId && focusedId && expectedId === focusedId) {
|
|
17391
|
+
return true;
|
|
17392
|
+
}
|
|
17393
|
+
return false;
|
|
17394
|
+
}
|
|
17395
|
+
async waitForFocusedTextInput(timeoutMs = 1500, expected) {
|
|
17305
17396
|
const deadline = Date.now() + timeoutMs;
|
|
17306
17397
|
while (Date.now() < deadline) {
|
|
17307
17398
|
try {
|
|
17308
|
-
const focused = await this.callTest(
|
|
17309
|
-
|
|
17310
|
-
);
|
|
17311
|
-
if (focused) return true;
|
|
17399
|
+
const focused = await this.callTest("getFocusedNode");
|
|
17400
|
+
if (focused && this.focusedTextInputMatches(focused, expected)) return true;
|
|
17312
17401
|
} catch {
|
|
17313
17402
|
}
|
|
17314
|
-
await
|
|
17403
|
+
await sleep2(50);
|
|
17315
17404
|
}
|
|
17316
17405
|
return false;
|
|
17317
17406
|
}
|
|
@@ -17322,7 +17411,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17322
17411
|
action: "press",
|
|
17323
17412
|
text: name
|
|
17324
17413
|
});
|
|
17325
|
-
await
|
|
17414
|
+
await sleep2(120);
|
|
17326
17415
|
}
|
|
17327
17416
|
async dispatchKey(ch) {
|
|
17328
17417
|
await this.bridge.send({
|
|
@@ -17331,7 +17420,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17331
17420
|
action: "dispatchKey",
|
|
17332
17421
|
text: ch
|
|
17333
17422
|
});
|
|
17334
|
-
await
|
|
17423
|
+
await sleep2(120);
|
|
17335
17424
|
}
|
|
17336
17425
|
async hideKeyboard() {
|
|
17337
17426
|
try {
|
|
@@ -17357,24 +17446,29 @@ var init_bridge_flow_runner = __esm({
|
|
|
17357
17446
|
}
|
|
17358
17447
|
})()`);
|
|
17359
17448
|
if (!state?.visible && !state?.focused) {
|
|
17360
|
-
await
|
|
17449
|
+
await sleep2(80);
|
|
17361
17450
|
return;
|
|
17362
17451
|
}
|
|
17363
|
-
await
|
|
17452
|
+
await sleep2(80);
|
|
17364
17453
|
}
|
|
17365
17454
|
}
|
|
17366
17455
|
async eraseText(count) {
|
|
17367
17456
|
for (let i = 0; i < count; i++) {
|
|
17368
|
-
await this.
|
|
17457
|
+
await this.bridge.send({
|
|
17458
|
+
type: "keyboard",
|
|
17459
|
+
simId: this.opts.simId,
|
|
17460
|
+
action: "dispatchKey",
|
|
17461
|
+
text: "Backspace"
|
|
17462
|
+
});
|
|
17369
17463
|
}
|
|
17370
|
-
await
|
|
17464
|
+
await sleep2(100);
|
|
17371
17465
|
}
|
|
17372
17466
|
async waitFor(opts) {
|
|
17373
17467
|
const deadline = Date.now() + (opts.timeout || DEFAULT_TIMEOUT);
|
|
17374
17468
|
while (Date.now() < deadline) {
|
|
17375
17469
|
const element = await this.findElement(opts);
|
|
17376
17470
|
if (element) return;
|
|
17377
|
-
await
|
|
17471
|
+
await sleep2(200);
|
|
17378
17472
|
}
|
|
17379
17473
|
const final = await this.findElement(opts);
|
|
17380
17474
|
const detail = final ? ` (matched node y=${Math.round(final.absolutePosition.y)} \u2014 still off-screen at deadline)` : "";
|
|
@@ -17386,7 +17480,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17386
17480
|
if (!this.hasFreshVisualSettle()) {
|
|
17387
17481
|
try {
|
|
17388
17482
|
await this.waitForVisualSettle();
|
|
17389
|
-
await
|
|
17483
|
+
await sleep2(250);
|
|
17390
17484
|
} catch {
|
|
17391
17485
|
}
|
|
17392
17486
|
}
|
|
@@ -17586,7 +17680,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17586
17680
|
if (!result?.ok) {
|
|
17587
17681
|
throw new Error("drag failed");
|
|
17588
17682
|
}
|
|
17589
|
-
await
|
|
17683
|
+
await sleep2(300);
|
|
17590
17684
|
}
|
|
17591
17685
|
async swipeCoords(start, end, duration = 300) {
|
|
17592
17686
|
const from = parsePoint(start);
|
|
@@ -17630,7 +17724,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17630
17724
|
if (!result?.ok) {
|
|
17631
17725
|
throw new Error(`scrollTo failed: ${result?.reason || "unknown error"}`);
|
|
17632
17726
|
}
|
|
17633
|
-
await
|
|
17727
|
+
await sleep2(250);
|
|
17634
17728
|
}
|
|
17635
17729
|
async pinch(opts) {
|
|
17636
17730
|
const result = await this.evaluate(`(async () => {
|
|
@@ -17646,7 +17740,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17646
17740
|
if (!result?.ok) {
|
|
17647
17741
|
throw new Error(`pinch failed: ${result?.reason || "unknown error"}`);
|
|
17648
17742
|
}
|
|
17649
|
-
await
|
|
17743
|
+
await sleep2(250);
|
|
17650
17744
|
}
|
|
17651
17745
|
async dumpTree(depth = 6) {
|
|
17652
17746
|
const tree = await this.bridge.send({
|
|
@@ -17703,7 +17797,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17703
17797
|
return;
|
|
17704
17798
|
}
|
|
17705
17799
|
await this.swipe(swipeDirection, 250);
|
|
17706
|
-
await
|
|
17800
|
+
await sleep2(500);
|
|
17707
17801
|
}
|
|
17708
17802
|
throw new Error(`scrollUntilVisible: "${opts.element}" not found`);
|
|
17709
17803
|
}
|
|
@@ -17717,7 +17811,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17717
17811
|
typeof opts.notVisible === "string" ? { text: opts.notVisible } : opts.notVisible
|
|
17718
17812
|
) : true;
|
|
17719
17813
|
if (visibleOkay && notVisibleOkay) return;
|
|
17720
|
-
await
|
|
17814
|
+
await sleep2(200);
|
|
17721
17815
|
}
|
|
17722
17816
|
throw new Error("extendedWaitUntil timed out");
|
|
17723
17817
|
}
|
|
@@ -17744,7 +17838,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17744
17838
|
PER_ATTEMPT_MS
|
|
17745
17839
|
);
|
|
17746
17840
|
} catch {
|
|
17747
|
-
await
|
|
17841
|
+
await sleep2(1e3);
|
|
17748
17842
|
}
|
|
17749
17843
|
}
|
|
17750
17844
|
if (!cleared) {
|
|
@@ -17755,17 +17849,54 @@ var init_bridge_flow_runner = __esm({
|
|
|
17755
17849
|
}
|
|
17756
17850
|
await this.evaluate("window.location.reload()").catch(() => {
|
|
17757
17851
|
});
|
|
17758
|
-
await
|
|
17852
|
+
await sleep2(500);
|
|
17759
17853
|
await this.refreshSimId();
|
|
17760
17854
|
}
|
|
17855
|
+
async softReloadGuestApp(resetStorage) {
|
|
17856
|
+
const reloaded = await this.evaluate(
|
|
17857
|
+
resetGuestAppStateEval(resetStorage),
|
|
17858
|
+
12e4
|
|
17859
|
+
);
|
|
17860
|
+
if (!reloaded) {
|
|
17861
|
+
throw new Error("guest app soft reload bridge unavailable");
|
|
17862
|
+
}
|
|
17863
|
+
}
|
|
17864
|
+
async rearmCaptureAfterRuntimeReload() {
|
|
17865
|
+
if (!this.recordingEnabled && !this.profilingEnabled) return;
|
|
17866
|
+
const deadline = Date.now() + 1e4;
|
|
17867
|
+
let lastError = null;
|
|
17868
|
+
while (Date.now() < deadline) {
|
|
17869
|
+
await this.refreshSimId();
|
|
17870
|
+
try {
|
|
17871
|
+
if (this.recordingEnabled) await this.ensureRecordingStarted();
|
|
17872
|
+
if (this.profilingEnabled) await this.startProfile();
|
|
17873
|
+
return;
|
|
17874
|
+
} catch (err) {
|
|
17875
|
+
lastError = err;
|
|
17876
|
+
await sleep2(250);
|
|
17877
|
+
}
|
|
17878
|
+
}
|
|
17879
|
+
throw new Error(
|
|
17880
|
+
`capture re-arm failed after app reload: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
17881
|
+
);
|
|
17882
|
+
}
|
|
17761
17883
|
async launchApp(opts) {
|
|
17762
17884
|
await this.refreshSimId();
|
|
17763
17885
|
if (opts && typeof opts === "object" && opts.arguments) {
|
|
17764
17886
|
console.log("[flow] launchApp.arguments ignored (sootsim has no native process)");
|
|
17765
17887
|
}
|
|
17766
17888
|
const wantsClear = !!(opts && typeof opts === "object" && opts.clearState);
|
|
17889
|
+
const wantsResetRuntime = readBooleanKey(opts, "resetRuntime");
|
|
17767
17890
|
if (!this.firstLaunchDone && !wantsClear) {
|
|
17768
17891
|
this.firstLaunchDone = true;
|
|
17892
|
+
if (wantsResetRuntime) {
|
|
17893
|
+
if (this.recordingEnabled) await this.ensureRecordingStarted();
|
|
17894
|
+
await this.softReloadGuestApp(false);
|
|
17895
|
+
await this.launchShellAppFromHomeIfNeeded(opts);
|
|
17896
|
+
await this.waitForTree(12e4);
|
|
17897
|
+
} else {
|
|
17898
|
+
await this.launchShellAppFromHomeIfNeeded(opts);
|
|
17899
|
+
}
|
|
17769
17900
|
await this.waitForTree(3e4);
|
|
17770
17901
|
} else {
|
|
17771
17902
|
this.firstLaunchDone = true;
|
|
@@ -17802,7 +17933,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17802
17933
|
})`);
|
|
17803
17934
|
this.markVisualSettled();
|
|
17804
17935
|
} catch {
|
|
17805
|
-
await
|
|
17936
|
+
await sleep2(180);
|
|
17806
17937
|
this.markVisualSettled();
|
|
17807
17938
|
}
|
|
17808
17939
|
}
|
|
@@ -17812,6 +17943,45 @@ var init_bridge_flow_runner = __esm({
|
|
|
17812
17943
|
hasFreshVisualSettle() {
|
|
17813
17944
|
return Date.now() - this.lastVisualSettledAtMs < 750;
|
|
17814
17945
|
}
|
|
17946
|
+
resolveShellLaunchAppId(opts, state) {
|
|
17947
|
+
if (typeof opts === "string" && opts.length > 0) return opts;
|
|
17948
|
+
if (isObjectRecord(opts)) {
|
|
17949
|
+
const explicit = readStringKey(opts, "appId") || readStringKey(opts, "id");
|
|
17950
|
+
if (explicit) return explicit;
|
|
17951
|
+
}
|
|
17952
|
+
return readRecentShellAppId(state) || "connect";
|
|
17953
|
+
}
|
|
17954
|
+
async waitForShellAppLaunched(appId, timeoutMs) {
|
|
17955
|
+
const deadline = Date.now() + timeoutMs;
|
|
17956
|
+
let lastState = null;
|
|
17957
|
+
while (Date.now() < deadline) {
|
|
17958
|
+
try {
|
|
17959
|
+
lastState = await getShellState(this.bridge);
|
|
17960
|
+
} catch {
|
|
17961
|
+
lastState = null;
|
|
17962
|
+
}
|
|
17963
|
+
if (lastState?.state === "app" && lastState.activeApp === appId && lastState.showSwitcher === false && typeof lastState.launchProgress === "number" && lastState.launchProgress >= 0.98) {
|
|
17964
|
+
return;
|
|
17965
|
+
}
|
|
17966
|
+
await sleep2(16);
|
|
17967
|
+
}
|
|
17968
|
+
}
|
|
17969
|
+
async launchShellAppFromHomeIfNeeded(opts) {
|
|
17970
|
+
let state = null;
|
|
17971
|
+
try {
|
|
17972
|
+
state = await getShellState(this.bridge);
|
|
17973
|
+
} catch {
|
|
17974
|
+
return false;
|
|
17975
|
+
}
|
|
17976
|
+
if (state?.state !== "home" || state.activeApp != null) return false;
|
|
17977
|
+
const appId = this.resolveShellLaunchAppId(opts, state);
|
|
17978
|
+
if (this.recordingEnabled) {
|
|
17979
|
+
await this.ensureRecordingStarted();
|
|
17980
|
+
}
|
|
17981
|
+
await callShellCommandWhenReady(this.bridge, "launchApp", 1e3, appId);
|
|
17982
|
+
await this.waitForShellAppLaunched(appId, 1e3);
|
|
17983
|
+
return true;
|
|
17984
|
+
}
|
|
17815
17985
|
async startProfile() {
|
|
17816
17986
|
await this.evaluate(`((sessionKey) => {
|
|
17817
17987
|
const perf = window.__sootsimPerf
|
|
@@ -17914,18 +18084,19 @@ var init_bridge_flow_runner = __esm({
|
|
|
17914
18084
|
}
|
|
17915
18085
|
return result;
|
|
17916
18086
|
}
|
|
17917
|
-
// maestro stopApp: tear down current app runtime
|
|
17918
|
-
//
|
|
17919
|
-
//
|
|
17920
|
-
//
|
|
17921
|
-
// engine's own bundle chunks, and wiping them 404s the next heavy reload.)
|
|
18087
|
+
// maestro stopApp: tear down the current app runtime without clearing app
|
|
18088
|
+
// data. sootsim has no separate native process, so a hard page reload is the
|
|
18089
|
+
// nearest equivalent to killing and later re-launching the tenant runtime.
|
|
18090
|
+
// State clearing belongs to clearState / launchApp({ clearState: true }).
|
|
17922
18091
|
async stopApp() {
|
|
17923
|
-
await this.reloadGuestApp(
|
|
18092
|
+
await this.reloadGuestApp(false);
|
|
18093
|
+
await this.rearmCaptureAfterRuntimeReload();
|
|
17924
18094
|
}
|
|
17925
18095
|
// maestro clearState: wipe app-owned storage and relaunch fresh. routes
|
|
17926
18096
|
// through the same engine soft-reload launchApp uses under `clearState: true`.
|
|
17927
18097
|
async clearState() {
|
|
17928
18098
|
await this.reloadGuestApp(true);
|
|
18099
|
+
await this.rearmCaptureAfterRuntimeReload();
|
|
17929
18100
|
}
|
|
17930
18101
|
// maestro clearKeychain: there is no real keychain in sootsim's browser
|
|
17931
18102
|
// sandbox. log loudly so the author notices, then continue — matching the
|
|
@@ -17990,7 +18161,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
17990
18161
|
if (!result?.ok) {
|
|
17991
18162
|
throw new Error(`openLink failed: ${result?.error || "no test bridge"}`);
|
|
17992
18163
|
}
|
|
17993
|
-
await
|
|
18164
|
+
await sleep2(300);
|
|
17994
18165
|
}
|
|
17995
18166
|
// evaluate a `when:` predicate. returns true if the step should run.
|
|
17996
18167
|
async evaluateWhen(when) {
|
|
@@ -18074,7 +18245,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
18074
18245
|
}
|
|
18075
18246
|
const isAssertion = !!(step.assertVisible || step.assertNotVisible || step.extendedWaitUntil || step.waitFor);
|
|
18076
18247
|
if (this.stepDelay > 0 && !isAssertion) {
|
|
18077
|
-
await
|
|
18248
|
+
await sleep2(this.stepDelay);
|
|
18078
18249
|
}
|
|
18079
18250
|
} catch (error) {
|
|
18080
18251
|
if (this.isOptional(step)) {
|
|
@@ -18131,7 +18302,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
18131
18302
|
} else if (step.launchApp) {
|
|
18132
18303
|
await this.launchApp(step.launchApp);
|
|
18133
18304
|
} else if (typeof step.wait === "number") {
|
|
18134
|
-
await
|
|
18305
|
+
await sleep2(step.wait);
|
|
18135
18306
|
} else if (step.dumpTree) {
|
|
18136
18307
|
await this.dumpTree(step.dumpTree);
|
|
18137
18308
|
} else if (step.tapAtCoords) {
|
|
@@ -18585,7 +18756,7 @@ var skill4 = {
|
|
|
18585
18756
|
};
|
|
18586
18757
|
|
|
18587
18758
|
// src/skills/builtin/test-flow.ts
|
|
18588
|
-
function
|
|
18759
|
+
function sleep3(ms) {
|
|
18589
18760
|
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
18590
18761
|
}
|
|
18591
18762
|
var skill5 = {
|
|
@@ -18631,7 +18802,7 @@ var skill5 = {
|
|
|
18631
18802
|
simId = opened.id;
|
|
18632
18803
|
break;
|
|
18633
18804
|
}
|
|
18634
|
-
await
|
|
18805
|
+
await sleep3(500);
|
|
18635
18806
|
}
|
|
18636
18807
|
if (!simId) {
|
|
18637
18808
|
throw new Error("no sim connected to the bridge host");
|
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.185 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
package/package.json
CHANGED
package/scripts/postinstall.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// postinstall — best-effort runtime install after
|
|
2
|
+
// postinstall — best-effort runtime install after npm/npx fetches sootsim.
|
|
3
3
|
//
|
|
4
4
|
// runs as a child of npm. failures here are non-fatal; setup/open/runtime
|
|
5
5
|
// commands can install the runtime later.
|
package/skills/soot.md
CHANGED
|
@@ -60,7 +60,7 @@ automation, inspecting the render tree, and managing sims.
|
|
|
60
60
|
| `sootsim claim` | take an exclusive lease on a sim |
|
|
61
61
|
| `sootsim agent` | attached projects + local agent sessions (codex/claude) |
|
|
62
62
|
| `sootsim close` | close a connected sim |
|
|
63
|
-
| `sootsim setup` |
|
|
63
|
+
| `sootsim setup` | bootstrap SootSim, then install the global CLI |
|
|
64
64
|
| `sootsim compat` | check package compatibility (alias: scan) |
|
|
65
65
|
| `sootsim electron` | launch the desktop companion |
|
|
66
66
|
| `sootsim daemon` | manage the sootsim bridge as a login agent |
|
|
@@ -104,7 +104,7 @@ skills for working with the SootSim native preview engine:
|
|
|
104
104
|
| skill | description |
|
|
105
105
|
| --- | --- |
|
|
106
106
|
| `/sootsim-debug` | Debug rendering, animation, gesture, performance, and accessibility issues in a React Native app running under sootsim. Reach for this whenever an animation looks wrong (janky, stutters, snaps, only updates once, or doesn't move at all), a swipe/transition/gesture misbehaves or feels broken, scrolling drops frames or feels slow, the UI renders the wrong tree/props, or a screen reader can't reach something — and drive the sootsim CLI debug tooling first, not screenshots or ad-hoc logging. |
|
|
107
|
-
| `/sootsim-setup` | Get sootsim connected to your React Native app — from `
|
|
107
|
+
| `/sootsim-setup` | Get sootsim connected to your React Native app — from `sootsim setup` to a driveable sim |
|
|
108
108
|
| `/sootsim-test` | Run automated tests against your React Native app under sootsim — native YAML flows, Maestro drop-in, or Detox drop-in |
|
|
109
109
|
| `/sootsim-visual` | Pixel-level rendering comparison between sootsim and native iOS — fonts, gradients, shadows, image fidelity |
|
|
110
110
|
|
package/skills/sootsim-setup.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sootsim-setup
|
|
3
|
-
description: Get sootsim connected to your React Native app — from `
|
|
3
|
+
description: Get sootsim connected to your React Native app — from `sootsim setup` to a driveable sim
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# sootsim setup
|
|
7
7
|
|
|
8
|
-
you
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
you want to drive a React Native app with SootSim from the CLI. this skill
|
|
9
|
+
takes you from `sootsim setup` to a connected, pinned sim that every other
|
|
10
|
+
sootsim skill assumes exists. no per-app SootSim install is required. if
|
|
11
|
+
`sootsim describe` already
|
|
11
12
|
returns a tree, you're past this skill — load `/sootsim-debug` for
|
|
12
13
|
debugging or `/sootsim-test` for writing tests.
|
|
13
14
|
|
|
@@ -26,7 +27,7 @@ debugging or `/sootsim-test` for writing tests.
|
|
|
26
27
|
## first move
|
|
27
28
|
|
|
28
29
|
```sh
|
|
29
|
-
sootsim setup # one-time
|
|
30
|
+
sootsim setup # one-time guided setup; installs daemon
|
|
30
31
|
sootsim open 8081 # load a metro/expo dev server
|
|
31
32
|
sootsim list # confirm exactly one sim is reachable
|
|
32
33
|
sootsim use <id> # pin it for the rest of the workflow
|
|
@@ -38,7 +39,7 @@ the detected dev servers. for hosted or unusual targets, pass the URL
|
|
|
38
39
|
explicitly:
|
|
39
40
|
|
|
40
41
|
```sh
|
|
41
|
-
sootsim open 8081
|
|
42
|
+
sootsim open 8081 # load a metro dev server
|
|
42
43
|
sootsim open https://my-app.local # load a hosted bundle
|
|
43
44
|
```
|
|
44
45
|
|