sootsim 0.1.302 → 0.1.304
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/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-QM5DJK6B.js → agent-EK355OQM.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-HDOQKZ2C.js → agent-wrapper-LCJJWHZE.js} +2 -2
- package/dist-cli/chunks/app-fonts-LIPU2DLT.js +4 -0
- package/dist-cli/chunks/{assert-URPY7JOQ.js → assert-OASKCPBX.js} +2 -2
- package/dist-cli/chunks/{auth-LDIGTG4T.js → auth-XYYKD33F.js} +2 -2
- package/dist-cli/chunks/{beta-7X7SMIUJ.js → beta-TOL55XPM.js} +2 -2
- package/dist-cli/chunks/{camera-44FBN2AD.js → camera-PHKVEQHR.js} +2 -2
- package/dist-cli/chunks/{chunk-47FKMZKZ.js → chunk-2MEUZOSD.js} +1 -1
- package/dist-cli/chunks/{chunk-N53HDXGW.js → chunk-2RLFUM3C.js} +8 -8
- package/dist-cli/chunks/{chunk-YY54A626.js → chunk-3UUHIHA6.js} +2 -2
- package/dist-cli/chunks/{chunk-QNA5RNYZ.js → chunk-5NJTX5OP.js} +2 -2
- package/dist-cli/chunks/{chunk-YY27LKQF.js → chunk-76OLOD2G.js} +2 -2
- package/dist-cli/chunks/{chunk-UEFW7TPW.js → chunk-7RFXZXKH.js} +1 -1
- package/dist-cli/chunks/{chunk-2BQCOQBK.js → chunk-A4UYZTV7.js} +2 -2
- package/dist-cli/chunks/{chunk-T3UJXMFJ.js → chunk-ABHNOM2C.js} +1 -1
- package/dist-cli/chunks/{chunk-PDB5OX3V.js → chunk-AJYA6R3N.js} +2 -2
- package/dist-cli/chunks/{chunk-TWOBAP7S.js → chunk-BJOT2LL6.js} +2 -2
- package/dist-cli/chunks/{chunk-UNDGU5PA.js → chunk-BPRMA4IC.js} +2 -2
- package/dist-cli/chunks/{chunk-QN5DSQNG.js → chunk-CMYVGJBQ.js} +1 -1
- package/dist-cli/chunks/{chunk-ZORZTTQL.js → chunk-ENXLKDQ6.js} +3 -3
- package/dist-cli/chunks/{chunk-WQWYWERD.js → chunk-EXW6TH3O.js} +2 -2
- package/dist-cli/chunks/{chunk-QOS3GSOM.js → chunk-FNI75AD7.js} +1 -1
- package/dist-cli/chunks/{chunk-KNBZZC7R.js → chunk-G4R7CPCY.js} +2 -2
- package/dist-cli/chunks/{chunk-XLAZCK5H.js → chunk-GF3LDVWF.js} +2 -2
- package/dist-cli/chunks/{chunk-ZADSXYX7.js → chunk-GMILMS7P.js} +2 -2
- package/dist-cli/chunks/{chunk-IJKBAKAA.js → chunk-HFA5ZACE.js} +21 -10
- package/dist-cli/chunks/{chunk-XRRW4YFF.js → chunk-HFKQUS4I.js} +3 -3
- package/dist-cli/chunks/{chunk-SMBMOSXY.js → chunk-INBBOCU4.js} +2 -2
- package/dist-cli/chunks/chunk-ITDTSNN2.js +4 -0
- package/dist-cli/chunks/{chunk-ZQLQVJUB.js → chunk-IWRRIQDJ.js} +2 -2
- package/dist-cli/chunks/{chunk-7F57RUPB.js → chunk-JDKWIB6V.js} +1 -1
- package/dist-cli/chunks/{chunk-XKUUILJ2.js → chunk-LRXSLMX4.js} +1 -1
- package/dist-cli/chunks/{chunk-H7J7U34H.js → chunk-M3ETYVNL.js} +1 -1
- package/dist-cli/chunks/{chunk-2AD7UVSQ.js → chunk-MSYPDBFG.js} +2 -2
- package/dist-cli/chunks/{chunk-LLCCT4VC.js → chunk-NXYKNKNL.js} +2 -2
- package/dist-cli/chunks/{chunk-NFC3BJMX.js → chunk-OSH6526H.js} +1 -1
- package/dist-cli/chunks/{chunk-HFHHYL3K.js → chunk-QWQHSUZC.js} +2 -2
- package/dist-cli/chunks/chunk-RJWQ3VAD.js +14 -0
- package/dist-cli/chunks/{chunk-VEOPRCNX.js → chunk-RQJDIDJ3.js} +1 -1
- package/dist-cli/chunks/{chunk-FNJ2IEDC.js → chunk-RT7TUHH7.js} +2 -2
- package/dist-cli/chunks/{chunk-W6XC5TUY.js → chunk-RYQUO6LT.js} +1 -1
- package/dist-cli/chunks/{chunk-N7ATA44P.js → chunk-SN6ARNCL.js} +2 -2
- package/dist-cli/chunks/{chunk-BJDIJYWM.js → chunk-SVFN66PF.js} +2 -2
- package/dist-cli/chunks/{chunk-5CWTAN4D.js → chunk-UB3OWUVK.js} +1 -1
- package/dist-cli/chunks/{chunk-D4BPRTTD.js → chunk-V6JDDX4B.js} +2 -2
- package/dist-cli/chunks/{chunk-RZLCDDE2.js → chunk-VUR5QXVX.js} +2 -2
- package/dist-cli/chunks/{chunk-BVUQ2PVZ.js → chunk-W3CSYOSQ.js} +1 -1
- package/dist-cli/chunks/{chunk-7UIDSSWQ.js → chunk-WNDYTKLC.js} +1 -1
- package/dist-cli/chunks/{chunk-2ELPPBLQ.js → chunk-XCVSB47R.js} +2 -2
- package/dist-cli/chunks/{chunk-C36FJ7OB.js → chunk-XHYSASAX.js} +1 -1
- package/dist-cli/chunks/{chunk-HNYGEEPF.js → chunk-XXS4TCOO.js} +3 -3
- package/dist-cli/chunks/{chunk-OOP74SPV.js → chunk-Y5YM7XHU.js} +1 -1
- package/dist-cli/chunks/{chunk-UJ7P2CWC.js → chunk-YAV6BH3A.js} +2 -2
- package/dist-cli/chunks/{chunk-AHPEOPNQ.js → chunk-YXHO2OUL.js} +1 -1
- package/dist-cli/chunks/chunk-ZDRI2LUG.js +125 -0
- package/dist-cli/chunks/{chunk-REJQMXOG.js → chunk-ZONISYZ5.js} +1 -1
- package/dist-cli/chunks/{cleanup-QTLASIO7.js → cleanup-GCTEGJMP.js} +2 -2
- package/dist-cli/chunks/{cli-version-EUG2MGT7.js → cli-version-G72HUH4E.js} +2 -2
- package/dist-cli/chunks/{compat-DA2Z6HOU.js → compat-IC4JHGBH.js} +2 -2
- package/dist-cli/chunks/{config-U65JAS2W.js → config-C65MZFU3.js} +2 -2
- package/dist-cli/chunks/{control-ZCFRXISU.js → control-RWLYBKQR.js} +2 -2
- package/dist-cli/chunks/daemon-D77E5G6Z.js +4 -0
- package/dist-cli/chunks/{debug-OXP67EDF.js → debug-LEL32PDN.js} +3 -3
- package/dist-cli/chunks/{desktop-ZEQXNFI2.js → desktop-RDSISJH2.js} +3 -3
- package/dist-cli/chunks/{detox-M4JBLH5P.js → detox-SCCWUIKK.js} +2 -2
- package/dist-cli/chunks/{device-ISL5YP5C.js → device-MTDEKDUK.js} +2 -2
- package/dist-cli/chunks/{diagnose-H2TRXSVS.js → diagnose-UZJCKLPZ.js} +2 -2
- package/dist-cli/chunks/disk-cleanup-HLWRVTVW.js +4 -0
- package/dist-cli/chunks/drivers-Q7GMKTBM.js +4 -0
- package/dist-cli/chunks/{film-LKYPZOJD.js → film-YBE544PG.js} +3 -3
- package/dist-cli/chunks/flow-5VOVAVZN.js +4 -0
- package/dist-cli/chunks/help-2PESJ7V2.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-JMWSVMJD.js → hidden-runtime-alias-KJYCJLSR.js} +2 -2
- package/dist-cli/chunks/{home-paths-S66AEW3L.js → home-paths-NSHWNEGK.js} +2 -2
- package/dist-cli/chunks/inspect-OIA3Q5MD.js +4 -0
- package/dist-cli/chunks/install-desktop-7KLACQUW.js +4 -0
- package/dist-cli/chunks/{login-EJEEYZGB.js → login-AEVUU72R.js} +4 -4
- package/dist-cli/chunks/{logout-QCEW2MME.js → logout-72XHF6J2.js} +2 -2
- package/dist-cli/chunks/{maestro-4IKBKIUF.js → maestro-OXSKQJ6B.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-WSYSKMND.js → maestro-generate-AKZFORVJ.js} +3 -3
- package/dist-cli/chunks/{mode-KQ5VDMPP.js → mode-U6KRG2PE.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-MMHEMCBJ.js → optional-demo-registry-L3VIWBI2.js} +2 -2
- package/dist-cli/chunks/{perf-LGZDBRUM.js → perf-KF2BJZIN.js} +2 -2
- package/dist-cli/chunks/{permissions-DA4JXY2N.js → permissions-TRJG4QAI.js} +2 -2
- package/dist-cli/chunks/{record-TPU2TOEU.js → record-TICJYZOA.js} +3 -3
- package/dist-cli/chunks/{report-issue-PPUNSEEQ.js → report-issue-OQPLBQMJ.js} +2 -2
- package/dist-cli/chunks/runtime-HDMLWNXW.js +4 -0
- package/dist-cli/chunks/screenshot-command-XLERKHVW.js +159 -0
- package/dist-cli/chunks/{screenshots-capture-AG2TIYLG.js → screenshots-capture-B6OORSD4.js} +2 -2
- package/dist-cli/chunks/{serve-C3WLV2OX.js → serve-5M7MIPWF.js} +2 -2
- package/dist-cli/chunks/{setup-4KZKLDZV.js → setup-HJZDC4PK.js} +2 -2
- package/dist-cli/chunks/{skills-65XCNSNM.js → skills-RXHLMGGL.js} +2 -2
- package/dist-cli/chunks/{storage-ADWG4UT7.js → storage-MMPD2XBS.js} +2 -2
- package/dist-cli/chunks/store-APKY72ZY.js +4 -0
- package/dist-cli/chunks/telemetry-W3YRHE67.js +4 -0
- package/dist-cli/chunks/{timeline-BRHYLQTW.js → timeline-6PF5BZ37.js} +2 -2
- package/dist-cli/chunks/{upgrade-AEJNAP6O.js → upgrade-QSMIK3RC.js} +2 -2
- package/dist-cli/chunks/upload-HQEOYILQ.js +4 -0
- package/dist-cli/chunks/{version-HZWBK4KJ.js → version-WLTFXEDC.js} +2 -2
- package/dist-cli/chunks/{web-LCSSJCZ4.js → web-DI73LQ7N.js} +2 -2
- package/dist-cli/chunks/{what-happened-GWA24LHG.js → what-happened-4SAMGZWR.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.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 +17 -8
- 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 +58 -3
- package/dist-lib/sdk.cjs +18 -6
- package/dist-lib/sdk.mjs +18 -6
- package/dist-lib/skills.cjs +26 -12
- package/dist-lib/vite.cjs +1 -1
- package/package.json +2 -2
- package/scripts/dev-server-scanner.ts +95 -9
- package/skills/sootsim-debug/SKILL.md +6 -0
- package/skills/sootsim-setup/SKILL.md +38 -0
- package/src/attached-projects.ts +2 -2
- package/src/host/bridge-host.ts +2 -2
- package/src/runtime-assets.ts +1 -1
- package/src/runtime-delivery.ts +1 -1
- package/src/vite-plugin.ts +1 -1
- package/dist-cli/chunks/app-fonts-VPJDIM5M.js +0 -4
- package/dist-cli/chunks/chunk-5TWYZNIF.js +0 -125
- package/dist-cli/chunks/chunk-GRMK3BZY.js +0 -4
- package/dist-cli/chunks/chunk-I4NP3TJR.js +0 -12
- package/dist-cli/chunks/daemon-S25HJFIG.js +0 -4
- package/dist-cli/chunks/disk-cleanup-DY6JAHH3.js +0 -4
- package/dist-cli/chunks/drivers-EE4LTPSZ.js +0 -4
- package/dist-cli/chunks/flow-WGICJ5KS.js +0 -4
- package/dist-cli/chunks/help-YQ63GAW6.js +0 -4
- package/dist-cli/chunks/inspect-VKVWW64M.js +0 -4
- package/dist-cli/chunks/install-desktop-CH27FTQI.js +0 -4
- package/dist-cli/chunks/runtime-7MZZR6SC.js +0 -4
- package/dist-cli/chunks/screenshot-command-2YSWGL4X.js +0 -156
- package/dist-cli/chunks/store-FEQIGIYH.js +0 -4
- package/dist-cli/chunks/telemetry-KBOJKIRS.js +0 -4
- package/dist-cli/chunks/upload-QKJRNNL3.js +0 -4
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// pid changes. before any HTTP, a TCP connect gate skips unreachable ports.
|
|
15
15
|
|
|
16
16
|
import { exec } from 'child_process'
|
|
17
|
+
import { readlink } from 'fs/promises'
|
|
17
18
|
import http from 'http'
|
|
18
19
|
import net from 'net'
|
|
19
20
|
import { promisify } from 'util'
|
|
@@ -222,27 +223,112 @@ export async function discoverListeningPorts(
|
|
|
222
223
|
return processes.map((p) => p.port)
|
|
223
224
|
}
|
|
224
225
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
/** parse `netstat -anv -p tcp` output for the pid listening on one port.
|
|
227
|
+
*
|
|
228
|
+
* macOS lays a LISTEN row out as
|
|
229
|
+
* tcp4 0 0 127.0.0.1.8090 *.* LISTEN 0 0 131072 131072 node:97330 ...
|
|
230
|
+
* so the local address is the 4th column with a DOT before the port (which is
|
|
231
|
+
* what keeps port 8137 from matching a row for 18137), and the owner is the
|
|
232
|
+
* only token shaped "<name>:<pid>".
|
|
233
|
+
*
|
|
234
|
+
* exported because this column layout is the fragile part and a child process
|
|
235
|
+
* cannot exercise it under bun's test runner, which hands back empty stdout. */
|
|
236
|
+
export function pidFromNetstat(stdout: string, port: number): number | null {
|
|
237
|
+
for (const line of stdout.split('\n')) {
|
|
238
|
+
if (!line.includes('LISTEN')) continue
|
|
239
|
+
const parts = line.trim().split(/\s+/)
|
|
240
|
+
if (!parts[3]?.endsWith(`.${port}`)) continue
|
|
241
|
+
for (const token of parts) {
|
|
242
|
+
const owner = token.match(/^\S+:(\d+)$/)
|
|
243
|
+
if (owner) {
|
|
244
|
+
const pid = Number(owner[1])
|
|
245
|
+
if (pid > 0) return pid
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return null
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** resolve the pid of the process listening on one local port.
|
|
253
|
+
*
|
|
254
|
+
* `lsof` walks every descriptor of every process, which measures 2-4s on a
|
|
255
|
+
* loaded machine — longer than any timeout worth giving it, so
|
|
256
|
+
* `discoverListeningProcesses` above degrades to its pid-less port list
|
|
257
|
+
* exactly when the machine is busy. netstat (macOS/BSD) and ss (linux) read
|
|
258
|
+
* the kernel socket table instead and answer in well under a second, and both
|
|
259
|
+
* carry the owning pid. use this whenever the question is "who owns this one
|
|
260
|
+
* port"; `discoverListeningProcesses` answers the different question of what
|
|
261
|
+
* is listening at all. */
|
|
262
|
+
export async function resolveListeningPid(port: number): Promise<number | null> {
|
|
263
|
+
if (!Number.isInteger(port) || port <= 0) return null
|
|
264
|
+
|
|
265
|
+
// macOS netstat: "tcp4 0 0 127.0.0.1.8090 *.* LISTEN ... node:97330 ..."
|
|
266
|
+
// the local address uses a dot before the port, and the owner column is the
|
|
267
|
+
// only token shaped "<name>:<pid>".
|
|
268
|
+
try {
|
|
269
|
+
const { stdout } = await execP('netstat -anv -p tcp 2>/dev/null', {
|
|
270
|
+
encoding: 'utf8',
|
|
271
|
+
timeout: 8000,
|
|
272
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
273
|
+
})
|
|
274
|
+
const pid = pidFromNetstat(stdout, port)
|
|
275
|
+
if (pid !== null) return pid
|
|
276
|
+
} catch {}
|
|
277
|
+
|
|
278
|
+
// linux ss: 'LISTEN 0 511 0.0.0.0:8081 0.0.0.0:* users:(("node",pid=1234,fd=5))'
|
|
279
|
+
try {
|
|
280
|
+
const { stdout } = await execP(`ss -tlnp 2>/dev/null`, {
|
|
281
|
+
encoding: 'utf8',
|
|
282
|
+
timeout: 8000,
|
|
283
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
284
|
+
})
|
|
285
|
+
for (const line of stdout.split('\n')) {
|
|
286
|
+
if (!new RegExp(`:${port}\\s`).test(line)) continue
|
|
287
|
+
const pid = Number(line.match(/pid=(\d+)/)?.[1])
|
|
288
|
+
if (pid > 0) return pid
|
|
289
|
+
}
|
|
290
|
+
} catch {}
|
|
291
|
+
|
|
292
|
+
return null
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// per-pid cwd cache. lsof is the only way to read another process's cwd on
|
|
296
|
+
// macOS and it is NOT cheap — measured at 3-8s for a single pid on a machine
|
|
297
|
+
// running a few dozen node processes — so caching the result until the pid
|
|
298
|
+
// goes away is what keeps the 5s tray scan viable.
|
|
228
299
|
const cwdByPid = new Map<number, string>()
|
|
229
300
|
|
|
230
|
-
/** resolve the current working directory of a pid
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
301
|
+
/** resolve the current working directory of a pid. returns null for pid 0
|
|
302
|
+
* (unknown owner) and whenever neither mechanism below can see the process.
|
|
303
|
+
* async — sync exec blocked CrBrowserMain at ~600ms on macOS.
|
|
304
|
+
*
|
|
305
|
+
* `-b -w` skips the blocking stat calls lsof otherwise makes against every
|
|
306
|
+
* mount, which roughly halves it. the timeout is generous because the answer
|
|
307
|
+
* is cached per pid: too tight a limit silently returns null on exactly the
|
|
308
|
+
* busy machines where auto-attaching a project matters most. */
|
|
234
309
|
export async function resolveProcessCwd(pid: number): Promise<string | null> {
|
|
235
310
|
if (pid <= 0) return null
|
|
236
311
|
const cached = cwdByPid.get(pid)
|
|
237
312
|
if (cached) return cached
|
|
313
|
+
|
|
314
|
+
// linux publishes the cwd as a symlink, which costs one readlink and no
|
|
315
|
+
// subprocess at all. macOS has no /proc and has to pay for lsof below.
|
|
316
|
+
try {
|
|
317
|
+
const cwd = await readlink(`/proc/${pid}/cwd`)
|
|
318
|
+
if (cwd) {
|
|
319
|
+
cwdByPid.set(pid, cwd)
|
|
320
|
+
return cwd
|
|
321
|
+
}
|
|
322
|
+
} catch {}
|
|
323
|
+
|
|
238
324
|
try {
|
|
239
325
|
// -Fn → machine-readable, one field per line. lines look like:
|
|
240
326
|
// p<pid>
|
|
241
327
|
// fcwd
|
|
242
328
|
// n<absolute path>
|
|
243
|
-
const { stdout } = await execP(`lsof -p ${pid} -a -d cwd -Fn 2>/dev/null`, {
|
|
329
|
+
const { stdout } = await execP(`lsof -b -w -p ${pid} -a -d cwd -Fn 2>/dev/null`, {
|
|
244
330
|
encoding: 'utf8',
|
|
245
|
-
timeout:
|
|
331
|
+
timeout: 8000,
|
|
246
332
|
})
|
|
247
333
|
for (const line of stdout.split('\n')) {
|
|
248
334
|
if (line.startsWith('n') && line.length > 1) {
|
|
@@ -63,6 +63,12 @@ regression test. a pile of ad-hoc logs helps no one and gets deleted.
|
|
|
63
63
|
query against it.
|
|
64
64
|
- **pin a sim once.** if more than one is live, an unpinned command
|
|
65
65
|
refuses to choose. run `sootsim use <id>` at the start of the workflow.
|
|
66
|
+
- **keep one sim and reuse its browser tab.** before `sootsim open`, run
|
|
67
|
+
`sootsim list --all`. if the target is already connected, pin it and use
|
|
68
|
+
`sootsim do reload`; do not open another tab to reload or retry a capture.
|
|
69
|
+
re-run `list --all` after each reload or reconnect; when another entry appears,
|
|
70
|
+
run `sootsim close --others` against the pinned sim immediately.
|
|
71
|
+
if the current sim must be replaced, close it before opening the replacement.
|
|
66
72
|
- **`debug eval` is an escape hatch.** if a top-level command feels
|
|
67
73
|
broken or missing, file an issue — every agent after you benefits from
|
|
68
74
|
a better CLI, not a pile of ad-hoc scripts.
|
|
@@ -23,6 +23,44 @@ debugging or `/sootsim-test` for writing tests.
|
|
|
23
23
|
- **an empty `sootsim list` is not "broken sootsim"** — it usually means the
|
|
24
24
|
daemon is down, the dev server port is wrong, or the runtime is missing.
|
|
25
25
|
walk the recovery checklist before reinstalling.
|
|
26
|
+
- **one sim for your whole session. switch APPS by navigating that sim, never by
|
|
27
|
+
opening another.** `sootsim open <port> --sim <id>` resolves that exact sim and
|
|
28
|
+
navigates it in place — no new tab, no new browser tree. that is the supported
|
|
29
|
+
way to move between apps and ports:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
sootsim open 8086 --sim <id> # one app, in your sim
|
|
33
|
+
sootsim open 8090 --sim <id> # a different app, same tab
|
|
34
|
+
sootsim reload --sim <id> # reload whatever it is showing
|
|
35
|
+
sootsim close <id> # dispose it when you are done
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
every `--new` spawns another browser tree, and each abandoned tab holds a
|
|
39
|
+
renderer process for the life of the browser. these land in somebody's actual
|
|
40
|
+
desktop Chrome. a run that opened one per app left 14 renderers against 2 live
|
|
41
|
+
sims on a shared machine and the owner noticed before we did.
|
|
42
|
+
- **sharing a machine with other agents? open ONE sim with `--new`, pin it, and
|
|
43
|
+
pass `--sim <id>` from then on.** that single `--new` is the only one you get.
|
|
44
|
+
an unpinned command has no sim of its own, so it falls back to whatever sim is
|
|
45
|
+
currently PRIMARY — and that can be another agent's live sim, mid-run. a plain
|
|
46
|
+
`sootsim open <port>` from an unpinned CLI will happily retarget somebody
|
|
47
|
+
else's sim to your port and take over their session; the warning it prints is
|
|
48
|
+
easy to miss in a transcript. the current-sim pin is stored per CLI identity
|
|
49
|
+
(`sootsim-current-sim-<identity>.json`, keyed by your process-tree root), so
|
|
50
|
+
pinning is genuinely per-agent and does not fight anyone else:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
sootsim open --new 8086 # your own sim; also records it as yours
|
|
54
|
+
sootsim list # read back its id
|
|
55
|
+
sootsim use <id> # pin it explicitly
|
|
56
|
+
sootsim describe --sim <id> # name it on every command after that
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`--new`, `--profile`, and `--ephemeral` are rejected outright when combined
|
|
60
|
+
with `--sim`, so if a command needs one of them you are starting a second sim
|
|
61
|
+
whether you meant to or not. if yours died, run `sootsim list --all` and adopt
|
|
62
|
+
an open unlocked sim with `sootsim use <id>` before you consider opening one.
|
|
63
|
+
always close yours when you finish.
|
|
26
64
|
- **never retry-loop `sootsim open` against a wedged or slow stack.** a
|
|
27
65
|
connect-timeout ("timed out waiting for opened sim to connect") means STOP and
|
|
28
66
|
diagnose — not retry. each retried open spawns a new browser tree (a
|
package/src/attached-projects.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { randomBytes, createHash } from 'node:crypto'
|
|
11
11
|
import fs from 'node:fs'
|
|
12
12
|
import path from 'node:path'
|
|
13
|
-
import { electronUserDataDir } from './home-paths'
|
|
13
|
+
import { electronUserDataDir } from './home-paths.ts'
|
|
14
14
|
|
|
15
15
|
// plan → attached-projects-and-agents.md §data model
|
|
16
16
|
export interface AttachedProject {
|
|
@@ -510,7 +510,7 @@ export async function seedFromDemoAppRegistry(): Promise<void> {
|
|
|
510
510
|
// optional internal-only registry — resolves to [] on a published install
|
|
511
511
|
// (the registry is not shipped), so this seed is a no-op for real users and
|
|
512
512
|
// never pins their ports to internal demo apps.
|
|
513
|
-
const { loadOptionalDemoApps } = await import('../scripts/optional-demo-registry')
|
|
513
|
+
const { loadOptionalDemoApps } = await import('../scripts/optional-demo-registry.ts')
|
|
514
514
|
const apps = await loadOptionalDemoApps()
|
|
515
515
|
if (apps.length === 0) return
|
|
516
516
|
mutateStore((store) => {
|
package/src/host/bridge-host.ts
CHANGED
|
@@ -44,9 +44,9 @@ import {
|
|
|
44
44
|
handleFetchProxyRequest,
|
|
45
45
|
isAppApiRequestUrl,
|
|
46
46
|
isFetchProxyRequestUrl,
|
|
47
|
-
} from './fetch-proxy-handler'
|
|
47
|
+
} from './fetch-proxy-handler.ts'
|
|
48
48
|
import { openUrl as openUrlInBrowser, type OpenUrlOptions } from './open-url.ts'
|
|
49
|
-
import { handleWebSocketProxyUpgrade } from './websocket-proxy'
|
|
49
|
+
import { handleWebSocketProxyUpgrade } from './websocket-proxy.ts'
|
|
50
50
|
|
|
51
51
|
const SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY = 'require-corp'
|
|
52
52
|
|
package/src/runtime-assets.ts
CHANGED
|
@@ -6,7 +6,7 @@ import fs from 'fs'
|
|
|
6
6
|
import path from 'path'
|
|
7
7
|
import { fileURLToPath } from 'url'
|
|
8
8
|
import { isValidRuntimeVersion } from '@contrast/runtime-delivery'
|
|
9
|
-
import { readActiveRuntime, runtimeDir } from './home-paths'
|
|
9
|
+
import { readActiveRuntime, runtimeDir } from './home-paths.ts'
|
|
10
10
|
|
|
11
11
|
export const SOOTSIM_RUNTIME_MISSING_MESSAGE =
|
|
12
12
|
'[sootsim] no engine runtime installed — run `sootsim setup`, or `sootsim runtime install`'
|
package/src/runtime-delivery.ts
CHANGED
package/src/vite-plugin.ts
CHANGED
|
@@ -661,7 +661,7 @@ export function reanimatedNativeSeamRedirect(): Plugin {
|
|
|
661
661
|
// the reanimated plugin above stays separate because it has package-specific
|
|
662
662
|
// edge cases (fabricUtils, validate-worklets-version). new migrations should
|
|
663
663
|
// use the manifest path unless they need similar special handling.
|
|
664
|
-
import { NATIVE_SEAM_MANIFEST } from './native-seam-manifest'
|
|
664
|
+
import { NATIVE_SEAM_MANIFEST } from './native-seam-manifest.ts'
|
|
665
665
|
export function manifestNativeSeamRedirect(): Plugin {
|
|
666
666
|
// build a fast lookup: pkg → { basenames, target }
|
|
667
667
|
const byPkg = new Map<
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.302 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
-
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
-
import{d as p}from"./chunk-GRMK3BZY.js";import"./chunk-VEOPRCNX.js";import"./chunk-C36FJ7OB.js";import{existsSync as h,mkdirSync as d,readFileSync as y,writeFileSync as g}from"node:fs";import{join as m}from"node:path";import{gzipSync as w}from"node:zlib";function f(t,e){let o=t.indexOf(`--${e}`);if(o!==-1&&o+1<t.length)return t[o+1];let i=t.find(r=>r.startsWith(`--${e}=`));return i?i.slice(e.length+3):void 0}async function S(t){let e=f(t,"wire")||"",o=f(t,"out-dir"),i=f(t,"manifest");if((!o||!i)&&(console.error(" usage: sootsim app-fonts stage --wire <wire> --out-dir <dir> --manifest <path>"),process.exit(1)),!e.trim()){console.log("no app fonts declared \u2014 nothing to stage");return}d(o,{recursive:!0});let r=await p(e,{onStaged:({url:n,byteLength:s})=>console.log(` staged app font: ${n} (${(s/1024).toFixed(1)} KiB)`),onError:(n,s)=>console.error(` warning: failed to fetch app font ${n}: ${s instanceof Error?s.message:s}`)}),a=[];for(let n of r){let s=w(n.bytes);g(m(o,n.urlhash),s),a.push({url:n.url,urlhash:n.urlhash,contentType:n.contentType,encoding:"gzip",sizeBytes:s.length,rawBytes:n.bytes.byteLength})}let c=[];if(h(i))try{let n=JSON.parse(y(i,"utf8"));Array.isArray(n)&&(c=n)}catch{}let u=new Set(c.map(n=>n.urlhash)),l=[...c,...a.filter(n=>!u.has(n.urlhash))];g(i,JSON.stringify(l)),console.log(`staged ${a.length} app font(s); manifest now has ${l.length} file(s)`)}async function E(t){let e=t[0];if(e==="stage"){await S(t.slice(1));return}console.error(` unknown app-fonts subcommand: ${e??"(none)"}`),console.error(" available: stage"),process.exit(1)}export{E as runAppFonts};
|