@agentuity/cli 0.0.35 → 0.0.42
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/banner.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/ast.d.ts +2 -0
- package/dist/cmd/bundle/ast.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/bundle/plugin.d.ts.map +1 -1
- 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/delete.d.ts.map +1 -1
- package/dist/cmd/project/download.d.ts.map +1 -1
- package/dist/cmd/project/list.d.ts.map +1 -1
- package/dist/cmd/project/show.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 +11 -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/logger.d.ts +1 -1
- package/dist/logger.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 +70 -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/banner.ts +7 -2
- package/src/cli.ts +7 -16
- package/src/cmd/auth/api.ts +40 -29
- package/src/cmd/auth/login.ts +7 -20
- package/src/cmd/auth/logout.ts +3 -3
- package/src/cmd/auth/signup.ts +6 -6
- package/src/cmd/bundle/ast.ts +169 -4
- 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/bundle/plugin.ts +42 -1
- package/src/cmd/dev/index.ts +100 -1
- 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 +10 -2
- package/src/cmd/project/delete.ts +43 -2
- package/src/cmd/project/download.ts +17 -0
- package/src/cmd/project/list.ts +33 -2
- package/src/cmd/project/show.ts +35 -3
- package/src/cmd/project/template-flow.ts +60 -5
- package/src/config.ts +77 -5
- package/src/index.ts +2 -2
- package/src/logger.ts +1 -1
- package/src/sound.ts +9 -3
- package/src/tui.ts +234 -104
- package/src/types.ts +97 -34
package/src/cmd/project/show.ts
CHANGED
|
@@ -1,12 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { createSubcommand } from '../../types';
|
|
3
|
+
import * as tui from '../../tui';
|
|
4
|
+
import { projectGet } from '@agentuity/server';
|
|
5
|
+
import { getAPIBaseURL, APIClient } from '../../api';
|
|
2
6
|
|
|
3
7
|
export const showSubcommand = createSubcommand({
|
|
4
8
|
name: 'show',
|
|
5
|
-
|
|
9
|
+
aliases: ['get'],
|
|
10
|
+
description: 'Show project detail',
|
|
6
11
|
requiresAuth: true,
|
|
12
|
+
schema: {
|
|
13
|
+
args: z.object({
|
|
14
|
+
id: z.string().describe('the project id'),
|
|
15
|
+
}),
|
|
16
|
+
options: z.object({
|
|
17
|
+
format: z
|
|
18
|
+
.enum(['json', 'table'])
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('the output format: json, table (default)'),
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
7
23
|
|
|
8
24
|
async handler(ctx) {
|
|
9
|
-
const {
|
|
10
|
-
|
|
25
|
+
const { opts, args, config } = ctx;
|
|
26
|
+
|
|
27
|
+
const apiUrl = getAPIBaseURL(config);
|
|
28
|
+
const client = new APIClient(apiUrl, config);
|
|
29
|
+
|
|
30
|
+
const project = await tui.spinner('Fetching project', () => {
|
|
31
|
+
return projectGet(client!, { id: args.id, mask: true });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (!project) {
|
|
35
|
+
tui.fatal('Project not found');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (opts?.format === 'json') {
|
|
39
|
+
console.log(JSON.stringify(project, null, 2));
|
|
40
|
+
} else {
|
|
41
|
+
console.table([project], ['id', 'orgId']);
|
|
42
|
+
}
|
|
11
43
|
},
|
|
12
44
|
});
|
|
@@ -3,12 +3,21 @@ import { existsSync, readdirSync, rmSync, statSync } from 'node:fs';
|
|
|
3
3
|
import { cwd } from 'node:process';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import enquirer from 'enquirer';
|
|
6
|
+
import {
|
|
7
|
+
projectCreate,
|
|
8
|
+
projectExists,
|
|
9
|
+
listOrganizations,
|
|
10
|
+
type OrganizationList,
|
|
11
|
+
} from '@agentuity/server';
|
|
6
12
|
import type { Logger } from '../../logger';
|
|
7
13
|
import * as tui from '../../tui';
|
|
8
14
|
import { playSound } from '../../sound';
|
|
9
15
|
import { fetchTemplates, type TemplateInfo } from './templates';
|
|
10
16
|
import { downloadTemplate, setupProject } from './download';
|
|
11
17
|
import { showBanner } from '../../banner';
|
|
18
|
+
import type { AuthData, Config } from '../../types';
|
|
19
|
+
import { getAPIBaseURL, APIClient } from '../../api';
|
|
20
|
+
import { createProjectConfig } from '../../config';
|
|
12
21
|
|
|
13
22
|
interface CreateFlowOptions {
|
|
14
23
|
projectName?: string;
|
|
@@ -20,6 +29,8 @@ interface CreateFlowOptions {
|
|
|
20
29
|
noBuild: boolean;
|
|
21
30
|
skipPrompts: boolean;
|
|
22
31
|
logger: Logger;
|
|
32
|
+
auth?: AuthData;
|
|
33
|
+
config?: Config;
|
|
23
34
|
}
|
|
24
35
|
|
|
25
36
|
export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
@@ -31,6 +42,8 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
31
42
|
templateBranch,
|
|
32
43
|
skipPrompts,
|
|
33
44
|
logger,
|
|
45
|
+
auth,
|
|
46
|
+
config,
|
|
34
47
|
} = options;
|
|
35
48
|
|
|
36
49
|
showBanner();
|
|
@@ -40,10 +53,8 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
40
53
|
tui.info(`📋 Loading templates from local directory: ${templateDir}...\n`);
|
|
41
54
|
}
|
|
42
55
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
await tui.spinner('Fetching templates', async () => {
|
|
46
|
-
templates = await fetchTemplates(templateDir, templateBranch);
|
|
56
|
+
const templates = await tui.spinner('Fetching templates', async () => {
|
|
57
|
+
return fetchTemplates(templateDir, templateBranch);
|
|
47
58
|
});
|
|
48
59
|
|
|
49
60
|
if (templates.length === 0) {
|
|
@@ -52,16 +63,42 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
52
63
|
|
|
53
64
|
// Step 2: Get project name
|
|
54
65
|
let projectName = initialProjectName;
|
|
66
|
+
|
|
67
|
+
let orgs: OrganizationList | undefined;
|
|
68
|
+
let client: APIClient | undefined;
|
|
69
|
+
let orgId: string | undefined;
|
|
70
|
+
|
|
71
|
+
if (auth) {
|
|
72
|
+
const apiUrl = getAPIBaseURL(config);
|
|
73
|
+
client = new APIClient(apiUrl, config);
|
|
74
|
+
orgs = await tui.spinner('Fetching organizations', async () => {
|
|
75
|
+
const resp = await listOrganizations(client!);
|
|
76
|
+
if (resp.data) {
|
|
77
|
+
return resp.data;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
if (!orgs) {
|
|
81
|
+
tui.fatal('no organizations could be found for your login');
|
|
82
|
+
}
|
|
83
|
+
orgId = await tui.selectOrganization(orgs, config?.preferences?.orgId);
|
|
84
|
+
}
|
|
85
|
+
|
|
55
86
|
if (!projectName && !skipPrompts) {
|
|
56
87
|
const response = await enquirer.prompt<{ name: string }>({
|
|
57
88
|
type: 'input',
|
|
58
89
|
name: 'name',
|
|
59
90
|
message: 'What is the name of your project?',
|
|
60
91
|
initial: 'My First Agent',
|
|
61
|
-
validate: (value: string) => {
|
|
92
|
+
validate: async (value: string) => {
|
|
62
93
|
if (!value || value.trim().length === 0) {
|
|
63
94
|
return 'Project name is required';
|
|
64
95
|
}
|
|
96
|
+
if (client) {
|
|
97
|
+
const exists = await projectExists(client, { name: value, organization_id: orgId! });
|
|
98
|
+
if (exists) {
|
|
99
|
+
return `Project with name '${value}' already exists in this organization`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
65
102
|
return true;
|
|
66
103
|
},
|
|
67
104
|
});
|
|
@@ -163,6 +200,24 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
163
200
|
logger,
|
|
164
201
|
});
|
|
165
202
|
|
|
203
|
+
if (auth && client && orgId) {
|
|
204
|
+
await tui.spinner('Registering your project', async () => {
|
|
205
|
+
const res = await projectCreate(client, {
|
|
206
|
+
name: projectName,
|
|
207
|
+
organization_id: orgId,
|
|
208
|
+
provider: 'bunjs',
|
|
209
|
+
});
|
|
210
|
+
if (res.success && res.data) {
|
|
211
|
+
return createProjectConfig(dest, {
|
|
212
|
+
projectId: res.data.id,
|
|
213
|
+
orgId,
|
|
214
|
+
apiKey: res.data.api_key,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
tui.fatal(res.message ?? 'failed to register project');
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
166
221
|
// Step 8: Show completion message
|
|
167
222
|
tui.success('✨ Project created successfully!\n');
|
|
168
223
|
tui.info('Next steps:');
|
package/src/config.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { join, extname, basename } from 'node:path';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { mkdir, readdir, readFile, writeFile, chmod } from 'node:fs/promises';
|
|
5
5
|
import type { Config, Profile, AuthData } from './types';
|
|
6
|
-
import { ConfigSchema } from './types';
|
|
6
|
+
import { ConfigSchema, ProjectSchema, BuildMetadataSchema, type BuildMetadata } from './types';
|
|
7
7
|
import * as tui from './tui';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@ export function getDefaultConfigDir(): string {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function getDefaultConfigPath(): string {
|
|
15
|
-
return join(getDefaultConfigDir(), '
|
|
15
|
+
return join(getDefaultConfigDir(), 'production.yaml');
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function getProfilePath(): string {
|
|
@@ -90,8 +90,15 @@ export async function fetchProfiles(): Promise<Profile[]> {
|
|
|
90
90
|
return profiles;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
function expandTilde(path: string): string {
|
|
94
|
+
if (path.startsWith('~/')) {
|
|
95
|
+
return join(homedir(), path.slice(2));
|
|
96
|
+
}
|
|
97
|
+
return path;
|
|
98
|
+
}
|
|
99
|
+
|
|
93
100
|
export async function loadConfig(customPath?: string): Promise<Config | null> {
|
|
94
|
-
const configPath = customPath
|
|
101
|
+
const configPath = customPath ? expandTilde(customPath) : await getProfile();
|
|
95
102
|
|
|
96
103
|
try {
|
|
97
104
|
const file = Bun.file(configPath);
|
|
@@ -248,7 +255,7 @@ function getPlaceholderValue(schema: z.ZodTypeAny): string {
|
|
|
248
255
|
}
|
|
249
256
|
}
|
|
250
257
|
|
|
251
|
-
function generateYAMLTemplate(name: string): string {
|
|
258
|
+
export function generateYAMLTemplate(name: string): string {
|
|
252
259
|
const lines: string[] = [];
|
|
253
260
|
|
|
254
261
|
// Add name (required)
|
|
@@ -308,4 +315,69 @@ function generateYAMLTemplate(name: string): string {
|
|
|
308
315
|
return lines.join('\n');
|
|
309
316
|
}
|
|
310
317
|
|
|
311
|
-
|
|
318
|
+
class ProjectConfigNotFoundExpection extends Error {
|
|
319
|
+
public name: string;
|
|
320
|
+
constructor() {
|
|
321
|
+
super('project not found');
|
|
322
|
+
this.name = 'ProjectConfigNotFoundExpection';
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
type ProjectConfig = z.infer<typeof ProjectSchema>;
|
|
327
|
+
|
|
328
|
+
export async function loadProjectConfig(dir: string): Promise<ProjectConfig> {
|
|
329
|
+
const configPath = join(dir, 'agentuity.json');
|
|
330
|
+
const file = Bun.file(configPath);
|
|
331
|
+
if (!(await file.exists())) {
|
|
332
|
+
throw new ProjectConfigNotFoundExpection();
|
|
333
|
+
}
|
|
334
|
+
const text = await file.text();
|
|
335
|
+
const config = JSON.parse(text);
|
|
336
|
+
const result = ProjectSchema.safeParse(config);
|
|
337
|
+
if (!result.success) {
|
|
338
|
+
tui.error(`Invalid project config at ${configPath}:`);
|
|
339
|
+
for (const issue of result.error.issues) {
|
|
340
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : 'root';
|
|
341
|
+
tui.bullet(`${path}: ${issue.message}`);
|
|
342
|
+
}
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
return result.data;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
type InitialProjectConfig = ProjectConfig & {
|
|
349
|
+
apiKey: string;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
export async function createProjectConfig(dir: string, config: InitialProjectConfig) {
|
|
353
|
+
// Create a sanitized config without the apiKey for agentuity.json
|
|
354
|
+
const { apiKey, ...sanitizedConfig } = config;
|
|
355
|
+
|
|
356
|
+
const configPath = join(dir, 'agentuity.json');
|
|
357
|
+
const configFile = Bun.file(configPath);
|
|
358
|
+
await configFile.write(JSON.stringify(sanitizedConfig, null, 2));
|
|
359
|
+
|
|
360
|
+
const envPath = join(dir, '.env');
|
|
361
|
+
const envFile = Bun.file(envPath);
|
|
362
|
+
await envFile.write(`AGENTUITY_SDK_KEY=${apiKey}`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export async function loadBuildMetadata(dir: string): Promise<BuildMetadata> {
|
|
366
|
+
const filename = join(dir, 'agentuity.metadata.json');
|
|
367
|
+
const file = Bun.file(filename);
|
|
368
|
+
if (!(await file.exists())) {
|
|
369
|
+
throw new Error(`couldn't find ${filename}`);
|
|
370
|
+
}
|
|
371
|
+
const buffer = await file.text();
|
|
372
|
+
const config = JSON.parse(buffer);
|
|
373
|
+
const result = BuildMetadataSchema.safeParse(config);
|
|
374
|
+
if (!result.success) {
|
|
375
|
+
tui.error(`Invalid build metadata at ${filename}:`);
|
|
376
|
+
for (const issue of result.error.issues) {
|
|
377
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : 'root';
|
|
378
|
+
tui.bullet(`${path}: ${issue.message}`);
|
|
379
|
+
}
|
|
380
|
+
process.exit(1);
|
|
381
|
+
}
|
|
382
|
+
return result.data;
|
|
383
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { createCLI, registerCommands } from './cli';
|
|
2
2
|
export { validateRuntime, isBun } from './runtime';
|
|
3
3
|
export { getVersion, getRevision, getPackageName, getPackage } from './version';
|
|
4
|
-
export { requireAuth, optionalAuth
|
|
4
|
+
export { requireAuth, optionalAuth } from './auth';
|
|
5
5
|
export {
|
|
6
6
|
loadConfig,
|
|
7
7
|
saveConfig,
|
|
@@ -16,7 +16,7 @@ export {
|
|
|
16
16
|
clearAuth,
|
|
17
17
|
getAuth,
|
|
18
18
|
} from './config';
|
|
19
|
-
export { APIClient, getAPIBaseURL, getAppBaseURL
|
|
19
|
+
export { APIClient, getAPIBaseURL, getAppBaseURL } from './api';
|
|
20
20
|
export { Logger, logger } from './logger';
|
|
21
21
|
export { showBanner } from './banner';
|
|
22
22
|
export { discoverCommands } from './cmd';
|
package/src/logger.ts
CHANGED
|
@@ -110,7 +110,7 @@ function getLogColors(scheme: ColorScheme): Record<LogLevel, LogColors> {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
export class Logger {
|
|
113
|
-
|
|
113
|
+
public level: LogLevel;
|
|
114
114
|
private showTimestamp: boolean;
|
|
115
115
|
private colorScheme: ColorScheme;
|
|
116
116
|
private colors: Record<LogLevel, LogColors>;
|
package/src/sound.ts
CHANGED
|
@@ -33,7 +33,13 @@ export function playSound(): void {
|
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
Bun.
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
if (process.stdout.isTTY && Bun.which(command[0])) {
|
|
37
|
+
try {
|
|
38
|
+
Bun.spawn(command, {
|
|
39
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
40
|
+
}).unref();
|
|
41
|
+
} catch {
|
|
42
|
+
/* ignore */
|
|
43
|
+
}
|
|
44
|
+
}
|
|
39
45
|
}
|