@agentuity/cli 0.0.42 → 0.0.44
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 +1 -1
- package/README.md +1 -1
- package/bin/cli.ts +7 -5
- package/dist/api.d.ts +3 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/auth.d.ts +10 -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 +4 -4
- package/dist/cmd/auth/api.d.ts.map +1 -1
- package/dist/cmd/auth/index.d.ts.map +1 -1
- package/dist/cmd/auth/login.d.ts.map +1 -1
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/add.d.ts +2 -0
- package/dist/cmd/auth/ssh/add.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/api.d.ts +16 -0
- package/dist/cmd/auth/ssh/api.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/delete.d.ts +2 -0
- package/dist/cmd/auth/ssh/delete.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/index.d.ts +3 -0
- package/dist/cmd/auth/ssh/index.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/list.d.ts +2 -0
- package/dist/cmd/auth/ssh/list.d.ts.map +1 -0
- package/dist/cmd/auth/whoami.d.ts +2 -0
- package/dist/cmd/auth/whoami.d.ts.map +1 -0
- package/dist/cmd/bundle/ast.d.ts +14 -3
- package/dist/cmd/bundle/ast.d.ts.map +1 -1
- package/dist/cmd/bundle/ast.test.d.ts +2 -0
- package/dist/cmd/bundle/ast.test.d.ts.map +1 -0
- package/dist/cmd/bundle/bundler.d.ts +6 -1
- package/dist/cmd/bundle/bundler.d.ts.map +1 -1
- package/dist/cmd/bundle/file.d.ts.map +1 -1
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts.map +1 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts.map +1 -0
- package/dist/cmd/bundle/index.d.ts +1 -1
- package/dist/cmd/bundle/index.d.ts.map +1 -1
- package/dist/cmd/bundle/plugin.d.ts +2 -0
- package/dist/cmd/bundle/plugin.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -0
- package/dist/cmd/cloud/domain.d.ts +17 -0
- package/dist/cmd/cloud/domain.d.ts.map +1 -0
- package/dist/cmd/cloud/index.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/add.d.ts +2 -0
- package/dist/cmd/cloud/resource/add.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/delete.d.ts +2 -0
- package/dist/cmd/cloud/resource/delete.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/index.d.ts +3 -0
- package/dist/cmd/cloud/resource/index.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/list.d.ts +2 -0
- package/dist/cmd/cloud/resource/list.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/download.d.ts +2 -0
- package/dist/cmd/cloud/scp/download.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/index.d.ts +3 -0
- package/dist/cmd/cloud/scp/index.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/upload.d.ts +2 -0
- package/dist/cmd/cloud/scp/upload.d.ts.map +1 -0
- package/dist/cmd/cloud/ssh.d.ts +2 -0
- package/dist/cmd/cloud/ssh.d.ts.map +1 -0
- package/dist/cmd/dev/api.d.ts +18 -0
- package/dist/cmd/dev/api.d.ts.map +1 -0
- package/dist/cmd/dev/download.d.ts +11 -0
- package/dist/cmd/dev/download.d.ts.map +1 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/templates.d.ts +3 -0
- package/dist/cmd/dev/templates.d.ts.map +1 -0
- package/dist/cmd/env/delete.d.ts +2 -0
- package/dist/cmd/env/delete.d.ts.map +1 -0
- package/dist/cmd/env/get.d.ts +2 -0
- package/dist/cmd/env/get.d.ts.map +1 -0
- package/dist/cmd/env/import.d.ts +2 -0
- package/dist/cmd/env/import.d.ts.map +1 -0
- package/dist/cmd/env/index.d.ts +2 -0
- package/dist/cmd/env/index.d.ts.map +1 -0
- package/dist/cmd/env/list.d.ts.map +1 -0
- package/dist/cmd/env/pull.d.ts +2 -0
- package/dist/cmd/env/pull.d.ts.map +1 -0
- package/dist/cmd/env/push.d.ts +2 -0
- package/dist/cmd/env/push.d.ts.map +1 -0
- package/dist/cmd/env/set.d.ts +2 -0
- package/dist/cmd/env/set.d.ts.map +1 -0
- package/dist/cmd/profile/show.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 +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 +5 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/secret/delete.d.ts +2 -0
- package/dist/cmd/secret/delete.d.ts.map +1 -0
- package/dist/cmd/secret/get.d.ts +2 -0
- package/dist/cmd/secret/get.d.ts.map +1 -0
- package/dist/cmd/secret/import.d.ts +2 -0
- package/dist/cmd/secret/import.d.ts.map +1 -0
- package/dist/cmd/secret/index.d.ts +2 -0
- package/dist/cmd/secret/index.d.ts.map +1 -0
- package/dist/cmd/secret/list.d.ts +2 -0
- package/dist/cmd/secret/list.d.ts.map +1 -0
- package/dist/cmd/secret/pull.d.ts +2 -0
- package/dist/cmd/secret/pull.d.ts.map +1 -0
- package/dist/cmd/secret/push.d.ts +2 -0
- package/dist/cmd/secret/push.d.ts.map +1 -0
- package/dist/cmd/secret/set.d.ts +2 -0
- package/dist/cmd/secret/set.d.ts.map +1 -0
- package/dist/cmd/version/index.d.ts.map +1 -1
- package/dist/config.d.ts +11 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/crypto/box.d.ts +65 -0
- package/dist/crypto/box.d.ts.map +1 -0
- package/dist/crypto/box.test.d.ts +2 -0
- package/dist/crypto/box.test.d.ts.map +1 -0
- package/dist/download.d.ts.map +1 -1
- package/dist/env-util.d.ts +67 -0
- package/dist/env-util.d.ts.map +1 -0
- package/dist/env-util.test.d.ts +2 -0
- package/dist/env-util.test.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/schema-parser.d.ts.map +1 -1
- package/dist/steps.d.ts +4 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/tui.d.ts +32 -2
- package/dist/tui.d.ts.map +1 -1
- package/dist/types.d.ts +250 -127
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/detectSubagent.d.ts +15 -0
- package/dist/utils/detectSubagent.d.ts.map +1 -0
- package/dist/utils/zip.d.ts +7 -0
- package/dist/utils/zip.d.ts.map +1 -0
- package/package.json +11 -3
- package/src/api-errors.md +2 -2
- package/src/api.ts +12 -7
- package/src/auth.ts +116 -7
- package/src/banner.ts +13 -6
- package/src/cli.ts +709 -36
- package/src/cmd/auth/api.ts +10 -16
- package/src/cmd/auth/index.ts +3 -1
- package/src/cmd/auth/login.ts +24 -8
- package/src/cmd/auth/signup.ts +15 -11
- package/src/cmd/auth/ssh/add.ts +263 -0
- package/src/cmd/auth/ssh/api.ts +94 -0
- package/src/cmd/auth/ssh/delete.ts +102 -0
- package/src/cmd/auth/ssh/index.ts +10 -0
- package/src/cmd/auth/ssh/list.ts +74 -0
- package/src/cmd/auth/whoami.ts +69 -0
- package/src/cmd/bundle/ast.test.ts +565 -0
- package/src/cmd/bundle/ast.ts +457 -44
- package/src/cmd/bundle/bundler.ts +255 -57
- package/src/cmd/bundle/file.ts +6 -12
- package/src/cmd/bundle/fix-duplicate-exports.test.ts +387 -0
- package/src/cmd/bundle/fix-duplicate-exports.ts +204 -0
- package/src/cmd/bundle/index.ts +11 -11
- package/src/cmd/bundle/patch/aisdk.ts +1 -1
- package/src/cmd/bundle/plugin.ts +373 -53
- package/src/cmd/cloud/deploy.ts +336 -0
- package/src/cmd/cloud/domain.ts +92 -0
- package/src/cmd/cloud/index.ts +11 -0
- package/src/cmd/cloud/resource/add.ts +56 -0
- package/src/cmd/cloud/resource/delete.ts +120 -0
- package/src/cmd/cloud/resource/index.ts +11 -0
- package/src/cmd/cloud/resource/list.ts +69 -0
- package/src/cmd/cloud/scp/download.ts +59 -0
- package/src/cmd/cloud/scp/index.ts +9 -0
- package/src/cmd/cloud/scp/upload.ts +62 -0
- package/src/cmd/cloud/ssh.ts +68 -0
- package/src/cmd/dev/api.ts +46 -0
- package/src/cmd/dev/download.ts +111 -0
- package/src/cmd/dev/index.ts +362 -34
- package/src/cmd/dev/templates.ts +84 -0
- package/src/cmd/env/delete.ts +47 -0
- package/src/cmd/env/get.ts +53 -0
- package/src/cmd/env/import.ts +102 -0
- package/src/cmd/env/index.ts +22 -0
- package/src/cmd/env/list.ts +56 -0
- package/src/cmd/env/pull.ts +80 -0
- package/src/cmd/env/push.ts +37 -0
- package/src/cmd/env/set.ts +71 -0
- package/src/cmd/index.ts +2 -2
- package/src/cmd/profile/show.ts +15 -6
- package/src/cmd/project/create.ts +7 -2
- package/src/cmd/project/delete.ts +75 -18
- package/src/cmd/project/download.ts +3 -3
- package/src/cmd/project/list.ts +8 -8
- package/src/cmd/project/show.ts +3 -7
- package/src/cmd/project/template-flow.ts +186 -48
- package/src/cmd/secret/delete.ts +40 -0
- package/src/cmd/secret/get.ts +54 -0
- package/src/cmd/secret/import.ts +64 -0
- package/src/cmd/secret/index.ts +22 -0
- package/src/cmd/secret/list.ts +56 -0
- package/src/cmd/secret/pull.ts +78 -0
- package/src/cmd/secret/push.ts +37 -0
- package/src/cmd/secret/set.ts +45 -0
- package/src/cmd/version/index.ts +2 -1
- package/src/config.ts +257 -27
- package/src/crypto/box.test.ts +431 -0
- package/src/crypto/box.ts +477 -0
- package/src/download.ts +1 -0
- package/src/env-util.test.ts +194 -0
- package/src/env-util.ts +290 -0
- package/src/index.ts +5 -1
- package/src/schema-parser.ts +2 -3
- package/src/steps.ts +144 -10
- package/src/terminal.ts +24 -23
- package/src/tui.ts +208 -68
- package/src/types.ts +292 -202
- package/src/utils/detectSubagent.ts +31 -0
- package/src/utils/zip.ts +38 -0
- package/dist/cmd/example/create-user.d.ts +0 -2
- package/dist/cmd/example/create-user.d.ts.map +0 -1
- package/dist/cmd/example/create.d.ts +0 -2
- package/dist/cmd/example/create.d.ts.map +0 -1
- package/dist/cmd/example/deploy.d.ts.map +0 -1
- package/dist/cmd/example/index.d.ts.map +0 -1
- package/dist/cmd/example/list.d.ts.map +0 -1
- package/dist/cmd/example/optional-auth.d.ts +0 -3
- package/dist/cmd/example/optional-auth.d.ts.map +0 -1
- package/dist/cmd/example/run-command.d.ts +0 -2
- package/dist/cmd/example/run-command.d.ts.map +0 -1
- package/dist/cmd/example/sound.d.ts +0 -3
- package/dist/cmd/example/sound.d.ts.map +0 -1
- package/dist/cmd/example/spinner.d.ts +0 -2
- package/dist/cmd/example/spinner.d.ts.map +0 -1
- package/dist/cmd/example/steps.d.ts +0 -2
- package/dist/cmd/example/steps.d.ts.map +0 -1
- package/dist/cmd/example/version.d.ts +0 -2
- package/dist/cmd/example/version.d.ts.map +0 -1
- package/dist/logger.d.ts +0 -24
- package/dist/logger.d.ts.map +0 -1
- package/src/cmd/example/create-user.ts +0 -38
- package/src/cmd/example/create.ts +0 -31
- package/src/cmd/example/deploy.ts +0 -36
- package/src/cmd/example/index.ts +0 -29
- package/src/cmd/example/list.ts +0 -32
- package/src/cmd/example/optional-auth.ts +0 -38
- package/src/cmd/example/run-command.ts +0 -45
- package/src/cmd/example/sound.ts +0 -14
- package/src/cmd/example/spinner.ts +0 -44
- package/src/cmd/example/steps.ts +0 -66
- package/src/cmd/example/version.ts +0 -13
- package/src/logger.ts +0 -235
- /package/dist/cmd/{example → cloud}/deploy.d.ts +0 -0
- /package/dist/cmd/{example → cloud}/index.d.ts +0 -0
- /package/dist/cmd/{example → env}/list.d.ts +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createSubcommand } from '../../types';
|
|
3
3
|
import * as tui from '../../tui';
|
|
4
|
-
import { projectDelete } from '@agentuity/server';
|
|
5
|
-
import
|
|
4
|
+
import { projectDelete, projectList } from '@agentuity/server';
|
|
5
|
+
import enquirer from 'enquirer';
|
|
6
6
|
|
|
7
7
|
export const deleteSubcommand = createSubcommand({
|
|
8
8
|
name: 'delete',
|
|
9
9
|
description: 'Delete a project',
|
|
10
10
|
aliases: ['rm', 'del'],
|
|
11
|
-
|
|
11
|
+
requires: { auth: true, apiClient: true },
|
|
12
12
|
schema: {
|
|
13
13
|
args: z.object({
|
|
14
|
-
id: z.string().describe('the project id'),
|
|
14
|
+
id: z.string().optional().describe('the project id'),
|
|
15
15
|
}),
|
|
16
16
|
options: z.object({
|
|
17
17
|
confirm: z.boolean().optional().describe('Skip confirmation prompts'),
|
|
@@ -19,10 +19,56 @@ export const deleteSubcommand = createSubcommand({
|
|
|
19
19
|
},
|
|
20
20
|
|
|
21
21
|
async handler(ctx) {
|
|
22
|
-
const { args, opts,
|
|
22
|
+
const { args, opts, apiClient } = ctx;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
let projectIds: string[] = [];
|
|
25
|
+
|
|
26
|
+
if (args.id) {
|
|
27
|
+
// Command line argument provided
|
|
28
|
+
projectIds = [args.id];
|
|
29
|
+
} else {
|
|
30
|
+
// Check TTY before attempting to prompt
|
|
31
|
+
if (!process.stdin.isTTY) {
|
|
32
|
+
tui.fatal('--id is required in non-interactive mode');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fetch projects and prompt for selection
|
|
36
|
+
const projects = await tui.spinner({
|
|
37
|
+
message: 'Fetching projects',
|
|
38
|
+
clearOnSuccess: true,
|
|
39
|
+
callback: async () => {
|
|
40
|
+
return projectList(apiClient);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (projects.length === 0) {
|
|
45
|
+
tui.info('No projects found to delete');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Sort projects by name
|
|
50
|
+
projects.sort((a, b) => a.name.localeCompare(b.name));
|
|
51
|
+
|
|
52
|
+
// Build choices for multi-select
|
|
53
|
+
const choices: Array<{ name: string; message: string }> = projects.map((project) => ({
|
|
54
|
+
name: project.id,
|
|
55
|
+
message: `${project.name.padEnd(25)} ${tui.muted(project.id)} (${project.orgName})`,
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
const response = await enquirer.prompt<{ projects: string[] }>({
|
|
59
|
+
type: 'multiselect',
|
|
60
|
+
name: 'projects',
|
|
61
|
+
message: 'Select project(s) to delete:',
|
|
62
|
+
choices,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
projectIds = response.projects;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (projectIds.length === 0) {
|
|
69
|
+
tui.info('No projects selected for deletion');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
26
72
|
|
|
27
73
|
const skipConfirm = opts?.confirm === true;
|
|
28
74
|
|
|
@@ -30,25 +76,36 @@ export const deleteSubcommand = createSubcommand({
|
|
|
30
76
|
tui.fatal('no TTY and --confirm is false');
|
|
31
77
|
}
|
|
32
78
|
|
|
79
|
+
// Confirm deletion
|
|
33
80
|
if (!skipConfirm) {
|
|
34
|
-
const
|
|
35
|
-
|
|
81
|
+
const projectNames = projectIds.join(', ');
|
|
82
|
+
tui.warning(`You are about to delete: ${tui.bold(projectNames)}`);
|
|
83
|
+
|
|
84
|
+
const confirm = await enquirer.prompt<{ confirm: boolean }>({
|
|
85
|
+
type: 'confirm',
|
|
86
|
+
name: 'confirm',
|
|
87
|
+
message: `Are you sure you want to delete ${projectIds.length > 1 ? 'these projects' : 'this project'}?`,
|
|
88
|
+
initial: false,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (!confirm.confirm) {
|
|
92
|
+
tui.info('Deletion cancelled');
|
|
36
93
|
return;
|
|
37
94
|
}
|
|
38
95
|
}
|
|
39
96
|
|
|
40
|
-
const deleted = await tui.spinner(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
97
|
+
const deleted = await tui.spinner({
|
|
98
|
+
message: `Deleting ${projectIds.length} project(s)`,
|
|
99
|
+
clearOnSuccess: true,
|
|
100
|
+
callback: async () => {
|
|
101
|
+
return projectDelete(apiClient, ...projectIds);
|
|
102
|
+
},
|
|
46
103
|
});
|
|
47
104
|
|
|
48
|
-
if (deleted) {
|
|
49
|
-
tui.success(`
|
|
105
|
+
if (deleted.length > 0) {
|
|
106
|
+
tui.success(`Deleted ${deleted.length} project(s): ${deleted.join(', ')}`);
|
|
50
107
|
} else {
|
|
51
|
-
tui.
|
|
108
|
+
tui.error('Failed to delete projects');
|
|
52
109
|
}
|
|
53
110
|
},
|
|
54
111
|
});
|
|
@@ -13,7 +13,7 @@ import { tmpdir } from 'node:os';
|
|
|
13
13
|
import { finished } from 'node:stream/promises';
|
|
14
14
|
import { createGunzip } from 'node:zlib';
|
|
15
15
|
import { extract, type Headers } from 'tar-fs';
|
|
16
|
-
import type { Logger } from '
|
|
16
|
+
import type { Logger } from '@agentuity/core';
|
|
17
17
|
import * as tui from '../../tui';
|
|
18
18
|
import { downloadWithSpinner } from '../../download';
|
|
19
19
|
import type { TemplateInfo } from './templates';
|
|
@@ -250,11 +250,11 @@ export async function setupProject(options: SetupOptions): Promise<void> {
|
|
|
250
250
|
clearOnSuccess: true,
|
|
251
251
|
});
|
|
252
252
|
|
|
253
|
-
// Create initial commit
|
|
253
|
+
// Create initial commit (disable GPG signing to avoid lock issues)
|
|
254
254
|
await tui.runCommand({
|
|
255
255
|
command: 'git commit -m "Initial Setup"',
|
|
256
256
|
cwd: dest,
|
|
257
|
-
cmd: ['git', 'commit', '-m', 'Initial Setup'],
|
|
257
|
+
cmd: ['git', '-c', 'commit.gpgsign=false', 'commit', '-m', 'Initial Setup'],
|
|
258
258
|
clearOnSuccess: true,
|
|
259
259
|
});
|
|
260
260
|
}
|
package/src/cmd/project/list.ts
CHANGED
|
@@ -2,13 +2,12 @@ import { z } from 'zod';
|
|
|
2
2
|
import { createSubcommand } from '../../types';
|
|
3
3
|
import * as tui from '../../tui';
|
|
4
4
|
import { projectList } from '@agentuity/server';
|
|
5
|
-
import { getAPIBaseURL, APIClient } from '../../api';
|
|
6
5
|
|
|
7
6
|
export const listSubcommand = createSubcommand({
|
|
8
7
|
name: 'list',
|
|
9
8
|
description: 'List all projects',
|
|
10
9
|
aliases: ['ls'],
|
|
11
|
-
|
|
10
|
+
requires: { auth: true, apiClient: true },
|
|
12
11
|
schema: {
|
|
13
12
|
options: z.object({
|
|
14
13
|
format: z
|
|
@@ -19,13 +18,14 @@ export const listSubcommand = createSubcommand({
|
|
|
19
18
|
},
|
|
20
19
|
|
|
21
20
|
async handler(ctx) {
|
|
22
|
-
const {
|
|
21
|
+
const { apiClient, opts } = ctx;
|
|
23
22
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
const projects = await tui.spinner({
|
|
24
|
+
message: 'Fetching projects',
|
|
25
|
+
clearOnSuccess: true,
|
|
26
|
+
callback: () => {
|
|
27
|
+
return projectList(apiClient);
|
|
28
|
+
},
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
// TODO: might want to sort by the last org_id we used
|
package/src/cmd/project/show.ts
CHANGED
|
@@ -2,13 +2,12 @@ import { z } from 'zod';
|
|
|
2
2
|
import { createSubcommand } from '../../types';
|
|
3
3
|
import * as tui from '../../tui';
|
|
4
4
|
import { projectGet } from '@agentuity/server';
|
|
5
|
-
import { getAPIBaseURL, APIClient } from '../../api';
|
|
6
5
|
|
|
7
6
|
export const showSubcommand = createSubcommand({
|
|
8
7
|
name: 'show',
|
|
9
8
|
aliases: ['get'],
|
|
10
9
|
description: 'Show project detail',
|
|
11
|
-
|
|
10
|
+
requires: { auth: true, apiClient: true },
|
|
12
11
|
schema: {
|
|
13
12
|
args: z.object({
|
|
14
13
|
id: z.string().describe('the project id'),
|
|
@@ -22,13 +21,10 @@ export const showSubcommand = createSubcommand({
|
|
|
22
21
|
},
|
|
23
22
|
|
|
24
23
|
async handler(ctx) {
|
|
25
|
-
const { opts, args,
|
|
26
|
-
|
|
27
|
-
const apiUrl = getAPIBaseURL(config);
|
|
28
|
-
const client = new APIClient(apiUrl, config);
|
|
24
|
+
const { opts, args, apiClient } = ctx;
|
|
29
25
|
|
|
30
26
|
const project = await tui.spinner('Fetching project', () => {
|
|
31
|
-
return projectGet(
|
|
27
|
+
return projectGet(apiClient, { id: args.id, mask: true });
|
|
32
28
|
});
|
|
33
29
|
|
|
34
30
|
if (!project) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { basename, resolve } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
import { existsSync, readdirSync, rmSync, statSync } from 'node:fs';
|
|
3
4
|
import { cwd } from 'node:process';
|
|
4
5
|
import { homedir } from 'node:os';
|
|
@@ -6,18 +7,29 @@ import enquirer from 'enquirer';
|
|
|
6
7
|
import {
|
|
7
8
|
projectCreate,
|
|
8
9
|
projectExists,
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
listResources,
|
|
11
|
+
projectEnvUpdate,
|
|
12
|
+
getServiceUrls,
|
|
13
|
+
APIClient as ServerAPIClient,
|
|
14
|
+
Resources,
|
|
15
|
+
createResources,
|
|
11
16
|
} from '@agentuity/server';
|
|
12
|
-
import type { Logger } from '
|
|
17
|
+
import type { Logger } from '@agentuity/core';
|
|
13
18
|
import * as tui from '../../tui';
|
|
14
19
|
import { playSound } from '../../sound';
|
|
15
20
|
import { fetchTemplates, type TemplateInfo } from './templates';
|
|
16
21
|
import { downloadTemplate, setupProject } from './download';
|
|
17
|
-
import { showBanner } from '../../banner';
|
|
18
22
|
import type { AuthData, Config } from '../../types';
|
|
19
|
-
import {
|
|
23
|
+
import type { APIClient } from '../../api';
|
|
20
24
|
import { createProjectConfig } from '../../config';
|
|
25
|
+
import {
|
|
26
|
+
findEnvFile,
|
|
27
|
+
readEnvFile,
|
|
28
|
+
filterAgentuitySdkKeys,
|
|
29
|
+
splitEnvAndSecrets,
|
|
30
|
+
} from '../../env-util';
|
|
31
|
+
|
|
32
|
+
type ResourcesTypes = z.infer<typeof Resources>;
|
|
21
33
|
|
|
22
34
|
interface CreateFlowOptions {
|
|
23
35
|
projectName?: string;
|
|
@@ -31,6 +43,9 @@ interface CreateFlowOptions {
|
|
|
31
43
|
logger: Logger;
|
|
32
44
|
auth?: AuthData;
|
|
33
45
|
config?: Config;
|
|
46
|
+
orgId?: string;
|
|
47
|
+
region?: string;
|
|
48
|
+
apiClient?: APIClient;
|
|
34
49
|
}
|
|
35
50
|
|
|
36
51
|
export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
@@ -44,43 +59,39 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
44
59
|
logger,
|
|
45
60
|
auth,
|
|
46
61
|
config,
|
|
62
|
+
orgId: selectedOrgId,
|
|
63
|
+
region,
|
|
64
|
+
apiClient,
|
|
47
65
|
} = options;
|
|
48
66
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Step 1: Fetch available templates
|
|
67
|
+
// Fetch available templates
|
|
52
68
|
if (templateDir) {
|
|
53
69
|
tui.info(`📋 Loading templates from local directory: ${templateDir}...\n`);
|
|
54
70
|
}
|
|
55
71
|
|
|
56
|
-
const templates = await tui.spinner(
|
|
57
|
-
|
|
72
|
+
const templates = await tui.spinner({
|
|
73
|
+
message: 'Fetching templates',
|
|
74
|
+
clearOnSuccess: true,
|
|
75
|
+
callback: async () => {
|
|
76
|
+
return fetchTemplates(templateDir, templateBranch);
|
|
77
|
+
},
|
|
58
78
|
});
|
|
59
79
|
|
|
60
80
|
if (templates.length === 0) {
|
|
61
81
|
logger.fatal('No templates available');
|
|
62
82
|
}
|
|
63
83
|
|
|
64
|
-
//
|
|
84
|
+
// Get project name
|
|
65
85
|
let projectName = initialProjectName;
|
|
66
86
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
let
|
|
87
|
+
// Organization is now automatically selected by the CLI framework via optional: { org: true }
|
|
88
|
+
const orgId = selectedOrgId;
|
|
89
|
+
let catalystClient: ServerAPIClient | undefined;
|
|
70
90
|
|
|
71
91
|
if (auth) {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
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);
|
|
92
|
+
const serviceUrls = getServiceUrls();
|
|
93
|
+
const catalystUrl = config?.overrides?.catalyst_url ?? serviceUrls.catalyst;
|
|
94
|
+
catalystClient = new ServerAPIClient(catalystUrl, logger, auth.apiKey);
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
if (!projectName && !skipPrompts) {
|
|
@@ -93,8 +104,11 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
93
104
|
if (!value || value.trim().length === 0) {
|
|
94
105
|
return 'Project name is required';
|
|
95
106
|
}
|
|
96
|
-
if (
|
|
97
|
-
const exists = await projectExists(
|
|
107
|
+
if (apiClient && auth && orgId) {
|
|
108
|
+
const exists = await projectExists(apiClient, {
|
|
109
|
+
name: value,
|
|
110
|
+
organization_id: orgId,
|
|
111
|
+
});
|
|
98
112
|
if (exists) {
|
|
99
113
|
return `Project with name '${value}' already exists in this organization`;
|
|
100
114
|
}
|
|
@@ -106,13 +120,13 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
106
120
|
}
|
|
107
121
|
projectName = projectName || 'My First Agent';
|
|
108
122
|
|
|
109
|
-
//
|
|
123
|
+
// Generate disk-friendly directory name
|
|
110
124
|
const dirName = projectName === '.' ? '.' : sanitizeDirectoryName(projectName);
|
|
111
125
|
|
|
112
|
-
//
|
|
126
|
+
// Determine destination directory
|
|
113
127
|
// Expand ~ to home directory
|
|
114
128
|
let expandedTargetDir = targetDir;
|
|
115
|
-
if (expandedTargetDir
|
|
129
|
+
if (expandedTargetDir?.startsWith('~')) {
|
|
116
130
|
expandedTargetDir = expandedTargetDir.replace(/^~/, homedir());
|
|
117
131
|
}
|
|
118
132
|
const baseDir = expandedTargetDir ? resolve(expandedTargetDir) : process.cwd();
|
|
@@ -144,7 +158,7 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
144
158
|
return;
|
|
145
159
|
}
|
|
146
160
|
rmSync(dest, { recursive: true, force: true });
|
|
147
|
-
tui.success(`Deleted ${dest}
|
|
161
|
+
tui.success(`Deleted ${dest}`);
|
|
148
162
|
} else {
|
|
149
163
|
logger.fatal(`Directory ${dest} already exists and is not empty.`, true);
|
|
150
164
|
}
|
|
@@ -181,7 +195,7 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
181
195
|
|
|
182
196
|
tui.info(`✨ Using template: ${tui.bold(selectedTemplate.name)}`);
|
|
183
197
|
|
|
184
|
-
//
|
|
198
|
+
// Download template
|
|
185
199
|
await downloadTemplate({
|
|
186
200
|
dest,
|
|
187
201
|
template: selectedTemplate,
|
|
@@ -190,7 +204,7 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
190
204
|
logger,
|
|
191
205
|
});
|
|
192
206
|
|
|
193
|
-
//
|
|
207
|
+
// Setup project (replace placeholders, install deps, build)
|
|
194
208
|
await setupProject({
|
|
195
209
|
dest,
|
|
196
210
|
projectName: projectName === '.' ? basename(dest) : projectName,
|
|
@@ -200,29 +214,153 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
200
214
|
logger,
|
|
201
215
|
});
|
|
202
216
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
217
|
+
const resourceConfig: ResourcesTypes = Resources.parse({});
|
|
218
|
+
|
|
219
|
+
if (auth && apiClient && catalystClient && orgId && region) {
|
|
220
|
+
// Fetch resources for selected org and region using Catalyst API
|
|
221
|
+
const resources = await tui.spinner({
|
|
222
|
+
message: 'Fetching resources',
|
|
223
|
+
clearOnSuccess: true,
|
|
224
|
+
callback: async () => {
|
|
225
|
+
return listResources(catalystClient, orgId, region);
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
logger.debug(`Resources for org ${orgId} in region ${region}:`, resources);
|
|
230
|
+
|
|
231
|
+
const choices = await enquirer.prompt<{
|
|
232
|
+
db_action: string;
|
|
233
|
+
s3_action: string;
|
|
234
|
+
}>([
|
|
235
|
+
{
|
|
236
|
+
type: 'select',
|
|
237
|
+
name: 'db_action',
|
|
238
|
+
message: 'Create SQL Database?',
|
|
239
|
+
choices: [
|
|
240
|
+
{ name: 'Create New', message: 'Create a new (free)' },
|
|
241
|
+
{ name: 'Skip', message: 'Skip or Setup later' },
|
|
242
|
+
...resources.db.map((db) => ({
|
|
243
|
+
name: db.name,
|
|
244
|
+
message: `Use database: ${db.name}`,
|
|
245
|
+
})),
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
type: 'select',
|
|
250
|
+
name: 's3_action',
|
|
251
|
+
message: 'Create Storage Bucket?',
|
|
252
|
+
choices: [
|
|
253
|
+
{ name: 'Create New', message: 'Create a new (free)' },
|
|
254
|
+
{ name: 'Skip', message: 'Skip or Setup later' },
|
|
255
|
+
...resources.s3.map((db) => ({
|
|
256
|
+
name: db.bucket_name,
|
|
257
|
+
message: `Use bucket: ${db.bucket_name}`,
|
|
258
|
+
})),
|
|
259
|
+
],
|
|
260
|
+
},
|
|
261
|
+
]);
|
|
262
|
+
switch (choices.s3_action) {
|
|
263
|
+
case 'Create New': {
|
|
264
|
+
const created = await tui.spinner({
|
|
265
|
+
message: 'Provisioning New Bucket',
|
|
266
|
+
clearOnSuccess: true,
|
|
267
|
+
callback: async () => {
|
|
268
|
+
return createResources(catalystClient, orgId, region!, [{ type: 's3' }]);
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
resourceConfig.storage = created[0].name;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
case 'Skip': {
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
default: {
|
|
278
|
+
resourceConfig.storage = choices.s3_action;
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
switch (choices.db_action) {
|
|
283
|
+
case 'Create New': {
|
|
284
|
+
const created = await tui.spinner({
|
|
285
|
+
message: 'Provisioning New SQL Database',
|
|
286
|
+
clearOnSuccess: true,
|
|
287
|
+
callback: async () => {
|
|
288
|
+
return createResources(catalystClient, orgId, region!, [{ type: 'db' }]);
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
resourceConfig.db = created[0].name;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
case 'Skip': {
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
default: {
|
|
298
|
+
resourceConfig.db = choices.db_action;
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (auth && apiClient && orgId) {
|
|
305
|
+
let projectId: string | undefined;
|
|
306
|
+
|
|
307
|
+
await tui.spinner({
|
|
308
|
+
message: 'Registering your project',
|
|
309
|
+
clearOnSuccess: true,
|
|
310
|
+
callback: async () => {
|
|
311
|
+
const project = await projectCreate(apiClient, {
|
|
312
|
+
name: projectName,
|
|
313
|
+
organization_id: orgId,
|
|
314
|
+
provider: 'bunjs',
|
|
315
|
+
});
|
|
316
|
+
projectId = project.id;
|
|
211
317
|
return createProjectConfig(dest, {
|
|
212
|
-
projectId:
|
|
318
|
+
projectId: project.id,
|
|
213
319
|
orgId,
|
|
214
|
-
apiKey:
|
|
320
|
+
apiKey: project.api_key,
|
|
321
|
+
deployment: {
|
|
322
|
+
resources: resourceConfig,
|
|
323
|
+
},
|
|
215
324
|
});
|
|
216
|
-
}
|
|
217
|
-
tui.fatal(res.message ?? 'failed to register project');
|
|
325
|
+
},
|
|
218
326
|
});
|
|
327
|
+
|
|
328
|
+
// After registration, push any existing env/secrets from .env.production
|
|
329
|
+
if (projectId) {
|
|
330
|
+
await tui.spinner({
|
|
331
|
+
message: 'Syncing environment variables',
|
|
332
|
+
clearOnSuccess: true,
|
|
333
|
+
callback: async () => {
|
|
334
|
+
try {
|
|
335
|
+
const envFilePath = await findEnvFile(dest);
|
|
336
|
+
const localEnv = await readEnvFile(envFilePath);
|
|
337
|
+
const filteredEnv = filterAgentuitySdkKeys(localEnv);
|
|
338
|
+
|
|
339
|
+
if (Object.keys(filteredEnv).length > 0) {
|
|
340
|
+
const { env, secrets } = splitEnvAndSecrets(filteredEnv);
|
|
341
|
+
await projectEnvUpdate(apiClient, {
|
|
342
|
+
id: projectId as string,
|
|
343
|
+
env,
|
|
344
|
+
secrets,
|
|
345
|
+
});
|
|
346
|
+
logger.debug(
|
|
347
|
+
`Synced ${Object.keys(filteredEnv).length} environment variables to cloud`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
} catch (error) {
|
|
351
|
+
// Non-fatal: just log the error
|
|
352
|
+
logger.debug('Failed to sync environment variables:', error);
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
}
|
|
219
357
|
}
|
|
220
358
|
|
|
221
|
-
//
|
|
359
|
+
// Show completion message
|
|
222
360
|
tui.success('✨ Project created successfully!\n');
|
|
223
361
|
tui.info('Next steps:');
|
|
224
362
|
if (dirName !== '.') {
|
|
225
|
-
const dirDisplay = cwd()
|
|
363
|
+
const dirDisplay = cwd() === targetDir ? basename(dirName) : dest;
|
|
226
364
|
tui.newline();
|
|
227
365
|
console.log(` 1. ${tui.bold(`cd ${dirDisplay}`)}`);
|
|
228
366
|
console.log(` 2. ${tui.bold('bun run dev')}`);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSubcommand } from '../../types';
|
|
3
|
+
import * as tui from '../../tui';
|
|
4
|
+
import { projectEnvDelete } from '@agentuity/server';
|
|
5
|
+
import { findEnvFile, readEnvFile, writeEnvFile, filterAgentuitySdkKeys } from '../../env-util';
|
|
6
|
+
|
|
7
|
+
export const deleteSubcommand = createSubcommand({
|
|
8
|
+
name: 'delete',
|
|
9
|
+
aliases: ['del', 'remove', 'rm'],
|
|
10
|
+
description: 'Delete a secret',
|
|
11
|
+
requires: { auth: true, project: true, apiClient: true },
|
|
12
|
+
schema: {
|
|
13
|
+
args: z.object({
|
|
14
|
+
key: z.string().describe('the secret key to delete'),
|
|
15
|
+
}),
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
async handler(ctx) {
|
|
19
|
+
const { args, apiClient, project, projectDir } = ctx;
|
|
20
|
+
|
|
21
|
+
// Delete from cloud (using secrets field)
|
|
22
|
+
await tui.spinner('Deleting secret from cloud', () => {
|
|
23
|
+
return projectEnvDelete(apiClient, {
|
|
24
|
+
id: project.projectId,
|
|
25
|
+
secrets: [args.key],
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Update local .env.production file
|
|
30
|
+
const envFilePath = await findEnvFile(projectDir);
|
|
31
|
+
const currentEnv = await readEnvFile(envFilePath);
|
|
32
|
+
delete currentEnv[args.key];
|
|
33
|
+
|
|
34
|
+
// Filter out AGENTUITY_ keys before writing
|
|
35
|
+
const filteredEnv = filterAgentuitySdkKeys(currentEnv);
|
|
36
|
+
await writeEnvFile(envFilePath, filteredEnv);
|
|
37
|
+
|
|
38
|
+
tui.success(`Secret '${args.key}' deleted successfully (cloud + ${envFilePath})`);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createSubcommand } from '../../types';
|
|
3
|
+
import * as tui from '../../tui';
|
|
4
|
+
import { projectGet } from '@agentuity/server';
|
|
5
|
+
import { maskSecret } from '../../env-util';
|
|
6
|
+
|
|
7
|
+
export const getSubcommand = createSubcommand({
|
|
8
|
+
name: 'get',
|
|
9
|
+
description: 'Get a secret value',
|
|
10
|
+
requires: { auth: true, project: true, apiClient: true },
|
|
11
|
+
schema: {
|
|
12
|
+
args: z.object({
|
|
13
|
+
key: z.string().describe('the secret key'),
|
|
14
|
+
}),
|
|
15
|
+
options: z.object({
|
|
16
|
+
mask: z
|
|
17
|
+
.boolean()
|
|
18
|
+
.default(!!process.stdout.isTTY)
|
|
19
|
+
.describe('mask the value in output (default: true in TTY, false otherwise)'),
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
async handler(ctx) {
|
|
24
|
+
const { args, opts, apiClient, project } = ctx;
|
|
25
|
+
|
|
26
|
+
// Fetch project with unmasked secrets
|
|
27
|
+
const projectData = await tui.spinner('Fetching secrets', () => {
|
|
28
|
+
return projectGet(apiClient, { id: project.projectId, mask: false });
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Look for the key in secrets
|
|
32
|
+
const value = projectData.secrets?.[args.key];
|
|
33
|
+
|
|
34
|
+
if (value === undefined) {
|
|
35
|
+
tui.fatal(`Secret '${args.key}' not found`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (process.stdout.isTTY) {
|
|
39
|
+
// Display the value, masked by default
|
|
40
|
+
if (opts?.mask) {
|
|
41
|
+
tui.success(`${args.key}=${maskSecret(value)}`);
|
|
42
|
+
} else {
|
|
43
|
+
tui.success(`${args.key}=${value}`);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// Display the value, masked by default
|
|
47
|
+
if (opts?.mask) {
|
|
48
|
+
console.log(`${args.key}=${maskSecret(value)}`);
|
|
49
|
+
} else {
|
|
50
|
+
console.log(`${args.key}=${value}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|