autokap 1.0.7 → 1.0.10
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/assets/cursors/macos.svg +4 -0
- package/assets/cursors/windows.svg +15 -0
- package/assets/skill/OPCODE-REFERENCE.md +635 -0
- package/assets/skill/README.md +39 -0
- package/assets/skill/SKILL.md +454 -468
- package/assets/skill/STUDIO-SKILL.md +476 -0
- package/assets/skill/references/examples.md +104 -0
- package/assets/skill/references/interactive-demo.md +225 -0
- package/assets/skill/references/mock-data.md +178 -0
- package/dist/action-verifier.d.ts +29 -0
- package/dist/action-verifier.js +133 -0
- package/dist/agent-action-recovery.d.ts +45 -0
- package/dist/agent-action-recovery.js +370 -0
- package/dist/agent-message-utils.d.ts +21 -0
- package/dist/agent-message-utils.js +77 -0
- package/dist/agent-url-utils.d.ts +30 -0
- package/dist/agent-url-utils.js +138 -0
- package/dist/agent.d.ts +92 -8
- package/dist/agent.js +2936 -781
- package/dist/ak-tree.d.ts +39 -0
- package/dist/ak-tree.js +368 -0
- package/dist/alt-text.d.ts +26 -0
- package/dist/alt-text.js +55 -0
- package/dist/auth-capture.d.ts +17 -0
- package/dist/auth-capture.js +197 -0
- package/dist/benchmark.d.ts +59 -0
- package/dist/benchmark.js +135 -0
- package/dist/billing-operation-logging.d.ts +3 -1
- package/dist/billing-operation-logging.js +4 -0
- package/dist/browser-bar.d.ts +14 -6
- package/dist/browser-bar.js +145 -8
- package/dist/browser-pool.d.ts +7 -0
- package/dist/browser-pool.js +15 -5
- package/dist/browser-utils.d.ts +31 -0
- package/dist/browser-utils.js +97 -0
- package/dist/browser.d.ts +61 -11
- package/dist/browser.js +1513 -59
- package/dist/capture-alt-text.js +2 -1
- package/dist/capture-encryption.d.ts +3 -1
- package/dist/capture-encryption.js +21 -6
- package/dist/capture-language-preflight.js +14 -0
- package/dist/capture-llm-page-identity.js +22 -10
- package/dist/capture-page-identity.d.ts +5 -7
- package/dist/capture-page-identity.js +211 -78
- package/dist/capture-preset-credentials.d.ts +50 -0
- package/dist/capture-preset-credentials.js +127 -0
- package/dist/capture-request-plan.d.ts +2 -2
- package/dist/capture-request-plan.js +64 -16
- package/dist/capture-run-optimizer.js +48 -33
- package/dist/capture-selector-memory.d.ts +5 -0
- package/dist/capture-selector-memory.js +18 -0
- package/dist/capture-strategy.d.ts +36 -0
- package/dist/capture-strategy.js +96 -0
- package/dist/capture-studio-sync.d.ts +1 -0
- package/dist/capture-studio-sync.js +9 -3
- package/dist/capture-surface-contract.d.ts +36 -0
- package/dist/capture-surface-contract.js +299 -0
- package/dist/capture-transition-engine.d.ts +28 -0
- package/dist/capture-transition-engine.js +292 -0
- package/dist/capture-variant-state.d.ts +2 -0
- package/dist/capture-variant-state.js +26 -0
- package/dist/capture-verification.d.ts +35 -0
- package/dist/capture-verification.js +95 -0
- package/dist/capture-viewport-lock.d.ts +48 -0
- package/dist/capture-viewport-lock.js +74 -0
- package/dist/circuit-breaker.d.ts +42 -0
- package/dist/circuit-breaker.js +119 -0
- package/dist/cli-config.d.ts +9 -1
- package/dist/cli-config.js +112 -7
- package/dist/cli-contract.d.ts +19 -0
- package/dist/cli-contract.js +173 -0
- package/dist/cli-runner-local.d.ts +12 -0
- package/dist/cli-runner-local.js +115 -0
- package/dist/cli-runner.d.ts +34 -0
- package/dist/cli-runner.js +580 -0
- package/dist/cli-utils.d.ts +0 -1
- package/dist/cli-utils.js +2 -5
- package/dist/cli.js +1011 -267
- package/dist/clip-begin-frame-recorder.d.ts +44 -0
- package/dist/clip-begin-frame-recorder.js +250 -0
- package/dist/clip-capture-backend.d.ts +25 -0
- package/dist/clip-capture-backend.js +189 -0
- package/dist/clip-capture-loop.d.ts +61 -0
- package/dist/clip-capture-loop.js +111 -0
- package/dist/clip-frame-recorder.d.ts +63 -0
- package/dist/clip-frame-recorder.js +305 -0
- package/dist/clip-orchestrator.js +9 -2
- package/dist/clip-postprocess.d.ts +31 -2
- package/dist/clip-postprocess.js +194 -68
- package/dist/clip-runtime.d.ts +18 -0
- package/dist/clip-runtime.js +67 -0
- package/dist/clip-scale.d.ts +10 -0
- package/dist/clip-scale.js +21 -0
- package/dist/clip-screencast-recorder.d.ts +42 -0
- package/dist/clip-screencast-recorder.js +242 -0
- package/dist/clip-sidecar.d.ts +54 -0
- package/dist/clip-sidecar.js +208 -0
- package/dist/cookie-dismiss.d.ts +2 -0
- package/dist/cookie-dismiss.js +48 -13
- package/dist/cost-logging.d.ts +8 -0
- package/dist/cost-logging.js +160 -46
- package/dist/cost-resolution-monitor.d.ts +16 -0
- package/dist/cost-resolution-monitor.js +34 -0
- package/dist/credential-templates.js +2 -2
- package/dist/cursor-overlay-script.d.ts +6 -0
- package/dist/cursor-overlay-script.js +169 -0
- package/dist/dom-css-purger.d.ts +65 -0
- package/dist/dom-css-purger.js +333 -0
- package/dist/dom-font-inliner.d.ts +45 -0
- package/dist/dom-font-inliner.js +148 -0
- package/dist/dom-patch-resolver.d.ts +52 -0
- package/dist/dom-patch-resolver.js +242 -0
- package/dist/dom-serializer.d.ts +82 -0
- package/dist/dom-serializer.js +378 -0
- package/dist/element-capture.d.ts +1 -41
- package/dist/element-capture.js +202 -446
- package/dist/env-validation.d.ts +5 -0
- package/dist/env-validation.js +63 -0
- package/dist/execution-schema.d.ts +4753 -0
- package/dist/execution-schema.js +563 -0
- package/dist/execution-types.d.ts +936 -0
- package/dist/execution-types.js +66 -0
- package/dist/fonts-loader.d.ts +14 -0
- package/dist/fonts-loader.js +55 -0
- package/dist/hybrid-navigator.js +12 -12
- package/dist/index.d.ts +11 -6
- package/dist/index.js +11 -4
- package/dist/legacy/agent-action-recovery.d.ts +45 -0
- package/dist/legacy/agent-action-recovery.js +370 -0
- package/dist/legacy/agent-message-utils.d.ts +21 -0
- package/dist/legacy/agent-message-utils.js +77 -0
- package/dist/legacy/agent-url-utils.d.ts +30 -0
- package/dist/legacy/agent-url-utils.js +138 -0
- package/dist/legacy/agent.d.ts +226 -0
- package/dist/legacy/agent.js +6666 -0
- package/dist/legacy/clip-orchestrator.d.ts +148 -0
- package/dist/legacy/clip-orchestrator.js +957 -0
- package/dist/legacy/credential-templates.d.ts +5 -0
- package/dist/legacy/credential-templates.js +60 -0
- package/dist/legacy/hybrid-navigator.d.ts +138 -0
- package/dist/legacy/hybrid-navigator.js +468 -0
- package/dist/legacy/llm-usage.d.ts +17 -0
- package/dist/legacy/llm-usage.js +45 -0
- package/dist/legacy/prompt-cache.d.ts +10 -0
- package/dist/legacy/prompt-cache.js +24 -0
- package/dist/legacy/prompts.d.ts +175 -0
- package/dist/legacy/prompts.js +1038 -0
- package/dist/legacy/tools.d.ts +4 -0
- package/dist/legacy/tools.js +216 -0
- package/dist/legacy/video-agent.d.ts +143 -0
- package/dist/legacy/video-agent.js +4788 -0
- package/dist/legacy/video-observation.d.ts +36 -0
- package/dist/legacy/video-observation.js +192 -0
- package/dist/legacy/video-planner.d.ts +12 -0
- package/dist/legacy/video-planner.js +501 -0
- package/dist/legacy/video-prompts.d.ts +37 -0
- package/dist/legacy/video-prompts.js +569 -0
- package/dist/legacy/video-tools.d.ts +3 -0
- package/dist/legacy/video-tools.js +59 -0
- package/dist/legacy/video-variant-state.d.ts +29 -0
- package/dist/legacy/video-variant-state.js +80 -0
- package/dist/legacy/vision-model.d.ts +17 -0
- package/dist/legacy/vision-model.js +74 -0
- package/dist/llm-healer.d.ts +55 -0
- package/dist/llm-healer.js +213 -0
- package/dist/llm-provider.d.ts +29 -0
- package/dist/llm-provider.js +83 -0
- package/dist/logger.d.ts +6 -2
- package/dist/logger.js +15 -1
- package/dist/mockup-html.js +35 -25
- package/dist/mockup.d.ts +95 -2
- package/dist/mockup.js +427 -166
- package/dist/mouse-animation.d.ts +2 -2
- package/dist/mouse-animation.js +34 -20
- package/dist/opcode-actions.d.ts +42 -0
- package/dist/opcode-actions.js +524 -0
- package/dist/opcode-runner.d.ts +51 -0
- package/dist/opcode-runner.js +779 -0
- package/dist/openrouter-client.d.ts +40 -0
- package/dist/openrouter-client.js +16 -0
- package/dist/overlay-engine.d.ts +24 -0
- package/dist/overlay-engine.js +176 -0
- package/dist/postcondition.d.ts +16 -0
- package/dist/postcondition.js +269 -0
- package/dist/program-patcher.d.ts +25 -0
- package/dist/program-patcher.js +44 -0
- package/dist/program-signing.d.ts +1094 -0
- package/dist/program-signing.js +140 -0
- package/dist/prompts.d.ts +13 -5
- package/dist/prompts.js +224 -351
- package/dist/provider-config.d.ts +17 -0
- package/dist/provider-config.js +42 -0
- package/dist/recovery-chain.d.ts +37 -0
- package/dist/recovery-chain.js +374 -0
- package/dist/remote-browser.d.ts +28 -4
- package/dist/remote-browser.js +60 -5
- package/dist/safari-browser-bar.d.ts +15 -0
- package/dist/safari-browser-bar.js +95 -0
- package/dist/safari-toolbar-asset.d.ts +15 -0
- package/dist/safari-toolbar-asset.js +12 -0
- package/dist/security.d.ts +2 -1
- package/dist/security.js +49 -10
- package/dist/selector-resolver.d.ts +34 -0
- package/dist/selector-resolver.js +181 -0
- package/dist/semantic-resolver.d.ts +35 -0
- package/dist/semantic-resolver.js +161 -0
- package/dist/server-capture-runtime.d.ts +5 -3
- package/dist/server-capture-runtime.js +42 -95
- package/dist/server-credit-usage.d.ts +2 -2
- package/dist/server-project-webhooks.d.ts +15 -1
- package/dist/server-project-webhooks.js +34 -8
- package/dist/server-screenshot-watermark.js +27 -5
- package/dist/session-profile.js +164 -1
- package/dist/sf-pro-symbols.d.ts +1 -0
- package/dist/sf-pro-symbols.js +55 -0
- package/dist/skill-packaging.d.ts +28 -0
- package/dist/skill-packaging.js +169 -0
- package/dist/smart-wait.d.ts +27 -0
- package/dist/smart-wait.js +81 -0
- package/dist/status-bar-render.d.ts +20 -0
- package/dist/status-bar-render.js +410 -0
- package/dist/status-bar.d.ts +9 -0
- package/dist/status-bar.js +298 -14
- package/dist/svg-browser-bar.d.ts +33 -0
- package/dist/svg-browser-bar.js +206 -0
- package/dist/svg-status-bar.d.ts +36 -0
- package/dist/svg-status-bar.js +597 -0
- package/dist/svg-text.d.ts +61 -0
- package/dist/svg-text.js +118 -0
- package/dist/tools.js +89 -451
- package/dist/types.d.ts +248 -7
- package/dist/types.js +23 -1
- package/dist/v2/action-verifier.d.ts +29 -0
- package/dist/v2/action-verifier.js +133 -0
- package/dist/v2/alt-text.d.ts +26 -0
- package/dist/v2/alt-text.js +55 -0
- package/dist/v2/benchmark.d.ts +59 -0
- package/dist/v2/benchmark.js +135 -0
- package/dist/v2/capture-strategy.d.ts +30 -0
- package/dist/v2/capture-strategy.js +67 -0
- package/dist/v2/capture-verification.d.ts +35 -0
- package/dist/v2/capture-verification.js +95 -0
- package/dist/v2/circuit-breaker.d.ts +42 -0
- package/dist/v2/circuit-breaker.js +119 -0
- package/dist/v2/cli-runner-local.d.ts +11 -0
- package/dist/v2/cli-runner-local.js +91 -0
- package/dist/v2/cli-runner.d.ts +34 -0
- package/dist/v2/cli-runner.js +300 -0
- package/dist/v2/compiler-prompts.d.ts +27 -0
- package/dist/v2/compiler-prompts.js +123 -0
- package/dist/v2/compiler.d.ts +37 -0
- package/dist/v2/compiler.js +147 -0
- package/dist/v2/explorer.d.ts +41 -0
- package/dist/v2/explorer.js +56 -0
- package/dist/v2/index.d.ts +37 -0
- package/dist/v2/index.js +31 -0
- package/dist/v2/llm-healer.d.ts +62 -0
- package/dist/v2/llm-healer.js +166 -0
- package/dist/v2/llm-provider.d.ts +29 -0
- package/dist/v2/llm-provider.js +80 -0
- package/dist/v2/opcode-runner.d.ts +47 -0
- package/dist/v2/opcode-runner.js +634 -0
- package/dist/v2/overlay-engine.d.ts +24 -0
- package/dist/v2/overlay-engine.js +150 -0
- package/dist/v2/postcondition.d.ts +16 -0
- package/dist/v2/postcondition.js +249 -0
- package/dist/v2/program-patcher.d.ts +25 -0
- package/dist/v2/program-patcher.js +44 -0
- package/dist/v2/recovery-chain.d.ts +30 -0
- package/dist/v2/recovery-chain.js +368 -0
- package/dist/v2/schema.d.ts +2580 -0
- package/dist/v2/schema.js +295 -0
- package/dist/v2/selector-resolver.d.ts +34 -0
- package/dist/v2/selector-resolver.js +181 -0
- package/dist/v2/semantic-resolver.d.ts +35 -0
- package/dist/v2/semantic-resolver.js +161 -0
- package/dist/v2/smart-wait.d.ts +27 -0
- package/dist/v2/smart-wait.js +81 -0
- package/dist/v2/types.d.ts +444 -0
- package/dist/v2/types.js +19 -0
- package/dist/v2/web-playwright-local.d.ts +69 -0
- package/dist/v2/web-playwright-local.js +392 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +5 -0
- package/dist/video-agent.js +18 -13
- package/dist/video-planner.js +2 -1
- package/dist/video-prompts.js +3 -3
- package/dist/web-playwright-local.d.ts +156 -0
- package/dist/web-playwright-local.js +989 -0
- package/dist/ws-auth.js +4 -1
- package/dist/ws-broadcast.d.ts +34 -0
- package/dist/ws-broadcast.js +85 -0
- package/dist/ws-connection-limits.d.ts +12 -0
- package/dist/ws-connection-limits.js +44 -0
- package/dist/ws-handler-utils.d.ts +32 -0
- package/dist/ws-handler-utils.js +139 -0
- package/dist/ws-handler.js +294 -164
- package/dist/ws-metrics-server.d.ts +9 -0
- package/dist/ws-metrics-server.js +31 -0
- package/dist/ws-server.js +41 -1
- package/package.json +62 -35
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AKNode, AKNodeRuntimeIndexEntry, AKTree, FocusQuery, InteractiveElement } from './types.js';
|
|
2
|
+
interface FingerprintInput {
|
|
3
|
+
tagName: string;
|
|
4
|
+
role?: string | null;
|
|
5
|
+
textContent?: string | null;
|
|
6
|
+
ariaLabel?: string | null;
|
|
7
|
+
htmlId?: string | null;
|
|
8
|
+
name?: string | null;
|
|
9
|
+
inputType?: string | null;
|
|
10
|
+
href?: string | null;
|
|
11
|
+
placeholder?: string | null;
|
|
12
|
+
bounds: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
w: number;
|
|
16
|
+
h: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface FocusResult {
|
|
20
|
+
tree: AKTree;
|
|
21
|
+
matches: AKNode[];
|
|
22
|
+
serialized: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function toAscii(value: string | null | undefined): string;
|
|
25
|
+
export declare function fingerprintAKNode(input: FingerprintInput): string;
|
|
26
|
+
export declare function disambiguateFingerprint(input: FingerprintInput, parentHint: string): string;
|
|
27
|
+
export declare function flattenAKNodes(root: AKNode): AKNode[];
|
|
28
|
+
export declare function findAKNodeById(root: AKNode, nodeId: string): AKNode | null;
|
|
29
|
+
export declare function buildAKNodeRuntimeIndex(tree: AKTree): Map<string, AKNodeRuntimeIndexEntry>;
|
|
30
|
+
export declare function deriveInteractiveElementsFromAKTree(tree: AKTree): InteractiveElement[];
|
|
31
|
+
export declare function collectInteractiveAKNodes(tree: AKTree, includeHidden?: boolean): AKNode[];
|
|
32
|
+
export declare function serializeAKTree(tree: AKTree, options?: {
|
|
33
|
+
root?: AKNode;
|
|
34
|
+
includeInteractiveSection?: boolean;
|
|
35
|
+
includeHidden?: boolean;
|
|
36
|
+
maxDepth?: number;
|
|
37
|
+
}): string;
|
|
38
|
+
export declare function focusAKTree(tree: AKTree, query: FocusQuery): FocusResult;
|
|
39
|
+
export {};
|
package/dist/ak-tree.js
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
function clipText(value, maxLength) {
|
|
3
|
+
return (value ?? '').replace(/\s+/g, ' ').trim().slice(0, maxLength);
|
|
4
|
+
}
|
|
5
|
+
export function toAscii(value) {
|
|
6
|
+
const normalized = (value ?? '')
|
|
7
|
+
.normalize('NFKD')
|
|
8
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
9
|
+
.replace(/[^\x20-\x7E]/g, '?')
|
|
10
|
+
.replace(/\s+/g, ' ')
|
|
11
|
+
.trim();
|
|
12
|
+
return normalized;
|
|
13
|
+
}
|
|
14
|
+
function quoted(value) {
|
|
15
|
+
return `"${toAscii(value).replace(/"/g, '\'')}"`;
|
|
16
|
+
}
|
|
17
|
+
export function fingerprintAKNode(input) {
|
|
18
|
+
const parts = [
|
|
19
|
+
input.tagName,
|
|
20
|
+
input.role || '',
|
|
21
|
+
clipText(input.textContent, 50),
|
|
22
|
+
clipText(input.ariaLabel, 50),
|
|
23
|
+
input.htmlId || '',
|
|
24
|
+
input.name || '',
|
|
25
|
+
input.inputType || '',
|
|
26
|
+
input.href || '',
|
|
27
|
+
input.placeholder || '',
|
|
28
|
+
String(Math.round(input.bounds.w)),
|
|
29
|
+
String(Math.round(input.bounds.h)),
|
|
30
|
+
];
|
|
31
|
+
return `ak_${createHash('sha256').update(parts.join('|')).digest('hex').slice(0, 8)}`;
|
|
32
|
+
}
|
|
33
|
+
export function disambiguateFingerprint(input, parentHint) {
|
|
34
|
+
const parts = [
|
|
35
|
+
input.tagName,
|
|
36
|
+
input.role || '',
|
|
37
|
+
clipText(input.textContent, 50),
|
|
38
|
+
clipText(input.ariaLabel, 50),
|
|
39
|
+
input.htmlId || '',
|
|
40
|
+
input.name || '',
|
|
41
|
+
input.inputType || '',
|
|
42
|
+
input.href || '',
|
|
43
|
+
input.placeholder || '',
|
|
44
|
+
String(Math.round(input.bounds.w)),
|
|
45
|
+
String(Math.round(input.bounds.h)),
|
|
46
|
+
];
|
|
47
|
+
return `ak_${createHash('sha256').update(`${parts.join('|')}§${parentHint}`).digest('hex').slice(0, 8)}`;
|
|
48
|
+
}
|
|
49
|
+
export function flattenAKNodes(root) {
|
|
50
|
+
const result = [];
|
|
51
|
+
const stack = [root];
|
|
52
|
+
while (stack.length > 0) {
|
|
53
|
+
const current = stack.shift();
|
|
54
|
+
if (!current)
|
|
55
|
+
continue;
|
|
56
|
+
result.push(current);
|
|
57
|
+
stack.unshift(...current.children);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
export function findAKNodeById(root, nodeId) {
|
|
62
|
+
const stack = [root];
|
|
63
|
+
while (stack.length > 0) {
|
|
64
|
+
const current = stack.pop();
|
|
65
|
+
if (!current)
|
|
66
|
+
continue;
|
|
67
|
+
if (current.id === nodeId)
|
|
68
|
+
return current;
|
|
69
|
+
stack.push(...current.children);
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
export function buildAKNodeRuntimeIndex(tree) {
|
|
74
|
+
const index = new Map();
|
|
75
|
+
for (const node of flattenAKNodes(tree.root)) {
|
|
76
|
+
index.set(node.id, {
|
|
77
|
+
id: node.id,
|
|
78
|
+
sourceRef: node.sourceRef,
|
|
79
|
+
bounds: node.bounds,
|
|
80
|
+
type: node.type,
|
|
81
|
+
label: node.label,
|
|
82
|
+
interactive: node.interactive,
|
|
83
|
+
visible: node.visible,
|
|
84
|
+
value: node.value,
|
|
85
|
+
attributes: { ...node.attributes },
|
|
86
|
+
state: { ...node.state },
|
|
87
|
+
semantic: {
|
|
88
|
+
pattern: node.semantic.pattern,
|
|
89
|
+
confidence: node.semantic.confidence,
|
|
90
|
+
traits: [...node.semantic.traits],
|
|
91
|
+
},
|
|
92
|
+
scroll: node.scroll ? { ...node.scroll } : undefined,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return index;
|
|
96
|
+
}
|
|
97
|
+
function computeVisibilityState(node, viewportHeight) {
|
|
98
|
+
if (!node.visible)
|
|
99
|
+
return 'offscreen';
|
|
100
|
+
if (node.bounds.y >= 0 && node.bounds.y + node.bounds.h <= viewportHeight) {
|
|
101
|
+
return 'full';
|
|
102
|
+
}
|
|
103
|
+
if (node.bounds.y > viewportHeight || node.bounds.y + node.bounds.h < 0) {
|
|
104
|
+
return 'offscreen';
|
|
105
|
+
}
|
|
106
|
+
return 'partial';
|
|
107
|
+
}
|
|
108
|
+
function mapNodeToLegacyRole(node) {
|
|
109
|
+
if (node.type === 'input')
|
|
110
|
+
return node.attributes.type ? `input[${node.attributes.type}]` : 'input';
|
|
111
|
+
return node.attributes.role || node.type;
|
|
112
|
+
}
|
|
113
|
+
export function deriveInteractiveElementsFromAKTree(tree) {
|
|
114
|
+
return flattenAKNodes(tree.root)
|
|
115
|
+
.filter((node) => node.interactive)
|
|
116
|
+
.sort((a, b) => {
|
|
117
|
+
if (a.bounds.y !== b.bounds.y)
|
|
118
|
+
return a.bounds.y - b.bounds.y;
|
|
119
|
+
return a.bounds.x - b.bounds.x;
|
|
120
|
+
})
|
|
121
|
+
.map((node, index) => ({
|
|
122
|
+
index,
|
|
123
|
+
tag: node.attributes.tagName?.toLowerCase() || node.type,
|
|
124
|
+
role: mapNodeToLegacyRole(node),
|
|
125
|
+
text: node.label,
|
|
126
|
+
ariaLabel: node.attributes['aria-label'] || null,
|
|
127
|
+
title: node.attributes.title || null,
|
|
128
|
+
ariaControls: node.attributes['aria-controls'] || null,
|
|
129
|
+
ariaExpanded: node.state.expanded !== undefined ? String(node.state.expanded) : (node.attributes['aria-expanded'] || null),
|
|
130
|
+
ariaHasPopup: node.attributes['aria-haspopup'] || null,
|
|
131
|
+
href: node.attributes.href || null,
|
|
132
|
+
inputType: node.attributes.type || null,
|
|
133
|
+
boundingBox: {
|
|
134
|
+
x: node.bounds.x,
|
|
135
|
+
y: node.bounds.y,
|
|
136
|
+
width: node.bounds.w,
|
|
137
|
+
height: node.bounds.h,
|
|
138
|
+
},
|
|
139
|
+
selector: node.sourceRef,
|
|
140
|
+
visible: node.visible,
|
|
141
|
+
visibilityState: computeVisibilityState(node, tree.page.viewport.height),
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
export function collectInteractiveAKNodes(tree, includeHidden = false) {
|
|
145
|
+
return flattenAKNodes(tree.root).filter((node) => node.interactive && (includeHidden || node.visible));
|
|
146
|
+
}
|
|
147
|
+
function describeScroll(scroll) {
|
|
148
|
+
const verticalMax = Math.max(0, scroll.scrollHeight - scroll.clientHeight);
|
|
149
|
+
const horizontalMax = Math.max(0, scroll.scrollWidth - scroll.clientWidth);
|
|
150
|
+
const verticalPct = verticalMax > 0 ? Math.round((scroll.scrollTop / verticalMax) * 100) : 0;
|
|
151
|
+
const horizontalPct = horizontalMax > 0 ? Math.round((scroll.scrollLeft / horizontalMax) * 100) : 0;
|
|
152
|
+
if (scroll.overflowY && scroll.overflowX) {
|
|
153
|
+
return `${scroll.scrollTop}/${scroll.scrollHeight} (${verticalPct}%) vertical | ${scroll.scrollLeft}/${scroll.scrollWidth} (${horizontalPct}%) horizontal`;
|
|
154
|
+
}
|
|
155
|
+
if (scroll.overflowX) {
|
|
156
|
+
return `${scroll.scrollLeft}/${scroll.scrollWidth} (${horizontalPct}%) horizontal`;
|
|
157
|
+
}
|
|
158
|
+
return `${scroll.scrollTop}/${scroll.scrollHeight} (${verticalPct}%) vertical`;
|
|
159
|
+
}
|
|
160
|
+
function buildNodeTags(node) {
|
|
161
|
+
const tags = [];
|
|
162
|
+
if (node.semantic.pattern)
|
|
163
|
+
tags.push(node.semantic.pattern);
|
|
164
|
+
tags.push(...node.semantic.traits);
|
|
165
|
+
return tags.length > 0 ? ` (${tags.join(', ')})` : '';
|
|
166
|
+
}
|
|
167
|
+
function serializeNodeLine(node) {
|
|
168
|
+
let line = `[${node.id}] ${node.type}`;
|
|
169
|
+
if (node.label)
|
|
170
|
+
line += ` ${quoted(node.label)}`;
|
|
171
|
+
if (node.value)
|
|
172
|
+
line += ` value=${quoted(node.value)}`;
|
|
173
|
+
if (node.attributes.placeholder)
|
|
174
|
+
line += ` placeholder=${quoted(node.attributes.placeholder)}`;
|
|
175
|
+
if (node.attributes.href)
|
|
176
|
+
line += ` href=${quoted(node.attributes.href)}`;
|
|
177
|
+
if (node.state.disabled)
|
|
178
|
+
line += ' [disabled]';
|
|
179
|
+
if (node.state.focused)
|
|
180
|
+
line += ' [focused]';
|
|
181
|
+
if (node.scroll)
|
|
182
|
+
line += ' [scrollable]';
|
|
183
|
+
line += `${buildNodeTags(node)} -- ${node.bounds.x},${node.bounds.y} ${node.bounds.w}x${node.bounds.h}`;
|
|
184
|
+
if (node.scroll) {
|
|
185
|
+
line += ` scroll: ${describeScroll(node.scroll)}`;
|
|
186
|
+
}
|
|
187
|
+
return toAscii(line);
|
|
188
|
+
}
|
|
189
|
+
function cloneNode(node) {
|
|
190
|
+
return {
|
|
191
|
+
...node,
|
|
192
|
+
state: { ...node.state },
|
|
193
|
+
style: { ...node.style },
|
|
194
|
+
semantic: {
|
|
195
|
+
pattern: node.semantic.pattern,
|
|
196
|
+
confidence: node.semantic.confidence,
|
|
197
|
+
traits: [...node.semantic.traits],
|
|
198
|
+
},
|
|
199
|
+
attributes: { ...node.attributes },
|
|
200
|
+
scroll: node.scroll ? { ...node.scroll } : undefined,
|
|
201
|
+
children: node.children.map(cloneNode),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function pruneNodeToDepth(node, depth, maxDepth) {
|
|
205
|
+
const clone = cloneNode(node);
|
|
206
|
+
if (maxDepth !== undefined && depth >= maxDepth) {
|
|
207
|
+
clone.children = [];
|
|
208
|
+
return clone;
|
|
209
|
+
}
|
|
210
|
+
clone.children = node.children.map((child) => pruneNodeToDepth(child, depth + 1, maxDepth));
|
|
211
|
+
return clone;
|
|
212
|
+
}
|
|
213
|
+
function matchTrait(node, traits) {
|
|
214
|
+
return traits.every((trait) => node.semantic.traits.includes(trait));
|
|
215
|
+
}
|
|
216
|
+
function hasInteractiveDescendant(node) {
|
|
217
|
+
return node.children.some((child) => child.interactive || hasInteractiveDescendant(child));
|
|
218
|
+
}
|
|
219
|
+
function matchesFocus(node, query) {
|
|
220
|
+
if (query.type && query.type.length > 0 && !query.type.includes(node.type)) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
if (query.semantic && query.semantic.length > 0 && (!node.semantic.pattern || !query.semantic.includes(node.semantic.pattern))) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
if (query.trait && query.trait.length > 0 && !matchTrait(node, query.trait)) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
if (typeof query.interactive === 'boolean') {
|
|
230
|
+
const effectiveInteractive = node.interactive
|
|
231
|
+
|| (query.interactive === true && !!query.semantic?.length && hasInteractiveDescendant(node));
|
|
232
|
+
if (effectiveInteractive !== query.interactive) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (typeof query.visible === 'boolean' && node.visible !== query.visible) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
if (query.labelContains && !node.label.toLowerCase().includes(query.labelContains.toLowerCase())) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
function pruneToMatchedPaths(node, query, maxDepth, depth = 0) {
|
|
245
|
+
const childResults = node.children
|
|
246
|
+
.map((child) => pruneToMatchedPaths(child, query, maxDepth, depth + 1))
|
|
247
|
+
.filter((entry) => entry !== null);
|
|
248
|
+
const childNodes = childResults
|
|
249
|
+
.map((entry) => entry.node)
|
|
250
|
+
.filter((entry) => entry != null);
|
|
251
|
+
const selfMatch = matchesFocus(node, query);
|
|
252
|
+
if (!selfMatch && childNodes.length === 0) {
|
|
253
|
+
return { node: null, matches: [] };
|
|
254
|
+
}
|
|
255
|
+
const clone = cloneNode(node);
|
|
256
|
+
if (maxDepth !== undefined && depth >= maxDepth) {
|
|
257
|
+
clone.children = [];
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
clone.children = childNodes;
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
node: clone,
|
|
264
|
+
matches: [
|
|
265
|
+
...(selfMatch ? [node] : []),
|
|
266
|
+
...childResults.flatMap((entry) => entry.matches),
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function extractMatches(node, query, maxDepth, depth = 0) {
|
|
271
|
+
const own = matchesFocus(node, query)
|
|
272
|
+
? [pruneNodeToDepth(node, 0, maxDepth)]
|
|
273
|
+
: [];
|
|
274
|
+
if (maxDepth !== undefined && depth >= maxDepth) {
|
|
275
|
+
return own;
|
|
276
|
+
}
|
|
277
|
+
return [...own, ...node.children.flatMap((child) => extractMatches(child, query, maxDepth, depth + 1))];
|
|
278
|
+
}
|
|
279
|
+
function findOverlayLabel(overlay, tree) {
|
|
280
|
+
const node = findAKNodeById(tree.root, overlay.nodeId);
|
|
281
|
+
return node?.semantic.pattern || node?.type || 'overlay';
|
|
282
|
+
}
|
|
283
|
+
export function serializeAKTree(tree, options = {}) {
|
|
284
|
+
const root = options.root ?? tree.root;
|
|
285
|
+
const includeHidden = options.includeHidden === true;
|
|
286
|
+
const lines = [];
|
|
287
|
+
const viewport = tree.page.viewport;
|
|
288
|
+
const pageScrollMax = Math.max(0, tree.page.scroll.scrollHeight - tree.page.scroll.clientHeight);
|
|
289
|
+
const pageScrollPct = pageScrollMax > 0 ? Math.round((tree.page.scroll.scrollTop / pageScrollMax) * 100) : 0;
|
|
290
|
+
lines.push('=== PAGE STATE ===');
|
|
291
|
+
lines.push(`url: ${toAscii(tree.page.url)}`);
|
|
292
|
+
lines.push(`title: ${quoted(tree.page.title)}`);
|
|
293
|
+
lines.push(`viewport: ${viewport.width}x${viewport.height} | page scroll: ${tree.page.scroll.scrollTop}/${tree.page.scroll.scrollHeight} (${pageScrollPct}%) vertical`);
|
|
294
|
+
lines.push('');
|
|
295
|
+
lines.push('OVERLAYS:');
|
|
296
|
+
if (tree.overlays.length === 0) {
|
|
297
|
+
lines.push(' (none)');
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
for (const overlay of tree.overlays) {
|
|
301
|
+
lines.push(toAscii(` [${overlay.nodeId}] ${findOverlayLabel(overlay, tree)} z:${overlay.zIndex} covers ${Math.round(overlay.coveragePercent)}%${overlay.blocksInteraction ? ' -- blocks interaction' : ''}`));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
lines.push('');
|
|
305
|
+
lines.push('=== PAGE STRUCTURE ===');
|
|
306
|
+
const walk = (node, depth) => {
|
|
307
|
+
if (!includeHidden && !node.visible)
|
|
308
|
+
return;
|
|
309
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth)
|
|
310
|
+
return;
|
|
311
|
+
lines.push(`${' '.repeat(depth)}${serializeNodeLine(node)}`);
|
|
312
|
+
for (const child of node.children) {
|
|
313
|
+
walk(child, depth + 1);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
walk(root, 0);
|
|
317
|
+
if (options.includeInteractiveSection !== false) {
|
|
318
|
+
const interactiveNodes = collectInteractiveAKNodes({ ...tree, root }, includeHidden);
|
|
319
|
+
lines.push('');
|
|
320
|
+
lines.push('=== INTERACTIVE ELEMENTS ===');
|
|
321
|
+
if (interactiveNodes.length === 0) {
|
|
322
|
+
lines.push('(none)');
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
for (const node of interactiveNodes) {
|
|
326
|
+
lines.push(toAscii(`[${node.id}] ${node.type}${node.label ? ` ${quoted(node.label)}` : ''}`));
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return lines.join('\n');
|
|
331
|
+
}
|
|
332
|
+
export function focusAKTree(tree, query) {
|
|
333
|
+
const scopedRoot = query.within ? (findAKNodeById(tree.root, query.within) ?? tree.root) : tree.root;
|
|
334
|
+
const maxDepth = query.maxDepth;
|
|
335
|
+
if (query.includeAncestors) {
|
|
336
|
+
const pruned = pruneToMatchedPaths(scopedRoot, query, maxDepth);
|
|
337
|
+
const nextRoot = pruned.node ?? {
|
|
338
|
+
...cloneNode(scopedRoot),
|
|
339
|
+
children: [],
|
|
340
|
+
};
|
|
341
|
+
const nextTree = {
|
|
342
|
+
...tree,
|
|
343
|
+
root: nextRoot,
|
|
344
|
+
overlays: tree.overlays.filter((overlay) => pruned.matches.some((node) => node.id === overlay.nodeId)),
|
|
345
|
+
};
|
|
346
|
+
return {
|
|
347
|
+
tree: nextTree,
|
|
348
|
+
matches: pruned.matches,
|
|
349
|
+
serialized: serializeAKTree(nextTree),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
const matches = extractMatches(scopedRoot, query, maxDepth);
|
|
353
|
+
const syntheticRoot = {
|
|
354
|
+
...cloneNode(scopedRoot),
|
|
355
|
+
children: matches.map((node) => cloneNode(node)),
|
|
356
|
+
};
|
|
357
|
+
const nextTree = {
|
|
358
|
+
...tree,
|
|
359
|
+
root: syntheticRoot,
|
|
360
|
+
overlays: tree.overlays.filter((overlay) => matches.some((node) => node.id === overlay.nodeId)),
|
|
361
|
+
};
|
|
362
|
+
return {
|
|
363
|
+
tree: nextTree,
|
|
364
|
+
matches,
|
|
365
|
+
serialized: serializeAKTree(nextTree),
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
//# sourceMappingURL=ak-tree.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture Agent — Alt Text Generation
|
|
3
|
+
*
|
|
4
|
+
* Generates accessible alt text for captured screenshots.
|
|
5
|
+
* Adapts to the variant's locale for localized descriptions.
|
|
6
|
+
* Cost: ~0.001 EUR per generation.
|
|
7
|
+
*/
|
|
8
|
+
import { type LLMProviderConfig, type LLMCallResult } from './llm-provider.js';
|
|
9
|
+
export interface AltTextResult {
|
|
10
|
+
altText: string;
|
|
11
|
+
llmResult?: LLMCallResult;
|
|
12
|
+
}
|
|
13
|
+
export interface AltTextContext {
|
|
14
|
+
/** What the screenshot captures */
|
|
15
|
+
description: string;
|
|
16
|
+
/** Target URL */
|
|
17
|
+
url: string;
|
|
18
|
+
/** Locale for the alt text language */
|
|
19
|
+
locale?: string;
|
|
20
|
+
/** Page/preset name */
|
|
21
|
+
presetName?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generates alt text for a screenshot, localized to the variant's language.
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateAltText(screenshot: Buffer, context: AltTextContext, llmConfig: LLMProviderConfig): Promise<AltTextResult>;
|
package/dist/alt-text.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture Agent — Alt Text Generation
|
|
3
|
+
*
|
|
4
|
+
* Generates accessible alt text for captured screenshots.
|
|
5
|
+
* Adapts to the variant's locale for localized descriptions.
|
|
6
|
+
* Cost: ~0.001 EUR per generation.
|
|
7
|
+
*/
|
|
8
|
+
import { callLLM } from './llm-provider.js';
|
|
9
|
+
const SYSTEM_PROMPT = `You generate concise alt text for web page screenshots.
|
|
10
|
+
|
|
11
|
+
Rules:
|
|
12
|
+
- Maximum 150 characters
|
|
13
|
+
- Describe what is VISIBLE, not what the page is about
|
|
14
|
+
- Use the language specified by the locale
|
|
15
|
+
- Start with the main visual element (e.g., "Dashboard showing 5 projects")
|
|
16
|
+
- Do not wrap in quotes
|
|
17
|
+
- Do not start with "Screenshot of" or "Image of"
|
|
18
|
+
|
|
19
|
+
Respond with ONLY the alt text, nothing else.`;
|
|
20
|
+
/**
|
|
21
|
+
* Generates alt text for a screenshot, localized to the variant's language.
|
|
22
|
+
*/
|
|
23
|
+
export async function generateAltText(screenshot, context, llmConfig) {
|
|
24
|
+
const locale = context.locale ?? 'en';
|
|
25
|
+
const userPrompt = [
|
|
26
|
+
`Generate alt text in ${localeToLanguage(locale)} for this screenshot.`,
|
|
27
|
+
`Page: ${context.presetName ?? context.url}`,
|
|
28
|
+
`Content: ${context.description}`,
|
|
29
|
+
].join('\n');
|
|
30
|
+
try {
|
|
31
|
+
const result = await callLLM({ ...llmConfig, maxTokens: 100, timeoutMs: 10000 }, SYSTEM_PROMPT, userPrompt, screenshot);
|
|
32
|
+
// Clean up: remove quotes, trim
|
|
33
|
+
let altText = result.text.replace(/^["']|["']$/g, '').trim();
|
|
34
|
+
if (altText.length > 150)
|
|
35
|
+
altText = altText.slice(0, 147) + '...';
|
|
36
|
+
return { altText, llmResult: result };
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Fallback: generate from context without LLM
|
|
40
|
+
return {
|
|
41
|
+
altText: `${context.presetName ?? 'Page'} — ${context.description}`.slice(0, 150),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function localeToLanguage(locale) {
|
|
46
|
+
const map = {
|
|
47
|
+
en: 'English', fr: 'French', de: 'German', es: 'Spanish',
|
|
48
|
+
pt: 'Portuguese', it: 'Italian', nl: 'Dutch', ja: 'Japanese',
|
|
49
|
+
ko: 'Korean', zh: 'Chinese', ar: 'Arabic', ru: 'Russian',
|
|
50
|
+
pl: 'Polish', sv: 'Swedish', da: 'Danish', fi: 'Finnish',
|
|
51
|
+
nb: 'Norwegian', tr: 'Turkish', cs: 'Czech', ro: 'Romanian',
|
|
52
|
+
};
|
|
53
|
+
return map[locale.split('-')[0]] ?? locale;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=alt-text.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface AuthCaptureOptions {
|
|
2
|
+
apiBaseUrl: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
projectId: string;
|
|
5
|
+
accountId: string;
|
|
6
|
+
startUrl: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Opens a headed Chromium window, lets the user log in, and uploads the
|
|
10
|
+
* resulting storageState (cookies + localStorage, HttpOnly included) to the
|
|
11
|
+
* given project credentials account.
|
|
12
|
+
*
|
|
13
|
+
* The session is captured continuously via polling so we don't depend on the
|
|
14
|
+
* user explicitly clicking a button — closing the window after login is
|
|
15
|
+
* enough. A "Save & close" button is also rendered for explicit confirmation.
|
|
16
|
+
*/
|
|
17
|
+
export declare function captureAuthSession(options: AuthCaptureOptions): Promise<void>;
|