@testdriverai/mcp 7.9.115-test → 7.9.117-test

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.
@@ -0,0 +1,176 @@
1
+ /**
2
+ * TestDriver action core — framework-agnostic.
3
+ *
4
+ * This module owns the actual computer-use logic: it holds the singleton SDK,
5
+ * the element-reference map, and the "last screenshot" used by `check`, and
6
+ * exposes one async function per action. Every function returns a neutral
7
+ * {@link ActionResult} — no MCP types, no eve types — so it can be wrapped by:
8
+ *
9
+ * - the MCP server (`server.ts`), which turns images into resource URIs and
10
+ * calls `createToolResult`, and
11
+ * - eve `defineTool()` files, which return the text/code/images as eve content.
12
+ *
13
+ * Keep MCP- and eve-specific concerns (Sentry, progress heartbeats, abort
14
+ * racing, image stores, UI resources) in the adapters. This file only knows
15
+ * about the TestDriver SDK and `generateActionCode`.
16
+ *
17
+ * State is process-global and single-session by design: one sandbox at a time,
18
+ * mirroring how the stdio MCP server has always behaved.
19
+ */
20
+ import { SessionStartInputSchema, type SessionStartInput } from "../provision-types.js";
21
+ import { type SessionState } from "../session.js";
22
+ export { SessionStartInputSchema, type SessionStartInput };
23
+ export interface ActionImage {
24
+ kind: "screenshot" | "cropped";
25
+ /** Raw base64 (no `data:` prefix). */
26
+ base64: string;
27
+ }
28
+ export interface ActionResult {
29
+ /** Whether the action succeeded (assertions/finds may legitimately be false). */
30
+ ok: boolean;
31
+ /** Human/agent-readable summary line(s). */
32
+ text: string;
33
+ /** Structured fields for programmatic consumers and UIs. */
34
+ data: Record<string, unknown>;
35
+ /** Code to append to the test file, when the action produces test code. */
36
+ code?: string;
37
+ /** Images produced by the action (screenshots / cropped element shots). */
38
+ images?: ActionImage[];
39
+ }
40
+ /** Thrown when an action runs without an active/valid session. */
41
+ export declare class NoActiveSessionError extends Error {
42
+ readonly code: "NO_SESSION" | "SESSION_EXPIRED";
43
+ readonly expiredSessionId?: string;
44
+ constructor(code: "NO_SESSION" | "SESSION_EXPIRED", message: string, expiredSessionId?: string);
45
+ }
46
+ /**
47
+ * Optional adapter-supplied recovery hook. When the singleton SDK is missing or
48
+ * stale at action time, {@link requireActiveSession} calls this to obtain the
49
+ * params needed to rebuild the connection from the still-alive sandbox, then
50
+ * reconnects before throwing NO_SESSION.
51
+ *
52
+ * Why a hook instead of mcp-core owning the handle: the durable facts (sandbox
53
+ * id, config) and the API key must survive a host process recycle, but this
54
+ * module's globals do NOT — they reset on the very recycle we're recovering
55
+ * from. So the *durable owner* (eve's per-session state) registers a resolver
56
+ * that reads its own durable store and re-resolves the key per call. Hosts with
57
+ * one long-lived process (stdio MCP server, CLI) register nothing: the resolver
58
+ * stays null and behavior is unchanged — `requireActiveSession` throws the same
59
+ * NO_SESSION/SESSION_EXPIRED as before.
60
+ *
61
+ * The resolver returns `null` when it has nothing to recover from (no sandbox
62
+ * provisioned this session), in which case we fall through to the normal throw.
63
+ * It is re-registered each step by the adapter (module globals reset on recycle),
64
+ * so a stale closure can't outlive the process it was bound to.
65
+ */
66
+ export type ReconnectResolver = () => Promise<ReconnectParams | null>;
67
+ /**
68
+ * Register (or clear, with `null`) the recovery hook. Durable adapters call this
69
+ * at the start of each step with a resolver bound to the current tool context.
70
+ */
71
+ export declare function setReconnectResolver(resolver: ReconnectResolver | null): void;
72
+ /** Expose internals the adapters legitimately need (read-only intent). */
73
+ export declare function getSdk(): any;
74
+ export declare function getLastScreenshotBase64(): string | null;
75
+ export declare function getElementRef(ref: string): {
76
+ element: any;
77
+ description: string;
78
+ coords: {
79
+ x: number;
80
+ y: number;
81
+ centerX: number;
82
+ centerY: number;
83
+ };
84
+ } | undefined;
85
+ /**
86
+ * Cheap, side-effect-free check for a usable in-process session: a live SDK and
87
+ * a current session that hasn't expired. Durable adapters call this *before*
88
+ * doing any expensive reconnect prep (e.g. re-resolving an API key), so the
89
+ * common warm-process path stays free. Note: unlike `requireActiveSession`, this
90
+ * does NOT refresh the keepAlive window — it only reports liveness.
91
+ */
92
+ export declare function hasLiveSession(): boolean;
93
+ export interface SessionStartHooks {
94
+ /** Called before a long await; return a stop fn. Lets adapters heartbeat. */
95
+ onProgress?: (message: string) => void;
96
+ }
97
+ /**
98
+ * Start a session and provision a sandbox. The adapter is responsible for
99
+ * progress/heartbeat and abort; this performs the provisioning and returns the
100
+ * neutral result (including the initial screenshot and provision code).
101
+ */
102
+ export declare function sessionStart(params: SessionStartInput, resolved: {
103
+ os: "linux" | "windows";
104
+ e2bTemplateId?: string;
105
+ apiKey?: string;
106
+ }, hooks?: SessionStartHooks): Promise<ActionResult>;
107
+ /**
108
+ * Parameters needed to rebuild the singleton SDK and reconnect to a sandbox
109
+ * that is still alive on the server but whose in-process connection was lost
110
+ * (e.g. the host process was recycled between durable workflow steps).
111
+ */
112
+ export interface ReconnectParams {
113
+ /** Cloud sandbox id (`sb-…`) to reconnect to. */
114
+ sandboxId: string;
115
+ os: "linux" | "windows";
116
+ keepAlive: number;
117
+ apiKey: string;
118
+ apiRoot?: string;
119
+ e2bTemplateId?: string;
120
+ /** Self-hosted instance IP, when the original session used one. */
121
+ ip?: string;
122
+ testFile?: string;
123
+ }
124
+ /**
125
+ * Rebuild the process-global SDK and reconnect it to an existing sandbox by id,
126
+ * skipping provisioning. This is the recovery path for hosts that do NOT keep a
127
+ * single long-lived process: eve runs each turn as a durable workflow on Vercel
128
+ * and may park or recycle the process between steps, which drops the SDK's
129
+ * realtime connection and wipes this module's singletons. The sandbox itself can
130
+ * still be alive on the server (the API holds it for `keepAlive`/grace), so we
131
+ * re-`connect({ sandboxId })` and re-register a local session instead of failing
132
+ * the action with NO_SESSION.
133
+ *
134
+ * Returns the (re)activated session id. Throws if the reconnect fails (the
135
+ * sandbox is gone) — callers translate that into a SESSION_EXPIRED so the agent
136
+ * knows to call session_start again.
137
+ */
138
+ export declare function reconnectSession(params: ReconnectParams): Promise<string>;
139
+ /**
140
+ * Ensure there is a usable session before an action, reconnecting from durable
141
+ * state if the in-process singleton was lost. Returns true when a fresh
142
+ * reconnect happened (the caller may want to recapture context), false when the
143
+ * existing session was already usable.
144
+ *
145
+ * Durable adapters call this at the top of each tool, passing the sandbox id and
146
+ * config they persisted at session_start. Hosts with a single long-lived process
147
+ * (the stdio MCP server, the CLI) never persist a sandbox id, so they pass none
148
+ * and this is a no-op — `requireActiveSession()` inside each action still guards
149
+ * them exactly as before.
150
+ */
151
+ export declare function ensureActiveSession(params?: ReconnectParams): Promise<boolean>;
152
+ /** Disconnect the SDK (best-effort); used by adapters on cancel/teardown. */
153
+ export declare function disconnect(): Promise<void>;
154
+ export declare function sessionStatus(): ActionResult;
155
+ export declare function sessionExtend(additionalMs: number): ActionResult;
156
+ export declare function find(description: string, timeout?: number): Promise<ActionResult>;
157
+ export declare function findAll(description: string, timeout?: number): Promise<ActionResult>;
158
+ export declare function click(ref: string, action?: "click" | "double-click" | "right-click"): Promise<ActionResult>;
159
+ export declare function hover(ref: string): Promise<ActionResult>;
160
+ export declare function findAndClick(description: string, action?: "click" | "double-click" | "right-click"): Promise<ActionResult>;
161
+ export declare function type(text: string, secret?: boolean, delay?: number): Promise<ActionResult>;
162
+ export declare function pressKeys(keys: string[]): Promise<ActionResult>;
163
+ export declare function scroll(direction?: "up" | "down" | "left" | "right", amount?: number): Promise<ActionResult>;
164
+ export declare function focusApplication(name: string): Promise<ActionResult>;
165
+ export declare function wait(timeout: number): Promise<ActionResult>;
166
+ export declare function exec(language: "sh" | "pwsh", code: string, timeout?: number): Promise<ActionResult>;
167
+ export declare function assert(assertion: string): Promise<ActionResult>;
168
+ /**
169
+ * AI analysis of the current screen vs. a "before" state. Does NOT generate
170
+ * code. `referenceImage` (bare base64), if provided, is used as the before
171
+ * image instead of the last captured screenshot.
172
+ */
173
+ export declare function check(task: string, referenceImage?: string): Promise<ActionResult>;
174
+ /** Capture a screenshot for the user (cursor visible). */
175
+ export declare function screenshot(): Promise<ActionResult>;
176
+ export type { SessionState };