sootsim 0.1.175 → 0.1.177

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 (153) hide show
  1. package/dist-cli/bin.js +3 -3
  2. package/dist-cli/chunks/{agent-A4WFJEFV.js → agent-3BCITLIZ.js} +3 -3
  3. package/dist-cli/chunks/{agent-wrapper-EOZBE6UT.js → agent-wrapper-26RIZVGD.js} +2 -2
  4. package/dist-cli/chunks/{app-fonts-H2I7IV7N.js → app-fonts-JVDHATQE.js} +2 -2
  5. package/dist-cli/chunks/{assert-36QXQUCE.js → assert-IT2OXM4Y.js} +2 -2
  6. package/dist-cli/chunks/beta-SPH73CAA.js +2 -0
  7. package/dist-cli/chunks/{camera-7HK2Y3PY.js → camera-ZYVEUCIO.js} +2 -2
  8. package/dist-cli/chunks/{chunk-2QTAUBZX.js → chunk-3L6I2M2Z.js} +3 -3
  9. package/dist-cli/chunks/chunk-4INGTBO7.js +4 -0
  10. package/dist-cli/chunks/{chunk-EEIUS5AS.js → chunk-4JESO36F.js} +4 -4
  11. package/dist-cli/chunks/{chunk-HWUFW3IP.js → chunk-4YNKFN2A.js} +2 -2
  12. package/dist-cli/chunks/{chunk-V7AGBG2P.js → chunk-52O56BTW.js} +2 -2
  13. package/dist-cli/chunks/{chunk-ZZWAHZ37.js → chunk-64QAFSY7.js} +1 -1
  14. package/dist-cli/chunks/{chunk-OMJ2DTQJ.js → chunk-65ZBQDQM.js} +2 -2
  15. package/dist-cli/chunks/{chunk-DV6SWCY7.js → chunk-A2WASN2L.js} +1 -1
  16. package/dist-cli/chunks/{chunk-H2J4Z7LY.js → chunk-A3VHHWLU.js} +2 -2
  17. package/dist-cli/chunks/{chunk-UMJDCX2P.js → chunk-AN4DM7IB.js} +2 -2
  18. package/dist-cli/chunks/{chunk-5QLWXLML.js → chunk-ATVKVVHZ.js} +2 -2
  19. package/dist-cli/chunks/chunk-B6GISAUX.js +1 -0
  20. package/dist-cli/chunks/{chunk-P2WO5LMI.js → chunk-BTTZN2SN.js} +2 -2
  21. package/dist-cli/chunks/{chunk-LYZXARZO.js → chunk-C5QOGCVN.js} +2 -2
  22. package/dist-cli/chunks/{chunk-RCPMRHTK.js → chunk-CH3MWM5W.js} +1 -1
  23. package/dist-cli/chunks/{chunk-7F2LH7U5.js → chunk-CHTYIQLE.js} +2 -2
  24. package/dist-cli/chunks/{chunk-SV3SRWN5.js → chunk-CUO7F2JE.js} +1 -1
  25. package/dist-cli/chunks/{chunk-YMBQBKKA.js → chunk-D2BBJUEY.js} +1 -1
  26. package/dist-cli/chunks/chunk-DGDBEXXQ.js +1 -0
  27. package/dist-cli/chunks/{chunk-3SUIAUIY.js → chunk-IBSEFPPL.js} +1 -1
  28. package/dist-cli/chunks/{chunk-ZPQY5DBY.js → chunk-JFLNZGDS.js} +2 -2
  29. package/dist-cli/chunks/{chunk-4UATZVHM.js → chunk-JHYLPDCC.js} +2 -2
  30. package/dist-cli/chunks/{chunk-XDDO46ZW.js → chunk-JS3NH2SJ.js} +1 -1
  31. package/dist-cli/chunks/{chunk-UXZRHPX6.js → chunk-JS7SSYDG.js} +2 -2
  32. package/dist-cli/chunks/{chunk-HWJ52K4J.js → chunk-JXO6UPGI.js} +1 -1
  33. package/dist-cli/chunks/{chunk-MLLINRL2.js → chunk-LTZPVG65.js} +1 -1
  34. package/dist-cli/chunks/{chunk-GJQGKFLY.js → chunk-NOLQYF76.js} +1 -1
  35. package/dist-cli/chunks/{chunk-2J67UJXT.js → chunk-NYGESF6F.js} +1 -1
  36. package/dist-cli/chunks/{chunk-QK76RK6J.js → chunk-NZWTC6K6.js} +1 -1
  37. package/dist-cli/chunks/{chunk-NPZPBSZD.js → chunk-PAU64XFG.js} +1 -1
  38. package/dist-cli/chunks/{chunk-IKJSGKUB.js → chunk-PL3ALTWB.js} +2 -2
  39. package/dist-cli/chunks/{chunk-ZG2A6LCL.js → chunk-QWZFOMCI.js} +2 -2
  40. package/dist-cli/chunks/{chunk-Y3OHYOFS.js → chunk-SNLUVL3H.js} +2 -2
  41. package/dist-cli/chunks/{chunk-KSF72FPP.js → chunk-SU3JJ7ER.js} +2 -2
  42. package/dist-cli/chunks/{chunk-XBK3XAKL.js → chunk-TVFHGWTW.js} +2 -2
  43. package/dist-cli/chunks/{chunk-JCQEG4R6.js → chunk-UBJQDMDG.js} +2 -2
  44. package/dist-cli/chunks/{chunk-VW643HG5.js → chunk-UJN3FMEX.js} +2 -2
  45. package/dist-cli/chunks/chunk-WKG5J4RD.js +2 -0
  46. package/dist-cli/chunks/{chunk-IISA6UXR.js → chunk-WRHJEI7Y.js} +1 -1
  47. package/dist-cli/chunks/{chunk-4UGD4KJM.js → chunk-WUEKKZ7Z.js} +2 -2
  48. package/dist-cli/chunks/{chunk-5D4PHINP.js → chunk-Y2637KG7.js} +1 -1
  49. package/dist-cli/chunks/chunk-YU6CNUJD.js +2 -0
  50. package/dist-cli/chunks/{chunk-46S56FJJ.js → chunk-YVDSGGOT.js} +1 -1
  51. package/dist-cli/chunks/{chunk-WM73SGMM.js → chunk-Z4IMGLHM.js} +2 -2
  52. package/dist-cli/chunks/{chunk-4PQ36DTJ.js → chunk-ZUTVEJVA.js} +3 -3
  53. package/dist-cli/chunks/cli-version-HENS6BZI.js +2 -0
  54. package/dist-cli/chunks/{compat-KWM6HXJD.js → compat-MNTQH57R.js} +3 -3
  55. package/dist-cli/chunks/{control-PVZRPH57.js → control-WQ7XEPCI.js} +2 -2
  56. package/dist-cli/chunks/{cpu-profile-3YLLRNVG.js → cpu-profile-P27HBXOI.js} +2 -2
  57. package/dist-cli/chunks/daemon-WUAZELEI.js +2 -0
  58. package/dist-cli/chunks/{debug-TD4EVFT7.js → debug-ES4A3SZQ.js} +3 -3
  59. package/dist-cli/chunks/{detox-S7M5WN3L.js → detox-Q36B2553.js} +2 -2
  60. package/dist-cli/chunks/{device-WR7GA4RN.js → device-NA7TB4E6.js} +2 -2
  61. package/dist-cli/chunks/{diagnose-JZMNR25X.js → diagnose-DKW5WI3X.js} +2 -2
  62. package/dist-cli/chunks/drivers-RFOOGIRC.js +2 -0
  63. package/dist-cli/chunks/{electron-V2YDDVKJ.js → electron-6C2VDAZW.js} +3 -3
  64. package/dist-cli/chunks/flow-GSHP52QS.js +2 -0
  65. package/dist-cli/chunks/help-J6PF4PZX.js +2 -0
  66. package/dist-cli/chunks/{hints-OK373YOJ.js → hints-W7ZZ6KZE.js} +2 -2
  67. package/dist-cli/chunks/{home-paths-IFY5UTLL.js → home-paths-K4347S7C.js} +2 -2
  68. package/dist-cli/chunks/{inspect-LRIJ7MQT.js → inspect-ZPHNFMEX.js} +4 -4
  69. package/dist-cli/chunks/{install-desktop-ESQL2Q2T.js → install-desktop-ZCCPJMOF.js} +3 -3
  70. package/dist-cli/chunks/{keys-IHG2YEL3.js → keys-XM67H4SM.js} +2 -2
  71. package/dist-cli/chunks/{login-CYIWYJGG.js → login-O4OGJKYL.js} +4 -4
  72. package/dist-cli/chunks/{logout-NALFLZWI.js → logout-DWCBRMLM.js} +2 -2
  73. package/dist-cli/chunks/{maestro-QKSXVPWG.js → maestro-MEWENIGQ.js} +2 -2
  74. package/dist-cli/chunks/optional-demo-registry-O3XS3WXJ.js +2 -0
  75. package/dist-cli/chunks/{preview-XCQGBN2I.js → preview-VPWG4462.js} +2 -2
  76. package/dist-cli/chunks/{profile-RDAPVU7K.js → profile-R4CSGXYJ.js} +2 -2
  77. package/dist-cli/chunks/{react-MM373YNE.js → react-5LFUOYV5.js} +2 -2
  78. package/dist-cli/chunks/{record-SQA376Z7.js → record-MHAAYOWF.js} +2 -2
  79. package/dist-cli/chunks/runtime-R2PRKIZM.js +2 -0
  80. package/dist-cli/chunks/{screenshot-FCKW6JV6.js → screenshot-XAEO7EBF.js} +2 -2
  81. package/dist-cli/chunks/{screenshot-mode-QVRUJXZ3.js → screenshot-mode-QNR5ESKN.js} +2 -2
  82. package/dist-cli/chunks/{screenshots-ITBCSBZS.js → screenshots-Z6OSENKY.js} +2 -2
  83. package/dist-cli/chunks/{screenshots-capture-H4EAYFH3.js → screenshots-capture-3DJPYJUD.js} +2 -2
  84. package/dist-cli/chunks/{serve-3GHYSGJR.js → serve-IVTQFOFI.js} +16 -16
  85. package/dist-cli/chunks/{setup-ME5SRHWD.js → setup-AMRSL4IK.js} +2 -2
  86. package/dist-cli/chunks/{skills-E5JE3SAI.js → skills-K4DG2CIH.js} +2 -2
  87. package/dist-cli/chunks/{slides-D37ML4LI.js → slides-UIH7KXFR.js} +2 -2
  88. package/dist-cli/chunks/store-2JY2VLVA.js +2 -0
  89. package/dist-cli/chunks/telemetry-KNKROOT5.js +2 -0
  90. package/dist-cli/chunks/{test-CWWQJG5K.js → test-XUJ2V5ZX.js} +3 -3
  91. package/dist-cli/chunks/{three-mode-WESGARG5.js → three-mode-P6HSLJMD.js} +2 -2
  92. package/dist-cli/chunks/{timeline-RUVZASG4.js → timeline-YSUY4PHV.js} +2 -2
  93. package/dist-cli/chunks/{upgrade-DKWD6TSY.js → upgrade-YZMDFQIH.js} +2 -2
  94. package/dist-cli/chunks/upload-TIH2LID6.js +2 -0
  95. package/dist-cli/chunks/{version-G45RLONC.js → version-5QAMZ5CK.js} +2 -2
  96. package/dist-cli/chunks/{web-X2HCJQQE.js → web-LM3JSBQF.js} +2 -2
  97. package/dist-cli/chunks/{what-happened-5DBVOXKC.js → what-happened-NYVQ7KER.js} +2 -2
  98. package/dist-cli/chunks/{whoami-ZDT3RQOC.js → whoami-AAHH72FM.js} +2 -2
  99. package/dist-lib/agent-daemon-client.cjs +10 -1
  100. package/dist-lib/agent-events.cjs +1 -1
  101. package/dist-lib/agent-sessions.cjs +1 -1
  102. package/dist-lib/attached-projects.cjs +1 -1
  103. package/dist-lib/auth/shared-session.cjs +1 -1
  104. package/dist-lib/backend-origin.cjs +1 -1
  105. package/dist-lib/beta.cjs +1 -1
  106. package/dist-lib/beta.mjs +1 -1
  107. package/dist-lib/bridge-constants.cjs +7 -1
  108. package/dist-lib/cli-constants.cjs +1 -1
  109. package/dist-lib/config.cjs +1 -1
  110. package/dist-lib/detox/index.cjs +1 -1
  111. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  112. package/dist-lib/home-paths.cjs +1 -1
  113. package/dist-lib/host/bridge-host.cjs +126 -12
  114. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  115. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  116. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  117. package/dist-lib/host/websocket-proxy.cjs +1 -1
  118. package/dist-lib/index.cjs +1 -1
  119. package/dist-lib/jump-to-source-babel.cjs +1 -1
  120. package/dist-lib/menu.cjs +1 -1
  121. package/dist-lib/menu.mjs +1 -1
  122. package/dist-lib/metro.cjs +1 -1
  123. package/dist-lib/profiles.cjs +1 -1
  124. package/dist-lib/render-mode.cjs +1 -1
  125. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  126. package/dist-lib/sdk.cjs +1 -1
  127. package/dist-lib/sdk.mjs +1 -1
  128. package/dist-lib/skills.cjs +237 -102
  129. package/dist-lib/vite.cjs +1 -1
  130. package/package.json +7 -1
  131. package/src/agent-daemon-client.ts +13 -0
  132. package/src/agent-identity.ts +21 -0
  133. package/src/agentbus-prompt.ts +80 -0
  134. package/src/bridge-constants.ts +9 -0
  135. package/src/host/agent-host.ts +42 -0
  136. package/src/host/bridge-host.ts +14 -1
  137. package/src/native-seam-manifest.ts +11 -0
  138. package/dist-cli/chunks/beta-7FRVMDBH.js +0 -2
  139. package/dist-cli/chunks/chunk-3G5EE3ST.js +0 -2
  140. package/dist-cli/chunks/chunk-HCKTFQLK.js +0 -2
  141. package/dist-cli/chunks/chunk-ODISDSXU.js +0 -1
  142. package/dist-cli/chunks/chunk-RAESCYIA.js +0 -4
  143. package/dist-cli/chunks/chunk-URQSBUTU.js +0 -1
  144. package/dist-cli/chunks/cli-version-HCYSKPJO.js +0 -2
  145. package/dist-cli/chunks/daemon-2DT4QAJ4.js +0 -2
  146. package/dist-cli/chunks/drivers-UMQTPEMU.js +0 -2
  147. package/dist-cli/chunks/flow-CKXTFJJ7.js +0 -2
  148. package/dist-cli/chunks/help-OEMLUQMD.js +0 -2
  149. package/dist-cli/chunks/optional-demo-registry-CIEW2ET7.js +0 -2
  150. package/dist-cli/chunks/runtime-CUNVH66R.js +0 -2
  151. package/dist-cli/chunks/store-UW5HH6DW.js +0 -2
  152. package/dist-cli/chunks/telemetry-KSBNWXNE.js +0 -2
  153. package/dist-cli/chunks/upload-LYANGCPB.js +0 -2
@@ -1,25 +1,25 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{b as oe,c as H,d as ae,e as F,f as ce,h as de,i as T,j as le,k as ue,l as pe,p as me,s as C,t as he,u as fe,v as ge,w as Se}from"./chunk-IKJSGKUB.js";import"./chunk-IISA6UXR.js";import{g as ne}from"./chunk-ZG2A6LCL.js";import{f as P}from"./chunk-KSF72FPP.js";import"./chunk-46S56FJJ.js";import{a as se}from"./chunk-LYZXARZO.js";import"./chunk-V7AGBG2P.js";import"./chunk-2J67UJXT.js";import"./chunk-RCPMRHTK.js";import"./chunk-OMJ2DTQJ.js";import{d as re}from"./chunk-HWJ52K4J.js";import{a as Z,b as Q}from"./chunk-Y3OHYOFS.js";import"./chunk-JCQEG4R6.js";import{a as te,b as ie}from"./chunk-HCKTFQLK.js";import"./chunk-RAESCYIA.js";import{C as E,D as $,E as J,F as N,H as K,I as V,K as G,M as q,N as z,O as X,P as U,Q as Y,y as M,z as j}from"./chunk-3SUIAUIY.js";import{a as ee}from"./chunk-SV3SRWN5.js";import"./chunk-ZZWAHZ37.js";import{spawn as Qe}from"child_process";import k from"fs";import{createServer as et}from"http";import S from"path";import{WebSocket as h,WebSocketServer as tt}from"ws";import ye from"node:fs";import R from"node:path";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 O=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 C?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 pe()}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 de(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return le(i.projectId?String(i.projectId):void 0);case"agent:start-session":return this.doStartSession(i.input??{});case"agent:send-prompt":{let n=String(i.sessionId),a=T(n);if(!a)throw new C("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await fe(n,r),this.notePromptAccepted(n,r,a.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await ge(String(i.sessionId));let s=T(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 C("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async doStartSession(e){if(!ae(e.projectId))throw new C("NO_PROJECT",`no project: ${e.projectId}`);let i=await he(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(d=>String(d.port)===i);if(!a||!a.cwd)return{project:null};let r=F().find(d=>d.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??Oe(a.framework),bundleId:a.bundleId??r?.bundleId})}}getTranscript(e){let t=me(e);return ye.existsSync(t)?ye.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=oe();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=Se(t,a=>{let r=this.coalescePromptEcho(t,a);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),a.type==="turn-completed"){let c=T(t);if(c)try{ce(c.projectId,{usd:a.costUsd,ts:a.ts})}catch(l){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${l instanceof Error?l.message:String(l)}
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){ue(e,t);let i=T(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 Oe(o){return o==="expo"?"expo":o==="one"||o==="vxrn"?"one":"unknown"}import Be from"http";import De from"https";var W="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",xe=[{hostSuffix:"uniswap.org",headers:{origin:"https://app.uniswap.org",referer:"https://app.uniswap.org/"},suppressBrowserUserAgent:!0}];function Le(o){let e=o.toLowerCase();for(let t of xe)if(e===t.hostSuffix||e.endsWith(`.${t.hostSuffix}`))return t}function ve(o){let e=Le(o.hostname);return{"accept-encoding":"identity",...e?.suppressBrowserUserAgent?{}:{"user-agent":W},...e?.headers}}var Me=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"]),Ne={"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"},Ue=new Set(["host","origin","referer","sec-fetch-site","sec-fetch-mode","sec-fetch-dest"]);function I(o){for(let[e,t]of Object.entries(Ne))o.setHeader(e,t)}function He(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 Fe(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 We(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(Me.has(i.toLowerCase())||(t[i]=Array.isArray(s)?s.join(", "):s));return Object.assign(t,e?ve(e):{"user-agent":W}),t}function je(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(Ue.has(i.toLowerCase())||(t[i]=s));return t.host=e.host,t.origin=e.origin,t.referer=`${e.origin}/`,t}function be(o){return o?.startsWith("/__fetch-proxy?")||o?.startsWith("/__proxy?")||!1}function we(o){return o?!!(o.startsWith("/__app-api?")||o.startsWith("/__app-api/")):!1}async function Ae(o,e){if(o.method==="OPTIONS"){I(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((o.url||"").split("?")[1]||"").get("url");if(!i){I(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{I(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=We(o.headers,s),a;if(o.method!=="GET"&&o.method!=="HEAD"){let d=[];for await(let u of o)d.push(Buffer.isBuffer(u)?u:Buffer.from(u));if(d.length>0){let u=Buffer.concat(d);a=Fe(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(d){I(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${He(s.href,d)}`);return}r.headers.forEach((d,u)=>{let p=u.toLowerCase();p==="content-encoding"||p==="transfer-encoding"||p==="content-length"||p==="set-cookie"||p.startsWith("access-control-")||e.setHeader(u,d)}),I(e);let c=r.headers.getSetCookie?.()??[];c.length>0&&e.setHeader("x-sootsim-set-cookie",c.join(", ")),e.statusCode=r.status;let l=Buffer.from(await r.arrayBuffer());e.end(l)}function ke(o,e){let t=o.url||"",i="",s="";if(t.startsWith("/__app-api?")){let l=new URL(t,"http://sootsim.local");i=l.searchParams.get("path")||"",s=l.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:"?De:Be,r=je(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},l=>{let d=Object.keys(l.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(l.statusCode??502,{...l.headers,"access-control-allow-origin":o.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":d}),l.pipe(e)});return c.on("error",l=>{e.statusCode=502,e.end(`app proxy error: ${l.message}`)}),o.pipe(c),!0}import{WebSocket as A,WebSocketServer as $e}from"ws";var Je="/__websocket-proxy",Ke=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 w(o,e,t){try{o.write(`HTTP/1.1 ${e} ${t}\r
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{b as ae,c as H,d as ce,e as F,f as de,h as le,i as C,j as ue,k as pe,l as me,p as he,s as v,t as fe,u as ge,v as Se,w as ye}from"./chunk-PL3ALTWB.js";import"./chunk-WRHJEI7Y.js";import{g as se}from"./chunk-QWZFOMCI.js";import{f as P}from"./chunk-SU3JJ7ER.js";import"./chunk-YVDSGGOT.js";import{a as oe}from"./chunk-C5QOGCVN.js";import"./chunk-52O56BTW.js";import"./chunk-NYGESF6F.js";import"./chunk-CH3MWM5W.js";import"./chunk-65ZBQDQM.js";import{d as ne}from"./chunk-JXO6UPGI.js";import{a as Q,b as ee}from"./chunk-SNLUVL3H.js";import"./chunk-UBJQDMDG.js";import{a as ie,b as re}from"./chunk-WKG5J4RD.js";import"./chunk-4INGTBO7.js";import{C as E,D as J,E as K,F as D,H as V,I as G,K as q,M as z,N as X,O as Y,P as U,Q as Z,y as M,z as j}from"./chunk-IBSEFPPL.js";import{a as te}from"./chunk-CUO7F2JE.js";import"./chunk-64QAFSY7.js";import{spawn as dt}from"child_process";import I from"fs";import{createServer as lt}from"http";import S from"path";import{WebSocket as h,WebSocketServer as ut}from"ws";import Ae from"node:fs";import _ from"node:path";import{spawn as Be}from"node:child_process";import Ne from"node:fs";import Me from"node:os";import De from"node:path";var ve=/^[A-Za-z0-9._:-]{1,160}$/;function W(o){if(!o?.startsWith("AGENTBUS_SESSION:"))return null;let e=o.slice(17).trim();return ve.test(e)?e:null}function be(o){return ve.test(o)}function Ue(o){return typeof o.text=="string"?o.text.trim():""}function He(o){let e=o?.trim();if(e)return e;let t=process.env.AGENTBUS_COMMAND?.trim();if(t)return t;let i=De.join(Me.homedir(),".local","bin","agentbus");return Ne.existsSync(i)?i:"agentbus"}async function we(o){let e=o.sessionId.trim();if(!be(e))throw new Error(`invalid agentbus session id: ${e||"<empty>"}`);let t=Ue(o.prompt);if(!t)throw new Error("prompt text is empty");let i=He(o.command),s=o.timeoutMs??15e3;await new Promise((n,a)=>{let r=Be(i,["send",e,t],{stdio:["ignore","ignore","pipe"],env:process.env}),c="",l=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",d=>{c.length<4e3&&(c+=String(d))}),r.on("error",d=>{clearTimeout(l),a(d)}),r.on("exit",(d,u)=>{if(clearTimeout(l),d===0){n();return}let p=c.trim();a(new Error(p||`agentbus send exited with ${u?`signal ${u}`:`code ${d??"unknown"}`}`))})})}var x=1;function Fe(){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 R=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 me()}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 le(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return ue(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 ge(n,r),this.notePromptAccepted(n,r,a.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await Se(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 we({sessionId:s,prompt:this.normalizePromptEnvelope(e)}),{ok:!0,routed:"agentbus",sessionId:s}}async doStartSession(e){if(!ce(e.projectId))throw new v("NO_PROJECT",`no project: ${e.projectId}`);let i=await fe(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?.()??Fe(),a=(await P({excludePorts:s})).find(d=>String(d.port)===i);if(!a||!a.cwd)return{project:null};let r=F().find(d=>d.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??We(a.framework),bundleId:a.bundleId??r?.bundleId})}}getTranscript(e){let t=he(e);return Ae.existsSync(t)?Ae.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=ae();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=ye(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(l){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${l instanceof Error?l.message:String(l)}
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){pe(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===x)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===x)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===x)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,s){if(e.readyState===x)try{e.send(JSON.stringify({id:t,error:i,...s?{code:s}:{}}))}catch{}}};function We(o){return o==="expo"?"expo":o==="one"||o==="vxrn"?"one":"unknown"}import Je from"http";import Ke 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",$e=[{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 $e)if(e===t.hostSuffix||e.endsWith(`.${t.hostSuffix}`))return t}function ke(o){let e=je(o.hostname);return{"accept-encoding":"identity",...e?.suppressBrowserUserAgent?{}:{"user-agent":$},...e?.headers}}var Ve=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"]),Ge={"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"},qe=new Set(["host","origin","referer","sec-fetch-site","sec-fetch-mode","sec-fetch-dest"]);function T(o){for(let[e,t]of Object.entries(Ge))o.setHeader(e,t)}function ze(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 Xe(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 Ye(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(Ve.has(i.toLowerCase())||(t[i]=Array.isArray(s)?s.join(", "):s));return Object.assign(t,e?ke(e):{"user-agent":$}),t}function Ze(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(qe.has(i.toLowerCase())||(t[i]=s));return t.host=e.host,t.origin=e.origin,t.referer=`${e.origin}/`,t}function Ie(o){return o?.startsWith("/__fetch-proxy?")||o?.startsWith("/__proxy?")||!1}function Ce(o){return o?!!(o.startsWith("/__app-api?")||o.startsWith("/__app-api/")):!1}async function Te(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=Ye(o.headers,s),a;if(o.method!=="GET"&&o.method!=="HEAD"){let d=[];for await(let u of o)d.push(Buffer.isBuffer(u)?u:Buffer.from(u));if(d.length>0){let u=Buffer.concat(d);a=Xe(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(d){T(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${ze(s.href,d)}`);return}r.headers.forEach((d,u)=>{let p=u.toLowerCase();p==="content-encoding"||p==="transfer-encoding"||p==="content-length"||p==="set-cookie"||p.startsWith("access-control-")||e.setHeader(u,d)}),T(e);let c=r.headers.getSetCookie?.()??[];c.length>0&&e.setHeader("x-sootsim-set-cookie",c.join(", ")),e.statusCode=r.status;let l=Buffer.from(await r.arrayBuffer());e.end(l)}function Ee(o,e){let t=o.url||"",i="",s="";if(t.startsWith("/__app-api?")){let l=new URL(t,"http://sootsim.local");i=l.searchParams.get("path")||"",s=l.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:"?Ke:Je,r=Ze(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},l=>{let d=Object.keys(l.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(l.statusCode??502,{...l.headers,"access-control-allow-origin":o.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":d}),l.pipe(e)});return c.on("error",l=>{e.statusCode=502,e.end(`app proxy error: ${l.message}`)}),o.pipe(c),!0}import{WebSocket as k,WebSocketServer as Qe}from"ws";var et="/__websocket-proxy",tt=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 Ve(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 Ge(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&&(Ke.has(n.toLowerCase())||(s[n]=Array.isArray(a)?a.join(", "):String(a)));return s}function qe(o){let e=new URL(o.href);return e.protocol=o.protocol==="wss:"?"https:":"http:",e.origin}function ze(o){let e=o.headers["sec-websocket-protocol"];return(Array.isArray(e)?e.join(","):e||"").split(",").map(i=>i.trim()).filter(Boolean)}function x(o,e,t){if(!(o.readyState===A.CLOSED||o.readyState===A.CLOSING))try{o.close(e,t)}catch{o.terminate()}}function Xe(o,e){let t=!1,i=(s,n,a,r)=>{t||(t=!0,x(n,a,r.toString()),s.readyState===A.OPEN&&x(s,a,r.toString()))};o.on("message",(s,n)=>{e.readyState===A.OPEN&&e.send(s,{binary:n})}),e.on("message",(s,n)=>{o.readyState===A.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",()=>x(e,1011,"proxy client error")),e.on("error",()=>x(o,1011,"upstream websocket error"))}function Ye(o,e,t){let i={...t};return Object.keys(i).some(s=>s.toLowerCase()==="origin")||(i.origin=qe(o)),new A(o.href,e,{headers:i})}function Ze(o){if(!o)return!1;try{return new URL(o,"http://localhost").pathname===Je}catch{return!1}}function Te(o,e,t){if(!Ze(o.url))return!1;if(!Ve(o))return w(e,403,"forbidden websocket proxy origin"),!0;let i,s;try{let c=new URL(o.url||"/","http://localhost"),l=c.searchParams.get("url");if(!l)return w(e,400,"missing websocket proxy url"),!0;if(i=new URL(l),i.protocol!=="ws:"&&i.protocol!=="wss:")return w(e,400,"invalid websocket proxy protocol"),!0;s=Ge(c.searchParams.get("headers"))}catch{return w(e,400,"invalid websocket proxy request"),!0}let n=ze(o),a=Ye(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 $e({noServer:!0,clientTracking:!1,handleProtocols(d){return c||d.values().next().value||!1}}).handleUpgrade(o,e,t,d=>{Xe(d,a)})}),a.once("error",()=>{r||(r=!0,w(e,502,"upstream websocket error"))}),a.once("close",()=>{r||(r=!0,w(e,502,"upstream websocket closed"))}),!0}var it="require-corp",rt=new Set(["tap","keyboard"]),nt=2e3,st=1e3;function ot(o){return!o||typeof o.type!="string"?!1:o.acquireLock===!0?!0:o.readOnly===!0?!1:rt.has(o.type)}var Ce=5e3,at=3600*1e3,ct="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",dt={".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 Ie(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(ee())};</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 Ee(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;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.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new O({getExcludePorts:e.agentScanExcludes}),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 it(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 rt(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&&(tt.has(n.toLowerCase())||(s[n]=Array.isArray(a)?a.join(", "):String(a)));return s}function nt(o){let e=new URL(o.href);return e.protocol=o.protocol==="wss:"?"https:":"http:",e.origin}function st(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 ot(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 at(o,e,t){let i={...t};return Object.keys(i).some(s=>s.toLowerCase()==="origin")||(i.origin=nt(o)),new k(o.href,e,{headers:i})}function ct(o){if(!o)return!1;try{return new URL(o,"http://localhost").pathname===et}catch{return!1}}function Pe(o,e,t){if(!ct(o.url))return!1;if(!it(o))return A(e,403,"forbidden websocket proxy origin"),!0;let i,s;try{let c=new URL(o.url||"/","http://localhost"),l=c.searchParams.get("url");if(!l)return A(e,400,"missing websocket proxy url"),!0;if(i=new URL(l),i.protocol!=="ws:"&&i.protocol!=="wss:")return A(e,400,"invalid websocket proxy protocol"),!0;s=rt(c.searchParams.get("headers"))}catch{return A(e,400,"invalid websocket proxy request"),!0}let n=st(o),a=at(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 Qe({noServer:!0,clientTracking:!1,handleProtocols(d){return c||d.values().next().value||!1}}).handleUpgrade(o,e,t,d=>{ot(d,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 pt="require-corp",mt=new Set(["tap","keyboard"]),ht=2e3,ft=1e3;function gt(o){return!o||typeof o.type!="string"?!1:o.acquireLock===!0?!0:o.readOnly===!0?!1:mt.has(o.type)}var _e=5e3,St=3600*1e3,yt="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",vt={".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 Re(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;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.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new R({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=et((c,l)=>this.handleHttpRequest(c,l)),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 tt({noServer:!0}),this.wireWebSocketServer(),n.on("upgrade",(c,l,d)=>{Te(c,l,d)||this.wss?.handleUpgrade(c,l,d,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=N(),l=this.getActiveRuntime(),d={type:"runtime:list:ok",id:r.id,installed:c,active:l.version,activeRuntimeDir:l.runtimeDir};try{e.send(JSON.stringify(d))}catch{}return}if(r.type==="runtime:use"){let c=typeof r.version=="string"?r.version:"";if(!N().includes(c)){try{e.send(JSON.stringify({type:"runtime:use:error",id:r.id,error:`runtime ${c||"(missing)"} is not installed`}))}catch{}return}let d=this.setActiveRuntime(c);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:d.version,runtimeDir:d.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 d=r,u=this.tryRestoreSimId(n,d.simId);n.url=d.url,n.title=d.title,n.userAgent=d.userAgent,typeof d.kind=="string"&&d.kind.trim()&&(n.kind=d.kind.trim()),d.meta&&typeof d.meta=="object"&&(n.meta=d.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 d=r;this.updateUserFocusLease(n,d);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){let d=r.patch&&typeof r.patch=="object"?r.patch:null;if(!d)return;let u;try{u=j(d)}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=lt((c,l)=>this.handleHttpRequest(c,l)),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 ut({noServer:!0}),this.wireWebSocketServer(),n.on("upgrade",(c,l,d)=>{Pe(c,l,d)||this.wss?.handleUpgrade(c,l,d,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(),l=this.getActiveRuntime(),d={type:"runtime:list:ok",id:r.id,installed:c,active:l.version,activeRuntimeDir:l.runtimeDir};try{e.send(JSON.stringify(d))}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 d=this.setActiveRuntime(c);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:d.version,runtimeDir:d.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 d=r,u=this.tryRestoreSimId(n,d.simId);n.url=d.url,n.title=d.title,n.userAgent=d.userAgent,typeof d.kind=="string"&&d.kind.trim()&&(n.kind=d.kind.trim()),d.meta&&typeof d.meta=="object"&&(n.meta=d.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 d=r;this.updateUserFocusLease(n,d);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){let d=r.patch&&typeof r.patch=="object"?r.patch:null;if(!d)return;let u;try{u=j(d)}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 d=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;d&&this.openPathInEditor(d,u,p);return}if(r.type==="bridge:boot-clients"&&n){let d=[];for(let[p,m]of this.cliSimBySocket)m===n.id&&d.push(p);for(let p of d){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 ${d.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 l=this.cliBySentId.get(r.id);if(l&&(this.cliBySentId.delete(r.id),l.ws.readyState===h.OPEN)){let d=this.getOtherCliIdentityCount(l.ws,l.simId),u=d>0?{...r,id:l.originalId,_otherCliCount:d}:{...r,id:l.originalId};l.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(ot(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 l=this.nextCommandId++;this.cliBySentId.set(l,{simId:c.id,ws:e,originalId:r.id});let{simId:d,...u}=r;if(c.ws.send(JSON.stringify({...u,id:l})),u.type==="close"){this.cliBySentId.delete(l),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)},nt);Ee(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(),!X(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{}},Ce),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{}},Ce),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(){return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,cwd:process.cwd(),startedAt:this.startedAt,heartbeatAt:Date.now(),source:"vite-dev"}}writeLockfileSnapshot(){q(this.buildLockfileSnapshot())}writeDevLockfileSnapshot(){z(this.buildDevLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=$(),this.activeRuntimeDirPath=K()}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[ct]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):at}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 ne();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
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 l=this.cliBySentId.get(r.id);if(l&&(this.cliBySentId.delete(r.id),l.ws.readyState===h.OPEN)){let d=this.getOtherCliIdentityCount(l.ws,l.simId),u=d>0?{...r,id:l.originalId,_otherCliCount:d}:{...r,id:l.originalId};l.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(gt(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 l=this.nextCommandId++;this.cliBySentId.set(l,{simId:c.id,ws:e,originalId:r.id});let{simId:d,...u}=r;if(c.ws.send(JSON.stringify({...u,id:l})),u.type==="close"){this.cliBySentId.delete(l),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)},ht);Re(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{}},_e),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{}},_e),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(){return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,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=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[yt]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):St}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 se();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
19
19
  `);return}let i=this.setActiveRuntime(t.latestVersion);process.stderr.write(`sootsim runtime updated to ${i.version} (${e})
20
20
  `)}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(J(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",it),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),be(e.url)){Ae(e,t);return}if(we(e.url)&&ke(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 l=s.searchParams.get("url");if(!l){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let d;try{d=new URL(l)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let u=d.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(d.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:v,value:b}=await g.read();if(v)break;t.write(Buffer.from(b))}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 l="{}";try{l=JSON.stringify(M())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(l);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 l of a.split("/"))if(l===".."){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}k.realpath(r,(l,d)=>{let u=l?r:d,p=u.endsWith(S.sep)?u:u+S.sep;if(!l){let m=(()=>{try{let f=k.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}}k.stat(u,(m,f)=>{if(m||!f?.isFile()){let b=S.extname(a).toLowerCase();if(b&&b!==".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 D=S.join(n,"index.html");k.readFile(D,(Pe,Re)=>{if(Pe){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(Ie(Re,this.effectivePort,this.sootbeanOrigin))});return}let y=S.extname(u).toLowerCase(),g=dt[y]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":g,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(y===".html"){k.readFile(u,(b,D)=>{if(b){try{t.end()}catch{}return}t.end(Ie(D,this.effectivePort,this.sootbeanOrigin))});return}let v=k.createReadStream(u);v.pipe(t),v.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 l=c?this.automationSimIdleReapTtlMs:this.simIdleReapTtlMs;if(r>=l){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(te,ie)}catch{try{e.terminate()}catch{}return}let t=setTimeout(()=>{if(e.readyState!==h.CLOSED)try{e.terminate()}catch{}},st);Ee(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:l=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(l)},reject:l=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(l)}}),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,l)=>new Promise(d=>{try{let u=Qe(c,l,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,d(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),d(!0))})}catch{d(!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 re(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{Y()}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,l=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{}l++}}let d={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:a+o.CLI_LEASE_TTL_MS};return t.cliLease=d,{granted:!0,lease:d,bootedCount:l}}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 lt(){return!!((process.env.XPC_SERVICE_NAME||"").includes("dev.sootsim.daemon")||process.env.INVOCATION_ID)}async function Jt(o,e={}){(o.includes("--help")||o.includes("-h"))&&(console.log(`
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",pt),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),Ie(e.url)){Te(e,t);return}if(Ce(e.url)&&Ee(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 l=s.searchParams.get("url");if(!l){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let d;try{d=new URL(l)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let u=d.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(d.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 l="{}";try{l=JSON.stringify(M())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(l);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 l of a.split("/"))if(l===".."){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,(l,d)=>{let u=l?r:d,p=u.endsWith(S.sep)?u:u+S.sep;if(!l){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,(Oe,Le)=>{if(Oe){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(Le,this.effectivePort,this.sootbeanOrigin))});return}let y=S.extname(u).toLowerCase(),g=vt[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 l=c?this.automationSimIdleReapTtlMs:this.simIdleReapTtlMs;if(r>=l){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{}},ft);Re(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:l=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(l)},reject:l=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(l)}}),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,l)=>new Promise(d=>{try{let u=dt(c,l,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,d(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),d(!0))})}catch{d(!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 ne(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,l=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{}l++}}let d={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:a+o.CLI_LEASE_TTL_MS};return t.cliLease=d,{granted:!0,lease:d,bootedCount:l}}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 bt(){return!!((process.env.XPC_SERVICE_NAME||"").includes("dev.sootsim.daemon")||process.env.INVOCATION_ID)}async function li(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=V();n&&G(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 se(),r=new L({port:i,writeLockfile:!0,sootbeanOrigin:a}),c=await r.startAsync({silent:s}),l=Date.now(),d=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 v=g.title||g.url||g.origin||"(unknown)";d(` + ${g.id} ${v}`)}for(let g of u)y.has(g)||d(` - ${g}`);u.clear();for(let g of y)u.add(g)},500);Z({event:"daemon_heartbeat",properties:{bridge_port:c,under_daemon:lt(),platform:process.platform,subsource:"daemon"}}),Q(),d(`sootsim bridge listening on ws://localhost:${c} (runtime http on same port)`),c!==i&&d(` (preferred port ${i} was taken \u2014 fell back to ${c})`),d(" ready for browser, electron, or headless playwright sims to connect"),d(" (ctrl-c to stop)");let m=async f=>{clearInterval(p),d(`
41
- ${f} received \u2014 shutting down after ${Math.round((Date.now()-l)/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{Jt 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=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 oe(),r=new L({port:i,writeLockfile:!0,sootbeanOrigin:a}),c=await r.startAsync({silent:s}),l=Date.now(),d=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)";d(` + ${g.id} ${b}`)}for(let g of u)y.has(g)||d(` - ${g}`);u.clear();for(let g of y)u.add(g)},500);Q({event:"daemon_heartbeat",properties:{bridge_port:c,under_daemon:bt(),platform:process.platform,subsource:"daemon"}}),ee(),d(`sootsim bridge listening on ws://localhost:${c} (runtime http on same port)`),c!==i&&d(` (preferred port ${i} was taken \u2014 fell back to ${c})`),d(" ready for browser, electron, or headless playwright sims to connect"),d(" (ctrl-c to stop)");let m=async f=>{clearInterval(p),d(`
41
+ ${f} received \u2014 shutting down after ${Math.round((Date.now()-l)/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{li as runServe};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{b as M,c as $}from"./chunk-XBK3XAKL.js";import{a as j,b as D}from"./chunk-5D4PHINP.js";import{a as P}from"./chunk-Y3OHYOFS.js";import"./chunk-JCQEG4R6.js";import"./chunk-5QLWXLML.js";import"./chunk-HWUFW3IP.js";import"./chunk-DV6SWCY7.js";import"./chunk-UMJDCX2P.js";import"./chunk-7F2LH7U5.js";import"./chunk-3G5EE3ST.js";import"./chunk-HCKTFQLK.js";import"./chunk-RAESCYIA.js";import{I as b,K as v}from"./chunk-3SUIAUIY.js";import"./chunk-SV3SRWN5.js";import"./chunk-XDDO46ZW.js";import"./chunk-QK76RK6J.js";import"./chunk-ZZWAHZ37.js";import{execSync as H}from"child_process";import{existsSync as g,readFileSync as I,writeFileSync as w}from"fs";import{join as K,relative as h,resolve as m}from"path";import{existsSync as c,readFileSync as d,readdirSync as W,statSync as A}from"fs";import{basename as N,dirname as V,join as i}from"path";function O(e){let o=e;for(;;){if(c(i(o,"turbo.json"))||c(i(o,"nx.json"))||c(i(o,"lerna.json"))||c(i(o,"pnpm-workspace.yaml")))return o;let n=i(o,"package.json");if(c(n))try{if(JSON.parse(d(n,"utf8")).workspaces)return o}catch{}let t=V(o);if(t===o)break;o=t}return e}function J(e){return c(i(e,"bun.lock"))||c(i(e,"bun.lockb"))?"bun":c(i(e,"pnpm-lock.yaml"))?"pnpm":c(i(e,"yarn.lock"))?"yarn":"npm"}function B(e){if(c(i(e,"turbo.json")))return"turbo";if(c(i(e,"nx.json")))return"nx";if(c(i(e,"pnpm-workspace.yaml")))return"pnpm";let o=i(e,"package.json");if(c(o))try{if(JSON.parse(d(o,"utf8")).workspaces)return"npm-workspaces"}catch{}return"single"}function G(e){return e.one?"one":e.expo?"expo":e["react-native"]?"bare":"unknown"}function S(e){let o=i(e,"package.json");if(!c(o))return null;let n;try{n=JSON.parse(d(o,"utf8"))}catch{return null}let t={...n.dependencies,...n.devDependencies},r=G(t);return r==="unknown"?null:{dir:e,name:n.name||N(e),framework:r,hasViteConfig:c(i(e,"vite.config.ts"))||c(i(e,"vite.config.js")),hasMetroConfig:c(i(e,"metro.config.js"))||c(i(e,"metro.config.ts")),hasSootsimDependency:!!t.sootsim,devCommand:n.scripts?.dev||null}}function U(e){let o=[],n=i(e,"pnpm-workspace.yaml");if(c(n)){let s=d(n,"utf8").match(/packages:\s*\n((?:\s+-\s+.+\n?)+)/);if(s){let p=s[1].split(`
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{b as M,c as $}from"./chunk-TVFHGWTW.js";import{a as j,b as D}from"./chunk-Y2637KG7.js";import{a as P}from"./chunk-SNLUVL3H.js";import"./chunk-UBJQDMDG.js";import"./chunk-ATVKVVHZ.js";import"./chunk-4YNKFN2A.js";import"./chunk-A2WASN2L.js";import"./chunk-AN4DM7IB.js";import"./chunk-CHTYIQLE.js";import"./chunk-YU6CNUJD.js";import"./chunk-WKG5J4RD.js";import"./chunk-4INGTBO7.js";import{I as b,K as v}from"./chunk-IBSEFPPL.js";import"./chunk-CUO7F2JE.js";import"./chunk-JS3NH2SJ.js";import"./chunk-NZWTC6K6.js";import"./chunk-64QAFSY7.js";import{execSync as H}from"child_process";import{existsSync as g,readFileSync as I,writeFileSync as w}from"fs";import{join as K,relative as h,resolve as m}from"path";import{existsSync as c,readFileSync as d,readdirSync as W,statSync as A}from"fs";import{basename as N,dirname as V,join as i}from"path";function O(e){let o=e;for(;;){if(c(i(o,"turbo.json"))||c(i(o,"nx.json"))||c(i(o,"lerna.json"))||c(i(o,"pnpm-workspace.yaml")))return o;let n=i(o,"package.json");if(c(n))try{if(JSON.parse(d(n,"utf8")).workspaces)return o}catch{}let t=V(o);if(t===o)break;o=t}return e}function J(e){return c(i(e,"bun.lock"))||c(i(e,"bun.lockb"))?"bun":c(i(e,"pnpm-lock.yaml"))?"pnpm":c(i(e,"yarn.lock"))?"yarn":"npm"}function B(e){if(c(i(e,"turbo.json")))return"turbo";if(c(i(e,"nx.json")))return"nx";if(c(i(e,"pnpm-workspace.yaml")))return"pnpm";let o=i(e,"package.json");if(c(o))try{if(JSON.parse(d(o,"utf8")).workspaces)return"npm-workspaces"}catch{}return"single"}function G(e){return e.one?"one":e.expo?"expo":e["react-native"]?"bare":"unknown"}function S(e){let o=i(e,"package.json");if(!c(o))return null;let n;try{n=JSON.parse(d(o,"utf8"))}catch{return null}let t={...n.dependencies,...n.devDependencies},r=G(t);return r==="unknown"?null:{dir:e,name:n.name||N(e),framework:r,hasViteConfig:c(i(e,"vite.config.ts"))||c(i(e,"vite.config.js")),hasMetroConfig:c(i(e,"metro.config.js"))||c(i(e,"metro.config.ts")),hasSootsimDependency:!!t.sootsim,devCommand:n.scripts?.dev||null}}function U(e){let o=[],n=i(e,"pnpm-workspace.yaml");if(c(n)){let s=d(n,"utf8").match(/packages:\s*\n((?:\s+-\s+.+\n?)+)/);if(s){let p=s[1].split(`
3
3
  `).filter(Boolean);for(let u of p){let a=u.replace(/^\s*-\s*['"]?/,"").replace(/['"]?\s*$/,"");a&&o.push(...C(e,a))}}return o}let t=i(e,"package.json");if(c(t))try{let r=JSON.parse(d(t,"utf8")),s=Array.isArray(r.workspaces)?r.workspaces:r.workspaces?.packages||[];for(let p of s)o.push(...C(e,p))}catch{}return o}function C(e,o){let n=o.replace(/\/\*\*?$/,"").replace(/\*$/,""),t=i(e,n);if(!c(t))return[];try{return W(t).map(s=>i(t,s)).filter(s=>{try{return A(s).isDirectory()&&c(i(s,"package.json"))}catch{return!1}})}catch{return[]}}function _(e){let o=B(e),n=J(e);if(o==="single"){let p=S(e);return{root:e,type:o,packageManager:n,apps:p?[p]:[]}}let t=U(e),r=[],s=S(e);s&&r.push(s);for(let p of t){if(p===e)continue;let u=S(p);u&&r.push(u)}return{root:e,type:o,packageManager:n,apps:r}}function R(e){switch(e){case"bun":return"bun add -d sootsim";case"pnpm":return"pnpm add -D sootsim";case"yarn":return"yarn add -D sootsim";case"npm":return"npm install -D sootsim"}}async function xe(e){(e.includes("--help")||e.includes("-h"))&&(console.log(`
4
4
  sootsim setup \u2014 set up this machine and, optionally, this repo
5
5
 
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import"./chunk-ZZWAHZ37.js";import*as r from"fs";import*as x from"os";import*as a from"path";import{fileURLToPath as p}from"url";function L(){try{let t=p(import.meta.resolve("sootsim/package.json"));return a.join(a.dirname(t),"skills")}catch{let t=a.dirname(p(import.meta.url));return a.resolve(t,"../../skills")}}var d=L(),w=new Set(["all","codex","claude"]);function h(){console.log(`sootsim skill
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import"./chunk-64QAFSY7.js";import*as r from"fs";import*as x from"os";import*as a from"path";import{fileURLToPath as p}from"url";function L(){try{let t=p(import.meta.resolve("sootsim/package.json"));return a.join(a.dirname(t),"skills")}catch{let t=a.dirname(p(import.meta.url));return a.resolve(t,"../../skills")}}var d=L(),w=new Set(["all","codex","claude"]);function h(){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.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{c as S,e as y,g as v,h as b,i as u}from"./chunk-OMJ2DTQJ.js";import"./chunk-HCKTFQLK.js";import"./chunk-RAESCYIA.js";import"./chunk-3SUIAUIY.js";import"./chunk-ZZWAHZ37.js";import{mkdirSync as $,writeFileSync as x}from"node:fs";import{dirname as k,isAbsolute as B,join as C,resolve as E}from"node:path";var z=`
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{c as S,e as y,g as v,h as b,i as u}from"./chunk-65ZBQDQM.js";import"./chunk-WKG5J4RD.js";import"./chunk-4INGTBO7.js";import"./chunk-IBSEFPPL.js";import"./chunk-64QAFSY7.js";import{mkdirSync as $,writeFileSync as x}from"node:fs";import{dirname as k,isAbsolute as B,join as C,resolve as E}from"node:path";var z=`
3
3
  sootsim slides \u2014 compose App Store screenshots in the live sim
4
4
 
5
5
  usage:
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a}from"./chunk-BTTZN2SN.js";import"./chunk-NZWTC6K6.js";import"./chunk-64QAFSY7.js";export{a as settingsStore};
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a,b}from"./chunk-SNLUVL3H.js";import"./chunk-UBJQDMDG.js";import"./chunk-IBSEFPPL.js";import"./chunk-64QAFSY7.js";export{b as flushCliTelemetry,a as trackCliEvent};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import"./chunk-ZZWAHZ37.js";import{spawn as m}from"child_process";import{existsSync as h,readdirSync as w}from"fs";import{resolve as u,dirname as x}from"path";import{fileURLToPath as y}from"url";var d=x(y(import.meta.resolve("sootsim-engine/package.json")));async function v(t,r){let l=t.includes("--flows"),f=t.includes("--detox"),c=t.includes("--parallel"),i=t.includes("--watch"),a=t.find((e,o)=>t[o-1]==="--reporter")||"console";if((t.includes("--help")||t.includes("-h"))&&(console.log(`
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import"./chunk-64QAFSY7.js";import{spawn as m}from"child_process";import{existsSync as h,readdirSync as w}from"fs";import{resolve as u,dirname as x}from"path";import{fileURLToPath as y}from"url";var d=x(y(import.meta.resolve("sootsim-engine/package.json")));async function v(t,r){let l=t.includes("--flows"),f=t.includes("--detox"),c=t.includes("--parallel"),i=t.includes("--watch"),a=t.find((e,o)=>t[o-1]==="--reporter")||"console";if((t.includes("--help")||t.includes("-h"))&&(console.log(`
3
3
  sootsim test \u2014 run tests against sootsim
4
4
 
5
5
  usage:
@@ -26,6 +26,6 @@ examples:
26
26
  notes:
27
27
  playwright is best for smoke and package-local debugging
28
28
  --detox is the preferred parity lane for behavior that should match real RN
29
- `),process.exit(0)),l)await b(t,r,c,a);else if(f){let{runDetox:e}=await import("./detox-S7M5WN3L.js");await e(t.filter(o=>o!=="--detox"),r)}else await g(t,r)}async function g(t,r){let l=["playwright","test"],f=t.find((e,o)=>t[o-1]==="-t")||t.find((e,o)=>t[o-1]==="--testNamePattern")||t.find((e,o)=>t[o-1]==="--grep");f&&l.push("-g",f),t.includes("--watch")&&l.push("--ui");let c=new Set(["--flows","--detox","--parallel","--watch","--reporter","-t","--testNamePattern","--grep"]);for(let e=0;e<t.length;e++){if(c.has(t[e])){(t[e]==="-t"||t[e]==="--testNamePattern"||t[e]==="--grep"||t[e]==="--reporter")&&e++;continue}l.push(t[e])}console.log(` running: npx ${l.join(" ")}`);let i=m("npx",l,{cwd:d,stdio:"inherit",env:{...process.env}}),a=await new Promise(e=>{i.on("exit",o=>e(o||0))});process.exit(a)}async function b(t,r,l,f){let c=["flows","test/flows","e2e/flows",".maestro","maestro"],i=[];for(let o of c){let s=u(d,o);if(h(s)){let p=w(s).filter(n=>n.endsWith(".yaml")||n.endsWith(".yml"));for(let n of p)i.push(u(s,n))}}for(let o of c){let s=u(process.cwd(),o);if(!s.startsWith(d)&&h(s)){let p=w(s).filter(n=>n.endsWith(".yaml")||n.endsWith(".yml"));for(let n of p)i.push(u(s,n))}}i.length===0&&(console.log(" no flow files found in flows/, test/flows/, or e2e/flows/"),process.exit(0)),console.log(` found ${i.length} flow(s)`);let a=0,e=0;for(let o of i)try{let{runFlowPlayback:s}=await import("./flow-CKXTFJJ7.js"),p=r.port?`http://localhost:${r.port}`:"http://localhost:5173";if(await s([o,"--url",p,"--new"])!==0){e++;continue}a++}catch{e++}console.log(`
29
+ `),process.exit(0)),l)await b(t,r,c,a);else if(f){let{runDetox:e}=await import("./detox-Q36B2553.js");await e(t.filter(o=>o!=="--detox"),r)}else await g(t,r)}async function g(t,r){let l=["playwright","test"],f=t.find((e,o)=>t[o-1]==="-t")||t.find((e,o)=>t[o-1]==="--testNamePattern")||t.find((e,o)=>t[o-1]==="--grep");f&&l.push("-g",f),t.includes("--watch")&&l.push("--ui");let c=new Set(["--flows","--detox","--parallel","--watch","--reporter","-t","--testNamePattern","--grep"]);for(let e=0;e<t.length;e++){if(c.has(t[e])){(t[e]==="-t"||t[e]==="--testNamePattern"||t[e]==="--grep"||t[e]==="--reporter")&&e++;continue}l.push(t[e])}console.log(` running: npx ${l.join(" ")}`);let i=m("npx",l,{cwd:d,stdio:"inherit",env:{...process.env}}),a=await new Promise(e=>{i.on("exit",o=>e(o||0))});process.exit(a)}async function b(t,r,l,f){let c=["flows","test/flows","e2e/flows",".maestro","maestro"],i=[];for(let o of c){let s=u(d,o);if(h(s)){let p=w(s).filter(n=>n.endsWith(".yaml")||n.endsWith(".yml"));for(let n of p)i.push(u(s,n))}}for(let o of c){let s=u(process.cwd(),o);if(!s.startsWith(d)&&h(s)){let p=w(s).filter(n=>n.endsWith(".yaml")||n.endsWith(".yml"));for(let n of p)i.push(u(s,n))}}i.length===0&&(console.log(" no flow files found in flows/, test/flows/, or e2e/flows/"),process.exit(0)),console.log(` found ${i.length} flow(s)`);let a=0,e=0;for(let o of i)try{let{runFlowPlayback:s}=await import("./flow-GSHP52QS.js"),p=r.port?`http://localhost:${r.port}`:"http://localhost:5173";if(await s([o,"--url",p,"--new"])!==0){e++;continue}a++}catch{e++}console.log(`
30
30
  results: ${a} passed, ${e} failed (${i.length} total)
31
31
  `),process.exit(e>0?1:0)}export{v as runTest};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as $}from"./chunk-WM73SGMM.js";import{c as p,e as h,i as R}from"./chunk-OMJ2DTQJ.js";import"./chunk-HCKTFQLK.js";import"./chunk-RAESCYIA.js";import"./chunk-3SUIAUIY.js";import"./chunk-ZZWAHZ37.js";var b=12e3;async function j(e,o){if((e.includes("--help")||e.includes("-h"))&&(console.log(`
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as $}from"./chunk-Z4IMGLHM.js";import{c as p,e as h,i as R}from"./chunk-65ZBQDQM.js";import"./chunk-WKG5J4RD.js";import"./chunk-4INGTBO7.js";import"./chunk-IBSEFPPL.js";import"./chunk-64QAFSY7.js";var b=12e3;async function j(e,o){if((e.includes("--help")||e.includes("-h"))&&(console.log(`
3
3
  sootsim three-mode \u2014 toggle the 3d device stage
4
4
 
5
5
  usage:
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{c as m,e as d,h as s}from"./chunk-OMJ2DTQJ.js";import"./chunk-HCKTFQLK.js";import"./chunk-RAESCYIA.js";import"./chunk-3SUIAUIY.js";import"./chunk-ZZWAHZ37.js";import{writeFileSync as g}from"fs";function u(){console.log(`
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{c as m,e as d,h as s}from"./chunk-65ZBQDQM.js";import"./chunk-WKG5J4RD.js";import"./chunk-4INGTBO7.js";import"./chunk-IBSEFPPL.js";import"./chunk-64QAFSY7.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:
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as s}from"./chunk-2QTAUBZX.js";import"./chunk-ZG2A6LCL.js";import"./chunk-OMJ2DTQJ.js";import"./chunk-HCKTFQLK.js";import"./chunk-RAESCYIA.js";import{G as i}from"./chunk-3SUIAUIY.js";import{a as e}from"./chunk-SV3SRWN5.js";import"./chunk-ZZWAHZ37.js";import{spawn as r}from"node:child_process";var a="https://registry.npmjs.org/sootsim/latest";async function h(o){let n=o.indexOf("--channel"),t=n>=0&&o[n+1]?o[n+1]:void 0;console.log(`sootsim upgrade
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as s}from"./chunk-3L6I2M2Z.js";import"./chunk-QWZFOMCI.js";import"./chunk-65ZBQDQM.js";import"./chunk-WKG5J4RD.js";import"./chunk-4INGTBO7.js";import{G as i}from"./chunk-IBSEFPPL.js";import{a as e}from"./chunk-CUO7F2JE.js";import"./chunk-64QAFSY7.js";import{spawn as r}from"node:child_process";var a="https://registry.npmjs.org/sootsim/latest";async function h(o){let n=o.indexOf("--channel"),t=n>=0&&o[n+1]?o[n+1]:void 0;console.log(`sootsim upgrade
3
3
  `),await c(),console.log(`
4
4
  runtime:`),await s(["install",...t?["--channel",t]:[]],{})}async function c(){let o=e(),n=await u();if(!n){console.log(` cli: v${o} \u2014 couldn't reach the npm registry, skipped`);return}if(i(n,o)<=0){console.log(` cli: v${o} (latest)`);return}console.log(` cli: v${o} \u2192 v${n} \u2014 installing globally\u2026`),await m(n)?console.log(` cli: installed v${n} \u2014 restart any running \`sootsim\` process to pick it up`):(console.log(" cli: automatic install failed \u2014 upgrade it yourself with:"),console.log(" npm install -g sootsim@latest"))}async function u(){try{let o=await fetch(a,{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}}function m(o){return new Promise(n=>{let t=r("npm",["install","-g",`sootsim@${o}`],{stdio:"inherit",shell:!0});t.on("error",()=>n(!1)),t.on("exit",l=>n(l===0))})}export{h as runUpgrade};
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a,b,c}from"./chunk-C5QOGCVN.js";import"./chunk-52O56BTW.js";import"./chunk-NYGESF6F.js";import"./chunk-CH3MWM5W.js";import"./chunk-65ZBQDQM.js";import"./chunk-JXO6UPGI.js";import"./chunk-SNLUVL3H.js";import"./chunk-UBJQDMDG.js";import"./chunk-WKG5J4RD.js";import"./chunk-4INGTBO7.js";import"./chunk-IBSEFPPL.js";import"./chunk-64QAFSY7.js";export{a as resolveDefaultUploadOrigin,b as resolvePublicPreviewOrigin,c as runUpload};
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.175 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{b as s,d as l,h as r}from"./chunk-ZG2A6LCL.js";import{a as i}from"./chunk-HWUFW3IP.js";import"./chunk-3SUIAUIY.js";import{a as t}from"./chunk-SV3SRWN5.js";import"./chunk-ZZWAHZ37.js";async function d(u){let{IS_BETA:a,BETA_LABEL:m}=await import("./beta-7FRVMDBH.js"),c=a?` \xB7 ${m}`:"";console.log(`sootsim v${t()}${c}`);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.outdated&&n.latest&&console.log(`
1
+ /*! sootsim v0.1.177 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{b as s,d as l,h as r}from"./chunk-QWZFOMCI.js";import{a as i}from"./chunk-4YNKFN2A.js";import"./chunk-IBSEFPPL.js";import{a as t}from"./chunk-CUO7F2JE.js";import"./chunk-64QAFSY7.js";async function d(u){let{IS_BETA:a,BETA_LABEL:m}=await import("./beta-SPH73CAA.js"),c=a?` \xB7 ${m}`:"";console.log(`sootsim v${t()}${c}`);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.outdated&&n.latest&&console.log(`
3
3
  \u2191 runtime v${n.latest} available \u2014 run \`sootsim upgrade\``),console.log(`
4
4
  what's new: ${s}`)}export{d as runVersion};