swarmbox 0.18.0 → 0.19.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/CHANGELOG.md CHANGED
@@ -5,6 +5,33 @@ Unreleased; the release names the version.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.19.0 (2026-11-13)
9
+
10
+ - A tool that fails gives the agent up to 40 lines (4000 characters) of the error, not just its first line, and
11
+ writes the whole of it to serve's output. A world whose seed script failed answered `run_start` with only
12
+ "world_seed.py failed (1):", and the traceback below it, which held the cause, reached neither.
13
+ - The README lists what the stand-in sandbox needs on Linux: bubblewrap, socat and ripgrep.
14
+ - A screen's downloads are kept: `screen_downloads` lists the files a screen saved (an export, a report, a
15
+ statement) and reads a text file's contents a page at a time, and an action that saved one says
16
+ "downloaded: #1 jobs.csv (2.0 KB, text)". A browser draws nothing for a download, so a tester could press
17
+ Export and never know what came out, or whether anything did. Each file is read through its stream (a remote
18
+ browser has no path), fingerprinted, and kept as text up to 500,000 characters. Its secrets are redacted:
19
+ token-shaped words anywhere in it, and in a CSV or TSV every cell under a secret-named header.
20
+ A download's text is the file as it is: redacted in place, never reparsed, so a JSON export's `424.10` and
21
+ its 20-digit ids read as written. A UTF-16 export (a spreadsheet's "Unicode text") is read by its byte-order
22
+ mark. A long run of key characters is redacted only when it mixes letters and digits and isn't a path. A page's
23
+ own blob: file shows its address whole; a data: one shows only its type and length; any address is cut at 300
24
+ characters. The browser's copy is deleted once read: it sat in the temp folder, which is memory on some
25
+ machines, until the screen closed.
26
+ - A blob: address in `screen_requests` shows whole, not cut to `:3110/<id>`.
27
+ - A secret kept as a number in JSON (`"api_key": 123456`) is redacted, in a download's text and in a request
28
+ body cut short. A tab-separated download is redacted by its column headers whatever its name, so a
29
+ spreadsheet's "Unicode text" export (.txt) is, as a .csv or .tsv is.
30
+ - A scenario file Swarmbox can't play says where and why, in words: "…/b.json isn't a scenario Swarmbox can
31
+ play: cast.0.part: Too big: expected string to have <=80 characters". It used to say only "failed: [", so an
32
+ agent couldn't tell what to fix. `scenario_list` lists every other scenario and names each file it can't play
33
+ with that reason; one bad file used to fail the whole list. `readScenarios` returns both.
34
+
8
35
  ## 0.18.0 (2026-11-11)
9
36
 
10
37
  - `serve` takes `standinSandbox`, and reads `SWARMBOX_NO_SANDBOX=1` as "off" when it isn't given. Before, only a
package/README.md CHANGED
@@ -45,6 +45,10 @@ Built for Swarmify's agents, and usable by any team whose product runs locally.
45
45
  start of what was sent and what came back, and what it keeps open (a live stream). An action's "refused:" line
46
46
  gives each refusal's number, with the server's reason (`error.message`, or FastAPI's `detail`). No headers are
47
47
  kept, and secrets in addresses and bodies are redacted.
48
+ - **A screen's downloads** (`screen_downloads`): the files it saved (an export, a report, a statement), with
49
+ name, size and fingerprint, and a text file's contents a page at a time. An action's "downloaded:" line names
50
+ each file it saved. Secrets in the text are redacted: token-shaped words anywhere, and in a CSV or TSV every
51
+ cell under a secret-named header.
48
52
  - **A daily budget** in browser-minutes and runs.
49
53
 
50
54
  ## Install
@@ -56,6 +60,12 @@ pnpm exec playwright-core install chromium
56
60
 
57
61
  `playwright-core` is a peer dependency, so your product and Swarmbox share one copy. Node 24 or later.
58
62
 
63
+ Stand-ins run in the operating-system sandbox. macOS has what it needs. On Linux, install **bubblewrap**,
64
+ **socat** and **ripgrep** (`apt-get install bubblewrap socat ripgrep`), and on Ubuntu 24.04 or later allow
65
+ unprivileged user namespaces (`kernel.apparmor_restrict_unprivileged_userns=0`), as `.github/workflows` does.
66
+ Without them `run_start` refuses and names what's missing. `SWARMBOX_NO_SANDBOX=1` runs stand-ins without the
67
+ sandbox: only on a throwaway machine of your own, never a shared one.
68
+
59
69
  ## Plugging a product in
60
70
 
61
71
  A product is one object (`Product` in `src/product.ts`): how to start a world, who is in it, how each of
@@ -0,0 +1,60 @@
1
+ import type { Download } from 'playwright-core';
2
+ export interface DownloadRecord {
3
+ /** Counts the screen's downloads from 1. */
4
+ seq: number;
5
+ at: string;
6
+ /** The name the page gave it. */
7
+ name: string;
8
+ /** Where it came from: a path on the screen's own origin, else the whole address. Secrets redacted. */
9
+ url: string;
10
+ state: 'saving' | 'saved' | 'failed';
11
+ bytes?: number;
12
+ sha256?: string;
13
+ /** A text file's contents (redacted), up to TEXT_KEPT characters. */
14
+ text?: string;
15
+ /** The text was longer than TEXT_KEPT, or the file longer than READ_MAX. */
16
+ cut?: boolean;
17
+ binary?: boolean;
18
+ failure?: string;
19
+ }
20
+ /** Kept per screen; the oldest go first. */
21
+ export declare const DOWNLOADS_KEPT = 50;
22
+ /** Of a file, read for its text; the fingerprint and size cover all of it. */
23
+ export declare const READ_MAX: number;
24
+ /** Of a text file, kept. */
25
+ export declare const TEXT_KEPT = 500000;
26
+ /** The longest a download is waited for after the action that started it. */
27
+ export declare const DOWNLOAD_WAIT_MS = 30000;
28
+ /**
29
+ * A file's text, or null when it isn't text: UTF-16 by its byte-order mark (a spreadsheet's "Unicode text"
30
+ * export holds NULs, so it's looked for first), else UTF-8 with no NUL. A character cut at the end of what's
31
+ * checked or kept is still text.
32
+ */
33
+ export declare function decodeText(name: string, bytes: Buffer): string | null;
34
+ /** Whether these bytes are a text file's. */
35
+ export declare function isText(name: string, bytes: Buffer): boolean;
36
+ export declare function redactWords(text: string): string;
37
+ /** A table with every cell under a secret-named header ("password", "api_key", "portal token"…) redacted. */
38
+ export declare function redactTable(text: string, sep: string): string;
39
+ /** A file's contents as kept: the text (redacted, bounded) or that it's binary. */
40
+ export declare function contents(name: string, bytes: Buffer, longer: boolean): Pick<DownloadRecord, 'text' | 'cut' | 'binary'>;
41
+ /**
42
+ * Where a download came from, for its line: a path on the screen's own origin, else the whole address, secrets
43
+ * redacted and bounded. A data: address is the file itself, so only its type and length are shown.
44
+ */
45
+ export declare function source(url: string, origin: string): string;
46
+ export interface DownloadLog {
47
+ records: DownloadRecord[];
48
+ /** The last record's number: an action's downloads are the ones after it. */
49
+ last(): number;
50
+ onDownload(d: Download): void;
51
+ /** Resolves when every download after `seq` has been saved or has failed, or after `ms`. */
52
+ settled(seq: number, ms?: number): Promise<DownloadRecord[]>;
53
+ }
54
+ /** A screen's log; `origin` is its own, whose addresses are shown as paths. */
55
+ export declare function downloadLog(origin: string): DownloadLog;
56
+ /** One line for a download: the readout after an action, and screen_downloads' list. */
57
+ export declare function downloadLine(r: DownloadRecord): string;
58
+ /** One download in full: its line, fingerprint and text from `offset`, at most `limit` characters. */
59
+ export declare function downloadText(r: DownloadRecord, offset?: number, limit?: number): string;
60
+ //# sourceMappingURL=downloads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloads.d.ts","sourceRoot":"","sources":["../src/downloads.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4CAA4C;AAC5C,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,8EAA8E;AAC9E,eAAO,MAAM,QAAQ,QAAmB,CAAC;AACzC,4BAA4B;AAC5B,eAAO,MAAM,SAAS,SAAU,CAAC;AACjC,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAOvC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAarE;AAED,6CAA6C;AAC7C,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3D;AAYD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIhD;AAkBD,6GAA6G;AAC7G,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAY7D;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,GACd,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC,CAgBjD;AAKD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,IAAI,IAAI,MAAM,CAAC;IACf,UAAU,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,4FAA4F;IAC5F,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CAC9D;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAuDvD;AAUD,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CAQtD;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,SAAI,EAAE,KAAK,SAAS,GAAG,MAAM,CAYlF"}
@@ -0,0 +1,214 @@
1
+ // What a screen saved as a file: an export, a report, a statement. A browser drew nothing for it, so without
2
+ // this the agent could press "Download" and never know what came out. Each download is read as it finishes:
3
+ // its name, size, a fingerprint, and, for a text file (CSV, JSON, a calendar file…), the text itself, which
4
+ // screen_downloads shows. Secrets in the text are redacted as a response body's are (redact.ts).
5
+ //
6
+ // Read through the download's stream, not its path: the path isn't there when the browser is remote.
7
+ import { createHash } from 'node:crypto';
8
+ import { REDACTED, redactText, redactUrl, secretName } from "./redact.js";
9
+ /** Kept per screen; the oldest go first. */
10
+ export const DOWNLOADS_KEPT = 50;
11
+ /** Of a file, read for its text; the fingerprint and size cover all of it. */
12
+ export const READ_MAX = 10 * 1024 * 1024;
13
+ /** Of a text file, kept. */
14
+ export const TEXT_KEPT = 500_000;
15
+ /** The longest a download is waited for after the action that started it. */
16
+ export const DOWNLOAD_WAIT_MS = 30_000;
17
+ /** Files whose bytes are text, by name; anything else is text only if it reads as UTF-8. */
18
+ const TEXT_NAMES = /\.(csv|tsv|txt|json|xml|ics|vcf|html?|md|iif|ofx|qbo|qfx|log|ya?ml)$/i;
19
+ /** How far into a file without a text name its UTF-8 is checked. */
20
+ const SNIFF = 64 * 1024;
21
+ /**
22
+ * A file's text, or null when it isn't text: UTF-16 by its byte-order mark (a spreadsheet's "Unicode text"
23
+ * export holds NULs, so it's looked for first), else UTF-8 with no NUL. A character cut at the end of what's
24
+ * checked or kept is still text.
25
+ */
26
+ export function decodeText(name, bytes) {
27
+ if (bytes[0] === 0xff && bytes[1] === 0xfe)
28
+ return new TextDecoder('utf-16le').decode(bytes);
29
+ if (bytes[0] === 0xfe && bytes[1] === 0xff)
30
+ return new TextDecoder('utf-16be').decode(bytes);
31
+ if (bytes.includes(0))
32
+ return null;
33
+ if (!TEXT_NAMES.test(name)) {
34
+ try {
35
+ // stream: a multi-byte character cut at SNIFF is held back, not an error.
36
+ new TextDecoder('utf-8', { fatal: true }).decode(bytes.subarray(0, SNIFF), { stream: true });
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ return new TextDecoder('utf-8').decode(bytes);
43
+ }
44
+ /** Whether these bytes are a text file's. */
45
+ export function isText(name, bytes) {
46
+ return decodeText(name, bytes) !== null;
47
+ }
48
+ /**
49
+ * A word that is a token by its shape wherever it sits in a file: a JWT or a provider's secret key, and a long
50
+ * run of key characters that mixes letters and digits and isn't a path. A body is redacted only when it is one
51
+ * token (redact.ts); a file is mostly not secret, so its words are looked at one by one. Best effort: a
52
+ * fingerprint or a slug with numbers in it reads as a token, and a short key (32 hex characters) doesn't.
53
+ */
54
+ const KNOWN_TOKEN = /\beyJ[\w-]+\.[\w-]+\.[\w-]*|\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{8,}|\bwhsec_[A-Za-z0-9]{8,}/g;
55
+ const LONG_RUN = /(?<![\w+/=-])[A-Za-z0-9_+/=-]{40,}(?![\w+/=-])/g;
56
+ export function redactWords(text) {
57
+ return text
58
+ .replace(KNOWN_TOKEN, REDACTED)
59
+ .replace(LONG_RUN, (w) => (w.startsWith('/') || !/\d/.test(w) || !/[A-Za-z]/.test(w) ? w : REDACTED));
60
+ }
61
+ /** A row's cells, split on `sep` outside quotes (a quoted cell holding a line break is read as two rows). */
62
+ function cells(row, sep) {
63
+ const out = [];
64
+ let cell = '';
65
+ let quoted = false;
66
+ for (const ch of row) {
67
+ if (ch === '"')
68
+ quoted = !quoted;
69
+ if (ch === sep && !quoted) {
70
+ out.push(cell);
71
+ cell = '';
72
+ }
73
+ else
74
+ cell += ch;
75
+ }
76
+ out.push(cell);
77
+ return out;
78
+ }
79
+ /** A table with every cell under a secret-named header ("password", "api_key", "portal token"…) redacted. */
80
+ export function redactTable(text, sep) {
81
+ const rows = text.split('\n');
82
+ const secret = cells(rows[0] ?? '', sep).map((h) => secretName(h.replace(/^\s*"|"\s*$/g, '').trim()));
83
+ if (!secret.some(Boolean))
84
+ return text;
85
+ return [
86
+ rows[0],
87
+ ...rows.slice(1).map((r) => cells(r, sep)
88
+ .map((c, i) => (secret[i] && c.trim() ? REDACTED : c))
89
+ .join(sep)),
90
+ ].join('\n');
91
+ }
92
+ /** A file's contents as kept: the text (redacted, bounded) or that it's binary. */
93
+ export function contents(name, bytes, longer) {
94
+ const raw = decodeText(name, bytes);
95
+ if (raw === null)
96
+ return { binary: true };
97
+ const ext = /\.([a-z]+)$/i.exec(name)?.[1]?.toLowerCase() ?? '';
98
+ // Redacted in place, never reparsed: an export's 424.10 and its 20-digit ids are read as the file has them.
99
+ let text = redactText(raw);
100
+ // A table by its name, or tab-separated text by its first line (a spreadsheet's "Unicode text" is .txt).
101
+ const sep = ext === 'csv' ? ',' : ext === 'tsv' || /^[^\n]*\t/.test(text) ? '\t' : null;
102
+ if (sep)
103
+ text = redactTable(text, sep);
104
+ text = redactWords(text);
105
+ let cut = longer;
106
+ if (text.length > TEXT_KEPT) {
107
+ text = text.slice(0, TEXT_KEPT);
108
+ cut = true;
109
+ }
110
+ return { text, ...(cut ? { cut } : {}) };
111
+ }
112
+ /** The longest "from" address shown. */
113
+ const URL_SHOWN = 300;
114
+ /**
115
+ * Where a download came from, for its line: a path on the screen's own origin, else the whole address, secrets
116
+ * redacted and bounded. A data: address is the file itself, so only its type and length are shown.
117
+ */
118
+ export function source(url, origin) {
119
+ const data = /^data:([^,;]*)/i.exec(url);
120
+ if (data)
121
+ return `data:${data[1] || 'text/plain'} (${url.length} characters)`;
122
+ const shown = redactUrl(url, origin);
123
+ return shown.length > URL_SHOWN ? `${shown.slice(0, URL_SHOWN)}…` : shown;
124
+ }
125
+ /** A screen's log; `origin` is its own, whose addresses are shown as paths. */
126
+ export function downloadLog(origin) {
127
+ const records = [];
128
+ const pending = new Map();
129
+ let seq = 0;
130
+ const read = async (d, rec) => {
131
+ try {
132
+ const stream = await d.createReadStream();
133
+ const hash = createHash('sha256');
134
+ const kept = [];
135
+ let size = 0;
136
+ for await (const chunk of stream) {
137
+ hash.update(chunk);
138
+ if (size < READ_MAX)
139
+ kept.push(chunk.subarray(0, READ_MAX - size));
140
+ size += chunk.length;
141
+ }
142
+ Object.assign(rec, {
143
+ state: 'saved',
144
+ bytes: size,
145
+ sha256: hash.digest('hex'),
146
+ ...contents(rec.name, Buffer.concat(kept), size > READ_MAX),
147
+ });
148
+ }
149
+ catch (e) {
150
+ rec.state = 'failed';
151
+ rec.failure = (await d.failure().catch(() => null)) ?? e.message.split('\n')[0];
152
+ }
153
+ // Read, so the browser's copy goes: it sits in the temp folder, which is memory on some machines.
154
+ await d.delete().catch(() => { });
155
+ };
156
+ return {
157
+ records,
158
+ last: () => seq,
159
+ onDownload(d) {
160
+ const rec = {
161
+ seq: ++seq,
162
+ at: new Date().toISOString(),
163
+ name: d.suggestedFilename(),
164
+ url: source(d.url(), origin),
165
+ state: 'saving',
166
+ };
167
+ records.push(rec);
168
+ if (records.length > DOWNLOADS_KEPT)
169
+ records.shift();
170
+ const done = read(d, rec).finally(() => pending.delete(rec.seq));
171
+ pending.set(rec.seq, done);
172
+ },
173
+ async settled(after, ms = DOWNLOAD_WAIT_MS) {
174
+ const waiting = [...pending].filter(([n]) => n > after).map(([, p]) => p);
175
+ if (waiting.length) {
176
+ let timer;
177
+ await Promise.race([Promise.all(waiting), new Promise((r) => (timer = setTimeout(r, ms)))]).finally(() => clearTimeout(timer));
178
+ }
179
+ return records.filter((r) => r.seq > after);
180
+ },
181
+ };
182
+ }
183
+ function size(bytes) {
184
+ return bytes < 1024
185
+ ? `${bytes} B`
186
+ : bytes < 1024 * 1024
187
+ ? `${(bytes / 1024).toFixed(1)} KB`
188
+ : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
189
+ }
190
+ /** One line for a download: the readout after an action, and screen_downloads' list. */
191
+ export function downloadLine(r) {
192
+ const what = r.state === 'saving'
193
+ ? 'still saving'
194
+ : r.state === 'failed'
195
+ ? `failed: ${r.failure ?? 'unknown'}`
196
+ : `${size(r.bytes ?? 0)}, ${r.binary ? 'binary' : `text${r.cut ? ', cut' : ''}`}`;
197
+ return `#${r.seq} ${r.name} (${what}) from ${r.url}`;
198
+ }
199
+ /** One download in full: its line, fingerprint and text from `offset`, at most `limit` characters. */
200
+ export function downloadText(r, offset = 0, limit = 20_000) {
201
+ const head = `${downloadLine(r)}${r.sha256 ? `\nsha256 ${r.sha256}` : ''}`;
202
+ if (r.state !== 'saved')
203
+ return head;
204
+ if (r.binary)
205
+ return `${head}\nA binary file: its contents aren't shown.`;
206
+ const text = r.text ?? '';
207
+ const part = text.slice(offset, offset + limit);
208
+ const more = offset + limit < text.length
209
+ ? `\n… ${text.length - offset - limit} more characters: offset ${offset + limit}`
210
+ : '';
211
+ const cut = r.cut ? '\n(the file was longer than Swarmbox keeps; the rest is not shown)' : '';
212
+ return `${head}\n---\n${part}${more}${!more ? cut : ''}`;
213
+ }
214
+ //# sourceMappingURL=downloads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloads.js","sourceRoot":"","sources":["../src/downloads.ts"],"names":[],"mappings":"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"}
package/dist/harness.d.ts CHANGED
@@ -5,6 +5,7 @@ import { type Stroke } from './fleet/sight.ts';
5
5
  import { type ClockMove, type ClockState, type FeedItem, type Hooks } from './hooks.ts';
6
6
  import type { Persona, Product, ProductWorld, WorldSpec } from './product.ts';
7
7
  import { type RequestLog, type RequestQuery, type RequestRecord } from './requests.ts';
8
+ import { type DownloadLog, type DownloadRecord } from './downloads.ts';
8
9
  import { type StandIn } from './standins/runner.ts';
9
10
  import { type DeviceState } from './device/device.ts';
10
11
  import { type Prop, type PropKind } from './device/props.ts';
@@ -56,6 +57,8 @@ export interface ScreenEntry {
56
57
  device: DeviceState;
57
58
  /** What it asked its servers for, newest last (bounded, secrets redacted). */
58
59
  requests: RequestLog;
60
+ /** What it saved as files, newest last (bounded, secrets in text redacted). */
61
+ downloads: DownloadLog;
59
62
  }
60
63
  /**
61
64
  * Something a screen's browser saw go wrong without anyone asking: an error in the console or an uncaught
@@ -132,6 +135,8 @@ export interface Harness<W extends ProductWorld = ProductWorld> {
132
135
  setNetwork(screenId: string, mode: NetworkMode): Promise<void>;
133
136
  /** What a screen asked its servers for, newest last. */
134
137
  requests(screenId: string, query?: RequestQuery): RequestRecord[];
138
+ /** What a screen saved as files, newest last. */
139
+ downloads(screenId: string): DownloadRecord[];
135
140
  screens(): ScreenEntry[];
136
141
  screen(screenId: string): ScreenEntry;
137
142
  read(screenId: string): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"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"}
package/dist/harness.js CHANGED
@@ -13,6 +13,7 @@ import { contained, launchFleet, setCookies, } from "./fleet/browser.js";
13
13
  import { behindModal, changes, coveredByOwnLabel, dialogsText, drag, scroll, draw, glance, openDialogs, pickAmong, whyNotClicked, } from "./fleet/sight.js";
14
14
  import { HooksMissing } from "./hooks.js";
15
15
  import { pendingSince, requestLog, selectRequests, } from "./requests.js";
16
+ import { downloadLine, downloadLog } from "./downloads.js";
16
17
  import { isThisMachine } from "./standins/guard.js";
17
18
  import { startStandIn } from "./standins/runner.js";
18
19
  import { setLocation, setNotifications, setUpDevice, showOnCamera, } from "./device/device.js";
@@ -555,6 +556,7 @@ export function createHarness(product, options = {}) {
555
556
  const cutUrls = new Set();
556
557
  const stalled = new Set();
557
558
  const requests = requestLog(w.fleet.originFor(persona.tenant));
559
+ const downloads = downloadLog(w.fleet.originFor(persona.tenant));
558
560
  const signal = (kind, text, url) => {
559
561
  signals.push({
560
562
  at: new Date().toISOString(),
@@ -582,6 +584,8 @@ export function createHarness(product, options = {}) {
582
584
  ...(options.colorScheme ? { colorScheme: options.colorScheme } : {}),
583
585
  onContext: async (ctx) => {
584
586
  await setUpDevice(ctx, device, (t) => signal('device', t));
587
+ // Every page the screen opens, its first and any popup: an export can open in a new tab.
588
+ ctx.on('page', (p) => p.on('download', (d) => downloads.onDownload(d)));
585
589
  ctx.on('console', (m) => {
586
590
  // A 4xx is the server refusing something, which the app handles and shows (a conflict, a
587
591
  // validation error); Chrome logs each as a console error regardless. 5xx are server-error below.
@@ -654,6 +658,7 @@ export function createHarness(product, options = {}) {
654
658
  network: { mode: 'online' },
655
659
  device,
656
660
  requests,
661
+ downloads,
657
662
  releaseStalled: () => {
658
663
  for (const route of stalled) {
659
664
  deliberate.add(route.request());
@@ -773,6 +778,7 @@ export function createHarness(product, options = {}) {
773
778
  screens: () => [...screens.values()],
774
779
  screen: getScreen,
775
780
  requests: (screenId, query) => selectRequests(getScreen(screenId).requests.records, query),
781
+ downloads: (screenId) => [...getScreen(screenId).downloads.records],
776
782
  async setNetwork(screenId, mode) {
777
783
  const s = getScreen(screenId);
778
784
  // The screen's one network route (attach) reads the mode on every request, so a change is just
@@ -802,6 +808,7 @@ export function createHarness(product, options = {}) {
802
808
  const page = s.screen.page;
803
809
  const before = await glance(page);
804
810
  const since = s.requests.last();
811
+ const savedBefore = s.downloads.last();
805
812
  // From here: what the server does next is what this action caused (or something late finishing). What it
806
813
  // did before (an iPad's queue sending once it's back online, another screen's work) is read off now, so
807
814
  // it isn't put down to this action.
@@ -957,6 +964,8 @@ export function createHarness(product, options = {}) {
957
964
  finally {
958
965
  page.off('response', onResponse);
959
966
  }
967
+ // A file the action saved: waited for until it's read, so the readout can say what came out.
968
+ const saved = s.downloads.last() > savedBefore ? await s.downloads.settled(savedBefore) : [];
960
969
  const changed = changes(before, await glance(page));
961
970
  let server = [];
962
971
  if (w.feedAt.has(s.persona.tenant)) {
@@ -984,6 +993,9 @@ export function createHarness(product, options = {}) {
984
993
  ]
985
994
  : []),
986
995
  ...(refusals.length ? [`refused: ${refusals.join('\n ')}`] : []),
996
+ ...(saved.length
997
+ ? [`downloaded: ${saved.map(downloadLine).join('\n ')} (screen_downloads)`]
998
+ : []),
987
999
  ...(stillOpen.length
988
1000
  ? [
989
1001
  `waiting: still open after ${ACTION_WAIT_MS / 1000} s: ${stillOpen