@agentuity/cli 0.0.33 → 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.
- package/AGENTS.md +2 -2
- package/README.md +4 -4
- package/dist/api.d.ts +6 -22
- package/dist/api.d.ts.map +1 -1
- package/dist/auth.d.ts +0 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cmd/auth/api.d.ts.map +1 -1
- package/dist/cmd/auth/login.d.ts +1 -2
- package/dist/cmd/auth/login.d.ts.map +1 -1
- package/dist/cmd/auth/logout.d.ts +1 -2
- package/dist/cmd/auth/logout.d.ts.map +1 -1
- package/dist/cmd/auth/signup.d.ts +1 -2
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/bundle/bundler.d.ts +1 -0
- package/dist/cmd/bundle/bundler.d.ts.map +1 -1
- package/dist/cmd/bundle/patch/index.d.ts.map +1 -1
- package/dist/cmd/bundle/patch/llm.d.ts +3 -0
- package/dist/cmd/bundle/patch/llm.d.ts.map +1 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/download.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +3 -0
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/config.d.ts +10 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/sound.d.ts.map +1 -1
- package/dist/tui.d.ts +16 -7
- package/dist/tui.d.ts.map +1 -1
- package/dist/types.d.ts +36 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/api.ts +27 -138
- package/src/auth.ts +87 -71
- package/src/cli.ts +6 -15
- package/src/cmd/auth/api.ts +40 -29
- package/src/cmd/auth/login.ts +5 -16
- package/src/cmd/auth/logout.ts +3 -3
- package/src/cmd/auth/signup.ts +6 -6
- package/src/cmd/bundle/bundler.ts +1 -0
- package/src/cmd/bundle/patch/index.ts +4 -0
- package/src/cmd/bundle/patch/llm.ts +36 -0
- package/src/cmd/dev/index.ts +17 -0
- package/src/cmd/example/optional-auth.ts +1 -1
- package/src/cmd/index.ts +1 -0
- package/src/cmd/profile/README.md +1 -1
- package/src/cmd/project/create.ts +11 -3
- package/src/cmd/project/download.ts +17 -0
- package/src/cmd/project/template-flow.ts +55 -1
- package/src/config.ts +54 -5
- package/src/index.ts +2 -2
- package/src/sound.ts +9 -3
- package/src/tui.ts +163 -60
- package/src/types.ts +68 -34
package/src/api.ts
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* API
|
|
2
|
+
* CLI-specific API client wrapper
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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 (
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
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/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
223
|
-
|
|
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
|
}
|
package/src/cmd/auth/api.ts
CHANGED
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
6
|
+
// Zod schemas for API validation
|
|
7
|
+
const OTPStartDataSchema = z.object({
|
|
8
|
+
otp: z.string(),
|
|
9
|
+
});
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const OTPCompleteDataSchema = z.object({
|
|
12
|
+
apiKey: z.string(),
|
|
13
|
+
userId: z.string(),
|
|
14
|
+
expires: z.number(),
|
|
15
|
+
});
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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,
|
|
40
|
-
const resp = await client.request
|
|
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,
|
|
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
|
|
64
|
-
|
|
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,
|
|
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
|
|
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) {
|
package/src/cmd/auth/login.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
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
|
|
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
|
+
});
|
package/src/cmd/auth/logout.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createSubcommand } from '../../types';
|
|
2
2
|
import { clearAuth } from '../../config';
|
|
3
3
|
import * as tui from '../../tui';
|
|
4
4
|
|
|
5
|
-
export const logoutCommand
|
|
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
|
+
});
|
package/src/cmd/auth/signup.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { getAPIBaseURL, getAppBaseURL, UpgradeRequiredError } from '
|
|
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
|
|
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
|
+
});
|
|
@@ -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
|
+
}
|