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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
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/xml packages/kernel packages/contracts packages/maestro packages/replay-test packages/provider-webdriver packages/provider-limrun && tsc -p tsconfig.json && tsc -p examples/sdk/tsconfig.json",
"typecheck": "tsc -b packages/xml packages/kernel packages/contracts packages/ad-script packages/maestro packages/replay-test packages/provider-webdriver packages/provider-limrun && 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 Down Expand Up @@ -245,6 +245,7 @@
"yaml": "^2.9.0"
},
"devDependencies": {
"@agent-device/ad-script": "workspace:*",
"@agent-device/contracts": "workspace:*",
"@agent-device/kernel": "workspace:*",
"@agent-device/maestro": "workspace:*",
Expand Down
18 changes: 18 additions & 0 deletions packages/ad-script/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@agent-device/ad-script",
"version": "0.0.0",
"private": true,
"sideEffects": false,
"type": "module",
"description": "Private canonical .ad replay script codec (read + write) for agent-device.",
"dependencies": {
"@agent-device/contracts": "workspace:*",
"@agent-device/kernel": "workspace:*"
},
"exports": {
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
57 changes: 57 additions & 0 deletions packages/ad-script/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* The `.ad` script codec façade (#1478 P5 scoping dossier, "the codec seam").
*
* The canonical `.ad` replay script format — read half (parsing a script into
* actions) and write half (formatting actions back into script lines) of one
* artifact, mutually coupled (`script-formatting.ts` calls into the `open`
* action's writer; `script.ts` calls into its parser). Shared by the daemon's
* session-script publication writer, the replay engine's script reader, the
* CLI's `replay export`, and Maestro's failure-label formatting.
*
* Also owns the `# agent-device:target-v1` annotation SERDE (wire type,
* canonical field order, normalization, size caps, payload parsing). The
* companion classification core (`classifyTargetBindingMatch`, local-identity
* + ancestry-prefix matching) is NOT part of this codec — it stays in
* `src/replay/target-identity.ts`, which imports the types below.
*/

export {
parseReplayScriptDetailed,
readReplayScriptMetadata,
REPLAY_VAR_KEY_RE,
} from './internal/script.ts';
export type { ParsedReplayScript, ReplayScriptMetadata } from './internal/script.ts';

export {
appendScriptSeriesFlags,
formatDivergenceActionLabel,
formatScriptArg,
formatScriptStringLiteral,
isClickLikeCommand,
isTouchTargetCommand,
stripRecordedRefGeneration,
} from './internal/script-utils.ts';

export {
formatPortableActionLine,
formatTargetAnnotationLines,
} from './internal/script-formatting.ts';

export {
normalizeIdentifierField,
normalizeLabelField,
normalizeRoleField,
parseTargetAnnotationV1Payload,
serializeTargetAnnotationV1,
truncateToUtf8Bytes,
utf8ByteLength,
TARGET_ANNOTATION_MAX_ANCESTRY,
TARGET_ANNOTATION_MAX_FIELD_BYTES,
TARGET_ANNOTATION_MAX_PAYLOAD_BYTES,
} from './internal/target-annotation-serde.ts';
export type {
TargetAncestryEntry,
TargetAnnotationV1,
TargetScrollRegion,
TargetVerification,
} from './internal/target-annotation-serde.ts';
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import fc from 'fast-check';
import { test } from 'vitest';
import assert from 'node:assert/strict';
import { PROPERTY_RUNS, replayScriptArb } from '../../__tests__/test-utils/index.ts';
import { AppError } from '@agent-device/kernel/errors';
import {
parseReplayScriptDetailed,
readReplayScriptMetadata,
REPLAY_METADATA_PLATFORMS,
} from '../script.ts';
import { formatPortableActionLine, formatTargetAnnotationLines } from '../script-formatting.ts';
import type { TargetAnnotationV1 } from '../target-identity.ts';
import type { TargetAnnotationV1 } from '../target-annotation-serde.ts';
import type { SessionAction } from '@agent-device/contracts/session';

// `writeReplayScript` (the `--update` heal-and-rewrite serializer) was
Expand Down Expand Up @@ -624,24 +622,10 @@ test('formatDivergenceActionLabel categorically drops fill/type text but keeps t
);
});

// Property, not another example: `.ad` scripts are written by hand, recorded,
// and rewritten, so the parser and the line formatter must agree on ONE
// canonical form — re-serializing a parsed script has to be a fixed point.
// Generated lines come from the shared `.ad` generator, so a new command shape
// extends the generator rather than adding another pinned script here.
test('serializing a parsed script is a fixed point for generated scripts', () => {
fc.assert(
fc.property(replayScriptArb, (script) => {
const parsed = parseReplayScriptDetailed(script).actions;
const canonical = formatReplayScriptForTest(parsed);
const reparsed = parseReplayScriptDetailed(canonical).actions;
assert.equal(formatReplayScriptForTest(reparsed), canonical);
// The action identity survives the rewrite: same commands, same targets.
assert.deepEqual(
reparsed.map((action) => [action.command, action.positionals]),
parsed.map((action) => [action.command, action.positionals]),
);
}),
{ numRuns: PROPERTY_RUNS },
);
});
// The property test asserting "serializing a parsed script is a fixed point
// for generated scripts" stays at `src/replay/__tests__/ad-script-round-trip.test.ts`:
// its script generator (`replayScriptArb`) is derived from the root command
// catalog and selector grammar (`src/__tests__/test-utils/property-arbitraries.ts`),
// which this package cannot import without an R11 package→root-src escape
// (#1478 P5 scoping dossier §5d). It exercises this package's exports via
// the `@agent-device/ad-script` specifier instead of duplicating the codec.
Loading
Loading