pi-agent-browser-native 0.2.48 → 0.2.49

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 (185) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +16 -6
  3. package/dist/extensions/agent-browser/index.js +785 -0
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +71 -0
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +121 -0
  6. package/dist/extensions/agent-browser/lib/bash-guard.js +190 -0
  7. package/dist/extensions/agent-browser/lib/command-policy.js +85 -0
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +302 -0
  9. package/dist/extensions/agent-browser/lib/config-policy.js +686 -0
  10. package/dist/extensions/agent-browser/lib/config.js +122 -0
  11. package/dist/extensions/agent-browser/lib/electron/cdp.js +51 -0
  12. package/dist/extensions/agent-browser/lib/electron/cleanup.js +212 -0
  13. package/dist/extensions/agent-browser/lib/electron/discovery.js +633 -0
  14. package/dist/extensions/agent-browser/lib/electron/launch.js +351 -0
  15. package/{extensions/agent-browser/lib/electron/text.ts → dist/extensions/agent-browser/lib/electron/text.js} +5 -5
  16. package/dist/extensions/agent-browser/lib/executable-path.js +20 -0
  17. package/dist/extensions/agent-browser/lib/fs-utils.js +18 -0
  18. package/dist/extensions/agent-browser/lib/input-modes/electron.js +165 -0
  19. package/dist/extensions/agent-browser/lib/input-modes/job.js +519 -0
  20. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +440 -0
  21. package/dist/extensions/agent-browser/lib/input-modes/params.js +164 -0
  22. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +119 -0
  23. package/dist/extensions/agent-browser/lib/input-modes/shared.js +42 -0
  24. package/dist/extensions/agent-browser/lib/input-modes/types.js +21 -0
  25. package/dist/extensions/agent-browser/lib/input-modes.js +10 -0
  26. package/dist/extensions/agent-browser/lib/json-schema.js +58 -0
  27. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +59 -0
  28. package/dist/extensions/agent-browser/lib/navigation-policy.js +83 -0
  29. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +62 -0
  30. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +39 -0
  31. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +276 -0
  32. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +909 -0
  33. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +443 -0
  34. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +47 -0
  35. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +141 -0
  36. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +108 -0
  37. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +112 -0
  38. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +158 -0
  39. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +54 -0
  40. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +762 -0
  41. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +491 -0
  42. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +40 -0
  43. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +5 -0
  44. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +731 -0
  45. package/dist/extensions/agent-browser/lib/orchestration/browser-run/types.js +1 -0
  46. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +718 -0
  47. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +247 -0
  48. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +68 -0
  49. package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js} +12 -11
  50. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +241 -0
  51. package/dist/extensions/agent-browser/lib/playbook.js +121 -0
  52. package/dist/extensions/agent-browser/lib/process.js +448 -0
  53. package/dist/extensions/agent-browser/lib/prompt-policy.js +91 -0
  54. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +220 -0
  55. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +111 -0
  56. package/{extensions/agent-browser/lib/results/artifact-state.ts → dist/extensions/agent-browser/lib/results/artifact-state.js} +4 -8
  57. package/dist/extensions/agent-browser/lib/results/categories.js +76 -0
  58. package/dist/extensions/agent-browser/lib/results/confirmation.js +63 -0
  59. package/dist/extensions/agent-browser/lib/results/contracts.js +8 -0
  60. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +74 -0
  61. package/dist/extensions/agent-browser/lib/results/envelope.js +166 -0
  62. package/dist/extensions/agent-browser/lib/results/network-routes.js +92 -0
  63. package/dist/extensions/agent-browser/lib/results/network.js +73 -0
  64. package/dist/extensions/agent-browser/lib/results/next-actions.js +72 -0
  65. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +515 -0
  66. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +397 -0
  67. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +55 -0
  68. package/dist/extensions/agent-browser/lib/results/presentation/common.js +46 -0
  69. package/dist/extensions/agent-browser/lib/results/presentation/content.js +24 -0
  70. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +960 -0
  71. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +205 -0
  72. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +134 -0
  73. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +159 -0
  74. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +216 -0
  75. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +104 -0
  76. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +152 -0
  77. package/dist/extensions/agent-browser/lib/results/presentation.js +177 -0
  78. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +107 -0
  79. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +50 -0
  80. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +225 -0
  81. package/{extensions/agent-browser/lib/results/shared.ts → dist/extensions/agent-browser/lib/results/shared.js} +0 -1
  82. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +208 -0
  83. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +78 -0
  84. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +331 -0
  85. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +40 -0
  86. package/dist/extensions/agent-browser/lib/results/snapshot.js +264 -0
  87. package/dist/extensions/agent-browser/lib/results/text.js +40 -0
  88. package/{extensions/agent-browser/lib/results.ts → dist/extensions/agent-browser/lib/results.js} +2 -32
  89. package/dist/extensions/agent-browser/lib/runtime.js +816 -0
  90. package/dist/extensions/agent-browser/lib/session-page-state.js +411 -0
  91. package/dist/extensions/agent-browser/lib/string-enum-schema.js +13 -0
  92. package/dist/extensions/agent-browser/lib/temp.js +498 -0
  93. package/dist/extensions/agent-browser/lib/web-search.js +562 -0
  94. package/docs/RELEASE.md +22 -11
  95. package/docs/SUPPORT_MATRIX.md +4 -3
  96. package/package.json +9 -5
  97. package/scripts/config.mjs +8 -2
  98. package/scripts/doctor.mjs +8 -7
  99. package/extensions/agent-browser/index.ts +0 -961
  100. package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
  101. package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
  102. package/extensions/agent-browser/lib/bash-guard.ts +0 -205
  103. package/extensions/agent-browser/lib/command-policy.ts +0 -71
  104. package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
  105. package/extensions/agent-browser/lib/config-policy.js +0 -690
  106. package/extensions/agent-browser/lib/config.ts +0 -211
  107. package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
  108. package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
  109. package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
  110. package/extensions/agent-browser/lib/electron/launch.ts +0 -499
  111. package/extensions/agent-browser/lib/executable-path.ts +0 -19
  112. package/extensions/agent-browser/lib/fs-utils.ts +0 -18
  113. package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
  114. package/extensions/agent-browser/lib/input-modes/job.ts +0 -527
  115. package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
  116. package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
  117. package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
  118. package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
  119. package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
  120. package/extensions/agent-browser/lib/input-modes.ts +0 -45
  121. package/extensions/agent-browser/lib/json-schema.ts +0 -73
  122. package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
  123. package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
  124. package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
  125. package/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.ts +0 -44
  126. package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -280
  127. package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -914
  128. package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -521
  129. package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
  130. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.ts +0 -158
  131. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.ts +0 -116
  132. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.ts +0 -147
  133. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.ts +0 -183
  134. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.ts +0 -58
  135. package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -847
  136. package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -559
  137. package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
  138. package/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.ts +0 -8
  139. package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
  140. package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -565
  141. package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
  142. package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
  143. package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
  144. package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -267
  145. package/extensions/agent-browser/lib/playbook.ts +0 -142
  146. package/extensions/agent-browser/lib/process.ts +0 -516
  147. package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
  148. package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
  149. package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
  150. package/extensions/agent-browser/lib/results/categories.ts +0 -106
  151. package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
  152. package/extensions/agent-browser/lib/results/contracts.ts +0 -241
  153. package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
  154. package/extensions/agent-browser/lib/results/envelope.ts +0 -195
  155. package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
  156. package/extensions/agent-browser/lib/results/network.ts +0 -78
  157. package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
  158. package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
  159. package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
  160. package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
  161. package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
  162. package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
  163. package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
  164. package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
  165. package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
  166. package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
  167. package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
  168. package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
  169. package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
  170. package/extensions/agent-browser/lib/results/presentation.ts +0 -257
  171. package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
  172. package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
  173. package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
  174. package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
  175. package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
  176. package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
  177. package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
  178. package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
  179. package/extensions/agent-browser/lib/results/text.ts +0 -40
  180. package/extensions/agent-browser/lib/runtime.ts +0 -988
  181. package/extensions/agent-browser/lib/session-page-state.ts +0 -512
  182. package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
  183. package/extensions/agent-browser/lib/temp.ts +0 -577
  184. package/extensions/agent-browser/lib/web-search.ts +0 -728
  185. /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
@@ -1,516 +0,0 @@
1
- /**
2
- * Purpose: Execute the upstream agent-browser binary for the pi-agent-browser extension.
3
- * Responsibilities: Spawn the agent-browser subprocess, forward a curated environment surface, stream optional stdin, bound in-memory output buffering, spill oversized stdout safely to a private temp file under a disk budget, and honor abort signals.
4
- * Scope: Process execution only; argument planning, output formatting, and pi tool registration live elsewhere.
5
- * Usage: Called by the extension tool after argument validation and session planning are complete.
6
- * Invariants/Assumptions: The binary name is always `agent-browser`; Windows routes through PowerShell to invoke npm launchers with escaped argv; callers handle semantic success/error interpretation.
7
- */
8
-
9
- import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
10
- import { chmod, mkdir } from "node:fs/promises";
11
- import { env as processEnv, platform as processPlatform } from "node:process";
12
-
13
- import { GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES, GLOBAL_VALUE_FLAGS, getFlagName } from "./argv-grammar.js";
14
- import { openSecureTempFile, writeSecureTempChunk } from "./temp.js";
15
-
16
- const MAX_BUFFERED_STDOUT_BYTES = 512 * 1_024;
17
- const MAX_BUFFERED_STDERR_CHARS = 32_000;
18
- const MAX_BUFFERED_STDOUT_TAIL_CHARS = 32_000;
19
- const PROCESS_STDOUT_SPILL_FILE_PREFIX = "process-stdout";
20
- const AGENT_BROWSER_SOCKET_DIR_ENV = "AGENT_BROWSER_SOCKET_DIR";
21
- const AGENT_BROWSER_DEFAULT_TIMEOUT_ENV = "AGENT_BROWSER_DEFAULT_TIMEOUT";
22
- const PI_AGENT_BROWSER_PROCESS_TIMEOUT_ENV = "PI_AGENT_BROWSER_PROCESS_TIMEOUT_MS";
23
- const DEFAULT_AGENT_BROWSER_SOCKET_DIR_PREFIX = "/tmp/piab";
24
- export const SAFE_AGENT_BROWSER_OPERATION_TIMEOUT_MS = 25_000;
25
- const DEFAULT_AGENT_BROWSER_PROCESS_TIMEOUT_MS = 35_000;
26
- /** Grace period after `exit` before resolving when `close` is delayed by inherited stdio handles. */
27
- const EXIT_STDIO_GRACE_MS = 100;
28
- const httpProxyEnvName = "http_proxy";
29
- const httpsProxyEnvName = "https_proxy";
30
- const allProxyEnvName = "all_proxy";
31
- const noProxyEnvName = "no_proxy";
32
- const INHERITED_ENV_NAMES = new Set([
33
- "ALL_PROXY",
34
- "APPDATA",
35
- "CI",
36
- "COLORTERM",
37
- "COMSPEC",
38
- "DBUS_SESSION_BUS_ADDRESS",
39
- "DISPLAY",
40
- "FORCE_COLOR",
41
- "HOME",
42
- "HOMEDRIVE",
43
- "HOMEPATH",
44
- "HTTPS_PROXY",
45
- "HTTP_PROXY",
46
- "LANG",
47
- "LC_ALL",
48
- "LC_CTYPE",
49
- "LOCALAPPDATA",
50
- "LOGNAME",
51
- "NO_COLOR",
52
- "NO_PROXY",
53
- "NODE_EXTRA_CA_CERTS",
54
- "NODE_TLS_REJECT_UNAUTHORIZED",
55
- "OS",
56
- "PATH",
57
- "PATHEXT",
58
- "PWD",
59
- "SHELL",
60
- "SSL_CERT_DIR",
61
- "SSL_CERT_FILE",
62
- "SYSTEMROOT",
63
- "TEMP",
64
- "TERM",
65
- "TMP",
66
- "TMPDIR",
67
- "TZ",
68
- "USER",
69
- "USERNAME",
70
- "USERPROFILE",
71
- "WAYLAND_DISPLAY",
72
- "XAUTHORITY",
73
- "AWS_ACCESS_KEY_ID",
74
- "AWS_SECRET_ACCESS_KEY",
75
- "AWS_SESSION_TOKEN",
76
- "AWS_PROFILE",
77
- "AWS_REGION",
78
- "AWS_DEFAULT_REGION",
79
- httpProxyEnvName,
80
- httpsProxyEnvName,
81
- allProxyEnvName,
82
- noProxyEnvName,
83
- ]);
84
- const INHERITED_ENV_PREFIXES = [
85
- "AGENT_BROWSER_",
86
- "AGENTCORE_",
87
- "AI_GATEWAY_",
88
- "BROWSERBASE_",
89
- "BROWSERLESS_",
90
- "BROWSER_USE_",
91
- "KERNEL_",
92
- "XDG_",
93
- ] as const;
94
-
95
- export interface ProcessRunResult {
96
- aborted: boolean;
97
- exitCode: number;
98
- spawnError?: Error;
99
- stderr: string;
100
- stdout: string;
101
- stdoutSpillPath?: string;
102
- timedOut: boolean;
103
- timeoutMs?: number;
104
- }
105
-
106
- function appendTail(text: string, addition: string, maxChars: number): string {
107
- const combined = text + addition;
108
- return combined.length <= maxChars ? combined : combined.slice(combined.length - maxChars);
109
- }
110
-
111
- function quoteWindowsPowerShellArg(value: string): string {
112
- return `'${value.replace(/'/g, "''")}'`;
113
- }
114
-
115
- const WINDOWS_LEADING_GLOBAL_VALUE_FLAGS = new Set<string>(GLOBAL_VALUE_FLAGS);
116
-
117
- /** Exported for unit tests that lock Windows launcher argv ordering. */
118
- export function reorderWindowsLeadingGlobalArgs(args: string[]): string[] {
119
- const leadingGlobals: string[] = [];
120
- let index = 0;
121
- while (index < args.length && args[index]?.startsWith("-")) {
122
- const token = args[index];
123
- const flagName = getFlagName(token);
124
- leadingGlobals.push(token);
125
- index += 1;
126
- if (WINDOWS_LEADING_GLOBAL_VALUE_FLAGS.has(flagName) && !token.includes("=") && index < args.length) {
127
- leadingGlobals.push(args[index]);
128
- index += 1;
129
- continue;
130
- }
131
- if (GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES.has(flagName) && ["true", "false"].includes(args[index] ?? "")) {
132
- leadingGlobals.push(args[index]);
133
- index += 1;
134
- }
135
- }
136
- if (leadingGlobals.length === 0 || index >= args.length) return args;
137
- return [args[index], ...leadingGlobals, ...args.slice(index + 1)];
138
- }
139
-
140
- function buildAgentBrowserSpawnCommand(args: string[]): { command: string; args: string[] } {
141
- if (processPlatform !== "win32") {
142
- return { command: "agent-browser", args };
143
- }
144
- const commandLine = ["&", "agent-browser", ...reorderWindowsLeadingGlobalArgs(args).map(quoteWindowsPowerShellArg)].join(" ");
145
- return { command: "powershell.exe", args: ["-NoLogo", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", commandLine] };
146
- }
147
-
148
- function terminateSpawnedChild(child: ChildProcessWithoutNullStreams, signal: NodeJS.Signals): void {
149
- if (processPlatform === "win32" && child.pid) {
150
- const killer = spawn("taskkill.exe", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" });
151
- killer.on("error", () => undefined);
152
- killer.unref();
153
- }
154
- child.kill(signal);
155
- }
156
-
157
- /** Exported for unit tests that lock subprocess exit-code precedence. */
158
- export function resolveSpawnedChildExitCode(input: {
159
- closeCode?: number | null;
160
- exitCode?: number | null;
161
- useExitFallback: boolean;
162
- timedOut: boolean;
163
- spawnError?: Error;
164
- }): number {
165
- // Precedence: observed `close` code when present, then wrapper timeout (124), then
166
- // post-`exit` fallback when inherited stdio delays `close`, then spawn failure (127).
167
- if (input.closeCode !== null && input.closeCode !== undefined) {
168
- return input.closeCode;
169
- }
170
- if (input.timedOut) {
171
- return 124;
172
- }
173
- if (input.useExitFallback && input.exitCode !== null && input.exitCode !== undefined) {
174
- return input.exitCode;
175
- }
176
- return input.spawnError ? 127 : 0;
177
- }
178
-
179
- interface SpawnedChildCompletionWatcher {
180
- clear: () => void;
181
- }
182
-
183
- function watchSpawnedChildCompletion(
184
- child: ChildProcessWithoutNullStreams,
185
- options: {
186
- graceMs: number;
187
- onComplete: (exitCode: number) => void;
188
- getContext: () => { timedOut: boolean; spawnError?: Error };
189
- },
190
- ): SpawnedChildCompletionWatcher {
191
- let exited = false;
192
- let exitCode: number | null = null;
193
- let postExitTimer: NodeJS.Timeout | undefined;
194
- // `completed` suppresses duplicate exit/close callbacks; `settled` in `finish` guards async spill cleanup.
195
- let completed = false;
196
-
197
- const complete = (closeCode?: number | null) => {
198
- if (completed) return;
199
- completed = true;
200
- if (postExitTimer) {
201
- clearTimeout(postExitTimer);
202
- postExitTimer = undefined;
203
- }
204
- const context = options.getContext();
205
- options.onComplete(
206
- resolveSpawnedChildExitCode({
207
- closeCode,
208
- exitCode,
209
- useExitFallback: exited,
210
- timedOut: context.timedOut,
211
- spawnError: context.spawnError,
212
- }),
213
- );
214
- };
215
-
216
- child.once("exit", (code) => {
217
- exited = true;
218
- exitCode = code;
219
- postExitTimer = setTimeout(() => {
220
- destroySpawnedChildStreams(child);
221
- complete(undefined);
222
- }, options.graceMs);
223
- postExitTimer.unref?.();
224
- });
225
- child.once("close", (code) => {
226
- complete(code);
227
- });
228
-
229
- return {
230
- clear: () => {
231
- if (postExitTimer) {
232
- clearTimeout(postExitTimer);
233
- postExitTimer = undefined;
234
- }
235
- },
236
- };
237
- }
238
-
239
- function destroySpawnedChildStreams(child: ChildProcessWithoutNullStreams): void {
240
- child.stdin?.destroy();
241
- child.stdout?.destroy();
242
- child.stderr?.destroy();
243
- }
244
-
245
- function parsePositiveIntegerEnv(value: string | undefined): number | undefined {
246
- if (value === undefined || !/^\d+$/.test(value.trim())) {
247
- return undefined;
248
- }
249
- const parsed = Number(value.trim());
250
- return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
251
- }
252
-
253
- function clampUpstreamDefaultTimeout(childEnv: NodeJS.ProcessEnv): void {
254
- const requestedTimeout = parsePositiveIntegerEnv(childEnv[AGENT_BROWSER_DEFAULT_TIMEOUT_ENV]);
255
- if (requestedTimeout === undefined || requestedTimeout > SAFE_AGENT_BROWSER_OPERATION_TIMEOUT_MS) {
256
- childEnv[AGENT_BROWSER_DEFAULT_TIMEOUT_ENV] = String(SAFE_AGENT_BROWSER_OPERATION_TIMEOUT_MS);
257
- }
258
- }
259
-
260
- export function getAgentBrowserProcessTimeoutMs(env: NodeJS.ProcessEnv = processEnv): number {
261
- return parsePositiveIntegerEnv(env[PI_AGENT_BROWSER_PROCESS_TIMEOUT_ENV]) ?? DEFAULT_AGENT_BROWSER_PROCESS_TIMEOUT_MS;
262
- }
263
-
264
- export function getAgentBrowserSocketDir(
265
- platform: NodeJS.Platform = processPlatform,
266
- uid: number | undefined = typeof process.getuid === "function" ? process.getuid() : undefined,
267
- ): string | undefined {
268
- if (platform === "win32") {
269
- return undefined;
270
- }
271
- return `${DEFAULT_AGENT_BROWSER_SOCKET_DIR_PREFIX}${typeof uid === "number" ? `-${uid}` : ""}`;
272
- }
273
-
274
- async function ensureAgentBrowserSocketDir(socketDir: string): Promise<boolean> {
275
- try {
276
- await mkdir(socketDir, { recursive: true, mode: 0o700 });
277
- await chmod(socketDir, 0o700).catch(() => undefined);
278
- return true;
279
- } catch {
280
- return false;
281
- }
282
- }
283
-
284
- function getChildEnvName(name: string): string | undefined {
285
- if (processPlatform === "win32") {
286
- const upperName = name.toUpperCase();
287
- if (INHERITED_ENV_NAMES.has(upperName)) return upperName;
288
- return INHERITED_ENV_PREFIXES.some((prefix) => upperName.startsWith(prefix)) ? upperName : undefined;
289
- }
290
- if (INHERITED_ENV_NAMES.has(name) || INHERITED_ENV_PREFIXES.some((prefix) => name.startsWith(prefix))) {
291
- return name;
292
- }
293
- return undefined;
294
- }
295
-
296
- export function buildAgentBrowserProcessEnv(
297
- baseEnv: NodeJS.ProcessEnv = processEnv,
298
- overrides: NodeJS.ProcessEnv | undefined = undefined,
299
- ): NodeJS.ProcessEnv {
300
- const childEnv: NodeJS.ProcessEnv = {};
301
- for (const [name, value] of Object.entries(baseEnv)) {
302
- const childName = getChildEnvName(name);
303
- if (value !== undefined && childName) {
304
- childEnv[childName] = value;
305
- }
306
- }
307
-
308
- if (!overrides) {
309
- clampUpstreamDefaultTimeout(childEnv);
310
- return childEnv;
311
- }
312
-
313
- for (const [name, value] of Object.entries(overrides)) {
314
- const childName = getChildEnvName(name) ?? name;
315
- if (value === undefined) {
316
- delete childEnv[childName];
317
- } else {
318
- childEnv[childName] = value;
319
- }
320
- }
321
- clampUpstreamDefaultTimeout(childEnv);
322
- return childEnv;
323
- }
324
-
325
- export async function runAgentBrowserProcess(options: {
326
- args: string[];
327
- cwd: string;
328
- env?: NodeJS.ProcessEnv;
329
- signal?: AbortSignal;
330
- stdin?: string;
331
- timeoutMs?: number;
332
- }): Promise<ProcessRunResult> {
333
- const { args, cwd, env, signal, stdin } = options;
334
- const timeoutMs = options.timeoutMs ?? getAgentBrowserProcessTimeoutMs();
335
- const explicitSocketDir = env?.[AGENT_BROWSER_SOCKET_DIR_ENV];
336
- let effectiveEnv = explicitSocketDir === undefined ? { ...env, [AGENT_BROWSER_SOCKET_DIR_ENV]: undefined } : env;
337
- const requestedSocketDir = explicitSocketDir ?? getAgentBrowserSocketDir();
338
- if (requestedSocketDir && (await ensureAgentBrowserSocketDir(requestedSocketDir))) {
339
- effectiveEnv = { ...env, [AGENT_BROWSER_SOCKET_DIR_ENV]: requestedSocketDir };
340
- }
341
-
342
- return await new Promise<ProcessRunResult>((resolve) => {
343
- let aborted = false;
344
- let settled = false;
345
- let spawnError: Error | undefined;
346
- let stderr = "";
347
- let stdoutBuffers: Buffer[] = [];
348
- let stdoutBufferedBytes = 0;
349
- let stdoutTail = "";
350
- let stdoutSpillHandle: Awaited<ReturnType<typeof openSecureTempFile>>["fileHandle"] | undefined;
351
- let stdoutSpillPath: string | undefined;
352
- let pendingStdoutWrite = Promise.resolve();
353
- let stdoutSpillError: Error | undefined;
354
- let killTimer: NodeJS.Timeout | undefined;
355
- let timeoutTimer: NodeJS.Timeout | undefined;
356
- let abortListener: (() => void) | undefined;
357
- let timedOut = false;
358
- let completionWatcher: SpawnedChildCompletionWatcher | undefined;
359
-
360
- const queueStdoutChunk = (buffer: Buffer) => {
361
- stdoutTail = appendTail(stdoutTail, buffer.toString("utf8"), MAX_BUFFERED_STDOUT_TAIL_CHARS);
362
- if (stdoutSpillError) return;
363
- if (!stdoutSpillPath && stdoutBufferedBytes + buffer.length <= MAX_BUFFERED_STDOUT_BYTES) {
364
- stdoutBuffers.push(buffer);
365
- stdoutBufferedBytes += buffer.length;
366
- return;
367
- }
368
-
369
- pendingStdoutWrite = pendingStdoutWrite
370
- .then(async () => {
371
- if (stdoutSpillError) return;
372
- if (!stdoutSpillHandle || !stdoutSpillPath) {
373
- const tempFile = await openSecureTempFile(PROCESS_STDOUT_SPILL_FILE_PREFIX, ".json");
374
- stdoutSpillHandle = tempFile.fileHandle;
375
- stdoutSpillPath = tempFile.path;
376
- if (stdoutBuffers.length > 0) {
377
- await writeSecureTempChunk({
378
- content: Buffer.concat(stdoutBuffers),
379
- fileHandle: stdoutSpillHandle,
380
- path: stdoutSpillPath,
381
- });
382
- stdoutBuffers = [];
383
- stdoutBufferedBytes = 0;
384
- }
385
- }
386
- await writeSecureTempChunk({ content: buffer, fileHandle: stdoutSpillHandle, path: stdoutSpillPath });
387
- })
388
- .catch((error) => {
389
- stdoutSpillError = error instanceof Error ? error : new Error(String(error));
390
- });
391
- };
392
-
393
- const removeAbortListener = () => {
394
- if (!signal || !abortListener) return;
395
- signal.removeEventListener("abort", abortListener);
396
- abortListener = undefined;
397
- };
398
-
399
- const finish = (exitCode: number) => {
400
- if (settled) return;
401
- settled = true;
402
- void pendingStdoutWrite.finally(async () => {
403
- removeAbortListener();
404
- if (killTimer) {
405
- clearTimeout(killTimer);
406
- }
407
- if (timeoutTimer) {
408
- clearTimeout(timeoutTimer);
409
- }
410
- completionWatcher?.clear();
411
- if (stdoutSpillHandle) {
412
- await stdoutSpillHandle.close().catch(() => undefined);
413
- }
414
- if (!spawnError && stdoutSpillError) {
415
- spawnError = stdoutSpillError;
416
- }
417
- // Idempotent teardown: streams may already be destroyed by the post-`exit` fallback.
418
- destroySpawnedChildStreams(child);
419
- resolve({
420
- aborted,
421
- exitCode,
422
- spawnError,
423
- stderr,
424
- stdout: stdoutSpillPath ? stdoutTail : Buffer.concat(stdoutBuffers).toString("utf8"),
425
- stdoutSpillPath,
426
- timedOut,
427
- timeoutMs: timedOut ? timeoutMs : undefined,
428
- });
429
- });
430
- };
431
-
432
- const spawnCommand = buildAgentBrowserSpawnCommand(args);
433
- const child = spawn(spawnCommand.command, spawnCommand.args, {
434
- cwd,
435
- env: buildAgentBrowserProcessEnv(processEnv, effectiveEnv),
436
- stdio: ["pipe", "pipe", "pipe"],
437
- });
438
-
439
- const terminateChild = (reason: "abort" | "timeout") => {
440
- if (settled) return;
441
- if (reason === "abort") {
442
- aborted = true;
443
- } else {
444
- timedOut = true;
445
- }
446
- terminateSpawnedChild(child, "SIGTERM");
447
- killTimer = setTimeout(() => {
448
- terminateSpawnedChild(child, "SIGKILL");
449
- }, 2_000);
450
- };
451
- const recordStdinError = (error: unknown) => {
452
- const stdinError = error instanceof Error ? error : new Error(String(error));
453
- const errorCode = (stdinError as NodeJS.ErrnoException).code;
454
- if (errorCode === "EPIPE" || errorCode === "EOF" || errorCode === "ERR_STREAM_DESTROYED") {
455
- return;
456
- }
457
- if (!spawnError) {
458
- spawnError = stdinError;
459
- }
460
- };
461
- const writeChildStdin = () => {
462
- if (aborted || signal?.aborted) {
463
- child.stdin.destroy();
464
- return;
465
- }
466
- try {
467
- if (stdin) {
468
- child.stdin.write(stdin);
469
- }
470
- child.stdin.end();
471
- } catch (error) {
472
- recordStdinError(error);
473
- child.stdin.destroy();
474
- }
475
- };
476
-
477
- child.stdin.on("error", recordStdinError);
478
- child.once("error", (error) => {
479
- spawnError = error instanceof Error ? error : new Error(String(error));
480
- finish(
481
- resolveSpawnedChildExitCode({
482
- useExitFallback: false,
483
- timedOut,
484
- spawnError,
485
- }),
486
- );
487
- });
488
- completionWatcher = watchSpawnedChildCompletion(child, {
489
- graceMs: EXIT_STDIO_GRACE_MS,
490
- onComplete: finish,
491
- getContext: () => ({ timedOut, spawnError }),
492
- });
493
- child.stdout.on("data", (chunk: Buffer | string) => {
494
- queueStdoutChunk(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
495
- });
496
- child.stderr.on("data", (chunk: Buffer | string) => {
497
- stderr = appendTail(stderr, chunk.toString(), MAX_BUFFERED_STDERR_CHARS);
498
- });
499
-
500
- if (timeoutMs > 0) {
501
- timeoutTimer = setTimeout(() => terminateChild("timeout"), timeoutMs);
502
- timeoutTimer.unref?.();
503
- }
504
-
505
- if (signal) {
506
- if (signal.aborted) {
507
- terminateChild("abort");
508
- } else {
509
- abortListener = () => terminateChild("abort");
510
- signal.addEventListener("abort", abortListener, { once: true });
511
- }
512
- }
513
-
514
- writeChildStdin();
515
- });
516
- }
@@ -1,105 +0,0 @@
1
- /**
2
- * Purpose: Derive operator prompt constraints for browser-run preflight guards and legacy bash policy.
3
- * Responsibilities: Parse the latest user message into requested artifact paths and legacy bash allowance.
4
- * Scope: Pure prompt-text policy; enforcement lives in orchestration prompt-guards and the extension entrypoint.
5
- */
6
-
7
- export interface PromptRequestedArtifact {
8
- kind: "recording" | "screenshot";
9
- path: string;
10
- required: boolean;
11
- }
12
-
13
- export interface PromptPolicy {
14
- allowLegacyAgentBrowserBash: boolean;
15
- requestedArtifacts: PromptRequestedArtifact[];
16
- }
17
-
18
- const BROWSER_PROMPT_PATTERNS = [
19
- /\b(?:agent[_ -]?browser|browser automation|eval\s+--stdin|screenshot|snapshot|tab\s+list)\b/i,
20
- /\b(?:react\s+(?:tree|inspect|renders|suspense)|web\s+vitals|core\s+web\s+vitals|pushstate)\b/i,
21
- /\b(?:live\s+docs?|online\s+research|research\s+(?:online|the\s+web)|search\s+(?:online|the\s+web)|web\s+research)\b/i,
22
- /\bbrowser\b.*\b(?:automation|click|fill|navigate|open|page|screenshot|site|snapshot|tab|url|visit|web(?:site| page)?)\b/i,
23
- /\b(?:browse|click|fill|login|navigate|open|visit)\b.*\b(?:https?:\/\/\S+|page|site|tab|url|web(?:site| page)?)\b/i,
24
- ];
25
-
26
- const LEGACY_BASH_ALLOW_PATTERNS = [
27
- /\b(?:bash-oriented workflow|bash workflow)\b/i,
28
- /\b(?:use|via|through|with)\s+bash\b/i,
29
- /\bnpx\s+agent-browser\b/i,
30
- /\bagent-browser\s+--(?:help|version)\b/i,
31
- /\bdebug(?:ging)?\b.*\b(?:agent[_ -]?browser|agent_browser|browser integration)\b/i,
32
- ];
33
-
34
- const PROMPT_ARTIFACT_PATH_PATTERN = /(?:^|[\s"'`(:])((?:\/[^\s"'`),;]+|[A-Za-z]:[\\/][^\s"'`),;]+|\.{1,2}[\\/][^\s"'`),;]+|[^\s"'`),;:\\/]+(?:[\\/][^\s"'`),;]+)+|[^\s"'`),;:\\/]+)\.(?:png|jpe?g|webp|gif|webm|mp4|har|pdf|trace|json))(?:[\s"'`),;.]|$)/gi;
35
-
36
- function extractPromptRequestedArtifacts(prompt: string): PromptRequestedArtifact[] {
37
- const artifacts: PromptRequestedArtifact[] = [];
38
- const seen = new Set<string>();
39
- for (const line of prompt.split(/\r?\n/)) {
40
- const lowerLine = line.toLowerCase();
41
- const kind = lowerLine.includes("screenshot")
42
- ? "screenshot"
43
- : /\b(?:screen\s+recording|recording|webm|video)\b/.test(lowerLine)
44
- ? "recording"
45
- : undefined;
46
- if (!kind) continue;
47
- PROMPT_ARTIFACT_PATH_PATTERN.lastIndex = 0;
48
- for (const match of line.matchAll(PROMPT_ARTIFACT_PATH_PATTERN)) {
49
- const path = match[1]?.trim();
50
- if (!path) continue;
51
- const key = `${kind}:${path}`;
52
- if (seen.has(key)) continue;
53
- seen.add(key);
54
- artifacts.push({
55
- kind,
56
- path,
57
- required: kind === "screenshot" || !/\b(?:if|when)\s+(?:recording\s+)?(?:is\s+)?available\b/i.test(line),
58
- });
59
- }
60
- }
61
- return artifacts;
62
- }
63
-
64
- export function buildPromptPolicy(prompt: string): PromptPolicy {
65
- return {
66
- allowLegacyAgentBrowserBash: LEGACY_BASH_ALLOW_PATTERNS.some((pattern) => pattern.test(prompt)),
67
- requestedArtifacts: extractPromptRequestedArtifacts(prompt),
68
- };
69
- }
70
-
71
- function getMessageText(content: unknown): string {
72
- if (typeof content === "string") return content;
73
- if (!Array.isArray(content)) return "";
74
-
75
- return content
76
- .map((item) => {
77
- if (typeof item !== "object" || item === null) return "";
78
- return item.type === "text" && typeof item.text === "string" ? item.text : "";
79
- })
80
- .filter((text) => text.length > 0)
81
- .join("\n");
82
- }
83
-
84
- export function shouldAppendBrowserSystemPrompt(prompt: string): boolean {
85
- const normalizedPrompt = prompt.trim();
86
- if (normalizedPrompt.length === 0) {
87
- return false;
88
- }
89
- return BROWSER_PROMPT_PATTERNS.some((pattern) => pattern.test(normalizedPrompt));
90
- }
91
-
92
- export function getLatestUserPrompt(branch: unknown[]): string {
93
- for (let index = branch.length - 1; index >= 0; index -= 1) {
94
- const entry = branch[index];
95
- if (typeof entry !== "object" || entry === null || !("type" in entry) || entry.type !== "message") {
96
- continue;
97
- }
98
- const message = "message" in entry ? entry.message : undefined;
99
- if (typeof message !== "object" || message === null || !("role" in message) || message.role !== "user") {
100
- continue;
101
- }
102
- return getMessageText("content" in message ? message.content : undefined);
103
- }
104
- return "";
105
- }