forked from aws/agentcore-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexit-codes.ts
More file actions
147 lines (127 loc) · 4 KB
/
Copy pathexit-codes.ts
File metadata and controls
147 lines (127 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import {
getErrorMessage,
isAccessDeniedError,
isChangesetInProgressError,
isExpiredTokenError,
isNoCredentialsError,
isStackInProgressError,
} from './errors.js';
/**
* Structured exit codes for different CLI failure categories.
* These enable programmatic distinction between failure types
* in CI/CD pipelines and wrapper scripts.
*/
export const ExitCode = {
/** Command succeeded */
SUCCESS: 0,
/** Unknown/unhandled error */
GENERAL_ERROR: 1,
/** Invalid CLI arguments or missing required flags */
INVALID_ARGS: 2,
/** AWS credentials expired or invalid */
AUTH_EXPIRED: 3,
/** IAM permission error */
ACCESS_DENIED: 4,
/** Requested agent doesn't exist */
AGENT_NOT_FOUND: 5,
/** Deployment/CloudFormation failure */
DEPLOY_FAILED: 6,
} as const;
/**
* Union type of all valid exit code values.
*/
export type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];
/**
* Determines the appropriate exit code for a given error.
*
* Checks error types in priority order:
* 1. Access denied (IAM permission errors)
* 2. Expired/invalid credentials
* 3. Missing credentials
* 4. Commander invalid argument errors
* 5. CloudFormation deployment failures
* 6. Agent not found
* 7. Default: general error
*
* @param err - The error to classify
* @returns The appropriate exit code number
*/
export function getExitCode(err: unknown): number {
// 1. Access denied errors (IAM permission issues)
if (isAccessDeniedError(err)) {
return ExitCode.ACCESS_DENIED;
}
// 2. Expired or invalid credentials
if (isExpiredTokenError(err)) {
return ExitCode.AUTH_EXPIRED;
}
// 3. Missing credentials (also an auth issue)
if (isNoCredentialsError(err)) {
return ExitCode.AUTH_EXPIRED;
}
// 4. Commander invalid argument errors
if (isCommanderInvalidArgError(err)) {
return ExitCode.INVALID_ARGS;
}
// 5. CloudFormation deployment failures
if (isStackInProgressError(err) || isChangesetInProgressError(err)) {
return ExitCode.DEPLOY_FAILED;
}
// 6. Agent not found
if (isAgentNotFoundError(err)) {
return ExitCode.AGENT_NOT_FOUND;
}
// 7. Default: general error
return ExitCode.GENERAL_ERROR;
}
/**
* Checks if an error is a Commander.js invalid argument error.
* Commander sets specific `code` and `exitCode` properties on its errors.
*/
function isCommanderInvalidArgError(err: unknown): boolean {
if (!err || typeof err !== 'object') {
return false;
}
const error = err as { code?: string; exitCode?: number };
// Commander.js sets code property for specific error types
if (
error.code === 'commander.invalidArgument' ||
error.code === 'commander.missingArgument' ||
error.code === 'commander.missingMandatoryOptionValue' ||
error.code === 'commander.optionMissingArgument'
) {
return true;
}
// Commander.js sets exitCode to 2 for argument validation errors
// combined with a Commander-specific constructor name
if (error.exitCode === 2) {
const ctorName = (err as { constructor?: { name?: string } }).constructor?.name;
if (ctorName === 'CommanderError' || ctorName === 'InvalidArgumentError') {
return true;
}
}
return false;
}
/**
* Checks if an error indicates that a requested agent was not found.
* Matches AWS ResourceNotFoundException and message-based patterns.
*/
function isAgentNotFoundError(err: unknown): boolean {
if (err && typeof err === 'object') {
const error = err as Record<string, unknown>;
// Check AWS SDK error name for ResourceNotFoundException
if (typeof error.name === 'string' && error.name === 'ResourceNotFoundException') {
return true;
}
}
const message = getErrorMessage(err).toLowerCase();
// Match patterns like "Agent 'my-agent' not found"
if (message.includes('agent') && (message.includes('not found') || message.includes('not deployed'))) {
return true;
}
// Match patterns like "No agents defined in agentcore.json"
if (message.includes('no agents defined')) {
return true;
}
return false;
}