Skip to content

Commit 7356c4c

Browse files
kamalcameroncooke
authored andcommitted
Support persisting custom env vars in session defaults
1 parent 59a7e98 commit 7356c4c

4 files changed

Lines changed: 73 additions & 0 deletions

File tree

src/mcp/tools/session-management/__tests__/session_clear_defaults.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ describe('session-clear-defaults tool', () => {
4949
expect(current.arch).toBe('arm64');
5050
});
5151

52+
it('should clear env when keys includes env', async () => {
53+
sessionStore.setDefaults({ env: { API_URL: 'https://staging.example.com', DEBUG: 'true' } });
54+
55+
const result = await sessionClearDefaultsLogic({ keys: ['env'] });
56+
57+
expect(result.isError).toBe(false);
58+
expect(result.content[0].text).toContain('Session defaults cleared');
59+
60+
const current = sessionStore.getAll();
61+
expect(current.env).toBeUndefined();
62+
expect(current.scheme).toBe('MyScheme');
63+
});
64+
5265
it('should clear all profiles only when all=true', async () => {
5366
sessionStore.setActiveProfile('ios');
5467
sessionStore.setDefaults({ scheme: 'IOS' });

src/mcp/tools/session-management/__tests__/session_set_defaults.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ describe('session-set-defaults tool', () => {
8787
expect(result.content[0].text).toContain('useLatestOS');
8888
});
8989

90+
it('should reject env values that are not strings', async () => {
91+
const result = await handler({
92+
env: {
93+
STAGING_ENABLED: 1 as unknown as string,
94+
},
95+
});
96+
97+
expect(result.isError).toBe(true);
98+
expect(result.content[0].text).toContain('Parameter validation failed');
99+
expect(result.content[0].text).toContain('env');
100+
});
101+
90102
it('should clear workspacePath when projectPath is set', async () => {
91103
sessionStore.setDefaults({ workspacePath: '/old/App.xcworkspace' });
92104
const result = await sessionSetDefaultsLogic(
@@ -358,6 +370,48 @@ describe('session-set-defaults tool', () => {
358370
expect(parsed.activeSessionDefaultsProfile).toBe('ios');
359371
});
360372

373+
it('should store env as a Record<string, string> default', async () => {
374+
const envVars = { STAGING_ENABLED: '1', DEBUG: 'true' };
375+
const result = await sessionSetDefaultsLogic({ env: envVars }, createContext());
376+
377+
expect(result.isError).toBe(false);
378+
expect(sessionStore.getAll().env).toEqual(envVars);
379+
});
380+
381+
it('should persist env to config when persist is true', async () => {
382+
const yaml = ['schemaVersion: 1', 'sessionDefaults: {}', ''].join('\n');
383+
384+
const writes: { path: string; content: string }[] = [];
385+
const fs = createMockFileSystemExecutor({
386+
existsSync: (targetPath: string) => targetPath === configPath,
387+
readFile: async (targetPath: string) => {
388+
if (targetPath !== configPath) {
389+
throw new Error(`Unexpected readFile path: ${targetPath}`);
390+
}
391+
return yaml;
392+
},
393+
writeFile: async (targetPath: string, content: string) => {
394+
writes.push({ path: targetPath, content });
395+
},
396+
});
397+
398+
await initConfigStore({ cwd, fs });
399+
400+
const envVars = { API_URL: 'https://staging.example.com' };
401+
const result = await sessionSetDefaultsLogic(
402+
{ env: envVars, persist: true },
403+
createContext(),
404+
);
405+
406+
expect(result.content[0].text).toContain('Persisted defaults to');
407+
expect(writes.length).toBe(1);
408+
409+
const parsed = parseYaml(writes[0].content) as {
410+
sessionDefaults?: Record<string, unknown>;
411+
};
412+
expect(parsed.sessionDefaults?.env).toEqual(envVars);
413+
});
414+
361415
it('should not persist when persist is true but no defaults were provided', async () => {
362416
const result = await sessionSetDefaultsLogic({ persist: true }, createContext());
363417

src/utils/session-defaults-schema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const sessionDefaultKeys = [
1616
'preferXcodebuild',
1717
'platform',
1818
'bundleId',
19+
'env',
1920
] as const;
2021

2122
export type SessionDefaultKey = (typeof sessionDefaultKeys)[number];
@@ -54,4 +55,8 @@ export const sessionDefaultsSchema = z.object({
5455
.string()
5556
.optional()
5657
.describe('Default bundle ID for launch/stop/log tools when working on a single app.'),
58+
env: z
59+
.record(z.string(), z.string())
60+
.optional()
61+
.describe('Default environment variables to pass to launched apps.'),
5762
});

src/utils/session-store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type SessionDefaults = {
2020
preferXcodebuild?: boolean;
2121
platform?: string;
2222
bundleId?: string;
23+
env?: Record<string, string>;
2324
};
2425

2526
class SessionStore {

0 commit comments

Comments
 (0)