@agentuity/cli 0.0.48 → 0.0.49
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/bin/cli.ts +26 -5
- package/dist/banner.d.ts +1 -1
- package/dist/banner.d.ts.map +1 -1
- package/dist/cli-logger.d.ts +27 -0
- package/dist/cli-logger.d.ts.map +1 -0
- package/dist/cli.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/logout.d.ts.map +1 -1
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/add.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/delete.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/index.d.ts +1 -2
- package/dist/cmd/auth/ssh/index.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/list.d.ts.map +1 -1
- package/dist/cmd/auth/whoami.d.ts.map +1 -1
- package/dist/cmd/bundle/ast.d.ts.map +1 -1
- package/dist/cmd/bundle/index.d.ts.map +1 -1
- package/dist/cmd/bundle/plugin.d.ts.map +1 -1
- package/dist/cmd/capabilities/index.d.ts +4 -0
- package/dist/cmd/capabilities/index.d.ts.map +1 -0
- package/dist/cmd/capabilities/show.d.ts +20 -0
- package/dist/cmd/capabilities/show.d.ts.map +1 -0
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/index.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/list.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/remove.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/rollback.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/show.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/undeploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/utils.d.ts +4 -2
- package/dist/cmd/cloud/deployment/utils.d.ts.map +1 -1
- package/dist/cmd/cloud/domain.d.ts.map +1 -1
- package/dist/cmd/cloud/index.d.ts.map +1 -1
- package/dist/cmd/cloud/resource/add.d.ts.map +1 -1
- package/dist/cmd/cloud/resource/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/resource/index.d.ts +1 -2
- package/dist/cmd/cloud/resource/index.d.ts.map +1 -1
- package/dist/cmd/cloud/resource/list.d.ts.map +1 -1
- package/dist/cmd/cloud/scp/download.d.ts.map +1 -1
- package/dist/cmd/cloud/scp/index.d.ts +1 -2
- package/dist/cmd/cloud/scp/index.d.ts.map +1 -1
- package/dist/cmd/cloud/scp/upload.d.ts.map +1 -1
- package/dist/cmd/cloud/ssh.d.ts.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- 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/index.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/index.d.ts.map +1 -1
- package/dist/cmd/kv/create-namespace.d.ts +3 -0
- package/dist/cmd/kv/create-namespace.d.ts.map +1 -0
- package/dist/cmd/kv/delete-namespace.d.ts +3 -0
- package/dist/cmd/kv/delete-namespace.d.ts.map +1 -0
- package/dist/cmd/kv/delete.d.ts +3 -0
- package/dist/cmd/kv/delete.d.ts.map +1 -0
- package/dist/cmd/kv/get.d.ts +3 -0
- package/dist/cmd/kv/get.d.ts.map +1 -0
- package/dist/cmd/kv/index.d.ts +2 -0
- package/dist/cmd/kv/index.d.ts.map +1 -0
- package/dist/cmd/kv/keys.d.ts +3 -0
- package/dist/cmd/kv/keys.d.ts.map +1 -0
- package/dist/cmd/kv/list-namespaces.d.ts +3 -0
- package/dist/cmd/kv/list-namespaces.d.ts.map +1 -0
- package/dist/cmd/kv/repl.d.ts +3 -0
- package/dist/cmd/kv/repl.d.ts.map +1 -0
- package/dist/cmd/kv/search.d.ts +3 -0
- package/dist/cmd/kv/search.d.ts.map +1 -0
- package/dist/cmd/kv/set.d.ts +3 -0
- package/dist/cmd/kv/set.d.ts.map +1 -0
- package/dist/cmd/kv/stats.d.ts +3 -0
- package/dist/cmd/kv/stats.d.ts.map +1 -0
- package/dist/cmd/kv/util.d.ts +8 -0
- package/dist/cmd/kv/util.d.ts.map +1 -0
- package/dist/cmd/objectstore/delete-bucket.d.ts +3 -0
- package/dist/cmd/objectstore/delete-bucket.d.ts.map +1 -0
- package/dist/cmd/objectstore/delete.d.ts +3 -0
- package/dist/cmd/objectstore/delete.d.ts.map +1 -0
- package/dist/cmd/objectstore/get.d.ts +3 -0
- package/dist/cmd/objectstore/get.d.ts.map +1 -0
- package/dist/cmd/objectstore/index.d.ts +2 -0
- package/dist/cmd/objectstore/index.d.ts.map +1 -0
- package/dist/cmd/objectstore/list-buckets.d.ts +3 -0
- package/dist/cmd/objectstore/list-buckets.d.ts.map +1 -0
- package/dist/cmd/objectstore/list-keys.d.ts +3 -0
- package/dist/cmd/objectstore/list-keys.d.ts.map +1 -0
- package/dist/cmd/objectstore/put.d.ts +3 -0
- package/dist/cmd/objectstore/put.d.ts.map +1 -0
- package/dist/cmd/objectstore/repl.d.ts +3 -0
- package/dist/cmd/objectstore/repl.d.ts.map +1 -0
- package/dist/cmd/objectstore/url.d.ts +3 -0
- package/dist/cmd/objectstore/url.d.ts.map +1 -0
- package/dist/cmd/objectstore/util.d.ts +8 -0
- package/dist/cmd/objectstore/util.d.ts.map +1 -0
- package/dist/cmd/profile/create.d.ts.map +1 -1
- package/dist/cmd/profile/delete.d.ts.map +1 -1
- package/dist/cmd/profile/index.d.ts.map +1 -1
- package/dist/cmd/profile/list.d.ts +1 -2
- package/dist/cmd/profile/list.d.ts.map +1 -1
- package/dist/cmd/profile/show.d.ts.map +1 -1
- package/dist/cmd/profile/use.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/index.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 +1 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/prompt/index.d.ts +4 -0
- package/dist/cmd/prompt/index.d.ts.map +1 -0
- package/dist/cmd/prompt/llm.d.ts +3 -0
- package/dist/cmd/prompt/llm.d.ts.map +1 -0
- package/dist/cmd/repl/index.d.ts +3 -0
- package/dist/cmd/repl/index.d.ts.map +1 -0
- package/dist/cmd/schema/index.d.ts +4 -0
- package/dist/cmd/schema/index.d.ts.map +1 -0
- package/dist/cmd/schema/show.d.ts +3 -0
- package/dist/cmd/schema/show.d.ts.map +1 -0
- 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/index.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/cmd/version/index.d.ts.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/errors.d.ts +83 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/explain.d.ts +47 -0
- package/dist/explain.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/json.d.ts +3 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/output.d.ts +136 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/repl.d.ts +124 -0
- package/dist/repl.d.ts.map +1 -0
- package/dist/schema-generator.d.ts +67 -0
- package/dist/schema-generator.d.ts.map +1 -0
- package/dist/tui.d.ts +11 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/types.d.ts +65 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -4
- package/src/banner.ts +7 -7
- package/src/cli-logger.ts +80 -0
- package/src/cli.ts +186 -54
- package/src/cmd/auth/index.ts +1 -0
- package/src/cmd/auth/login.ts +7 -2
- package/src/cmd/auth/logout.ts +4 -0
- package/src/cmd/auth/signup.ts +7 -2
- package/src/cmd/auth/ssh/add.ts +20 -3
- package/src/cmd/auth/ssh/delete.ts +57 -4
- package/src/cmd/auth/ssh/index.ts +4 -3
- package/src/cmd/auth/ssh/list.ts +29 -12
- package/src/cmd/auth/whoami.ts +32 -21
- package/src/cmd/bundle/ast.ts +27 -5
- package/src/cmd/bundle/index.ts +20 -0
- package/src/cmd/bundle/plugin.ts +36 -12
- package/src/cmd/capabilities/index.ts +12 -0
- package/src/cmd/capabilities/show.ts +256 -0
- package/src/cmd/cloud/deploy.ts +54 -0
- package/src/cmd/cloud/deployment/index.ts +1 -0
- package/src/cmd/cloud/deployment/list.ts +50 -3
- package/src/cmd/cloud/deployment/remove.ts +26 -2
- package/src/cmd/cloud/deployment/rollback.ts +35 -4
- package/src/cmd/cloud/deployment/show.ts +37 -2
- package/src/cmd/cloud/deployment/undeploy.ts +12 -1
- package/src/cmd/cloud/deployment/utils.ts +5 -2
- package/src/cmd/cloud/domain.ts +3 -2
- package/src/cmd/cloud/index.ts +8 -1
- package/src/cmd/cloud/resource/add.ts +19 -0
- package/src/cmd/cloud/resource/delete.ts +24 -3
- package/src/cmd/cloud/resource/index.ts +4 -3
- package/src/cmd/cloud/resource/list.ts +36 -10
- package/src/cmd/cloud/scp/download.ts +27 -1
- package/src/cmd/cloud/scp/index.ts +4 -3
- package/src/cmd/cloud/scp/upload.ts +27 -1
- package/src/cmd/cloud/ssh.ts +12 -0
- package/src/cmd/dev/index.ts +11 -7
- package/src/cmd/dev/templates.ts +1 -1
- package/src/cmd/env/delete.ts +17 -0
- package/src/cmd/env/get.ts +17 -1
- package/src/cmd/env/import.ts +47 -3
- package/src/cmd/env/index.ts +1 -0
- package/src/cmd/env/list.ts +13 -1
- package/src/cmd/env/pull.ts +20 -0
- package/src/cmd/env/push.ts +33 -1
- package/src/cmd/env/set.ts +25 -1
- package/src/cmd/index.ts +9 -2
- package/src/cmd/kv/create-namespace.ts +45 -0
- package/src/cmd/kv/delete-namespace.ts +73 -0
- package/src/cmd/kv/delete.ts +51 -0
- package/src/cmd/kv/get.ts +65 -0
- package/src/cmd/kv/index.ts +31 -0
- package/src/cmd/kv/keys.ts +57 -0
- package/src/cmd/kv/list-namespaces.ts +43 -0
- package/src/cmd/kv/repl.ts +284 -0
- package/src/cmd/kv/search.ts +80 -0
- package/src/cmd/kv/set.ts +63 -0
- package/src/cmd/kv/stats.ts +96 -0
- package/src/cmd/kv/util.ts +32 -0
- package/src/cmd/objectstore/delete-bucket.ts +72 -0
- package/src/cmd/objectstore/delete.ts +59 -0
- package/src/cmd/objectstore/get.ts +64 -0
- package/src/cmd/objectstore/index.ts +27 -0
- package/src/cmd/objectstore/list-buckets.ts +45 -0
- package/src/cmd/objectstore/list-keys.ts +60 -0
- package/src/cmd/objectstore/put.ts +62 -0
- package/src/cmd/objectstore/repl.ts +235 -0
- package/src/cmd/objectstore/url.ts +59 -0
- package/src/cmd/objectstore/util.ts +28 -0
- package/src/cmd/profile/create.ts +28 -2
- package/src/cmd/profile/delete.ts +17 -2
- package/src/cmd/profile/index.ts +1 -0
- package/src/cmd/profile/list.ts +7 -3
- package/src/cmd/profile/show.ts +20 -5
- package/src/cmd/profile/use.ts +8 -0
- package/src/cmd/project/create.ts +31 -0
- package/src/cmd/project/delete.ts +24 -2
- package/src/cmd/project/index.ts +1 -0
- package/src/cmd/project/list.ts +23 -9
- package/src/cmd/project/show.ts +27 -8
- package/src/cmd/project/template-flow.ts +10 -6
- package/src/cmd/prompt/index.ts +12 -0
- package/src/cmd/prompt/llm.ts +368 -0
- package/src/cmd/repl/index.ts +477 -0
- package/src/cmd/schema/index.ts +12 -0
- package/src/cmd/schema/show.ts +27 -0
- package/src/cmd/secret/delete.ts +17 -0
- package/src/cmd/secret/get.ts +20 -1
- package/src/cmd/secret/import.ts +45 -2
- package/src/cmd/secret/index.ts +1 -0
- package/src/cmd/secret/list.ts +10 -1
- package/src/cmd/secret/pull.ts +20 -0
- package/src/cmd/secret/push.ts +33 -1
- package/src/cmd/secret/set.ts +20 -0
- package/src/cmd/version/index.ts +15 -2
- package/src/config.ts +17 -4
- package/src/errors.ts +222 -0
- package/src/explain.ts +126 -0
- package/src/index.ts +51 -0
- package/src/json.ts +28 -0
- package/src/output.ts +307 -0
- package/src/repl.ts +1517 -0
- package/src/schema-generator.ts +389 -0
- package/src/tui.ts +84 -13
- package/src/types.ts +62 -12
package/src/cli.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
Optional,
|
|
10
10
|
Logger,
|
|
11
11
|
AuthData,
|
|
12
|
+
GlobalOptions,
|
|
12
13
|
} from './types';
|
|
13
14
|
import { showBanner } from './banner';
|
|
14
15
|
import { requireAuth, optionalAuth, requireOrg, optionalOrg as selectOptionalOrg } from './auth';
|
|
@@ -18,6 +19,9 @@ import * as tui from './tui';
|
|
|
18
19
|
import { parseArgsSchema, parseOptionsSchema, buildValidationInput } from './schema-parser';
|
|
19
20
|
import { defaultProfileName, loadProjectConfig } from './config';
|
|
20
21
|
import { APIClient, getAPIBaseURL, type APIClient as APIClientType } from './api';
|
|
22
|
+
import { ErrorCode, ExitCode, createError, exitWithError } from './errors';
|
|
23
|
+
import { getCommand } from './command-prefix';
|
|
24
|
+
import { isValidateMode, outputValidation, type ValidationResult } from './output';
|
|
21
25
|
|
|
22
26
|
function createAPIClient(baseCtx: CommandContext, config: Config | null): APIClient {
|
|
23
27
|
try {
|
|
@@ -41,6 +45,71 @@ function createAPIClient(baseCtx: CommandContext, config: Config | null): APICli
|
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Execute handler or output validation result based on mode
|
|
50
|
+
*/
|
|
51
|
+
async function executeOrValidate(
|
|
52
|
+
ctx: CommandContext,
|
|
53
|
+
commandName: string,
|
|
54
|
+
handler?: (ctx: CommandContext) => unknown | Promise<unknown>
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
if (isValidateMode(ctx.options)) {
|
|
57
|
+
// In validate mode, just output success (validation already passed via Zod)
|
|
58
|
+
const result: ValidationResult = {
|
|
59
|
+
valid: true,
|
|
60
|
+
command: commandName,
|
|
61
|
+
};
|
|
62
|
+
outputValidation(result, ctx.options);
|
|
63
|
+
} else if (handler) {
|
|
64
|
+
// Normal execution
|
|
65
|
+
await handler(ctx);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Handle validation error - output structured result in validate mode, otherwise log and exit
|
|
71
|
+
*/
|
|
72
|
+
function handleValidationError(
|
|
73
|
+
error: unknown,
|
|
74
|
+
commandName: string,
|
|
75
|
+
baseCtx: { options: GlobalOptions; logger: Logger }
|
|
76
|
+
): never {
|
|
77
|
+
if (error && typeof error === 'object' && 'issues' in error) {
|
|
78
|
+
const issues = (error as { issues: Array<{ path: string[]; message: string }> }).issues;
|
|
79
|
+
|
|
80
|
+
if (isValidateMode(baseCtx.options)) {
|
|
81
|
+
// In validate mode, output structured validation result
|
|
82
|
+
const result: ValidationResult = {
|
|
83
|
+
valid: false,
|
|
84
|
+
command: commandName,
|
|
85
|
+
errors: issues.map((issue) => ({
|
|
86
|
+
field: issue.path?.length ? issue.path.join('.') : 'unknown',
|
|
87
|
+
message: issue.message,
|
|
88
|
+
})),
|
|
89
|
+
};
|
|
90
|
+
outputValidation(result, baseCtx.options);
|
|
91
|
+
process.exit(ExitCode.VALIDATION_ERROR);
|
|
92
|
+
} else {
|
|
93
|
+
// Use centralized error handling
|
|
94
|
+
exitWithError(
|
|
95
|
+
{
|
|
96
|
+
code: ErrorCode.VALIDATION_FAILED,
|
|
97
|
+
message: 'Validation error',
|
|
98
|
+
details: {
|
|
99
|
+
issues: issues.map((issue) => ({
|
|
100
|
+
field: issue.path?.length ? issue.path.join('.') : 'unknown',
|
|
101
|
+
message: issue.message,
|
|
102
|
+
})),
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
baseCtx.logger,
|
|
106
|
+
baseCtx.options.errorFormat ?? 'text'
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
|
|
44
113
|
type Normalized = {
|
|
45
114
|
requiresAuth: boolean;
|
|
46
115
|
optionalAuth: false | string;
|
|
@@ -97,7 +166,12 @@ function normalizeReqs(def: CommandDefinition | SubcommandDefinition): Normalize
|
|
|
97
166
|
};
|
|
98
167
|
}
|
|
99
168
|
|
|
100
|
-
function handleProjectConfigError(
|
|
169
|
+
function handleProjectConfigError(
|
|
170
|
+
error: unknown,
|
|
171
|
+
requiresProject: boolean,
|
|
172
|
+
logger: Logger,
|
|
173
|
+
errorFormat?: 'json' | 'text'
|
|
174
|
+
): never {
|
|
101
175
|
if (
|
|
102
176
|
requiresProject &&
|
|
103
177
|
error &&
|
|
@@ -105,8 +179,14 @@ function handleProjectConfigError(error: unknown, requiresProject: boolean, logg
|
|
|
105
179
|
'name' in error &&
|
|
106
180
|
error.name === 'ProjectConfigNotFoundExpection'
|
|
107
181
|
) {
|
|
108
|
-
|
|
109
|
-
'
|
|
182
|
+
exitWithError(
|
|
183
|
+
createError(ErrorCode.PROJECT_NOT_FOUND, 'Invalid project folder', undefined, [
|
|
184
|
+
'Use --dir to specify a different directory',
|
|
185
|
+
'Change to a directory containing agentuity.json',
|
|
186
|
+
`Run "${getCommand('project init')}" to create a new project`,
|
|
187
|
+
]),
|
|
188
|
+
logger,
|
|
189
|
+
errorFormat ?? 'text'
|
|
110
190
|
);
|
|
111
191
|
}
|
|
112
192
|
throw error;
|
|
@@ -117,11 +197,11 @@ export async function createCLI(version: string): Promise<Command> {
|
|
|
117
197
|
|
|
118
198
|
program
|
|
119
199
|
.name('agentuity')
|
|
120
|
-
.description('Agentuity CLI')
|
|
121
200
|
.version(version, '-V, --version', 'Display version')
|
|
122
|
-
.helpOption('-h, --help', 'Display help')
|
|
201
|
+
.helpOption('-h, --help=[json]', 'Display help (with optional JSON output)')
|
|
123
202
|
.allowUnknownOption(false)
|
|
124
|
-
.allowExcessArguments(false)
|
|
203
|
+
.allowExcessArguments(false)
|
|
204
|
+
.showHelpAfterError(true);
|
|
125
205
|
|
|
126
206
|
program
|
|
127
207
|
.option('--config <path>', 'Config file path')
|
|
@@ -133,7 +213,15 @@ export async function createCLI(version: string): Promise<Command> {
|
|
|
133
213
|
'Use a specific organization when performing operations',
|
|
134
214
|
process.env.AGENTUITY_CLOUD_ORG_ID
|
|
135
215
|
)
|
|
136
|
-
.option('--color-scheme <scheme>', 'Color scheme: light or dark')
|
|
216
|
+
.option('--color-scheme <scheme>', 'Color scheme: light or dark')
|
|
217
|
+
.option('--color <mode>', 'Color output: auto, always, never', 'auto')
|
|
218
|
+
.option('--error-format <format>', 'Error output format: json or text', 'text')
|
|
219
|
+
.option('--json', 'Output in JSON format (machine-readable)', false)
|
|
220
|
+
.option('--quiet', 'Suppress non-essential output', false)
|
|
221
|
+
.option('--no-progress', 'Disable progress indicators', false)
|
|
222
|
+
.option('--explain', 'Show what the command would do without executing', false)
|
|
223
|
+
.option('--dry-run', 'Execute command without making changes', false)
|
|
224
|
+
.option('--validate', 'Validate arguments and options without executing', false);
|
|
137
225
|
|
|
138
226
|
const skipVersionCheckOption = program.createOption(
|
|
139
227
|
'--skip-version-check',
|
|
@@ -160,7 +248,7 @@ export async function createCLI(version: string): Promise<Command> {
|
|
|
160
248
|
});
|
|
161
249
|
}
|
|
162
250
|
console.error();
|
|
163
|
-
console.error(`Run '
|
|
251
|
+
console.error(`Run '${getCommand('--help')}' for usage information.`);
|
|
164
252
|
process.exit(1);
|
|
165
253
|
});
|
|
166
254
|
|
|
@@ -173,7 +261,7 @@ export async function createCLI(version: string): Promise<Command> {
|
|
|
173
261
|
const match = str.match(/got (\d+)/);
|
|
174
262
|
if (match) {
|
|
175
263
|
write(`error: unknown command or subcommand\n`);
|
|
176
|
-
write(`\nRun '
|
|
264
|
+
write(`\nRun '${getCommand('--help')}' for available commands.\n`);
|
|
177
265
|
} else {
|
|
178
266
|
write(str);
|
|
179
267
|
}
|
|
@@ -219,7 +307,17 @@ async function resolveRegion(opts: ResolveRegionOptions): Promise<string | undef
|
|
|
219
307
|
// No regions available
|
|
220
308
|
if (regions.length === 0) {
|
|
221
309
|
if (required) {
|
|
222
|
-
|
|
310
|
+
const errorFormat = (options as Record<string, unknown>).errorFormat as
|
|
311
|
+
| 'json'
|
|
312
|
+
| 'text'
|
|
313
|
+
| undefined;
|
|
314
|
+
exitWithError(
|
|
315
|
+
createError(ErrorCode.NO_REGIONS_AVAILABLE, 'No cloud regions available', undefined, [
|
|
316
|
+
'Contact support if you need access to cloud regions',
|
|
317
|
+
]),
|
|
318
|
+
logger,
|
|
319
|
+
errorFormat ?? 'text'
|
|
320
|
+
);
|
|
223
321
|
}
|
|
224
322
|
return undefined;
|
|
225
323
|
}
|
|
@@ -231,8 +329,19 @@ async function resolveRegion(opts: ResolveRegionOptions): Promise<string | undef
|
|
|
231
329
|
if (region) {
|
|
232
330
|
const found = regions.find((r) => r.region === region);
|
|
233
331
|
if (!found) {
|
|
234
|
-
|
|
235
|
-
|
|
332
|
+
const errorFormat = (options as Record<string, unknown>).errorFormat as
|
|
333
|
+
| 'json'
|
|
334
|
+
| 'text'
|
|
335
|
+
| undefined;
|
|
336
|
+
exitWithError(
|
|
337
|
+
createError(
|
|
338
|
+
ErrorCode.REGION_NOT_FOUND,
|
|
339
|
+
`Invalid region '${region}'`,
|
|
340
|
+
{ region, availableRegions: regions.map((r) => r.region) },
|
|
341
|
+
[`Use one of: ${regions.map((r) => r.region).join(', ')}`]
|
|
342
|
+
),
|
|
343
|
+
logger,
|
|
344
|
+
errorFormat ?? 'text'
|
|
236
345
|
);
|
|
237
346
|
}
|
|
238
347
|
return region;
|
|
@@ -249,7 +358,20 @@ async function resolveRegion(opts: ResolveRegionOptions): Promise<string | undef
|
|
|
249
358
|
|
|
250
359
|
// No flag provided - handle TTY vs non-TTY
|
|
251
360
|
if (required && !process.stdin.isTTY) {
|
|
252
|
-
|
|
361
|
+
const errorFormat = (options as Record<string, unknown>).errorFormat as
|
|
362
|
+
| 'json'
|
|
363
|
+
| 'text'
|
|
364
|
+
| undefined;
|
|
365
|
+
exitWithError(
|
|
366
|
+
createError(
|
|
367
|
+
ErrorCode.REGION_REQUIRED,
|
|
368
|
+
'--region flag is required in non-interactive mode',
|
|
369
|
+
{ availableRegions: regions.map((r) => r.region) },
|
|
370
|
+
[`Use --region with one of: ${regions.map((r) => r.region).join(', ')}`]
|
|
371
|
+
),
|
|
372
|
+
logger,
|
|
373
|
+
errorFormat ?? 'text'
|
|
374
|
+
);
|
|
253
375
|
}
|
|
254
376
|
|
|
255
377
|
if (process.stdin.isTTY) {
|
|
@@ -274,6 +396,13 @@ async function registerSubcommand(
|
|
|
274
396
|
cmd.aliases(subcommand.aliases);
|
|
275
397
|
}
|
|
276
398
|
|
|
399
|
+
// Add examples to help text
|
|
400
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
401
|
+
const examples = (subcommand as any).examples as string[] | undefined;
|
|
402
|
+
if (examples && examples.length > 0) {
|
|
403
|
+
cmd.addHelpText('after', '\nExamples:\n' + examples.map((ex) => ` ${ex}`).join('\n'));
|
|
404
|
+
}
|
|
405
|
+
|
|
277
406
|
// Check if this subcommand has its own subcommands (nested subcommands)
|
|
278
407
|
const subDef = subcommand as unknown as { subcommands?: SubcommandDefinition[] };
|
|
279
408
|
if (subDef.subcommands && subDef.subcommands.length > 0) {
|
|
@@ -368,8 +497,14 @@ async function registerSubcommand(
|
|
|
368
497
|
'name' in error &&
|
|
369
498
|
error.name === 'ProjectConfigNotFoundExpection'
|
|
370
499
|
) {
|
|
371
|
-
|
|
372
|
-
'
|
|
500
|
+
exitWithError(
|
|
501
|
+
createError(ErrorCode.PROJECT_NOT_FOUND, 'Invalid project folder', undefined, [
|
|
502
|
+
'Use --dir to specify a different directory',
|
|
503
|
+
'Change to a directory containing agentuity.json',
|
|
504
|
+
`Run "${getCommand('project init')}" to create a new project`,
|
|
505
|
+
]),
|
|
506
|
+
baseCtx.logger,
|
|
507
|
+
baseCtx.options.errorFormat
|
|
373
508
|
);
|
|
374
509
|
}
|
|
375
510
|
throw error;
|
|
@@ -448,22 +583,21 @@ async function registerSubcommand(
|
|
|
448
583
|
ctx.region = region;
|
|
449
584
|
}
|
|
450
585
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
586
|
+
await executeOrValidate(
|
|
587
|
+
ctx as CommandContext,
|
|
588
|
+
`${parent.name()} ${subcommand.name}`,
|
|
589
|
+
subcommand.handler
|
|
590
|
+
);
|
|
454
591
|
} catch (error) {
|
|
455
592
|
if (error && typeof error === 'object' && 'issues' in error) {
|
|
456
|
-
|
|
457
|
-
const issues = (error as { issues: Array<{ path: string[]; message: string }> })
|
|
458
|
-
.issues;
|
|
459
|
-
for (const issue of issues) {
|
|
460
|
-
baseCtx.logger.error(
|
|
461
|
-
` ${issue.path?.length ? issue.path.join('.') + ': ' : ''}${issue.message}`
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
process.exit(1);
|
|
593
|
+
handleValidationError(error, `${parent.name()} ${subcommand.name}`, baseCtx);
|
|
465
594
|
}
|
|
466
|
-
handleProjectConfigError(
|
|
595
|
+
handleProjectConfigError(
|
|
596
|
+
error,
|
|
597
|
+
normalized.requiresProject,
|
|
598
|
+
baseCtx.logger,
|
|
599
|
+
baseCtx.options.errorFormat
|
|
600
|
+
);
|
|
467
601
|
}
|
|
468
602
|
} else {
|
|
469
603
|
const ctx: Record<string, unknown> = {
|
|
@@ -596,22 +730,21 @@ async function registerSubcommand(
|
|
|
596
730
|
ctx.region = region;
|
|
597
731
|
}
|
|
598
732
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
733
|
+
await executeOrValidate(
|
|
734
|
+
ctx as CommandContext,
|
|
735
|
+
`${parent.name()} ${subcommand.name}`,
|
|
736
|
+
subcommand.handler
|
|
737
|
+
);
|
|
602
738
|
} catch (error) {
|
|
603
739
|
if (error && typeof error === 'object' && 'issues' in error) {
|
|
604
|
-
|
|
605
|
-
const issues = (error as { issues: Array<{ path: string[]; message: string }> })
|
|
606
|
-
.issues;
|
|
607
|
-
for (const issue of issues) {
|
|
608
|
-
baseCtx.logger.error(
|
|
609
|
-
` ${issue.path?.length ? issue.path.join('.') + ': ' : ''}${issue.message}`
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
process.exit(1);
|
|
740
|
+
handleValidationError(error, `${parent.name()} ${subcommand.name}`, baseCtx);
|
|
613
741
|
}
|
|
614
|
-
handleProjectConfigError(
|
|
742
|
+
handleProjectConfigError(
|
|
743
|
+
error,
|
|
744
|
+
normalized.requiresProject,
|
|
745
|
+
baseCtx.logger,
|
|
746
|
+
baseCtx.options.errorFormat
|
|
747
|
+
);
|
|
615
748
|
}
|
|
616
749
|
} else {
|
|
617
750
|
const ctx: Record<string, unknown> = {
|
|
@@ -694,22 +827,21 @@ async function registerSubcommand(
|
|
|
694
827
|
ctx as CommandContext & { apiClient: APIClientType }
|
|
695
828
|
);
|
|
696
829
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
830
|
+
await executeOrValidate(
|
|
831
|
+
ctx as CommandContext,
|
|
832
|
+
`${parent.name()} ${subcommand.name}`,
|
|
833
|
+
subcommand.handler
|
|
834
|
+
);
|
|
700
835
|
} catch (error) {
|
|
701
836
|
if (error && typeof error === 'object' && 'issues' in error) {
|
|
702
|
-
|
|
703
|
-
const issues = (error as { issues: Array<{ path: string[]; message: string }> })
|
|
704
|
-
.issues;
|
|
705
|
-
for (const issue of issues) {
|
|
706
|
-
baseCtx.logger.error(
|
|
707
|
-
` ${issue.path?.length ? issue.path.join('.') + ': ' : ''}${issue.message}`
|
|
708
|
-
);
|
|
709
|
-
}
|
|
710
|
-
process.exit(1);
|
|
837
|
+
handleValidationError(error, `${parent.name()} ${subcommand.name}`, baseCtx);
|
|
711
838
|
}
|
|
712
|
-
handleProjectConfigError(
|
|
839
|
+
handleProjectConfigError(
|
|
840
|
+
error,
|
|
841
|
+
normalized.requiresProject,
|
|
842
|
+
baseCtx.logger,
|
|
843
|
+
baseCtx.options.errorFormat
|
|
844
|
+
);
|
|
713
845
|
}
|
|
714
846
|
} else {
|
|
715
847
|
const ctx: Record<string, unknown> = {
|
package/src/cmd/auth/index.ts
CHANGED
|
@@ -8,5 +8,6 @@ import { sshSubcommand } from './ssh';
|
|
|
8
8
|
export const command = createCommand({
|
|
9
9
|
name: 'auth',
|
|
10
10
|
description: 'Authentication and authorization related commands',
|
|
11
|
+
tags: ['read-only', 'fast'],
|
|
11
12
|
subcommands: [loginCommand, logoutCommand, signupCommand, whoamiCommand, sshSubcommand],
|
|
12
13
|
});
|
package/src/cmd/auth/login.ts
CHANGED
|
@@ -4,12 +4,17 @@ import { getAppBaseURL } from '../../api';
|
|
|
4
4
|
import { saveAuth } from '../../config';
|
|
5
5
|
import { generateLoginOTP, pollForLoginCompletion } from './api';
|
|
6
6
|
import * as tui from '../../tui';
|
|
7
|
+
import { getCommand } from '../../command-prefix';
|
|
8
|
+
import { ErrorCode } from '../../errors';
|
|
7
9
|
|
|
8
10
|
export const loginCommand = createSubcommand({
|
|
9
11
|
name: 'login',
|
|
10
12
|
description: 'Login to the Agentuity Platform using a browser-based authentication flow',
|
|
13
|
+
tags: ['mutating', 'creates-resource', 'slow', 'api-intensive'],
|
|
11
14
|
toplevel: true,
|
|
15
|
+
idempotent: false,
|
|
12
16
|
requires: { apiClient: true },
|
|
17
|
+
examples: [getCommand('auth login'), getCommand('login')],
|
|
13
18
|
async handler(ctx) {
|
|
14
19
|
const { logger, config, apiClient } = ctx;
|
|
15
20
|
|
|
@@ -78,9 +83,9 @@ export const loginCommand = createSubcommand({
|
|
|
78
83
|
error.issues.map((i) => tui.arrow(`${i.message} for ${i.path}`));
|
|
79
84
|
process.exit(1);
|
|
80
85
|
} else if (error instanceof Error) {
|
|
81
|
-
logger.fatal(`Login failed: ${error.message}
|
|
86
|
+
logger.fatal(`Login failed: ${error.message}`, ErrorCode.AUTH_FAILED);
|
|
82
87
|
} else {
|
|
83
|
-
logger.fatal('Login failed');
|
|
88
|
+
logger.fatal('Login failed', ErrorCode.AUTH_FAILED);
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
},
|
package/src/cmd/auth/logout.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { createSubcommand } from '../../types';
|
|
2
2
|
import { clearAuth } from '../../config';
|
|
3
3
|
import * as tui from '../../tui';
|
|
4
|
+
import { getCommand } from '../../command-prefix';
|
|
4
5
|
|
|
5
6
|
export const logoutCommand = createSubcommand({
|
|
6
7
|
name: 'logout',
|
|
7
8
|
description: 'Logout of the Agentuity Cloud Platform',
|
|
9
|
+
tags: ['mutating', 'deletes-resource', 'fast', 'requires-auth'],
|
|
8
10
|
toplevel: true,
|
|
11
|
+
idempotent: false,
|
|
12
|
+
examples: [getCommand('auth logout'), getCommand('logout')],
|
|
9
13
|
|
|
10
14
|
async handler() {
|
|
11
15
|
await clearAuth();
|
package/src/cmd/auth/signup.ts
CHANGED
|
@@ -3,12 +3,17 @@ import { getAppBaseURL, UpgradeRequiredError } from '@agentuity/server';
|
|
|
3
3
|
import { saveAuth } from '../../config';
|
|
4
4
|
import { generateSignupOTP, pollForSignupCompletion } from './api';
|
|
5
5
|
import * as tui from '../../tui';
|
|
6
|
+
import { getCommand } from '../../command-prefix';
|
|
7
|
+
import { ErrorCode } from '../../errors';
|
|
6
8
|
|
|
7
9
|
export const signupCommand = createSubcommand({
|
|
8
10
|
name: 'signup',
|
|
9
11
|
description: 'Create a new Agentuity Cloud Platform account',
|
|
12
|
+
tags: ['mutating', 'creates-resource', 'slow', 'api-intensive'],
|
|
10
13
|
toplevel: true,
|
|
14
|
+
idempotent: false,
|
|
11
15
|
requires: { apiClient: true },
|
|
16
|
+
examples: [getCommand('auth signup'), getCommand('signup')],
|
|
12
17
|
|
|
13
18
|
async handler(ctx) {
|
|
14
19
|
const { logger, config, apiClient } = ctx;
|
|
@@ -46,9 +51,9 @@ export const signupCommand = createSubcommand({
|
|
|
46
51
|
tui.banner('CLI Upgrade Required', bannerBody);
|
|
47
52
|
process.exit(1);
|
|
48
53
|
} else if (error instanceof Error) {
|
|
49
|
-
logger.fatal(`Signup failed: ${error.message}
|
|
54
|
+
logger.fatal(`Signup failed: ${error.message}`, ErrorCode.AUTH_FAILED);
|
|
50
55
|
} else {
|
|
51
|
-
logger.fatal('Signup failed');
|
|
56
|
+
logger.fatal('Signup failed', ErrorCode.AUTH_FAILED);
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
},
|
package/src/cmd/auth/ssh/add.ts
CHANGED
|
@@ -7,11 +7,19 @@ import { readFileSync, readdirSync, statSync } from 'fs';
|
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { homedir } from 'os';
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
+
import { ErrorCode } from '../../../errors';
|
|
10
11
|
|
|
11
12
|
const optionsSchema = z.object({
|
|
12
13
|
file: z.string().optional().describe('File containing the public key'),
|
|
13
14
|
});
|
|
14
15
|
|
|
16
|
+
const SSHAddResponseSchema = z.object({
|
|
17
|
+
success: z.boolean().describe('Whether the operation succeeded'),
|
|
18
|
+
fingerprint: z.string().describe('SSH key fingerprint'),
|
|
19
|
+
keyType: z.string().describe('SSH key type (e.g., ssh-rsa, ssh-ed25519)'),
|
|
20
|
+
added: z.number().describe('Number of keys added'),
|
|
21
|
+
});
|
|
22
|
+
|
|
15
23
|
interface SSHKeyOption {
|
|
16
24
|
path: string;
|
|
17
25
|
filename: string;
|
|
@@ -107,15 +115,24 @@ export const addCommand = createSubcommand({
|
|
|
107
115
|
name: 'add',
|
|
108
116
|
aliases: ['create'],
|
|
109
117
|
description: 'Add an SSH public key to your account (reads from file or stdin)',
|
|
118
|
+
tags: ['mutating', 'creates-resource', 'slow', 'requires-auth'],
|
|
119
|
+
idempotent: false,
|
|
110
120
|
requires: { apiClient: true, auth: true },
|
|
121
|
+
examples: [
|
|
122
|
+
getCommand('auth ssh add'),
|
|
123
|
+
getCommand('auth ssh add --file ~/.ssh/id_ed25519.pub'),
|
|
124
|
+
getCommand('auth ssh add --file ./deploy_key.pub'),
|
|
125
|
+
'cat ~/.ssh/id_rsa.pub | ' + getCommand('auth ssh add'),
|
|
126
|
+
],
|
|
111
127
|
schema: {
|
|
112
128
|
options: optionsSchema,
|
|
129
|
+
response: SSHAddResponseSchema,
|
|
113
130
|
},
|
|
114
131
|
async handler(ctx) {
|
|
115
132
|
const { logger, apiClient, opts } = ctx;
|
|
116
133
|
|
|
117
134
|
if (!apiClient) {
|
|
118
|
-
logger.fatal('API client is not available');
|
|
135
|
+
logger.fatal('API client is not available', ErrorCode.INTERNAL_ERROR);
|
|
119
136
|
}
|
|
120
137
|
|
|
121
138
|
try {
|
|
@@ -254,9 +271,9 @@ export const addCommand = createSubcommand({
|
|
|
254
271
|
} catch (error) {
|
|
255
272
|
logger.trace(error);
|
|
256
273
|
if (error instanceof Error) {
|
|
257
|
-
logger.fatal(`Failed to add SSH key: ${error.message}
|
|
274
|
+
logger.fatal(`Failed to add SSH key: ${error.message}`, ErrorCode.API_ERROR);
|
|
258
275
|
} else {
|
|
259
|
-
logger.fatal('Failed to add SSH key');
|
|
276
|
+
logger.fatal('Failed to add SSH key', ErrorCode.API_ERROR);
|
|
260
277
|
}
|
|
261
278
|
}
|
|
262
279
|
},
|
|
@@ -3,12 +3,29 @@ import { removeSSHKey, listSSHKeys } from './api';
|
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
4
|
import enquirer from 'enquirer';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
import { isExplainMode, isDryRunMode, outputExplain, outputDryRun } from '../../../explain';
|
|
7
|
+
import { getCommand } from '../../../command-prefix';
|
|
8
|
+
import { ErrorCode } from '../../../errors';
|
|
9
|
+
|
|
10
|
+
const SSHDeleteResponseSchema = z.object({
|
|
11
|
+
success: z.boolean().describe('Whether the operation succeeded'),
|
|
12
|
+
removed: z.number().describe('Number of keys removed'),
|
|
13
|
+
fingerprints: z.array(z.string()).describe('Fingerprints of removed keys'),
|
|
14
|
+
});
|
|
6
15
|
|
|
7
16
|
export const deleteCommand = createSubcommand({
|
|
8
17
|
name: 'delete',
|
|
9
18
|
aliases: ['rm', 'del', 'remove'],
|
|
10
19
|
description: 'Delete an SSH key from your account',
|
|
20
|
+
tags: ['destructive', 'deletes-resource', 'slow', 'requires-auth'],
|
|
11
21
|
requires: { apiClient: true, auth: true },
|
|
22
|
+
idempotent: false,
|
|
23
|
+
examples: [
|
|
24
|
+
getCommand('auth ssh delete'),
|
|
25
|
+
getCommand('auth ssh delete <fingerprint>'),
|
|
26
|
+
getCommand('--explain auth ssh delete abc123'),
|
|
27
|
+
getCommand('--dry-run auth ssh delete abc123'),
|
|
28
|
+
],
|
|
12
29
|
schema: {
|
|
13
30
|
args: z.object({
|
|
14
31
|
fingerprints: z.array(z.string()).optional().describe('SSH key fingerprint(s) to remove'),
|
|
@@ -16,12 +33,13 @@ export const deleteCommand = createSubcommand({
|
|
|
16
33
|
options: z.object({
|
|
17
34
|
confirm: z.boolean().default(true).describe('prompt for confirmation before deletion'),
|
|
18
35
|
}),
|
|
36
|
+
response: SSHDeleteResponseSchema,
|
|
19
37
|
},
|
|
20
38
|
async handler(ctx) {
|
|
21
|
-
const { logger, apiClient, args, opts } = ctx;
|
|
39
|
+
const { logger, apiClient, args, opts, options } = ctx;
|
|
22
40
|
|
|
23
41
|
if (!apiClient) {
|
|
24
|
-
logger.fatal('API client is not available');
|
|
42
|
+
logger.fatal('API client is not available', ErrorCode.INTERNAL_ERROR);
|
|
25
43
|
}
|
|
26
44
|
|
|
27
45
|
const shouldConfirm = process.stdin.isTTY ? opts.confirm : false;
|
|
@@ -67,6 +85,22 @@ export const deleteCommand = createSubcommand({
|
|
|
67
85
|
}
|
|
68
86
|
}
|
|
69
87
|
|
|
88
|
+
// If in explain mode, show what would happen
|
|
89
|
+
if (isExplainMode(options)) {
|
|
90
|
+
outputExplain(
|
|
91
|
+
{
|
|
92
|
+
command: 'auth ssh delete',
|
|
93
|
+
description: 'Delete SSH keys from your account',
|
|
94
|
+
steps: fingerprintsToRemove.map((fp) => ({
|
|
95
|
+
action: `Remove SSH key with fingerprint: ${fp}`,
|
|
96
|
+
})),
|
|
97
|
+
warnings: ['This action cannot be undone'],
|
|
98
|
+
},
|
|
99
|
+
options
|
|
100
|
+
);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
70
104
|
if (shouldConfirm) {
|
|
71
105
|
tui.newline();
|
|
72
106
|
const confirmed = await tui.confirm(
|
|
@@ -80,6 +114,19 @@ export const deleteCommand = createSubcommand({
|
|
|
80
114
|
}
|
|
81
115
|
}
|
|
82
116
|
|
|
117
|
+
// Handle dry-run mode
|
|
118
|
+
if (isDryRunMode(options)) {
|
|
119
|
+
for (const fingerprint of fingerprintsToRemove) {
|
|
120
|
+
outputDryRun(`Would remove SSH key: ${fingerprint}`, options);
|
|
121
|
+
}
|
|
122
|
+
tui.newline();
|
|
123
|
+
tui.info(
|
|
124
|
+
`[DRY RUN] Would remove ${fingerprintsToRemove.length} SSH key${fingerprintsToRemove.length > 1 ? 's' : ''}`
|
|
125
|
+
);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Actually execute the deletion
|
|
83
130
|
for (const fingerprint of fingerprintsToRemove) {
|
|
84
131
|
await tui.spinner(`Removing SSH key ${fingerprint}...`, () =>
|
|
85
132
|
removeSSHKey(apiClient, fingerprint)
|
|
@@ -90,12 +137,18 @@ export const deleteCommand = createSubcommand({
|
|
|
90
137
|
tui.success(
|
|
91
138
|
`Removed ${fingerprintsToRemove.length} SSH key${fingerprintsToRemove.length > 1 ? 's' : ''}`
|
|
92
139
|
);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
success: true,
|
|
143
|
+
removed: fingerprintsToRemove.length,
|
|
144
|
+
fingerprints: fingerprintsToRemove,
|
|
145
|
+
};
|
|
93
146
|
} catch (error) {
|
|
94
147
|
logger.trace(error);
|
|
95
148
|
if (error instanceof Error) {
|
|
96
|
-
logger.fatal(`Failed to remove SSH key: ${error.message}
|
|
149
|
+
logger.fatal(`Failed to remove SSH key: ${error.message}`, ErrorCode.API_ERROR);
|
|
97
150
|
} else {
|
|
98
|
-
logger.fatal('Failed to remove SSH key');
|
|
151
|
+
logger.fatal('Failed to remove SSH key', ErrorCode.API_ERROR);
|
|
99
152
|
}
|
|
100
153
|
}
|
|
101
154
|
},
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createCommand } from '../../../types';
|
|
2
2
|
import { listCommand } from './list';
|
|
3
3
|
import { addCommand } from './add';
|
|
4
4
|
import { deleteCommand } from './delete';
|
|
5
5
|
|
|
6
|
-
export const sshSubcommand
|
|
6
|
+
export const sshSubcommand = createCommand({
|
|
7
7
|
name: 'ssh',
|
|
8
8
|
description: 'Manage SSH keys',
|
|
9
|
+
tags: ['fast', 'requires-auth'],
|
|
9
10
|
subcommands: [listCommand, addCommand, deleteCommand],
|
|
10
|
-
};
|
|
11
|
+
});
|