@agenticmail/enterprise 0.5.78 → 0.5.79
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/dist/chunk-7RNT4O5T.js +15198 -0
- package/dist/chunk-AGFOJCSB.js +2191 -0
- package/dist/chunk-F4GSFCM3.js +898 -0
- package/dist/chunk-PZA7YOJE.js +898 -0
- package/dist/chunk-Q3V7VZFQ.js +2191 -0
- package/dist/chunk-RRFB6G6M.js +15198 -0
- package/dist/chunk-VX3VFMVB.js +409 -0
- package/dist/cli.js +1 -1
- package/dist/dashboard/pages/agent-detail.js +313 -1
- package/dist/index.js +4 -3
- package/dist/pw-ai-KPETTB25.js +2212 -0
- package/dist/routes-PDHMCIXU.js +6676 -0
- package/dist/runtime-7HW4GX5L.js +48 -0
- package/dist/runtime-XXDCZZIK.js +48 -0
- package/dist/server-FMP4BFGW.js +12 -0
- package/dist/server-JRHDUNII.js +12 -0
- package/dist/setup-O5FPRLK4.js +20 -0
- package/dist/setup-S4Z4PPIJ.js +20 -0
- package/package.json +15 -2
- package/src/agent-tools/common.ts +25 -0
- package/src/agent-tools/index.ts +3 -0
- package/src/agent-tools/schema/typebox.ts +25 -0
- package/src/agent-tools/tools/browser-tool.schema.ts +112 -0
- package/src/agent-tools/tools/browser-tool.ts +388 -0
- package/src/agent-tools/tools/gateway.ts +126 -0
- package/src/agent-tools/tools/nodes-utils.ts +80 -0
- package/src/browser/bridge-auth-registry.ts +34 -0
- package/src/browser/bridge-server.ts +93 -0
- package/src/browser/cdp.helpers.ts +180 -0
- package/src/browser/cdp.ts +466 -0
- package/src/browser/chrome.executables.ts +625 -0
- package/src/browser/chrome.profile-decoration.ts +198 -0
- package/src/browser/chrome.ts +349 -0
- package/src/browser/client-actions-core.ts +259 -0
- package/src/browser/client-actions-observe.ts +184 -0
- package/src/browser/client-actions-state.ts +284 -0
- package/src/browser/client-actions-types.ts +16 -0
- package/src/browser/client-actions-url.ts +11 -0
- package/src/browser/client-actions.ts +4 -0
- package/src/browser/client-fetch.ts +253 -0
- package/src/browser/client.ts +337 -0
- package/src/browser/config.ts +296 -0
- package/src/browser/constants.ts +8 -0
- package/src/browser/control-auth.ts +94 -0
- package/src/browser/control-service.ts +81 -0
- package/src/browser/csrf.ts +87 -0
- package/src/browser/enterprise-compat.ts +518 -0
- package/src/browser/extension-relay.ts +834 -0
- package/src/browser/http-auth.ts +63 -0
- package/src/browser/navigation-guard.ts +50 -0
- package/src/browser/paths.ts +49 -0
- package/src/browser/profiles-service.ts +187 -0
- package/src/browser/profiles.ts +113 -0
- package/src/browser/proxy-files.ts +41 -0
- package/src/browser/pw-ai-module.ts +52 -0
- package/src/browser/pw-ai-state.ts +9 -0
- package/src/browser/pw-ai.ts +65 -0
- package/src/browser/pw-role-snapshot.ts +434 -0
- package/src/browser/pw-session.ts +810 -0
- package/src/browser/pw-tools-core.activity.ts +68 -0
- package/src/browser/pw-tools-core.downloads.ts +281 -0
- package/src/browser/pw-tools-core.interactions.ts +646 -0
- package/src/browser/pw-tools-core.responses.ts +124 -0
- package/src/browser/pw-tools-core.shared.ts +70 -0
- package/src/browser/pw-tools-core.snapshot.ts +213 -0
- package/src/browser/pw-tools-core.state.ts +209 -0
- package/src/browser/pw-tools-core.storage.ts +128 -0
- package/src/browser/pw-tools-core.trace.ts +37 -0
- package/src/browser/pw-tools-core.ts +8 -0
- package/src/browser/resolved-config-refresh.ts +59 -0
- package/src/browser/routes/agent.act.shared.ts +52 -0
- package/src/browser/routes/agent.act.ts +575 -0
- package/src/browser/routes/agent.debug.ts +149 -0
- package/src/browser/routes/agent.shared.ts +143 -0
- package/src/browser/routes/agent.snapshot.ts +333 -0
- package/src/browser/routes/agent.storage.ts +451 -0
- package/src/browser/routes/agent.ts +13 -0
- package/src/browser/routes/basic.ts +202 -0
- package/src/browser/routes/dispatcher.ts +126 -0
- package/src/browser/routes/index.ts +11 -0
- package/src/browser/routes/path-output.ts +1 -0
- package/src/browser/routes/tabs.ts +217 -0
- package/src/browser/routes/types.ts +26 -0
- package/src/browser/routes/utils.ts +73 -0
- package/src/browser/screenshot.ts +54 -0
- package/src/browser/server-context.ts +688 -0
- package/src/browser/server-context.types.ts +65 -0
- package/src/browser/server-lifecycle.ts +48 -0
- package/src/browser/server-middleware.ts +37 -0
- package/src/browser/server.ts +110 -0
- package/src/browser/target-id.ts +30 -0
- package/src/browser/trash.ts +21 -0
- package/src/dashboard/pages/agent-detail.js +313 -1
- package/src/engine/agent-routes.ts +46 -0
- package/src/security/external-content.ts +299 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
export type RoleRef = {
|
|
2
|
+
role: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
/** Index used only when role+name duplicates exist. */
|
|
5
|
+
nth?: number;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type RoleRefMap = Record<string, RoleRef>;
|
|
9
|
+
|
|
10
|
+
export type RoleSnapshotStats = {
|
|
11
|
+
lines: number;
|
|
12
|
+
chars: number;
|
|
13
|
+
refs: number;
|
|
14
|
+
interactive: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type RoleSnapshotOptions = {
|
|
18
|
+
/** Only include interactive elements (buttons, links, inputs, etc.). */
|
|
19
|
+
interactive?: boolean;
|
|
20
|
+
/** Maximum depth to include (0 = root only). */
|
|
21
|
+
maxDepth?: number;
|
|
22
|
+
/** Remove unnamed structural elements and empty branches. */
|
|
23
|
+
compact?: boolean;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const INTERACTIVE_ROLES = new Set([
|
|
27
|
+
"button",
|
|
28
|
+
"link",
|
|
29
|
+
"textbox",
|
|
30
|
+
"checkbox",
|
|
31
|
+
"radio",
|
|
32
|
+
"combobox",
|
|
33
|
+
"listbox",
|
|
34
|
+
"menuitem",
|
|
35
|
+
"menuitemcheckbox",
|
|
36
|
+
"menuitemradio",
|
|
37
|
+
"option",
|
|
38
|
+
"searchbox",
|
|
39
|
+
"slider",
|
|
40
|
+
"spinbutton",
|
|
41
|
+
"switch",
|
|
42
|
+
"tab",
|
|
43
|
+
"treeitem",
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
const CONTENT_ROLES = new Set([
|
|
47
|
+
"heading",
|
|
48
|
+
"cell",
|
|
49
|
+
"gridcell",
|
|
50
|
+
"columnheader",
|
|
51
|
+
"rowheader",
|
|
52
|
+
"listitem",
|
|
53
|
+
"article",
|
|
54
|
+
"region",
|
|
55
|
+
"main",
|
|
56
|
+
"navigation",
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const STRUCTURAL_ROLES = new Set([
|
|
60
|
+
"generic",
|
|
61
|
+
"group",
|
|
62
|
+
"list",
|
|
63
|
+
"table",
|
|
64
|
+
"row",
|
|
65
|
+
"rowgroup",
|
|
66
|
+
"grid",
|
|
67
|
+
"treegrid",
|
|
68
|
+
"menu",
|
|
69
|
+
"menubar",
|
|
70
|
+
"toolbar",
|
|
71
|
+
"tablist",
|
|
72
|
+
"tree",
|
|
73
|
+
"directory",
|
|
74
|
+
"document",
|
|
75
|
+
"application",
|
|
76
|
+
"presentation",
|
|
77
|
+
"none",
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
export function getRoleSnapshotStats(snapshot: string, refs: RoleRefMap): RoleSnapshotStats {
|
|
81
|
+
const interactive = Object.values(refs).filter((r) => INTERACTIVE_ROLES.has(r.role)).length;
|
|
82
|
+
return {
|
|
83
|
+
lines: snapshot.split("\n").length,
|
|
84
|
+
chars: snapshot.length,
|
|
85
|
+
refs: Object.keys(refs).length,
|
|
86
|
+
interactive,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getIndentLevel(line: string): number {
|
|
91
|
+
const match = line.match(/^(\s*)/);
|
|
92
|
+
return match ? Math.floor(match[1].length / 2) : 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function matchInteractiveSnapshotLine(
|
|
96
|
+
line: string,
|
|
97
|
+
options: RoleSnapshotOptions,
|
|
98
|
+
): { roleRaw: string; role: string; name?: string; suffix: string } | null {
|
|
99
|
+
const depth = getIndentLevel(line);
|
|
100
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
104
|
+
if (!match) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
const [, , roleRaw, name, suffix] = match;
|
|
108
|
+
if (roleRaw.startsWith("/")) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const role = roleRaw.toLowerCase();
|
|
112
|
+
return {
|
|
113
|
+
roleRaw,
|
|
114
|
+
role,
|
|
115
|
+
...(name ? { name } : {}),
|
|
116
|
+
suffix,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
type RoleNameTracker = {
|
|
121
|
+
counts: Map<string, number>;
|
|
122
|
+
refsByKey: Map<string, string[]>;
|
|
123
|
+
getKey: (role: string, name?: string) => string;
|
|
124
|
+
getNextIndex: (role: string, name?: string) => number;
|
|
125
|
+
trackRef: (role: string, name: string | undefined, ref: string) => void;
|
|
126
|
+
getDuplicateKeys: () => Set<string>;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
function createRoleNameTracker(): RoleNameTracker {
|
|
130
|
+
const counts = new Map<string, number>();
|
|
131
|
+
const refsByKey = new Map<string, string[]>();
|
|
132
|
+
return {
|
|
133
|
+
counts,
|
|
134
|
+
refsByKey,
|
|
135
|
+
getKey(role: string, name?: string) {
|
|
136
|
+
return `${role}:${name ?? ""}`;
|
|
137
|
+
},
|
|
138
|
+
getNextIndex(role: string, name?: string) {
|
|
139
|
+
const key = this.getKey(role, name);
|
|
140
|
+
const current = counts.get(key) ?? 0;
|
|
141
|
+
counts.set(key, current + 1);
|
|
142
|
+
return current;
|
|
143
|
+
},
|
|
144
|
+
trackRef(role: string, name: string | undefined, ref: string) {
|
|
145
|
+
const key = this.getKey(role, name);
|
|
146
|
+
const list = refsByKey.get(key) ?? [];
|
|
147
|
+
list.push(ref);
|
|
148
|
+
refsByKey.set(key, list);
|
|
149
|
+
},
|
|
150
|
+
getDuplicateKeys() {
|
|
151
|
+
const out = new Set<string>();
|
|
152
|
+
for (const [key, refs] of refsByKey) {
|
|
153
|
+
if (refs.length > 1) {
|
|
154
|
+
out.add(key);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function removeNthFromNonDuplicates(refs: RoleRefMap, tracker: RoleNameTracker) {
|
|
163
|
+
const duplicates = tracker.getDuplicateKeys();
|
|
164
|
+
for (const [ref, data] of Object.entries(refs)) {
|
|
165
|
+
const key = tracker.getKey(data.role, data.name);
|
|
166
|
+
if (!duplicates.has(key)) {
|
|
167
|
+
delete refs[ref]?.nth;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function compactTree(tree: string) {
|
|
173
|
+
const lines = tree.split("\n");
|
|
174
|
+
const result: string[] = [];
|
|
175
|
+
|
|
176
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
177
|
+
const line = lines[i];
|
|
178
|
+
if (line.includes("[ref=")) {
|
|
179
|
+
result.push(line);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (line.includes(":") && !line.trimEnd().endsWith(":")) {
|
|
183
|
+
result.push(line);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const currentIndent = getIndentLevel(line);
|
|
188
|
+
let hasRelevantChildren = false;
|
|
189
|
+
for (let j = i + 1; j < lines.length; j += 1) {
|
|
190
|
+
const childIndent = getIndentLevel(lines[j]);
|
|
191
|
+
if (childIndent <= currentIndent) {
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
if (lines[j]?.includes("[ref=")) {
|
|
195
|
+
hasRelevantChildren = true;
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (hasRelevantChildren) {
|
|
200
|
+
result.push(line);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return result.join("\n");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function processLine(
|
|
208
|
+
line: string,
|
|
209
|
+
refs: RoleRefMap,
|
|
210
|
+
options: RoleSnapshotOptions,
|
|
211
|
+
tracker: RoleNameTracker,
|
|
212
|
+
nextRef: () => string,
|
|
213
|
+
): string | null {
|
|
214
|
+
const depth = getIndentLevel(line);
|
|
215
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
220
|
+
if (!match) {
|
|
221
|
+
return options.interactive ? null : line;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const [, prefix, roleRaw, name, suffix] = match;
|
|
225
|
+
if (roleRaw.startsWith("/")) {
|
|
226
|
+
return options.interactive ? null : line;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const role = roleRaw.toLowerCase();
|
|
230
|
+
const isInteractive = INTERACTIVE_ROLES.has(role);
|
|
231
|
+
const isContent = CONTENT_ROLES.has(role);
|
|
232
|
+
const isStructural = STRUCTURAL_ROLES.has(role);
|
|
233
|
+
|
|
234
|
+
if (options.interactive && !isInteractive) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
if (options.compact && isStructural && !name) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const shouldHaveRef = isInteractive || (isContent && name);
|
|
242
|
+
if (!shouldHaveRef) {
|
|
243
|
+
return line;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const ref = nextRef();
|
|
247
|
+
const nth = tracker.getNextIndex(role, name);
|
|
248
|
+
tracker.trackRef(role, name, ref);
|
|
249
|
+
refs[ref] = {
|
|
250
|
+
role,
|
|
251
|
+
name,
|
|
252
|
+
nth,
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
let enhanced = `${prefix}${roleRaw}`;
|
|
256
|
+
if (name) {
|
|
257
|
+
enhanced += ` "${name}"`;
|
|
258
|
+
}
|
|
259
|
+
enhanced += ` [ref=${ref}]`;
|
|
260
|
+
if (nth > 0) {
|
|
261
|
+
enhanced += ` [nth=${nth}]`;
|
|
262
|
+
}
|
|
263
|
+
if (suffix) {
|
|
264
|
+
enhanced += suffix;
|
|
265
|
+
}
|
|
266
|
+
return enhanced;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function parseRoleRef(raw: string): string | null {
|
|
270
|
+
const trimmed = raw.trim();
|
|
271
|
+
if (!trimmed) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
const normalized = trimmed.startsWith("@")
|
|
275
|
+
? trimmed.slice(1)
|
|
276
|
+
: trimmed.startsWith("ref=")
|
|
277
|
+
? trimmed.slice(4)
|
|
278
|
+
: trimmed;
|
|
279
|
+
return /^e\d+$/.test(normalized) ? normalized : null;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function buildRoleSnapshotFromAriaSnapshot(
|
|
283
|
+
ariaSnapshot: string,
|
|
284
|
+
options: RoleSnapshotOptions = {},
|
|
285
|
+
): { snapshot: string; refs: RoleRefMap } {
|
|
286
|
+
const lines = ariaSnapshot.split("\n");
|
|
287
|
+
const refs: RoleRefMap = {};
|
|
288
|
+
const tracker = createRoleNameTracker();
|
|
289
|
+
|
|
290
|
+
let counter = 0;
|
|
291
|
+
const nextRef = () => {
|
|
292
|
+
counter += 1;
|
|
293
|
+
return `e${counter}`;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
if (options.interactive) {
|
|
297
|
+
const result: string[] = [];
|
|
298
|
+
for (const line of lines) {
|
|
299
|
+
const parsed = matchInteractiveSnapshotLine(line, options);
|
|
300
|
+
if (!parsed) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const { roleRaw, role, name, suffix } = parsed;
|
|
304
|
+
if (!INTERACTIVE_ROLES.has(role)) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const ref = nextRef();
|
|
309
|
+
const nth = tracker.getNextIndex(role, name);
|
|
310
|
+
tracker.trackRef(role, name, ref);
|
|
311
|
+
refs[ref] = {
|
|
312
|
+
role,
|
|
313
|
+
name,
|
|
314
|
+
nth,
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
let enhanced = `- ${roleRaw}`;
|
|
318
|
+
if (name) {
|
|
319
|
+
enhanced += ` "${name}"`;
|
|
320
|
+
}
|
|
321
|
+
enhanced += ` [ref=${ref}]`;
|
|
322
|
+
if (nth > 0) {
|
|
323
|
+
enhanced += ` [nth=${nth}]`;
|
|
324
|
+
}
|
|
325
|
+
if (suffix.includes("[")) {
|
|
326
|
+
enhanced += suffix;
|
|
327
|
+
}
|
|
328
|
+
result.push(enhanced);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
removeNthFromNonDuplicates(refs, tracker);
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
snapshot: result.join("\n") || "(no interactive elements)",
|
|
335
|
+
refs,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const result: string[] = [];
|
|
340
|
+
for (const line of lines) {
|
|
341
|
+
const processed = processLine(line, refs, options, tracker, nextRef);
|
|
342
|
+
if (processed !== null) {
|
|
343
|
+
result.push(processed);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
removeNthFromNonDuplicates(refs, tracker);
|
|
348
|
+
|
|
349
|
+
const tree = result.join("\n") || "(empty)";
|
|
350
|
+
return {
|
|
351
|
+
snapshot: options.compact ? compactTree(tree) : tree,
|
|
352
|
+
refs,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function parseAiSnapshotRef(suffix: string): string | null {
|
|
357
|
+
const match = suffix.match(/\[ref=(e\d+)\]/i);
|
|
358
|
+
return match ? match[1] : null;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Build a role snapshot from Playwright's AI snapshot output while preserving Playwright's own
|
|
363
|
+
* aria-ref ids (e.g. ref=e13). This makes the refs self-resolving across calls.
|
|
364
|
+
*/
|
|
365
|
+
export function buildRoleSnapshotFromAiSnapshot(
|
|
366
|
+
aiSnapshot: string,
|
|
367
|
+
options: RoleSnapshotOptions = {},
|
|
368
|
+
): { snapshot: string; refs: RoleRefMap } {
|
|
369
|
+
const lines = String(aiSnapshot ?? "").split("\n");
|
|
370
|
+
const refs: RoleRefMap = {};
|
|
371
|
+
|
|
372
|
+
if (options.interactive) {
|
|
373
|
+
const out: string[] = [];
|
|
374
|
+
for (const line of lines) {
|
|
375
|
+
const parsed = matchInteractiveSnapshotLine(line, options);
|
|
376
|
+
if (!parsed) {
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
const { roleRaw, role, name, suffix } = parsed;
|
|
380
|
+
if (!INTERACTIVE_ROLES.has(role)) {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const ref = parseAiSnapshotRef(suffix);
|
|
384
|
+
if (!ref) {
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
refs[ref] = { role, ...(name ? { name } : {}) };
|
|
388
|
+
out.push(`- ${roleRaw}${name ? ` "${name}"` : ""}${suffix}`);
|
|
389
|
+
}
|
|
390
|
+
return {
|
|
391
|
+
snapshot: out.join("\n") || "(no interactive elements)",
|
|
392
|
+
refs,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const out: string[] = [];
|
|
397
|
+
for (const line of lines) {
|
|
398
|
+
const depth = getIndentLevel(line);
|
|
399
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
404
|
+
if (!match) {
|
|
405
|
+
out.push(line);
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
const [, , roleRaw, name, suffix] = match;
|
|
409
|
+
if (roleRaw.startsWith("/")) {
|
|
410
|
+
out.push(line);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const role = roleRaw.toLowerCase();
|
|
415
|
+
const isStructural = STRUCTURAL_ROLES.has(role);
|
|
416
|
+
|
|
417
|
+
if (options.compact && isStructural && !name) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const ref = parseAiSnapshotRef(suffix);
|
|
422
|
+
if (ref) {
|
|
423
|
+
refs[ref] = { role, ...(name ? { name } : {}) };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
out.push(line);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const tree = out.join("\n") || "(empty)";
|
|
430
|
+
return {
|
|
431
|
+
snapshot: options.compact ? compactTree(tree) : tree,
|
|
432
|
+
refs,
|
|
433
|
+
};
|
|
434
|
+
}
|