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.
- package/CHANGELOG.md +63 -19
- package/README.md +52 -19
- package/dist/extensions/agent-browser/index.js +785 -0
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +71 -0
- package/dist/extensions/agent-browser/lib/argv-grammar.js +121 -0
- package/dist/extensions/agent-browser/lib/bash-guard.js +190 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +85 -0
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +302 -0
- package/dist/extensions/agent-browser/lib/config-policy.js +686 -0
- package/dist/extensions/agent-browser/lib/config.js +122 -0
- package/dist/extensions/agent-browser/lib/electron/cdp.js +51 -0
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +212 -0
- package/dist/extensions/agent-browser/lib/electron/discovery.js +633 -0
- package/dist/extensions/agent-browser/lib/electron/launch.js +351 -0
- package/{extensions/agent-browser/lib/electron/text.ts → dist/extensions/agent-browser/lib/electron/text.js} +5 -5
- package/dist/extensions/agent-browser/lib/executable-path.js +20 -0
- package/dist/extensions/agent-browser/lib/fs-utils.js +18 -0
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +165 -0
- package/dist/extensions/agent-browser/lib/input-modes/job.js +519 -0
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +440 -0
- package/dist/extensions/agent-browser/lib/input-modes/params.js +164 -0
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +119 -0
- package/dist/extensions/agent-browser/lib/input-modes/shared.js +42 -0
- package/dist/extensions/agent-browser/lib/input-modes/types.js +21 -0
- package/dist/extensions/agent-browser/lib/input-modes.js +10 -0
- package/dist/extensions/agent-browser/lib/json-schema.js +58 -0
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +59 -0
- package/dist/extensions/agent-browser/lib/navigation-policy.js +83 -0
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +62 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +39 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +276 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +909 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +443 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +47 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +141 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +108 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +112 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +158 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +54 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +762 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +491 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +40 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +5 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +731 -0
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/types.js +1 -0
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +718 -0
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +247 -0
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +68 -0
- package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js} +12 -11
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +241 -0
- package/dist/extensions/agent-browser/lib/playbook.js +121 -0
- package/dist/extensions/agent-browser/lib/process.js +448 -0
- package/dist/extensions/agent-browser/lib/prompt-policy.js +91 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +220 -0
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +111 -0
- package/{extensions/agent-browser/lib/results/artifact-state.ts → dist/extensions/agent-browser/lib/results/artifact-state.js} +4 -8
- package/dist/extensions/agent-browser/lib/results/categories.js +76 -0
- package/dist/extensions/agent-browser/lib/results/confirmation.js +63 -0
- package/dist/extensions/agent-browser/lib/results/contracts.js +8 -0
- package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +74 -0
- package/dist/extensions/agent-browser/lib/results/envelope.js +166 -0
- package/dist/extensions/agent-browser/lib/results/network-routes.js +92 -0
- package/dist/extensions/agent-browser/lib/results/network.js +73 -0
- package/dist/extensions/agent-browser/lib/results/next-actions.js +72 -0
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +515 -0
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +397 -0
- package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +55 -0
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +46 -0
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +24 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +960 -0
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +205 -0
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +134 -0
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +159 -0
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +216 -0
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +104 -0
- package/dist/extensions/agent-browser/lib/results/presentation/skills.js +152 -0
- package/dist/extensions/agent-browser/lib/results/presentation.js +177 -0
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +107 -0
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +50 -0
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +225 -0
- package/{extensions/agent-browser/lib/results/shared.ts → dist/extensions/agent-browser/lib/results/shared.js} +0 -1
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +208 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +78 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +331 -0
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +40 -0
- package/dist/extensions/agent-browser/lib/results/snapshot.js +264 -0
- package/dist/extensions/agent-browser/lib/results/text.js +40 -0
- package/{extensions/agent-browser/lib/results.ts → dist/extensions/agent-browser/lib/results.js} +2 -32
- package/dist/extensions/agent-browser/lib/runtime.js +816 -0
- package/dist/extensions/agent-browser/lib/session-page-state.js +411 -0
- package/dist/extensions/agent-browser/lib/string-enum-schema.js +13 -0
- package/dist/extensions/agent-browser/lib/temp.js +498 -0
- package/dist/extensions/agent-browser/lib/web-search.js +562 -0
- package/docs/ARCHITECTURE.md +10 -10
- package/docs/COMMAND_REFERENCE.md +35 -21
- package/docs/ELECTRON.md +3 -3
- package/docs/RELEASE.md +46 -26
- package/docs/REQUIREMENTS.md +1 -1
- package/docs/SUPPORT_MATRIX.md +35 -106
- package/docs/TOOL_CONTRACT.md +23 -21
- package/package.json +12 -8
- package/scripts/agent-browser-capability-baseline.mjs +6 -3
- package/scripts/config.mjs +8 -2
- package/scripts/doctor.mjs +19 -17
- package/scripts/platform-smoke.mjs +1 -1
- package/extensions/agent-browser/index.ts +0 -952
- package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
- package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
- package/extensions/agent-browser/lib/bash-guard.ts +0 -205
- package/extensions/agent-browser/lib/command-policy.ts +0 -71
- package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
- package/extensions/agent-browser/lib/config-policy.js +0 -690
- package/extensions/agent-browser/lib/config.ts +0 -209
- package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
- package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
- package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
- package/extensions/agent-browser/lib/electron/launch.ts +0 -499
- package/extensions/agent-browser/lib/executable-path.ts +0 -19
- package/extensions/agent-browser/lib/fs-utils.ts +0 -18
- package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
- package/extensions/agent-browser/lib/input-modes/job.ts +0 -451
- package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
- package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
- package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
- package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
- package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
- package/extensions/agent-browser/lib/input-modes.ts +0 -45
- package/extensions/agent-browser/lib/json-schema.ts +0 -73
- package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
- package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
- package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
- package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -257
- package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -912
- package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -512
- package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -1481
- package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -564
- package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
- package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
- package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -564
- package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
- package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
- package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
- package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -252
- package/extensions/agent-browser/lib/playbook.ts +0 -142
- package/extensions/agent-browser/lib/process.ts +0 -516
- package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
- package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
- package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
- package/extensions/agent-browser/lib/results/categories.ts +0 -106
- package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
- package/extensions/agent-browser/lib/results/contracts.ts +0 -241
- package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
- package/extensions/agent-browser/lib/results/envelope.ts +0 -195
- package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
- package/extensions/agent-browser/lib/results/network.ts +0 -78
- package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
- package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
- package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
- package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
- package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
- package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
- package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
- package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
- package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
- package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
- package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
- package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
- package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
- package/extensions/agent-browser/lib/results/presentation.ts +0 -257
- package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
- package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
- package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
- package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
- package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
- package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
- package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
- package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
- package/extensions/agent-browser/lib/results/text.ts +0 -40
- package/extensions/agent-browser/lib/runtime.ts +0 -988
- package/extensions/agent-browser/lib/session-page-state.ts +0 -512
- package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
- package/extensions/agent-browser/lib/temp.ts +0 -577
- package/extensions/agent-browser/lib/web-search.ts +0 -721
- /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
|
-
}
|