@trusty-squire/mcp 1.1.34 → 1.1.35-rc.1

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 (61) hide show
  1. package/dist/bin.js +15 -0
  2. package/dist/bin.js.map +1 -1
  3. package/dist/bot/act/act.d.ts.map +1 -1
  4. package/dist/bot/act/act.js +25 -4
  5. package/dist/bot/act/act.js.map +1 -1
  6. package/dist/bot/broker/mcp-socket.d.ts.map +1 -1
  7. package/dist/bot/broker/mcp-socket.js +5 -0
  8. package/dist/bot/broker/mcp-socket.js.map +1 -1
  9. package/dist/bot/broker/operator.d.ts.map +1 -1
  10. package/dist/bot/broker/operator.js +1 -0
  11. package/dist/bot/broker/operator.js.map +1 -1
  12. package/dist/bot/browser.d.ts +2 -1
  13. package/dist/bot/browser.d.ts.map +1 -1
  14. package/dist/bot/browser.js +64 -19
  15. package/dist/bot/browser.js.map +1 -1
  16. package/dist/bot/download-transfer.d.ts +12 -0
  17. package/dist/bot/download-transfer.d.ts.map +1 -0
  18. package/dist/bot/download-transfer.js +103 -0
  19. package/dist/bot/download-transfer.js.map +1 -0
  20. package/dist/bot/downloads.d.ts +64 -0
  21. package/dist/bot/downloads.d.ts.map +1 -0
  22. package/dist/bot/downloads.js +300 -0
  23. package/dist/bot/downloads.js.map +1 -0
  24. package/dist/bot/observe/observe.d.ts +1 -0
  25. package/dist/bot/observe/observe.d.ts.map +1 -1
  26. package/dist/bot/observe/observe.js +17 -0
  27. package/dist/bot/observe/observe.js.map +1 -1
  28. package/dist/bot/operate-drive.d.ts +4 -0
  29. package/dist/bot/operate-drive.d.ts.map +1 -1
  30. package/dist/bot/operate-drive.js +49 -2
  31. package/dist/bot/operate-drive.js.map +1 -1
  32. package/dist/bot/owned-pages.d.ts +2 -1
  33. package/dist/bot/owned-pages.d.ts.map +1 -1
  34. package/dist/bot/owned-pages.js +4 -1
  35. package/dist/bot/owned-pages.js.map +1 -1
  36. package/dist/bot/page-driver.d.ts +2 -0
  37. package/dist/bot/page-driver.d.ts.map +1 -1
  38. package/dist/bot/page-driver.js +4 -1
  39. package/dist/bot/page-driver.js.map +1 -1
  40. package/dist/bot/provision-session.d.ts +1 -0
  41. package/dist/bot/provision-session.d.ts.map +1 -1
  42. package/dist/bot/screenshot-click.d.ts +4 -2
  43. package/dist/bot/screenshot-click.d.ts.map +1 -1
  44. package/dist/bot/screenshot-click.js +22 -14
  45. package/dist/bot/screenshot-click.js.map +1 -1
  46. package/dist/bot/session/lifecycle.d.ts.map +1 -1
  47. package/dist/bot/session/lifecycle.js +2 -0
  48. package/dist/bot/session/lifecycle.js.map +1 -1
  49. package/dist/bot/upload-error.d.ts +11 -0
  50. package/dist/bot/upload-error.d.ts.map +1 -0
  51. package/dist/bot/upload-error.js +26 -0
  52. package/dist/bot/upload-error.js.map +1 -0
  53. package/dist/tools/provision-drive-schema.d.ts +1 -0
  54. package/dist/tools/provision-drive-schema.d.ts.map +1 -1
  55. package/dist/tools/provision-drive-schema.js +44 -5
  56. package/dist/tools/provision-drive-schema.js.map +1 -1
  57. package/dist/tools/provision-drive.d.ts +67 -4
  58. package/dist/tools/provision-drive.d.ts.map +1 -1
  59. package/dist/tools/provision-drive.js +160 -8
  60. package/dist/tools/provision-drive.js.map +1 -1
  61. package/package.json +1 -1
@@ -0,0 +1,12 @@
1
+ import { type Socket } from "node:net";
2
+ export declare const DOWNLOAD_HANDLE_PREFIX = "trusty-squire-download ";
3
+ /** Broker side: stream one redeemed handle, then close the socket. */
4
+ export declare function serveDownloadHandle(socket: Socket, handle: string): void;
5
+ export interface FetchedDownload {
6
+ path: string;
7
+ size_bytes: number;
8
+ sha256: string;
9
+ }
10
+ /** Agent side: redeem a handle and write the file into destDir. */
11
+ export declare function fetchDownloadHandle(socketPath: string, handle: string, destDir: string): Promise<FetchedDownload>;
12
+ //# sourceMappingURL=download-transfer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-transfer.d.ts","sourceRoot":"","sources":["../../src/bot/download-transfer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AASzD,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAUhE,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAcxE;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,mEAAmE;AACnE,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,CAAC,CAmD1B"}
@@ -0,0 +1,103 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createReadStream, createWriteStream } from "node:fs";
3
+ import { link, rm } from "node:fs/promises";
4
+ import { createConnection } from "node:net";
5
+ import { join, parse as parsePath } from "node:path";
6
+ import { pipeline } from "node:stream/promises";
7
+ import { redeemDownloadHandle } from "./downloads.js";
8
+ // Delivers a download handle over the shared MCP socket to a process on the
9
+ // agent's machine. The client sends this prefix plus the handle as its first
10
+ // line, instead of an agent identity. The broker replies with one JSON header
11
+ // line, then the raw file bytes.
12
+ export const DOWNLOAD_HANDLE_PREFIX = "trusty-squire-download ";
13
+ /** Broker side: stream one redeemed handle, then close the socket. */
14
+ export function serveDownloadHandle(socket, handle) {
15
+ const redeemed = redeemDownloadHandle(handle);
16
+ if (redeemed === null) {
17
+ socket.end(`${JSON.stringify({ ok: false, error: "unknown_or_expired_handle" })}\n`);
18
+ return;
19
+ }
20
+ const header = {
21
+ ok: true,
22
+ filename: redeemed.filename,
23
+ size_bytes: redeemed.size_bytes,
24
+ sha256: redeemed.sha256,
25
+ };
26
+ socket.write(`${JSON.stringify(header)}\n`);
27
+ void pipeline(createReadStream(redeemed.path), socket).catch(() => socket.destroy());
28
+ }
29
+ /** Agent side: redeem a handle and write the file into destDir. */
30
+ export async function fetchDownloadHandle(socketPath, handle, destDir) {
31
+ const socket = createConnection(socketPath);
32
+ socket.write(`${DOWNLOAD_HANDLE_PREFIX}${handle}\n`);
33
+ const header = await new Promise((resolve, reject) => {
34
+ let buffered = Buffer.alloc(0);
35
+ const onData = (chunk) => {
36
+ buffered = Buffer.concat([buffered, chunk]);
37
+ const end = buffered.indexOf(10);
38
+ if (end < 0) {
39
+ if (buffered.length > 4096)
40
+ reject(new Error("download handle reply has no header"));
41
+ return;
42
+ }
43
+ socket.off("data", onData);
44
+ socket.off("error", reject);
45
+ socket.pause();
46
+ try {
47
+ resolve({
48
+ header: JSON.parse(buffered.subarray(0, end).toString("utf8")),
49
+ rest: buffered.subarray(end + 1),
50
+ });
51
+ }
52
+ catch (error) {
53
+ reject(error);
54
+ }
55
+ };
56
+ socket.on("data", onData);
57
+ socket.once("error", reject);
58
+ socket.once("end", () => reject(new Error("broker closed the connection before replying")));
59
+ });
60
+ if (!header.header.ok || !header.header.filename || !header.header.sha256) {
61
+ socket.destroy();
62
+ throw new Error(`download handle refused: ${header.header.error ?? "invalid reply"}`);
63
+ }
64
+ const { filename, sha256: expected } = header.header;
65
+ const partial = join(destDir, `.${parsePath(filename).base}.${process.pid}.partial`);
66
+ const hash = createHash("sha256");
67
+ let size = 0;
68
+ const out = createWriteStream(partial, { flags: "wx", mode: 0o600 });
69
+ try {
70
+ socket.unshift(header.rest);
71
+ socket.on("data", (chunk) => {
72
+ hash.update(chunk);
73
+ size += chunk.length;
74
+ });
75
+ await pipeline(socket, out);
76
+ const sha256 = hash.digest("hex");
77
+ if (sha256 !== expected)
78
+ throw new Error("received file does not match the download sha256");
79
+ const path = await claimName(partial, destDir, filename);
80
+ return { path, size_bytes: size, sha256 };
81
+ }
82
+ finally {
83
+ await rm(partial, { force: true });
84
+ }
85
+ }
86
+ // Hard-link the finished file under the first free name, so an existing file
87
+ // is never overwritten.
88
+ async function claimName(partial, destDir, filename) {
89
+ const { name, ext } = parsePath(filename);
90
+ for (let attempt = 0; attempt < 100; attempt += 1) {
91
+ const path = join(destDir, attempt === 0 ? filename : `${name} (${attempt})${ext}`);
92
+ try {
93
+ await link(partial, path);
94
+ return path;
95
+ }
96
+ catch (error) {
97
+ if (error.code !== "EEXIST")
98
+ throw error;
99
+ }
100
+ }
101
+ throw new Error("dest_dir already holds 100 files with this name");
102
+ }
103
+ //# sourceMappingURL=download-transfer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-transfer.js","sourceRoot":"","sources":["../../src/bot/download-transfer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { Page } from "playwright";
2
+ export type DownloadState = "in_progress" | "complete" | "failed";
3
+ export interface DownloadRecord {
4
+ download_id: string;
5
+ state: DownloadState;
6
+ filename: string;
7
+ mime_type: string;
8
+ /** Absolute path on the broker host. Set once the file is in the session folder. */
9
+ path: string | null;
10
+ size_bytes: number | null;
11
+ sha256: string | null;
12
+ error?: string;
13
+ }
14
+ export declare function downloadsRoot(): string;
15
+ /** A single path segment: no separators, control characters, or dot names. */
16
+ export declare function safeDownloadFilename(suggested: string): string;
17
+ export declare function sha256File(path: string): Promise<string>;
18
+ /** One session's downloads. Records never cross to another tracker. */
19
+ export declare class SessionDownloads {
20
+ private readonly entries;
21
+ private readonly watched;
22
+ private readonly contentTypes;
23
+ private folder;
24
+ private committedBytes;
25
+ private sequence;
26
+ /** Record every download this page starts. Idempotent per page. */
27
+ watch(page: Page): void;
28
+ /** Records whose state changed since the last report, oldest first. */
29
+ takeReport(): DownloadRecord[];
30
+ get(downloadId: string): DownloadRecord | undefined;
31
+ list(): DownloadRecord[];
32
+ /** Sequence marker; `since(marker)` returns downloads started after it. */
33
+ marker(): number;
34
+ since(marker: number): DownloadRecord[];
35
+ hasInProgress(): boolean;
36
+ /** Wait until no download started after `marker` is in progress, or until `timeoutMs` passes. */
37
+ settle(timeoutMs: number, signal?: AbortSignal, marker?: number): Promise<void>;
38
+ /** Wait for one download to finish. Returns the record in its latest state. */
39
+ wait(downloadId: string, timeoutMs: number, signal?: AbortSignal): Promise<DownloadRecord | undefined>;
40
+ /** Cancel running downloads, revoke handles, and delete the session folder. */
41
+ dispose(): Promise<void>;
42
+ private sessionFolder;
43
+ private begin;
44
+ private finish;
45
+ }
46
+ export interface DownloadHandle {
47
+ id: string;
48
+ expires_at: string;
49
+ }
50
+ interface HandleEntry {
51
+ owner: SessionDownloads;
52
+ path: string;
53
+ filename: string;
54
+ size_bytes: number;
55
+ sha256: string;
56
+ expiresAt: number;
57
+ }
58
+ /** A short-lived, single-use bearer for one completed download. */
59
+ export declare function mintDownloadHandle(owner: SessionDownloads, record: DownloadRecord): DownloadHandle;
60
+ export type RedeemedHandle = Omit<HandleEntry, "owner" | "expiresAt">;
61
+ /** Consume a handle. Unknown, used, and expired handles all refuse alike. */
62
+ export declare function redeemDownloadHandle(id: string): RedeemedHandle | null;
63
+ export {};
64
+ //# sourceMappingURL=downloads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloads.d.ts","sourceRoot":"","sources":["../../src/bot/downloads.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAY,IAAI,EAAY,MAAM,YAAY,CAAC;AAO3D,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,wBAAgB,aAAa,IAAI,MAAM,CAGtC;AAYD,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAM9D;AAQD,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D;AAMD,uEAAuE;AACvE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAK;IAErB,mEAAmE;IACnE,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAsBvB,uEAAuE;IACvE,UAAU,IAAI,cAAc,EAAE;IAU9B,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAKnD,IAAI,IAAI,cAAc,EAAE;IAIxB,2EAA2E;IAC3E,MAAM,IAAI,MAAM;IAIhB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE;IAIvC,aAAa,IAAI,OAAO;IAIxB,iGAAiG;IAC3F,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAShF,+EAA+E;IACzE,IAAI,CACR,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAOtC,+EAA+E;IACzE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB9B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,KAAK;YAuBC,MAAM;CAmCrB;AA4BD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,WAAW;IACnB,KAAK,EAAE,gBAAgB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAQD,mEAAmE;AACnE,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,cAAc,GACrB,cAAc,CAgBhB;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,WAAW,CAAC,CAAC;AAEtE,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAUtE"}
@@ -0,0 +1,300 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { createReadStream } from "node:fs";
3
+ import { mkdir, mkdtemp, rm, stat } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ import { basename, extname, join } from "node:path";
6
+ import { pipeline } from "node:stream/promises";
7
+ const DEFAULT_SESSION_CAP_BYTES = 2 * 1024 * 1024 * 1024;
8
+ const DEFAULT_HANDLE_TTL_MS = 5 * 60_000;
9
+ const RECENT_RESPONSE_LIMIT = 64;
10
+ const MIME_BY_EXTENSION = {
11
+ ".bin": "application/octet-stream",
12
+ ".csv": "text/csv",
13
+ ".gif": "image/gif",
14
+ ".gz": "application/gzip",
15
+ ".html": "text/html",
16
+ ".jpeg": "image/jpeg",
17
+ ".jpg": "image/jpeg",
18
+ ".json": "application/json",
19
+ ".mov": "video/quicktime",
20
+ ".mp3": "audio/mpeg",
21
+ ".mp4": "video/mp4",
22
+ ".pdf": "application/pdf",
23
+ ".png": "image/png",
24
+ ".svg": "image/svg+xml",
25
+ ".txt": "text/plain",
26
+ ".wav": "audio/wav",
27
+ ".webm": "video/webm",
28
+ ".webp": "image/webp",
29
+ ".zip": "application/zip",
30
+ };
31
+ export function downloadsRoot() {
32
+ const configured = process.env.TRUSTY_SQUIRE_DOWNLOADS_DIR?.trim();
33
+ return configured ? configured : join(homedir(), ".trusty-squire", "downloads");
34
+ }
35
+ function sessionCapBytes() {
36
+ const parsed = Number(process.env.TRUSTY_SQUIRE_DOWNLOAD_SESSION_CAP_BYTES);
37
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_SESSION_CAP_BYTES;
38
+ }
39
+ function handleTtlMs() {
40
+ const parsed = Number(process.env.TRUSTY_SQUIRE_DOWNLOAD_HANDLE_TTL_MS);
41
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_HANDLE_TTL_MS;
42
+ }
43
+ /** A single path segment: no separators, control characters, or dot names. */
44
+ export function safeDownloadFilename(suggested) {
45
+ const cleaned = basename(suggested.replace(/[\\/]/g, "_"))
46
+ .replace(/[\u0000-\u001f\u007f]/g, "")
47
+ .trim()
48
+ .slice(0, 200);
49
+ return cleaned === "" || cleaned === "." || cleaned === ".." ? "download" : cleaned;
50
+ }
51
+ function mimeFor(filename, contentType) {
52
+ const declared = contentType?.split(";")[0]?.trim().toLowerCase();
53
+ if (declared)
54
+ return declared;
55
+ return MIME_BY_EXTENSION[extname(filename).toLowerCase()] ?? "application/octet-stream";
56
+ }
57
+ export async function sha256File(path) {
58
+ const hash = createHash("sha256");
59
+ await pipeline(createReadStream(path), hash);
60
+ return hash.digest("hex");
61
+ }
62
+ function errorText(error) {
63
+ return error instanceof Error ? error.message : String(error);
64
+ }
65
+ /** One session's downloads. Records never cross to another tracker. */
66
+ export class SessionDownloads {
67
+ entries = new Map();
68
+ watched = new WeakSet();
69
+ contentTypes = new Map();
70
+ folder = null;
71
+ committedBytes = 0;
72
+ sequence = 0;
73
+ /** Record every download this page starts. Idempotent per page. */
74
+ watch(page) {
75
+ if (this.watched.has(page))
76
+ return;
77
+ this.watched.add(page);
78
+ const onResponse = (response) => {
79
+ const contentType = response.headers()["content-type"];
80
+ if (contentType === undefined)
81
+ return;
82
+ this.contentTypes.delete(response.url());
83
+ this.contentTypes.set(response.url(), contentType);
84
+ if (this.contentTypes.size > RECENT_RESPONSE_LIMIT) {
85
+ const oldest = this.contentTypes.keys().next().value;
86
+ if (oldest !== undefined)
87
+ this.contentTypes.delete(oldest);
88
+ }
89
+ };
90
+ const onDownload = (download) => this.begin(download);
91
+ page.on("response", onResponse);
92
+ page.on("download", onDownload);
93
+ page.once("close", () => {
94
+ page.off("response", onResponse);
95
+ page.off("download", onDownload);
96
+ });
97
+ }
98
+ /** Records whose state changed since the last report, oldest first. */
99
+ takeReport() {
100
+ const changed = [];
101
+ for (const entry of this.entries.values()) {
102
+ if (entry.reported === entry.version)
103
+ continue;
104
+ entry.reported = entry.version;
105
+ changed.push({ ...entry.record });
106
+ }
107
+ return changed;
108
+ }
109
+ get(downloadId) {
110
+ const entry = this.entries.get(downloadId);
111
+ return entry === undefined ? undefined : { ...entry.record };
112
+ }
113
+ list() {
114
+ return [...this.entries.values()].map((entry) => ({ ...entry.record }));
115
+ }
116
+ /** Sequence marker; `since(marker)` returns downloads started after it. */
117
+ marker() {
118
+ return this.sequence;
119
+ }
120
+ since(marker) {
121
+ return [...this.entries.values()].slice(marker).map((entry) => ({ ...entry.record }));
122
+ }
123
+ hasInProgress() {
124
+ return [...this.entries.values()].some((entry) => entry.record.state === "in_progress");
125
+ }
126
+ /** Wait until no download started after `marker` is in progress, or until `timeoutMs` passes. */
127
+ async settle(timeoutMs, signal, marker = 0) {
128
+ const pending = [...this.entries.values()]
129
+ .slice(marker)
130
+ .filter((entry) => entry.record.state === "in_progress")
131
+ .map((entry) => entry.settled);
132
+ if (pending.length === 0)
133
+ return;
134
+ await waitBounded(Promise.all(pending), timeoutMs, signal);
135
+ }
136
+ /** Wait for one download to finish. Returns the record in its latest state. */
137
+ async wait(downloadId, timeoutMs, signal) {
138
+ const entry = this.entries.get(downloadId);
139
+ if (entry === undefined)
140
+ return undefined;
141
+ if (entry.record.state === "in_progress")
142
+ await waitBounded(entry.settled, timeoutMs, signal);
143
+ return { ...entry.record };
144
+ }
145
+ /** Cancel running downloads, revoke handles, and delete the session folder. */
146
+ async dispose() {
147
+ const entries = [...this.entries.values()];
148
+ this.entries.clear();
149
+ this.sequence = 0;
150
+ this.committedBytes = 0;
151
+ revokeHandlesFor(this);
152
+ await Promise.all(entries.map(async (entry) => {
153
+ await entry.download?.cancel().catch(() => undefined);
154
+ await entry.download?.delete().catch(() => undefined);
155
+ }));
156
+ const folder = this.folder;
157
+ this.folder = null;
158
+ if (folder !== null) {
159
+ const path = await folder.catch(() => null);
160
+ if (path !== null)
161
+ await rm(path, { recursive: true, force: true });
162
+ }
163
+ }
164
+ sessionFolder() {
165
+ if (this.folder === null) {
166
+ const root = downloadsRoot();
167
+ this.folder = mkdir(root, { recursive: true, mode: 0o700 }).then(async () => await mkdtemp(join(root, "session-")));
168
+ }
169
+ return this.folder;
170
+ }
171
+ begin(download) {
172
+ const downloadId = `dl-${randomBytes(6).toString("hex")}`;
173
+ const filename = safeDownloadFilename(download.suggestedFilename());
174
+ const entry = {
175
+ record: {
176
+ download_id: downloadId,
177
+ state: "in_progress",
178
+ filename,
179
+ mime_type: mimeFor(filename, this.contentTypes.get(download.url())),
180
+ path: null,
181
+ size_bytes: null,
182
+ sha256: null,
183
+ },
184
+ version: 1,
185
+ reported: 0,
186
+ settled: Promise.resolve(),
187
+ download,
188
+ };
189
+ this.entries.set(downloadId, entry);
190
+ this.sequence += 1;
191
+ entry.settled = this.finish(entry, download);
192
+ }
193
+ async finish(entry, download) {
194
+ const update = (patch) => {
195
+ if (this.entries.get(entry.record.download_id) !== entry)
196
+ return;
197
+ entry.record = { ...entry.record, ...patch };
198
+ entry.version += 1;
199
+ };
200
+ let counted = 0;
201
+ try {
202
+ const staged = await download.path();
203
+ const failure = await download.failure();
204
+ if (failure !== null)
205
+ throw new Error(failure);
206
+ const size = (await stat(staged)).size;
207
+ if (this.committedBytes + size > sessionCapBytes())
208
+ throw new Error("session_download_cap_exceeded");
209
+ this.committedBytes += size;
210
+ counted = size;
211
+ const folder = join(await this.sessionFolder(), entry.record.download_id);
212
+ await mkdir(folder, { mode: 0o700 });
213
+ const path = join(folder, entry.record.filename);
214
+ await download.saveAs(path);
215
+ await download.delete().catch(() => undefined);
216
+ const sha256 = await sha256File(path);
217
+ if (this.entries.get(entry.record.download_id) !== entry) {
218
+ await rm(folder, { recursive: true, force: true });
219
+ return;
220
+ }
221
+ update({ state: "complete", path, size_bytes: size, sha256 });
222
+ }
223
+ catch (error) {
224
+ if (this.entries.get(entry.record.download_id) === entry)
225
+ this.committedBytes -= counted;
226
+ await download.delete().catch(() => undefined);
227
+ update({ state: "failed", error: errorText(error) });
228
+ }
229
+ finally {
230
+ entry.download = null;
231
+ }
232
+ }
233
+ }
234
+ async function waitBounded(work, timeoutMs, signal) {
235
+ let timer;
236
+ let onAbort;
237
+ try {
238
+ await Promise.race([
239
+ work,
240
+ new Promise((resolve) => {
241
+ timer = setTimeout(resolve, timeoutMs);
242
+ }),
243
+ new Promise((_, reject) => {
244
+ if (signal === undefined)
245
+ return;
246
+ onAbort = () => reject(signal.reason ?? new Error("operation_cancelled"));
247
+ if (signal.aborted)
248
+ onAbort();
249
+ else
250
+ signal.addEventListener("abort", onAbort, { once: true });
251
+ }),
252
+ ]);
253
+ }
254
+ finally {
255
+ if (timer !== undefined)
256
+ clearTimeout(timer);
257
+ if (onAbort !== undefined)
258
+ signal?.removeEventListener("abort", onAbort);
259
+ }
260
+ }
261
+ const handles = new Map();
262
+ function revokeHandlesFor(owner) {
263
+ for (const [id, entry] of handles)
264
+ if (entry.owner === owner)
265
+ handles.delete(id);
266
+ }
267
+ /** A short-lived, single-use bearer for one completed download. */
268
+ export function mintDownloadHandle(owner, record) {
269
+ if (record.state !== "complete" || record.path === null || record.sha256 === null)
270
+ throw new Error("Only a complete download can be handed out");
271
+ const now = Date.now();
272
+ for (const [id, entry] of handles)
273
+ if (entry.expiresAt <= now)
274
+ handles.delete(id);
275
+ const id = `dlh-${randomBytes(24).toString("base64url")}`;
276
+ const expiresAt = now + handleTtlMs();
277
+ handles.set(id, {
278
+ owner,
279
+ path: record.path,
280
+ filename: record.filename,
281
+ size_bytes: record.size_bytes ?? 0,
282
+ sha256: record.sha256,
283
+ expiresAt,
284
+ });
285
+ return { id, expires_at: new Date(expiresAt).toISOString() };
286
+ }
287
+ /** Consume a handle. Unknown, used, and expired handles all refuse alike. */
288
+ export function redeemDownloadHandle(id) {
289
+ const entry = handles.get(id);
290
+ handles.delete(id);
291
+ if (entry === undefined || entry.expiresAt <= Date.now())
292
+ return null;
293
+ return {
294
+ path: entry.path,
295
+ filename: entry.filename,
296
+ size_bytes: entry.size_bytes,
297
+ sha256: entry.sha256,
298
+ };
299
+ }
300
+ //# sourceMappingURL=downloads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloads.js","sourceRoot":"","sources":["../../src/bot/downloads.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ export declare function compactV2PublicObservation(session: Session, fields: {
32
32
  hint?: string;
33
33
  page_readiness?: Observation["page_readiness"];
34
34
  }, outputFormat?: "compact" | "full"): Observation;
35
+ export declare const CHROME_DOWNLOADS_HINT = "chrome://downloads is Chrome's internal downloads page, which observe cannot read. Use operate_download with session_id and a download_id from the downloads list in an operate_* step result.";
35
36
  export declare function observeQuery(sessionId: string, query: string, role?: SafeControlV2["role"], cursor?: string): Promise<Record<string, unknown>>;
36
37
  export declare function observedOAuthChallenge(sessionId: string): Promise<Observation["oauth"] | undefined>;
37
38
  export declare function observedThreeDsChallenge(sessionId: string): Promise<Observation["three_ds"] | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../../src/bot/observe/observe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../../src/bot/observe/observe.ts"],"names":[],"mappings":"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"}
@@ -490,6 +490,17 @@ export function compactV2PublicObservation(session, fields, outputFormat = "full
490
490
  throw new Error("compact-v2 budget metadata exceeded");
491
491
  return degraded;
492
492
  }
493
+ export const CHROME_DOWNLOADS_HINT = "chrome://downloads is Chrome's internal downloads page, which observe cannot read. Use operate_download with session_id and a download_id from the downloads list in an operate_* step result.";
494
+ // Chrome renders its downloads page in internal components that the page
495
+ // reader cannot see. Point the agent at the session's download records instead.
496
+ function chromeDownloadsObservation(session, page, outputFormat = "compact") {
497
+ const url = page.url();
498
+ if (!/^chrome:\/\/downloads(?:[/?#]|$)/.test(url))
499
+ return undefined;
500
+ invalidateCompactV2Snapshot(session);
501
+ retainSessionElements(session, []);
502
+ return compactV2PublicObservation(session, { url, stage: safeStageV2(url, []), guidance: CHROME_DOWNLOADS_HINT }, outputFormat);
503
+ }
493
504
  function pendingPageObservation(session, page, readiness, outputFormat = "compact", hint) {
494
505
  invalidateCompactV2Snapshot(session);
495
506
  retainSessionElements(session, []);
@@ -776,6 +787,9 @@ async function observeQueryOwned(sessionId, query, role, cursor) {
776
787
  // and semantic page hints once, together, before filtering.
777
788
  const queryPage = sourcePage ?? session.browser.activePage();
778
789
  if (queryPage !== null && queryPage !== undefined) {
790
+ const downloadsPage = chromeDownloadsObservation(session, queryPage);
791
+ if (downloadsPage !== undefined)
792
+ return { ...downloadsPage };
779
793
  const readiness = await waitForPageReady(queryPage, { kind: "observation" });
780
794
  if (!readiness.ready)
781
795
  return { ...pendingPageObservation(session, queryPage, readiness) };
@@ -1039,6 +1053,9 @@ export async function observeSession(session, _detail = "compact", startMetadata
1039
1053
  }
1040
1054
  const observationPage = sourcePage ?? session.browser.activePage();
1041
1055
  if (observationPage !== null && observationPage !== undefined) {
1056
+ const downloadsPage = chromeDownloadsObservation(session, observationPage, outputFormat);
1057
+ if (downloadsPage !== undefined)
1058
+ return downloadsPage;
1042
1059
  const readiness = await waitForPageReady(observationPage, { kind: "observation" });
1043
1060
  if (!readiness.ready) {
1044
1061
  return pendingPageObservation(session, observationPage, readiness, outputFormat, startMetadata?.hintPages?.[0]);