sootsim 0.0.4 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +24 -9
- package/dist-cli/bin.js +15 -20
- package/dist-cli/chunks/{agent-PJAOF4JS.js → agent-EQRQGSBL.js} +4 -4
- package/dist-cli/chunks/agent-wrapper-AWKZ67GN.js +15 -0
- package/dist-cli/chunks/{assert-P47NW4AF.js → assert-ZVGELUZB.js} +2 -2
- package/dist-cli/chunks/auto-bootstrap-UEOLNAWJ.js +2 -0
- package/dist-cli/chunks/beta-4MD7WSI4.js +2 -0
- package/dist-cli/chunks/chunk-2ZPJHSIJ.js +11 -0
- package/dist-cli/chunks/chunk-4IO3D5XG.js +2 -0
- package/dist-cli/chunks/chunk-4OHVCGMF.js +2 -0
- package/dist-cli/chunks/chunk-56BIMCDH.js +2 -0
- package/dist-cli/chunks/chunk-5FLDI6CV.js +66 -0
- package/dist-cli/chunks/{chunk-WWDJCKMI.js → chunk-B3RAGRK6.js} +1 -1
- package/dist-cli/chunks/chunk-BGAPLYMS.js +61 -0
- package/dist-cli/chunks/chunk-CX3ZIPD3.js +3 -0
- package/dist-cli/chunks/{chunk-I6XGFZPA.js → chunk-DSTV2VJT.js} +2 -2
- package/dist-cli/chunks/chunk-EDBFYOQB.js +2 -0
- package/dist-cli/chunks/chunk-ERLA3F77.js +1 -0
- package/dist-cli/chunks/chunk-FCQLQ7NA.js +117 -0
- package/dist-cli/chunks/chunk-H2HSOHXN.js +7 -0
- package/dist-cli/chunks/chunk-HYYMBXIX.js +2 -0
- package/dist-cli/chunks/chunk-JMGDVXAV.js +3 -0
- package/dist-cli/chunks/chunk-JMU5IGIU.js +1 -0
- package/dist-cli/chunks/chunk-KA5JJCWL.js +1 -0
- package/dist-cli/chunks/chunk-L4F4JRKJ.js +348 -0
- package/dist-cli/chunks/chunk-LDWXH43L.js +4 -0
- package/dist-cli/chunks/chunk-PERKPZ7T.js +4 -0
- package/dist-cli/chunks/chunk-PN6FWLD4.js +5 -0
- package/dist-cli/chunks/chunk-QD7YIVPS.js +64 -0
- package/dist-cli/chunks/chunk-QWKO62QM.js +2 -0
- package/dist-cli/chunks/{chunk-6SZMLFCR.js → chunk-QXMZNJV5.js} +1 -1
- package/dist-cli/chunks/chunk-R77F5J3X.js +4 -0
- package/dist-cli/chunks/chunk-RLNIKWFO.js +27 -0
- package/dist-cli/chunks/chunk-RX6RHGSI.js +2 -0
- package/dist-cli/chunks/chunk-S74RCIVB.js +2 -0
- package/dist-cli/chunks/chunk-SK4SOISL.js +1 -0
- package/dist-cli/chunks/{chunk-AFQBSK2J.js → chunk-T5L73GJB.js} +1 -1
- package/dist-cli/chunks/{chunk-432TMHBG.js → chunk-UIQ3536J.js} +1 -1
- package/dist-cli/chunks/chunk-URSEYCC5.js +16 -0
- package/dist-cli/chunks/chunk-WFXYY3DU.js +3 -0
- package/dist-cli/chunks/{chunk-DQKQYPIG.js → chunk-WHLHA5R5.js} +4 -4
- package/dist-cli/chunks/chunk-WLIVBPPY.js +3 -0
- package/dist-cli/chunks/{chunk-UQ3N6FZF.js → chunk-X6BP5JFC.js} +4 -4
- package/dist-cli/chunks/chunk-YFXTO4QX.js +5 -0
- package/dist-cli/chunks/{chunk-4XBPZQLW.js → chunk-Z5SVSAZO.js} +2 -2
- package/dist-cli/chunks/{chunk-5TTQKPGH.js → chunk-Z5X3PITK.js} +3 -3
- package/dist-cli/chunks/chunk-ZBOIGEGO.js +5 -0
- package/dist-cli/chunks/chunk-ZERYEI3L.js +17 -0
- package/dist-cli/chunks/{compat-ILLJ7VDL.js → compat-QQ3OJDBI.js} +2 -2
- package/dist-cli/chunks/{config-CDIAJIIT.js → config-LT27SC25.js} +2 -2
- package/dist-cli/chunks/control-3BO54QMO.js +2 -0
- package/dist-cli/chunks/cpu-profile-XEO3JCVB.js +22 -0
- package/dist-cli/chunks/daemon-3J2SAVQZ.js +83 -0
- package/dist-cli/chunks/{debug-6SMCTPMC.js → debug-OGQLIH4U.js} +4 -4
- package/dist-cli/chunks/demo-app-registry-5RZCXLWB.js +2 -0
- package/dist-cli/chunks/detox-Z2OSCIQU.js +49 -0
- package/dist-cli/chunks/device-RPTVD25S.js +16 -0
- package/dist-cli/chunks/diagnose-LAEXBNOQ.js +41 -0
- package/dist-cli/chunks/drivers-PSQUUAYC.js +2 -0
- package/dist-cli/chunks/electron-S2463O3P.js +18 -0
- package/dist-cli/chunks/flow-34YCVQDB.js +2 -0
- package/dist-cli/chunks/hints-E5PXPWFT.js +2 -0
- package/dist-cli/chunks/home-paths-F5SGBTRZ.js +2 -0
- package/dist-cli/chunks/inspect-EVGMEZ3G.js +1101 -0
- package/dist-cli/chunks/install-AM5PTJT3.js +2 -0
- package/dist-cli/chunks/install-desktop-ZNWYKTWQ.js +23 -0
- package/dist-cli/chunks/{keys-OWQ7SOTM.js → keys-5ETF6DYO.js} +2 -2
- package/dist-cli/chunks/{launch-WUEDHSO5.js → launch-DHUCNFX6.js} +3 -3
- package/dist-cli/chunks/login-KDR34JIP.js +26 -0
- package/dist-cli/chunks/logout-R6WIJYCW.js +2 -0
- package/dist-cli/chunks/maestro-ZOOJ2YVH.js +80 -0
- package/dist-cli/chunks/{preview-4RVHA2PP.js → preview-YFADHNBD.js} +2 -2
- package/dist-cli/chunks/profile-CQSC32HB.js +22 -0
- package/dist-cli/chunks/react-QSQD6CJE.js +30 -0
- package/dist-cli/chunks/{record-KEWLM5JR.js → record-IWLEYATN.js} +5 -5
- package/dist-cli/chunks/runtime-WKMNKYTN.js +25 -0
- package/dist-cli/chunks/screenshot-VJXHV57I.js +28 -0
- package/dist-cli/chunks/screenshot-mode-FA4VQ76K.js +17 -0
- package/dist-cli/chunks/screenshots-U4FQXHVK.js +70 -0
- package/dist-cli/chunks/server-7WZLM5NQ.js +35 -0
- package/dist-cli/chunks/setup-repo-3BXLAX5E.js +2 -0
- package/dist-cli/chunks/{skills-DJA6QEVR.js → skills-KO7RCY24.js} +2 -2
- package/dist-cli/chunks/start-EBD7T2GW.js +23 -0
- package/dist-cli/chunks/store-ONX3EBS4.js +2 -0
- package/dist-cli/chunks/telemetry-MFR7TUW7.js +2 -0
- package/dist-cli/chunks/{test-IWUHNFXV.js → test-OSVUG54G.js} +3 -3
- package/dist-cli/chunks/three-mode-MDBXZQG4.js +39 -0
- package/dist-cli/chunks/timeline-UJOKZKQR.js +22 -0
- package/dist-cli/chunks/upload-H2SMWP6T.js +2 -0
- package/dist-cli/chunks/what-happened-LFWH74FR.js +15 -0
- package/dist-cli/chunks/whoami-CUF56TLP.js +2 -0
- package/dist-lib/agent-daemon-client.cjs +6 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +42 -39
- package/dist-lib/attached-projects.cjs +30 -28
- package/dist-lib/auth/shared-session.cjs +35 -27
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +6 -2
- package/dist-lib/dev-bundle-resolution.cjs +7 -21
- package/dist-lib/home-paths.cjs +112 -30
- package/dist-lib/host/bridge-host.cjs +1817 -579
- package/dist-lib/host/fetch-proxy-handler.cjs +248 -0
- package/dist-lib/index.cjs +22 -22
- package/dist-lib/metro.cjs +22 -22
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/vite-base.cjs +3224 -764
- package/dist-lib/vite.cjs +1 -1
- package/package.json +11 -3
- package/dist-cli/chunks/agent-wrapper-STO7PLQD.js +0 -15
- package/dist-cli/chunks/auto-bootstrap-SC2LMI2H.js +0 -2
- package/dist-cli/chunks/chunk-47S5DXXX.js +0 -11
- package/dist-cli/chunks/chunk-4VXB2DBA.js +0 -119
- package/dist-cli/chunks/chunk-AUR2LTNX.js +0 -3
- package/dist-cli/chunks/chunk-BQRM4E66.js +0 -4
- package/dist-cli/chunks/chunk-C3QLIYCS.js +0 -16
- package/dist-cli/chunks/chunk-EHMSE3Q3.js +0 -2
- package/dist-cli/chunks/chunk-F4ARVCRR.js +0 -1
- package/dist-cli/chunks/chunk-HAKR72LJ.js +0 -2
- package/dist-cli/chunks/chunk-HGFIS26A.js +0 -2
- package/dist-cli/chunks/chunk-MQDPKSCK.js +0 -308
- package/dist-cli/chunks/chunk-MZPAJ5PQ.js +0 -1
- package/dist-cli/chunks/chunk-OAHMYSMD.js +0 -2
- package/dist-cli/chunks/chunk-QIP7LYQI.js +0 -5
- package/dist-cli/chunks/chunk-QQOBLF7O.js +0 -22
- package/dist-cli/chunks/chunk-SY74J6F4.js +0 -5
- package/dist-cli/chunks/chunk-UKYK63H6.js +0 -3
- package/dist-cli/chunks/chunk-UNFERMZ3.js +0 -27
- package/dist-cli/chunks/chunk-VGXARPIH.js +0 -3
- package/dist-cli/chunks/chunk-W3TYN64D.js +0 -62
- package/dist-cli/chunks/chunk-W7CYWXRZ.js +0 -4
- package/dist-cli/chunks/chunk-WRF43M33.js +0 -4
- package/dist-cli/chunks/chunk-WVBPATRA.js +0 -2
- package/dist-cli/chunks/chunk-XJF46GU2.js +0 -2
- package/dist-cli/chunks/chunk-ZF5FCFLD.js +0 -2
- package/dist-cli/chunks/chunk-ZKNI5MRD.js +0 -1
- package/dist-cli/chunks/control-7QGKUCAX.js +0 -2
- package/dist-cli/chunks/daemon-4BLYGM5N.js +0 -49
- package/dist-cli/chunks/demo-app-registry-HLI5UGGI.js +0 -2
- package/dist-cli/chunks/detox-R4G5INNB.js +0 -49
- package/dist-cli/chunks/device-YSLCWS4E.js +0 -16
- package/dist-cli/chunks/drivers-YIXRFFBQ.js +0 -2
- package/dist-cli/chunks/electron-JZOFO37G.js +0 -15
- package/dist-cli/chunks/flow-L7X5FGIN.js +0 -2
- package/dist-cli/chunks/hints-O4QR6UGI.js +0 -2
- package/dist-cli/chunks/home-paths-4YJJYGR6.js +0 -2
- package/dist-cli/chunks/inspect-DRFAUJUH.js +0 -1030
- package/dist-cli/chunks/install-BATRTWRI.js +0 -65
- package/dist-cli/chunks/install-desktop-6X474IQ3.js +0 -23
- package/dist-cli/chunks/install-dev-desktop-CAJHPRNP.js +0 -100
- package/dist-cli/chunks/login-54YJ2KH6.js +0 -26
- package/dist-cli/chunks/logout-XECXLEXW.js +0 -2
- package/dist-cli/chunks/maestro-PMHK6EHI.js +0 -75
- package/dist-cli/chunks/profile-3IVNHUS6.js +0 -22
- package/dist-cli/chunks/runtime-PJKHEB36.js +0 -25
- package/dist-cli/chunks/screenshot-BXRAQERZ.js +0 -26
- package/dist-cli/chunks/screenshot-mode-5IXEDIUS.js +0 -17
- package/dist-cli/chunks/screenshots-T4MQF3TB.js +0 -70
- package/dist-cli/chunks/server-CIP3LH45.js +0 -29
- package/dist-cli/chunks/store-SPC247DB.js +0 -2
- package/dist-cli/chunks/upload-UPD2RSYF.js +0 -2
- package/dist-cli/chunks/whoami-MCXFWKIH.js +0 -2
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{b as Y,c as D,d as X,e as H,f as Z,h as Q,i as w,j as ee,k as te,l as ie,p as re,s as A,t as ne,u as se,v as oe,w as ae}from"./chunk-R77F5J3X.js";import"./chunk-UIQ3536J.js";import{a as E}from"./chunk-ZBOIGEGO.js";import"./chunk-QWKO62QM.js";import"./chunk-QD7YIVPS.js";import{e as z}from"./chunk-LDWXH43L.js";import{a as V,b as G}from"./chunk-S74RCIVB.js";import"./chunk-WFXYY3DU.js";import{d as q}from"./chunk-4IO3D5XG.js";import"./chunk-ERLA3F77.js";import{A as W,B as O,D as F,E as j,F as $,G as J,H as K,I as N,u as _,v as U,y as T,z as M}from"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";import{spawn as Te}from"child_process";import v from"fs";import{createServer as Ee}from"http";import S from"path";import{WebSocket as m,WebSocketServer as Ie}from"ws";import ce from"node:fs";import I from"node:path";var P=1;function ge(){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 x=class{subscriptions=new Map;sessionsBySocket=new Map;allSockets=new Set;pendingPromptEchoes=new Map;pendingTurns=new Map;opts;constructor(e={}){this.opts=e}registerSocket(e){this.allSockets.add(e)}unregisterSocket(e){let t=this.sessionsBySocket.get(e);if(t){for(let i of t)this.decrementSubscription(i);this.sessionsBySocket.delete(e)}this.allSockets.delete(e)}async handleMessage(e,t){let i=t?.type;if(typeof i!="string"||!i.startsWith("agent:"))return!1;let s=t.id;try{let n=await this.dispatch(e,i,t);this.respond(e,s,n)}catch(n){n instanceof A?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 ie()}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 Q(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return ee(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=w(n);if(!o)throw new A("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await se(n,r),this.notePromptAccepted(n,r,o.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await oe(String(i.sessionId));let s=w(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 A("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async doStartSession(e){if(!X(e.projectId))throw new A("NO_PROJECT",`no project: ${e.projectId}`);let i=await ne(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?.()??ge(),o=(await E({excludePorts:s})).find(l=>String(l.port)===i);if(!o||!o.cwd)return{project:null};let r=H().find(l=>l.cwd===o.cwd)??null,c=Array.from(new Set([...r?.knownBundleUrls??[],o.bundleUrl,t]));return{project:D({cwd:o.cwd,name:o.projectName??I.basename(o.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[o.cwd],knownBundleUrls:c,framework:r?.framework??Se(o.framework),bundleId:o.bundleId??r?.bundleId})}}getTranscript(e){let t=re(e);return ce.existsSync(t)?ce.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=Y();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 s=this.subscriptions.get(t);if(s)return s.refCount++,{ok:!0,refCount:s.refCount};let n=ae(t,o=>{let r=this.coalescePromptEcho(t,o);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),o.type==="turn-completed"){let c=w(t);if(c)try{Z(c.projectId,{usd:o.costUsd,ts:o.ts})}catch(d){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${d instanceof Error?d.message:String(d)}
|
|
4
|
+
`)}}});return this.subscriptions.set(t,{unsubscribe:n,refCount:1}),{ok:!0,refCount:1}}unsubscribeSocket(e,t){let i=this.sessionsBySocket.get(e);return!i||!i.has(t)?{ok:!0,refCount:0}:(i.delete(t),this.decrementSubscription(t))}decrementSubscription(e){let t=this.subscriptions.get(e);if(!t)return{ok:!0,refCount:0};if(t.refCount--,t.refCount<=0){try{t.unsubscribe()}catch{}return this.subscriptions.delete(e),{ok:!0,refCount:0}}return{ok:!0,refCount:t.refCount}}dropSessionFanout(e){let t=this.subscriptions.get(e);if(t){try{t.unsubscribe()}catch{}this.subscriptions.delete(e)}for(let i of this.sessionsBySocket.values())i.delete(e);this.clearPromptTracking(e)}normalizePromptEnvelope(e){if(e?.prompt&&typeof e.prompt=="object"){let t=e.prompt;return{text:String(t.text??""),...typeof t.displayText=="string"?{displayText:t.displayText}:{},...typeof t.inspectSummary=="string"?{inspectSummary:t.inspectSummary}:{},...typeof t.inspectTrace=="string"?{inspectTrace:t.inspectTrace}:{}}}return{text:String(e?.text??""),...typeof e?.displayText=="string"?{displayText:e.displayText}:{},...typeof e?.inspectSummary=="string"?{inspectSummary:e.inspectSummary}:{},...typeof e?.inspectTrace=="string"?{inspectTrace:e.inspectTrace}:{}}}notePromptAccepted(e,t,i){let s=Date.now(),n=this.pendingPromptEchoes.get(e)??[];n.push({sentAt:s}),this.pendingPromptEchoes.set(e,n);let 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){te(e,t);let i=w(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 Se(a){return a==="expo"?"expo":a==="one"||a==="vxrn"?"one":"unknown"}import ye from"http";import ve from"https";var be="sootsim",we=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"]),Ae={"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 k(a){for(let[e,t]of Object.entries(Ae))a.setHeader(e,t)}function ke(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 Ce(a){let e={};for(let[t,i]of Object.entries(a))i&&(we.has(t.toLowerCase())||(e[t]=Array.isArray(i)?i.join(", "):i));return e["user-agent"]=be,e}function de(a){return a?.startsWith("/__fetch-proxy?")||a?.startsWith("/__proxy?")||!1}function le(a){return a?!!(a.startsWith("/__app-api?")||a.startsWith("/__app-api/")):!1}async function ue(a,e){if(a.method==="OPTIONS"){k(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((a.url||"").split("?")[1]||"").get("url");if(!i){k(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{k(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=Ce(a.headers),o;if(a.method!=="GET"&&a.method!=="HEAD"){let l=[];for await(let u of a)l.push(Buffer.isBuffer(u)?u:Buffer.from(u));l.length>0&&(o=Buffer.concat(l))}let r;try{r=await fetch(s.href,{method:a.method,headers:n,body:o,redirect:"follow"})}catch(l){k(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${ke(s.href,l)}`);return}r.headers.forEach((l,u)=>{let p=u.toLowerCase();p==="content-encoding"||p==="transfer-encoding"||p==="content-length"||p==="set-cookie"||p.startsWith("access-control-")||e.setHeader(u,l)}),k(e);let c=r.headers.getSetCookie?.()??[];c.length>0&&e.setHeader("x-sootsim-set-cookie",c.join(", ")),e.statusCode=r.status;let d=Buffer.from(await r.arrayBuffer());e.end(d)}function pe(a,e){let t=a.url||"",i="",s="";if(t.startsWith("/__app-api?")){let d=new URL(t,"http://sootsim.local");i=d.searchParams.get("path")||"",s=d.searchParams.get("origin")?.trim()||""}else if(t.startsWith("/__app-api/"))i=t.slice(10);else return!1;if(!s)return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: missing origin query param"),!0;if(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:"?ve:ye,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},d=>{let l=Object.keys(d.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(d.statusCode??502,{...d.headers,"access-control-allow-origin":a.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":l}),d.pipe(e)});return c.on("error",d=>{e.statusCode=502,e.end(`app proxy error: ${d.message}`)}),a.pipe(c),!0}var Pe=new Set(["tap","keyboard","close"]);function xe(a){return!a||typeof a.type!="string"?!1:a.acquireLock===!0?!0:a.readOnly===!0?!1:Pe.has(a.type)}var Re=5e3,Be=3600*1e3,Le="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",_e={".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 he(a){let e;try{let s=_();e=JSON.stringify(s)}catch{e="{}"}let t=`<script>window.__sootsimSharedConfig=${e};</script>`,i=a.toString("utf8");return i.includes("</head>")?i.replace("</head>",t+"</head>"):i.includes("</body>")?i.replace("</body>",t+"</body>"):t+i}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;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 x({getExcludePorts:e.agentScanExcludes})}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(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=Ee((c,d)=>this.handleHttpRequest(c,d)),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 Ie({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=O(),d=this.getActiveRuntime(),l={type:"runtime:list:ok",id:r.id,installed:c,active:d.version,activeRuntimeDir:d.runtimeDir};try{e.send(JSON.stringify(l))}catch{}return}if(r.type==="runtime:use"){let c=typeof r.version=="string"?r.version:"";if(!O().includes(c)){try{e.send(JSON.stringify({type:"runtime:use:error",id:r.id,error:`runtime ${c||"(missing)"} is not installed`}))}catch{}return}let l=this.setActiveRuntime(c);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:l.version,runtimeDir:l.runtimeDir}))}catch{}return}if(r.type==="runtime:get"){let c=this.getActiveRuntime();try{e.send(JSON.stringify({type:"runtime:get:ok",id:r.id,active:c.version,activeRuntimeDir:c.runtimeDir}))}catch{}return}if(s==="sim"){if(n&&(n.lastSeenAt=Date.now()),r.type==="bridge:register"&&n){let l=r,u=this.tryRestoreSimId(n,l.simId);n.url=l.url,n.title=l.title,n.userAgent=l.userAgent,u&&(this.broadcastSimAssignments(),this.broadcastSimClientStates());return}if(r.type==="bridge:user-focus-state"&&n){let l=r;this.updateUserFocusLease(n,l.focused===!0);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){let l=r.patch&&typeof r.patch=="object"?r.patch:null;if(!l)return;let u;try{u=U(l)}catch(h){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${h instanceof Error?h.message:String(h)}
|
|
8
|
+
`);return}let p=JSON.stringify({type:"bridge:shared-config-changed",config:u});for(let h of this.sims.values())if(h.ws.readyState===m.OPEN)try{h.ws.send(p)}catch{}return}if(r.type==="bridge:open-path"){let l=typeof r.path=="string"?r.path:"",u=typeof r.line=="number"&&Number.isFinite(r.line)?r.line:void 0,p=typeof r.column=="number"&&Number.isFinite(r.column)?r.column:void 0;l&&this.openPathInEditor(l,u,p);return}if(r.type==="bridge:boot-clients"&&n){let l=[];for(let[p,h]of this.cliSimBySocket)h===n.id&&l.push(p);for(let p of l){this.cliSimBySocket.delete(p);try{p.close(1e3,"booted by sim")}catch{}}let u=!!n.cliLease;n.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:Date.now()+a.USER_BOOT_LEASE_TTL_MS},process.stderr.write(`sootsim booted ${l.length} cli client(s)${u?" (overrode prior lease)":""}; held sim for user [${n.id}]
|
|
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 d=this.cliBySentId.get(r.id);if(d&&(this.cliBySentId.delete(r.id),d.ws.readyState===m.OPEN)){let l=this.getOtherCliIdentityCount(d.ws,d.simId),u=l>0?{...r,id:d.originalId,i:l}:{...r,id:d.originalId};d.ws.send(JSON.stringify(u))}return}(async()=>{this.cliLastCommandAt.set(e,Date.now());try{if(r.type==="bridge:bye"){let p=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[h,g]of this.cliBySentId)g.ws===e&&this.cliBySentId.delete(h);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===m.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===m.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===m.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),h=this.tryAcquireLease(e,p,{force:r.force===!0});if(!h.granted){e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${p.id} is locked by another cli`,o:h.lock}));return}this.setCliSimTarget(e,p.id),this.recordSimAction(p.id,h.bootedCount>0?`cli force-claimed sim (booted ${h.bootedCount})`:"cli claimed sim"),e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,result:{simId:p.id,lockedBy:h.lease.cliIdentityKey,lockExpiresAt:h.lease.expiresAt,bootedCount:h.bootedCount}}));return}let c=await this.waitForSim(r.simId);if(xe(r)){let p=this.tryAcquireLease(e,c);if(!p.granted){e.readyState===m.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 d=this.nextCommandId++;this.cliBySentId.set(d,{simId:c.id,ws:e,originalId:r.id});let{simId:l,...u}=r;c.ws.send(JSON.stringify({...u,id:d}))}catch(c){e.readyState===m.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===m.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
|
+
`),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(),!K(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{}},Re),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(){J(this.buildLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=M(),this.activeRuntimeDirPath=F()}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=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[Le]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):Be}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
|
+
`);let t=await z();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
|
|
13
|
+
`);return}let i=this.setActiveRuntime(t.latestVersion);process.stderr.write(`sootsim runtime updated to ${i.version} (${e})
|
|
14
|
+
`)}catch(t){process.stderr.write(`sootsim runtime update failed (${e}): ${t instanceof Error?t.message:String(t)}
|
|
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(W(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===m.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(de(e.url)){ue(e,t);return}if(le(e.url)&&pe(e,t))return;let i=(e.method||"GET").toUpperCase();if(i!=="GET"&&i!=="HEAD"){t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed");return}let s=new URL(e.url||"/","http://localhost");if(s.pathname==="/__bundle-proxy"){let d=s.searchParams.get("url");if(!d){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let l;try{l=new URL(d)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let u=l.hostname;if(!(u==="localhost"||u==="127.0.0.1"||u==="::1"||u.endsWith(".localhost"))){t.writeHead(403,{"Content-Type":"text/plain"}),t.end("bundle-proxy: only loopback targets allowed");return}(async()=>{try{let h=await fetch(l.toString(),{redirect:"follow"}),g={},f=h.headers.get("content-type");if(f&&(g["Content-Type"]=f),g["Cache-Control"]="no-store",t.writeHead(h.status,g),!h.body){t.end();return}let b=h.body.getReader();for(;;){let{done:C,value:y}=await b.read();if(C)break;t.write(Buffer.from(y))}t.end()}catch(h){t.writeHead(502,{"Content-Type":"text/plain"}),t.end(`bundle-proxy: upstream fetch failed: ${h instanceof Error?h.message:String(h)}`)}})();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 d="{}";try{d=JSON.stringify(_())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(d);return}t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed (use the bridge over WS for writes)");return}this.refreshActiveRuntime();let n=this.activeRuntimeDirPath;if(!n){t.writeHead(503,{"Content-Type":"text/plain; charset=utf-8"}),t.end("sootsim: no active runtime installed. run `sootsim runtime install` to fetch one.");return}let 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 d of o.split("/"))if(d===".."){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}v.realpath(r,(d,l)=>{let u=d?r:l,p=u.endsWith(S.sep)?u:u+S.sep;if(!d){let h=(()=>{try{let g=v.realpathSync(n);return g.endsWith(S.sep)?g:g+S.sep}catch{return c}})();if(!p.startsWith(h)&&u+S.sep!==h){t.writeHead(403),t.end("forbidden");return}}v.stat(u,(h,g)=>{if(h||!g?.isFile()){let y=S.extname(o).toLowerCase();if(y&&y!==".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 L=S.join(n,"index.html");v.readFile(L,(me,fe)=>{if(me){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(he(fe))});return}let f=S.extname(u).toLowerCase(),b=_e[f]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":b,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(f===".html"){v.readFile(u,(y,L)=>{if(y){try{t.end()}catch{}return}t.end(he(L))});return}let C=v.createReadStream(u);C.pipe(t),C.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)}sweepDeadWebSockets(){if(this.wss)for(let e of this.wss.clients){if(e.readyState!==m.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{}}}}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:d=>{clearTimeout(o),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(d)},reject:d=>{clearTimeout(o),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(d)}}),this.broadcastSimClientStates();let{simId:r,...c}=e;t.ws.send(JSON.stringify({...c,id:i}))})}async evaluate(e,t){return this.sendCommand({type:"evaluate",code:e,simId:t})}async focusSim(e){return this.sendCommand({type:"focus",simId:e})}async closeSim(e){return this.sendCommand({type:"close",simId:e})}async openPathInEditor(e,t,i){let s=t!=null?`:${t}${i!=null?`:${i}`:""}`:"",n=`${e}${s}`,o=(c,d)=>new Promise(l=>{try{let u=Te(c,d,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,l(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),l(!0))})}catch{l(!1)}}),r=process.env.REACT_EDITOR||process.env.EDITOR;if(r){let c=r.split(" ").filter(Boolean);if(c.length&&await 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 q(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=m.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===m.OPEN?"open":t===m.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}}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,d=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 h=this.cliIdentityKeyBySocket.get(u);if(h&&h!==s){this.cliSimBySocket.delete(u);try{u.close(1e3,"lease claimed by another cli")}catch{}d++}}let l={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:o+a.CLI_LEASE_TTL_MS};return t.cliLease=l,{granted:!0,lease:l,bootedCount:d}}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 i=this.sims.get(e);return i?.ws.readyState===m.OPEN?i:null}let t=this.primarySimId!=null?this.sims.get(this.primarySimId):null;if(t?.ws.readyState===m.OPEN)return t;for(let i of this.sims.values())if(i.ws.readyState===m.OPEN)return i;return null}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,i=e.origin?.includes(":5173"),s=t?.origin?.includes(":5173");return!t||t.ws.readyState!==m.OPEN||!!i||!s}broadcastSimAssignments(){for(let e of this.sims.values())e.ws.readyState===m.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!==m.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!==m.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!==m.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===m.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 Oe(){let a=process.env.XPC_SERVICE_NAME||"";return!!(a.includes("dev.sootsim.daemon")||a.includes("dev.sootsim.server")||process.env.INVOCATION_ID)}async function at(a,e={}){(a.includes("--help")||a.includes("-h"))&&(console.log(`
|
|
17
|
+
sootsim server \u2014 run the sootsim bridge daemon in the foreground
|
|
18
|
+
|
|
19
|
+
hosts the WS bridge that CLI commands talk to. once running, any sootsim
|
|
20
|
+
renderer (browser, electron, headless playwright) that connects to port 7668
|
|
21
|
+
becomes drivable from 'sootsim describe', 'sootsim tap', etc.
|
|
22
|
+
|
|
23
|
+
usage:
|
|
24
|
+
sootsim server [options]
|
|
25
|
+
|
|
26
|
+
options:
|
|
27
|
+
--port <n> bridge port (defaults to ${7668})
|
|
28
|
+
--quiet suppress per-connection logging
|
|
29
|
+
|
|
30
|
+
examples:
|
|
31
|
+
sootsim server
|
|
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 s=a.includes("--quiet")||a.includes("-q"),n=j();n&&$(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=new R({port:i,writeLockfile:!0}),r=await o.startAsync({silent:s}),c=Date.now(),d=h=>{s||process.stdout.write(`${h}
|
|
34
|
+
`)},l=new Set,u=setInterval(()=>{let h=o.listSims(),g=new Set(h.map(f=>f.id));for(let f of h)if(!l.has(f.id)){let b=f.title||f.url||f.origin||"(unknown)";d(` + ${f.id} ${b}`)}for(let f of l)g.has(f)||d(` - ${f}`);l.clear();for(let f of g)l.add(f)},500);V({event:"daemon_heartbeat",properties:{bridge_port:r,under_daemon:Oe(),platform:process.platform,subsource:"daemon"}}),G(),d(`sootsim bridge listening on ws://localhost:${r} (runtime http on same port)`),r!==i&&d(` (preferred port ${i} was taken \u2014 fell back to ${r})`),d(" ready for browser, electron, or headless playwright sims to connect"),d(" (ctrl-c to stop)");let p=async h=>{clearInterval(u),d(`
|
|
35
|
+
${h} received \u2014 shutting down after ${Math.round((Date.now()-c)/1e3)}s`);try{await o.close()}catch{}process.exit(0)};process.on("SIGINT",()=>p("SIGINT")),process.on("SIGTERM",()=>p("SIGTERM")),process.on("SIGHUP",()=>p("SIGHUP")),process.on("exit",()=>{try{o.removeLockfile()}catch{}}),await new Promise(()=>{})}export{at as runServer};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{a}from"./chunk-BGAPLYMS.js";import"./chunk-QXMZNJV5.js";import"./chunk-H2HSOHXN.js";import"./chunk-S74RCIVB.js";import"./chunk-WFXYY3DU.js";import"./chunk-ZERYEI3L.js";import"./chunk-PERKPZ7T.js";import"./chunk-ERLA3F77.js";import"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";export{a as runSetupRepo};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! sootsim v0.
|
|
2
|
-
import"./chunk-
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import"./chunk-B3RAGRK6.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
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{d as _}from"./chunk-4IO3D5XG.js";import"./chunk-ZERYEI3L.js";import"./chunk-PERKPZ7T.js";import"./chunk-ERLA3F77.js";import{E as b,F as v,i as D,y as O,z as $}from"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";import{spawn as N}from"child_process";import{existsSync as F}from"fs";import{WebSocket as B}from"ws";var k=["\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 T(){return process.stderr.isTTY===!0}function l(t,e){return T()?`${A[t]}${e}${A.reset}`:e}function L(t,e){switch(t){case"pending":return l("dim","\xB7");case"running":return l("cyan",e);case"done":return l("green","\u2713");case"fail":return l("red","\u2717");case"skip":return l("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||!T()||this.steps.some(e=>e.state==="running")&&(this.timer=setInterval(()=>{this.frame=(this.frame+1)%k.length,this.draw()},80),this.timer?.unref?.())}stopSpinner(){this.timer&&(clearInterval(this.timer),this.timer=null)}draw(){if(!T()){this.drawForwardOnly();return}this.eraseRendered();let e=[];this.bannerText&&(e.push(l("bold",this.bannerText)),e.push(""));let s=k[this.frame],i=Math.max(...this.steps.map(r=>r.label.length),0);for(let r of this.steps){let n=L(r.state,s),u=r.label.padEnd(i),y=r.detail?` ${l("dim",r.detail)}`:"";e.push(` ${n} ${u}${y}`)}process.stderr.write(e.join(`
|
|
3
|
+
`)+`
|
|
4
|
+
`),this.lastLineCount=e.length,this.steps.some(r=>r.state==="running")||this.stopSpinner()}bannerPrinted=!1;lastEmitted=new Map;drawForwardOnly(){this.bannerText&&!this.bannerPrinted&&(process.stderr.write(this.bannerText+`
|
|
5
|
+
|
|
6
|
+
`),this.bannerPrinted=!0);for(let e of this.steps){let s=`${e.state}:${e.detail||""}`;if(this.lastEmitted.get(e.label)===s)continue;if(e.state==="pending"){this.lastEmitted.set(e.label,s);continue}let r=L(e.state,k[0]),n=e.detail?` ${e.detail}`:"";process.stderr.write(` ${r} ${e.label}${n}
|
|
7
|
+
`),this.lastEmitted.set(e.label,s)}}eraseRendered(){this.lastLineCount!==0&&(process.stderr.write(`\x1B[${this.lastLineCount}A\x1B[0J`),this.lastLineCount=0)}};var U=3e4,I=1e4;async function Z(t,e={}){if(t.includes("--help")||t.includes("-h")){console.log(`
|
|
8
|
+
sootsim start \u2014 install + run sootsim, open it in your browser
|
|
9
|
+
|
|
10
|
+
bare \`sootsim\` (or \`npx sootsim\`) defaults to this command. it makes sure
|
|
11
|
+
the engine runtime is on disk, ensures the bridge daemon is up (or falls
|
|
12
|
+
back to a detached server), then opens the iOS shell in your browser.
|
|
13
|
+
|
|
14
|
+
usage:
|
|
15
|
+
sootsim start [options]
|
|
16
|
+
sootsim # same thing
|
|
17
|
+
|
|
18
|
+
options:
|
|
19
|
+
--port <n> bridge port (default: ${7668})
|
|
20
|
+
--no-open don't open the browser at the end
|
|
21
|
+
`);return}O();let s=t.indexOf("--port"),i=s>=0&&t[s+1]?Number(t[s+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${t[s+1]}`),process.exit(1));let r=t.includes("--no-open"),n=new S,{IS_BETA:u,BETA_TAGLINE:y}=await import("./beta-4MD7WSI4.js");n.banner(u?`sootsim \u2014 ${y}`:"sootsim \u2014 starting up");let c=n.add("runtime"),d=n.add("server"),x=n.add("ready"),f=n.add("open");n.render();let g=null;try{c.start("checking\u2026");let a=$();if(a&&F(D(a)))g=a,c.done(`v${a}`);else{c.start("downloading engine (~6 MB)\u2026");let{runRuntime:h}=await import("./runtime-WKMNKYTN.js");n.pause(),await h(["install"],{}),n.resume(),g=$(),c.done(g?`v${g}`:"installed")}}catch(a){c.fail(m(a)),n.finish(),process.exit(1)}let o=i,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:h}=await import("./daemon-3J2SAVQZ.js");n.pause(),await h({port:i,force:!0}),n.resume();let R=b();o=v(R)?R.bridgePort:i,p="daemon-installed",d.done(`daemon registered (port ${o})`)}catch(h){n.resume(),d.start("daemon unavailable, starting standalone server\u2026"),o=await C(i),p="standalone",d.done(`standalone (port ${o}) \u2014 ${m(h)}`)}}else d.start("starting standalone server\u2026"),o=await C(i),p="standalone",d.done(`standalone (port ${o})`)}catch(a){d.fail(m(a)),n.finish(),process.exit(1)}try{if(x.start("waiting for bridge\u2026"),!await V(o,U))throw new Error(`bridge never came online on port ${o}`);x.done(`ws://localhost:${o}`)}catch(a){x.fail(m(a)),n.finish(),process.exit(1)}let w=`http://localhost:${o}/`;if(r){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 ${m(a)})`)}n.finish(),p==="standalone"?(console.log(`
|
|
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 i=new B(`ws://127.0.0.1:${t}`,{handshakeTimeout:e}),r=!1,n=u=>{if(!r){r=!0;try{i.close()}catch{}s(u)}};i.once("open",()=>n(!0)),i.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(i=>setTimeout(i,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 i=Date.now()+I;for(;Date.now()<i;){let r=b();if(v(r))return r.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 m(t){return t instanceof Error?t.message:String(t)}export{Z as runStart};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! sootsim v0.
|
|
2
|
-
import"./chunk-
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import"./chunk-B3RAGRK6.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-
|
|
29
|
+
`),process.exit(0)),l)await b(t,r,c,a);else if(f){let{runDetox:e}=await import("./detox-Z2OSCIQU.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-34YCVQDB.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};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{a as k}from"./chunk-URSEYCC5.js";import{c as b,e as v,i as w}from"./chunk-ZERYEI3L.js";import"./chunk-PERKPZ7T.js";import"./chunk-ERLA3F77.js";import"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";async function z(e,o){if((e.includes("--help")||e.includes("-h"))&&(console.log(`
|
|
3
|
+
sootsim three-mode \u2014 toggle the 3d device stage
|
|
4
|
+
|
|
5
|
+
usage:
|
|
6
|
+
sootsim three-mode [on|off|toggle]
|
|
7
|
+
sootsim three-mode configure [options]
|
|
8
|
+
sootsim 3d-mode [on|off|toggle]
|
|
9
|
+
|
|
10
|
+
arguments:
|
|
11
|
+
on enable 3d mode
|
|
12
|
+
off disable 3d mode
|
|
13
|
+
toggle flip the current state (default)
|
|
14
|
+
|
|
15
|
+
configure options:
|
|
16
|
+
--background <id> set the 3d background
|
|
17
|
+
--colorway <id> set the phone colorway
|
|
18
|
+
--script <id> apply a camera preset pose
|
|
19
|
+
--progress <0..1> script progress to sample (default: 1)
|
|
20
|
+
--animate run the script instead of sampling one frame
|
|
21
|
+
--slow run the script slowly when --animate is set
|
|
22
|
+
--environment on|off enable or disable environment objects
|
|
23
|
+
--env-shape <id> orb | pill | diamond | pane
|
|
24
|
+
--env-spread <id> tight | medium | wide
|
|
25
|
+
--env-size <id> small | medium | large
|
|
26
|
+
--env-color <id> peach | gold | mint | sky | violet
|
|
27
|
+
--env-glow on|off enable or disable environment glow
|
|
28
|
+
--env-plastic on|off enable or disable environment plastic material
|
|
29
|
+
--room on|off enable or disable the room effect
|
|
30
|
+
--bokeh on|off enable or disable bokeh
|
|
31
|
+
--reset-pose return to the default hero pose before other changes
|
|
32
|
+
|
|
33
|
+
examples:
|
|
34
|
+
sootsim three-mode
|
|
35
|
+
sootsim three-mode on
|
|
36
|
+
sootsim three-mode configure --script hero-arc --background gradient-neon
|
|
37
|
+
sootsim three-mode configure --environment on --env-shape pane --room on
|
|
38
|
+
sootsim 3d-mode off
|
|
39
|
+
`),process.exit(0)),y(e)){await M(e,o);return}await k(e,o,{modeKey:"threeMode",displayName:"three-mode",actionId:"toggle-three-mode"})}function y(e){return e[0]==="configure"||e.some(o=>["--background","--colorway","--script","--progress","--animate","--slow","--environment","--env-shape","--env-spread","--env-size","--env-color","--env-glow","--env-plastic","--room","--bokeh","--reset-pose"].includes(o))}async function M(e,o){let n=b(e,{port:o.port,stripBooleanFlags:["--animate","--slow","--reset-pose"],stripValueFlags:["--background","--colorway","--script","--progress","--environment","--env-shape","--env-spread","--env-size","--env-color","--env-glow","--env-plastic","--room","--bokeh"]}),a=B(e),t=v({...n,commandTimeoutMs:8e3});try{let d=await w(t,"SootSim.bridges.threeMode.configure",a);console.log(` three-mode: configured (${$(d)})`)}finally{t.close()}}function B(e){let o=r=>e.find((i,c)=>e[c-1]===r),n={},a=o("--colorway");a&&(n.colorway=a);let t=o("--background");t&&(n.background=t);let d=s(o("--room"),"--room");d!==void 0&&(n.room=d);let m=s(o("--bokeh"),"--bokeh");m!==void 0&&(n.bokeh=m),e.includes("--reset-pose")&&(n.resetPose=!0);let p=s(o("--environment"),"--environment"),f={},l={};for(let[r,i]of[["--env-shape","shape"],["--env-spread","spread"],["--env-size","size"],["--env-color","color"]]){let c=o(r);c&&(f[i]=c)}let u=s(o("--env-glow"),"--env-glow");u!==void 0&&(l.glow=u);let g=s(o("--env-plastic"),"--env-plastic");g!==void 0&&(l.plastic=g),(p!==void 0||Object.keys(f).length>0||Object.keys(l).length>0)&&(n.environment=p===!1?!1:{pins:f,effects:l});let h=o("--script");if(h){let r=o("--progress"),i=r===void 0?1:Number.parseFloat(r);if(!Number.isFinite(i))throw new Error(`--progress expects a number from 0 to 1, got "${r}"`);n.script={id:h,progress:i,animate:e.includes("--animate"),slow:e.includes("--slow")}}return n}function s(e,o){if(e===void 0)return;let n=e.toLowerCase();if(["on","true","yes","1"].includes(n))return!0;if(["off","false","no","0"].includes(n))return!1;throw new Error(`${o} expects on or off, got "${e}"`)}function $(e){return[`ready=${!!e.ready}`,`background=${String(e.background??"unknown")}`,`colorway=${String(e.colorway??"unknown")}`,`environment=${e.environmentActive?"on":"off"}`,`room=${e.room?"on":"off"}`,`bokeh=${e.bokeh?"on":"off"}`].join(", ")}export{z as runThreeMode};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{c as m,e as d,h as s}from"./chunk-ZERYEI3L.js";import"./chunk-PERKPZ7T.js";import"./chunk-ERLA3F77.js";import"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";import{writeFileSync as g}from"fs";function u(){console.log(`
|
|
3
|
+
sootsim timeline \u2014 control the semantic event timeline
|
|
4
|
+
|
|
5
|
+
usage:
|
|
6
|
+
sootsim timeline <subcommand> [args]
|
|
7
|
+
|
|
8
|
+
subcommands:
|
|
9
|
+
status show enabled kinds and ring sizes
|
|
10
|
+
start [kinds] enable kinds (csv); 'all' for every opt-in
|
|
11
|
+
stop [kinds] disable kinds (csv); 'all' for every kind
|
|
12
|
+
clear drop all events + cursors
|
|
13
|
+
dump <file> write current merged ring to JSON
|
|
14
|
+
|
|
15
|
+
note: cheap kinds (console, fetch, app-launch, keyboard, screen, alert,
|
|
16
|
+
toast, notification, route, shell, actionsheet, picker, react-commit) record at all
|
|
17
|
+
times. start/stop only need to be used for opt-in kinds (scroll, gesture,
|
|
18
|
+
text-input, reanimated, animation).
|
|
19
|
+
|
|
20
|
+
read the timeline with: sootsim what-happened
|
|
21
|
+
`)}async function h(o,p){let n=m(o,{port:p.port,stripBooleanFlags:["--json","--help","-h"]}),l=n.positional[0];(!l||o.includes("--help")||o.includes("-h"))&&(u(),process.exit(0));let a=o.includes("--json"),t=d(n),r=n.positional.slice(1),i=r[0]?r[0].split(",").map(e=>e.trim()).filter(Boolean):[];try{switch(l){case"status":{let e=await s(t,"SootSim.bridges.timeline.status");console.log(JSON.stringify(e,null,a?0:2));break}case"start":case"enable":{i.length===0&&i.push("all"),await s(t,"SootSim.bridges.timeline.enable",...i);let e=await s(t,"SootSim.bridges.timeline.status");console.log(JSON.stringify(e,null,a?0:2));break}case"stop":case"disable":{i.length===0&&i.push("all"),await s(t,"SootSim.bridges.timeline.disable",...i);let e=await s(t,"SootSim.bridges.timeline.status");console.log(JSON.stringify(e,null,a?0:2));break}case"clear":{await s(t,"SootSim.bridges.timeline.clear"),console.log(" cleared");break}case"dump":{let e=r[0];e||(console.error(" usage: sootsim timeline dump <file>"),process.exit(1));let c=await s(t,"SootSim.bridges.timeline.recent",{limit:1e6});g(e,JSON.stringify(c.events,null,2)+`
|
|
22
|
+
`),console.log(` wrote ${c.events.length} event(s) to ${e}`);break}default:console.error(` unknown subcommand: ${l}`),u(),process.exit(1)}}finally{t.close()}}export{h as runTimeline};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{a,b,c}from"./chunk-5FLDI6CV.js";import"./chunk-CX3ZIPD3.js";import"./chunk-JMU5IGIU.js";import"./chunk-S74RCIVB.js";import"./chunk-WFXYY3DU.js";import"./chunk-4IO3D5XG.js";import"./chunk-ZERYEI3L.js";import"./chunk-PERKPZ7T.js";import"./chunk-ERLA3F77.js";import"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";export{a as resolveDefaultUploadOrigin,b as resolvePublicPreviewOrigin,c as runUpload};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{c as w,e as b,h as d}from"./chunk-ZERYEI3L.js";import{b as S}from"./chunk-PERKPZ7T.js";import"./chunk-ERLA3F77.js";import"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";function T(n){let e=[];for(let t=0;t<n.length;t++)if(n[t]==="--since"&&t+1<n.length){e.push(t,t+1);let o=n[t+1].trim(),i=/^(\d+(?:\.\d+)?)(ms|s|m)?$/.exec(o);if(i){let l=Number(i[1]),u=i[2]??"ms",r=u==="s"?l*1e3:u==="m"?l*6e4:l;return{since:Date.now()-r,consumed:e}}let s=Number(o);if(Number.isFinite(s)&&s>1e12)return{since:s,consumed:e}}return{consumed:e}}function x(n){let e=[];for(let t=0;t<n.length;t++)if(n[t]==="--kinds"&&t+1<n.length)return e.push(t,t+1),{kinds:n[t+1].split(",").map(o=>o.trim()).filter(Boolean),consumed:e};return{consumed:e}}function A(n){let e=[];for(let t=0;t<n.length;t++)if(n[t]==="--limit"&&t+1<n.length){e.push(t,t+1);let o=Number(n[t+1]);if(Number.isFinite(o)&&o>0)return{limit:o,consumed:e}}return{consumed:e}}function M(n,e){if(e===null)return new Date(n).toLocaleTimeString();let t=(n-e)/1e3;return`${t>=0?"+":""}${t.toFixed(2)}s`}function E(n,e){switch(n){case"app-launch":return e.phase==="launch"?`launch ${e.appName??e.toAppId??""}`:`dismiss ${e.appName??e.fromAppId??""} \u2192 ${e.toAppId??""}`;case"toast":return`"${e.text??""}"${e.durationMs?` (${e.durationMs}ms)`:""}`;case"keyboard":return`${e.phase??"?"}${e.heightPx?` h=${e.heightPx}`:""}${e.mode?` ${e.mode}`:""}`;case"screen":return`${e.phase??"?"} ${e.name??e.activeName??""}`;case"route":return`${e.phase??"?"} ${e.path??e.pathname??""}`;case"alert":case"actionsheet":case"picker":return`${e.phase??"?"} ${e.title??e.message??""}`;case"notification":return`${e.title??""}${e.body?` \u2014 ${e.body}`:""}`;case"fetch":return`${e.method??"GET"} ${e.url??""}${e.status?` -> ${e.status}`:""}`;case"console":return`${e.level??"log"}: ${(e.message??"").toString().slice(0,120)}`;case"shell":return`${e.event??e.type??e.phase??""}`;case"scroll":return`${e.phase??"?"} ${e.target??""}`;case"gesture":return`${e.phase??"?"} ${e.type??""}`;case"text-input":return`${e.phase??"?"}${e.value!==void 0?` "${String(e.value).slice(0,40)}"`:""}`;case"react-commit":{let t=e.slowest;return`${e.fiberCount??"?"} fibers ${e.durationMs??"?"}ms${t?.displayName?` \xB7 ${t.displayName} ${t.durationMs??"?"}ms`:""}`}case"reanimated":case"animation":return`${e.kind??""} ${e.target??""}${e.durationMs?` ${e.durationMs}ms`:""}`}}function y(n,e){let t=M(n.t,e).padStart(8),o=n.context.padEnd(6),i=`[${n.kind}]`.padEnd(15),s="",l=n.data;return l&&typeof l=="object"&&(s=E(n.kind,l)),` ${t} ${o} ${i} ${s}`}function k(n){let e=[],t={label:"initial state",events:[],startedAt:n[0]?.t??null};e.push(t);for(let o of n)if(t.events.push(o),o.kind==="screen"||o.kind==="route"){let i=o.data,s=i?.phase;if(!s||s==="enter"||s==="appear"||s==="active"){let l=i?.name||i?.activeName||i?.path||i?.pathname||o.kind;e.length===1&&t.events.length===1?t.label=`${o.kind}: ${l}`:(t={label:`${o.kind}: ${l}`,events:[],startedAt:o.t},e.push(t))}}return e}function R(n){if(n.total===0)return"nothing recorded";let e=[],t=["error","warning","console","fetch","toast","alert","actionsheet","picker","notification","screen","route","keyboard","app-launch","shell","scroll","gesture","text-input","react-commit","animation","reanimated"],o=new Set;for(let i of t){let s=n.byKind[i];s&&(e.push(`${s} ${i}${s===1?"":"s"}`),o.add(i))}for(let[i,s]of Object.entries(n.byKind))!o.has(i)&&s&&e.push(`${s} ${i}${s===1?"":"s"}`);return e.join(" \xB7 ")}async function B(n,e){let t=w(n,{port:e.port,stripBooleanFlags:["--summary","--all","--json","--no-advance","--help","-h","--flow"],stripValueFlags:["--since","--kinds","--limit"]});(n.includes("--help")||n.includes("-h"))&&(console.log(`
|
|
3
|
+
sootsim what-happened \u2014 show recent events from the semantic timeline
|
|
4
|
+
|
|
5
|
+
usage:
|
|
6
|
+
sootsim what-happened # since last CLI call
|
|
7
|
+
sootsim what-happened --summary # one-line counts
|
|
8
|
+
sootsim what-happened --all # full ring (ignore cursor)
|
|
9
|
+
sootsim what-happened --since 5s # absolute window
|
|
10
|
+
sootsim what-happened --kinds toast,fetch
|
|
11
|
+
sootsim what-happened --limit 50
|
|
12
|
+
sootsim what-happened --json
|
|
13
|
+
sootsim what-happened --no-advance # don't advance cursor after read
|
|
14
|
+
`),process.exit(0));let o=n.includes("--summary"),i=n.includes("--flow"),s=n.includes("--all"),l=n.includes("--json"),u=n.includes("--no-advance"),{since:r}=T(n),{kinds:f}=x(n),{limit:F}=A(n),$=S(),v={limit:F??200,...f&&f.length?{kinds:f}:{},...r!==void 0?{since:r}:s?{}:{sinceCursor:$}},m=b(t);try{if(o){let c=await d(m,"SootSim.bridges.timeline.summary",v);if(l)console.log(JSON.stringify(c));else{let p=s?"all time":r!==void 0?`last ${((Date.now()-r)/1e3).toFixed(1)}s`:"since last call";console.log(` ${p}: ${R(c)}`)}!u&&!s&&c.lastAt&&await d(m,"SootSim.bridges.timeline.cursorAdvance",$,c.lastAt);return}let a=await d(m,"SootSim.bridges.timeline.recent",v);if(l)console.log(JSON.stringify(i?k(a.events):a,null,2));else if(a.events.length===0)console.log(s?" no events recorded":r!==void 0?" no events in window":" no new events since last call");else if(i){let c=a.events[0]?.t??null,p=k(a.events),g=s?`\u2500\u2500\u2500 ${a.events.length} event(s) total \u2014 flow view \u2500\u2500\u2500`:r!==void 0?`\u2500\u2500\u2500 ${a.events.length} event(s) in last ${((Date.now()-r)/1e3).toFixed(1)}s \u2014 flow view \u2500\u2500\u2500`:`\u2500\u2500\u2500 ${a.events.length} event(s) since last call \u2014 flow view \u2500\u2500\u2500`;console.log(` ${g}`);for(let h of p){console.log(`
|
|
15
|
+
\u2500\u2500 ${h.label} (${h.events.length} event${h.events.length===1?"":"s"}) \u2500\u2500`);for(let N of h.events)console.log(y(N,c))}}else{let c=a.events[0]?.t??null,p=s?`\u2500\u2500\u2500 ${a.events.length} event(s) total \u2500\u2500\u2500`:r!==void 0?`\u2500\u2500\u2500 ${a.events.length} event(s) in last ${((Date.now()-r)/1e3).toFixed(1)}s \u2500\u2500\u2500`:`\u2500\u2500\u2500 ${a.events.length} event(s) since last call \u2500\u2500\u2500`;console.log(` ${p}`);for(let g of a.events)console.log(y(g,c))}!u&&!s&&a.watermark>0&&await d(m,"SootSim.bridges.timeline.cursorAdvance",$,a.watermark)}finally{m.close()}}export{B as runWhatHappened};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{d as n}from"./chunk-WFXYY3DU.js";import"./chunk-PN6FWLD4.js";import"./chunk-B3RAGRK6.js";async function s(){let o=await n();o?.token||(console.log(" not signed in"),process.exit(1));let e=o.user;console.log(` ${e?.email||e?.name||e?.id||"signed in"}`),console.log(` origin: ${o.origin}`),console.log(` updated: ${o.updatedAt}`)}export{s as runWhoami};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -47,6 +47,9 @@ var import_ws = require("ws");
|
|
|
47
47
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
48
48
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
49
49
|
|
|
50
|
+
// src/home-paths.ts
|
|
51
|
+
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
52
|
+
|
|
50
53
|
// src/attached-projects.ts
|
|
51
54
|
var COST_HISTORY_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
52
55
|
|
|
@@ -190,6 +193,8 @@ var AgentDaemonClient = class {
|
|
|
190
193
|
});
|
|
191
194
|
this.ws.on("message", (data) => this.handleMessage(data));
|
|
192
195
|
this.ws.on("close", () => this.handleClose());
|
|
196
|
+
this.ws.on("error", () => {
|
|
197
|
+
});
|
|
193
198
|
}
|
|
194
199
|
async waitReady() {
|
|
195
200
|
return this.ready;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.
|
|
1
|
+
/*! sootsim v0.1.37 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -49,7 +49,7 @@ module.exports = __toCommonJS(agent_sessions_exports);
|
|
|
49
49
|
var import_node_child_process = require("node:child_process");
|
|
50
50
|
var import_node_crypto2 = require("node:crypto");
|
|
51
51
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
52
|
-
var
|
|
52
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
53
53
|
var import_node_readline = __toESM(require("node:readline"), 1);
|
|
54
54
|
|
|
55
55
|
// src/agent-events.ts
|
|
@@ -94,36 +94,38 @@ function encodeAgentPromptEnvelope(input) {
|
|
|
94
94
|
// src/attached-projects.ts
|
|
95
95
|
var import_node_crypto = require("node:crypto");
|
|
96
96
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
97
|
-
var
|
|
97
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
98
|
+
|
|
99
|
+
// src/home-paths.ts
|
|
100
|
+
var import_node_os = require("node:os");
|
|
98
101
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
102
|
+
var SOOTSIM_HOME_ENV = "SOOTSIM_HOME";
|
|
103
|
+
function sootsimHomeDir() {
|
|
104
|
+
const override = process.env[SOOTSIM_HOME_ENV];
|
|
105
|
+
if (override && override.length > 0) return import_node_path.default.resolve(override);
|
|
106
|
+
return import_node_path.default.join((0, import_node_os.homedir)(), ".sootsim");
|
|
107
|
+
}
|
|
108
|
+
function electronDir() {
|
|
109
|
+
return import_node_path.default.join(sootsimHomeDir(), "electron");
|
|
110
|
+
}
|
|
111
|
+
function electronUserDataDir() {
|
|
112
|
+
return import_node_path.default.join(electronDir(), "userData");
|
|
113
|
+
}
|
|
114
|
+
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
115
|
+
|
|
116
|
+
// src/attached-projects.ts
|
|
99
117
|
var overrideDir = null;
|
|
100
118
|
function userDataDir() {
|
|
101
119
|
if (overrideDir) return overrideDir;
|
|
102
120
|
const fromEnv = process.env.SOOTSIM_USER_DATA_DIR;
|
|
103
121
|
if (fromEnv) return fromEnv;
|
|
104
|
-
|
|
105
|
-
const electron = require("electron");
|
|
106
|
-
if (electron.app?.getPath) return electron.app.getPath("userData");
|
|
107
|
-
} catch {
|
|
108
|
-
}
|
|
109
|
-
return platformDefaultUserDataDir();
|
|
110
|
-
}
|
|
111
|
-
function platformDefaultUserDataDir() {
|
|
112
|
-
const home = import_node_os.default.homedir();
|
|
113
|
-
if (process.platform === "darwin") {
|
|
114
|
-
return import_node_path.default.join(home, "Library", "Application Support", "sootsim");
|
|
115
|
-
}
|
|
116
|
-
if (process.platform === "win32") {
|
|
117
|
-
return import_node_path.default.join(process.env.APPDATA || home, "sootsim");
|
|
118
|
-
}
|
|
119
|
-
const xdg = process.env.XDG_CONFIG_HOME || import_node_path.default.join(home, ".config");
|
|
120
|
-
return import_node_path.default.join(xdg, "sootsim");
|
|
122
|
+
return electronUserDataDir();
|
|
121
123
|
}
|
|
122
124
|
function getUserDataDir() {
|
|
123
125
|
return userDataDir();
|
|
124
126
|
}
|
|
125
127
|
function storeFile() {
|
|
126
|
-
return
|
|
128
|
+
return import_node_path2.default.join(userDataDir(), "attached-projects.json");
|
|
127
129
|
}
|
|
128
130
|
function cloneEmpty() {
|
|
129
131
|
return {
|
|
@@ -165,7 +167,7 @@ function loadStore() {
|
|
|
165
167
|
}
|
|
166
168
|
function writeStore(store) {
|
|
167
169
|
const file = storeFile();
|
|
168
|
-
import_node_fs.default.mkdirSync(
|
|
170
|
+
import_node_fs.default.mkdirSync(import_node_path2.default.dirname(file), { recursive: true });
|
|
169
171
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
170
172
|
const fd = import_node_fs.default.openSync(tmp, "w", 384);
|
|
171
173
|
try {
|
|
@@ -259,16 +261,16 @@ function updateSessionStatus(id, patch) {
|
|
|
259
261
|
|
|
260
262
|
// src/agent-sessions.ts
|
|
261
263
|
function sessionDir(sessionId) {
|
|
262
|
-
return
|
|
264
|
+
return import_node_path3.default.join(getUserDataDir(), "sessions", sessionId);
|
|
263
265
|
}
|
|
264
266
|
function promptFifoPath(sessionId) {
|
|
265
|
-
return
|
|
267
|
+
return import_node_path3.default.join(sessionDir(sessionId), "prompt.in");
|
|
266
268
|
}
|
|
267
269
|
function eventsFifoPath(sessionId) {
|
|
268
|
-
return
|
|
270
|
+
return import_node_path3.default.join(sessionDir(sessionId), "events.out");
|
|
269
271
|
}
|
|
270
272
|
function transcriptPath(sessionId) {
|
|
271
|
-
return
|
|
273
|
+
return import_node_path3.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
|
|
272
274
|
}
|
|
273
275
|
function pidIsAlive(pid, sessionId) {
|
|
274
276
|
if (!pid) return false;
|
|
@@ -290,8 +292,8 @@ function resolveSootsimInvocation() {
|
|
|
290
292
|
const resourcesPath = process.resourcesPath;
|
|
291
293
|
if (resourcesPath) {
|
|
292
294
|
const candidates = [
|
|
293
|
-
|
|
294
|
-
|
|
295
|
+
import_node_path3.default.join(resourcesPath, "bin", "sootsim"),
|
|
296
|
+
import_node_path3.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
|
|
295
297
|
];
|
|
296
298
|
for (const c of candidates) {
|
|
297
299
|
if (import_node_fs2.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
|
|
@@ -317,12 +319,12 @@ function tryWorkspaceSootsim() {
|
|
|
317
319
|
const sootsimDir = resolveSootsimPackageDir();
|
|
318
320
|
if (!sootsimDir) return null;
|
|
319
321
|
const binaryName = `sootsim-${process.platform}-${process.arch}`;
|
|
320
|
-
const distBinary =
|
|
322
|
+
const distBinary = import_node_path3.default.join(sootsimDir, "dist-bin", binaryName);
|
|
321
323
|
if (import_node_fs2.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
|
|
322
|
-
const distBin =
|
|
324
|
+
const distBin = import_node_path3.default.join(sootsimDir, "dist-cli", "bin.js");
|
|
323
325
|
if (import_node_fs2.default.existsSync(distBin)) {
|
|
324
326
|
try {
|
|
325
|
-
const src =
|
|
327
|
+
const src = import_node_path3.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
|
|
326
328
|
if (import_node_fs2.default.existsSync(src)) {
|
|
327
329
|
const srcMtime = import_node_fs2.default.statSync(src).mtimeMs;
|
|
328
330
|
const buildMtime = import_node_fs2.default.statSync(distBin).mtimeMs;
|
|
@@ -344,14 +346,14 @@ function tryWorkspaceSootsim() {
|
|
|
344
346
|
function resolveSootsimPackageDir() {
|
|
345
347
|
try {
|
|
346
348
|
const resolved = require.resolve("sootsim/package.json");
|
|
347
|
-
return
|
|
349
|
+
return import_node_path3.default.dirname(resolved);
|
|
348
350
|
} catch {
|
|
349
351
|
}
|
|
350
352
|
const here = fileFromImportMeta();
|
|
351
353
|
if (!here) return null;
|
|
352
|
-
let cur =
|
|
354
|
+
let cur = import_node_path3.default.dirname(here);
|
|
353
355
|
for (let i = 0; i < 8; i++) {
|
|
354
|
-
const pkg =
|
|
356
|
+
const pkg = import_node_path3.default.join(cur, "package.json");
|
|
355
357
|
try {
|
|
356
358
|
if (import_node_fs2.default.existsSync(pkg)) {
|
|
357
359
|
const parsed = JSON.parse(import_node_fs2.default.readFileSync(pkg, "utf8"));
|
|
@@ -359,7 +361,7 @@ function resolveSootsimPackageDir() {
|
|
|
359
361
|
}
|
|
360
362
|
} catch {
|
|
361
363
|
}
|
|
362
|
-
const parent =
|
|
364
|
+
const parent = import_node_path3.default.dirname(cur);
|
|
363
365
|
if (parent === cur) break;
|
|
364
366
|
cur = parent;
|
|
365
367
|
}
|
|
@@ -375,13 +377,13 @@ function fileFromImportMeta() {
|
|
|
375
377
|
}
|
|
376
378
|
}
|
|
377
379
|
async function withStartLock(projectId, provider, fn) {
|
|
378
|
-
const lockDir =
|
|
380
|
+
const lockDir = import_node_path3.default.join(getUserDataDir(), "locks");
|
|
379
381
|
import_node_fs2.default.mkdirSync(lockDir, { recursive: true });
|
|
380
382
|
try {
|
|
381
383
|
import_node_fs2.default.chmodSync(lockDir, 448);
|
|
382
384
|
} catch {
|
|
383
385
|
}
|
|
384
|
-
const lockPath =
|
|
386
|
+
const lockPath = import_node_path3.default.join(lockDir, `start-${projectId}-${provider}.lock`);
|
|
385
387
|
const deadline = Date.now() + 4e3;
|
|
386
388
|
let fd = null;
|
|
387
389
|
while (fd === null) {
|
|
@@ -432,7 +434,7 @@ function isProcessAlive(pid) {
|
|
|
432
434
|
}
|
|
433
435
|
}
|
|
434
436
|
function mkfifoSync(p) {
|
|
435
|
-
const parent =
|
|
437
|
+
const parent = import_node_path3.default.dirname(p);
|
|
436
438
|
import_node_fs2.default.mkdirSync(parent, { recursive: true });
|
|
437
439
|
try {
|
|
438
440
|
import_node_fs2.default.chmodSync(parent, 448);
|
|
@@ -497,7 +499,7 @@ async function startSession(opts) {
|
|
|
497
499
|
const transcript = transcriptPath(session.id);
|
|
498
500
|
mkfifoSync(promptIn);
|
|
499
501
|
mkfifoSync(eventsOut);
|
|
500
|
-
const transcriptDir =
|
|
502
|
+
const transcriptDir = import_node_path3.default.dirname(transcript);
|
|
501
503
|
import_node_fs2.default.mkdirSync(transcriptDir, { recursive: true });
|
|
502
504
|
try {
|
|
503
505
|
import_node_fs2.default.chmodSync(transcriptDir, 448);
|
|
@@ -524,6 +526,7 @@ async function startSession(opts) {
|
|
|
524
526
|
];
|
|
525
527
|
if (opts.codexBin) wrapperArgs.push("--codex-bin", opts.codexBin);
|
|
526
528
|
if (opts.claudeBin) wrapperArgs.push("--claude-bin", opts.claudeBin);
|
|
529
|
+
if (opts.freshThread) wrapperArgs.push("--fresh-thread");
|
|
527
530
|
if (claudeSessionUuid) {
|
|
528
531
|
wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
|
|
529
532
|
}
|