@juxtapose/core 0.4.0 → 0.6.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 (153) hide show
  1. package/dist/agent/handoff.d.ts +8 -1
  2. package/dist/agent/handoff.js +75 -7
  3. package/dist/agent/handoff.js.map +1 -1
  4. package/dist/analysis/affected.d.ts +37 -0
  5. package/dist/analysis/affected.js +97 -22
  6. package/dist/analysis/affected.js.map +1 -1
  7. package/dist/analysis/cause.d.ts +32 -0
  8. package/dist/analysis/cause.js +187 -0
  9. package/dist/analysis/cause.js.map +1 -0
  10. package/dist/baseline/approve.d.ts +24 -0
  11. package/dist/baseline/approve.js +54 -0
  12. package/dist/baseline/approve.js.map +1 -0
  13. package/dist/baseline/git-store.d.ts +4 -0
  14. package/dist/baseline/git-store.js +22 -0
  15. package/dist/baseline/git-store.js.map +1 -1
  16. package/dist/browser/acquire.d.ts +15 -0
  17. package/dist/browser/acquire.js +26 -0
  18. package/dist/browser/acquire.js.map +1 -0
  19. package/dist/browser/browser.d.ts +53 -0
  20. package/dist/browser/browser.js +122 -0
  21. package/dist/browser/browser.js.map +1 -0
  22. package/dist/browser/cdp.d.ts +81 -0
  23. package/dist/browser/cdp.js +230 -0
  24. package/dist/browser/cdp.js.map +1 -0
  25. package/dist/browser/daemon/client.d.ts +145 -0
  26. package/dist/browser/daemon/client.js +764 -0
  27. package/dist/browser/daemon/client.js.map +1 -0
  28. package/dist/browser/daemon/state.d.ts +99 -0
  29. package/dist/browser/daemon/state.js +297 -0
  30. package/dist/browser/daemon/state.js.map +1 -0
  31. package/dist/browser/daemon/supervisor-main.d.ts +1 -0
  32. package/dist/browser/daemon/supervisor-main.js +54 -0
  33. package/dist/browser/daemon/supervisor-main.js.map +1 -0
  34. package/dist/browser/daemon/supervisor.d.ts +37 -0
  35. package/dist/browser/daemon/supervisor.js +777 -0
  36. package/dist/browser/daemon/supervisor.js.map +1 -0
  37. package/dist/{capture/launch.d.ts → browser/flags.d.ts} +19 -1
  38. package/dist/browser/flags.js +146 -0
  39. package/dist/browser/flags.js.map +1 -0
  40. package/dist/browser/index.d.ts +14 -0
  41. package/dist/browser/index.js +14 -0
  42. package/dist/browser/index.js.map +1 -0
  43. package/dist/browser/install.d.ts +33 -0
  44. package/dist/browser/install.js +167 -0
  45. package/dist/browser/install.js.map +1 -0
  46. package/dist/browser/launch.d.ts +37 -0
  47. package/dist/browser/launch.js +254 -0
  48. package/dist/browser/launch.js.map +1 -0
  49. package/dist/browser/page.d.ts +125 -0
  50. package/dist/browser/page.js +564 -0
  51. package/dist/browser/page.js.map +1 -0
  52. package/dist/browser/pins.d.ts +12 -0
  53. package/dist/browser/pins.js +57 -0
  54. package/dist/browser/pins.js.map +1 -0
  55. package/dist/browser/private-dir.d.ts +7 -0
  56. package/dist/browser/private-dir.js +24 -0
  57. package/dist/browser/private-dir.js.map +1 -0
  58. package/dist/browser/resolve.d.ts +31 -0
  59. package/dist/browser/resolve.js +126 -0
  60. package/dist/browser/resolve.js.map +1 -0
  61. package/dist/browser/selectors.d.ts +10 -0
  62. package/dist/browser/selectors.js +60 -0
  63. package/dist/browser/selectors.js.map +1 -0
  64. package/dist/browser/transport.d.ts +51 -0
  65. package/dist/browser/transport.js +124 -0
  66. package/dist/browser/transport.js.map +1 -0
  67. package/dist/browser/types.d.ts +4 -0
  68. package/dist/browser/types.js +2 -0
  69. package/dist/browser/types.js.map +1 -0
  70. package/dist/browser/zip.d.ts +27 -0
  71. package/dist/browser/zip.js +241 -0
  72. package/dist/browser/zip.js.map +1 -0
  73. package/dist/capture/capture.d.ts +7 -1
  74. package/dist/capture/capture.js +25 -8
  75. package/dist/capture/capture.js.map +1 -1
  76. package/dist/capture/env.d.ts +1 -1
  77. package/dist/capture/pool.d.ts +1 -1
  78. package/dist/capture/pool.js +41 -8
  79. package/dist/capture/pool.js.map +1 -1
  80. package/dist/capture/settle.d.ts +1 -1
  81. package/dist/capture/settle.js +2 -0
  82. package/dist/capture/settle.js.map +1 -1
  83. package/dist/capture/snap.d.ts +43 -0
  84. package/dist/capture/snap.js +103 -0
  85. package/dist/capture/snap.js.map +1 -0
  86. package/dist/capture/structure.d.ts +77 -0
  87. package/dist/capture/structure.js +498 -0
  88. package/dist/capture/structure.js.map +1 -0
  89. package/dist/diff/compare.d.ts +19 -0
  90. package/dist/diff/compare.js +19 -0
  91. package/dist/diff/compare.js.map +1 -0
  92. package/dist/diff/crops.d.ts +26 -0
  93. package/dist/diff/crops.js +92 -0
  94. package/dist/diff/crops.js.map +1 -0
  95. package/dist/diff/structural/classify.d.ts +29 -0
  96. package/dist/diff/structural/classify.js +113 -0
  97. package/dist/diff/structural/classify.js.map +1 -0
  98. package/dist/diff/structural/coverage.d.ts +11 -0
  99. package/dist/diff/structural/coverage.js +37 -0
  100. package/dist/diff/structural/coverage.js.map +1 -0
  101. package/dist/diff/structural/deltas.d.ts +29 -0
  102. package/dist/diff/structural/deltas.js +218 -0
  103. package/dist/diff/structural/deltas.js.map +1 -0
  104. package/dist/diff/structural/disambiguate.d.ts +3 -0
  105. package/dist/diff/structural/disambiguate.js +89 -0
  106. package/dist/diff/structural/disambiguate.js.map +1 -0
  107. package/dist/diff/structural/label.d.ts +15 -0
  108. package/dist/diff/structural/label.js +64 -0
  109. package/dist/diff/structural/label.js.map +1 -0
  110. package/dist/diff/structural/match.d.ts +13 -0
  111. package/dist/diff/structural/match.js +135 -0
  112. package/dist/diff/structural/match.js.map +1 -0
  113. package/dist/diff/structural/shift.d.ts +2 -0
  114. package/dist/diff/structural/shift.js +144 -0
  115. package/dist/diff/structural/shift.js.map +1 -0
  116. package/dist/diff/structural/summary.d.ts +31 -0
  117. package/dist/diff/structural/summary.js +420 -0
  118. package/dist/diff/structural/summary.js.map +1 -0
  119. package/dist/diff/structural.d.ts +40 -0
  120. package/dist/diff/structural.js +219 -0
  121. package/dist/diff/structural.js.map +1 -0
  122. package/dist/index.d.ts +28 -4
  123. package/dist/index.js +32 -3
  124. package/dist/index.js.map +1 -1
  125. package/dist/platform.d.ts +1 -1
  126. package/dist/platforms/urls.d.ts +3 -0
  127. package/dist/platforms/urls.js +89 -0
  128. package/dist/platforms/urls.js.map +1 -0
  129. package/dist/report/comment.js +9 -3
  130. package/dist/report/comment.js.map +1 -1
  131. package/dist/report/format.d.ts +18 -0
  132. package/dist/report/format.js +20 -0
  133. package/dist/report/format.js.map +1 -1
  134. package/dist/report/html.js +2 -2
  135. package/dist/report/html.js.map +1 -1
  136. package/dist/run/groups.d.ts +2 -0
  137. package/dist/run/groups.js +45 -0
  138. package/dist/run/groups.js.map +1 -0
  139. package/dist/run/run.d.ts +6 -2
  140. package/dist/run/run.js +74 -6
  141. package/dist/run/run.js.map +1 -1
  142. package/dist/shell-quote.d.ts +2 -0
  143. package/dist/shell-quote.js +10 -0
  144. package/dist/shell-quote.js.map +1 -0
  145. package/dist/types.d.ts +201 -5
  146. package/dist/types.js +0 -2
  147. package/dist/types.js.map +1 -1
  148. package/dist/url-platform.d.ts +2 -2
  149. package/dist/url-platform.js +2 -2
  150. package/dist/url-platform.js.map +1 -1
  151. package/package.json +6 -10
  152. package/dist/capture/launch.js +0 -56
  153. package/dist/capture/launch.js.map +0 -1
@@ -0,0 +1,81 @@
1
+ import type { Transport } from './transport.js';
2
+ export interface RawMessage {
3
+ id?: number;
4
+ method?: string;
5
+ params?: unknown;
6
+ result?: unknown;
7
+ error?: {
8
+ code: number;
9
+ message: string;
10
+ };
11
+ sessionId?: string;
12
+ }
13
+ export declare const SEND_TIMEOUT_MS = 30000;
14
+ export declare class CdpError extends Error {
15
+ readonly code: number;
16
+ constructor(code: number, method: string, message: string);
17
+ }
18
+ export declare class TargetClosedError extends Error {
19
+ constructor(reason?: string, method?: string);
20
+ }
21
+ export declare class SendTimeoutError extends Error {
22
+ constructor(method: string, timeout: number);
23
+ }
24
+ type Handler = (params: unknown, sessionId?: string) => void;
25
+ export declare class CdpConnection {
26
+ private readonly transport;
27
+ private lastId;
28
+ private readonly pending;
29
+ /** key = `${sessionId ?? ''}\n${method}` */
30
+ private readonly handlers;
31
+ private readonly closeWaiters;
32
+ private _closed;
33
+ private closeReason;
34
+ onClose: ((reason?: string) => void) | null;
35
+ /** Every parsed frame, before routing. The PR 2 supervisor proxies from here. */
36
+ onRaw: ((m: RawMessage) => void) | null;
37
+ /**
38
+ * A throwing event handler or onRaw must not escape into the stream's data
39
+ * event (an uncaught exception would kill the daemon) nor skip the rest of
40
+ * the chunk. Default: one line on stderr.
41
+ */
42
+ onError: (error: unknown, where: 'handler' | 'onRaw') => void;
43
+ constructor(transport: Transport);
44
+ get closed(): boolean;
45
+ get pendingCount(): number;
46
+ /** Number of distinct (session, method) handler keys; empty sets are pruned. */
47
+ get handlerKeyCount(): number;
48
+ /** Total registered handlers, summed over every key; a leak test's yardstick. */
49
+ get handlerCount(): number;
50
+ /**
51
+ * Call `listener` once when the connection closes (at once if it already
52
+ * has); returns the unsubscribe. Pages use it to fail in-flight work fast
53
+ * instead of waiting out each send's timeout.
54
+ */
55
+ onClosed(listener: (e: Error) => void): () => void;
56
+ allocateId(): number;
57
+ /**
58
+ * Throws TargetClosedError once the connection is closed, so a proxying
59
+ * caller (the PR 2 supervisor) learns its client message was not delivered
60
+ * instead of waiting for a reply that cannot come.
61
+ */
62
+ sendRaw(message: RawMessage & {
63
+ id: number;
64
+ method: string;
65
+ }): void;
66
+ send<T = unknown>(method: string, params?: object, sessionId?: string, opts?: {
67
+ timeout?: number;
68
+ }): Promise<T>;
69
+ on(method: string, handler: Handler, sessionId?: string): () => void;
70
+ /**
71
+ * Without a sessionId this listens on the browser session only, where
72
+ * session-scoped events never arrive; pass the page's sessionId for page
73
+ * events.
74
+ */
75
+ once<P = unknown>(method: string, sessionId?: string, predicate?: (p: P) => boolean): Promise<P>;
76
+ close(): void;
77
+ private dispatch;
78
+ private runHandlers;
79
+ private handleClose;
80
+ }
81
+ export {};
@@ -0,0 +1,230 @@
1
+ // packages/core/src/browser/cdp.ts
2
+ //
3
+ // The whole protocol client: ids out, replies back, events routed by
4
+ // sessionId. Playwright's CRConnection does the same in ~300 lines plus
5
+ // the parts we never use.
6
+ //
7
+ // Every send has a Node-side timeout. Chrome answers Runtime.evaluate only
8
+ // when the script returns, so a story with a synchronous infinite loop would
9
+ // otherwise hang the worker and the run.
10
+ export const SEND_TIMEOUT_MS = 30_000;
11
+ export class CdpError extends Error {
12
+ code;
13
+ constructor(code, method, message) {
14
+ super(`${method}: ${message}`);
15
+ this.code = code;
16
+ this.name = 'CdpError';
17
+ }
18
+ }
19
+ export class TargetClosedError extends Error {
20
+ constructor(reason = 'browser closed', method) {
21
+ super(`jux: browser connection closed (${reason})${method ? ` while waiting for ${method}` : ''}`);
22
+ this.name = 'TargetClosedError';
23
+ }
24
+ }
25
+ export class SendTimeoutError extends Error {
26
+ constructor(method, timeout) {
27
+ super(`jux: ${method} got no reply from the browser within ${timeout} ms`);
28
+ this.name = 'SendTimeoutError';
29
+ }
30
+ }
31
+ export class CdpConnection {
32
+ transport;
33
+ lastId = 0;
34
+ pending = new Map();
35
+ /** key = `${sessionId ?? ''}\n${method}` */
36
+ handlers = new Map();
37
+ closeWaiters = new Set();
38
+ _closed = false;
39
+ closeReason;
40
+ onClose = null;
41
+ /** Every parsed frame, before routing. The PR 2 supervisor proxies from here. */
42
+ onRaw = null;
43
+ /**
44
+ * A throwing event handler or onRaw must not escape into the stream's data
45
+ * event (an uncaught exception would kill the daemon) nor skip the rest of
46
+ * the chunk. Default: one line on stderr.
47
+ */
48
+ onError = (error, where) => {
49
+ const msg = error instanceof Error ? error.message : String(error);
50
+ process.stderr.write(`jux: ${where} threw: ${msg}\n`);
51
+ };
52
+ constructor(transport) {
53
+ this.transport = transport;
54
+ transport.onMessage = (m) => this.dispatch(m);
55
+ transport.onClose = (reason) => this.handleClose(reason);
56
+ }
57
+ get closed() {
58
+ return this._closed;
59
+ }
60
+ get pendingCount() {
61
+ return this.pending.size;
62
+ }
63
+ /** Number of distinct (session, method) handler keys; empty sets are pruned. */
64
+ get handlerKeyCount() {
65
+ return this.handlers.size;
66
+ }
67
+ /** Total registered handlers, summed over every key; a leak test's yardstick. */
68
+ get handlerCount() {
69
+ let n = 0;
70
+ for (const set of this.handlers.values())
71
+ n += set.size;
72
+ return n;
73
+ }
74
+ /**
75
+ * Call `listener` once when the connection closes (at once if it already
76
+ * has); returns the unsubscribe. Pages use it to fail in-flight work fast
77
+ * instead of waiting out each send's timeout.
78
+ */
79
+ onClosed(listener) {
80
+ if (this._closed) {
81
+ listener(new TargetClosedError(this.closeReason));
82
+ return () => { };
83
+ }
84
+ this.closeWaiters.add(listener);
85
+ return () => this.closeWaiters.delete(listener);
86
+ }
87
+ allocateId() {
88
+ return ++this.lastId;
89
+ }
90
+ /**
91
+ * Throws TargetClosedError once the connection is closed, so a proxying
92
+ * caller (the PR 2 supervisor) learns its client message was not delivered
93
+ * instead of waiting for a reply that cannot come.
94
+ */
95
+ sendRaw(message) {
96
+ if (this._closed)
97
+ throw new TargetClosedError(this.closeReason, message.method);
98
+ this.transport.send(JSON.stringify(message));
99
+ }
100
+ send(method, params = {}, sessionId, opts = {}) {
101
+ if (this._closed)
102
+ return Promise.reject(new TargetClosedError(this.closeReason, method));
103
+ const id = this.allocateId();
104
+ const timeout = opts.timeout ?? SEND_TIMEOUT_MS;
105
+ return new Promise((resolve, reject) => {
106
+ const timer = setTimeout(() => {
107
+ this.pending.delete(id);
108
+ reject(new SendTimeoutError(method, timeout));
109
+ }, timeout);
110
+ timer.unref();
111
+ this.pending.set(id, {
112
+ method,
113
+ resolve: resolve,
114
+ reject,
115
+ timer,
116
+ });
117
+ try {
118
+ this.sendRaw(sessionId ? { id, method, params, sessionId } : { id, method, params });
119
+ }
120
+ catch (e) {
121
+ clearTimeout(timer);
122
+ this.pending.delete(id);
123
+ reject(e instanceof Error ? e : new Error(String(e)));
124
+ }
125
+ });
126
+ }
127
+ on(method, handler, sessionId) {
128
+ const key = `${sessionId ?? ''}\n${method}`;
129
+ let set = this.handlers.get(key);
130
+ if (!set)
131
+ this.handlers.set(key, (set = new Set()));
132
+ set.add(handler);
133
+ return () => {
134
+ set.delete(handler);
135
+ if (set.size === 0 && this.handlers.get(key) === set)
136
+ this.handlers.delete(key);
137
+ };
138
+ }
139
+ /**
140
+ * Without a sessionId this listens on the browser session only, where
141
+ * session-scoped events never arrive; pass the page's sessionId for page
142
+ * events.
143
+ */
144
+ once(method, sessionId, predicate = () => true) {
145
+ if (this._closed)
146
+ return Promise.reject(new TargetClosedError(this.closeReason, method));
147
+ return new Promise((resolve, reject) => {
148
+ const onClosed = (e) => {
149
+ off();
150
+ reject(e);
151
+ };
152
+ const off = this.on(method, (params) => {
153
+ if (!predicate(params))
154
+ return;
155
+ off();
156
+ this.closeWaiters.delete(onClosed);
157
+ resolve(params);
158
+ }, sessionId);
159
+ this.closeWaiters.add(onClosed);
160
+ });
161
+ }
162
+ close() {
163
+ this.transport.close();
164
+ }
165
+ dispatch(raw) {
166
+ let m;
167
+ try {
168
+ m = JSON.parse(raw);
169
+ }
170
+ catch {
171
+ return; // Chrome never sends non-JSON frames; nothing to do but ignore.
172
+ }
173
+ try {
174
+ this.onRaw?.(m);
175
+ }
176
+ catch (e) {
177
+ this.onError(e, 'onRaw');
178
+ }
179
+ if (m.id !== undefined) {
180
+ const p = this.pending.get(m.id);
181
+ if (!p)
182
+ return; // a raw (proxied) id, or a reply after its timeout
183
+ this.pending.delete(m.id);
184
+ clearTimeout(p.timer);
185
+ if (m.error)
186
+ p.reject(new CdpError(m.error.code, p.method, m.error.message));
187
+ else
188
+ p.resolve(m.result);
189
+ return;
190
+ }
191
+ if (m.method) {
192
+ const set = this.handlers.get(`${m.sessionId ?? ''}\n${m.method}`);
193
+ if (set)
194
+ this.runHandlers(set, m);
195
+ // Session-less listeners see every event (the browser session's Target.* events).
196
+ if (m.sessionId) {
197
+ const all = this.handlers.get(`\n${m.method}`);
198
+ if (all)
199
+ this.runHandlers(all, m);
200
+ }
201
+ }
202
+ }
203
+ runHandlers(set, m) {
204
+ for (const h of [...set]) {
205
+ try {
206
+ h(m.params, m.sessionId);
207
+ }
208
+ catch (e) {
209
+ this.onError(e, 'handler');
210
+ }
211
+ }
212
+ }
213
+ handleClose(reason) {
214
+ if (this._closed)
215
+ return;
216
+ this._closed = true;
217
+ this.closeReason = reason;
218
+ for (const p of this.pending.values()) {
219
+ clearTimeout(p.timer);
220
+ p.reject(new TargetClosedError(reason, p.method));
221
+ }
222
+ this.pending.clear();
223
+ const err = new TargetClosedError(reason);
224
+ for (const w of [...this.closeWaiters])
225
+ w(err);
226
+ this.closeWaiters.clear();
227
+ this.onClose?.(reason);
228
+ }
229
+ }
230
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../../src/browser/cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ import { Browser } from '../browser.js';
3
+ import { type DaemonPaths, type DaemonState } from './state.js';
4
+ export interface SpawnArgs {
5
+ executablePath: string;
6
+ args: string[];
7
+ stateDir: string;
8
+ key: string;
9
+ idleMinutes: number;
10
+ }
11
+ export interface WarmOptions {
12
+ executablePath: string;
13
+ args?: string[];
14
+ stateDir: string;
15
+ /** The caller's environment: the key is computed from it and the daemon runs with it. */
16
+ env?: NodeJS.ProcessEnv;
17
+ idleMinutes?: number;
18
+ /** Test seam: start a daemon for these args with this env. Default: a detached supervisor-main. */
19
+ spawnDaemon?: (args: SpawnArgs, env: NodeJS.ProcessEnv) => ChildProcess | void;
20
+ connectTimeoutMs?: number;
21
+ /** Test seam: see CommandReader. */
22
+ readCommand?: CommandReader;
23
+ }
24
+ /**
25
+ * The command line of a pid, '' when no such process exists, null when this
26
+ * machine gives no way to read it (no /proc and no ps).
27
+ */
28
+ export type CommandReader = (pid: number) => Promise<string | null>;
29
+ /**
30
+ * `CI` is the convention; these are the systems that do not set it (GitHub
31
+ * Actions does, but `CI` can be unset in a step's env; Jenkins sets BUILD_ID).
32
+ */
33
+ export declare const CI_ENV_VARS: readonly ["CI", "GITHUB_ACTIONS", "JENKINS_URL", "BUILD_ID", "TEAMCITY_VERSION", "BUILDKITE", "GITLAB_CI", "TF_BUILD", "CODEBUILD_BUILD_ID"];
34
+ /** Off with `--no-daemon`, JUX_NO_DAEMON (any truthy value), or any CI marker. */
35
+ export declare function daemonEnabled(env: NodeJS.ProcessEnv, flagNoDaemon?: boolean): boolean;
36
+ /**
37
+ * JUX_BROWSER_IDLE_MINUTES within [1, 35000], else the default (undefined).
38
+ * The upper bound is setTimeout's: 100000 minutes overflowed to a 1 ms idle
39
+ * timer and the daemon quit as soon as its last client left. Infinity used to
40
+ * pass too, became null in the spawn JSON, and every supervisor exited 1.
41
+ */
42
+ export declare function daemonIdleMinutes(env: NodeJS.ProcessEnv): number | undefined;
43
+ type StatusOptions = Pick<WarmOptions, 'executablePath' | 'stateDir' | 'args' | 'env' | 'readCommand'>;
44
+ /**
45
+ * A hash of `entry` and every file it reaches through relative imports. The
46
+ * supervisor that serves a client is whichever build spawned it; after a
47
+ * rebuild or an upgrade the supervisor's flags, allowlist or protocol can
48
+ * differ from this client's, and reusing it would render with the old code.
49
+ * A missing file hashes as missing (vitest runs the .ts sources, where the
50
+ * .js entry does not exist).
51
+ */
52
+ export declare function buildIdentity(entry: string): string;
53
+ /**
54
+ * `<@juxtapose/core version>+<build hash of the supervisor entry>`. Cached
55
+ * per process, but rechecked by stat on every call (about ten files): a
56
+ * Storybook addon or review server that stays up across a `pnpm build` kept
57
+ * the old key while spawning the new supervisor-main from disk, so it never
58
+ * shared a daemon with the CLI and ran a mixed build (PR #102 re-review N5).
59
+ */
60
+ export declare function juxIdentity(entry?: string): string;
61
+ /**
62
+ * The daemon key for these options. It covers everything a fresh launch
63
+ * would render with: the binary (path, size, mtime), the pin, the full Chrome
64
+ * command line jux would launch, the render env and this jux build. Keys that
65
+ * differ name different sockets, so a daemon from an older jux or other
66
+ * flags is never reused; it idles out.
67
+ */
68
+ export declare function daemonKeyFor(opts: Pick<WarmOptions, 'executablePath' | 'args' | 'env'>, jux?: string): string;
69
+ /**
70
+ * Start a detached supervisor-main with the caller's env: the key was computed
71
+ * from that env, so Chrome must render with it (TZ, LANG, fonts), not with
72
+ * whatever env this process happens to have. Detached in its own process
73
+ * group with stdio ignored: it outlives this jux, and a Ctrl-C to this
74
+ * terminal must not reach it.
75
+ *
76
+ * NODE_OPTIONS is not a render input and is dropped: VS Code's debug
77
+ * terminal (`--require …/bootloader.js`), `--inspect` or `--cpu-prof` would
78
+ * otherwise attach to a process that lives for hours, and `--cpu-prof` would
79
+ * write a profile into the project when it finally exits. The cwd is the
80
+ * state dir for the same reason: not the project that happened to start it.
81
+ */
82
+ export declare function spawnSupervisor(args: SpawnArgs, env: NodeJS.ProcessEnv, entry?: string): ChildProcess;
83
+ export declare const defaultReadCommand: CommandReader;
84
+ /**
85
+ * Remove the files of the daemon `s` describes, and nothing newer. The state
86
+ * goes only if it still names the same pid and start time: between our read
87
+ * and this call another client may have spawned a replacement that wrote its
88
+ * own (the review traced `jux browser stop` deleting a new daemon's files
89
+ * while the old one's Chrome took 5 s to close, orphaning the new one). The
90
+ * socket goes only if it is the path that state named and nothing listens on
91
+ * it, compared by inode so a socket bound meanwhile is left alone.
92
+ */
93
+ export declare function clearStaleState(paths: DaemonPaths, s: DaemonState): Promise<void>;
94
+ /**
95
+ * The warm daemon's browser, or a private one if the daemon cannot be had.
96
+ * Never rejects because of the daemon; a private launch failure rejects as in
97
+ * PR 1.
98
+ */
99
+ export declare function connectWarmBrowser(opts: WarmOptions): Promise<{
100
+ browser: Browser;
101
+ warm: boolean;
102
+ }>;
103
+ /**
104
+ * Start (or find) the daemon without a private fallback: `jux browser start`
105
+ * must not launch and close a whole Chrome just to report that the daemon
106
+ * could not start.
107
+ */
108
+ export declare function startDaemon(opts: WarmOptions): Promise<{
109
+ state: DaemonState;
110
+ } | {
111
+ error: string;
112
+ }>;
113
+ /** The running daemon for this fingerprint, or null. A dead daemon's files are cleared. */
114
+ export declare function daemonStatus(given: StatusOptions): Promise<DaemonState | null>;
115
+ type ListOptions = Pick<WarmOptions, 'stateDir' | 'readCommand'>;
116
+ /** Every live daemon in `stateDir`, whichever key; dead ones' files are cleared on the way. */
117
+ export declare function listDaemons(opts: ListOptions): Promise<DaemonState[]>;
118
+ /**
119
+ * What stopping one daemon did: `none` (nothing running, or the state named a
120
+ * pid that is not ours and nothing listened on its socket), `stopped` (its
121
+ * pid is gone), `unverified` (a live pid we could not confirm as ours:
122
+ * nothing is signalled or removed), or `running` (ours, signalled, and still
123
+ * alive after 2 s).
124
+ */
125
+ export type StopResult = {
126
+ outcome: 'none' | 'stopped';
127
+ } | {
128
+ outcome: 'unverified' | 'running';
129
+ pid: number;
130
+ reason: string;
131
+ };
132
+ /** Stop the daemon for this fingerprint only. */
133
+ export declare function stopDaemon(given: StatusOptions): Promise<StopResult>;
134
+ /** One daemon `stopAllDaemons` found, and what stopping it did. */
135
+ export type DaemonStop = {
136
+ key: string;
137
+ pid: number;
138
+ } & StopResult;
139
+ /**
140
+ * Stop every daemon in `stateDir`, whichever key it runs under, each through
141
+ * the same verification as `stopDaemon`. Entries whose outcome is `none`
142
+ * (stale files, reused pids) are cleared and left out.
143
+ */
144
+ export declare function stopAllDaemons(opts: ListOptions): Promise<DaemonStop[]>;
145
+ export {};