sootsim 0.1.200 → 0.1.202

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 +5 -4
  2. package/dist-cli/chunks/{agent-RJBLYNGF.js → agent-SP6EE5XV.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-E6WLI6L3.js → agent-wrapper-PWZVJ3OK.js} +2 -2
  4. package/dist-cli/chunks/{app-fonts-O3VYBYQW.js → app-fonts-EMJB6QLM.js} +2 -2
  5. package/dist-cli/chunks/{assert-VFBTT2JB.js → assert-H2B6TDXT.js} +2 -2
  6. package/dist-cli/chunks/{auth-DQ6AJU2X.js → auth-SOHXBYLQ.js} +2 -2
  7. package/dist-cli/chunks/beta-CCNQQ73A.js +2 -0
  8. package/dist-cli/chunks/{camera-C2OFA3JA.js → camera-ULLCBM5H.js} +2 -2
  9. package/dist-cli/chunks/{chunk-UGJFYNMX.js → chunk-2CID4LNK.js} +3 -3
  10. package/dist-cli/chunks/chunk-2V43M57C.js +2 -0
  11. package/dist-cli/chunks/{chunk-GKXPIE6X.js → chunk-3ZENZOIX.js} +2 -2
  12. package/dist-cli/chunks/{chunk-6RHOWIGL.js → chunk-4KT2BGQE.js} +1 -1
  13. package/dist-cli/chunks/{chunk-P4PCUR4Y.js → chunk-4KVSVFRF.js} +1 -1
  14. package/dist-cli/chunks/{chunk-VACKEJ3E.js → chunk-4NM6JBYH.js} +1 -1
  15. package/dist-cli/chunks/chunk-5J63S2NM.js +1 -0
  16. package/dist-cli/chunks/{chunk-7BS4AKZT.js → chunk-5SKKMM7E.js} +1 -1
  17. package/dist-cli/chunks/chunk-6FZ6SNVP.js +4 -0
  18. package/dist-cli/chunks/{chunk-3BEGOL5T.js → chunk-6QFVYLX6.js} +2 -2
  19. package/dist-cli/chunks/{chunk-IJ6DRL7N.js → chunk-AAQVPSIV.js} +2 -2
  20. package/dist-cli/chunks/{chunk-XF3JBBPU.js → chunk-B6JB4THC.js} +2 -2
  21. package/dist-cli/chunks/{chunk-JJOS6L5H.js → chunk-BZ7AW7ZB.js} +2 -2
  22. package/dist-cli/chunks/{chunk-OCA5CK4S.js → chunk-CB7LDZKJ.js} +3 -3
  23. package/dist-cli/chunks/{chunk-6JKBWHIO.js → chunk-CGJ2U6ST.js} +1 -1
  24. package/dist-cli/chunks/chunk-DKBKU55D.js +2 -0
  25. package/dist-cli/chunks/{chunk-QSWT3OVG.js → chunk-DRJ4YWUG.js} +1 -1
  26. package/dist-cli/chunks/{chunk-XAIDHR55.js → chunk-EMOZJ773.js} +2 -2
  27. package/dist-cli/chunks/{chunk-KFGBNAV3.js → chunk-ENXHZGSL.js} +1 -1
  28. package/dist-cli/chunks/{chunk-I6DJFJQ6.js → chunk-F2LLN4U7.js} +2 -2
  29. package/dist-cli/chunks/{chunk-3PAUJH34.js → chunk-GUYKLSTX.js} +1 -1
  30. package/dist-cli/chunks/chunk-GZKT53SA.js +7 -0
  31. package/dist-cli/chunks/{chunk-DWFS6IIT.js → chunk-HZYHSLNH.js} +2 -2
  32. package/dist-cli/chunks/chunk-I6O7NBPZ.js +1 -0
  33. package/dist-cli/chunks/{chunk-U5O3F3NB.js → chunk-JP7J325R.js} +2 -2
  34. package/dist-cli/chunks/{chunk-5SB3N45C.js → chunk-K3UBHPVP.js} +1 -1
  35. package/dist-cli/chunks/{chunk-VFSOKG53.js → chunk-KRGHRSKY.js} +2 -2
  36. package/dist-cli/chunks/{chunk-VP4Y767U.js → chunk-KYGUR727.js} +2 -2
  37. package/dist-cli/chunks/{chunk-2E4DUZEV.js → chunk-LNDRRZP3.js} +2 -2
  38. package/dist-cli/chunks/{chunk-NEQRFWA3.js → chunk-OG6TFGYF.js} +2 -2
  39. package/dist-cli/chunks/{chunk-PJAKGC4A.js → chunk-PL4GXELT.js} +1 -1
  40. package/dist-cli/chunks/{chunk-MZLG4WVE.js → chunk-RJVIUQK4.js} +1 -1
  41. package/dist-cli/chunks/{chunk-4RUK2YSF.js → chunk-ROYBEBG2.js} +1 -1
  42. package/dist-cli/chunks/{chunk-42G5ZRQR.js → chunk-RS7QLHEH.js} +2 -2
  43. package/dist-cli/chunks/{chunk-LSDJTPOY.js → chunk-RWXCSRNE.js} +2 -2
  44. package/dist-cli/chunks/{chunk-NX4VSQD5.js → chunk-RZQO4Q7E.js} +1 -1
  45. package/dist-cli/chunks/{chunk-SFUQJU5Q.js → chunk-SQBX2HS7.js} +6 -6
  46. package/dist-cli/chunks/{chunk-NK4FF37S.js → chunk-TANTCV45.js} +2 -2
  47. package/dist-cli/chunks/chunk-W4Y3JJX6.js +29 -0
  48. package/dist-cli/chunks/chunk-WILIVPUU.js +567 -0
  49. package/dist-cli/chunks/{chunk-GMBG6JLV.js → chunk-WVDWIXPH.js} +2 -2
  50. package/dist-cli/chunks/{chunk-HGBMGQGP.js → chunk-Z5VMWFCY.js} +1 -1
  51. package/dist-cli/chunks/cli-version-Z4NGLJLH.js +2 -0
  52. package/dist-cli/chunks/{compat-L2E3OQW3.js → compat-YW3OJ7RX.js} +3 -3
  53. package/dist-cli/chunks/{config-K4IMJRHG.js → config-ZGOXFEX4.js} +2 -2
  54. package/dist-cli/chunks/{control-OXJ7S7UG.js → control-75JRFOYV.js} +2 -2
  55. package/dist-cli/chunks/daemon-SHFBQRHD.js +2 -0
  56. package/dist-cli/chunks/{debug-ZPKRTLGX.js → debug-4APEP64L.js} +3 -3
  57. package/dist-cli/chunks/{desktop-YA2UL7Q4.js → desktop-CS7S4CXK.js} +3 -3
  58. package/dist-cli/chunks/detox-7R7DOKQM.js +50 -0
  59. package/dist-cli/chunks/{device-M6YG7TKY.js → device-EIDKLBEK.js} +2 -2
  60. package/dist-cli/chunks/{diagnose-3OUFTELV.js → diagnose-J2F7MJAJ.js} +2 -2
  61. package/dist-cli/chunks/drivers-55L7BHDF.js +2 -0
  62. package/dist-cli/chunks/flow-AHWVTHJP.js +2 -0
  63. package/dist-cli/chunks/help-C4BTMPEE.js +2 -0
  64. package/dist-cli/chunks/home-paths-WVCREWI7.js +2 -0
  65. package/dist-cli/chunks/inspect-M4Z4SSSB.js +2 -0
  66. package/dist-cli/chunks/install-desktop-PVRUAEMA.js +2 -0
  67. package/dist-cli/chunks/{login-RNYBOMNF.js → login-EOBJ7CZ4.js} +4 -4
  68. package/dist-cli/chunks/{logout-XBW3BXL4.js → logout-RL7D66VQ.js} +2 -2
  69. package/dist-cli/chunks/maestro-F66ZIJKA.js +96 -0
  70. package/dist-cli/chunks/{mode-E353E6HN.js → mode-R2VIW66U.js} +2 -2
  71. package/dist-cli/chunks/optional-demo-registry-ILX5YV34.js +2 -0
  72. package/dist-cli/chunks/{perf-CIOBGFHU.js → perf-PGYO5BBR.js} +2 -2
  73. package/dist-cli/chunks/{record-I626AYJ5.js → record-IGDVHC67.js} +3 -3
  74. package/dist-cli/chunks/runtime-43RJGUGS.js +2 -0
  75. package/dist-cli/chunks/{screenshot-command-TTB5OOL2.js → screenshot-command-HX4GVUJM.js} +2 -2
  76. package/dist-cli/chunks/{serve-AEBEXTTW.js → serve-3TFVHYLY.js} +18 -18
  77. package/dist-cli/chunks/{setup-7QCI53ZK.js → setup-JSPPRVET.js} +3 -3
  78. package/dist-cli/chunks/{skills-7LHL5KHW.js → skills-LK3B76W7.js} +2 -2
  79. package/dist-cli/chunks/{storage-BVWLYY23.js → storage-NC5RNBUA.js} +2 -2
  80. package/dist-cli/chunks/store-3XMEKA6H.js +2 -0
  81. package/dist-cli/chunks/telemetry-CVJ5YZNS.js +2 -0
  82. package/dist-cli/chunks/test-2CXPLH5N.js +69 -0
  83. package/dist-cli/chunks/{timeline-BVR4E6PY.js → timeline-WDTEVELN.js} +2 -2
  84. package/dist-cli/chunks/upgrade-TT2IJSNJ.js +4 -0
  85. package/dist-cli/chunks/upload-4HMNB4HA.js +2 -0
  86. package/dist-cli/chunks/version-JUNH4FOR.js +4 -0
  87. package/dist-cli/chunks/{web-HYLNFAXS.js → web-BWCW26ZA.js} +2 -2
  88. package/dist-cli/chunks/{what-happened-YGRE2NFG.js → what-happened-L6EEB6MB.js} +2 -2
  89. package/dist-lib/agent-daemon-client.cjs +1 -1
  90. package/dist-lib/agent-events.cjs +1 -1
  91. package/dist-lib/agent-identity.cjs +1 -1
  92. package/dist-lib/agent-sessions.cjs +1 -1
  93. package/dist-lib/attached-projects.cjs +1 -1
  94. package/dist-lib/auth/shared-session.cjs +1 -1
  95. package/dist-lib/backend-origin.cjs +1 -1
  96. package/dist-lib/beta.cjs +1 -1
  97. package/dist-lib/beta.mjs +1 -1
  98. package/dist-lib/bridge-constants.cjs +1 -1
  99. package/dist-lib/cli-constants.cjs +1 -1
  100. package/dist-lib/config.cjs +1 -1
  101. package/dist-lib/detox/index.cjs +1 -1
  102. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  103. package/dist-lib/home-paths.cjs +32 -1
  104. package/dist-lib/host/bridge-host.cjs +51 -2
  105. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  106. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  107. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  108. package/dist-lib/host/websocket-proxy.cjs +1 -1
  109. package/dist-lib/index.cjs +1 -1
  110. package/dist-lib/jump-to-source-babel.cjs +1 -1
  111. package/dist-lib/menu.cjs +1 -1
  112. package/dist-lib/menu.mjs +1 -1
  113. package/dist-lib/metro.cjs +1 -1
  114. package/dist-lib/profiles.cjs +1 -1
  115. package/dist-lib/render-mode.cjs +1 -1
  116. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  117. package/dist-lib/sdk.cjs +1 -1
  118. package/dist-lib/sdk.mjs +1 -1
  119. package/dist-lib/skills.cjs +115 -36
  120. package/dist-lib/vite.cjs +1 -1
  121. package/package.json +1 -1
  122. package/src/home-paths.ts +48 -1
  123. package/src/host/bridge-host.ts +12 -0
  124. package/src/runtime-delivery.ts +59 -9
  125. package/src/screenshots/frame-compose.ts +21 -13
  126. package/dist-cli/chunks/beta-ZXPAAXGE.js +0 -2
  127. package/dist-cli/chunks/chunk-CB3I3VQT.js +0 -6
  128. package/dist-cli/chunks/chunk-EY2OMKPT.js +0 -1
  129. package/dist-cli/chunks/chunk-M3AUV33V.js +0 -4
  130. package/dist-cli/chunks/chunk-RJ6WD7XJ.js +0 -567
  131. package/dist-cli/chunks/chunk-TMXLUWD2.js +0 -27
  132. package/dist-cli/chunks/chunk-USDJA22M.js +0 -1
  133. package/dist-cli/chunks/chunk-VXBWUAYL.js +0 -2
  134. package/dist-cli/chunks/cli-version-E3OGD447.js +0 -2
  135. package/dist-cli/chunks/daemon-G5GBYBJ4.js +0 -2
  136. package/dist-cli/chunks/detox-LKEZBGH5.js +0 -49
  137. package/dist-cli/chunks/drivers-CTSUKCFK.js +0 -2
  138. package/dist-cli/chunks/flow-R5GJJLLW.js +0 -2
  139. package/dist-cli/chunks/help-CSSCFOBR.js +0 -2
  140. package/dist-cli/chunks/home-paths-4V6CGISP.js +0 -2
  141. package/dist-cli/chunks/inspect-NIBEAJND.js +0 -2
  142. package/dist-cli/chunks/install-desktop-7TYE6TTP.js +0 -2
  143. package/dist-cli/chunks/maestro-3EBOG357.js +0 -96
  144. package/dist-cli/chunks/optional-demo-registry-BEUP6OEZ.js +0 -2
  145. package/dist-cli/chunks/runtime-254BNZHB.js +0 -2
  146. package/dist-cli/chunks/store-6KAKNNCL.js +0 -2
  147. package/dist-cli/chunks/telemetry-EZ42CD35.js +0 -2
  148. package/dist-cli/chunks/test-BK4GZZR2.js +0 -69
  149. package/dist-cli/chunks/upgrade-AY5XC5QI.js +0 -4
  150. package/dist-cli/chunks/upload-HOF4XBAG.js +0 -2
  151. package/dist-cli/chunks/version-WQM34S4E.js +0 -4
@@ -1,25 +1,25 @@
1
- /*! sootsim v0.1.200 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{b as ce,c as H,d as le,e as F,f as de,h as ue,i as C,j as pe,k as me,l as he,p as fe,s as v,t as ge,u as Se,v as ye,w as ve}from"./chunk-U5O3F3NB.js";import"./chunk-HGBMGQGP.js";import{a as ae}from"./chunk-JJOS6L5H.js";import"./chunk-NK4FF37S.js";import{g as oe}from"./chunk-M3AUV33V.js";import{f as P,g as ne}from"./chunk-GMBG6JLV.js";import"./chunk-6JKBWHIO.js";import"./chunk-MZLG4WVE.js";import"./chunk-VACKEJ3E.js";import"./chunk-VFSOKG53.js";import{d as se}from"./chunk-QSWT3OVG.js";import{a as Q,b as ee}from"./chunk-VP4Y767U.js";import"./chunk-LSDJTPOY.js";import{a as ie,b as re}from"./chunk-PJAKGC4A.js";import"./chunk-NX4VSQD5.js";import{D as E,E as J,F as K,G as D,I as V,J as G,L as q,N as z,O as X,P as Y,Q as U,R as Z,y as M,z as j}from"./chunk-CB3I3VQT.js";import{a as te}from"./chunk-5SB3N45C.js";import"./chunk-6RHOWIGL.js";import{spawn as dt}from"child_process";import I from"fs";import{createServer as ut}from"http";import S from"path";import{WebSocket as h,WebSocketServer as pt}from"ws";import ke from"node:fs";import _ from"node:path";import{spawn as Ne}from"node:child_process";import Me from"node:fs";import De from"node:os";import Ue from"node:path";var be=/^[A-Za-z0-9._:-]{1,160}$/;function W(o){if(!o?.startsWith("AGENTBUS_SESSION:"))return null;let e=o.slice(17).trim();return be.test(e)?e:null}function we(o){return be.test(o)}function He(o){return typeof o.text=="string"?o.text.trim():""}function Fe(o){let e=o?.trim();if(e)return e;let t=process.env.AGENTBUS_COMMAND?.trim();if(t)return t;let i=Ue.join(De.homedir(),".local","bin","agentbus");return Me.existsSync(i)?i:"agentbus"}async function Ae(o){let e=o.sessionId.trim();if(!we(e))throw new Error(`invalid agentbus session id: ${e||"<empty>"}`);let t=He(o.prompt);if(!t)throw new Error("prompt text is empty");let i=Fe(o.command),s=o.timeoutMs??15e3;await new Promise((n,a)=>{let r=Ne(i,["send",e,t],{stdio:["ignore","ignore","pipe"],env:process.env}),c="",d=setTimeout(()=>{try{r.kill("SIGTERM")}catch{}a(new Error(`agentbus send timed out after ${Math.round(s/1e3)}s`))},s);r.stderr?.setEncoding("utf8"),r.stderr?.on("data",l=>{c.length<4e3&&(c+=String(l))}),r.on("error",l=>{clearTimeout(d),a(l)}),r.on("exit",(l,u)=>{if(clearTimeout(d),l===0){n();return}let p=c.trim();a(new Error(p||`agentbus send exited with ${u?`signal ${u}`:`code ${l??"unknown"}`}`))})})}var R=1;function We(){return[Number(process.env.VITE_PORT_WEB||process.env.PORT||3e3),Number(process.env.VITE_PORT_ZERO||7849),Number(process.env.VITE_PORT_POSTGRES||7432),Number(process.env.VITE_PORT_R2||9500)].filter(o=>Number.isFinite(o)&&o>0)}var x=class{subscriptions=new Map;sessionsBySocket=new Map;allSockets=new Set;pendingPromptEchoes=new Map;pendingTurns=new Map;opts;constructor(e={}){this.opts=e}registerSocket(e){this.allSockets.add(e)}unregisterSocket(e){let t=this.sessionsBySocket.get(e);if(t){for(let i of t)this.decrementSubscription(i);this.sessionsBySocket.delete(e)}this.allSockets.delete(e)}async handleMessage(e,t){let i=t?.type;if(typeof i!="string"||!i.startsWith("agent:"))return!1;let s=t.id;try{let n=await this.dispatch(e,i,t);this.respond(e,s,n)}catch(n){n instanceof v?this.respondError(e,s,n.message,n.code):this.respondError(e,s,n instanceof Error?n.message:String(n))}return!0}async seedOnBoot(){try{await he()}catch(e){process.stderr.write(`[sootsim-agent] seedFromDemoAppRegistry failed: ${e instanceof Error?e.message:String(e)}
3
- `)}}close(){for(let e of this.subscriptions.values())try{e.unsubscribe()}catch{}this.subscriptions.clear(),this.sessionsBySocket.clear(),this.allSockets.clear()}async dispatch(e,t,i){switch(t){case"agent:list-projects":return F();case"agent:upsert-project":return H(i.input??{});case"agent:delete-project":return ue(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return pe(i.projectId?String(i.projectId):void 0);case"agent:start-session":return this.doStartSession(i.input??{});case"agent:send-claimed-prompt":return this.sendClaimedPrompt(i);case"agent:send-prompt":{let n=String(i.sessionId),a=C(n);if(!a)throw new v("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await Se(n,r),this.notePromptAccepted(n,r,a.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await ye(String(i.sessionId));let s=C(String(i.sessionId));return s&&this.broadcastSessionStatus(s),{ok:!0};case"agent:get-transcript":return this.getTranscript(String(i.sessionId));case"agent:get-paths":return this.getPaths();case"agent:subscribe-events":return this.subscribeSocket(e,String(i.sessionId));case"agent:unsubscribe-events":return this.unsubscribeSocket(e,String(i.sessionId));default:throw new v("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async sendClaimedPrompt(e){let t=typeof e.simId=="string"?e.simId.trim():"";if(!t)throw new v("NO_SIM","agent:send-claimed-prompt requires simId");let i=this.opts.resolveCliLease?.(t)??null;if(!i||i.kind!=="cli"||i.expiresAt<=Date.now())throw new v("NO_CLAIM",`sim ${t} has no active CLI claim`);let s=W(i.cliIdentityKey);if(!s)throw new v("UNSUPPORTED_CLAIM",`sim ${t} is claimed by a CLI identity that is not promptable`);return await Ae({sessionId:s,prompt:this.normalizePromptEnvelope(e)}),{ok:!0,routed:"agentbus",sessionId:s}}async doStartSession(e){if(!le(e.projectId))throw new v("NO_PROJECT",`no project: ${e.projectId}`);let i=await ge(e);return this.broadcastSessionStatus(i.session),i}async autoAttachForUrl(e){let t=e.bundleUrl??"",i=(()=>{try{return new URL(t).port||null}catch{return null}})();if(!i)return{project:null};let s=this.opts.getExcludePorts?.()??We(),a=(await P({excludePorts:s})).find(l=>String(l.port)===i);if(!a||!a.cwd)return{project:null};let r=F().find(l=>l.cwd===a.cwd)??null,c=Array.from(new Set([...r?.knownBundleUrls??[],a.bundleUrl,t]));return{project:H({cwd:a.cwd,name:a.projectName??_.basename(a.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[a.cwd],knownBundleUrls:c,framework:r?.framework??$e(a.framework),bundleId:a.bundleId??r?.bundleId})}}getTranscript(e){let t=fe(e);return ke.existsSync(t)?ke.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=ce();return{userDataDir:e,storeFile:_.join(e,"attached-projects.json"),sessionsDir:_.join(e,"sessions"),transcriptsDir:_.join(e,"transcripts")}}subscribeSocket(e,t){let i=this.sessionsBySocket.get(e);if(i||(i=new Set,this.sessionsBySocket.set(e,i)),i.has(t))return{ok:!0,refCount:this.subscriptions.get(t)?.refCount??1};i.add(t);let s=this.subscriptions.get(t);if(s)return s.refCount++,{ok:!0,refCount:s.refCount};let n=ve(t,a=>{let r=this.coalescePromptEcho(t,a);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),a.type==="turn-completed"){let c=C(t);if(c)try{de(c.projectId,{usd:a.costUsd,ts:a.ts})}catch(d){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${d instanceof Error?d.message:String(d)}
4
- `)}}});return this.subscriptions.set(t,{unsubscribe:n,refCount:1}),{ok:!0,refCount:1}}unsubscribeSocket(e,t){let i=this.sessionsBySocket.get(e);return!i||!i.has(t)?{ok:!0,refCount:0}:(i.delete(t),this.decrementSubscription(t))}decrementSubscription(e){let t=this.subscriptions.get(e);if(!t)return{ok:!0,refCount:0};if(t.refCount--,t.refCount<=0){try{t.unsubscribe()}catch{}return this.subscriptions.delete(e),{ok:!0,refCount:0}}return{ok:!0,refCount:t.refCount}}dropSessionFanout(e){let t=this.subscriptions.get(e);if(t){try{t.unsubscribe()}catch{}this.subscriptions.delete(e)}for(let i of this.sessionsBySocket.values())i.delete(e);this.clearPromptTracking(e)}normalizePromptEnvelope(e){if(e?.prompt&&typeof e.prompt=="object"){let t=e.prompt;return{text:String(t.text??""),...typeof t.displayText=="string"?{displayText:t.displayText}:{},...typeof t.inspectSummary=="string"?{inspectSummary:t.inspectSummary}:{},...typeof t.inspectTrace=="string"?{inspectTrace:t.inspectTrace}:{}}}return{text:String(e?.text??""),...typeof e?.displayText=="string"?{displayText:e.displayText}:{},...typeof e?.inspectSummary=="string"?{inspectSummary:e.inspectSummary}:{},...typeof e?.inspectTrace=="string"?{inspectTrace:e.inspectTrace}:{}}}notePromptAccepted(e,t,i){let s=Date.now(),n=this.pendingPromptEchoes.get(e)??[];n.push({sentAt:s}),this.pendingPromptEchoes.set(e,n);let a=Math.max(this.pendingTurns.get(e)??0,i?1:0)+1;this.pendingTurns.set(e,a);let r=t.displayText??t.text;return this.patchSession(e,{lastPrompt:r,status:"working",needsAttention:!1}),this.fanOutEvent(e,{type:"prompt-received",text:r,...t.inspectSummary?{inspectSummary:t.inspectSummary}:{},...t.inspectTrace?{inspectTrace:t.inspectTrace}:{},ts:s}),{ok:!0,queued:a>1,pendingTurns:a,queueDepth:Math.max(0,a-1)}}applySessionEvent(e,t){switch(t.type){case"prompt-received":case"turn-started":this.patchSession(e,{status:"working",needsAttention:!1});return;case"turn-completed":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"idle",needsAttention:!1,lastTurnFiles:t.filesTouched,currentlyEditing:void 0});return}case"approval-needed":this.patchSession(e,{status:"needs-attention",needsAttention:!0});return;case"error":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"needs-attention",needsAttention:i<=0,currentlyEditing:void 0});return}case"exited":this.clearPromptTracking(e),this.patchSession(e,{status:"ended",needsAttention:!1,wrapperPid:void 0,currentlyEditing:void 0});return;case"ready":case"turn-reasoning":case"turn-message":case"turn-plan":case"tool-call":case"file-edited":case"file-diff-delta":return}}patchSession(e,t){me(e,t);let i=C(e);i&&this.broadcastSessionStatus(i)}coalescePromptEcho(e,t){if(t.type!=="prompt-received")return t;let i=this.pendingPromptEchoes.get(e);if(!i||i.length===0)return t;for(;i.length>0&&Date.now()-i[0].sentAt>15e3;)i.shift();return i.length===0?(this.pendingPromptEchoes.delete(e),t):(i.shift(),i.length===0?this.pendingPromptEchoes.delete(e):this.pendingPromptEchoes.set(e,i),null)}consumeSettledTurn(e){let t=Math.max(0,(this.pendingTurns.get(e)??1)-1);return t>0?this.pendingTurns.set(e,t):this.pendingTurns.delete(e),t}clearPromptTracking(e){this.pendingPromptEchoes.delete(e),this.pendingTurns.delete(e)}fanOutEvent(e,t){let i=JSON.stringify({type:"agent:event",sessionId:e,event:t});for(let[s,n]of this.sessionsBySocket)if(n.has(e)&&s.readyState===R)try{s.send(i)}catch{}}broadcastSessionStatus(e){let t=JSON.stringify({type:"agent:session-status",session:e});for(let i of this.allSockets)if(i.readyState===R)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===R)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,s){if(e.readyState===R)try{e.send(JSON.stringify({id:t,error:i,...s?{code:s}:{}}))}catch{}}};function $e(o){return o==="expo"?"expo":o==="one"||o==="vxrn"?"one":"unknown"}import Ke from"http";import Ve from"https";var $="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",je=[{hostSuffix:"uniswap.org",headers:{origin:"https://app.uniswap.org",referer:"https://app.uniswap.org/"},suppressBrowserUserAgent:!0}];function Je(o){let e=o.toLowerCase();for(let t of je)if(e===t.hostSuffix||e.endsWith(`.${t.hostSuffix}`))return t}function Ie(o){let e=Je(o.hostname);return{"accept-encoding":"identity",...e?.suppressBrowserUserAgent?{}:{"user-agent":$},...e?.headers}}var Ge=new Set(["host","origin","referer","user-agent","accept-encoding","cookie","connection","keep-alive","transfer-encoding","upgrade","content-length","sec-fetch-site","sec-fetch-mode","sec-fetch-dest","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform"]),qe={"access-control-allow-origin":"*","access-control-allow-methods":"GET,POST,PUT,DELETE,PATCH,OPTIONS","access-control-allow-headers":"*","access-control-expose-headers":"*","access-control-max-age":"3600"},ze=new Set(["host","origin","referer","sec-fetch-site","sec-fetch-mode","sec-fetch-dest"]);function T(o){for(let[e,t]of Object.entries(qe))o.setHeader(e,t)}function Xe(o,e){let t=[],i=e;i?.code&&t.push(i.code),i?.message&&t.push(i.message),i?.cause?.code&&t.push(i.cause.code),i?.cause?.message&&t.push(i.cause.message);let n=[...new Set(t.filter(Boolean))].join(" | ")||String(e);return o.includes("stored-in-.env.local")?`${n} | upstream url still contains placeholder env values`:n}function Ye(o){let t=(Array.isArray(o)?o[0]:o)?.split(";",1)[0]?.trim().toLowerCase();return t?t.startsWith("text/")||t==="application/json"||t.endsWith("+json")||t==="application/x-www-form-urlencoded"||t==="application/xml"||t.endsWith("+xml")||t==="application/javascript"||t==="application/graphql":!1}function Ze(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(Ge.has(i.toLowerCase())||(t[i]=Array.isArray(s)?s.join(", "):s));return Object.assign(t,e?Ie(e):{"user-agent":$}),t}function Qe(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(ze.has(i.toLowerCase())||(t[i]=s));return t.host=e.host,t.origin=e.origin,t.referer=`${e.origin}/`,t}function Ce(o){return o?.startsWith("/__fetch-proxy?")||o?.startsWith("/__proxy?")||!1}function Te(o){return o?!!(o.startsWith("/__app-api?")||o.startsWith("/__app-api/")):!1}async function Ee(o,e){if(o.method==="OPTIONS"){T(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((o.url||"").split("?")[1]||"").get("url");if(!i){T(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{T(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=Ze(o.headers,s),a;if(o.method!=="GET"&&o.method!=="HEAD"){let l=[];for await(let u of o)l.push(Buffer.isBuffer(u)?u:Buffer.from(u));if(l.length>0){let u=Buffer.concat(l);a=Ye(o.headers["content-type"])?u.toString("utf8"):u}}let r;try{r=await fetch(s.href,{method:o.method,headers:n,body:a,redirect:"follow"})}catch(l){T(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${Xe(s.href,l)}`);return}r.headers.forEach((l,u)=>{let p=u.toLowerCase();p==="content-encoding"||p==="transfer-encoding"||p==="content-length"||p==="set-cookie"||p.startsWith("access-control-")||e.setHeader(u,l)}),T(e);let c=r.headers.getSetCookie?.()??[];c.length>0&&e.setHeader("x-sootsim-set-cookie",c.join(", ")),e.statusCode=r.status;let d=Buffer.from(await r.arrayBuffer());e.end(d)}function Pe(o,e){let t=o.url||"",i="",s="";if(t.startsWith("/__app-api?")){let d=new URL(t,"http://sootsim.local");i=d.searchParams.get("path")||"",s=d.searchParams.get("origin")?.trim()||""}else if(t.startsWith("/__app-api/"))i=t.slice(10);else return!1;if(!s)return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: missing origin query param"),!0;if(o.method==="OPTIONS")return e.writeHead(204,{"Access-Control-Allow-Origin":o.headers.origin||"*","Access-Control-Allow-Methods":"GET,POST,PUT,PATCH,DELETE,OPTIONS","Access-Control-Allow-Headers":o.headers["access-control-request-headers"]||"*","Access-Control-Allow-Credentials":"true","Access-Control-Max-Age":"86400"}),e.end(),!0;let n;try{n=new URL(i,s)}catch{return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: invalid origin or path"),!0}let a=n.protocol==="https:"?Ve:Ke,r=Qe(o.headers,n),c=a.request({hostname:n.hostname,port:n.port||(n.protocol==="https:"?443:80),path:n.pathname+n.search,method:o.method,headers:r},d=>{let l=Object.keys(d.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(d.statusCode??502,{...d.headers,"access-control-allow-origin":o.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":l}),d.pipe(e)});return c.on("error",d=>{e.statusCode=502,e.end(`app proxy error: ${d.message}`)}),o.pipe(c),!0}import{WebSocket as k,WebSocketServer as et}from"ws";var tt="/__websocket-proxy",it=new Set(["host","connection","upgrade","transfer-encoding","content-length","sec-websocket-accept","sec-websocket-extensions","sec-websocket-key","sec-websocket-protocol","sec-websocket-version"]);function A(o,e,t){try{o.write(`HTTP/1.1 ${e} ${t}\r
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{b as le,c as H,d as de,e as F,f as ue,h as pe,i as C,j as me,k as he,l as fe,p as ge,s as v,t as Se,u as ye,v as ve,w as be}from"./chunk-JP7J325R.js";import"./chunk-Z5VMWFCY.js";import{a as ce}from"./chunk-BZ7AW7ZB.js";import"./chunk-TANTCV45.js";import{h as ae}from"./chunk-6FZ6SNVP.js";import{f as P,g as se}from"./chunk-WVDWIXPH.js";import"./chunk-CGJ2U6ST.js";import"./chunk-RJVIUQK4.js";import"./chunk-4NM6JBYH.js";import"./chunk-KRGHRSKY.js";import{d as oe}from"./chunk-DRJ4YWUG.js";import{a as ee,b as te}from"./chunk-KYGUR727.js";import"./chunk-RWXCSRNE.js";import{a as re,b as ne}from"./chunk-PL4GXELT.js";import"./chunk-RZQO4Q7E.js";import{E as J,G as E,H as K,I as V,J as D,L as G,M as q,O as z,Q as X,R as Y,S as Z,T as U,U as Q,y as M,z as j}from"./chunk-GZKT53SA.js";import{a as ie}from"./chunk-K3UBHPVP.js";import"./chunk-4KT2BGQE.js";import{spawn as ut}from"child_process";import I from"fs";import{createServer as pt}from"http";import S from"path";import{WebSocket as h,WebSocketServer as mt}from"ws";import Ie from"node:fs";import R from"node:path";import{spawn as Me}from"node:child_process";import De from"node:fs";import Ue from"node:os";import He from"node:path";var we=/^[A-Za-z0-9._:-]{1,160}$/;function W(o){if(!o?.startsWith("AGENTBUS_SESSION:"))return null;let e=o.slice(17).trim();return we.test(e)?e:null}function Ae(o){return we.test(o)}function Fe(o){return typeof o.text=="string"?o.text.trim():""}function We(o){let e=o?.trim();if(e)return e;let t=process.env.AGENTBUS_COMMAND?.trim();if(t)return t;let i=He.join(Ue.homedir(),".local","bin","agentbus");return De.existsSync(i)?i:"agentbus"}async function ke(o){let e=o.sessionId.trim();if(!Ae(e))throw new Error(`invalid agentbus session id: ${e||"<empty>"}`);let t=Fe(o.prompt);if(!t)throw new Error("prompt text is empty");let i=We(o.command),s=o.timeoutMs??15e3;await new Promise((n,a)=>{let r=Me(i,["send",e,t],{stdio:["ignore","ignore","pipe"],env:process.env}),c="",d=setTimeout(()=>{try{r.kill("SIGTERM")}catch{}a(new Error(`agentbus send timed out after ${Math.round(s/1e3)}s`))},s);r.stderr?.setEncoding("utf8"),r.stderr?.on("data",l=>{c.length<4e3&&(c+=String(l))}),r.on("error",l=>{clearTimeout(d),a(l)}),r.on("exit",(l,u)=>{if(clearTimeout(d),l===0){n();return}let p=c.trim();a(new Error(p||`agentbus send exited with ${u?`signal ${u}`:`code ${l??"unknown"}`}`))})})}var _=1;function $e(){return[Number(process.env.VITE_PORT_WEB||process.env.PORT||3e3),Number(process.env.VITE_PORT_ZERO||7849),Number(process.env.VITE_PORT_POSTGRES||7432),Number(process.env.VITE_PORT_R2||9500)].filter(o=>Number.isFinite(o)&&o>0)}var x=class{subscriptions=new Map;sessionsBySocket=new Map;allSockets=new Set;pendingPromptEchoes=new Map;pendingTurns=new Map;opts;constructor(e={}){this.opts=e}registerSocket(e){this.allSockets.add(e)}unregisterSocket(e){let t=this.sessionsBySocket.get(e);if(t){for(let i of t)this.decrementSubscription(i);this.sessionsBySocket.delete(e)}this.allSockets.delete(e)}async handleMessage(e,t){let i=t?.type;if(typeof i!="string"||!i.startsWith("agent:"))return!1;let s=t.id;try{let n=await this.dispatch(e,i,t);this.respond(e,s,n)}catch(n){n instanceof v?this.respondError(e,s,n.message,n.code):this.respondError(e,s,n instanceof Error?n.message:String(n))}return!0}async seedOnBoot(){try{await fe()}catch(e){process.stderr.write(`[sootsim-agent] seedFromDemoAppRegistry failed: ${e instanceof Error?e.message:String(e)}
3
+ `)}}close(){for(let e of this.subscriptions.values())try{e.unsubscribe()}catch{}this.subscriptions.clear(),this.sessionsBySocket.clear(),this.allSockets.clear()}async dispatch(e,t,i){switch(t){case"agent:list-projects":return F();case"agent:upsert-project":return H(i.input??{});case"agent:delete-project":return pe(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return me(i.projectId?String(i.projectId):void 0);case"agent:start-session":return this.doStartSession(i.input??{});case"agent:send-claimed-prompt":return this.sendClaimedPrompt(i);case"agent:send-prompt":{let n=String(i.sessionId),a=C(n);if(!a)throw new v("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await ye(n,r),this.notePromptAccepted(n,r,a.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await ve(String(i.sessionId));let s=C(String(i.sessionId));return s&&this.broadcastSessionStatus(s),{ok:!0};case"agent:get-transcript":return this.getTranscript(String(i.sessionId));case"agent:get-paths":return this.getPaths();case"agent:subscribe-events":return this.subscribeSocket(e,String(i.sessionId));case"agent:unsubscribe-events":return this.unsubscribeSocket(e,String(i.sessionId));default:throw new v("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async sendClaimedPrompt(e){let t=typeof e.simId=="string"?e.simId.trim():"";if(!t)throw new v("NO_SIM","agent:send-claimed-prompt requires simId");let i=this.opts.resolveCliLease?.(t)??null;if(!i||i.kind!=="cli"||i.expiresAt<=Date.now())throw new v("NO_CLAIM",`sim ${t} has no active CLI claim`);let s=W(i.cliIdentityKey);if(!s)throw new v("UNSUPPORTED_CLAIM",`sim ${t} is claimed by a CLI identity that is not promptable`);return await ke({sessionId:s,prompt:this.normalizePromptEnvelope(e)}),{ok:!0,routed:"agentbus",sessionId:s}}async doStartSession(e){if(!de(e.projectId))throw new v("NO_PROJECT",`no project: ${e.projectId}`);let i=await Se(e);return this.broadcastSessionStatus(i.session),i}async autoAttachForUrl(e){let t=e.bundleUrl??"",i=(()=>{try{return new URL(t).port||null}catch{return null}})();if(!i)return{project:null};let s=this.opts.getExcludePorts?.()??$e(),a=(await P({excludePorts:s})).find(l=>String(l.port)===i);if(!a||!a.cwd)return{project:null};let r=F().find(l=>l.cwd===a.cwd)??null,c=Array.from(new Set([...r?.knownBundleUrls??[],a.bundleUrl,t]));return{project:H({cwd:a.cwd,name:a.projectName??R.basename(a.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[a.cwd],knownBundleUrls:c,framework:r?.framework??je(a.framework),bundleId:a.bundleId??r?.bundleId})}}getTranscript(e){let t=ge(e);return Ie.existsSync(t)?Ie.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=le();return{userDataDir:e,storeFile:R.join(e,"attached-projects.json"),sessionsDir:R.join(e,"sessions"),transcriptsDir:R.join(e,"transcripts")}}subscribeSocket(e,t){let i=this.sessionsBySocket.get(e);if(i||(i=new Set,this.sessionsBySocket.set(e,i)),i.has(t))return{ok:!0,refCount:this.subscriptions.get(t)?.refCount??1};i.add(t);let s=this.subscriptions.get(t);if(s)return s.refCount++,{ok:!0,refCount:s.refCount};let n=be(t,a=>{let r=this.coalescePromptEcho(t,a);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),a.type==="turn-completed"){let c=C(t);if(c)try{ue(c.projectId,{usd:a.costUsd,ts:a.ts})}catch(d){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${d instanceof Error?d.message:String(d)}
4
+ `)}}});return this.subscriptions.set(t,{unsubscribe:n,refCount:1}),{ok:!0,refCount:1}}unsubscribeSocket(e,t){let i=this.sessionsBySocket.get(e);return!i||!i.has(t)?{ok:!0,refCount:0}:(i.delete(t),this.decrementSubscription(t))}decrementSubscription(e){let t=this.subscriptions.get(e);if(!t)return{ok:!0,refCount:0};if(t.refCount--,t.refCount<=0){try{t.unsubscribe()}catch{}return this.subscriptions.delete(e),{ok:!0,refCount:0}}return{ok:!0,refCount:t.refCount}}dropSessionFanout(e){let t=this.subscriptions.get(e);if(t){try{t.unsubscribe()}catch{}this.subscriptions.delete(e)}for(let i of this.sessionsBySocket.values())i.delete(e);this.clearPromptTracking(e)}normalizePromptEnvelope(e){if(e?.prompt&&typeof e.prompt=="object"){let t=e.prompt;return{text:String(t.text??""),...typeof t.displayText=="string"?{displayText:t.displayText}:{},...typeof t.inspectSummary=="string"?{inspectSummary:t.inspectSummary}:{},...typeof t.inspectTrace=="string"?{inspectTrace:t.inspectTrace}:{}}}return{text:String(e?.text??""),...typeof e?.displayText=="string"?{displayText:e.displayText}:{},...typeof e?.inspectSummary=="string"?{inspectSummary:e.inspectSummary}:{},...typeof e?.inspectTrace=="string"?{inspectTrace:e.inspectTrace}:{}}}notePromptAccepted(e,t,i){let s=Date.now(),n=this.pendingPromptEchoes.get(e)??[];n.push({sentAt:s}),this.pendingPromptEchoes.set(e,n);let a=Math.max(this.pendingTurns.get(e)??0,i?1:0)+1;this.pendingTurns.set(e,a);let r=t.displayText??t.text;return this.patchSession(e,{lastPrompt:r,status:"working",needsAttention:!1}),this.fanOutEvent(e,{type:"prompt-received",text:r,...t.inspectSummary?{inspectSummary:t.inspectSummary}:{},...t.inspectTrace?{inspectTrace:t.inspectTrace}:{},ts:s}),{ok:!0,queued:a>1,pendingTurns:a,queueDepth:Math.max(0,a-1)}}applySessionEvent(e,t){switch(t.type){case"prompt-received":case"turn-started":this.patchSession(e,{status:"working",needsAttention:!1});return;case"turn-completed":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"idle",needsAttention:!1,lastTurnFiles:t.filesTouched,currentlyEditing:void 0});return}case"approval-needed":this.patchSession(e,{status:"needs-attention",needsAttention:!0});return;case"error":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"needs-attention",needsAttention:i<=0,currentlyEditing:void 0});return}case"exited":this.clearPromptTracking(e),this.patchSession(e,{status:"ended",needsAttention:!1,wrapperPid:void 0,currentlyEditing:void 0});return;case"ready":case"turn-reasoning":case"turn-message":case"turn-plan":case"tool-call":case"file-edited":case"file-diff-delta":return}}patchSession(e,t){he(e,t);let i=C(e);i&&this.broadcastSessionStatus(i)}coalescePromptEcho(e,t){if(t.type!=="prompt-received")return t;let i=this.pendingPromptEchoes.get(e);if(!i||i.length===0)return t;for(;i.length>0&&Date.now()-i[0].sentAt>15e3;)i.shift();return i.length===0?(this.pendingPromptEchoes.delete(e),t):(i.shift(),i.length===0?this.pendingPromptEchoes.delete(e):this.pendingPromptEchoes.set(e,i),null)}consumeSettledTurn(e){let t=Math.max(0,(this.pendingTurns.get(e)??1)-1);return t>0?this.pendingTurns.set(e,t):this.pendingTurns.delete(e),t}clearPromptTracking(e){this.pendingPromptEchoes.delete(e),this.pendingTurns.delete(e)}fanOutEvent(e,t){let i=JSON.stringify({type:"agent:event",sessionId:e,event:t});for(let[s,n]of this.sessionsBySocket)if(n.has(e)&&s.readyState===_)try{s.send(i)}catch{}}broadcastSessionStatus(e){let t=JSON.stringify({type:"agent:session-status",session:e});for(let i of this.allSockets)if(i.readyState===_)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===_)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,s){if(e.readyState===_)try{e.send(JSON.stringify({id:t,error:i,...s?{code:s}:{}}))}catch{}}};function je(o){return o==="expo"?"expo":o==="one"||o==="vxrn"?"one":"unknown"}import Ve from"http";import Ge from"https";var $="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",Je=[{hostSuffix:"uniswap.org",headers:{origin:"https://app.uniswap.org",referer:"https://app.uniswap.org/"},suppressBrowserUserAgent:!0}];function Ke(o){let e=o.toLowerCase();for(let t of Je)if(e===t.hostSuffix||e.endsWith(`.${t.hostSuffix}`))return t}function Ce(o){let e=Ke(o.hostname);return{"accept-encoding":"identity",...e?.suppressBrowserUserAgent?{}:{"user-agent":$},...e?.headers}}var qe=new Set(["host","origin","referer","user-agent","accept-encoding","cookie","connection","keep-alive","transfer-encoding","upgrade","content-length","sec-fetch-site","sec-fetch-mode","sec-fetch-dest","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform"]),ze={"access-control-allow-origin":"*","access-control-allow-methods":"GET,POST,PUT,DELETE,PATCH,OPTIONS","access-control-allow-headers":"*","access-control-expose-headers":"*","access-control-max-age":"3600"},Xe=new Set(["host","origin","referer","sec-fetch-site","sec-fetch-mode","sec-fetch-dest"]);function T(o){for(let[e,t]of Object.entries(ze))o.setHeader(e,t)}function Ye(o,e){let t=[],i=e;i?.code&&t.push(i.code),i?.message&&t.push(i.message),i?.cause?.code&&t.push(i.cause.code),i?.cause?.message&&t.push(i.cause.message);let n=[...new Set(t.filter(Boolean))].join(" | ")||String(e);return o.includes("stored-in-.env.local")?`${n} | upstream url still contains placeholder env values`:n}function Ze(o){let t=(Array.isArray(o)?o[0]:o)?.split(";",1)[0]?.trim().toLowerCase();return t?t.startsWith("text/")||t==="application/json"||t.endsWith("+json")||t==="application/x-www-form-urlencoded"||t==="application/xml"||t.endsWith("+xml")||t==="application/javascript"||t==="application/graphql":!1}function Qe(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(qe.has(i.toLowerCase())||(t[i]=Array.isArray(s)?s.join(", "):s));return Object.assign(t,e?Ce(e):{"user-agent":$}),t}function et(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(Xe.has(i.toLowerCase())||(t[i]=s));return t.host=e.host,t.origin=e.origin,t.referer=`${e.origin}/`,t}function Te(o){return o?.startsWith("/__fetch-proxy?")||o?.startsWith("/__proxy?")||!1}function Ee(o){return o?!!(o.startsWith("/__app-api?")||o.startsWith("/__app-api/")):!1}async function Pe(o,e){if(o.method==="OPTIONS"){T(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((o.url||"").split("?")[1]||"").get("url");if(!i){T(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{T(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=Qe(o.headers,s),a;if(o.method!=="GET"&&o.method!=="HEAD"){let l=[];for await(let u of o)l.push(Buffer.isBuffer(u)?u:Buffer.from(u));if(l.length>0){let u=Buffer.concat(l);a=Ze(o.headers["content-type"])?u.toString("utf8"):u}}let r;try{r=await fetch(s.href,{method:o.method,headers:n,body:a,redirect:"follow"})}catch(l){T(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${Ye(s.href,l)}`);return}r.headers.forEach((l,u)=>{let p=u.toLowerCase();p==="content-encoding"||p==="transfer-encoding"||p==="content-length"||p==="set-cookie"||p.startsWith("access-control-")||e.setHeader(u,l)}),T(e);let c=r.headers.getSetCookie?.()??[];c.length>0&&e.setHeader("x-sootsim-set-cookie",c.join(", ")),e.statusCode=r.status;let d=Buffer.from(await r.arrayBuffer());e.end(d)}function Re(o,e){let t=o.url||"",i="",s="";if(t.startsWith("/__app-api?")){let d=new URL(t,"http://sootsim.local");i=d.searchParams.get("path")||"",s=d.searchParams.get("origin")?.trim()||""}else if(t.startsWith("/__app-api/"))i=t.slice(10);else return!1;if(!s)return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: missing origin query param"),!0;if(o.method==="OPTIONS")return e.writeHead(204,{"Access-Control-Allow-Origin":o.headers.origin||"*","Access-Control-Allow-Methods":"GET,POST,PUT,PATCH,DELETE,OPTIONS","Access-Control-Allow-Headers":o.headers["access-control-request-headers"]||"*","Access-Control-Allow-Credentials":"true","Access-Control-Max-Age":"86400"}),e.end(),!0;let n;try{n=new URL(i,s)}catch{return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: invalid origin or path"),!0}let a=n.protocol==="https:"?Ge:Ve,r=et(o.headers,n),c=a.request({hostname:n.hostname,port:n.port||(n.protocol==="https:"?443:80),path:n.pathname+n.search,method:o.method,headers:r},d=>{let l=Object.keys(d.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(d.statusCode??502,{...d.headers,"access-control-allow-origin":o.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":l}),d.pipe(e)});return c.on("error",d=>{e.statusCode=502,e.end(`app proxy error: ${d.message}`)}),o.pipe(c),!0}import{WebSocket as k,WebSocketServer as tt}from"ws";var it="/__websocket-proxy",rt=new Set(["host","connection","upgrade","transfer-encoding","content-length","sec-websocket-accept","sec-websocket-extensions","sec-websocket-key","sec-websocket-protocol","sec-websocket-version"]);function A(o,e,t){try{o.write(`HTTP/1.1 ${e} ${t}\r
5
5
  Connection: close\r
6
6
  Content-Type: text/plain\r
7
7
  Content-Length: ${t.length}\r
8
8
  \r
9
- ${t}`)}catch{}o.destroy()}function rt(o){let e=o.headers.origin,t=o.headers.host;if(!e||!t)return!1;try{return new URL(e).host===t}catch{return!1}}function nt(o){if(!o)return{};let e=o.replace(/-/g,"+").replace(/_/g,"/"),t=e+"=".repeat((4-e.length%4)%4),i=JSON.parse(Buffer.from(t,"base64").toString("utf8"));if(!i||typeof i!="object"||Array.isArray(i))return{};let s={};for(let[n,a]of Object.entries(i))a!=null&&(it.has(n.toLowerCase())||(s[n]=Array.isArray(a)?a.join(", "):String(a)));return s}function st(o){let e=new URL(o.href);return e.protocol=o.protocol==="wss:"?"https:":"http:",e.origin}function ot(o){let e=o.headers["sec-websocket-protocol"];return(Array.isArray(e)?e.join(","):e||"").split(",").map(i=>i.trim()).filter(Boolean)}function O(o,e,t){if(!(o.readyState===k.CLOSED||o.readyState===k.CLOSING))try{o.close(e,t)}catch{o.terminate()}}function at(o,e){let t=!1,i=(s,n,a,r)=>{t||(t=!0,O(n,a,r.toString()),s.readyState===k.OPEN&&O(s,a,r.toString()))};o.on("message",(s,n)=>{e.readyState===k.OPEN&&e.send(s,{binary:n})}),e.on("message",(s,n)=>{o.readyState===k.OPEN&&o.send(s,{binary:n})}),o.on("close",(s,n)=>i(o,e,s,n)),e.on("close",(s,n)=>i(e,o,s,n)),o.on("error",()=>O(e,1011,"proxy client error")),e.on("error",()=>O(o,1011,"upstream websocket error"))}function ct(o,e,t){let i={...t};return Object.keys(i).some(s=>s.toLowerCase()==="origin")||(i.origin=st(o)),new k(o.href,e,{headers:i})}function lt(o){if(!o)return!1;try{return new URL(o,"http://localhost").pathname===tt}catch{return!1}}function _e(o,e,t){if(!lt(o.url))return!1;if(!rt(o))return A(e,403,"forbidden websocket proxy origin"),!0;let i,s;try{let c=new URL(o.url||"/","http://localhost"),d=c.searchParams.get("url");if(!d)return A(e,400,"missing websocket proxy url"),!0;if(i=new URL(d),i.protocol!=="ws:"&&i.protocol!=="wss:")return A(e,400,"invalid websocket proxy protocol"),!0;s=nt(c.searchParams.get("headers"))}catch{return A(e,400,"invalid websocket proxy request"),!0}let n=ot(o),a=ct(i,n,s),r=!1;return e.once("close",()=>{r||a.terminate()}),a.once("open",()=>{if(r)return;r=!0;let c=a.protocol;new et({noServer:!0,clientTracking:!1,handleProtocols(l){return c||l.values().next().value||!1}}).handleUpgrade(o,e,t,l=>{at(l,a)})}),a.once("error",()=>{r||(r=!0,A(e,502,"upstream websocket error"))}),a.once("close",()=>{r||(r=!0,A(e,502,"upstream websocket closed"))}),!0}var mt="require-corp",ht=new Set(["tap","keyboard"]),ft=2e3,gt=1e3;function St(o){return!o||typeof o.type!="string"?!1:o.acquireLock===!0?!0:o.readOnly===!0?!1:ht.has(o.type)}var Re=5e3,yt=3600*1e3,vt="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",bt={".html":"text/html; charset=utf-8",".js":"application/javascript",".cjs":"application/javascript",".mjs":"application/javascript",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".wasm":"application/wasm",".ttf":"font/ttf",".otf":"font/otf",".woff":"font/woff",".woff2":"font/woff2",".map":"application/json",".txt":"text/plain; charset=utf-8"};function xe(o,e,t){let i;try{let c=M();i=JSON.stringify(c)}catch{i="{}"}let s=e>0?`window.__sootsimBridgePort=${e};`:"",n=t?`window.__sootsimSootbeanOrigin=${JSON.stringify(t)};`:"",a=`<script>window.__sootsimSharedConfig=${i};`+s+n+`window.__sootsimCliVersion=${JSON.stringify(te())};</script>`,r=o.toString("utf8");return r.includes("<head>")?r.replace("<head>",`<head>${a}`):r.includes("</head>")?r.replace("</head>",a+"</head>"):r.includes("</body>")?r.replace("</body>",a+"</body>"):a+r}function Oe(o){typeof o=="object"&&o!==null&&"unref"in o&&o.unref()}var L=class o{port;openUrlHandler;httpServer=null;wss=null;nextCommandId=1;nextSimNumber=161;sims=new Map;primarySimId=null;pendingCommands=new Map;cliBySentId=new Map;cliSimBySocket=new Map;cliLastCommandAt=new Map;cliIdentityKeyBySocket=new Map;cliLabelBySocket=new Map;restorableSims=new Map;nextCliFallbackId=1;cliIdleTimer=null;agentHost;static CLI_IDLE_TIMEOUT_MS=6e4;static CLI_LEASE_TTL_MS=6e5;static USER_ACTIVE_LEASE_TTL_MS=8e3;static USER_BOOT_LEASE_TTL_MS=6e4;static SIM_RECONNECT_TTL_MS=3e4;static SIM_IDLE_REAP_TTL_MS=30*6e4;static AUTOMATION_SIM_IDLE_REAP_TTL_MS=10*6e4;static MAX_CONCURRENT_AUTOMATION_SIMS=6;static AUTOMATION_SIM_ACTIVE_GRACE_MS=6e4;preferredPort;portFallbackCount;simIdleReapTtlMs;automationSimIdleReapTtlMs;maxConcurrentAutomationSims;automationSimActiveGraceMs;shouldWriteLockfile;shouldWriteDevLockfile;getShellPort;sootbeanOrigin=null;effectivePort=0;startedAt=0;heartbeatTimer=null;devHeartbeatTimer=null;wsHeartbeatTimer=null;wsIsAlive=new WeakMap;static WS_HEARTBEAT_INTERVAL_MS=3e4;runtimeUpdateTimer=null;runtimeUpdateInFlight=null;activeRuntimeVersion=null;activeRuntimeDirPath=null;scanCache=null;scanCacheAt=0;inflightScan=null;static SCAN_FRESH_MS=2e3;constructor(e={}){this.preferredPort=e.port||7668,this.port=this.preferredPort,this.shouldWriteLockfile=e.writeLockfile===!0,this.shouldWriteDevLockfile=e.writeDevLockfile===!0,this.getShellPort=e.getShellPort??null,this.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new x({getExcludePorts:e.agentScanExcludes,resolveCliLease:t=>{let i=this.sims.get(t),s=i?this.getActiveLease(i):null;return s?{kind:s.kind,cliIdentityKey:s.cliIdentityKey,expiresAt:s.expiresAt}:null}}),this.sootbeanOrigin=e.sootbeanOrigin?.replace(/\/$/,"")||null,this.simIdleReapTtlMs=e.simIdleReapTtlMs??o.SIM_IDLE_REAP_TTL_MS,this.automationSimIdleReapTtlMs=e.automationSimIdleReapTtlMs??o.AUTOMATION_SIM_IDLE_REAP_TTL_MS,this.maxConcurrentAutomationSims=e.maxConcurrentAutomationSims??o.MAX_CONCURRENT_AUTOMATION_SIMS,this.automationSimActiveGraceMs=e.automationSimActiveGraceMs??o.AUTOMATION_SIM_ACTIVE_GRACE_MS}getAgentHost(){return this.agentHost}reapIdleSimsForTest(e=Date.now()){this.reapIdleSims(e)}start(e){this.startAsync(e)}async startAsync(e){if(this.httpServer||this.wss)return this.effectivePort;this.refreshActiveRuntime();for(let t=0;t<this.portFallbackCount;t++){let i=this.preferredPort+t;try{return await this.bindOnce(i,e?.silent===!0),this.effectivePort=i,this.port=i,this.startedAt=Date.now(),t>0&&!e?.silent&&process.stderr.write(`ws bridge bound to port ${i} (preferred ${this.preferredPort} was taken)
9
+ ${t}`)}catch{}o.destroy()}function nt(o){let e=o.headers.origin,t=o.headers.host;if(!e||!t)return!1;try{return new URL(e).host===t}catch{return!1}}function st(o){if(!o)return{};let e=o.replace(/-/g,"+").replace(/_/g,"/"),t=e+"=".repeat((4-e.length%4)%4),i=JSON.parse(Buffer.from(t,"base64").toString("utf8"));if(!i||typeof i!="object"||Array.isArray(i))return{};let s={};for(let[n,a]of Object.entries(i))a!=null&&(rt.has(n.toLowerCase())||(s[n]=Array.isArray(a)?a.join(", "):String(a)));return s}function ot(o){let e=new URL(o.href);return e.protocol=o.protocol==="wss:"?"https:":"http:",e.origin}function at(o){let e=o.headers["sec-websocket-protocol"];return(Array.isArray(e)?e.join(","):e||"").split(",").map(i=>i.trim()).filter(Boolean)}function O(o,e,t){if(!(o.readyState===k.CLOSED||o.readyState===k.CLOSING))try{o.close(e,t)}catch{o.terminate()}}function ct(o,e){let t=!1,i=(s,n,a,r)=>{t||(t=!0,O(n,a,r.toString()),s.readyState===k.OPEN&&O(s,a,r.toString()))};o.on("message",(s,n)=>{e.readyState===k.OPEN&&e.send(s,{binary:n})}),e.on("message",(s,n)=>{o.readyState===k.OPEN&&o.send(s,{binary:n})}),o.on("close",(s,n)=>i(o,e,s,n)),e.on("close",(s,n)=>i(e,o,s,n)),o.on("error",()=>O(e,1011,"proxy client error")),e.on("error",()=>O(o,1011,"upstream websocket error"))}function lt(o,e,t){let i={...t};return Object.keys(i).some(s=>s.toLowerCase()==="origin")||(i.origin=ot(o)),new k(o.href,e,{headers:i})}function dt(o){if(!o)return!1;try{return new URL(o,"http://localhost").pathname===it}catch{return!1}}function _e(o,e,t){if(!dt(o.url))return!1;if(!nt(o))return A(e,403,"forbidden websocket proxy origin"),!0;let i,s;try{let c=new URL(o.url||"/","http://localhost"),d=c.searchParams.get("url");if(!d)return A(e,400,"missing websocket proxy url"),!0;if(i=new URL(d),i.protocol!=="ws:"&&i.protocol!=="wss:")return A(e,400,"invalid websocket proxy protocol"),!0;s=st(c.searchParams.get("headers"))}catch{return A(e,400,"invalid websocket proxy request"),!0}let n=at(o),a=lt(i,n,s),r=!1;return e.once("close",()=>{r||a.terminate()}),a.once("open",()=>{if(r)return;r=!0;let c=a.protocol;new tt({noServer:!0,clientTracking:!1,handleProtocols(l){return c||l.values().next().value||!1}}).handleUpgrade(o,e,t,l=>{ct(l,a)})}),a.once("error",()=>{r||(r=!0,A(e,502,"upstream websocket error"))}),a.once("close",()=>{r||(r=!0,A(e,502,"upstream websocket closed"))}),!0}var ht="require-corp",ft=new Set(["tap","keyboard"]),gt=2e3,St=1e3;function yt(o){return!o||typeof o.type!="string"?!1:o.acquireLock===!0?!0:o.readOnly===!0?!1:ft.has(o.type)}var xe=5e3,vt=3600*1e3,bt="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",wt={".html":"text/html; charset=utf-8",".js":"application/javascript",".cjs":"application/javascript",".mjs":"application/javascript",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".wasm":"application/wasm",".ttf":"font/ttf",".otf":"font/otf",".woff":"font/woff",".woff2":"font/woff2",".map":"application/json",".txt":"text/plain; charset=utf-8"};function Oe(o,e,t){let i;try{let c=M();i=JSON.stringify(c)}catch{i="{}"}let s=e>0?`window.__sootsimBridgePort=${e};`:"",n=t?`window.__sootsimSootbeanOrigin=${JSON.stringify(t)};`:"",a=`<script>window.__sootsimSharedConfig=${i};`+s+n+`window.__sootsimCliVersion=${JSON.stringify(ie())};</script>`,r=o.toString("utf8");return r.includes("<head>")?r.replace("<head>",`<head>${a}`):r.includes("</head>")?r.replace("</head>",a+"</head>"):r.includes("</body>")?r.replace("</body>",a+"</body>"):a+r}function Le(o){typeof o=="object"&&o!==null&&"unref"in o&&o.unref()}var L=class o{port;openUrlHandler;httpServer=null;wss=null;nextCommandId=1;nextSimNumber=161;sims=new Map;primarySimId=null;pendingCommands=new Map;cliBySentId=new Map;cliSimBySocket=new Map;cliLastCommandAt=new Map;cliIdentityKeyBySocket=new Map;cliLabelBySocket=new Map;restorableSims=new Map;nextCliFallbackId=1;cliIdleTimer=null;agentHost;static CLI_IDLE_TIMEOUT_MS=6e4;static CLI_LEASE_TTL_MS=6e5;static USER_ACTIVE_LEASE_TTL_MS=8e3;static USER_BOOT_LEASE_TTL_MS=6e4;static SIM_RECONNECT_TTL_MS=3e4;static SIM_IDLE_REAP_TTL_MS=30*6e4;static AUTOMATION_SIM_IDLE_REAP_TTL_MS=10*6e4;static MAX_CONCURRENT_AUTOMATION_SIMS=6;static AUTOMATION_SIM_ACTIVE_GRACE_MS=6e4;preferredPort;portFallbackCount;simIdleReapTtlMs;automationSimIdleReapTtlMs;maxConcurrentAutomationSims;automationSimActiveGraceMs;shouldWriteLockfile;shouldWriteDevLockfile;getShellPort;sootbeanOrigin=null;effectivePort=0;startedAt=0;heartbeatTimer=null;devHeartbeatTimer=null;wsHeartbeatTimer=null;wsIsAlive=new WeakMap;static WS_HEARTBEAT_INTERVAL_MS=3e4;runtimeUpdateTimer=null;runtimeUpdateInFlight=null;activeRuntimeVersion=null;activeRuntimeDirPath=null;scanCache=null;scanCacheAt=0;inflightScan=null;static SCAN_FRESH_MS=2e3;constructor(e={}){this.preferredPort=e.port||7668,this.port=this.preferredPort,this.shouldWriteLockfile=e.writeLockfile===!0,this.shouldWriteDevLockfile=e.writeDevLockfile===!0,this.getShellPort=e.getShellPort??null,this.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new x({getExcludePorts:e.agentScanExcludes,resolveCliLease:t=>{let i=this.sims.get(t),s=i?this.getActiveLease(i):null;return s?{kind:s.kind,cliIdentityKey:s.cliIdentityKey,expiresAt:s.expiresAt}:null}}),this.sootbeanOrigin=e.sootbeanOrigin?.replace(/\/$/,"")||null,this.simIdleReapTtlMs=e.simIdleReapTtlMs??o.SIM_IDLE_REAP_TTL_MS,this.automationSimIdleReapTtlMs=e.automationSimIdleReapTtlMs??o.AUTOMATION_SIM_IDLE_REAP_TTL_MS,this.maxConcurrentAutomationSims=e.maxConcurrentAutomationSims??o.MAX_CONCURRENT_AUTOMATION_SIMS,this.automationSimActiveGraceMs=e.automationSimActiveGraceMs??o.AUTOMATION_SIM_ACTIVE_GRACE_MS}getAgentHost(){return this.agentHost}reapIdleSimsForTest(e=Date.now()){this.reapIdleSims(e)}start(e){this.startAsync(e)}async startAsync(e){if(this.httpServer||this.wss)return this.effectivePort;this.refreshActiveRuntime();for(let t=0;t<this.portFallbackCount;t++){let i=this.preferredPort+t;try{return await this.bindOnce(i,e?.silent===!0),this.effectivePort=i,this.port=i,this.startedAt=Date.now(),t>0&&!e?.silent&&process.stderr.write(`ws bridge bound to port ${i} (preferred ${this.preferredPort} was taken)
10
10
  `),this.afterBind(),i}catch(s){if(s?.code!=="EADDRINUSE")throw s;e?.silent||process.stderr.write(`ws bridge port ${i} already in use, trying ${i+1}
11
- `)}}throw new Error(`could not bind ws bridge after ${this.portFallbackCount} attempts starting at ${this.preferredPort}`)}bindOnce(e,t){return new Promise((i,s)=>{let n=ut((c,d)=>this.handleHttpRequest(c,d)),a=!1,r=c=>{if(!a){a=!0;try{n.close()}catch{}this.httpServer=null,this.wss=null,s(c)}};n.once("error",r),n.listen(e,"127.0.0.1",()=>{a||(a=!0,n.removeListener("error",r),n.on("error",c=>{process.stderr.write(`ws bridge http error: ${String(c)}
12
- `)}),this.httpServer=n,this.wss=new pt({noServer:!0}),this.wireWebSocketServer(),n.on("upgrade",(c,d,l)=>{_e(c,d,l)||this.wss?.handleUpgrade(c,d,l,u=>{this.wss?.emit("connection",u,c)})}),i())})})}wireWebSocketServer(){this.wss&&this.wss.on("connection",(e,t)=>{let i=t.headers.origin,s=i?"sim":"cli",n=null;if(e.on("error",()=>{}),this.wsIsAlive.set(e,!0),e.on("pong",()=>{this.wsIsAlive.set(e,!0)}),this.agentHost.registerSocket(e),s==="sim")n={id:this.allocateSimId(),ws:e,origin:i,connectedAt:Date.now(),lastSeenAt:Date.now(),lastActiveAt:0,recentActions:[]},this.sims.set(n.id,n),this.shouldPromoteSim(n)&&(this.primarySimId=n.id),this.broadcastSimAssignments(),this.broadcastSimClientStates();else{let a=`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,a)}e.on("message",a=>{let r;try{r=JSON.parse(a.toString())}catch{return}if(!(!r||typeof r!="object")){if(typeof r.type=="string"&&r.type.startsWith("agent:")){this.agentHost.handleMessage(e,r);return}if(r.type==="runtime:list"){let c=D(),d=this.getActiveRuntime(),l={type:"runtime:list:ok",id:r.id,installed:c,active:d.version,activeRuntimeDir:d.runtimeDir};try{e.send(JSON.stringify(l))}catch{}return}if(r.type==="runtime:use"){let c=typeof r.version=="string"?r.version:"";if(!D().includes(c)){try{e.send(JSON.stringify({type:"runtime:use:error",id:r.id,error:`runtime ${c||"(missing)"} is not installed`}))}catch{}return}let l=this.setActiveRuntime(c);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:l.version,runtimeDir:l.runtimeDir}))}catch{}return}if(r.type==="runtime:get"){let c=this.getActiveRuntime();try{e.send(JSON.stringify({type:"runtime:get:ok",id:r.id,active:c.version,activeRuntimeDir:c.runtimeDir}))}catch{}return}if(s==="sim"){if(n&&(n.lastSeenAt=Date.now()),r.type==="bridge:register"&&n){let l=r,u=this.tryRestoreSimId(n,l.simId);n.url=l.url,n.title=l.title,n.userAgent=l.userAgent,typeof l.kind=="string"&&l.kind.trim()&&(n.kind=l.kind.trim()),l.meta&&typeof l.meta=="object"&&(n.meta=l.meta);let p=this.primarySimId!==n.id&&this.shouldPromoteSim(n);p&&(this.primarySimId=n.id),(u||p)&&(this.broadcastSimAssignments(),this.broadcastSimClientStates());return}if(r.type==="bridge:user-focus-state"&&n){let l=r;this.updateUserFocusLease(n,l);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){let l=r.patch&&typeof r.patch=="object"?r.patch:null;if(!l)return;let u;try{u=j(l)}catch(m){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${m instanceof Error?m.message:String(m)}
11
+ `)}}throw new Error(`could not bind ws bridge after ${this.portFallbackCount} attempts starting at ${this.preferredPort}`)}bindOnce(e,t){return new Promise((i,s)=>{let n=pt((c,d)=>this.handleHttpRequest(c,d)),a=!1,r=c=>{if(!a){a=!0;try{n.close()}catch{}this.httpServer=null,this.wss=null,s(c)}};n.once("error",r),n.listen(e,"127.0.0.1",()=>{a||(a=!0,n.removeListener("error",r),n.on("error",c=>{process.stderr.write(`ws bridge http error: ${String(c)}
12
+ `)}),this.httpServer=n,this.wss=new mt({noServer:!0}),this.wireWebSocketServer(),n.on("upgrade",(c,d,l)=>{_e(c,d,l)||this.wss?.handleUpgrade(c,d,l,u=>{this.wss?.emit("connection",u,c)})}),i())})})}wireWebSocketServer(){this.wss&&this.wss.on("connection",(e,t)=>{let i=t.headers.origin,s=i?"sim":"cli",n=null;if(e.on("error",()=>{}),this.wsIsAlive.set(e,!0),e.on("pong",()=>{this.wsIsAlive.set(e,!0)}),this.agentHost.registerSocket(e),s==="sim")n={id:this.allocateSimId(),ws:e,origin:i,connectedAt:Date.now(),lastSeenAt:Date.now(),lastActiveAt:0,recentActions:[]},this.sims.set(n.id,n),this.shouldPromoteSim(n)&&(this.primarySimId=n.id),this.broadcastSimAssignments(),this.broadcastSimClientStates();else{let a=`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,a)}e.on("message",a=>{let r;try{r=JSON.parse(a.toString())}catch{return}if(!(!r||typeof r!="object")){if(typeof r.type=="string"&&r.type.startsWith("agent:")){this.agentHost.handleMessage(e,r);return}if(r.type==="runtime:list"){let c=D(),d=this.getActiveRuntime(),l={type:"runtime:list:ok",id:r.id,installed:c,active:d.version,activeRuntimeDir:d.runtimeDir};try{e.send(JSON.stringify(l))}catch{}return}if(r.type==="runtime:use"){let c=typeof r.version=="string"?r.version:"";if(!D().includes(c)){try{e.send(JSON.stringify({type:"runtime:use:error",id:r.id,error:`runtime ${c||"(missing)"} is not installed`}))}catch{}return}let l=this.setActiveRuntime(c);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:l.version,runtimeDir:l.runtimeDir}))}catch{}return}if(r.type==="runtime:get"){let c=this.getActiveRuntime();try{e.send(JSON.stringify({type:"runtime:get:ok",id:r.id,active:c.version,activeRuntimeDir:c.runtimeDir}))}catch{}return}if(s==="sim"){if(n&&(n.lastSeenAt=Date.now()),r.type==="bridge:register"&&n){let l=r,u=this.tryRestoreSimId(n,l.simId);n.url=l.url,n.title=l.title,n.userAgent=l.userAgent,typeof l.kind=="string"&&l.kind.trim()&&(n.kind=l.kind.trim()),l.meta&&typeof l.meta=="object"&&(n.meta=l.meta);let p=this.primarySimId!==n.id&&this.shouldPromoteSim(n);p&&(this.primarySimId=n.id),(u||p)&&(this.broadcastSimAssignments(),this.broadcastSimClientStates());return}if(r.type==="bridge:user-focus-state"&&n){let l=r;this.updateUserFocusLease(n,l);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){let l=r.patch&&typeof r.patch=="object"?r.patch:null;if(!l)return;let u;try{u=j(l)}catch(m){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${m instanceof Error?m.message:String(m)}
13
13
  `);return}let p=JSON.stringify({type:"bridge:shared-config-changed",config:u});for(let m of this.sims.values())if(m.ws.readyState===h.OPEN)try{m.ws.send(p)}catch{}return}if(r.type==="bridge:open-path"){let l=typeof r.path=="string"?r.path:"",u=typeof r.line=="number"&&Number.isFinite(r.line)?r.line:void 0,p=typeof r.column=="number"&&Number.isFinite(r.column)?r.column:void 0;l&&this.openPathInEditor(l,u,p);return}if(r.type==="bridge:boot-clients"&&n){let l=[];for(let[p,m]of this.cliSimBySocket)m===n.id&&l.push(p);for(let p of l){this.cliSimBySocket.delete(p);try{p.close(1e3,"booted by sim")}catch{}}let u=!!n.cliLease;n.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:Date.now()+o.USER_BOOT_LEASE_TTL_MS},process.stderr.write(`sootsim booted ${l.length} cli client(s)${u?" (overrode prior lease)":""}; held sim for user [${n.id}]
14
- `),this.recordSimAction(n.id,"sim booted cli clients"),this.broadcastSimClientStates();return}let c=this.pendingCommands.get(r.id);if(c){this.pendingCommands.delete(r.id),r.error?c.reject(new Error(r.error)):c.resolve(r.result);return}let d=this.cliBySentId.get(r.id);if(d&&(this.cliBySentId.delete(r.id),d.ws.readyState===h.OPEN)){let l=this.getOtherCliIdentityCount(d.ws,d.simId),u=l>0?{...r,id:d.originalId,_otherCliCount:l}:{...r,id:d.originalId};d.ws.send(JSON.stringify(u))}return}(async()=>{this.cliLastCommandAt.set(e,Date.now());try{if(r.type==="bridge:bye"){let p=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[m,f]of this.cliBySentId)f.ws===e&&this.cliBySentId.delete(m);p&&this.broadcastSimClientStates();return}if(r.type==="bridge:hello"){let p=typeof r.cliIdentityKey=="string"&&r.cliIdentityKey.trim()?r.cliIdentityKey.trim():this.cliIdentityKeyBySocket.get(e)||`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,p),typeof r.cliLabel=="string"&&r.cliLabel.trim()&&this.cliLabelBySocket.set(e,r.cliLabel.trim()),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{cliIdentityKey:p,leaseTtlMs:o.CLI_LEASE_TTL_MS,leasing:!0}}));return}if(r.type==="bridge:list-sims"){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:this.listSims()}));return}if(r.type==="bridge:open"){if(typeof r.url!="string"||!r.url)throw new Error("bridge:open requires a url");await this.openUrl(r.url,{newWindow:r.newWindow===!0}),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{ok:!0,url:r.url}}));return}if(r.type==="bridge:claim"){let p=await this.waitForSim(r.simId),m=this.tryAcquireLease(e,p,{force:r.force===!0});if(!m.granted){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${p.id} is locked by another cli`,_locked:m.lock}));return}this.setCliSimTarget(e,p.id),this.recordSimAction(p.id,m.bootedCount>0?`cli force-claimed sim (booted ${m.bootedCount})`:"cli claimed sim"),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{simId:p.id,lockedBy:m.lease.cliIdentityKey,lockExpiresAt:m.lease.expiresAt,bootedCount:m.bootedCount}}));return}let c=await this.waitForSim(r.simId);if(St(r)){let p=this.tryAcquireLease(e,c);if(!p.granted){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${c.id} is locked by another cli \u2014 use \`sootsim claim ${c.id} --force\` or \`sootsim open --new\``,_locked:p.lock}));return}}else this.ensureCliIdentityKey(e);this.setCliSimTarget(e,c.id),this.recordSimAction(c.id,this.describeForwardedCommand(r));let d=this.nextCommandId++;this.cliBySentId.set(d,{simId:c.id,ws:e,originalId:r.id});let{simId:l,...u}=r;if(c.ws.send(JSON.stringify({...u,id:d})),u.type==="close"){this.cliBySentId.delete(d),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{requested:!0,simId:c.id}}));let p=c.ws,m=setTimeout(()=>{this.closeSimSocketFromHost(p)},ft);Oe(m)}}catch(c){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:c instanceof Error?c.message:String(c)}))}})()}}),e.on("close",()=>{if(this.agentHost.unregisterSocket(e),s==="sim"&&n){this.rememberDisconnectedSim(n),this.primarySimId===n.id&&(this.primarySimId=this.getOpenSim()?.id??null);for(let[a,r]of this.pendingCommands)r.simId===n.id&&(r.reject(new Error("sim disconnected")),this.pendingCommands.delete(a));for(let[a,r]of this.cliBySentId)r.simId===n.id&&(r.ws.readyState===h.OPEN&&r.ws.send(JSON.stringify({id:r.originalId,error:"sim disconnected before responding"})),this.cliBySentId.delete(a));this.broadcastSimAssignments(),this.broadcastSimClientStates()}else if(s==="cli"){let a=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[r,c]of this.cliBySentId)c.ws===e&&this.cliBySentId.delete(r);a&&this.broadcastSimClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
15
- `),this.cliIdleTimer=setInterval(()=>this.sweepIdleCliClients(),3e4),this.cliIdleTimer.unref(),this.wsHeartbeatTimer=setInterval(()=>this.sweepDeadWebSockets(),o.WS_HEARTBEAT_INTERVAL_MS),this.wsHeartbeatTimer.unref(),this.shouldWriteLockfile){try{if(E(),!Y(this.buildLockfileSnapshot()))throw new Error("another sootsim daemon wrote the lockfile during startup \u2014 aborting")}catch(e){throw process.stderr.write(`ws bridge failed to claim daemon lockfile: ${String(e)}
16
- `),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},Re),this.heartbeatTimer.unref(),this.startRuntimeUpdater()}if(this.shouldWriteDevLockfile){try{this.writeDevLockfileSnapshot()}catch(e){process.stderr.write(`ws bridge failed to write dev bridge lockfile: ${String(e)}
17
- `)}this.devHeartbeatTimer=setInterval(()=>{try{this.writeDevLockfileSnapshot()}catch{}},Re),this.devHeartbeatTimer.unref()}this.agentHost.seedOnBoot()}bootstrapping=!0;buildLockfileSnapshot(){return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,activeRuntimeDir:this.activeRuntimeDirPath,startedAt:this.startedAt,heartbeatAt:Date.now(),bootstrapping:this.bootstrapping}}buildDevLockfileSnapshot(){let e=this.getShellPort?.()??null;return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,...e&&e>0?{shellPort:e}:{},cwd:process.cwd(),startedAt:this.startedAt,heartbeatAt:Date.now(),source:"vite-dev"}}writeLockfileSnapshot(){z(this.buildLockfileSnapshot())}writeDevLockfileSnapshot(){X(this.buildDevLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=J(),this.activeRuntimeDirPath=ne()??V()}runServerScan(){if(this.inflightScan)return this.inflightScan;let e=this.effectivePort>0?[this.effectivePort]:[];return this.inflightScan=P({excludePorts:e,buildIconProxyUrl:t=>`/__bundle-proxy?url=${encodeURIComponent(t)}`}).then(t=>(this.scanCache=t,this.scanCacheAt=Date.now(),t)).catch(t=>{let i=t instanceof Error?t.message:String(t);return console.error("[sootsim] /__server-scan failed:",i),this.scanCache??[]}).finally(()=>{this.inflightScan=null}),this.inflightScan}handleServerScan(e){let t=s=>{e.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(s))},i=Date.now()-this.scanCacheAt;if(this.scanCache&&i<o.SCAN_FRESH_MS){t(this.scanCache);return}if(this.scanCache){t(this.scanCache),this.runServerScan().catch(()=>{});return}this.runServerScan().then(s=>t(s))}resolveRuntimeUpdateIntervalMs(){let e=Number(process.env[vt]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):yt}startRuntimeUpdater(){if(!this.shouldWriteLockfile||this.runtimeUpdateTimer)return;this.runRuntimeUpdate("startup");let e=this.resolveRuntimeUpdateIntervalMs();this.runtimeUpdateTimer=setInterval(()=>{this.runRuntimeUpdate("periodic")},e),this.runtimeUpdateTimer.unref()}runRuntimeUpdate(e){return this.runtimeUpdateInFlight?this.runtimeUpdateInFlight:(this.runtimeUpdateInFlight=(async()=>{try{e==="startup"&&process.stderr.write(`sootsim: checking for runtime updates\u2026
18
- `);let t=await oe();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
19
- `);return}let i=this.setActiveRuntime(t.latestVersion);process.stderr.write(`sootsim runtime updated to ${i.version} (${e})
20
- `)}catch(t){process.stderr.write(`sootsim runtime update failed (${e}): ${t instanceof Error?t.message:String(t)}
14
+ `),this.recordSimAction(n.id,"sim booted cli clients"),this.broadcastSimClientStates();return}let c=this.pendingCommands.get(r.id);if(c){this.pendingCommands.delete(r.id),r.error?c.reject(new Error(r.error)):c.resolve(r.result);return}let d=this.cliBySentId.get(r.id);if(d&&(this.cliBySentId.delete(r.id),d.ws.readyState===h.OPEN)){let l=this.getOtherCliIdentityCount(d.ws,d.simId),u=l>0?{...r,id:d.originalId,_otherCliCount:l}:{...r,id:d.originalId};d.ws.send(JSON.stringify(u))}return}(async()=>{this.cliLastCommandAt.set(e,Date.now());try{if(r.type==="bridge:bye"){let p=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[m,f]of this.cliBySentId)f.ws===e&&this.cliBySentId.delete(m);p&&this.broadcastSimClientStates();return}if(r.type==="bridge:hello"){let p=typeof r.cliIdentityKey=="string"&&r.cliIdentityKey.trim()?r.cliIdentityKey.trim():this.cliIdentityKeyBySocket.get(e)||`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,p),typeof r.cliLabel=="string"&&r.cliLabel.trim()&&this.cliLabelBySocket.set(e,r.cliLabel.trim()),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{cliIdentityKey:p,leaseTtlMs:o.CLI_LEASE_TTL_MS,leasing:!0}}));return}if(r.type==="bridge:list-sims"){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:this.listSims()}));return}if(r.type==="bridge:open"){if(typeof r.url!="string"||!r.url)throw new Error("bridge:open requires a url");await this.openUrl(r.url,{newWindow:r.newWindow===!0}),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{ok:!0,url:r.url}}));return}if(r.type==="bridge:claim"){let p=await this.waitForSim(r.simId),m=this.tryAcquireLease(e,p,{force:r.force===!0});if(!m.granted){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${p.id} is locked by another cli`,_locked:m.lock}));return}this.setCliSimTarget(e,p.id),this.recordSimAction(p.id,m.bootedCount>0?`cli force-claimed sim (booted ${m.bootedCount})`:"cli claimed sim"),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{simId:p.id,lockedBy:m.lease.cliIdentityKey,lockExpiresAt:m.lease.expiresAt,bootedCount:m.bootedCount}}));return}let c=await this.waitForSim(r.simId);if(yt(r)){let p=this.tryAcquireLease(e,c);if(!p.granted){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${c.id} is locked by another cli \u2014 use \`sootsim claim ${c.id} --force\` or \`sootsim open --new\``,_locked:p.lock}));return}}else this.ensureCliIdentityKey(e);this.setCliSimTarget(e,c.id),this.recordSimAction(c.id,this.describeForwardedCommand(r));let d=this.nextCommandId++;this.cliBySentId.set(d,{simId:c.id,ws:e,originalId:r.id});let{simId:l,...u}=r;if(c.ws.send(JSON.stringify({...u,id:d})),u.type==="close"){this.cliBySentId.delete(d),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{requested:!0,simId:c.id}}));let p=c.ws,m=setTimeout(()=>{this.closeSimSocketFromHost(p)},gt);Le(m)}}catch(c){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:c instanceof Error?c.message:String(c)}))}})()}}),e.on("close",()=>{if(this.agentHost.unregisterSocket(e),s==="sim"&&n){this.rememberDisconnectedSim(n),this.primarySimId===n.id&&(this.primarySimId=this.getOpenSim()?.id??null);for(let[a,r]of this.pendingCommands)r.simId===n.id&&(r.reject(new Error("sim disconnected")),this.pendingCommands.delete(a));for(let[a,r]of this.cliBySentId)r.simId===n.id&&(r.ws.readyState===h.OPEN&&r.ws.send(JSON.stringify({id:r.originalId,error:"sim disconnected before responding"})),this.cliBySentId.delete(a));this.broadcastSimAssignments(),this.broadcastSimClientStates()}else if(s==="cli"){let a=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[r,c]of this.cliBySentId)c.ws===e&&this.cliBySentId.delete(r);a&&this.broadcastSimClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
15
+ `),this.cliIdleTimer=setInterval(()=>this.sweepIdleCliClients(),3e4),this.cliIdleTimer.unref(),this.wsHeartbeatTimer=setInterval(()=>this.sweepDeadWebSockets(),o.WS_HEARTBEAT_INTERVAL_MS),this.wsHeartbeatTimer.unref(),this.shouldWriteLockfile){try{if(E(),!Z(this.buildLockfileSnapshot()))throw new Error("another sootsim daemon wrote the lockfile during startup \u2014 aborting")}catch(e){throw process.stderr.write(`ws bridge failed to claim daemon lockfile: ${String(e)}
16
+ `),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},xe),this.heartbeatTimer.unref(),this.startRuntimeUpdater()}if(this.shouldWriteDevLockfile){try{this.writeDevLockfileSnapshot()}catch(e){process.stderr.write(`ws bridge failed to write dev bridge lockfile: ${String(e)}
17
+ `)}this.devHeartbeatTimer=setInterval(()=>{try{this.writeDevLockfileSnapshot()}catch{}},xe),this.devHeartbeatTimer.unref()}this.agentHost.seedOnBoot()}bootstrapping=!0;buildLockfileSnapshot(){return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,activeRuntimeDir:this.activeRuntimeDirPath,startedAt:this.startedAt,heartbeatAt:Date.now(),bootstrapping:this.bootstrapping}}buildDevLockfileSnapshot(){let e=this.getShellPort?.()??null;return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,...e&&e>0?{shellPort:e}:{},cwd:process.cwd(),startedAt:this.startedAt,heartbeatAt:Date.now(),source:"vite-dev"}}writeLockfileSnapshot(){X(this.buildLockfileSnapshot())}writeDevLockfileSnapshot(){Y(this.buildDevLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=K(),this.activeRuntimeDirPath=se()??G()}runServerScan(){if(this.inflightScan)return this.inflightScan;let e=this.effectivePort>0?[this.effectivePort]:[];return this.inflightScan=P({excludePorts:e,buildIconProxyUrl:t=>`/__bundle-proxy?url=${encodeURIComponent(t)}`}).then(t=>(this.scanCache=t,this.scanCacheAt=Date.now(),t)).catch(t=>{let i=t instanceof Error?t.message:String(t);return console.error("[sootsim] /__server-scan failed:",i),this.scanCache??[]}).finally(()=>{this.inflightScan=null}),this.inflightScan}handleServerScan(e){let t=s=>{e.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(s))},i=Date.now()-this.scanCacheAt;if(this.scanCache&&i<o.SCAN_FRESH_MS){t(this.scanCache);return}if(this.scanCache){t(this.scanCache),this.runServerScan().catch(()=>{});return}this.runServerScan().then(s=>t(s))}resolveRuntimeUpdateIntervalMs(){let e=Number(process.env[bt]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):vt}startRuntimeUpdater(){if(!this.shouldWriteLockfile||this.runtimeUpdateTimer)return;this.runRuntimeUpdate("startup");let e=this.resolveRuntimeUpdateIntervalMs();this.runtimeUpdateTimer=setInterval(()=>{this.runRuntimeUpdate("periodic")},e),this.runtimeUpdateTimer.unref()}runRuntimeUpdate(e){return this.runtimeUpdateInFlight?this.runtimeUpdateInFlight:(this.runtimeUpdateInFlight=(async()=>{try{e==="startup"&&process.stderr.write(`sootsim: checking for runtime updates\u2026
18
+ `);let t=await ae();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
19
+ `);return}let i=this.activeRuntimeVersion,s=this.setActiveRuntime(t.latestVersion);process.stderr.write(`sootsim runtime updated to ${s.version} (${e})
20
+ `);try{J({from:i,to:s.version,at:Date.now()})}catch{}}catch(t){process.stderr.write(`sootsim runtime update failed (${e}): ${t instanceof Error?t.message:String(t)}
21
21
  `)}finally{if(this.runtimeUpdateInFlight=null,e==="startup"&&this.bootstrapping){if(this.bootstrapping=!1,this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}process.stderr.write(`sootsim: ready
22
- `)}}})(),this.runtimeUpdateInFlight)}setActiveRuntime(e){if(K(e),this.refreshActiveRuntime(),this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}let t=JSON.stringify({type:"runtime:changed",version:e,runtimeDir:this.activeRuntimeDirPath});for(let i of this.sims.values())if(i.ws.readyState===h.OPEN)try{i.ws.send(t)}catch{}return{version:e,runtimeDir:this.activeRuntimeDirPath}}getActiveRuntime(){return{version:this.activeRuntimeVersion,runtimeDir:this.activeRuntimeDirPath}}removeLockfile(){if(this.shouldWriteLockfile)try{U()}catch{}}handleHttpRequest(e,t){if(t.setHeader("Cross-Origin-Opener-Policy","same-origin"),t.setHeader("Cross-Origin-Embedder-Policy",mt),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),Ce(e.url)){Ee(e,t);return}if(Te(e.url)&&Pe(e,t))return;let i=(e.method||"GET").toUpperCase();if(i!=="GET"&&i!=="HEAD"){t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed");return}let s=new URL(e.url||"/","http://localhost");if(s.pathname==="/__bundle-proxy"){let d=s.searchParams.get("url");if(!d){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let l;try{l=new URL(d)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let u=l.hostname;if(!(u==="localhost"||u==="127.0.0.1"||u==="::1"||u.endsWith(".localhost"))){t.writeHead(403,{"Content-Type":"text/plain"}),t.end("bundle-proxy: only loopback targets allowed");return}(async()=>{try{let m=await fetch(l.toString(),{redirect:"follow"}),f={},y=m.headers.get("content-type");if(y&&(f["Content-Type"]=y),f["Cache-Control"]="no-store",t.writeHead(m.status,f),!m.body){t.end();return}let g=m.body.getReader();for(;;){let{done:b,value:w}=await g.read();if(b)break;t.write(Buffer.from(w))}t.end()}catch(m){t.writeHead(502,{"Content-Type":"text/plain"}),t.end(`bundle-proxy: upstream fetch failed: ${m instanceof Error?m.message:String(m)}`)}})();return}if(s.pathname==="/__server-scan"){this.handleServerScan(t);return}if(s.pathname==="/healthz"){t.writeHead(200,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify({ok:!0,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,bridgeSource:this.shouldWriteDevLockfile?"vite-dev":this.shouldWriteLockfile?"daemon":"embedded",startedAt:this.startedAt,uptimeMs:this.startedAt>0?Date.now()-this.startedAt:0}));return}if(s.pathname==="/__sootsim/shared-config"){if(t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Cache-Control","no-store"),i==="GET"||i==="HEAD"){let d="{}";try{d=JSON.stringify(M())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(d);return}t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed (use the bridge over WS for writes)");return}this.refreshActiveRuntime();let n=this.activeRuntimeDirPath;if(!n){t.writeHead(503,{"Content-Type":"text/plain; charset=utf-8"}),t.end("sootsim: no active runtime installed. run `sootsim runtime install` to fetch one.");return}let a=s.pathname;if(a==="/runtime"||a==="/runtime/"?a="/":a.startsWith("/runtime/")?a=a.slice(8):a==="/sootsim"||a==="/sootsim/"?a="/":a.startsWith("/sootsim/")&&(a=a.slice(8)),(a===""||a==="/")&&(a="/index.html"),a.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&a.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let d of a.split("/"))if(d===".."){t.writeHead(403),t.end("forbidden");return}let r=S.resolve(n,"."+a),c=n.endsWith(S.sep)?n:n+S.sep;if(!r.startsWith(c)&&r!==n){t.writeHead(403),t.end("forbidden");return}I.realpath(r,(d,l)=>{let u=d?r:l,p=u.endsWith(S.sep)?u:u+S.sep;if(!d){let m=(()=>{try{let f=I.realpathSync(n);return f.endsWith(S.sep)?f:f+S.sep}catch{return c}})();if(!p.startsWith(m)&&u+S.sep!==m){t.writeHead(403),t.end("forbidden");return}}I.stat(u,(m,f)=>{if(m||!f?.isFile()){let w=S.extname(a).toLowerCase();if(w&&w!==".html"){t.writeHead(404),t.end("not found");return}if(a.startsWith("/__")||a.startsWith("/api/")||a==="/api"){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("not found");return}let N=S.join(n,"index.html");I.readFile(N,(Le,Be)=>{if(Le){t.writeHead(404),t.end("not found");return}if(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),i==="HEAD"){t.end();return}t.end(xe(Be,this.effectivePort,this.sootbeanOrigin))});return}let y=S.extname(u).toLowerCase(),g=bt[y]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":g,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(y===".html"){I.readFile(u,(w,N)=>{if(w){try{t.end()}catch{}return}t.end(xe(N,this.effectivePort,this.sootbeanOrigin))});return}let b=I.createReadStream(u);b.pipe(t),b.on("error",()=>{try{t.end()}catch{}})})})}sweepIdleCliClients(){let e=Date.now(),t=!1;for(let[i,s]of this.cliSimBySocket){let n=this.cliLastCommandAt.get(i)??0;if(!(e-n<o.CLI_IDLE_TIMEOUT_MS)){this.cliSimBySocket.delete(i),this.cliLastCommandAt.delete(i);for(let[a,r]of this.cliBySentId)r.ws===i&&this.cliBySentId.delete(a);try{i.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastSimClientStates(),this.sweepRestorableSims(e),this.reapIdleSims(e)}isAutomationSim(e){return e.meta?.sootsimHostDriver==="playwright"}automationSimOwnerAlive(e){let t=Number(e.meta?.sootsimHostPid);if(!Number.isInteger(t)||t<=1||t===process.pid)return!1;try{return process.kill(t,0),!0}catch(i){return i.code==="EPERM"}}reapIdleSims(e=Date.now()){let t=new Set(this.cliSimBySocket.values()),i=[];for(let n of this.sims.values()){if(n.id===this.primarySimId||t.has(n.id)||this.getActiveLease(n))continue;let a=Math.max(n.lastActiveAt,n.connectedAt),r=e-a,c=this.isAutomationSim(n);if(c&&this.automationSimOwnerAlive(n))continue;let d=c?this.automationSimIdleReapTtlMs:this.simIdleReapTtlMs;if(r>=d){this.closeSimSocketFromHost(n.ws);continue}c&&i.push({sim:n,idleMs:r})}let s=this.maxConcurrentAutomationSims;if(i.length>s){i.sort((n,a)=>a.idleMs-n.idleMs);for(let{sim:n,idleMs:a}of i.slice(0,i.length-s))a<this.automationSimActiveGraceMs||this.closeSimSocketFromHost(n.ws)}}sweepDeadWebSockets(){if(this.wss)for(let e of this.wss.clients){if(e.readyState!==h.OPEN)continue;if(this.wsIsAlive.get(e)===!1){try{e.terminate()}catch{}continue}this.wsIsAlive.set(e,!1);try{e.ping()}catch{try{e.terminate()}catch{}}}}closeSimSocketFromHost(e){if(e.readyState!==h.OPEN)return;try{e.close(ie,re)}catch{try{e.terminate()}catch{}return}let t=setTimeout(()=>{if(e.readyState!==h.CLOSED)try{e.terminate()}catch{}},gt);Oe(t)}listSims(){return Array.from(this.sims.values()).sort((e,t)=>e.id===this.primarySimId?-1:t.id===this.primarySimId?1:e.connectedAt-t.connectedAt).map(e=>this.describeSim(e))}async sendCommand(e){let t=await this.waitForSim(e.simId),i=this.nextCommandId++;return new Promise((s,n)=>{let a=setTimeout(()=>{this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(new Error("command timed out after 30s"))},3e4);this.pendingCommands.set(i,{simId:t.id,resolve:d=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(d)},reject:d=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(d)}}),this.broadcastSimClientStates();let{simId:r,...c}=e;t.ws.send(JSON.stringify({...c,id:i}))})}async evaluate(e,t){return this.sendCommand({type:"evaluate",code:e,simId:t})}async focusSim(e){return this.sendCommand({type:"focus",simId:e})}async closeSim(e){return this.sendCommand({type:"close",simId:e})}async openPathInEditor(e,t,i){let s=t!=null?`:${t}${i!=null?`:${i}`:""}`:"",n=`${e}${s}`,a=(c,d)=>new Promise(l=>{try{let u=dt(c,d,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,l(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),l(!0))})}catch{l(!1)}}),r=process.env.REACT_EDITOR||process.env.EDITOR;if(r){let c=r.split(" ").filter(Boolean);if(c.length&&await a(c[0],[...c.slice(1),"-g",n]))return}await a("cursor",["-g",n])||await a("code",["-g",n])||await this.openUrl(e)}async openUrl(e,t={}){if(this.openUrlHandler){await this.openUrlHandler(e,t);return}await se(e,t)}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.devHeartbeatTimer&&(clearInterval(this.devHeartbeatTimer),this.devHeartbeatTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null),this.shouldWriteLockfile)try{U()}catch{}if(this.shouldWriteDevLockfile)try{Z()}catch{}this.effectivePort=0,this.startedAt=0,this.agentHost.close();for(let[i,s]of this.pendingCommands)s.reject(new Error("server closing")),this.pendingCommands.delete(i);for(let i of this.sims.values())i.ws.close();this.sims.clear(),this.primarySimId=null;let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}describeSim(e){let t;try{t=e.ws.readyState}catch{t=h.CLOSED}let i=this.getActiveLease(e);return{id:e.id,origin:e.origin,url:e.url,title:e.title,userAgent:e.userAgent,connectedAt:e.connectedAt,lastSeenAt:e.lastSeenAt,lastActiveAt:e.lastActiveAt||void 0,isPrimary:e.id===this.primarySimId,readyState:t===h.OPEN?"open":t===h.CLOSING?"closing":"closed",attachedCliCount:this.getAttachedCliCount(e.id),lockedBy:i?i.cliLabel||i.cliIdentityKey:void 0,lockedByKind:i?i.kind:void 0,lockExpiresAt:i?i.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused,kind:e.kind,meta:e.meta}}getActiveLease(e){let t=e.cliLease;return t?Date.now()>=t.expiresAt?(e.cliLease=void 0,null):t:null}tryAcquireLease(e,t,i={}){let s=this.cliIdentityKeyBySocket.get(e)??(()=>{let u=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,u),u})(),n=this.cliLabelBySocket.get(e),a=Date.now(),r=this.getActiveLease(t),c=r&&r.cliIdentityKey===s,d=0;if(r&&!c&&!i.force)return{granted:!1,lease:r,lock:{by:r.cliLabel||r.cliIdentityKey,expiresInMs:Math.max(0,r.expiresAt-a)},bootedCount:0};if(r&&!c&&i.force)for(let[u,p]of this.cliSimBySocket){if(p!==t.id)continue;let m=this.cliIdentityKeyBySocket.get(u);if(m&&m!==s){this.cliSimBySocket.delete(u);try{u.close(1e3,"lease claimed by another cli")}catch{}d++}}let l={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:a+o.CLI_LEASE_TTL_MS};return t.cliLease=l,{granted:!0,lease:l,bootedCount:d}}updateUserFocusLease(e,t){let i=t.focused===!0,s=typeof t.visible=="boolean"?t.visible:void 0,n=typeof t.visibilityState=="string"?t.visibilityState:void 0,a=typeof t.documentFocused=="boolean"?t.documentFocused:void 0;e.userFocused===i&&e.userVisible===s&&e.visibilityState===n&&e.documentFocused===a||(e.userFocused=i,e.userVisible=s,e.visibilityState=n,e.documentFocused=a,this.broadcastSimClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);if(t&&t.kind==="cli")return;let s=Date.now()+o.USER_ACTIVE_LEASE_TTL_MS,n=t&&t.kind==="user-active"?Math.max(t.expiresAt,s):s;e.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:n},this.broadcastSimClientStates()}ensureCliIdentityKey(e){let t=this.cliIdentityKeyBySocket.get(e);if(t)return t;let i=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,i),i}getOpenSim(e){if(e){let s=this.sims.get(e);return s?.ws.readyState===h.OPEN?s:null}let t=this.primarySimId!=null?this.sims.get(this.primarySimId):null;if(t?.ws.readyState===h.OPEN&&t.url)return t;let i=null;for(let s of this.sims.values())if(s.ws.readyState===h.OPEN){if(s.url)return s;i??=s}return t?.ws.readyState===h.OPEN?t:i}async waitForSim(e,t={}){let i=t.attempts??10,s=t.intervalMs??200;for(let n=0;n<i;n++){let a=this.getOpenSim(e);if(a)return a;await new Promise(r=>setTimeout(r,s))}throw new Error(e?`no sim connected with id ${e}`:"no sim connected")}shouldPromoteSim(e){let t=this.primarySimId?this.sims.get(this.primarySimId):null;if(!e.url)return!t;let i=t?.ws.readyState===h.OPEN;if(!t||!i||!t.url)return!0;let s=e.origin?.includes(":5173"),n=t.origin?.includes(":5173");return!!s||!n}broadcastSimAssignments(){for(let e of this.sims.values())e.ws.readyState===h.OPEN&&e.ws.send(JSON.stringify({type:"bridge:welcome",simId:e.id,isPrimary:e.id===this.primarySimId}))}broadcastSimClientStates(){for(let e of this.sims.values()){if(e.ws.readyState!==h.OPEN)continue;let t=this.getActiveLease(e),i={type:"bridge:client-state",attachedCliCount:this.getAttachedCliCount(e.id),activeAgentCommandCount:this.getActiveAgentCommandCount(e.id),recentActions:e.recentActions,lockedBy:t?t.cliLabel||t.cliIdentityKey:void 0,lockedByKind:t?t.kind:void 0,lockExpiresAt:t?t.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused};e.ws.send(JSON.stringify(i))}}setCliSimTarget(e,t){let i=this.cliSimBySocket.get(e);i!==t&&(this.cliSimBySocket.set(e,t),this.recordSimAction(t,i?"cli switched sims":"cli connected",!1),this.broadcastSimClientStates())}recordSimAction(e,t,i=!0){let s=t?.trim();if(!s)return;let n=this.sims.get(e);if(!n)return;let a=Date.now();n.lastActiveAt=a,n.recentActions=[{label:s,at:a},...n.recentActions.filter(r=>r.label!==s)].slice(0,4),i&&this.broadcastSimClientStates()}describeForwardedCommand(e){switch(e?.type){case"evaluate":return"evaluated page state";case"screenshot":return"captured screenshot";case"tap":return"sent tap event";case"keyboard":return e?.action==="type"?"typed text":"used keyboard";case"tree":return"dumped tree";case"focus":return"focused sim";case"close":return"requested close";default:return typeof e?.type=="string"?e.type:null}}getAttachedCliCount(e){let t=new Set;for(let[i,s]of this.cliSimBySocket){if(s!==e||i.readyState!==h.OPEN)continue;let n=this.cliIdentityKeyBySocket.get(i);t.add(n??`ws-unknown-${t.size}`)}return t.size}getOtherCliIdentityCount(e,t){let i=this.cliIdentityKeyBySocket.get(e),s=new Set;for(let[n,a]of this.cliSimBySocket){if(a!==t||n.readyState!==h.OPEN)continue;let r=this.cliIdentityKeyBySocket.get(n);r&&r===i||s.add(r??`ws-unknown-${s.size}`)}return s.size}getActiveAgentCommandCount(e){let t=0;for(let i of this.pendingCommands.values())i.simId===e&&t++;return t}allocateSimId(){for(;;){let e=this.nextSimNumber.toString(16);if(this.nextSimNumber++,!this.sims.has(e)&&!this.restorableSims.has(e))return e}}tryRestoreSimId(e,t){let i=t?.trim();if(!i||i===e.id)return!1;let s=this.sims.get(i);if(s&&s!==e&&s.ws.readyState===h.OPEN)return!1;let n=this.getRestorableSimState(i),a=e.id;this.sims.delete(a),e.id=i,n&&(e.recentActions=n.recentActions.map(r=>({...r})),e.lastActiveAt=n.lastActiveAt,e.cliLease=n.cliLease?{...n.cliLease}:void 0,this.restorableSims.delete(i)),this.sims.set(e.id,e),this.primarySimId===a&&(this.primarySimId=e.id);for(let[r,c]of this.cliSimBySocket)c===a&&this.cliSimBySocket.set(r,e.id);return!0}rememberDisconnectedSim(e){let t=this.getActiveLease(e);this.restorableSims.set(e.id,{recentActions:e.recentActions.map(i=>({...i})),lastActiveAt:e.lastActiveAt,cliLease:t&&t.kind==="cli"?{...t}:void 0,expiresAt:Date.now()+o.SIM_RECONNECT_TTL_MS}),this.sims.delete(e.id)}getRestorableSimState(e){let t=this.restorableSims.get(e);return t?t.expiresAt<=Date.now()?(this.restorableSims.delete(e),null):(t.cliLease&&t.cliLease.expiresAt<=Date.now()&&(t.cliLease=void 0),t):null}sweepRestorableSims(e=Date.now()){for(let[t,i]of this.restorableSims)if(!(i.expiresAt>e)){this.restorableSims.delete(t);for(let[s,n]of this.cliSimBySocket)n===t&&this.cliSimBySocket.delete(s)}}resetServerState(){this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null);let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}};function wt(){return!!((process.env.XPC_SERVICE_NAME||"").includes("dev.sootsim.daemon")||process.env.INVOCATION_ID)}async function pi(o,e={}){(o.includes("--help")||o.includes("-h"))&&(console.log(`
22
+ `)}}})(),this.runtimeUpdateInFlight)}setActiveRuntime(e){if(V(e),this.refreshActiveRuntime(),this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}let t=JSON.stringify({type:"runtime:changed",version:e,runtimeDir:this.activeRuntimeDirPath});for(let i of this.sims.values())if(i.ws.readyState===h.OPEN)try{i.ws.send(t)}catch{}return{version:e,runtimeDir:this.activeRuntimeDirPath}}getActiveRuntime(){return{version:this.activeRuntimeVersion,runtimeDir:this.activeRuntimeDirPath}}removeLockfile(){if(this.shouldWriteLockfile)try{U()}catch{}}handleHttpRequest(e,t){if(t.setHeader("Cross-Origin-Opener-Policy","same-origin"),t.setHeader("Cross-Origin-Embedder-Policy",ht),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),Te(e.url)){Pe(e,t);return}if(Ee(e.url)&&Re(e,t))return;let i=(e.method||"GET").toUpperCase();if(i!=="GET"&&i!=="HEAD"){t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed");return}let s=new URL(e.url||"/","http://localhost");if(s.pathname==="/__bundle-proxy"){let d=s.searchParams.get("url");if(!d){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let l;try{l=new URL(d)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let u=l.hostname;if(!(u==="localhost"||u==="127.0.0.1"||u==="::1"||u.endsWith(".localhost"))){t.writeHead(403,{"Content-Type":"text/plain"}),t.end("bundle-proxy: only loopback targets allowed");return}(async()=>{try{let m=await fetch(l.toString(),{redirect:"follow"}),f={},y=m.headers.get("content-type");if(y&&(f["Content-Type"]=y),f["Cache-Control"]="no-store",t.writeHead(m.status,f),!m.body){t.end();return}let g=m.body.getReader();for(;;){let{done:b,value:w}=await g.read();if(b)break;t.write(Buffer.from(w))}t.end()}catch(m){t.writeHead(502,{"Content-Type":"text/plain"}),t.end(`bundle-proxy: upstream fetch failed: ${m instanceof Error?m.message:String(m)}`)}})();return}if(s.pathname==="/__server-scan"){this.handleServerScan(t);return}if(s.pathname==="/healthz"){t.writeHead(200,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify({ok:!0,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,bridgeSource:this.shouldWriteDevLockfile?"vite-dev":this.shouldWriteLockfile?"daemon":"embedded",startedAt:this.startedAt,uptimeMs:this.startedAt>0?Date.now()-this.startedAt:0}));return}if(s.pathname==="/__sootsim/shared-config"){if(t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Cache-Control","no-store"),i==="GET"||i==="HEAD"){let d="{}";try{d=JSON.stringify(M())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(d);return}t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed (use the bridge over WS for writes)");return}this.refreshActiveRuntime();let n=this.activeRuntimeDirPath;if(!n){t.writeHead(503,{"Content-Type":"text/plain; charset=utf-8"}),t.end("sootsim: no active runtime installed. run `sootsim runtime install` to fetch one.");return}let a=s.pathname;if(a==="/runtime"||a==="/runtime/"?a="/":a.startsWith("/runtime/")?a=a.slice(8):a==="/sootsim"||a==="/sootsim/"?a="/":a.startsWith("/sootsim/")&&(a=a.slice(8)),(a===""||a==="/")&&(a="/index.html"),a.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&a.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let d of a.split("/"))if(d===".."){t.writeHead(403),t.end("forbidden");return}let r=S.resolve(n,"."+a),c=n.endsWith(S.sep)?n:n+S.sep;if(!r.startsWith(c)&&r!==n){t.writeHead(403),t.end("forbidden");return}I.realpath(r,(d,l)=>{let u=d?r:l,p=u.endsWith(S.sep)?u:u+S.sep;if(!d){let m=(()=>{try{let f=I.realpathSync(n);return f.endsWith(S.sep)?f:f+S.sep}catch{return c}})();if(!p.startsWith(m)&&u+S.sep!==m){t.writeHead(403),t.end("forbidden");return}}I.stat(u,(m,f)=>{if(m||!f?.isFile()){let w=S.extname(a).toLowerCase();if(w&&w!==".html"){t.writeHead(404),t.end("not found");return}if(a.startsWith("/__")||a.startsWith("/api/")||a==="/api"){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("not found");return}let N=S.join(n,"index.html");I.readFile(N,(Be,Ne)=>{if(Be){t.writeHead(404),t.end("not found");return}if(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),i==="HEAD"){t.end();return}t.end(Oe(Ne,this.effectivePort,this.sootbeanOrigin))});return}let y=S.extname(u).toLowerCase(),g=wt[y]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":g,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(y===".html"){I.readFile(u,(w,N)=>{if(w){try{t.end()}catch{}return}t.end(Oe(N,this.effectivePort,this.sootbeanOrigin))});return}let b=I.createReadStream(u);b.pipe(t),b.on("error",()=>{try{t.end()}catch{}})})})}sweepIdleCliClients(){let e=Date.now(),t=!1;for(let[i,s]of this.cliSimBySocket){let n=this.cliLastCommandAt.get(i)??0;if(!(e-n<o.CLI_IDLE_TIMEOUT_MS)){this.cliSimBySocket.delete(i),this.cliLastCommandAt.delete(i);for(let[a,r]of this.cliBySentId)r.ws===i&&this.cliBySentId.delete(a);try{i.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastSimClientStates(),this.sweepRestorableSims(e),this.reapIdleSims(e)}isAutomationSim(e){return e.meta?.sootsimHostDriver==="playwright"}automationSimOwnerAlive(e){let t=Number(e.meta?.sootsimHostPid);if(!Number.isInteger(t)||t<=1||t===process.pid)return!1;try{return process.kill(t,0),!0}catch(i){return i.code==="EPERM"}}reapIdleSims(e=Date.now()){let t=new Set(this.cliSimBySocket.values()),i=[];for(let n of this.sims.values()){if(n.id===this.primarySimId||t.has(n.id)||this.getActiveLease(n))continue;let a=Math.max(n.lastActiveAt,n.connectedAt),r=e-a,c=this.isAutomationSim(n);if(c&&this.automationSimOwnerAlive(n))continue;let d=c?this.automationSimIdleReapTtlMs:this.simIdleReapTtlMs;if(r>=d){this.closeSimSocketFromHost(n.ws);continue}c&&i.push({sim:n,idleMs:r})}let s=this.maxConcurrentAutomationSims;if(i.length>s){i.sort((n,a)=>a.idleMs-n.idleMs);for(let{sim:n,idleMs:a}of i.slice(0,i.length-s))a<this.automationSimActiveGraceMs||this.closeSimSocketFromHost(n.ws)}}sweepDeadWebSockets(){if(this.wss)for(let e of this.wss.clients){if(e.readyState!==h.OPEN)continue;if(this.wsIsAlive.get(e)===!1){try{e.terminate()}catch{}continue}this.wsIsAlive.set(e,!1);try{e.ping()}catch{try{e.terminate()}catch{}}}}closeSimSocketFromHost(e){if(e.readyState!==h.OPEN)return;try{e.close(re,ne)}catch{try{e.terminate()}catch{}return}let t=setTimeout(()=>{if(e.readyState!==h.CLOSED)try{e.terminate()}catch{}},St);Le(t)}listSims(){return Array.from(this.sims.values()).sort((e,t)=>e.id===this.primarySimId?-1:t.id===this.primarySimId?1:e.connectedAt-t.connectedAt).map(e=>this.describeSim(e))}async sendCommand(e){let t=await this.waitForSim(e.simId),i=this.nextCommandId++;return new Promise((s,n)=>{let a=setTimeout(()=>{this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(new Error("command timed out after 30s"))},3e4);this.pendingCommands.set(i,{simId:t.id,resolve:d=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(d)},reject:d=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(d)}}),this.broadcastSimClientStates();let{simId:r,...c}=e;t.ws.send(JSON.stringify({...c,id:i}))})}async evaluate(e,t){return this.sendCommand({type:"evaluate",code:e,simId:t})}async focusSim(e){return this.sendCommand({type:"focus",simId:e})}async closeSim(e){return this.sendCommand({type:"close",simId:e})}async openPathInEditor(e,t,i){let s=t!=null?`:${t}${i!=null?`:${i}`:""}`:"",n=`${e}${s}`,a=(c,d)=>new Promise(l=>{try{let u=ut(c,d,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,l(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),l(!0))})}catch{l(!1)}}),r=process.env.REACT_EDITOR||process.env.EDITOR;if(r){let c=r.split(" ").filter(Boolean);if(c.length&&await a(c[0],[...c.slice(1),"-g",n]))return}await a("cursor",["-g",n])||await a("code",["-g",n])||await this.openUrl(e)}async openUrl(e,t={}){if(this.openUrlHandler){await this.openUrlHandler(e,t);return}await oe(e,t)}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.devHeartbeatTimer&&(clearInterval(this.devHeartbeatTimer),this.devHeartbeatTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null),this.shouldWriteLockfile)try{U()}catch{}if(this.shouldWriteDevLockfile)try{Q()}catch{}this.effectivePort=0,this.startedAt=0,this.agentHost.close();for(let[i,s]of this.pendingCommands)s.reject(new Error("server closing")),this.pendingCommands.delete(i);for(let i of this.sims.values())i.ws.close();this.sims.clear(),this.primarySimId=null;let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}describeSim(e){let t;try{t=e.ws.readyState}catch{t=h.CLOSED}let i=this.getActiveLease(e);return{id:e.id,origin:e.origin,url:e.url,title:e.title,userAgent:e.userAgent,connectedAt:e.connectedAt,lastSeenAt:e.lastSeenAt,lastActiveAt:e.lastActiveAt||void 0,isPrimary:e.id===this.primarySimId,readyState:t===h.OPEN?"open":t===h.CLOSING?"closing":"closed",attachedCliCount:this.getAttachedCliCount(e.id),lockedBy:i?i.cliLabel||i.cliIdentityKey:void 0,lockedByKind:i?i.kind:void 0,lockExpiresAt:i?i.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused,kind:e.kind,meta:e.meta}}getActiveLease(e){let t=e.cliLease;return t?Date.now()>=t.expiresAt?(e.cliLease=void 0,null):t:null}tryAcquireLease(e,t,i={}){let s=this.cliIdentityKeyBySocket.get(e)??(()=>{let u=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,u),u})(),n=this.cliLabelBySocket.get(e),a=Date.now(),r=this.getActiveLease(t),c=r&&r.cliIdentityKey===s,d=0;if(r&&!c&&!i.force)return{granted:!1,lease:r,lock:{by:r.cliLabel||r.cliIdentityKey,expiresInMs:Math.max(0,r.expiresAt-a)},bootedCount:0};if(r&&!c&&i.force)for(let[u,p]of this.cliSimBySocket){if(p!==t.id)continue;let m=this.cliIdentityKeyBySocket.get(u);if(m&&m!==s){this.cliSimBySocket.delete(u);try{u.close(1e3,"lease claimed by another cli")}catch{}d++}}let l={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:a+o.CLI_LEASE_TTL_MS};return t.cliLease=l,{granted:!0,lease:l,bootedCount:d}}updateUserFocusLease(e,t){let i=t.focused===!0,s=typeof t.visible=="boolean"?t.visible:void 0,n=typeof t.visibilityState=="string"?t.visibilityState:void 0,a=typeof t.documentFocused=="boolean"?t.documentFocused:void 0;e.userFocused===i&&e.userVisible===s&&e.visibilityState===n&&e.documentFocused===a||(e.userFocused=i,e.userVisible=s,e.visibilityState=n,e.documentFocused=a,this.broadcastSimClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);if(t&&t.kind==="cli")return;let s=Date.now()+o.USER_ACTIVE_LEASE_TTL_MS,n=t&&t.kind==="user-active"?Math.max(t.expiresAt,s):s;e.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:n},this.broadcastSimClientStates()}ensureCliIdentityKey(e){let t=this.cliIdentityKeyBySocket.get(e);if(t)return t;let i=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,i),i}getOpenSim(e){if(e){let s=this.sims.get(e);return s?.ws.readyState===h.OPEN?s:null}let t=this.primarySimId!=null?this.sims.get(this.primarySimId):null;if(t?.ws.readyState===h.OPEN&&t.url)return t;let i=null;for(let s of this.sims.values())if(s.ws.readyState===h.OPEN){if(s.url)return s;i??=s}return t?.ws.readyState===h.OPEN?t:i}async waitForSim(e,t={}){let i=t.attempts??10,s=t.intervalMs??200;for(let n=0;n<i;n++){let a=this.getOpenSim(e);if(a)return a;await new Promise(r=>setTimeout(r,s))}throw new Error(e?`no sim connected with id ${e}`:"no sim connected")}shouldPromoteSim(e){let t=this.primarySimId?this.sims.get(this.primarySimId):null;if(!e.url)return!t;let i=t?.ws.readyState===h.OPEN;if(!t||!i||!t.url)return!0;let s=e.origin?.includes(":5173"),n=t.origin?.includes(":5173");return!!s||!n}broadcastSimAssignments(){for(let e of this.sims.values())e.ws.readyState===h.OPEN&&e.ws.send(JSON.stringify({type:"bridge:welcome",simId:e.id,isPrimary:e.id===this.primarySimId}))}broadcastSimClientStates(){for(let e of this.sims.values()){if(e.ws.readyState!==h.OPEN)continue;let t=this.getActiveLease(e),i={type:"bridge:client-state",attachedCliCount:this.getAttachedCliCount(e.id),activeAgentCommandCount:this.getActiveAgentCommandCount(e.id),recentActions:e.recentActions,lockedBy:t?t.cliLabel||t.cliIdentityKey:void 0,lockedByKind:t?t.kind:void 0,lockExpiresAt:t?t.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused};e.ws.send(JSON.stringify(i))}}setCliSimTarget(e,t){let i=this.cliSimBySocket.get(e);i!==t&&(this.cliSimBySocket.set(e,t),this.recordSimAction(t,i?"cli switched sims":"cli connected",!1),this.broadcastSimClientStates())}recordSimAction(e,t,i=!0){let s=t?.trim();if(!s)return;let n=this.sims.get(e);if(!n)return;let a=Date.now();n.lastActiveAt=a,n.recentActions=[{label:s,at:a},...n.recentActions.filter(r=>r.label!==s)].slice(0,4),i&&this.broadcastSimClientStates()}describeForwardedCommand(e){switch(e?.type){case"evaluate":return"evaluated page state";case"screenshot":return"captured screenshot";case"tap":return"sent tap event";case"keyboard":return e?.action==="type"?"typed text":"used keyboard";case"tree":return"dumped tree";case"focus":return"focused sim";case"close":return"requested close";default:return typeof e?.type=="string"?e.type:null}}getAttachedCliCount(e){let t=new Set;for(let[i,s]of this.cliSimBySocket){if(s!==e||i.readyState!==h.OPEN)continue;let n=this.cliIdentityKeyBySocket.get(i);t.add(n??`ws-unknown-${t.size}`)}return t.size}getOtherCliIdentityCount(e,t){let i=this.cliIdentityKeyBySocket.get(e),s=new Set;for(let[n,a]of this.cliSimBySocket){if(a!==t||n.readyState!==h.OPEN)continue;let r=this.cliIdentityKeyBySocket.get(n);r&&r===i||s.add(r??`ws-unknown-${s.size}`)}return s.size}getActiveAgentCommandCount(e){let t=0;for(let i of this.pendingCommands.values())i.simId===e&&t++;return t}allocateSimId(){for(;;){let e=this.nextSimNumber.toString(16);if(this.nextSimNumber++,!this.sims.has(e)&&!this.restorableSims.has(e))return e}}tryRestoreSimId(e,t){let i=t?.trim();if(!i||i===e.id)return!1;let s=this.sims.get(i);if(s&&s!==e&&s.ws.readyState===h.OPEN)return!1;let n=this.getRestorableSimState(i),a=e.id;this.sims.delete(a),e.id=i,n&&(e.recentActions=n.recentActions.map(r=>({...r})),e.lastActiveAt=n.lastActiveAt,e.cliLease=n.cliLease?{...n.cliLease}:void 0,this.restorableSims.delete(i)),this.sims.set(e.id,e),this.primarySimId===a&&(this.primarySimId=e.id);for(let[r,c]of this.cliSimBySocket)c===a&&this.cliSimBySocket.set(r,e.id);return!0}rememberDisconnectedSim(e){let t=this.getActiveLease(e);this.restorableSims.set(e.id,{recentActions:e.recentActions.map(i=>({...i})),lastActiveAt:e.lastActiveAt,cliLease:t&&t.kind==="cli"?{...t}:void 0,expiresAt:Date.now()+o.SIM_RECONNECT_TTL_MS}),this.sims.delete(e.id)}getRestorableSimState(e){let t=this.restorableSims.get(e);return t?t.expiresAt<=Date.now()?(this.restorableSims.delete(e),null):(t.cliLease&&t.cliLease.expiresAt<=Date.now()&&(t.cliLease=void 0),t):null}sweepRestorableSims(e=Date.now()){for(let[t,i]of this.restorableSims)if(!(i.expiresAt>e)){this.restorableSims.delete(t);for(let[s,n]of this.cliSimBySocket)n===t&&this.cliSimBySocket.delete(s)}}resetServerState(){this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null);let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}};function At(){return!!((process.env.XPC_SERVICE_NAME||"").includes("dev.sootsim.daemon")||process.env.INVOCATION_ID)}async function mi(o,e={}){(o.includes("--help")||o.includes("-h"))&&(console.log(`
23
23
  sootsim serve \u2014 run the sootsim bridge in the foreground
24
24
 
25
25
  hosts the WS bridge that CLI commands talk to. once running, any sootsim
@@ -36,6 +36,6 @@ options:
36
36
  examples:
37
37
  sootsim serve
38
38
  sootsim serve --port 7668 --quiet
39
- `),process.exit(0));let t=o.indexOf("--port"),i=t>=0&&o[t+1]?Number(o[t+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${o[t+1]}`),process.exit(1));let s=o.includes("--quiet")||o.includes("-q"),n=G();n&&q(n)&&(console.error(` a sootsim bridge is already running (pid ${n.pid}, port ${n.bridgePort})`),console.error(" stop it with 'sootsim daemon stop' first"),process.exit(1)),E();let a=await ae(),r=new L({port:i,writeLockfile:!0,sootbeanOrigin:a}),c=await r.startAsync({silent:s}),d=Date.now(),l=f=>{s||process.stdout.write(`${f}
40
- `)},u=new Set,p=setInterval(()=>{let f=r.listSims(),y=new Set(f.map(g=>g.id));for(let g of f)if(!u.has(g.id)){let b=g.title||g.url||g.origin||"(unknown)";l(` + ${g.id} ${b}`)}for(let g of u)y.has(g)||l(` - ${g}`);u.clear();for(let g of y)u.add(g)},500);Q({event:"daemon_heartbeat",properties:{bridge_port:c,under_daemon:wt(),platform:process.platform,subsource:"daemon"}}),ee(),l(`sootsim bridge listening on ws://localhost:${c} (runtime http on same port)`),c!==i&&l(` (preferred port ${i} was taken \u2014 fell back to ${c})`),l(" ready for browser, electron, or headless playwright sims to connect"),l(" (ctrl-c to stop)");let m=async f=>{clearInterval(p),l(`
41
- ${f} received \u2014 shutting down after ${Math.round((Date.now()-d)/1e3)}s`);try{await r.close()}catch{}process.exit(0)};process.on("SIGINT",()=>m("SIGINT")),process.on("SIGTERM",()=>m("SIGTERM")),process.on("SIGHUP",()=>m("SIGHUP")),process.on("exit",()=>{try{r.removeLockfile()}catch{}}),await new Promise(()=>{})}export{pi as runServe};
39
+ `),process.exit(0));let t=o.indexOf("--port"),i=t>=0&&o[t+1]?Number(o[t+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${o[t+1]}`),process.exit(1));let s=o.includes("--quiet")||o.includes("-q"),n=q();n&&z(n)&&(console.error(` a sootsim bridge is already running (pid ${n.pid}, port ${n.bridgePort})`),console.error(" stop it with 'sootsim daemon stop' first"),process.exit(1)),E();let a=await ce(),r=new L({port:i,writeLockfile:!0,sootbeanOrigin:a}),c=await r.startAsync({silent:s}),d=Date.now(),l=f=>{s||process.stdout.write(`${f}
40
+ `)},u=new Set,p=setInterval(()=>{let f=r.listSims(),y=new Set(f.map(g=>g.id));for(let g of f)if(!u.has(g.id)){let b=g.title||g.url||g.origin||"(unknown)";l(` + ${g.id} ${b}`)}for(let g of u)y.has(g)||l(` - ${g}`);u.clear();for(let g of y)u.add(g)},500);ee({event:"daemon_heartbeat",properties:{bridge_port:c,under_daemon:At(),platform:process.platform,subsource:"daemon"}}),te(),l(`sootsim bridge listening on ws://localhost:${c} (runtime http on same port)`),c!==i&&l(` (preferred port ${i} was taken \u2014 fell back to ${c})`),l(" ready for browser, electron, or headless playwright sims to connect"),l(" (ctrl-c to stop)");let m=async f=>{clearInterval(p),l(`
41
+ ${f} received \u2014 shutting down after ${Math.round((Date.now()-d)/1e3)}s`);try{await r.close()}catch{}process.exit(0)};process.on("SIGINT",()=>m("SIGINT")),process.on("SIGTERM",()=>m("SIGTERM")),process.on("SIGHUP",()=>m("SIGHUP")),process.on("exit",()=>{try{r.removeLockfile()}catch{}}),await new Promise(()=>{})}export{mi as runServe};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.200 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as g,b as k}from"./chunk-3PAUJH34.js";import{b as S,c as x}from"./chunk-GKXPIE6X.js";import{a as w}from"./chunk-VP4Y767U.js";import"./chunk-LSDJTPOY.js";import"./chunk-42G5ZRQR.js";import"./chunk-2E4DUZEV.js";import"./chunk-SFUQJU5Q.js";import"./chunk-I6DJFJQ6.js";import"./chunk-PJAKGC4A.js";import"./chunk-NX4VSQD5.js";import{E as v,J as f,L as m,l as b}from"./chunk-CB3I3VQT.js";import"./chunk-5SB3N45C.js";import"./chunk-7BS4AKZT.js";import"./chunk-VXBWUAYL.js";import"./chunk-6RHOWIGL.js";import{existsSync as r,mkdirSync as j,readFileSync as d,readdirSync as I,writeFileSync as D}from"fs";import{basename as p,dirname as y,join as i,relative as c,resolve as h}from"path";var T=["bun","pnpm","npm"];async function pe(n){(n.includes("--help")||n.includes("-h"))&&(console.log(`
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as g,b as k}from"./chunk-GUYKLSTX.js";import{b as S,c as x}from"./chunk-3ZENZOIX.js";import{a as w}from"./chunk-KYGUR727.js";import"./chunk-RWXCSRNE.js";import"./chunk-RS7QLHEH.js";import"./chunk-LNDRRZP3.js";import"./chunk-SQBX2HS7.js";import"./chunk-F2LLN4U7.js";import"./chunk-PL4GXELT.js";import"./chunk-RZQO4Q7E.js";import{H as v,M as f,O as m,l as b}from"./chunk-GZKT53SA.js";import"./chunk-K3UBHPVP.js";import"./chunk-5SKKMM7E.js";import"./chunk-2V43M57C.js";import"./chunk-4KT2BGQE.js";import{existsSync as r,mkdirSync as j,readFileSync as d,readdirSync as I,writeFileSync as D}from"fs";import{basename as p,dirname as y,join as i,relative as c,resolve as h}from"path";var T=["bun","pnpm","npm"];async function pe(n){(n.includes("--help")||n.includes("-h"))&&(console.log(`
3
3
  sootsim setup \u2014 set up this machine for SootSim
4
4
 
5
5
  usage:
@@ -94,4 +94,4 @@ module.exports = {
94
94
  4. inspect and drive it:
95
95
  sootsim describe
96
96
  sootsim do tap-text "Sign in"
97
- `)}function N(n,e){switch(n){case"bun":return`bunx ${e}`;case"pnpm":return`pnpm exec ${e}`;case"npm":return`npx ${e}`}}function ne(n,e){switch(n){case"bun":return`bun run ${e}`;case"pnpm":return`pnpm run ${e}`;case"npm":return`npm run ${e}`}}function oe(n){switch(n){case"bun":return"bun add -g sootsim";case"pnpm":return"pnpm add -g sootsim";case"npm":return"npm i -g sootsim"}}async function te(n,e){if(!e||n.dryRun)return;if(console.log(" last step:"),!process.stdin.isTTY){console.log(" run `sootsim open` after your Metro/Expo/One server is up");return}if(!await g("I'll run `sootsim open` for you now?",!0)){console.log(" later: sootsim open");return}let{runOpenCommand:o}=await import("./control-OXJ7S7UG.js");await o([],{port:7668})}async function R(n,e,o){return o.yes?!0:process.stdin.isTTY?g(n,e):(console.log(` ${n} ${e?"[Y/n]":"[y/N]"} n (non-interactive; pass --yes to accept)`),!1)}export{J as detectConfigScaffoldExt,M as detectNodeVersionPins,W as detectPreferredPackageManager,E as readMachineSetupStatus,pe as runSetup,de as shouldRunSetupForBareCommand};
97
+ `)}function N(n,e){switch(n){case"bun":return`bunx ${e}`;case"pnpm":return`pnpm exec ${e}`;case"npm":return`npx ${e}`}}function ne(n,e){switch(n){case"bun":return`bun run ${e}`;case"pnpm":return`pnpm run ${e}`;case"npm":return`npm run ${e}`}}function oe(n){switch(n){case"bun":return"bun add -g sootsim";case"pnpm":return"pnpm add -g sootsim";case"npm":return"npm i -g sootsim"}}async function te(n,e){if(!e||n.dryRun)return;if(console.log(" last step:"),!process.stdin.isTTY){console.log(" run `sootsim open` after your Metro/Expo/One server is up");return}if(!await g("I'll run `sootsim open` for you now?",!0)){console.log(" later: sootsim open");return}let{runOpenCommand:o}=await import("./control-75JRFOYV.js");await o([],{port:7668})}async function R(n,e,o){return o.yes?!0:process.stdin.isTTY?g(n,e):(console.log(` ${n} ${e?"[Y/n]":"[y/N]"} n (non-interactive; pass --yes to accept)`),!1)}export{J as detectConfigScaffoldExt,M as detectNodeVersionPins,W as detectPreferredPackageManager,E as readMachineSetupStatus,pe as runSetup,de as shouldRunSetupForBareCommand};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.200 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import"./chunk-6RHOWIGL.js";import*as i from"fs";import*as I from"os";import*as a from"path";import{fileURLToPath as h}from"url";function $(){try{let t=h(import.meta.resolve("sootsim/package.json"));return a.join(a.dirname(t),"skills")}catch{let t=a.dirname(h(import.meta.url));return a.resolve(t,"../../skills")}}var d=$(),w=new Set(["all","codex","claude"]);function S(){console.log(`sootsim skill
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import"./chunk-4KT2BGQE.js";import*as i from"fs";import*as I from"os";import*as a from"path";import{fileURLToPath as h}from"url";function $(){try{let t=h(import.meta.resolve("sootsim/package.json"));return a.join(a.dirname(t),"skills")}catch{let t=a.dirname(h(import.meta.url));return a.resolve(t,"../../skills")}}var d=$(),w=new Set(["all","codex","claude"]);function S(){console.log(`sootsim skill
3
3
 
4
4
  install and inspect bundled SootSim agent skills.
5
5
 
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.200 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{k as f}from"./chunk-UGJFYNMX.js";import"./chunk-IJ6DRL7N.js";import"./chunk-XF3JBBPU.js";import"./chunk-GMBG6JLV.js";import"./chunk-EY2OMKPT.js";import"./chunk-6JKBWHIO.js";import"./chunk-MZLG4WVE.js";import"./chunk-VACKEJ3E.js";import"./chunk-XAIDHR55.js";import"./chunk-4RUK2YSF.js";import"./chunk-VFSOKG53.js";import{a as t,b as n,c as l,d as c,e as a}from"./chunk-DWFS6IIT.js";import"./chunk-KFGBNAV3.js";import"./chunk-QSWT3OVG.js";import"./chunk-P4PCUR4Y.js";import"./chunk-NEQRFWA3.js";import"./chunk-SFUQJU5Q.js";import"./chunk-I6DJFJQ6.js";import"./chunk-PJAKGC4A.js";import"./chunk-NX4VSQD5.js";import"./chunk-CB3I3VQT.js";import"./chunk-VXBWUAYL.js";import"./chunk-6RHOWIGL.js";function p(){console.log(`
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{k as f}from"./chunk-2CID4LNK.js";import"./chunk-AAQVPSIV.js";import"./chunk-B6JB4THC.js";import"./chunk-WVDWIXPH.js";import"./chunk-I6O7NBPZ.js";import"./chunk-CGJ2U6ST.js";import"./chunk-RJVIUQK4.js";import"./chunk-4NM6JBYH.js";import"./chunk-EMOZJ773.js";import"./chunk-ROYBEBG2.js";import"./chunk-KRGHRSKY.js";import{a as t,b as n,c as l,d as c,e as a}from"./chunk-HZYHSLNH.js";import"./chunk-ENXHZGSL.js";import"./chunk-DRJ4YWUG.js";import"./chunk-4KVSVFRF.js";import"./chunk-OG6TFGYF.js";import"./chunk-SQBX2HS7.js";import"./chunk-F2LLN4U7.js";import"./chunk-PL4GXELT.js";import"./chunk-RZQO4Q7E.js";import"./chunk-GZKT53SA.js";import"./chunk-2V43M57C.js";import"./chunk-4KT2BGQE.js";function p(){console.log(`
3
3
  sootsim storage profile \u2014 manage isolated storage profiles
4
4
 
5
5
  usage:
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a}from"./chunk-OG6TFGYF.js";import"./chunk-2V43M57C.js";import"./chunk-4KT2BGQE.js";export{a as settingsStore};
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a,b}from"./chunk-KYGUR727.js";import"./chunk-RWXCSRNE.js";import"./chunk-GZKT53SA.js";import"./chunk-4KT2BGQE.js";export{b as flushCliTelemetry,a as trackCliEvent};
@@ -0,0 +1,69 @@
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as P,b as N,c as A}from"./chunk-DKBKU55D.js";import{a as L}from"./chunk-AAQVPSIV.js";import{a as k}from"./chunk-BZ7AW7ZB.js";import{a as O,b as M}from"./chunk-TANTCV45.js";import"./chunk-CGJ2U6ST.js";import"./chunk-RJVIUQK4.js";import{f as F}from"./chunk-ROYBEBG2.js";import{g as D,i as E}from"./chunk-KRGHRSKY.js";import"./chunk-DRJ4YWUG.js";import"./chunk-KYGUR727.js";import"./chunk-RWXCSRNE.js";import"./chunk-PL4GXELT.js";import"./chunk-RZQO4Q7E.js";import"./chunk-GZKT53SA.js";import"./chunk-4KT2BGQE.js";import{spawn as Y}from"child_process";import{existsSync as _,mkdtempSync as H,readdirSync as I,writeFileSync as G}from"fs";import{tmpdir as K}from"os";import{resolve as S,dirname as z,join as R,relative as X}from"path";import{fileURLToPath as q}from"url";var $=z(q(import.meta.resolve("sootsim-engine/package.json"))),Q=process.env.SOOTSIM_TEST_MODEL||"deepseek-v4-flash",j=18e3,Z=18e4;async function Te(e,t){let n=e.includes("--flows"),u=e.includes("--detox"),l=e.includes("--parallel"),s=e.includes("--watch"),a=e.find((i,c)=>e[c-1]==="--reporter")||"console",o=ee(e);if((e.includes("--help")||e.includes("-h"))&&(console.log(`
3
+ sootsim test \u2014 run tests against sootsim
4
+
5
+ usage:
6
+ sootsim test [options]
7
+ sootsim test "natural language goal" [--owner <org> --repo <repo>]
8
+
9
+ modes:
10
+ (default) run package-local playwright tests
11
+ "<prompt>" generate, run, upload, and register a replayable flow
12
+ --flows run YAML flows
13
+ --detox run shared Detox-style conformance suites
14
+
15
+ options:
16
+ --parallel run tests in parallel
17
+ --watch re-run on changes
18
+ --reporter output format (console|json|junit)
19
+ --origin sootbean upload / LLM origin (default: auto)
20
+ --owner org account to attach the uploaded run to
21
+ --repo repo name for --owner
22
+ -t, --testNamePattern <pat>
23
+ filter tests by name
24
+
25
+ examples:
26
+ sootsim test
27
+ sootsim test "tap the login button and verify the welcome screen"
28
+ sootsim test --flows
29
+ sootsim test --detox --watch
30
+ sootsim test -t "login"
31
+
32
+ notes:
33
+ playwright is best for smoke and package-local debugging
34
+ --detox is the preferred parity lane for behavior that should match real RN
35
+ `),process.exit(0)),o&&!n&&!u)await ce(o.prompt,o.index,e,t);else if(n)await pe(e,t,l,a);else if(u){let{runDetox:i}=await import("./detox-7R7DOKQM.js");await i(e.filter(c=>c!=="--detox"),t)}else await ue(e,t)}function h(e,t){let n=e.indexOf(t);return n>=0?e[n+1]:void 0}function C(e,t){for(let n of t){let u=h(e,n);if(u)return u}}var J=new Set(["--reporter","-t","--testNamePattern","--grep","--origin","--preview-origin","--public-origin","--preview-public-origin","--owner","--repo","--url","--driver","--sim","--device","--slow","--tail-wait","--remap","--replace"]);function ee(e){for(let t=0;t<e.length;t++){let n=e[t];if(n){if(J.has(n)){t+=1;continue}if(!n.startsWith("-"))return _(n)||/\.(?:[cm]?[jt]sx?|ya?ml|json)$/i.test(n)||!/\s/.test(n)&&n.length<16?null:{prompt:n,index:t}}}return null}function te(e,t){return e.filter((n,u)=>u!==t)}async function ne(e,t){let n=te(e,t),u=D(n,{stripBooleanFlags:["--parallel","--watch","--flows","--detox","--new","--headless","--headed","--electron","--preview-open"],stripValueFlags:[...J]}),l=E(u);try{let s=await F(l,{describe:!0,verbose:!1,filter:"",compact:!0,hideXy:!0}),o=[s.shell?`shell: ${JSON.stringify(s.shell)}`:"",s.keyboard?`keyboard: ${JSON.stringify(s.keyboard)}`:"",typeof s.nodeCount=="number"?`nodes: ${s.nodeCount}`:"",s.tree||""].filter(Boolean).join(`
36
+ `);return o.length>j?o.slice(0,j)+`
37
+ [tree truncated]`:o}finally{l.close()}}var oe=`
38
+ You write SootSim YAML flows from a user's natural-language test goal.
39
+ Return only JSON, no markdown, with this exact shape:
40
+ {"summary":"short human-readable result goal","steps":[{"waitFor":{"text":"...","timeout":10000}}]}
41
+
42
+ Use only these flow commands:
43
+ - waitFor: { "text"?: string, "id"?: string, "timeout"?: number }
44
+ - assertVisible: string or { "text"?: string, "id"?: string }
45
+ - assertNotVisible: string or { "text"?: string, "id"?: string }
46
+ - tapOn: string or { "text"?: string, "id"?: string, "index"?: number }
47
+ - inputText: string
48
+ - pressKey: string
49
+ - hideKeyboard: true
50
+ - swipe: { "direction": "UP" | "DOWN" | "LEFT" | "RIGHT", "duration"?: number }
51
+ - waitForAnimationToEnd: true
52
+ - takeScreenshot: "label"
53
+
54
+ Prefer ids/testIDs from the tree. Prefer visible text when no id exists.
55
+ Do not invent app-specific data that is not visible. Keep the flow short.
56
+ End with an assertion or wait that proves the user's goal.
57
+ `.trim();function re(e,t){return`
58
+ User goal:
59
+ ${e}
60
+
61
+ Current SootSim visible tree:
62
+ ${t||"[no tree available]"}
63
+
64
+ Generate the shortest replayable flow that verifies the goal from this current state.
65
+ `.trim()}function U(e){return typeof e=="string"?e:Array.isArray(e)?e.map(t=>t&&typeof t=="object"&&t.type==="text"?String(t.text??""):"").join(""):""}async function se(e){let t=await fetch(`${e.origin.replace(/\/$/,"")}/api/llm`,{method:"POST",headers:{"content-type":"application/json",authorization:e.authHeader},body:JSON.stringify({modelId:Q,context:{systemPrompt:oe,messages:[{role:"user",content:re(e.prompt,e.describe),timestamp:Date.now()}]},options:{maxTokens:1800,temperature:.2},threadId:null}),signal:AbortSignal.timeout(Z)});if(!t.ok||!t.body){let c=await t.text().catch(()=>"");throw new Error(`/api/llm ${t.status}${c?`: ${c}`:""}`)}let n=t.body.getReader(),u=new TextDecoder,l=[],s="",a="",o=c=>{let p=c.trim();if(!p)return;let r=JSON.parse(p);if(r.type==="text_delta"&&r.delta)l.push(r.delta);else if(r.type==="text_end"&&r.content)s=r.content;else if(r.type==="done")s=U(r.message?.content);else if(r.type==="error")throw new Error(r.error?.errorMessage||U(r.error?.content)||"llm error")};for(;;){let{value:c,done:p}=await n.read();if(p)break;a+=u.decode(c,{stream:!0});let r;for(;(r=a.indexOf(`
66
+ `))>=0;)o(a.slice(0,r)),a=a.slice(r+1)}a+=u.decode(),a.trim()&&o(a);let i=(s||l.join("")).trim();if(!i)throw new Error("llm returned an empty test flow");return i}function ie(e){let t=e.match(/```(?:json)?\s*([\s\S]*?)```/i),n=t?t[1]:e.slice(e.indexOf("{"),e.lastIndexOf("}")+1);return JSON.parse(n)}function B(e){return!!(e&&typeof e=="object"&&!Array.isArray(e))}function le(e){let t=ie(e);if(!B(t))throw new Error("llm did not return a JSON object");let n=typeof t.summary=="string"&&t.summary.trim()?t.summary.trim().slice(0,500):"SootSim generated test",u=t.steps;if(!Array.isArray(u)||u.length===0)throw new Error("llm returned no flow steps");let l=u.map((s,a)=>{if(!B(s))throw new Error(`flow step ${a+1} is not an object`);return s});return{summary:n,steps:l,yamlText:L.stringify(l)}}function ae(e,t,n,u){let l=[n,"--preview","--preview-origin",u,"--billing-kind","test_run"],s=new Set(["--public-origin","--preview-public-origin","--owner","--repo","--url","--driver","--sim","--device","--slow","--tail-wait","--remap","--replace"]),a=new Set(["--new","--headless","--headed","--electron","--preview-open","--no-shell","--shell-only"]);for(let o=0;o<e.length;o++){if(o===t)continue;let i=e[o];if(i==="--origin"||i==="--preview-origin"){o+=1;continue}if(i==="--public-origin"){let c=e[o+1];c&&l.push("--preview-public-origin",c),o+=1;continue}if(s.has(i)){let c=e[o+1];c&&l.push(i,c),o+=1;continue}a.has(i)&&l.push(i)}return l}async function ce(e,t,n,u){let l=O();(!l||l.kind==="github")&&(console.error(' sootsim test "<prompt>" needs a login or SOOTSIM_API_KEY.'),console.error(" API keys must include preview_upload and llm scopes."),process.exit(1));let s=M(l),a=await k(C(n,["--origin","--preview-origin"]));console.log(" inspecting current sim\u2026");let o=await ne(n,t);console.log(" generating flow\u2026");let i=await se({prompt:e,describe:o,origin:a,authHeader:s}),c=le(i),p=H(R(K(),"sootsim-test-")),r=R(p,"flow.yaml");G(r,c.yamlText),console.log(` flow: ${r}`);let m=Date.now(),{runFlowPlayback:d,getLastFlowPreviewUploadResult:v,getLastFlowTraceSteps:y}=await import("./flow-AHWVTHJP.js"),w=ae(n,t,r,a),g=await d(w),f=v(),b=y(),V=b.find(W=>W.status==="failure"),T=g===0?"passed":"failed",x=await A({origin:a,kind:"nl",prompt:e,summary:c.summary,status:T,failureMessage:T==="failed"?V?.error??"flow playback failed":null,previewShareId:f?.shareId??null,owner:h(n,"--owner")??null,repo:h(n,"--repo")??null,durationMs:Date.now()-m,flowYamlSizeBytes:Buffer.byteLength(c.yamlText,"utf8"),...P(b),auth:l});console.log(`
67
+ result: ${T}`),x&&console.log(` run: ${x.id}`),f?.previewUrl&&console.log(` preview: ${f.previewUrl}`),x?.traceUrl&&console.log(` replay: ${x.traceUrl}`),process.exit(g)}async function ue(e,t){let n=["playwright","test"],u=e.find((o,i)=>e[i-1]==="-t")||e.find((o,i)=>e[i-1]==="--testNamePattern")||e.find((o,i)=>e[i-1]==="--grep");u&&n.push("-g",u),e.includes("--watch")&&n.push("--ui");let l=new Set(["--flows","--detox","--parallel","--watch","--reporter","-t","--testNamePattern","--grep"]);for(let o=0;o<e.length;o++){if(l.has(e[o])){(e[o]==="-t"||e[o]==="--testNamePattern"||e[o]==="--grep"||e[o]==="--reporter")&&o++;continue}n.push(e[o])}console.log(` running: npx ${n.join(" ")}`);let s=Y("npx",n,{cwd:$,stdio:"inherit",env:{...process.env}}),a=await new Promise(o=>{s.on("exit",i=>o(i||0))});process.exit(a)}async function pe(e,t,n,u){let l=["flows","test/flows","e2e/flows",".maestro","maestro"],s=[];for(let p of l){let r=S($,p);if(_(r)){let m=I(r).filter(d=>d.endsWith(".yaml")||d.endsWith(".yml"));for(let d of m)s.push(S(r,d))}}for(let p of l){let r=S(process.cwd(),p);if(!r.startsWith($)&&_(r)){let m=I(r).filter(d=>d.endsWith(".yaml")||d.endsWith(".yml"));for(let d of m)s.push(S(r,d))}}s.length===0&&(console.log(" no flow files found in flows/, test/flows/, or e2e/flows/"),process.exit(0)),console.log(` found ${s.length} flow(s)`);let a=O(),o=await k(C(e,["--origin","--preview-origin"])),i=0,c=0;for(let p of s){let r=1,m=Date.now();try{let{runFlowPlayback:w}=await import("./flow-AHWVTHJP.js"),g=t.port?`http://localhost:${t.port}`:"http://localhost:5173";r=await w([p,"--url",g,"--new"])}catch{r=1}r===0?i++:c++;let{getLastFlowPreviewUploadResult:d,getLastFlowTraceSteps:v}=await import("./flow-AHWVTHJP.js"),y=d();if(N({uploadedShare:!!y,auth:a})){let w=v(),g=w.find(b=>b.status==="failure"),f=await A({origin:o,kind:"flow",name:X(process.cwd(),p),status:r===0?"passed":"failed",failureMessage:r===0?null:g?.error??"flow playback failed",previewShareId:y?.shareId??null,owner:h(e,"--owner")??null,repo:h(e,"--repo")??null,durationMs:Date.now()-m,...P(w),auth:a});f&&console.log(` run: ${f.id}${f.traceUrl?` \xB7 replay: ${f.traceUrl}`:""}`)}}console.log(`
68
+ results: ${i} passed, ${c} failed (${s.length} total)
69
+ `),process.exit(c>0?1:0)}export{Te as runTest};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.200 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{g as m,i as d,l as s}from"./chunk-VFSOKG53.js";import"./chunk-PJAKGC4A.js";import"./chunk-NX4VSQD5.js";import"./chunk-CB3I3VQT.js";import"./chunk-6RHOWIGL.js";import{writeFileSync as g}from"fs";function u(){console.log(`
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{g as m,i as d,l as s}from"./chunk-KRGHRSKY.js";import"./chunk-PL4GXELT.js";import"./chunk-RZQO4Q7E.js";import"./chunk-GZKT53SA.js";import"./chunk-4KT2BGQE.js";import{writeFileSync as g}from"fs";function u(){console.log(`
3
3
  sootsim timeline \u2014 control the semantic event timeline
4
4
 
5
5
  usage:
@@ -0,0 +1,4 @@
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as c}from"./chunk-W4Y3JJX6.js";import{e as a}from"./chunk-6FZ6SNVP.js";import"./chunk-KRGHRSKY.js";import"./chunk-PL4GXELT.js";import"./chunk-RZQO4Q7E.js";import{K as l,h as s}from"./chunk-GZKT53SA.js";import{a as r}from"./chunk-K3UBHPVP.js";import"./chunk-4KT2BGQE.js";import{spawn as u}from"node:child_process";import d from"node:fs";import m from"node:path";var g="https://registry.npmjs.org/sootsim/latest";async function I(o){let n=o.indexOf("--channel"),t=n>=0&&o[n+1]?o[n+1]:void 0;console.log(`sootsim upgrade
3
+ `),console.log("runtime:");let e=a();e&&(console.log(` pinned to ${e} \u2014 installing the pin, not channel latest`),console.log(" (run `sootsim runtime unpin` to follow latest again)")),await c(["install",...t?["--channel",t]:[]],{}),console.log(`
4
+ cli:`),await f()}function p(){if(s())return{kind:"dev"};let o=process.argv[1]??"";try{o=d.realpathSync(o)}catch{}let n=m.sep;return o.includes(`${n}_npx${n}`)||o.includes(`${n}.bunx${n}`)?{kind:"npx"}:o.includes(`${n}.bun${n}`)?{kind:"global",command:"bun",args:["add","-g","sootsim@latest"]}:o.includes(`${n}pnpm${n}`)?{kind:"global",command:"pnpm",args:["add","-g","sootsim@latest"]}:{kind:"global",command:"npm",args:["i","-g","sootsim@latest"]}}async function f(){let o=r(),n=await v();if(!n){console.log(` v${o} \u2014 couldn't reach the npm registry, skipped`);return}if(l(n,o)<=0){console.log(` v${o} (latest)`);return}let t=p();if(console.log(` v${o} \u2192 v${n}`),t.kind==="dev"){console.log(" running from the soot dev checkout \u2014 pull instead of upgrading");return}if(t.kind==="npx"){console.log(" running from the npx cache \u2014 get the latest with:"),console.log(" npx sootsim@latest");return}let e=`${t.command} ${t.args.join(" ")}`;console.log(` updating global install (${e})\u2026`),await h(t.command,t.args)?console.log(` updated to v${n}`):(console.log(" update failed \u2014 run it yourself:"),console.log(` ${e}`))}function h(o,n){return new Promise(t=>{let e=u(o,n,{stdio:"inherit"});e.on("error",()=>t(!1)),e.on("exit",i=>t(i===0))})}async function v(){try{let o=await fetch(g,{headers:{accept:"application/json"},signal:AbortSignal.timeout(8e3)});if(!o.ok)return null;let n=await o.json();return typeof n.version=="string"&&n.version?n.version:null}catch{return null}}export{I as runUpgrade};
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a,b,c}from"./chunk-BZ7AW7ZB.js";import"./chunk-TANTCV45.js";import"./chunk-CGJ2U6ST.js";import"./chunk-RJVIUQK4.js";import"./chunk-KRGHRSKY.js";import"./chunk-DRJ4YWUG.js";import"./chunk-KYGUR727.js";import"./chunk-RWXCSRNE.js";import"./chunk-PL4GXELT.js";import"./chunk-RZQO4Q7E.js";import"./chunk-GZKT53SA.js";import"./chunk-4KT2BGQE.js";export{a as resolveDefaultUploadOrigin,b as resolvePublicPreviewOrigin,c as runUpload};
@@ -0,0 +1,4 @@
1
+ /*! sootsim v0.1.202 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{b as s,d as l,i as r}from"./chunk-6FZ6SNVP.js";import{a as i}from"./chunk-LNDRRZP3.js";import"./chunk-GZKT53SA.js";import{a as t}from"./chunk-K3UBHPVP.js";import"./chunk-4KT2BGQE.js";async function f(c){let{IS_BETA:m,BETA_LABEL:a}=await import("./beta-CCNQQ73A.js"),u=m?` \xB7 ${a}`:"";console.log(`sootsim v${t()}${u}`);let o=i(),e=l();o.isDevBridge?(console.log(o.primary),o.installedRuntime&&console.log(`${o.installedRuntime} \xB7 ${e}`)):o.primary==="runtime not installed"?console.log("runtime not installed \u2014 run `sootsim runtime install`"):console.log(`${o.primary} \xB7 ${e}`);let n=await r({channel:e});n.pinned&&console.log(` runtime pinned to v${n.pinned} (\`sootsim runtime unpin\` to follow latest)`),n.outdated&&n.latest&&console.log(`
3
+ \u2191 runtime v${n.latest} available \u2014 run \`sootsim upgrade\``),console.log(`
4
+ what's new: ${s}`)}export{f as runVersion};