prompttest 1.3.5 → 1.5.0
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/LICENSE +6 -0
- package/README.md +191 -41
- package/TERMS.md +138 -0
- package/dist/bin/prompttest.js +489 -230
- package/dist/bin/server.d.ts +1 -0
- package/dist/engine.bundle.js +1000 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +292 -154
- package/dist/lib/adaptive-timing.d.ts +55 -0
- package/dist/lib/adb-provisioner.d.ts +55 -0
- package/dist/lib/adb.d.ts +29 -0
- package/dist/lib/baseline.d.ts +52 -4
- package/dist/lib/dfs-engine.d.ts +43 -0
- package/dist/lib/explorer.d.ts +44 -0
- package/dist/lib/feedback.d.ts +35 -0
- package/dist/lib/jail-guard.d.ts +59 -0
- package/dist/lib/live-server.d.ts +5 -0
- package/dist/lib/prompt-runner.d.ts +1 -0
- package/dist/lib/quiescence.d.ts +44 -0
- package/dist/lib/recorder.d.ts +24 -0
- package/dist/lib/reporter.d.ts +2 -0
- package/dist/lib/step-handlers.d.ts +2 -0
- package/dist/lib/triage.d.ts +50 -0
- package/dist/lib/wizard.d.ts +42 -0
- package/dist/lib/zip-util.d.ts +36 -0
- package/docs/ARCHITECTURE.md +4 -4
- package/docs/CLI_CONTRACT.md +131 -0
- package/docs/CLI_STUDIO_CONTRACT.md +123 -0
- package/docs/PERFORMANCE_BASELINE.md +71 -0
- package/docs/PRODUCT_STATUS.md +56 -0
- package/docs/USER_MANUAL.md +6 -7
- package/package.json +12 -3
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module adaptive-timing
|
|
3
|
+
* @description Device-Aware Adaptive Dynamic Waiting & Auto-Profiling.
|
|
4
|
+
*
|
|
5
|
+
* Automatically balances test timing between ultra-fast physical devices (USB 3.0)
|
|
6
|
+
* and resource-constrained CI emulators (software-rendered VMs in GitHub Actions).
|
|
7
|
+
*
|
|
8
|
+
* Implements exponential backoff condition-driven polling with instant short-circuiting:
|
|
9
|
+
* fast devices finish immediately upon event completion, while slow emulators receive
|
|
10
|
+
* adaptive headroom without CPU exhaustion.
|
|
11
|
+
*/
|
|
12
|
+
import type { AndroidDriver } from './adb.js';
|
|
13
|
+
export interface DeviceProfile {
|
|
14
|
+
/** Whether the target device is an emulator / virtual device */
|
|
15
|
+
isEmulator: boolean;
|
|
16
|
+
/** Whether the process is executing inside a CI / CD environment (e.g. GitHub Actions) */
|
|
17
|
+
isCI: boolean;
|
|
18
|
+
/** Calculated dynamic velocity multiplier (1.0 = real device, 1.5 = local emulator, 2.5 = CI) */
|
|
19
|
+
velocityMultiplier: number;
|
|
20
|
+
/** Default timeout ceiling for UI element detection */
|
|
21
|
+
defaultTimeoutMs: number;
|
|
22
|
+
/** Extended timeout ceiling for multi-step transitions and cold loads */
|
|
23
|
+
extendedTimeoutMs: number;
|
|
24
|
+
/** Minimum stability duration for dual-sample quiescence verification */
|
|
25
|
+
quiescenceSettleMs: number;
|
|
26
|
+
/** Initial polling interval in milliseconds */
|
|
27
|
+
initialPollMs: number;
|
|
28
|
+
/** Maximum backoff polling interval in milliseconds */
|
|
29
|
+
maxPollIntervalMs: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Probes the connected device and host runtime to construct an adaptive timing profile.
|
|
33
|
+
* Cached per session so that subsequent steps reuse the profiled characteristics.
|
|
34
|
+
*
|
|
35
|
+
* @param driver - Android driver instance
|
|
36
|
+
* @param serial - Optional target device serial
|
|
37
|
+
*/
|
|
38
|
+
export declare function profileDeviceEnvironment(driver: AndroidDriver, serial?: string): Promise<DeviceProfile>;
|
|
39
|
+
/**
|
|
40
|
+
* Resets the cached device profile (primarily used in testing).
|
|
41
|
+
*/
|
|
42
|
+
export declare function resetDeviceProfile(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Polls an asynchronous condition using adaptive backoff with immediate short-circuiting.
|
|
45
|
+
*
|
|
46
|
+
* Fast devices short-circuit the instant the condition returns a truthy value.
|
|
47
|
+
* Slow emulators receive backoff polling that preserves CPU cycles for rendering.
|
|
48
|
+
*
|
|
49
|
+
* @param checkFn - Async callback returning a truthy value when the condition is met.
|
|
50
|
+
* @param timeoutMs - Maximum duration to wait before giving up.
|
|
51
|
+
* @param initialIntervalMs - Starting interval between checks.
|
|
52
|
+
* @param maxIntervalMs - Cap for the backoff interval.
|
|
53
|
+
* @returns The resolved value of the condition, or throws a timeout Error.
|
|
54
|
+
*/
|
|
55
|
+
export declare function pollWithAdaptiveBackoff<T>(checkFn: () => Promise<T | null | undefined | false>, timeoutMs: number, initialIntervalMs?: number, maxIntervalMs?: number): Promise<T>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module adb-provisioner
|
|
3
|
+
* @description
|
|
4
|
+
* Zero-dependency hardware discovery and ADB provisioning engine.
|
|
5
|
+
* Automatically discovers, validates, and provisions Android Debug Bridge (ADB)
|
|
6
|
+
* binaries across Windows, macOS, and Linux without requiring full Android Studio installation.
|
|
7
|
+
*/
|
|
8
|
+
export interface AdbDiagnosticInfo {
|
|
9
|
+
binaryPath: string;
|
|
10
|
+
isAvailable: boolean;
|
|
11
|
+
version?: string;
|
|
12
|
+
source: 'PROMPTTEST_OVERRIDE' | 'BUNDLED_LOCAL' | 'SYSTEM_PATH' | 'ANDROID_HOME' | 'STANDALONE_CACHE' | 'STANDARD_SDK' | 'FALLBACK';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Discovers the absolute or executable path to the ADB binary on the host system.
|
|
16
|
+
* Evaluates candidate locations in strict order of reliability:
|
|
17
|
+
* 1. Environment override (`PROMPTTEST_ADB_PATH`)
|
|
18
|
+
* 2. Bundled / Adjacent platform-tools (next to executable, app bundle, or current cwd)
|
|
19
|
+
* 3. System PATH lookup
|
|
20
|
+
* 4. Android SDK environment variables (`ANDROID_HOME`, `ANDROID_SDK_ROOT`)
|
|
21
|
+
* 5. Standard platform installation paths
|
|
22
|
+
* 6. Standalone user cache (`~/.prompttest/platform-tools/adb`)
|
|
23
|
+
*/
|
|
24
|
+
export declare function getAdbBinary(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Checks whether the resolved ADB binary is executable and operational.
|
|
27
|
+
*
|
|
28
|
+
* @param customPath Optional custom binary path to verify.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isAdbAvailable(customPath?: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Returns full diagnostics about ADB availability and resolution origin.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getAdbDiagnostics(): AdbDiagnosticInfo;
|
|
35
|
+
/**
|
|
36
|
+
* Resets cached ADB path (useful for testing and runtime environment shifts).
|
|
37
|
+
*/
|
|
38
|
+
export declare function resetAdbCache(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Automatically downloads and provisions official platform-tools if ADB is missing.
|
|
41
|
+
*/
|
|
42
|
+
export declare function downloadPlatformToolsFallback(customDestDir?: string): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Prompts the user for explicit permission to download official platform-tools if ADB is missing.
|
|
45
|
+
* Automatically approved if --download-adb, -y, or --yes flag is present in process.argv.
|
|
46
|
+
*/
|
|
47
|
+
export declare function promptUserForAdbDownload(): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Asserts that ADB is available, prompting for user permission before automated provisioning if missing.
|
|
50
|
+
*
|
|
51
|
+
* @param options.skipPrompt If true, bypasses the user prompt (e.g. when --download-adb flag is passed).
|
|
52
|
+
*/
|
|
53
|
+
export declare function ensureAdbProvisioned(options?: {
|
|
54
|
+
skipPrompt?: boolean;
|
|
55
|
+
}): Promise<string>;
|
package/dist/lib/adb.d.ts
CHANGED
|
@@ -19,6 +19,29 @@ export interface AndroidDevice {
|
|
|
19
19
|
/** The product name of the device (optional) */
|
|
20
20
|
product?: string;
|
|
21
21
|
}
|
|
22
|
+
export interface DeviceMetrics {
|
|
23
|
+
battery?: {
|
|
24
|
+
level?: number;
|
|
25
|
+
temperatureC?: number;
|
|
26
|
+
status?: string;
|
|
27
|
+
};
|
|
28
|
+
display?: {
|
|
29
|
+
width?: number;
|
|
30
|
+
height?: number;
|
|
31
|
+
density?: number;
|
|
32
|
+
};
|
|
33
|
+
memory?: {
|
|
34
|
+
pssKb?: number;
|
|
35
|
+
privateDirtyKb?: number;
|
|
36
|
+
nativeHeapKb?: number;
|
|
37
|
+
};
|
|
38
|
+
graphics?: {
|
|
39
|
+
framesRendered?: number;
|
|
40
|
+
jankyFrames?: number;
|
|
41
|
+
percentile90Ms?: number;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export declare function parseDeviceMetrics(batteryOutput: string, displayOutput: string, memoryOutput: string, graphicsOutput: string): DeviceMetrics;
|
|
22
45
|
/**
|
|
23
46
|
* AndroidDriver is responsible for executing ADB commands and handling device interactions.
|
|
24
47
|
* It manages the default targeted device, executes shell commands, extracts device state,
|
|
@@ -323,6 +346,11 @@ export declare class AndroidDriver {
|
|
|
323
346
|
* @throws An Error if the device IP cannot be detected.
|
|
324
347
|
*/
|
|
325
348
|
disconnectWifi(target?: string): Promise<string>;
|
|
349
|
+
pairWifi(target: string, pairingCode: string): Promise<{
|
|
350
|
+
success: boolean;
|
|
351
|
+
message: string;
|
|
352
|
+
}>;
|
|
353
|
+
getDeviceMetrics(serial?: string): Promise<DeviceMetrics>;
|
|
326
354
|
/**
|
|
327
355
|
* Streams the Android events logcat buffer in real-time.
|
|
328
356
|
* Used for detecting screen transitions via wm_on_resume_called events.
|
|
@@ -378,6 +406,7 @@ export declare class AndroidDriver {
|
|
|
378
406
|
}, localDestPath: string, serial?: string): Promise<string>;
|
|
379
407
|
/**
|
|
380
408
|
* Checks if the virtual software keyboard (IME) is currently active and visible on screen.
|
|
409
|
+
* Uses fast shell grep filtering across Android IME & Window properties with resilient fallbacks.
|
|
381
410
|
* @param serial Optional target device serial.
|
|
382
411
|
* @returns Promise resolving to true if virtual keyboard is displayed.
|
|
383
412
|
*/
|
package/dist/lib/baseline.d.ts
CHANGED
|
@@ -2,19 +2,33 @@
|
|
|
2
2
|
* Rectangular region on the screen to ignore during visual comparison.
|
|
3
3
|
*/
|
|
4
4
|
export interface MaskRegion {
|
|
5
|
-
/** The starting horizontal pixel coordinate. */
|
|
5
|
+
/** The starting horizontal pixel coordinate or relative float (0.0 - 1.0). */
|
|
6
6
|
x: number;
|
|
7
|
-
/** The starting vertical pixel coordinate. */
|
|
7
|
+
/** The starting vertical pixel coordinate or relative float (0.0 - 1.0). */
|
|
8
8
|
y: number;
|
|
9
|
-
/** Width of the region in pixels. */
|
|
9
|
+
/** Width of the region in pixels or relative float (0.0 - 1.0). */
|
|
10
10
|
width: number;
|
|
11
|
-
/** Height of the region in pixels. */
|
|
11
|
+
/** Height of the region in pixels or relative float (0.0 - 1.0). */
|
|
12
12
|
height: number;
|
|
13
|
+
/** Optional human-readable label for the ignored region (e.g., 'Status Bar', 'Clock'). */
|
|
14
|
+
label?: string;
|
|
13
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Predefined tolerance and sensitivity presets for visual comparison.
|
|
18
|
+
*/
|
|
19
|
+
export type MatchingMode = 'strict' | 'moderate' | 'relaxed';
|
|
20
|
+
export declare const MATCHING_MODES: Record<MatchingMode, {
|
|
21
|
+
threshold: number;
|
|
22
|
+
pixelmatchThreshold: number;
|
|
23
|
+
label: string;
|
|
24
|
+
description: string;
|
|
25
|
+
}>;
|
|
14
26
|
/**
|
|
15
27
|
* Options for configuring visual baseline comparisons.
|
|
16
28
|
*/
|
|
17
29
|
export interface BaselineCompareOptions {
|
|
30
|
+
/** Matching preset mode ('strict', 'moderate', 'relaxed'). Defaults to 'moderate'. */
|
|
31
|
+
mode?: MatchingMode;
|
|
18
32
|
/** Override the maximum allowed diffRatio (0.0 to 1.0) before failing. */
|
|
19
33
|
threshold?: number;
|
|
20
34
|
/** Array of bounding boxes to mask out (e.g. dynamic clocks, battery, animations). */
|
|
@@ -61,6 +75,24 @@ export declare class BaselineManager {
|
|
|
61
75
|
constructor(baselineDir?: string, threshold?: number);
|
|
62
76
|
private filePath;
|
|
63
77
|
private diffFilePath;
|
|
78
|
+
private masksFilePath;
|
|
79
|
+
/**
|
|
80
|
+
* Retrieves saved mask regions for a specific test step.
|
|
81
|
+
*
|
|
82
|
+
* @param specName The name of the test specification.
|
|
83
|
+
* @param stepIndex The 0-based index of the step within the spec.
|
|
84
|
+
* @returns Array of MaskRegion bounding boxes.
|
|
85
|
+
*/
|
|
86
|
+
getMasks(specName: string, stepIndex: number): Promise<MaskRegion[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Persists mask regions to disk for a specific test step.
|
|
89
|
+
*
|
|
90
|
+
* @param specName The name of the test specification.
|
|
91
|
+
* @param stepIndex The 0-based index of the step within the spec.
|
|
92
|
+
* @param masks Array of MaskRegion bounding boxes.
|
|
93
|
+
* @returns The file path where masks were stored.
|
|
94
|
+
*/
|
|
95
|
+
saveMasks(specName: string, stepIndex: number, masks: MaskRegion[]): Promise<string>;
|
|
64
96
|
/**
|
|
65
97
|
* Saves a new screenshot as the baseline reference for a specific test step.
|
|
66
98
|
* Uses an atomic write (via a temp file) to prevent partial writes.
|
|
@@ -96,14 +128,30 @@ export declare class BaselineManager {
|
|
|
96
128
|
private fitToCanvas;
|
|
97
129
|
/**
|
|
98
130
|
* Masks specified rectangular regions in-place by setting their RGBA values to 0.
|
|
131
|
+
* Supports both pixel coordinates and relative fractional coordinates (0.0 to 1.0).
|
|
99
132
|
*/
|
|
100
133
|
private applyMasks;
|
|
134
|
+
/**
|
|
135
|
+
* Overwrites the golden baseline with the current screenshot or a provided buffer.
|
|
136
|
+
*
|
|
137
|
+
* @param specName The name of the test specification.
|
|
138
|
+
* @param stepIndex The 0-based index of the step within the spec.
|
|
139
|
+
* @param screenshot Optional replacement buffer; if omitted, copies current run screenshot.
|
|
140
|
+
*/
|
|
141
|
+
approveBaseline(specName: string, stepIndex: number, screenshot?: Buffer): Promise<string>;
|
|
101
142
|
/**
|
|
102
143
|
* Deletes all saved baseline, current, and diff images for a given spec.
|
|
103
144
|
*
|
|
104
145
|
* @param specName The name of the test specification to clear baselines for.
|
|
105
146
|
*/
|
|
106
147
|
clearBaselines(specName: string): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Deletes all saved baseline, current, diff images, and masks for a single specific step.
|
|
150
|
+
*
|
|
151
|
+
* @param specName The name of the test specification.
|
|
152
|
+
* @param stepIndex The 1-based step index to delete.
|
|
153
|
+
*/
|
|
154
|
+
deleteStepBaseline(specName: string, stepIndex: number): Promise<void>;
|
|
107
155
|
}
|
|
108
156
|
/**
|
|
109
157
|
* A globally accessible singleton instance of BaselineManager.
|
package/dist/lib/dfs-engine.d.ts
CHANGED
|
@@ -25,6 +25,28 @@ export interface NavigationFrame {
|
|
|
25
25
|
actionTaken?: string;
|
|
26
26
|
timestamp: number;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Telemetry event emitted by the DFS engine while traversing the state graph.
|
|
30
|
+
* Consumed by the Studio Auto-Pilot tab through the live-server SSE stream.
|
|
31
|
+
*/
|
|
32
|
+
export interface DfsTelemetryEvent {
|
|
33
|
+
/** Event category: executor action, screen discovery, safety block, defect, or completion. */
|
|
34
|
+
type: 'action' | 'state_change' | 'safety_block' | 'crash' | 'done';
|
|
35
|
+
/** Plain-English description. Action descriptions are spec-compatible instructions. */
|
|
36
|
+
description: string;
|
|
37
|
+
/** Canonical semantic hash of the screen the event occurred on. */
|
|
38
|
+
screenHash?: string;
|
|
39
|
+
/** Human-readable screen title (domain path) used to label the state-graph node. */
|
|
40
|
+
screenTitle?: string;
|
|
41
|
+
/** DFS depth of the screen the event occurred on. */
|
|
42
|
+
depth?: number;
|
|
43
|
+
/** Number of interactive candidate elements catalogued on the screen. */
|
|
44
|
+
elementCount?: number;
|
|
45
|
+
/** Number of unique screens discovered so far. */
|
|
46
|
+
discoveredScreens?: number;
|
|
47
|
+
/** Number of interaction steps consumed so far. */
|
|
48
|
+
totalSteps?: number;
|
|
49
|
+
}
|
|
28
50
|
export interface DfsEngineOptions {
|
|
29
51
|
packageName: string;
|
|
30
52
|
serial?: string;
|
|
@@ -36,6 +58,12 @@ export interface DfsEngineOptions {
|
|
|
36
58
|
safetyBlacklist?: readonly (string | RegExp)[];
|
|
37
59
|
screenshotPolicy?: 'all' | 'state-change' | 'failure-only';
|
|
38
60
|
skipAlreadyCrawled?: boolean;
|
|
61
|
+
/** Optional telemetry sink invoked for every traversal event (Studio Auto-Pilot SSE). */
|
|
62
|
+
onStep?: (event: DfsTelemetryEvent) => void;
|
|
63
|
+
/** Optional abort flag checked between steps to terminate traversal gracefully. */
|
|
64
|
+
abortSignal?: {
|
|
65
|
+
aborted: boolean;
|
|
66
|
+
};
|
|
39
67
|
}
|
|
40
68
|
/**
|
|
41
69
|
* Universal Hierarchical State-Graph DFS Engine (Universal Exploration Engine).
|
|
@@ -55,7 +83,22 @@ export declare class HierarchicalDfsEngine {
|
|
|
55
83
|
devDefectsList: string[];
|
|
56
84
|
safetyHitList: string[];
|
|
57
85
|
externalSkippedList: string[];
|
|
86
|
+
/** Telemetry listener registered for the active traversal session. */
|
|
87
|
+
private stepListener?;
|
|
88
|
+
/** Abort flag registered for the active traversal session. */
|
|
89
|
+
private abortFlag?;
|
|
58
90
|
constructor(driver?: AndroidDriver, reporter?: QaReporter, memory?: MemoryEngine);
|
|
91
|
+
/**
|
|
92
|
+
* Emits a telemetry event to the registered listener, defaulting the live counters.
|
|
93
|
+
* Screen depth and element counts are back-filled from the state-graph ledger so the
|
|
94
|
+
* Studio Auto-Pilot graph renders real hierarchy instead of a flat staircase.
|
|
95
|
+
* Listener failures are swallowed so observability can never break traversal.
|
|
96
|
+
*
|
|
97
|
+
* @param event - The traversal event to broadcast.
|
|
98
|
+
*/
|
|
99
|
+
private emitStep;
|
|
100
|
+
/** Returns true when the active session has been aborted by the caller. */
|
|
101
|
+
private isAborted;
|
|
59
102
|
/**
|
|
60
103
|
* Captures UI hierarchy globally, intercepting and triaging any development error consoles,
|
|
61
104
|
* LogBox overlays, warnings, info toasts, or ANRs before returning a clean app hierarchy.
|
package/dist/lib/explorer.d.ts
CHANGED
|
@@ -3,6 +3,36 @@ import { type SafetyMode, type UiNode } from './crawler.js';
|
|
|
3
3
|
import { SemanticFormFiller } from './form-filler.js';
|
|
4
4
|
import { QaReporter } from './reporter.js';
|
|
5
5
|
import { MemoryEngine } from './memory.js';
|
|
6
|
+
/**
|
|
7
|
+
* Represents a single autonomous exploration event, emitted as the explorer acts.
|
|
8
|
+
* Used for Studio SSE streaming via the /api/explore/* endpoints.
|
|
9
|
+
*/
|
|
10
|
+
export interface ExploreEvent {
|
|
11
|
+
/** Type of event: action taken, state change, safety block, crash intercepted, session done, or error. */
|
|
12
|
+
type: 'action' | 'state_change' | 'safety_block' | 'crash' | 'done' | 'error';
|
|
13
|
+
/** Monotonic step counter within this session. */
|
|
14
|
+
stepNumber: number;
|
|
15
|
+
/** Human-readable description of the event. */
|
|
16
|
+
description: string;
|
|
17
|
+
/** MD5-prefix hash of the screen hierarchy at this moment (for state-graph nodes). */
|
|
18
|
+
screenHash?: string;
|
|
19
|
+
/** Optional human-readable title for the screen (domain path) used to label the state-graph node. */
|
|
20
|
+
screenTitle?: string;
|
|
21
|
+
/** Optional traversal depth of the screen this event occurred on (DFS nesting level). */
|
|
22
|
+
depth?: number;
|
|
23
|
+
/** Optional number of interactive candidate elements catalogued on the screen. */
|
|
24
|
+
elementCount?: number;
|
|
25
|
+
/** Total discovered unique screens so far. */
|
|
26
|
+
discoveredScreens?: number;
|
|
27
|
+
/** Duration of the action in milliseconds. */
|
|
28
|
+
durationMs?: number;
|
|
29
|
+
/** Total step budget consumed so far. */
|
|
30
|
+
totalSteps?: number;
|
|
31
|
+
/** Package being explored. */
|
|
32
|
+
packageName?: string;
|
|
33
|
+
/** Auto-generated spec lines (only present on 'done' event). */
|
|
34
|
+
generatedSpec?: string;
|
|
35
|
+
}
|
|
6
36
|
/**
|
|
7
37
|
* Configuration options for the AutonomousExplorer.
|
|
8
38
|
*/
|
|
@@ -31,6 +61,20 @@ export interface ExplorerOptions {
|
|
|
31
61
|
stepBudget?: number;
|
|
32
62
|
/** Screenshot policy ('state-change', 'failure-only', 'all') (AX-16). Default is 'state-change'. */
|
|
33
63
|
screenshots?: 'state-change' | 'failure-only' | 'all';
|
|
64
|
+
/** Whether to record entire exploration session to an MP4 video (Phase 26). Default is false. */
|
|
65
|
+
video?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Optional callback fired after every significant exploration event.
|
|
68
|
+
* Used by live-server to SSE-stream progress to Studio Auto-Pilot tab.
|
|
69
|
+
*/
|
|
70
|
+
onStep?: (event: ExploreEvent) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Optional abort signal. When set, the explorer checks this flag between steps
|
|
73
|
+
* and terminates the session gracefully if it becomes true.
|
|
74
|
+
*/
|
|
75
|
+
abortSignal?: {
|
|
76
|
+
aborted: boolean;
|
|
77
|
+
};
|
|
34
78
|
}
|
|
35
79
|
/**
|
|
36
80
|
* AutonomousExplorer implements the heuristic mobile crawler.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module feedback
|
|
3
|
+
* @description
|
|
4
|
+
* Direct in-CLI feedback and community suggestion portal for PromptTest.
|
|
5
|
+
* Collects user ratings, feature suggestions, or issue reports and generates
|
|
6
|
+
* 1-click pre-filled submissions to the public prompttest-community repository.
|
|
7
|
+
*/
|
|
8
|
+
export type FeedbackCategory = 'feature' | 'bug' | 'general';
|
|
9
|
+
export interface FeedbackData {
|
|
10
|
+
rating?: number;
|
|
11
|
+
category: FeedbackCategory;
|
|
12
|
+
message: string;
|
|
13
|
+
author?: string;
|
|
14
|
+
environment?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface FeedbackOptions {
|
|
17
|
+
input?: NodeJS.ReadableStream;
|
|
18
|
+
output?: NodeJS.WritableStream;
|
|
19
|
+
directMessage?: string;
|
|
20
|
+
category?: FeedbackCategory;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Constructs a pre-filled GitHub issue or discussion URL based on the feedback category.
|
|
24
|
+
*
|
|
25
|
+
* @param data - The user feedback payload.
|
|
26
|
+
* @returns The fully-encoded GitHub URL.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildFeedbackUrl(data: FeedbackData): string;
|
|
29
|
+
/**
|
|
30
|
+
* Starts an interactive feedback collection session in the terminal.
|
|
31
|
+
*
|
|
32
|
+
* @param options - Stream and direct message options.
|
|
33
|
+
* @returns The generated pre-filled GitHub URL.
|
|
34
|
+
*/
|
|
35
|
+
export declare function startFeedbackSession(options?: FeedbackOptions): Promise<string>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module jail-guard
|
|
3
|
+
* @description Zero-Overhead In-Memory App Boundary Guardian for PromptTest.
|
|
4
|
+
*
|
|
5
|
+
* Enforces strict package boundary isolation to guarantee that automation
|
|
6
|
+
* NEVER sends touch, text, or gesture events into third-party personal apps
|
|
7
|
+
* (e.g. banking apps, email, browsers) or home screen launchers.
|
|
8
|
+
*
|
|
9
|
+
* Operates directly on the in-memory parsed hierarchy (UiNode.packageName)
|
|
10
|
+
* with 0 ms additional ADB overhead in normal operation.
|
|
11
|
+
*/
|
|
12
|
+
import type { UiNode } from './crawler.js';
|
|
13
|
+
import type { AndroidDriver } from './adb.js';
|
|
14
|
+
/**
|
|
15
|
+
* Registry of known Android OEM launchers and desktop interfaces.
|
|
16
|
+
*/
|
|
17
|
+
export declare const KNOWN_LAUNCHER_PACKAGES: readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* Registry of allowed Android system overlay and framework packages
|
|
20
|
+
* (keyboards, permission dialogs, autofill, package installer).
|
|
21
|
+
*/
|
|
22
|
+
export declare const KNOWN_SYSTEM_PACKAGES: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* Checks if a given package name corresponds to a known launcher or desktop interface.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isLauncherPackage(pkg: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Checks if a given package name corresponds to an allowed Android system overlay.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isAllowedSystemPackage(pkg: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Determines whether a specific node's package belongs to the target app under test
|
|
33
|
+
* or an allowed system overlay (keyboard, permission prompt, system UI).
|
|
34
|
+
*
|
|
35
|
+
* @param nodePackage - The package name of the UI node being interacted with.
|
|
36
|
+
* @param targetPackage - The target application package under test (if specified).
|
|
37
|
+
*/
|
|
38
|
+
export declare function isTargetOrAllowedSystem(nodePackage?: string, targetPackage?: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Extracts the primary / foreground package from a flattened list of UiNodes.
|
|
41
|
+
* Evaluates non-system, interactive nodes first, then falls back to the root node.
|
|
42
|
+
*/
|
|
43
|
+
export declare function detectScreenPackage(nodes: UiNode[]): string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Guards the app boundary: If an escape is detected (screen belongs to a launcher or foreign app),
|
|
46
|
+
* it blocks further actions, prevents unsafe back-presses on launchers, and brings the target app
|
|
47
|
+
* back to the foreground.
|
|
48
|
+
*
|
|
49
|
+
* @param nodes - In-memory UI nodes from current hierarchy dump.
|
|
50
|
+
* @param targetPackage - The expected target application package.
|
|
51
|
+
* @param driver - Android driver instance for containment recovery.
|
|
52
|
+
* @param serial - Optional target device serial.
|
|
53
|
+
* @returns Details on whether an escape occurred and whether recovery succeeded.
|
|
54
|
+
*/
|
|
55
|
+
export declare function guardAppBoundary(nodes: UiNode[], targetPackage: string, driver: AndroidDriver, serial?: string): Promise<{
|
|
56
|
+
escaped: boolean;
|
|
57
|
+
recovered: boolean;
|
|
58
|
+
currentPackage: string | null;
|
|
59
|
+
}>;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import http from 'http';
|
|
10
10
|
import { AuditStep, QaReportData } from './reporter.js';
|
|
11
|
+
import { AndroidDriver } from './adb.js';
|
|
11
12
|
export interface LiveServerOptions {
|
|
12
13
|
/** The port number to listen on. Defaults to 4040 (or 0 for random available port). */
|
|
13
14
|
port?: number;
|
|
@@ -15,10 +16,14 @@ export interface LiveServerOptions {
|
|
|
15
16
|
host?: string;
|
|
16
17
|
/** Directory where screenshots, recordings, and report artifacts are located. */
|
|
17
18
|
outputDir?: string;
|
|
19
|
+
/** Directory containing test specifications. Defaults to process.cwd()/specs. */
|
|
20
|
+
specsDir?: string;
|
|
18
21
|
/** Name of the test suite being executed. */
|
|
19
22
|
suiteName?: string;
|
|
20
23
|
/** Initial report data if available. */
|
|
21
24
|
initialReport?: QaReportData;
|
|
25
|
+
/** Optional AndroidDriver instance for interactive device state and actions. */
|
|
26
|
+
driver?: AndroidDriver;
|
|
22
27
|
}
|
|
23
28
|
export interface LiveServerHandle {
|
|
24
29
|
/** The underlying Node.js HTTP server instance. */
|
|
@@ -19,6 +19,7 @@ export declare class PromptRunner {
|
|
|
19
19
|
private lastHierarchy;
|
|
20
20
|
private screenDimensions;
|
|
21
21
|
private navBarHeight;
|
|
22
|
+
private targetPackage;
|
|
22
23
|
/**
|
|
23
24
|
* Initializes a new instance of the PromptRunner.
|
|
24
25
|
* Uses dependency injection for core services, defaulting to singletons if omitted.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module quiescence
|
|
3
|
+
* @description Dynamic Screen Quiescence & Idling Sentinel for PromptTest.
|
|
4
|
+
*
|
|
5
|
+
* Implements self-synchronizing stability detection inspired by Playwright's networkidle
|
|
6
|
+
* and Android Espresso's IdlingResource. Replaces fragile static timers with dual-sample
|
|
7
|
+
* layout stabilization and active in-flight loading sentinel checks.
|
|
8
|
+
*/
|
|
9
|
+
import type { UiNode } from './crawler.js';
|
|
10
|
+
import type { ExecutionContext } from './step-handlers.js';
|
|
11
|
+
export interface QuiescenceResult {
|
|
12
|
+
/** Whether the screen reached verified stability before the timeout */
|
|
13
|
+
settled: boolean;
|
|
14
|
+
/** Milliseconds elapsed during stabilization */
|
|
15
|
+
durationMs: number;
|
|
16
|
+
/** Final structural hash of the quiescent screen */
|
|
17
|
+
finalHash: string;
|
|
18
|
+
/** Flattened UI nodes of the quiescent screen */
|
|
19
|
+
flat: UiNode[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Inspects a flattened UI hierarchy to detect active in-flight network spinners,
|
|
23
|
+
* shimmers, progress bars, or server-waiting indicators.
|
|
24
|
+
*
|
|
25
|
+
* @param nodes - Flattened array of UiNodes
|
|
26
|
+
* @returns Status indicating whether loading is in progress and why.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isLoadingInProgress(nodes: UiNode[]): {
|
|
29
|
+
loading: boolean;
|
|
30
|
+
reason?: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Dynamically waits until the application screen achieves 100% quiescence:
|
|
34
|
+
* 1. All active loading indicators and spinners have vanished.
|
|
35
|
+
* 2. Two consecutive UI hierarchy snapshots yield matching structural hashes.
|
|
36
|
+
*
|
|
37
|
+
* Exits immediately once settled, saving seconds on fast devices while providing
|
|
38
|
+
* dynamic patience for slow network requests or cloud emulators.
|
|
39
|
+
*
|
|
40
|
+
* @param ctx - Execution context providing driver and hierarchy access.
|
|
41
|
+
* @param timeoutMs - Maximum wait ceiling (defaults to 4500ms).
|
|
42
|
+
* @param sampleIntervalMs - Interval between stability probe samples (defaults to 150ms).
|
|
43
|
+
*/
|
|
44
|
+
export declare function waitForQuiescence(ctx: ExecutionContext, timeoutMs?: number, sampleIntervalMs?: number): Promise<QuiescenceResult>;
|
package/dist/lib/recorder.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface RecordedEvent {
|
|
|
23
23
|
* into semantic PromptTest step instructions.
|
|
24
24
|
*/
|
|
25
25
|
export declare class AutonomousRecorder {
|
|
26
|
+
onStep?: (step: string) => void;
|
|
26
27
|
private driver;
|
|
27
28
|
private deviceLock;
|
|
28
29
|
private isRecording;
|
|
@@ -82,6 +83,29 @@ export declare class AutonomousRecorder {
|
|
|
82
83
|
*/
|
|
83
84
|
private appendStep;
|
|
84
85
|
private extractBrandSlug;
|
|
86
|
+
/**
|
|
87
|
+
* Starts an interactive real-time recording session on the target Android device.
|
|
88
|
+
* Automatically detects the active app, starts capturing gestures and key events,
|
|
89
|
+
* monitors screen transitions, and writes out a plain-text spec.
|
|
90
|
+
*
|
|
91
|
+
* @param outputSpecPath Optional file path to save the generated test spec to.
|
|
92
|
+
* @param serial Optional serial number of the target device to record from.
|
|
93
|
+
* @param options Additional recording configuration options.
|
|
94
|
+
* @returns A promise that resolves when the recording session concludes.
|
|
95
|
+
*/
|
|
96
|
+
/**
|
|
97
|
+
* Starts a non-blocking recording session (used by both CLI and Live Server).
|
|
98
|
+
*/
|
|
99
|
+
startSession(outputSpecPath?: string, serial?: string, options?: RecordOptions): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Stops an active recording session, terminates background processes,
|
|
102
|
+
* releases device lock, and returns the recorded steps and file paths.
|
|
103
|
+
*/
|
|
104
|
+
stopSession(): Promise<{
|
|
105
|
+
steps: string[];
|
|
106
|
+
specPath: string;
|
|
107
|
+
reportPath: string;
|
|
108
|
+
}>;
|
|
85
109
|
/**
|
|
86
110
|
* Starts an interactive real-time recording session on the target Android device.
|
|
87
111
|
* Automatically detects the active app, starts capturing gestures and key events,
|
package/dist/lib/reporter.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface AuditStep {
|
|
|
31
31
|
durationMs?: number;
|
|
32
32
|
/** Relative path to the failure triage bundle directory if step failed. */
|
|
33
33
|
triageBundle?: string;
|
|
34
|
+
/** Relative execution offset in milliseconds from start of run / video recording. */
|
|
35
|
+
videoOffsetMs?: number;
|
|
34
36
|
/** Additional diagnostic data or context about the step. */
|
|
35
37
|
details?: Record<string, unknown>;
|
|
36
38
|
}
|
|
@@ -21,6 +21,8 @@ import { PromptStep } from './prompt-runner.js';
|
|
|
21
21
|
* It encapsulates the driver instance, state cache, and common UI interaction logic.
|
|
22
22
|
*/
|
|
23
23
|
export interface ExecutionContext {
|
|
24
|
+
/** Target application package name under test (used for jail guard containment). */
|
|
25
|
+
targetPackage?: string;
|
|
24
26
|
/** The ADB-based Android UI driver used to interact with the device. */
|
|
25
27
|
driver: AndroidDriver;
|
|
26
28
|
/** Memory engine used to record and learn resilient locators over time. */
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module triage
|
|
3
|
+
* @description
|
|
4
|
+
* Auto-crash triage and privacy-safe GitHub bug report link generator for PromptTest.
|
|
5
|
+
* Provides passive, zero-telemetry 1-click issue reporting when unexpected
|
|
6
|
+
* internal framework crashes or unhandled exceptions occur.
|
|
7
|
+
*/
|
|
8
|
+
export interface TriageOptions {
|
|
9
|
+
errorMessage: string;
|
|
10
|
+
stack?: string;
|
|
11
|
+
command?: string;
|
|
12
|
+
exitCode?: number;
|
|
13
|
+
repoUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface TriageContext {
|
|
16
|
+
command?: string;
|
|
17
|
+
exitCode?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Sanitizes stack traces and error messages by stripping personal user directories
|
|
21
|
+
* (e.g. C:\Users\username\... or /Users/username/...) to protect developer privacy.
|
|
22
|
+
*
|
|
23
|
+
* @param trace - The raw stack trace or log string.
|
|
24
|
+
* @returns Sanitized string with user home directories replaced by '~'.
|
|
25
|
+
*/
|
|
26
|
+
export declare function sanitizeStackTrace(trace?: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Distinguishes whether an error is an expected test failure (e.g., assertion failed,
|
|
29
|
+
* element not found timeout) or an unexpected internal framework/runtime crash
|
|
30
|
+
* (TypeError, process panic, unhandled exception).
|
|
31
|
+
*
|
|
32
|
+
* @param error - The caught error or rejection reason.
|
|
33
|
+
* @returns true if the error represents an unexpected framework crash.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isFrameworkCrash(error: unknown): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Builds a sanitized, length-bounded pre-filled GitHub issue URL matching
|
|
38
|
+
* the 1_bug_report.yml template in prompttest-community.
|
|
39
|
+
*
|
|
40
|
+
* @param options - Error context and command details.
|
|
41
|
+
* @returns The fully-encoded GitHub issue URL.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildIssueUrl(options: TriageOptions): string;
|
|
44
|
+
/**
|
|
45
|
+
* Renders a polite, non-intrusive diagnostic crash triage box in the console.
|
|
46
|
+
*
|
|
47
|
+
* @param error - The caught crash error.
|
|
48
|
+
* @param context - Additional execution context (e.g. command run, exit code).
|
|
49
|
+
*/
|
|
50
|
+
export declare function displayCrashTriage(error: unknown, context?: TriageContext): void;
|