pi-agent-browser-native 0.2.76 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +10 -19
- package/dist/extensions/agent-browser/index.js +221 -23
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +0 -5
- package/dist/extensions/agent-browser/lib/argv-grammar.js +4 -5
- package/dist/extensions/agent-browser/lib/command-policy.js +0 -5
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +0 -6
- package/dist/extensions/agent-browser/lib/config-policy.js +0 -5
- package/dist/extensions/agent-browser/lib/config.js +0 -6
- package/dist/extensions/agent-browser/lib/electron/cdp.js +6 -7
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +0 -7
- package/dist/extensions/agent-browser/lib/electron/discovery.js +0 -7
- package/dist/extensions/agent-browser/lib/electron/launch.js +0 -7
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +0 -5
- package/dist/extensions/agent-browser/lib/input-modes/job.js +0 -5
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +0 -5
- package/dist/extensions/agent-browser/lib/input-modes/params.js +1 -6
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +0 -5
- package/dist/extensions/agent-browser/lib/input-modes/shared.js +0 -5
- package/dist/extensions/agent-browser/lib/input-modes/types.js +0 -5
- package/dist/extensions/agent-browser/lib/json-schema.js +0 -5
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +4 -5
- package/dist/extensions/agent-browser/lib/managed-session-capabilities.js +0 -2
- package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +0 -3
- package/dist/extensions/agent-browser/lib/managed-session-restore.js +30 -13
- package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +0 -5
- package/dist/extensions/agent-browser/lib/managed-session-state-policy.js +1 -7
- package/dist/extensions/agent-browser/lib/managed-session-storage.js +0 -5
- package/dist/extensions/agent-browser/lib/navigation-policy.js +0 -5
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +41 -30
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +4 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +20 -11
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +42 -20
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +40 -9
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +17 -1
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +42 -18
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +4 -1
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +42 -1
- package/dist/extensions/agent-browser/lib/parsing.js +0 -7
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +4 -1
- package/dist/extensions/agent-browser/lib/playbook.js +4 -10
- package/dist/extensions/agent-browser/lib/process-identity.js +0 -5
- package/dist/extensions/agent-browser/lib/process.js +12 -9
- package/dist/extensions/agent-browser/lib/prompt-policy.js +171 -27
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +1 -8
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +6 -7
- package/dist/extensions/agent-browser/lib/results/categories.js +1 -8
- package/dist/extensions/agent-browser/lib/results/confirmation.js +0 -7
- package/dist/extensions/agent-browser/lib/results/contracts.js +0 -7
- package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +0 -7
- package/dist/extensions/agent-browser/lib/results/envelope.js +0 -7
- package/dist/extensions/agent-browser/lib/results/network.js +0 -7
- package/dist/extensions/agent-browser/lib/results/next-actions.js +0 -30
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +1 -7
- package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/managed-list-filter.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/skills.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation.js +0 -5
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +0 -7
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +0 -7
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot.js +0 -7
- package/dist/extensions/agent-browser/lib/results/text.js +0 -7
- package/dist/extensions/agent-browser/lib/runtime.js +4 -14
- package/dist/extensions/agent-browser/lib/session-page-state.js +0 -7
- package/dist/extensions/agent-browser/lib/string-enum-schema.js +0 -5
- package/dist/extensions/agent-browser/lib/temp.js +0 -7
- package/dist/extensions/agent-browser/lib/web-search.js +0 -5
- package/docs/ARCHITECTURE.md +17 -16
- package/docs/COMMAND_REFERENCE.md +10 -9
- package/docs/ELECTRON.md +3 -19
- package/docs/RELEASE.md +5 -17
- package/docs/REQUIREMENTS.md +4 -4
- package/docs/SUPPORT_MATRIX.md +18 -17
- package/docs/TOOL_CONTRACT.md +23 -19
- package/docs/platform-smoke.md +1 -1
- package/package.json +5 -6
- package/scripts/doctor.mjs +1 -1
- package/dist/extensions/agent-browser/lib/electron/text.js +0 -13
- package/dist/extensions/agent-browser/lib/input-modes.js +0 -10
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +0 -5
- package/dist/extensions/agent-browser/lib/results/artifact-state.js +0 -13
- package/dist/extensions/agent-browser/lib/results.js +0 -14
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Register the native agent_browser tool for pi so agents can invoke agent-browser without going through bash.
|
|
3
|
-
* Responsibilities: Define the tool schema, inject thin wrapper behavior around the upstream CLI, manage extension-owned browser session convenience, and return pi-friendly content/details.
|
|
4
|
-
* Scope: Native tool registration and orchestration only; the wrapper intentionally stays close to the upstream agent-browser CLI.
|
|
5
|
-
* Usage: Loaded by pi through the package manifest in this package, or explicitly via `pi --no-extensions -e .` during local checkout development.
|
|
6
|
-
* Invariants/Assumptions: agent-browser is installed separately on PATH, the wrapper targets the current locally installed upstream version only, and no backward-compatibility shims are provided.
|
|
7
|
-
*/
|
|
8
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
9
2
|
import { dirname, join } from "node:path";
|
|
10
3
|
import { fileURLToPath } from "node:url";
|
|
11
4
|
import { Text } from "@earendil-works/pi-tui";
|
|
12
5
|
import { PROJECT_RULE_PROMPT, buildBrowserDefaultProfileGuideline, buildBrowserExecutablePathGuideline, buildToolPromptGuidelines, } from "./lib/playbook.js";
|
|
13
6
|
import { SessionPageState } from "./lib/session-page-state.js";
|
|
14
|
-
import { canUseHeadlessCompatibilityUserAgent, createEphemeralSessionSeed, createFreshSessionName, createImplicitSessionName, extractCommandTokens, getImplicitSessionCloseTimeoutMs, getImplicitSessionIdleTimeoutMs, restoreManagedSessionStateFromBranch, validateToolArgs, } from "./lib/runtime.js";
|
|
15
|
-
import { extractExplicitNamespace, extractExplicitSessionName, resolveAgentBrowserNamespace } from "./lib/argv-grammar.js";
|
|
7
|
+
import { canUseHeadlessCompatibilityUserAgent, createEphemeralSessionSeed, createFreshSessionName, createImplicitSessionName, extractCommandTokens, getImplicitSessionCloseTimeoutMs, getImplicitSessionIdleTimeoutMs, isRestorableManagedSessionName, restoreManagedSessionStateFromBranch, validateToolArgs, } from "./lib/runtime.js";
|
|
8
|
+
import { extractExplicitNamespace, extractExplicitSessionName, isUpstreamEnvFlagEnabled, resolveAgentBrowserNamespace } from "./lib/argv-grammar.js";
|
|
16
9
|
import { cleanupManagedSessionRestoreConfig, ManagedSessionRestoreState } from "./lib/managed-session-restore.js";
|
|
17
10
|
import { isRecord } from "./lib/parsing.js";
|
|
18
11
|
import { buildPromptPolicy, getLatestUserPrompt, shouldAppendBrowserSystemPrompt } from "./lib/prompt-policy.js";
|
|
19
12
|
import { isCloseCommand } from "./lib/command-taxonomy.js";
|
|
13
|
+
import { hasLaunchScopedFlagToken } from "./lib/launch-scoped-flags.js";
|
|
20
14
|
import { cleanupSecureTempArtifacts } from "./lib/temp.js";
|
|
21
|
-
import { AGENT_BROWSER_PARAMS
|
|
15
|
+
import { AGENT_BROWSER_PARAMS } from "./lib/input-modes/params.js";
|
|
22
16
|
import { parseAllowedDomainsPolicyFromArgs } from "./lib/navigation-policy.js";
|
|
23
17
|
import { closeManagedSession, getSessionContextKey, runAgentBrowserTool } from "./lib/orchestration/browser-run/index.js";
|
|
24
18
|
import { findElectronLaunchRecordForSession, getActiveElectronRecords } from "./lib/orchestration/browser-run/session-state.js";
|
|
@@ -111,6 +105,57 @@ function restoreManagedSessionCompatibilityWorkaroundFromBranch(branch, sessionN
|
|
|
111
105
|
}
|
|
112
106
|
return restored;
|
|
113
107
|
}
|
|
108
|
+
function restoreManagedSessionHeadedAutosaveDisabledFromBranch(branch, sessionName, namespace) {
|
|
109
|
+
let restored = false;
|
|
110
|
+
const targetKey = getSessionContextKey(sessionName, namespace);
|
|
111
|
+
for (const entry of branch) {
|
|
112
|
+
if (!isRecord(entry) || entry.type !== "message")
|
|
113
|
+
continue;
|
|
114
|
+
const message = isRecord(entry.message) ? entry.message : undefined;
|
|
115
|
+
if (!message || message.toolName !== "agent_browser")
|
|
116
|
+
continue;
|
|
117
|
+
const details = isRecord(message.details) ? message.details : undefined;
|
|
118
|
+
if (!details)
|
|
119
|
+
continue;
|
|
120
|
+
if (getSessionContextKey(typeof details.sessionName === "string" ? details.sessionName : undefined, typeof details.namespace === "string" ? details.namespace : undefined) !== targetKey)
|
|
121
|
+
continue;
|
|
122
|
+
const outcome = getManagedSessionOutcome(details);
|
|
123
|
+
const activeAfterFailure = outcome?.activeAfter === true
|
|
124
|
+
&& typeof outcome.currentSessionName === "string"
|
|
125
|
+
&& getSessionContextKey(outcome.currentSessionName, typeof outcome.currentSessionNamespace === "string" ? outcome.currentSessionNamespace : undefined) === targetKey;
|
|
126
|
+
if ((getSuccessfulToolResult(details, message) || activeAfterFailure) && typeof details.managedSessionHeadedAutosaveDisabled === "boolean") {
|
|
127
|
+
restored = details.managedSessionHeadedAutosaveDisabled;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return restored;
|
|
131
|
+
}
|
|
132
|
+
function restoreManagedSessionHeadedAutosaveIntervalFromBranch(branch, sessionName, namespace) {
|
|
133
|
+
let restored;
|
|
134
|
+
const targetKey = getSessionContextKey(sessionName, namespace);
|
|
135
|
+
for (const entry of branch) {
|
|
136
|
+
if (!isRecord(entry) || entry.type !== "message")
|
|
137
|
+
continue;
|
|
138
|
+
const message = isRecord(entry.message) ? entry.message : undefined;
|
|
139
|
+
if (!message || message.toolName !== "agent_browser")
|
|
140
|
+
continue;
|
|
141
|
+
const details = isRecord(message.details) ? message.details : undefined;
|
|
142
|
+
if (!details)
|
|
143
|
+
continue;
|
|
144
|
+
if (getSessionContextKey(typeof details.sessionName === "string" ? details.sessionName : undefined, typeof details.namespace === "string" ? details.namespace : undefined) !== targetKey)
|
|
145
|
+
continue;
|
|
146
|
+
const outcome = getManagedSessionOutcome(details);
|
|
147
|
+
const activeAfterFailure = outcome?.activeAfter === true
|
|
148
|
+
&& typeof outcome.currentSessionName === "string"
|
|
149
|
+
&& getSessionContextKey(outcome.currentSessionName, typeof outcome.currentSessionNamespace === "string" ? outcome.currentSessionNamespace : undefined) === targetKey;
|
|
150
|
+
if (!getSuccessfulToolResult(details, message) && !activeAfterFailure)
|
|
151
|
+
continue;
|
|
152
|
+
if (typeof details.managedSessionHeadedAutosaveInterval === "string")
|
|
153
|
+
restored = details.managedSessionHeadedAutosaveInterval;
|
|
154
|
+
else if (details.managedSessionHeadedAutosaveDisabled === true)
|
|
155
|
+
restored = "0";
|
|
156
|
+
}
|
|
157
|
+
return restored;
|
|
158
|
+
}
|
|
114
159
|
function getToolResultArgs(details) {
|
|
115
160
|
if (Array.isArray(details.args) && details.args.every((arg) => typeof arg === "string"))
|
|
116
161
|
return details.args;
|
|
@@ -118,6 +163,42 @@ function getToolResultArgs(details) {
|
|
|
118
163
|
return details.effectiveArgs;
|
|
119
164
|
return [];
|
|
120
165
|
}
|
|
166
|
+
function isAttachedBrowserInvocation(args, env = process.env) {
|
|
167
|
+
const autoConnectEnv = env.AGENT_BROWSER_AUTO_CONNECT;
|
|
168
|
+
return extractCommandTokens(args)[0] === "connect"
|
|
169
|
+
|| hasLaunchScopedFlagToken(args, "--cdp")
|
|
170
|
+
|| hasLaunchScopedFlagToken(args, "--auto-connect")
|
|
171
|
+
|| env.AGENT_BROWSER_CDP !== undefined
|
|
172
|
+
|| isUpstreamEnvFlagEnabled(autoConnectEnv);
|
|
173
|
+
}
|
|
174
|
+
function restoreAttachedSessionKeysFromBranch(branch) {
|
|
175
|
+
const attachedSessionKeys = new Set();
|
|
176
|
+
for (const entry of branch) {
|
|
177
|
+
if (!isRecord(entry) || entry.type !== "message")
|
|
178
|
+
continue;
|
|
179
|
+
const message = isRecord(entry.message) ? entry.message : undefined;
|
|
180
|
+
if (!message || message.toolName !== "agent_browser")
|
|
181
|
+
continue;
|
|
182
|
+
const details = isRecord(message.details) ? message.details : undefined;
|
|
183
|
+
if (!details)
|
|
184
|
+
continue;
|
|
185
|
+
const managedSessionOutcome = isRecord(details.managedSessionOutcome) ? details.managedSessionOutcome : undefined;
|
|
186
|
+
const retainedFailedAttachment = details.attachedBrowserSession === true && managedSessionOutcome?.activeAfter === true;
|
|
187
|
+
if (!getSuccessfulToolResult(details, message) && !retainedFailedAttachment)
|
|
188
|
+
continue;
|
|
189
|
+
const args = getToolResultArgs(details);
|
|
190
|
+
const sessionName = typeof details.sessionName === "string" ? details.sessionName : extractExplicitSessionName(args);
|
|
191
|
+
if (!sessionName)
|
|
192
|
+
continue;
|
|
193
|
+
const namespace = typeof details.namespace === "string" ? details.namespace : extractExplicitNamespace(args);
|
|
194
|
+
const sessionKey = getSessionContextKey(sessionName, namespace) ?? sessionName;
|
|
195
|
+
if (isCloseCommand(extractCommandTokens(args)[0]))
|
|
196
|
+
attachedSessionKeys.delete(sessionKey);
|
|
197
|
+
else if (details.attachedBrowserSession === true || isAttachedBrowserInvocation(args, {}))
|
|
198
|
+
attachedSessionKeys.add(sessionKey);
|
|
199
|
+
}
|
|
200
|
+
return attachedSessionKeys;
|
|
201
|
+
}
|
|
121
202
|
function restoreAllowedDomainsBySessionFromBranch(branch) {
|
|
122
203
|
const restoredPolicies = new Map();
|
|
123
204
|
for (const entry of branch) {
|
|
@@ -179,7 +260,9 @@ function trackOwnedManagedSession(sessions, sessionName, cwd, options = {}) {
|
|
|
179
260
|
const key = getSessionContextKey(sessionName, options.namespace) ?? sessionName;
|
|
180
261
|
const existing = sessions.get(key);
|
|
181
262
|
const branchOwned = existing && !existing.branchOwned ? false : options.branchOwned === true;
|
|
182
|
-
|
|
263
|
+
const headedManagedAutosaveDisabled = options.headedManagedAutosaveDisabled ?? existing?.headedManagedAutosaveDisabled;
|
|
264
|
+
const headedManagedAutosaveInterval = options.headedManagedAutosaveInterval ?? existing?.headedManagedAutosaveInterval;
|
|
265
|
+
sessions.set(key, { branchOwned, cwd, headedManagedAutosaveDisabled, headedManagedAutosaveInterval, namespace: options.namespace, sessionName });
|
|
183
266
|
}
|
|
184
267
|
function untrackOwnedManagedSession(sessions, sessionName, namespace) {
|
|
185
268
|
if (!sessionName)
|
|
@@ -210,7 +293,11 @@ function syncOwnedManagedSessionsFromResult(sessions, result, cwd) {
|
|
|
210
293
|
const attemptedSessionName = typeof outcome.attemptedSessionName === "string" ? outcome.attemptedSessionName : undefined;
|
|
211
294
|
if (outcome.activeAfter === true && (status === "created" || status === "replaced" || status === "unchanged")) {
|
|
212
295
|
const namespace = isRecord(details) && typeof details.namespace === "string" ? details.namespace : undefined;
|
|
213
|
-
trackOwnedManagedSession(sessions, currentSessionName, cwd, {
|
|
296
|
+
trackOwnedManagedSession(sessions, currentSessionName, cwd, {
|
|
297
|
+
headedManagedAutosaveDisabled: details?.managedSessionHeadedAutosaveDisabled === true,
|
|
298
|
+
headedManagedAutosaveInterval: typeof details?.managedSessionHeadedAutosaveInterval === "string" ? details.managedSessionHeadedAutosaveInterval : undefined,
|
|
299
|
+
namespace,
|
|
300
|
+
});
|
|
214
301
|
}
|
|
215
302
|
if (succeeded && status === "closed") {
|
|
216
303
|
untrackOwnedManagedSession(sessions, attemptedSessionName ?? currentSessionName);
|
|
@@ -345,10 +432,18 @@ function setBranchRankForString(map, value, rank) {
|
|
|
345
432
|
if (typeof value === "string" && value.length > 0)
|
|
346
433
|
map.set(value, rank);
|
|
347
434
|
}
|
|
435
|
+
function setBranchManagedSessionActive(events, sessionName, namespace, rank) {
|
|
436
|
+
if (typeof sessionName !== "string" || sessionName.length === 0)
|
|
437
|
+
return;
|
|
438
|
+
const key = getSessionContextKey(sessionName, namespace) ?? sessionName;
|
|
439
|
+
events.managedSessionActiveIdentities.set(key, { namespace, sessionName });
|
|
440
|
+
events.managedSessionActiveRanks.set(key, rank);
|
|
441
|
+
}
|
|
348
442
|
function collectBranchManagedResourceEvents(branch) {
|
|
349
443
|
const events = {
|
|
350
444
|
electronLaunchActiveRanks: new Map(),
|
|
351
445
|
electronLaunchCleanupRanks: new Map(),
|
|
446
|
+
managedSessionActiveIdentities: new Map(),
|
|
352
447
|
managedSessionActiveRanks: new Map(),
|
|
353
448
|
managedSessionCloseRanks: new Map(),
|
|
354
449
|
};
|
|
@@ -377,17 +472,17 @@ function collectBranchManagedResourceEvents(branch) {
|
|
|
377
472
|
const outcomeCurrentSessionName = typeof outcome?.currentSessionName === "string" ? outcome.currentSessionName : undefined;
|
|
378
473
|
const outcomeAttemptedSessionName = typeof outcome?.attemptedSessionName === "string" ? outcome.attemptedSessionName : undefined;
|
|
379
474
|
if (outcomeSucceeded && outcome.activeAfter === true && (outcomeStatus === "created" || outcomeStatus === "replaced" || outcomeStatus === "unchanged")) {
|
|
380
|
-
|
|
475
|
+
setBranchManagedSessionActive(events, outcomeCurrentSessionName, namespace, eventRank);
|
|
381
476
|
}
|
|
382
477
|
if (outcomeSucceeded && outcomeStatus === "closed") {
|
|
383
478
|
setBranchRankForString(events.managedSessionCloseRanks, getSessionContextKey(outcomeAttemptedSessionName ?? outcomeCurrentSessionName ?? sessionName, namespace), eventRank);
|
|
384
479
|
}
|
|
385
|
-
if (
|
|
480
|
+
if (outcome && outcomeStatus === "replaced" && outcome.replacedSessionClosed !== false) {
|
|
386
481
|
const replacedSessionNamespace = typeof outcome.replacedSessionNamespace === "string" ? outcome.replacedSessionNamespace : namespace;
|
|
387
482
|
setBranchRankForString(events.managedSessionCloseRanks, getSessionContextKey(typeof outcome.replacedSessionName === "string" ? outcome.replacedSessionName : undefined, replacedSessionNamespace), eventRank);
|
|
388
483
|
}
|
|
389
|
-
if (succeeded && !isCloseCommand(command) && sessionName && (usedImplicitSession || sessionMode === "fresh")) {
|
|
390
|
-
events
|
|
484
|
+
if (succeeded && !isCloseCommand(command) && sessionName && (usedImplicitSession || sessionMode === "fresh" || details.managedSessionHeadedAutosaveDisabled === true || typeof details.managedSessionHeadedAutosaveInterval === "string")) {
|
|
485
|
+
setBranchManagedSessionActive(events, sessionName, namespace, eventRank);
|
|
391
486
|
}
|
|
392
487
|
if (succeeded && isCloseCommand(command)) {
|
|
393
488
|
setBranchRankForString(events.managedSessionCloseRanks, getSessionContextKey(explicitSessionName ?? sessionName ?? outcomeAttemptedSessionName ?? outcomeCurrentSessionName, namespace), eventRank);
|
|
@@ -433,18 +528,18 @@ function syncElectronCleanupManagedSessions(sessions, cleanupResults) {
|
|
|
433
528
|
untrackOwnedManagedSession(sessions, sessionName);
|
|
434
529
|
}
|
|
435
530
|
}
|
|
436
|
-
async function closeOwnedManagedSessionsExcept(sessions, restoreState, keepSessionName, timeoutMs, keepNamespace) {
|
|
531
|
+
async function closeOwnedManagedSessionsExcept(sessions, restoreState, keepSessionName, timeoutMs, attachedSessionKeys, keepNamespace) {
|
|
437
532
|
const keepKey = getSessionContextKey(keepSessionName, keepNamespace);
|
|
438
533
|
for (const [key, owner] of [...sessions]) {
|
|
439
534
|
if (key === keepKey)
|
|
440
535
|
continue;
|
|
441
|
-
const error = await closeManagedSession({ cwd: owner.cwd, namespace: owner.namespace, restoreState, sessionName: owner.sessionName, timeoutMs });
|
|
536
|
+
const error = await closeManagedSession({ cwd: owner.cwd, headedManagedAutosaveInterval: owner.headedManagedAutosaveInterval, namespace: owner.namespace, preserveAttachedBrowserSession: attachedSessionKeys.has(key), restoreState, sessionName: owner.sessionName, timeoutMs });
|
|
442
537
|
if (!error)
|
|
443
538
|
sessions.delete(key);
|
|
444
539
|
}
|
|
445
540
|
}
|
|
446
|
-
async function closeOwnedManagedSessions(sessions, restoreState, timeoutMs) {
|
|
447
|
-
await closeOwnedManagedSessionsExcept(sessions, restoreState, undefined, timeoutMs);
|
|
541
|
+
async function closeOwnedManagedSessions(sessions, restoreState, timeoutMs, attachedSessionKeys) {
|
|
542
|
+
await closeOwnedManagedSessionsExcept(sessions, restoreState, undefined, timeoutMs, attachedSessionKeys);
|
|
448
543
|
}
|
|
449
544
|
function getOffBranchOwnedElectronLaunchRecords(ownedRecords, branchRecords) {
|
|
450
545
|
const activeBranchLaunchIds = new Set(getActiveElectronRecords(branchRecords).map((record) => record.launchId));
|
|
@@ -577,6 +672,8 @@ export default function agentBrowserExtension(pi) {
|
|
|
577
672
|
let managedSessionActive = false;
|
|
578
673
|
let managedSessionBaseName = createImplicitSessionName(undefined, process.cwd(), ephemeralSessionSeed);
|
|
579
674
|
let managedSessionCompatibilityWorkaround;
|
|
675
|
+
let managedSessionHeadedAutosaveDisabled = false;
|
|
676
|
+
let managedSessionHeadedAutosaveInterval;
|
|
580
677
|
let managedSessionName = managedSessionBaseName;
|
|
581
678
|
let managedSessionCwd = process.cwd();
|
|
582
679
|
let managedSessionNamespace;
|
|
@@ -585,6 +682,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
585
682
|
let traceOwners = new Map();
|
|
586
683
|
let artifactManifest;
|
|
587
684
|
let allowedDomainsBySession = new Map();
|
|
685
|
+
let attachedSessionKeys = new Set();
|
|
588
686
|
let networkRoutesBySession = new Map();
|
|
589
687
|
let electronLaunchRecords = new Map();
|
|
590
688
|
let ownedElectronLaunchRecords = new Map();
|
|
@@ -600,6 +698,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
600
698
|
const key = getSessionContextKey(sessionName, namespace) ?? sessionName;
|
|
601
699
|
allowedDomainsBySession = new Map(allowedDomainsBySession);
|
|
602
700
|
allowedDomainsBySession.delete(key);
|
|
701
|
+
attachedSessionKeys.delete(key);
|
|
603
702
|
networkRoutesBySession = new Map(networkRoutesBySession);
|
|
604
703
|
networkRoutesBySession.delete(key);
|
|
605
704
|
sessionPageState.clearSession(key);
|
|
@@ -610,6 +709,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
610
709
|
const previousManagedSessionActive = managedSessionActive;
|
|
611
710
|
const previousManagedSessionName = managedSessionName;
|
|
612
711
|
const previousFreshSessionOrdinal = freshSessionOrdinal;
|
|
712
|
+
const previousAttachedSessionKeys = attachedSessionKeys;
|
|
613
713
|
managedSessionBaseName = createImplicitSessionName(ctx.sessionManager.getSessionId(), ctx.cwd, ephemeralSessionSeed);
|
|
614
714
|
const branch = ctx.sessionManager.getBranch();
|
|
615
715
|
const branchResourceEvents = collectBranchManagedResourceEvents(branch);
|
|
@@ -640,14 +740,24 @@ export default function agentBrowserExtension(pi) {
|
|
|
640
740
|
managedSessionCompatibilityWorkaround = managedSessionActive
|
|
641
741
|
? restoreManagedSessionCompatibilityWorkaroundFromBranch(branch, managedSessionName, managedSessionNamespace)
|
|
642
742
|
: undefined;
|
|
743
|
+
managedSessionHeadedAutosaveDisabled = managedSessionActive
|
|
744
|
+
&& restoreManagedSessionHeadedAutosaveDisabledFromBranch(branch, managedSessionName, managedSessionNamespace);
|
|
745
|
+
managedSessionHeadedAutosaveInterval = managedSessionActive
|
|
746
|
+
? restoreManagedSessionHeadedAutosaveIntervalFromBranch(branch, managedSessionName, managedSessionNamespace)
|
|
747
|
+
: undefined;
|
|
643
748
|
managedSessionCwd = ctx.cwd;
|
|
644
749
|
freshSessionOrdinal = nextFreshSessionOrdinal;
|
|
645
750
|
sessionPageState = SessionPageState.fromBranch(branch);
|
|
646
751
|
traceOwners = new Map();
|
|
647
752
|
artifactManifest = restoreArtifactManifestFromBranch(branch);
|
|
648
753
|
allowedDomainsBySession = restoreAllowedDomainsBySessionFromBranch(branch);
|
|
754
|
+
attachedSessionKeys = restoreAttachedSessionKeysFromBranch(branch);
|
|
649
755
|
networkRoutesBySession = new Map();
|
|
650
756
|
electronLaunchRecords = restoreElectronLaunchRecordsFromBranch(branch);
|
|
757
|
+
for (const record of getActiveElectronRecords(electronLaunchRecords)) {
|
|
758
|
+
if (record.sessionName)
|
|
759
|
+
attachedSessionKeys.add(getSessionContextKey(record.sessionName) ?? record.sessionName);
|
|
760
|
+
}
|
|
651
761
|
if (options.resetRuntimeOwnership) {
|
|
652
762
|
ownedManagedSessions.clear();
|
|
653
763
|
ownedElectronLaunchRecords = new Map();
|
|
@@ -659,13 +769,57 @@ export default function agentBrowserExtension(pi) {
|
|
|
659
769
|
}
|
|
660
770
|
removeInactiveOwnedElectronLaunchRecords(ownedElectronLaunchRecords, branchOwnedElectronLaunchIds, electronLaunchRecords, branchResourceEvents.electronLaunchActiveRanks, branchResourceEvents.electronLaunchCleanupRanks);
|
|
661
771
|
}
|
|
772
|
+
for (const [sessionKey, identity] of branchResourceEvents.managedSessionActiveIdentities) {
|
|
773
|
+
const activeRank = branchResourceEvents.managedSessionActiveRanks.get(sessionKey);
|
|
774
|
+
const closeRank = branchResourceEvents.managedSessionCloseRanks.get(sessionKey);
|
|
775
|
+
if (activeRank === undefined || (closeRank !== undefined && closeRank >= activeRank))
|
|
776
|
+
continue;
|
|
777
|
+
if (!isRestorableManagedSessionName(identity.sessionName, managedSessionBaseName))
|
|
778
|
+
continue;
|
|
779
|
+
trackOwnedManagedSession(ownedManagedSessions, identity.sessionName, ctx.cwd, {
|
|
780
|
+
branchOwned: true,
|
|
781
|
+
headedManagedAutosaveDisabled: restoreManagedSessionHeadedAutosaveDisabledFromBranch(branch, identity.sessionName, identity.namespace),
|
|
782
|
+
headedManagedAutosaveInterval: restoreManagedSessionHeadedAutosaveIntervalFromBranch(branch, identity.sessionName, identity.namespace),
|
|
783
|
+
namespace: identity.namespace,
|
|
784
|
+
});
|
|
785
|
+
}
|
|
662
786
|
if (restoredState.active) {
|
|
663
|
-
trackOwnedManagedSession(ownedManagedSessions, restoredState.sessionName, ctx.cwd, {
|
|
787
|
+
trackOwnedManagedSession(ownedManagedSessions, restoredState.sessionName, ctx.cwd, {
|
|
788
|
+
branchOwned: true,
|
|
789
|
+
headedManagedAutosaveDisabled: managedSessionHeadedAutosaveDisabled,
|
|
790
|
+
headedManagedAutosaveInterval: managedSessionHeadedAutosaveInterval,
|
|
791
|
+
namespace: restoredState.namespace,
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
for (const record of getActiveElectronRecords(electronLaunchRecords)) {
|
|
795
|
+
if (!record.sessionName || !isRestorableManagedSessionName(record.sessionName, managedSessionBaseName))
|
|
796
|
+
continue;
|
|
797
|
+
const sessionKey = getSessionContextKey(record.sessionName) ?? record.sessionName;
|
|
798
|
+
const activeRank = branchResourceEvents.managedSessionActiveRanks.get(sessionKey);
|
|
799
|
+
const closeRank = branchResourceEvents.managedSessionCloseRanks.get(sessionKey);
|
|
800
|
+
if (activeRank === undefined || (closeRank !== undefined && closeRank >= activeRank))
|
|
801
|
+
continue;
|
|
802
|
+
trackOwnedManagedSession(ownedManagedSessions, record.sessionName, ctx.cwd, {
|
|
803
|
+
branchOwned: true,
|
|
804
|
+
headedManagedAutosaveDisabled: restoreManagedSessionHeadedAutosaveDisabledFromBranch(branch, record.sessionName),
|
|
805
|
+
headedManagedAutosaveInterval: restoreManagedSessionHeadedAutosaveIntervalFromBranch(branch, record.sessionName),
|
|
806
|
+
});
|
|
664
807
|
}
|
|
665
808
|
mergeActiveElectronLaunchRecords(ownedElectronLaunchRecords, electronLaunchRecords, {
|
|
666
809
|
branchOwnedLaunchIds: branchOwnedElectronLaunchIds,
|
|
667
810
|
markBranchOwned: true,
|
|
668
811
|
});
|
|
812
|
+
if (!options.resetRuntimeOwnership) {
|
|
813
|
+
for (const sessionKey of previousAttachedSessionKeys) {
|
|
814
|
+
if (ownedManagedSessions.has(sessionKey))
|
|
815
|
+
attachedSessionKeys.add(sessionKey);
|
|
816
|
+
}
|
|
817
|
+
for (const record of ownedElectronLaunchRecords.values()) {
|
|
818
|
+
const sessionKey = getSessionContextKey(record.sessionName);
|
|
819
|
+
if (sessionKey && previousAttachedSessionKeys.has(sessionKey))
|
|
820
|
+
attachedSessionKeys.add(sessionKey);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
669
823
|
};
|
|
670
824
|
const registerWebSearchToolIfAvailable = (configState) => {
|
|
671
825
|
if (webSearchToolRegistered || !canRegisterWebSearchTool(configState))
|
|
@@ -707,10 +861,12 @@ export default function agentBrowserExtension(pi) {
|
|
|
707
861
|
? ownedElectronLaunchRecords
|
|
708
862
|
: getOffBranchOwnedElectronLaunchRecords(ownedElectronLaunchRecords, electronLaunchRecords);
|
|
709
863
|
const electronCleanupResults = await cleanupActiveElectronHostLaunches({
|
|
864
|
+
attachedSessionKeys,
|
|
710
865
|
cwd: shutdownCwd,
|
|
711
866
|
electronChildProcesses,
|
|
712
867
|
electronLaunchRecords: electronRecordsToCleanup,
|
|
713
868
|
managedSessionRestoreState,
|
|
869
|
+
ownedManagedSessions,
|
|
714
870
|
timeoutMs: implicitSessionCloseTimeoutMs,
|
|
715
871
|
});
|
|
716
872
|
preservedElectronProfileDirs = [...new Set([
|
|
@@ -719,19 +875,22 @@ export default function agentBrowserExtension(pi) {
|
|
|
719
875
|
])];
|
|
720
876
|
syncElectronCleanupManagedSessions(ownedManagedSessions, electronCleanupResults);
|
|
721
877
|
if (quitting) {
|
|
722
|
-
await closeOwnedManagedSessions(ownedManagedSessions, managedSessionRestoreState, implicitSessionCloseTimeoutMs);
|
|
878
|
+
await closeOwnedManagedSessions(ownedManagedSessions, managedSessionRestoreState, implicitSessionCloseTimeoutMs, attachedSessionKeys);
|
|
723
879
|
}
|
|
724
880
|
else {
|
|
725
|
-
await closeOwnedManagedSessionsExcept(ownedManagedSessions, managedSessionRestoreState, managedSessionActive ? managedSessionName : undefined, implicitSessionCloseTimeoutMs, managedSessionActive ? managedSessionNamespace : undefined);
|
|
881
|
+
await closeOwnedManagedSessionsExcept(ownedManagedSessions, managedSessionRestoreState, managedSessionActive ? managedSessionName : undefined, implicitSessionCloseTimeoutMs, attachedSessionKeys, managedSessionActive ? managedSessionNamespace : undefined);
|
|
726
882
|
}
|
|
727
883
|
});
|
|
728
884
|
managedSessionActive = false;
|
|
729
885
|
managedSessionCompatibilityWorkaround = undefined;
|
|
886
|
+
managedSessionHeadedAutosaveDisabled = false;
|
|
887
|
+
managedSessionHeadedAutosaveInterval = undefined;
|
|
730
888
|
managedSessionNamespace = undefined;
|
|
731
889
|
sessionPageState.reset();
|
|
732
890
|
traceOwners = new Map();
|
|
733
891
|
artifactManifest = undefined;
|
|
734
892
|
allowedDomainsBySession = new Map();
|
|
893
|
+
attachedSessionKeys = new Set();
|
|
735
894
|
networkRoutesBySession = new Map();
|
|
736
895
|
electronLaunchRecords = new Map();
|
|
737
896
|
ownedElectronLaunchRecords = new Map();
|
|
@@ -822,6 +981,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
822
981
|
ownedRecords: ownedElectronLaunchRecords,
|
|
823
982
|
});
|
|
824
983
|
const electronHostResult = await handleElectronHostInput({
|
|
984
|
+
attachedSessionKeys,
|
|
825
985
|
compiledElectron,
|
|
826
986
|
cwd: ctx.cwd,
|
|
827
987
|
electronChildProcesses,
|
|
@@ -831,6 +991,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
831
991
|
managedSessionName,
|
|
832
992
|
managedSessionNamespace,
|
|
833
993
|
managedSessionRestoreState,
|
|
994
|
+
ownedManagedSessions,
|
|
834
995
|
redactedCompiledElectron,
|
|
835
996
|
sessionPageState,
|
|
836
997
|
signal,
|
|
@@ -858,6 +1019,8 @@ export default function agentBrowserExtension(pi) {
|
|
|
858
1019
|
if (closedSessionName === managedSessionName) {
|
|
859
1020
|
managedSessionActive = false;
|
|
860
1021
|
managedSessionCompatibilityWorkaround = undefined;
|
|
1022
|
+
managedSessionHeadedAutosaveDisabled = false;
|
|
1023
|
+
managedSessionHeadedAutosaveInterval = undefined;
|
|
861
1024
|
managedSessionNamespace = undefined;
|
|
862
1025
|
freshSessionOrdinal += 1;
|
|
863
1026
|
managedSessionName = createFreshSessionName(managedSessionBaseName, ephemeralSessionSeed, freshSessionOrdinal);
|
|
@@ -891,6 +1054,7 @@ export default function agentBrowserExtension(pi) {
|
|
|
891
1054
|
const browserRunState = {
|
|
892
1055
|
allowedDomainsBySession,
|
|
893
1056
|
artifactManifest,
|
|
1057
|
+
attachedSessionKeys,
|
|
894
1058
|
closedManagedSessionNames: new Set(),
|
|
895
1059
|
electronChildProcesses,
|
|
896
1060
|
electronLaunchRecords,
|
|
@@ -899,6 +1063,8 @@ export default function agentBrowserExtension(pi) {
|
|
|
899
1063
|
managedSessionActive,
|
|
900
1064
|
managedSessionBaseName,
|
|
901
1065
|
managedSessionCompatibilityWorkaround,
|
|
1066
|
+
managedSessionHeadedAutosaveDisabled,
|
|
1067
|
+
managedSessionHeadedAutosaveInterval,
|
|
902
1068
|
managedSessionCwd,
|
|
903
1069
|
managedSessionName,
|
|
904
1070
|
managedSessionNamespace,
|
|
@@ -911,6 +1077,14 @@ export default function agentBrowserExtension(pi) {
|
|
|
911
1077
|
const initialAllowedDomainsBySession = browserRunState.allowedDomainsBySession;
|
|
912
1078
|
const initialArtifactManifest = browserRunState.artifactManifest;
|
|
913
1079
|
const initialNetworkRoutesBySession = browserRunState.networkRoutesBySession;
|
|
1080
|
+
const attachedSessionRequested = isAttachedBrowserInvocation(toolArgs)
|
|
1081
|
+
|| (resolvedInput.kind === "electron" && resolvedInput.compiledElectron.action === "launch");
|
|
1082
|
+
const allocatesFreshManagedSession = explicitSessionName === undefined
|
|
1083
|
+
&& (params.sessionMode === "fresh" || (resolvedInput.kind === "electron" && resolvedInput.compiledElectron.action === "launch"));
|
|
1084
|
+
const reusableSessionKey = allocatesFreshManagedSession
|
|
1085
|
+
? undefined
|
|
1086
|
+
: callerOwnedSessionQueueKey ?? getSessionContextKey(browserRunState.managedSessionName, browserRunState.managedSessionNamespace);
|
|
1087
|
+
const attachedSessionKnown = reusableSessionKey !== undefined && attachedSessionKeys.has(reusableSessionKey);
|
|
914
1088
|
let result = await runAgentBrowserTool({
|
|
915
1089
|
ctx,
|
|
916
1090
|
cwd: ctx.cwd,
|
|
@@ -921,12 +1095,34 @@ export default function agentBrowserExtension(pi) {
|
|
|
921
1095
|
input: resolvedInput,
|
|
922
1096
|
onUpdate,
|
|
923
1097
|
params,
|
|
1098
|
+
establishAttachedBrowserSession: attachedSessionRequested && !attachedSessionKnown,
|
|
1099
|
+
preserveAttachedBrowserSession: attachedSessionRequested || attachedSessionKnown,
|
|
924
1100
|
promptPolicy,
|
|
925
1101
|
sessionPageStateUpdate,
|
|
926
1102
|
signal,
|
|
927
1103
|
state: browserRunState,
|
|
928
1104
|
});
|
|
929
1105
|
const branchRestoreStillCurrent = branchRestoreGenerationAtStart === branchRestoreGeneration;
|
|
1106
|
+
if (branchRestoreStillCurrent) {
|
|
1107
|
+
const resultDetails = isRecord(result.details) ? result.details : undefined;
|
|
1108
|
+
const resultSessionName = typeof resultDetails?.sessionName === "string"
|
|
1109
|
+
? resultDetails.sessionName
|
|
1110
|
+
: extractExplicitSessionName(toolArgs);
|
|
1111
|
+
const resultNamespace = typeof resultDetails?.namespace === "string"
|
|
1112
|
+
? resultDetails.namespace
|
|
1113
|
+
: resolveAgentBrowserNamespace(toolArgs, process.env.AGENT_BROWSER_NAMESPACE);
|
|
1114
|
+
const resultSessionKey = getSessionContextKey(resultSessionName, resultNamespace) ?? resultSessionName;
|
|
1115
|
+
const managedSessionOutcome = isRecord(resultDetails?.managedSessionOutcome) ? resultDetails.managedSessionOutcome : undefined;
|
|
1116
|
+
const attachedSessionRemainsActive = result.isError !== true
|
|
1117
|
+
|| (attachedSessionRequested && managedSessionOutcome?.activeAfter === true);
|
|
1118
|
+
const closesAttachedSession = result.isError !== true && isCloseCommand(extractCommandTokens(toolArgs)[0]);
|
|
1119
|
+
if (resultSessionKey && closesAttachedSession)
|
|
1120
|
+
attachedSessionKeys.delete(resultSessionKey);
|
|
1121
|
+
else if (resultSessionKey && attachedSessionRemainsActive && (attachedSessionRequested || attachedSessionKnown)) {
|
|
1122
|
+
attachedSessionKeys.add(resultSessionKey);
|
|
1123
|
+
result = { ...result, details: { ...(resultDetails ?? {}), attachedBrowserSession: true } };
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
930
1126
|
if (branchRestoreStillCurrent) {
|
|
931
1127
|
allowedDomainsBySession = mergeBrowserRunMap(allowedDomainsBySession, initialAllowedDomainsBySession, browserRunState.allowedDomainsBySession);
|
|
932
1128
|
networkRoutesBySession = mergeBrowserRunMap(networkRoutesBySession, initialNetworkRoutesBySession, browserRunState.networkRoutesBySession);
|
|
@@ -947,6 +1143,8 @@ export default function agentBrowserExtension(pi) {
|
|
|
947
1143
|
freshSessionOrdinal = Math.max(freshSessionOrdinal, browserRunState.freshSessionOrdinal);
|
|
948
1144
|
managedSessionActive = browserRunState.managedSessionActive;
|
|
949
1145
|
managedSessionCompatibilityWorkaround = browserRunState.managedSessionCompatibilityWorkaround;
|
|
1146
|
+
managedSessionHeadedAutosaveDisabled = browserRunState.managedSessionHeadedAutosaveDisabled === true;
|
|
1147
|
+
managedSessionHeadedAutosaveInterval = browserRunState.managedSessionHeadedAutosaveInterval;
|
|
950
1148
|
managedSessionCwd = browserRunState.managedSessionCwd;
|
|
951
1149
|
managedSessionName = browserRunState.managedSessionName;
|
|
952
1150
|
managedSessionNamespace = browserRunState.managedSessionNamespace;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Parse raw agent-browser argv once into a stable command descriptor for planners and policy.
|
|
3
|
-
* Responsibilities: Own command-token extraction, command/subcommand identification, and descriptor construction.
|
|
4
|
-
* Scope: Pure argv parsing; runtime planning and session policy consume descriptors instead of re-parsing tokens.
|
|
5
|
-
*/
|
|
6
1
|
import { GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES, VALUE_FLAGS, optionalGlobalValueFlagConsumesNext } from "./argv-grammar.js";
|
|
7
2
|
import { isOpenNavigationCommand } from "./command-taxonomy.js";
|
|
8
3
|
function isBooleanLiteral(token) {
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Shared argv flag-shape metadata and helpers for command discovery and sessionless policy checks.
|
|
3
|
-
* Responsibilities: Own global/command value-flag sets and boolean/value-flag validation used during argv parsing.
|
|
4
|
-
* Scope: Pure token grammar; command semantics and subprocess execution live elsewhere.
|
|
5
|
-
*/
|
|
6
1
|
import { isKnownCommandToken } from "./command-taxonomy.js";
|
|
7
2
|
export const GLOBAL_VALUE_FLAGS = [
|
|
8
3
|
"--session",
|
|
@@ -125,6 +120,10 @@ export function getBooleanFlagValue(args, flag) {
|
|
|
125
120
|
export function isBooleanFlagEnabled(args, flag) {
|
|
126
121
|
return getBooleanFlagValue(args, flag) ?? false;
|
|
127
122
|
}
|
|
123
|
+
/** Match upstream env_var_is_truthy exactly: lowercase only, without trimming or accepting "off". */
|
|
124
|
+
export function isUpstreamEnvFlagEnabled(value) {
|
|
125
|
+
return value !== undefined && !["", "0", "false", "no"].includes(value.toLowerCase());
|
|
126
|
+
}
|
|
128
127
|
/** Mirror upstream sanitize_session_component for namespace/socket/state identity. */
|
|
129
128
|
export function canonicalizeAgentBrowserNamespace(value) {
|
|
130
129
|
if (value === undefined)
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Own upstream command-shape policies that decide whether the wrapper should allocate a managed browser session.
|
|
3
|
-
* Responsibilities: Keep local/sessionless command grammar out of the runtime execution planner while preserving exact upstream shapes.
|
|
4
|
-
* Scope: Pure argv-token policy; command discovery, subprocess execution, and presentation live in focused modules.
|
|
5
|
-
*/
|
|
6
1
|
import { hasOnlyBooleanFlags, hasOnlyOptionFlags, isNonFlagToken, stripSessionlessShapeGlobalFlags } from "./argv-grammar.js";
|
|
7
2
|
const SESSIONLESS_AUTH_SUBCOMMANDS = new Set(["save", "list", "show", "delete", "remove"]);
|
|
8
3
|
const PLUGIN_SESSIONLESS_SUBCOMMANDS = new Set(["list", "show", "add", "run"]);
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Centralize upstream agent-browser command capabilities that wrapper behavior depends on.
|
|
3
|
-
* Responsibilities: Normalize command aliases once and expose capability predicates for runtime planning,
|
|
4
|
-
* session/ref guards, result recommendations, and presentation summaries without coupling unrelated behaviors.
|
|
5
|
-
* Scope: Static command capability taxonomy only; command-shape parsing, spawning, and formatting live elsewhere.
|
|
6
|
-
*/
|
|
7
1
|
const ADDITIONAL_COMMAND_TOKENS = [
|
|
8
2
|
"a11y", "auth", "chat", "clipboard", "confirm", "connect", "dashboard", "deny", "device", "dialog", "diff", "doctor", "errors", "eval", "find", "frame", "get", "highlight", "inspect", "install", "is", "mcp", "plugin", "plugins", "profiles", "profiler", "react", "record", "removeinitscript", "session", "set", "skills", "snapshot", "state", "stream", "trace", "upgrade", "vitals", "wait", "web-vitals", "window",
|
|
9
3
|
];
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
/**
|
|
3
|
-
* Purpose: Canonical pi-agent-browser-native config policy shared by runtime and setup CLI.
|
|
4
|
-
* Responsibilities: Own config paths, provider descriptors, credential source parsing, layer validation/merge, status projection, and redacted summaries.
|
|
5
|
-
* Scope: Pure configuration policy plus synchronous status loading; secret command execution and browser/web-search runtime calls live elsewhere.
|
|
6
|
-
*/
|
|
7
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
3
|
import { homedir } from "node:os";
|
|
9
4
|
import { join, resolve } from "node:path";
|
|
@@ -1,9 +1,3 @@
|
|
|
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: Credential sources from loaded config are passed through to the runtime; command credentials are resolved lazily at execution time and displayed values stay redacted.
|
|
6
|
-
*/
|
|
7
1
|
import { exec as execCallback } from "node:child_process";
|
|
8
2
|
import { readFile } from "node:fs/promises";
|
|
9
3
|
import { promisify } from "node:util";
|
|
@@ -1,10 +1,3 @@
|
|
|
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
1
|
import { isRecord } from "../parsing.js";
|
|
9
2
|
const ELECTRON_CDP_FETCH_TIMEOUT_MS = 1_000;
|
|
10
3
|
function asString(value) {
|
|
@@ -49,3 +42,9 @@ export async function fetchCdpJson(url, signal) {
|
|
|
49
42
|
clearTimeout(timeout);
|
|
50
43
|
}
|
|
51
44
|
}
|
|
45
|
+
export function boundElectronProbeString(value, maxLength = 240) {
|
|
46
|
+
const trimmed = value?.trim();
|
|
47
|
+
if (!trimmed)
|
|
48
|
+
return undefined;
|
|
49
|
+
return trimmed.length > maxLength ? `${trimmed.slice(0, Math.max(0, maxLength - 3))}...` : trimmed;
|
|
50
|
+
}
|
|
@@ -1,10 +1,3 @@
|
|
|
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
1
|
import { execFile } from "node:child_process";
|
|
9
2
|
import { rm } from "node:fs/promises";
|
|
10
3
|
import { promisify } from "node:util";
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Discover installed Electron desktop applications without invoking upstream agent-browser.
|
|
3
|
-
* Responsibilities: Scan bounded macOS app bundles and Linux .desktop launchers, apply Electron framework evidence gates, and return small platform-tagged app metadata.
|
|
4
|
-
* Scope: Discovery only; launch, cleanup, status, and CDP attachment live in later Electron lifecycle work items.
|
|
5
|
-
* Usage: Called by the agent_browser top-level electron.list shorthand and directly by tests through parameterized scan locations.
|
|
6
|
-
* Invariants/Assumptions: Discovery is best-effort, missing scan roots are ignored, malformed .desktop files are skipped, and results are capped before they reach model-visible output.
|
|
7
|
-
*/
|
|
8
1
|
import { constants as fsConstants } from "node:fs";
|
|
9
2
|
import { access, readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
10
3
|
import { homedir } from "node:os";
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Launch wrapper-owned Electron applications and discover their CDP endpoint.
|
|
3
|
-
* Responsibilities: Resolve Electron targets, enforce caller-owned allow/deny policy, create isolated userDataDir profiles, launch with remote debugging on an OS-chosen port, poll DevToolsActivePort, and read bounded CDP version/target metadata.
|
|
4
|
-
* Scope: Host-side Electron lifecycle setup only; upstream agent-browser attach/presentation stays in the extension entrypoint.
|
|
5
|
-
* Usage: Called by the agent_browser electron.launch shorthand before routing through upstream `connect`.
|
|
6
|
-
* Invariants/Assumptions: The wrapper only launches targets with Electron framework evidence, always uses an isolated temp profile, never accepts a caller-supplied remote debugging port, and cleans any spawned process/profile when cancellation interrupts readiness.
|
|
7
|
-
*/
|
|
8
1
|
import { spawn } from "node:child_process";
|
|
9
2
|
import { randomUUID } from "node:crypto";
|
|
10
3
|
import { readFile, rm } from "node:fs/promises";
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Compile top-level Electron wrapper inputs into validated Electron actions.
|
|
3
|
-
* Responsibilities: Enforce action-specific fields, launch-target rules, and wrapper-owned flag safety.
|
|
4
|
-
* Scope: Electron input-mode validation only; launch/probe/cleanup execution stays in the extension entrypoint.
|
|
5
|
-
*/
|
|
6
1
|
import { isRecord } from "../parsing.js";
|
|
7
2
|
import { AGENT_BROWSER_ELECTRON_ACTIONS, AGENT_BROWSER_ELECTRON_HANDOFFS, AGENT_BROWSER_ELECTRON_LIST_FIELDS, AGENT_BROWSER_ELECTRON_PROBE_FIELDS, AGENT_BROWSER_ELECTRON_RESERVED_APP_ARGS, AGENT_BROWSER_ELECTRON_TARGET_TYPES, } from "./types.js";
|
|
8
3
|
function validateOptionalNonEmptyString(input, fieldName) {
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Compile constrained job and lightweight QA wrapper inputs to upstream batch commands.
|
|
3
|
-
* Responsibilities: Validate job/QA fields, produce argv/stdin, and summarize QA diagnostic results.
|
|
4
|
-
* Scope: Job and QA modes only.
|
|
5
|
-
*/
|
|
6
1
|
import { isRecord } from "../parsing.js";
|
|
7
2
|
import { summarizeNetworkFailures } from "../results/network.js";
|
|
8
3
|
import { getBatchResultItems, getCommandNameFromBatchItem, getSelectValues } from "./shared.js";
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Compile and analyze experimental DOM/source and network source lookup input modes.
|
|
3
|
-
* Responsibilities: Build lookup batches, collect DOM/React/workspace candidates, and redact network lookup surfaces.
|
|
4
|
-
* Scope: Source lookup and network source lookup only.
|
|
5
|
-
*/
|
|
6
1
|
import { readFile, readdir } from "node:fs/promises";
|
|
7
2
|
import { extname, join } from "node:path";
|
|
8
3
|
import { isRecord } from "../parsing.js";
|