pi-agent-browser-native 0.2.47 → 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 +63 -19
  2. package/README.md +52 -19
  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/ARCHITECTURE.md +10 -10
  95. package/docs/COMMAND_REFERENCE.md +35 -21
  96. package/docs/ELECTRON.md +3 -3
  97. package/docs/RELEASE.md +46 -26
  98. package/docs/REQUIREMENTS.md +1 -1
  99. package/docs/SUPPORT_MATRIX.md +35 -106
  100. package/docs/TOOL_CONTRACT.md +23 -21
  101. package/package.json +12 -8
  102. package/scripts/agent-browser-capability-baseline.mjs +6 -3
  103. package/scripts/config.mjs +8 -2
  104. package/scripts/doctor.mjs +19 -17
  105. package/scripts/platform-smoke.mjs +1 -1
  106. package/extensions/agent-browser/index.ts +0 -952
  107. package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
  108. package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
  109. package/extensions/agent-browser/lib/bash-guard.ts +0 -205
  110. package/extensions/agent-browser/lib/command-policy.ts +0 -71
  111. package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
  112. package/extensions/agent-browser/lib/config-policy.js +0 -690
  113. package/extensions/agent-browser/lib/config.ts +0 -209
  114. package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
  115. package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
  116. package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
  117. package/extensions/agent-browser/lib/electron/launch.ts +0 -499
  118. package/extensions/agent-browser/lib/executable-path.ts +0 -19
  119. package/extensions/agent-browser/lib/fs-utils.ts +0 -18
  120. package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
  121. package/extensions/agent-browser/lib/input-modes/job.ts +0 -451
  122. package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
  123. package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
  124. package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
  125. package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
  126. package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
  127. package/extensions/agent-browser/lib/input-modes.ts +0 -45
  128. package/extensions/agent-browser/lib/json-schema.ts +0 -73
  129. package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
  130. package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
  131. package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
  132. package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -257
  133. package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -912
  134. package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -512
  135. package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
  136. package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -1481
  137. package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -564
  138. package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
  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 -564
  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 -252
  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 -721
  185. /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
@@ -1,209 +0,0 @@
1
- /**
2
- * Purpose: Load pi-agent-browser-native package configuration from Pi-scoped global, project, or explicit paths.
3
- * Responsibilities: Resolve config layers, resolve secrets without exposing values, and provide redacted status for tools/CLIs.
4
- * Scope: Package-owned configuration only; canonical config policy lives in config-policy.js, browser command execution and web-search API calls live in focused modules.
5
- * Invariants/Assumptions: Raw project-local plaintext credentials are unsafe and rejected by the shared config policy; command credentials are resolved lazily at execution time.
6
- */
7
-
8
- import { exec as execCallback } from "node:child_process";
9
- import { readFile } from "node:fs/promises";
10
- import { promisify } from "node:util";
11
-
12
- import {
13
- SECRET_COMMAND_TIMEOUT_MS,
14
- buildAgentBrowserConfigState,
15
- getAgentBrowserConfigPaths,
16
- getWebSearchCredentialSource,
17
- getWebSearchProviderOrder,
18
- loadAgentBrowserConfigStateSync,
19
- mergeAgentBrowserConfig,
20
- parseAgentBrowserConfigLayer,
21
- resolveEnvInterpolations,
22
- } from "./config-policy.js";
23
- import type {
24
- AgentBrowserConfig,
25
- AgentBrowserConfigLoadOptions,
26
- AgentBrowserConfigScope,
27
- AgentBrowserConfigState,
28
- BrowserDefaultProfileConfig,
29
- BrowserDefaultProfilePolicy,
30
- ConfigLayer,
31
- CredentialSource,
32
- CredentialSourceKind,
33
- WebSearchProvider,
34
- } from "./config-policy.js";
35
-
36
- export {
37
- AGENT_BROWSER_CONFIG_ENV,
38
- BRAVE_API_KEY_ENV,
39
- CONFIG_RELATIVE_PATH,
40
- DEFAULT_WEB_SEARCH_PROVIDER,
41
- EXA_API_KEY_ENV,
42
- GLOBAL_CONFIG_RELATIVE_PATH,
43
- SECRET_COMMAND_TIMEOUT_MS,
44
- WEB_SEARCH_PROVIDER_CONFIG_KEYS,
45
- WEB_SEARCH_PROVIDER_DESCRIPTORS,
46
- WEB_SEARCH_PROVIDER_ENV_VARS,
47
- WEB_SEARCH_PROVIDERS,
48
- buildAgentBrowserConfigState,
49
- buildWebSearchCredentialSources,
50
- canRegisterWebSearchTool,
51
- classifyCredentialSource,
52
- formatBrowserExecutableStatus,
53
- formatBrowserProfileStatus,
54
- getAgentBrowserConfigPaths,
55
- getCredentialSourceSummary,
56
- getGlobalAgentBrowserConfigPath,
57
- getProjectAgentBrowserConfigPath,
58
- getWebSearchCredentialSource,
59
- getWebSearchProviderConfigKey,
60
- getWebSearchProviderDescriptor,
61
- getWebSearchProviderEnvVar,
62
- getWebSearchProviderLabel,
63
- getWebSearchProviderOrder,
64
- hasPotentialCredentialSource,
65
- isPlaintextCredentialValue,
66
- isProjectSafeCredentialValueForProvider,
67
- isWebSearchProvider,
68
- loadAgentBrowserConfigStateSync,
69
- mergeAgentBrowserConfig,
70
- parseAgentBrowserConfigLayer,
71
- resolveEnvInterpolations,
72
- summarizeConfigFiles,
73
- validateAgentBrowserConfig,
74
- validateWebSearchProvider,
75
- } from "./config-policy.js";
76
- export type {
77
- AgentBrowserConfig,
78
- AgentBrowserConfigLoadOptions,
79
- AgentBrowserConfigScope,
80
- AgentBrowserConfigState,
81
- BrowserDefaultProfileConfig,
82
- BrowserDefaultProfilePolicy,
83
- ConfigLayer,
84
- CredentialSource,
85
- CredentialSourceKind,
86
- WebSearchProvider,
87
- WebSearchProviderDescriptor,
88
- } from "./config-policy.js";
89
-
90
- const exec = promisify(execCallback);
91
-
92
- export interface ResolvedCredential {
93
- source: CredentialSource;
94
- value: string;
95
- }
96
-
97
- async function readConfigLayer(path: string, scope: ConfigLayer["scope"], errors: string[], warnings: string[]): Promise<ConfigLayer | undefined> {
98
- let raw: string;
99
- try {
100
- raw = await readFile(path, "utf8");
101
- } catch (error) {
102
- if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
103
- return undefined;
104
- }
105
- errors.push(`Could not read ${scope} config ${path}: ${error instanceof Error ? error.message : String(error)}`);
106
- return undefined;
107
- }
108
- return parseAgentBrowserConfigLayer(raw, path, scope, errors, warnings);
109
- }
110
-
111
- export async function loadAgentBrowserConfig(options: AgentBrowserConfigLoadOptions = {}): Promise<AgentBrowserConfigState> {
112
- const env = options.env ?? process.env;
113
- const paths = getAgentBrowserConfigPaths({ cwd: options.cwd, env });
114
- const includeProjectConfig = options.includeProjectConfig !== false;
115
- const errors: string[] = [];
116
- const warnings: string[] = [];
117
- const layerCandidates = [
118
- { path: paths.global, scope: "global" as const },
119
- ...(includeProjectConfig ? [{ path: paths.project, scope: "project" as const }] : []),
120
- ...(paths.override ? [{ path: paths.override, scope: "override" as const }] : []),
121
- ];
122
- const layers: ConfigLayer[] = [];
123
- let mergedConfig: AgentBrowserConfig = {};
124
- for (const candidate of layerCandidates) {
125
- const layer = await readConfigLayer(candidate.path, candidate.scope, errors, warnings);
126
- if (!layer) continue;
127
- layers.push(layer);
128
- mergedConfig = mergeAgentBrowserConfig(mergedConfig, layer.config);
129
- }
130
- return buildAgentBrowserConfigState({
131
- env,
132
- errors,
133
- layers,
134
- mergedConfig,
135
- paths,
136
- projectConfigIncluded: includeProjectConfig,
137
- warnings,
138
- });
139
- }
140
-
141
- export function loadAgentBrowserConfigSync(options: AgentBrowserConfigLoadOptions = {}): AgentBrowserConfigState {
142
- return loadAgentBrowserConfigStateSync(options);
143
- }
144
-
145
- async function resolveCommandCredential(rawValue: string, signal?: AbortSignal): Promise<string | undefined> {
146
- const command = rawValue.slice(1).trim();
147
- if (!command) return undefined;
148
- try {
149
- const result = await exec(command, {
150
- signal,
151
- timeout: SECRET_COMMAND_TIMEOUT_MS,
152
- maxBuffer: 1024 * 1024,
153
- });
154
- const value = result.stdout.trim();
155
- return value.length > 0 ? value : undefined;
156
- } catch (error) {
157
- if (signal?.aborted) throw error;
158
- throw new Error("Credential command failed without exposing command output. Check pi-agent-browser-config web-search status and the configured secret manager command.");
159
- }
160
- }
161
-
162
- export async function resolveCredentialSource(
163
- source: CredentialSource | undefined,
164
- options: { env?: NodeJS.ProcessEnv; signal?: AbortSignal } = {},
165
- ): Promise<ResolvedCredential | undefined> {
166
- if (!source) return undefined;
167
- let value: string | undefined;
168
- if (source.kind === "command") {
169
- value = await resolveCommandCredential(source.rawValue, options.signal);
170
- } else if (source.kind === "env") {
171
- value = resolveEnvInterpolations(source.rawValue, options.env ?? process.env)?.trim();
172
- } else {
173
- value = source.rawValue.trim();
174
- }
175
- return value ? { source, value } : undefined;
176
- }
177
-
178
- export async function resolveWebSearchCredential(
179
- state: AgentBrowserConfigState,
180
- provider: WebSearchProvider,
181
- options: { env?: NodeJS.ProcessEnv; signal?: AbortSignal } = {},
182
- ): Promise<ResolvedCredential | undefined> {
183
- return resolveCredentialSource(getWebSearchCredentialSource(state, provider), options);
184
- }
185
-
186
- export async function resolvePreferredWebSearchCredential(
187
- state: AgentBrowserConfigState,
188
- options: { env?: NodeJS.ProcessEnv; provider?: WebSearchProvider | "auto"; signal?: AbortSignal } = {},
189
- ): Promise<{ provider: WebSearchProvider; credential: ResolvedCredential } | undefined> {
190
- for (const provider of getWebSearchProviderOrder(state, options.provider)) {
191
- const credential = await resolveWebSearchCredential(state, provider, options);
192
- if (credential) return { provider, credential };
193
- }
194
- return undefined;
195
- }
196
-
197
- export async function hasResolvableCredentialSource(
198
- state: AgentBrowserConfigState,
199
- options: { env?: NodeJS.ProcessEnv } = {},
200
- ): Promise<boolean> {
201
- if (!state.webSearchEnabled || state.errors.length > 0) return false;
202
- for (const provider of getWebSearchProviderOrder(state)) {
203
- const source = getWebSearchCredentialSource(state, provider);
204
- if (!source) continue;
205
- if (source.kind === "command") return true;
206
- if ((await resolveCredentialSource(source, options))?.value) return true;
207
- }
208
- return false;
209
- }
@@ -1,69 +0,0 @@
1
- /**
2
- * Purpose: Parse and fetch Chrome DevTools Protocol metadata for wrapper-owned Electron launches.
3
- * Responsibilities: Normalize CDP version/target JSON and perform bounded localhost CDP JSON fetches.
4
- * Scope: Tiny Electron CDP boundary helpers only; launch, status, cleanup, and target selection stay in their owning modules.
5
- * Usage: Imported by Electron launch and cleanup paths when polling `/json/version` and `/json/list`.
6
- * Invariants/Assumptions: Malformed or unavailable CDP endpoints return undefined/empty metadata rather than throwing, matching prior caller behavior.
7
- */
8
-
9
- import { isRecord } from "../parsing.js";
10
-
11
- const ELECTRON_CDP_FETCH_TIMEOUT_MS = 1_000;
12
-
13
- export interface ElectronCdpVersion {
14
- browser?: string;
15
- protocolVersion?: string;
16
- userAgent?: string;
17
- v8Version?: string;
18
- webKitVersion?: string;
19
- webSocketDebuggerUrl?: string;
20
- }
21
-
22
- export interface ElectronCdpTarget {
23
- id?: string;
24
- title?: string;
25
- type?: string;
26
- url?: string;
27
- webSocketDebuggerUrl?: string;
28
- }
29
-
30
- function asString(value: unknown): string | undefined {
31
- return typeof value === "string" && value.trim().length > 0 ? value : undefined;
32
- }
33
-
34
- export function parseCdpVersion(value: unknown): ElectronCdpVersion | undefined {
35
- if (!isRecord(value)) return undefined;
36
- return {
37
- browser: asString(value.Browser) ?? asString(value.browser),
38
- protocolVersion: asString(value["Protocol-Version"]) ?? asString(value.protocolVersion),
39
- userAgent: asString(value["User-Agent"]) ?? asString(value.userAgent),
40
- v8Version: asString(value["V8-Version"]) ?? asString(value.v8Version),
41
- webKitVersion: asString(value["WebKit-Version"]) ?? asString(value.webKitVersion),
42
- webSocketDebuggerUrl: asString(value.webSocketDebuggerUrl),
43
- };
44
- }
45
-
46
- export function parseCdpTargets(value: unknown): ElectronCdpTarget[] {
47
- if (!Array.isArray(value)) return [];
48
- return value.filter(isRecord).map((target) => ({
49
- id: asString(target.id),
50
- title: asString(target.title),
51
- type: asString(target.type),
52
- url: asString(target.url),
53
- webSocketDebuggerUrl: asString(target.webSocketDebuggerUrl),
54
- }));
55
- }
56
-
57
- export async function fetchCdpJson(url: string): Promise<unknown | undefined> {
58
- const controller = new AbortController();
59
- const timeout = setTimeout(() => controller.abort(), ELECTRON_CDP_FETCH_TIMEOUT_MS);
60
- try {
61
- const response = await fetch(url, { signal: controller.signal });
62
- if (!response.ok) return undefined;
63
- return await response.json() as unknown;
64
- } catch {
65
- return undefined;
66
- } finally {
67
- clearTimeout(timeout);
68
- }
69
- }
@@ -1,235 +0,0 @@
1
- /**
2
- * Purpose: Inspect and clean wrapper-owned Electron launch resources.
3
- * Responsibilities: Report CDP liveness/targets without mutation and remove only tracked process/profile resources during explicit or shutdown cleanup.
4
- * Scope: Host-side Electron status and resource cleanup only; upstream managed-session close remains in the extension entrypoint.
5
- * Usage: Called by electron.status, electron.cleanup, and session_shutdown handling.
6
- * Invariants/Assumptions: Cleanup operates only on launch records produced by this wrapper and prefers partial cleanup reporting over killing or deleting untracked resources.
7
- */
8
-
9
- import { execFile, type ChildProcess } from "node:child_process";
10
- import { rm } from "node:fs/promises";
11
- import { promisify } from "node:util";
12
-
13
- import { fetchCdpJson, parseCdpTargets, parseCdpVersion } from "./cdp.js";
14
- import { ELECTRON_PROFILE_DIR_PREFIX, type ElectronCdpTarget, type ElectronCdpVersion, type ElectronLaunchRecord } from "./launch.js";
15
- import { pathExists } from "../fs-utils.js";
16
- import { getSecureTempChildDirectoryValidationError } from "../temp.js";
17
-
18
- const ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS = 5_000;
19
- const ELECTRON_CLEANUP_POLL_INTERVAL_MS = 100;
20
- const RESTORED_PROCESS_COMMAND_TIMEOUT_MS = 1_000;
21
- const execFileAsync = promisify(execFile);
22
-
23
- export interface ElectronLaunchStatus {
24
- cleanupState: ElectronLaunchRecord["cleanupState"];
25
- launchId: string;
26
- pid?: number;
27
- pidAlive?: boolean;
28
- port: number;
29
- portAlive: boolean;
30
- targets: ElectronCdpTarget[];
31
- version?: ElectronCdpVersion;
32
- }
33
-
34
- export interface ElectronCleanupStep {
35
- error?: string;
36
- resource: "debug-port" | "managed-session" | "process" | "user-data-dir";
37
- sessionName?: string;
38
- state: "already-gone" | "failed" | "removed" | "skipped";
39
- }
40
-
41
- export interface ElectronCleanupResult {
42
- launchId: string;
43
- partial: boolean;
44
- record: ElectronLaunchRecord;
45
- remainingResources: string[];
46
- steps: ElectronCleanupStep[];
47
- summary: string;
48
- }
49
-
50
- function sleep(ms: number): Promise<void> {
51
- return new Promise((resolve) => setTimeout(resolve, ms));
52
- }
53
-
54
- function isPidAlive(pid: number | undefined): boolean | undefined {
55
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0) return undefined;
56
- try {
57
- process.kill(pid, 0);
58
- return true;
59
- } catch (error) {
60
- const code = (error as NodeJS.ErrnoException).code;
61
- return code === "EPERM" ? true : false;
62
- }
63
- }
64
-
65
- async function isPortAlive(port: number): Promise<{ targets: ElectronCdpTarget[]; version?: ElectronCdpVersion }> {
66
- const version = parseCdpVersion(await fetchCdpJson(`http://127.0.0.1:${port}/json/version`));
67
- if (!version) return { targets: [] };
68
- const targets = parseCdpTargets(await fetchCdpJson(`http://127.0.0.1:${port}/json/list`));
69
- return { targets, version };
70
- }
71
-
72
- export async function inspectElectronLaunchStatus(record: ElectronLaunchRecord): Promise<ElectronLaunchStatus> {
73
- const cdp = await isPortAlive(record.port);
74
- return {
75
- cleanupState: record.cleanupState,
76
- launchId: record.launchId,
77
- pid: record.pid,
78
- pidAlive: isPidAlive(record.pid),
79
- port: record.port,
80
- portAlive: cdp.version !== undefined,
81
- targets: cdp.targets,
82
- version: cdp.version,
83
- };
84
- }
85
-
86
- async function waitForProcessExit(child: ChildProcess | undefined, pid: number | undefined, deadlineMs: number): Promise<boolean> {
87
- while (Date.now() <= deadlineMs) {
88
- if (child && (child.exitCode !== null || child.signalCode !== null)) return true;
89
- if (isPidAlive(pid) === false) return true;
90
- await sleep(ELECTRON_CLEANUP_POLL_INTERVAL_MS);
91
- }
92
- return isPidAlive(pid) === false;
93
- }
94
-
95
- async function readPidCommandLine(pid: number | undefined): Promise<string | undefined> {
96
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0) return undefined;
97
- try {
98
- const { stdout } = await execFileAsync("ps", ["-ww", "-p", String(pid), "-o", "command="], {
99
- timeout: RESTORED_PROCESS_COMMAND_TIMEOUT_MS,
100
- });
101
- return stdout.trim() || undefined;
102
- } catch {
103
- return undefined;
104
- }
105
- }
106
-
107
- function restoredLaunchCommandMatchesRecord(record: ElectronLaunchRecord, commandLine: string | undefined): boolean {
108
- return commandLine?.includes(`--user-data-dir=${record.userDataDir}`) === true;
109
- }
110
-
111
- async function getRestoredProcessVerificationError(record: ElectronLaunchRecord): Promise<string | undefined> {
112
- const commandLine = await readPidCommandLine(record.pid);
113
- if (!commandLine) {
114
- return `PID ${record.pid} is alive, but this session has no tracked child handle and its command line could not be inspected; refusing to signal a restored PID that may have been reused.`;
115
- }
116
- if (!restoredLaunchCommandMatchesRecord(record, commandLine)) {
117
- return `PID ${record.pid} is alive, but this session has no tracked child handle and its command line does not include wrapper-owned user data dir ${record.userDataDir}; refusing to signal a restored PID that may have been reused.`;
118
- }
119
- return undefined;
120
- }
121
-
122
- function killPid(pid: number | undefined, signal: NodeJS.Signals): boolean {
123
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0) return false;
124
- try {
125
- process.kill(pid, signal);
126
- return true;
127
- } catch {
128
- return false;
129
- }
130
- }
131
-
132
- function killProcessGroup(processGroupId: number | undefined, signal: NodeJS.Signals): boolean {
133
- if (process.platform === "win32" || !processGroupId || !Number.isSafeInteger(processGroupId) || processGroupId <= 0) return false;
134
- try {
135
- process.kill(-processGroupId, signal);
136
- return true;
137
- } catch {
138
- return false;
139
- }
140
- }
141
-
142
- function signalRestoredLaunchProcess(record: ElectronLaunchRecord, signal: NodeJS.Signals): boolean {
143
- return killProcessGroup(record.processGroupId, signal) || killPid(record.pid, signal);
144
- }
145
-
146
- async function cleanupProcess(record: ElectronLaunchRecord, child: ChildProcess | undefined, deadlineMs: number): Promise<ElectronCleanupStep> {
147
- if (!record.pid) return { resource: "process", state: "skipped" };
148
- if (isPidAlive(record.pid) === false) return { resource: "process", state: "already-gone" };
149
- if (!child) {
150
- const verificationError = await getRestoredProcessVerificationError(record);
151
- if (verificationError) return { error: verificationError, resource: "process", state: "failed" };
152
- if (!signalRestoredLaunchProcess(record, "SIGTERM")) {
153
- return { error: `PID ${record.pid} matched wrapper launch metadata but could not be signaled.`, resource: "process", state: "failed" };
154
- }
155
- if (await waitForProcessExit(undefined, record.pid, deadlineMs)) return { resource: "process", state: "removed" };
156
- signalRestoredLaunchProcess(record, "SIGKILL");
157
- if (await waitForProcessExit(undefined, record.pid, Date.now() + 1_000)) return { resource: "process", state: "removed" };
158
- return { error: `PID ${record.pid} remained alive after SIGTERM/SIGKILL.`, resource: "process", state: "failed" };
159
- }
160
- if (child.exitCode === null && child.signalCode === null) child.kill("SIGTERM");
161
- else killPid(record.pid, "SIGTERM");
162
- if (await waitForProcessExit(child, record.pid, deadlineMs)) return { resource: "process", state: "removed" };
163
- if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
164
- else killPid(record.pid, "SIGKILL");
165
- if (await waitForProcessExit(child, record.pid, Date.now() + 1_000)) return { resource: "process", state: "removed" };
166
- return { error: `PID ${record.pid} remained alive after SIGTERM/SIGKILL.`, resource: "process", state: "failed" };
167
- }
168
-
169
- async function cleanupUserDataDir(record: ElectronLaunchRecord): Promise<ElectronCleanupStep> {
170
- if (!record.userDataDir) return { resource: "user-data-dir", state: "skipped" };
171
- if (!await pathExists(record.userDataDir)) return { resource: "user-data-dir", state: "already-gone" };
172
- const validationError = await getSecureTempChildDirectoryValidationError(record.userDataDir, ELECTRON_PROFILE_DIR_PREFIX);
173
- if (validationError) return { error: validationError, resource: "user-data-dir", state: "failed" };
174
- try {
175
- await rm(record.userDataDir, { force: true, recursive: true });
176
- return { resource: "user-data-dir", state: await pathExists(record.userDataDir) ? "failed" : "removed" };
177
- } catch (error) {
178
- return { error: error instanceof Error ? error.message : String(error), resource: "user-data-dir", state: "failed" };
179
- }
180
- }
181
-
182
- function shouldSkipUserDataDirCleanup(processStep: ElectronCleanupStep, debugPortStep: ElectronCleanupStep): string | undefined {
183
- if (processStep.state === "failed") return `Skipped because process cleanup failed: ${processStep.error ?? "process state could not be verified"}.`;
184
- if (debugPortStep.state === "failed") return `Skipped because debug port cleanup is incomplete: ${debugPortStep.error ?? "debug port still responds"}.`;
185
- return undefined;
186
- }
187
-
188
- async function cleanupDebugPort(record: ElectronLaunchRecord): Promise<ElectronCleanupStep> {
189
- const cdp = await isPortAlive(record.port);
190
- return cdp.version ? { resource: "debug-port", state: "failed", error: `/json/version still responds on port ${record.port}.` } : { resource: "debug-port", state: "already-gone" };
191
- }
192
-
193
- function summarizeCleanup(launchId: string, steps: ElectronCleanupStep[]): { partial: boolean; remainingResources: string[]; summary: string } {
194
- const remainingResources = steps
195
- .filter((step) => step.state === "failed" || (step.resource === "user-data-dir" && step.state === "skipped" && step.error))
196
- .map((step) => step.resource);
197
- const partial = remainingResources.length > 0;
198
- return {
199
- partial,
200
- remainingResources,
201
- summary: partial
202
- ? `Electron cleanup for ${launchId} is partial; remaining resources: ${remainingResources.join(", ")}.`
203
- : `Electron cleanup for ${launchId} completed.`,
204
- };
205
- }
206
-
207
- export async function cleanupElectronLaunchResources(options: {
208
- child?: ChildProcess;
209
- record: ElectronLaunchRecord;
210
- timeoutMs?: number;
211
- }): Promise<ElectronCleanupResult> {
212
- const timeoutMs = Number.isSafeInteger(options.timeoutMs) && (options.timeoutMs ?? 0) > 0
213
- ? options.timeoutMs as number
214
- : ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS;
215
- const deadlineMs = Date.now() + timeoutMs;
216
- const processStep = await cleanupProcess(options.record, options.child, deadlineMs);
217
- const debugPortStep = await cleanupDebugPort(options.record);
218
- const userDataDirSkipReason = shouldSkipUserDataDirCleanup(processStep, debugPortStep);
219
- const userDataDirStep = userDataDirSkipReason
220
- ? { error: userDataDirSkipReason, resource: "user-data-dir" as const, state: "skipped" as const }
221
- : await cleanupUserDataDir(options.record);
222
- const steps = [processStep, debugPortStep, userDataDirStep];
223
- const summary = summarizeCleanup(options.record.launchId, steps);
224
- return {
225
- launchId: options.record.launchId,
226
- partial: summary.partial,
227
- record: {
228
- ...options.record,
229
- cleanupState: summary.partial ? "partial" : "cleaned",
230
- },
231
- remainingResources: summary.remainingResources,
232
- steps,
233
- summary: summary.summary,
234
- };
235
- }