Skip to content

Commit dc37f86

Browse files
feat: expose iOS launch args for open (#598)
Co-authored-by: Michał Pierzchała <thymikee@gmail.com>
1 parent ae73b77 commit dc37f86

17 files changed

Lines changed: 309 additions & 13 deletions

src/__tests__/cli-client-commands.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,13 +537,15 @@ test('open forwards launch console option to the client apps API', async () => {
537537
version: false,
538538
platform: 'ios',
539539
launchConsole: '/tmp/launch-console.log',
540+
launchArgs: ['-FeatureFlag', 'YES'],
540541
},
541542
client,
542543
});
543544

544545
assert.equal(handled, true);
545546
assert.equal(observed?.platform, 'ios');
546547
assert.equal(observed?.launchConsole, '/tmp/launch-console.log');
548+
assert.deepEqual(observed?.launchArgs, ['-FeatureFlag', 'YES']);
547549
});
548550

549551
test('apps command defaults to user-installed and prints discovery hint', async () => {

src/__tests__/runtime-apps.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ test('runtime app commands call typed backend lifecycle primitives', async () =>
2020
const opened = await device.apps.open({
2121
session: 'default',
2222
app: ' com.example.app ',
23+
launchArgs: ['-FeatureFlag', 'YES'],
2324
relaunch: true,
2425
});
2526
assert.deepEqual(opened, {
@@ -61,7 +62,7 @@ test('runtime app commands call typed backend lifecycle primitives', async () =>
6162
{
6263
command: 'openApp',
6364
target: { app: 'com.example.app' },
64-
options: { relaunch: true },
65+
options: { launchArgs: ['-FeatureFlag', 'YES'], relaunch: true },
6566
session: 'default',
6667
},
6768
{ command: 'closeApp', app: 'com.example.app' },

src/backend.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ export type BackendOpenTarget = {
195195
};
196196

197197
export type BackendOpenOptions = {
198+
launchArgs?: string[];
198199
relaunch?: boolean;
199200
};
200201

src/client-normalizers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ export function buildFlags(options: InternalRequestOptions): CommandFlags {
276276
surface: options.surface,
277277
activity: options.activity,
278278
launchConsole: options.launchConsole,
279+
launchArgs: options.launchArgs,
279280
relaunch: options.relaunch,
280281
shutdown: options.shutdown,
281282
saveScript: options.saveScript,

src/client-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export type AppOpenOptions = AgentDeviceRequestOverrides &
175175
surface?: 'app' | 'frontmost-app' | 'desktop' | 'menubar';
176176
activity?: string;
177177
launchConsole?: string;
178+
launchArgs?: string[];
178179
relaunch?: boolean;
179180
saveScript?: boolean | string;
180181
noRecord?: boolean;
@@ -844,6 +845,7 @@ export type InternalRequestOptions = AgentDeviceClientConfig &
844845
surface?: 'app' | 'frontmost-app' | 'desktop' | 'menubar';
845846
activity?: string;
846847
launchConsole?: string;
848+
launchArgs?: string[];
847849
relaunch?: boolean;
848850
shutdown?: boolean;
849851
saveScript?: boolean | string;

src/commands/apps.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const MAX_APP_PUSH_PAYLOAD_BYTES = 8 * 1024;
2222

2323
export type OpenAppCommandOptions = CommandContext &
2424
BackendOpenTarget & {
25+
launchArgs?: string[];
2526
relaunch?: boolean;
2627
};
2728

@@ -109,6 +110,7 @@ export const openAppCommand: RuntimeCommand<OpenAppCommandOptions, OpenAppComman
109110
toAppBackendContext(runtime, options),
110111
target,
111112
{
113+
launchArgs: options.launchArgs,
112114
relaunch: options.relaunch,
113115
},
114116
);

src/commands/cli-grammar/apps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export const appCliReaders = {
3636
surface: flags.surface,
3737
activity: flags.activity,
3838
launchConsole: flags.launchConsole,
39+
launchArgs: flags.launchArgs,
3940
relaunch: flags.relaunch,
4041
saveScript: flags.saveScript,
4142
noRecord: flags.noRecord,

src/commands/client-command-contracts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export const clientCommandDefinitions = [
8181
surface: enumField(SURFACE_VALUES),
8282
activity: stringField('Android activity name.'),
8383
launchConsole: stringField('Launch console mode.'),
84+
launchArgs: stringArrayField('iOS launch arguments forwarded verbatim to the app process.'),
8485
relaunch: booleanField('Force relaunch.'),
8586
saveScript: jsonSchemaField<boolean | string>({ oneOf: [booleanSchema(), stringSchema()] }),
8687
noRecord: booleanField('Do not record this action.'),

src/daemon-client.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export type OpenAppOptions = {
5555
serial?: NonNullable<DaemonRequest['flags']>['serial'];
5656
activity?: NonNullable<DaemonRequest['flags']>['activity'];
5757
launchConsole?: NonNullable<DaemonRequest['flags']>['launchConsole'];
58+
launchArgs?: NonNullable<DaemonRequest['flags']>['launchArgs'];
5859
out?: NonNullable<DaemonRequest['flags']>['out'];
5960
saveScript?: NonNullable<DaemonRequest['flags']>['saveScript'];
6061
relaunch?: boolean;
@@ -213,6 +214,7 @@ export async function openApp(options: OpenAppOptions = {}): Promise<DaemonRespo
213214
serial,
214215
activity,
215216
launchConsole,
217+
launchArgs,
216218
out,
217219
saveScript,
218220
relaunch,
@@ -234,6 +236,7 @@ export async function openApp(options: OpenAppOptions = {}): Promise<DaemonRespo
234236
...(serial !== undefined ? { serial } : {}),
235237
...(activity !== undefined ? { activity } : {}),
236238
...(launchConsole !== undefined ? { launchConsole } : {}),
239+
...(launchArgs !== undefined ? { launchArgs } : {}),
237240
...(out !== undefined ? { out } : {}),
238241
...(saveScript !== undefined ? { saveScript } : {}),
239242
...(relaunch ? { relaunch: true } : {}),

src/daemon/handlers/__tests__/session-open-runtime.test.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,14 @@ test('open applies stored runtime launchUrl and reports runtime hints', async ()
146146
}
147147
});
148148

149-
test('open applies launchConsole only to the direct app launch before runtime launchUrl', async () => {
149+
test('open applies launch-only flags only to the direct app launch before runtime launchUrl', async () => {
150150
const sessionStore = makeSessionStore();
151151
const launchConsolePath = path.join(os.tmpdir(), 'launch-console.log');
152152
const dispatchCalls: Array<{
153153
command: string;
154154
positionals: string[];
155155
launchConsole?: string;
156+
launchArgs?: string[];
156157
}> = [];
157158

158159
sessionStore.setRuntimeHints('launch-console-runtime', {
@@ -167,7 +168,12 @@ test('open applies launchConsole only to the direct app launch before runtime la
167168
booted: true,
168169
});
169170
mockDispatch.mockImplementation(async (_device, command, positionals, _outPath, context) => {
170-
dispatchCalls.push({ command, positionals, launchConsole: context?.launchConsole });
171+
dispatchCalls.push({
172+
command,
173+
positionals,
174+
launchConsole: context?.launchConsole,
175+
launchArgs: context?.launchArgs,
176+
});
171177
return {};
172178
});
173179

@@ -177,7 +183,7 @@ test('open applies launchConsole only to the direct app launch before runtime la
177183
session: 'launch-console-runtime',
178184
command: 'open',
179185
positionals: ['Demo'],
180-
flags: { platform: 'ios', launchConsole: launchConsolePath },
186+
flags: { platform: 'ios', launchConsole: launchConsolePath, launchArgs: ['-Flag', 'YES'] },
181187
},
182188
sessionName: 'launch-console-runtime',
183189
logPath: path.join(os.tmpdir(), 'daemon.log'),
@@ -187,8 +193,18 @@ test('open applies launchConsole only to the direct app launch before runtime la
187193

188194
expect(response?.ok).toBe(true);
189195
expect(dispatchCalls).toEqual([
190-
{ command: 'open', positionals: ['Demo'], launchConsole: launchConsolePath },
191-
{ command: 'open', positionals: ['myapp://dev-client'], launchConsole: undefined },
196+
{
197+
command: 'open',
198+
positionals: ['Demo'],
199+
launchConsole: launchConsolePath,
200+
launchArgs: ['-Flag', 'YES'],
201+
},
202+
{
203+
command: 'open',
204+
positionals: ['myapp://dev-client'],
205+
launchConsole: undefined,
206+
launchArgs: undefined,
207+
},
192208
]);
193209
});
194210

0 commit comments

Comments
 (0)