mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
2ec4e91b11
* refactor(core): move the command descriptor registry into its own package `src/core/command-descriptor/`, `src/command-catalog.ts`, `src/core/wait-positionals.ts` and `src/core/parse-timeout.ts` move as git renames into a new private package `@agent-device/command-registry` (deps: contracts, selectors). One subpath per module points straight at the moved file; no `index.ts`, no re-export at the old path. Every consumer switches to the owning specifier. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz * test(host-kit): pin the command-registry package inside the daemon code graph The daemon reaches the registry and its catalog only by workspace specifier. A walk that stopped at the package boundary would report an unchanged signature after a descriptor edit, and the client would keep reusing a daemon running the superseded policy. The manifest is asserted beside the sources because its `exports` map is what chose them. The cache doc comment quoting the old ~800-module graph is corrected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz * chore(gates): point the descriptor-registry gates at the package path R66's `COMMAND_DESCRIPTOR_MODULE`, R16's record-runtime join subject and the Fallow `AssertTrue` totality-guard key follow the registry to its package. The two descriptor hubs leave `HUB_ENTRY_FILES` because the package manifest now publishes them, so the eager-closure gate discovers them as facades and one entry gets one rule; this also flips `denyPlatformImplementations` from false (hub) to true (package entry) for both, which is intentional and stricter. `command-registry` joins the ranked spine at rank 1. No `APPROVED_OVER_CEILING` row: rename detection carries every moved entry's merge-base baseline, so all twelve fall under the no-growth rule rather than a ceiling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz --------- Co-authored-by: Claude <noreply@anthropic.com>
168 lines
5.1 KiB
TypeScript
168 lines
5.1 KiB
TypeScript
import { PUBLIC_COMMANDS } from '@agent-device/command-registry/catalog';
|
|
import type { AndroidEmulatorBehaviorId } from './behavior-coverage.ts';
|
|
import { assertAutomationSystem } from './live-automation-scenario.ts';
|
|
import { installCachedFixture } from './live-bootstrap.ts';
|
|
import { assertCaptureAndClose } from './live-capture-scenario.ts';
|
|
import { assertFormInput, assertKeyboardIme } from './live-form-scenario.ts';
|
|
import type { LiveContext } from './live-harness.ts';
|
|
import { assertInventoryAndInstall } from './live-inventory-scenario.ts';
|
|
import { assertLifecycleAndSystem } from './live-lifecycle-scenario.ts';
|
|
import { assertMaestroClickableFirst } from './live-maestro-clickable-first-scenario.ts';
|
|
import { assertObservabilityAndArtifacts } from './live-observability-scenario.ts';
|
|
import { assertFixtureReplays } from './live-replay-scenarios.ts';
|
|
import type { AndroidEmulatorScenarioStart } from './scenario-start.ts';
|
|
|
|
const C = PUBLIC_COMMANDS;
|
|
const AUTOMATION_DEEP_LINK =
|
|
'agent-device-test-app:///automation?event=cold.start&payload=%7B%22source%22%3A%22android-deep-link%22%7D';
|
|
|
|
export type AndroidEmulatorScenario = {
|
|
behaviors: readonly AndroidEmulatorBehaviorId[];
|
|
commands: readonly string[];
|
|
id: string;
|
|
run: (context: LiveContext) => Promise<void>;
|
|
start?: AndroidEmulatorScenarioStart;
|
|
tier?: 'smoke' | 'full';
|
|
};
|
|
|
|
export const ANDROID_EMULATOR_FIXTURE_BOOTSTRAP: AndroidEmulatorScenario = {
|
|
behaviors: [],
|
|
commands: [C.install],
|
|
id: 'smoke:fixture-bootstrap',
|
|
run: installCachedFixture,
|
|
};
|
|
|
|
export const ANDROID_EMULATOR_LIVE_SCENARIOS = [
|
|
{
|
|
behaviors: [],
|
|
commands: [C.devices, C.capabilities, C.apps, C.doctor],
|
|
id: 'smoke:inventory',
|
|
run: assertInventoryAndInstall,
|
|
},
|
|
{
|
|
behaviors: [
|
|
'android-resource-id-selectors',
|
|
'cold-start-deep-link-navigation',
|
|
'home-recents-restoration',
|
|
'orientation-fixture-state',
|
|
'safe-back-navigation',
|
|
],
|
|
commands: [
|
|
C.alert,
|
|
C.appSwitcher,
|
|
C.appState,
|
|
C.back,
|
|
C.click,
|
|
C.diff,
|
|
C.find,
|
|
C.get,
|
|
C.home,
|
|
C.is,
|
|
C.longPress,
|
|
C.open,
|
|
C.orientation,
|
|
C.press,
|
|
C.snapshot,
|
|
C.wait,
|
|
],
|
|
id: 'smoke:automation-system',
|
|
run: assertAutomationSystem,
|
|
start: {
|
|
ime: 'system',
|
|
landmark: 'Automation lab',
|
|
url: AUTOMATION_DEEP_LINK,
|
|
},
|
|
},
|
|
{
|
|
behaviors: ['maestro-clickable-first-selection'],
|
|
commands: [],
|
|
id: 'smoke:maestro-clickable-first',
|
|
run: assertMaestroClickableFirst,
|
|
start: {
|
|
ime: 'system',
|
|
landmark: 'Automation lab',
|
|
url: 'agent-device-test-app:///automation',
|
|
},
|
|
},
|
|
{
|
|
behaviors: ['test-ime-restoration', 'test-ime-unicode-input'],
|
|
commands: [C.fill, C.focus, C.type],
|
|
id: 'smoke:form-input',
|
|
run: assertFormInput,
|
|
start: {
|
|
ime: 'test',
|
|
landmark: 'Checkout form',
|
|
url: 'agent-device-test-app:///form',
|
|
},
|
|
},
|
|
{
|
|
behaviors: ['safe-keyboard-dismissal', 'system-ime-keyboard'],
|
|
commands: [C.keyboard],
|
|
id: 'smoke:keyboard-ime',
|
|
run: assertKeyboardIme,
|
|
start: {
|
|
ime: 'system',
|
|
landmark: 'Checkout form',
|
|
url: 'agent-device-test-app:///form',
|
|
},
|
|
},
|
|
{
|
|
behaviors: [],
|
|
commands: [C.close, C.screenshot],
|
|
id: 'smoke:capture-close',
|
|
run: assertCaptureAndClose,
|
|
start: {
|
|
ime: 'system',
|
|
landmark: 'Agent Device Tester',
|
|
url: 'agent-device-test-app:///',
|
|
},
|
|
},
|
|
{
|
|
behaviors: [
|
|
'ime-owned-input-recovery',
|
|
'push-broadcast-delivery',
|
|
'runtime-permission-recovery',
|
|
],
|
|
commands: [C.push, C.settings],
|
|
id: 'full:lifecycle-system',
|
|
run: assertLifecycleAndSystem,
|
|
tier: 'full',
|
|
},
|
|
{
|
|
behaviors: [],
|
|
commands: [C.artifacts, C.batch, C.events, C.logs, C.perf, C.record, C.trace],
|
|
id: 'full:observability-artifacts',
|
|
run: assertObservabilityAndArtifacts,
|
|
tier: 'full',
|
|
},
|
|
{
|
|
behaviors: ['helper-backed-gesture-recovery', 'long-list-scroll-recovery'],
|
|
commands: [C.gesture, C.replay, C.scroll, C.swipe, C.test],
|
|
id: 'full:fixture-replays',
|
|
run: assertFixtureReplays,
|
|
tier: 'full',
|
|
},
|
|
] as const satisfies readonly AndroidEmulatorScenario[];
|
|
|
|
export type AndroidEmulatorScenarioId = (typeof ANDROID_EMULATOR_LIVE_SCENARIOS)[number]['id'];
|
|
|
|
export function selectAndroidEmulatorScenarios(
|
|
requestedIds?: readonly string[],
|
|
): readonly AndroidEmulatorScenario[] {
|
|
if (requestedIds === undefined) return ANDROID_EMULATOR_LIVE_SCENARIOS;
|
|
if (requestedIds.length === 0) {
|
|
throw new Error('select at least one Android emulator E2E scenario');
|
|
}
|
|
const byId = new Map(ANDROID_EMULATOR_LIVE_SCENARIOS.map((scenario) => [scenario.id, scenario]));
|
|
const selected: AndroidEmulatorScenario[] = [];
|
|
const seen = new Set<string>();
|
|
for (const id of requestedIds) {
|
|
if (seen.has(id)) throw new Error(`duplicate Android emulator E2E scenario: ${id}`);
|
|
const scenario = byId.get(id as AndroidEmulatorScenarioId);
|
|
if (!scenario) throw new Error(`unknown Android emulator E2E scenario: ${id}`);
|
|
seen.add(id);
|
|
selected.push(scenario);
|
|
}
|
|
return selected;
|
|
}
|