kadi-deploy 0.19.0

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.
Files changed (52) hide show
  1. package/.env.example +6 -0
  2. package/.prettierrc +6 -0
  3. package/README.md +589 -0
  4. package/agent.json +23 -0
  5. package/index.js +11 -0
  6. package/package.json +42 -0
  7. package/quick-command.txt +92 -0
  8. package/scripts/preflight.js +458 -0
  9. package/scripts/preflight.sh +300 -0
  10. package/src/cli/bid-selector.ts +222 -0
  11. package/src/cli/colors.ts +216 -0
  12. package/src/cli/index.ts +11 -0
  13. package/src/cli/prompts.ts +190 -0
  14. package/src/cli/spinners.ts +165 -0
  15. package/src/commands/deploy-local.ts +475 -0
  16. package/src/commands/deploy.ts +1342 -0
  17. package/src/commands/down.ts +679 -0
  18. package/src/commands/index.ts +10 -0
  19. package/src/commands/lock.ts +571 -0
  20. package/src/config/agent-loader.ts +177 -0
  21. package/src/config/index.ts +9 -0
  22. package/src/display/deployment-info.ts +220 -0
  23. package/src/display/pricing.ts +137 -0
  24. package/src/display/resources.ts +234 -0
  25. package/src/enhanced-registry-manager.ts +892 -0
  26. package/src/index.ts +307 -0
  27. package/src/infrastructure/registry.ts +269 -0
  28. package/src/schemas/profiles.ts +529 -0
  29. package/src/secrets/broker-urls.ts +109 -0
  30. package/src/secrets/handshake.ts +407 -0
  31. package/src/secrets/index.ts +69 -0
  32. package/src/secrets/inject-env.ts +171 -0
  33. package/src/secrets/nonce.ts +31 -0
  34. package/src/secrets/normalize.ts +204 -0
  35. package/src/secrets/prepare.ts +152 -0
  36. package/src/secrets/validate.ts +243 -0
  37. package/src/secrets/vault.ts +80 -0
  38. package/src/types/akash.ts +116 -0
  39. package/src/types/container-registry-ability.d.ts +158 -0
  40. package/src/types/external.ts +49 -0
  41. package/src/types.ts +211 -0
  42. package/src/utils/akt-price.ts +74 -0
  43. package/tests/agent-loader.test.ts +239 -0
  44. package/tests/autonomous.test.ts +244 -0
  45. package/tests/down.test.ts +1143 -0
  46. package/tests/lock.test.ts +1148 -0
  47. package/tests/nonce.test.ts +34 -0
  48. package/tests/normalize.test.ts +270 -0
  49. package/tests/secrets-schema.test.ts +301 -0
  50. package/tests/types.test.ts +198 -0
  51. package/tsconfig.json +18 -0
  52. package/vitest.config.ts +9 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * CLI Color Utilities
3
+ *
4
+ * Provides a consistent color scheme across kadi-deploy.
5
+ * Wraps the `chalk` library with semantic color functions.
6
+ *
7
+ * @module cli/colors
8
+ */
9
+
10
+ import chalk from 'chalk';
11
+
12
+ /**
13
+ * Success message color (green)
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * console.log(success('Deployment complete!'));
18
+ * ```
19
+ */
20
+ export const success = chalk.green;
21
+
22
+ /**
23
+ * Error message color (red)
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * console.error(error('Deployment failed'));
28
+ * ```
29
+ */
30
+ export const error = chalk.red;
31
+
32
+ /**
33
+ * Warning message color (yellow)
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * console.log(warning('Certificate will expire soon'));
38
+ * ```
39
+ */
40
+ export const warning = chalk.yellow;
41
+
42
+ /**
43
+ * Info message color (blue)
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * console.log(info('Loading profile...'));
48
+ * ```
49
+ */
50
+ export const info = chalk.blue;
51
+
52
+ /**
53
+ * Dim/subtle text color (gray)
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * console.log(dim('Using default settings'));
58
+ * ```
59
+ */
60
+ export const dim = chalk.dim;
61
+
62
+ /**
63
+ * Bold text
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * console.log(bold('IMPORTANT:'), 'Read this carefully');
68
+ * ```
69
+ */
70
+ export const bold = chalk.bold;
71
+
72
+ /**
73
+ * Cyan color for highlights
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * console.log(`Deploying to ${highlight('mainnet')}`);
78
+ * ```
79
+ */
80
+ export const highlight = chalk.cyan;
81
+
82
+ /**
83
+ * Magenta color for special values
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * console.log(`DSEQ: ${special('12345')}`);
88
+ * ```
89
+ */
90
+ export const special = chalk.magenta;
91
+
92
+ /**
93
+ * Underlined text
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * console.log(underline('https://provider.akash.network'));
98
+ * ```
99
+ */
100
+ export const underline = chalk.underline;
101
+
102
+ /**
103
+ * Strikethrough text
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * console.log(strikethrough('deprecated option'));
108
+ * ```
109
+ */
110
+ export const strikethrough = chalk.strikethrough;
111
+
112
+ /**
113
+ * Formats a URL for display
114
+ *
115
+ * @param url - URL to format
116
+ * @returns Formatted URL string (cyan + underline)
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * console.log(`Visit: ${formatUrl('https://akash.network')}`);
121
+ * ```
122
+ */
123
+ export function formatUrl(url: string): string {
124
+ return underline(highlight(url));
125
+ }
126
+
127
+ /**
128
+ * Formats a key-value pair for display
129
+ *
130
+ * @param key - Key name
131
+ * @param value - Value to display
132
+ * @returns Formatted string
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * console.log(formatKeyValue('Network', 'mainnet'));
137
+ * // Output: "Network: mainnet" (with colors)
138
+ * ```
139
+ */
140
+ export function formatKeyValue(key: string, value: string | number): string {
141
+ return `${dim(key + ':')} ${value}`;
142
+ }
143
+
144
+ /**
145
+ * Formats a code/command for display
146
+ *
147
+ * @param code - Code or command string
148
+ * @returns Formatted code string (gray background)
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * console.log(`Run ${formatCode('kadi deploy --profile prod')}`);
153
+ * ```
154
+ */
155
+ export function formatCode(code: string): string {
156
+ return chalk.bgGray.white(` ${code} `);
157
+ }
158
+
159
+ /**
160
+ * Formats a price/cost value
161
+ *
162
+ * @param amount - Amount value
163
+ * @param currency - Currency symbol or code
164
+ * @returns Formatted price string (green)
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * console.log(formatPrice('10.50', 'AKT'));
169
+ * // Output: "10.50 AKT" (green)
170
+ * ```
171
+ */
172
+ export function formatPrice(amount: string | number, currency: string): string {
173
+ return success(`${amount} ${currency}`);
174
+ }
175
+
176
+ /**
177
+ * Formats a section header
178
+ *
179
+ * @param title - Section title
180
+ * @returns Formatted header string (bold + cyan)
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * console.log(formatHeader('Deployment Summary'));
185
+ * ```
186
+ */
187
+ export function formatHeader(title: string): string {
188
+ return bold(highlight(`\n${title}`));
189
+ }
190
+
191
+ /**
192
+ * Formats a list item with a bullet
193
+ *
194
+ * @param text - Item text
195
+ * @param bullet - Bullet character (defaults to '•')
196
+ * @returns Formatted list item
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * console.log(formatListItem('Service deployed'));
201
+ * console.log(formatListItem('Profile loaded', '→'));
202
+ * ```
203
+ */
204
+ export function formatListItem(text: string, bullet: string = '•'): string {
205
+ return `${dim(bullet)} ${text}`;
206
+ }
207
+
208
+ /**
209
+ * Raw chalk instance for advanced usage
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * console.log(chalk.bgBlue.white('Custom styling'));
214
+ * ```
215
+ */
216
+ export { chalk };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CLI Utilities Barrel Export
3
+ *
4
+ * Centralized export point for all CLI helper functions.
5
+ *
6
+ * @module cli
7
+ */
8
+
9
+ export * from './spinners.js';
10
+ export * from './prompts.js';
11
+ export * from './colors.js';
@@ -0,0 +1,190 @@
1
+ /**
2
+ * CLI Interactive Prompts
3
+ *
4
+ * Provides a consistent interface for user input across kadi-deploy.
5
+ * Wraps the `enquirer` library with type-safe prompt methods.
6
+ *
7
+ * @module cli/prompts
8
+ */
9
+
10
+ import enquirer from 'enquirer';
11
+
12
+ /**
13
+ * Prompts user to confirm an action (yes/no)
14
+ *
15
+ * @param message - Question to ask the user
16
+ * @param defaultValue - Default answer if user presses Enter (defaults to false)
17
+ * @returns Promise resolving to boolean (true = yes, false = no)
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const proceed = await confirmPrompt('Deploy to mainnet?', false);
22
+ * if (proceed) {
23
+ * // ... deploy ...
24
+ * }
25
+ * ```
26
+ */
27
+ export async function confirmPrompt(
28
+ message: string,
29
+ defaultValue: boolean = false
30
+ ): Promise<boolean> {
31
+ const response = await enquirer.prompt<{ confirmed: boolean }>({
32
+ type: 'confirm',
33
+ name: 'confirmed',
34
+ message,
35
+ initial: defaultValue,
36
+ });
37
+ return response.confirmed;
38
+ }
39
+
40
+ /**
41
+ * Prompts user to input text
42
+ *
43
+ * @param message - Prompt message
44
+ * @param defaultValue - Default value if user presses Enter
45
+ * @param required - Whether input is required (defaults to true)
46
+ * @returns Promise resolving to user's input string
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const projectId = await textPrompt(
51
+ * 'Enter WalletConnect Project ID:',
52
+ * undefined,
53
+ * true
54
+ * );
55
+ * ```
56
+ */
57
+ export async function textPrompt(
58
+ message: string,
59
+ defaultValue?: string,
60
+ required: boolean = true
61
+ ): Promise<string> {
62
+ const response = await enquirer.prompt<{ value: string }>({
63
+ type: 'input',
64
+ name: 'value',
65
+ message,
66
+ initial: defaultValue,
67
+ validate: required ? (input: string) => input.length > 0 || 'Input is required' : undefined,
68
+ });
69
+ return response.value;
70
+ }
71
+
72
+ /**
73
+ * Prompts user to input a password (hidden)
74
+ *
75
+ * @param message - Prompt message
76
+ * @param required - Whether input is required (defaults to true)
77
+ * @returns Promise resolving to user's password
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * const password = await passwordPrompt('Enter wallet password:');
82
+ * ```
83
+ */
84
+ export async function passwordPrompt(
85
+ message: string,
86
+ required: boolean = true
87
+ ): Promise<string> {
88
+ const response = await enquirer.prompt<{ password: string }>({
89
+ type: 'password',
90
+ name: 'password',
91
+ message,
92
+ validate: required ? (input: string) => input.length > 0 || 'Password is required' : undefined,
93
+ });
94
+ return response.password;
95
+ }
96
+
97
+ /**
98
+ * Prompts user to select from a list of choices
99
+ *
100
+ * @param message - Prompt message
101
+ * @param choices - Array of choice strings
102
+ * @param defaultChoice - Index of default choice (optional)
103
+ * @returns Promise resolving to selected choice
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const network = await selectPrompt(
108
+ * 'Select network:',
109
+ * ['mainnet', 'testnet'],
110
+ * 1
111
+ * );
112
+ * ```
113
+ */
114
+ export async function selectPrompt(
115
+ message: string,
116
+ choices: string[],
117
+ defaultChoice?: number
118
+ ): Promise<string> {
119
+ const response = await enquirer.prompt<{ selected: string }>({
120
+ type: 'select',
121
+ name: 'selected',
122
+ message,
123
+ choices,
124
+ initial: defaultChoice,
125
+ });
126
+ return response.selected;
127
+ }
128
+
129
+ /**
130
+ * Prompts user to select multiple items from a list
131
+ *
132
+ * @param message - Prompt message
133
+ * @param choices - Array of choice strings
134
+ * @param defaultChoices - Array of initially selected indices (optional)
135
+ * @returns Promise resolving to array of selected choices
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const services = await multiSelectPrompt(
140
+ * 'Select services to deploy:',
141
+ * ['api', 'web', 'worker'],
142
+ * [0, 1]
143
+ * );
144
+ * ```
145
+ */
146
+ export async function multiSelectPrompt(
147
+ message: string,
148
+ choices: string[],
149
+ defaultChoices?: number[]
150
+ ): Promise<string[]> {
151
+ const response = await enquirer.prompt<{ selected: string[] }>({
152
+ type: 'multiselect',
153
+ name: 'selected',
154
+ message,
155
+ choices,
156
+ initial: defaultChoices,
157
+ });
158
+ return response.selected;
159
+ }
160
+
161
+ /**
162
+ * Prompts user with a custom enquirer prompt
163
+ *
164
+ * Use this for advanced prompt scenarios not covered by the convenience methods.
165
+ *
166
+ * @param options - Enquirer prompt options
167
+ * @returns Promise resolving to prompt response
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * const result = await customPrompt({
172
+ * type: 'autocomplete',
173
+ * name: 'provider',
174
+ * message: 'Select provider:',
175
+ * choices: providerList
176
+ * });
177
+ * ```
178
+ */
179
+ export async function customPrompt<T = Record<string, unknown>>(
180
+ options: {
181
+ type: string;
182
+ name: string;
183
+ message: string;
184
+ choices?: string[] | { name: string; value: unknown }[];
185
+ initial?: unknown;
186
+ validate?: (value: unknown) => boolean | string;
187
+ }
188
+ ): Promise<T> {
189
+ return await enquirer.prompt<T>(options);
190
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * CLI Spinner Utilities
3
+ *
4
+ * Provides a consistent interface for progress indicators across kadi-deploy.
5
+ * Wraps the `ora` library with additional convenience methods.
6
+ *
7
+ * @module cli/spinners
8
+ */
9
+
10
+ import ora, { Ora } from 'ora';
11
+
12
+ /**
13
+ * Creates and starts a spinner with a message
14
+ *
15
+ * @param message - Initial spinner message
16
+ * @returns Ora spinner instance
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const spinner = startSpinner('Deploying to Akash...');
21
+ * // ... do work ...
22
+ * spinner.succeed('Deployed successfully!');
23
+ * ```
24
+ */
25
+ export function startSpinner(message: string): Ora {
26
+ return ora(message).start();
27
+ }
28
+
29
+ /**
30
+ * Creates a spinner without starting it
31
+ *
32
+ * Useful when you need to prepare a spinner but start it later.
33
+ *
34
+ * @param message - Spinner message
35
+ * @returns Ora spinner instance (not started)
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const spinner = createSpinner('Processing...');
40
+ * // ... some setup ...
41
+ * spinner.start();
42
+ * ```
43
+ */
44
+ export function createSpinner(message: string): Ora {
45
+ return ora(message);
46
+ }
47
+
48
+ /**
49
+ * Updates spinner message while it's running
50
+ *
51
+ * @param spinner - Active spinner instance
52
+ * @param message - New message to display
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const spinner = startSpinner('Step 1...');
57
+ * updateSpinner(spinner, 'Step 2...');
58
+ * updateSpinner(spinner, 'Step 3...');
59
+ * spinner.succeed('Complete!');
60
+ * ```
61
+ */
62
+ export function updateSpinner(spinner: Ora, message: string): void {
63
+ spinner.text = message;
64
+ }
65
+
66
+ /**
67
+ * Completes spinner with success message
68
+ *
69
+ * @param spinner - Active spinner instance
70
+ * @param message - Success message (optional)
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const spinner = startSpinner('Deploying...');
75
+ * // ... work ...
76
+ * succeedSpinner(spinner, 'Deployment complete!');
77
+ * ```
78
+ */
79
+ export function succeedSpinner(spinner: Ora, message?: string): void {
80
+ if (message) {
81
+ spinner.succeed(message);
82
+ } else {
83
+ spinner.succeed();
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Completes spinner with failure message
89
+ *
90
+ * @param spinner - Active spinner instance
91
+ * @param message - Failure message (optional)
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const spinner = startSpinner('Deploying...');
96
+ * try {
97
+ * // ... work ...
98
+ * } catch (error) {
99
+ * failSpinner(spinner, 'Deployment failed');
100
+ * }
101
+ * ```
102
+ */
103
+ export function failSpinner(spinner: Ora, message?: string): void {
104
+ if (message) {
105
+ spinner.fail(message);
106
+ } else {
107
+ spinner.fail();
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Completes spinner with warning message
113
+ *
114
+ * @param spinner - Active spinner instance
115
+ * @param message - Warning message (optional)
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const spinner = startSpinner('Checking certificate...');
120
+ * warnSpinner(spinner, 'Certificate expired, creating new one');
121
+ * ```
122
+ */
123
+ export function warnSpinner(spinner: Ora, message?: string): void {
124
+ if (message) {
125
+ spinner.warn(message);
126
+ } else {
127
+ spinner.warn();
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Completes spinner with info message
133
+ *
134
+ * @param spinner - Active spinner instance
135
+ * @param message - Info message (optional)
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const spinner = startSpinner('Loading profile...');
140
+ * infoSpinner(spinner, 'Using profile: production');
141
+ * ```
142
+ */
143
+ export function infoSpinner(spinner: Ora, message?: string): void {
144
+ if (message) {
145
+ spinner.info(message);
146
+ } else {
147
+ spinner.info();
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Stops spinner without any completion message
153
+ *
154
+ * @param spinner - Active spinner instance
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const spinner = startSpinner('Loading...');
159
+ * stopSpinner(spinner);
160
+ * console.log('Custom message here');
161
+ * ```
162
+ */
163
+ export function stopSpinner(spinner: Ora): void {
164
+ spinner.stop();
165
+ }