@agentuity/cli 0.0.93 → 0.0.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -75,6 +75,11 @@ export { showBanner } from './banner';
75
75
  export { discoverCommands } from './cmd';
76
76
  export { detectColorScheme } from './terminal';
77
77
  export { getCommandPrefix, getCommand } from './command-prefix';
78
+ export {
79
+ bootstrapRuntimeEnv,
80
+ type RuntimeBootstrapOptions,
81
+ type RuntimeBootstrapResult,
82
+ } from './runtime-bootstrap';
78
83
  export * as tui from './tui';
79
84
  export {
80
85
  createRepl,
@@ -0,0 +1,161 @@
1
+ # Runtime Bootstrap Utility
2
+
3
+ ## Problem
4
+
5
+ When running SDK test applications locally (integration-suite, cloud-deployment), they weren't respecting:
6
+
7
+ - Profile-specific `.env` files (`.env.local`, `.env.production`)
8
+ - Profile-specific config files (`agentuity.local.json`, `agentuity.production.json`)
9
+
10
+ This caused tests to fail because:
11
+
12
+ 1. `AGENTUITY_SDK_KEY` wasn't loaded from `.env.local`
13
+ 2. `AGENTUITY_REGION` wasn't set to `local` for local profile
14
+ 3. Services tried to connect to production URLs instead of `*.agentuity.io`
15
+
16
+ ## Solution
17
+
18
+ The `bootstrapRuntimeEnv()` function loads profile-aware configuration and environment variables **before** `createApp()` is called.
19
+
20
+ ### What it does:
21
+
22
+ 1. **Resolves active profile** via `loadConfig()`
23
+ - Checks `AGENTUITY_PROFILE` env var
24
+ - Reads `~/.config/agentuity/profile` file
25
+ - Falls back to `production` profile
26
+
27
+ 2. **Loads `.env` files** based on profile:
28
+ - For `local` profile: `.env.local`, `.env.development`, `.env`
29
+ - For `production` profile: `.env.production`, `.env`
30
+
31
+ 3. **Sets environment variables**:
32
+ - Only sets if not already defined (existing env wins)
33
+ - For `local` profile: defaults `AGENTUITY_REGION=local`
34
+ - Sets `AGENTUITY_PROFILE` to match active profile
35
+
36
+ 4. **Loads project config**:
37
+ - For `local` profile: `agentuity.local.json`
38
+ - For `production` profile: `agentuity.json` or `agentuity.production.json`
39
+
40
+ ### Usage
41
+
42
+ Call `bootstrapRuntimeEnv()` at the top of your `app.ts` **before** `createApp()`:
43
+
44
+ ```ts
45
+ import { createApp } from '@agentuity/runtime';
46
+ import { bootstrapRuntimeEnv } from '@agentuity/cli';
47
+
48
+ // Bootstrap runtime environment based on active profile
49
+ await bootstrapRuntimeEnv();
50
+
51
+ // Now createApp() will use the correct env vars
52
+ const app = await createApp();
53
+ ```
54
+
55
+ ### Options
56
+
57
+ ```ts
58
+ await bootstrapRuntimeEnv({
59
+ projectDir: '/path/to/project', // default: process.cwd()
60
+ profile: 'local', // override active profile
61
+ });
62
+ ```
63
+
64
+ ### Local Development Setup
65
+
66
+ To run tests locally with local services:
67
+
68
+ 1. **Create local profile** (if not exists):
69
+
70
+ ```bash
71
+ cd ~/.config/agentuity
72
+ touch local.yaml
73
+ echo "name: local" > local.yaml
74
+ ```
75
+
76
+ 2. **Select local profile**:
77
+
78
+ ```bash
79
+ agentuity profile switch local
80
+ # Or set env var:
81
+ export AGENTUITY_PROFILE=local
82
+ ```
83
+
84
+ 3. **Create `.env.local`** in project root:
85
+
86
+ ```bash
87
+ AGENTUITY_SDK_KEY=your-sdk-key-here
88
+ AGENTUITY_REGION=local # Optional, auto-set for local profile
89
+ ```
90
+
91
+ 4. **(Optional) Create `agentuity.local.json`** for project-specific overrides:
92
+ ```json
93
+ {
94
+ "projectId": "proj_local_test",
95
+ "orgId": "org_local",
96
+ "region": "local"
97
+ }
98
+ ```
99
+
100
+ ### How it works
101
+
102
+ The bootstrap process follows this precedence (highest to lowest):
103
+
104
+ 1. **Explicit env vars** (from shell/CI) - always wins
105
+ 2. **Profile-specific .env** (`.env.local` for local profile)
106
+ 3. **Development/production .env** (`.env.development` or `.env.production`)
107
+ 4. **Default .env** (`.env`)
108
+
109
+ For config files:
110
+
111
+ 1. **Profile-specific config** (`agentuity.local.json` for local profile)
112
+ 2. **Default config** (`agentuity.json`)
113
+
114
+ ### Integration Points
115
+
116
+ This utility is used by:
117
+
118
+ - `sdk/apps/testing/integration-suite/app.ts`
119
+ - `sdk/apps/testing/cloud-deployment/app.ts`
120
+
121
+ It reuses existing infrastructure from the CLI:
122
+
123
+ - `loadConfig()` - Resolves active profile
124
+ - `loadProjectConfig()` - Loads profile-specific project config
125
+ - `getEnvFilePaths()` - Determines which .env files to load
126
+ - `readEnvFile()` - Parses .env files
127
+
128
+ ### Design Decisions
129
+
130
+ **Why not embed in `createApp()`?**
131
+
132
+ - `createApp()` is a runtime primitive that should work in any environment
133
+ - CLI config and profile logic is Bun-specific
134
+ - Test harnesses can opt-in to this behavior without forcing it on all SDK users
135
+
136
+ **Why not auto-detect local vs production?**
137
+
138
+ - Profile system is the single source of truth
139
+ - `NODE_ENV` alone is insufficient (can be `development` in production)
140
+ - Region alone is insufficient (multiple regions, not just local vs cloud)
141
+ - Profile explicitly declares intent: "I want local services"
142
+
143
+ ### Testing
144
+
145
+ To verify it works:
146
+
147
+ ```bash
148
+ # Set local profile
149
+ export AGENTUITY_PROFILE=local
150
+
151
+ # Build and run
152
+ cd sdk/apps/testing/integration-suite
153
+ bun run build
154
+ cd .agentuity && bun run app.js
155
+
156
+ # Check logs for:
157
+ # [TEST-SUITE] Profile: local
158
+ # [TEST-SUITE] Region: local
159
+ ```
160
+
161
+ Services should connect to `*.agentuity.io` instead of `*.agentuity.cloud`.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Runtime environment bootstrapping utility
3
+ *
4
+ * Loads configuration and environment variables based on the active profile
5
+ * before createApp() is called. This ensures .env.{profile} files and
6
+ * agentuity.{profile}.json configs are respected.
7
+ */
8
+
9
+ import { loadConfig, loadProjectConfig } from './config';
10
+ import { getEnvFilePaths, readEnvFile, type EnvVars } from './env-util';
11
+ import type { Config, ProjectConfig } from './types';
12
+
13
+ export interface RuntimeBootstrapOptions {
14
+ /**
15
+ * Project directory containing agentuity.json and .env files
16
+ * @default process.cwd()
17
+ */
18
+ projectDir?: string;
19
+
20
+ /**
21
+ * Override the active profile (otherwise uses loadConfig())
22
+ */
23
+ profile?: string;
24
+ }
25
+
26
+ export interface RuntimeBootstrapResult {
27
+ /**
28
+ * Resolved CLI config (from ~/.config/agentuity/)
29
+ */
30
+ config: Config | null;
31
+
32
+ /**
33
+ * Resolved project config (agentuity.json or agentuity.{profile}.json)
34
+ */
35
+ projectConfig: ProjectConfig | null;
36
+ }
37
+
38
+ /**
39
+ * Bootstrap runtime environment by loading profile-aware config and env files.
40
+ *
41
+ * This function:
42
+ * 1. Resolves the active profile (from AGENTUITY_PROFILE env or profile config)
43
+ * 2. Loads .env.{profile}, .env.development, or .env based on profile
44
+ * 3. Sets AGENTUITY_REGION=local for local profile
45
+ * 4. Loads agentuity.{profile}.json if it exists
46
+ * 5. Does NOT override environment variables already set
47
+ *
48
+ * Call this BEFORE createApp() in your app.ts:
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import { bootstrapRuntimeEnv } from '@agentuity/cli/runtime-bootstrap';
53
+ * import { createApp } from '@agentuity/runtime';
54
+ *
55
+ * // Load config and env based on active profile
56
+ * await bootstrapRuntimeEnv();
57
+ *
58
+ * // Now createApp() will use the correct env vars
59
+ * const app = await createApp();
60
+ * ```
61
+ */
62
+ export async function bootstrapRuntimeEnv(
63
+ options: RuntimeBootstrapOptions = {}
64
+ ): Promise<RuntimeBootstrapResult> {
65
+ const projectDir = options.projectDir || process.cwd();
66
+
67
+ // Load CLI config to determine active profile
68
+ let cfg: Config | null = null;
69
+ try {
70
+ cfg = await loadConfig();
71
+ // Override profile if specified
72
+ if (options.profile) {
73
+ cfg = { ...cfg, name: options.profile };
74
+ }
75
+ } catch {
76
+ // No config found - OK for tests without CLI setup
77
+ }
78
+
79
+ // Determine which .env files to load based on profile
80
+ const isProduction = process.env.NODE_ENV === 'production';
81
+ const envPaths = getEnvFilePaths(projectDir, {
82
+ configName: cfg?.name,
83
+ isProduction,
84
+ });
85
+
86
+ // Load and merge env files (later files override earlier ones)
87
+ let fileEnv: EnvVars = {};
88
+ for (const path of envPaths) {
89
+ const vars = await readEnvFile(path);
90
+ // Later files override earlier ones
91
+ fileEnv = { ...fileEnv, ...vars };
92
+ }
93
+
94
+ // Apply to process.env ONLY if not already set
95
+ // This ensures existing env vars (from shell/CI) always win
96
+ for (const [key, value] of Object.entries(fileEnv)) {
97
+ if (process.env[key] === undefined) {
98
+ process.env[key] = value;
99
+ }
100
+ }
101
+
102
+ // For local profile, default AGENTUITY_REGION to 'local'
103
+ // This makes getServiceUrls() use *.agentuity.io instead of *.agentuity.cloud
104
+ if (cfg?.name === 'local' && !process.env.AGENTUITY_REGION) {
105
+ process.env.AGENTUITY_REGION = 'local';
106
+ }
107
+
108
+ // Propagate profile name into env for consistency
109
+ if (cfg?.name && !process.env.AGENTUITY_PROFILE) {
110
+ process.env.AGENTUITY_PROFILE = cfg.name;
111
+ }
112
+
113
+ // Load project config (agentuity.json or agentuity.{profile}.json)
114
+ let projectConfig: ProjectConfig | null = null;
115
+ try {
116
+ projectConfig = await loadProjectConfig(projectDir, cfg ?? undefined);
117
+ } catch {
118
+ // OK for tests that don't need project config
119
+ }
120
+
121
+ return {
122
+ config: cfg,
123
+ projectConfig,
124
+ };
125
+ }