@oh-my-pi/pi-coding-agent 16.1.9 → 16.1.11
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 +46 -0
- package/dist/cli.js +3455 -3430
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/edit/streaming.d.ts +5 -5
- package/dist/types/export/html/index.d.ts +31 -2
- package/dist/types/export/html/web-palette.d.ts +117 -0
- package/dist/types/hindsight/content.d.ts +7 -0
- package/dist/types/hindsight/transcript.d.ts +1 -1
- package/dist/types/modes/components/hook-editor.d.ts +2 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +0 -1
- package/dist/types/modes/interactive-mode.d.ts +5 -0
- package/dist/types/modes/types.d.ts +17 -0
- package/dist/types/modes/utils/keybinding-matchers.d.ts +13 -0
- package/dist/types/sdk.d.ts +1 -0
- package/dist/types/session/agent-session.d.ts +4 -0
- package/dist/types/session/session-context.d.ts +2 -0
- package/dist/types/session/session-entries.d.ts +6 -0
- package/dist/types/session/session-manager.d.ts +2 -1
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/tools/acp-bridge.d.ts +29 -0
- package/dist/types/tools/browser/aria/aria-snapshot.d.ts +39 -0
- package/dist/types/tools/browser/cmux/cmux-tab.d.ts +10 -0
- package/dist/types/tools/browser/tab-worker.d.ts +20 -0
- package/dist/types/tools/browser.d.ts +1 -0
- package/dist/types/tools/find.d.ts +1 -2
- package/dist/types/tools/write.d.ts +1 -2
- package/dist/types/utils/image-loading.d.ts +4 -3
- package/dist/types/utils/jj.d.ts +25 -0
- package/dist/types/utils/title-generator.d.ts +0 -2
- package/package.json +12 -12
- package/scripts/generate-aria-snapshot.ts +134 -0
- package/scripts/generate-share-viewer.ts +4 -2
- package/src/autoresearch/git.ts +12 -0
- package/src/config/settings-schema.ts +12 -0
- package/src/discovery/opencode.ts +47 -4
- package/src/edit/hashline/filesystem.ts +8 -0
- package/src/edit/modes/patch.ts +18 -2
- package/src/edit/modes/replace.ts +13 -10
- package/src/edit/streaming.ts +5 -5
- package/src/export/html/index.ts +50 -8
- package/src/export/html/web-palette.ts +142 -0
- package/src/hindsight/backend.ts +4 -4
- package/src/hindsight/content.ts +17 -1
- package/src/hindsight/transcript.ts +2 -2
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/modes/components/agent-dashboard.ts +8 -8
- package/src/modes/components/hook-editor.ts +13 -10
- package/src/modes/components/session-selector.ts +3 -0
- package/src/modes/controllers/event-controller.ts +29 -5
- package/src/modes/controllers/extension-ui-controller.ts +6 -2
- package/src/modes/controllers/selector-controller.ts +3 -5
- package/src/modes/interactive-mode.ts +69 -29
- package/src/modes/theme/dark.json +1 -1
- package/src/modes/types.ts +18 -0
- package/src/modes/utils/keybinding-matchers.ts +36 -1
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/system/project-prompt.md +2 -0
- package/src/prompts/system/system-prompt.md +0 -1
- package/src/prompts/tools/browser.md +5 -2
- package/src/sdk.ts +20 -2
- package/src/session/agent-session.ts +38 -14
- package/src/session/session-context.ts +5 -0
- package/src/session/session-entries.ts +6 -0
- package/src/session/session-manager.ts +3 -1
- package/src/system-prompt.ts +15 -3
- package/src/task/worktree.ts +12 -4
- package/src/thinking.ts +1 -1
- package/src/tools/acp-bridge.ts +66 -0
- package/src/tools/bash.ts +3 -3
- package/src/tools/browser/aria/aria-snapshot.bundle.txt +7 -0
- package/src/tools/browser/aria/aria-snapshot.ts +103 -0
- package/src/tools/browser/cmux/cmux-tab.ts +73 -1
- package/src/tools/browser/tab-worker.ts +242 -47
- package/src/tools/browser.ts +5 -0
- package/src/tools/find.ts +1 -2
- package/src/tools/index.ts +1 -1
- package/src/tools/write.ts +3 -27
- package/src/utils/git.ts +3 -2
- package/src/utils/image-loading.ts +6 -3
- package/src/utils/jj.ts +47 -0
- package/src/utils/title-generator.ts +31 -99
|
@@ -210,7 +210,7 @@ import { resolveMemoryBackend } from "../memory-backend";
|
|
|
210
210
|
import { shutdownMnemopiEmbedClient } from "../mnemopi/embed-client";
|
|
211
211
|
import { getMnemopiSessionState, type MnemopiSessionState, setMnemopiSessionState } from "../mnemopi/state";
|
|
212
212
|
import { containsOrchestrate, ORCHESTRATE_NOTICE } from "../modes/orchestrate";
|
|
213
|
-
import {
|
|
213
|
+
import { theme } from "../modes/theme/theme";
|
|
214
214
|
import { parseTurnBudget } from "../modes/turn-budget";
|
|
215
215
|
import { containsUltrathink, ULTRATHINK_NOTICE } from "../modes/ultrathink";
|
|
216
216
|
import { computeNonMessageBreakdown, computeNonMessageTokens } from "../modes/utils/context-usage";
|
|
@@ -477,6 +477,8 @@ export interface AgentSessionConfig {
|
|
|
477
477
|
modelRegistry: ModelRegistry;
|
|
478
478
|
/** Tool registry for LSP and settings */
|
|
479
479
|
toolRegistry?: Map<string, AgentTool>;
|
|
480
|
+
/** Tool names whose current registry entry is still the built-in implementation. */
|
|
481
|
+
builtInToolNames?: Iterable<string>;
|
|
480
482
|
/** Current session pre-LLM message transform pipeline */
|
|
481
483
|
transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => AgentMessage[] | Promise<AgentMessage[]>;
|
|
482
484
|
/** Provider payload hook used by the active session request path */
|
|
@@ -1290,6 +1292,7 @@ export class AgentSession {
|
|
|
1290
1292
|
// Generic tool discovery (covers built-in + MCP + extension when tools.discoveryMode === "all")
|
|
1291
1293
|
#discoverableToolSearchIndex: DiscoverableToolSearchIndex | null = null;
|
|
1292
1294
|
#selectedDiscoveredToolNames = new Set<string>();
|
|
1295
|
+
#builtInToolNames = new Set<string>();
|
|
1293
1296
|
#rpcHostToolNames = new Set<string>();
|
|
1294
1297
|
#defaultSelectedMCPServerNames = new Set<string>();
|
|
1295
1298
|
#defaultSelectedMCPToolNames = new Set<string>();
|
|
@@ -1566,6 +1569,7 @@ export class AgentSession {
|
|
|
1566
1569
|
this.#pruneToolDescriptions = config.pruneToolDescriptions === true;
|
|
1567
1570
|
this.#validateRetryFallbackChains();
|
|
1568
1571
|
this.#toolRegistry = config.toolRegistry ?? new Map();
|
|
1572
|
+
this.#builtInToolNames = new Set(config.builtInToolNames ?? []);
|
|
1569
1573
|
this.#requestedToolNames = config.requestedToolNames;
|
|
1570
1574
|
this.#transformContext = config.transformContext ?? (messages => messages);
|
|
1571
1575
|
this.#onPayload = config.onPayload;
|
|
@@ -4496,6 +4500,11 @@ export class AgentSession {
|
|
|
4496
4500
|
return this.#toolRegistry.get(name);
|
|
4497
4501
|
}
|
|
4498
4502
|
|
|
4503
|
+
/** True when the current registry entry for `name` came from a built-in factory. */
|
|
4504
|
+
hasBuiltInTool(name: string): boolean {
|
|
4505
|
+
return this.#builtInToolNames.has(name);
|
|
4506
|
+
}
|
|
4507
|
+
|
|
4499
4508
|
/**
|
|
4500
4509
|
* Get all configured tool names (built-in via --tools or default, plus custom tools).
|
|
4501
4510
|
*/
|
|
@@ -6835,7 +6844,7 @@ export class AgentSession {
|
|
|
6835
6844
|
this.#pendingNextTurnMessages = [];
|
|
6836
6845
|
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
6837
6846
|
|
|
6838
|
-
this.sessionManager.appendThinkingLevelChange(this.thinkingLevel);
|
|
6847
|
+
this.sessionManager.appendThinkingLevelChange(this.thinkingLevel, this.configuredThinkingLevel());
|
|
6839
6848
|
this.sessionManager.appendServiceTierChange(this.serviceTier ?? null);
|
|
6840
6849
|
if (nextDiscoverySessionToolNames) {
|
|
6841
6850
|
await this.#applyActiveToolsByName(nextDiscoverySessionToolNames, { persistMCPSelection: false });
|
|
@@ -7234,16 +7243,20 @@ export class AgentSession {
|
|
|
7234
7243
|
return;
|
|
7235
7244
|
}
|
|
7236
7245
|
|
|
7246
|
+
const wasAuto = this.#autoThinking;
|
|
7237
7247
|
this.#autoThinking = false;
|
|
7238
7248
|
this.#autoResolvedLevel = undefined;
|
|
7239
7249
|
const effectiveLevel = resolveThinkingLevelForModel(this.model, level);
|
|
7240
|
-
|
|
7250
|
+
// Leaving auto must persist even when the resolved effort is unchanged (e.g.
|
|
7251
|
+
// auto resolved to medium, then the user pins medium): otherwise the latest
|
|
7252
|
+
// session entry keeps `configured: "auto"` and resume re-enables auto.
|
|
7253
|
+
const isChanging = wasAuto || effectiveLevel !== this.#thinkingLevel;
|
|
7241
7254
|
|
|
7242
7255
|
this.#thinkingLevel = effectiveLevel;
|
|
7243
7256
|
this.#applyThinkingLevelToAgent(effectiveLevel);
|
|
7244
7257
|
|
|
7245
7258
|
if (isChanging) {
|
|
7246
|
-
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
7259
|
+
this.sessionManager.appendThinkingLevelChange(effectiveLevel, effectiveLevel);
|
|
7247
7260
|
if (persist && effectiveLevel !== undefined && effectiveLevel !== ThinkingLevel.Off) {
|
|
7248
7261
|
this.settings.set("defaultThinkingLevel", effectiveLevel);
|
|
7249
7262
|
}
|
|
@@ -7332,7 +7345,7 @@ export class AgentSession {
|
|
|
7332
7345
|
this.#thinkingLevel = effort;
|
|
7333
7346
|
this.#applyThinkingLevelToAgent(effort);
|
|
7334
7347
|
if (shouldPersistResolution) {
|
|
7335
|
-
this.sessionManager.appendThinkingLevelChange(effort);
|
|
7348
|
+
this.sessionManager.appendThinkingLevelChange(effort, AUTO_THINKING);
|
|
7336
7349
|
}
|
|
7337
7350
|
this.#emit({
|
|
7338
7351
|
type: "thinking_level_changed",
|
|
@@ -11608,18 +11621,26 @@ export class AgentSession {
|
|
|
11608
11621
|
.some(entry => entry.type === "service_tier_change");
|
|
11609
11622
|
const defaultThinkingLevel = parseConfiguredThinkingLevel(this.settings.get("defaultThinkingLevel"));
|
|
11610
11623
|
const configuredServiceTier = this.settings.get("serviceTier");
|
|
11611
|
-
//
|
|
11612
|
-
//
|
|
11613
|
-
//
|
|
11614
|
-
//
|
|
11615
|
-
//
|
|
11616
|
-
//
|
|
11624
|
+
// Restore the thinking selector. Each change persists the configured
|
|
11625
|
+
// selector (`auto` or a concrete level), so prefer it: an `auto` session
|
|
11626
|
+
// resumes in auto mode (reclassifying the next turn) instead of freezing at
|
|
11627
|
+
// the last resolved level. Entries written before the `configured` field
|
|
11628
|
+
// existed fall back to the concrete level (legacy pin-on-resume behavior).
|
|
11629
|
+
// With no thinking entry, fall back to the global default so fresh sessions
|
|
11630
|
+
// still classify their first turn.
|
|
11631
|
+
const restoredConfigured = sessionContext.configuredThinkingLevel;
|
|
11617
11632
|
const restoredThinkingLevel: ConfiguredThinkingLevel | undefined =
|
|
11618
11633
|
hasThinkingEntry || (defaultThinkingLevel === AUTO_THINKING && sessionContext.thinkingLevel !== "off")
|
|
11619
|
-
?
|
|
11634
|
+
? restoredConfigured === AUTO_THINKING
|
|
11635
|
+
? AUTO_THINKING
|
|
11636
|
+
: (sessionContext.thinkingLevel as ThinkingLevel | undefined)
|
|
11620
11637
|
: defaultThinkingLevel;
|
|
11621
11638
|
if (restoredThinkingLevel === AUTO_THINKING) {
|
|
11622
11639
|
this.#autoThinking = true;
|
|
11640
|
+
// Resume in auto (pending) like a fresh auto session: the next user
|
|
11641
|
+
// turn reclassifies. We intentionally do not seed the last resolved
|
|
11642
|
+
// effort, so the cold (--continue) and in-app switch paths display
|
|
11643
|
+
// identically as `auto` until then.
|
|
11623
11644
|
this.#autoResolvedLevel = undefined;
|
|
11624
11645
|
this.#thinkingLevel = resolveProvisionalAutoLevel(this.model);
|
|
11625
11646
|
} else {
|
|
@@ -12513,9 +12534,12 @@ export class AgentSession {
|
|
|
12513
12534
|
* @returns Path to exported file
|
|
12514
12535
|
*/
|
|
12515
12536
|
async exportToHtml(outputPath?: string): Promise<string> {
|
|
12516
|
-
|
|
12537
|
+
// Public HTML export ships in the omp brand palette (collab-web
|
|
12538
|
+
// pink/purple), matching my.omp.sh — not the host's terminal theme.
|
|
12539
|
+
// Callers who want a themed export can pass `palette: "theme"` with
|
|
12540
|
+
// `themeName` directly to `exportSessionToHtml`.
|
|
12517
12541
|
const { exportSessionToHtml } = await import("../export/html");
|
|
12518
|
-
return exportSessionToHtml(this.sessionManager, this.state, { outputPath,
|
|
12542
|
+
return exportSessionToHtml(this.sessionManager, this.state, { outputPath, palette: "web" });
|
|
12519
12543
|
}
|
|
12520
12544
|
|
|
12521
12545
|
// =========================================================================
|
|
@@ -7,6 +7,8 @@ import { type CompactionEntry, EPHEMERAL_MODEL_CHANGE_ROLE, type SessionEntry }
|
|
|
7
7
|
export interface SessionContext {
|
|
8
8
|
messages: AgentMessage[];
|
|
9
9
|
thinkingLevel?: string;
|
|
10
|
+
/** Configured thinking selector (`"auto"` or a concrete level) from the latest change. */
|
|
11
|
+
configuredThinkingLevel?: string;
|
|
10
12
|
serviceTier?: ServiceTier;
|
|
11
13
|
/** Model roles: { default: "provider/modelId", small: "provider/modelId", ... } */
|
|
12
14
|
models: Record<string, string>;
|
|
@@ -134,6 +136,7 @@ export function buildSessionContext(
|
|
|
134
136
|
|
|
135
137
|
// Extract settings and find compaction
|
|
136
138
|
let thinkingLevel: string | undefined = "off";
|
|
139
|
+
let configuredThinkingLevel: string | undefined;
|
|
137
140
|
let serviceTier: ServiceTier | undefined;
|
|
138
141
|
const models: Record<string, string> = {};
|
|
139
142
|
let compaction: CompactionEntry | null = null;
|
|
@@ -154,6 +157,7 @@ export function buildSessionContext(
|
|
|
154
157
|
for (const entry of path) {
|
|
155
158
|
if (entry.type === "thinking_level_change") {
|
|
156
159
|
thinkingLevel = entry.thinkingLevel ?? "off";
|
|
160
|
+
configuredThinkingLevel = entry.configured ?? entry.thinkingLevel ?? undefined;
|
|
157
161
|
} else if (entry.type === "model_change") {
|
|
158
162
|
// New format: { model: "provider/id", role?: string }
|
|
159
163
|
if (entry.model) {
|
|
@@ -388,6 +392,7 @@ export function buildSessionContext(
|
|
|
388
392
|
messages,
|
|
389
393
|
cacheMissExplainedAt: options?.transcript ? cacheMissExplainedAt : undefined,
|
|
390
394
|
thinkingLevel,
|
|
395
|
+
configuredThinkingLevel,
|
|
391
396
|
serviceTier,
|
|
392
397
|
models,
|
|
393
398
|
injectedTtsrRules,
|
|
@@ -37,6 +37,12 @@ export interface SessionMessageEntry extends SessionEntryBase {
|
|
|
37
37
|
export interface ThinkingLevelChangeEntry extends SessionEntryBase {
|
|
38
38
|
type: "thinking_level_change";
|
|
39
39
|
thinkingLevel?: string | null;
|
|
40
|
+
/**
|
|
41
|
+
* The user-configured selector at the time of this change: `"auto"` when auto
|
|
42
|
+
* mode was active, otherwise the concrete level. Absent on entries written
|
|
43
|
+
* before auto-mode persistence existed; readers fall back to `thinkingLevel`.
|
|
44
|
+
*/
|
|
45
|
+
configured?: string | null;
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
export interface ModelChangeEntry extends SessionEntryBase {
|
|
@@ -1158,11 +1158,13 @@ export class SessionManager {
|
|
|
1158
1158
|
return entry.id;
|
|
1159
1159
|
}
|
|
1160
1160
|
|
|
1161
|
-
|
|
1161
|
+
/** Append a thinking level change as child of current leaf, then advance leaf. Returns entry id. */
|
|
1162
|
+
appendThinkingLevelChange(thinkingLevel?: string, configured?: string): string {
|
|
1162
1163
|
const entry: ThinkingLevelChangeEntry = {
|
|
1163
1164
|
type: "thinking_level_change",
|
|
1164
1165
|
...this.#freshEntryFields(),
|
|
1165
1166
|
thinkingLevel: thinkingLevel ?? null,
|
|
1167
|
+
configured: configured ?? null,
|
|
1166
1168
|
};
|
|
1167
1169
|
this.#recordEntry(entry);
|
|
1168
1170
|
return entry.id;
|
package/src/system-prompt.ts
CHANGED
|
@@ -421,6 +421,8 @@ export interface BuildSystemPromptOptions {
|
|
|
421
421
|
model?: string;
|
|
422
422
|
/** Personality preset rendered into the default system prompt. "none" omits the block. Default: "default" */
|
|
423
423
|
personality?: Personality;
|
|
424
|
+
/** Whether to include the workspace directory tree in the system prompt. Default: false */
|
|
425
|
+
includeWorkspaceTree?: boolean;
|
|
424
426
|
}
|
|
425
427
|
|
|
426
428
|
/** Result of building provider-facing system prompt messages. */
|
|
@@ -461,6 +463,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
461
463
|
memoryRootEnabled = false,
|
|
462
464
|
model,
|
|
463
465
|
personality = "default",
|
|
466
|
+
includeWorkspaceTree = false,
|
|
464
467
|
} = options;
|
|
465
468
|
const inlineToolDescriptors = providedInlineToolDescriptors ?? false;
|
|
466
469
|
const resolvedCwd = cwd ?? getProjectDir();
|
|
@@ -523,9 +526,17 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
523
526
|
const workspaceTreePromise =
|
|
524
527
|
providedWorkspaceTree !== undefined
|
|
525
528
|
? Promise.resolve(providedWorkspaceTree)
|
|
526
|
-
:
|
|
527
|
-
|
|
528
|
-
|
|
529
|
+
: includeWorkspaceTree
|
|
530
|
+
? logger.time("buildWorkspaceTree", () =>
|
|
531
|
+
buildWorkspaceTree(resolvedCwd, { timeoutMs: SYSTEM_PROMPT_PREP_TIMEOUT_MS }),
|
|
532
|
+
)
|
|
533
|
+
: Promise.resolve({
|
|
534
|
+
rootPath: resolvedCwd,
|
|
535
|
+
rendered: "",
|
|
536
|
+
truncated: false,
|
|
537
|
+
totalLines: 0,
|
|
538
|
+
agentsMdFiles: [],
|
|
539
|
+
});
|
|
529
540
|
const skillsPromise: Promise<Skill[]> =
|
|
530
541
|
providedSkills !== undefined
|
|
531
542
|
? Promise.resolve(providedSkills)
|
|
@@ -670,6 +681,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
670
681
|
secretsEnabled,
|
|
671
682
|
hasMemoryRoot: memoryRootEnabled,
|
|
672
683
|
hasObsidian: hasObsidian(),
|
|
684
|
+
includeWorkspaceTree,
|
|
673
685
|
};
|
|
674
686
|
const rendered = prompt.render(resolvedCustomPrompt ? customSystemPromptTemplate : systemPromptTemplate, data);
|
|
675
687
|
const systemPrompt = [rendered];
|
package/src/task/worktree.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
|
|
5
5
|
import * as natives from "@oh-my-pi/pi-natives";
|
|
6
6
|
import { getWorktreeDir, hashPath, logger, Snowflake } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import * as git from "../utils/git";
|
|
8
|
+
import * as jj from "../utils/jj";
|
|
8
9
|
import { mapWithConcurrencyLimit } from "./parallel";
|
|
9
10
|
|
|
10
11
|
const { IsoBackendKind } = natives;
|
|
@@ -28,12 +29,19 @@ export interface WorktreeBaseline {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export async function getRepoRoot(cwd: string): Promise<string> {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// Pure-jj check runs first so a jj workspace nested under an unrelated
|
|
33
|
+
// outer Git checkout is rejected at its own root rather than silently
|
|
34
|
+
// mutating the surrounding Git tree behind jj's back.
|
|
35
|
+
if (await jj.isPureJjRepo(cwd)) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
"Isolated task execution requires a Git checkout, but this workspace is pure Jujutsu (`.jj/` without a colocated `.git/`). Run `jj git init --colocate` to add a Git checkout, or set `task.isolation.mode: none` to disable task isolation.",
|
|
38
|
+
);
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
const repoRoot = await git.repo.root(cwd);
|
|
42
|
+
if (repoRoot) return repoRoot;
|
|
43
|
+
|
|
44
|
+
throw new Error("Git repository not found for isolated task execution.");
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
const GIT_NO_INDEX_NULL_PATH = process.platform === "win32" ? "NUL" : "/dev/null";
|
package/src/thinking.ts
CHANGED
|
@@ -32,7 +32,7 @@ const THINKING_LEVEL_METADATA: Record<ThinkingLevel, ThinkingLevelMetadata> = {
|
|
|
32
32
|
[ThinkingLevel.High]: { value: ThinkingLevel.High, label: "high", description: "Deep reasoning (~16k tokens)" },
|
|
33
33
|
[ThinkingLevel.XHigh]: {
|
|
34
34
|
value: ThinkingLevel.XHigh,
|
|
35
|
-
label: "
|
|
35
|
+
label: "xhigh",
|
|
36
36
|
description: "Maximum reasoning (~32k tokens)",
|
|
37
37
|
},
|
|
38
38
|
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared ACP client bridge routing for file-write sites.
|
|
3
|
+
*
|
|
4
|
+
* When an ACP client (e.g. Zed) advertises the `fs.writeTextFile` capability,
|
|
5
|
+
* all write-mode tools must route through it so the editor's open buffer is
|
|
6
|
+
* updated immediately. Internal artifacts ('/Users/theo/.omp/agent/sessions/-Projects-oh-my-pi/2026-06-10T09-11-41-506Z_019eb0cd-3ec2-7000-92aa-1b82aa4d78f0/local' plan files, other scheme
|
|
7
|
+
* URLs) are always written directly to disk — those are OMP-owned and should
|
|
8
|
+
* never be pushed into the editor.
|
|
9
|
+
*/
|
|
10
|
+
import type { ToolSession } from ".";
|
|
11
|
+
import { invalidateFsScanAfterWrite } from "./fs-cache-invalidation";
|
|
12
|
+
import { isInternalUrlPath } from "./path-utils";
|
|
13
|
+
import { resolvePlanPath } from "./plan-mode-guard";
|
|
14
|
+
import { ToolError } from "./tool-errors";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Return `true` when an ACP client bridge write is appropriate for this path.
|
|
18
|
+
*
|
|
19
|
+
* Returns `false` for internal-URL paths (e.g. `'/Users/theo/.omp/agent/sessions/-Projects-oh-my-pi/2026-06-10T09-11-41-506Z_019eb0cd-3ec2-7000-92aa-1b82aa4d78f0/local/PLAN.md'`) and for the
|
|
20
|
+
* active plan file while plan mode is enabled — both are OMP-internal artifacts
|
|
21
|
+
* that must stay off the editor's buffer.
|
|
22
|
+
*/
|
|
23
|
+
export function shouldRouteWriteThroughBridge(
|
|
24
|
+
session: ToolSession,
|
|
25
|
+
requestedPath: string,
|
|
26
|
+
absolutePath: string,
|
|
27
|
+
): boolean {
|
|
28
|
+
if (isInternalUrlPath(requestedPath)) return false;
|
|
29
|
+
|
|
30
|
+
const state = session.getPlanModeState?.();
|
|
31
|
+
if (!state?.enabled || !isInternalUrlPath(state.planFilePath)) return true;
|
|
32
|
+
|
|
33
|
+
return absolutePath !== resolvePlanPath(session, state.planFilePath);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Try to route a file write through the ACP client bridge.
|
|
38
|
+
*
|
|
39
|
+
* Performs the full guard check, bridge call (wrapped in {@link ToolError}),
|
|
40
|
+
* FS-scan cache invalidation, and session mutation-version bump.
|
|
41
|
+
*
|
|
42
|
+
* Returns `true` when the bridge was used and the caller must skip the
|
|
43
|
+
* writethrough path. Returns `false` when the bridge is unavailable or the
|
|
44
|
+
* path should not be routed through it.
|
|
45
|
+
*/
|
|
46
|
+
export async function routeWriteThroughBridge(
|
|
47
|
+
session: ToolSession,
|
|
48
|
+
requestedPath: string,
|
|
49
|
+
absolutePath: string,
|
|
50
|
+
content: string,
|
|
51
|
+
): Promise<boolean> {
|
|
52
|
+
if (!shouldRouteWriteThroughBridge(session, requestedPath, absolutePath)) return false;
|
|
53
|
+
|
|
54
|
+
const bridge = session.getClientBridge?.();
|
|
55
|
+
if (!bridge?.capabilities.writeTextFile || !bridge.writeTextFile) return false;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await bridge.writeTextFile({ path: absolutePath, content });
|
|
59
|
+
} catch (error) {
|
|
60
|
+
throw new ToolError(error instanceof Error ? error.message : String(error));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
invalidateFsScanAfterWrite(absolutePath);
|
|
64
|
+
session.bumpFileMutationVersion?.(absolutePath);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
package/src/tools/bash.ts
CHANGED
|
@@ -1132,9 +1132,9 @@ function getPartialJson<TArgs>(args: TArgs | undefined): string | undefined {
|
|
|
1132
1132
|
}
|
|
1133
1133
|
|
|
1134
1134
|
export function getBashEnvForDisplay(args: BashRenderArgs): Record<string, string> | undefined {
|
|
1135
|
-
//
|
|
1136
|
-
//
|
|
1137
|
-
//
|
|
1135
|
+
// The parsed args don't always mirror the exact current stream prefix, so recover
|
|
1136
|
+
// env from the raw JSON buffer to surface `NAME="..." cmd` in the preview as it
|
|
1137
|
+
// streams rather than only once the args object finishes.
|
|
1138
1138
|
const partialEnv = extractPartialBashEnv(args.__partialJson);
|
|
1139
1139
|
if (partialEnv && args.env) return { ...partialEnv, ...args.env };
|
|
1140
1140
|
return args.env ?? partialEnv;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// @generated by scripts/generate-aria-snapshot.ts from Playwright v1.61.0
|
|
2
|
+
// Bundled from Playwright's injected ARIA-snapshot sources (Apache-2.0, (c) Microsoft).
|
|
3
|
+
// Do not edit by hand. Regenerate with: bun scripts/generate-aria-snapshot.ts
|
|
4
|
+
var{defineProperty:M_,getOwnPropertyNames:WX,getOwnPropertyDescriptor:LX}=Object,zX=Object.prototype.hasOwnProperty;function MX(_){return this[_]}var jX=(_)=>{var J=(k_??=new WeakMap).get(_),Z;if(J)return J;if(J=M_({},"__esModule",{value:!0}),_&&typeof _==="object"||typeof _==="function"){for(var $ of WX(_))if(!zX.call(J,$))M_(J,$,{get:MX.bind(_,$),enumerable:!(Z=LX(_,$))||Z.enumerable})}return k_.set(_,J),J},k_;var FX=(_)=>_;function BX(_,J){this[_]=FX.bind(null,J)}var IX=(_,J)=>{for(var Z in J)M_(_,Z,{get:J[Z],enumerable:!0,configurable:!0,set:BX.bind(J,Z)})};var YZ={};IX(YZ,{resolveAriaRef:()=>$Z,ariaSnapshot:()=>ZZ});module.exports=jX(YZ);function h_(_,J){if(_.role!==J.role||_.name!==J.name)return!1;if(!VX(_,J)||d(_)!==d(J))return!1;let Z=Object.keys(_.props),$=Object.keys(J.props);return Z.length===$.length&&Z.every((X)=>_.props[X]===J.props[X])}function d(_){return _.box.cursor==="pointer"}function VX(_,J){return _.active===J.active&&_.checked===J.checked&&_.disabled===J.disabled&&_.expanded===J.expanded&&_.invalid===J.invalid&&_.selected===J.selected&&_.level===J.level&&_.pressed===J.pressed}var u_;function j_(_){let J=u_?.get(_);if(J===void 0)J=_.replace(/[\u200b\u00ad]/g,"").trim().replace(/\s+/g," "),u_?.set(_,J);return J}function F_(_){return _.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function p_(_,J){let Z=_.length,$=J.length,X=0,Q=0,U=Array(Z+1).fill(null).map(()=>Array($+1).fill(0));for(let W=1;W<=Z;W++)for(let Y=1;Y<=$;Y++)if(_[W-1]===J[Y-1]){if(U[W][Y]=U[W-1][Y-1]+1,U[W][Y]>X)X=U[W][Y],Q=W}return _.slice(Q-X,Q)}var HZ=new RegExp("([\\u001B\\u009B][[\\]()#?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{0,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))","g");function c_(_){if(!m_(_))return _;return"'"+_.replace(/'/g,"''")+"'"}function e(_){if(!m_(_))return _;return'"'+_.replace(/[\\"\x00-\x1f\x7f-\x9f]/g,(J)=>{switch(J){case"\\":return"\\\\";case'"':return"\\\"";case"\b":return"\\b";case"\f":return"\\f";case`
|
|
5
|
+
`:return"\\n";case"\r":return"\\r";case"\t":return"\\t";default:return"\\x"+J.charCodeAt(0).toString(16).padStart(2,"0")}})+'"'}function m_(_){if(_.length===0)return!0;if(/^\s|\s$/.test(_))return!0;if(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/.test(_))return!0;if(/^-/.test(_))return!0;if(/[\n:](\s|$)/.test(_))return!0;if(/\s#/.test(_))return!0;if(/[\n\r]/.test(_))return!0;if(/^[&*\],?!>|@"'#%]/.test(_))return!0;if(/[{}`]/.test(_))return!0;if(/^\[/.test(_))return!0;if(!isNaN(Number(_))||["y","n","yes","no","true","false","on","off","null"].includes(_.toLowerCase()))return!0;return!1}var DX={};function h(_){if(_.parentElement)return _.parentElement;if(!_.parentNode)return;if(_.parentNode.nodeType===11&&_.parentNode.host)return _.parentNode.host}function d_(_){let J=_;while(J.parentNode)J=J.parentNode;if(J.nodeType===11||J.nodeType===9)return J}function OX(_){while(_.parentElement)_=_.parentElement;return h(_)}function s(_,J,Z){while(_){let $=_.closest(J);if(Z&&$!==Z&&$?.contains(Z))return;if($)return $;_=OX(_)}}function b(_,J){let Z=J==="::before"?R_:J==="::after"?D_:V_;if(Z&&Z.has(_))return Z.get(_);let $=_.ownerDocument&&_.ownerDocument.defaultView?_.ownerDocument.defaultView.getComputedStyle(_,J):void 0;return Z?.set(_,$),$}function B_(_,J){if(J=J??b(_),!J)return!0;if(Element.prototype.checkVisibility&&DX.browserNameForWorkarounds!=="webkit"){if(!_.checkVisibility())return!1}else{let Z=_.closest("details,summary");if(Z!==_&&Z?.nodeName==="DETAILS"&&!Z.open)return!1}if(J.visibility!=="visible")return!1;return!0}function i(_){let J=b(_);if(!J)return{visible:!0,inline:!1};let Z=J.cursor;if(J.display==="contents"){for(let X=_.firstChild;X;X=X.nextSibling){if(X.nodeType===1&&__(X))return{visible:!0,inline:!1,cursor:Z};if(X.nodeType===3&&I_(X))return{visible:!0,inline:!0,cursor:Z}}return{visible:!1,inline:!1,cursor:Z}}if(!B_(_,J))return{cursor:Z,visible:!1,inline:!1};let $=_.getBoundingClientRect();return{cursor:Z,visible:$.width>0&&$.height>0,inline:J.display==="inline"}}function __(_){return i(_).visible}function I_(_){let J=_.ownerDocument.createRange();J.selectNode(_);let Z=J.getBoundingClientRect();return Z.width>0&&Z.height>0}function V(_){let J=_.tagName;if(typeof J==="string")return J.toUpperCase();if(_ instanceof HTMLFormElement)return"FORM";return _.tagName.toUpperCase()}var V_,R_,D_,s_=0;function i_(){++s_,V_??=new Map,R_??=new Map,D_??=new Map}function l_(){if(!--s_)V_=void 0,R_=void 0,D_=void 0}var R=function(_,J,Z){return _>=J&&_<=Z};function A(_){return R(_,48,57)}function r_(_){return A(_)||R(_,65,70)||R(_,97,102)}function wX(_){return R(_,65,90)}function AX(_){return R(_,97,122)}function EX(_){return wX(_)||AX(_)}function PX(_){return _>=128}function J_(_){return EX(_)||PX(_)||_===95}function a_(_){return J_(_)||A(_)||_===45}function fX(_){return R(_,0,8)||_===11||R(_,14,31)||_===127}function u(_){return _===10}function T(_){return u(_)||_===9||_===32}var CX=1114111;class Z_ extends Error{constructor(_){super(_);this.name="InvalidCharacterError"}}function bX(_){let J=[];for(let Z=0;Z<_.length;Z++){let $=_.charCodeAt(Z);if($===13&&_.charCodeAt(Z+1)===10)$=10,Z++;if($===13||$===12)$=10;if($===0)$=65533;if(R($,55296,56319)&&R(_.charCodeAt(Z+1),56320,57343)){let X=$-55296,Q=_.charCodeAt(Z+1)-56320;$=Math.pow(2,16)+X*Math.pow(2,10)+Q,Z++}J.push($)}return J}function D(_){if(_<=65535)return String.fromCharCode(_);_-=Math.pow(2,16);let J=Math.floor(_/Math.pow(2,10))+55296,Z=_%Math.pow(2,10)+56320;return String.fromCharCode(J)+String.fromCharCode(Z)}function n_(_){let J=bX(_),Z=-1,$=[],X,Q=0,U=0,W=0,Y=function(){Q+=1,W=U,U=0},K={line:Q,column:U},z=function(G){if(G>=J.length)return-1;return J[G]},q=function(G){if(G===void 0)G=1;if(G>3)throw"Spec Error: no more than three codepoints of lookahead.";return z(Z+G)},L=function(G){if(G===void 0)G=1;if(Z+=G,X=z(Z),u(X))Y();else U+=G;return!0},I=function(){if(Z-=1,u(X))Q-=1,U=W;else U-=1;return K.line=Q,K.column=U,!0},H=function(G){if(G===void 0)G=X;return G===-1},F=function(){},j=function(){},w=function(){if(E(),L(),T(X)){while(T(q()))L();return new $_}else if(X===34)return K_();else if(X===35)if(a_(q())||k(q(1),q(2))){let G=new jJ("");if(o(q(1),q(2),q(3)))G.type="id";return G.value=t(),G}else return new O(X);else if(X===36)if(q()===61)return L(),new KJ;else return new O(X);else if(X===39)return K_();else if(X===40)return new HJ;else if(X===41)return new Y_;else if(X===42)if(q()===61)return L(),new WJ;else return new O(X);else if(X===43)if(W_())return I(),S();else return new O(X);else if(X===44)return new XJ;else if(X===45)if(W_())return I(),S();else if(q(1)===45&&q(2)===62)return L(2),new e_;else if(QX())return I(),m();else return new O(X);else if(X===46)if(W_())return I(),S();else return new O(X);else if(X===58)return new _J;else if(X===59)return new JJ;else if(X===60)if(q(1)===33&&q(2)===45&&q(3)===45)return L(3),new t_;else return new O(X);else if(X===64)if(o(q(1),q(2),q(3)))return new MJ(t());else return new O(X);else if(X===91)return new YJ;else if(X===92)if(n())return I(),m();else return j(),new O(X);else if(X===93)return new QJ;else if(X===94)if(q()===61)return L(),new UJ;else return new O(X);else if(X===123)return new ZJ;else if(X===124)if(q()===61)return L(),new GJ;else if(q()===124)return L(),new LJ;else return new O(X);else if(X===125)return new $J;else if(X===126)if(q()===61)return L(),new qJ;else return new O(X);else if(A(X))return I(),S();else if(J_(X))return I(),m();else if(H())return new zJ;else return new O(X)},E=function(){while(q(1)===47&&q(2)===42){L(2);while(!0)if(L(),X===42&&q()===47){L();break}else if(H()){j();return}}},S=function(){let G=qX();if(o(q(1),q(2),q(3))){let M=new VJ;return M.value=G.value,M.repr=G.repr,M.type=G.type,M.unit=t(),M}else if(q()===37){L();let M=new IJ;return M.value=G.value,M.repr=G.repr,M}else{let M=new BJ;return M.value=G.value,M.repr=G.repr,M.type=G.type,M}},m=function(){let G=t();if(G.toLowerCase()==="url"&&q()===40){L();while(T(q(1))&&T(q(2)))L();if(q()===34||q()===39)return new p(G);else if(T(q())&&(q(2)===34||q(2)===39))return new p(G);else return a()}else if(q()===40)return L(),new p(G);else return new Q_(G)},K_=function(G){if(G===void 0)G=X;let M="";while(L())if(X===G||H())return new H_(M);else if(u(X))return j(),I(),new o_;else if(X===92)if(H(q()))F();else if(u(q()))L();else M+=D(C());else M+=D(X);throw Error("Internal error")},a=function(){let G=new FJ("");while(T(q()))L();if(H(q()))return G;while(L())if(X===41||H())return G;else if(T(X)){while(T(q()))L();if(q()===41||H(q()))return L(),G;else return L_(),new X_}else if(X===34||X===39||X===40||fX(X))return j(),L_(),new X_;else if(X===92)if(n())G.value+=D(C());else return j(),L_(),new X_;else G.value+=D(X);throw Error("Internal error")},C=function(){if(L(),r_(X)){let G=[X];for(let P=0;P<5;P++)if(r_(q()))L(),G.push(X);else break;if(T(q()))L();let M=parseInt(G.map(function(P){return String.fromCharCode(P)}).join(""),16);if(M>CX)M=65533;return M}else if(H())return 65533;else return X},k=function(G,M){if(G!==92)return!1;if(u(M))return!1;return!0},n=function(){return k(X,q())},o=function(G,M,P){if(G===45)return J_(M)||M===45||k(M,P);else if(J_(G))return!0;else if(G===92)return k(G,M);else return!1},QX=function(){return o(X,q(1),q(2))},HX=function(G,M,P){if(G===43||G===45){if(A(M))return!0;if(M===46&&A(P))return!0;return!1}else if(G===46){if(A(M))return!0;return!1}else if(A(G))return!0;else return!1},W_=function(){return HX(X,q(1),q(2))},t=function(){let G="";while(L())if(a_(X))G+=D(X);else if(n())G+=D(C());else return I(),G;throw Error("Internal parse error")},qX=function(){let G="",M="integer";if(q()===43||q()===45)L(),G+=D(X);while(A(q()))L(),G+=D(X);if(q(1)===46&&A(q(2))){L(),G+=D(X),L(),G+=D(X),M="number";while(A(q()))L(),G+=D(X)}let P=q(1),z_=q(2),UX=q(3);if((P===69||P===101)&&A(z_)){L(),G+=D(X),L(),G+=D(X),M="number";while(A(q()))L(),G+=D(X)}else if((P===69||P===101)&&(z_===43||z_===45)&&A(UX)){L(),G+=D(X),L(),G+=D(X),L(),G+=D(X),M="number";while(A(q()))L(),G+=D(X)}let KX=GX(G);return{type:M,value:KX,repr:G}},GX=function(G){return+G},L_=function(){while(L())if(X===41||H())return;else if(n())C(),F();else F()},N_=0;while(!H(q()))if($.push(w()),N_++,N_>J.length*2)throw Error("I'm infinite-looping!");return $}class B{tokenType="";value;toJSON(){return{token:this.tokenType}}toString(){return this.tokenType}toSource(){return""+this}}class o_ extends B{tokenType="BADSTRING"}class X_ extends B{tokenType="BADURL"}class $_ extends B{tokenType="WHITESPACE";toString(){return"WS"}toSource(){return" "}}class t_ extends B{tokenType="CDO";toSource(){return"<!--"}}class e_ extends B{tokenType="CDC";toSource(){return"-->"}}class _J extends B{tokenType=":"}class JJ extends B{tokenType=";"}class XJ extends B{tokenType=","}class g extends B{value="";mirror=""}class ZJ extends g{tokenType="{";constructor(){super();this.value="{",this.mirror="}"}}class $J extends g{tokenType="}";constructor(){super();this.value="}",this.mirror="{"}}class YJ extends g{tokenType="[";constructor(){super();this.value="[",this.mirror="]"}}class QJ extends g{tokenType="]";constructor(){super();this.value="]",this.mirror="["}}class HJ extends g{tokenType="(";constructor(){super();this.value="(",this.mirror=")"}}class Y_ extends g{tokenType=")";constructor(){super();this.value=")",this.mirror="("}}class qJ extends B{tokenType="~="}class GJ extends B{tokenType="|="}class UJ extends B{tokenType="^="}class KJ extends B{tokenType="$="}class WJ extends B{tokenType="*="}class LJ extends B{tokenType="||"}class zJ extends B{tokenType="EOF";toSource(){return""}}class O extends B{tokenType="DELIM";value="";constructor(_){super();this.value=D(_)}toString(){return"DELIM("+this.value+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_}toSource(){if(this.value==="\\")return"\\\n";else return this.value}}class N extends B{value="";ASCIIMatch(_){return this.value.toLowerCase()===_.toLowerCase()}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_}}class Q_ extends N{constructor(_){super();this.value=_}tokenType="IDENT";toString(){return"IDENT("+this.value+")"}toSource(){return l(this.value)}}class p extends N{tokenType="FUNCTION";mirror;constructor(_){super();this.value=_,this.mirror=")"}toString(){return"FUNCTION("+this.value+")"}toSource(){return l(this.value)+"("}}class MJ extends N{tokenType="AT-KEYWORD";constructor(_){super();this.value=_}toString(){return"AT("+this.value+")"}toSource(){return"@"+l(this.value)}}class jJ extends N{tokenType="HASH";type;constructor(_){super();this.value=_,this.type="unrestricted"}toString(){return"HASH("+this.value+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_.type=this.type,_}toSource(){if(this.type==="id")return"#"+l(this.value);else return"#"+yX(this.value)}}class H_ extends N{tokenType="STRING";constructor(_){super();this.value=_}toString(){return'"'+RJ(this.value)+'"'}}class FJ extends N{tokenType="URL";constructor(_){super();this.value=_}toString(){return"URL("+this.value+")"}toSource(){return'url("'+RJ(this.value)+'")'}}class BJ extends B{tokenType="NUMBER";type;repr;constructor(){super();this.type="integer",this.repr=""}toString(){if(this.type==="integer")return"INT("+this.value+")";return"NUMBER("+this.value+")"}toJSON(){let _=super.toJSON();return _.value=this.value,_.type=this.type,_.repr=this.repr,_}toSource(){return this.repr}}class IJ extends B{tokenType="PERCENTAGE";repr;constructor(){super();this.repr=""}toString(){return"PERCENTAGE("+this.value+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_.repr=this.repr,_}toSource(){return this.repr+"%"}}class VJ extends B{tokenType="DIMENSION";type;repr;unit;constructor(){super();this.type="integer",this.repr="",this.unit=""}toString(){return"DIM("+this.value+","+this.unit+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_.type=this.type,_.repr=this.repr,_.unit=this.unit,_}toSource(){let _=this.repr,J=l(this.unit);if(J[0].toLowerCase()==="e"&&(J[1]==="-"||R(J.charCodeAt(1),48,57)))J="\\65 "+J.slice(1,J.length);return _+J}}function l(_){_=""+_;let J="",Z=_.charCodeAt(0);for(let $=0;$<_.length;$++){let X=_.charCodeAt($);if(X===0)throw new Z_("Invalid character: the input contains U+0000.");if(R(X,1,31)||X===127||$===0&&R(X,48,57)||$===1&&R(X,48,57)&&Z===45)J+="\\"+X.toString(16)+" ";else if(X>=128||X===45||X===95||R(X,48,57)||R(X,65,90)||R(X,97,122))J+=_[$];else J+="\\"+_[$]}return J}function yX(_){_=""+_;let J="";for(let Z=0;Z<_.length;Z++){let $=_.charCodeAt(Z);if($===0)throw new Z_("Invalid character: the input contains U+0000.");if($>=128||$===45||$===95||R($,48,57)||R($,65,90)||R($,97,122))J+=_[Z];else J+="\\"+$.toString(16)+" "}return J}function RJ(_){_=""+_;let J="";for(let Z=0;Z<_.length;Z++){let $=_.charCodeAt(Z);if($===0)throw new Z_("Invalid character: the input contains U+0000.");if(R($,1,31)||$===127)J+="\\"+$.toString(16)+" ";else if($===34||$===92)J+="\\"+_[Z];else J+=_[Z]}return J}function DJ(_){return _.hasAttribute("aria-label")||_.hasAttribute("aria-labelledby")}var OJ="article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]",TX=[["aria-atomic",void 0],["aria-busy",void 0],["aria-controls",void 0],["aria-current",void 0],["aria-describedby",void 0],["aria-details",void 0],["aria-dropeffect",void 0],["aria-flowto",void 0],["aria-grabbed",void 0],["aria-hidden",void 0],["aria-keyshortcuts",void 0],["aria-label",["caption","code","deletion","emphasis","generic","insertion","paragraph","presentation","strong","subscript","superscript"]],["aria-labelledby",["caption","code","deletion","emphasis","generic","insertion","paragraph","presentation","strong","subscript","superscript"]],["aria-live",void 0],["aria-owns",void 0],["aria-relevant",void 0],["aria-roledescription",["generic"]]];function fJ(_,J){return TX.some(([Z,$])=>{return!$?.includes(J||"")&&_.hasAttribute(Z)})}function CJ(_){return!Number.isNaN(Number(String(_.getAttribute("tabindex"))))}function xX(_){return!mJ(_)&&(vX(_)||CJ(_))}function vX(_){let J=V(_);if(["BUTTON","DETAILS","SELECT","TEXTAREA"].includes(J))return!0;if(J==="A"||J==="AREA")return _.hasAttribute("href");if(J==="INPUT")return!_.hidden;return!1}var gX={A:(_)=>{return _.hasAttribute("href")?"link":null},AREA:(_)=>{return _.hasAttribute("href")?"link":null},ARTICLE:()=>"article",ASIDE:()=>"complementary",BLOCKQUOTE:()=>"blockquote",BUTTON:()=>"button",CAPTION:()=>"caption",CODE:()=>"code",DATALIST:()=>"listbox",DD:()=>"definition",DEL:()=>"deletion",DETAILS:()=>"group",DFN:()=>"term",DIALOG:()=>"dialog",DT:()=>"term",EM:()=>"emphasis",FIELDSET:()=>"group",FIGURE:()=>"figure",FOOTER:(_)=>s(_,OJ)?null:"contentinfo",FORM:(_)=>DJ(_)?"form":null,H1:()=>"heading",H2:()=>"heading",H3:()=>"heading",H4:()=>"heading",H5:()=>"heading",H6:()=>"heading",HEADER:(_)=>s(_,OJ)?null:"banner",HR:()=>"separator",HTML:()=>"document",IMG:(_)=>_.getAttribute("alt")===""&&!_.getAttribute("title")&&!fJ(_)&&!CJ(_)?"presentation":"img",INPUT:(_)=>{let J=_.type.toLowerCase();if(J==="search")return _.hasAttribute("list")?"combobox":"searchbox";if(["email","tel","text","url",""].includes(J)){let Z=G_(_,_.getAttribute("list"))[0];return Z&&V(Z)==="DATALIST"?"combobox":"textbox"}if(J==="hidden")return null;if(J==="file")return"button";return lX[J]||"textbox"},INS:()=>"insertion",LI:()=>"listitem",MAIN:()=>"main",MARK:()=>"mark",MATH:()=>"math",MENU:()=>"list",METER:()=>"meter",NAV:()=>"navigation",OL:()=>"list",OPTGROUP:()=>"group",OPTION:()=>"option",OUTPUT:()=>"status",P:()=>"paragraph",PROGRESS:()=>"progressbar",SEARCH:()=>"search",SECTION:(_)=>DJ(_)?"region":null,SELECT:(_)=>_.hasAttribute("multiple")||_.size>1?"listbox":"combobox",STRONG:()=>"strong",SUB:()=>"subscript",SUP:()=>"superscript",SVG:()=>"img",TABLE:()=>"table",TBODY:()=>"rowgroup",TD:(_)=>{let J=s(_,"table"),Z=J?O_(J):"";return Z==="grid"||Z==="treegrid"?"gridcell":"cell"},TEXTAREA:()=>"textbox",TFOOT:()=>"rowgroup",TH:(_)=>{let J=_.getAttribute("scope");if(J==="col"||J==="colgroup")return"columnheader";if(J==="row"||J==="rowgroup")return"rowheader";let{nextElementSibling:Z,previousElementSibling:$}=_,X=!!_.parentElement&&V(_.parentElement)==="TR"?_.parentElement:void 0;if(!Z&&!$){if(X){let Q=s(X,"table");if(Q&&Q.rows.length<=1)return null}return"columnheader"}if(wJ(Z)&&wJ($))return"columnheader";if(AJ(Z)||AJ($))return"rowheader";return"columnheader"},THEAD:()=>"rowgroup",TIME:()=>"time",TR:()=>"row",UL:()=>"list"};function wJ(_){return!!_&&V(_)==="TH"}function AJ(_){if(!_||V(_)!=="TD")return!1;return!!(_.textContent?.trim()||_.children.length>0)}var NX={DD:["DL","DIV"],DIV:["DL"],DT:["DL","DIV"],LI:["OL","UL"],TBODY:["TABLE"],TD:["TR"],TFOOT:["TABLE"],TH:["TR"],THEAD:["TABLE"],TR:["THEAD","TBODY","TFOOT","TABLE"]};function EJ(_){let J=gX[V(_)]?.(_)||"";if(!J)return null;let Z=_;while(Z){let $=h(Z),X=NX[V(Z)];if(!X||!$||!X.includes(V($)))break;let Q=O_($);if((Q==="none"||Q==="presentation")&&!bJ($,Q))return Q;Z=$}return J}var kX=["alert","alertdialog","application","article","banner","blockquote","button","caption","cell","checkbox","code","columnheader","combobox","complementary","contentinfo","definition","deletion","dialog","directory","document","emphasis","feed","figure","form","generic","grid","gridcell","group","heading","img","insertion","link","list","listbox","listitem","log","main","mark","marquee","math","meter","menu","menubar","menuitem","menuitemcheckbox","menuitemradio","navigation","none","note","option","paragraph","presentation","progressbar","radio","radiogroup","region","row","rowgroup","rowheader","scrollbar","search","searchbox","separator","slider","spinbutton","status","strong","subscript","superscript","switch","tab","table","tablist","tabpanel","term","textbox","time","timer","toolbar","tooltip","tree","treegrid","treeitem"];function O_(_){return(_.getAttribute("role")||"").split(" ").map((Z)=>Z.trim()).find((Z)=>kX.includes(Z))||null}function bJ(_,J){return fJ(_,J)||xX(_)}function f(_){let J=O_(_);if(!J)return EJ(_);if(J==="none"||J==="presentation"){let Z=EJ(_);if(bJ(_,Z))return Z}return J}function yJ(_){return _===null?void 0:_.toLowerCase()==="true"}function SJ(_){return["STYLE","SCRIPT","NOSCRIPT","TEMPLATE"].includes(V(_))}function y(_){if(SJ(_))return!0;let J=b(_),Z=_.nodeName==="SLOT";if(J?.display==="contents"&&!Z){for(let X=_.firstChild;X;X=X.nextSibling){if(X.nodeType===1&&!y(X))return!1;if(X.nodeType===3&&I_(X))return!1}return!0}if(!(_.nodeName==="OPTION"&&!!_.closest("select"))&&!Z&&!B_(_,J))return!0;return TJ(_)}function TJ(_){let J=q_?.get(_);if(J===void 0){if(J=!1,_.parentElement&&_.parentElement.shadowRoot&&!_.assignedSlot)J=!0;if(!J){let Z=b(_);J=!Z||Z.display==="none"||yJ(_.getAttribute("aria-hidden"))===!0}if(!J){let Z=h(_);if(Z)J=TJ(Z)}q_?.set(_,J)}return J}function G_(_,J){if(!J)return[];let Z=d_(_);if(!Z)return[];try{let $=J.split(" ").filter((Q)=>!!Q),X=[];for(let Q of $){let U=Z.querySelector("#"+CSS.escape(Q));if(U&&!X.includes(U))X.push(U)}return X}catch($){return[]}}function x(_){return _.trim()}function hX(_){return _.split(" ").map((J)=>J.replace(/\r\n/g,`
|
|
6
|
+
`).replace(/[\u200b\u00ad]/g,"").replace(/\s\s*/g," ")).join(" ").trim()}function PJ(_,J){let Z=[..._.querySelectorAll(J)];for(let $ of G_(_,_.getAttribute("aria-owns"))){if($.matches(J))Z.push($);Z.push(...$.querySelectorAll(J))}return Z}function c(_,J){let Z=J==="::before"?T_:J==="::after"?x_:S_;if(Z?.has(_))return Z?.get(_);let $=b(_,J),X;if($){let Q=$.content;if(Q&&Q!=="none"&&Q!=="normal"){if($.display!=="none"&&$.visibility!=="hidden")X=uX(_,Q,!!J)}}if(J&&X!==void 0){if(($?.display||"inline")!=="inline")X=" "+X+" "}if(Z)Z.set(_,X);return X}function uX(_,J,Z){if(!J||J==="none"||J==="normal")return;try{let $=n_(J).filter((W)=>!(W instanceof $_)),X=$.findIndex((W)=>W instanceof O&&W.value==="/");if(X!==-1)$=$.slice(X+1);else if(!Z)return;let Q=[],U=0;while(U<$.length)if($[U]instanceof H_)Q.push($[U].value),U++;else if(U+2<$.length&&$[U]instanceof p&&$[U].value==="attr"&&$[U+1]instanceof Q_&&$[U+2]instanceof Y_){let W=$[U+1].value;Q.push(_.getAttribute(W)||""),U+=3}else return;return Q.join("")}catch{}}function pX(_){let J=_.getAttribute("aria-labelledby");if(J===null)return null;let Z=G_(_,J);return Z.length?Z:null}function cX(_,J){let Z=["button","cell","checkbox","columnheader","gridcell","heading","link","menuitem","menuitemcheckbox","menuitemradio","option","radio","row","rowheader","switch","tab","tooltip","treeitem"].includes(_),$=J&&["","caption","code","contentinfo","definition","deletion","emphasis","insertion","list","listitem","mark","none","paragraph","presentation","region","row","rowgroup","section","strong","subscript","superscript","table","term","time"].includes(_);return Z||$}function xJ(_,J){let Z=J?y_:b_,$=Z?.get(_);if($===void 0){if($="",!["caption","code","definition","deletion","emphasis","generic","insertion","mark","paragraph","presentation","strong","subscript","suggestion","superscript","term","time"].includes(f(_)||""))$=hX(v(_,{includeHidden:J,visitedElements:new Set,embeddedInTargetElement:"self"}));Z?.set(_,$)}return $}var vJ=["application","checkbox","columnheader","combobox","gridcell","listbox","radiogroup","rowheader","searchbox","slider","spinbutton","switch","textbox","tree"];function gJ(_){let J=_.getAttribute("aria-invalid");if(!J||J.trim()===""||J.toLocaleLowerCase()==="false")return"false";if(J==="true"||J==="grammar"||J==="spelling")return J;return"true"}function v(_,J){if(J.visitedElements.has(_))return"";let Z={...J,embeddedInTargetElement:J.embeddedInTargetElement==="self"?"descendant":J.embeddedInTargetElement};if(!J.includeHidden){let Y=!!J.embeddedInLabelledBy?.hidden||!!J.embeddedInDescribedBy?.hidden||!!J.embeddedInNativeTextAlternative?.hidden||!!J.embeddedInLabel?.hidden;if(SJ(_)||!Y&&y(_))return J.visitedElements.add(_),""}let $=pX(_);if(!J.embeddedInLabelledBy){let Y=($||[]).map((K)=>v(K,{...J,embeddedInLabelledBy:{element:K,hidden:y(K)},embeddedInDescribedBy:void 0,embeddedInTargetElement:void 0,embeddedInLabel:void 0,embeddedInNativeTextAlternative:void 0})).join(" ");if(Y)return Y}let X=f(_)||"",Q=V(_);if(!!J.embeddedInLabel||!!J.embeddedInLabelledBy||J.embeddedInTargetElement==="descendant"){let Y=[..._.labels||[]].includes(_),K=($||[]).includes(_);if(!Y&&!K){if(X==="textbox"){if(J.visitedElements.add(_),Q==="INPUT"||Q==="TEXTAREA")return _.value;return _.textContent||""}if(["combobox","listbox"].includes(X)){J.visitedElements.add(_);let z;if(Q==="SELECT"){if(z=[..._.selectedOptions],!z.length&&_.options.length)z.push(_.options[0])}else{let q=X==="combobox"?PJ(_,"*").find((L)=>f(L)==="listbox"):_;z=q?PJ(q,'[aria-selected="true"]').filter((L)=>f(L)==="option"):[]}if(!z.length&&Q==="INPUT")return _.value;return z.map((q)=>v(q,Z)).join(" ")}if(["progressbar","scrollbar","slider","spinbutton","meter"].includes(X)){if(J.visitedElements.add(_),_.hasAttribute("aria-valuetext"))return _.getAttribute("aria-valuetext")||"";if(_.hasAttribute("aria-valuenow"))return _.getAttribute("aria-valuenow")||"";return _.getAttribute("value")||""}if(["menu"].includes(X))return J.visitedElements.add(_),""}}let U=_.getAttribute("aria-label")||"";if(x(U))return J.visitedElements.add(_),U;if(!["presentation","none"].includes(X)){if(Q==="INPUT"&&["button","submit","reset"].includes(_.type)){J.visitedElements.add(_);let Y=_.value||"";if(x(Y))return Y;if(_.type==="submit")return"Submit";if(_.type==="reset")return"Reset";return _.getAttribute("title")||""}if(Q==="INPUT"&&_.type==="file"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length&&!J.embeddedInLabelledBy)return r(Y,J);return"Choose File"}if(Q==="INPUT"&&_.type==="image"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length&&!J.embeddedInLabelledBy)return r(Y,J);let K=_.getAttribute("alt")||"";if(x(K))return K;let z=_.getAttribute("title")||"";if(x(z))return z;return"Submit"}if(!$&&Q==="BUTTON"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length)return r(Y,J)}if(!$&&Q==="OUTPUT"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length)return r(Y,J);return _.getAttribute("title")||""}if(!$&&(Q==="TEXTAREA"||Q==="SELECT"||Q==="INPUT")){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length)return r(Y,J);let K=Q==="INPUT"&&["text","password","search","tel","email","url"].includes(_.type)||Q==="TEXTAREA",z=_.getAttribute("placeholder")||"",q=_.getAttribute("title")||"";if(!K||q)return q;return z}if(!$&&Q==="FIELDSET"){J.visitedElements.add(_);for(let K=_.firstElementChild;K;K=K.nextElementSibling)if(V(K)==="LEGEND")return v(K,{...Z,embeddedInNativeTextAlternative:{element:K,hidden:y(K)}});return _.getAttribute("title")||""}if(!$&&Q==="FIGURE"){J.visitedElements.add(_);for(let K=_.firstElementChild;K;K=K.nextElementSibling)if(V(K)==="FIGCAPTION")return v(K,{...Z,embeddedInNativeTextAlternative:{element:K,hidden:y(K)}});return _.getAttribute("title")||""}if(Q==="IMG"){J.visitedElements.add(_);let Y=_.getAttribute("alt")||"";if(x(Y))return Y;return _.getAttribute("title")||""}if(Q==="TABLE"){J.visitedElements.add(_);for(let K=_.firstElementChild;K;K=K.nextElementSibling)if(V(K)==="CAPTION")return v(K,{...Z,embeddedInNativeTextAlternative:{element:K,hidden:y(K)}});let Y=_.getAttribute("summary")||"";if(Y)return Y}if(Q==="AREA"){J.visitedElements.add(_);let Y=_.getAttribute("alt")||"";if(x(Y))return Y;return _.getAttribute("title")||""}if(Q==="SVG"||_.ownerSVGElement){J.visitedElements.add(_);for(let Y=_.firstElementChild;Y;Y=Y.nextElementSibling)if(V(Y)==="TITLE"&&Y.ownerSVGElement)return v(Y,{...Z,embeddedInLabelledBy:{element:Y,hidden:y(Y)}})}if(_.ownerSVGElement&&Q==="A"){let Y=_.getAttribute("xlink:title")||"";if(x(Y))return J.visitedElements.add(_),Y}}let W=Q==="SUMMARY"&&!["presentation","none"].includes(X);if(cX(X,J.embeddedInTargetElement==="descendant")||W||!!J.embeddedInLabelledBy||!!J.embeddedInDescribedBy||!!J.embeddedInLabel||!!J.embeddedInNativeTextAlternative){J.visitedElements.add(_);let Y=mX(_,Z);if(J.embeddedInTargetElement==="self"?x(Y):Y)return Y}if(!["presentation","none"].includes(X)||Q==="IFRAME"){J.visitedElements.add(_);let Y=_.getAttribute("title")||"";if(x(Y))return Y}return J.visitedElements.add(_),""}function mX(_,J){let Z=[],$=(Q,U)=>{if(U&&Q.assignedSlot)return;if(Q.nodeType===1){let W=b(Q)?.display||"inline",Y=v(Q,J);if(W!=="inline"||Q.nodeName==="BR")Y=" "+Y+" ";Z.push(Y)}else if(Q.nodeType===3)Z.push(Q.textContent||"")};Z.push(c(_,"::before")||"");let X=c(_);if(X!==void 0)Z.push(X);else{let Q=_.nodeName==="SLOT"?_.assignedNodes():[];if(Q.length)for(let U of Q)$(U,!1);else{for(let U=_.firstChild;U;U=U.nextSibling)$(U,!0);if(_.shadowRoot)for(let U=_.shadowRoot.firstChild;U;U=U.nextSibling)$(U,!0);for(let U of G_(_,_.getAttribute("aria-owns")))$(U,!0)}}return Z.push(c(_,"::after")||""),Z.join("")}var w_=["gridcell","option","row","tab","rowheader","columnheader","treeitem"];function NJ(_){if(V(_)==="OPTION")return _.selected;if(w_.includes(f(_)||""))return yJ(_.getAttribute("aria-selected"))===!0;return!1}var A_=["checkbox","menuitemcheckbox","option","radio","switch","menuitemradio","treeitem"];function kJ(_){let J=dX(_,!0);return J==="error"?!1:J}function dX(_,J){let Z=V(_);if(J&&Z==="INPUT"&&_.indeterminate)return"mixed";if(Z==="INPUT"&&["checkbox","radio"].includes(_.type))return _.checked;if(A_.includes(f(_)||"")){let $=_.getAttribute("aria-checked");if($==="true")return!0;if(J&&$==="mixed")return"mixed";return!1}return"error"}var E_=["button"];function hJ(_){if(E_.includes(f(_)||"")){let J=_.getAttribute("aria-pressed");if(J==="true")return!0;if(J==="mixed")return"mixed"}return!1}var P_=["application","button","checkbox","combobox","gridcell","link","listbox","menuitem","row","rowheader","tab","treeitem","columnheader","menuitemcheckbox","menuitemradio","rowheader","switch"];function uJ(_){if(V(_)==="DETAILS")return _.open;if(P_.includes(f(_)||"")){let J=_.getAttribute("aria-expanded");if(J===null)return;if(J==="true")return!0;return!1}return}var f_=["heading","listitem","row","treeitem"];function pJ(_){let J={H1:1,H2:2,H3:3,H4:4,H5:5,H6:6}[V(_)];if(J)return J;if(f_.includes(f(_)||"")){let Z=_.getAttribute("aria-level"),$=Z===null?Number.NaN:Number(Z);if(Number.isInteger($)&&$>=1)return $}return 0}var C_=["application","button","composite","gridcell","group","input","link","menuitem","scrollbar","separator","tab","checkbox","columnheader","combobox","grid","listbox","menu","menubar","menuitemcheckbox","menuitemradio","option","radio","radiogroup","row","rowheader","searchbox","select","slider","spinbutton","switch","tablist","textbox","toolbar","tree","treegrid","treeitem"];function cJ(_){return mJ(_)||dJ(_)}function mJ(_){return["BUTTON","INPUT","SELECT","TEXTAREA","OPTION","OPTGROUP"].includes(V(_))&&(_.hasAttribute("disabled")||sX(_)||iX(_))}function sX(_){return V(_)==="OPTION"&&!!_.closest("OPTGROUP[DISABLED]")}function iX(_){let J=_?.closest("FIELDSET[DISABLED]");if(!J)return!1;let Z=J.querySelector(":scope > LEGEND");return!Z||!Z.contains(_)}function dJ(_,J=!1){if(!_)return!1;if(J||C_.includes(f(_)||"")){let Z=(_.getAttribute("aria-disabled")||"").toLowerCase();if(Z==="true")return!0;if(Z==="false")return!1;return dJ(h(_),!0)}return!1}function r(_,J){return[..._].map((Z)=>v(Z,{...J,embeddedInLabel:{element:Z,hidden:y(Z)},embeddedInNativeTextAlternative:void 0,embeddedInLabelledBy:void 0,embeddedInDescribedBy:void 0,embeddedInTargetElement:void 0})).filter((Z)=>!!Z).join(" ")}function sJ(_){let J=v_,Z=_,$,X=[];for(;Z;Z=h(Z)){let Q=J.get(Z);if(Q!==void 0){$=Q;break}X.push(Z);let U=b(Z);if(!U){$=!0;break}let W=U.pointerEvents;if(W){$=W!=="none";break}}if($===void 0)$=!0;for(let Q of X)J.set(Q,$);return $}var b_,y_,iJ,lJ,rJ,q_,S_,T_,x_,v_,aJ=0;function nJ(){i_(),++aJ,b_??=new Map,y_??=new Map,iJ??=new Map,lJ??=new Map,rJ??=new Map,q_??=new Map,S_??=new Map,T_??=new Map,x_??=new Map,v_??=new Map}function oJ(){if(!--aJ)b_=void 0,y_=void 0,iJ=void 0,lJ=void 0,rJ=void 0,q_=void 0,S_=void 0,T_=void 0,x_=void 0,v_=void 0;l_()}var lX={button:"button",checkbox:"checkbox",image:"button",number:"spinbutton",radio:"radio",range:"slider",reset:"button",submit:"button"};var aX=0;function eJ(_){let J=_.boxes;if(_.mode==="ai")return{visibility:"ariaOrVisible",refs:"interactable",refPrefix:_.refPrefix,includeGenericRole:!0,renderActive:!_.doNotRenderActive,renderCursorPointer:!0,renderBoxes:J};if(_.mode==="autoexpect")return{visibility:"ariaAndVisible",refs:"none",renderBoxes:J};if(_.mode==="codegen")return{visibility:"aria",refs:"none",renderStringsAsRegex:!0,renderBoxes:J};return{visibility:"aria",refs:"none",renderBoxes:J}}function _X(_,J){let Z=eJ(J),$=new Set,X={root:{role:"fragment",name:"",children:[],props:{},box:i(_),receivesPointerEvents:!0},elements:new Map,refs:new Map,iframeRefs:[]};g_(X.root,_);let Q=(W,Y,K)=>{if($.has(Y))return;if($.add(Y),Y.nodeType===Node.TEXT_NODE&&Y.nodeValue){if(!K)return;let F=Y.nodeValue;if(W.role!=="textbox"&&F)W.children.push(Y.nodeValue||"");return}if(Y.nodeType!==Node.ELEMENT_NODE)return;let z=Y,q=!y(z),L=q;if(Z.visibility==="ariaOrVisible")L=q||__(z);if(Z.visibility==="ariaAndVisible")L=q&&__(z);if(Z.visibility==="aria"&&!L)return;let I=[];if(z.hasAttribute("aria-owns")){let F=z.getAttribute("aria-owns").split(/\s+/);for(let j of F){let w=_.ownerDocument.getElementById(j);if(w)I.push(w)}}let H=L?nX(z,Z):null;if(H){if(H.ref){if(X.elements.set(H.ref,z),X.refs.set(z,H.ref),H.role==="iframe")X.iframeRefs.push(H.ref)}W.children.push(H)}U(H||W,z,I,L)};function U(W,Y,K,z){let L=(b(Y)?.display||"inline")!=="inline"||Y.nodeName==="BR"?" ":"";if(L)W.children.push(L);W.children.push(c(Y,"::before")||"");let I=Y.nodeName==="SLOT"?Y.assignedNodes():[];if(I.length)for(let H of I)Q(W,H,z);else{for(let H=Y.firstChild;H;H=H.nextSibling)if(!H.assignedSlot)Q(W,H,z);if(Y.shadowRoot)for(let H=Y.shadowRoot.firstChild;H;H=H.nextSibling)Q(W,H,z)}for(let H of K)Q(W,H,z);if(W.children.push(c(Y,"::after")||""),L)W.children.push(L);if(W.children.length===1&&W.name===W.children[0])W.children=[];if(W.role==="link"&&Y.hasAttribute("href")){let H=Y.getAttribute("href");W.props.url=H}if(W.role==="textbox"&&Y.hasAttribute("placeholder")&&Y.getAttribute("placeholder")!==W.name){let H=Y.getAttribute("placeholder");W.props.placeholder=H}}nJ();try{Q(X.root,_,!0)}finally{oJ()}return tX(X.root),oX(X.root),X}function tJ(_,J){if(J.refs==="none")return;if(J.refs==="interactable"&&(!_.box.visible||!_.receivesPointerEvents))return;let Z=$X(_),$=Z._ariaRef;if(!$||$.role!==_.role||$.name!==_.name)$={role:_.role,name:_.name,ref:(J.refPrefix??"")+"e"+ ++aX},Z._ariaRef=$;_.ref=$.ref}function nX(_,J){let Z=_.ownerDocument.activeElement===_;if(_.nodeName==="IFRAME"){let K={role:"iframe",name:"",children:[],props:{},box:i(_),receivesPointerEvents:!0,active:Z};return g_(K,_),tJ(K,J),K}let $=J.includeGenericRole?"generic":null,X=f(_)??$;if(!X||X==="presentation"||X==="none")return null;let Q=j_(xJ(_,!1)||""),U=sJ(_),W=i(_);if(X==="generic"&&W.inline&&_.childNodes.length===1&&_.childNodes[0].nodeType===Node.TEXT_NODE)return null;let Y={role:X,name:Q,children:[],props:{},box:W,receivesPointerEvents:U,active:Z};if(g_(Y,_),tJ(Y,J),A_.includes(X))Y.checked=kJ(_);if(C_.includes(X))Y.disabled=cJ(_);if(P_.includes(X))Y.expanded=uJ(_);if(vJ.includes(X)){let K=gJ(_);Y.invalid=K==="false"?!1:K==="true"?!0:K}if(f_.includes(X))Y.level=pJ(_);if(E_.includes(X))Y.pressed=hJ(_);if(w_.includes(X))Y.selected=NJ(_);if(_ instanceof HTMLInputElement||_ instanceof HTMLTextAreaElement){if(_.type!=="checkbox"&&_.type!=="radio"&&_.type!=="file")Y.children=[_.value]}return Y}function oX(_){let J=(Z)=>{let $=[];for(let Q of Z.children||[]){if(typeof Q==="string"){$.push(Q);continue}let U=J(Q);$.push(...U)}if(Z.role==="generic"&&!Z.name&&$.length<=1&&$.every((Q)=>typeof Q!=="string"&&!!Q.ref))return $;return Z.children=$,[Z]};J(_)}function tX(_){let J=($,X)=>{if(!$.length)return;let Q=j_($.join(""));if(Q)X.push(Q);$.length=0},Z=($)=>{let X=[],Q=[];for(let U of $.children||[])if(typeof U==="string")Q.push(U);else J(Q,X),Z(U),X.push(U);if(J(Q,X),$.children=X.length?X:[],$.children.length===1&&$.children[0]===$.name)$.children=[]};Z(_)}var jZ=Symbol("cachedRegex");function JX(_,J=new Map){if(_?.ref)J.set(_.ref,_);for(let Z of _?.children||[])if(typeof Z!=="string")JX(Z,J);return J}function eX(_,J){let Z=JX(J?.root),$=new Map,X=(Q,U)=>{let W=Q.children.length===U?.children.length&&h_(Q,U),Y=W;for(let K=0;K<Q.children.length;K++){let z=Q.children[K],q=U?.children[K];if(typeof z==="string")W&&=z===q,Y&&=z===q;else{let L=typeof q!=="string"?q:void 0;if(z.ref)L=Z.get(z.ref);let I=X(z,L);if(!L||!I&&!z.ref||L!==q)Y=!1;W&&=I&&L===q}}return $.set(Q,W?"same":Y?"skip":"changed"),W};return X(_.root,Z.get(J?.root?.ref)),$}function _Z(_,J){let Z=[],$=(X)=>{let Q=J.get(X);if(Q==="same");else if(Q==="skip"){for(let U of X.children)if(typeof U!=="string")$(U)}else Z.push(X)};for(let X of _)if(typeof X==="string")Z.push(X);else $(X);return Z}function U_(_){return" ".repeat(_)}function XX(_,J,Z){let $=eJ(J),X=[],Q={},U=$.renderStringsAsRegex?XZ:()=>!0,W=$.renderStringsAsRegex?JZ:(H)=>H,Y=_.root.role==="fragment"?_.root.children:[_.root],K=eX(_,Z);if(Z)Y=_Z(Y,K);let z=(H,F)=>{if(J.depth&&F>J.depth)return;let j=e(W(H));if(j)X.push(U_(F)+"- text: "+j)},q=(H,F)=>{let j=H.role;if(H.name&&H.name.length<=900){let w=W(H.name);if(w){let E=w.startsWith("/")&&w.endsWith("/")?w:JSON.stringify(w);j+=" "+E}}if(H.checked==="mixed")j+=" [checked=mixed]";if(H.checked===!0)j+=" [checked]";if(H.disabled)j+=" [disabled]";if(H.expanded)j+=" [expanded]";if(H.active&&$.renderActive)j+=" [active]";if(H.invalid==="grammar"||H.invalid==="spelling")j+=` [invalid=${H.invalid}]`;if(H.invalid===!0)j+=" [invalid]";if(H.level)j+=` [level=${H.level}]`;if(H.pressed==="mixed")j+=" [pressed=mixed]";if(H.pressed===!0)j+=" [pressed]";if(H.selected===!0)j+=" [selected]";if(H.ref){if(j+=` [ref=${H.ref}]`,F&&d(H))j+=" [cursor=pointer]"}if($.renderBoxes){let w=$X(H);if(w){let E=w.getBoundingClientRect();j+=` [box=${Math.round(E.x)},${Math.round(E.y)},${Math.round(E.width)},${Math.round(E.height)}]`}}return j},L=(H)=>{return H?.children.length===1&&typeof H.children[0]==="string"&&!Object.keys(H.props).length?H.children[0]:void 0},I=(H,F,j)=>{if(J.depth&&F>J.depth)return;if(H.role==="iframe"&&H.ref)Q[H.ref]=F;if(K.get(H)==="same"&&H.ref){X.push(U_(F)+`- ref=${H.ref} [unchanged]`);return}let w=!!Z&&!F,E=U_(F)+"- "+(w?"<changed> ":"")+c_(q(H,j)),S=L(H),m=!!J.depth&&F===J.depth;if(!S&&(!H.children.length||m)&&!Object.keys(H.props).length)X.push(E);else if(S!==void 0)if(U(H,S))X.push(E+": "+e(W(S)));else X.push(E);else{X.push(E+":");for(let[C,k]of Object.entries(H.props))X.push(U_(F+1)+"- /"+C+": "+e(k));let a=!!H.ref&&j&&d(H);for(let C of H.children)if(typeof C==="string")z(U(H,C)?C:"",F+1);else I(C,F+1,j&&!a)}};for(let H of Y)if(typeof H==="string")z(H,0);else I(H,0,!!$.renderCursorPointer);return{text:X.join(`
|
|
7
|
+
`),iframeDepths:Q}}function JZ(_){let J=[{regex:/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/,replacement:"[0-9a-fA-F-]+"},{regex:/\b[\d,.]+[bkmBKM]+\b/,replacement:"[\\d,.]+[bkmBKM]+"},{regex:/\b\d+[hmsp]+\b/,replacement:"\\d+[hmsp]+"},{regex:/\b[\d,.]+[hmsp]+\b/,replacement:"[\\d,.]+[hmsp]+"},{regex:/\b\d+,\d+\b/,replacement:"\\d+,\\d+"},{regex:/\b\d+\.\d{2,}\b/,replacement:"\\d+\\.\\d+"},{regex:/\b\d{2,}\.\d+\b/,replacement:"\\d+\\.\\d+"},{regex:/\b\d{2,}\b/,replacement:"\\d+"}],Z="",$=0,X=new RegExp(J.map((Q)=>"("+Q.regex.source+")").join("|"),"g");if(_.replace(X,(Q,...U)=>{let W=U[U.length-2],Y=U.slice(0,-2);Z+=F_(_.slice($,W));for(let K=0;K<Y.length;K++)if(Y[K]){let{replacement:z}=J[K];Z+=z;break}return $=W+Q.length,Q}),!Z)return _;return Z+=F_(_.slice($)),String(new RegExp(Z))}function XZ(_,J){if(!J.length)return!1;if(!_.name)return!0;let Z=J.length<=200&&_.name.length<=200?p_(J,_.name):"",$=J;while(Z&&$.includes(Z))$=$.replace(Z,"");return $.trim().length/J.length>0.1}var ZX=Symbol("element");function $X(_){return _[ZX]}function g_(_,J){_[ZX]=J}function YX(_){let J=(Z)=>{for(let $ of Array.from(Z.querySelectorAll("*"))){_($);let X=$.shadowRoot;if(X)J(X)}};J(document)}function ZZ(_,J={}){YX((Q)=>{if(Q._ariaRef)delete Q._ariaRef});let Z=_??document.body??document.documentElement,$={mode:"ai",depth:J.depth,boxes:J.boxes},X=_X(Z,$);return XX(X,$).text}function $Z(_){let J=null;return YX((Z)=>{if(!J&&Z._ariaRef?.ref===_)J=Z}),J}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { ElementHandle, JSHandle, Page } from "puppeteer-core";
|
|
2
|
+
import ariaBundle from "./aria-snapshot.bundle.txt" with { type: "text" };
|
|
3
|
+
// `aria-snapshot.bundle.txt` is a generated, committed artifact: Playwright's
|
|
4
|
+
// injected ARIA-snapshot sources (pinned, Apache-2.0) bundled to a CJS module.
|
|
5
|
+
// The upstream sources are NOT vendored — regenerate the bundle with:
|
|
6
|
+
// bun scripts/generate-aria-snapshot.ts
|
|
7
|
+
// (fetches the pinned tag, bundles in a temp dir, rewrites the .txt artifact.)
|
|
8
|
+
|
|
9
|
+
export interface AriaSnapshotOptions {
|
|
10
|
+
/** Maximum tree depth to render. */
|
|
11
|
+
depth?: number;
|
|
12
|
+
/** Append `[box=x,y,w,h]` bounding boxes to each node. */
|
|
13
|
+
boxes?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Page-side evaluators built ONCE here in the worker — never inside the page, so
|
|
18
|
+
* page CSP never applies. They run the generated Playwright ARIA-snapshot bundle
|
|
19
|
+
* (CJS, see scripts/generate-aria-snapshot.ts) in a throwaway module scope.
|
|
20
|
+
*
|
|
21
|
+
* Puppeteer serializes these functions to a CDP `Runtime.evaluate` in the page's
|
|
22
|
+
* MAIN world (the only world where the bundle's `_ariaRef` ref expandos live —
|
|
23
|
+
* isolated-world locators/query-handlers cannot see them). Nothing is installed
|
|
24
|
+
* on `window`; the only footprint is the `_ariaRef` markers the snapshot writes,
|
|
25
|
+
* which are the price of actionable `[ref=eN]` ids.
|
|
26
|
+
*/
|
|
27
|
+
function buildEvaluator(params: string, call: string): (...args: unknown[]) => unknown {
|
|
28
|
+
return new Function(
|
|
29
|
+
...params.split(",").map(p => p.trim()),
|
|
30
|
+
`var module = { exports: {} };\n${ariaBundle}\nreturn module.exports.${call};`,
|
|
31
|
+
) as unknown as (...args: unknown[]) => unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Handles (root) must stay top-level args: Puppeteer only unwraps JSHandles
|
|
35
|
+
// passed positionally to page.evaluate, never ones nested inside an object.
|
|
36
|
+
const evaluateAriaSnapshot = buildEvaluator("root, request", "ariaSnapshot(root, request)");
|
|
37
|
+
const evaluateResolveRef = buildEvaluator("ref", "resolveAriaRef(ref)");
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Capture a Playwright-format ARIA snapshot of `root` (or the whole document when
|
|
41
|
+
* null). Always runs in `ai` mode so every node carries a `[ref=eN]` id; resolve
|
|
42
|
+
* those to elements with {@link resolveAriaRefHandle}. Ids are renumbered from e1
|
|
43
|
+
* on each call and remain valid until the next snapshot.
|
|
44
|
+
*/
|
|
45
|
+
export async function captureAriaSnapshot(
|
|
46
|
+
page: Page,
|
|
47
|
+
root: ElementHandle | null,
|
|
48
|
+
options: AriaSnapshotOptions = {},
|
|
49
|
+
): Promise<string> {
|
|
50
|
+
const request = { depth: options.depth, boxes: options.boxes };
|
|
51
|
+
return (await page.evaluate(evaluateAriaSnapshot as never, root as never, request as never)) as string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a `[ref=eN]` id from the latest snapshot to a live `ElementHandle`, or
|
|
56
|
+
* null when the ref no longer matches any element. Runs in the main world so it
|
|
57
|
+
* sees the `_ariaRef` expandos the snapshot wrote.
|
|
58
|
+
*/
|
|
59
|
+
export async function resolveAriaRefHandle(page: Page, ref: string): Promise<ElementHandle | null> {
|
|
60
|
+
const handle = (await page.evaluateHandle(evaluateResolveRef as never, ref as never)) as JSHandle;
|
|
61
|
+
const element = handle.asElement();
|
|
62
|
+
if (!element) {
|
|
63
|
+
await handle.dispose().catch(() => undefined);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return element as ElementHandle;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const ARIA_REF_PREFIXES = ["aria-ref=", "aria-ref/", "ariaref/"];
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Recognize the explicit `[ref=eN]` selector forms and return the bare ref id,
|
|
73
|
+
* else null. Accepts `aria-ref=e5` (Playwright-MCP style), `aria-ref/e5`, and
|
|
74
|
+
* `ariaref/e5` — lets `tab.click("aria-ref=e5")` etc. act on snapshot refs. A
|
|
75
|
+
* bare `e5` is intentionally NOT a ref selector: the cmux backend already uses
|
|
76
|
+
* bare `eN`/`@eN` for its own observe ids, so requiring the prefix keeps action
|
|
77
|
+
* selectors meaning the same thing on both backends. (`tab.ref("e5")` still
|
|
78
|
+
* accepts a bare id directly.)
|
|
79
|
+
*/
|
|
80
|
+
export function parseAriaRefSelector(selector: string): string | null {
|
|
81
|
+
const trimmed = selector.trim();
|
|
82
|
+
for (const prefix of ARIA_REF_PREFIXES) {
|
|
83
|
+
if (trimmed.startsWith(prefix)) {
|
|
84
|
+
const id = trimmed.slice(prefix.length).trim();
|
|
85
|
+
return /^e\d+$/.test(id) ? id : null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Build a self-contained expression script that runs the vendored bundle in the
|
|
93
|
+
* page and returns the ARIA snapshot YAML. Used by the cmux backend, whose
|
|
94
|
+
* `browser.eval` RPC takes a script string and returns the completion value (it
|
|
95
|
+
* has no ElementHandle to pass in). The script resolves `selector` via
|
|
96
|
+
* `document.querySelector` in-page (CSS selectors only) or falls back to the
|
|
97
|
+
* whole document. Like the puppeteer path it installs nothing on `window`.
|
|
98
|
+
*/
|
|
99
|
+
export function buildAriaSnapshotScript(selector: string | undefined, options: AriaSnapshotOptions = {}): string {
|
|
100
|
+
const request = { depth: options.depth, boxes: options.boxes };
|
|
101
|
+
const sel = selector ? JSON.stringify(selector) : "null";
|
|
102
|
+
return `(function(){var module={exports:{}};\n${ariaBundle}\nvar __sel=${sel};var __root=__sel?document.querySelector(__sel):null;if(__sel&&!__root)throw new Error("tab.ariaSnapshot: selector "+__sel+" matched no element");return module.exports.ariaSnapshot(__root,${JSON.stringify(request)});})()`;
|
|
103
|
+
}
|