sootsim 0.1.250 → 0.1.252

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +8 -5
  2. package/dist-cli/bin.js +4 -4
  3. package/dist-cli/chunks/{agent-JPKDUK4P.js → agent-JRN5KS75.js} +2 -2
  4. package/dist-cli/chunks/{agent-wrapper-Z64YICSQ.js → agent-wrapper-2ZH2WQ2L.js} +2 -2
  5. package/dist-cli/chunks/{app-fonts-524IXHZF.js → app-fonts-LBQ7A7LL.js} +2 -2
  6. package/dist-cli/chunks/{assert-WZRU7L2S.js → assert-XFQCRREO.js} +2 -2
  7. package/dist-cli/chunks/{auth-3ZPMASCJ.js → auth-DAMRQQ53.js} +2 -2
  8. package/dist-cli/chunks/beta-JJ4YSCOE.js +2 -0
  9. package/dist-cli/chunks/{camera-FPGFHVAE.js → camera-NQWFOHXI.js} +2 -2
  10. package/dist-cli/chunks/chunk-25FMG2DR.js +1 -0
  11. package/dist-cli/chunks/{chunk-ZFJZLRAG.js → chunk-4P7EXY3Q.js} +2 -2
  12. package/dist-cli/chunks/{chunk-JMJJJQ3N.js → chunk-54RVP6DQ.js} +1 -1
  13. package/dist-cli/chunks/{chunk-ODXX3PDC.js → chunk-56CSO42W.js} +2 -2
  14. package/dist-cli/chunks/{chunk-7SDQP3K6.js → chunk-5PVVFMLA.js} +2 -2
  15. package/dist-cli/chunks/{chunk-LFRFK56L.js → chunk-677KF26C.js} +1 -1
  16. package/dist-cli/chunks/{chunk-ZBAOOQ7L.js → chunk-AJVA4XFD.js} +2 -2
  17. package/dist-cli/chunks/{chunk-OOYVCERU.js → chunk-BU4QJGYM.js} +2 -2
  18. package/dist-cli/chunks/{chunk-LCEWHXGT.js → chunk-F2DZ3EHN.js} +2 -2
  19. package/dist-cli/chunks/chunk-F7NVK7U5.js +29 -0
  20. package/dist-cli/chunks/{chunk-GVEBFN3A.js → chunk-FCNI6ZWQ.js} +2 -2
  21. package/dist-cli/chunks/{chunk-7CESRUUF.js → chunk-GBJS3QVL.js} +2 -2
  22. package/dist-cli/chunks/{chunk-RDQ4RP2I.js → chunk-GPECMCCD.js} +2 -2
  23. package/dist-cli/chunks/{chunk-HQVZVJWB.js → chunk-GRPNPAFQ.js} +1 -1
  24. package/dist-cli/chunks/{chunk-EJQGI6U6.js → chunk-HERRSHL3.js} +2 -2
  25. package/dist-cli/chunks/{chunk-QQDVBF5C.js → chunk-HNYCB3ZY.js} +1 -1
  26. package/dist-cli/chunks/chunk-HV773SED.js +4 -0
  27. package/dist-cli/chunks/{chunk-DOOM7A5G.js → chunk-J4XJHPJV.js} +2 -2
  28. package/dist-cli/chunks/{chunk-TIWQBBA6.js → chunk-JYJ37QKN.js} +2 -2
  29. package/dist-cli/chunks/chunk-K5UURTEB.js +1 -0
  30. package/dist-cli/chunks/{chunk-AV734IPM.js → chunk-LHAUZJH5.js} +1 -1
  31. package/dist-cli/chunks/{chunk-XBWJ7DPK.js → chunk-LL7KIGNG.js} +2 -2
  32. package/dist-cli/chunks/{chunk-HTGCR74O.js → chunk-LXRPMNYD.js} +2 -2
  33. package/dist-cli/chunks/{chunk-2FGQSNTC.js → chunk-LYIN47A5.js} +2 -2
  34. package/dist-cli/chunks/{chunk-Q72PZST6.js → chunk-MJU6KNLI.js} +3 -3
  35. package/dist-cli/chunks/{chunk-23DV2XSE.js → chunk-MMCNYDBD.js} +1 -1
  36. package/dist-cli/chunks/{chunk-G2QKQWCY.js → chunk-NADQK2CU.js} +1 -1
  37. package/dist-cli/chunks/{chunk-N52AECUU.js → chunk-NB6RTLLI.js} +3 -3
  38. package/dist-cli/chunks/{chunk-S5ILN4OM.js → chunk-NNEUAQME.js} +3 -3
  39. package/dist-cli/chunks/{chunk-RMP6YTMJ.js → chunk-NTZYSZ3Q.js} +2 -2
  40. package/dist-cli/chunks/{chunk-AWT2ISDX.js → chunk-NYKHYDBN.js} +1 -1
  41. package/dist-cli/chunks/{chunk-7WCUYHR3.js → chunk-OSPFE643.js} +1 -1
  42. package/dist-cli/chunks/{chunk-DX6CUGUF.js → chunk-PLK4SCBY.js} +2 -2
  43. package/dist-cli/chunks/{chunk-HLDQHWK5.js → chunk-PVDPE5BH.js} +1 -1
  44. package/dist-cli/chunks/{chunk-L5VG4RQT.js → chunk-QHNYUT7D.js} +1 -1
  45. package/dist-cli/chunks/{chunk-ZA4K47LA.js → chunk-S6DIPG7L.js} +2 -2
  46. package/dist-cli/chunks/{chunk-YACJ3KQ4.js → chunk-T2BJFGBC.js} +1 -1
  47. package/dist-cli/chunks/{chunk-CJMASJXU.js → chunk-TDWFR6H5.js} +2 -2
  48. package/dist-cli/chunks/{chunk-COON6LFC.js → chunk-U5JMZPBD.js} +1 -1
  49. package/dist-cli/chunks/{chunk-N6WXF6OS.js → chunk-UA5FVOEO.js} +1 -1
  50. package/dist-cli/chunks/chunk-UVE2LY6V.js +7 -0
  51. package/dist-cli/chunks/{chunk-GHJRRNR3.js → chunk-WS3DDBN3.js} +1 -1
  52. package/dist-cli/chunks/{chunk-KZZFQRPX.js → chunk-X2IKDV5A.js} +1 -1
  53. package/dist-cli/chunks/{chunk-GXNJSLZM.js → chunk-ZKN7GCX4.js} +2 -2
  54. package/dist-cli/chunks/cli-version-OZF5OMW4.js +2 -0
  55. package/dist-cli/chunks/{compat-C3N6PFK5.js → compat-ME4QWRZ6.js} +3 -3
  56. package/dist-cli/chunks/{config-UVEGEV7N.js → config-TMMSBXDV.js} +2 -2
  57. package/dist-cli/chunks/{control-ROSEFQH3.js → control-QGYYWKJP.js} +2 -2
  58. package/dist-cli/chunks/daemon-6NBHEVXS.js +2 -0
  59. package/dist-cli/chunks/{debug-VLB6FCUL.js → debug-LFJ46Q45.js} +3 -3
  60. package/dist-cli/chunks/{desktop-LAPJ2XXG.js → desktop-W5GPU7JA.js} +3 -3
  61. package/dist-cli/chunks/{detox-UKRIYJBM.js → detox-U3B3N3K7.js} +2 -2
  62. package/dist-cli/chunks/{device-HABOB4FC.js → device-I2WVQFXL.js} +2 -2
  63. package/dist-cli/chunks/{diagnose-TPTVALBD.js → diagnose-6TQOA4QJ.js} +2 -2
  64. package/dist-cli/chunks/drivers-5J25VDIG.js +2 -0
  65. package/dist-cli/chunks/{film-RZABTGXV.js → film-P5E64XQH.js} +3 -3
  66. package/dist-cli/chunks/flow-LD6MOZQC.js +2 -0
  67. package/dist-cli/chunks/help-VCWJZBQU.js +2 -0
  68. package/dist-cli/chunks/{hidden-runtime-alias-AITHRBI5.js → hidden-runtime-alias-ICP5W4W5.js} +2 -2
  69. package/dist-cli/chunks/home-paths-MCD3DISJ.js +2 -0
  70. package/dist-cli/chunks/inspect-VF575AD3.js +2 -0
  71. package/dist-cli/chunks/install-desktop-Q4Y6FTSA.js +2 -0
  72. package/dist-cli/chunks/{login-LIPDXOLT.js → login-A5LRYTNO.js} +4 -4
  73. package/dist-cli/chunks/{logout-7TCXGQM4.js → logout-M3HFZGFU.js} +2 -2
  74. package/dist-cli/chunks/{maestro-CQRCUEZJ.js → maestro-HNREOYXF.js} +3 -3
  75. package/dist-cli/chunks/{maestro-generate-TBBDRYEU.js → maestro-generate-BEEDUOOJ.js} +3 -3
  76. package/dist-cli/chunks/{mode-Z7E6YZTJ.js → mode-IBFHS3G2.js} +2 -2
  77. package/dist-cli/chunks/optional-demo-registry-6XYQJXI5.js +2 -0
  78. package/dist-cli/chunks/{perf-OS7TTPQ2.js → perf-62BD5VIU.js} +2 -2
  79. package/dist-cli/chunks/{record-YH22UVU2.js → record-2ILPO4XB.js} +3 -3
  80. package/dist-cli/chunks/runtime-WCDQFR7G.js +2 -0
  81. package/dist-cli/chunks/{screenshot-command-DV35HE24.js → screenshot-command-YZR5KVV2.js} +3 -3
  82. package/dist-cli/chunks/{screenshots-capture-OV6RMSA2.js → screenshots-capture-QHQ43OBD.js} +2 -2
  83. package/dist-cli/chunks/{serve-WTZRYS6X.js → serve-GQ4PUD5P.js} +15 -15
  84. package/dist-cli/chunks/{setup-AQ46RLHL.js → setup-C74I2RO3.js} +3 -3
  85. package/dist-cli/chunks/{skills-P6P5L7CV.js → skills-I7EVR3MU.js} +2 -2
  86. package/dist-cli/chunks/{storage-PIHIVEBL.js → storage-CH6BAYB4.js} +2 -2
  87. package/dist-cli/chunks/store-PTQ4QMFA.js +2 -0
  88. package/dist-cli/chunks/telemetry-AJDAGOFX.js +2 -0
  89. package/dist-cli/chunks/{timeline-334MEYTC.js → timeline-FUS7F5LI.js} +2 -2
  90. package/dist-cli/chunks/{upgrade-UVEGTAME.js → upgrade-DHMZFD5R.js} +4 -4
  91. package/dist-cli/chunks/upload-XJXPQMKX.js +2 -0
  92. package/dist-cli/chunks/version-M2GSAVKM.js +4 -0
  93. package/dist-cli/chunks/web-NV7UM2T7.js +2 -0
  94. package/dist-cli/chunks/{what-happened-3UH7ZQW6.js → what-happened-VRDDXQWR.js} +2 -2
  95. package/dist-lib/agent-daemon-client.cjs +1 -1
  96. package/dist-lib/agent-events.cjs +1 -1
  97. package/dist-lib/agent-identity.cjs +1 -1
  98. package/dist-lib/agent-sessions.cjs +1 -1
  99. package/dist-lib/attached-projects.cjs +1 -1
  100. package/dist-lib/auth/shared-session.cjs +1 -1
  101. package/dist-lib/backend-origin.cjs +1 -1
  102. package/dist-lib/beta.cjs +1 -1
  103. package/dist-lib/beta.mjs +1 -1
  104. package/dist-lib/bridge-constants.cjs +1 -1
  105. package/dist-lib/cli-constants.cjs +1 -1
  106. package/dist-lib/config.cjs +1 -1
  107. package/dist-lib/detox/index.cjs +1 -1
  108. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  109. package/dist-lib/home-paths.cjs +1 -33
  110. package/dist-lib/host/bridge-host.cjs +396 -329
  111. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  112. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  113. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  114. package/dist-lib/host/websocket-proxy.cjs +1 -1
  115. package/dist-lib/index.cjs +1 -1
  116. package/dist-lib/jump-to-source-babel.cjs +1 -1
  117. package/dist-lib/menu.cjs +1 -1
  118. package/dist-lib/menu.mjs +1 -1
  119. package/dist-lib/metro.cjs +1 -1
  120. package/dist-lib/profiles.cjs +1 -1
  121. package/dist-lib/render-mode.cjs +1 -1
  122. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  123. package/dist-lib/sdk.cjs +1 -1
  124. package/dist-lib/sdk.mjs +1 -1
  125. package/dist-lib/skills.cjs +517 -437
  126. package/dist-lib/vite.cjs +1 -1
  127. package/package.json +2 -1
  128. package/src/home-paths.ts +5 -40
  129. package/src/host/bridge-host.ts +4 -5
  130. package/src/runtime-delivery.ts +32 -377
  131. package/dist-cli/chunks/beta-BBI3GYZ6.js +0 -2
  132. package/dist-cli/chunks/chunk-2UGQF7XX.js +0 -4
  133. package/dist-cli/chunks/chunk-J3XNJTO5.js +0 -1
  134. package/dist-cli/chunks/chunk-M7NRJV7O.js +0 -1
  135. package/dist-cli/chunks/chunk-PZR5U4RD.js +0 -29
  136. package/dist-cli/chunks/chunk-TJBXFUCI.js +0 -7
  137. package/dist-cli/chunks/cli-version-GWSUBSWJ.js +0 -2
  138. package/dist-cli/chunks/daemon-NVFYFCWX.js +0 -2
  139. package/dist-cli/chunks/drivers-ZUD4PX2W.js +0 -2
  140. package/dist-cli/chunks/flow-NHVT35XI.js +0 -2
  141. package/dist-cli/chunks/help-CM77GYXU.js +0 -2
  142. package/dist-cli/chunks/home-paths-XIHGBDLL.js +0 -2
  143. package/dist-cli/chunks/inspect-2WK43KRH.js +0 -2
  144. package/dist-cli/chunks/install-desktop-TS2RBWU5.js +0 -2
  145. package/dist-cli/chunks/optional-demo-registry-ANMKFJWS.js +0 -2
  146. package/dist-cli/chunks/runtime-WYDPR5RI.js +0 -2
  147. package/dist-cli/chunks/store-SVTB7QDS.js +0 -2
  148. package/dist-cli/chunks/telemetry-HM3ULN5U.js +0 -2
  149. package/dist-cli/chunks/upload-BIEPTIMK.js +0 -2
  150. package/dist-cli/chunks/version-VITMYQHS.js +0 -4
  151. package/dist-cli/chunks/web-G5IDDAAI.js +0 -2
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.252 | (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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sootsim",
3
- "version": "0.1.250",
3
+ "version": "0.1.252",
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",
@@ -171,6 +171,7 @@
171
171
  }
172
172
  },
173
173
  "devDependencies": {
174
+ "@contrast/runtime-delivery": "workspace:*",
174
175
  "@sootsim/compat": "workspace:*",
175
176
  "@sootsim/globals": "workspace:*",
176
177
  "@sootsim/skills": "workspace:*",
package/src/home-paths.ts CHANGED
@@ -304,46 +304,11 @@ export function writeActiveRuntime(version: string): void {
304
304
  fs.writeFileSync(activeRuntimeFile(), `${version}\n`, 'utf8')
305
305
  }
306
306
 
307
- /** list installed runtime versions (directories under runtimes/). sorted
308
- * ascending by semver when parseable, falling back to lexicographic for
309
- * odd names. */
310
- export function listInstalledRuntimes(): string[] {
311
- try {
312
- return fs
313
- .readdirSync(runtimesDir(), { withFileTypes: true })
314
- .filter((d) => d.isDirectory())
315
- .map((d) => d.name)
316
- .sort(compareSemver)
317
- } catch {
318
- return []
319
- }
320
- }
321
-
322
- /** compare two version strings as coarse semver. treats pre-release
323
- * tags as lower than release of the same major.minor.patch. callers
324
- * that need strict semver compliance should use a dedicated library. */
325
- export function compareSemver(a: string, b: string): number {
326
- const parse = (v: string): [number[], string] => {
327
- const hyphen = v.indexOf('-')
328
- const core = hyphen >= 0 ? v.slice(0, hyphen) : v
329
- const pre = hyphen >= 0 ? v.slice(hyphen + 1) : ''
330
- const parts = core.split('.').map((n) => Number.parseInt(n, 10))
331
- if (parts.some((n) => !Number.isFinite(n))) return [[Number.POSITIVE_INFINITY], v]
332
- return [parts, pre]
333
- }
334
- const [an, ap] = parse(a)
335
- const [bn, bp] = parse(b)
336
- for (let i = 0; i < Math.max(an.length, bn.length); i++) {
337
- const av = an[i] ?? 0
338
- const bv = bn[i] ?? 0
339
- if (av !== bv) return av - bv
340
- }
341
- // pre-release of same core sorts lower than release (empty pre).
342
- if (ap === bp) return 0
343
- if (!ap) return 1
344
- if (!bp) return -1
345
- return ap < bp ? -1 : 1
346
- }
307
+ // listInstalledRuntimes + compareSemver live in @contrast/runtime-delivery:
308
+ // they are delivery machinery (sorting the hosted catalog, deciding whether
309
+ // channel latest is newer than active), shared with contrast, and this module
310
+ // stays free of that dependency so every published `sootsim/*` export that
311
+ // resolves through it keeps working with no bundling requirement.
347
312
 
348
313
  /** absolute path to the active runtime's directory, or null if none active
349
314
  * or the active version is no longer installed. */
@@ -18,7 +18,6 @@ import {
18
18
  claimDaemonLockfile,
19
19
  ensureSootsimHome,
20
20
  isSootsimDevCheckout,
21
- listInstalledRuntimes,
22
21
  readActiveRuntime,
23
22
  readSharedConfig,
24
23
  removeDaemonLockfile,
@@ -33,7 +32,7 @@ import {
33
32
  type SharedConfig,
34
33
  } from '../home-paths.ts'
35
34
  import { resolveDevCheckoutRuntimeRoot } from '../runtime-assets.ts'
36
- import { updateRuntimeToLatest } from '../runtime-delivery.ts'
35
+ import { sootsimRuntime } from '../runtime-delivery.ts'
37
36
  import { AgentHost, type AgentHostOptions } from './agent-host.ts'
38
37
  import {
39
38
  handleAppApiRequest,
@@ -650,7 +649,7 @@ export class SootSimBridgeHost {
650
649
  // are handled in-daemon; install runs entirely inside the CLI so
651
650
  // we don't need a daemon-side handler for it.
652
651
  if (msg.type === 'runtime:list') {
653
- const versions = listInstalledRuntimes()
652
+ const versions = sootsimRuntime.listInstalled()
654
653
  const active = this.getActiveRuntime()
655
654
  const reply = {
656
655
  type: 'runtime:list:ok',
@@ -666,7 +665,7 @@ export class SootSimBridgeHost {
666
665
  }
667
666
  if (msg.type === 'runtime:use') {
668
667
  const version = typeof msg.version === 'string' ? msg.version : ''
669
- const installed = listInstalledRuntimes()
668
+ const installed = sootsimRuntime.listInstalled()
670
669
  if (!installed.includes(version)) {
671
670
  try {
672
671
  ws.send(
@@ -1305,7 +1304,7 @@ export class SootSimBridgeHost {
1305
1304
  if (reason === 'startup') {
1306
1305
  process.stderr.write('sootsim: checking for runtime updates…\n')
1307
1306
  }
1308
- const result = await updateRuntimeToLatest()
1307
+ const result = await sootsimRuntime.updateToLatest()
1309
1308
  if (!result.updated || !result.latestVersion) {
1310
1309
  if (reason === 'startup') {
1311
1310
  process.stderr.write(
@@ -1,39 +1,27 @@
1
- import { spawn } from 'child_process'
2
- import crypto from 'crypto'
3
- import fs from 'fs'
4
- import path from 'path'
5
- import { Readable } from 'stream'
6
- import { pipeline } from 'stream/promises'
1
+ // sootsim's binding of the shared runtime-delivery machinery.
2
+ //
3
+ // the machinery itself (hosted manifest, sha256-verified tarballs, channels,
4
+ // pinning, auto-update) lives in @contrast/runtime-delivery and knows nothing
5
+ // about sootsim. this file supplies sootsim's identity: ~/.sootsim, the
6
+ // SOOTSIM_* env overrides, and the contrast.dev/runtimes hosting layout.
7
+ //
8
+ // @contrast/runtime-delivery is an internal workspace package that is never
9
+ // published, so both the CLI bundle and dist-lib inline it (see the `alias`
10
+ // entry in scripts/build-cli.ts). pack-smoke fails the build if it ever leaks
11
+ // out as a bare require.
12
+
13
+ import { createRuntimeDelivery, type RuntimeProduct } from '@contrast/runtime-delivery'
7
14
  import {
8
15
  cacheDir,
9
- compareSemver,
10
16
  configFilePath,
11
17
  ensureSootsimHome,
12
18
  readActiveRuntime,
13
19
  runtimeDir,
20
+ runtimesDir,
14
21
  writeActiveRuntime,
15
22
  } from './home-paths'
16
23
 
17
24
  export const DEFAULT_RUNTIME_CDN_ORIGIN = 'https://contrast.dev'
18
- export const RUNTIME_CDN_ORIGIN_ENV = 'SOOTSIM_CDN_ORIGIN'
19
- export const RUNTIME_CHANNEL_ENV = 'SOOTSIM_RUNTIME_CHANNEL'
20
- export const RUNTIME_PIN_ENV = 'SOOTSIM_RUNTIME_VERSION'
21
-
22
- export interface RuntimeManifestChannel {
23
- latest: string
24
- }
25
-
26
- export interface RuntimeManifestVersion {
27
- tarball?: string
28
- sha256: string
29
- size?: number
30
- published?: string
31
- }
32
-
33
- export interface RuntimeManifest {
34
- channels: Record<string, RuntimeManifestChannel>
35
- versions: Record<string, RuntimeManifestVersion>
36
- }
37
25
 
38
26
  /** website URL where the sootsim changelog is rendered. the CLI used to drain
39
27
  * a paginated /api/changelog/sootsim endpoint here; the changelog is now a
@@ -42,356 +30,23 @@ export interface RuntimeManifest {
42
30
  * notes` points users at the page. */
43
31
  export const SOOTSIM_CHANGELOG_URL = 'https://sootsim.com/changelog'
44
32
 
45
- export interface RuntimeInstallOptions {
46
- version?: string | null
47
- channel?: string
48
- cdnOrigin?: string
49
- force?: boolean
50
- setActive?: boolean
51
- }
52
-
53
- export interface RuntimeInstallResult {
54
- version: string
55
- channel: string
56
- cdnOrigin: string
57
- runtimeDir: string
58
- installed: boolean
59
- activated: boolean
60
- manifest: RuntimeManifest
61
- }
62
-
63
- export interface RuntimeUpdateResult {
64
- checked: boolean
65
- updated: boolean
66
- reason?: string
67
- activeVersion: string | null
68
- latestVersion?: string
69
- install?: RuntimeInstallResult
70
- }
71
-
72
- interface SootsimConfig {
73
- runtimeChannel?: string
74
- runtimeVersion?: string
75
- cdnOrigin?: string
76
- }
77
-
78
- function readConfig(): SootsimConfig {
79
- try {
80
- const parsed = JSON.parse(fs.readFileSync(configFilePath(), 'utf8')) as SootsimConfig
81
- return parsed && typeof parsed === 'object' ? parsed : {}
82
- } catch {
83
- return {}
84
- }
85
- }
86
-
87
- export function resolveRuntimeCdnOrigin(input?: string): string {
88
- const config = readConfig()
89
- const value =
90
- input ||
91
- process.env[RUNTIME_CDN_ORIGIN_ENV] ||
92
- config.cdnOrigin ||
93
- DEFAULT_RUNTIME_CDN_ORIGIN
94
- return value.replace(/\/+$/, '')
95
- }
96
-
97
- export function resolveRuntimeChannel(input?: string): string {
98
- const config = readConfig()
99
- return input || process.env[RUNTIME_CHANNEL_ENV] || config.runtimeChannel || 'stable'
100
- }
101
-
102
- /** pinned runtime version, or null when following the channel's latest.
103
- * env wins over config so CI can pin per-invocation; the persistent pin
104
- * lives in ~/.sootsim/config.json (`sootsim runtime pin <version>`). */
105
- export function resolveRuntimePin(): string | null {
106
- const env = process.env[RUNTIME_PIN_ENV]
107
- if (env && env.trim()) return env.trim()
108
- const config = readConfig()
109
- return typeof config.runtimeVersion === 'string' && config.runtimeVersion.trim()
110
- ? config.runtimeVersion.trim()
111
- : null
112
- }
113
-
114
- export function runtimeManifestUrl(cdnOrigin?: string): string {
115
- const url = new URL(`${resolveRuntimeCdnOrigin(cdnOrigin)}/runtimes/manifest.json`)
116
- // cdn edges can keep the no-query manifest around longer than its
117
- // max-age. runtime checks need the latest manifest every time.
118
- url.searchParams.set('t', String(Date.now()))
119
- return url.toString()
120
- }
121
-
122
- export function runtimeTarballUrl(version: string, cdnOrigin?: string): string {
123
- return `${resolveRuntimeCdnOrigin(cdnOrigin)}/runtimes/sootsim-runtime-${version}.tar.gz`
124
- }
125
-
126
- export async function fetchRuntimeManifest(cdnOrigin?: string): Promise<RuntimeManifest> {
127
- const url = runtimeManifestUrl(cdnOrigin)
128
- const res = await fetch(url, { headers: { Accept: 'application/json' } })
129
- if (!res.ok) {
130
- throw new Error(`manifest fetch failed: ${res.status} ${res.statusText} (${url})`)
131
- }
132
- return (await res.json()) as RuntimeManifest
133
- }
134
-
135
- export function resolveRuntimeVersion(
136
- manifest: RuntimeManifest,
137
- opts: Pick<RuntimeInstallOptions, 'version' | 'channel'> = {},
138
- ): { version: string; channel: string; entry: RuntimeManifestVersion } {
139
- const channel = resolveRuntimeChannel(opts.channel)
140
- const version =
141
- opts.version || resolveRuntimePin() || manifest.channels[channel]?.latest
142
- if (!version) {
143
- throw new Error(
144
- `no version specified and channel '${channel}' has no latest entry in the manifest`,
145
- )
146
- }
147
- const entry = manifest.versions[version]
148
- if (!entry) {
149
- throw new Error(
150
- `version ${version} not found in manifest; available: ${
151
- Object.keys(manifest.versions).slice(-10).join(', ') || '(none)'
152
- }`,
153
- )
154
- }
155
- return { version, channel, entry }
156
- }
157
-
158
- export async function installRuntime(
159
- opts: RuntimeInstallOptions = {},
160
- ): Promise<RuntimeInstallResult> {
161
- ensureSootsimHome()
162
-
163
- const cdnOrigin = resolveRuntimeCdnOrigin(opts.cdnOrigin)
164
- const manifest = await fetchRuntimeManifest(cdnOrigin)
165
- const { version, channel, entry } = resolveRuntimeVersion(manifest, opts)
166
- const destDir = runtimeDir(version)
167
- const setActive = opts.setActive !== false
168
-
169
- if (!opts.force && fs.existsSync(path.join(destDir, 'index.html'))) {
170
- if (setActive) writeActiveRuntime(version)
171
- return {
172
- version,
173
- channel,
174
- cdnOrigin,
175
- runtimeDir: destDir,
176
- installed: false,
177
- activated: setActive,
178
- manifest,
179
- }
180
- }
181
-
182
- const tarUrl = entry.tarball || runtimeTarballUrl(version, cdnOrigin)
183
- const tarCachePath = path.join(cacheDir(), `sootsim-runtime-${version}.tar.gz`)
184
- process.stderr.write(`sootsim: downloading runtime ${version}…\n`)
185
- await downloadToFile(tarUrl, tarCachePath)
186
- process.stderr.write(`sootsim: extracting runtime ${version}…\n`)
187
-
188
- const actualSha = await sha256File(tarCachePath)
189
- if (actualSha !== entry.sha256) {
190
- fs.rmSync(tarCachePath, { force: true })
191
- throw new Error(
192
- `sha256 mismatch for runtime ${version}: expected ${entry.sha256}, actual ${actualSha}`,
193
- )
194
- }
195
-
196
- const tmpDir = path.join(path.dirname(destDir), `.installing-${version}-${process.pid}`)
197
- fs.rmSync(tmpDir, { recursive: true, force: true })
198
- fs.mkdirSync(tmpDir, { recursive: true })
199
- try {
200
- await extractTarball(tarCachePath, tmpDir)
201
- if (!fs.existsSync(path.join(tmpDir, 'index.html'))) {
202
- throw new Error(`extracted tarball for runtime ${version} is missing index.html`)
203
- }
204
- fs.rmSync(destDir, { recursive: true, force: true })
205
- fs.renameSync(tmpDir, destDir)
206
- } catch (err) {
207
- fs.rmSync(tmpDir, { recursive: true, force: true })
208
- throw err
209
- }
210
-
211
- if (setActive) writeActiveRuntime(version)
212
- return {
213
- version,
214
- channel,
215
- cdnOrigin,
216
- runtimeDir: destDir,
217
- installed: true,
218
- activated: setActive,
219
- manifest,
220
- }
221
- }
222
-
223
- export async function updateRuntimeToLatest(
224
- opts: Pick<RuntimeInstallOptions, 'channel' | 'cdnOrigin'> = {},
225
- ): Promise<RuntimeUpdateResult> {
226
- ensureSootsimHome()
227
- const cdnOrigin = resolveRuntimeCdnOrigin(opts.cdnOrigin)
228
- const channel = resolveRuntimeChannel(opts.channel)
229
-
230
- // a pinned runtime never follows the channel. when the pin is already
231
- // active + on disk this is a no-network no-op; otherwise install exactly
232
- // the pinned version (it must still exist in the hosted manifest).
233
- const pin = resolveRuntimePin()
234
- if (pin) {
235
- const activeVersion = readActiveRuntime()
236
- const pinInstalled = fs.existsSync(path.join(runtimeDir(pin), 'index.html'))
237
- if (activeVersion === pin && pinInstalled) {
238
- return {
239
- checked: true,
240
- updated: false,
241
- reason: `runtime is pinned to ${pin}`,
242
- activeVersion,
243
- latestVersion: pin,
244
- }
245
- }
246
- const install = await installRuntime({
247
- version: pin,
248
- channel,
249
- cdnOrigin,
250
- setActive: false,
251
- })
252
- return {
253
- checked: true,
254
- updated: true,
255
- reason: `runtime is pinned to ${pin}`,
256
- activeVersion: pin,
257
- latestVersion: pin,
258
- install,
259
- }
260
- }
261
-
262
- const manifest = await fetchRuntimeManifest(cdnOrigin)
263
- const latestVersion = manifest.channels[channel]?.latest
264
- if (!latestVersion) {
265
- return {
266
- checked: true,
267
- updated: false,
268
- reason: `channel '${channel}' has no latest runtime`,
269
- activeVersion: readActiveRuntime(),
270
- }
271
- }
272
- const entry = manifest.versions[latestVersion]
273
- if (!entry) {
274
- return {
275
- checked: true,
276
- updated: false,
277
- reason: `manifest is missing version ${latestVersion}`,
278
- activeVersion: readActiveRuntime(),
279
- latestVersion,
280
- }
281
- }
282
-
283
- const activeVersion = readActiveRuntime()
284
- const activeDir = activeVersion ? runtimeDir(activeVersion) : null
285
- const activeInstalled = activeDir
286
- ? fs.existsSync(path.join(activeDir, 'index.html'))
287
- : false
288
- const shouldInstall =
289
- !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0
290
-
291
- if (!shouldInstall) {
292
- return {
293
- checked: true,
294
- updated: false,
295
- reason: 'active runtime is current',
296
- activeVersion,
297
- latestVersion,
298
- }
299
- }
300
-
301
- // setActive=false: callers like the daemon flip the active runtime
302
- // themselves so they can broadcast runtime:changed to connected
303
- // browsers. CLI install uses installRuntime() directly with
304
- // setActive=true and is unaffected.
305
- const install = await installRuntime({
306
- version: latestVersion,
307
- channel,
308
- cdnOrigin,
309
- setActive: false,
310
- })
311
- return {
312
- checked: true,
313
- updated: true,
314
- activeVersion: latestVersion,
315
- latestVersion,
316
- install,
317
- }
318
- }
319
-
320
- export interface RuntimeUpToDateCheck {
321
- active: string | null
322
- latest: string | null
323
- // pinned version when one is set — a pinned runtime is only "outdated"
324
- // when the pin itself isn't active yet, never against channel latest.
325
- pinned: string | null
326
- // true only when a target version is known and it is newer than / not
327
- // the active one (or nothing is active yet). network failures resolve
328
- // to false so callers can treat this as a best-effort hint.
329
- outdated: boolean
330
- }
331
-
332
- /** read-only check: is the active runtime the latest on its channel (or,
333
- * when pinned, the pin)? unlike updateRuntimeToLatest this never downloads
334
- * or activates — it's for surfacing a "newer runtime available" hint at
335
- * startup / in help. */
336
- export async function checkRuntimeUpToDate(
337
- opts: Pick<RuntimeInstallOptions, 'channel' | 'cdnOrigin'> = {},
338
- ): Promise<RuntimeUpToDateCheck> {
339
- const active = readActiveRuntime()
340
- const pinned = resolveRuntimePin()
341
- if (pinned) {
342
- return { active, latest: pinned, pinned, outdated: active !== pinned }
343
- }
344
- try {
345
- const manifest = await fetchRuntimeManifest(resolveRuntimeCdnOrigin(opts.cdnOrigin))
346
- const channel = resolveRuntimeChannel(opts.channel)
347
- const latest = manifest.channels[channel]?.latest ?? null
348
- const outdated = !!(latest && (!active || compareSemver(latest, active) > 0))
349
- return { active, latest, pinned: null, outdated }
350
- } catch {
351
- return { active, latest: null, pinned: null, outdated: false }
352
- }
353
- }
354
-
355
- async function downloadToFile(url: string, destPath: string): Promise<void> {
356
- const res = await fetch(url)
357
- if (!res.ok || !res.body) {
358
- throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`)
359
- }
360
- fs.mkdirSync(path.dirname(destPath), { recursive: true })
361
- const tmp = `${destPath}.partial`
362
- try {
363
- await pipeline(
364
- Readable.fromWeb(res.body as unknown as Parameters<typeof Readable.fromWeb>[0]),
365
- fs.createWriteStream(tmp),
366
- )
367
- fs.renameSync(tmp, destPath)
368
- } catch (err) {
369
- try {
370
- fs.unlinkSync(tmp)
371
- } catch {}
372
- throw err
373
- }
374
- }
375
-
376
- function sha256File(filePath: string): Promise<string> {
377
- return new Promise((resolve, reject) => {
378
- const hash = crypto.createHash('sha256')
379
- const stream = fs.createReadStream(filePath)
380
- stream.on('data', (chunk) => hash.update(chunk))
381
- stream.on('error', reject)
382
- stream.on('end', () => resolve(hash.digest('hex')))
383
- })
33
+ export const SOOTSIM_RUNTIME_PRODUCT: RuntimeProduct = {
34
+ id: 'sootsim',
35
+ defaultCdnOrigin: DEFAULT_RUNTIME_CDN_ORIGIN,
36
+ manifestPath: '/runtimes/manifest.json',
37
+ tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.gz`,
38
+ env: {
39
+ cdnOrigin: 'SOOTSIM_CDN_ORIGIN',
40
+ channel: 'SOOTSIM_RUNTIME_CHANNEL',
41
+ pin: 'SOOTSIM_RUNTIME_VERSION',
42
+ },
43
+ ensureHome: ensureSootsimHome,
44
+ configFile: configFilePath,
45
+ runtimesDir,
46
+ runtimeDir,
47
+ cacheDir,
48
+ readActiveRuntime,
49
+ writeActiveRuntime,
384
50
  }
385
51
 
386
- function extractTarball(tarPath: string, destDir: string): Promise<void> {
387
- return new Promise((resolve, reject) => {
388
- const child = spawn('tar', ['-xzf', tarPath, '-C', destDir], {
389
- stdio: ['ignore', 'inherit', 'inherit'],
390
- })
391
- child.on('error', reject)
392
- child.on('exit', (code) => {
393
- if (code === 0) resolve()
394
- else reject(new Error(`tar exited with code ${code}`))
395
- })
396
- })
397
- }
52
+ export const sootsimRuntime = createRuntimeDelivery(SOOTSIM_RUNTIME_PRODUCT)
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c,d}from"./chunk-L5VG4RQT.js";import"./chunk-23DV2XSE.js";export{d as BETA_ASK_HEADLINE,b as BETA_LABEL,c as BETA_TAGLINE,a as IS_BETA};
@@ -1,4 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{G as R,H as d,I as x,K as w,l as g,u as $,x as b}from"./chunk-TJBXFUCI.js";import{spawn as E}from"child_process";import k from"crypto";import o from"fs";import u from"path";import{Readable as C}from"stream";import{pipeline as T}from"stream/promises";var _="https://contrast.dev",U="SOOTSIM_CDN_ORIGIN",D="SOOTSIM_RUNTIME_CHANNEL",P="SOOTSIM_RUNTIME_VERSION",X="https://sootsim.com/changelog";function y(){try{let t=JSON.parse(o.readFileSync(b(),"utf8"));return t&&typeof t=="object"?t:{}}catch{return{}}}function f(t){let n=y();return(t||process.env[U]||n.cdnOrigin||_).replace(/\/+$/,"")}function S(t){let n=y();return t||process.env[D]||n.runtimeChannel||"stable"}function O(){let t=process.env[P];if(t&&t.trim())return t.trim();let n=y();return typeof n.runtimeVersion=="string"&&n.runtimeVersion.trim()?n.runtimeVersion.trim():null}function A(t){let n=new URL(`${f(t)}/runtimes/manifest.json`);return n.searchParams.set("t",String(Date.now())),n.toString()}function j(t,n){return`${f(n)}/runtimes/sootsim-runtime-${t}.tar.gz`}async function I(t){let n=A(t),r=await fetch(n,{headers:{Accept:"application/json"}});if(!r.ok)throw new Error(`manifest fetch failed: ${r.status} ${r.statusText} (${n})`);return await r.json()}function L(t,n={}){let r=S(n.channel),e=n.version||O()||t.channels[r]?.latest;if(!e)throw new Error(`no version specified and channel '${r}' has no latest entry in the manifest`);let s=t.versions[e];if(!s)throw new Error(`version ${e} not found in manifest; available: ${Object.keys(t.versions).slice(-10).join(", ")||"(none)"}`);return{version:e,channel:r,entry:s}}async function N(t={}){R();let n=f(t.cdnOrigin),r=await I(n),{version:e,channel:s,entry:i}=L(r,t),c=g(e),a=t.setActive!==!1;if(!t.force&&o.existsSync(u.join(c,"index.html")))return a&&x(e),{version:e,channel:s,cdnOrigin:n,runtimeDir:c,installed:!1,activated:a,manifest:r};let h=i.tarball||j(e,n),m=u.join($(),`sootsim-runtime-${e}.tar.gz`);process.stderr.write(`sootsim: downloading runtime ${e}\u2026
3
- `),await F(h,m),process.stderr.write(`sootsim: extracting runtime ${e}\u2026
4
- `);let v=await G(m);if(v!==i.sha256)throw o.rmSync(m,{force:!0}),new Error(`sha256 mismatch for runtime ${e}: expected ${i.sha256}, actual ${v}`);let l=u.join(u.dirname(c),`.installing-${e}-${process.pid}`);o.rmSync(l,{recursive:!0,force:!0}),o.mkdirSync(l,{recursive:!0});try{if(await H(m,l),!o.existsSync(u.join(l,"index.html")))throw new Error(`extracted tarball for runtime ${e} is missing index.html`);o.rmSync(c,{recursive:!0,force:!0}),o.renameSync(l,c)}catch(p){throw o.rmSync(l,{recursive:!0,force:!0}),p}return a&&x(e),{version:e,channel:s,cdnOrigin:n,runtimeDir:c,installed:!0,activated:a,manifest:r}}async function Y(t={}){R();let n=f(t.cdnOrigin),r=S(t.channel),e=O();if(e){let p=d(),V=o.existsSync(u.join(g(e),"index.html"));if(p===e&&V)return{checked:!0,updated:!1,reason:`runtime is pinned to ${e}`,activeVersion:p,latestVersion:e};let M=await N({version:e,channel:r,cdnOrigin:n,setActive:!1});return{checked:!0,updated:!0,reason:`runtime is pinned to ${e}`,activeVersion:e,latestVersion:e,install:M}}let s=await I(n),i=s.channels[r]?.latest;if(!i)return{checked:!0,updated:!1,reason:`channel '${r}' has no latest runtime`,activeVersion:d()};if(!s.versions[i])return{checked:!0,updated:!1,reason:`manifest is missing version ${i}`,activeVersion:d(),latestVersion:i};let a=d(),h=a?g(a):null,m=h?o.existsSync(u.join(h,"index.html")):!1;if(!(!a||!m||w(i,a)>0))return{checked:!0,updated:!1,reason:"active runtime is current",activeVersion:a,latestVersion:i};let l=await N({version:i,channel:r,cdnOrigin:n,setActive:!1});return{checked:!0,updated:!0,activeVersion:i,latestVersion:i,install:l}}async function Z(t={}){let n=d(),r=O();if(r)return{active:n,latest:r,pinned:r,outdated:n!==r};try{let e=await I(f(t.cdnOrigin)),s=S(t.channel),i=e.channels[s]?.latest??null,c=!!(i&&(!n||w(i,n)>0));return{active:n,latest:i,pinned:null,outdated:c}}catch{return{active:n,latest:null,pinned:null,outdated:!1}}}async function F(t,n){let r=await fetch(t);if(!r.ok||!r.body)throw new Error(`download failed: ${r.status} ${r.statusText} (${t})`);o.mkdirSync(u.dirname(n),{recursive:!0});let e=`${n}.partial`;try{await T(C.fromWeb(r.body),o.createWriteStream(e)),o.renameSync(e,n)}catch(s){try{o.unlinkSync(e)}catch{}throw s}}function G(t){return new Promise((n,r)=>{let e=k.createHash("sha256"),s=o.createReadStream(t);s.on("data",i=>e.update(i)),s.on("error",r),s.on("end",()=>n(e.digest("hex")))})}function H(t,n){return new Promise((r,e)=>{let s=E("tar",["-xzf",t,"-C",n],{stdio:["ignore","inherit","inherit"]});s.on("error",e),s.on("exit",i=>{i===0?r():e(new Error(`tar exited with code ${i}`))})})}export{_ as a,X as b,f as c,S as d,O as e,I as f,N as g,Y as h,Z as i};
@@ -1 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
@@ -1 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
@@ -1,29 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as k,b as O,c as x,e as m,f as I,g as h}from"./chunk-2UGQF7XX.js";import{d as R}from"./chunk-ZA4K47LA.js";import{G as v,H as a,I as y,J as u,K as b,l as w,z as d}from"./chunk-TJBXFUCI.js";import S from"fs";import{WebSocket as N}from"ws";async function J(t,e={}){let[s,...n]=t;if(!s||s==="--help"||s==="-h"){A();return}switch(s){case"install":return T(n,e);case"list":case"ls":return _(n);case"use":return C(n);case"remove":case"rm":return U(n);case"which":case"active":return E();case"pin":return F(n);case"unpin":return P();case"notes":case"changelog":return G(n);default:console.error(` unknown runtime subcommand: ${s}`),A(),process.exit(1)}}function A(){console.log(`
3
- sootsim runtime \u2014 manage engine runtimes under ~/.sootsim/runtimes/
4
-
5
- usage:
6
- sootsim runtime install [version] install a version (default: pin or channel latest)
7
- sootsim runtime list show installed + available versions
8
- sootsim runtime use <version> switch active runtime
9
- sootsim runtime pin [version] pin the runtime (stops background updates moving it)
10
- sootsim runtime unpin clear the pin and follow channel latest again
11
- sootsim runtime remove <version> delete an installed runtime
12
- sootsim runtime which print active runtime version
13
- sootsim runtime notes print hosted release notes URL
14
-
15
- flags:
16
- --channel <name> channel to resolve 'latest' from (default: stable)
17
- --force reinstall even if the version is already on disk
18
- --set-active=false do not switch active runtime after install
19
-
20
- environment:
21
- SOOTSIM_CDN_ORIGIN override the CDN base URL (default: ${k})
22
-
23
- examples:
24
- sootsim runtime install
25
- sootsim runtime install 1.2.3
26
- sootsim runtime install --channel beta
27
- sootsim runtime use 1.2.3
28
- sootsim runtime notes
29
- `)}async function T(t,e){let{version:s,flags:n}=M(t),o=n.channel??e.channel??"stable",l=n.force===!0,r=n.setActive!==!1;v(),console.log("sootsim runtime install"),console.log(` cdn: ${x()}`);try{let i=await h({version:s,channel:o,force:l,setActive:r});console.log(` version: ${i.version} (channel: ${i.channel})`),i.installed?console.log(` installed ${i.version}`):console.log(` already installed at ${i.runtimeDir}`),r&&await f(i.version)}catch(i){console.error(` ${p(i)}`),process.exit(1)}}async function f(t){y(t),console.log(` active: ${t}`),await L(t)||console.log(` (no daemon running \u2014 next sootsim/electron launch will pick up ${t})`)}async function L(t){let{isDaemonLockfileFresh:e,readDaemonLockfile:s}=await import("./home-paths-XIHGBDLL.js"),n=s();if(!e(n))return!1;let o=R();return new Promise(l=>{let r=!1,i=!1,g=D=>{r||(r=!0,l(D))},c=new N(`ws://127.0.0.1:${o}`,{handshakeTimeout:800}),$=setTimeout(()=>{try{c.close()}catch{}g(i)},1500);c.on("open",()=>{try{c.send(JSON.stringify({type:"runtime:use",version:t,id:0})),i=!0}catch{}setTimeout(()=>{try{c.close()}catch{}},100)}),c.on("close",()=>{clearTimeout($),g(i)}),c.on("error",()=>{clearTimeout($),g(!1)})})}async function _(t){v();let e=u(),s=a(),n=m();if(console.log("installed:"),e.length===0)console.log(" (none)");else for(let o of e)console.log(` ${o===s?"*":" "} ${o}${o===n?" (pinned)":""}`);n&&!e.includes(n)&&console.log(`pinned: ${n} (not installed \u2014 run \`sootsim runtime install\`)`);try{let o=await I();console.log("available (latest per channel):");for(let[r,i]of Object.entries(o.channels))console.log(` ${r.padEnd(8)} ${i.latest}`);let l=Object.keys(o.versions).sort(b).reverse();if(l.length>1){console.log("hosted versions:");for(let r of l)console.log(` ${r}`)}}catch(o){console.log(`available: (could not fetch manifest: ${p(o)})`)}}async function C(t){let e=t[0];e||(console.error(" usage: sootsim runtime use <version>"),process.exit(1));let s=u();s.includes(e)||(console.error(` version ${e} is not installed`),console.error(` installed: ${s.join(", ")||"(none)"}`),console.error(` run \`sootsim runtime install ${e}\` first`),process.exit(1)),await f(e)}async function U(t){let e=t[0];e||(console.error(" usage: sootsim runtime remove <version>"),process.exit(1)),a()===e&&(console.error(` cannot remove active runtime ${e}`),console.error(" switch with `sootsim runtime use <other>` first, or install another version"),process.exit(1));let n=w(e);if(!S.existsSync(n)){console.error(` ${e} is not installed`);return}S.rmSync(n,{recursive:!0,force:!0}),console.log(` removed ${e}`)}async function E(){let t=a();if(!t){console.log(" no active runtime");return}console.log(t)}async function F(t){let e=t[0];if(!e){let n=m();n?console.log(` runtime pinned to ${n}`):(console.log(" no pin \u2014 runtime follows channel latest"),console.log(" usage: sootsim runtime pin <version>"));return}if(d({runtimeVersion:e}),console.log(` pinned runtime to ${e}`),u().includes(e)){a()!==e&&await f(e);return}try{let n=await h({version:e,setActive:!1});console.log(n.installed?` installed ${n.version}`:` already installed at ${n.runtimeDir}`),await f(e)}catch(n){console.error(` ${p(n)}`),console.error(` pin saved, but ${e} could not be installed \u2014 check \`sootsim runtime list\` for hosted versions`),process.exit(1)}}async function P(){let t=m();if(!t){console.log(" no pin set");return}d({runtimeVersion:void 0}),console.log(` unpinned (was ${t}) \u2014 runtime follows channel latest again`),console.log(" run `sootsim upgrade` to move to the latest now")}async function G(t){t.length>0&&(console.error(" usage: sootsim runtime notes"),process.exit(1));let e=a();e&&console.log(` active runtime: v${e}`),console.log(` release notes: ${O}`)}function M(t){let e={},s=[];for(let n=0;n<t.length;n++){let o=t[n];if(o==="--channel"&&n+1<t.length){e.channel=t[n+1],n++;continue}if(o.startsWith("--channel=")){e.channel=o.slice(10);continue}if(o==="--force"){e.force=!0;continue}if(o==="--set-active=false"||o==="--no-set-active"){e.setActive=!1;continue}s.push(o)}return{version:s[0]??null,flags:e}}function p(t){return t instanceof Error?t.message:String(t)}export{J as a};
@@ -1,7 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{randomUUID as I}from"node:crypto";import r from"node:fs";import{homedir as E}from"node:os";import o from"node:path";var _="SOOTSIM_HOME",P="active",j="daemon.json",F="dev-bridge.json",w="config.json",L=3e4;function u(){let e=process.env[_];return e&&e.length>0?o.resolve(e):o.join(E(),".sootsim")}function R(){if(process.env.SOOTSIM_FORCE_DAEMON_INSTALL==="1")return!1;let e=process.env.SOOTSIM_DEV;if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;let t=process.argv[1];if(!t)return!1;try{return r.realpathSync(t).includes(`${o.sep}packages${o.sep}sootsim${o.sep}`)}catch{return!1}}function T(){return process.env.SOOTSIM_FORCE_DAEMON_INSTALL==="1"?!1:process.env.IS_TAMAGUI_DEV==="1"}function z(){return R()||T()}function f(){return o.join(u(),"runtimes")}function B(e){return o.join(f(),e)}function O(){return o.join(f(),P)}function D(){return o.join(u(),"electron")}function Q(){return o.join(D(),"userData")}function Z(e){return o.join(D(),e)}function C(){return o.join(u(),"profiles")}function M(){return o.join(u(),"daemon-app")}function $(){return o.join(M(),"SootSim Daemon.app")}function ee(){return o.join($(),"Contents","MacOS","sootsim-daemon")}function U(){return o.join(u(),"cache")}function m(){return o.join(u(),j)}function d(){return o.join(u(),F)}function x(){return o.join(u(),w)}function h(){try{let e=r.readFileSync(x(),"utf8"),t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function N(e){l();let t=h(),i={...t,...e};e.settings&&typeof e.settings=="object"&&(i.settings={...t.settings&&typeof t.settings=="object"?t.settings:{},...e.settings});let c=`${x()}.tmp`;return r.writeFileSync(c,`${JSON.stringify(i,null,2)}
3
- `,"utf8"),r.renameSync(c,x()),i}function te(){return h().telemetry!==!1}function re(){let e=h().anonymousId;if(typeof e=="string"&&e.trim())return e;let t=`anon-cli-${I()}`;return N({anonymousId:t}),t}function ne(e){N({telemetry:e})}function g(){return o.join(u(),"runtime-upgraded.json")}function oe(e){l();let t=`${g()}.tmp`;r.writeFileSync(t,`${JSON.stringify(e)}
4
- `,"utf8"),r.renameSync(t,g())}function ie(){try{let e=r.readFileSync(g(),"utf8");r.unlinkSync(g());let t=JSON.parse(e);return typeof t?.to!="string"||!t.to?null:{from:typeof t.from=="string"?t.from:null,to:t.to,at:typeof t.at=="number"?t.at:0}}catch{return null}}function l(){r.mkdirSync(u(),{recursive:!0}),r.mkdirSync(f(),{recursive:!0}),r.mkdirSync(D(),{recursive:!0}),r.mkdirSync(C(),{recursive:!0}),r.mkdirSync(U(),{recursive:!0})}function J(){try{let e=r.readFileSync(O(),"utf8").trim();return e.length>0?e:null}catch{return null}}function se(e){r.mkdirSync(f(),{recursive:!0}),r.writeFileSync(O(),`${e}
5
- `,"utf8")}function ue(){try{return r.readdirSync(f(),{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name).sort(V)}catch{return[]}}function V(e,t){let i=s=>{let a=s.indexOf("-"),p=a>=0?s.slice(0,a):s,A=a>=0?s.slice(a+1):"",k=p.split(".").map(b=>Number.parseInt(b,10));return k.some(b=>!Number.isFinite(b))?[[Number.POSITIVE_INFINITY],s]:[k,A]},[c,n]=i(e),[v,S]=i(t);for(let s=0;s<Math.max(c.length,v.length);s++){let a=c[s]??0,p=v[s]??0;if(a!==p)return a-p}return n===S?0:n?S?n<S?-1:1:-1:1}function ce(){let e=J();if(!e)return null;let t=B(e);try{if(r.statSync(t).isDirectory())return t}catch{}return null}var y=16*1024;function H(){try{let e=r.openSync(m(),"r");try{let t=Buffer.alloc(y),i=r.readSync(e,t,0,y,0),c=t.subarray(0,i).toString("utf8"),n=JSON.parse(c);return n&&n.schema===1&&typeof n.pid=="number"&&typeof n.bridgePort=="number"&&typeof n.runtimePort=="number"&&typeof n.startedAt=="number"&&typeof n.heartbeatAt=="number"?n:null}finally{r.closeSync(e)}}catch{return null}}function ae(){try{let e=r.openSync(d(),"r");try{let t=Buffer.alloc(y),i=r.readSync(e,t,0,y,0),c=t.subarray(0,i).toString("utf8"),n=JSON.parse(c);return n&&n.schema===1&&n.source==="vite-dev"&&typeof n.pid=="number"&&typeof n.bridgePort=="number"&&typeof n.runtimePort=="number"&&typeof n.cwd=="string"&&typeof n.startedAt=="number"&&typeof n.heartbeatAt=="number"&&(n.shellPort===void 0||typeof n.shellPort=="number")?n:null}finally{r.closeSync(e)}}catch{return null}}function G(e,t=Date.now()){if(!e||t-e.heartbeatAt>L)return!1;try{return process.kill(e.pid,0),!0}catch{return!1}}function fe(e,t=Date.now()){if(!e||t-e.heartbeatAt>L)return!1;try{return process.kill(e.pid,0),!0}catch{return!1}}function K(e){l();let t=`${m()}.tmp`;r.writeFileSync(t,`${JSON.stringify(e,null,2)}
6
- `,"utf8"),r.renameSync(t,m())}function le(e){l();let t=`${d()}.tmp`;r.writeFileSync(t,`${JSON.stringify(e,null,2)}
7
- `,"utf8"),r.renameSync(t,d())}function pe(e){l();let t=H();return t&&G(t)&&t.pid!==e.pid?!1:(K(e),!0)}function me(){try{r.unlinkSync(m())}catch{}}function de(){try{r.unlinkSync(d())}catch{}}export{_ as a,P as b,j as c,F as d,w as e,L as f,u as g,R as h,T as i,z as j,f as k,B as l,O as m,D as n,Q as o,Z as p,C as q,M as r,$ as s,ee as t,U as u,m as v,d as w,x,h as y,N as z,te as A,re as B,ne as C,g as D,oe as E,ie as F,l as G,J as H,se as I,ue as J,V as K,ce as L,H as M,ae as N,G as O,fe as P,K as Q,le as R,pe as S,me as T,de as U};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a}from"./chunk-LFRFK56L.js";import"./chunk-23DV2XSE.js";export{a as getCliVersion};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c,d,e}from"./chunk-ZBAOOQ7L.js";import"./chunk-RDQ4RP2I.js";import"./chunk-DOOM7A5G.js";import"./chunk-2FGQSNTC.js";import"./chunk-CJMASJXU.js";import"./chunk-RMP6YTMJ.js";import"./chunk-ODXX3PDC.js";import"./chunk-QQDVBF5C.js";import"./chunk-N6WXF6OS.js";import"./chunk-HLDQHWK5.js";import"./chunk-TJBXFUCI.js";import"./chunk-LFRFK56L.js";import"./chunk-L5VG4RQT.js";import"./chunk-OOYVCERU.js";import"./chunk-23DV2XSE.js";export{c as daemonInstall,b as getDaemonServiceStatus,a as runDaemon,d as teardownDaemonService,e as teardownSootsimHome};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import"./chunk-M7NRJV7O.js";import{f as a,g as b,h as c,i as d,j as e,k as f,l as g,m as h,n as i}from"./chunk-DX6CUGUF.js";import"./chunk-GHJRRNR3.js";import"./chunk-JMJJJQ3N.js";import"./chunk-N6WXF6OS.js";import"./chunk-TJBXFUCI.js";import"./chunk-23DV2XSE.js";export{e as ALL_DRIVERS,i as buildDriverListRows,a as chromiumDriver,b as electronDriver,f as getAllDrivers,g as getDriver,c as playwrightDriver,h as resolveDriver,d as systemDriver};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{c,d,e,f,g,h}from"./chunk-S5ILN4OM.js";import"./chunk-ZFJZLRAG.js";import"./chunk-HQVZVJWB.js";import{c as a,d as b}from"./chunk-N52AECUU.js";import"./chunk-TIWQBBA6.js";import"./chunk-7SDQP3K6.js";import"./chunk-HTGCR74O.js";import"./chunk-EJQGI6U6.js";import"./chunk-XBWJ7DPK.js";import"./chunk-J3XNJTO5.js";import"./chunk-DX6CUGUF.js";import"./chunk-GHJRRNR3.js";import"./chunk-KZZFQRPX.js";import"./chunk-YACJ3KQ4.js";import"./chunk-JMJJJQ3N.js";import"./chunk-AWT2ISDX.js";import"./chunk-GXNJSLZM.js";import"./chunk-COON6LFC.js";import"./chunk-ZA4K47LA.js";import"./chunk-G2QKQWCY.js";import"./chunk-RDQ4RP2I.js";import"./chunk-DOOM7A5G.js";import"./chunk-RMP6YTMJ.js";import"./chunk-ODXX3PDC.js";import"./chunk-QQDVBF5C.js";import"./chunk-N6WXF6OS.js";import"./chunk-HLDQHWK5.js";import"./chunk-TJBXFUCI.js";import"./chunk-7CESRUUF.js";import"./chunk-OOYVCERU.js";import"./chunk-23DV2XSE.js";export{e as discoverSootsimUrl,c as getLastFlowPreviewUploadResult,d as getLastFlowTraceSteps,g as hoistLeadingSimFlag,a as parseFlowFile,f as runFlowPlayback,h as runMaestroAuthoring,b as validateFlowFile};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c}from"./chunk-2FGQSNTC.js";import"./chunk-CJMASJXU.js";import"./chunk-RMP6YTMJ.js";import"./chunk-ODXX3PDC.js";import"./chunk-QQDVBF5C.js";import"./chunk-N6WXF6OS.js";import"./chunk-HLDQHWK5.js";import"./chunk-TJBXFUCI.js";import"./chunk-LFRFK56L.js";import"./chunk-L5VG4RQT.js";import"./chunk-OOYVCERU.js";import"./chunk-23DV2XSE.js";export{c as printCommandHelp,b as printGroupHelp,a as printHelp};