@agentuity/cli 0.0.35 → 0.0.41

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.
Files changed (57) hide show
  1. package/AGENTS.md +2 -2
  2. package/README.md +4 -4
  3. package/dist/api.d.ts +6 -22
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/auth.d.ts +0 -2
  6. package/dist/auth.d.ts.map +1 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cmd/auth/api.d.ts.map +1 -1
  9. package/dist/cmd/auth/login.d.ts +1 -2
  10. package/dist/cmd/auth/login.d.ts.map +1 -1
  11. package/dist/cmd/auth/logout.d.ts +1 -2
  12. package/dist/cmd/auth/logout.d.ts.map +1 -1
  13. package/dist/cmd/auth/signup.d.ts +1 -2
  14. package/dist/cmd/auth/signup.d.ts.map +1 -1
  15. package/dist/cmd/bundle/bundler.d.ts +1 -0
  16. package/dist/cmd/bundle/bundler.d.ts.map +1 -1
  17. package/dist/cmd/bundle/patch/index.d.ts.map +1 -1
  18. package/dist/cmd/bundle/patch/llm.d.ts +3 -0
  19. package/dist/cmd/bundle/patch/llm.d.ts.map +1 -0
  20. package/dist/cmd/dev/index.d.ts.map +1 -1
  21. package/dist/cmd/index.d.ts.map +1 -1
  22. package/dist/cmd/project/create.d.ts.map +1 -1
  23. package/dist/cmd/project/download.d.ts.map +1 -1
  24. package/dist/cmd/project/template-flow.d.ts +3 -0
  25. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  26. package/dist/config.d.ts +10 -2
  27. package/dist/config.d.ts.map +1 -1
  28. package/dist/index.d.ts +2 -2
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/sound.d.ts.map +1 -1
  31. package/dist/tui.d.ts +16 -7
  32. package/dist/tui.d.ts.map +1 -1
  33. package/dist/types.d.ts +36 -7
  34. package/dist/types.d.ts.map +1 -1
  35. package/package.json +3 -2
  36. package/src/api.ts +27 -138
  37. package/src/auth.ts +87 -71
  38. package/src/cli.ts +6 -15
  39. package/src/cmd/auth/api.ts +40 -29
  40. package/src/cmd/auth/login.ts +5 -16
  41. package/src/cmd/auth/logout.ts +3 -3
  42. package/src/cmd/auth/signup.ts +6 -6
  43. package/src/cmd/bundle/bundler.ts +1 -0
  44. package/src/cmd/bundle/patch/index.ts +4 -0
  45. package/src/cmd/bundle/patch/llm.ts +36 -0
  46. package/src/cmd/dev/index.ts +17 -0
  47. package/src/cmd/example/optional-auth.ts +1 -1
  48. package/src/cmd/index.ts +1 -0
  49. package/src/cmd/profile/README.md +1 -1
  50. package/src/cmd/project/create.ts +11 -3
  51. package/src/cmd/project/download.ts +17 -0
  52. package/src/cmd/project/template-flow.ts +55 -1
  53. package/src/config.ts +54 -5
  54. package/src/index.ts +2 -2
  55. package/src/sound.ts +9 -3
  56. package/src/tui.ts +163 -60
  57. package/src/types.ts +68 -34
package/src/api.ts CHANGED
@@ -1,24 +1,17 @@
1
1
  /**
2
- * API Client for Agentuity Platform
2
+ * CLI-specific API client wrapper
3
3
  *
4
- * Handles HTTP requests to the API with automatic error parsing and User-Agent headers.
5
- *
6
- * Error handling:
7
- * - UPGRADE_REQUIRED (409): Throws UpgradeRequiredError
8
- * - Other errors: Throws Error with API message or status text
9
- *
10
- * See api-errors.md for full documentation.
4
+ * Re-exports from @agentuity/server with CLI-specific configuration
11
5
  */
12
6
 
13
7
  import type { Config } from './types';
14
8
  import { getVersion, getRevision } from './version';
15
-
16
- interface APIErrorResponse {
17
- success: boolean;
18
- code?: string;
19
- message: string;
20
- details?: Record<string, unknown>;
21
- }
9
+ import {
10
+ APIClient as BaseAPIClient,
11
+ getAPIBaseURL as baseGetAPIBaseURL,
12
+ getAppBaseURL as baseGetAppBaseURL,
13
+ type APIClientConfig,
14
+ } from '@agentuity/server';
22
15
 
23
16
  function getUserAgent(config?: Config | null): string {
24
17
  // If we're skipping version check, send "dev" to signal the server to skip too
@@ -61,140 +54,36 @@ function shouldSkipVersionCheck(config?: Config | null): boolean {
61
54
  return false;
62
55
  }
63
56
 
64
- export class UpgradeRequiredError extends Error {
65
- constructor(message: string) {
66
- super(message);
67
- this.name = 'UpgradeRequiredError';
68
- }
69
- }
70
-
71
- export class APIError extends Error {
72
- constructor(
73
- message: string,
74
- public status: number,
75
- public code?: string
76
- ) {
77
- super(message);
78
- this.name = 'APIError';
79
- }
80
- }
81
-
82
- export class APIClient {
83
- constructor(
84
- private baseUrl: string,
85
- private apiKey?: string,
86
- private config?: Config | null
87
- ) {}
88
-
89
- async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {
90
- const url = `${this.baseUrl}${endpoint}`;
91
- const headers: Record<string, string> = {
92
- 'Content-Type': 'application/json',
93
- 'User-Agent': getUserAgent(this.config),
57
+ // CLI-specific wrapper around the base APIClient
58
+ export class APIClient extends BaseAPIClient {
59
+ constructor(baseUrl: string, config?: Config | null);
60
+ constructor(baseUrl: string, apiKey: string, config?: Config | null);
61
+ constructor(baseUrl: string, apiKeyOrConfig?: string | Config | null, config?: Config | null) {
62
+ const clientConfig: APIClientConfig = {
63
+ skipVersionCheck: shouldSkipVersionCheck(
64
+ typeof apiKeyOrConfig === 'string' ? config : apiKeyOrConfig
65
+ ),
66
+ userAgent: getUserAgent(typeof apiKeyOrConfig === 'string' ? config : apiKeyOrConfig),
94
67
  };
95
68
 
96
- if (this.apiKey) {
97
- headers['Authorization'] = `Bearer ${this.apiKey}`;
98
- }
99
-
100
- const response = await fetch(url, {
101
- method,
102
- headers,
103
- body: body ? JSON.stringify(body) : undefined,
104
- });
105
-
106
- if (!response.ok) {
107
- const responseBody = await response.text();
108
-
109
- // Try to parse error response
110
- let errorData: APIErrorResponse | null = null;
111
- try {
112
- errorData = JSON.parse(responseBody) as APIErrorResponse;
113
- } catch {
114
- // Not JSON, ignore
115
- }
116
-
117
- if (process.env.DEBUG) {
118
- // Sanitize headers to avoid leaking API keys
119
- const sanitizedHeaders = { ...headers };
120
- for (const key in sanitizedHeaders) {
121
- if (key.toLowerCase() === 'authorization') {
122
- sanitizedHeaders[key] = 'REDACTED';
123
- }
124
- }
125
-
126
- console.error('API Error Details:');
127
- console.error(' URL:', url);
128
- console.error(' Method:', method);
129
- console.error(' Status:', response.status, response.statusText);
130
- console.error(' Headers:', JSON.stringify(sanitizedHeaders, null, 2));
131
- console.error(' Response:', responseBody);
69
+ if (typeof apiKeyOrConfig === 'string') {
70
+ super(baseUrl, apiKeyOrConfig, clientConfig);
71
+ } else {
72
+ if (apiKeyOrConfig?.auth?.api_key) {
73
+ super(baseUrl, apiKeyOrConfig.auth.api_key, clientConfig);
74
+ } else {
75
+ super(baseUrl, clientConfig);
132
76
  }
133
-
134
- // Check for UPGRADE_REQUIRED error
135
- if (errorData?.code === 'UPGRADE_REQUIRED') {
136
- // Skip version check in development
137
- if (shouldSkipVersionCheck(this.config)) {
138
- if (process.env.DEBUG) {
139
- console.error(
140
- '[DEBUG] Skipping version check (flag/env/config override or dev mode)'
141
- );
142
- }
143
- // Continue as if there was no error - the server should still process the request
144
- // but we'll throw a different error since we can't continue with a 409
145
- throw new Error('Version check skipped, but request failed. Try upgrading the CLI.');
146
- }
147
-
148
- throw new UpgradeRequiredError(
149
- errorData.message || 'Please upgrade to the latest version of the CLI'
150
- );
151
- }
152
-
153
- // Throw with message from API if available
154
- if (errorData?.message) {
155
- throw new APIError(errorData.message, response.status, errorData.code);
156
- }
157
-
158
- throw new APIError(
159
- `API error: ${response.status} ${response.statusText}`,
160
- response.status
161
- );
162
- }
163
-
164
- // Successful response; handle empty bodies (e.g., 204 No Content)
165
- if (response.status === 204) {
166
- return undefined as T;
167
77
  }
168
- const contentLength = response.headers.get('content-length');
169
- if (contentLength === '0') {
170
- return undefined as T;
171
- }
172
- return response.json() as Promise<T>;
173
78
  }
174
79
  }
175
80
 
176
81
  export function getAPIBaseURL(config?: Config | null): string {
177
- if (process.env.AGENTUITY_API_URL) {
178
- return process.env.AGENTUITY_API_URL;
179
- }
180
-
181
82
  const overrides = config?.overrides as { api_url?: string } | undefined;
182
- if (overrides?.api_url) {
183
- return overrides.api_url;
184
- }
185
-
186
- return 'https://api.agentuity.com';
83
+ return baseGetAPIBaseURL(overrides);
187
84
  }
188
85
 
189
86
  export function getAppBaseURL(config?: Config | null): string {
190
- if (process.env.AGENTUITY_APP_URL) {
191
- return process.env.AGENTUITY_APP_URL;
192
- }
193
-
194
87
  const overrides = config?.overrides as { app_url?: string } | undefined;
195
- if (overrides?.app_url) {
196
- return overrides.app_url;
197
- }
198
-
199
- return 'https://app.agentuity.com';
88
+ return baseGetAppBaseURL(overrides);
200
89
  }
package/src/auth.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { existsSync } from 'node:fs';
2
- import { getDefaultConfigDir, getAuth } from './config';
2
+ import enquirer from 'enquirer';
3
+ import { getDefaultConfigDir, getAuth, saveConfig, loadConfig } from './config';
3
4
  import { getCommand } from './command-prefix';
4
5
  import type { CommandContext, AuthData } from './types';
5
6
  import * as tui from './tui';
6
- import enquirer from 'enquirer';
7
7
 
8
8
  export function isTTY(): boolean {
9
9
  return process.stdin.isTTY === true && process.stdout.isTTY === true;
@@ -91,76 +91,92 @@ export async function optionalAuth(
91
91
  return auth;
92
92
  }
93
93
 
94
- if (!isTTY()) {
95
- // In non-TTY mode, just return null
96
- return null;
97
- }
98
-
99
- // Show signup benefits box
100
- tui.showSignupBenefits();
101
-
102
- // Show select menu with custom or default text
103
- const defaultContinueText = 'Start without an account (run locally)';
104
- const response = await enquirer.prompt<{ action: string }>({
105
- type: 'select',
106
- name: 'action',
107
- message: 'How would you like to continue?',
108
- choices: [
109
- {
110
- name: 'login',
111
- message: 'Create an account or login',
112
- },
113
- {
114
- name: 'local',
115
- message: continueText || defaultContinueText,
116
- },
117
- ],
118
- });
119
-
120
- if (response.action === 'local') {
121
- return null;
122
- }
123
- tui.newline();
124
-
125
- // Import and run login flow
126
- const { loginCommand } = await import('./cmd/auth/login');
127
- await loginCommand.handler(ctx);
94
+ // Show signup benefits but don't block - just return null
95
+ if (isTTY()) {
96
+ const config = await loadConfig();
97
+ // check to see if we've shown the banner or logged in before
98
+ const benefitsShown = config?.preferences?.signup_banner_shown === true;
99
+ const hasLoggedIn = hasLoggedInBefore();
100
+
101
+ // if we haven't shown it, show it once and then remember that we've shown it
102
+ if (!benefitsShown && hasLoggedIn) {
103
+ tui.showSignupBenefits();
104
+
105
+ if (!config) {
106
+ ctx.config = { name: 'production' };
107
+ } else {
108
+ ctx.config = config;
109
+ }
110
+
111
+ if (!ctx.config.preferences) {
112
+ ctx.config.preferences = {};
113
+ }
114
+ ctx.config.preferences.signup_banner_shown = true;
115
+ await saveConfig(ctx.config);
116
+
117
+ // Show select menu with custom or default text
118
+ const defaultContinueText = 'Start without an account (run locally)';
119
+ const response = await enquirer.prompt<{ action: string }>({
120
+ type: 'select',
121
+ name: 'action',
122
+ message: 'How would you like to continue?',
123
+ choices: [
124
+ {
125
+ name: 'login',
126
+ message: 'Create an account or login',
127
+ },
128
+ {
129
+ name: 'local',
130
+ message: continueText || defaultContinueText,
131
+ },
132
+ ],
133
+ });
134
+
135
+ if (response.action === 'local') {
136
+ tui.showLoggedOutMessage();
137
+ return null;
138
+ }
139
+
140
+ tui.newline();
141
+
142
+ // Import and run login flow
143
+ const { loginCommand } = await import('./cmd/auth/login');
144
+ await loginCommand.handler(ctx);
145
+ return getAuth();
146
+ }
128
147
 
129
- // After login completes, verify we have auth
130
- const newAuth = await getAuth();
131
- if (!newAuth || newAuth.expires <= new Date()) {
132
- return null;
148
+ if (hasLoggedIn) {
149
+ tui.warning('You are not currently logged in');
150
+ tui.newline();
151
+ const response = await enquirer.prompt<{ action: string }>({
152
+ type: 'select',
153
+ name: 'action',
154
+ message: 'How would you like to continue?',
155
+ choices: [
156
+ {
157
+ name: 'local',
158
+ message: 'Continue without login',
159
+ },
160
+ {
161
+ name: 'login',
162
+ message: 'Login',
163
+ },
164
+ ],
165
+ });
166
+
167
+ if (response.action === 'local') {
168
+ tui.showLoggedOutMessage();
169
+ return null;
170
+ }
171
+
172
+ tui.newline();
173
+
174
+ // Import and run login flow
175
+ const { loginCommand } = await import('./cmd/auth/login');
176
+ await loginCommand.handler(ctx);
177
+ return getAuth();
178
+ }
133
179
  }
134
- tui.newline();
135
-
136
- return newAuth;
137
- }
138
180
 
139
- export function withAuth<TArgs extends unknown[]>(
140
- ctx: CommandContext<false>,
141
- handler: (ctx: CommandContext<true>, ...args: TArgs) => Promise<void> | void
142
- ): (...args: TArgs) => Promise<void> {
143
- return async (...args: TArgs) => {
144
- const auth = await requireAuth(ctx);
145
- const authenticatedCtx: CommandContext<true> = {
146
- ...ctx,
147
- auth,
148
- };
149
- return handler(authenticatedCtx, ...args);
150
- };
151
- }
152
-
153
- export function withOptionalAuth<TArgs extends unknown[]>(
154
- ctx: CommandContext<false>,
155
- handler: (
156
- ctx: CommandContext<false>,
157
- auth: AuthData | null,
158
- ...args: TArgs
159
- ) => Promise<void> | void,
160
- continueText?: string
161
- ): (...args: TArgs) => Promise<void> {
162
- return async (...args: TArgs) => {
163
- const auth = await optionalAuth(ctx, continueText);
164
- return handler(ctx, auth, ...args);
165
- };
181
+ return null;
166
182
  }
package/src/cli.ts CHANGED
@@ -14,7 +14,7 @@ export async function createCLI(version: string): Promise<Command> {
14
14
  .helpOption('-h, --help', 'Display help');
15
15
 
16
16
  program
17
- .option('--config <path>', 'Config file path', '~/.config/agentuity/config.yaml')
17
+ .option('--config <path>', 'Config file path', '~/.config/agentuity/production.yaml')
18
18
  .option('--log-level <level>', 'Log level', 'info')
19
19
  .option('--log-timestamp', 'Show timestamps in log output', false)
20
20
  .option('--no-log-prefix', 'Hide log level prefixes', false)
@@ -131,7 +131,7 @@ async function registerSubcommand(
131
131
  const input = buildValidationInput(subcommand.schema, args, options);
132
132
  const ctx: Record<string, unknown> = {
133
133
  ...baseCtx,
134
- ...(auth ? { auth } : {}),
134
+ auth,
135
135
  };
136
136
  if (subcommand.schema.args) {
137
137
  ctx.args = subcommand.schema.args.parse(input.args);
@@ -152,14 +152,9 @@ async function registerSubcommand(
152
152
  }
153
153
  throw error;
154
154
  }
155
- } else if (auth) {
156
- const ctx: CommandContext<true> = {
157
- ...baseCtx,
158
- auth,
159
- };
160
- await subcommand.handler(ctx);
161
155
  } else {
162
- await subcommand.handler(baseCtx as CommandContext<false>);
156
+ const ctx = { ...baseCtx, auth };
157
+ await subcommand.handler(ctx as CommandContext);
163
158
  }
164
159
  } else {
165
160
  if (subcommand.schema) {
@@ -219,12 +214,8 @@ export async function registerCommands(
219
214
  const continueText =
220
215
  typeof cmdDef.optionalAuth === 'string' ? cmdDef.optionalAuth : undefined;
221
216
  const auth = await optionalAuth(baseCtx as CommandContext<false>, continueText);
222
- if (auth) {
223
- const ctx: CommandContext<true> = { ...baseCtx, auth };
224
- await cmdDef.handler!(ctx);
225
- } else {
226
- await cmdDef.handler!(baseCtx as CommandContext<false>);
227
- }
217
+ const ctx = { ...baseCtx, auth };
218
+ await cmdDef.handler!(ctx as CommandContext);
228
219
  } else {
229
220
  await cmdDef.handler!(baseCtx as CommandContext<false>);
230
221
  }
@@ -1,34 +1,36 @@
1
- import { APIClient, APIError } from '../../api';
1
+ import { z } from 'zod';
2
+ import { APIError, APIResponseSchema } from '@agentuity/server';
3
+ import { APIClient } from '../../api';
2
4
  import type { Config } from '../../types';
3
5
 
4
- interface APIResponse<T> {
5
- success: boolean;
6
- message: string;
7
- data?: T;
8
- }
6
+ // Zod schemas for API validation
7
+ const OTPStartDataSchema = z.object({
8
+ otp: z.string(),
9
+ });
9
10
 
10
- interface OTPStartData {
11
- otp: string;
12
- }
11
+ const OTPCompleteDataSchema = z.object({
12
+ apiKey: z.string(),
13
+ userId: z.string(),
14
+ expires: z.number(),
15
+ });
13
16
 
14
- interface OTPCompleteData {
15
- apiKey: string;
16
- userId: string;
17
- expires: number;
18
- }
17
+ const SignupCompleteDataSchema = z.object({
18
+ userId: z.string(),
19
+ apiKey: z.string(),
20
+ expiresAt: z.number(),
21
+ });
19
22
 
23
+ const OTPCheckRequestSchema = z.object({
24
+ otp: z.string(),
25
+ });
26
+
27
+ // Exported result types
20
28
  export interface LoginResult {
21
29
  apiKey: string;
22
30
  userId: string;
23
31
  expires: Date;
24
32
  }
25
33
 
26
- interface SignupCompleteData {
27
- userId: string;
28
- apiKey: string;
29
- expiresAt: number;
30
- }
31
-
32
34
  export interface SignupResult {
33
35
  apiKey: string;
34
36
  userId: string;
@@ -36,8 +38,12 @@ export interface SignupResult {
36
38
  }
37
39
 
38
40
  export async function generateLoginOTP(apiUrl: string, config?: Config | null): Promise<string> {
39
- const client = new APIClient(apiUrl, undefined, config);
40
- const resp = await client.request<APIResponse<OTPStartData>>('GET', '/cli/auth/start');
41
+ const client = new APIClient(apiUrl, config);
42
+ const resp = await client.request(
43
+ 'GET',
44
+ '/cli/auth/start',
45
+ APIResponseSchema(OTPStartDataSchema)
46
+ );
41
47
 
42
48
  if (!resp.success) {
43
49
  throw new Error(resp.message);
@@ -56,13 +62,17 @@ export async function pollForLoginCompletion(
56
62
  config?: Config | null,
57
63
  timeoutMs = 60000
58
64
  ): Promise<LoginResult> {
59
- const client = new APIClient(apiUrl, undefined, config);
65
+ const client = new APIClient(apiUrl, config);
60
66
  const started = Date.now();
61
67
 
62
68
  while (Date.now() - started < timeoutMs) {
63
- const resp = await client.request<APIResponse<OTPCompleteData>>('POST', '/cli/auth/check', {
64
- otp,
65
- });
69
+ const resp = await client.request(
70
+ 'POST',
71
+ '/cli/auth/check',
72
+ APIResponseSchema(OTPCompleteDataSchema),
73
+ { otp },
74
+ OTPCheckRequestSchema
75
+ );
66
76
 
67
77
  if (!resp.success) {
68
78
  throw new Error(resp.message);
@@ -99,14 +109,15 @@ export async function pollForSignupCompletion(
99
109
  config?: Config | null,
100
110
  timeoutMs = 300000
101
111
  ): Promise<SignupResult> {
102
- const client = new APIClient(apiUrl, undefined, config);
112
+ const client = new APIClient(apiUrl, config);
103
113
  const started = Date.now();
104
114
 
105
115
  while (Date.now() - started < timeoutMs) {
106
116
  try {
107
- const resp = await client.request<APIResponse<SignupCompleteData>>(
117
+ const resp = await client.request(
108
118
  'GET',
109
- `/cli/auth/signup/${otp}`
119
+ `/cli/auth/signup/${otp}`,
120
+ APIResponseSchema(SignupCompleteDataSchema)
110
121
  );
111
122
 
112
123
  if (!resp.success) {
@@ -1,10 +1,11 @@
1
- import type { SubcommandDefinition } from '../../types';
2
- import { getAPIBaseURL, getAppBaseURL, UpgradeRequiredError } from '../../api';
1
+ import { createSubcommand } from '../../types';
2
+ import { UpgradeRequiredError } from '@agentuity/server';
3
+ import { getAPIBaseURL, getAppBaseURL } from '../../api';
3
4
  import { saveAuth } from '../../config';
4
5
  import { generateLoginOTP, pollForLoginCompletion } from './api';
5
6
  import * as tui from '../../tui';
6
7
 
7
- export const loginCommand: SubcommandDefinition = {
8
+ export const loginCommand = createSubcommand({
8
9
  name: 'login',
9
10
  description: 'Login to the Agentuity Platform using a browser-based authentication flow',
10
11
  toplevel: true,
@@ -45,18 +46,6 @@ export const loginCommand: SubcommandDefinition = {
45
46
  console.log(tui.muted('This code will expire in 60 seconds'));
46
47
  tui.newline();
47
48
 
48
- if (process.platform === 'darwin') {
49
- await tui.waitForAnyKey('Press any key to open the URL in your browser...');
50
- tui.newline();
51
- try {
52
- Bun.spawn(['open', authURL], {
53
- stdio: ['ignore', 'ignore', 'ignore'],
54
- });
55
- } catch {
56
- // Ignore browser open errors
57
- }
58
- }
59
-
60
49
  console.log('Waiting for login to complete...');
61
50
 
62
51
  const result = await pollForLoginCompletion(apiUrl, otp, config);
@@ -81,4 +70,4 @@ export const loginCommand: SubcommandDefinition = {
81
70
  }
82
71
  }
83
72
  },
84
- };
73
+ });
@@ -1,8 +1,8 @@
1
- import type { SubcommandDefinition } from '../../types';
1
+ import { createSubcommand } from '../../types';
2
2
  import { clearAuth } from '../../config';
3
3
  import * as tui from '../../tui';
4
4
 
5
- export const logoutCommand: SubcommandDefinition = {
5
+ export const logoutCommand = createSubcommand({
6
6
  name: 'logout',
7
7
  description: 'Logout of the Agentuity Cloud Platform',
8
8
  toplevel: true,
@@ -11,4 +11,4 @@ export const logoutCommand: SubcommandDefinition = {
11
11
  await clearAuth();
12
12
  tui.success('You have been logged out');
13
13
  },
14
- };
14
+ });
@@ -1,18 +1,18 @@
1
- import type { SubcommandDefinition } from '../../types';
2
- import { getAPIBaseURL, getAppBaseURL, UpgradeRequiredError } from '../../api';
1
+ import { createSubcommand } from '../../types';
2
+ import { getAPIBaseURL, getAppBaseURL, UpgradeRequiredError } from '@agentuity/server';
3
3
  import { saveAuth } from '../../config';
4
4
  import { generateSignupOTP, pollForSignupCompletion } from './api';
5
5
  import * as tui from '../../tui';
6
6
 
7
- export const signupCommand: SubcommandDefinition = {
7
+ export const signupCommand = createSubcommand({
8
8
  name: 'signup',
9
9
  description: 'Create a new Agentuity Cloud Platform account',
10
10
  toplevel: true,
11
11
 
12
12
  async handler(ctx) {
13
13
  const { logger, config } = ctx;
14
- const apiUrl = getAPIBaseURL(config);
15
- const appUrl = getAppBaseURL(config);
14
+ const apiUrl = getAPIBaseURL(config?.overrides);
15
+ const appUrl = getAppBaseURL(config?.overrides);
16
16
 
17
17
  try {
18
18
  const otp = generateSignupOTP();
@@ -48,4 +48,4 @@ export const signupCommand: SubcommandDefinition = {
48
48
  }
49
49
  }
50
50
  },
51
- };
51
+ });
@@ -7,6 +7,7 @@ import { getVersion } from '../../version';
7
7
  export interface BundleOptions {
8
8
  rootDir: string;
9
9
  dev?: boolean;
10
+ env?: Map<string, string>;
10
11
  }
11
12
 
12
13
  export async function bundle({ dev = false, rootDir }: BundleOptions) {
@@ -1,4 +1,5 @@
1
1
  import { generatePatches as aisdkGeneratePatches } from './aisdk';
2
+ import { generatePatches as llmGeneratePatches } from './llm';
2
3
  import { type PatchModule, searchBackwards } from './_util';
3
4
 
4
5
  export function generatePatches(): Map<string, PatchModule> {
@@ -6,6 +7,9 @@ export function generatePatches(): Map<string, PatchModule> {
6
7
  for (const [name, patch] of aisdkGeneratePatches()) {
7
8
  patches.set(name, patch);
8
9
  }
10
+ for (const [name, patch] of llmGeneratePatches()) {
11
+ patches.set(name, patch);
12
+ }
9
13
  return patches;
10
14
  }
11
15
 
@@ -0,0 +1,36 @@
1
+ import { type PatchModule, generateEnvGuard, generateGatewayEnvGuard } from './_util';
2
+
3
+ function registerLLMPatch(
4
+ patches: Map<string, PatchModule>,
5
+ module: string,
6
+ filename: string,
7
+ key: string,
8
+ baseurl: string,
9
+ name: string
10
+ ) {
11
+ patches.set(module, {
12
+ module,
13
+ filename,
14
+ body: {
15
+ before: generateEnvGuard(
16
+ key,
17
+ generateGatewayEnvGuard(key, 'process.env.AGENTUITY_SDK_KEY', baseurl, name)
18
+ ),
19
+ },
20
+ });
21
+ }
22
+
23
+ export function generatePatches(): Map<string, PatchModule> {
24
+ const patches = new Map<string, PatchModule>();
25
+ registerLLMPatch(
26
+ patches,
27
+ '@anthropic-ai',
28
+ 'index',
29
+ 'ANTHROPIC_API_KEY',
30
+ 'ANTHROPIC_BASE_URL',
31
+ 'anthropic'
32
+ );
33
+ registerLLMPatch(patches, 'groq-sdk', 'index', 'GROQ_API_KEY', 'GROQ_BASE_URL', 'groq');
34
+ registerLLMPatch(patches, 'openai', 'index', 'OPENAI_API_KEY', 'OPENAI_BASE_URL', 'openai');
35
+ return patches;
36
+ }