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
34 changes: 8 additions & 26 deletions scripts/integration-progress-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,29 +570,17 @@ function readCommandContractBlocks(text) {
for (const match of text.matchAll(/\bconst\s+([A-Z0-9_]+)\s*=\s*['"]([^'"]+)['"]/g)) {
constants.set(match[1], match[2]);
}

const metadataNames = new Map();
for (const match of text.matchAll(
/\bconst\s+([A-Za-z0-9_]+CommandMetadata)\s*=\s*defineFieldCommandMetadata\(\s*([^,\s)]+)/g,
)) {
metadataNames.set(match[1], readMetadataName(match[2], constants));
}
const nameOf = (token) => token.match(/^['"]([^'"]+)['"]$/)?.[1] ?? constants.get(token);

const starts = [
...text.matchAll(/defineExecutableCommand\(\s*metadata\(\s*['"]([^'"]+)['"]\s*\)/g),
...[...text.matchAll(/defineExecutableCommand\(\s*([A-Za-z0-9_]+CommandMetadata)\b/g)].flatMap(
(match) => {
const name = metadataNames.get(match[1]);
return name ? [{ ...match, 1: name }] : [];
},
),
...text.matchAll(/defineFieldCommand\(\s*['"]([^'"]+)['"]/g),
...text.matchAll(/defineCommand\(\s*\{[\s\S]*?\bname:\s*['"]([^'"]+)['"]/g),
...text.matchAll(/defineCommandFacet\(\s*\{[\s\S]*?\bname:\s*([A-Za-z0-9_]+|['"][^'"]+['"])/g),
...text.matchAll(/defineFieldCommand\(\s*(['"][^'"]+['"])/g),
...text.matchAll(/defineCommand\(\s*\{[\s\S]*?\bname:\s*(['"][^'"]+['"])/g),
]
.map((match) => ({
index: match.index ?? 0,
name: match[1],
}))
.flatMap((match) => {
const name = nameOf(match[1]);
return name ? [{ index: match.index ?? 0, name }] : [];
})
.sort((a, b) => a.index - b.index);

return starts.map((start, index) => {
Expand All @@ -604,12 +592,6 @@ function readCommandContractBlocks(text) {
});
}

function readMetadataName(token, constants) {
const literal = token.match(/^['"]([^'"]+)['"]$/);
if (literal) return literal[1];
return constants.get(token);
}

function extractProviderScenarioCommandReferences(text, clientCommandMethods) {
return [
...extractLiteralCommandReferences(text),
Expand Down
7 changes: 1 addition & 6 deletions src/commands/batch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { CommandSchemaOverride } from '../../cli-schema/types.ts';
import { commonInputFromFlags } from '../cli-grammar/common.ts';
import type { CliReader } from '../cli-grammar/types.ts';
import { defineCommandFacet, defineCommandFamilyFromFacets } from '../family/types.ts';
import { defineExecutableCommand } from '../command-contract.ts';
import { commonToClientOptions } from '../common-input-fields.ts';
import { batchCliOutputFormatters } from './output.ts';
import { createBatchCommandMetadata, type BatchCommandStep, type BatchInput } from './metadata.ts';
Expand All @@ -12,10 +11,6 @@ import { createBatchDaemonWriter } from './projection.ts';

const batchCommandMetadata = createBatchCommandMetadata();

const batchCommandDefinition = defineExecutableCommand(batchCommandMetadata, (client, input) =>
client.batch.run(toBatchOptions(input)),
);

const batchCliSchema = {
usageOverride: 'batch [--steps <json> | --steps-file <path>]',
listUsageOverride: 'batch --steps <json> | --steps-file <path>',
Expand Down Expand Up @@ -74,7 +69,7 @@ const batchCommandFacet = defineCommandFacet({
cliDetail: buildBatchCliDetail(),
},
metadata: batchCommandMetadata,
definition: batchCommandDefinition,
run: (client, input) => client.batch.run(toBatchOptions(input)),
cliSchema: batchCliSchema,
cliReader: batchCliReader,
cliOutputFormatter: batchCliOutputFormatters.batch,
Expand Down
7 changes: 1 addition & 6 deletions src/commands/capture/alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { PUBLIC_COMMANDS } from '../../command-catalog.ts';
import type { AlertCommandOptions } from '@agent-device/contracts/client';
import { enumField, integerField } from '../command-input.ts';
import { compactRecord } from '../input-readers.ts';
import { defineExecutableCommand } from '../command-contract.ts';
import {
commonInputFromFlags,
direct,
Expand All @@ -30,10 +29,6 @@ const alertCommandMetadata = defineFieldCommandMetadata(
},
);

const alertCommandDefinition = defineExecutableCommand(alertCommandMetadata, (client, input) =>
client.command.alert(input),
);

const alertCliSchema = {
usageOverride: 'alert [get|accept|dismiss|wait] [timeout]',
positionalArgs: ['action?', 'timeout?'],
Expand All @@ -54,7 +49,7 @@ export const alertCommandFacet = defineCommandFacet({
summary: 'Inspect, accept, or dismiss a platform alert',
},
metadata: alertCommandMetadata,
definition: alertCommandDefinition,
run: (client, input) => client.command.alert(input),
cliSchema: alertCliSchema,
cliReader: alertCliReader,
daemonWriter: alertDaemonWriter,
Expand Down
7 changes: 1 addition & 6 deletions src/commands/capture/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
requiredField,
stringField,
} from '../command-input.ts';
import { defineExecutableCommand } from '../command-contract.ts';
import { commonInputFromFlags, direct, requiredDaemonString } from '../cli-grammar/common.ts';
import type { CliReader, DaemonWriter } from '../cli-grammar/types.ts';
import { defineCommandFacet } from '../family/types.ts';
Expand All @@ -28,10 +27,6 @@ const diffCommandMetadata = defineFieldCommandMetadata(DIFF_COMMAND_NAME, diffCo
raw: booleanField(),
});

const diffCommandDefinition = defineExecutableCommand(diffCommandMetadata, (client, input) =>
client.capture.diff(input),
);

const diffCliSchema = {
usageOverride:
'diff snapshot | diff screenshot --baseline <path> [current.png] [--out <diff.png>] [--threshold <0-1>] [--overlay-refs]',
Expand Down Expand Up @@ -66,7 +61,7 @@ export const diffCommandFacet = defineCommandFacet({
'Live iOS simulator screenshot diffs normalize status-bar chrome by default; use screenshot --normalize-status-bar when capturing reusable baselines.',
},
metadata: diffCommandMetadata,
definition: diffCommandDefinition,
run: (client, input) => client.capture.diff(input),
cliSchema: diffCliSchema,
cliReader: diffCliReader,
daemonWriter: diffDaemonWriter,
Expand Down
8 changes: 1 addition & 7 deletions src/commands/capture/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
retiredField,
stringField,
} from '../command-input.ts';
import { defineExecutableCommand } from '../command-contract.ts';
import { commonInputFromFlags, optionalString, request } from '../cli-grammar/common.ts';
import type { CliReader, DaemonWriter } from '../cli-grammar/types.ts';
import { defineCommandFacet } from '../family/types.ts';
Expand Down Expand Up @@ -50,11 +49,6 @@ const screenshotCommandMetadata = defineFieldCommandMetadata(
},
);

const screenshotCommandDefinition = defineExecutableCommand(
screenshotCommandMetadata,
(client, input) => client.capture.screenshot(input),
);

const screenshotCliSchema = {
positionalArgs: ['path?'],
allowedFlags: SCREENSHOT_COMMAND_FLAG_KEYS,
Expand Down Expand Up @@ -83,7 +77,7 @@ export const screenshotCommandFacet = defineCommandFacet({
'Web defaults to the viewport; use --fullscreen, --full, or -f for the entire page. iOS simulators default to 1x logical-point output; use --pixel-density to request a different screenshot density. macOS app sessions default to the app window; use --fullscreen for full desktop, --scale to downscale, --crop-on <selector> to crop the capture to the frame the selector resolves on the same screen (currently iOS simulators and Android emulators), --overlay-refs to annotate current refs, --normalize-status-bar for deterministic iOS simulator chrome, or --no-stabilize for low-latency Android capture loops.',
},
metadata: screenshotCommandMetadata,
definition: screenshotCommandDefinition,
run: (client, input) => client.capture.screenshot(input),
cliSchema: screenshotCliSchema,
cliReader: screenshotCliReader,
daemonWriter: screenshotDaemonWriter,
Expand Down
8 changes: 1 addition & 7 deletions src/commands/capture/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import type { CommandSchemaOverride } from '../../cli-schema/types.ts';
import type { CliFlags } from '@agent-device/contracts/command';
import { AppError } from '@agent-device/kernel/errors';
import { readLocationCoordinate } from '@agent-device/kernel/location-coordinates';
import { defineExecutableCommand } from '../command-contract.ts';
import { enumField, numberField, requiredField, stringField } from '../command-input.ts';
import {
direct,
Expand Down Expand Up @@ -37,11 +36,6 @@ const settingsCommandMetadata = defineFieldCommandMetadata(
},
);

const settingsCommandDefinition = defineExecutableCommand(
settingsCommandMetadata,
(client, input) => client.settings.update(input as SettingsUpdateOptions),
);

const settingsCliSchema = {
usageOverride: SETTINGS_USAGE_OVERRIDE,
listUsageOverride: 'settings [area] [options]',
Expand All @@ -63,7 +57,7 @@ export const settingsCommandFacet = defineCommandFacet({
'macOS supports only settings appearance <light|dark|toggle> and settings permission <grant|reset> <accessibility|screen-recording|input-monitoring>; wifi|airplane|location|animations remain unsupported on macOS. Mobile permission actions use the active session app. On Android, deny|reset of a permission the app currently holds kills a running app; the response reports priorGrantState (granted|not_granted|unknown) and warns for granted and unknown, with open <app> --relaunch to restore it. Permission changes require a resolvable foreground user and fail without mutating if adb cannot report one. Android settings airplane on|off is applied by the connectivity service (Android 11+) and reports the airplaneMode that service holds; older builds fail without changing device state.',
},
metadata: settingsCommandMetadata,
definition: settingsCommandDefinition,
run: (client, input) => client.settings.update(input as SettingsUpdateOptions),
cliSchema: settingsCliSchema,
cliReader: settingsCliReader,
daemonWriter: settingsDaemonWriter,
Expand Down
8 changes: 1 addition & 7 deletions src/commands/capture/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { PUBLIC_COMMANDS } from '../../command-catalog.ts';
import { SNAPSHOT_BACKEND_CAPABILITIES } from '@agent-device/capture-kit/snapshot-quality-backend-capabilities';
import { SNAPSHOT_FLAGS } from '../cli-grammar/flag-groups.ts';
import { booleanField, integerField, stringField } from '../command-input.ts';
import { defineExecutableCommand } from '../command-contract.ts';
import {
commonInputFromFlags,
direct,
Expand Down Expand Up @@ -49,11 +48,6 @@ const snapshotCommandMetadata = defineFieldCommandMetadata(
},
);

const snapshotCommandDefinition = defineExecutableCommand(
snapshotCommandMetadata,
(client, input) => client.capture.snapshot(input),
);

const snapshotCliSchema = {
usageOverride:
'snapshot [--diff] [-i] [-d <depth>] [-s <scope>] [--raw] [--actions] [--force-full] [--timeout <ms>]',
Expand Down Expand Up @@ -88,7 +82,7 @@ export const snapshotCommandFacet = defineCommandFacet({
cliDetail: `For iOS raw-coordinate fallback after a no-op ref press, inspect rects with snapshot -i --json, press the rect center, then verify with diff snapshot -i or snapshot --diff. iOS backend capability contract: ${snapshotBackendCapabilityHelp}.`,
},
metadata: snapshotCommandMetadata,
definition: snapshotCommandDefinition,
run: (client, input) => client.capture.snapshot(input),
cliSchema: snapshotCliSchema,
cliReader: snapshotCliReader,
daemonWriter: snapshotDaemonWriter,
Expand Down
7 changes: 1 addition & 6 deletions src/commands/capture/wait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { AppError } from '@agent-device/kernel/errors';
import { isValidSelectorExpression } from '@agent-device/selectors';
import { booleanField, enumField, integerField, stringField } from '../command-input.ts';
import { optionalEnum } from '../input-readers.ts';
import { defineExecutableCommand } from '../command-contract.ts';
import {
direct,
optionalNumber,
Expand Down Expand Up @@ -43,10 +42,6 @@ const waitCommandMetadata = defineFieldCommandMetadata(WAIT_COMMAND_NAME, waitCo
raw: booleanField(),
});

const waitCommandDefinition = defineExecutableCommand(waitCommandMetadata, (client, input) =>
client.command.wait(waitInputToOptions(input)),
);

const waitCliSchema = {
usageOverride:
'wait <ms>|text <text>|@ref|<selector>|absent <selector> [timeoutMs]|stable [quietMs] [timeoutMs]',
Expand All @@ -68,7 +63,7 @@ export const waitCommandFacet = defineCommandFacet({
summary: 'Wait for a duration, text, selector, strict absence, or stable UI',
},
metadata: waitCommandMetadata,
definition: waitCommandDefinition,
run: (client, input) => client.command.wait(waitInputToOptions(input)),
cliSchema: waitCliSchema,
cliReader: waitCliReader,
daemonWriter: waitDaemonWriter,
Expand Down
20 changes: 0 additions & 20 deletions src/commands/command-contract.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { AgentDeviceClient } from '../client/client-types.ts';
import type { InputAudienceMap } from './input-audience.ts';

export type JsonSchema = {
Expand Down Expand Up @@ -51,14 +50,6 @@ export type CommandMetadata<Name extends string, Input> = {
inputAudience: InputAudienceMap;
};

export type ExecutableCommandContract<Name extends string, Input, Result> = CommandMetadata<
Name,
Input
> & {
run: (client: AgentDeviceClient, input: Input) => Promise<Result>;
invoke: (client: AgentDeviceClient, input: unknown) => Promise<Result>;
};

export type CliOutput = {
data: unknown;
jsonData?: unknown;
Expand All @@ -71,14 +62,3 @@ export function defineCommandMetadata<Name extends string, Input>(
): CommandMetadata<Name, Input> {
return definition;
}

export function defineExecutableCommand<Name extends string, Input, Result>(
metadata: CommandMetadata<Name, Input>,
run: (client: AgentDeviceClient, input: Input) => Promise<Result>,
): ExecutableCommandContract<Name, Input, Result> {
return {
...metadata,
run,
invoke: async (client, input) => await run(client, metadata.readInput(input)),
};
}
4 changes: 2 additions & 2 deletions src/commands/debugging/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { describe, expect, test } from 'vitest';
import type { CliFlags } from '@agent-device/contracts/command';
import { debugCliReader, debugCommandDefinition, debugCommandMetadata } from './index.ts';
import { debugCliReader, debugCommandFacet, debugCommandMetadata } from './index.ts';

describe('debugging command interface', () => {
test('owns debug public metadata', () => {
expect(debugCommandMetadata.name).toBe('debug');
expect(debugCommandDefinition.name).toBe('debug');
expect(debugCommandFacet.definition.name).toBe('debug');
});

test('reads debug symbols crash artifact inputs', () => {
Expand Down
10 changes: 2 additions & 8 deletions src/commands/debugging/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { AppError } from '@agent-device/kernel/errors';
import type { CommandSchemaOverride } from '../../cli-schema/types.ts';
import { enumField, requiredField, stringField } from '../command-input.ts';
import { defineCommandFacet, defineCommandFamilyFromFacets } from '../family/types.ts';
import { defineExecutableCommand } from '../command-contract.ts';
import { defineFieldCommandMetadata } from '../field-command-contract.ts';
import { commonInputFromFlags } from '../cli-grammar/common.ts';
import type { CliReader } from '../cli-grammar/types.ts';
Expand All @@ -26,11 +25,6 @@ export const debugCommandMetadata = defineFieldCommandMetadata(
},
);

export const debugCommandDefinition = defineExecutableCommand(
debugCommandMetadata,
(client, input) => client.debug.symbols(input),
);

const debugCliSchema = {
usageOverride:
'debug symbols --artifact <crash.ips|crash.log> (--dsym <App.dSYM> | --search-path <dir>) [--out <symbolicated>]',
Expand All @@ -48,13 +42,13 @@ export const debugCliReader: CliReader = (positionals, flags) => ({
out: flags.out,
});

const debugCommandFacet = defineCommandFacet({
export const debugCommandFacet = defineCommandFacet({
name: DEBUG_COMMAND_NAME,
text: {
summary: 'Symbolicate Apple crash artifacts',
},
metadata: debugCommandMetadata,
definition: debugCommandDefinition,
run: (client, input) => client.debug.symbols(input),
cliSchema: debugCliSchema,
cliReader: debugCliReader,
cliOutputFormatter: debuggingCliOutputFormatters.debug,
Expand Down
Loading
Loading