@stim-cli/server 1.23.1 → 1.25.0
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/README.md +41 -13
- package/dist/{protocol-BKpAsa9G.mjs → protocol-VEZO2CyR.mjs} +70 -2
- package/dist/protocol.mjs +1 -1
- package/dist/protocol.schema.json +162 -6
- package/dist/{stim-server-Z2tFBWaG.mjs → stim-server-DowAx-6v.mjs} +96 -12
- package/dist/stim-server.mjs +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -49,8 +49,8 @@ and [device-host clients](#device-host-approval). The plain listing shows
|
|
|
49
49
|
[Actions](#actions).
|
|
50
50
|
|
|
51
51
|
`GET http://127.0.0.1:7787/health` answers requests from this machine with the
|
|
52
|
-
server's name, versions, `stimBuild` (the digest of the bundled Stim's build,
|
|
53
|
-
|
|
52
|
+
server's name, versions, `stimBuild` (the digest of the bundled Stim's build),
|
|
53
|
+
protocol, `stimHome`, `startup`, `busy`
|
|
54
54
|
(the offloaded `builds` and `hostedSessions` running now) and the current
|
|
55
55
|
Tailscale state. It answers HTTP 200 once `startup.state` is `ready`; while the
|
|
56
56
|
state is `pending` or `degraded` (see the LaunchAgent notes below) it answers
|
|
@@ -547,8 +547,11 @@ are not carried over: phones pair again, and remote machines are approved
|
|
|
547
547
|
again with a new setup ticket.
|
|
548
548
|
|
|
549
549
|
Stim Desktop and other clients of the server's own user on the same machine do
|
|
550
|
-
not pair. They connect to the Unix socket `$STIM_HOME/server/local.sock
|
|
551
|
-
|
|
550
|
+
not pair. They connect to the Unix socket `$STIM_HOME/server/local.sock`. If
|
|
551
|
+
that path exceeds the platform's limit (103 UTF-8 bytes on macOS, 107 on Linux), the socket instead lives at
|
|
552
|
+
`/tmp/stim-sockets-<uid>/<sha256-of-normalized-socket-path>.sock`, so long hosted
|
|
553
|
+
session homes remain usable and distinct homes keep distinct sockets. The
|
|
554
|
+
socket is mode 0600 in a mode 0700 directory owned by this user and needs no handshake.
|
|
552
555
|
That connection gets read and control. The Desktop-only methods (`route.setup`,
|
|
553
556
|
`machines.update.*`, `device-host.sessions` and `device-host.sessions.stop`)
|
|
554
557
|
work only there; on a server Desktop started, only after the private Desktop
|
|
@@ -556,8 +559,13 @@ bootstrap proof (see [Private Desktop bootstrap](#private-desktop-bootstrap)).
|
|
|
556
559
|
Windows has no socket.
|
|
557
560
|
|
|
558
561
|
The network address, `tailscale whois` and the `X-Forwarded-For` header that
|
|
559
|
-
`tailscale serve` adds never authenticate. They
|
|
560
|
-
`stim-server devices`) and key the rate limits below.
|
|
562
|
+
`tailscale serve` adds never authenticate. They label a record (`from` in
|
|
563
|
+
`stim-server devices`) and key the rate limits below. Tailscale rewrites the
|
|
564
|
+
header to the real tailnet source, so remote clients cannot forge it. A local
|
|
565
|
+
process on the host can connect to the loopback port and forge it to lock one
|
|
566
|
+
named peer, or the shared local bucket, out for the lockout window. It
|
|
567
|
+
authenticates nothing and reads nothing. This is accepted because it needs
|
|
568
|
+
local code execution on the host.
|
|
561
569
|
|
|
562
570
|
A connection must finish the handshake and send `hello` within 5 seconds of
|
|
563
571
|
each step. Five failed attempts from the same peer address within a minute
|
|
@@ -1143,6 +1151,12 @@ stream over WireGuard with socket backpressure; no public tunnel, Funnel or
|
|
|
1143
1151
|
Tailscale serve configuration change is needed. The 64 KiB server message
|
|
1144
1152
|
limit remains unchanged.
|
|
1145
1153
|
|
|
1154
|
+
An approved client calls `device-host.metro.ports` with `{ports}`, at most 256
|
|
1155
|
+
of them, before it starts Metro for an iOS Expo dev client, and the host
|
|
1156
|
+
answers `{busy}`: the listed ports that already accept loopback connections,
|
|
1157
|
+
apart from the client's own dev-client bridges. The feature
|
|
1158
|
+
`hosted-metro-ports` advertises it.
|
|
1159
|
+
|
|
1146
1160
|
Replaying the same open request keeps the port. Client disconnection leaves
|
|
1147
1161
|
the bridge available for the same session while its server owner lives. Call
|
|
1148
1162
|
`device-host.metro.close` to replace a gateway, then reopen on the same port;
|
|
@@ -1601,6 +1615,8 @@ connected since stim-server started keeps its directory when revoked.
|
|
|
1601
1615
|
same Ruby selection and UTF-8 locale defaults as `pod install`; omitting
|
|
1602
1616
|
`rubyVersion` uses the worker's default Ruby. It
|
|
1603
1617
|
returns `toolchain` (`stimBuild`, a digest of the bundled Stim's built code;
|
|
1618
|
+
`compat`, the bundled Stim's build compatibility version, which a client
|
|
1619
|
+
compares instead of `stimBuild` when it is present;
|
|
1604
1620
|
`os`, the OS stim-server runs on as Node names it (`darwin`, `linux`, `win32`);
|
|
1605
1621
|
`arch`; `xcode`; `simulatorSdk`; `macosSdk` (from
|
|
1606
1622
|
`xcrun --sdk macosx --show-sdk-version`); `cocoapods`; `runtimes`, the simulator
|
|
@@ -1638,8 +1654,10 @@ connected since stim-server started keeps its directory when revoked.
|
|
|
1638
1654
|
architecture and target options. These are exact lookups, not a full inventory.
|
|
1639
1655
|
With `react-native-peer-cache`, a React Native/Expo development offer can send
|
|
1640
1656
|
`reactNativeArtifact: { project, fingerprint, isExpo, platform, toolchain, ios | android }`.
|
|
1641
|
-
The query includes the caller's compatible toolchain
|
|
1642
|
-
|
|
1657
|
+
The query includes the caller's compatible toolchain, whose `toolchain.compat`
|
|
1658
|
+
takes the place of `stimBuild` with `build-compat`, and normalized native
|
|
1659
|
+
build choices; a caller sends React Native and SwiftPM queries only to a
|
|
1660
|
+
server with `build-compat`; the worker constructs its own receipt around compilation.
|
|
1643
1661
|
The returned identity is opaque, not an alias for the caller's local cache key.
|
|
1644
1662
|
The completed receipt binds the worker-verified post-mutation fingerprint
|
|
1645
1663
|
and native options to the toolchain checked before and after compilation.
|
|
@@ -1647,7 +1665,7 @@ connected since stim-server started keeps its directory when revoked.
|
|
|
1647
1665
|
does not discard a matching archive. Older workers receive no new query
|
|
1648
1666
|
parameters and continue through their normal build path.
|
|
1649
1667
|
With `swiftpm-peer-cache`, `swiftpmArtifact` carries `project`, `sourceDigest`,
|
|
1650
|
-
`stimBuild`, complete `inputs` (`ignored`, `outputs`, `localFiles`,
|
|
1668
|
+
`stimBuild` or, with `build-compat`, `compat` in its place, complete `inputs` (`ignored`, `outputs`, `localFiles`,
|
|
1651
1669
|
`environment`) and `build` (`product`, `infoPlist`, `resources`, `assetCatalog`).
|
|
1652
1670
|
Resource and catalog paths are repository-relative; the plist is
|
|
1653
1671
|
project-relative. The worker verifies actual transferred files and full
|
|
@@ -1697,14 +1715,25 @@ connected since stim-server started keeps its directory when revoked.
|
|
|
1697
1715
|
simulator runtime identifier, required for `ios`, null for `android`),
|
|
1698
1716
|
`fingerprint`, `packageName`, `isExpo`, `optimizations`, `android` (for
|
|
1699
1717
|
`android`: `variant`, `abi`, `gradleBuildCache`, `pch` and `compilerCache`,
|
|
1700
|
-
`ccache` or `none`) and `
|
|
1718
|
+
`ccache` or `none`), `stimBuild` and, from a caller that saw `build-compat`, `compat`, after the whole manifest of `repo` was
|
|
1701
1719
|
synced on this connection. A peer-cache-capable React Native caller can set
|
|
1702
1720
|
`cacheArtifact: true` to retain a completed development archive when its cache
|
|
1703
|
-
write and remote policies allow it.
|
|
1721
|
+
write and remote policies allow it. With the `fingerprint-sources` feature, a
|
|
1722
|
+
caller can send `fingerprintSources`, the `id` and `hash` of each source of
|
|
1723
|
+
`fingerprint`, and a `fingerprint-mismatch` failure names the sources that
|
|
1724
|
+
differ and the synced files prebuild or `pod install` rewrote. With the
|
|
1725
|
+
`fingerprint-ignored` feature, it can send `fingerprintIgnored`, the paths
|
|
1726
|
+
relative to `project` that its git ignores for `fingerprint` through
|
|
1727
|
+
`.git/info/exclude` or a global excludes file, which the machine's synced
|
|
1728
|
+
checkout has no copy of. With the `fingerprint-tracked` feature, it can
|
|
1729
|
+
send `fingerprintTracked`, the top-level entry names of `project` that its
|
|
1730
|
+
git tracks although an ignore pattern matches them, which the machine's
|
|
1731
|
+
empty index would skip. It returns `{ "job" }`. It fails with
|
|
1704
1732
|
`build-busy` while the offer would be declined, naming the reason, or while
|
|
1705
1733
|
another build of the same client and repository runs, or while every one
|
|
1706
1734
|
of this machine's `concurrency.maxBuilds` slots is held, and with
|
|
1707
|
-
`build-refused` when `
|
|
1735
|
+
`build-refused` when `compat` differs from this machine's, or, when either
|
|
1736
|
+
side has no `compat`, when `stimBuild` differs. The build runs `offload-worker.mjs` of the bundled Stim with
|
|
1708
1737
|
`STIM_HOME` set to the repository's area. It makes the area's checkout
|
|
1709
1738
|
hold exactly the manifest (a file git lists as untracked and not ignored,
|
|
1710
1739
|
and not in the manifest, is deleted; ignored dependencies and generated
|
|
@@ -2497,7 +2526,6 @@ silent only when every notification it sums up is. An older server ignores
|
|
|
2497
2526
|
`levels` and alerts for every event but `started`.
|
|
2498
2527
|
|
|
2499
2528
|
The server and phone import the same pure rules from `@stim-cli/core/oversight`.
|
|
2500
|
-
The phone formats home attention messages locally from the facts the shared rule selects.
|
|
2501
2529
|
`__tests__/oversight-agreement.test.ts` checks their categories, workspace names
|
|
2502
2530
|
and needs-attention vectors. Notification delivery remains local to each.
|
|
2503
2531
|
|
|
@@ -290,15 +290,21 @@ const swiftpmArtifactInputs = {
|
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
};
|
|
293
|
+
const buildCompat = {
|
|
294
|
+
type: "integer",
|
|
295
|
+
minimum: 1,
|
|
296
|
+
description: "The Stim build compatibility version, sent to a stim-server with the build-compat feature."
|
|
297
|
+
};
|
|
298
|
+
const stimIdentity = [{ required: ["stimBuild"] }, { required: ["compat"] }];
|
|
293
299
|
const swiftpmArtifactQuery = {
|
|
294
300
|
type: "object",
|
|
295
301
|
required: [
|
|
296
302
|
"project",
|
|
297
303
|
"sourceDigest",
|
|
298
|
-
"stimBuild",
|
|
299
304
|
"inputs",
|
|
300
305
|
"build"
|
|
301
306
|
],
|
|
307
|
+
oneOf: stimIdentity,
|
|
302
308
|
additionalProperties: false,
|
|
303
309
|
properties: {
|
|
304
310
|
project: { type: "string" },
|
|
@@ -308,6 +314,7 @@ const swiftpmArtifactQuery = {
|
|
|
308
314
|
minLength: 1,
|
|
309
315
|
maxLength: 256
|
|
310
316
|
},
|
|
317
|
+
compat: buildCompat,
|
|
311
318
|
inputs: swiftpmArtifactInputs,
|
|
312
319
|
build: {
|
|
313
320
|
type: "object",
|
|
@@ -379,13 +386,14 @@ const reactNativeArtifactQuery = {
|
|
|
379
386
|
platform: { enum: ["ios", "android"] },
|
|
380
387
|
toolchain: {
|
|
381
388
|
type: "object",
|
|
382
|
-
|
|
389
|
+
oneOf: stimIdentity,
|
|
383
390
|
additionalProperties: false,
|
|
384
391
|
properties: {
|
|
385
392
|
stimBuild: {
|
|
386
393
|
type: "string",
|
|
387
394
|
minLength: 1
|
|
388
395
|
},
|
|
396
|
+
compat: buildCompat,
|
|
389
397
|
arch: {
|
|
390
398
|
type: "string",
|
|
391
399
|
minLength: 1
|
|
@@ -2275,6 +2283,20 @@ function protocolJsonSchema() {
|
|
|
2275
2283
|
pattern: "^[a-f0-9]{64}$"
|
|
2276
2284
|
}
|
|
2277
2285
|
}, ["gatewayPort", "secret"])),
|
|
2286
|
+
request("device-host.metro.ports", {
|
|
2287
|
+
type: "object",
|
|
2288
|
+
required: ["ports"],
|
|
2289
|
+
additionalProperties: false,
|
|
2290
|
+
properties: { ports: {
|
|
2291
|
+
type: "array",
|
|
2292
|
+
maxItems: 256,
|
|
2293
|
+
items: {
|
|
2294
|
+
type: "integer",
|
|
2295
|
+
minimum: 1,
|
|
2296
|
+
maximum: 65535
|
|
2297
|
+
}
|
|
2298
|
+
} }
|
|
2299
|
+
}),
|
|
2278
2300
|
request("device-host.metro.close", session({})),
|
|
2279
2301
|
request("device-host.frames.subscribe", session({
|
|
2280
2302
|
fps: {
|
|
@@ -3106,6 +3128,48 @@ function protocolJsonSchema() {
|
|
|
3106
3128
|
type: ["string", "null"],
|
|
3107
3129
|
minLength: 1
|
|
3108
3130
|
},
|
|
3131
|
+
fingerprintSources: {
|
|
3132
|
+
type: "array",
|
|
3133
|
+
maxItems: 2e4,
|
|
3134
|
+
description: "The id and hash of each source of fingerprint, to name the sources that differ.",
|
|
3135
|
+
items: {
|
|
3136
|
+
type: "object",
|
|
3137
|
+
required: ["id", "hash"],
|
|
3138
|
+
additionalProperties: false,
|
|
3139
|
+
properties: {
|
|
3140
|
+
id: {
|
|
3141
|
+
type: "string",
|
|
3142
|
+
minLength: 1,
|
|
3143
|
+
maxLength: 1024
|
|
3144
|
+
},
|
|
3145
|
+
hash: {
|
|
3146
|
+
type: ["string", "null"],
|
|
3147
|
+
pattern: "^[0-9a-f]{1,128}$"
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
},
|
|
3152
|
+
fingerprintIgnored: {
|
|
3153
|
+
type: "array",
|
|
3154
|
+
maxItems: 2e4,
|
|
3155
|
+
description: "Paths relative to project that git ignores for fingerprint on the caller, such as through .git/info/exclude.",
|
|
3156
|
+
items: {
|
|
3157
|
+
type: "string",
|
|
3158
|
+
minLength: 1,
|
|
3159
|
+
maxLength: 1024
|
|
3160
|
+
}
|
|
3161
|
+
},
|
|
3162
|
+
fingerprintTracked: {
|
|
3163
|
+
type: "array",
|
|
3164
|
+
maxItems: 2e4,
|
|
3165
|
+
description: "Top-level entries of project that the caller git tracks for fingerprint although an ignore pattern matches them.",
|
|
3166
|
+
items: {
|
|
3167
|
+
type: "string",
|
|
3168
|
+
minLength: 1,
|
|
3169
|
+
maxLength: 255,
|
|
3170
|
+
pattern: "^[^/\\u0000]+$"
|
|
3171
|
+
}
|
|
3172
|
+
},
|
|
3109
3173
|
native: { oneOf: [{
|
|
3110
3174
|
type: "object",
|
|
3111
3175
|
required: [
|
|
@@ -3248,6 +3312,10 @@ function protocolJsonSchema() {
|
|
|
3248
3312
|
stimBuild: {
|
|
3249
3313
|
type: "string",
|
|
3250
3314
|
minLength: 1
|
|
3315
|
+
},
|
|
3316
|
+
compat: {
|
|
3317
|
+
...buildCompat,
|
|
3318
|
+
description: "Compared instead of stimBuild by a machine whose build.offer toolchain reports compat."
|
|
3251
3319
|
}
|
|
3252
3320
|
}
|
|
3253
3321
|
}),
|
package/dist/protocol.mjs
CHANGED
|
@@ -1271,11 +1271,16 @@
|
|
|
1271
1271
|
"native-gradle-artifact-cache",
|
|
1272
1272
|
"native-gradle-peer-cache",
|
|
1273
1273
|
"react-native-peer-cache",
|
|
1274
|
+
"fingerprint-sources",
|
|
1275
|
+
"fingerprint-ignored",
|
|
1276
|
+
"fingerprint-tracked",
|
|
1274
1277
|
"swiftpm-peer-cache",
|
|
1275
1278
|
"build-dependency-cache",
|
|
1276
1279
|
"hosted-android-data",
|
|
1277
1280
|
"hosted-android-process",
|
|
1281
|
+
"hosted-metro-ports",
|
|
1278
1282
|
"server-update",
|
|
1283
|
+
"build-compat",
|
|
1279
1284
|
"status-views",
|
|
1280
1285
|
"desktop-reports",
|
|
1281
1286
|
"desktop-report-platform",
|
|
@@ -3183,6 +3188,44 @@
|
|
|
3183
3188
|
}
|
|
3184
3189
|
}
|
|
3185
3190
|
},
|
|
3191
|
+
{
|
|
3192
|
+
"type": "object",
|
|
3193
|
+
"required": [
|
|
3194
|
+
"id",
|
|
3195
|
+
"method",
|
|
3196
|
+
"params"
|
|
3197
|
+
],
|
|
3198
|
+
"additionalProperties": false,
|
|
3199
|
+
"properties": {
|
|
3200
|
+
"id": {
|
|
3201
|
+
"type": [
|
|
3202
|
+
"integer",
|
|
3203
|
+
"string"
|
|
3204
|
+
]
|
|
3205
|
+
},
|
|
3206
|
+
"method": {
|
|
3207
|
+
"const": "device-host.metro.ports"
|
|
3208
|
+
},
|
|
3209
|
+
"params": {
|
|
3210
|
+
"type": "object",
|
|
3211
|
+
"required": [
|
|
3212
|
+
"ports"
|
|
3213
|
+
],
|
|
3214
|
+
"additionalProperties": false,
|
|
3215
|
+
"properties": {
|
|
3216
|
+
"ports": {
|
|
3217
|
+
"type": "array",
|
|
3218
|
+
"maxItems": 256,
|
|
3219
|
+
"items": {
|
|
3220
|
+
"type": "integer",
|
|
3221
|
+
"minimum": 1,
|
|
3222
|
+
"maximum": 65535
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
},
|
|
3186
3229
|
{
|
|
3187
3230
|
"type": "object",
|
|
3188
3231
|
"required": [
|
|
@@ -6843,8 +6886,17 @@
|
|
|
6843
6886
|
},
|
|
6844
6887
|
"toolchain": {
|
|
6845
6888
|
"type": "object",
|
|
6846
|
-
"
|
|
6847
|
-
|
|
6889
|
+
"oneOf": [
|
|
6890
|
+
{
|
|
6891
|
+
"required": [
|
|
6892
|
+
"stimBuild"
|
|
6893
|
+
]
|
|
6894
|
+
},
|
|
6895
|
+
{
|
|
6896
|
+
"required": [
|
|
6897
|
+
"compat"
|
|
6898
|
+
]
|
|
6899
|
+
}
|
|
6848
6900
|
],
|
|
6849
6901
|
"additionalProperties": false,
|
|
6850
6902
|
"properties": {
|
|
@@ -6852,6 +6904,11 @@
|
|
|
6852
6904
|
"type": "string",
|
|
6853
6905
|
"minLength": 1
|
|
6854
6906
|
},
|
|
6907
|
+
"compat": {
|
|
6908
|
+
"type": "integer",
|
|
6909
|
+
"minimum": 1,
|
|
6910
|
+
"description": "The Stim build compatibility version, sent to a stim-server with the build-compat feature."
|
|
6911
|
+
},
|
|
6855
6912
|
"arch": {
|
|
6856
6913
|
"type": "string",
|
|
6857
6914
|
"minLength": 1
|
|
@@ -6988,10 +7045,21 @@
|
|
|
6988
7045
|
"required": [
|
|
6989
7046
|
"project",
|
|
6990
7047
|
"sourceDigest",
|
|
6991
|
-
"stimBuild",
|
|
6992
7048
|
"inputs",
|
|
6993
7049
|
"build"
|
|
6994
7050
|
],
|
|
7051
|
+
"oneOf": [
|
|
7052
|
+
{
|
|
7053
|
+
"required": [
|
|
7054
|
+
"stimBuild"
|
|
7055
|
+
]
|
|
7056
|
+
},
|
|
7057
|
+
{
|
|
7058
|
+
"required": [
|
|
7059
|
+
"compat"
|
|
7060
|
+
]
|
|
7061
|
+
}
|
|
7062
|
+
],
|
|
6995
7063
|
"additionalProperties": false,
|
|
6996
7064
|
"properties": {
|
|
6997
7065
|
"project": {
|
|
@@ -7006,6 +7074,11 @@
|
|
|
7006
7074
|
"minLength": 1,
|
|
7007
7075
|
"maxLength": 256
|
|
7008
7076
|
},
|
|
7077
|
+
"compat": {
|
|
7078
|
+
"type": "integer",
|
|
7079
|
+
"minimum": 1,
|
|
7080
|
+
"description": "The Stim build compatibility version, sent to a stim-server with the build-compat feature."
|
|
7081
|
+
},
|
|
7009
7082
|
"inputs": {
|
|
7010
7083
|
"type": "object",
|
|
7011
7084
|
"required": [
|
|
@@ -7303,6 +7376,54 @@
|
|
|
7303
7376
|
],
|
|
7304
7377
|
"minLength": 1
|
|
7305
7378
|
},
|
|
7379
|
+
"fingerprintSources": {
|
|
7380
|
+
"type": "array",
|
|
7381
|
+
"maxItems": 20000,
|
|
7382
|
+
"description": "The id and hash of each source of fingerprint, to name the sources that differ.",
|
|
7383
|
+
"items": {
|
|
7384
|
+
"type": "object",
|
|
7385
|
+
"required": [
|
|
7386
|
+
"id",
|
|
7387
|
+
"hash"
|
|
7388
|
+
],
|
|
7389
|
+
"additionalProperties": false,
|
|
7390
|
+
"properties": {
|
|
7391
|
+
"id": {
|
|
7392
|
+
"type": "string",
|
|
7393
|
+
"minLength": 1,
|
|
7394
|
+
"maxLength": 1024
|
|
7395
|
+
},
|
|
7396
|
+
"hash": {
|
|
7397
|
+
"type": [
|
|
7398
|
+
"string",
|
|
7399
|
+
"null"
|
|
7400
|
+
],
|
|
7401
|
+
"pattern": "^[0-9a-f]{1,128}$"
|
|
7402
|
+
}
|
|
7403
|
+
}
|
|
7404
|
+
}
|
|
7405
|
+
},
|
|
7406
|
+
"fingerprintIgnored": {
|
|
7407
|
+
"type": "array",
|
|
7408
|
+
"maxItems": 20000,
|
|
7409
|
+
"description": "Paths relative to project that git ignores for fingerprint on the caller, such as through .git/info/exclude.",
|
|
7410
|
+
"items": {
|
|
7411
|
+
"type": "string",
|
|
7412
|
+
"minLength": 1,
|
|
7413
|
+
"maxLength": 1024
|
|
7414
|
+
}
|
|
7415
|
+
},
|
|
7416
|
+
"fingerprintTracked": {
|
|
7417
|
+
"type": "array",
|
|
7418
|
+
"maxItems": 20000,
|
|
7419
|
+
"description": "Top-level entries of project that the caller git tracks for fingerprint although an ignore pattern matches them.",
|
|
7420
|
+
"items": {
|
|
7421
|
+
"type": "string",
|
|
7422
|
+
"minLength": 1,
|
|
7423
|
+
"maxLength": 255,
|
|
7424
|
+
"pattern": "^[^/\\u0000]+$"
|
|
7425
|
+
}
|
|
7426
|
+
},
|
|
7306
7427
|
"native": {
|
|
7307
7428
|
"oneOf": [
|
|
7308
7429
|
{
|
|
@@ -7562,6 +7683,11 @@
|
|
|
7562
7683
|
"stimBuild": {
|
|
7563
7684
|
"type": "string",
|
|
7564
7685
|
"minLength": 1
|
|
7686
|
+
},
|
|
7687
|
+
"compat": {
|
|
7688
|
+
"type": "integer",
|
|
7689
|
+
"minimum": 1,
|
|
7690
|
+
"description": "Compared instead of stimBuild by a machine whose build.offer toolchain reports compat."
|
|
7565
7691
|
}
|
|
7566
7692
|
}
|
|
7567
7693
|
}
|
|
@@ -7844,8 +7970,17 @@
|
|
|
7844
7970
|
},
|
|
7845
7971
|
"toolchain": {
|
|
7846
7972
|
"type": "object",
|
|
7847
|
-
"
|
|
7848
|
-
|
|
7973
|
+
"oneOf": [
|
|
7974
|
+
{
|
|
7975
|
+
"required": [
|
|
7976
|
+
"stimBuild"
|
|
7977
|
+
]
|
|
7978
|
+
},
|
|
7979
|
+
{
|
|
7980
|
+
"required": [
|
|
7981
|
+
"compat"
|
|
7982
|
+
]
|
|
7983
|
+
}
|
|
7849
7984
|
],
|
|
7850
7985
|
"additionalProperties": false,
|
|
7851
7986
|
"properties": {
|
|
@@ -7853,6 +7988,11 @@
|
|
|
7853
7988
|
"type": "string",
|
|
7854
7989
|
"minLength": 1
|
|
7855
7990
|
},
|
|
7991
|
+
"compat": {
|
|
7992
|
+
"type": "integer",
|
|
7993
|
+
"minimum": 1,
|
|
7994
|
+
"description": "The Stim build compatibility version, sent to a stim-server with the build-compat feature."
|
|
7995
|
+
},
|
|
7856
7996
|
"arch": {
|
|
7857
7997
|
"type": "string",
|
|
7858
7998
|
"minLength": 1
|
|
@@ -7989,10 +8129,21 @@
|
|
|
7989
8129
|
"required": [
|
|
7990
8130
|
"project",
|
|
7991
8131
|
"sourceDigest",
|
|
7992
|
-
"stimBuild",
|
|
7993
8132
|
"inputs",
|
|
7994
8133
|
"build"
|
|
7995
8134
|
],
|
|
8135
|
+
"oneOf": [
|
|
8136
|
+
{
|
|
8137
|
+
"required": [
|
|
8138
|
+
"stimBuild"
|
|
8139
|
+
]
|
|
8140
|
+
},
|
|
8141
|
+
{
|
|
8142
|
+
"required": [
|
|
8143
|
+
"compat"
|
|
8144
|
+
]
|
|
8145
|
+
}
|
|
8146
|
+
],
|
|
7996
8147
|
"additionalProperties": false,
|
|
7997
8148
|
"properties": {
|
|
7998
8149
|
"project": {
|
|
@@ -8007,6 +8158,11 @@
|
|
|
8007
8158
|
"minLength": 1,
|
|
8008
8159
|
"maxLength": 256
|
|
8009
8160
|
},
|
|
8161
|
+
"compat": {
|
|
8162
|
+
"type": "integer",
|
|
8163
|
+
"minimum": 1,
|
|
8164
|
+
"description": "The Stim build compatibility version, sent to a stim-server with the build-compat feature."
|
|
8165
|
+
},
|
|
8010
8166
|
"inputs": {
|
|
8011
8167
|
"type": "object",
|
|
8012
8168
|
"required": [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as protocol_exports } from "./protocol-
|
|
1
|
+
import { n as protocol_exports } from "./protocol-VEZO2CyR.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { execFile, execFileSync, spawn } from "node:child_process";
|
|
4
4
|
import { appendFileSync, chmodSync, closeSync, constants, copyFileSync, cpSync, createReadStream, existsSync, futimesSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, statfsSync, watch, writeFileSync, writeSync } from "node:fs";
|
|
@@ -3226,6 +3226,32 @@ function validFile(file) {
|
|
|
3226
3226
|
const validRepo = (repo) => typeof repo === "string" && new RegExp(protocol_exports.BUILD_REPO_PATTERN).test(repo);
|
|
3227
3227
|
const gb = (bytes) => (bytes / 1024 ** 3).toFixed(1);
|
|
3228
3228
|
const optional = (value) => typeof value === "string" ? value : null;
|
|
3229
|
+
const MAX_FINGERPRINT_SOURCES = 2e4;
|
|
3230
|
+
function fingerprintSources(value) {
|
|
3231
|
+
if (value === void 0) return void 0;
|
|
3232
|
+
if (!Array.isArray(value) || value.length > MAX_FINGERPRINT_SOURCES) return null;
|
|
3233
|
+
return value.every((source) => isJsonObject(source) && Object.keys(source).every((key) => key === "id" || key === "hash") && typeof source.id === "string" && source.id.length > 0 && source.id.length <= MAX_PATH_CHARS && (source.hash === null || typeof source.hash === "string" && /^[0-9a-f]{1,128}$/.test(source.hash))) ? value : null;
|
|
3234
|
+
}
|
|
3235
|
+
function fingerprintIgnored(value) {
|
|
3236
|
+
if (value === void 0) return void 0;
|
|
3237
|
+
if (!Array.isArray(value) || value.length > MAX_FINGERPRINT_SOURCES) return null;
|
|
3238
|
+
const paths = [];
|
|
3239
|
+
for (const path of value) {
|
|
3240
|
+
if (typeof path !== "string" || path.length === 0 || path.length > MAX_PATH_CHARS) return null;
|
|
3241
|
+
paths.push(path);
|
|
3242
|
+
}
|
|
3243
|
+
return paths;
|
|
3244
|
+
}
|
|
3245
|
+
function fingerprintTracked(value) {
|
|
3246
|
+
if (value === void 0) return void 0;
|
|
3247
|
+
if (!Array.isArray(value) || value.length > MAX_FINGERPRINT_SOURCES) return null;
|
|
3248
|
+
const names = [];
|
|
3249
|
+
for (const name of value) {
|
|
3250
|
+
if (!(typeof name === "string" && name.length > 0 && name.length <= 255 && name !== "." && name !== ".." && !/[/\0]/.test(name))) return null;
|
|
3251
|
+
names.push(name);
|
|
3252
|
+
}
|
|
3253
|
+
return names;
|
|
3254
|
+
}
|
|
3229
3255
|
const GRADLE_NAME = /^[A-Za-z0-9_-]{1,100}$/;
|
|
3230
3256
|
const GRADLE_ROOT = /^[A-Za-z0-9._/ -]{1,200}$/;
|
|
3231
3257
|
const GRADLE_MODULE = /^(:(?!\.\.?(?::|$))[A-Za-z0-9._-]+){1,20}$/;
|
|
@@ -3257,7 +3283,7 @@ function macosBuildOptions(params) {
|
|
|
3257
3283
|
const artifactQuery = options.artifactInputs === void 0 ? null : swiftpmArtifactQuery({
|
|
3258
3284
|
project: params.project,
|
|
3259
3285
|
sourceDigest: params.fingerprint,
|
|
3260
|
-
stimBuild: params.stimBuild,
|
|
3286
|
+
...typeof params.compat === "number" ? { compat: params.compat } : { stimBuild: params.stimBuild },
|
|
3261
3287
|
inputs: options.artifactInputs,
|
|
3262
3288
|
build: {
|
|
3263
3289
|
product: options.product,
|
|
@@ -3522,7 +3548,7 @@ var BuildHost = class {
|
|
|
3522
3548
|
},
|
|
3523
3549
|
warm: {
|
|
3524
3550
|
checkout: existsSync(join(area, "src")),
|
|
3525
|
-
dependencies: typeof params.lockfile === "string" && dependencies !== void 0 && reusableDependencies(area, dependencies.project,
|
|
3551
|
+
dependencies: typeof params.lockfile === "string" && dependencies !== void 0 && reusableDependencies(area, dependencies.project, params.lockfile, this.options.env),
|
|
3526
3552
|
build: false
|
|
3527
3553
|
},
|
|
3528
3554
|
...artifact !== void 0 ? { artifact } : {}
|
|
@@ -3610,7 +3636,7 @@ var BuildHost = class {
|
|
|
3610
3636
|
const query = swiftpmArtifactQuery({
|
|
3611
3637
|
project: job.project,
|
|
3612
3638
|
sourceDigest: job.expectedFingerprint,
|
|
3613
|
-
stimBuild: job.stimBuild,
|
|
3639
|
+
...typeof job.compat === "number" ? { compat: job.compat } : { stimBuild: job.stimBuild },
|
|
3614
3640
|
inputs: options.artifactInputs,
|
|
3615
3641
|
build: {
|
|
3616
3642
|
product: options.product,
|
|
@@ -4305,7 +4331,13 @@ var BuildSession = class {
|
|
|
4305
4331
|
native = input;
|
|
4306
4332
|
}
|
|
4307
4333
|
if (native?.provider !== "gradle" && (typeof params.fingerprint !== "string" || !params.fingerprint)) return refusal("bad-request", "build.start needs params.fingerprint.");
|
|
4334
|
+
const expectedSources = fingerprintSources(params.fingerprintSources);
|
|
4335
|
+
if (expectedSources === null) return refusal("bad-request", `params.fingerprintSources must be at most ${MAX_FINGERPRINT_SOURCES} sources, each an id and a hex hash or null.`);
|
|
4308
4336
|
if (!native && [...this.files.values()].some((file) => file.kind === "directory")) return refusal("bad-request", "Directory entries require a native build request.");
|
|
4337
|
+
const expectedIgnored = fingerprintIgnored(params.fingerprintIgnored);
|
|
4338
|
+
if (expectedIgnored === null) return refusal("bad-request", `params.fingerprintIgnored must be at most ${MAX_FINGERPRINT_SOURCES} paths of at most ${MAX_PATH_CHARS} characters.`);
|
|
4339
|
+
const expectedTracked = fingerprintTracked(params.fingerprintTracked);
|
|
4340
|
+
if (expectedTracked === null) return refusal("bad-request", `params.fingerprintTracked must be at most ${MAX_FINGERPRINT_SOURCES} top-level entry names.`);
|
|
4309
4341
|
const android = platform === "android" ? androidOptions(params.android) : null;
|
|
4310
4342
|
if (platform === "android" && !android) return refusal("bad-request", "An android build needs params.android: variant and abi (string or null), gradleBuildCache, pch and compilerCache.");
|
|
4311
4343
|
let macos = null;
|
|
@@ -4320,7 +4352,11 @@ var BuildSession = class {
|
|
|
4320
4352
|
for (const file of this.files.values()) if (!existsSync(this.blobPath(file.sha256))) return refusal("bad-request", `The blob of ${file.path} is missing; sync again.`);
|
|
4321
4353
|
const toolchain = await this.host.toolchain(null, native?.provider);
|
|
4322
4354
|
if (this.closed) return refusal("build-refused", "The connection closed.");
|
|
4323
|
-
|
|
4355
|
+
const compat = typeof params.compat === "number" ? params.compat : void 0;
|
|
4356
|
+
if (!toolchain) return refusal("build-refused", "This machine runs Stim build unknown.");
|
|
4357
|
+
if (compat !== void 0 && toolchain.compat !== void 0) {
|
|
4358
|
+
if (toolchain.compat !== compat) return refusal("build-refused", `This machine runs Stim build ${toolchain.stimBuild ?? "unknown"} with build compatibility ${toolchain.compat}, not ${compat}.`);
|
|
4359
|
+
} else if (toolchain.stimBuild !== params.stimBuild) return refusal("build-refused", `This machine runs Stim build ${toolchain.stimBuild ?? "unknown"}.`);
|
|
4324
4360
|
const launched = this.host.launch({
|
|
4325
4361
|
client: this.client,
|
|
4326
4362
|
repo: params.repo,
|
|
@@ -4333,15 +4369,18 @@ var BuildSession = class {
|
|
|
4333
4369
|
android,
|
|
4334
4370
|
macos,
|
|
4335
4371
|
project: params.project,
|
|
4336
|
-
packageName: optional(params.packageName),
|
|
4337
4372
|
isExpo: params.isExpo === true,
|
|
4338
4373
|
cacheArtifact: params.cacheArtifact === true,
|
|
4339
4374
|
stimBuild: params.stimBuild,
|
|
4375
|
+
...compat !== void 0 && toolchain.compat !== void 0 ? { compat } : {},
|
|
4340
4376
|
configuration: optional(params.configuration),
|
|
4341
4377
|
scheme: optional(params.scheme),
|
|
4342
4378
|
iosProjectPath: optional(params.iosProjectPath),
|
|
4343
4379
|
runtime: optional(params.runtime),
|
|
4344
4380
|
expectedFingerprint: params.fingerprint,
|
|
4381
|
+
...expectedSources ? { expectedSources } : {},
|
|
4382
|
+
...expectedIgnored ? { expectedIgnored } : {},
|
|
4383
|
+
...expectedTracked ? { expectedTracked } : {},
|
|
4345
4384
|
optimizations: isJsonObject(params.optimizations) ? params.optimizations : null
|
|
4346
4385
|
}
|
|
4347
4386
|
});
|
|
@@ -6823,6 +6862,28 @@ function hostedDeviceExclusions(records) {
|
|
|
6823
6862
|
key: hostedDeviceId(record.device)
|
|
6824
6863
|
}] : []);
|
|
6825
6864
|
}
|
|
6865
|
+
/** macOS lets 127.0.0.1 bind beside a wildcard listener and takes its loopback traffic, so probe by connecting. */
|
|
6866
|
+
function loopbackAccepts(port) {
|
|
6867
|
+
const accepts = (host) => new Promise((resolve) => {
|
|
6868
|
+
const socket = connect({
|
|
6869
|
+
host,
|
|
6870
|
+
port
|
|
6871
|
+
});
|
|
6872
|
+
const done = (open) => {
|
|
6873
|
+
socket.destroy();
|
|
6874
|
+
resolve(open);
|
|
6875
|
+
};
|
|
6876
|
+
socket.setTimeout(1e3, () => done(true));
|
|
6877
|
+
socket.once("connect", () => done(true));
|
|
6878
|
+
socket.once("error", (error) => done(![
|
|
6879
|
+
"ECONNREFUSED",
|
|
6880
|
+
"EADDRNOTAVAIL",
|
|
6881
|
+
"EAFNOSUPPORT",
|
|
6882
|
+
"ENETUNREACH"
|
|
6883
|
+
].includes(error.code ?? "")));
|
|
6884
|
+
});
|
|
6885
|
+
return Promise.all([accepts("127.0.0.1"), accepts("::1")]).then((open) => open.includes(true));
|
|
6886
|
+
}
|
|
6826
6887
|
/** Owns hosted reservations, not build jobs or viewer connections. Native work runs in the packaged CLI child. */
|
|
6827
6888
|
var DeviceHost = class {
|
|
6828
6889
|
owned = /* @__PURE__ */ new Map();
|
|
@@ -7190,15 +7251,20 @@ var DeviceHost = class {
|
|
|
7190
7251
|
await this.restoreAndroidMetro(record, owned);
|
|
7191
7252
|
return { result: { port } };
|
|
7192
7253
|
}
|
|
7254
|
+
const devClientPort = record.platform === "ios" ? params.clientMetroPort : void 0;
|
|
7193
7255
|
const bridge = createMetroBridge({
|
|
7194
7256
|
peer,
|
|
7195
7257
|
gatewayPort: params.gatewayPort,
|
|
7196
7258
|
secret: params.secret
|
|
7197
7259
|
});
|
|
7198
|
-
const
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7260
|
+
const inUse = () => Object.assign(/* @__PURE__ */ new Error(`Port ${devClientPort} is in use on the hosting Mac, and an Expo dev client loads its bundle from the client's Metro port.`), { code: "device-busy" });
|
|
7261
|
+
const ready = (async () => {
|
|
7262
|
+
if (devClientPort !== void 0 && await loopbackAccepts(devClientPort)) throw inUse();
|
|
7263
|
+
return new Promise((resolve, reject) => {
|
|
7264
|
+
bridge.server.once("error", (error) => reject(devClientPort !== void 0 && error.code === "EADDRINUSE" ? inUse() : error));
|
|
7265
|
+
bridge.server.listen(devClientPort ?? record.metroPort ?? 0, "127.0.0.1", () => resolve(bridge.server.address().port));
|
|
7266
|
+
});
|
|
7267
|
+
})();
|
|
7202
7268
|
const metro = {
|
|
7203
7269
|
bridge,
|
|
7204
7270
|
ready,
|
|
@@ -7224,7 +7290,7 @@ var DeviceHost = class {
|
|
|
7224
7290
|
throw error;
|
|
7225
7291
|
}
|
|
7226
7292
|
} catch (error) {
|
|
7227
|
-
return refused$1("action-failed", error.message);
|
|
7293
|
+
return refused$1(error.code === "device-busy" ? "device-busy" : "action-failed", error.message);
|
|
7228
7294
|
}
|
|
7229
7295
|
}
|
|
7230
7296
|
async restoreAndroidMetro(record, owned) {
|
|
@@ -7253,6 +7319,24 @@ var DeviceHost = class {
|
|
|
7253
7319
|
if (owned.data === settled) delete owned.data;
|
|
7254
7320
|
}
|
|
7255
7321
|
}
|
|
7322
|
+
/** Names the ports a new dev-client bridge could not bind, apart from this client's own dev-client bridges. */
|
|
7323
|
+
async metroPorts(client, params) {
|
|
7324
|
+
if (this.closed || !this.options.allowed(client)) return refused$1("forbidden", "Current device-host approval is required.");
|
|
7325
|
+
if (!isJsonObject(params) || !Array.isArray(params.ports) || params.ports.length > 256 || params.ports.some((port) => typeof port !== "number" || !Number.isInteger(port) || port < 1 || port > 65535)) return refused$1("bad-request", "Metro ports needs at most 256 TCP ports.");
|
|
7326
|
+
try {
|
|
7327
|
+
const ports = [...new Set(params.ports)];
|
|
7328
|
+
const sessions = new Set(readHostedSessions().flatMap((record) => record.client === client ? [record.id] : []));
|
|
7329
|
+
const own = new Set([...this.owned].flatMap(([id, { metro }]) => sessions.has(id) && metro?.port !== void 0 && metro.port === metro.clientMetroPort ? [metro.port] : []));
|
|
7330
|
+
const busy = [];
|
|
7331
|
+
const queue = ports.filter((port) => !own.has(port));
|
|
7332
|
+
await Promise.all(Array.from({ length: 16 }, async () => {
|
|
7333
|
+
for (let port = queue.shift(); port !== void 0; port = queue.shift()) if (await loopbackAccepts(port)) busy.push(port);
|
|
7334
|
+
}));
|
|
7335
|
+
return { result: { busy: busy.toSorted((a, b) => a - b) } };
|
|
7336
|
+
} catch (error) {
|
|
7337
|
+
return refused$1("action-failed", error.message);
|
|
7338
|
+
}
|
|
7339
|
+
}
|
|
7256
7340
|
async metroClose(client, params) {
|
|
7257
7341
|
if (!this.options.allowed(client)) return refused$1("forbidden", "Current device-host approval is required.");
|
|
7258
7342
|
if (!isJsonObject(params) || typeof params.session !== "string") return refused$1("bad-request", "Metro close needs a session.");
|
|
@@ -16909,7 +16993,7 @@ async function startServer(options) {
|
|
|
16909
16993
|
});
|
|
16910
16994
|
}
|
|
16911
16995
|
if (method.startsWith("device-host.input.")) return input(id, method.slice(12), raw, session);
|
|
16912
|
-
const answer = method === "device-host.offer" ? await hostedDevices.offer(session.id, raw) : method === "device-host.reserve" ? await hostedDevices.reserve(session.id, raw) : method === "device-host.attach" ? hostedDevices.attach(session.id, raw) : method === "device-host.stop" ? hostedDevices.stop(session.id, raw) : method === "device-host.app.offer" ? hostedDevices.appOffer(session.id, raw) : method === "device-host.app.chunk" ? await hostedDevices.appChunk(session.id, raw) : method === "device-host.app.handoff" ? await hostedDevices.appHandoff(session.id, raw) : method === "device-host.app.launch" ? hostedDevices.appLaunch(session.id, raw) : method === "device-host.app.attach" ? hostedDevices.appAttach(session.id, raw) : method === "device-host.logs.query" ? await hostedDevices.logsQuery(session.id, raw) : method === "device-host.metro.open" ? await hostedDevices.metroOpen(session.id, raw, peer) : await hostedDevices.metroClose(session.id, raw);
|
|
16996
|
+
const answer = method === "device-host.offer" ? await hostedDevices.offer(session.id, raw) : method === "device-host.reserve" ? await hostedDevices.reserve(session.id, raw) : method === "device-host.attach" ? hostedDevices.attach(session.id, raw) : method === "device-host.stop" ? hostedDevices.stop(session.id, raw) : method === "device-host.app.offer" ? hostedDevices.appOffer(session.id, raw) : method === "device-host.app.chunk" ? await hostedDevices.appChunk(session.id, raw) : method === "device-host.app.handoff" ? await hostedDevices.appHandoff(session.id, raw) : method === "device-host.app.launch" ? hostedDevices.appLaunch(session.id, raw) : method === "device-host.app.attach" ? hostedDevices.appAttach(session.id, raw) : method === "device-host.logs.query" ? await hostedDevices.logsQuery(session.id, raw) : method === "device-host.metro.open" ? await hostedDevices.metroOpen(session.id, raw, peer) : method === "device-host.metro.ports" ? await hostedDevices.metroPorts(session.id, raw) : await hostedDevices.metroClose(session.id, raw);
|
|
16913
16997
|
return send(socket, "error" in answer ? {
|
|
16914
16998
|
id,
|
|
16915
16999
|
error: answer.error
|
package/dist/stim-server.mjs
CHANGED
|
@@ -4,6 +4,6 @@ const encode = (version) => version.split(".", 3).reduce((sum, part) => sum * 1e
|
|
|
4
4
|
if (encode(process.versions.node) < encode("22.12.0")) {
|
|
5
5
|
process.stderr.write(`STIM_NODE_UNSUPPORTED: stim-server needs Node 22.12.0 or later; this is Node ${process.versions.node} at ${process.execPath}. To run stim-server where a project pins an older Node, see https://stim.appandflow.com/docs/requirements#older-node-pins\n`);
|
|
6
6
|
process.exitCode = 1;
|
|
7
|
-
} else import("./stim-server-
|
|
7
|
+
} else import("./stim-server-DowAx-6v.mjs");
|
|
8
8
|
//#endregion
|
|
9
9
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stim-cli/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Serves Stim status to paired clients over Tailscale, and runs reload and stop for clients granted control.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"./protocol.schema.json": "./dist/protocol.schema.json"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@stim-cli/agent-driver": "
|
|
32
|
-
"@stim-cli/agent-driver-agent-device": "
|
|
33
|
-
"@stim-cli/cache": "
|
|
34
|
-
"@stim-cli/core": "
|
|
35
|
-
"@stim-cli/transport": "
|
|
36
|
-
"@stim-cli/transport-tailscale": "
|
|
37
|
-
"stim": "1.
|
|
31
|
+
"@stim-cli/agent-driver": "1.25.0",
|
|
32
|
+
"@stim-cli/agent-driver-agent-device": "1.25.0",
|
|
33
|
+
"@stim-cli/cache": "1.25.0",
|
|
34
|
+
"@stim-cli/core": "1.25.0",
|
|
35
|
+
"@stim-cli/transport": "1.25.0",
|
|
36
|
+
"@stim-cli/transport-tailscale": "1.25.0",
|
|
37
|
+
"stim": "1.25.0",
|
|
38
38
|
"ws": "^8.21.3"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|