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,512 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Own wrapper-known per-session browser page target, ref snapshot, invalidation, and pinning state.
|
|
3
|
-
* Responsibilities: Restore state from persisted tool details, apply ordered tab/ref updates atomically, and expose order-free public state views to the extension entrypoint.
|
|
4
|
-
* Scope: Session page state only; browser process execution, tab probing, and presentation policies stay in the extension entrypoint.
|
|
5
|
-
* Usage: `index.ts` creates one store per Pi session lifecycle and records observations through update tokens.
|
|
6
|
-
* Invariants/Assumptions: One tool-call update token must govern all page-state observations from that invocation; stale overlapping updates must not overwrite newer state.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { isCloseCommand, isReadOnlyDiagnosticSessionTargetCommand } from "./command-taxonomy.js";
|
|
10
|
-
import { isRecord } from "./parsing.js";
|
|
11
|
-
import { getEditableRefEvidence } from "./results/editable-ref-evidence.js";
|
|
12
|
-
import { enrichSnapshotRefEntries, getSnapshotRefEntries } from "./results/snapshot-refs.js";
|
|
13
|
-
import { parseSnapshotLines } from "./results/snapshot-segments.js";
|
|
14
|
-
|
|
15
|
-
export interface SessionTabTarget {
|
|
16
|
-
title?: string;
|
|
17
|
-
url: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface OrderedSessionTabTarget {
|
|
21
|
-
order: number;
|
|
22
|
-
target: SessionTabTarget;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface SessionRefSnapshot {
|
|
26
|
-
refIds: string[];
|
|
27
|
-
refs?: Record<string, { isContentEditable?: boolean; isEditable?: boolean; name: string; role: string }>;
|
|
28
|
-
target?: SessionTabTarget;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface OrderedSessionRefSnapshot extends SessionRefSnapshot {
|
|
32
|
-
order: number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface SessionRefSnapshotInvalidation {
|
|
36
|
-
reason: "no-active-page";
|
|
37
|
-
summary: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface OrderedSessionRefSnapshotInvalidation extends SessionRefSnapshotInvalidation {
|
|
41
|
-
order: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface BatchRefSnapshotState {
|
|
45
|
-
invalidation?: SessionRefSnapshotInvalidation;
|
|
46
|
-
snapshot?: SessionRefSnapshot;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export type SessionTabPinningReason = "drift" | "restore";
|
|
50
|
-
|
|
51
|
-
export type SessionPageStateUpdateToken = number & { readonly __sessionPageStateUpdateToken: unique symbol };
|
|
52
|
-
|
|
53
|
-
export interface SessionPageStateView {
|
|
54
|
-
pinningReason?: SessionTabPinningReason;
|
|
55
|
-
refSnapshot?: SessionRefSnapshot;
|
|
56
|
-
refSnapshotInvalidation?: SessionRefSnapshotInvalidation;
|
|
57
|
-
tabTarget?: SessionTabTarget;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface SessionPageStateUpdateResult extends SessionPageStateView {
|
|
61
|
-
applied: boolean;
|
|
62
|
-
stale?: boolean;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function normalizeComparableUrl(url: string | undefined): string | undefined {
|
|
66
|
-
const normalizedUrl = url?.trim();
|
|
67
|
-
if (!normalizedUrl) {
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
try {
|
|
71
|
-
const parsedUrl = new URL(normalizedUrl);
|
|
72
|
-
parsedUrl.hash = "";
|
|
73
|
-
return parsedUrl.toString();
|
|
74
|
-
} catch {
|
|
75
|
-
return undefined;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function normalizeSessionTabTarget(target: { title?: string; url?: string } | undefined): SessionTabTarget | undefined {
|
|
80
|
-
if (!target) {
|
|
81
|
-
return undefined;
|
|
82
|
-
}
|
|
83
|
-
const url = normalizeComparableUrl(target.url);
|
|
84
|
-
if (!url) {
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
const title = target.title?.trim();
|
|
88
|
-
return { title: title && title.length > 0 ? title : undefined, url };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function isAboutBlankUrl(url: string | undefined): boolean {
|
|
92
|
-
return normalizeComparableUrl(url) === "about:blank";
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function isAboutBlankSessionTabTarget(target: SessionTabTarget | undefined): boolean {
|
|
96
|
-
return isAboutBlankUrl(target?.url);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function commandExplicitlyTargetsAboutBlank(commandTokens: string[]): boolean {
|
|
100
|
-
return commandTokens.some((token) => isAboutBlankUrl(token));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function targetsMatch(left: SessionTabTarget | undefined, right: SessionTabTarget | undefined): boolean {
|
|
104
|
-
if (!left || !right) return true;
|
|
105
|
-
return normalizeComparableUrl(left.url) === normalizeComparableUrl(right.url);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function extractStringResultField(data: unknown, fieldName: "result" | "title" | "url" | "value"): string | undefined {
|
|
109
|
-
if (typeof data === "string") {
|
|
110
|
-
if (fieldName === "value") return data;
|
|
111
|
-
const text = data.trim();
|
|
112
|
-
return text.length > 0 ? text : undefined;
|
|
113
|
-
}
|
|
114
|
-
if (!isRecord(data) || typeof data[fieldName] !== "string") {
|
|
115
|
-
return undefined;
|
|
116
|
-
}
|
|
117
|
-
if (fieldName === "value") return data[fieldName];
|
|
118
|
-
const text = data[fieldName].trim();
|
|
119
|
-
return text.length > 0 ? text : undefined;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function extractSessionTabTargetFromData(data: unknown): SessionTabTarget | undefined {
|
|
123
|
-
const directTarget = normalizeSessionTabTarget({
|
|
124
|
-
title: extractStringResultField(data, "title"),
|
|
125
|
-
url: extractStringResultField(data, "url"),
|
|
126
|
-
});
|
|
127
|
-
if (directTarget) {
|
|
128
|
-
return directTarget;
|
|
129
|
-
}
|
|
130
|
-
if (isRecord(data) && typeof data.origin === "string") {
|
|
131
|
-
return normalizeSessionTabTarget({ url: data.origin });
|
|
132
|
-
}
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function extractBatchResultCommand(item: Record<string, unknown>): string[] {
|
|
137
|
-
return Array.isArray(item.command) ? item.command.filter((token): token is string => typeof token === "string") : [];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function extractSessionTabTargetFromCommandData(commandTokens: string[], data: unknown): SessionTabTarget | undefined {
|
|
141
|
-
const [command, subcommand] = commandTokens;
|
|
142
|
-
return isReadOnlyDiagnosticSessionTargetCommand(command, subcommand) ? undefined : extractSessionTabTargetFromData(data);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export function extractSessionTabTargetFromBatchResults(data: unknown): SessionTabTarget | undefined {
|
|
146
|
-
if (!Array.isArray(data)) {
|
|
147
|
-
return undefined;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
let currentTarget: SessionTabTarget | undefined;
|
|
151
|
-
let pendingTitle: string | undefined;
|
|
152
|
-
for (const item of data) {
|
|
153
|
-
if (!isRecord(item) || item.success === false) {
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
const [name, subcommand] = extractBatchResultCommand(item);
|
|
157
|
-
const result = item.result;
|
|
158
|
-
|
|
159
|
-
if (name === "get" && subcommand === "title") {
|
|
160
|
-
pendingTitle = extractStringResultField(result, "title");
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
if (name === "get" && subcommand === "url") {
|
|
164
|
-
const url = extractStringResultField(result, "url");
|
|
165
|
-
const target = normalizeSessionTabTarget({ title: pendingTitle, url });
|
|
166
|
-
if (target) {
|
|
167
|
-
currentTarget = target;
|
|
168
|
-
}
|
|
169
|
-
pendingTitle = undefined;
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
const resultTarget = extractSessionTabTargetFromCommandData([name, subcommand].filter((token): token is string => token !== undefined), result);
|
|
173
|
-
if (resultTarget) {
|
|
174
|
-
currentTarget = resultTarget;
|
|
175
|
-
}
|
|
176
|
-
pendingTitle = undefined;
|
|
177
|
-
}
|
|
178
|
-
return currentTarget;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function deriveSessionTabTarget(options: {
|
|
182
|
-
command?: string;
|
|
183
|
-
data: unknown;
|
|
184
|
-
navigationSummary?: { title?: string; url?: string };
|
|
185
|
-
previousTarget?: SessionTabTarget;
|
|
186
|
-
subcommand?: string;
|
|
187
|
-
}): SessionTabTarget | undefined {
|
|
188
|
-
if (isCloseCommand(options.command)) {
|
|
189
|
-
return undefined;
|
|
190
|
-
}
|
|
191
|
-
const commandDataTarget = isReadOnlyDiagnosticSessionTargetCommand(options.command, options.subcommand)
|
|
192
|
-
? undefined
|
|
193
|
-
: extractSessionTabTargetFromData(options.data);
|
|
194
|
-
return (
|
|
195
|
-
normalizeSessionTabTarget(options.navigationSummary) ??
|
|
196
|
-
extractSessionTabTargetFromBatchResults(options.data) ??
|
|
197
|
-
commandDataTarget ??
|
|
198
|
-
options.previousTarget
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function batchContainsOnlyReadOnlyDiagnosticTargets(data: unknown): boolean {
|
|
203
|
-
if (!Array.isArray(data) || data.length === 0) {
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
return data.every((item) => {
|
|
207
|
-
if (!isRecord(item)) return false;
|
|
208
|
-
const [command, subcommand] = extractBatchResultCommand(item);
|
|
209
|
-
return isReadOnlyDiagnosticSessionTargetCommand(command, subcommand);
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function getRestoredSessionTabTarget(details: Record<string, unknown>, command: string | undefined, subcommand: string | undefined): SessionTabTarget | undefined {
|
|
214
|
-
if (isReadOnlyDiagnosticSessionTargetCommand(command, subcommand)) {
|
|
215
|
-
return undefined;
|
|
216
|
-
}
|
|
217
|
-
const storedTarget = isRecord(details.sessionTabTarget)
|
|
218
|
-
? normalizeSessionTabTarget({
|
|
219
|
-
title: typeof details.sessionTabTarget.title === "string" ? details.sessionTabTarget.title : undefined,
|
|
220
|
-
url: typeof details.sessionTabTarget.url === "string" ? details.sessionTabTarget.url : undefined,
|
|
221
|
-
})
|
|
222
|
-
: undefined;
|
|
223
|
-
if (command !== "batch") {
|
|
224
|
-
return storedTarget;
|
|
225
|
-
}
|
|
226
|
-
const batchTarget = extractSessionTabTargetFromBatchResults(details.data);
|
|
227
|
-
if (batchTarget) {
|
|
228
|
-
return batchTarget;
|
|
229
|
-
}
|
|
230
|
-
if (isRecord(details.compiledNetworkSourceLookup) || batchContainsOnlyReadOnlyDiagnosticTargets(details.data)) {
|
|
231
|
-
return undefined;
|
|
232
|
-
}
|
|
233
|
-
return storedTarget;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function extractRefSnapshotRefs(data: unknown): Record<string, { isContentEditable?: boolean; isEditable?: boolean; name: string; role: string }> | undefined {
|
|
237
|
-
if (!isRecord(data) || !isRecord(data.refs)) return undefined;
|
|
238
|
-
const snapshotLines = typeof data.snapshot === "string" ? parseSnapshotLines(data.snapshot) : [];
|
|
239
|
-
const lineByRef = new Map(snapshotLines.flatMap((line) => line.ref ? [[line.ref, line.raw] as const] : []));
|
|
240
|
-
const entries = enrichSnapshotRefEntries(getSnapshotRefEntries(data), snapshotLines);
|
|
241
|
-
const refs = Object.fromEntries(entries.flatMap((entry) => {
|
|
242
|
-
if (!/^e\d+$/.test(entry.id) || entry.role.length === 0) return [];
|
|
243
|
-
const isContentEditable = getEditableRefEvidence({ ref: entry.refData, text: lineByRef.get(entry.id) });
|
|
244
|
-
return [[entry.id, { ...(isContentEditable === true ? { isContentEditable: true } : {}), ...(entry.isEditable !== undefined ? { isEditable: entry.isEditable } : {}), name: entry.name, role: entry.role }] as const];
|
|
245
|
-
}));
|
|
246
|
-
return Object.keys(refs).length > 0 ? refs : undefined;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
export function extractRefSnapshotFromData(data: unknown): SessionRefSnapshot | undefined {
|
|
250
|
-
if (!isRecord(data)) return undefined;
|
|
251
|
-
const refs = extractRefSnapshotRefs(data);
|
|
252
|
-
return {
|
|
253
|
-
refIds: isRecord(data.refs) ? Object.keys(data.refs).filter((refId) => /^e\d+$/.test(refId)) : [],
|
|
254
|
-
...(refs ? { refs } : {}),
|
|
255
|
-
target: extractSessionTabTargetFromData(data),
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function getBatchResultFailureText(item: Record<string, unknown>): string | undefined {
|
|
260
|
-
const result = isRecord(item.result) ? item.result : undefined;
|
|
261
|
-
const parts = [item.error, result?.error, typeof item.result === "string" ? item.result : undefined]
|
|
262
|
-
.filter((part): part is string => typeof part === "string" && part.trim().length > 0);
|
|
263
|
-
return parts.length > 0 ? parts.join("\n") : undefined;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export function buildNoActivePageRefSnapshotInvalidation(): SessionRefSnapshotInvalidation {
|
|
267
|
-
return {
|
|
268
|
-
reason: "no-active-page",
|
|
269
|
-
summary: "The latest snapshot for this session reported No active page. Old page-scoped refs are invalid until snapshot -i succeeds.",
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
export function isNoActivePageSnapshotFailure(command: string | undefined, text: string | undefined): boolean {
|
|
274
|
-
return command === "snapshot" && /\bno active page\b/i.test(text ?? "");
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export function extractLatestRefSnapshotStateFromBatchResults(data: unknown): BatchRefSnapshotState | undefined {
|
|
278
|
-
if (!Array.isArray(data)) return undefined;
|
|
279
|
-
let latestState: BatchRefSnapshotState | undefined;
|
|
280
|
-
for (const item of data) {
|
|
281
|
-
if (!isRecord(item)) continue;
|
|
282
|
-
const [name] = extractBatchResultCommand(item);
|
|
283
|
-
if (name !== "snapshot") continue;
|
|
284
|
-
if (item.success === false) {
|
|
285
|
-
if (isNoActivePageSnapshotFailure(name, getBatchResultFailureText(item))) {
|
|
286
|
-
latestState = { invalidation: buildNoActivePageRefSnapshotInvalidation() };
|
|
287
|
-
}
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
const snapshot = extractRefSnapshotFromData(item.result);
|
|
291
|
-
if (snapshot) {
|
|
292
|
-
latestState = { snapshot };
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return latestState;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function getRestoredRefSnapshotInvalidation(details: Record<string, unknown>, command: string | undefined): SessionRefSnapshotInvalidation | undefined {
|
|
299
|
-
const invalidation = isRecord(details.refSnapshotInvalidation) ? details.refSnapshotInvalidation : undefined;
|
|
300
|
-
if (invalidation && invalidation.reason === "no-active-page") {
|
|
301
|
-
return buildNoActivePageRefSnapshotInvalidation();
|
|
302
|
-
}
|
|
303
|
-
const errorText = typeof details.error === "string"
|
|
304
|
-
? details.error
|
|
305
|
-
: typeof details.summary === "string"
|
|
306
|
-
? details.summary
|
|
307
|
-
: undefined;
|
|
308
|
-
return isNoActivePageSnapshotFailure(command, errorText) ? buildNoActivePageRefSnapshotInvalidation() : undefined;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function getRestoredRefSnapshot(details: Record<string, unknown>): SessionRefSnapshot | undefined {
|
|
312
|
-
const refSnapshot = isRecord(details.refSnapshot) ? details.refSnapshot : undefined;
|
|
313
|
-
if (!refSnapshot || !Array.isArray(refSnapshot.refIds)) return undefined;
|
|
314
|
-
const refIds = refSnapshot.refIds.filter((refId): refId is string => typeof refId === "string" && /^e\d+$/.test(refId));
|
|
315
|
-
const refRecord = isRecord(refSnapshot.refs) ? refSnapshot.refs : undefined;
|
|
316
|
-
const refEntries = refRecord
|
|
317
|
-
? Object.fromEntries(refIds.flatMap((refId) => {
|
|
318
|
-
const entry = refRecord[refId];
|
|
319
|
-
if (!isRecord(entry) || typeof entry.name !== "string" || typeof entry.role !== "string") return [];
|
|
320
|
-
const isContentEditable = typeof entry.isContentEditable === "boolean" ? entry.isContentEditable : undefined;
|
|
321
|
-
const isEditable = typeof entry.isEditable === "boolean" ? entry.isEditable : undefined;
|
|
322
|
-
return [[refId, { ...(isContentEditable !== undefined ? { isContentEditable } : {}), ...(isEditable !== undefined ? { isEditable } : {}), name: entry.name, role: entry.role }] as const];
|
|
323
|
-
}))
|
|
324
|
-
: undefined;
|
|
325
|
-
return {
|
|
326
|
-
refIds,
|
|
327
|
-
...(refEntries && Object.keys(refEntries).length > 0 ? { refs: refEntries } : {}),
|
|
328
|
-
target: isRecord(refSnapshot.target)
|
|
329
|
-
? normalizeSessionTabTarget({
|
|
330
|
-
title: typeof refSnapshot.target.title === "string" ? refSnapshot.target.title : undefined,
|
|
331
|
-
url: typeof refSnapshot.target.url === "string" ? refSnapshot.target.url : undefined,
|
|
332
|
-
})
|
|
333
|
-
: undefined,
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
function getLatestTabTargetOrder(targets: Map<string, OrderedSessionTabTarget>): number {
|
|
338
|
-
let latestOrder = 0;
|
|
339
|
-
for (const target of targets.values()) {
|
|
340
|
-
latestOrder = Math.max(latestOrder, target.order);
|
|
341
|
-
}
|
|
342
|
-
return latestOrder;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function getLatestRefStateOrder(
|
|
346
|
-
snapshots: Map<string, OrderedSessionRefSnapshot>,
|
|
347
|
-
invalidations: Map<string, OrderedSessionRefSnapshotInvalidation>,
|
|
348
|
-
): number {
|
|
349
|
-
let latestOrder = 0;
|
|
350
|
-
for (const snapshot of snapshots.values()) latestOrder = Math.max(latestOrder, snapshot.order);
|
|
351
|
-
for (const invalidation of invalidations.values()) latestOrder = Math.max(latestOrder, invalidation.order);
|
|
352
|
-
return latestOrder;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
function shouldApplyTabTargetUpdate(current: { order: number } | undefined, updateOrder: number): boolean {
|
|
356
|
-
return !current || updateOrder >= current.order;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function shouldApplyRefStateUpdate(options: {
|
|
360
|
-
currentInvalidation?: { order: number };
|
|
361
|
-
currentSnapshot?: { order: number };
|
|
362
|
-
updateOrder: number;
|
|
363
|
-
}): boolean {
|
|
364
|
-
const currentOrder = Math.max(options.currentSnapshot?.order ?? 0, options.currentInvalidation?.order ?? 0);
|
|
365
|
-
return options.updateOrder >= currentOrder;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function stripRefSnapshotOrder(snapshot: OrderedSessionRefSnapshot | SessionRefSnapshot | undefined): SessionRefSnapshot | undefined {
|
|
369
|
-
return snapshot ? { refIds: snapshot.refIds, ...(snapshot.refs ? { refs: snapshot.refs } : {}), target: snapshot.target } : undefined;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function stripRefSnapshotInvalidationOrder(invalidation: OrderedSessionRefSnapshotInvalidation | SessionRefSnapshotInvalidation | undefined): SessionRefSnapshotInvalidation | undefined {
|
|
373
|
-
return invalidation ? { reason: invalidation.reason, summary: invalidation.summary } : undefined;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
export class SessionPageState {
|
|
377
|
-
private refSnapshotInvalidations = new Map<string, OrderedSessionRefSnapshotInvalidation>();
|
|
378
|
-
private refSnapshots = new Map<string, OrderedSessionRefSnapshot>();
|
|
379
|
-
private tabPinningReasons = new Map<string, SessionTabPinningReason>();
|
|
380
|
-
private tabTargets = new Map<string, OrderedSessionTabTarget>();
|
|
381
|
-
private updateOrder = 0;
|
|
382
|
-
|
|
383
|
-
static fromBranch(branch: unknown[]): SessionPageState {
|
|
384
|
-
const state = new SessionPageState();
|
|
385
|
-
let restoredOrder = 0;
|
|
386
|
-
for (const entry of branch) {
|
|
387
|
-
if (!isRecord(entry) || entry.type !== "message") continue;
|
|
388
|
-
const message = isRecord(entry.message) ? entry.message : undefined;
|
|
389
|
-
if (!message || message.toolName !== "agent_browser") continue;
|
|
390
|
-
const details = isRecord(message.details) ? message.details : undefined;
|
|
391
|
-
if (!details) continue;
|
|
392
|
-
const sessionName = typeof details.sessionName === "string" ? details.sessionName : undefined;
|
|
393
|
-
if (!sessionName) continue;
|
|
394
|
-
const command = typeof details.command === "string" ? details.command : undefined;
|
|
395
|
-
const subcommand = typeof details.subcommand === "string" ? details.subcommand : undefined;
|
|
396
|
-
if (isCloseCommand(command) && message.isError !== true) {
|
|
397
|
-
restoredOrder += 1;
|
|
398
|
-
state.clearSession(sessionName);
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
const tabTarget = getRestoredSessionTabTarget(details, command, subcommand);
|
|
402
|
-
const refSnapshotInvalidation = getRestoredRefSnapshotInvalidation(details, command);
|
|
403
|
-
const refSnapshot = refSnapshotInvalidation ? undefined : getRestoredRefSnapshot(details);
|
|
404
|
-
if (!tabTarget && !refSnapshotInvalidation && !refSnapshot) continue;
|
|
405
|
-
restoredOrder += 1;
|
|
406
|
-
if (tabTarget) state.tabTargets.set(sessionName, { order: restoredOrder, target: tabTarget });
|
|
407
|
-
if (refSnapshotInvalidation) {
|
|
408
|
-
state.refSnapshots.delete(sessionName);
|
|
409
|
-
state.refSnapshotInvalidations.set(sessionName, { ...refSnapshotInvalidation, order: restoredOrder });
|
|
410
|
-
} else if (refSnapshot) {
|
|
411
|
-
state.refSnapshotInvalidations.delete(sessionName);
|
|
412
|
-
state.refSnapshots.set(sessionName, { ...refSnapshot, order: restoredOrder });
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
state.updateOrder = Math.max(
|
|
416
|
-
restoredOrder,
|
|
417
|
-
getLatestTabTargetOrder(state.tabTargets),
|
|
418
|
-
getLatestRefStateOrder(state.refSnapshots, state.refSnapshotInvalidations),
|
|
419
|
-
);
|
|
420
|
-
state.tabPinningReasons = new Map([...state.tabTargets.keys()].map((sessionName) => [sessionName, "restore"]));
|
|
421
|
-
return state;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
beginUpdate(): SessionPageStateUpdateToken {
|
|
425
|
-
this.updateOrder += 1;
|
|
426
|
-
return this.updateOrder as SessionPageStateUpdateToken;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
reset(): void {
|
|
430
|
-
this.refSnapshotInvalidations = new Map<string, OrderedSessionRefSnapshotInvalidation>();
|
|
431
|
-
this.refSnapshots = new Map<string, OrderedSessionRefSnapshot>();
|
|
432
|
-
this.tabPinningReasons = new Map<string, SessionTabPinningReason>();
|
|
433
|
-
this.tabTargets = new Map<string, OrderedSessionTabTarget>();
|
|
434
|
-
this.updateOrder = 0;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
get(sessionName: string | undefined): SessionPageStateView {
|
|
438
|
-
if (!sessionName) return {};
|
|
439
|
-
return {
|
|
440
|
-
pinningReason: this.tabPinningReasons.get(sessionName),
|
|
441
|
-
refSnapshot: stripRefSnapshotOrder(this.refSnapshots.get(sessionName)),
|
|
442
|
-
refSnapshotInvalidation: stripRefSnapshotInvalidationOrder(this.refSnapshotInvalidations.get(sessionName)),
|
|
443
|
-
tabTarget: this.tabTargets.get(sessionName)?.target,
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
applyTabTarget(options: {
|
|
448
|
-
sessionName: string;
|
|
449
|
-
target: SessionTabTarget;
|
|
450
|
-
update: SessionPageStateUpdateToken;
|
|
451
|
-
}): SessionPageStateUpdateResult {
|
|
452
|
-
const current = this.tabTargets.get(options.sessionName);
|
|
453
|
-
if (!shouldApplyTabTargetUpdate(current, options.update)) {
|
|
454
|
-
return { ...this.get(options.sessionName), applied: false, stale: true };
|
|
455
|
-
}
|
|
456
|
-
this.tabTargets.set(options.sessionName, { order: options.update, target: options.target });
|
|
457
|
-
return { ...this.get(options.sessionName), applied: true };
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
applyRefSnapshot(options: {
|
|
461
|
-
fallbackTarget?: SessionTabTarget;
|
|
462
|
-
sessionName: string;
|
|
463
|
-
snapshot: SessionRefSnapshot;
|
|
464
|
-
update: SessionPageStateUpdateToken;
|
|
465
|
-
}): SessionPageStateUpdateResult {
|
|
466
|
-
if (!shouldApplyRefStateUpdate({
|
|
467
|
-
currentInvalidation: this.refSnapshotInvalidations.get(options.sessionName),
|
|
468
|
-
currentSnapshot: this.refSnapshots.get(options.sessionName),
|
|
469
|
-
updateOrder: options.update,
|
|
470
|
-
})) {
|
|
471
|
-
return { ...this.get(options.sessionName), applied: false, stale: true };
|
|
472
|
-
}
|
|
473
|
-
const snapshot = { ...options.snapshot, target: options.snapshot.target ?? options.fallbackTarget };
|
|
474
|
-
this.refSnapshotInvalidations.delete(options.sessionName);
|
|
475
|
-
this.refSnapshots.set(options.sessionName, { ...snapshot, order: options.update });
|
|
476
|
-
return { ...this.get(options.sessionName), applied: true };
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
applyRefSnapshotInvalidation(options: {
|
|
480
|
-
invalidation: SessionRefSnapshotInvalidation;
|
|
481
|
-
sessionName: string;
|
|
482
|
-
update: SessionPageStateUpdateToken;
|
|
483
|
-
}): SessionPageStateUpdateResult {
|
|
484
|
-
if (!shouldApplyRefStateUpdate({
|
|
485
|
-
currentInvalidation: this.refSnapshotInvalidations.get(options.sessionName),
|
|
486
|
-
currentSnapshot: this.refSnapshots.get(options.sessionName),
|
|
487
|
-
updateOrder: options.update,
|
|
488
|
-
})) {
|
|
489
|
-
return { ...this.get(options.sessionName), applied: false, stale: true };
|
|
490
|
-
}
|
|
491
|
-
this.refSnapshots.delete(options.sessionName);
|
|
492
|
-
this.refSnapshotInvalidations.set(options.sessionName, { ...options.invalidation, order: options.update });
|
|
493
|
-
return { ...this.get(options.sessionName), applied: true };
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
clearSession(sessionName: string): void {
|
|
497
|
-
this.refSnapshotInvalidations.delete(sessionName);
|
|
498
|
-
this.refSnapshots.delete(sessionName);
|
|
499
|
-
this.tabPinningReasons.delete(sessionName);
|
|
500
|
-
this.tabTargets.delete(sessionName);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
markPinning(sessionName: string, reason: SessionTabPinningReason): void {
|
|
504
|
-
this.tabPinningReasons.set(sessionName, reason);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
clearRestorePinning(sessionName: string): void {
|
|
508
|
-
if (this.tabPinningReasons.get(sessionName) === "restore") {
|
|
509
|
-
this.tabPinningReasons.delete(sessionName);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Build compact JSON-schema string enums without importing pi runtime helpers.
|
|
3
|
-
* Responsibilities: Mirror pi-ai StringEnum's `{ type: "string", enum: [...] }` shape while keeping extension startup imports light.
|
|
4
|
-
* Scope: Schema construction only.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { JsonSchema, type TSchemaOptions, type TUnsafe } from "./json-schema.js";
|
|
8
|
-
|
|
9
|
-
export type StringEnumBuilder = typeof StringEnum;
|
|
10
|
-
|
|
11
|
-
export function StringEnum<const Values extends readonly string[]>(
|
|
12
|
-
values: Values,
|
|
13
|
-
options?: TSchemaOptions,
|
|
14
|
-
): TUnsafe<Values[number]> {
|
|
15
|
-
return JsonSchema.Unsafe<Values[number]>({
|
|
16
|
-
type: "string",
|
|
17
|
-
enum: [...values],
|
|
18
|
-
...options,
|
|
19
|
-
});
|
|
20
|
-
}
|