@agentuity/cli 0.1.14 → 0.1.16
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/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +7 -6
- package/dist/auth.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +69 -11
- package/dist/cli.js.map +1 -1
- package/dist/cmd/ai/index.d.ts.map +1 -1
- package/dist/cmd/ai/index.js +6 -1
- package/dist/cmd/ai/index.js.map +1 -1
- package/dist/cmd/ai/opencode/index.d.ts +3 -0
- package/dist/cmd/ai/opencode/index.d.ts.map +1 -0
- package/dist/cmd/ai/opencode/index.js +27 -0
- package/dist/cmd/ai/opencode/index.js.map +1 -0
- package/dist/cmd/ai/opencode/install.d.ts +3 -0
- package/dist/cmd/ai/opencode/install.d.ts.map +1 -0
- package/dist/cmd/ai/opencode/install.js +102 -0
- package/dist/cmd/ai/opencode/install.js.map +1 -0
- package/dist/cmd/ai/opencode/run.d.ts +3 -0
- package/dist/cmd/ai/opencode/run.d.ts.map +1 -0
- package/dist/cmd/ai/opencode/run.js +88 -0
- package/dist/cmd/ai/opencode/run.js.map +1 -0
- package/dist/cmd/ai/opencode/uninstall.d.ts +3 -0
- package/dist/cmd/ai/opencode/uninstall.d.ts.map +1 -0
- package/dist/cmd/ai/opencode/uninstall.js +82 -0
- package/dist/cmd/ai/opencode/uninstall.js.map +1 -0
- package/dist/cmd/build/vite/beacon-plugin.d.ts.map +1 -1
- package/dist/cmd/build/vite/beacon-plugin.js.map +1 -1
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +1 -1
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/cloud/env/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/env/delete.js +87 -34
- package/dist/cmd/cloud/env/delete.js.map +1 -1
- package/dist/cmd/cloud/env/get.d.ts.map +1 -1
- package/dist/cmd/cloud/env/get.js +50 -16
- package/dist/cmd/cloud/env/get.js.map +1 -1
- package/dist/cmd/cloud/env/import.d.ts.map +1 -1
- package/dist/cmd/cloud/env/import.js +76 -32
- package/dist/cmd/cloud/env/import.js.map +1 -1
- package/dist/cmd/cloud/env/index.d.ts.map +1 -1
- package/dist/cmd/cloud/env/index.js +6 -2
- package/dist/cmd/cloud/env/index.js.map +1 -1
- package/dist/cmd/cloud/env/list.d.ts.map +1 -1
- package/dist/cmd/cloud/env/list.js +94 -23
- package/dist/cmd/cloud/env/list.js.map +1 -1
- package/dist/cmd/cloud/env/org-util.d.ts +16 -0
- package/dist/cmd/cloud/env/org-util.d.ts.map +1 -0
- package/dist/cmd/cloud/env/org-util.js +28 -0
- package/dist/cmd/cloud/env/org-util.js.map +1 -0
- package/dist/cmd/cloud/env/pull.d.ts.map +1 -1
- package/dist/cmd/cloud/env/pull.js +61 -29
- package/dist/cmd/cloud/env/pull.js.map +1 -1
- package/dist/cmd/cloud/env/push.d.ts.map +1 -1
- package/dist/cmd/cloud/env/push.js +69 -23
- package/dist/cmd/cloud/env/push.js.map +1 -1
- package/dist/cmd/cloud/env/set.d.ts.map +1 -1
- package/dist/cmd/cloud/env/set.js +69 -26
- package/dist/cmd/cloud/env/set.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.js +1 -1
- package/dist/cmd/cloud/keyvalue/create-namespace.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete-namespace.js +2 -2
- package/dist/cmd/cloud/keyvalue/delete-namespace.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/delete.js +1 -1
- package/dist/cmd/cloud/keyvalue/delete.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/get.js +1 -1
- package/dist/cmd/cloud/keyvalue/get.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/index.js +1 -1
- package/dist/cmd/cloud/keyvalue/index.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/keys.js +1 -1
- package/dist/cmd/cloud/keyvalue/keys.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/list-namespaces.js +1 -1
- package/dist/cmd/cloud/keyvalue/list-namespaces.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/repl.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/repl.js +8 -5
- package/dist/cmd/cloud/keyvalue/repl.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/search.js +1 -1
- package/dist/cmd/cloud/keyvalue/search.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/set.js +1 -1
- package/dist/cmd/cloud/keyvalue/set.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/stats.js +1 -1
- package/dist/cmd/cloud/keyvalue/stats.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/util.d.ts +4 -4
- package/dist/cmd/cloud/keyvalue/util.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/util.js +4 -9
- package/dist/cmd/cloud/keyvalue/util.js.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/create.js +20 -2
- package/dist/cmd/project/create.js.map +1 -1
- package/dist/cmd/project/download.d.ts +3 -1
- package/dist/cmd/project/download.d.ts.map +1 -1
- package/dist/cmd/project/download.js +5 -0
- package/dist/cmd/project/download.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +5 -0
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +188 -79
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/cmd/setup/index.d.ts.map +1 -1
- package/dist/cmd/setup/index.js +2 -1
- package/dist/cmd/setup/index.js.map +1 -1
- package/dist/onboarding/agentPrompt.d.ts +8 -0
- package/dist/onboarding/agentPrompt.d.ts.map +1 -0
- package/dist/onboarding/agentPrompt.js +263 -0
- package/dist/onboarding/agentPrompt.js.map +1 -0
- package/dist/schema-generator.d.ts +1 -1
- package/dist/schema-generator.d.ts.map +1 -1
- package/dist/schema-parser.d.ts +1 -1
- package/dist/schema-parser.d.ts.map +1 -1
- package/dist/schema-parser.js +36 -1
- package/dist/schema-parser.js.map +1 -1
- package/dist/tui/prompt.d.ts.map +1 -1
- package/dist/tui/prompt.js +7 -1
- package/dist/tui/prompt.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +91 -28
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +7 -7
- package/src/auth.ts +7 -6
- package/src/cli.ts +84 -11
- package/src/cmd/ai/index.ts +6 -1
- package/src/cmd/ai/opencode/index.ts +28 -0
- package/src/cmd/ai/opencode/install.ts +120 -0
- package/src/cmd/ai/opencode/run.ts +103 -0
- package/src/cmd/ai/opencode/uninstall.ts +90 -0
- package/src/cmd/build/vite/beacon-plugin.ts +3 -1
- package/src/cmd/build/vite/vite-builder.ts +5 -1
- package/src/cmd/cloud/env/delete.ts +100 -41
- package/src/cmd/cloud/env/get.ts +53 -16
- package/src/cmd/cloud/env/import.ts +86 -37
- package/src/cmd/cloud/env/index.ts +6 -2
- package/src/cmd/cloud/env/list.ts +102 -27
- package/src/cmd/cloud/env/org-util.ts +37 -0
- package/src/cmd/cloud/env/pull.ts +67 -31
- package/src/cmd/cloud/env/push.ts +81 -28
- package/src/cmd/cloud/env/set.ts +82 -33
- package/src/cmd/cloud/keyvalue/create-namespace.ts +1 -1
- package/src/cmd/cloud/keyvalue/delete-namespace.ts +2 -2
- package/src/cmd/cloud/keyvalue/delete.ts +1 -1
- package/src/cmd/cloud/keyvalue/get.ts +1 -1
- package/src/cmd/cloud/keyvalue/index.ts +1 -1
- package/src/cmd/cloud/keyvalue/keys.ts +1 -1
- package/src/cmd/cloud/keyvalue/list-namespaces.ts +1 -1
- package/src/cmd/cloud/keyvalue/repl.ts +8 -5
- package/src/cmd/cloud/keyvalue/search.ts +1 -1
- package/src/cmd/cloud/keyvalue/set.ts +1 -1
- package/src/cmd/cloud/keyvalue/stats.ts +1 -1
- package/src/cmd/cloud/keyvalue/util.ts +8 -17
- package/src/cmd/project/create.ts +21 -2
- package/src/cmd/project/download.ts +7 -1
- package/src/cmd/project/template-flow.ts +215 -80
- package/src/cmd/setup/index.ts +2 -1
- package/src/onboarding/agentPrompt.ts +263 -0
- package/src/schema-generator.ts +1 -1
- package/src/schema-parser.ts +42 -3
- package/src/tui/prompt.ts +10 -3
- package/src/tui.ts +95 -31
- package/src/types.ts +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createSubcommand } from '../../../types';
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
|
-
import { projectEnvDelete, projectGet } from '@agentuity/server';
|
|
4
|
+
import { projectEnvDelete, projectGet, orgEnvDelete, orgEnvGet } from '@agentuity/server';
|
|
5
5
|
import {
|
|
6
6
|
findExistingEnvFile,
|
|
7
7
|
readEnvFile,
|
|
@@ -11,34 +11,50 @@ import {
|
|
|
11
11
|
} from '../../../env-util';
|
|
12
12
|
import { getCommand } from '../../../command-prefix';
|
|
13
13
|
import { ErrorCode } from '../../../errors';
|
|
14
|
+
import { resolveOrgId, isOrgScope } from './org-util';
|
|
14
15
|
|
|
15
16
|
const EnvDeleteResponseSchema = z.object({
|
|
16
17
|
success: z.boolean().describe('Whether the operation succeeded'),
|
|
17
18
|
key: z.string().describe('Variable key that was deleted'),
|
|
18
|
-
path: z.string().describe('Local file path where variable was removed'),
|
|
19
|
+
path: z.string().optional().describe('Local file path where variable was removed (project scope only)'),
|
|
19
20
|
secret: z.boolean().describe('Whether a secret was deleted'),
|
|
21
|
+
scope: z.enum(['project', 'org']).describe('The scope from which the variable was deleted'),
|
|
20
22
|
});
|
|
21
23
|
|
|
22
24
|
export const deleteSubcommand = createSubcommand({
|
|
23
25
|
name: 'delete',
|
|
24
26
|
aliases: ['del', 'remove', 'rm'],
|
|
25
27
|
description: 'Delete an environment variable or secret',
|
|
26
|
-
tags: ['destructive', 'deletes-resource', 'slow', 'requires-auth'
|
|
28
|
+
tags: ['destructive', 'deletes-resource', 'slow', 'requires-auth'],
|
|
27
29
|
idempotent: true,
|
|
28
30
|
examples: [
|
|
29
31
|
{ command: getCommand('env delete OLD_FEATURE_FLAG'), description: 'Delete variable' },
|
|
30
32
|
{ command: getCommand('env rm API_KEY'), description: 'Delete a secret' },
|
|
33
|
+
{ command: getCommand('env rm OPENAI_API_KEY --org'), description: 'Delete org-level secret' },
|
|
31
34
|
],
|
|
32
|
-
requires: { auth: true,
|
|
35
|
+
requires: { auth: true, apiClient: true },
|
|
36
|
+
optional: { project: true },
|
|
33
37
|
schema: {
|
|
34
38
|
args: z.object({
|
|
35
39
|
key: z.string().describe('the variable or secret key to delete'),
|
|
36
40
|
}),
|
|
41
|
+
options: z.object({
|
|
42
|
+
org: z
|
|
43
|
+
.union([z.boolean(), z.string()])
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('delete from organization level (use --org for default org, or --org <orgId> for specific org)'),
|
|
46
|
+
}),
|
|
37
47
|
response: EnvDeleteResponseSchema,
|
|
38
48
|
},
|
|
39
49
|
|
|
40
50
|
async handler(ctx) {
|
|
41
|
-
const { args, project, projectDir, apiClient } = ctx;
|
|
51
|
+
const { args, project, projectDir, apiClient, config, opts } = ctx;
|
|
52
|
+
const useOrgScope = isOrgScope(opts?.org);
|
|
53
|
+
|
|
54
|
+
// Require project context if not using org scope
|
|
55
|
+
if (!useOrgScope && !project) {
|
|
56
|
+
tui.fatal('Project context required. Run from a project directory or use --org for organization scope.');
|
|
57
|
+
}
|
|
42
58
|
|
|
43
59
|
// Validate key doesn't start with reserved AGENTUITY_ prefix (except AGENTUITY_PUBLIC_)
|
|
44
60
|
if (isReservedAgentuityKey(args.key)) {
|
|
@@ -47,45 +63,88 @@ export const deleteSubcommand = createSubcommand({
|
|
|
47
63
|
);
|
|
48
64
|
}
|
|
49
65
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
66
|
+
if (useOrgScope) {
|
|
67
|
+
// Organization scope
|
|
68
|
+
const orgId = await resolveOrgId(apiClient, config, opts!.org!);
|
|
54
69
|
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
// First, determine if this key exists in env or secrets
|
|
71
|
+
const orgData = await tui.spinner('Checking organization variable', () => {
|
|
72
|
+
return orgEnvGet(apiClient, { id: orgId, mask: true });
|
|
73
|
+
});
|
|
57
74
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
75
|
+
const isSecret = orgData.secrets?.[args.key] !== undefined;
|
|
76
|
+
const isEnv = orgData.env?.[args.key] !== undefined;
|
|
77
|
+
|
|
78
|
+
if (!isSecret && !isEnv) {
|
|
79
|
+
tui.fatal(`Variable '${args.key}' not found in organization`, ErrorCode.RESOURCE_NOT_FOUND);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Delete from cloud
|
|
83
|
+
const label = isSecret ? 'secret' : 'environment variable';
|
|
84
|
+
await tui.spinner(`Deleting organization ${label} from cloud`, () => {
|
|
85
|
+
return orgEnvDelete(apiClient, {
|
|
86
|
+
id: orgId,
|
|
87
|
+
...(isSecret ? { secrets: [args.key] } : { env: [args.key] }),
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
tui.success(
|
|
92
|
+
`Organization ${isSecret ? 'secret' : 'environment variable'} '${args.key}' deleted successfully`
|
|
93
|
+
);
|
|
61
94
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
95
|
+
return {
|
|
96
|
+
success: true,
|
|
97
|
+
key: args.key,
|
|
98
|
+
secret: isSecret,
|
|
99
|
+
scope: 'org' as const,
|
|
100
|
+
};
|
|
101
|
+
} else {
|
|
102
|
+
// Project scope (existing behavior)
|
|
103
|
+
const projectData = await tui.spinner('Checking variable', () => {
|
|
104
|
+
return projectGet(apiClient, { id: project!.projectId, mask: true });
|
|
68
105
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
106
|
+
|
|
107
|
+
const isSecret = projectData.secrets?.[args.key] !== undefined;
|
|
108
|
+
const isEnv = projectData.env?.[args.key] !== undefined;
|
|
109
|
+
|
|
110
|
+
if (!isSecret && !isEnv) {
|
|
111
|
+
tui.fatal(`Variable '${args.key}' not found`, ErrorCode.RESOURCE_NOT_FOUND);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Delete from cloud using the correct field
|
|
115
|
+
const label = isSecret ? 'secret' : 'environment variable';
|
|
116
|
+
await tui.spinner(`Deleting ${label} from cloud`, () => {
|
|
117
|
+
return projectEnvDelete(apiClient, {
|
|
118
|
+
id: project!.projectId,
|
|
119
|
+
...(isSecret ? { secrets: [args.key] } : { env: [args.key] }),
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Update local .env file only if we have a project directory
|
|
124
|
+
// (not when using --project-id without being in a project folder)
|
|
125
|
+
let envFilePath: string | undefined;
|
|
126
|
+
if (projectDir) {
|
|
127
|
+
envFilePath = await findExistingEnvFile(projectDir);
|
|
128
|
+
const currentEnv = await readEnvFile(envFilePath);
|
|
129
|
+
delete currentEnv[args.key];
|
|
130
|
+
|
|
131
|
+
// Filter out AGENTUITY_ keys before writing
|
|
132
|
+
const filteredEnv = filterAgentuitySdkKeys(currentEnv);
|
|
133
|
+
await writeEnvFile(envFilePath, filteredEnv);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const successMsg = envFilePath
|
|
137
|
+
? `${isSecret ? 'Secret' : 'Environment variable'} '${args.key}' deleted successfully (cloud + ${envFilePath})`
|
|
138
|
+
: `${isSecret ? 'Secret' : 'Environment variable'} '${args.key}' deleted successfully (cloud only)`;
|
|
139
|
+
tui.success(successMsg);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
success: true,
|
|
143
|
+
key: args.key,
|
|
144
|
+
path: envFilePath,
|
|
145
|
+
secret: isSecret,
|
|
146
|
+
scope: 'project' as const,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
90
149
|
},
|
|
91
150
|
});
|
package/src/cmd/cloud/env/get.ts
CHANGED
|
@@ -1,55 +1,90 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createSubcommand } from '../../../types';
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
|
-
import { projectGet } from '@agentuity/server';
|
|
4
|
+
import { projectGet, orgEnvGet } from '@agentuity/server';
|
|
5
5
|
import { getCommand } from '../../../command-prefix';
|
|
6
6
|
import { ErrorCode } from '../../../errors';
|
|
7
|
+
import { resolveOrgId, isOrgScope } from './org-util';
|
|
7
8
|
|
|
8
9
|
const EnvGetResponseSchema = z.object({
|
|
9
10
|
key: z.string().describe('Environment variable key name'),
|
|
10
11
|
value: z.string().describe('Environment variable value'),
|
|
11
12
|
secret: z.boolean().describe('Whether the value is stored as a secret'),
|
|
13
|
+
scope: z.enum(['project', 'org']).describe('The scope where the variable was found'),
|
|
12
14
|
});
|
|
13
15
|
|
|
14
16
|
export const getSubcommand = createSubcommand({
|
|
15
17
|
name: 'get',
|
|
16
18
|
description: 'Get an environment variable or secret value',
|
|
17
|
-
tags: ['read-only', 'fast', 'requires-auth'
|
|
19
|
+
tags: ['read-only', 'fast', 'requires-auth'],
|
|
18
20
|
examples: [
|
|
19
21
|
{ command: getCommand('env get NODE_ENV'), description: 'Get environment variable' },
|
|
20
22
|
{ command: getCommand('env get API_KEY'), description: 'Get a secret value' },
|
|
21
23
|
{ command: getCommand('env get API_KEY --no-mask'), description: 'Show unmasked value' },
|
|
24
|
+
{ command: getCommand('env get OPENAI_API_KEY --org'), description: 'Get org-level variable' },
|
|
22
25
|
],
|
|
23
|
-
requires: { auth: true,
|
|
26
|
+
requires: { auth: true, apiClient: true },
|
|
27
|
+
optional: { project: true },
|
|
24
28
|
schema: {
|
|
25
29
|
args: z.object({
|
|
26
30
|
key: z.string().describe('the environment variable or secret key'),
|
|
27
31
|
}),
|
|
28
32
|
options: z.object({
|
|
29
33
|
maskSecret: z.boolean().optional().describe('mask the secret value in output'),
|
|
34
|
+
org: z
|
|
35
|
+
.union([z.boolean(), z.string()])
|
|
36
|
+
.optional()
|
|
37
|
+
.describe('get from organization level (use --org for default org, or --org <orgId> for specific org)'),
|
|
30
38
|
}),
|
|
31
39
|
response: EnvGetResponseSchema,
|
|
32
40
|
},
|
|
33
41
|
idempotent: true,
|
|
34
42
|
|
|
35
43
|
async handler(ctx) {
|
|
36
|
-
const { args, opts, apiClient, project, options } = ctx;
|
|
44
|
+
const { args, opts, apiClient, project, options, config } = ctx;
|
|
45
|
+
const useOrgScope = isOrgScope(opts?.org);
|
|
37
46
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
47
|
+
// Require project context if not using org scope
|
|
48
|
+
if (!useOrgScope && !project) {
|
|
49
|
+
tui.fatal('Project context required. Run from a project directory or use --org for organization scope.');
|
|
50
|
+
}
|
|
42
51
|
|
|
43
|
-
// Look for the key in both env and secrets
|
|
44
52
|
let value: string | undefined;
|
|
45
53
|
let isSecret = false;
|
|
54
|
+
let scope: 'project' | 'org';
|
|
55
|
+
|
|
56
|
+
if (useOrgScope) {
|
|
57
|
+
// Organization scope
|
|
58
|
+
const orgId = await resolveOrgId(apiClient, config, opts!.org!);
|
|
59
|
+
|
|
60
|
+
const orgData = await tui.spinner('Fetching organization variable', () => {
|
|
61
|
+
return orgEnvGet(apiClient, { id: orgId, mask: false });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (orgData.secrets?.[args.key] !== undefined) {
|
|
65
|
+
value = orgData.secrets[args.key];
|
|
66
|
+
isSecret = true;
|
|
67
|
+
} else if (orgData.env?.[args.key] !== undefined) {
|
|
68
|
+
value = orgData.env[args.key];
|
|
69
|
+
isSecret = false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
scope = 'org';
|
|
73
|
+
} else {
|
|
74
|
+
// Project scope
|
|
75
|
+
const projectData = await tui.spinner('Fetching variable', () => {
|
|
76
|
+
return projectGet(apiClient, { id: project!.projectId, mask: false });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (projectData.secrets?.[args.key] !== undefined) {
|
|
80
|
+
value = projectData.secrets[args.key];
|
|
81
|
+
isSecret = true;
|
|
82
|
+
} else if (projectData.env?.[args.key] !== undefined) {
|
|
83
|
+
value = projectData.env[args.key];
|
|
84
|
+
isSecret = false;
|
|
85
|
+
}
|
|
46
86
|
|
|
47
|
-
|
|
48
|
-
value = projectData.secrets[args.key];
|
|
49
|
-
isSecret = true;
|
|
50
|
-
} else if (projectData.env?.[args.key] !== undefined) {
|
|
51
|
-
value = projectData.env[args.key];
|
|
52
|
-
isSecret = false;
|
|
87
|
+
scope = 'project';
|
|
53
88
|
}
|
|
54
89
|
|
|
55
90
|
if (value === undefined) {
|
|
@@ -62,13 +97,15 @@ export const getSubcommand = createSubcommand({
|
|
|
62
97
|
if (!options.json) {
|
|
63
98
|
const displayValue = shouldMask ? tui.maskSecret(value) : value;
|
|
64
99
|
const typeLabel = isSecret ? ' (secret)' : '';
|
|
65
|
-
|
|
100
|
+
const scopeLabel = useOrgScope ? ' [org]' : '';
|
|
101
|
+
tui.success(`${args.key}=${displayValue}${typeLabel}${scopeLabel}`);
|
|
66
102
|
}
|
|
67
103
|
|
|
68
104
|
return {
|
|
69
105
|
key: args.key,
|
|
70
106
|
value,
|
|
71
107
|
secret: isSecret,
|
|
108
|
+
scope,
|
|
72
109
|
};
|
|
73
110
|
},
|
|
74
111
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createSubcommand } from '../../../types';
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
|
-
import { projectEnvUpdate } from '@agentuity/server';
|
|
4
|
+
import { projectEnvUpdate, orgEnvUpdate } from '@agentuity/server';
|
|
5
5
|
import {
|
|
6
6
|
findExistingEnvFile,
|
|
7
7
|
readEnvFile,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isReservedAgentuityKey,
|
|
14
14
|
} from '../../../env-util';
|
|
15
15
|
import { getCommand } from '../../../command-prefix';
|
|
16
|
+
import { resolveOrgId, isOrgScope } from './org-util';
|
|
16
17
|
|
|
17
18
|
const EnvImportResponseSchema = z.object({
|
|
18
19
|
success: z.boolean().describe('Whether import succeeded'),
|
|
@@ -20,8 +21,9 @@ const EnvImportResponseSchema = z.object({
|
|
|
20
21
|
envCount: z.number().describe('Number of env vars imported'),
|
|
21
22
|
secretCount: z.number().describe('Number of secrets imported'),
|
|
22
23
|
skipped: z.number().describe('Number of items skipped'),
|
|
23
|
-
path: z.string().describe('Local file path where variables were saved'),
|
|
24
|
+
path: z.string().optional().describe('Local file path where variables were saved (project scope only)'),
|
|
24
25
|
file: z.string().describe('Source file path'),
|
|
26
|
+
scope: z.enum(['project', 'org']).describe('The scope where variables were imported'),
|
|
25
27
|
});
|
|
26
28
|
|
|
27
29
|
export const importSubcommand = createSubcommand({
|
|
@@ -33,7 +35,6 @@ export const importSubcommand = createSubcommand({
|
|
|
33
35
|
'slow',
|
|
34
36
|
'api-intensive',
|
|
35
37
|
'requires-auth',
|
|
36
|
-
'requires-project',
|
|
37
38
|
],
|
|
38
39
|
examples: [
|
|
39
40
|
{
|
|
@@ -44,18 +45,35 @@ export const importSubcommand = createSubcommand({
|
|
|
44
45
|
command: getCommand('cloud env import .env.local'),
|
|
45
46
|
description: 'Import from .env.local file',
|
|
46
47
|
},
|
|
48
|
+
{
|
|
49
|
+
command: getCommand('cloud env import .env.shared --org'),
|
|
50
|
+
description: 'Import to organization level',
|
|
51
|
+
},
|
|
47
52
|
],
|
|
48
53
|
idempotent: false,
|
|
49
|
-
requires: { auth: true,
|
|
54
|
+
requires: { auth: true, apiClient: true },
|
|
55
|
+
optional: { project: true },
|
|
50
56
|
schema: {
|
|
51
57
|
args: z.object({
|
|
52
58
|
file: z.string().describe('path to the .env file to import'),
|
|
53
59
|
}),
|
|
60
|
+
options: z.object({
|
|
61
|
+
org: z
|
|
62
|
+
.union([z.boolean(), z.string()])
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('import to organization level (use --org for default org)'),
|
|
65
|
+
}),
|
|
54
66
|
response: EnvImportResponseSchema,
|
|
55
67
|
},
|
|
56
68
|
|
|
57
69
|
async handler(ctx) {
|
|
58
|
-
const { args, apiClient, project, projectDir } = ctx;
|
|
70
|
+
const { args, apiClient, project, projectDir, config, opts } = ctx;
|
|
71
|
+
const useOrgScope = isOrgScope(opts?.org);
|
|
72
|
+
|
|
73
|
+
// Require project context if not using org scope
|
|
74
|
+
if (!useOrgScope && !project) {
|
|
75
|
+
tui.fatal('Project context required. Run from a project directory or use --org for organization scope.');
|
|
76
|
+
}
|
|
59
77
|
|
|
60
78
|
// Read the import file
|
|
61
79
|
const importedVars = await readEnvFile(args.file);
|
|
@@ -68,8 +86,8 @@ export const importSubcommand = createSubcommand({
|
|
|
68
86
|
envCount: 0,
|
|
69
87
|
secretCount: 0,
|
|
70
88
|
skipped: 0,
|
|
71
|
-
path: '',
|
|
72
89
|
file: args.file,
|
|
90
|
+
scope: useOrgScope ? 'org' as const : 'project' as const,
|
|
73
91
|
};
|
|
74
92
|
}
|
|
75
93
|
|
|
@@ -84,8 +102,8 @@ export const importSubcommand = createSubcommand({
|
|
|
84
102
|
envCount: 0,
|
|
85
103
|
secretCount: 0,
|
|
86
104
|
skipped: Object.keys(importedVars).length,
|
|
87
|
-
path: '',
|
|
88
105
|
file: args.file,
|
|
106
|
+
scope: useOrgScope ? 'org' as const : 'project' as const,
|
|
89
107
|
};
|
|
90
108
|
}
|
|
91
109
|
|
|
@@ -104,40 +122,71 @@ export const importSubcommand = createSubcommand({
|
|
|
104
122
|
}
|
|
105
123
|
}
|
|
106
124
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
125
|
+
const envCount = Object.keys(env).length;
|
|
126
|
+
const secretCount = Object.keys(secrets).length;
|
|
127
|
+
const totalCount = envCount + secretCount;
|
|
128
|
+
|
|
129
|
+
if (useOrgScope) {
|
|
130
|
+
// Organization scope
|
|
131
|
+
const orgId = await resolveOrgId(apiClient, config, opts!.org!);
|
|
132
|
+
|
|
133
|
+
await tui.spinner('Importing variables to organization', () => {
|
|
134
|
+
return orgEnvUpdate(apiClient, {
|
|
135
|
+
id: orgId,
|
|
136
|
+
env,
|
|
137
|
+
secrets,
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
tui.success(
|
|
142
|
+
`Imported ${totalCount} variable${totalCount !== 1 ? 's' : ''} to organization from ${args.file} (${envCount} env, ${secretCount} secret${secretCount !== 1 ? 's' : ''})`
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
imported: totalCount,
|
|
148
|
+
envCount,
|
|
149
|
+
secretCount,
|
|
150
|
+
skipped: Object.keys(importedVars).length - totalCount,
|
|
151
|
+
file: args.file,
|
|
152
|
+
scope: 'org' as const,
|
|
153
|
+
};
|
|
154
|
+
} else {
|
|
155
|
+
// Project scope (existing behavior)
|
|
156
|
+
await tui.spinner('Importing variables to cloud', () => {
|
|
157
|
+
return projectEnvUpdate(apiClient, {
|
|
158
|
+
id: project!.projectId,
|
|
159
|
+
env,
|
|
160
|
+
secrets,
|
|
161
|
+
});
|
|
113
162
|
});
|
|
114
|
-
});
|
|
115
163
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
164
|
+
// Merge with local .env file only if we have a project directory
|
|
165
|
+
let localEnvPath: string | undefined;
|
|
166
|
+
if (projectDir) {
|
|
167
|
+
localEnvPath = await findExistingEnvFile(projectDir);
|
|
168
|
+
const localEnv = await readEnvFile(localEnvPath);
|
|
169
|
+
const mergedEnv = mergeEnvVars(localEnv, filteredVars);
|
|
120
170
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
171
|
+
await writeEnvFile(localEnvPath, mergedEnv, {
|
|
172
|
+
skipKeys: Object.keys(mergedEnv).filter(isReservedAgentuityKey),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
124
175
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
176
|
+
tui.success(
|
|
177
|
+
`Imported ${totalCount} variable${totalCount !== 1 ? 's' : ''} from ${args.file} (${envCount} env, ${secretCount} secret${secretCount !== 1 ? 's' : ''})`
|
|
178
|
+
);
|
|
128
179
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
file: args.file,
|
|
141
|
-
};
|
|
180
|
+
return {
|
|
181
|
+
success: true,
|
|
182
|
+
imported: totalCount,
|
|
183
|
+
envCount,
|
|
184
|
+
secretCount,
|
|
185
|
+
skipped: Object.keys(importedVars).length - totalCount,
|
|
186
|
+
path: localEnvPath,
|
|
187
|
+
file: args.file,
|
|
188
|
+
scope: 'project' as const,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
142
191
|
},
|
|
143
192
|
});
|
|
@@ -10,8 +10,8 @@ import { getCommand } from '../../../command-prefix';
|
|
|
10
10
|
|
|
11
11
|
export const command = createCommand({
|
|
12
12
|
name: 'env',
|
|
13
|
-
description: 'Manage environment variables and secrets for your project',
|
|
14
|
-
tags: ['fast', 'requires-auth'
|
|
13
|
+
description: 'Manage environment variables and secrets for your project or organization',
|
|
14
|
+
tags: ['fast', 'requires-auth'],
|
|
15
15
|
examples: [
|
|
16
16
|
{ command: getCommand('cloud env list'), description: 'List all variables and secrets' },
|
|
17
17
|
{
|
|
@@ -22,6 +22,10 @@ export const command = createCommand({
|
|
|
22
22
|
command: getCommand('cloud env set API_KEY "sk_..." --secret'),
|
|
23
23
|
description: 'Set a secret',
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
command: getCommand('cloud env set OPENAI_API_KEY "sk_..." --secret --org'),
|
|
27
|
+
description: 'Set an organization-wide secret',
|
|
28
|
+
},
|
|
25
29
|
],
|
|
26
30
|
subcommands: [
|
|
27
31
|
listSubcommand,
|