sootsim 0.1.185 → 0.1.186

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 (157) hide show
  1. package/dist-cli/bin.js +3 -3
  2. package/dist-cli/chunks/{agent-VF756RZU.js → agent-HOCS7BA7.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-IAFL7ROV.js → agent-wrapper-OFIKO65K.js} +2 -2
  4. package/dist-cli/chunks/{app-fonts-VWLEC7ZA.js → app-fonts-PXVMBZZ7.js} +2 -2
  5. package/dist-cli/chunks/{assert-I55QVGG7.js → assert-OZS6AXZE.js} +2 -2
  6. package/dist-cli/chunks/beta-LUMNYREE.js +2 -0
  7. package/dist-cli/chunks/{camera-CYYBJH7W.js → camera-QJ2PKIJB.js} +2 -2
  8. package/dist-cli/chunks/{chunk-2T73IGB2.js → chunk-2B2D2EBR.js} +2 -2
  9. package/dist-cli/chunks/{chunk-ARNLQPMQ.js → chunk-353E6UCU.js} +2 -2
  10. package/dist-cli/chunks/chunk-3ISH4ZRW.js +1 -0
  11. package/dist-cli/chunks/{chunk-PIUKLO3W.js → chunk-4HVMPXJZ.js} +1 -1
  12. package/dist-cli/chunks/chunk-5TTEOJ4A.js +1 -0
  13. package/dist-cli/chunks/chunk-5XIRXMOS.js +971 -0
  14. package/dist-cli/chunks/chunk-6MJVRIUP.js +118 -0
  15. package/dist-cli/chunks/{chunk-EXFB33AZ.js → chunk-6OQVIQY7.js} +2 -2
  16. package/dist-cli/chunks/chunk-BU5CRHHR.js +24 -0
  17. package/dist-cli/chunks/{chunk-TUF6EPCQ.js → chunk-DPXVA7ZF.js} +2 -2
  18. package/dist-cli/chunks/{chunk-R4KLD4P4.js → chunk-FN64EREO.js} +2 -2
  19. package/dist-cli/chunks/{chunk-BI56RR3G.js → chunk-FUHNIWFL.js} +4 -4
  20. package/dist-cli/chunks/{chunk-WEJKLJ4B.js → chunk-GNGEYMS3.js} +2 -2
  21. package/dist-cli/chunks/{chunk-QTFCJYBF.js → chunk-I65LTDPY.js} +3 -3
  22. package/dist-cli/chunks/{chunk-BMCBPMTC.js → chunk-INIASYOZ.js} +1 -1
  23. package/dist-cli/chunks/{chunk-FUHXL6BW.js → chunk-KNICGV7H.js} +1 -1
  24. package/dist-cli/chunks/{chunk-E5DE33BU.js → chunk-LV7DFIBL.js} +1 -1
  25. package/dist-cli/chunks/{chunk-M3P67TBN.js → chunk-MAGDSBXT.js} +1 -1
  26. package/dist-cli/chunks/chunk-MP4CRGWM.js +2 -0
  27. package/dist-cli/chunks/{chunk-MADEJDFD.js → chunk-MPUCQL3Q.js} +1 -1
  28. package/dist-cli/chunks/{chunk-FY6DJGOS.js → chunk-N3PLEUYD.js} +39 -15
  29. package/dist-cli/chunks/{chunk-CYBRFHPU.js → chunk-NYYP5QQK.js} +2 -2
  30. package/dist-cli/chunks/{chunk-4OUQAR34.js → chunk-O2SQQXUO.js} +1 -1
  31. package/dist-cli/chunks/{chunk-K2THZIVC.js → chunk-OMFESSKA.js} +1 -1
  32. package/dist-cli/chunks/{chunk-C3UEINOZ.js → chunk-P5UT637B.js} +2 -2
  33. package/dist-cli/chunks/{chunk-C63EVPDN.js → chunk-POOE26UD.js} +2 -2
  34. package/dist-cli/chunks/{chunk-HQG4DRQ3.js → chunk-PTUTIFWJ.js} +1 -1
  35. package/dist-cli/chunks/{chunk-IJP257WP.js → chunk-QBLTH2F6.js} +1 -1
  36. package/dist-cli/chunks/{chunk-LJ3SOZBF.js → chunk-RAY2ZSNI.js} +2 -2
  37. package/dist-cli/chunks/{chunk-DZLBZGHN.js → chunk-RDM3LVH2.js} +2 -2
  38. package/dist-cli/chunks/chunk-RP5CVR6O.js +382 -0
  39. package/dist-cli/chunks/{chunk-PKZNXDUJ.js → chunk-TYV3FMBE.js} +2 -2
  40. package/dist-cli/chunks/{chunk-4NUQVW5P.js → chunk-U3BTJLRM.js} +17 -6
  41. package/dist-cli/chunks/{chunk-QQ4NSPAD.js → chunk-UATE6GSA.js} +2 -2
  42. package/dist-cli/chunks/chunk-V434ATFM.js +13 -0
  43. package/dist-cli/chunks/{chunk-GX6MKIFC.js → chunk-VGAD3CMW.js} +1 -1
  44. package/dist-cli/chunks/{chunk-LI4RLX6B.js → chunk-VPUJQTEO.js} +1 -1
  45. package/dist-cli/chunks/chunk-WBPTJ3WC.js +5 -0
  46. package/dist-cli/chunks/{chunk-NL5IFN4T.js → chunk-WFSLSEGX.js} +2 -2
  47. package/dist-cli/chunks/{chunk-TFZO277G.js → chunk-XFQOFRYY.js} +1 -1
  48. package/dist-cli/chunks/{chunk-TNHF6BON.js → chunk-XQ6PPMM6.js} +1 -1
  49. package/dist-cli/chunks/{chunk-FHJTTB3W.js → chunk-YYZGAZQI.js} +2 -2
  50. package/dist-cli/chunks/{chunk-WBY4JJ2K.js → chunk-ZE2O7AA5.js} +2 -2
  51. package/dist-cli/chunks/{chunk-X4KS33ZC.js → chunk-ZJ64K2PL.js} +2 -2
  52. package/dist-cli/chunks/cli-version-474OBNTF.js +2 -0
  53. package/dist-cli/chunks/{compat-ZJA3N4ZT.js → compat-BNXJOVMU.js} +3 -3
  54. package/dist-cli/chunks/control-6LPRGKTF.js +2 -0
  55. package/dist-cli/chunks/{cpu-profile-ACSQMVXY.js → cpu-profile-3KXOGOJP.js} +2 -2
  56. package/dist-cli/chunks/daemon-OMT3RVU4.js +2 -0
  57. package/dist-cli/chunks/{debug-W2ZOVTQO.js → debug-B3MN6772.js} +11 -10
  58. package/dist-cli/chunks/{detox-ANJO6T27.js → detox-YKSX4DUO.js} +2 -2
  59. package/dist-cli/chunks/{device-KPPN4KYD.js → device-NZX6AKQI.js} +2 -2
  60. package/dist-cli/chunks/{diagnose-5PEJYGES.js → diagnose-26HE6KS5.js} +2 -2
  61. package/dist-cli/chunks/drivers-2PZC4QA3.js +2 -0
  62. package/dist-cli/chunks/{electron-U456QLSQ.js → electron-XEUWIM47.js} +3 -3
  63. package/dist-cli/chunks/flow-P22NDT6V.js +2 -0
  64. package/dist-cli/chunks/help-ECGL4JSP.js +2 -0
  65. package/dist-cli/chunks/{hints-MBBQLMQU.js → hints-C56M4PMW.js} +2 -2
  66. package/dist-cli/chunks/{home-paths-KQKYP2SE.js → home-paths-EYH3RBPS.js} +2 -2
  67. package/dist-cli/chunks/inspect-LJYG4WC6.js +2 -0
  68. package/dist-cli/chunks/{install-desktop-OR6ZJ43X.js → install-desktop-UWHLWFKB.js} +3 -3
  69. package/dist-cli/chunks/{keys-JSQMBUE7.js → keys-Q37NM52E.js} +2 -2
  70. package/dist-cli/chunks/{login-DVMWAI3G.js → login-6E6ZEJRF.js} +4 -4
  71. package/dist-cli/chunks/{logout-RIVPFE5N.js → logout-A7QHH6DQ.js} +2 -2
  72. package/dist-cli/chunks/{maestro-TX6FPTVH.js → maestro-YJRGFGDQ.js} +2 -2
  73. package/dist-cli/chunks/optional-demo-registry-OVWOHGTW.js +2 -0
  74. package/dist-cli/chunks/{preview-3AD7WNA6.js → preview-3OYFVL4A.js} +2 -2
  75. package/dist-cli/chunks/{profile-HY55VFNR.js → profile-5Z2YGBCJ.js} +2 -2
  76. package/dist-cli/chunks/{react-HDRCKCKV.js → react-ZNFFE3VQ.js} +2 -2
  77. package/dist-cli/chunks/{record-HW4C7QYN.js → record-V4CBW3GG.js} +2 -2
  78. package/dist-cli/chunks/runtime-OC6S2C22.js +2 -0
  79. package/dist-cli/chunks/{screenshot-XFR3QN5T.js → screenshot-QWMRWTIQ.js} +2 -2
  80. package/dist-cli/chunks/{screenshot-mode-Y5CVO267.js → screenshot-mode-36EUFBF5.js} +2 -2
  81. package/dist-cli/chunks/{screenshots-RKUL2ZZT.js → screenshots-LOS6WHZN.js} +2 -2
  82. package/dist-cli/chunks/{screenshots-capture-RVNF75ZD.js → screenshots-capture-6D6TBI6A.js} +2 -2
  83. package/dist-cli/chunks/{serve-QMRYLWL5.js → serve-YWGZ2JSI.js} +16 -16
  84. package/dist-cli/chunks/{setup-ELNJS7AI.js → setup-JS35KZ6P.js} +3 -3
  85. package/dist-cli/chunks/{skills-GPSJYS4W.js → skills-2TRDAXNC.js} +2 -2
  86. package/dist-cli/chunks/{slides-OCFNPIFG.js → slides-AO5MBP5Q.js} +2 -2
  87. package/dist-cli/chunks/store-HQKPCA6W.js +2 -0
  88. package/dist-cli/chunks/telemetry-I2H25VVF.js +2 -0
  89. package/dist-cli/chunks/{telemetry-KFZQUFG5.js → telemetry-MBWJUKBU.js} +2 -2
  90. package/dist-cli/chunks/{test-Z2HZXCZM.js → test-TRP2O6AP.js} +3 -3
  91. package/dist-cli/chunks/{three-mode-NKJFCDYS.js → three-mode-VVNOGAZT.js} +2 -2
  92. package/dist-cli/chunks/{timeline-PRGQMQRR.js → timeline-4WDFXUXB.js} +2 -2
  93. package/dist-cli/chunks/{upgrade-3NW7JRRX.js → upgrade-NHQRFD4J.js} +2 -2
  94. package/dist-cli/chunks/upload-6C2EC56N.js +2 -0
  95. package/dist-cli/chunks/{version-FDTZRIYT.js → version-T7O46MZL.js} +2 -2
  96. package/dist-cli/chunks/{web-4N5QQEQJ.js → web-7YW2ISLF.js} +2 -2
  97. package/dist-cli/chunks/{what-happened-IX2RRCOS.js → what-happened-IDOUXSFI.js} +2 -2
  98. package/dist-cli/chunks/{whoami-QZ42FYYF.js → whoami-DQBR3UTO.js} +2 -2
  99. package/dist-lib/agent-daemon-client.cjs +1 -1
  100. package/dist-lib/agent-events.cjs +1 -1
  101. package/dist-lib/agent-sessions.cjs +1 -1
  102. package/dist-lib/attached-projects.cjs +1 -1
  103. package/dist-lib/auth/shared-session.cjs +1 -1
  104. package/dist-lib/backend-origin.cjs +1 -1
  105. package/dist-lib/beta.cjs +1 -1
  106. package/dist-lib/beta.mjs +1 -1
  107. package/dist-lib/bridge-constants.cjs +1 -1
  108. package/dist-lib/cli-constants.cjs +1 -1
  109. package/dist-lib/config.cjs +1 -1
  110. package/dist-lib/detox/index.cjs +1 -1
  111. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  112. package/dist-lib/home-paths.cjs +2 -2
  113. package/dist-lib/host/bridge-host.cjs +77 -44
  114. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  115. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  116. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  117. package/dist-lib/host/websocket-proxy.cjs +1 -1
  118. package/dist-lib/index.cjs +28 -1
  119. package/dist-lib/jump-to-source-babel.cjs +1 -1
  120. package/dist-lib/menu.cjs +1 -1
  121. package/dist-lib/menu.mjs +1 -1
  122. package/dist-lib/metro.cjs +28 -1
  123. package/dist-lib/profiles.cjs +1 -1
  124. package/dist-lib/render-mode.cjs +1 -1
  125. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  126. package/dist-lib/sdk.cjs +38 -10
  127. package/dist-lib/sdk.mjs +38 -10
  128. package/dist-lib/skills.cjs +283 -254
  129. package/dist-lib/vite.cjs +28 -1
  130. package/package.json +1 -1
  131. package/src/home-paths.ts +8 -1
  132. package/src/host/bridge-host.ts +15 -1
  133. package/src/runtime-assets.ts +70 -0
  134. package/src/vite-plugin.ts +9 -0
  135. package/dist-cli/chunks/beta-X6YPQVZH.js +0 -2
  136. package/dist-cli/chunks/chunk-7OAUPGLN.js +0 -23
  137. package/dist-cli/chunks/chunk-IGJHME3T.js +0 -1
  138. package/dist-cli/chunks/chunk-JRL7PFNZ.js +0 -463
  139. package/dist-cli/chunks/chunk-KOKIECMB.js +0 -118
  140. package/dist-cli/chunks/chunk-OAHGYDJR.js +0 -13
  141. package/dist-cli/chunks/chunk-PDLQWZN4.js +0 -2
  142. package/dist-cli/chunks/chunk-SL6565MR.js +0 -1
  143. package/dist-cli/chunks/chunk-V4M2R6FZ.js +0 -2
  144. package/dist-cli/chunks/chunk-V5JEPE3P.js +0 -5
  145. package/dist-cli/chunks/chunk-XU5EMZ4B.js +0 -264
  146. package/dist-cli/chunks/cli-version-ICHQMND6.js +0 -2
  147. package/dist-cli/chunks/control-CZFSYSYG.js +0 -2
  148. package/dist-cli/chunks/daemon-337B4P3B.js +0 -2
  149. package/dist-cli/chunks/drivers-MSDIFHBD.js +0 -2
  150. package/dist-cli/chunks/flow-JL3SC6HC.js +0 -2
  151. package/dist-cli/chunks/help-PA4RTR5X.js +0 -2
  152. package/dist-cli/chunks/inspect-ZP5SM4EW.js +0 -987
  153. package/dist-cli/chunks/optional-demo-registry-ONYG6DUI.js +0 -2
  154. package/dist-cli/chunks/runtime-RHHPW5WO.js +0 -2
  155. package/dist-cli/chunks/store-MBKDUQEQ.js +0 -2
  156. package/dist-cli/chunks/telemetry-46XXIUEE.js +0 -2
  157. package/dist-cli/chunks/upload-QVDVJ6ZK.js +0 -2
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.185 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.186 | (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;
@@ -109,7 +109,32 @@ function isDaemonLockfileFresh(lock, now = Date.now()) {
109
109
  // src/runtime-assets.ts
110
110
  var import_fs = __toESM(require("fs"), 1);
111
111
  var import_path = __toESM(require("path"), 1);
112
+ var import_url = require("url");
112
113
  var SOOTSIM_RUNTIME_MISSING_MESSAGE = "[sootsim] no engine runtime installed \u2014 run `sootsim setup`, or `sootsim runtime install`";
114
+ var _monorepoRootCache;
115
+ function findMonorepoRoot() {
116
+ if (_monorepoRootCache !== void 0) return _monorepoRootCache;
117
+ let dir = import_path.default.dirname((0, import_url.fileURLToPath)(__sootsim_import_meta_url));
118
+ for (let i = 0; i < 12 && dir !== import_path.default.dirname(dir); i++) {
119
+ if (import_fs.default.existsSync(import_path.default.join(dir, "packages/sootsim-engine/package.json")) && import_fs.default.existsSync(import_path.default.join(dir, "public/sootsim"))) {
120
+ _monorepoRootCache = dir;
121
+ return dir;
122
+ }
123
+ dir = import_path.default.dirname(dir);
124
+ }
125
+ _monorepoRootCache = null;
126
+ return null;
127
+ }
128
+ function resolveDevCheckoutRuntimeRoot() {
129
+ if (process.env.SOOTSIM_HOME && readActiveRuntime()) return null;
130
+ const root = findMonorepoRoot();
131
+ if (!root) return null;
132
+ const devBuild = import_path.default.join(root, "public/sootsim");
133
+ if (import_fs.default.existsSync(import_path.default.join(devBuild, "index.html")) && import_fs.default.existsSync(import_path.default.join(devBuild, "engine/index.html")) && import_fs.default.existsSync(import_path.default.join(devBuild, "engine-tenant/worker.js"))) {
134
+ return devBuild;
135
+ }
136
+ return null;
137
+ }
113
138
  var MIME_TYPES = {
114
139
  ".js": "application/javascript",
115
140
  ".mjs": "application/javascript",
@@ -145,6 +170,8 @@ var ROOT_RUNTIME_PATHS = [
145
170
  "/preview-sw.js"
146
171
  ];
147
172
  function resolveActiveRuntimeRoot() {
173
+ const devRoot = resolveDevCheckoutRuntimeRoot();
174
+ if (devRoot) return devRoot;
148
175
  const active = readActiveRuntime();
149
176
  if (!active) return null;
150
177
  const dir = runtimeDir(active);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sootsim",
3
- "version": "0.1.185",
3
+ "version": "0.1.186",
4
4
  "description": "sootsim CLI + vite/metro plugins + skills registry. bridge client for driving the proprietary sootsim-engine over WebSocket.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "MIT",
package/src/home-paths.ts CHANGED
@@ -332,6 +332,12 @@ export interface DevBridgeLockfile {
332
332
  platform: NodeJS.Platform
333
333
  bridgePort: number
334
334
  runtimePort: number
335
+ /** http port of the vite shell dev server that owns this bridge (e.g. 5173).
336
+ * optional: lockfiles written before this field existed still parse, and
337
+ * readers fall back to the default shell URL. this is what lets the CLI
338
+ * resolve the shell base URL and the bridge port from the SAME world
339
+ * instead of mixing dev bridge + daemon runtime (the split-brain bug). */
340
+ shellPort?: number
335
341
  cwd: string
336
342
  startedAt: number
337
343
  heartbeatAt: number
@@ -387,7 +393,8 @@ export function readDevBridgeLockfile(): DevBridgeLockfile | null {
387
393
  typeof parsed.runtimePort === 'number' &&
388
394
  typeof parsed.cwd === 'string' &&
389
395
  typeof parsed.startedAt === 'number' &&
390
- typeof parsed.heartbeatAt === 'number'
396
+ typeof parsed.heartbeatAt === 'number' &&
397
+ (parsed.shellPort === undefined || typeof parsed.shellPort === 'number')
391
398
  ) {
392
399
  return parsed as DevBridgeLockfile
393
400
  }
@@ -30,6 +30,7 @@ import {
30
30
  type DevBridgeLockfile,
31
31
  type SharedConfig,
32
32
  } from '../home-paths.ts'
33
+ import { resolveDevCheckoutRuntimeRoot } from '../runtime-assets.ts'
33
34
  import { updateRuntimeToLatest } from '../runtime-delivery.ts'
34
35
  import { AgentHost, type AgentHostOptions } from './agent-host.ts'
35
36
  import {
@@ -224,6 +225,11 @@ export interface BridgeHostOptions {
224
225
  * this so local CLI commands prefer the live source bridge over a standalone
225
226
  * daemon or stale default-port listener. */
226
227
  writeDevLockfile?: boolean
228
+ /** resolve the http port of the vite shell dev server that hosts this
229
+ * bridge (e.g. 5173). called on every dev-lockfile write so the port
230
+ * fills in once the vite server is actually listening. only meaningful
231
+ * with writeDevLockfile. */
232
+ getShellPort?: () => number | null
227
233
  /** the sootbean origin this daemon's runtimes should talk to for auth,
228
234
  * billing, and preview uploads — inlined into served runtime html as
229
235
  * `window.__sootsimSootbeanOrigin`. without it the engine's origin.ts
@@ -397,6 +403,7 @@ export class SootSimBridgeHost {
397
403
  private automationSimActiveGraceMs: number
398
404
  private shouldWriteLockfile: boolean
399
405
  private shouldWriteDevLockfile: boolean
406
+ private getShellPort: (() => number | null) | null
400
407
  private sootbeanOrigin: string | null = null
401
408
  private effectivePort = 0
402
409
  private startedAt = 0
@@ -431,6 +438,7 @@ export class SootSimBridgeHost {
431
438
  // default off — callers that want the lockfile (sootsim serve) opt in.
432
439
  this.shouldWriteLockfile = opts.writeLockfile === true
433
440
  this.shouldWriteDevLockfile = opts.writeDevLockfile === true
441
+ this.getShellPort = opts.getShellPort ?? null
434
442
  // fallback freely on port collision regardless of who owns the lockfile.
435
443
  // serve.ts already refuses to start if a fresh daemon.json exists, so
436
444
  // two daemons can't race the lockfile. without this, an unrelated process
@@ -1164,12 +1172,14 @@ export class SootSimBridgeHost {
1164
1172
  }
1165
1173
 
1166
1174
  private buildDevLockfileSnapshot(): DevBridgeLockfile {
1175
+ const shellPort = this.getShellPort?.() ?? null
1167
1176
  return {
1168
1177
  schema: 1,
1169
1178
  pid: process.pid,
1170
1179
  platform: process.platform,
1171
1180
  bridgePort: this.effectivePort,
1172
1181
  runtimePort: this.effectivePort,
1182
+ ...(shellPort && shellPort > 0 ? { shellPort } : {}),
1173
1183
  cwd: process.cwd(),
1174
1184
  startedAt: this.startedAt,
1175
1185
  heartbeatAt: Date.now(),
@@ -1187,7 +1197,11 @@ export class SootSimBridgeHost {
1187
1197
 
1188
1198
  private refreshActiveRuntime() {
1189
1199
  this.activeRuntimeVersion = readActiveRuntime()
1190
- this.activeRuntimeDirPath = getActiveRuntimeDir()
1200
+ // mode boundary (see runtime-assets resolveDevCheckoutRuntimeRoot): inside
1201
+ // the soot monorepo dev checkout serve the fresh dev-stack build so local
1202
+ // engine edits reach previews without a publish; otherwise the installed
1203
+ // runtime. the version above stays the installed version for display.
1204
+ this.activeRuntimeDirPath = resolveDevCheckoutRuntimeRoot() ?? getActiveRuntimeDir()
1191
1205
  }
1192
1206
 
1193
1207
  private runServerScan(): Promise<DiscoveredServer[]> {
@@ -4,11 +4,78 @@
4
4
 
5
5
  import fs from 'fs'
6
6
  import path from 'path'
7
+ import { fileURLToPath } from 'url'
7
8
  import { readActiveRuntime, runtimeDir } from './home-paths'
8
9
 
9
10
  export const SOOTSIM_RUNTIME_MISSING_MESSAGE =
10
11
  '[sootsim] no engine runtime installed — run `sootsim setup`, or `sootsim runtime install`'
11
12
 
13
+ // --- dev-checkout mode boundary --------------------------------------------
14
+ //
15
+ // there is exactly one rule for which engine gets served: INSIDE the soot
16
+ // monorepo dev checkout the fresh dev-stack build (public/sootsim, kept current
17
+ // by `bun dev`'s watch:sootsim) IS the engine; OUTSIDE it (a published CLI in a
18
+ // user's project, or an isolated home) the installed runtime IS. this is a mode
19
+ // boundary, not a preference or a runtime fallback chain — the check is
20
+ // structural (the monorepo layout is present next to this module) and
21
+ // deterministic (the dev build's files exist). it exists because the daemon and
22
+ // the /__soot plugin otherwise serve ~/.sootsim/runtimes/<active>, a PUBLISHED
23
+ // runtime that `bun dev` never refreshes, so local engine edits are invisible
24
+ // until a manual publish — the silent trap that cost a full night of
25
+ // already-fixed bugs re-reproducing.
26
+ //
27
+ // the isolated CI headless path (scripts/local-publish-runtime.sh) sets
28
+ // SOOTSIM_HOME to a dedicated dir precisely to validate the published-runtime
29
+ // code path; keying off that EXISTING isolation env keeps it (and packaged
30
+ // electron with a custom home) on the installed runtime.
31
+ let _monorepoRootCache: string | null | undefined
32
+
33
+ function findMonorepoRoot(): string | null {
34
+ if (_monorepoRootCache !== undefined) return _monorepoRootCache
35
+ let dir = path.dirname(fileURLToPath(import.meta.url))
36
+ // walk up until we find the soot monorepo: it has packages/sootsim-engine and
37
+ // a public/sootsim dev-build output slot. bounded by the filesystem root.
38
+ for (let i = 0; i < 12 && dir !== path.dirname(dir); i++) {
39
+ if (
40
+ fs.existsSync(path.join(dir, 'packages/sootsim-engine/package.json')) &&
41
+ fs.existsSync(path.join(dir, 'public/sootsim'))
42
+ ) {
43
+ _monorepoRootCache = dir
44
+ return dir
45
+ }
46
+ dir = path.dirname(dir)
47
+ }
48
+ _monorepoRootCache = null
49
+ return null
50
+ }
51
+
52
+ /** the fresh dev-stack engine build to serve when running inside the soot
53
+ * monorepo dev checkout, or null when the installed runtime should serve
54
+ * (published CLI, packaged electron, or an isolated SOOTSIM_HOME). */
55
+ export function resolveDevCheckoutRuntimeRoot(): string | null {
56
+ // an explicit home that has a STAGED/active runtime is the isolation the
57
+ // CI/local-publish path sets up to validate the installed-runtime code path —
58
+ // honor that staged runtime. an explicit home with NO active runtime is just
59
+ // an isolated dev daemon (own lockfile, doesn't clobber ~/.sootsim), which
60
+ // still wants the dev build; and the default home (SOOTSIM_HOME unset) always
61
+ // does. keying on "explicit home + a runtime deliberately staged there" keeps
62
+ // it structural, not a bespoke toggle.
63
+ if (process.env.SOOTSIM_HOME && readActiveRuntime()) return null
64
+ const root = findMonorepoRoot()
65
+ if (!root) return null
66
+ const devBuild = path.join(root, 'public/sootsim')
67
+ // require the runtime shape the installed runtime also has, so serving it is
68
+ // a drop-in (index.html shell + engine/ + engine-tenant/worker.js tenant).
69
+ if (
70
+ fs.existsSync(path.join(devBuild, 'index.html')) &&
71
+ fs.existsSync(path.join(devBuild, 'engine/index.html')) &&
72
+ fs.existsSync(path.join(devBuild, 'engine-tenant/worker.js'))
73
+ ) {
74
+ return devBuild
75
+ }
76
+ return null
77
+ }
78
+
12
79
  const MIME_TYPES: Record<string, string> = {
13
80
  '.js': 'application/javascript',
14
81
  '.mjs': 'application/javascript',
@@ -46,6 +113,9 @@ const ROOT_RUNTIME_PATHS = [
46
113
  ]
47
114
 
48
115
  export function resolveActiveRuntimeRoot(): string | null {
116
+ // mode boundary: inside the dev checkout the dev-stack build is the engine.
117
+ const devRoot = resolveDevCheckoutRuntimeRoot()
118
+ if (devRoot) return devRoot
49
119
  const active = readActiveRuntime()
50
120
  if (!active) return null
51
121
  const dir = runtimeDir(active)
@@ -598,6 +598,15 @@ export function wsBridgePlugin(): Plugin {
598
598
  portOffset: process.env.PORT_OFFSET,
599
599
  }),
600
600
  writeDevLockfile: true,
601
+ // resolved on every lockfile heartbeat: the address is null until
602
+ // vite's http server is listening, then the real bound port. lets
603
+ // CLI commands resolve the shell base URL from the same lockfile
604
+ // that names the bridge port (one world, no split-brain).
605
+ getShellPort: () => {
606
+ const addr = server.httpServer?.address()
607
+ if (addr && typeof addr === 'object') return addr.port
608
+ return server.config.server.port || null
609
+ },
601
610
  })
602
611
  bridgeHost.start?.({ silent: true })
603
612
  })
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.185 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c,d}from"./chunk-M3P67TBN.js";import"./chunk-GX6MKIFC.js";export{d as BETA_ASK_HEADLINE,b as BETA_LABEL,c as BETA_TAGLINE,a as IS_BETA};
@@ -1,23 +0,0 @@
1
- /*! sootsim v0.1.185 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as A,d as W,f as x}from"./chunk-E5DE33BU.js";import{I as v,J as P,K as T,L as C,j as k}from"./chunk-BI56RR3G.js";import{WebSocket as I}from"ws";function E(){if(k()){let n=P();if(n&&C(n))return n.bridgePort}let e=v();return e&&T(e)?e.bridgePort:7668}var w=class extends Error{lock;constructor(n,i){super(n),this.name="BridgeSimLockedError",this.lock=i}};function L(e){return e==="flag"?"via --sim":e==="saved"?"saved via `sootsim use`":"primary fallback \u2014 no sim pinned"}function V(e,n={}){let i=new Set,a=n.port??E(),l=n.commandTimeoutMs??15e3,r,m="none",h=new Set(n.stripBooleanFlags??[]),b=new Set(n.stripValueFlags??[]);for(let t=0;t<e.length;t++){let d=e[t];if(d==="--port"||d==="-p"){i.add(t),t+1<e.length&&(i.add(t+1),a=Number(e[t+1])),t++;continue}if(d.startsWith("--port=")){i.add(t),a=Number(d.slice(7));continue}if(d==="--timeout"){i.add(t),t+1<e.length&&(i.add(t+1),l=Number(e[t+1])),t++;continue}if(d==="--sim"||d==="--session"||d==="--tab"){i.add(t),t+1<e.length&&(i.add(t+1),r=e[t+1]?.trim()||void 0,m="flag"),t++;continue}let s=d.startsWith("--sim=")?d.slice(6):d.startsWith("--session=")?d.slice(10):d.startsWith("--tab=")?d.slice(6):void 0;if(s!==void 0){i.add(t),r=s.trim()||void 0,m="flag";continue}if(h.has(d)){i.add(t);continue}b.has(d)&&(i.add(t),t+1<e.length&&i.add(t+1),t++)}if(!r){let t=W();t&&(r=t.trim()||void 0,m="saved")}return{positional:e.filter((t,d)=>!i.has(d)),wsPort:a,simId:r,simIdSource:m,commandTimeoutMs:l}}function M(e,n={}){let i=1,a=n.commandTimeoutMs??15e3,l=new Map,r=new I(`ws://localhost:${e}`),m=A(),h=new Promise((s,o)=>{r.on("open",()=>{try{r.send(JSON.stringify({type:"bridge:hello",id:0,cliIdentityKey:m.key,cliIdentitySource:m.source,cliLabel:n.cliLabel}))}catch{}s()}),r.on("error",c=>{let g=c.message?`: ${c.message}`:"";o(new Error(`could not connect to ws://localhost:${e}${g}`))})}),b=!1,t=!1;function d(s,o){if(t||process.env.SOOTSIM_QUIET_TARGET_NOTICE==="1"||s.startsWith("bridge:")||s==="focus"||s==="close")return;t=!0;let c=o??"primary",g=L(o?n.simIdSource:"none");process.stderr.write(` \u2192 ${c} (${g})
3
- `)}return r.on("message",s=>{let o;try{o=JSON.parse(s.toString())}catch{return}if(o.id===0)return;let c=l.get(o.id);c&&(l.delete(o.id),o._otherCliCount>0&&!b&&(b=!0,process.stderr.write(`
4
- \u26A0 ${o._otherCliCount} other CLI identity/identities are driving this sim
5
- taps, scrolls, and keyboard input from multiple agents will collide on
6
- the same screen state (this is not a bridge throughput limit).
7
- use \`sootsim open --new\` for an isolated sim per agent.
8
-
9
- `)),o.error?o._locked?c.reject(new w(o.error,o._locked)):c.reject(new Error(o.error)):c.resolve(o.result))}),r.on("close",(s,o)=>{let c=o?.toString()||"connection closed";for(let[g,u]of l)l.delete(g),u.reject(new Error(`sim disconnected: ${c} (code ${s})`))}),{async send(s,o){let c=o?.timeoutMs??a,g=async u=>{await h;let f=i++;return new Promise((F,S)=>{let B=setTimeout(()=>{l.delete(f),S(new Error(`command timed out after ${Math.round(c/1e3)}s`))},c);l.set(f,{resolve:p=>{clearTimeout(B),F(p)},reject:p=>{clearTimeout(B),S(p)}});let y={...s,id:f};y.simId===void 0&&u&&(y.simId=u),d(s.type??"",y.simId),r.send(JSON.stringify(y))})};try{return await g(n.simId)}catch(u){let f=u instanceof Error?u.message:String(u);throw n.simIdSource==="saved"&&n.simId&&s.simId===void 0&&f===`no sim connected with id ${n.simId}`?(x(),new Error(`saved sim ${n.simId} is gone; run \`sootsim list\` and \`sootsim use <sim>\`, or open a fresh sim`)):u}},async listSims(){let s=await this.send({type:"bridge:list-sims"});return Array.isArray(s)?s:[]},async openUrl(s,o={}){return this.send({type:"bridge:open",url:s,newWindow:o.newWindow===!0})},async focusSim(s){return this.send({type:"focus",simId:s})},async closeSim(s){return this.send({type:"close",simId:s})},async claim(s,o={}){return await this.send({type:"bridge:claim",simId:s,force:o.force===!0})},close(){try{r.readyState===I.OPEN&&r.send(JSON.stringify({type:"bridge:bye",id:0}))}catch{}r.close();let s=setTimeout(()=>{r.readyState!==I.CLOSED&&r.terminate()},250)}}}function j(e){return M(e.wsPort,{commandTimeoutMs:e.commandTimeoutMs,simId:e.simId,simIdSource:e.simIdSource})}function O(e,n){let i=e.filter(r=>r.readyState==="open"&&r.id!==n),a=i.find(r=>r.userFocused)??i.find(r=>r.userVisible===!0&&r.isPrimary)??i.find(r=>r.userVisible===!0)??i.find(r=>r.isPrimary);if(!a)return null;let l=[a.isPrimary?"primary":null,a.userVisible===!1?"hidden":a.userVisible===!0?"visible":null,a.userFocused?"focused":null].filter(Boolean);return`${a.id}${l.length?` [${l.join(", ")}]`:""}`}async function q(e){try{let n=await e.send({type:"evaluate",code:`(() => ({
10
- hidden: document.hidden,
11
- visibilityState: document.visibilityState,
12
- hasFocus: typeof document.hasFocus === 'function' ? document.hasFocus() : null,
13
- simId: window.__sootsimBridge?.id ?? window.SootSim?.state?.simId ?? null,
14
- url: location.href
15
- }))()`}),i=typeof n=="object"&&n!==null?n:{hidden:n===!0};if(i.hidden===!0===!0){let l=null;try{l=O(await e.listSims(),i.simId)}catch{}return process.stderr.write(`
16
- \u26A0 target sim${i.simId?` ${i.simId}`:""} is hidden (document.hidden = true)
17
- `+(i.visibilityState?` visibility: ${i.visibilityState}
18
- `:"")+` animations and rAF callbacks are throttled \u2014 coordinates may be wrong
19
- and launch/transition animations will not complete.
20
- `+(l?` another open sim looks usable: ${l}; target it with --sim.
21
- `:" run `sootsim list` to find the visible sim and target it with --sim.\n")+` page-level window.focus() cannot unhide a browser tab.
22
-
23
- `),{hidden:!0,warned:!0,simId:i.simId}}return{hidden:!1,warned:!1,simId:i.simId}}catch{return{hidden:!1,warned:!1}}}async function J(e,n,i={}){let a={type:"evaluate",code:n};return i.acquireLock&&(a.acquireLock=!0),e.send(a)}async function U(e,n,...i){return e.send({type:"call",path:n,args:i})}async function H(e,n,...i){return e.send({type:"call",path:n,args:i,acquireLock:!0})}export{E as a,w as b,V as c,M as d,j as e,q as f,J as g,U as h,H as i};
@@ -1 +0,0 @@
1
- /*! sootsim v0.1.185 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */