diff --git a/packages/cli/src/cmd/dev/index.ts b/packages/cli/src/cmd/dev/index.ts index dca47eb20..5d2132b28 100644 --- a/packages/cli/src/cmd/dev/index.ts +++ b/packages/cli/src/cmd/dev/index.ts @@ -58,16 +58,39 @@ function normalizeOrgId(orgId: string | undefined): string | undefined { return trimmed ? trimmed : undefined; } +const DEV_ORG_ENV_ALIASES = [ + 'AGENTUITY_ORGID', + 'AGENTUITY_ORG_ID', + 'AGENTUITY_CLOUD_ORG_ID', +] as const; + +function envOrgId(env: Readonly>): string | undefined { + for (const name of DEV_ORG_ENV_ALIASES) { + const value = normalizeOrgId(env[name]); + if (value) return value; + } + return undefined; +} + export function resolveDevOrgId(options: ResolveDevOrgIdOptions): string | undefined { return ( normalizeOrgId(options.projectConfig?.orgId) ?? - normalizeOrgId(options.env.AGENTUITY_ORGID) ?? - normalizeOrgId(options.env.AGENTUITY_ORG_ID) ?? - normalizeOrgId(options.env.AGENTUITY_CLOUD_ORG_ID) ?? + envOrgId(options.env) ?? normalizeOrgId(options.config?.preferences?.orgId) ); } +/** Materialize the resolved org under every known alias so readers agree. */ +export function applyDevOrgEnv( + env: Record, + orgId: string | undefined +): void { + if (!orgId) return; + for (const name of DEV_ORG_ENV_ALIASES) { + env[name] = orgId; + } +} + export const command = createCommand({ name: 'dev', description: 'Run the project development server', @@ -172,17 +195,11 @@ export const command = createCommand({ env.AGENTUITY_CATALYST_URL = config.overrides.catalyst_url; } - // Load agentuity.json (if present) so we can surface the project's - // orgId to the dev process. The aigateway client and other service - // clients accept orgId as a constructor option but otherwise have no - // way to pick it up under `agentuity dev`. Other parts of the platform - // (pi, coder-tui) already read AGENTUITY_ORGID from env, so we match - // that name here. + // Materialize the resolved org under every known alias so downstream + // readers agree regardless of which name they check. const projectConfig = await tryLoadProjectConfig(rootDir, config); const orgId = resolveDevOrgId({ env, projectConfig, config }); - if (orgId && !normalizeOrgId(env.AGENTUITY_ORGID)) { - env.AGENTUITY_ORGID = orgId; - } + applyDevOrgEnv(env, orgId); // Inject AI Gateway env vars so LLM SDKs route through Agentuity const gatewayInjected = injectGatewayEnv(env, logger); diff --git a/packages/cli/test/cmd/dev/org-id.test.ts b/packages/cli/test/cmd/dev/org-id.test.ts index 5119ee97f..0400e55cb 100644 --- a/packages/cli/test/cmd/dev/org-id.test.ts +++ b/packages/cli/test/cmd/dev/org-id.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from 'bun:test'; -import { resolveDevOrgId } from '../../../src/cmd/dev/index.ts'; +import { applyDevOrgEnv, resolveDevOrgId } from '../../../src/cmd/dev/index.ts'; describe('resolveDevOrgId', () => { test('prefers project org ID over env and config values', () => { @@ -49,3 +49,77 @@ describe('resolveDevOrgId', () => { ).toBe('org_alt'); }); }); + +describe('applyDevOrgEnv', () => { + test('publishes the resolved org under every org env alias', () => { + const env: Record = {}; + applyDevOrgEnv(env, 'org_project'); + expect(env.AGENTUITY_ORGID).toBe('org_project'); + expect(env.AGENTUITY_ORG_ID).toBe('org_project'); + expect(env.AGENTUITY_CLOUD_ORG_ID).toBe('org_project'); + }); + + test('overwrites stale shell aliases with the resolved org', () => { + const env: Record = { + AGENTUITY_ORG_ID: 'org_stale', + AGENTUITY_CLOUD_ORG_ID: 'org_other', + }; + applyDevOrgEnv(env, 'org_project'); + expect(env.AGENTUITY_ORGID).toBe('org_project'); + expect(env.AGENTUITY_ORG_ID).toBe('org_project'); + expect(env.AGENTUITY_CLOUD_ORG_ID).toBe('org_project'); + }); + + test('overwrites blank aliases', () => { + const env: Record = { + AGENTUITY_ORGID: '', + AGENTUITY_CLOUD_ORG_ID: ' ', + }; + applyDevOrgEnv(env, 'org_project'); + expect(env.AGENTUITY_ORGID).toBe('org_project'); + expect(env.AGENTUITY_ORG_ID).toBe('org_project'); + expect(env.AGENTUITY_CLOUD_ORG_ID).toBe('org_project'); + }); + + test('does nothing without a resolved org', () => { + const env: Record = { + AGENTUITY_ORG_ID: 'org_shell', + }; + applyDevOrgEnv(env, undefined); + expect(env).toEqual({ AGENTUITY_ORG_ID: 'org_shell' }); + }); +}); + +describe('resolveDevOrgId + applyDevOrgEnv', () => { + test('project org wins and is written to every alias over stale shell env', () => { + const env: Record = { + AGENTUITY_ORG_ID: 'org_stale', + }; + const orgId = resolveDevOrgId({ + env, + projectConfig: { orgId: 'org_project' }, + config: null, + }); + applyDevOrgEnv(env, orgId); + expect(orgId).toBe('org_project'); + expect(env.AGENTUITY_ORGID).toBe('org_project'); + expect(env.AGENTUITY_ORG_ID).toBe('org_project'); + expect(env.AGENTUITY_CLOUD_ORG_ID).toBe('org_project'); + }); + + test('env-only resolution rewrites every alias to the resolved value', () => { + const env: Record = { + AGENTUITY_ORG_ID: 'org_shell', + }; + const orgId = resolveDevOrgId({ + env, + projectConfig: null, + config: null, + }); + applyDevOrgEnv(env, orgId); + expect(orgId).toBe('org_shell'); + expect(env.AGENTUITY_ORGID).toBe('org_shell'); + expect(env.AGENTUITY_ORG_ID).toBe('org_shell'); + expect(env.AGENTUITY_CLOUD_ORG_ID).toBe('org_shell'); + }); +});