@agentuity/cli 0.0.43 → 0.0.44
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/tui.ts
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* Provides semantic helpers for console output with automatic icons and colors.
|
|
5
5
|
* Uses Bun's built-in color support and ANSI escape codes.
|
|
6
6
|
*/
|
|
7
|
+
import { stringWidth } from 'bun';
|
|
7
8
|
import enquirer from 'enquirer';
|
|
8
|
-
import type
|
|
9
|
+
import { type OrganizationList, projectList } from '@agentuity/server';
|
|
9
10
|
import type { ColorScheme } from './terminal';
|
|
10
|
-
import {
|
|
11
|
+
import { type APIClient as APIClientType } from './api';
|
|
12
|
+
import * as readline from 'readline';
|
|
11
13
|
|
|
12
14
|
// Icons
|
|
13
15
|
const ICONS = {
|
|
@@ -19,8 +21,13 @@ const ICONS = {
|
|
|
19
21
|
bullet: '•',
|
|
20
22
|
} as const;
|
|
21
23
|
|
|
22
|
-
function shouldUseColors(): boolean {
|
|
23
|
-
return
|
|
24
|
+
export function shouldUseColors(): boolean {
|
|
25
|
+
return (
|
|
26
|
+
!process.env.NO_COLOR &&
|
|
27
|
+
!process.env.CI &&
|
|
28
|
+
process.env.TERM !== 'dumb' &&
|
|
29
|
+
!!process.stdout.isTTY
|
|
30
|
+
);
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
// Color definitions (light/dark adaptive) using Bun.color
|
|
@@ -76,6 +83,11 @@ let currentColorScheme: ColorScheme = process.env.CI ? 'light' : 'dark';
|
|
|
76
83
|
|
|
77
84
|
export function setColorScheme(scheme: ColorScheme): void {
|
|
78
85
|
currentColorScheme = scheme;
|
|
86
|
+
process.env.COLOR_SCHEME = scheme;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function isDarkMode(): boolean {
|
|
90
|
+
return currentColorScheme === 'dark';
|
|
79
91
|
}
|
|
80
92
|
|
|
81
93
|
function getColor(colorKey: keyof ReturnType<typeof getColors>): string {
|
|
@@ -142,6 +154,15 @@ export function muted(text: string): string {
|
|
|
142
154
|
return `${color}${text}${reset}`;
|
|
143
155
|
}
|
|
144
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Format text in warn color
|
|
159
|
+
*/
|
|
160
|
+
export function warn(text: string): string {
|
|
161
|
+
const color = getColor('warning');
|
|
162
|
+
const reset = getColor('reset');
|
|
163
|
+
return `${color}${text}${reset}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
145
166
|
/**
|
|
146
167
|
* Format text in bold
|
|
147
168
|
*/
|
|
@@ -158,8 +179,8 @@ export function link(url: string, title?: string): string {
|
|
|
158
179
|
const color = getColor('link');
|
|
159
180
|
const reset = getColor('reset');
|
|
160
181
|
|
|
161
|
-
// Check if terminal supports hyperlinks (OSC 8)
|
|
162
|
-
if (supportsHyperlinks()) {
|
|
182
|
+
// Check if terminal supports hyperlinks (OSC 8) and colors are enabled
|
|
183
|
+
if (shouldUseColors() && supportsHyperlinks()) {
|
|
163
184
|
return `\x1b]8;;${url}\x07${color}${title ?? url}${reset}\x1b]8;;\x07`;
|
|
164
185
|
}
|
|
165
186
|
|
|
@@ -208,24 +229,40 @@ export function newline(): void {
|
|
|
208
229
|
console.log('');
|
|
209
230
|
}
|
|
210
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Get the display width of a string, handling ANSI codes and OSC 8 hyperlinks
|
|
234
|
+
*
|
|
235
|
+
* Note: Bun.stringWidth() counts OSC 8 hyperlink escape sequences in the width,
|
|
236
|
+
* which causes incorrect alignment. We strip OSC 8 codes first, then use Bun.stringWidth()
|
|
237
|
+
* to handle regular ANSI codes and unicode characters correctly.
|
|
238
|
+
*/
|
|
239
|
+
function getDisplayWidth(str: string): number {
|
|
240
|
+
// Remove OSC-8 hyperlink sequences using Unicode escapes (\u001b = ESC, \u0007 = BEL) to satisfy linter
|
|
241
|
+
// eslint-disable-next-line no-control-regex
|
|
242
|
+
const withoutOSC8 = str.replace(/\u001b\]8;;[^\u0007]*\u0007/g, '');
|
|
243
|
+
return Bun.stringWidth(withoutOSC8);
|
|
244
|
+
}
|
|
245
|
+
|
|
211
246
|
/**
|
|
212
247
|
* Pad a string to a specific length on the right
|
|
213
248
|
*/
|
|
214
249
|
export function padRight(str: string, length: number, pad = ' '): string {
|
|
215
|
-
|
|
250
|
+
const displayWidth = getDisplayWidth(str);
|
|
251
|
+
if (displayWidth >= length) {
|
|
216
252
|
return str;
|
|
217
253
|
}
|
|
218
|
-
return str + pad.repeat(length -
|
|
254
|
+
return str + pad.repeat(length - displayWidth);
|
|
219
255
|
}
|
|
220
256
|
|
|
221
257
|
/**
|
|
222
258
|
* Pad a string to a specific length on the left
|
|
223
259
|
*/
|
|
224
260
|
export function padLeft(str: string, length: number, pad = ' '): string {
|
|
225
|
-
|
|
261
|
+
const displayWidth = getDisplayWidth(str);
|
|
262
|
+
if (displayWidth >= length) {
|
|
226
263
|
return str;
|
|
227
264
|
}
|
|
228
|
-
return pad.repeat(length -
|
|
265
|
+
return pad.repeat(length - displayWidth) + str;
|
|
229
266
|
}
|
|
230
267
|
|
|
231
268
|
interface BannerOptions {
|
|
@@ -245,11 +282,8 @@ interface BannerOptions {
|
|
|
245
282
|
* Responsive to terminal width - adapts to narrow terminals
|
|
246
283
|
*/
|
|
247
284
|
export function banner(title: string, body: string, options?: BannerOptions): void {
|
|
248
|
-
// Get terminal width, default to
|
|
249
|
-
const termWidth = process.stdout.columns ||
|
|
250
|
-
const minWidth = options?.minWidth ?? 40;
|
|
251
|
-
const maxWidth = Math.max(minWidth, Math.min(termWidth - 2, 80)); // Between 40 and 80, with 2 char margin
|
|
252
|
-
const padding = options?.padding ?? 4;
|
|
285
|
+
// Get terminal width, default to 120 if not available
|
|
286
|
+
const termWidth = process.stdout.columns || 120;
|
|
253
287
|
|
|
254
288
|
const border = {
|
|
255
289
|
topLeft: '╭',
|
|
@@ -260,15 +294,27 @@ export function banner(title: string, body: string, options?: BannerOptions): vo
|
|
|
260
294
|
vertical: '│',
|
|
261
295
|
};
|
|
262
296
|
|
|
263
|
-
//
|
|
264
|
-
const bodyLines = wrapText(body, maxWidth - padding); // -4 for padding and borders
|
|
265
|
-
|
|
266
|
-
// Calculate width based on content
|
|
297
|
+
// Calculate content width first (before wrapping)
|
|
267
298
|
const titleWidth = getDisplayWidth(title);
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
const
|
|
271
|
-
|
|
299
|
+
const bodyLines = body.split('\n');
|
|
300
|
+
const maxBodyWidth = Math.max(0, ...bodyLines.map((line) => getDisplayWidth(line)));
|
|
301
|
+
const requiredContentWidth = Math.max(titleWidth, maxBodyWidth);
|
|
302
|
+
|
|
303
|
+
// Box width = content + borders (2) + side spaces (2)
|
|
304
|
+
const boxWidth = Math.min(requiredContentWidth + 4, termWidth);
|
|
305
|
+
|
|
306
|
+
// If required content width exceeds terminal width, skip box and print plain text
|
|
307
|
+
if (requiredContentWidth + 4 > termWidth) {
|
|
308
|
+
console.log('\n' + bold(title));
|
|
309
|
+
console.log(body + '\n');
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Inner width is box width minus borders (2) and side spaces (2)
|
|
314
|
+
const innerWidth = boxWidth - 4;
|
|
315
|
+
|
|
316
|
+
// Wrap text to fit box width
|
|
317
|
+
const wrappedBodyLines = wrapText(body, innerWidth);
|
|
272
318
|
|
|
273
319
|
// Colors
|
|
274
320
|
const borderColor = getColor('muted');
|
|
@@ -294,10 +340,7 @@ export function banner(title: string, body: string, options?: BannerOptions): vo
|
|
|
294
340
|
const titleDisplayWidth = getDisplayWidth(title);
|
|
295
341
|
if (options?.centerTitle === true || options?.centerTitle === undefined) {
|
|
296
342
|
const titlePadding = Math.max(0, Math.floor((innerWidth - titleDisplayWidth) / 2));
|
|
297
|
-
const titleRightPadding = Math.max(
|
|
298
|
-
0,
|
|
299
|
-
Math.max(0, innerWidth - titlePadding - titleDisplayWidth) - padding
|
|
300
|
-
);
|
|
343
|
+
const titleRightPadding = Math.max(0, innerWidth - titlePadding - titleDisplayWidth);
|
|
301
344
|
const titleLine =
|
|
302
345
|
' '.repeat(titlePadding) +
|
|
303
346
|
`${titleColor}${bold(title)}${reset}` +
|
|
@@ -306,7 +349,7 @@ export function banner(title: string, body: string, options?: BannerOptions): vo
|
|
|
306
349
|
`${borderColor}${border.vertical} ${reset}${titleLine}${borderColor} ${border.vertical}${reset}`
|
|
307
350
|
);
|
|
308
351
|
} else {
|
|
309
|
-
const titleRightPadding = Math.max(0,
|
|
352
|
+
const titleRightPadding = Math.max(0, innerWidth - titleDisplayWidth);
|
|
310
353
|
const titleLine = `${titleColor}${bold(title)}${reset}` + ' '.repeat(titleRightPadding);
|
|
311
354
|
lines.push(
|
|
312
355
|
`${borderColor}${border.vertical} ${reset}${titleLine}${borderColor} ${border.vertical}${reset}`
|
|
@@ -321,9 +364,9 @@ export function banner(title: string, body: string, options?: BannerOptions): vo
|
|
|
321
364
|
}
|
|
322
365
|
|
|
323
366
|
// Body lines
|
|
324
|
-
for (const line of
|
|
367
|
+
for (const line of wrappedBodyLines) {
|
|
325
368
|
const lineWidth = getDisplayWidth(line);
|
|
326
|
-
const linePadding = Math.max(0,
|
|
369
|
+
const linePadding = Math.max(0, innerWidth - lineWidth);
|
|
327
370
|
lines.push(
|
|
328
371
|
`${borderColor}${border.vertical} ${reset}${line}${' '.repeat(linePadding)}${borderColor} ${border.vertical}${reset}`
|
|
329
372
|
);
|
|
@@ -465,7 +508,7 @@ export function showSignupBenefits(): void {
|
|
|
465
508
|
];
|
|
466
509
|
|
|
467
510
|
console.log('');
|
|
468
|
-
lines.
|
|
511
|
+
lines.map((line) => console.log(CYAN + line + RESET));
|
|
469
512
|
console.log('');
|
|
470
513
|
}
|
|
471
514
|
|
|
@@ -498,7 +541,7 @@ export function showLoggedOutMessage(): void {
|
|
|
498
541
|
];
|
|
499
542
|
|
|
500
543
|
console.log('');
|
|
501
|
-
lines.filter(Boolean).
|
|
544
|
+
lines.filter(Boolean).map((line) => console.log(YELLOW + line + RESET));
|
|
502
545
|
}
|
|
503
546
|
|
|
504
547
|
/**
|
|
@@ -553,20 +596,6 @@ export async function copyToClipboard(text: string): Promise<boolean> {
|
|
|
553
596
|
}
|
|
554
597
|
}
|
|
555
598
|
|
|
556
|
-
/**
|
|
557
|
-
* Get the display width of a string, handling ANSI codes and OSC 8 hyperlinks
|
|
558
|
-
*
|
|
559
|
-
* Note: Bun.stringWidth() counts OSC 8 hyperlink escape sequences in the width,
|
|
560
|
-
* which causes incorrect alignment. We strip OSC 8 codes first, then use Bun.stringWidth()
|
|
561
|
-
* to handle regular ANSI codes and unicode characters correctly.
|
|
562
|
-
*/
|
|
563
|
-
function getDisplayWidth(str: string): number {
|
|
564
|
-
// Strip OSC 8 hyperlink sequences: \x1b]8;;URL\x07...\x1b]8;;\x07
|
|
565
|
-
// eslint-disable-next-line no-control-regex
|
|
566
|
-
const withoutOSC8 = str.replace(/\x1b\]8;;[^\x07]*\x07/g, '');
|
|
567
|
-
return Bun.stringWidth(withoutOSC8);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
599
|
/**
|
|
571
600
|
* Extract ANSI codes from the beginning of a string
|
|
572
601
|
*/
|
|
@@ -676,6 +705,11 @@ export interface SimpleSpinnerOptions<T> {
|
|
|
676
705
|
type?: 'simple';
|
|
677
706
|
message: string;
|
|
678
707
|
callback: (() => Promise<T>) | Promise<T>;
|
|
708
|
+
/**
|
|
709
|
+
* If true, clear the spinner output on success (no icon, no message)
|
|
710
|
+
* Defaults to false
|
|
711
|
+
*/
|
|
712
|
+
clearOnSuccess?: boolean;
|
|
679
713
|
}
|
|
680
714
|
|
|
681
715
|
/**
|
|
@@ -685,6 +719,11 @@ export interface ProgressSpinnerOptions<T> {
|
|
|
685
719
|
type: 'progress';
|
|
686
720
|
message: string;
|
|
687
721
|
callback: (progress: SpinnerProgressCallback) => Promise<T>;
|
|
722
|
+
/**
|
|
723
|
+
* If true, clear the spinner output on success (no icon, no message)
|
|
724
|
+
* Defaults to false
|
|
725
|
+
*/
|
|
726
|
+
clearOnSuccess?: boolean;
|
|
688
727
|
}
|
|
689
728
|
|
|
690
729
|
/**
|
|
@@ -735,7 +774,7 @@ export async function spinner<T>(
|
|
|
735
774
|
const reset = getColor('reset');
|
|
736
775
|
|
|
737
776
|
// If no TTY, just execute the callback without animation
|
|
738
|
-
if (!process.
|
|
777
|
+
if (!process.stderr.isTTY) {
|
|
739
778
|
try {
|
|
740
779
|
const result =
|
|
741
780
|
options.type === 'progress'
|
|
@@ -744,6 +783,12 @@ export async function spinner<T>(
|
|
|
744
783
|
? await options.callback()
|
|
745
784
|
: await options.callback;
|
|
746
785
|
|
|
786
|
+
// If clearOnSuccess is true, don't show success message
|
|
787
|
+
if (!options.clearOnSuccess) {
|
|
788
|
+
const successColor = getColor('success');
|
|
789
|
+
console.error(`${successColor}${ICONS.success} ${message}${reset}`);
|
|
790
|
+
}
|
|
791
|
+
|
|
747
792
|
return result;
|
|
748
793
|
} catch (err) {
|
|
749
794
|
const errorColor = getColor('error');
|
|
@@ -766,7 +811,7 @@ export async function spinner<T>(
|
|
|
766
811
|
let currentProgress: number | undefined;
|
|
767
812
|
|
|
768
813
|
// Hide cursor
|
|
769
|
-
process.
|
|
814
|
+
process.stderr.write('\x1B[?25l');
|
|
770
815
|
|
|
771
816
|
// Start animation
|
|
772
817
|
const interval = setInterval(() => {
|
|
@@ -781,7 +826,7 @@ export async function spinner<T>(
|
|
|
781
826
|
: '';
|
|
782
827
|
|
|
783
828
|
// Clear line and render
|
|
784
|
-
process.
|
|
829
|
+
process.stderr.write('\r\x1B[K' + `${frame} ${message}${progressIndicator}`);
|
|
785
830
|
frameIndex++;
|
|
786
831
|
}, 120);
|
|
787
832
|
|
|
@@ -801,27 +846,30 @@ export async function spinner<T>(
|
|
|
801
846
|
|
|
802
847
|
// Clear interval and line
|
|
803
848
|
clearInterval(interval);
|
|
804
|
-
process.
|
|
849
|
+
process.stderr.write('\r\x1B[K');
|
|
805
850
|
|
|
806
|
-
//
|
|
807
|
-
|
|
808
|
-
|
|
851
|
+
// If clearOnSuccess is false, show success message
|
|
852
|
+
if (!options.clearOnSuccess) {
|
|
853
|
+
// Show success
|
|
854
|
+
const successColor = getColor('success');
|
|
855
|
+
console.error(`${successColor}${ICONS.success} ${message}${reset}`);
|
|
856
|
+
}
|
|
809
857
|
|
|
810
858
|
// Show cursor
|
|
811
|
-
process.
|
|
859
|
+
process.stderr.write('\x1B[?25h');
|
|
812
860
|
|
|
813
861
|
return result;
|
|
814
862
|
} catch (err) {
|
|
815
863
|
// Clear interval and line
|
|
816
864
|
clearInterval(interval);
|
|
817
|
-
process.
|
|
865
|
+
process.stderr.write('\r\x1B[K');
|
|
818
866
|
|
|
819
867
|
// Show error
|
|
820
868
|
const errorColor = getColor('error');
|
|
821
869
|
console.error(`${errorColor}${ICONS.error} ${message}${reset}`);
|
|
822
870
|
|
|
823
871
|
// Show cursor
|
|
824
|
-
process.
|
|
872
|
+
process.stderr.write('\x1B[?25h');
|
|
825
873
|
|
|
826
874
|
throw err;
|
|
827
875
|
}
|
|
@@ -856,12 +904,10 @@ export interface CommandRunnerOptions {
|
|
|
856
904
|
* If true or undefined, will truncate each line of output
|
|
857
905
|
*/
|
|
858
906
|
truncate?: boolean;
|
|
859
|
-
|
|
860
907
|
/**
|
|
861
908
|
* If undefined, will show up to 3 last lines of output while running. Customize the number with this property.
|
|
862
909
|
*/
|
|
863
910
|
maxLinesOutput?: number;
|
|
864
|
-
|
|
865
911
|
/**
|
|
866
912
|
* If undefined, will show up to 10 last lines on failure. Customize the number with this property.
|
|
867
913
|
*/
|
|
@@ -1085,6 +1131,33 @@ export async function runCommand(options: CommandRunnerOptions): Promise<number>
|
|
|
1085
1131
|
}
|
|
1086
1132
|
}
|
|
1087
1133
|
|
|
1134
|
+
/**
|
|
1135
|
+
* Prompt user for text input
|
|
1136
|
+
* Returns the input string
|
|
1137
|
+
*/
|
|
1138
|
+
export async function prompt(message: string): Promise<string> {
|
|
1139
|
+
process.stdout.write(message);
|
|
1140
|
+
|
|
1141
|
+
// Check if we're in a TTY environment
|
|
1142
|
+
if (!process.stdin.isTTY) {
|
|
1143
|
+
console.log('');
|
|
1144
|
+
return '';
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// Use readline for full line input
|
|
1148
|
+
const rl = readline.createInterface({
|
|
1149
|
+
input: process.stdin,
|
|
1150
|
+
output: process.stdout,
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
return new Promise((resolve) => {
|
|
1154
|
+
rl.question('', (answer: string) => {
|
|
1155
|
+
rl.close();
|
|
1156
|
+
resolve(answer);
|
|
1157
|
+
});
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1088
1161
|
export async function selectOrganization(
|
|
1089
1162
|
orgs: OrganizationList,
|
|
1090
1163
|
initial?: string
|
|
@@ -1096,17 +1169,75 @@ export async function selectOrganization(
|
|
|
1096
1169
|
);
|
|
1097
1170
|
}
|
|
1098
1171
|
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1172
|
+
if (process.env.AGENTUITY_CLOUD_ORG_ID) {
|
|
1173
|
+
const org = orgs.find((o) => o.id === process.env.AGENTUITY_CLOUD_ORG_ID);
|
|
1174
|
+
if (org) {
|
|
1175
|
+
return org.id;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
if (!process.stdin.isTTY) {
|
|
1180
|
+
if (orgs.length === 1) {
|
|
1181
|
+
return orgs[0].id;
|
|
1182
|
+
}
|
|
1183
|
+
if (initial) {
|
|
1184
|
+
return initial;
|
|
1185
|
+
}
|
|
1186
|
+
fatal(
|
|
1187
|
+
'Organization selection required but cannot prompt in non-interactive environment. Set AGENTUITY_CLOUD_ORG_ID or provide a default organization using --org-id'
|
|
1188
|
+
);
|
|
1101
1189
|
}
|
|
1102
1190
|
|
|
1103
1191
|
const response = await enquirer.prompt<{ action: string }>({
|
|
1104
1192
|
type: 'select',
|
|
1105
1193
|
name: 'action',
|
|
1106
1194
|
message: 'Select an organization',
|
|
1107
|
-
initial,
|
|
1195
|
+
initial: initial || (orgs.length === 1 ? orgs[0].id : undefined),
|
|
1108
1196
|
choices: orgs.map((o) => ({ message: o.name, name: o.id })),
|
|
1109
1197
|
});
|
|
1110
1198
|
|
|
1111
1199
|
return response.action;
|
|
1112
1200
|
}
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* show a project list picker
|
|
1204
|
+
*
|
|
1205
|
+
* @param apiClient
|
|
1206
|
+
* @param showDeployment
|
|
1207
|
+
* @returns
|
|
1208
|
+
*/
|
|
1209
|
+
export async function showProjectList(
|
|
1210
|
+
apiClient: APIClientType,
|
|
1211
|
+
showDeploymentId = false
|
|
1212
|
+
): Promise<string> {
|
|
1213
|
+
const projects = await spinner({
|
|
1214
|
+
message: 'Fetching projects',
|
|
1215
|
+
clearOnSuccess: true,
|
|
1216
|
+
callback: () => {
|
|
1217
|
+
return projectList(apiClient, showDeploymentId);
|
|
1218
|
+
},
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1221
|
+
if (projects.length === 0) {
|
|
1222
|
+
return '';
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// TODO: might want to sort by the last org_id we used
|
|
1226
|
+
if (projects) {
|
|
1227
|
+
projects.sort((a, b) => {
|
|
1228
|
+
return a.name.localeCompare(b.name);
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
const response = await enquirer.prompt<{ id: string }>({
|
|
1233
|
+
type: 'select',
|
|
1234
|
+
name: 'id',
|
|
1235
|
+
message: 'Select a project:',
|
|
1236
|
+
choices: projects.map((p) => ({
|
|
1237
|
+
name: p.id,
|
|
1238
|
+
message: `${p.name.padEnd(25, ' ')} ${muted(p.id)} ${showDeploymentId ? muted(p.latestDeploymentId ?? 'no deployment') : ''}`,
|
|
1239
|
+
})),
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
return response.id;
|
|
1243
|
+
}
|