Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .fallowrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@
"scripts/write-xcuitest-cache-metadata.mjs",
"scripts/help-conformance-sample-outputs.d.mts"
],
"ignoreDependencies": ["@theme"],
"ignoreDependencies": [
"@theme",
// @agent-device/maestro owns the source import, while the published root
// build externalizes yaml and retains runtime imports in packed chunks.
"yaml"
],
"ignoreExports": [
{
"comment": "Authoritative supported-command list; sole consumer is the conformance oracle (scripts/maestro-conformance, an ignored tooling tree).",
"file": "src/compat/maestro/program-ir-command-parser.ts",
"exports": ["SUPPORTED_MAESTRO_COMMAND_NAMES"]
},
{
"comment": "Daemon route handlers are reached only through the dynamic `import()` table in request-handler-chain.ts, which --production analysis cannot follow to a consumer.",
"file": "src/daemon/handlers/{lease,session,snapshot,react-native,record-trace,find,interaction}.ts",
Expand Down
2 changes: 1 addition & 1 deletion CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ Evidence: [ADR 0002](docs/adr/0002-persistent-platform-helper-sessions.md),
[`find.test.ts`](src/daemon/handlers/__tests__/find.test.ts),
[`snapshot-handler.test.ts`](src/daemon/handlers/__tests__/snapshot-handler.test.ts),
[`snapshot-scoped-refs.test.ts`](src/daemon/handlers/__tests__/snapshot-scoped-refs.test.ts),
[`runtime-targets-typed.test.ts`](src/compat/maestro/__tests__/runtime-targets-typed.test.ts), and
[`runtime-targets-typed.test.ts`](packages/maestro/src/internal/__tests__/runtime-targets-typed.test.ts), and
[`android-test-suite.test.ts`](test/integration/provider-scenarios/android-test-suite.test.ts).

## Testing Principles
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/0012-interactive-replay.md
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ via `open --save-script` (`src/daemon/session-action-recorder.ts`,
`||` alternates (`buildSelectorChainForNode(...).join(' || ')`,
`src/commands/interaction/runtime/resolution.ts:242`, mirrored in
`src/daemon/handlers/session-replay-heal.ts:131-135`); Maestro YAML flows import through `--maestro`
(`src/compat/maestro/`); progress is step-indexed (`stepIndex`/`stepTotal` in
(`packages/maestro/src/internal/`); progress is step-indexed (`stepIndex`/`stepTotal` in
`emitReplayTestActionProgress`, `session-replay-runtime.ts:243-260`).

Recovery was opt-in `--update`/`-u` healing (`replayUpdate` flag,
Expand Down
2 changes: 1 addition & 1 deletion fallow-baselines/health.json
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@
"src/platforms/apple/core/debug-symbols/utils.ts:high impact",
"src/platforms/linux/snapshot.ts:high impact",
"src/core/interaction-targeting.ts:high impact",
"src/compat/maestro/runtime-targets.ts:high impact",
"packages/maestro/src/internal/runtime-targets.ts:high impact",
"src/utils/source-value.ts:high impact",
"src/request/cancel.ts:high impact",
"src/commands/interaction/selectors.ts:untested risk",
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@
"package:npm": "pnpm build && pnpm build:xcuitest:ios && pnpm build:xcuitest:macos && pnpm build:xcuitest:tvos && pnpm build:xcuitest:visionos && pnpm build:macos-helper:clean && pnpm package:apple-runner:npm && pnpm build:android",
"ad": "node bin/agent-device.mjs",
"bench:help-conformance": "node scripts/help-conformance-bench.mjs",
"maestro:conformance": "node --experimental-strip-types --test scripts/maestro-conformance/verify.test.ts scripts/maestro-conformance/differential/run.test.ts scripts/maestro-conformance/differential/invariants.test.ts",
"maestro:conformance:regenerate": "node scripts/maestro-conformance/regenerate.mjs",
"maestro:conformance:differential": "node --experimental-strip-types scripts/maestro-conformance/differential/run.ts",
"maestro:conformance": "node --experimental-strip-types --test packages/maestro/test/conformance/verify.test.ts packages/maestro/test/conformance/differential/run.test.ts packages/maestro/test/conformance/differential/invariants.test.ts",
"maestro:conformance:regenerate": "node --experimental-strip-types scripts/maestro-conformance/regenerate.mjs",
"maestro:conformance:differential": "node --experimental-strip-types packages/maestro/test/conformance/differential/run.ts",
"prototype:program-boundary": "node --experimental-strip-types scripts/prototypes/daemon-boundaries/program-boundary.ts",
"prototype:session-boundary": "node --experimental-strip-types scripts/prototypes/daemon-boundaries/session-boundary.ts",
"size": "node scripts/size-report.mjs",
Expand Down Expand Up @@ -145,7 +145,7 @@
"check:unit": "pnpm check:contention-retry && pnpm test:unit && pnpm test:smoke",
"check": "pnpm check:tooling && pnpm check:fallow && pnpm check:unit",
"prepack": "pnpm check:mcp-metadata && pnpm package:npm",
"typecheck": "tsc -b packages/kernel packages/contracts && tsc -p tsconfig.json && tsc -p examples/sdk/tsconfig.json",
"typecheck": "tsc -b packages/kernel packages/contracts packages/maestro && tsc -p tsconfig.json && tsc -p examples/sdk/tsconfig.json",
"test-app:install": "pnpm install --dir examples/test-app",
"test-app:start": "pnpm --dir examples/test-app start",
"test-app:ios": "pnpm --dir examples/test-app ios",
Expand All @@ -158,7 +158,7 @@
"test-app:maestro:android": "pnpm test-app:maestro --platform android",
"test": "pnpm test:unit",
"test:unit": "vitest run --project unit-core --project subprocess-stub",
"test:maestro-compat": "vitest run --project unit-core src/compat/maestro src/compat/__tests__/replay-input.test.ts",
"test:maestro-compat": "vitest run --project unit-core packages/maestro src/daemon/adapters/maestro src/compat/__tests__/replay-input.test.ts",
"test:coverage": "vitest run --coverage",
"test:coverage:ci": "node --experimental-strip-types scripts/lib/contention-retry-run.ts --coverage",
"check:contention-retry": "node --experimental-strip-types --test scripts/lib/contention-retry-policy.test.ts",
Expand Down Expand Up @@ -247,6 +247,7 @@
"devDependencies": {
"@agent-device/contracts": "workspace:*",
"@agent-device/kernel": "workspace:*",
"@agent-device/maestro": "workspace:*",
"@chenglou/freerange": "^0.0.1",
"@stryker-mutator/core": "9.6.1",
"@stryker-mutator/vitest-runner": "9.6.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/session-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { TargetAnnotationV1 } from './target-annotation.ts';

// One recorded action in a session's script.
//
// `replay/` reads and writes these (6 modules) and `compat/maestro/` exports them, so declaring the
// `replay/` reads and writes these and the Maestro package exports them, so declaring the
// shape inside `daemon/types.ts` made both zones depend on the daemon server to describe a file
// format neither of them asks the daemon to produce. The daemon still owns the RECORDING — it is
// the only thing that appends actions; this is only the shape they are appended in.
Expand Down
19 changes: 19 additions & 0 deletions packages/maestro/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@agent-device/maestro",
"version": "0.0.0",
"private": true,
"sideEffects": false,
"type": "module",
"description": "Private Maestro compatibility engine for agent-device.",
"dependencies": {
"@agent-device/contracts": "workspace:*",
"@agent-device/kernel": "workspace:*",
"yaml": "^2.9.0"
},
"exports": {
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
29 changes: 29 additions & 0 deletions packages/maestro/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import fs from 'node:fs';
import path from 'node:path';
import { describe, expect, test } from 'vitest';
import * as maestro from './index.ts';

describe('@agent-device/maestro facade', () => {
test('the package root contains declarations and re-exports only', () => {
const source = fs.readFileSync(path.join(import.meta.dirname, 'index.ts'), 'utf8');
expect(source).not.toMatch(/^(?:import|const|let|var|function|class)\b/m);
});

test('keeps conformance and ranking machinery private', () => {
const exports = Object.keys(maestro);
expect(exports).not.toContain('parseMaestroConformanceSource');
expect(exports).not.toContain('canonicalizeUpstreamMaestroFlow');
expect(exports).not.toContain('SUPPORTED_MAESTRO_COMMAND_NAMES');
expect(exports).not.toContain('MAESTRO_CONFORMANCE_CONSTANTS');
expect(exports).not.toContain('MAESTRO_COMPATIBILITY_PRESETS');
expect(exports).not.toContain('rankMaestroFailureCandidates');
});

test('publishes no implementation subpaths and declares pure modules', () => {
const manifest = JSON.parse(
fs.readFileSync(path.join(import.meta.dirname, '../package.json'), 'utf8'),
) as { exports: Record<string, unknown>; sideEffects?: boolean };
expect(Object.keys(manifest.exports)).toEqual(['.']);
expect(manifest.sideEffects).toBe(false);
});
});
56 changes: 56 additions & 0 deletions packages/maestro/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export {
collectMaestroFailureSuggestions,
executeMaestroFlow,
inspectMaestroFlow,
type MaestroActionEvent,
type MaestroCompletedActionEvent,
type MaestroExecutionObserver,
type MaestroExecutionOptions,
type MaestroExecutionOutcome,
type MaestroFailedAction,
type MaestroFlow,
} from './internal/facade-execution.ts';

export {
exportReplayActionsToMaestro,
type MaestroExportOptions,
type MaestroExportResult,
type MaestroExportWarning,
} from './internal/facade-export.ts';

export {
formatMaestroCompatibilityReference,
MAESTRO_COMPATIBILITY_ADR_URL,
MAESTRO_COMPATIBILITY_ISSUE_URL,
MAESTRO_COMPAT_LIMITATIONS,
MAESTRO_COMPAT_SUPPORTED_CAPABILITIES,
} from './internal/facade-support.ts';

export {
createMaestroRuntimePort,
literalFromMaestroRegex,
maestroObservationMatches,
maestroTestFailure,
MAESTRO_RUNTIME_ADAPTER_POLICY,
resolveMaestroScrollableGesture,
resolveMaestroTargetFromSnapshot,
type MaestroDispatchSelector,
type MaestroObservation,
type MaestroObservationCondition,
type MaestroObservationIdentity,
type MaestroPlatform,
type MaestroRuntimeMetrics,
type MaestroRuntimeCommand,
type MaestroRuntimeOperationContext,
type MaestroRuntimeOperationResult,
type MaestroRuntimeOperations,
type MaestroRuntimePort,
type MaestroRuntimePortLifecycle,
type MaestroRuntimeReadContext,
type MaestroSelector,
type MaestroSinglePointerGestureInput,
type MaestroSnapshotTargetQuery,
type MaestroTargetMatch,
type MaestroTargetQuery,
type MaestroTargetResolution,
} from './internal/facade-runtime-port.ts';
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import type {
MaestroProgram,
MaestroSelector,
MaestroSwipeGesture,
} from '../../src/compat/maestro/program-ir.ts';
import { MAESTRO_COMPATIBILITY_PRESETS } from '../../src/compat/maestro/compatibility-policy.ts';
} from './program-ir.ts';
import { MAESTRO_COMPATIBILITY_PRESETS } from './compatibility-policy.ts';

export type CanonicalSelector = {
text?: string;
Expand Down Expand Up @@ -434,7 +434,7 @@ function canonicalizeAgentCommand(
case 'stopApp':
return { kind: 'stopApp' };
case 'repeat':
return { kind: 'repeat', times: numLike(command.times) ?? str(command.times) };
return { kind: 'repeat', times: numLike(command.times) ?? str(command.times) ?? '' };
case 'retry':
return dropUndefined({
kind: 'retry',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'node:path';
import { AppError } from '@agent-device/kernel/errors';
import { createRequestCanceledError } from '../../request/cancel.ts';
import { createRequestCanceledError } from './shared.ts';
import {
MAESTRO_NUMERIC_FIELD_CONSTRAINTS,
numericDescription,
Expand Down
File renamed without changes.
Loading
Loading