@agentuity/cli 0.0.43 → 0.0.45
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/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.map +1 -1
- 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/plugin.d.ts +2 -0
- package/dist/cmd/bundle/plugin.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- 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 -1
- 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.map +1 -1
- package/dist/cmd/env/get.d.ts.map +1 -1
- package/dist/cmd/env/import.d.ts.map +1 -1
- package/dist/cmd/env/list.d.ts.map +1 -1
- package/dist/cmd/env/pull.d.ts.map +1 -1
- package/dist/cmd/env/push.d.ts.map +1 -1
- package/dist/cmd/env/set.d.ts.map +1 -1
- 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/list.d.ts.map +1 -1
- package/dist/cmd/project/show.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +4 -0
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/secret/delete.d.ts.map +1 -1
- package/dist/cmd/secret/get.d.ts.map +1 -1
- package/dist/cmd/secret/import.d.ts.map +1 -1
- package/dist/cmd/secret/list.d.ts.map +1 -1
- package/dist/cmd/secret/pull.d.ts.map +1 -1
- package/dist/cmd/secret/push.d.ts.map +1 -1
- package/dist/cmd/secret/set.d.ts.map +1 -1
- package/dist/config.d.ts +9 -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/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 +31 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/types.d.ts +249 -126
- 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 +695 -63
- package/src/cmd/auth/api.ts +10 -16
- package/src/cmd/auth/index.ts +2 -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 +13 -13
- 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 +9 -9
- package/src/cmd/bundle/patch/aisdk.ts +1 -1
- package/src/cmd/bundle/plugin.ts +373 -53
- package/src/cmd/cloud/deploy.ts +300 -93
- package/src/cmd/cloud/domain.ts +92 -0
- package/src/cmd/cloud/index.ts +4 -1
- 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 +360 -34
- package/src/cmd/dev/templates.ts +84 -0
- package/src/cmd/env/delete.ts +5 -20
- package/src/cmd/env/get.ts +5 -18
- package/src/cmd/env/import.ts +5 -20
- package/src/cmd/env/list.ts +5 -18
- package/src/cmd/env/pull.ts +10 -23
- package/src/cmd/env/push.ts +5 -23
- package/src/cmd/env/set.ts +5 -20
- 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 +2 -2
- package/src/cmd/project/list.ts +8 -8
- package/src/cmd/project/show.ts +3 -7
- package/src/cmd/project/template-flow.ts +170 -72
- package/src/cmd/secret/delete.ts +5 -20
- package/src/cmd/secret/get.ts +5 -18
- package/src/cmd/secret/import.ts +5 -20
- package/src/cmd/secret/list.ts +5 -18
- package/src/cmd/secret/pull.ts +10 -23
- package/src/cmd/secret/push.ts +5 -23
- package/src/cmd/secret/set.ts +5 -20
- package/src/config.ts +224 -24
- 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 +1 -1
- package/src/steps.ts +65 -6
- package/src/terminal.ts +24 -23
- package/src/tui.ts +192 -61
- package/src/types.ts +291 -201
- 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 +0 -2
- package/dist/cmd/example/deploy.d.ts.map +0 -1
- package/dist/cmd/example/index.d.ts +0 -2
- package/dist/cmd/example/index.d.ts.map +0 -1
- package/dist/cmd/example/list.d.ts +0 -2
- 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/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/cmd/secret/pull.ts
CHANGED
|
@@ -3,8 +3,6 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { createSubcommand } from '../../types';
|
|
4
4
|
import * as tui from '../../tui';
|
|
5
5
|
import { projectGet } from '@agentuity/server';
|
|
6
|
-
import { getAPIBaseURL, APIClient } from '../../api';
|
|
7
|
-
import { loadProjectConfig } from '../../config';
|
|
8
6
|
import {
|
|
9
7
|
findEnvFile,
|
|
10
8
|
findExistingEnvFile,
|
|
@@ -16,40 +14,29 @@ import {
|
|
|
16
14
|
export const pullSubcommand = createSubcommand({
|
|
17
15
|
name: 'pull',
|
|
18
16
|
description: 'Pull secrets from cloud to local .env.production file',
|
|
19
|
-
|
|
17
|
+
requires: { auth: true, project: true, apiClient: true },
|
|
20
18
|
schema: {
|
|
21
19
|
options: z.object({
|
|
22
|
-
dir: z.string().optional().describe('project directory (default: current directory)'),
|
|
23
20
|
force: z.boolean().default(false).describe('overwrite local values with cloud values'),
|
|
24
21
|
}),
|
|
25
22
|
},
|
|
26
23
|
|
|
27
24
|
async handler(ctx) {
|
|
28
|
-
const { opts,
|
|
29
|
-
const dir = opts?.dir ?? process.cwd();
|
|
30
|
-
|
|
31
|
-
// Load project config to get project ID
|
|
32
|
-
const projectConfig = await loadProjectConfig(dir);
|
|
33
|
-
if (!projectConfig) {
|
|
34
|
-
tui.fatal(`No Agentuity project found in ${dir}. Missing agentuity.json`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const apiUrl = getAPIBaseURL(config);
|
|
38
|
-
const client = new APIClient(apiUrl, config);
|
|
25
|
+
const { opts, apiClient, project, projectDir } = ctx;
|
|
39
26
|
|
|
40
27
|
// Fetch project with unmasked secrets
|
|
41
|
-
const
|
|
42
|
-
return projectGet(
|
|
28
|
+
const projectData = await tui.spinner('Pulling secrets from cloud', () => {
|
|
29
|
+
return projectGet(apiClient, { id: project.projectId, mask: false });
|
|
43
30
|
});
|
|
44
31
|
|
|
45
|
-
const cloudSecrets =
|
|
32
|
+
const cloudSecrets = projectData.secrets || {};
|
|
46
33
|
|
|
47
34
|
// Read current local env from existing file (.env.production or .env)
|
|
48
|
-
const existingEnvPath = await findExistingEnvFile(
|
|
35
|
+
const existingEnvPath = await findExistingEnvFile(projectDir);
|
|
49
36
|
const localEnv = await readEnvFile(existingEnvPath);
|
|
50
37
|
|
|
51
38
|
// Target file is always .env.production
|
|
52
|
-
const targetEnvPath = await findEnvFile(
|
|
39
|
+
const targetEnvPath = await findEnvFile(projectDir);
|
|
53
40
|
|
|
54
41
|
// Merge: cloud values override local if force=true, otherwise keep local
|
|
55
42
|
let mergedEnv: Record<string, string>;
|
|
@@ -67,12 +54,12 @@ export const pullSubcommand = createSubcommand({
|
|
|
67
54
|
});
|
|
68
55
|
|
|
69
56
|
// Write AGENTUITY_SDK_KEY to .env if present and missing locally
|
|
70
|
-
if (
|
|
71
|
-
const dotEnvPath = join(
|
|
57
|
+
if (projectData.api_key) {
|
|
58
|
+
const dotEnvPath = join(projectDir, '.env');
|
|
72
59
|
const dotEnv = await readEnvFile(dotEnvPath);
|
|
73
60
|
|
|
74
61
|
if (!dotEnv.AGENTUITY_SDK_KEY) {
|
|
75
|
-
dotEnv.AGENTUITY_SDK_KEY =
|
|
62
|
+
dotEnv.AGENTUITY_SDK_KEY = projectData.api_key;
|
|
76
63
|
await writeEnvFile(dotEnvPath, dotEnv, {
|
|
77
64
|
addComment: (key) => {
|
|
78
65
|
if (key === 'AGENTUITY_SDK_KEY') {
|
package/src/cmd/secret/push.ts
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import { createSubcommand } from '../../types';
|
|
3
2
|
import * as tui from '../../tui';
|
|
4
3
|
import { projectEnvUpdate } from '@agentuity/server';
|
|
5
|
-
import { getAPIBaseURL, APIClient } from '../../api';
|
|
6
|
-
import { loadProjectConfig } from '../../config';
|
|
7
4
|
import { findEnvFile, readEnvFile, filterAgentuitySdkKeys } from '../../env-util';
|
|
8
5
|
|
|
9
6
|
export const pushSubcommand = createSubcommand({
|
|
10
7
|
name: 'push',
|
|
11
8
|
description: 'Push secrets from local .env.production file to cloud',
|
|
12
|
-
|
|
13
|
-
schema: {
|
|
14
|
-
options: z.object({
|
|
15
|
-
dir: z.string().optional().describe('project directory (default: current directory)'),
|
|
16
|
-
}),
|
|
17
|
-
},
|
|
9
|
+
requires: { auth: true, project: true, apiClient: true },
|
|
18
10
|
|
|
19
11
|
async handler(ctx) {
|
|
20
|
-
const {
|
|
21
|
-
const dir = opts?.dir ?? process.cwd();
|
|
22
|
-
|
|
23
|
-
// Load project config to get project ID
|
|
24
|
-
const projectConfig = await loadProjectConfig(dir);
|
|
25
|
-
if (!projectConfig) {
|
|
26
|
-
tui.fatal(`No Agentuity project found in ${dir}. Missing agentuity.json`);
|
|
27
|
-
}
|
|
12
|
+
const { apiClient, project, projectDir } = ctx;
|
|
28
13
|
|
|
29
14
|
// Read local env file
|
|
30
|
-
const envFilePath = await findEnvFile(
|
|
15
|
+
const envFilePath = await findEnvFile(projectDir);
|
|
31
16
|
const localEnv = await readEnvFile(envFilePath);
|
|
32
17
|
|
|
33
18
|
// Filter out AGENTUITY_ prefixed keys (don't push SDK keys)
|
|
@@ -38,13 +23,10 @@ export const pushSubcommand = createSubcommand({
|
|
|
38
23
|
return;
|
|
39
24
|
}
|
|
40
25
|
|
|
41
|
-
const apiUrl = getAPIBaseURL(config);
|
|
42
|
-
const client = new APIClient(apiUrl, config);
|
|
43
|
-
|
|
44
26
|
// Push to cloud (using secrets field)
|
|
45
27
|
await tui.spinner('Pushing secrets to cloud', () => {
|
|
46
|
-
return projectEnvUpdate(
|
|
47
|
-
id:
|
|
28
|
+
return projectEnvUpdate(apiClient, {
|
|
29
|
+
id: project.projectId,
|
|
48
30
|
secrets: filteredSecrets,
|
|
49
31
|
});
|
|
50
32
|
});
|
package/src/cmd/secret/set.ts
CHANGED
|
@@ -2,52 +2,37 @@ import { z } from 'zod';
|
|
|
2
2
|
import { createSubcommand } from '../../types';
|
|
3
3
|
import * as tui from '../../tui';
|
|
4
4
|
import { projectEnvUpdate } from '@agentuity/server';
|
|
5
|
-
import { getAPIBaseURL, APIClient } from '../../api';
|
|
6
|
-
import { loadProjectConfig } from '../../config';
|
|
7
5
|
import { findEnvFile, readEnvFile, writeEnvFile, filterAgentuitySdkKeys } from '../../env-util';
|
|
8
6
|
|
|
9
7
|
export const setSubcommand = createSubcommand({
|
|
10
8
|
name: 'set',
|
|
11
9
|
description: 'Set a secret',
|
|
12
|
-
|
|
10
|
+
requires: { auth: true, project: true, apiClient: true },
|
|
13
11
|
schema: {
|
|
14
12
|
args: z.object({
|
|
15
13
|
key: z.string().min(1, 'key must not be empty').describe('the secret key'),
|
|
16
14
|
value: z.string().min(1, 'value must not be empty').describe('the secret value'),
|
|
17
15
|
}),
|
|
18
|
-
options: z.object({
|
|
19
|
-
dir: z.string().optional().describe('project directory (default: current directory)'),
|
|
20
|
-
}),
|
|
21
16
|
},
|
|
22
17
|
|
|
23
18
|
async handler(ctx) {
|
|
24
|
-
const { args,
|
|
25
|
-
const dir = opts?.dir ?? process.cwd();
|
|
19
|
+
const { args, apiClient, project, projectDir } = ctx;
|
|
26
20
|
|
|
27
21
|
// Validate key doesn't start with AGENTUITY_
|
|
28
22
|
if (args.key.startsWith('AGENTUITY_')) {
|
|
29
23
|
tui.fatal('Cannot set AGENTUITY_ prefixed variables. These are reserved for system use.');
|
|
30
24
|
}
|
|
31
25
|
|
|
32
|
-
// Load project config to get project ID
|
|
33
|
-
const projectConfig = await loadProjectConfig(dir);
|
|
34
|
-
if (!projectConfig) {
|
|
35
|
-
tui.fatal(`No Agentuity project found in ${dir}. Missing agentuity.json`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const apiUrl = getAPIBaseURL(config);
|
|
39
|
-
const client = new APIClient(apiUrl, config);
|
|
40
|
-
|
|
41
26
|
// Set in cloud (using secrets field)
|
|
42
27
|
await tui.spinner('Setting secret in cloud', () => {
|
|
43
|
-
return projectEnvUpdate(
|
|
44
|
-
id:
|
|
28
|
+
return projectEnvUpdate(apiClient, {
|
|
29
|
+
id: project.projectId,
|
|
45
30
|
secrets: { [args.key]: args.value },
|
|
46
31
|
});
|
|
47
32
|
});
|
|
48
33
|
|
|
49
34
|
// Update local .env.production file
|
|
50
|
-
const envFilePath = await findEnvFile(
|
|
35
|
+
const envFilePath = await findEnvFile(projectDir);
|
|
51
36
|
const currentEnv = await readEnvFile(envFilePath);
|
|
52
37
|
currentEnv[args.key] = args.value;
|
|
53
38
|
|
package/src/config.ts
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import type { Logger } from '@agentuity/core';
|
|
4
|
+
import {
|
|
5
|
+
BuildMetadataSchema,
|
|
6
|
+
type BuildMetadata,
|
|
7
|
+
getServiceUrls,
|
|
8
|
+
APIClient as ServerAPIClient,
|
|
9
|
+
} from '@agentuity/server';
|
|
1
10
|
import { YAML } from 'bun';
|
|
2
11
|
import { join, extname, basename, resolve, normalize } from 'node:path';
|
|
3
12
|
import { homedir } from 'node:os';
|
|
4
13
|
import { mkdir, readdir, readFile, writeFile, chmod } from 'node:fs/promises';
|
|
14
|
+
import JSON5 from 'json5';
|
|
5
15
|
import type { Config, Profile, AuthData } from './types';
|
|
6
|
-
import { ConfigSchema, ProjectSchema
|
|
16
|
+
import { ConfigSchema, ProjectSchema } from './types';
|
|
7
17
|
import * as tui from './tui';
|
|
8
|
-
|
|
18
|
+
|
|
19
|
+
export const defaultProfileName = 'production';
|
|
9
20
|
|
|
10
21
|
export function getDefaultConfigDir(): string {
|
|
11
22
|
return join(homedir(), '.config', 'agentuity');
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
export function getDefaultConfigPath(): string {
|
|
15
|
-
return join(getDefaultConfigDir(), '
|
|
26
|
+
return join(getDefaultConfigDir(), defaultProfileName + '.yaml');
|
|
16
27
|
}
|
|
17
28
|
|
|
18
29
|
export function getProfilePath(): string {
|
|
@@ -71,7 +82,7 @@ export async function fetchProfiles(): Promise<Profile[]> {
|
|
|
71
82
|
const content = await readFile(filePath, 'utf-8');
|
|
72
83
|
const match = nameRegex.exec(content);
|
|
73
84
|
|
|
74
|
-
if (match
|
|
85
|
+
if (match?.[1]) {
|
|
75
86
|
profiles.push({
|
|
76
87
|
name: match[1],
|
|
77
88
|
filename: filePath,
|
|
@@ -103,22 +114,24 @@ export async function loadConfig(customPath?: string): Promise<Config | null> {
|
|
|
103
114
|
try {
|
|
104
115
|
const file = Bun.file(configPath);
|
|
105
116
|
const exists = await file.exists();
|
|
117
|
+
let result: ReturnType<typeof ConfigSchema.safeParse>;
|
|
106
118
|
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
if (exists) {
|
|
120
|
+
const content = await file.text();
|
|
121
|
+
const config = YAML.parse(content);
|
|
110
122
|
|
|
111
|
-
|
|
112
|
-
|
|
123
|
+
// check to see if this is a legacy config file that might not have the required name
|
|
124
|
+
// and in this case we can just use the filename
|
|
125
|
+
const _config = config as { name?: string };
|
|
126
|
+
if (!_config.name) {
|
|
127
|
+
_config.name = basename(configPath).replace(extname(configPath), '');
|
|
128
|
+
}
|
|
113
129
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (!_config.name) {
|
|
118
|
-
_config.name = basename(configPath).replace(extname(configPath), '');
|
|
130
|
+
result = ConfigSchema.safeParse(config);
|
|
131
|
+
} else {
|
|
132
|
+
result = ConfigSchema.safeParse({ name: defaultProfileName });
|
|
119
133
|
}
|
|
120
134
|
|
|
121
|
-
const result = ConfigSchema.safeParse(config);
|
|
122
135
|
if (!result.success) {
|
|
123
136
|
tui.error(`Invalid config in ${configPath}:`);
|
|
124
137
|
for (const issue of result.error.issues) {
|
|
@@ -128,6 +141,36 @@ export async function loadConfig(customPath?: string): Promise<Config | null> {
|
|
|
128
141
|
process.exit(1);
|
|
129
142
|
}
|
|
130
143
|
|
|
144
|
+
// allow environment variables to override
|
|
145
|
+
const overrides = result.data.overrides ?? ConfigSchema.shape.overrides.parse({});
|
|
146
|
+
if (overrides) {
|
|
147
|
+
if (process.env.AGENTUITY_API_URL) {
|
|
148
|
+
overrides.api_url = process.env.AGENTUITY_API_URL;
|
|
149
|
+
}
|
|
150
|
+
if (process.env.AGENTUITY_APP_URL) {
|
|
151
|
+
overrides.app_url = process.env.AGENTUITY_APP_URL;
|
|
152
|
+
}
|
|
153
|
+
if (process.env.AGENTUITY_CATALYST_URL) {
|
|
154
|
+
overrides.catalyst_url = process.env.AGENTUITY_CATALYST_URL;
|
|
155
|
+
}
|
|
156
|
+
if (process.env.AGENTUITY_TRANSPORT_URL) {
|
|
157
|
+
overrides.transport_url = process.env.AGENTUITY_TRANSPORT_URL;
|
|
158
|
+
}
|
|
159
|
+
if (process.env.AGENTUITY_KEYVALUE_URL) {
|
|
160
|
+
overrides.kv_url = process.env.AGENTUITY_KEYVALUE_URL;
|
|
161
|
+
}
|
|
162
|
+
if (process.env.AGENTUITY_OBJECTSTORE_URL) {
|
|
163
|
+
overrides.object_url = process.env.AGENTUITY_OBJECTSTORE_URL;
|
|
164
|
+
}
|
|
165
|
+
if (process.env.AGENTUITY_VECTOR_URL) {
|
|
166
|
+
overrides.vector_url = process.env.AGENTUITY_VECTOR_URL;
|
|
167
|
+
}
|
|
168
|
+
if (process.env.AGENTUITY_STREAM_URL) {
|
|
169
|
+
overrides.stream_url = process.env.AGENTUITY_STREAM_URL;
|
|
170
|
+
}
|
|
171
|
+
result.data.overrides = overrides;
|
|
172
|
+
}
|
|
173
|
+
|
|
131
174
|
return result.data;
|
|
132
175
|
} catch (error) {
|
|
133
176
|
if (error instanceof Error) {
|
|
@@ -239,6 +282,15 @@ export async function saveOrgId(orgId: string): Promise<void> {
|
|
|
239
282
|
}
|
|
240
283
|
|
|
241
284
|
export async function getAuth(): Promise<AuthData | null> {
|
|
285
|
+
// allow automated login from environment variables if present
|
|
286
|
+
if (process.env.AGENTUITY_CLI_API_KEY && process.env.AGENTUITY_USER_ID) {
|
|
287
|
+
return {
|
|
288
|
+
apiKey: process.env.AGENTUITY_CLI_API_KEY,
|
|
289
|
+
userId: process.env.AGENTUITY_USER_ID,
|
|
290
|
+
expires: new Date(Date.now() + 30 * 60_000),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
242
294
|
const config = await loadConfig();
|
|
243
295
|
if (!config) return null;
|
|
244
296
|
const auth = config.auth as { api_key?: string; user_id?: string; expires?: number } | undefined;
|
|
@@ -280,6 +332,81 @@ function getPlaceholderValue(schema: z.ZodTypeAny): string {
|
|
|
280
332
|
}
|
|
281
333
|
}
|
|
282
334
|
|
|
335
|
+
function extractDefaultValue(schema: z.ZodTypeAny): unknown {
|
|
336
|
+
let unwrapped = schema;
|
|
337
|
+
|
|
338
|
+
// Unwrap optional layers
|
|
339
|
+
while (unwrapped instanceof z.ZodOptional) {
|
|
340
|
+
unwrapped = (unwrapped._def as unknown as { innerType: z.ZodTypeAny }).innerType;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Check if it's a ZodDefault (has defaultValue in def or _def)
|
|
344
|
+
const checkDef = (obj: unknown): unknown => {
|
|
345
|
+
if (typeof obj !== 'object' || obj === null) return undefined;
|
|
346
|
+
const anyObj = obj as Record<string, unknown>;
|
|
347
|
+
|
|
348
|
+
// Check `def` property first (used in some Zod versions)
|
|
349
|
+
if ('def' in anyObj && typeof anyObj.def === 'object' && anyObj.def !== null) {
|
|
350
|
+
const def = anyObj.def as Record<string, unknown>;
|
|
351
|
+
if (def.type === 'default' && 'defaultValue' in def) {
|
|
352
|
+
const val = def.defaultValue;
|
|
353
|
+
return typeof val === 'function' ? (val as () => unknown)() : val;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Check `_def` property (standard Zod property)
|
|
358
|
+
if ('_def' in anyObj && typeof anyObj._def === 'object' && anyObj._def !== null) {
|
|
359
|
+
const def = anyObj._def as Record<string, unknown>;
|
|
360
|
+
if (def.type === 'default' && 'defaultValue' in def) {
|
|
361
|
+
const val = def.defaultValue;
|
|
362
|
+
return typeof val === 'function' ? (val as () => unknown)() : val;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return undefined;
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
return checkDef(unwrapped);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function getValueWithDefaults(schema: z.ZodTypeAny, providedValue: unknown): unknown {
|
|
373
|
+
// If value is explicitly provided, use it
|
|
374
|
+
if (providedValue !== undefined) {
|
|
375
|
+
return providedValue;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Try to extract default value
|
|
379
|
+
const defaultValue = extractDefaultValue(schema);
|
|
380
|
+
if (defaultValue !== undefined) {
|
|
381
|
+
return defaultValue;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// For optional fields without defaults, check if it's an object
|
|
385
|
+
let unwrapped = schema;
|
|
386
|
+
if (schema instanceof z.ZodOptional) {
|
|
387
|
+
unwrapped = (schema._def as unknown as { innerType: z.ZodTypeAny }).innerType;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// If it's an object schema, recursively populate defaults
|
|
391
|
+
if (unwrapped instanceof z.ZodObject) {
|
|
392
|
+
const shape = unwrapped.shape;
|
|
393
|
+
const result: Record<string, unknown> = {};
|
|
394
|
+
let hasAnyDefaults = false;
|
|
395
|
+
|
|
396
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
397
|
+
const fieldValue = getValueWithDefaults(fieldSchema as z.ZodTypeAny, undefined);
|
|
398
|
+
if (fieldValue !== undefined) {
|
|
399
|
+
result[key] = fieldValue;
|
|
400
|
+
hasAnyDefaults = true;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return hasAnyDefaults ? result : undefined;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
|
|
283
410
|
export function generateYAMLTemplate(name: string): string {
|
|
284
411
|
const lines: string[] = [];
|
|
285
412
|
|
|
@@ -350,15 +477,61 @@ class ProjectConfigNotFoundExpection extends Error {
|
|
|
350
477
|
|
|
351
478
|
type ProjectConfig = z.infer<typeof ProjectSchema>;
|
|
352
479
|
|
|
353
|
-
|
|
354
|
-
|
|
480
|
+
function generateJSON5WithComments(
|
|
481
|
+
schema: z.ZodObject<z.ZodRawShape>,
|
|
482
|
+
data: Record<string, unknown>
|
|
483
|
+
): string {
|
|
484
|
+
const lines: string[] = ['{'];
|
|
485
|
+
const shape = schema.shape;
|
|
486
|
+
const keys = Object.keys(shape);
|
|
487
|
+
|
|
488
|
+
for (let i = 0; i < keys.length; i++) {
|
|
489
|
+
const key = keys[i];
|
|
490
|
+
const fieldSchema = shape[key] as z.ZodTypeAny;
|
|
491
|
+
const description = getSchemaDescription(fieldSchema);
|
|
492
|
+
const providedValue = data[key];
|
|
493
|
+
|
|
494
|
+
if (description) {
|
|
495
|
+
lines.push(` // ${description}`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Get value with defaults applied
|
|
499
|
+
const valueWithDefaults = getValueWithDefaults(fieldSchema, providedValue);
|
|
500
|
+
const safeValue = valueWithDefaults === undefined ? null : valueWithDefaults;
|
|
501
|
+
const jsonValue = JSON.stringify(safeValue, null, 2).replace(/\n/g, '\n ');
|
|
502
|
+
const comma = i < keys.length - 1 ? ',' : '';
|
|
503
|
+
lines.push(` ${JSON.stringify(key)}: ${jsonValue}${comma}`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
lines.push('}');
|
|
507
|
+
return lines.join('\n');
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export async function loadProjectConfig(
|
|
511
|
+
dir: string,
|
|
512
|
+
config?: Config | null
|
|
513
|
+
): Promise<ProjectConfig> {
|
|
514
|
+
let configPath = join(dir, 'agentuity.json');
|
|
515
|
+
|
|
516
|
+
// Check for profile-specific override if config is provided
|
|
517
|
+
if (config?.name) {
|
|
518
|
+
const profileConfigPath = join(dir, `agentuity.${config.name}.json`);
|
|
519
|
+
if (await Bun.file(profileConfigPath).exists()) {
|
|
520
|
+
configPath = profileConfigPath;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
355
524
|
const file = Bun.file(configPath);
|
|
356
525
|
if (!(await file.exists())) {
|
|
526
|
+
// TODO: check to see if a valid project that was created unauthenticated
|
|
527
|
+
// and then if so:
|
|
528
|
+
// 1. if authentication, offer to import the project
|
|
529
|
+
// 2. tell them that they need to login to use the command and import the project
|
|
357
530
|
throw new ProjectConfigNotFoundExpection();
|
|
358
531
|
}
|
|
359
532
|
const text = await file.text();
|
|
360
|
-
const
|
|
361
|
-
const result = ProjectSchema.safeParse(
|
|
533
|
+
const parsedConfig = JSON5.parse(text);
|
|
534
|
+
const result = ProjectSchema.safeParse(parsedConfig);
|
|
362
535
|
if (!result.success) {
|
|
363
536
|
tui.error(`Invalid project config at ${configPath}:`);
|
|
364
537
|
for (const issue of result.error.issues) {
|
|
@@ -375,20 +548,17 @@ type InitialProjectConfig = ProjectConfig & {
|
|
|
375
548
|
};
|
|
376
549
|
|
|
377
550
|
export async function createProjectConfig(dir: string, config: InitialProjectConfig) {
|
|
378
|
-
// Create a sanitized config without the apiKey for agentuity.json
|
|
379
551
|
const { apiKey, ...sanitizedConfig } = config;
|
|
380
552
|
|
|
381
553
|
const configPath = join(dir, 'agentuity.json');
|
|
382
|
-
const
|
|
383
|
-
await
|
|
554
|
+
const json5Content = generateJSON5WithComments(ProjectSchema, sanitizedConfig);
|
|
555
|
+
await Bun.write(configPath, json5Content + '\n');
|
|
384
556
|
|
|
385
|
-
// Write SDK key to .env with comment
|
|
386
557
|
const envPath = join(dir, '.env');
|
|
387
558
|
const comment =
|
|
388
559
|
'# AGENTUITY_SDK_KEY is a sensitive value and should not be committed to version control.';
|
|
389
560
|
const content = `${comment}\nAGENTUITY_SDK_KEY=${apiKey}\n`;
|
|
390
561
|
await Bun.write(envPath, content);
|
|
391
|
-
// Set restrictive permissions (owner read/write only) to protect sensitive key
|
|
392
562
|
await chmod(envPath, 0o600);
|
|
393
563
|
}
|
|
394
564
|
|
|
@@ -411,3 +581,33 @@ export async function loadBuildMetadata(dir: string): Promise<BuildMetadata> {
|
|
|
411
581
|
}
|
|
412
582
|
return result.data;
|
|
413
583
|
}
|
|
584
|
+
|
|
585
|
+
export async function loadDevelopmentProjectSDKKey(
|
|
586
|
+
projectDir: string
|
|
587
|
+
): Promise<string | undefined> {
|
|
588
|
+
const files: string[] = ['.env.development', '.env.local', '.env'];
|
|
589
|
+
for (const filename of files) {
|
|
590
|
+
const fn = join(projectDir, filename);
|
|
591
|
+
if (existsSync(fn)) {
|
|
592
|
+
const buf = await Bun.file(fn).text();
|
|
593
|
+
const tok = buf.split(/\n/);
|
|
594
|
+
for (const t of tok) {
|
|
595
|
+
if (t.charAt(0) !== '#' && t.startsWith('AGENTUITY_SDK_KEY=')) {
|
|
596
|
+
const i = t.indexOf('=');
|
|
597
|
+
return t.substring(i + 1).trim();
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export function getCatalystAPIClient(config: Config | null, logger: Logger, auth: AuthData) {
|
|
605
|
+
const serviceUrls = getServiceUrls();
|
|
606
|
+
const catalystUrl = config?.overrides?.catalyst_url ?? serviceUrls.catalyst;
|
|
607
|
+
return new ServerAPIClient(catalystUrl, logger, auth.apiKey);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export function getIONHost(config: Config | null) {
|
|
611
|
+
const url = new URL(config?.overrides?.ion_url ?? 'https://ion.agentuity.cloud');
|
|
612
|
+
return url.hostname;
|
|
613
|
+
}
|