Skip to content
Open
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
8 changes: 6 additions & 2 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,17 @@ jobs:
preferred-device-name: iPhone 17 Pro

- name: Run iOS simulator smoke replay
run: node --experimental-strip-types src/bin.ts test test/integration/replays/ios/simulator/01-settings.ad --retries 2 --report-junit test/artifacts/replays-ios-simulator-smoke.junit.xml
run: |
pnpm clean:daemon
node --experimental-strip-types src/bin.ts test test/integration/replays/ios/simulator/01-settings.ad --retries 2 --report-junit test/artifacts/replays-ios-simulator-smoke.junit.xml

- name: Run iOS physical device smoke replay
if: env.IOS_UDID != ''
env:
IOS_UDID: ${{ vars.IOS_UDID }}
run: node --experimental-strip-types src/bin.ts test test/integration/replays/ios/device/01-physical-lifecycle.ad --udid "$IOS_UDID" --retries 2 --report-junit test/artifacts/replays-ios-device-smoke.junit.xml
run: |
pnpm clean:daemon
node --experimental-strip-types src/bin.ts test test/integration/replays/ios/device/01-physical-lifecycle.ad --udid "$IOS_UDID" --retries 2 --report-junit test/artifacts/replays-ios-device-smoke.junit.xml

- name: Upload iOS artifacts
if: always()
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ concurrency: preview-${{ github.ref }}

jobs:
deploy-preview:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
472 changes: 247 additions & 225 deletions fallow-baselines/dupes.json

Large diffs are not rendered by default.

101 changes: 33 additions & 68 deletions fallow-baselines/health.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,14 @@
}
},
"src/cli/commands/output.ts": {
"complexity_critical": {
"count": 2
},
"complexity_high": {
"count": 2
},
"crap_critical": {
"count": 2
"complexity_moderate": {
"count": 1
},
"crap_high": {
"count": 2
"crap_moderate": {
"count": 4
}
},
"src/cli/commands/react-devtools.ts": {
"crap_high": {
"count": 1
},
"crap_moderate": {
"count": 1
}
Expand All @@ -118,14 +109,11 @@
"complexity_high": {
"count": 1
},
"complexity_moderate": {
"count": 1
},
"crap_high": {
"count": 1
},
"crap_moderate": {
"count": 4
"count": 3
}
},
"src/client-companion-tunnel.ts": {
Expand Down Expand Up @@ -230,7 +218,7 @@
"count": 2
},
"crap_high": {
"count": 3
"count": 4
},
"crap_moderate": {
"count": 5
Expand All @@ -256,11 +244,6 @@
"count": 4
}
},
"src/daemon.ts": {
"crap_critical": {
"count": 1
}
},
"src/daemon/__tests__/http-server.test.ts": {
"crap_moderate": {
"count": 1
Expand Down Expand Up @@ -441,7 +424,7 @@
"count": 1
},
"crap_high": {
"count": 2
"count": 1
}
},
"src/daemon/handlers/session-perf.ts": {
Expand Down Expand Up @@ -532,6 +515,11 @@
"count": 3
}
},
"src/daemon/handlers/snapshot-settings.ts": {
"complexity_moderate": {
"count": 1
}
},
"src/daemon/http-server.ts": {
"complexity_critical": {
"count": 1
Expand Down Expand Up @@ -575,7 +563,7 @@
"count": 2
},
"crap_moderate": {
"count": 4
"count": 3
}
},
"src/daemon/runtime-hints.ts": {
Expand Down Expand Up @@ -643,14 +631,6 @@
"count": 2
}
},
"src/daemon/transport.ts": {
"crap_high": {
"count": 1
},
"crap_moderate": {
"count": 1
}
},
"src/platforms/android/app-lifecycle.ts": {
"complexity_moderate": {
"count": 1
Expand Down Expand Up @@ -688,7 +668,7 @@
}
},
"src/platforms/android/settings.ts": {
"complexity_moderate": {
"complexity_high": {
"count": 1
}
},
Expand All @@ -698,18 +678,9 @@
}
},
"src/platforms/android/ui-hierarchy.ts": {
"complexity_critical": {
"count": 1
},
"complexity_high": {
"count": 1
},
"complexity_moderate": {
"count": 1
},
"crap_critical": {
"count": 1
},
"crap_high": {
"count": 1
},
Expand Down Expand Up @@ -741,11 +712,6 @@
"count": 1
}
},
"src/platforms/ios/__tests__/perf.test.ts": {
"crap_high": {
"count": 1
}
},
"src/platforms/ios/apps.ts": {
"complexity_high": {
"count": 1
Expand Down Expand Up @@ -1035,52 +1001,51 @@
},
"runtime_coverage_findings": [],
"target_keys": [
"src/daemon/handlers/session.ts:complexity",
"src/daemon/handlers/snapshot-capture.ts:high impact",
"src/daemon/handlers/session.ts:complexity",
"src/daemon/handlers/session-device-utils.ts:high impact",
"src/utils/process-identity.ts:high impact",
"src/client-shared.ts:high impact",
"src/daemon/handlers/session-replay-script.ts:complexity",
"src/daemon/config.ts:high impact",
"src/commands/selector-read-utils.ts:high impact",
"src/utils/args.ts:high impact",
"src/daemon/config.ts:high impact",
"src/daemon/handlers/session-replay-heal.ts:complexity",
"src/daemon/android-snapshot-freshness.ts:high impact",
"src/daemon/session-store.ts:complexity",
"src/platforms/boot-diagnostics.ts:complexity",
"src/cli/commands/connection-runtime.ts:complexity",
"src/daemon/handlers/session-replay-heal.ts:complexity",
"src/cli/commands/output.ts:complexity",
"src/platforms/boot-diagnostics.ts:complexity",
"src/utils/args.ts:high impact",
"src/daemon/session-store.ts:complexity",
"src/daemon/handlers/session-open-target.ts:high impact",
"src/daemon/handlers/snapshot-alert.ts:complexity",
"src/cli/commands/connection.ts:untested risk",
"src/daemon/handlers/session-inventory.ts:complexity",
"src/utils/success-text.ts:high impact",
"src/daemon/handlers/session-inventory.ts:complexity",
"src/daemon/handlers/install-source.ts:complexity",
"src/daemon/script-utils.ts:high impact",
"src/utils/snapshot-processing.ts:high impact",
"src/daemon/handlers/session-open-target.ts:high impact",
"src/cli.ts:complexity",
"src/cli/commands/output.ts:untested risk",
"src/daemon/script-utils.ts:high impact",
"src/utils/process-identity.ts:high impact",
"src/utils/output.ts:high impact",
"src/cli.ts:complexity",
"src/platforms/ios/xml.ts:high impact",
"src/daemon/handlers/session-state.ts:complexity",
"src/daemon/handlers/session-open.ts:complexity",
"src/platforms/android/ui-hierarchy.ts:high impact",
"src/daemon/request-cancel.ts:high impact",
"src/utils/device.ts:high impact",
"src/platforms/android/input-actions.ts:complexity",
"src/daemon/app-log-process.ts:high impact",
"src/utils/snapshot-lines.ts:high impact",
"src/client-metro.ts:complexity",
"src/daemon/app-log-process.ts:high impact",
"src/utils/selector-build.ts:high impact",
"src/platforms/ios/xml.ts:high impact",
"src/client-metro.ts:complexity",
"src/platforms/android/input-actions.ts:complexity",
"src/utils/text-surface.ts:high impact",
"src/cli-test.ts:untested risk",
"src/utils/keyed-lock.ts:high impact",
"src/daemon/app-log-stream.ts:high impact",
"src/core/batch.ts:complexity",
"src/platforms/ios/runner-xctestrun.ts:complexity",
"src/daemon/app-log-stream.ts:high impact",
"src/platforms/android/sdk.ts:high impact",
"src/utils/source-value.ts:high impact",
"src/utils/screenshot-diff-regions.ts:complexity",
"src/client-companion-tunnel-worker.ts:complexity",
"src/daemon/screenshot-overlay.ts:untested risk",
"src/utils/screenshot-diff-non-text.ts:complexity"
]
}
}
2 changes: 2 additions & 0 deletions skills/agent-device/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ agent-device help dogfood
Default loop: `open -> snapshot/-i -> get/is/find or press/fill/scroll/wait -> verify -> close`.

Use this skill only to route into version-matched CLI help. Let `help workflow` provide exact command shapes, platform limits, and current workflow guidance.

For precise location workflows, read the installed `settings` help before planning so coordinate support and platform limits come from the active CLI version.
82 changes: 81 additions & 1 deletion src/__tests__/cli-client-commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
MetroPrepareOptions,
MetroReloadOptions,
} from '../client.ts';
import type { SettingsUpdateOptions } from '../client-types.ts';
import { AppError } from '../utils/errors.ts';
import { resolveCliOptions } from '../utils/cli-options.ts';

Expand Down Expand Up @@ -740,6 +741,82 @@ test('install prints command-owned success output in human mode', async () => {
assert.match(stdout, /Installed: Demo/);
});

test('settings location set forwards coordinates to client settings update', async () => {
let observed: SettingsUpdateOptions | undefined;
const client = createStubClient({
installFromSource: async () => ({
launchTarget: 'com.example.demo',
packageName: 'com.example.demo',
identifiers: { appId: 'com.example.demo' },
}),
updateSettings: async (options) => {
observed = options;
return { identifiers: { session: 'default' } };
},
});

const handled = await tryRunClientBackedCommand({
command: 'settings',
positionals: ['location', 'set', '37.3349', '-122.009'],
flags: {
json: false,
help: false,
version: false,
platform: 'ios',
session: 'maps',
},
client,
});

assert.equal(handled, true);
assert.equal(observed?.platform, 'ios');
assert.equal(observed?.setting, 'location');
assert.equal(observed?.state, 'set');
assert.equal(observed?.latitude, 37.3349);
assert.equal(observed?.longitude, -122.009);
});

test('settings location set rejects invalid coordinates before client call', async () => {
const client = createStubClient({
installFromSource: async () => ({
launchTarget: 'com.example.demo',
packageName: 'com.example.demo',
identifiers: { appId: 'com.example.demo' },
}),
updateSettings: async () => {
throw new Error('unexpected settings update');
},
});

const cases: Array<[string[], RegExp]> = [
[['location', 'set', '91', '-122.009'], /latitude must be a number from -90 to 90/],
[['location', 'set', '37.3349', 'not-a-number'], /longitude must be a number from -180 to 180/],
];

for (const [positionals, message] of cases) {
await assert.rejects(
() =>
tryRunClientBackedCommand({
command: 'settings',
positionals,
flags: {
json: false,
help: false,
version: false,
platform: 'ios',
},
client,
}),
(error: unknown) => {
assert.equal(error instanceof AppError, true);
assert.equal((error as AppError).code, 'INVALID_ARGS');
assert.match((error as AppError).message, message);
return true;
},
);
}
});

async function captureStdout(run: () => Promise<void>): Promise<string> {
let stdout = '';
const originalWrite = process.stdout.write.bind(process.stdout);
Expand All @@ -763,6 +840,7 @@ function createStubClient(params: {
reloadMetro?: AgentDeviceClient['metro']['reload'];
open?: AgentDeviceClient['apps']['open'];
screenshot?: AgentDeviceClient['capture']['screenshot'];
updateSettings?: AgentDeviceClient['settings']['update'];
}): AgentDeviceClient {
const unexpectedCommandCall = async (): Promise<never> => {
throw new Error('unexpected command call');
Expand Down Expand Up @@ -894,7 +972,9 @@ function createStubClient(params: {
batch: createThrowingMethodGroup<AgentDeviceClient['batch']>(),
observability: createThrowingMethodGroup<AgentDeviceClient['observability']>(),
recording: createThrowingMethodGroup<AgentDeviceClient['recording']>(),
settings: createThrowingMethodGroup<AgentDeviceClient['settings']>(),
settings: {
update: params.updateSettings ?? unexpectedCommandCall,
},
};
}

Expand Down
10 changes: 10 additions & 0 deletions src/cli/commands/generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { announceReplayTestRun } from '../../cli-test.ts';
import { splitSelectorFromArgs } from '../../daemon/selectors.ts';
import { AppError } from '../../utils/errors.ts';
import type { CliFlags } from '../../utils/command-schema.ts';
import { readLocationCoordinate } from '../../utils/location-coordinates.ts';
import { buildSelectionOptions } from './shared.ts';
import { writeCommandCliOutput } from './output.ts';
import type { ClientCommandHandler, ClientCommandHandlerMap } from './router-types.ts';
Expand Down Expand Up @@ -471,6 +472,15 @@ function readSettingsOptions(positionals: string[], flags: CliFlags): SettingsUp
) {
return { ...base, setting, state };
}
if (setting === 'location' && state === 'set') {
return {
...base,
setting,
state,
latitude: readLocationCoordinate(positionals[2], 'latitude'),
longitude: readLocationCoordinate(positionals[3], 'longitude'),
};
}
if (setting === 'appearance' && (state === 'light' || state === 'dark' || state === 'toggle')) {
return { ...base, setting, state };
}
Expand Down
Loading
Loading