@vostride/agent-qa-android 0.1.21 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,34 +1,161 @@
1
- import { PlatformAdapter, PlatformConfig, ObserveOptions, ScreenState, Action, ActionResult, ConsoleLogEntry } from '@vostride/agent-qa-core';
1
+ import { PlatformAdapter, PlatformConfig, ObserveOptions, ActionsFor, ActionResult, ConsoleLogEntry, LiveStreamCapability, RecordingCapability } from '@vostride/agent-qa-runner';
2
+ import { ScreenState } from '@vostride/agent-qa-schema';
2
3
 
3
- declare class AndroidPlatformAdapter implements PlatformAdapter {
4
+ declare class AndroidPlatformAdapter implements PlatformAdapter<'android'> {
4
5
  readonly platform: "android";
5
6
  private driver;
6
7
  private lastRefs;
7
8
  private config;
8
9
  private activeWebContext;
9
10
  private currentContext;
10
- private recordingEnabled;
11
- private videoDir;
12
- private videoPath;
11
+ private recordingCapability;
12
+ private liveStreamCapability;
13
13
  private consoleLogs;
14
14
  private consoleDrainIndex;
15
15
  private captureConsole;
16
16
  private appPackage;
17
17
  private appPid;
18
+ private appRegistry;
18
19
  setup(config: PlatformConfig): Promise<void>;
19
20
  cleanup(): Promise<void>;
20
21
  private hasSeenWebContext;
21
22
  observe(_options?: ObserveOptions): Promise<ScreenState>;
22
- execute(action: Action): Promise<ActionResult>;
23
+ execute(action: ActionsFor<'android'>): Promise<ActionResult>;
23
24
  screenshot(): Promise<Buffer | undefined>;
24
25
  pollDeviceLogs(): Promise<void>;
25
26
  drainConsoleLogs(level?: string): ConsoleLogEntry[];
26
- getVideoPath(): Promise<string | null>;
27
- private stopAndSaveRecording;
27
+ /**
28
+ * 428 D-11: the labelled 1s snapshot preview, over `captureScreenshot()` — `takeScreenshot()`
29
+ * and nothing else. Never `screenshot()`: that one switches the Appium context, and a tick
30
+ * landing between a step's context switch and its command would run the command in the wrong
31
+ * context. Declared before the driver exists (a capture then answers `undefined`), so the
32
+ * composition's selection never falls through to `screenshot()`.
33
+ */
34
+ get liveStream(): LiveStreamCapability;
35
+ get recording(): RecordingCapability | undefined;
28
36
  private tryObserveWeb;
29
37
  private observeNative;
30
38
  private ensureContext;
31
39
  private captureScreenshot;
40
+ /** Read the live text of a focused element handle; undefined when nothing is readable. */
41
+ private readElementText;
42
+ private focusedMatches;
43
+ /** An empty field's getText() returns its hint (437 Pitfall 4), so a showing hint reads ''. */
44
+ private readFocusedValue;
45
+ /**
46
+ * The `mobile: shell` route of keyevent and openQuickSettings (437 D-18). A refusal by secure
47
+ * Appium is recorded as unavailable and any other driver error as failed; neither is a pass.
48
+ */
49
+ private runShell;
50
+ /** The one submit mechanism on every Android path (437 D-13); pressed once, never retried. */
51
+ private pressEnter;
52
+ /** 437 FA-2 (owner, 2026-10-08): line breaks into a single-line field are refused before typing. */
53
+ private refuseLineBreaks;
54
+ /**
55
+ * Native fill from the focused handle (437 D-08..D-10, D-12, D-13, D-15, D-17). Delivers once
56
+ * (addValue for append, setValue for replace), reads back from the same handle and records the
57
+ * shared verdict. An unknown append prior or an unreadable read-back is unverified, which never
58
+ * stops a requested Enter; a mismatch or a multi-line field holds it. A driver error during
59
+ * delivery ends the fill: nothing is typed again and no Enter follows. A secure field yields
60
+ * length sentinels only.
61
+ */
62
+ private fillNativeCompound;
63
+ /** The focused element handle, or undefined when UiAutomator2 reports none or the lookup fails. */
64
+ private focusedField;
65
+ /**
66
+ * 437 D-11 (WR-02): where the focused node is relative to the ref, judged by its read bounds.
67
+ * An unreadable or unparseable value is no evidence, so the native path stays (D-04, D-15).
68
+ * 444.1 D-07: 'elsewhere' needs positive evidence, the bounds of another observed field.
69
+ */
70
+ private focusIsElsewhere;
71
+ /** Ctrl+A then DEL as key input; clears only the view holding input focus (437 D-14). */
72
+ private clearByKeys;
73
+ /**
74
+ * The last-resort keyboard path (437 D-14): the tap left no focused handle. Replace clears by
75
+ * keys, the text goes through one `mobile: type` (Appium's Unicode IME, exact for every D-08
76
+ * text), and the value is read back only when a focused handle can be found afterwards. An
77
+ * append's prior value is unknown, so it is never better than unverified. The field's kind comes
78
+ * from the observed input-type (D-15): only positive evidence refuses line breaks or holds Enter.
79
+ */
80
+ private fillKeyboardPath;
81
+ /**
82
+ * Native and keyboard clearText (437 D-16): clearValue on the focused handle, or Ctrl+A then DEL
83
+ * when the tap left none, then the hint-aware read-back judged against the empty string. The
84
+ * caller has already checked that a focused handle is the referenced field (WR-02).
85
+ */
86
+ private clearNativeOrKeyboard;
87
+ private isSecure;
88
+ private settleClear;
89
+ /** A driver error while clearing ends the clear; it is never repeated. */
90
+ private interruptedClear;
91
+ /** A driver error during delivery ends the fill: nothing is typed again and no Enter follows. */
92
+ private interruptedFill;
93
+ /**
94
+ * The shared end of every Android fill (437 D-09, D-10, D-13, D-15, D-17): records the verdict
95
+ * and, when a submit was requested, holds Enter on a mismatch or a multi-line field and otherwise
96
+ * presses it once through `enter`.
97
+ */
98
+ private settleFill;
99
+ /** A real W3C touch tap in the WebView context at the ref's CSS-pixel centre (437 D-11). */
100
+ private trustedWebTap;
101
+ /** Whether the tap left an editable field focused at the ref's point; read-only. */
102
+ private probeWebFocus;
103
+ /** Polls the read-only probe until the tap's field holds focus; returns the last answer. */
104
+ private awaitWebFocus;
105
+ private readWebFieldValue;
106
+ /** Runs a driver call from NATIVE_APP and always returns to the active WebView context. */
107
+ private withNativeContext;
108
+ /** 437 D-11: a tap that left no editable field, or another field, focused writes nothing. */
109
+ private refuseFocus;
110
+ /**
111
+ * WebView clearText (437 D-11, D-16): the same tap and focus probe as the fill, W3C Ctrl+A and
112
+ * Backspace, then a read-back judged against the empty string. Never success without that check.
113
+ */
114
+ private clearWebViewField;
115
+ /**
116
+ * WebView fill as trusted input (437 D-11): a W3C tap on the ref, a read-only focus probe,
117
+ * W3C Ctrl+A and Backspace for replace, `mobile: type` from NATIVE_APP, a read-only read-back,
118
+ * and one `mobile: pressKey 66` from NATIVE_APP. No script writes the field or fires an event.
119
+ */
120
+ private fillWebViewCompound;
121
+ /**
122
+ * EXEC-02 platform primitives injected into the shared runner scroll loops (D-02/D-03; 436-02
123
+ * D-25). A native swipe is `mobile: scrollGesture` over the container (the ref's bounds, else the
124
+ * screen), whose boolean is the driver's own boundary signal; in a WebView the touch swipe is
125
+ * measured over every WebView scroller before and after (436-18), paired by identity (436-23).
126
+ * nativeSearchScroll drives the UiAutomator
127
+ * `UiScrollable.scrollIntoView` rung over an injection-escaped selector; readInterimTree is a
128
+ * light page-source parse — NO refMap mint, NO screenshot, lastRefs untouched.
129
+ */
130
+ private buildAndroidScrollPrimitives;
131
+ /**
132
+ * The WebView scrollers a touch swipe may have acted on (436-18 · D-25), read by the shared
133
+ * WEBVIEW_SCROLLERS_SCRIPT. The touch point cannot be mapped into the WebView's CSS coordinates,
134
+ * so the swipe is judged over all of them.
135
+ * 2026-10-08 (436-23): a frame in view reads unknown; members carry an identity and are paired
136
+ * by it; open shadow roots are walked; only on-screen element scrollers are members.
137
+ */
138
+ private readWebViewScrollers;
139
+ /**
140
+ * EXEC-03 openApp (D-10/D-11/D-12). Resolve a human name to a package id (or validate an
141
+ * explicit bundleId) over the session-cached registry, then launch via activateApp. On a
142
+ * resolution MISS the registry is re-enumerated exactly once (catches mid-run installs) before
143
+ * erroring with the resolver's candidate ids. Never a best-guess launch (T-359-04).
144
+ */
145
+ private openApp;
146
+ /** Return the cached registry, enumerating once on first use. Failed enumeration returns null (uncached). */
147
+ private ensureAppRegistry;
148
+ /**
149
+ * Enumerate installed apps through the driver only (ownership contract — no adb/child_process).
150
+ * `mobile: listApps` maps package ids → AppRegistryEntry (labels only when the same call carries
151
+ * them, D-10 — no per-package round-trips). On failure, fall back to `mobile: shell` pm-list ONLY
152
+ * when the AGENT_QA_ANDROID_USE_MOBILE_SHELL gate is '1' (Pitfall 4). Null = enumeration unavailable.
153
+ */
154
+ private enumerateApps;
155
+ /** Coerce a `mobile: listApps` result (package-id-keyed map, or an array of entries) into the registry. */
156
+ private mapListApps;
157
+ /** Parse `pm list packages` output ("package:com.foo\n…") into id-only registry entries. */
158
+ private parsePmListPackages;
32
159
  private executeAction;
33
160
  }
34
161
 
package/dist/index.d.ts CHANGED
@@ -1,34 +1,161 @@
1
- import { PlatformAdapter, PlatformConfig, ObserveOptions, ScreenState, Action, ActionResult, ConsoleLogEntry } from '@vostride/agent-qa-core';
1
+ import { PlatformAdapter, PlatformConfig, ObserveOptions, ActionsFor, ActionResult, ConsoleLogEntry, LiveStreamCapability, RecordingCapability } from '@vostride/agent-qa-runner';
2
+ import { ScreenState } from '@vostride/agent-qa-schema';
2
3
 
3
- declare class AndroidPlatformAdapter implements PlatformAdapter {
4
+ declare class AndroidPlatformAdapter implements PlatformAdapter<'android'> {
4
5
  readonly platform: "android";
5
6
  private driver;
6
7
  private lastRefs;
7
8
  private config;
8
9
  private activeWebContext;
9
10
  private currentContext;
10
- private recordingEnabled;
11
- private videoDir;
12
- private videoPath;
11
+ private recordingCapability;
12
+ private liveStreamCapability;
13
13
  private consoleLogs;
14
14
  private consoleDrainIndex;
15
15
  private captureConsole;
16
16
  private appPackage;
17
17
  private appPid;
18
+ private appRegistry;
18
19
  setup(config: PlatformConfig): Promise<void>;
19
20
  cleanup(): Promise<void>;
20
21
  private hasSeenWebContext;
21
22
  observe(_options?: ObserveOptions): Promise<ScreenState>;
22
- execute(action: Action): Promise<ActionResult>;
23
+ execute(action: ActionsFor<'android'>): Promise<ActionResult>;
23
24
  screenshot(): Promise<Buffer | undefined>;
24
25
  pollDeviceLogs(): Promise<void>;
25
26
  drainConsoleLogs(level?: string): ConsoleLogEntry[];
26
- getVideoPath(): Promise<string | null>;
27
- private stopAndSaveRecording;
27
+ /**
28
+ * 428 D-11: the labelled 1s snapshot preview, over `captureScreenshot()` — `takeScreenshot()`
29
+ * and nothing else. Never `screenshot()`: that one switches the Appium context, and a tick
30
+ * landing between a step's context switch and its command would run the command in the wrong
31
+ * context. Declared before the driver exists (a capture then answers `undefined`), so the
32
+ * composition's selection never falls through to `screenshot()`.
33
+ */
34
+ get liveStream(): LiveStreamCapability;
35
+ get recording(): RecordingCapability | undefined;
28
36
  private tryObserveWeb;
29
37
  private observeNative;
30
38
  private ensureContext;
31
39
  private captureScreenshot;
40
+ /** Read the live text of a focused element handle; undefined when nothing is readable. */
41
+ private readElementText;
42
+ private focusedMatches;
43
+ /** An empty field's getText() returns its hint (437 Pitfall 4), so a showing hint reads ''. */
44
+ private readFocusedValue;
45
+ /**
46
+ * The `mobile: shell` route of keyevent and openQuickSettings (437 D-18). A refusal by secure
47
+ * Appium is recorded as unavailable and any other driver error as failed; neither is a pass.
48
+ */
49
+ private runShell;
50
+ /** The one submit mechanism on every Android path (437 D-13); pressed once, never retried. */
51
+ private pressEnter;
52
+ /** 437 FA-2 (owner, 2026-10-08): line breaks into a single-line field are refused before typing. */
53
+ private refuseLineBreaks;
54
+ /**
55
+ * Native fill from the focused handle (437 D-08..D-10, D-12, D-13, D-15, D-17). Delivers once
56
+ * (addValue for append, setValue for replace), reads back from the same handle and records the
57
+ * shared verdict. An unknown append prior or an unreadable read-back is unverified, which never
58
+ * stops a requested Enter; a mismatch or a multi-line field holds it. A driver error during
59
+ * delivery ends the fill: nothing is typed again and no Enter follows. A secure field yields
60
+ * length sentinels only.
61
+ */
62
+ private fillNativeCompound;
63
+ /** The focused element handle, or undefined when UiAutomator2 reports none or the lookup fails. */
64
+ private focusedField;
65
+ /**
66
+ * 437 D-11 (WR-02): where the focused node is relative to the ref, judged by its read bounds.
67
+ * An unreadable or unparseable value is no evidence, so the native path stays (D-04, D-15).
68
+ * 444.1 D-07: 'elsewhere' needs positive evidence, the bounds of another observed field.
69
+ */
70
+ private focusIsElsewhere;
71
+ /** Ctrl+A then DEL as key input; clears only the view holding input focus (437 D-14). */
72
+ private clearByKeys;
73
+ /**
74
+ * The last-resort keyboard path (437 D-14): the tap left no focused handle. Replace clears by
75
+ * keys, the text goes through one `mobile: type` (Appium's Unicode IME, exact for every D-08
76
+ * text), and the value is read back only when a focused handle can be found afterwards. An
77
+ * append's prior value is unknown, so it is never better than unverified. The field's kind comes
78
+ * from the observed input-type (D-15): only positive evidence refuses line breaks or holds Enter.
79
+ */
80
+ private fillKeyboardPath;
81
+ /**
82
+ * Native and keyboard clearText (437 D-16): clearValue on the focused handle, or Ctrl+A then DEL
83
+ * when the tap left none, then the hint-aware read-back judged against the empty string. The
84
+ * caller has already checked that a focused handle is the referenced field (WR-02).
85
+ */
86
+ private clearNativeOrKeyboard;
87
+ private isSecure;
88
+ private settleClear;
89
+ /** A driver error while clearing ends the clear; it is never repeated. */
90
+ private interruptedClear;
91
+ /** A driver error during delivery ends the fill: nothing is typed again and no Enter follows. */
92
+ private interruptedFill;
93
+ /**
94
+ * The shared end of every Android fill (437 D-09, D-10, D-13, D-15, D-17): records the verdict
95
+ * and, when a submit was requested, holds Enter on a mismatch or a multi-line field and otherwise
96
+ * presses it once through `enter`.
97
+ */
98
+ private settleFill;
99
+ /** A real W3C touch tap in the WebView context at the ref's CSS-pixel centre (437 D-11). */
100
+ private trustedWebTap;
101
+ /** Whether the tap left an editable field focused at the ref's point; read-only. */
102
+ private probeWebFocus;
103
+ /** Polls the read-only probe until the tap's field holds focus; returns the last answer. */
104
+ private awaitWebFocus;
105
+ private readWebFieldValue;
106
+ /** Runs a driver call from NATIVE_APP and always returns to the active WebView context. */
107
+ private withNativeContext;
108
+ /** 437 D-11: a tap that left no editable field, or another field, focused writes nothing. */
109
+ private refuseFocus;
110
+ /**
111
+ * WebView clearText (437 D-11, D-16): the same tap and focus probe as the fill, W3C Ctrl+A and
112
+ * Backspace, then a read-back judged against the empty string. Never success without that check.
113
+ */
114
+ private clearWebViewField;
115
+ /**
116
+ * WebView fill as trusted input (437 D-11): a W3C tap on the ref, a read-only focus probe,
117
+ * W3C Ctrl+A and Backspace for replace, `mobile: type` from NATIVE_APP, a read-only read-back,
118
+ * and one `mobile: pressKey 66` from NATIVE_APP. No script writes the field or fires an event.
119
+ */
120
+ private fillWebViewCompound;
121
+ /**
122
+ * EXEC-02 platform primitives injected into the shared runner scroll loops (D-02/D-03; 436-02
123
+ * D-25). A native swipe is `mobile: scrollGesture` over the container (the ref's bounds, else the
124
+ * screen), whose boolean is the driver's own boundary signal; in a WebView the touch swipe is
125
+ * measured over every WebView scroller before and after (436-18), paired by identity (436-23).
126
+ * nativeSearchScroll drives the UiAutomator
127
+ * `UiScrollable.scrollIntoView` rung over an injection-escaped selector; readInterimTree is a
128
+ * light page-source parse — NO refMap mint, NO screenshot, lastRefs untouched.
129
+ */
130
+ private buildAndroidScrollPrimitives;
131
+ /**
132
+ * The WebView scrollers a touch swipe may have acted on (436-18 · D-25), read by the shared
133
+ * WEBVIEW_SCROLLERS_SCRIPT. The touch point cannot be mapped into the WebView's CSS coordinates,
134
+ * so the swipe is judged over all of them.
135
+ * 2026-10-08 (436-23): a frame in view reads unknown; members carry an identity and are paired
136
+ * by it; open shadow roots are walked; only on-screen element scrollers are members.
137
+ */
138
+ private readWebViewScrollers;
139
+ /**
140
+ * EXEC-03 openApp (D-10/D-11/D-12). Resolve a human name to a package id (or validate an
141
+ * explicit bundleId) over the session-cached registry, then launch via activateApp. On a
142
+ * resolution MISS the registry is re-enumerated exactly once (catches mid-run installs) before
143
+ * erroring with the resolver's candidate ids. Never a best-guess launch (T-359-04).
144
+ */
145
+ private openApp;
146
+ /** Return the cached registry, enumerating once on first use. Failed enumeration returns null (uncached). */
147
+ private ensureAppRegistry;
148
+ /**
149
+ * Enumerate installed apps through the driver only (ownership contract — no adb/child_process).
150
+ * `mobile: listApps` maps package ids → AppRegistryEntry (labels only when the same call carries
151
+ * them, D-10 — no per-package round-trips). On failure, fall back to `mobile: shell` pm-list ONLY
152
+ * when the AGENT_QA_ANDROID_USE_MOBILE_SHELL gate is '1' (Pitfall 4). Null = enumeration unavailable.
153
+ */
154
+ private enumerateApps;
155
+ /** Coerce a `mobile: listApps` result (package-id-keyed map, or an array of entries) into the registry. */
156
+ private mapListApps;
157
+ /** Parse `pm list packages` output ("package:com.foo\n…") into id-only registry entries. */
158
+ private parsePmListPackages;
32
159
  private executeAction;
33
160
  }
34
161