@stim-cli/core 1.20.2 → 1.22.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.
Files changed (34) hide show
  1. package/README.md +2 -0
  2. package/dist/{core-BkgfKqJ8.mjs → core-BTsCO1nW.mjs} +444 -60
  3. package/dist/{index-VDWBflH3.d.mts → index-DKq1j8dw.d.mts} +340 -91
  4. package/dist/index.d.mts +101 -5
  5. package/dist/index.mjs +3 -3
  6. package/dist/keyed-delta-BBoOeR2J.mjs +289 -0
  7. package/dist/noise-DYIbymAJ.d.mts +100 -0
  8. package/dist/noise-session.d.mts +164 -0
  9. package/dist/noise-session.mjs +402 -0
  10. package/dist/noise.d.mts +2 -0
  11. package/dist/noise.mjs +393 -0
  12. package/dist/oversight.mjs +16 -6
  13. package/dist/{ownership-claim-O31Y5iIb.mjs → ownership-claim-DHUs_Dir.mjs} +1 -1
  14. package/dist/{ownership-claim-Xxxr9MPp.d.mts → ownership-claim-RY3fbm1D.d.mts} +3 -2
  15. package/dist/ownership-claim.d.mts +2 -2
  16. package/dist/ownership-claim.mjs +2 -2
  17. package/dist/phone-protocol.d.mts +85 -16
  18. package/dist/phone-protocol.mjs +2 -2
  19. package/dist/{process-identity-BTyww2Xj.d.mts → process-identity-DVNGpF5c.d.mts} +1 -1
  20. package/dist/process-identity.d.mts +1 -1
  21. package/dist/process-identity.mjs +3 -1
  22. package/dist/{protocol-pH632kA3.d.mts → protocol-BjJt4ghB.d.mts} +632 -65
  23. package/dist/protocol.d.mts +2 -2
  24. package/dist/protocol.mjs +81 -10
  25. package/dist/receive-protocol.d.mts +1 -1
  26. package/dist/receive-protocol.mjs +20163 -14469
  27. package/dist/state.d.mts +2 -2
  28. package/dist/state.mjs +1261 -208
  29. package/dist/toolchain.d.mts +64 -0
  30. package/dist/toolchain.mjs +326 -0
  31. package/dist/workspace-link.d.mts +16 -0
  32. package/dist/workspace-link.mjs +50 -0
  33. package/package.json +21 -1
  34. package/dist/status-derived-C13g6eQt.mjs +0 -151
package/dist/index.d.mts CHANGED
@@ -1,13 +1,59 @@
1
+ import { N as BuildSwiftpmArtifactQuery, j as BuildReactNativeArtifactQuery, m as BuildArtifactIdentity } from "./protocol-BjJt4ghB.mjs";
1
2
  import { Server } from "node:net";
2
3
  //#region dir-lock.d.ts
3
4
  interface DirLockOptions {
4
- /** @deprecated Occupied locks are never expired. */
5
- staleMs?: number;
6
5
  waitMs?: number;
7
6
  pollMs?: number;
8
7
  ensureParent?: () => void;
9
8
  }
10
9
  declare function withDirLock<T>(lockPath: string, fn: () => T, { waitMs, pollMs, ensureParent }?: DirLockOptions): T;
10
+ /**
11
+ * `withDirLock` that waits for a contended lock on a timer instead of blocking the thread. `fn` still runs
12
+ * synchronously: nothing awaits between taking the lock, running `fn` and releasing the lock, so the held
13
+ * transaction and reentrant nesting behave exactly as with `withDirLock`.
14
+ * An optional signal cancels acquisition; it cannot interrupt the synchronous transaction.
15
+ */
16
+ declare function withDirLockAsync<T>(lockPath: string, fn: () => T, options?: DirLockOptions & {
17
+ signal?: AbortSignal;
18
+ }): Promise<T>;
19
+ /**
20
+ * Holds the directory lock and its ownership claim until the body settles. Transactions are exclusive even
21
+ * within one process and are not reentrant. Cancellation stops acquisition; the body owns cancellation after admission.
22
+ */
23
+ declare function withDirLockTransaction<T>(lockPath: string, fn: () => T | Promise<T>, options?: DirLockOptions & {
24
+ signal?: AbortSignal;
25
+ }): Promise<T>;
26
+ //#endregion
27
+ //#region context.d.ts
28
+ /** Where an operation writes progress that the CLI prints and an API client receives through `onProgress`. */
29
+ type StimOutput = (stream: "stdout" | "stderr", text: string) => void;
30
+ /**
31
+ * Everything one Stim operation takes from its caller instead of from `process`. The CLI builds one per command
32
+ * from `process`; `createStim` builds one per operation from the client's options. Engine code receives it as a
33
+ * parameter.
34
+ */
35
+ interface StimContext {
36
+ home: string;
37
+ buildCache: string | null;
38
+ projectRoot: string;
39
+ env: NodeJS.ProcessEnv;
40
+ cwd: string;
41
+ runId: string;
42
+ signal: AbortSignal;
43
+ output: StimOutput;
44
+ }
45
+ /**
46
+ * Runs `fn` with `context` reachable through `ambientContext()`, including after an `await` inside it. A temporary
47
+ * bridge for call sites that are not passed a context yet: `configDir()`, `runId()` and the exec wrapper's base
48
+ * environment.
49
+ */
50
+ declare function withAmbientContext<T>(context: StimContext, fn: () => T): T;
51
+ /** The context set by `withAmbientContext`, for call sites that are not passed one yet. */
52
+ declare function ambientContext(): StimContext | undefined;
53
+ /** Writes `text` to the ambient context's output, or to the process stream outside one. */
54
+ declare function ambientWrite(stream: "stdout" | "stderr", text: string): void;
55
+ /** The environment of the ambient context, or `process.env` outside one. */
56
+ declare function ambientEnv(): NodeJS.ProcessEnv;
11
57
  //#endregion
12
58
  //#region macos-resources.d.ts
13
59
  /** Whether a resource destination is a contained, non-empty path under Contents/Resources. */
@@ -17,6 +63,22 @@ declare function validMacosResourceDestination(value: unknown): value is string;
17
63
  /** Quote a path for a shell command Stim prints for a human to copy and run. */
18
64
  declare function quotedPath(path: string): string;
19
65
  //#endregion
66
+ //#region systemd-unit.d.ts
67
+ /**
68
+ * One double-quoted word as systemd.syntax(7) reads it: C escapes inside the quotes, `%` doubled because unit files
69
+ * expand specifiers, and in `ExecStart=` `$` doubled because systemd expands variables in command lines.
70
+ */
71
+ declare function quoteUnitWord(value: string, exec: boolean): string;
72
+ /** The words of a unit value `quoteUnitWord` wrote, or null when the value is not in that form. */
73
+ declare function unitWords(line: string, exec: boolean): string[] | null;
74
+ interface UnitLine {
75
+ section: string;
76
+ key: string;
77
+ value: string;
78
+ }
79
+ /** The `key=value` lines of a unit file with the section each is in, skipping comments and blank lines. */
80
+ declare function unitLines(text: string): UnitLine[];
81
+ //#endregion
20
82
  //#region artifact-store.d.ts
21
83
  declare function artifactIn(dir: string): string | null;
22
84
  declare function resolveArtifact(dir: string): string | null;
@@ -28,21 +90,42 @@ interface StoreArtifactOptions {
28
90
  }
29
91
  declare function storeArtifact(dest: string, buildPath: string, { runFile, overwrite, writeMetadata, onRenameError }: StoreArtifactOptions): string | null;
30
92
  //#endregion
93
+ //#region artifact-store-async.d.ts
94
+ interface AsyncStoreArtifactOptions extends Omit<StoreArtifactOptions, "runFile"> {
95
+ /** Resolves after the copy and its owned child work have ended. */
96
+ runFile: (file: string, args: string[]) => Promise<unknown>;
97
+ signal?: AbortSignal;
98
+ }
99
+ /** Awaits copying before atomic publication; cancellation before publication preserves the previous entry. */
100
+ declare function storeArtifactAsync(dest: string, buildPath: string, { runFile, overwrite, writeMetadata, onRenameError, signal }: AsyncStoreArtifactOptions): Promise<string | null>;
101
+ //#endregion
31
102
  //#region compiled-helper.d.ts
32
103
  /**
33
104
  * Returns `<dir>/<name>-<hash>`, compiling it with `compile` first when it is missing. The hash covers `version` and
34
105
  * each input's name and bytes, so a changed source or compiler builds a new helper beside the old one. `compile`
35
106
  * writes to a private temporary path that is renamed into place, so concurrent builders never expose a partial file.
36
- * Pruning is best effort and keeps this helper, the newest previous build, helpers modified in the last ten minutes and running helpers. It runs after a build and on the first call per process.
107
+ * Pruning is best effort and keeps this helper, the newest previous build, helpers modified in the last ten minutes and running helpers. It runs after a build and on the first call per process unless `prune` is false.
37
108
  */
38
- declare function compiledHelper({ dir, name, inputs, version, compile }: {
109
+ declare function compiledHelper({ dir, name, inputs, version, compile, prune }: {
39
110
  dir: string;
40
111
  name: string;
41
112
  inputs: readonly string[];
42
113
  version: string;
43
114
  compile: (output: string) => Promise<void>;
115
+ prune?: boolean;
44
116
  }): Promise<string>;
45
117
  //#endregion
118
+ //#region dependency-install.d.ts
119
+ /** The existing worker install command and marker identity for a repository's selected lockfile. */
120
+ declare function dependencyInstall(root: string, packageName: string | null): {
121
+ command: "pnpm" | "yarn" | "npm";
122
+ args: string[];
123
+ lockfile: string;
124
+ digest: string;
125
+ } | null;
126
+ /** Whether the worker can reuse this project's dependency install without running the package manager. */
127
+ declare function reusableDependencies(area: string, project: string, packageName: string | null, lockfile: string): boolean;
128
+ //#endregion
46
129
  //#region metro-bridge.d.ts
47
130
  interface MetroBridge {
48
131
  server: Server;
@@ -61,6 +144,19 @@ declare function createMetroBridge({ gatewayPort, peer, secret }: {
61
144
  secret: string;
62
145
  }): MetroBridge;
63
146
  //#endregion
147
+ //#region react-native-artifact.d.ts
148
+ /** Validates and canonicalizes the choices used by completed React Native peer artifacts. */
149
+ declare function reactNativeArtifactQuery(value: unknown): BuildReactNativeArtifactQuery | null;
150
+ /** The identity of a canonical React Native query and the toolchain verified around its build. */
151
+ declare function reactNativeArtifactIdentity(receipt: {
152
+ query: BuildReactNativeArtifactQuery;
153
+ toolchain: object;
154
+ }): BuildArtifactIdentity;
155
+ //#endregion
156
+ //#region swiftpm-artifact.d.ts
157
+ /** Validates and canonicalizes the source and build choices of a completed SwiftPM peer artifact. */
158
+ declare function swiftpmArtifactQuery(value: unknown): BuildSwiftpmArtifactQuery | null;
159
+ //#endregion
64
160
  //#region index.d.ts
65
161
  declare function configDir(): string;
66
162
  /** Creates `dir` and its missing parents owner-only, and narrows an existing `dir` that grants group or other access when the filesystem and owner allow it. */
@@ -125,4 +221,4 @@ declare function updateCacheManifest(file: string, mutate: (caches: Array<Record
125
221
  declare function cacheDirRefusal(dir: string): string | null;
126
222
  declare function registerCache({ dir, name, prune, note, entriesDepth, layout, replaces }: RegisterOptions): void;
127
223
  //#endregion
128
- export { BuildRunOptions, CacheManifest, CacheRegistrationMatch, type DirLockOptions, LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, type MetroBridge, RegisterOptions, STORE_ROOT_TAG, type StoreArtifactOptions, artifactIn, buildCacheKey, buildCacheRoot, cacheDirRefusal, cacheManifestLockPath, cacheNameSegment, cachePathSetting, compiledHelper, configDir, createMetroBridge, createMetroGateway, ensurePrivateDir, hostSimulatorArch, metroCacheRoot, quotedPath, readCacheManifest, registerCache, resolveArtifact, rotateLog, rotatedLogPath, sharedStoreRoot, storeArtifact, tagSharedStore, updateCacheManifest, validMacosResourceDestination, withDirLock, workspaceId, workspaceLogDir, workspaceName, workspaceSlug, workspaceStateDir };
224
+ export { type AsyncStoreArtifactOptions, BuildRunOptions, CacheManifest, CacheRegistrationMatch, type DirLockOptions, LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, type MetroBridge, RegisterOptions, STORE_ROOT_TAG, type StimContext, type StimOutput, type StoreArtifactOptions, type UnitLine, ambientContext, ambientEnv, ambientWrite, artifactIn, buildCacheKey, buildCacheRoot, cacheDirRefusal, cacheManifestLockPath, cacheNameSegment, cachePathSetting, compiledHelper, configDir, createMetroBridge, createMetroGateway, dependencyInstall, ensurePrivateDir, hostSimulatorArch, metroCacheRoot, quoteUnitWord, quotedPath, reactNativeArtifactIdentity, reactNativeArtifactQuery, readCacheManifest, registerCache, resolveArtifact, reusableDependencies, rotateLog, rotatedLogPath, sharedStoreRoot, storeArtifact, storeArtifactAsync, swiftpmArtifactQuery, tagSharedStore, unitLines, unitWords, updateCacheManifest, validMacosResourceDestination, withAmbientContext, withDirLock, withDirLockAsync, withDirLockTransaction, workspaceId, workspaceLogDir, workspaceName, workspaceSlug, workspaceStateDir };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { S as quotedPath } from "./ownership-claim-O31Y5iIb.mjs";
2
- import { A as resolveArtifact, C as workspaceName, D as createMetroGateway, E as createMetroBridge, M as validMacosResourceDestination, O as compiledHelper, R as withDirLock, S as workspaceLogDir, T as workspaceStateDir, _ as rotatedLogPath, a as buildCacheRoot, b as updateCacheManifest, c as cacheNameSegment, d as ensurePrivateDir, f as hostSimulatorArch, g as rotateLog, h as registerCache, i as buildCacheKey, j as storeArtifact, k as artifactIn, l as cachePathSetting, m as readCacheManifest, n as METRO_NAMED_CACHE_LAYOUT, o as cacheDirRefusal, p as metroCacheRoot, r as STORE_ROOT_TAG, s as cacheManifestLockPath, t as LOG_ROTATE_BYTES, u as configDir, v as sharedStoreRoot, w as workspaceSlug, x as workspaceId, y as tagSharedStore } from "./core-BkgfKqJ8.mjs";
3
- export { LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, STORE_ROOT_TAG, artifactIn, buildCacheKey, buildCacheRoot, cacheDirRefusal, cacheManifestLockPath, cacheNameSegment, cachePathSetting, compiledHelper, configDir, createMetroBridge, createMetroGateway, ensurePrivateDir, hostSimulatorArch, metroCacheRoot, quotedPath, readCacheManifest, registerCache, resolveArtifact, rotateLog, rotatedLogPath, sharedStoreRoot, storeArtifact, tagSharedStore, updateCacheManifest, validMacosResourceDestination, withDirLock, workspaceId, workspaceLogDir, workspaceName, workspaceSlug, workspaceStateDir };
1
+ import { C as quotedPath } from "./ownership-claim-DHUs_Dir.mjs";
2
+ import { $ as withDirLockTransaction, A as createMetroGateway, B as unitWords, C as workspaceName, D as reactNativeArtifactIdentity, E as swiftpmArtifactQuery, F as artifactIn, G as withAmbientContext, H as ambientContext, I as resolveArtifact, L as storeArtifact, M as reusableDependencies, N as compiledHelper, O as reactNativeArtifactQuery, P as storeArtifactAsync, Q as withDirLockAsync, R as quoteUnitWord, S as workspaceLogDir, T as workspaceStateDir, U as ambientEnv, V as validMacosResourceDestination, W as ambientWrite, Z as withDirLock, _ as rotatedLogPath, a as buildCacheRoot, b as updateCacheManifest, c as cacheNameSegment, d as ensurePrivateDir, f as hostSimulatorArch, g as rotateLog, h as registerCache, i as buildCacheKey, j as dependencyInstall, k as createMetroBridge, l as cachePathSetting, m as readCacheManifest, n as METRO_NAMED_CACHE_LAYOUT, o as cacheDirRefusal, p as metroCacheRoot, r as STORE_ROOT_TAG, s as cacheManifestLockPath, t as LOG_ROTATE_BYTES, u as configDir, v as sharedStoreRoot, w as workspaceSlug, x as workspaceId, y as tagSharedStore, z as unitLines } from "./core-BTsCO1nW.mjs";
3
+ export { LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, STORE_ROOT_TAG, ambientContext, ambientEnv, ambientWrite, artifactIn, buildCacheKey, buildCacheRoot, cacheDirRefusal, cacheManifestLockPath, cacheNameSegment, cachePathSetting, compiledHelper, configDir, createMetroBridge, createMetroGateway, dependencyInstall, ensurePrivateDir, hostSimulatorArch, metroCacheRoot, quoteUnitWord, quotedPath, reactNativeArtifactIdentity, reactNativeArtifactQuery, readCacheManifest, registerCache, resolveArtifact, reusableDependencies, rotateLog, rotatedLogPath, sharedStoreRoot, storeArtifact, storeArtifactAsync, swiftpmArtifactQuery, tagSharedStore, unitLines, unitWords, updateCacheManifest, validMacosResourceDestination, withAmbientContext, withDirLock, withDirLockAsync, withDirLockTransaction, workspaceId, workspaceLogDir, workspaceName, workspaceSlug, workspaceStateDir };
@@ -0,0 +1,289 @@
1
+ //#region state/status-derived.ts
2
+ const PLATFORMS = ["ios", "android"];
3
+ function isRunning(platform, device) {
4
+ if (platform === "ios") return device.state === "Booted";
5
+ return device.state === "detected" && !device.physical;
6
+ }
7
+ function appPresence(env, platform, device) {
8
+ if (!isRunning(platform, device) || device.app?.state === "running") return null;
9
+ const everBuilt = env.builds?.[platform]?.some((entry) => entry.result === "succeeded") ?? true;
10
+ if (env.lastBuilds?.[platform]?.status === "failed" && !everBuilt) return "none";
11
+ return device.app?.state === "stopped" ? "closed" : null;
12
+ }
13
+ function deviceSlots(env) {
14
+ return [{
15
+ slot: "default",
16
+ ios: env.ios,
17
+ android: env.android
18
+ }, ...env.slots ?? []];
19
+ }
20
+ function latestBuild(env) {
21
+ let latest = null;
22
+ for (const platform of PLATFORMS) {
23
+ const build = env.lastBuilds?.[platform];
24
+ if (build && (latest === null || Date.parse(build.startedAt) > Date.parse(latest.startedAt))) latest = build;
25
+ }
26
+ return latest;
27
+ }
28
+ function stage(kind, since, platform = null) {
29
+ return {
30
+ kind,
31
+ since: since ?? null,
32
+ platform,
33
+ closedApps: []
34
+ };
35
+ }
36
+ function workspaceStage(env) {
37
+ if (env.macos?.build.state === "running") return stage("building", env.macos.build.startedAt, "macos");
38
+ if (env.macos?.build.state === "failed") return stage("build-failed", env.macos.build.finishedAt ?? env.macos.build.startedAt, "macos");
39
+ if (env.build?.state === "running") return stage("building", env.build.startedAt, env.build.platform);
40
+ const macosApp = env.macos?.state === "running" || env.macos?.state === "orphaned" ? env.macos : null;
41
+ const live = env.live || macosApp !== null;
42
+ if (!live && env.phase === "warming") return stage("warming", env.phaseSince);
43
+ if (!live && env.phase === "ready") return stage("ready", env.phaseSince);
44
+ const latest = latestBuild(env);
45
+ if (latest?.status === "failed") return stage("build-failed", latest.finishedAt ?? latest.startedAt, latest.platform);
46
+ if (live || (env.remoteDevices?.length ?? 0) > 0) {
47
+ const closedApps = deviceSlots(env).flatMap(({ slot, ...devices }) => PLATFORMS.flatMap((platform) => {
48
+ const device = devices[platform];
49
+ return device && appPresence(env, platform, device) === "closed" ? [{
50
+ platform,
51
+ slot
52
+ }] : [];
53
+ }));
54
+ return {
55
+ ...stage("running", env.supervisor?.startedAt ?? macosApp?.build.finishedAt ?? macosApp?.build.startedAt),
56
+ closedApps
57
+ };
58
+ }
59
+ const lastStop = env.metro?.lastStop;
60
+ return stage("stopped", lastStop && "at" in lastStop ? lastStop.at : null);
61
+ }
62
+ function checksState(checks) {
63
+ if (!checks) return null;
64
+ if (checks.failing > 0) return "failing";
65
+ if (checks.pending > 0) return "pending";
66
+ return checks.passing > 0 ? "passing" : null;
67
+ }
68
+ function gitChip(worktree) {
69
+ const git = worktree.git;
70
+ if (!git) return null;
71
+ const pull = worktree.pullRequest;
72
+ const parts = [];
73
+ const ahead = git.ahead ?? 0;
74
+ const behind = git.behind ?? 0;
75
+ if (ahead || behind) parts.push({
76
+ kind: "arrows",
77
+ ahead,
78
+ behind
79
+ });
80
+ const uncommitted = git.changed + git.untracked;
81
+ if (uncommitted) parts.push({
82
+ kind: "changed",
83
+ count: uncommitted
84
+ });
85
+ if (git.mergedInto !== null) {
86
+ if (pull?.state !== "merged") parts.push({
87
+ kind: "merged",
88
+ into: git.mergedInto
89
+ });
90
+ } else if (git.upstream === null) parts.push({ kind: "no-upstream" });
91
+ return {
92
+ parts,
93
+ ci: pull ? checksState(pull.checks) : null
94
+ };
95
+ }
96
+ function buildCause(build) {
97
+ if (("result" in build ? build.result : build.status) !== "failed") return null;
98
+ const at = build.diagnostics?.find((d) => d.file && d.line !== null && d.line !== void 0);
99
+ if (at) return {
100
+ key: `${at.file}:${at.line}`,
101
+ file: at.file,
102
+ line: at.line
103
+ };
104
+ return {
105
+ key: build.errorCode ?? "failed",
106
+ file: null,
107
+ line: null
108
+ };
109
+ }
110
+ function withCauses(builds) {
111
+ if (!builds) return builds;
112
+ return Object.fromEntries(Object.entries(builds).map(([platform, list]) => [platform, list?.map((build) => withCause(build))]));
113
+ }
114
+ function withCause(build) {
115
+ const cause = buildCause(build);
116
+ return cause ? {
117
+ ...build,
118
+ cause
119
+ } : build;
120
+ }
121
+ function withGitChip(worktree) {
122
+ const chip = gitChip(worktree);
123
+ return chip ? {
124
+ ...worktree,
125
+ gitChip: chip
126
+ } : worktree;
127
+ }
128
+ /** The environment with the conclusions clients draw from it: `stage`, `appPresence`, `gitChip` and `cause`. */
129
+ function withDerivedFacts(env) {
130
+ const device = (platform, record) => record ? {
131
+ ...record,
132
+ appPresence: appPresence(env, platform, record)
133
+ } : record;
134
+ const derived = {
135
+ ...env,
136
+ stage: workspaceStage(env)
137
+ };
138
+ if (env.ios) derived.ios = device("ios", env.ios);
139
+ if (env.android) derived.android = device("android", env.android);
140
+ if (env.slots) derived.slots = env.slots.map((slot) => ({
141
+ ...slot,
142
+ ios: device("ios", slot.ios),
143
+ android: device("android", slot.android)
144
+ }));
145
+ if (env.worktree) derived.worktree = withGitChip(env.worktree);
146
+ if (env.lastBuilds) derived.lastBuilds = Object.fromEntries(Object.entries(env.lastBuilds).map(([platform, build]) => [platform, withCause(build)]));
147
+ if (env.builds) derived.builds = withCauses(env.builds);
148
+ return derived;
149
+ }
150
+ //#endregion
151
+ //#region state/status-views.ts
152
+ /** How many of the newest archives the workspace list names. */
153
+ const SUMMARY_ARCHIVES = 10;
154
+ function summaryBuild({ fingerprint: _fingerprint, missReason: _missReason, diagnostics, ...build }) {
155
+ const located = diagnostics?.find((diagnostic) => diagnostic.file && diagnostic.line !== null);
156
+ const kept = build;
157
+ if (located) kept.diagnostics = [located];
158
+ return kept;
159
+ }
160
+ function summaryHistory(entries) {
161
+ const streak = entries.findIndex((entry) => entry.result !== "failed");
162
+ return entries.slice(0, Math.max(1, streak === -1 ? entries.length : streak)).map(({ result, slot, phases, configuration: _configuration, cacheKey: _cacheKey, compileSteps: _steps, ...build }) => Object.assign(summaryBuild(build), {
163
+ result,
164
+ slot,
165
+ phases
166
+ }));
167
+ }
168
+ function summaryWorktree({ pullRequest, ...worktree }) {
169
+ if (!pullRequest) return pullRequest === void 0 ? worktree : {
170
+ ...worktree,
171
+ pullRequest
172
+ };
173
+ const { reviewDecision: _reviewDecision, checkedAt: _checkedAt, ...kept } = pullRequest;
174
+ return {
175
+ ...worktree,
176
+ pullRequest: kept
177
+ };
178
+ }
179
+ /** The summary of one environment of a status payload. */
180
+ function workspaceSummary(environment) {
181
+ const { logs, builds, lastBuilds, macos, agentDevice, worktree, ...rest } = environment;
182
+ const summary = rest;
183
+ if (worktree !== void 0) summary.worktree = worktree && summaryWorktree(worktree);
184
+ if (logs !== void 0) summary.logs = logs && { errorsSinceMarker: logs.errorsSinceMarker };
185
+ if (lastBuilds) {
186
+ summary.lastBuilds = {};
187
+ if (lastBuilds.ios) summary.lastBuilds.ios = summaryBuild(lastBuilds.ios);
188
+ if (lastBuilds.android) summary.lastBuilds.android = summaryBuild(lastBuilds.android);
189
+ }
190
+ if (builds) {
191
+ summary.builds = {};
192
+ for (const platform of [
193
+ "ios",
194
+ "android",
195
+ "macos"
196
+ ]) {
197
+ const entries = builds[platform];
198
+ if (entries) summary.builds[platform] = summaryHistory(entries);
199
+ }
200
+ }
201
+ if (macos !== void 0) summary.macos = macos && (({ arguments: _arguments, ...app }) => app)(macos);
202
+ if (environment.tutorial && agentDevice) summary.agentDevice = agentDevice;
203
+ return summary;
204
+ }
205
+ function worktreeRow({ path, branch, repository, git, gitChip, pullRequest }) {
206
+ const row = { path };
207
+ if (branch !== void 0) row.branch = branch;
208
+ if (repository !== void 0) row.repository = repository;
209
+ if (git !== void 0) row.git = git;
210
+ if (gitChip !== void 0) row.gitChip = gitChip;
211
+ if (pullRequest !== void 0) row.pullRequest = pullRequest && (({ reviewDecision: _review, checkedAt: _checked, ...kept }) => kept)(pullRequest);
212
+ return row;
213
+ }
214
+ /** The live views of a status payload as `stim status --json` prints it. */
215
+ function statusViews(payload) {
216
+ const archived = payload.archived ?? [];
217
+ return {
218
+ workspaces: payload.environments.map(workspaceSummary),
219
+ worktrees: payload.unprovisionedWorktrees.map(worktreeRow),
220
+ archived: {
221
+ count: payload.archivedUsage?.count ?? archived.length,
222
+ bytes: payload.archivedUsage?.bytes ?? 0,
223
+ newest: archived.toSorted((a, b) => b.removedAt.localeCompare(a.removedAt)).slice(0, 10).map(({ id, projectRoot, project, workspace, removedAt }) => ({
224
+ id,
225
+ projectRoot,
226
+ project,
227
+ workspace,
228
+ removedAt
229
+ }))
230
+ },
231
+ machine: {
232
+ capacity: payload.capacity,
233
+ machine: payload.machine ?? null,
234
+ deviceLeases: payload.deviceLeases,
235
+ simctlAvailable: payload.simctlAvailable,
236
+ maintenance: payload.maintenance ? (({ recent: _recent, sizes: _sizes, ...rest }) => rest)(payload.maintenance) : null
237
+ },
238
+ details: new Map(payload.environments.map((environment) => [environment.path, environment]))
239
+ };
240
+ }
241
+ //#endregion
242
+ //#region state/keyed-delta.ts
243
+ /**
244
+ * Tracks the JSON of the entities last sent on one subscription, so the next emit carries only what changed. An
245
+ * entity counts as changed when its JSON differs, so the order of its fields matters and producers build entities
246
+ * with a stable field order.
247
+ */
248
+ var KeyedEntities = class {
249
+ sent = /* @__PURE__ */ new Map();
250
+ key;
251
+ constructor(key) {
252
+ this.key = key;
253
+ }
254
+ /** Records `entities` as sent in full, for a snapshot. */
255
+ reset(entities) {
256
+ this.sent = new Map(entities.map((entity) => [this.key(entity), JSON.stringify(entity)]));
257
+ }
258
+ /** The delta from what was last sent to `entities`, recorded as sent; null when nothing changed. */
259
+ next(entities) {
260
+ const sent = /* @__PURE__ */ new Map();
261
+ const upsert = [];
262
+ for (const entity of entities) {
263
+ const key = this.key(entity);
264
+ const json = JSON.stringify(entity);
265
+ sent.set(key, json);
266
+ if (this.sent.get(key) !== json) upsert.push(entity);
267
+ }
268
+ const remove = [...this.sent.keys()].filter((key) => !sent.has(key));
269
+ this.sent = sent;
270
+ return upsert.length || remove.length ? {
271
+ upsert,
272
+ remove
273
+ } : null;
274
+ }
275
+ };
276
+ /** Applies `delta` to `entities` keyed by `key`, keeping the order of `entities` and appending new keys. */
277
+ function applyKeyedDelta(entities, delta, key) {
278
+ const removed = new Set(delta.remove);
279
+ const replaced = new Map(delta.upsert.map((entity) => [key(entity), entity]));
280
+ return [...entities.flatMap((entity) => {
281
+ const id = key(entity);
282
+ if (removed.has(id)) return [];
283
+ const replacement = replaced.get(id);
284
+ replaced.delete(id);
285
+ return [replacement ?? entity];
286
+ }), ...replaced.values()];
287
+ }
288
+ //#endregion
289
+ export { workspaceSummary as a, statusViews as i, applyKeyedDelta as n, withDerivedFacts as o, SUMMARY_ARCHIVES as r, withGitChip as s, KeyedEntities as t };
@@ -0,0 +1,100 @@
1
+ //#region noise.d.ts
2
+ declare const NOISE_XX = "Noise_XX_25519_ChaChaPoly_SHA256";
3
+ declare const NOISE_XX_PSK2 = "Noise_XXpsk2_25519_ChaChaPoly_SHA256";
4
+ type NoiseProtocolName = typeof NOISE_XX | typeof NOISE_XX_PSK2;
5
+ /** Largest handshake message either side writes or reads, payload included. */
6
+ declare const MAX_HANDSHAKE_MESSAGE_BYTES = 1024;
7
+ /** Thrown for any handshake or transport failure; the handshake or transport is unusable afterwards. */
8
+ declare class NoiseError extends Error {
9
+ override name: string;
10
+ }
11
+ /** A raw 32-byte X25519 key pair. */
12
+ interface NoiseKeyPair {
13
+ readonly publicKey: Buffer;
14
+ readonly privateKey: Buffer;
15
+ }
16
+ declare function generateNoiseKeyPair(): NoiseKeyPair;
17
+ declare function noiseKeyPairFromPrivateKey(privateKey: Uint8Array): NoiseKeyPair;
18
+ /** X25519 of a raw 32-byte private key and a peer's raw 32-byte public key; it throws for a low-order key. */
19
+ type NoiseDh = (privateKey: Buffer, publicKey: Buffer) => Uint8Array;
20
+ /** Noise's CipherState: a key and a 64-bit counter used as the nonce. */
21
+ declare class CipherState {
22
+ #private;
23
+ constructor(key?: Uint8Array);
24
+ hasKey(): boolean;
25
+ setNonce(n: bigint): void;
26
+ encryptWithAd(ad: Uint8Array, plaintext: Uint8Array): Buffer;
27
+ decryptWithAd(ad: Uint8Array, ciphertext: Uint8Array): Buffer;
28
+ }
29
+ interface HandshakeOptions {
30
+ protocol: NoiseProtocolName;
31
+ initiator: boolean;
32
+ prologue: Uint8Array;
33
+ staticKeyPair: NoiseKeyPair;
34
+ /** 32 bytes, required for {@link NOISE_XX_PSK2} and refused for {@link NOISE_XX}. */
35
+ psk?: Uint8Array;
36
+ /** Fixed ephemeral key, only for reproducing published test vectors. */
37
+ ephemeralKeyPair?: NoiseKeyPair;
38
+ /**
39
+ * X25519 in place of node:crypto's, for a runtime whose node:crypto cannot derive with an imported raw public key,
40
+ * such as Cloudflare workerd.
41
+ */
42
+ dh?: NoiseDh;
43
+ }
44
+ /**
45
+ * Noise's HandshakeState for {@link NOISE_XX} and {@link NOISE_XX_PSK2}. The initiator writes messages 1 and 3. Any
46
+ * error from {@link writeMessage} or {@link readMessage}, including an out-of-turn call, a call after the last
47
+ * message, or an invalid or oversized message, ends the handshake: every later call throws {@link NoiseError}.
48
+ */
49
+ declare class HandshakeState {
50
+ #private;
51
+ constructor(options: HandshakeOptions);
52
+ get isComplete(): boolean;
53
+ /** The peer's static public key, once the message that carries it has been read and authenticated. */
54
+ get remoteStaticPublicKey(): Buffer | undefined;
55
+ get handshakeHash(): Buffer;
56
+ writeMessage(payload?: Uint8Array): Buffer;
57
+ readMessage(message: Uint8Array): Buffer;
58
+ /** Noise's Split(), returning this side's sending and receiving cipher states. It can be called once. */
59
+ split(): {
60
+ send: CipherState;
61
+ receive: CipherState;
62
+ };
63
+ }
64
+ interface NoiseTransportOptions {
65
+ send: CipherState;
66
+ receive: CipherState;
67
+ /** Largest message, in bytes (UTF-8 bytes for text), this side may send. */
68
+ maxSendBytes: number;
69
+ /** Largest message, in bytes (UTF-8 bytes for text), this side accepts. */
70
+ maxReceiveBytes: number;
71
+ }
72
+ /** A message carried by one WebSocket message: text or binary, as the sender passed it. */
73
+ type NoiseMessage = {
74
+ type: "text";
75
+ data: string;
76
+ } | {
77
+ type: "binary";
78
+ data: Buffer;
79
+ };
80
+ /**
81
+ * Stim's transport framing after the handshake: each WebSocket message is one ChaCha20-Poly1305 message with empty
82
+ * associated data under the next counter value. The first plaintext byte is the message type, 0x01 text or 0x02
83
+ * binary. Counters are not sent, so a reordered, replayed, dropped or altered message fails to decrypt. Any decryption
84
+ * failure closes the transport: every later call throws {@link NoiseError}. Nonce 2^64-1 is reserved and never used:
85
+ * after a direction's last usable message, at counter 2^64-2, the next call in that direction closes the transport.
86
+ */
87
+ declare class NoiseTransport {
88
+ #private;
89
+ constructor(options: NoiseTransportOptions);
90
+ get closed(): boolean;
91
+ /**
92
+ * Encrypts a string as a text message or bytes as a binary message. Data over `maxSendBytes` (UTF-8 bytes for text)
93
+ * throws a `RangeError`, consumes no counter, and leaves the transport open: it is the caller's own error and nothing
94
+ * was sent.
95
+ */
96
+ encrypt(data: string | Uint8Array): Buffer;
97
+ decrypt(message: Uint8Array): NoiseMessage;
98
+ }
99
+ //#endregion
100
+ export { NOISE_XX as a, NoiseError as c, NoiseProtocolName as d, NoiseTransport as f, noiseKeyPairFromPrivateKey as h, MAX_HANDSHAKE_MESSAGE_BYTES as i, NoiseKeyPair as l, generateNoiseKeyPair as m, HandshakeOptions as n, NOISE_XX_PSK2 as o, NoiseTransportOptions as p, HandshakeState as r, NoiseDh as s, CipherState as t, NoiseMessage as u };