sootsim 0.1.146 → 0.1.148

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.
Files changed (151) hide show
  1. package/dist-cli/bin.js +3 -3
  2. package/dist-cli/chunks/{agent-PNNXV6F3.js → agent-A5AQOHSI.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-JTYAONCG.js → agent-wrapper-S6AUOIXU.js} +2 -2
  4. package/dist-cli/chunks/{app-fonts-YGTRUUJT.js → app-fonts-MQDZ55OI.js} +2 -2
  5. package/dist-cli/chunks/{assert-HDFDQLHK.js → assert-USJNKN7R.js} +2 -2
  6. package/dist-cli/chunks/auto-bootstrap-CKH5ZZSJ.js +2 -0
  7. package/dist-cli/chunks/beta-Q6IKT5HT.js +2 -0
  8. package/dist-cli/chunks/{camera-4B7OAHRD.js → camera-C4SKSA76.js} +2 -2
  9. package/dist-cli/chunks/{chunk-H2EIYIRP.js → chunk-23QZQBTT.js} +1 -1
  10. package/dist-cli/chunks/{chunk-XO4VQYFP.js → chunk-2B26APLC.js} +2 -2
  11. package/dist-cli/chunks/{chunk-ERAE4LJT.js → chunk-2GROEF3J.js} +3 -3
  12. package/dist-cli/chunks/{chunk-K6X7LUFG.js → chunk-2OJ53PGA.js} +1 -1
  13. package/dist-cli/chunks/{chunk-PCW4TKI2.js → chunk-2SDVI2JB.js} +2 -2
  14. package/dist-cli/chunks/{chunk-C44OZFHJ.js → chunk-474QHKFY.js} +2 -2
  15. package/dist-cli/chunks/{chunk-YBSNSFBX.js → chunk-4JVDEEJJ.js} +1 -1
  16. package/dist-cli/chunks/{chunk-HWB7DPXH.js → chunk-4T5Q2CUU.js} +1 -1
  17. package/dist-cli/chunks/{chunk-DP5FSZHW.js → chunk-7EBPIOTW.js} +1 -1
  18. package/dist-cli/chunks/{chunk-HZHZY7N5.js → chunk-A57WJDB2.js} +2 -2
  19. package/dist-cli/chunks/{chunk-IAO27BWC.js → chunk-AXLTLDHE.js} +2 -2
  20. package/dist-cli/chunks/{chunk-4KNMAGC4.js → chunk-BCRYE4YH.js} +1 -1
  21. package/dist-cli/chunks/{chunk-A7JX3OQC.js → chunk-BCWW5RSQ.js} +1 -1
  22. package/dist-cli/chunks/{chunk-XRQDMB2J.js → chunk-BDKC2GLL.js} +2 -2
  23. package/dist-cli/chunks/{chunk-GD473DHN.js → chunk-BWE6H36P.js} +2 -2
  24. package/dist-cli/chunks/{chunk-AOPFT3S4.js → chunk-CKOXSYJ6.js} +1 -1
  25. package/dist-cli/chunks/{chunk-WFXLVOUA.js → chunk-CN3ACF52.js} +2 -2
  26. package/dist-cli/chunks/{chunk-IADMCPLZ.js → chunk-F3MFOV7R.js} +1 -1
  27. package/dist-cli/chunks/{chunk-2PYDOYIS.js → chunk-G5BKDQGP.js} +1 -1
  28. package/dist-cli/chunks/{chunk-ATJRNMNA.js → chunk-GXHVONDU.js} +2 -2
  29. package/dist-cli/chunks/{chunk-JFQXWAWN.js → chunk-IQVOFR7U.js} +2 -2
  30. package/dist-cli/chunks/{chunk-G7JMTSF6.js → chunk-IYRFX6KX.js} +1 -1
  31. package/dist-cli/chunks/chunk-JQFOV34Q.js +1 -0
  32. package/dist-cli/chunks/{chunk-TZXKFPBJ.js → chunk-K4QZ6WX6.js} +2 -2
  33. package/dist-cli/chunks/{chunk-UD4SYXDQ.js → chunk-KZ6AQHHA.js} +2 -2
  34. package/dist-cli/chunks/{chunk-RTD4RNZV.js → chunk-NK6RKGX2.js} +1 -1
  35. package/dist-cli/chunks/{chunk-MIIAYBFL.js → chunk-NMN4JPG2.js} +1 -1
  36. package/dist-cli/chunks/{chunk-VZSXOG4N.js → chunk-NOBEILT5.js} +1 -1
  37. package/dist-cli/chunks/{chunk-BBIN2U26.js → chunk-PMM6MNCR.js} +2 -2
  38. package/dist-cli/chunks/chunk-ROADBGFV.js +2 -0
  39. package/dist-cli/chunks/{chunk-MVLNHZMU.js → chunk-S3WEUJM3.js} +2 -2
  40. package/dist-cli/chunks/chunk-SY5JYGZE.js +1 -0
  41. package/dist-cli/chunks/{chunk-JZW2R5D7.js → chunk-T4FJHKU4.js} +2 -2
  42. package/dist-cli/chunks/{chunk-VKKWYLIZ.js → chunk-TWOGFNQ7.js} +1 -1
  43. package/dist-cli/chunks/{chunk-R7CMXY5T.js → chunk-TYHRA7FX.js} +2 -2
  44. package/dist-cli/chunks/{chunk-FK2YXBKR.js → chunk-U2U22DTV.js} +1 -1
  45. package/dist-cli/chunks/{chunk-H6LFGGJW.js → chunk-UK7GX57G.js} +2 -2
  46. package/dist-cli/chunks/chunk-V4EYA5L5.js +1 -0
  47. package/dist-cli/chunks/{chunk-SZNVNYEP.js → chunk-XWUUFV45.js} +2 -2
  48. package/dist-cli/chunks/{chunk-TLFNO2L4.js → chunk-XYFPDYAI.js} +1 -1
  49. package/dist-cli/chunks/{chunk-Q6BHESL2.js → chunk-Y5E53BEN.js} +2 -2
  50. package/dist-cli/chunks/{chunk-BE2ZDRIJ.js → chunk-YONGHIDE.js} +2 -2
  51. package/dist-cli/chunks/{chunk-MSQUL5BU.js → chunk-YXZD545S.js} +3 -3
  52. package/dist-cli/chunks/{chunk-2FYSNCRJ.js → chunk-ZMG6VGYA.js} +2 -2
  53. package/dist-cli/chunks/{chunk-35QJJ4MM.js → chunk-ZNYPWEMX.js} +3 -3
  54. package/dist-cli/chunks/cli-version-5KMLKVRO.js +2 -0
  55. package/dist-cli/chunks/{compat-F4WAO62Y.js → compat-7NMHHJXV.js} +3 -3
  56. package/dist-cli/chunks/{config-WAIORJNJ.js → config-XKL7G2P3.js} +2 -2
  57. package/dist-cli/chunks/{control-M54456XG.js → control-ZGD3NJES.js} +2 -2
  58. package/dist-cli/chunks/{cpu-profile-NNMDXCWI.js → cpu-profile-ITFDFMIJ.js} +2 -2
  59. package/dist-cli/chunks/{daemon-UXSN6QDY.js → daemon-LHFCZTK6.js} +2 -2
  60. package/dist-cli/chunks/{debug-JAQVYKQG.js → debug-C3X2PP3H.js} +3 -3
  61. package/dist-cli/chunks/{detox-QOL7PD62.js → detox-ITXRK6EB.js} +2 -2
  62. package/dist-cli/chunks/{device-WPAQY2ZH.js → device-PBA26VX4.js} +2 -2
  63. package/dist-cli/chunks/{diagnose-FKN4ALSH.js → diagnose-IWYHJJ7K.js} +2 -2
  64. package/dist-cli/chunks/drivers-5B4IZBF3.js +2 -0
  65. package/dist-cli/chunks/{electron-YQKH55P6.js → electron-6NRCOUQ3.js} +3 -3
  66. package/dist-cli/chunks/flow-ITIKFOJJ.js +2 -0
  67. package/dist-cli/chunks/help-A26MVCNK.js +2 -0
  68. package/dist-cli/chunks/{hints-GIJN25JB.js → hints-RBTS7PGP.js} +2 -2
  69. package/dist-cli/chunks/{home-paths-KIR4SAL4.js → home-paths-XKUYGHWD.js} +2 -2
  70. package/dist-cli/chunks/{inspect-YRP3UFG4.js → inspect-7V5RQUJM.js} +3 -3
  71. package/dist-cli/chunks/install-AJ3BWZ2Z.js +2 -0
  72. package/dist-cli/chunks/{install-desktop-INHP4VUQ.js → install-desktop-MD77SEFP.js} +3 -3
  73. package/dist-cli/chunks/{keys-CBKA6IB7.js → keys-LJMI7F3J.js} +2 -2
  74. package/dist-cli/chunks/{launch-JZ463USO.js → launch-RKUIUORR.js} +3 -3
  75. package/dist-cli/chunks/{login-VHP4DNC2.js → login-M7EXKPAT.js} +4 -4
  76. package/dist-cli/chunks/{logout-NRG4U6Z7.js → logout-OVAZMIW5.js} +2 -2
  77. package/dist-cli/chunks/{maestro-KPNXHCFR.js → maestro-S4RQPFHB.js} +2 -2
  78. package/dist-cli/chunks/optional-demo-registry-DA3SDA2G.js +2 -0
  79. package/dist-cli/chunks/{preview-O44G7W2U.js → preview-QSIZ6KNZ.js} +2 -2
  80. package/dist-cli/chunks/{profile-RMYP6I2J.js → profile-6QQ3G5X7.js} +2 -2
  81. package/dist-cli/chunks/{react-CFUB2U76.js → react-HR7OT4NK.js} +2 -2
  82. package/dist-cli/chunks/{record-YSLIYV2X.js → record-ZRSPOPCY.js} +2 -2
  83. package/dist-cli/chunks/runtime-X5RH4ZUA.js +2 -0
  84. package/dist-cli/chunks/{runtime-delivery-DDUSKKTU.js → runtime-delivery-MFVXZGIF.js} +2 -2
  85. package/dist-cli/chunks/{screenshot-MH7JQVO7.js → screenshot-QNQ4TJ3I.js} +2 -2
  86. package/dist-cli/chunks/{screenshot-mode-JRRQPP37.js → screenshot-mode-27K7PUTV.js} +2 -2
  87. package/dist-cli/chunks/{screenshots-32GEAUAF.js → screenshots-LH7R6LV3.js} +2 -2
  88. package/dist-cli/chunks/{server-ROXPXSIK.js → server-QQRPB6AJ.js} +12 -12
  89. package/dist-cli/chunks/setup-repo-CTPFDKV3.js +2 -0
  90. package/dist-cli/chunks/{skills-T74U4JC7.js → skills-KNFHQD77.js} +2 -2
  91. package/dist-cli/chunks/{slides-OM25OBW3.js → slides-GWMFQQAF.js} +2 -2
  92. package/dist-cli/chunks/{start-NLHWSRC7.js → start-4INDW3QD.js} +4 -4
  93. package/dist-cli/chunks/store-SIN5AXHS.js +2 -0
  94. package/dist-cli/chunks/telemetry-QHL6TKNR.js +2 -0
  95. package/dist-cli/chunks/{test-RYMENNXC.js → test-Q3CEHSD5.js} +3 -3
  96. package/dist-cli/chunks/three-mode-GTKSFFV7.js +58 -0
  97. package/dist-cli/chunks/{timeline-ANKR37NA.js → timeline-NBDNN5SP.js} +2 -2
  98. package/dist-cli/chunks/{upgrade-ZANSK5HX.js → upgrade-UE7B726I.js} +2 -2
  99. package/dist-cli/chunks/upload-UXXFJA3K.js +2 -0
  100. package/dist-cli/chunks/{version-DYXEOGY7.js → version-SS32LC2F.js} +2 -2
  101. package/dist-cli/chunks/{web-LUMZCTLY.js → web-A3EW2IWT.js} +2 -2
  102. package/dist-cli/chunks/{what-happened-SIQGZLHO.js → what-happened-NVKZVCHT.js} +2 -2
  103. package/dist-cli/chunks/{whoami-YI5RAQBT.js → whoami-FWRWWX2E.js} +2 -2
  104. package/dist-lib/agent-daemon-client.cjs +1 -1
  105. package/dist-lib/agent-events.cjs +1 -1
  106. package/dist-lib/agent-sessions.cjs +1 -1
  107. package/dist-lib/attached-projects.cjs +1 -1
  108. package/dist-lib/auth/shared-session.cjs +1 -1
  109. package/dist-lib/backend-origin.cjs +1 -1
  110. package/dist-lib/beta.cjs +1 -1
  111. package/dist-lib/beta.mjs +1 -1
  112. package/dist-lib/bridge-constants.cjs +1 -1
  113. package/dist-lib/cli-constants.cjs +1 -1
  114. package/dist-lib/config.cjs +1 -1
  115. package/dist-lib/detox/index.cjs +1 -1
  116. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  117. package/dist-lib/home-paths.cjs +1 -1
  118. package/dist-lib/host/bridge-host.cjs +62 -3
  119. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  120. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  121. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  122. package/dist-lib/host/websocket-proxy.cjs +1 -1
  123. package/dist-lib/index.cjs +1 -1
  124. package/dist-lib/metro.cjs +1 -1
  125. package/dist-lib/profiles.cjs +1 -1
  126. package/dist-lib/render-mode.cjs +1 -1
  127. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  128. package/dist-lib/sdk.cjs +1 -1
  129. package/dist-lib/sdk.mjs +1 -1
  130. package/dist-lib/skills.cjs +62 -3
  131. package/dist-lib/vite.cjs +1 -1
  132. package/package.json +1 -1
  133. package/src/host/bridge-host.ts +92 -4
  134. package/dist-cli/chunks/auto-bootstrap-S7SSJMD3.js +0 -2
  135. package/dist-cli/chunks/beta-E3MSUPWU.js +0 -2
  136. package/dist-cli/chunks/chunk-3RPHEE3K.js +0 -2
  137. package/dist-cli/chunks/chunk-DRCRPS2N.js +0 -1
  138. package/dist-cli/chunks/chunk-OU42HTKN.js +0 -1
  139. package/dist-cli/chunks/chunk-Y76W7GZV.js +0 -1
  140. package/dist-cli/chunks/cli-version-AJWPSNS4.js +0 -2
  141. package/dist-cli/chunks/drivers-FTOUKVJ5.js +0 -2
  142. package/dist-cli/chunks/flow-EJXOH72E.js +0 -2
  143. package/dist-cli/chunks/help-ID6MSA6T.js +0 -2
  144. package/dist-cli/chunks/install-S4YF4O3O.js +0 -2
  145. package/dist-cli/chunks/optional-demo-registry-VXBG2NEH.js +0 -2
  146. package/dist-cli/chunks/runtime-YVV2FMMD.js +0 -2
  147. package/dist-cli/chunks/setup-repo-E2IJJBCE.js +0 -2
  148. package/dist-cli/chunks/store-EISWHA6H.js +0 -2
  149. package/dist-cli/chunks/telemetry-7AXVZMQT.js +0 -2
  150. package/dist-cli/chunks/three-mode-MK242N4J.js +0 -54
  151. package/dist-cli/chunks/upload-DWWZQMVH.js +0 -2
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{C as T,D as A,E as y,P as _,Q as b,R as S}from"./chunk-DP5FSZHW.js";import{c as N,e as F}from"./chunk-BBIN2U26.js";import{b as k}from"./chunk-YBSNSFBX.js";import"./chunk-FK2YXBKR.js";import"./chunk-IADMCPLZ.js";import"./chunk-TLFNO2L4.js";function O(n){let t=[];for(let e=0;e<n.length;e++)if(n[e]==="--since"&&e+1<n.length){t.push(e,e+1);let s=n[e+1].trim(),l=/^(\d+(?:\.\d+)?)(ms|s|m)?$/.exec(s);if(l){let r=Number(l[1]),u=l[2]??"ms",v=u==="s"?r*1e3:u==="m"?r*6e4:r;return{since:Date.now()-v,consumed:t}}let i=Number(s);if(Number.isFinite(i)&&i>1e12)return{since:i,consumed:t}}return{consumed:t}}function B(n){let t=[];for(let e=0;e<n.length;e++)if(n[e]==="--kinds"&&e+1<n.length)return t.push(e,e+1),{kinds:n[e+1].split(",").map(s=>s.trim()).filter(Boolean),consumed:t};return{consumed:t}}function D(n){let t=[];for(let e=0;e<n.length;e++)if(n[e]==="--limit"&&e+1<n.length){t.push(e,e+1);let s=Number(n[e+1]);if(Number.isFinite(s)&&s>0)return{limit:s,consumed:t}}return{consumed:t}}function x(n){let t=[],e={label:"initial state",events:[],startedAt:n[0]?.t??null};t.push(e);for(let s of n)if(e.events.push(s),s.kind==="screen"||s.kind==="route"){let l=s.data,i=l?.phase;if(!i||i==="enter"||i==="appear"||i==="active"){let r=l?.name||l?.activeName||l?.path||l?.pathname||s.kind;t.length===1&&e.events.length===1?e.label=`${s.kind}: ${r}`:(e={label:`${s.kind}: ${r}`,events:[],startedAt:s.t},t.push(e))}}return t}async function J(n,t){let e=N(n,{port:t.port,stripBooleanFlags:["--summary","--all","--json","--no-advance","--help","-h","--flow","--noisy"],stripValueFlags:["--since","--kinds","--limit"]});(n.includes("--help")||n.includes("-h"))&&(console.log(`
1
+ /*! sootsim v0.1.148 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{C as T,D as A,E as y,P as _,Q as b,R as S}from"./chunk-7EBPIOTW.js";import{c as N,e as F}from"./chunk-PMM6MNCR.js";import{b as k}from"./chunk-4JVDEEJJ.js";import"./chunk-U2U22DTV.js";import"./chunk-F3MFOV7R.js";import"./chunk-XYFPDYAI.js";function O(n){let t=[];for(let e=0;e<n.length;e++)if(n[e]==="--since"&&e+1<n.length){t.push(e,e+1);let s=n[e+1].trim(),l=/^(\d+(?:\.\d+)?)(ms|s|m)?$/.exec(s);if(l){let r=Number(l[1]),u=l[2]??"ms",v=u==="s"?r*1e3:u==="m"?r*6e4:r;return{since:Date.now()-v,consumed:t}}let i=Number(s);if(Number.isFinite(i)&&i>1e12)return{since:i,consumed:t}}return{consumed:t}}function B(n){let t=[];for(let e=0;e<n.length;e++)if(n[e]==="--kinds"&&e+1<n.length)return t.push(e,e+1),{kinds:n[e+1].split(",").map(s=>s.trim()).filter(Boolean),consumed:t};return{consumed:t}}function D(n){let t=[];for(let e=0;e<n.length;e++)if(n[e]==="--limit"&&e+1<n.length){t.push(e,e+1);let s=Number(n[e+1]);if(Number.isFinite(s)&&s>0)return{limit:s,consumed:t}}return{consumed:t}}function x(n){let t=[],e={label:"initial state",events:[],startedAt:n[0]?.t??null};t.push(e);for(let s of n)if(e.events.push(s),s.kind==="screen"||s.kind==="route"){let l=s.data,i=l?.phase;if(!i||i==="enter"||i==="appear"||i==="active"){let r=l?.name||l?.activeName||l?.path||l?.pathname||s.kind;t.length===1&&e.events.length===1?e.label=`${s.kind}: ${r}`:(e={label:`${s.kind}: ${r}`,events:[],startedAt:s.t},t.push(e))}}return t}async function J(n,t){let e=N(n,{port:t.port,stripBooleanFlags:["--summary","--all","--json","--no-advance","--help","-h","--flow","--noisy"],stripValueFlags:["--since","--kinds","--limit"]});(n.includes("--help")||n.includes("-h"))&&(console.log(`
3
3
  sootsim what-happened \u2014 show recent events from the semantic timeline
4
4
 
5
5
  usage:
@@ -1,2 +1,2 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{d as i}from"./chunk-HZHZY7N5.js";import{d as n}from"./chunk-R7CMXY5T.js";import"./chunk-IADMCPLZ.js";import"./chunk-TLFNO2L4.js";async function u(){let o=i();if(o||(console.log(" not signed in"),console.log(" set SOOTSIM_API_KEY=sk_sootsim_\u2026 or run `sootsim login`"),process.exit(1)),o.kind==="api-key"){let r=`${o.secret.slice(0,14)}\u2026`,t=o.source==="env"?"SOOTSIM_API_KEY env var":"saved key (~/.config/sootsim/credentials.json)";console.log(` api key ${r}`),console.log(` source: ${t}`);return}if(o.kind==="github"){console.log(` github token (${o.source})`),console.log(` repo: ${o.repoId}`);return}let e=await n(),s=e?.user;console.log(` ${s?.email||s?.name||s?.id||"signed in"}`),console.log(` origin: ${e?.origin??o.origin}`),e?.updatedAt&&console.log(` updated: ${e.updatedAt}`)}export{u as runWhoami};
1
+ /*! sootsim v0.1.148 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{d as i}from"./chunk-A57WJDB2.js";import{d as n}from"./chunk-TYHRA7FX.js";import"./chunk-F3MFOV7R.js";import"./chunk-XYFPDYAI.js";async function u(){let o=i();if(o||(console.log(" not signed in"),console.log(" set SOOTSIM_API_KEY=sk_sootsim_\u2026 or run `sootsim login`"),process.exit(1)),o.kind==="api-key"){let r=`${o.secret.slice(0,14)}\u2026`,t=o.source==="env"?"SOOTSIM_API_KEY env var":"saved key (~/.config/sootsim/credentials.json)";console.log(` api key ${r}`),console.log(` source: ${t}`);return}if(o.kind==="github"){console.log(` github token (${o.source})`),console.log(` repo: ${o.repoId}`);return}let e=await n(),s=e?.user;console.log(` ${s?.email||s?.name||s?.id||"signed in"}`),console.log(` origin: ${e?.origin??o.origin}`),e?.updatedAt&&console.log(` updated: ${e.updatedAt}`)}export{u as runWhoami};
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/beta.ts
4
4
  var IS_BETA = true;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -2784,9 +2784,24 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
2784
2784
  // terminal 4001 code, so the client closes the abandoned window instead
2785
2785
  // of reconnecting the zombie straight back in.
2786
2786
  static SIM_IDLE_REAP_TTL_MS = 30 * 6e4;
2787
+ // automation sims (spawned by the playwright driver: `sootsim open --driver
2788
+ // playwright`, the factory/screenshot capture path — `meta.sootsimHostDriver
2789
+ // === 'playwright'`) are unattended one-shot browsers, never a human's tab. a
2790
+ // capture run opens one per slide/app/retry and the 30-min human/dev TTL lets
2791
+ // hundreds pile up inside the window — orphaned ms-playwright chromiums that
2792
+ // drove the box to swap-thrash (load hit 157 in one incident). give them a far
2793
+ // shorter idle TTL, and cap how many can sit concurrently: reap the most-idle
2794
+ // overflow, but never a sim active within ACTIVE_GRACE (an agent composing
2795
+ // between captures), nor primary / cli-attached / leased sims.
2796
+ static AUTOMATION_SIM_IDLE_REAP_TTL_MS = 10 * 6e4;
2797
+ static MAX_CONCURRENT_AUTOMATION_SIMS = 6;
2798
+ static AUTOMATION_SIM_ACTIVE_GRACE_MS = 6e4;
2787
2799
  preferredPort;
2788
2800
  portFallbackCount;
2789
2801
  simIdleReapTtlMs;
2802
+ automationSimIdleReapTtlMs;
2803
+ maxConcurrentAutomationSims;
2804
+ automationSimActiveGraceMs;
2790
2805
  shouldWriteLockfile;
2791
2806
  sootbeanOrigin = null;
2792
2807
  effectivePort = 0;
@@ -2823,6 +2838,9 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
2823
2838
  this.agentHost = new AgentHost({ getExcludePorts: opts.agentScanExcludes });
2824
2839
  this.sootbeanOrigin = opts.sootbeanOrigin?.replace(/\/$/, "") || null;
2825
2840
  this.simIdleReapTtlMs = opts.simIdleReapTtlMs ?? _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS;
2841
+ this.automationSimIdleReapTtlMs = opts.automationSimIdleReapTtlMs ?? _SootSimBridgeHost.AUTOMATION_SIM_IDLE_REAP_TTL_MS;
2842
+ this.maxConcurrentAutomationSims = opts.maxConcurrentAutomationSims ?? _SootSimBridgeHost.MAX_CONCURRENT_AUTOMATION_SIMS;
2843
+ this.automationSimActiveGraceMs = opts.automationSimActiveGraceMs ?? _SootSimBridgeHost.AUTOMATION_SIM_ACTIVE_GRACE_MS;
2826
2844
  }
2827
2845
  /** expose the agent host so tests and embedders can inspect state or
2828
2846
  * inject behavior. not part of the public WS protocol. */
@@ -3819,15 +3837,56 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
3819
3837
  // using is the primary and/or holds a fresh user-active lease; one that is
3820
3838
  // none of those and idle past the TTL is abandoned regardless of a stale
3821
3839
  // focus flag.
3840
+ // automation sims are spawned by the playwright driver (`sootsim open
3841
+ // --driver playwright`, the factory/screenshot capture path), which tags them
3842
+ // with `meta.sootsimHostDriver === 'playwright'` via the host's addInitScript.
3843
+ // they are unattended one-shot browsers, never a human's tab, so they get a
3844
+ // shorter idle TTL and a concurrent cap.
3845
+ isAutomationSim(sim) {
3846
+ return sim.meta?.sootsimHostDriver === "playwright";
3847
+ }
3848
+ // an automation sim whose spawning playwright host process is still alive is
3849
+ // an ACTIVE run, not an abandoned tab. mirrors the cli's playwrightHostPidForSim
3850
+ // (control.ts): extract the host pid from meta, then check liveness so the
3851
+ // host-side idle GC never kills a live capture/factory sim mid-run.
3852
+ automationSimOwnerAlive(sim) {
3853
+ const pid = Number(sim.meta?.sootsimHostPid);
3854
+ if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return false;
3855
+ try {
3856
+ process.kill(pid, 0);
3857
+ return true;
3858
+ } catch (err) {
3859
+ return err.code === "EPERM";
3860
+ }
3861
+ }
3822
3862
  reapIdleSims(now = Date.now()) {
3823
3863
  const attachedSimIds = new Set(this.cliSimBySocket.values());
3864
+ const automationLive = [];
3824
3865
  for (const sim of this.sims.values()) {
3825
3866
  if (sim.id === this.primarySimId) continue;
3826
3867
  if (attachedSimIds.has(sim.id)) continue;
3827
3868
  if (this.getActiveLease(sim)) continue;
3828
3869
  const lastTouched = Math.max(sim.lastActiveAt, sim.connectedAt);
3829
- if (now - lastTouched < this.simIdleReapTtlMs) continue;
3830
- this.closeSimSocketFromHost(sim.ws);
3870
+ const idleMs = now - lastTouched;
3871
+ const automation = this.isAutomationSim(sim);
3872
+ if (automation && this.automationSimOwnerAlive(sim)) continue;
3873
+ const ttl = automation ? this.automationSimIdleReapTtlMs : this.simIdleReapTtlMs;
3874
+ if (idleMs >= ttl) {
3875
+ this.closeSimSocketFromHost(sim.ws);
3876
+ continue;
3877
+ }
3878
+ if (automation) automationLive.push({ sim, idleMs });
3879
+ }
3880
+ const cap = this.maxConcurrentAutomationSims;
3881
+ if (automationLive.length > cap) {
3882
+ automationLive.sort((a, b) => b.idleMs - a.idleMs);
3883
+ for (const { sim, idleMs } of automationLive.slice(
3884
+ 0,
3885
+ automationLive.length - cap
3886
+ )) {
3887
+ if (idleMs < this.automationSimActiveGraceMs) continue;
3888
+ this.closeSimSocketFromHost(sim.ws);
3889
+ }
3831
3890
  }
3832
3891
  }
3833
3892
  // ping every connected ws; if the previous round's ping went unanswered,
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/host/fetch-proxy-overrides.ts
4
4
  var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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/dist-lib/sdk.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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 __defProp = Object.defineProperty;
package/dist-lib/sdk.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // cli/commands/inspect/core.ts
4
4
  function resolveMaxMsFlag(args, fallbackMs) {
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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;
@@ -12824,9 +12824,24 @@ var init_bridge_host = __esm({
12824
12824
  // terminal 4001 code, so the client closes the abandoned window instead
12825
12825
  // of reconnecting the zombie straight back in.
12826
12826
  static SIM_IDLE_REAP_TTL_MS = 30 * 6e4;
12827
+ // automation sims (spawned by the playwright driver: `sootsim open --driver
12828
+ // playwright`, the factory/screenshot capture path — `meta.sootsimHostDriver
12829
+ // === 'playwright'`) are unattended one-shot browsers, never a human's tab. a
12830
+ // capture run opens one per slide/app/retry and the 30-min human/dev TTL lets
12831
+ // hundreds pile up inside the window — orphaned ms-playwright chromiums that
12832
+ // drove the box to swap-thrash (load hit 157 in one incident). give them a far
12833
+ // shorter idle TTL, and cap how many can sit concurrently: reap the most-idle
12834
+ // overflow, but never a sim active within ACTIVE_GRACE (an agent composing
12835
+ // between captures), nor primary / cli-attached / leased sims.
12836
+ static AUTOMATION_SIM_IDLE_REAP_TTL_MS = 10 * 6e4;
12837
+ static MAX_CONCURRENT_AUTOMATION_SIMS = 6;
12838
+ static AUTOMATION_SIM_ACTIVE_GRACE_MS = 6e4;
12827
12839
  preferredPort;
12828
12840
  portFallbackCount;
12829
12841
  simIdleReapTtlMs;
12842
+ automationSimIdleReapTtlMs;
12843
+ maxConcurrentAutomationSims;
12844
+ automationSimActiveGraceMs;
12830
12845
  shouldWriteLockfile;
12831
12846
  sootbeanOrigin = null;
12832
12847
  effectivePort = 0;
@@ -12863,6 +12878,9 @@ var init_bridge_host = __esm({
12863
12878
  this.agentHost = new AgentHost({ getExcludePorts: opts.agentScanExcludes });
12864
12879
  this.sootbeanOrigin = opts.sootbeanOrigin?.replace(/\/$/, "") || null;
12865
12880
  this.simIdleReapTtlMs = opts.simIdleReapTtlMs ?? _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS;
12881
+ this.automationSimIdleReapTtlMs = opts.automationSimIdleReapTtlMs ?? _SootSimBridgeHost.AUTOMATION_SIM_IDLE_REAP_TTL_MS;
12882
+ this.maxConcurrentAutomationSims = opts.maxConcurrentAutomationSims ?? _SootSimBridgeHost.MAX_CONCURRENT_AUTOMATION_SIMS;
12883
+ this.automationSimActiveGraceMs = opts.automationSimActiveGraceMs ?? _SootSimBridgeHost.AUTOMATION_SIM_ACTIVE_GRACE_MS;
12866
12884
  }
12867
12885
  /** expose the agent host so tests and embedders can inspect state or
12868
12886
  * inject behavior. not part of the public WS protocol. */
@@ -13859,15 +13877,56 @@ var init_bridge_host = __esm({
13859
13877
  // using is the primary and/or holds a fresh user-active lease; one that is
13860
13878
  // none of those and idle past the TTL is abandoned regardless of a stale
13861
13879
  // focus flag.
13880
+ // automation sims are spawned by the playwright driver (`sootsim open
13881
+ // --driver playwright`, the factory/screenshot capture path), which tags them
13882
+ // with `meta.sootsimHostDriver === 'playwright'` via the host's addInitScript.
13883
+ // they are unattended one-shot browsers, never a human's tab, so they get a
13884
+ // shorter idle TTL and a concurrent cap.
13885
+ isAutomationSim(sim) {
13886
+ return sim.meta?.sootsimHostDriver === "playwright";
13887
+ }
13888
+ // an automation sim whose spawning playwright host process is still alive is
13889
+ // an ACTIVE run, not an abandoned tab. mirrors the cli's playwrightHostPidForSim
13890
+ // (control.ts): extract the host pid from meta, then check liveness so the
13891
+ // host-side idle GC never kills a live capture/factory sim mid-run.
13892
+ automationSimOwnerAlive(sim) {
13893
+ const pid = Number(sim.meta?.sootsimHostPid);
13894
+ if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return false;
13895
+ try {
13896
+ process.kill(pid, 0);
13897
+ return true;
13898
+ } catch (err) {
13899
+ return err.code === "EPERM";
13900
+ }
13901
+ }
13862
13902
  reapIdleSims(now = Date.now()) {
13863
13903
  const attachedSimIds = new Set(this.cliSimBySocket.values());
13904
+ const automationLive = [];
13864
13905
  for (const sim of this.sims.values()) {
13865
13906
  if (sim.id === this.primarySimId) continue;
13866
13907
  if (attachedSimIds.has(sim.id)) continue;
13867
13908
  if (this.getActiveLease(sim)) continue;
13868
13909
  const lastTouched = Math.max(sim.lastActiveAt, sim.connectedAt);
13869
- if (now - lastTouched < this.simIdleReapTtlMs) continue;
13870
- this.closeSimSocketFromHost(sim.ws);
13910
+ const idleMs = now - lastTouched;
13911
+ const automation = this.isAutomationSim(sim);
13912
+ if (automation && this.automationSimOwnerAlive(sim)) continue;
13913
+ const ttl = automation ? this.automationSimIdleReapTtlMs : this.simIdleReapTtlMs;
13914
+ if (idleMs >= ttl) {
13915
+ this.closeSimSocketFromHost(sim.ws);
13916
+ continue;
13917
+ }
13918
+ if (automation) automationLive.push({ sim, idleMs });
13919
+ }
13920
+ const cap = this.maxConcurrentAutomationSims;
13921
+ if (automationLive.length > cap) {
13922
+ automationLive.sort((a, b) => b.idleMs - a.idleMs);
13923
+ for (const { sim, idleMs } of automationLive.slice(
13924
+ 0,
13925
+ automationLive.length - cap
13926
+ )) {
13927
+ if (idleMs < this.automationSimActiveGraceMs) continue;
13928
+ this.closeSimSocketFromHost(sim.ws);
13929
+ }
13871
13930
  }
13872
13931
  }
13873
13932
  // ping every connected ws; if the previous round's ping went unanswered,
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.148 | (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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sootsim",
3
- "version": "0.1.146",
3
+ "version": "0.1.148",
4
4
  "description": "sootsim CLI + vite/metro plugins + skills registry. bridge client for driving the proprietary sootsim-engine over WebSocket.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "MIT",
@@ -228,6 +228,18 @@ export interface BridgeHostOptions {
228
228
  * can drive the real timer path deterministically instead of mocking
229
229
  * time. production callers should never set this. */
230
230
  simIdleReapTtlMs?: number
231
+ /** override the idle GC TTL (ms) for automation sims (playwright-driver,
232
+ * capture/factory). defaults to AUTOMATION_SIM_IDLE_REAP_TTL_MS (10 min).
233
+ * test-only, like simIdleReapTtlMs. */
234
+ automationSimIdleReapTtlMs?: number
235
+ /** cap on concurrent non-primary automation sims before the reaper drops
236
+ * the most-idle overflow. defaults to MAX_CONCURRENT_AUTOMATION_SIMS (6).
237
+ * test-only. */
238
+ maxConcurrentAutomationSims?: number
239
+ /** grace (ms) below which an automation sim is never reaped by the cap,
240
+ * even when over it. defaults to AUTOMATION_SIM_ACTIVE_GRACE_MS (60 s).
241
+ * test-only. */
242
+ automationSimActiveGraceMs?: number
231
243
  }
232
244
 
233
245
  const DAEMON_HEARTBEAT_INTERVAL_MS = 5_000
@@ -354,10 +366,25 @@ export class SootSimBridgeHost {
354
366
  // terminal 4001 code, so the client closes the abandoned window instead
355
367
  // of reconnecting the zombie straight back in.
356
368
  private static SIM_IDLE_REAP_TTL_MS = 30 * 60_000
369
+ // automation sims (spawned by the playwright driver: `sootsim open --driver
370
+ // playwright`, the factory/screenshot capture path — `meta.sootsimHostDriver
371
+ // === 'playwright'`) are unattended one-shot browsers, never a human's tab. a
372
+ // capture run opens one per slide/app/retry and the 30-min human/dev TTL lets
373
+ // hundreds pile up inside the window — orphaned ms-playwright chromiums that
374
+ // drove the box to swap-thrash (load hit 157 in one incident). give them a far
375
+ // shorter idle TTL, and cap how many can sit concurrently: reap the most-idle
376
+ // overflow, but never a sim active within ACTIVE_GRACE (an agent composing
377
+ // between captures), nor primary / cli-attached / leased sims.
378
+ private static AUTOMATION_SIM_IDLE_REAP_TTL_MS = 10 * 60_000
379
+ private static MAX_CONCURRENT_AUTOMATION_SIMS = 6
380
+ private static AUTOMATION_SIM_ACTIVE_GRACE_MS = 60_000
357
381
 
358
382
  private preferredPort: number
359
383
  private portFallbackCount: number
360
384
  private simIdleReapTtlMs: number
385
+ private automationSimIdleReapTtlMs: number
386
+ private maxConcurrentAutomationSims: number
387
+ private automationSimActiveGraceMs: number
361
388
  private shouldWriteLockfile: boolean
362
389
  private sootbeanOrigin: string | null = null
363
390
  private effectivePort = 0
@@ -403,6 +430,12 @@ export class SootSimBridgeHost {
403
430
  this.sootbeanOrigin = opts.sootbeanOrigin?.replace(/\/$/, '') || null
404
431
  this.simIdleReapTtlMs =
405
432
  opts.simIdleReapTtlMs ?? SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS
433
+ this.automationSimIdleReapTtlMs =
434
+ opts.automationSimIdleReapTtlMs ?? SootSimBridgeHost.AUTOMATION_SIM_IDLE_REAP_TTL_MS
435
+ this.maxConcurrentAutomationSims =
436
+ opts.maxConcurrentAutomationSims ?? SootSimBridgeHost.MAX_CONCURRENT_AUTOMATION_SIMS
437
+ this.automationSimActiveGraceMs =
438
+ opts.automationSimActiveGraceMs ?? SootSimBridgeHost.AUTOMATION_SIM_ACTIVE_GRACE_MS
406
439
  }
407
440
 
408
441
  /** expose the agent host so tests and embedders can inspect state or
@@ -1624,8 +1657,35 @@ export class SootSimBridgeHost {
1624
1657
  // using is the primary and/or holds a fresh user-active lease; one that is
1625
1658
  // none of those and idle past the TTL is abandoned regardless of a stale
1626
1659
  // focus flag.
1660
+ // automation sims are spawned by the playwright driver (`sootsim open
1661
+ // --driver playwright`, the factory/screenshot capture path), which tags them
1662
+ // with `meta.sootsimHostDriver === 'playwright'` via the host's addInitScript.
1663
+ // they are unattended one-shot browsers, never a human's tab, so they get a
1664
+ // shorter idle TTL and a concurrent cap.
1665
+ private isAutomationSim(sim: BridgeSimConnection): boolean {
1666
+ return sim.meta?.sootsimHostDriver === 'playwright'
1667
+ }
1668
+
1669
+ // an automation sim whose spawning playwright host process is still alive is
1670
+ // an ACTIVE run, not an abandoned tab. mirrors the cli's playwrightHostPidForSim
1671
+ // (control.ts): extract the host pid from meta, then check liveness so the
1672
+ // host-side idle GC never kills a live capture/factory sim mid-run.
1673
+ private automationSimOwnerAlive(sim: BridgeSimConnection): boolean {
1674
+ const pid = Number(sim.meta?.sootsimHostPid)
1675
+ if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return false
1676
+ try {
1677
+ process.kill(pid, 0) // ESRCH → dead; EPERM → alive but unsignalable
1678
+ return true
1679
+ } catch (err) {
1680
+ return (err as NodeJS.ErrnoException).code === 'EPERM'
1681
+ }
1682
+ }
1683
+
1627
1684
  private reapIdleSims(now = Date.now()) {
1628
1685
  const attachedSimIds = new Set(this.cliSimBySocket.values())
1686
+ // automation sims that pass every "someone cares" gate but are still under
1687
+ // their TTL — candidates for the concurrent-cap pass below.
1688
+ const automationLive: { sim: BridgeSimConnection; idleMs: number }[] = []
1629
1689
  for (const sim of this.sims.values()) {
1630
1690
  if (sim.id === this.primarySimId) continue
1631
1691
  if (attachedSimIds.has(sim.id)) continue
@@ -1633,10 +1693,38 @@ export class SootSimBridgeHost {
1633
1693
  // never-CLI-driven sims have lastActiveAt 0 — fall back to connectedAt
1634
1694
  // so a freshly opened, not-yet-primary tab isn't reaped on the spot.
1635
1695
  const lastTouched = Math.max(sim.lastActiveAt, sim.connectedAt)
1636
- if (now - lastTouched < this.simIdleReapTtlMs) continue
1637
- // terminal close → client closes the window, does not reconnect; the
1638
- // 'close' handler runs rememberDisconnectedSim this.sims.delete.
1639
- this.closeSimSocketFromHost(sim.ws)
1696
+ const idleMs = now - lastTouched
1697
+ const automation = this.isAutomationSim(sim)
1698
+ // a live-owner automation sim is an ACTIVE run (its spawning playwright host
1699
+ // process is still alive) — never reap it. the host keeps Chrome alive
1700
+ // intentionally and tears it down itself when ITS owner driver dies; only
1701
+ // orphaned/host-dead autos are the leak this reaper targets. (2026-06: the
1702
+ // 10-min automation TTL was reaping live capture + factory sims mid-run —
1703
+ // too aggressive.) continue skips both the TTL reap and the cap pass below.
1704
+ if (automation && this.automationSimOwnerAlive(sim)) continue
1705
+ const ttl = automation ? this.automationSimIdleReapTtlMs : this.simIdleReapTtlMs
1706
+ if (idleMs >= ttl) {
1707
+ // terminal close → client closes the window, does not reconnect; the
1708
+ // 'close' handler runs rememberDisconnectedSim → this.sims.delete.
1709
+ this.closeSimSocketFromHost(sim.ws)
1710
+ continue
1711
+ }
1712
+ if (automation) automationLive.push({ sim, idleMs })
1713
+ }
1714
+ // concurrent cap: a burst of capture opens can pile up hundreds inside the
1715
+ // TTL window. keep at most maxConcurrentAutomationSims of the freshest;
1716
+ // reap the most-idle overflow, but never one active within the grace (an
1717
+ // agent mid-capture between screenshots).
1718
+ const cap = this.maxConcurrentAutomationSims
1719
+ if (automationLive.length > cap) {
1720
+ automationLive.sort((a, b) => b.idleMs - a.idleMs) // most-idle first
1721
+ for (const { sim, idleMs } of automationLive.slice(
1722
+ 0,
1723
+ automationLive.length - cap,
1724
+ )) {
1725
+ if (idleMs < this.automationSimActiveGraceMs) continue
1726
+ this.closeSimSocketFromHost(sim.ws)
1727
+ }
1640
1728
  }
1641
1729
  }
1642
1730
 
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c,d}from"./chunk-MSQUL5BU.js";import"./chunk-BBIN2U26.js";import"./chunk-YBSNSFBX.js";import"./chunk-FK2YXBKR.js";import"./chunk-IADMCPLZ.js";import"./chunk-TLFNO2L4.js";export{c as ensureDaemonRunning,a as ensureRuntimeInstalled,d as ensureSootsimReady,b as resolveBootstrapPort};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c,d,e}from"./chunk-HWB7DPXH.js";import"./chunk-TLFNO2L4.js";export{e as BETA_ASK_HEADLINE,c as BETA_LABEL,d as BETA_TAGLINE,b as BETA_VERSION_TARGET,a as IS_BETA};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- var t="http://localhost:5173/";export{t as a};
@@ -1 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
@@ -1 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
@@ -1 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a}from"./chunk-4KNMAGC4.js";import"./chunk-TLFNO2L4.js";export{a as getCliVersion};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import"./chunk-Y76W7GZV.js";import{a,b,c,d,e,f,g,h,i}from"./chunk-C44OZFHJ.js";import"./chunk-H2EIYIRP.js";import"./chunk-UD4SYXDQ.js";import"./chunk-DRCRPS2N.js";import"./chunk-A7JX3OQC.js";import"./chunk-YBSNSFBX.js";import"./chunk-IADMCPLZ.js";import"./chunk-TLFNO2L4.js";export{e as ALL_DRIVERS,i as buildDriverListRows,a as chromiumDriver,b as electronDriver,f as getAllDrivers,g as getDriver,c as playwrightDriver,h as resolveDriver,d as systemDriver};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as c,b as d,c as e,d as f}from"./chunk-ERAE4LJT.js";import"./chunk-BE2ZDRIJ.js";import"./chunk-OU42HTKN.js";import"./chunk-PCW4TKI2.js";import"./chunk-JZW2R5D7.js";import"./chunk-HZHZY7N5.js";import{c as a,d as b}from"./chunk-H6LFGGJW.js";import"./chunk-IAO27BWC.js";import"./chunk-XRQDMB2J.js";import"./chunk-MVLNHZMU.js";import"./chunk-DP5FSZHW.js";import"./chunk-MIIAYBFL.js";import"./chunk-BBIN2U26.js";import"./chunk-G7JMTSF6.js";import"./chunk-C44OZFHJ.js";import"./chunk-H2EIYIRP.js";import"./chunk-UD4SYXDQ.js";import"./chunk-DRCRPS2N.js";import"./chunk-A7JX3OQC.js";import"./chunk-YBSNSFBX.js";import"./chunk-Q6BHESL2.js";import"./chunk-R7CMXY5T.js";import"./chunk-WFXLVOUA.js";import"./chunk-3RPHEE3K.js";import"./chunk-FK2YXBKR.js";import"./chunk-XO4VQYFP.js";import"./chunk-RTD4RNZV.js";import"./chunk-IADMCPLZ.js";import"./chunk-TLFNO2L4.js";export{c as discoverSootsimUrl,e as hoistLeadingSimFlag,a as parseFlowFile,f as runFlow,d as runFlowPlayback,b as validateFlowFile};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c}from"./chunk-TZXKFPBJ.js";import"./chunk-WFXLVOUA.js";import"./chunk-AOPFT3S4.js";import"./chunk-3RPHEE3K.js";import"./chunk-FK2YXBKR.js";import"./chunk-4KNMAGC4.js";import"./chunk-HWB7DPXH.js";import"./chunk-RTD4RNZV.js";import"./chunk-IADMCPLZ.js";import"./chunk-TLFNO2L4.js";export{c as printCommandHelp,b as printGroupHelp,a as printHelp};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as o}from"./chunk-ATJRNMNA.js";import"./chunk-2PYDOYIS.js";import"./chunk-MSQUL5BU.js";import"./chunk-BBIN2U26.js";import"./chunk-YBSNSFBX.js";import"./chunk-Q6BHESL2.js";import"./chunk-R7CMXY5T.js";import"./chunk-FK2YXBKR.js";import"./chunk-IADMCPLZ.js";import"./chunk-TLFNO2L4.js";async function t(n){console.error(" note: `sootsim install` is now `sootsim setup-repo`. forwarding\u2026\n"),await o(n)}export{t as runInstall};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.146 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b}from"./chunk-G7JMTSF6.js";import"./chunk-TLFNO2L4.js";export{a as loadOptionalDemoApps,b as optionalDemoAppsSync};