sootsim 0.1.51 → 0.1.52

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 (137) hide show
  1. package/dist-cli/bin.js +7 -7
  2. package/dist-cli/chunks/{agent-RLBVAUCW.js → agent-RUWGJCSS.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-TWLPNETE.js → agent-wrapper-FBCGP5N7.js} +2 -2
  4. package/dist-cli/chunks/{assert-JLQSBZPM.js → assert-IOU2NWE2.js} +2 -2
  5. package/dist-cli/chunks/auto-bootstrap-OYBDYAZM.js +2 -0
  6. package/dist-cli/chunks/beta-D4OEPOSE.js +2 -0
  7. package/dist-cli/chunks/{chunk-JZ65NOXB.js → chunk-2QNHBNWB.js} +2 -2
  8. package/dist-cli/chunks/{chunk-P45EZ2VW.js → chunk-3DDSYQHM.js} +2 -2
  9. package/dist-cli/chunks/{chunk-SLAAAEUZ.js → chunk-3MIWVHCX.js} +1 -1
  10. package/dist-cli/chunks/{chunk-PTW5KT4I.js → chunk-4TSGUAV3.js} +2 -2
  11. package/dist-cli/chunks/{chunk-3BUWCNVX.js → chunk-6QDFLMJL.js} +1 -1
  12. package/dist-cli/chunks/{chunk-VXLRXQER.js → chunk-7Y3FYPJH.js} +2 -2
  13. package/dist-cli/chunks/{chunk-2ZCJFJJN.js → chunk-A3YSGT76.js} +2 -2
  14. package/dist-cli/chunks/{chunk-ZT7672XM.js → chunk-ABEYZDD7.js} +3 -3
  15. package/dist-cli/chunks/{chunk-6NR6NFDC.js → chunk-BF7F45CZ.js} +2 -2
  16. package/dist-cli/chunks/{chunk-5PKYORP6.js → chunk-CTEXZ7BE.js} +1 -1
  17. package/dist-cli/chunks/{chunk-P2IC3VRD.js → chunk-DNKB2V2W.js} +2 -2
  18. package/dist-cli/chunks/chunk-DSJ7PGU3.js +2 -0
  19. package/dist-cli/chunks/{chunk-4QM4J2UK.js → chunk-DVCE2KQL.js} +1 -1
  20. package/dist-cli/chunks/{chunk-L4OPPOPY.js → chunk-EJYVXNQL.js} +2 -2
  21. package/dist-cli/chunks/{chunk-VDUWPVZT.js → chunk-EQPRFEHH.js} +2 -2
  22. package/dist-cli/chunks/{chunk-XWHWPFBE.js → chunk-EXQJSXDF.js} +1 -1
  23. package/dist-cli/chunks/{chunk-DBHV5S2L.js → chunk-EYRQG47K.js} +1 -1
  24. package/dist-cli/chunks/{chunk-SPMHQKNI.js → chunk-FPIJBBYW.js} +78 -78
  25. package/dist-cli/chunks/{chunk-RSEV5NWY.js → chunk-FVBSPGBR.js} +2 -2
  26. package/dist-cli/chunks/{chunk-45XEBYVX.js → chunk-GNQSOQXZ.js} +2 -2
  27. package/dist-cli/chunks/{chunk-265YGINI.js → chunk-H4G7IRXG.js} +6 -3
  28. package/dist-cli/chunks/{chunk-LMINUIAR.js → chunk-HRIQRZX3.js} +1 -1
  29. package/dist-cli/chunks/{chunk-DBYZF6KL.js → chunk-I5WEW3ES.js} +1 -1
  30. package/dist-cli/chunks/{chunk-54IIO5BV.js → chunk-IQU56D6C.js} +1 -1
  31. package/dist-cli/chunks/{chunk-IENPCJTB.js → chunk-IXITVIJV.js} +4 -4
  32. package/dist-cli/chunks/{chunk-FSTOUA6L.js → chunk-JPLTR6JM.js} +1 -1
  33. package/dist-cli/chunks/{chunk-FUHHRW7G.js → chunk-JPX7OS7B.js} +2 -2
  34. package/dist-cli/chunks/chunk-KVQWMXDV.js +2 -0
  35. package/dist-cli/chunks/{chunk-BKXH674Z.js → chunk-MBH3NFBC.js} +2 -2
  36. package/dist-cli/chunks/{chunk-HATEGE6O.js → chunk-MSKCUZ5B.js} +4 -4
  37. package/dist-cli/chunks/{chunk-BGZRRNK4.js → chunk-MTE3DEWY.js} +1 -1
  38. package/dist-cli/chunks/{chunk-IEYPDVW2.js → chunk-MWGIKDXO.js} +2 -2
  39. package/dist-cli/chunks/{chunk-EOYTPHOU.js → chunk-PDZ4JVAW.js} +1 -1
  40. package/dist-cli/chunks/{chunk-M7HK7MWE.js → chunk-PZJSYDQ7.js} +3 -3
  41. package/dist-cli/chunks/{chunk-67AZW4HJ.js → chunk-Q2424XB2.js} +1 -1
  42. package/dist-cli/chunks/chunk-SEETW74F.js +1 -0
  43. package/dist-cli/chunks/{chunk-AWQGGSDW.js → chunk-T6RAXKVI.js} +2 -2
  44. package/dist-cli/chunks/{chunk-ZEIDKF3M.js → chunk-U3UHXJNE.js} +1 -1
  45. package/dist-cli/chunks/{chunk-ET5NKJVL.js → chunk-UCCSXQ2P.js} +29 -29
  46. package/dist-cli/chunks/chunk-ULHAQFCE.js +1 -0
  47. package/dist-cli/chunks/{chunk-VR2UDTSA.js → chunk-USGUHWUJ.js} +2 -2
  48. package/dist-cli/chunks/{chunk-CLSZB5BN.js → chunk-UXE5BFPK.js} +2 -2
  49. package/dist-cli/chunks/{chunk-AQN3BB3D.js → chunk-YDKXZS7D.js} +1 -1
  50. package/dist-cli/chunks/chunk-YVGHAT6Q.js +1 -0
  51. package/dist-cli/chunks/cli-version-2VO66OZ6.js +2 -0
  52. package/dist-cli/chunks/{compat-WUI6VQPS.js → compat-ZBLH6EWV.js} +3 -3
  53. package/dist-cli/chunks/{config-XCFL4A6Z.js → config-DH2GG63H.js} +2 -2
  54. package/dist-cli/chunks/control-W3BOP6AT.js +2 -0
  55. package/dist-cli/chunks/{cpu-profile-CPOEDK5W.js → cpu-profile-3PRCXZMV.js} +2 -2
  56. package/dist-cli/chunks/{daemon-NFZOWPYN.js → daemon-XSFKUDKZ.js} +2 -2
  57. package/dist-cli/chunks/{debug-G6FBH3B4.js → debug-VAWCOXQ3.js} +3 -3
  58. package/dist-cli/chunks/demo-app-registry-7GNP7WE4.js +2 -0
  59. package/dist-cli/chunks/{detox-PUCPDKAO.js → detox-UABOFTDQ.js} +2 -2
  60. package/dist-cli/chunks/{device-IUUKTF7R.js → device-LCB4N66D.js} +2 -2
  61. package/dist-cli/chunks/diagnose-MT3WMY4M.js +41 -0
  62. package/dist-cli/chunks/drivers-YGVUWGMB.js +2 -0
  63. package/dist-cli/chunks/{electron-HGY5WSFG.js → electron-WVNFRA4S.js} +3 -3
  64. package/dist-cli/chunks/flow-OUOMEOSC.js +2 -0
  65. package/dist-cli/chunks/{hints-H7IVKEWB.js → hints-PFAKBGFX.js} +2 -2
  66. package/dist-cli/chunks/{home-paths-U5CDMYH5.js → home-paths-X6RB72PF.js} +2 -2
  67. package/dist-cli/chunks/{inspect-6WSCE3W3.js → inspect-UFYXDO6B.js} +74 -71
  68. package/dist-cli/chunks/install-NBUHIXEP.js +2 -0
  69. package/dist-cli/chunks/{install-desktop-QTZ3IBQW.js → install-desktop-W6QJX52Y.js} +3 -3
  70. package/dist-cli/chunks/{keys-DCQXAY66.js → keys-ORDSAMP7.js} +2 -2
  71. package/dist-cli/chunks/{launch-FTHBNATG.js → launch-NQZTWTPY.js} +3 -3
  72. package/dist-cli/chunks/{login-4GUBAGPQ.js → login-J2NVLHK5.js} +4 -4
  73. package/dist-cli/chunks/{logout-N25HFETU.js → logout-HI7A6PFH.js} +2 -2
  74. package/dist-cli/chunks/{maestro-WQBZZDTR.js → maestro-KIOOFK5M.js} +9 -9
  75. package/dist-cli/chunks/{preview-6MWJ6BSM.js → preview-QUJO4B4G.js} +2 -2
  76. package/dist-cli/chunks/{profile-UXJEGF4I.js → profile-U6RWYQV2.js} +2 -2
  77. package/dist-cli/chunks/{react-MHPIWH3F.js → react-3V65RTQC.js} +2 -2
  78. package/dist-cli/chunks/record-476LFCQV.js +41 -0
  79. package/dist-cli/chunks/runtime-4TK5DY5R.js +2 -0
  80. package/dist-cli/chunks/{runtime-delivery-IIDHK55K.js → runtime-delivery-BSRHUXJQ.js} +2 -2
  81. package/dist-cli/chunks/{screenshot-MDE5ZSST.js → screenshot-2S3BCN35.js} +2 -2
  82. package/dist-cli/chunks/{screenshot-mode-7W7L7IN3.js → screenshot-mode-SZCHOYZV.js} +2 -2
  83. package/dist-cli/chunks/{screenshots-24LEZPD7.js → screenshots-LGP7LA3M.js} +2 -2
  84. package/dist-cli/chunks/{server-52HFHX3S.js → server-G4BGS6GE.js} +11 -11
  85. package/dist-cli/chunks/setup-repo-5LUDPPSI.js +2 -0
  86. package/dist-cli/chunks/{skills-3DGYETTU.js → skills-2YOLQVV6.js} +2 -2
  87. package/dist-cli/chunks/{start-NFVPQX74.js → start-SF3I4SLN.js} +4 -4
  88. package/dist-cli/chunks/store-LLUQKQB7.js +2 -0
  89. package/dist-cli/chunks/telemetry-RDTORLS2.js +2 -0
  90. package/dist-cli/chunks/{test-THI53N25.js → test-YYHXTVDI.js} +3 -3
  91. package/dist-cli/chunks/{three-mode-HUI4SESE.js → three-mode-5U3H4QDF.js} +2 -2
  92. package/dist-cli/chunks/{timeline-KAJ6PR4S.js → timeline-IOEIFEH2.js} +2 -2
  93. package/dist-cli/chunks/{upgrade-APDFMQCW.js → upgrade-YF2U5QJY.js} +2 -2
  94. package/dist-cli/chunks/upload-3DFSK4NV.js +2 -0
  95. package/dist-cli/chunks/web-GAOXH77P.js +2 -0
  96. package/dist-cli/chunks/{what-happened-4VMBEL5Z.js → what-happened-DBI2RQVE.js} +2 -2
  97. package/dist-cli/chunks/{whoami-NJOQICNO.js → whoami-YDAMLYNA.js} +2 -2
  98. package/dist-lib/agent-daemon-client.cjs +1 -1
  99. package/dist-lib/agent-events.cjs +1 -1
  100. package/dist-lib/agent-sessions.cjs +1 -1
  101. package/dist-lib/attached-projects.cjs +1 -1
  102. package/dist-lib/auth/shared-session.cjs +1 -1
  103. package/dist-lib/backend-origin.cjs +1 -1
  104. package/dist-lib/bridge-constants.cjs +1 -1
  105. package/dist-lib/cli-constants.cjs +1 -1
  106. package/dist-lib/config.cjs +1 -1
  107. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  108. package/dist-lib/home-paths.cjs +1 -1
  109. package/dist-lib/host/bridge-host.cjs +63 -7
  110. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  111. package/dist-lib/index.cjs +1 -1
  112. package/dist-lib/metro.cjs +1 -1
  113. package/dist-lib/profiles.cjs +1 -1
  114. package/dist-lib/render-mode.cjs +1 -1
  115. package/dist-lib/vite-base.cjs +67 -7
  116. package/dist-lib/vite.cjs +1 -1
  117. package/package.json +1 -1
  118. package/dist-cli/chunks/auto-bootstrap-UKUFJBJA.js +0 -2
  119. package/dist-cli/chunks/beta-4OEWPO5F.js +0 -2
  120. package/dist-cli/chunks/chunk-3HO4Q25D.js +0 -1
  121. package/dist-cli/chunks/chunk-4D7Z64YQ.js +0 -2
  122. package/dist-cli/chunks/chunk-ACQXOAQI.js +0 -2
  123. package/dist-cli/chunks/chunk-DV3SI64Q.js +0 -1
  124. package/dist-cli/chunks/chunk-EWSS4C2R.js +0 -1
  125. package/dist-cli/chunks/control-KE4VM2BN.js +0 -2
  126. package/dist-cli/chunks/demo-app-registry-U4FCHIYP.js +0 -2
  127. package/dist-cli/chunks/diagnose-6RY4YXSP.js +0 -41
  128. package/dist-cli/chunks/drivers-2FY62QZA.js +0 -2
  129. package/dist-cli/chunks/flow-HEYPRCST.js +0 -2
  130. package/dist-cli/chunks/install-NPNUNOL6.js +0 -2
  131. package/dist-cli/chunks/record-K5DRP3G7.js +0 -18
  132. package/dist-cli/chunks/runtime-UVFYTDXE.js +0 -2
  133. package/dist-cli/chunks/setup-repo-ZHEBGISP.js +0 -2
  134. package/dist-cli/chunks/store-R2RI4XAS.js +0 -2
  135. package/dist-cli/chunks/telemetry-KGU6DBN6.js +0 -2
  136. package/dist-cli/chunks/upload-K7OWH74D.js +0 -2
  137. package/dist-cli/chunks/web-XDGC5KGT.js +0 -2
@@ -1,19 +1,19 @@
1
- /*! sootsim v0.1.51 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{b as Q,c as D,d as ee,e as H,f as te,h as ie,i as A,j as re,k as ne,l as se,p as oe,s as k,t as ae,u as ce,v as de,w as le}from"./chunk-L4OPPOPY.js";import"./chunk-DBHV5S2L.js";import{a as E}from"./chunk-AWQGGSDW.js";import"./chunk-SLAAAEUZ.js";import"./chunk-FUHHRW7G.js";import{a as Z}from"./chunk-IENPCJTB.js";import"./chunk-6NR6NFDC.js";import"./chunk-EWSS4C2R.js";import{d as Y}from"./chunk-BGZRRNK4.js";import{a as M}from"./chunk-54IIO5BV.js";import"./chunk-BKXH674Z.js";import"./chunk-5PKYORP6.js";import{k as X}from"./chunk-CLSZB5BN.js";import{a as q,b as z}from"./chunk-VXLRXQER.js";import"./chunk-P2IC3VRD.js";import{a as U}from"./chunk-ACQXOAQI.js";import{A as j,B as L,D as $,E as J,F as K,G as V,H as G,I as N,u as B,v as F,y as T,z as W}from"./chunk-FSTOUA6L.js";import"./chunk-3BUWCNVX.js";import{spawn as Re}from"child_process";import w from"fs";import{createServer as _e}from"http";import S from"path";import{WebSocket as h,WebSocketServer as xe}from"ws";import ue from"node:fs";import I from"node:path";var P=1;function be(){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(a=>Number.isFinite(a)&&a>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 o=t.id;try{let n=await this.dispatch(e,i,t);this.respond(e,o,n)}catch(n){n instanceof k?this.respondError(e,o,n.message,n.code):this.respondError(e,o,n instanceof Error?n.message:String(n))}return!0}async seedOnBoot(){try{await se()}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 H();case"agent:upsert-project":return D(i.input??{});case"agent:delete-project":return ie(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return re(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),s=A(n);if(!s)throw new k("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await ce(n,r),this.notePromptAccepted(n,r,s.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await de(String(i.sessionId));let o=A(String(i.sessionId));return o&&this.broadcastSessionStatus(o),{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 k("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async doStartSession(e){if(!ee(e.projectId))throw new k("NO_PROJECT",`no project: ${e.projectId}`);let i=await ae(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 o=this.opts.getExcludePorts?.()??be(),s=(await E({excludePorts:o})).find(d=>String(d.port)===i);if(!s||!s.cwd)return{project:null};let r=H().find(d=>d.cwd===s.cwd)??null,c=Array.from(new Set([...r?.knownBundleUrls??[],s.bundleUrl,t]));return{project:D({cwd:s.cwd,name:s.projectName??I.basename(s.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[s.cwd],knownBundleUrls:c,framework:r?.framework??we(s.framework),bundleId:s.bundleId??r?.bundleId})}}getTranscript(e){let t=oe(e);return ue.existsSync(t)?ue.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=Q();return{userDataDir:e,storeFile:I.join(e,"attached-projects.json"),sessionsDir:I.join(e,"sessions"),transcriptsDir:I.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 o=this.subscriptions.get(t);if(o)return o.refCount++,{ok:!0,refCount:o.refCount};let n=le(t,s=>{let r=this.coalescePromptEcho(t,s);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),s.type==="turn-completed"){let c=A(t);if(c)try{te(c.projectId,{usd:s.costUsd,ts:s.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 o=Date.now(),n=this.pendingPromptEchoes.get(e)??[];n.push({sentAt:o}),this.pendingPromptEchoes.set(e,n);let s=Math.max(this.pendingTurns.get(e)??0,i?1:0)+1;this.pendingTurns.set(e,s);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:o}),{ok:!0,queued:s>1,pendingTurns:s,queueDepth:Math.max(0,s-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){ne(e,t);let i=A(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[o,n]of this.sessionsBySocket)if(n.has(e)&&o.readyState===P)try{o.send(i)}catch{}}broadcastSessionStatus(e){let t=JSON.stringify({type:"agent:session-status",session:e});for(let i of this.allSockets)if(i.readyState===P)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===P)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,o){if(e.readyState===P)try{e.send(JSON.stringify({id:t,error:i,...o?{code:o}:{}}))}catch{}}};function we(a){return a==="expo"?"expo":a==="one"||a==="vxrn"?"one":"unknown"}import Ae from"http";import ke from"https";var Ce="sootsim",Te=new Set(["host","origin","referer","user-agent","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"]),Ee={"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"};function C(a){for(let[e,t]of Object.entries(Ee))a.setHeader(e,t)}function Ie(a,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 a.includes("stored-in-.env.local")?`${n} | upstream url still contains placeholder env values`:n}function Pe(a){let e={};for(let[t,i]of Object.entries(a))i&&(Te.has(t.toLowerCase())||(e[t]=Array.isArray(i)?i.join(", "):i));return e["user-agent"]=Ce,e}function pe(a){return a?.startsWith("/__fetch-proxy?")||a?.startsWith("/__proxy?")||!1}function me(a){return a?!!(a.startsWith("/__app-api?")||a.startsWith("/__app-api/")):!1}async function he(a,e){if(a.method==="OPTIONS"){C(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((a.url||"").split("?")[1]||"").get("url");if(!i){C(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let o;try{o=new URL(i)}catch{C(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=Pe(a.headers),s;if(a.method!=="GET"&&a.method!=="HEAD"){let d=[];for await(let u of a)d.push(Buffer.isBuffer(u)?u:Buffer.from(u));d.length>0&&(s=Buffer.concat(d))}let r;try{r=await fetch(o.href,{method:a.method,headers:n,body:s,redirect:"follow"})}catch(d){C(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${Ie(o.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)}),C(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 fe(a,e){let t=a.url||"",i="",o="";if(t.startsWith("/__app-api?")){let l=new URL(t,"http://sootsim.local");i=l.searchParams.get("path")||"",o=l.searchParams.get("origin")?.trim()||""}else if(t.startsWith("/__app-api/"))i=t.slice(10);else return!1;if(!o)return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: missing origin query param"),!0;if(a.method==="OPTIONS")return e.writeHead(204,{"Access-Control-Allow-Origin":a.headers.origin||"*","Access-Control-Allow-Methods":"GET,POST,PUT,PATCH,DELETE,OPTIONS","Access-Control-Allow-Headers":a.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,o)}catch{return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: invalid origin or path"),!0}let s=n.protocol==="https:"?ke:Ae,r={...a.headers};delete r.host,r.host=n.host;let c=s.request({hostname:n.hostname,port:n.port||(n.protocol==="https:"?443:80),path:n.pathname+n.search,method:a.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":a.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}`)}),a.pipe(c),!0}var Be=new Set(["tap","keyboard","close"]),Le=2e3,Ne=1e3;function De(a){return!a||typeof a.type!="string"?!1:a.acquireLock===!0?!0:a.readOnly===!0?!1:Be.has(a.type)}var He=5e3,Ue=3600*1e3,Me="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",Fe={".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 ge(a,e,t){let i;try{let c=B();i=JSON.stringify(c)}catch{i="{}"}let o=e>0?`window.__sootsimBridgePort=${e};`:"",n=t?`window.__sootsimSootbeanOrigin=${JSON.stringify(t)};`:"",s=`<script>window.__sootsimSharedConfig=${i};`+o+n+`window.__sootsimCliVersion=${JSON.stringify(M())};</script>`,r=a.toString("utf8");return r.includes("</head>")?r.replace("</head>",s+"</head>"):r.includes("</body>")?r.replace("</body>",s+"</body>"):s+r}function Se(a){typeof a=="object"&&a!==null&&"unref"in a&&a.unref()}var R=class a{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;preferredPort;portFallbackCount;shouldWriteLockfile;sootbeanOrigin=null;effectivePort=0;startedAt=0;heartbeatTimer=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.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new O({getExcludePorts:e.agentScanExcludes}),this.sootbeanOrigin=e.sootbeanOrigin?.replace(/\/$/,"")||null}getAgentHost(){return this.agentHost}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)
5
- `),this.afterBind(),i}catch(o){if(o?.code!=="EADDRINUSE")throw o;e?.silent||process.stderr.write(`ws bridge port ${i} already in use, trying ${i+1}
6
- `)}}throw new Error(`could not bind ws bridge after ${this.portFallbackCount} attempts starting at ${this.preferredPort}`)}bindOnce(e,t){return new Promise((i,o)=>{let n=_e((c,l)=>this.handleHttpRequest(c,l)),s=!1,r=c=>{if(!s){s=!0;try{n.close()}catch{}this.httpServer=null,this.wss=null,o(c)}};n.once("error",r),n.listen(e,"127.0.0.1",()=>{s||(s=!0,n.removeListener("error",r),n.on("error",c=>{process.stderr.write(`ws bridge http error: ${String(c)}
7
- `)}),this.httpServer=n,this.wss=new xe({server:n}),this.wireWebSocketServer(),i())})})}wireWebSocketServer(){this.wss&&this.wss.on("connection",(e,t)=>{let i=t.headers.origin,o=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),o==="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 s=`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,s)}e.on("message",s=>{let r;try{r=JSON.parse(s.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=L(),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(!L().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(o==="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),u&&(this.broadcastSimAssignments(),this.broadcastSimClientStates());return}if(r.type==="bridge:user-focus-state"&&n){let d=r;this.updateUserFocusLease(n,d.focused===!0);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=F(d)}catch(m){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${m instanceof Error?m.message:String(m)}
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{b as Q,c as D,d as ee,e as H,f as te,h as ie,i as A,j as re,k as ne,l as se,p as oe,s as k,t as ae,u as ce,v as de,w as le}from"./chunk-EJYVXNQL.js";import"./chunk-EYRQG47K.js";import{a as I}from"./chunk-T6RAXKVI.js";import{a as Z}from"./chunk-IXITVIJV.js";import"./chunk-BF7F45CZ.js";import"./chunk-3MIWVHCX.js";import"./chunk-YVGHAT6Q.js";import{d as Y}from"./chunk-MTE3DEWY.js";import"./chunk-JPX7OS7B.js";import{a as U}from"./chunk-IQU56D6C.js";import{a as q,b as z}from"./chunk-7Y3FYPJH.js";import"./chunk-DNKB2V2W.js";import"./chunk-MBH3NFBC.js";import"./chunk-CTEXZ7BE.js";import{a as M}from"./chunk-DSJ7PGU3.js";import{k as X}from"./chunk-UXE5BFPK.js";import{A as j,B,D as $,E as J,F as K,G as V,H as G,I as N,u as L,v as F,y as T,z as W}from"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.js";import{spawn as _e}from"child_process";import w from"fs";import{createServer as Re}from"http";import S from"path";import{WebSocket as h,WebSocketServer as xe}from"ws";import ue from"node:fs";import E from"node:path";var P=1;function be(){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(a=>Number.isFinite(a)&&a>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 k?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 se()}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 H();case"agent:upsert-project":return D(i.input??{});case"agent:delete-project":return ie(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return re(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),o=A(n);if(!o)throw new k("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await ce(n,r),this.notePromptAccepted(n,r,o.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await de(String(i.sessionId));let s=A(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 k("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async doStartSession(e){if(!ee(e.projectId))throw new k("NO_PROJECT",`no project: ${e.projectId}`);let i=await ae(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?.()??be(),o=(await I({excludePorts:s})).find(d=>String(d.port)===i);if(!o||!o.cwd)return{project:null};let r=H().find(d=>d.cwd===o.cwd)??null,c=Array.from(new Set([...r?.knownBundleUrls??[],o.bundleUrl,t]));return{project:D({cwd:o.cwd,name:o.projectName??E.basename(o.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[o.cwd],knownBundleUrls:c,framework:r?.framework??we(o.framework),bundleId:o.bundleId??r?.bundleId})}}getTranscript(e){let t=oe(e);return ue.existsSync(t)?ue.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=Q();return{userDataDir:e,storeFile:E.join(e,"attached-projects.json"),sessionsDir:E.join(e,"sessions"),transcriptsDir:E.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=le(t,o=>{let r=this.coalescePromptEcho(t,o);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),o.type==="turn-completed"){let c=A(t);if(c)try{te(c.projectId,{usd:o.costUsd,ts:o.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 o=Math.max(this.pendingTurns.get(e)??0,i?1:0)+1;this.pendingTurns.set(e,o);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:o>1,pendingTurns:o,queueDepth:Math.max(0,o-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){ne(e,t);let i=A(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===P)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===P)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===P)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,s){if(e.readyState===P)try{e.send(JSON.stringify({id:t,error:i,...s?{code:s}:{}}))}catch{}}};function we(a){return a==="expo"?"expo":a==="one"||a==="vxrn"?"one":"unknown"}import Ae from"http";import ke from"https";var Ce="sootsim",Te=new Set(["host","origin","referer","user-agent","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"]),Ie={"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"};function C(a){for(let[e,t]of Object.entries(Ie))a.setHeader(e,t)}function Ee(a,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 a.includes("stored-in-.env.local")?`${n} | upstream url still contains placeholder env values`:n}function Pe(a){let e={};for(let[t,i]of Object.entries(a))i&&(Te.has(t.toLowerCase())||(e[t]=Array.isArray(i)?i.join(", "):i));return e["user-agent"]=Ce,e}function pe(a){return a?.startsWith("/__fetch-proxy?")||a?.startsWith("/__proxy?")||!1}function me(a){return a?!!(a.startsWith("/__app-api?")||a.startsWith("/__app-api/")):!1}async function he(a,e){if(a.method==="OPTIONS"){C(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((a.url||"").split("?")[1]||"").get("url");if(!i){C(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{C(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=Pe(a.headers),o;if(a.method!=="GET"&&a.method!=="HEAD"){let d=[];for await(let u of a)d.push(Buffer.isBuffer(u)?u:Buffer.from(u));d.length>0&&(o=Buffer.concat(d))}let r;try{r=await fetch(s.href,{method:a.method,headers:n,body:o,redirect:"follow"})}catch(d){C(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${Ee(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)}),C(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 fe(a,e){let t=a.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(a.method==="OPTIONS")return e.writeHead(204,{"Access-Control-Allow-Origin":a.headers.origin||"*","Access-Control-Allow-Methods":"GET,POST,PUT,PATCH,DELETE,OPTIONS","Access-Control-Allow-Headers":a.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 o=n.protocol==="https:"?ke:Ae,r={...a.headers};delete r.host,r.host=n.host;let c=o.request({hostname:n.hostname,port:n.port||(n.protocol==="https:"?443:80),path:n.pathname+n.search,method:a.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":a.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}`)}),a.pipe(c),!0}var Le=new Set(["tap","keyboard","close"]),Be=2e3,Ne=1e3;function De(a){return!a||typeof a.type!="string"?!1:a.acquireLock===!0?!0:a.readOnly===!0?!1:Le.has(a.type)}var He=5e3,Me=3600*1e3,Ue="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",Fe={".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 ge(a,e,t){let i;try{let c=L();i=JSON.stringify(c)}catch{i="{}"}let s=e>0?`window.__sootsimBridgePort=${e};`:"",n=t?`window.__sootsimSootbeanOrigin=${JSON.stringify(t)};`:"",o=`<script>window.__sootsimSharedConfig=${i};`+s+n+`window.__sootsimCliVersion=${JSON.stringify(U())};</script>`,r=a.toString("utf8");return r.includes("</head>")?r.replace("</head>",o+"</head>"):r.includes("</body>")?r.replace("</body>",o+"</body>"):o+r}function Se(a){typeof a=="object"&&a!==null&&"unref"in a&&a.unref()}var _=class a{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;preferredPort;portFallbackCount;simIdleReapTtlMs;shouldWriteLockfile;sootbeanOrigin=null;effectivePort=0;startedAt=0;heartbeatTimer=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.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??a.SIM_IDLE_REAP_TTL_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)
5
+ `),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}
6
+ `)}}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=Re((c,l)=>this.handleHttpRequest(c,l)),o=!1,r=c=>{if(!o){o=!0;try{n.close()}catch{}this.httpServer=null,this.wss=null,s(c)}};n.once("error",r),n.listen(e,"127.0.0.1",()=>{o||(o=!0,n.removeListener("error",r),n.on("error",c=>{process.stderr.write(`ws bridge http error: ${String(c)}
7
+ `)}),this.httpServer=n,this.wss=new xe({server:n}),this.wireWebSocketServer(),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 o=`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,o)}e.on("message",o=>{let r;try{r=JSON.parse(o.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=B(),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(!B().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.focused===!0);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=F(d)}catch(m){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${m instanceof Error?m.message:String(m)}
8
8
  `);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()+a.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}]
9
- `),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,i: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:a.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`,o: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(De(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\``,o: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)},Le);Se(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),o==="sim"&&n){this.rememberDisconnectedSim(n),this.primarySimId===n.id&&(this.primarySimId=this.getOpenSim()?.id??null);for(let[s,r]of this.pendingCommands)r.simId===n.id&&(r.reject(new Error("sim disconnected")),this.pendingCommands.delete(s));for(let[s,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(s));this.broadcastSimAssignments(),this.broadcastSimClientStates()}else if(o==="cli"){let s=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);s&&this.broadcastSimClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
9
+ `),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,i: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:a.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`,o: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(De(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\``,o: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)},Be);Se(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[o,r]of this.pendingCommands)r.simId===n.id&&(r.reject(new Error("sim disconnected")),this.pendingCommands.delete(o));for(let[o,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(o));this.broadcastSimAssignments(),this.broadcastSimClientStates()}else if(s==="cli"){let o=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);o&&this.broadcastSimClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
10
10
  `),this.cliIdleTimer=setInterval(()=>this.sweepIdleCliClients(),3e4),this.cliIdleTimer.unref(),this.wsHeartbeatTimer=setInterval(()=>this.sweepDeadWebSockets(),a.WS_HEARTBEAT_INTERVAL_MS),this.wsHeartbeatTimer.unref(),this.shouldWriteLockfile){try{if(T(),!G(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)}
11
- `),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},He),this.heartbeatTimer.unref(),this.startRuntimeUpdater()}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}}writeLockfileSnapshot(){V(this.buildLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=W(),this.activeRuntimeDirPath=$()}runServerScan(){if(this.inflightScan)return this.inflightScan;let e=this.effectivePort>0?[this.effectivePort]:[];return this.inflightScan=E({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=o=>{e.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(o))},i=Date.now()-this.scanCacheAt;if(this.scanCache&&i<a.SCAN_FRESH_MS){t(this.scanCache);return}if(this.scanCache){t(this.scanCache),this.runServerScan().catch(()=>{});return}this.runServerScan().then(o=>t(o))}resolveRuntimeUpdateIntervalMs(){let e=Number(process.env[Me]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):Ue}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
11
+ `),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},He),this.heartbeatTimer.unref(),this.startRuntimeUpdater()}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}}writeLockfileSnapshot(){V(this.buildLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=W(),this.activeRuntimeDirPath=$()}runServerScan(){if(this.inflightScan)return this.inflightScan;let e=this.effectivePort>0?[this.effectivePort]:[];return this.inflightScan=I({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<a.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[Ue]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):Me}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
12
12
  `);let t=await X();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
13
13
  `);return}let i=this.setActiveRuntime(t.latestVersion);process.stderr.write(`sootsim runtime updated to ${i.version} (${e})
14
14
  `)}catch(t){process.stderr.write(`sootsim runtime update failed (${e}): ${t instanceof Error?t.message:String(t)}
15
15
  `)}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
16
- `)}}})(),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{N()}catch{}}handleHttpRequest(e,t){if(t.setHeader("Cross-Origin-Opener-Policy","same-origin"),t.setHeader("Cross-Origin-Embedder-Policy","credentialless"),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),pe(e.url)){he(e,t);return}if(me(e.url)&&fe(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 o=new URL(e.url||"/","http://localhost");if(o.pathname==="/__bundle-proxy"){let l=o.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(o.pathname==="/__server-scan"){this.handleServerScan(t);return}if(o.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,startedAt:this.startedAt,uptimeMs:this.startedAt>0?Date.now()-this.startedAt:0}));return}if(o.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(B())}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 s=o.pathname;if(s==="/runtime"||s==="/runtime/"?s="/":s.startsWith("/runtime/")&&(s=s.slice(8)),(s===""||s==="/")&&(s="/index.html"),s.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&s.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let l of s.split("/"))if(l===".."){t.writeHead(403),t.end("forbidden");return}let r=S.resolve(n,"."+s),c=n.endsWith(S.sep)?n:n+S.sep;if(!r.startsWith(c)&&r!==n){t.writeHead(403),t.end("forbidden");return}w.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=w.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}}w.stat(u,(m,f)=>{if(m||!f?.isFile()){let b=S.extname(s).toLowerCase();if(b&&b!==".html"){t.writeHead(404),t.end("not found");return}if(s.startsWith("/__")||s.startsWith("/api/")||s==="/api"){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("not found");return}let x=S.join(n,"index.html");w.readFile(x,(ye,ve)=>{if(ye){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(ge(ve,this.effectivePort,this.sootbeanOrigin))});return}let y=S.extname(u).toLowerCase(),g=Fe[y]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":g,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(y===".html"){w.readFile(u,(b,x)=>{if(b){try{t.end()}catch{}return}t.end(ge(x,this.effectivePort,this.sootbeanOrigin))});return}let v=w.createReadStream(u);v.pipe(t),v.on("error",()=>{try{t.end()}catch{}})})})}sweepIdleCliClients(){let e=Date.now(),t=!1;for(let[i,o]of this.cliSimBySocket){let n=this.cliLastCommandAt.get(i)??0;if(!(e-n<a.CLI_IDLE_TIMEOUT_MS)){this.cliSimBySocket.delete(i),this.cliLastCommandAt.delete(i);for(let[s,r]of this.cliBySentId)r.ws===i&&this.cliBySentId.delete(s);try{i.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastSimClientStates(),this.sweepRestorableSims(e)}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(4001,U)}catch{try{e.terminate()}catch{}return}let t=setTimeout(()=>{if(e.readyState!==h.CLOSED)try{e.terminate()}catch{}},Ne);Se(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((o,n)=>{let s=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(s),this.pendingCommands.delete(i),this.broadcastSimClientStates(),o(l)},reject:l=>{clearTimeout(s),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 o=t!=null?`:${t}${i!=null?`:${i}`:""}`:"",n=`${e}${o}`,s=(c,l)=>new Promise(d=>{try{let u=Re(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 s(c[0],[...c.slice(1),"-g",n]))return}await s("cursor",["-g",n])||await s("code",["-g",n])||await this.openUrl(e)}async openUrl(e,t={}){if(this.openUrlHandler){await this.openUrlHandler(e,t);return}await Y(e,t)}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null),this.shouldWriteLockfile)try{N()}catch{}this.effectivePort=0,this.startedAt=0,this.agentHost.close();for(let[i,o]of this.pendingCommands)o.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,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 o=this.cliIdentityKeyBySocket.get(e)??(()=>{let u=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,u),u})(),n=this.cliLabelBySocket.get(e),s=Date.now(),r=this.getActiveLease(t),c=r&&r.cliIdentityKey===o,l=0;if(r&&!c&&!i.force)return{granted:!1,lease:r,lock:{by:r.cliLabel||r.cliIdentityKey,expiresInMs:Math.max(0,r.expiresAt-s)},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!==o){this.cliSimBySocket.delete(u);try{u.close(1e3,"lease claimed by another cli")}catch{}l++}}let d={kind:"cli",cliIdentityKey:o,cliLabel:n,expiresAt:s+a.CLI_LEASE_TTL_MS};return t.cliLease=d,{granted:!0,lease:d,bootedCount:l}}updateUserFocusLease(e,t){let i=t;e.userFocused!==i&&(e.userFocused=i,this.broadcastSimClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);if(t&&t.kind==="cli")return;let o=Date.now()+a.USER_ACTIVE_LEASE_TTL_MS,n=t&&t.kind==="user-active"?Math.max(t.expiresAt,o):o;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 i=this.sims.get(e);return i?.ws.readyState===h.OPEN?i:null}let t=this.primarySimId!=null?this.sims.get(this.primarySimId):null;if(t?.ws.readyState===h.OPEN)return t;for(let i of this.sims.values())if(i.ws.readyState===h.OPEN)return i;return null}async waitForSim(e,t={}){let i=t.attempts??10,o=t.intervalMs??200;for(let n=0;n<i;n++){let s=this.getOpenSim(e);if(s)return s;await new Promise(r=>setTimeout(r,o))}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,i=e.origin?.includes(":5173"),o=t?.origin?.includes(":5173");return!t||t.ws.readyState!==h.OPEN||!!i||!o}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};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 o=t?.trim();if(!o)return;let n=this.sims.get(e);if(!n)return;let s=Date.now();n.lastActiveAt=s,n.recentActions=[{label:o,at:s},...n.recentActions.filter(r=>r.label!==o)].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,o]of this.cliSimBySocket){if(o!==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),o=new Set;for(let[n,s]of this.cliSimBySocket){if(s!==t||n.readyState!==h.OPEN)continue;let r=this.cliIdentityKeyBySocket.get(n);r&&r===i||o.add(r??`ws-unknown-${o.size}`)}return o.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 o=this.sims.get(i);if(o&&o!==e&&o.ws.readyState===h.OPEN)return!1;let n=this.getRestorableSimState(i),s=e.id;this.sims.delete(s),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===s&&(this.primarySimId=e.id);for(let[r,c]of this.cliSimBySocket)c===s&&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()+a.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[o,n]of this.cliSimBySocket)n===t&&this.cliSimBySocket.delete(o)}}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 We(){let a=process.env.XPC_SERVICE_NAME||"";return!!(a.includes("dev.sootsim.daemon")||a.includes("dev.sootsim.server")||process.env.INVOCATION_ID)}async function gt(a,e={}){(a.includes("--help")||a.includes("-h"))&&(console.log(`
16
+ `)}}})(),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{N()}catch{}}handleHttpRequest(e,t){if(t.setHeader("Cross-Origin-Opener-Policy","same-origin"),t.setHeader("Cross-Origin-Embedder-Policy","credentialless"),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),pe(e.url)){he(e,t);return}if(me(e.url)&&fe(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,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(L())}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 o=s.pathname;if(o==="/runtime"||o==="/runtime/"?o="/":o.startsWith("/runtime/")&&(o=o.slice(8)),(o===""||o==="/")&&(o="/index.html"),o.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&o.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let l of o.split("/"))if(l===".."){t.writeHead(403),t.end("forbidden");return}let r=S.resolve(n,"."+o),c=n.endsWith(S.sep)?n:n+S.sep;if(!r.startsWith(c)&&r!==n){t.writeHead(403),t.end("forbidden");return}w.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=w.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}}w.stat(u,(m,f)=>{if(m||!f?.isFile()){let b=S.extname(o).toLowerCase();if(b&&b!==".html"){t.writeHead(404),t.end("not found");return}if(o.startsWith("/__")||o.startsWith("/api/")||o==="/api"){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("not found");return}let x=S.join(n,"index.html");w.readFile(x,(ye,ve)=>{if(ye){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(ge(ve,this.effectivePort,this.sootbeanOrigin))});return}let y=S.extname(u).toLowerCase(),g=Fe[y]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":g,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(y===".html"){w.readFile(u,(b,x)=>{if(b){try{t.end()}catch{}return}t.end(ge(x,this.effectivePort,this.sootbeanOrigin))});return}let v=w.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<a.CLI_IDLE_TIMEOUT_MS)){this.cliSimBySocket.delete(i),this.cliLastCommandAt.delete(i);for(let[o,r]of this.cliBySentId)r.ws===i&&this.cliBySentId.delete(o);try{i.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastSimClientStates(),this.sweepRestorableSims(e),this.reapIdleSims(e)}reapIdleSims(e=Date.now()){let t=new Set(this.cliSimBySocket.values());for(let i of this.sims.values()){if(i.id===this.primarySimId||t.has(i.id)||this.getActiveLease(i))continue;let s=Math.max(i.lastActiveAt,i.connectedAt);e-s<this.simIdleReapTtlMs||this.closeSimSocketFromHost(i.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(4001,M)}catch{try{e.terminate()}catch{}return}let t=setTimeout(()=>{if(e.readyState!==h.CLOSED)try{e.terminate()}catch{}},Ne);Se(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 o=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(o),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(l)},reject:l=>{clearTimeout(o),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}`,o=(c,l)=>new Promise(d=>{try{let u=_e(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 o(c[0],[...c.slice(1),"-g",n]))return}await o("cursor",["-g",n])||await o("code",["-g",n])||await this.openUrl(e)}async openUrl(e,t={}){if(this.openUrlHandler){await this.openUrlHandler(e,t);return}await Y(e,t)}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null),this.shouldWriteLockfile)try{N()}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,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),o=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-o)},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:o+a.CLI_LEASE_TTL_MS};return t.cliLease=d,{granted:!0,lease:d,bootedCount:l}}updateUserFocusLease(e,t){let i=t;e.userFocused!==i&&(e.userFocused=i,this.broadcastSimClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);if(t&&t.kind==="cli")return;let s=Date.now()+a.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 o=this.getOpenSim(e);if(o)return o;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};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 o=Date.now();n.lastActiveAt=o,n.recentActions=[{label:s,at:o},...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,o]of this.cliSimBySocket){if(o!==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),o=e.id;this.sims.delete(o),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===o&&(this.primarySimId=e.id);for(let[r,c]of this.cliSimBySocket)c===o&&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()+a.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 We(){let a=process.env.XPC_SERVICE_NAME||"";return!!(a.includes("dev.sootsim.daemon")||a.includes("dev.sootsim.server")||process.env.INVOCATION_ID)}async function gt(a,e={}){(a.includes("--help")||a.includes("-h"))&&(console.log(`
17
17
  sootsim server \u2014 run the sootsim bridge daemon in the foreground
18
18
 
19
19
  hosts the WS bridge that CLI commands talk to. once running, any sootsim
@@ -30,6 +30,6 @@ options:
30
30
  examples:
31
31
  sootsim server
32
32
  sootsim server --port 7668 --quiet
33
- `),process.exit(0));let t=a.indexOf("--port"),i=t>=0&&a[t+1]?Number(a[t+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${a[t+1]}`),process.exit(1));let o=a.includes("--quiet")||a.includes("-q"),n=J();n&&K(n)&&(console.error(` a sootsim daemon is already running (pid ${n.pid}, port ${n.bridgePort})`),console.error(" stop it with 'sootsim daemon stop' first"),process.exit(1)),T();let s=await Z(),r=new R({port:i,writeLockfile:!0,sootbeanOrigin:s}),c=await r.startAsync({silent:o}),l=Date.now(),d=f=>{o||process.stdout.write(`${f}
33
+ `),process.exit(0));let t=a.indexOf("--port"),i=t>=0&&a[t+1]?Number(a[t+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${a[t+1]}`),process.exit(1));let s=a.includes("--quiet")||a.includes("-q"),n=J();n&&K(n)&&(console.error(` a sootsim daemon is already running (pid ${n.pid}, port ${n.bridgePort})`),console.error(" stop it with 'sootsim daemon stop' first"),process.exit(1)),T();let o=await Z(),r=new _({port:i,writeLockfile:!0,sootbeanOrigin:o}),c=await r.startAsync({silent:s}),l=Date.now(),d=f=>{s||process.stdout.write(`${f}
34
34
  `)},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);q({event:"daemon_heartbeat",properties:{bridge_port:c,under_daemon:We(),platform:process.platform,subsource:"daemon"}}),z(),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(`
35
35
  ${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{gt as runServer};
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a}from"./chunk-FVBSPGBR.js";import"./chunk-YDKXZS7D.js";import"./chunk-MSKCUZ5B.js";import"./chunk-7Y3FYPJH.js";import"./chunk-DNKB2V2W.js";import"./chunk-MBH3NFBC.js";import"./chunk-CTEXZ7BE.js";import"./chunk-DSJ7PGU3.js";import"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.js";export{a as runSetupRepo};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.51 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import"./chunk-3BUWCNVX.js";import*as l from"fs";import*as i from"path";import{fileURLToPath as f}from"url";function g(){try{let s=f(import.meta.resolve("sootsim/package.json"));return i.join(i.dirname(s),"skills")}catch{let s=i.dirname(f(import.meta.url));return i.resolve(s,"../../skills")}}var m=g();function d(s){let n=s.match(/^---\n([\s\S]*?)\n---/);if(!n)return null;let e=n[1],o=e.match(/^name:\s*(.+)$/m),r=e.match(/^description:\s*(.+)$/m);return o?{name:o[1].trim(),description:r?.[1]?.trim()||""}:null}function p(){if(!l.existsSync(m))return[];let s=l.readdirSync(m).filter(e=>e.endsWith(".md")),n=[];for(let e of s){let o=l.readFileSync(i.join(m,e),"utf8"),r=d(o);r&&n.push({...r,filename:e})}return n}function u(s,n){let e=i.join(m,s.filename),o=i.join(n,s.filename);l.copyFileSync(e,o),console.log(` copied ${s.name} \u2192 ${o}`)}async function h(s){if(s.includes("--list")||s.includes("-l")||s.length===0){let t=p();if(t.length===0){console.log(" no skills found");return}console.log(`
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import"./chunk-6QDFLMJL.js";import*as l from"fs";import*as i from"path";import{fileURLToPath as f}from"url";function g(){try{let s=f(import.meta.resolve("sootsim/package.json"));return i.join(i.dirname(s),"skills")}catch{let s=i.dirname(f(import.meta.url));return i.resolve(s,"../../skills")}}var m=g();function d(s){let n=s.match(/^---\n([\s\S]*?)\n---/);if(!n)return null;let e=n[1],o=e.match(/^name:\s*(.+)$/m),r=e.match(/^description:\s*(.+)$/m);return o?{name:o[1].trim(),description:r?.[1]?.trim()||""}:null}function p(){if(!l.existsSync(m))return[];let s=l.readdirSync(m).filter(e=>e.endsWith(".md")),n=[];for(let e of s){let o=l.readFileSync(i.join(m,e),"utf8"),r=d(o);r&&n.push({...r,filename:e})}return n}function u(s,n){let e=i.join(m,s.filename),o=i.join(n,s.filename);l.copyFileSync(e,o),console.log(` copied ${s.name} \u2192 ${o}`)}async function h(s){if(s.includes("--list")||s.includes("-l")||s.length===0){let t=p();if(t.length===0){console.log(" no skills found");return}console.log(`
3
3
  available skills:
4
4
  `);for(let c of t)console.log(` ${c.name}`),console.log(` ${c.description}
5
5
  `);console.log(" usage: sootsim skills <target-dir> [skill-name...]"),console.log(" example: sootsim skills ./my-project"),console.log(` example: sootsim skills ./my-project debug perf
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.51 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{d as _}from"./chunk-BGZRRNK4.js";import"./chunk-BKXH674Z.js";import"./chunk-5PKYORP6.js";import"./chunk-ACQXOAQI.js";import{E as b,F as v,i as D,y as O,z as x}from"./chunk-FSTOUA6L.js";import"./chunk-3BUWCNVX.js";import{spawn as N}from"child_process";import{existsSync as F}from"fs";import{WebSocket as B}from"ws";var T=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];var A={reset:"\x1B[0m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",cyan:"\x1B[36m",bold:"\x1B[1m"};function k(){return process.stderr.isTTY===!0}function u(t,e){return k()?`${A[t]}${e}${A.reset}`:e}function L(t,e){switch(t){case"pending":return u("dim","\xB7");case"running":return u("cyan",e);case"done":return u("green","\u2713");case"fail":return u("red","\u2717");case"skip":return u("yellow","\u25CB")}}var E=class{constructor(e,s){this.stepper=e;this.data=s}start(e){this.data.state="running",e!==void 0&&(this.data.detail=e),this.stepper.render()}update(e){this.data.detail=e,this.stepper.render()}done(e){this.data.state="done",e!==void 0&&(this.data.detail=e),this.stepper.render()}fail(e){this.data.state="fail",e!==void 0&&(this.data.detail=e),this.stepper.render()}skip(e){this.data.state="skip",e!==void 0&&(this.data.detail=e),this.stepper.render()}},S=class{steps=[];bannerText="";frame=0;timer=null;lastLineCount=0;paused=!1;finished=!1;banner(e){this.bannerText=e}add(e){let s={label:e,state:"pending"};return this.steps.push(s),new E(this,s)}render(){this.paused||this.finished||(this.startSpinner(),this.draw())}pause(){this.paused||(this.paused=!0,this.stopSpinner(),this.eraseRendered(),this.lastLineCount=0)}resume(){this.paused&&(this.paused=!1,this.draw(),this.startSpinner())}finish(){this.finished||(this.finished=!0,this.stopSpinner(),this.draw())}startSpinner(){this.timer||!k()||this.steps.some(e=>e.state==="running")&&(this.timer=setInterval(()=>{this.frame=(this.frame+1)%T.length,this.draw()},80),this.timer?.unref?.())}stopSpinner(){this.timer&&(clearInterval(this.timer),this.timer=null)}draw(){if(!k()){this.drawForwardOnly();return}this.eraseRendered();let e=[];this.bannerText&&(e.push(u("bold",this.bannerText)),e.push(""));let s=T[this.frame],r=Math.max(...this.steps.map(i=>i.label.length),0);for(let i of this.steps){let n=L(i.state,s),c=i.label.padEnd(r),y=i.detail?` ${u("dim",i.detail)}`:"";e.push(` ${n} ${c}${y}`)}process.stderr.write(e.join(`
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{d as _}from"./chunk-MTE3DEWY.js";import"./chunk-MBH3NFBC.js";import"./chunk-CTEXZ7BE.js";import"./chunk-DSJ7PGU3.js";import{E as b,F as v,i as D,y as O,z as x}from"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.js";import{spawn as N}from"child_process";import{existsSync as F}from"fs";import{WebSocket as B}from"ws";var T=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];var A={reset:"\x1B[0m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",cyan:"\x1B[36m",bold:"\x1B[1m"};function k(){return process.stderr.isTTY===!0}function u(t,e){return k()?`${A[t]}${e}${A.reset}`:e}function L(t,e){switch(t){case"pending":return u("dim","\xB7");case"running":return u("cyan",e);case"done":return u("green","\u2713");case"fail":return u("red","\u2717");case"skip":return u("yellow","\u25CB")}}var E=class{constructor(e,s){this.stepper=e;this.data=s}start(e){this.data.state="running",e!==void 0&&(this.data.detail=e),this.stepper.render()}update(e){this.data.detail=e,this.stepper.render()}done(e){this.data.state="done",e!==void 0&&(this.data.detail=e),this.stepper.render()}fail(e){this.data.state="fail",e!==void 0&&(this.data.detail=e),this.stepper.render()}skip(e){this.data.state="skip",e!==void 0&&(this.data.detail=e),this.stepper.render()}},S=class{steps=[];bannerText="";frame=0;timer=null;lastLineCount=0;paused=!1;finished=!1;banner(e){this.bannerText=e}add(e){let s={label:e,state:"pending"};return this.steps.push(s),new E(this,s)}render(){this.paused||this.finished||(this.startSpinner(),this.draw())}pause(){this.paused||(this.paused=!0,this.stopSpinner(),this.eraseRendered(),this.lastLineCount=0)}resume(){this.paused&&(this.paused=!1,this.draw(),this.startSpinner())}finish(){this.finished||(this.finished=!0,this.stopSpinner(),this.draw())}startSpinner(){this.timer||!k()||this.steps.some(e=>e.state==="running")&&(this.timer=setInterval(()=>{this.frame=(this.frame+1)%T.length,this.draw()},80),this.timer?.unref?.())}stopSpinner(){this.timer&&(clearInterval(this.timer),this.timer=null)}draw(){if(!k()){this.drawForwardOnly();return}this.eraseRendered();let e=[];this.bannerText&&(e.push(u("bold",this.bannerText)),e.push(""));let s=T[this.frame],r=Math.max(...this.steps.map(i=>i.label.length),0);for(let i of this.steps){let n=L(i.state,s),c=i.label.padEnd(r),y=i.detail?` ${u("dim",i.detail)}`:"";e.push(` ${n} ${c}${y}`)}process.stderr.write(e.join(`
3
3
  `)+`
4
4
  `),this.lastLineCount=e.length,this.steps.some(i=>i.state==="running")||this.stopSpinner()}bannerPrinted=!1;lastEmitted=new Map;drawForwardOnly(){this.bannerText&&!this.bannerPrinted&&(process.stderr.write(this.bannerText+`
5
5
 
@@ -18,6 +18,6 @@ usage:
18
18
  options:
19
19
  --port <n> bridge port (default: ${7668})
20
20
  --no-open don't open the browser at the end
21
- `);return}O();let s=t.indexOf("--port"),r=s>=0&&t[s+1]?Number(t[s+1]):e.port??7668;Number.isNaN(r)&&(console.error(` invalid --port value: ${t[s+1]}`),process.exit(1));let i=t.includes("--no-open"),n=new S,{IS_BETA:c,BETA_TAGLINE:y}=await import("./beta-4OEWPO5F.js");n.banner(c?`sootsim \u2014 ${y}`:"sootsim \u2014 starting up");let m=n.add("runtime"),d=n.add("server"),$=n.add("ready"),f=n.add("open");n.render();let g=null;try{m.start("checking\u2026");let a=x();if(a&&F(D(a))){g=a;let l=await q();m.done(l?`v${a} \u2014 v${l} available, run \`sootsim upgrade\``:`v${a}`)}else{m.start("downloading engine (~6 MB)\u2026");let{runRuntime:l}=await import("./runtime-UVFYTDXE.js");n.pause(),await l(["install"],{}),n.resume(),g=x(),m.done(g?`v${g}`:"installed")}}catch(a){m.fail(h(a)),n.finish(),process.exit(1)}let o=r,p="standalone";try{d.start("checking\u2026");let a=b();if(v(a)&&await P(a.bridgePort,800))o=a.bridgePort,p="daemon-existing",d.done(`already running (port ${o})`);else if(process.platform==="darwin"||process.platform==="linux"){d.start("registering background daemon\u2026");try{let{daemonInstall:l}=await import("./daemon-NFZOWPYN.js");n.pause(),await l({port:r,force:!0}),n.resume();let R=b();o=v(R)?R.bridgePort:r,p="daemon-installed",d.done(`daemon registered (port ${o})`)}catch(l){n.resume(),d.start("daemon unavailable, starting standalone server\u2026"),o=await C(r),p="standalone",d.done(`standalone (port ${o}) \u2014 ${h(l)}`)}}else d.start("starting standalone server\u2026"),o=await C(r),p="standalone",d.done(`standalone (port ${o})`)}catch(a){d.fail(h(a)),n.finish(),process.exit(1)}try{if($.start("waiting for bridge\u2026"),!await V(o,U))throw new Error(`bridge never came online on port ${o}`);$.done(`ws://localhost:${o}`)}catch(a){$.fail(h(a)),n.finish(),process.exit(1)}let w=`http://localhost:${o}/`;if(i){f.skip(w),n.finish();return}try{f.start("launching browser\u2026"),await _(w),f.done(w)}catch(a){f.skip(`${w} (open it manually \u2014 ${h(a)})`)}n.finish(),p==="standalone"?(console.log(`
21
+ `);return}O();let s=t.indexOf("--port"),r=s>=0&&t[s+1]?Number(t[s+1]):e.port??7668;Number.isNaN(r)&&(console.error(` invalid --port value: ${t[s+1]}`),process.exit(1));let i=t.includes("--no-open"),n=new S,{IS_BETA:c,BETA_TAGLINE:y}=await import("./beta-D4OEPOSE.js");n.banner(c?`sootsim \u2014 ${y}`:"sootsim \u2014 starting up");let m=n.add("runtime"),d=n.add("server"),$=n.add("ready"),f=n.add("open");n.render();let g=null;try{m.start("checking\u2026");let a=x();if(a&&F(D(a))){g=a;let l=await q();m.done(l?`v${a} \u2014 v${l} available, run \`sootsim upgrade\``:`v${a}`)}else{m.start("downloading engine (~6 MB)\u2026");let{runRuntime:l}=await import("./runtime-4TK5DY5R.js");n.pause(),await l(["install"],{}),n.resume(),g=x(),m.done(g?`v${g}`:"installed")}}catch(a){m.fail(h(a)),n.finish(),process.exit(1)}let o=r,p="standalone";try{d.start("checking\u2026");let a=b();if(v(a)&&await P(a.bridgePort,800))o=a.bridgePort,p="daemon-existing",d.done(`already running (port ${o})`);else if(process.platform==="darwin"||process.platform==="linux"){d.start("registering background daemon\u2026");try{let{daemonInstall:l}=await import("./daemon-XSFKUDKZ.js");n.pause(),await l({port:r,force:!0}),n.resume();let R=b();o=v(R)?R.bridgePort:r,p="daemon-installed",d.done(`daemon registered (port ${o})`)}catch(l){n.resume(),d.start("daemon unavailable, starting standalone server\u2026"),o=await C(r),p="standalone",d.done(`standalone (port ${o}) \u2014 ${h(l)}`)}}else d.start("starting standalone server\u2026"),o=await C(r),p="standalone",d.done(`standalone (port ${o})`)}catch(a){d.fail(h(a)),n.finish(),process.exit(1)}try{if($.start("waiting for bridge\u2026"),!await V(o,U))throw new Error(`bridge never came online on port ${o}`);$.done(`ws://localhost:${o}`)}catch(a){$.fail(h(a)),n.finish(),process.exit(1)}let w=`http://localhost:${o}/`;if(i){f.skip(w),n.finish();return}try{f.start("launching browser\u2026"),await _(w),f.done(w)}catch(a){f.skip(`${w} (open it manually \u2014 ${h(a)})`)}n.finish(),p==="standalone"?(console.log(`
22
22
  running in standalone mode. sootsim will exit when this process does.
23
- press ctrl-c to stop.`),await new Promise(()=>{})):p==="daemon-installed"&&console.log("\n installed as a background daemon \u2014 it'll restart on login.\n manage it with `sootsim daemon status / restart / uninstall`.")}function P(t,e){return new Promise(s=>{let r=new B(`ws://127.0.0.1:${t}`,{handshakeTimeout:e}),i=!1,n=c=>{if(!i){i=!0;try{r.close()}catch{}s(c)}};r.once("open",()=>n(!0)),r.once("error",()=>n(!1)),setTimeout(()=>n(!1),e)})}async function V(t,e){let s=Date.now()+e;for(;Date.now()<s;){if(await P(t,500))return!0;await new Promise(r=>setTimeout(r,200))}return!1}async function C(t){let e=W();N(e,["server","--quiet","--port",String(t)],{detached:!0,stdio:"ignore",env:process.env}).unref();let r=Date.now()+I;for(;Date.now()<r;){let i=b();if(v(i))return i.bridgePort;await new Promise(n=>setTimeout(n,150))}if(await P(t,800))return t;throw new Error(`standalone server didn't come online within ${Math.round(I/1e3)}s`)}function W(){let t=process.argv[1];return t&&F(t)?t:"sootsim"}function h(t){return t instanceof Error?t.message:String(t)}async function q(){try{let{checkRuntimeUpToDate:t}=await import("./runtime-delivery-IIDHK55K.js"),e,s=await Promise.race([t(),new Promise(r=>{e=setTimeout(()=>r(null),2500)})]);return e&&clearTimeout(e),s&&s.outdated?s.latest:null}catch{return null}}export{ee as runStart};
23
+ press ctrl-c to stop.`),await new Promise(()=>{})):p==="daemon-installed"&&console.log("\n installed as a background daemon \u2014 it'll restart on login.\n manage it with `sootsim daemon status / restart / uninstall`.")}function P(t,e){return new Promise(s=>{let r=new B(`ws://127.0.0.1:${t}`,{handshakeTimeout:e}),i=!1,n=c=>{if(!i){i=!0;try{r.close()}catch{}s(c)}};r.once("open",()=>n(!0)),r.once("error",()=>n(!1)),setTimeout(()=>n(!1),e)})}async function V(t,e){let s=Date.now()+e;for(;Date.now()<s;){if(await P(t,500))return!0;await new Promise(r=>setTimeout(r,200))}return!1}async function C(t){let e=W();N(e,["server","--quiet","--port",String(t)],{detached:!0,stdio:"ignore",env:process.env}).unref();let r=Date.now()+I;for(;Date.now()<r;){let i=b();if(v(i))return i.bridgePort;await new Promise(n=>setTimeout(n,150))}if(await P(t,800))return t;throw new Error(`standalone server didn't come online within ${Math.round(I/1e3)}s`)}function W(){let t=process.argv[1];return t&&F(t)?t:"sootsim"}function h(t){return t instanceof Error?t.message:String(t)}async function q(){try{let{checkRuntimeUpToDate:t}=await import("./runtime-delivery-BSRHUXJQ.js"),e,s=await Promise.race([t(),new Promise(r=>{e=setTimeout(()=>r(null),2500)})]);return e&&clearTimeout(e),s&&s.outdated?s.latest:null}catch{return null}}export{ee as runStart};
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a}from"./chunk-GNQSOQXZ.js";import"./chunk-Q2424XB2.js";import"./chunk-6QDFLMJL.js";export{a as settingsStore};
@@ -0,0 +1,2 @@
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a,b}from"./chunk-7Y3FYPJH.js";import"./chunk-DNKB2V2W.js";import"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.js";export{b as flushCliTelemetry,a as trackCliEvent};
@@ -1,5 +1,5 @@
1
- /*! sootsim v0.1.51 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import"./chunk-3BUWCNVX.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.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import"./chunk-6QDFLMJL.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-PUCPDKAO.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-HEYPRCST.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-UABOFTDQ.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-OUOMEOSC.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.51 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as k}from"./chunk-JZ65NOXB.js";import{c as b,e as v,i as w}from"./chunk-BKXH674Z.js";import"./chunk-5PKYORP6.js";import"./chunk-ACQXOAQI.js";import"./chunk-FSTOUA6L.js";import"./chunk-3BUWCNVX.js";async function z(e,o){if((e.includes("--help")||e.includes("-h"))&&(console.log(`
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as k}from"./chunk-2QNHBNWB.js";import{c as b,e as v,i as w}from"./chunk-MBH3NFBC.js";import"./chunk-CTEXZ7BE.js";import"./chunk-DSJ7PGU3.js";import"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.js";async function z(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.51 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{c as m,e as d,h as s}from"./chunk-BKXH674Z.js";import"./chunk-5PKYORP6.js";import"./chunk-ACQXOAQI.js";import"./chunk-FSTOUA6L.js";import"./chunk-3BUWCNVX.js";import{writeFileSync as g}from"fs";function u(){console.log(`
1
+ /*! sootsim v0.1.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{c as m,e as d,h as s}from"./chunk-MBH3NFBC.js";import"./chunk-CTEXZ7BE.js";import"./chunk-DSJ7PGU3.js";import"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.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.51 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as i}from"./chunk-54IIO5BV.js";import{a as s}from"./chunk-M7HK7MWE.js";import"./chunk-BKXH674Z.js";import"./chunk-5PKYORP6.js";import"./chunk-CLSZB5BN.js";import"./chunk-ACQXOAQI.js";import{C as e}from"./chunk-FSTOUA6L.js";import"./chunk-3BUWCNVX.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.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as i}from"./chunk-IQU56D6C.js";import{a as s}from"./chunk-PZJSYDQ7.js";import"./chunk-MBH3NFBC.js";import"./chunk-CTEXZ7BE.js";import"./chunk-DSJ7PGU3.js";import"./chunk-UXE5BFPK.js";import{C as e}from"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.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=i(),n=await u();if(!n){console.log(` cli: v${o} \u2014 couldn't reach the npm registry, skipped`);return}if(e(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.52 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a,b,c}from"./chunk-IXITVIJV.js";import"./chunk-BF7F45CZ.js";import"./chunk-YVGHAT6Q.js";import"./chunk-MTE3DEWY.js";import"./chunk-7Y3FYPJH.js";import"./chunk-DNKB2V2W.js";import"./chunk-MBH3NFBC.js";import"./chunk-CTEXZ7BE.js";import"./chunk-DSJ7PGU3.js";import"./chunk-JPLTR6JM.js";import"./chunk-6QDFLMJL.js";export{a as resolveDefaultUploadOrigin,b as resolvePublicPreviewOrigin,c as runUpload};