@enactprotocol/cli 1.2.13 → 2.0.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 (73) hide show
  1. package/README.md +88 -0
  2. package/package.json +34 -38
  3. package/src/commands/auth/index.ts +940 -0
  4. package/src/commands/cache/index.ts +361 -0
  5. package/src/commands/config/README.md +239 -0
  6. package/src/commands/config/index.ts +164 -0
  7. package/src/commands/env/README.md +197 -0
  8. package/src/commands/env/index.ts +392 -0
  9. package/src/commands/exec/README.md +110 -0
  10. package/src/commands/exec/index.ts +195 -0
  11. package/src/commands/get/index.ts +198 -0
  12. package/src/commands/index.ts +30 -0
  13. package/src/commands/inspect/index.ts +264 -0
  14. package/src/commands/install/README.md +146 -0
  15. package/src/commands/install/index.ts +682 -0
  16. package/src/commands/list/README.md +115 -0
  17. package/src/commands/list/index.ts +138 -0
  18. package/src/commands/publish/index.ts +350 -0
  19. package/src/commands/report/index.ts +366 -0
  20. package/src/commands/run/README.md +124 -0
  21. package/src/commands/run/index.ts +686 -0
  22. package/src/commands/search/index.ts +368 -0
  23. package/src/commands/setup/index.ts +274 -0
  24. package/src/commands/sign/index.ts +652 -0
  25. package/src/commands/trust/README.md +214 -0
  26. package/src/commands/trust/index.ts +453 -0
  27. package/src/commands/unyank/index.ts +107 -0
  28. package/src/commands/yank/index.ts +143 -0
  29. package/src/index.ts +96 -0
  30. package/src/types.ts +81 -0
  31. package/src/utils/errors.ts +409 -0
  32. package/src/utils/exit-codes.ts +159 -0
  33. package/src/utils/ignore.ts +147 -0
  34. package/src/utils/index.ts +107 -0
  35. package/src/utils/output.ts +242 -0
  36. package/src/utils/spinner.ts +214 -0
  37. package/tests/commands/auth.test.ts +217 -0
  38. package/tests/commands/cache.test.ts +286 -0
  39. package/tests/commands/config.test.ts +277 -0
  40. package/tests/commands/env.test.ts +293 -0
  41. package/tests/commands/exec.test.ts +112 -0
  42. package/tests/commands/get.test.ts +179 -0
  43. package/tests/commands/inspect.test.ts +201 -0
  44. package/tests/commands/install-integration.test.ts +343 -0
  45. package/tests/commands/install.test.ts +288 -0
  46. package/tests/commands/list.test.ts +160 -0
  47. package/tests/commands/publish.test.ts +186 -0
  48. package/tests/commands/report.test.ts +194 -0
  49. package/tests/commands/run.test.ts +231 -0
  50. package/tests/commands/search.test.ts +131 -0
  51. package/tests/commands/sign.test.ts +164 -0
  52. package/tests/commands/trust.test.ts +236 -0
  53. package/tests/commands/unyank.test.ts +114 -0
  54. package/tests/commands/yank.test.ts +154 -0
  55. package/tests/e2e.test.ts +554 -0
  56. package/tests/fixtures/calculator/enact.yaml +34 -0
  57. package/tests/fixtures/echo-tool/enact.md +31 -0
  58. package/tests/fixtures/env-tool/enact.yaml +19 -0
  59. package/tests/fixtures/greeter/enact.yaml +18 -0
  60. package/tests/fixtures/invalid-tool/enact.yaml +4 -0
  61. package/tests/index.test.ts +8 -0
  62. package/tests/types.test.ts +84 -0
  63. package/tests/utils/errors.test.ts +303 -0
  64. package/tests/utils/exit-codes.test.ts +189 -0
  65. package/tests/utils/ignore.test.ts +461 -0
  66. package/tests/utils/output.test.ts +126 -0
  67. package/tsconfig.json +17 -0
  68. package/tsconfig.tsbuildinfo +1 -0
  69. package/dist/index.js +0 -231612
  70. package/dist/index.js.bak +0 -231611
  71. package/dist/web/static/app.js +0 -663
  72. package/dist/web/static/index.html +0 -117
  73. package/dist/web/static/style.css +0 -291
@@ -0,0 +1,107 @@
1
+ /**
2
+ * CLI utilities
3
+ */
4
+
5
+ // Output formatting
6
+ export {
7
+ colors,
8
+ symbols,
9
+ success,
10
+ error,
11
+ warning,
12
+ info,
13
+ dim,
14
+ newline,
15
+ header,
16
+ keyValue,
17
+ listItem,
18
+ table,
19
+ json,
20
+ jsonCompact,
21
+ formatError,
22
+ errorWithDetails,
23
+ suggest,
24
+ status,
25
+ clearLine,
26
+ type TableColumn,
27
+ } from "./output";
28
+
29
+ // Spinner and prompts
30
+ export {
31
+ createSpinner,
32
+ withSpinner,
33
+ intro,
34
+ outro,
35
+ confirm,
36
+ text,
37
+ password,
38
+ select,
39
+ isCancel,
40
+ cancel,
41
+ log,
42
+ logInfo,
43
+ logSuccess,
44
+ logWarning,
45
+ logError,
46
+ logStep,
47
+ type SpinnerInstance,
48
+ } from "./spinner";
49
+
50
+ // Exit codes
51
+ export {
52
+ EXIT_SUCCESS,
53
+ EXIT_FAILURE,
54
+ EXIT_USAGE,
55
+ EXIT_DATAERR,
56
+ EXIT_NOINPUT,
57
+ EXIT_NOUSER,
58
+ EXIT_NOHOST,
59
+ EXIT_UNAVAILABLE,
60
+ EXIT_SOFTWARE,
61
+ EXIT_OSERR,
62
+ EXIT_OSFILE,
63
+ EXIT_CANTCREAT,
64
+ EXIT_IOERR,
65
+ EXIT_TEMPFAIL,
66
+ EXIT_PROTOCOL,
67
+ EXIT_NOPERM,
68
+ EXIT_CONFIG,
69
+ EXIT_TOOL_NOT_FOUND,
70
+ EXIT_MANIFEST_ERROR,
71
+ EXIT_EXECUTION_ERROR,
72
+ EXIT_TIMEOUT,
73
+ EXIT_TRUST_ERROR,
74
+ EXIT_REGISTRY_ERROR,
75
+ EXIT_AUTH_ERROR,
76
+ EXIT_VALIDATION_ERROR,
77
+ EXIT_NETWORK_ERROR,
78
+ EXIT_CONTAINER_ERROR,
79
+ getExitCodeDescription,
80
+ exit,
81
+ exitSuccess,
82
+ exitFailure,
83
+ } from "./exit-codes";
84
+
85
+ // Error handling
86
+ export {
87
+ CliError,
88
+ ToolNotFoundError,
89
+ ManifestError,
90
+ ValidationError,
91
+ AuthError,
92
+ NetworkError,
93
+ RegistryError,
94
+ TrustError,
95
+ TimeoutError,
96
+ ExecutionError,
97
+ ContainerError,
98
+ FileNotFoundError,
99
+ PermissionError,
100
+ ConfigError,
101
+ UsageError,
102
+ handleError,
103
+ withErrorHandling,
104
+ categorizeError,
105
+ ErrorMessages,
106
+ printErrorWithSuggestions,
107
+ } from "./errors";
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Output utilities for CLI
3
+ *
4
+ * Provides consistent formatting, colors, and output helpers
5
+ */
6
+
7
+ import pc from "picocolors";
8
+
9
+ // ============================================================================
10
+ // Colors and Formatting
11
+ // ============================================================================
12
+
13
+ export const colors = {
14
+ // Status colors
15
+ success: pc.green,
16
+ error: pc.red,
17
+ warning: pc.yellow,
18
+ info: pc.blue,
19
+ dim: pc.dim,
20
+ bold: pc.bold,
21
+
22
+ // Semantic colors
23
+ command: pc.cyan,
24
+ path: pc.underline,
25
+ value: pc.yellow,
26
+ key: pc.bold,
27
+ version: pc.magenta,
28
+ };
29
+
30
+ // ============================================================================
31
+ // Symbols
32
+ // ============================================================================
33
+
34
+ export const symbols = {
35
+ success: pc.green("✓"),
36
+ error: pc.red("✗"),
37
+ warning: pc.yellow("⚠"),
38
+ info: pc.blue("ℹ"),
39
+ arrow: pc.dim("→"),
40
+ bullet: pc.dim("•"),
41
+ check: pc.green("✔"),
42
+ cross: pc.red("✘"),
43
+ };
44
+
45
+ // ============================================================================
46
+ // Output Functions
47
+ // ============================================================================
48
+
49
+ /**
50
+ * Print a success message
51
+ */
52
+ export function success(message: string): void {
53
+ console.log(`${symbols.success} ${message}`);
54
+ }
55
+
56
+ /**
57
+ * Print an error message
58
+ */
59
+ export function error(message: string): void {
60
+ console.error(`${symbols.error} ${colors.error(message)}`);
61
+ }
62
+
63
+ /**
64
+ * Print a warning message
65
+ */
66
+ export function warning(message: string): void {
67
+ console.warn(`${symbols.warning} ${colors.warning(message)}`);
68
+ }
69
+
70
+ /**
71
+ * Print an info message
72
+ */
73
+ export function info(message: string): void {
74
+ console.log(`${symbols.info} ${message}`);
75
+ }
76
+
77
+ /**
78
+ * Print a dim/subtle message
79
+ */
80
+ export function dim(message: string): void {
81
+ console.log(colors.dim(message));
82
+ }
83
+
84
+ /**
85
+ * Print a newline
86
+ */
87
+ export function newline(): void {
88
+ console.log();
89
+ }
90
+
91
+ /**
92
+ * Print a header
93
+ */
94
+ export function header(text: string): void {
95
+ console.log();
96
+ console.log(colors.bold(text));
97
+ console.log(colors.dim("─".repeat(text.length)));
98
+ }
99
+
100
+ /**
101
+ * Print a key-value pair
102
+ */
103
+ export function keyValue(key: string, value: string, indent = 0): void {
104
+ const padding = " ".repeat(indent);
105
+ console.log(`${padding}${colors.key(key)}: ${value}`);
106
+ }
107
+
108
+ /**
109
+ * Print a list item
110
+ */
111
+ export function listItem(text: string, indent = 0): void {
112
+ const padding = " ".repeat(indent);
113
+ console.log(`${padding}${symbols.bullet} ${text}`);
114
+ }
115
+
116
+ // ============================================================================
117
+ // Tables
118
+ // ============================================================================
119
+
120
+ export interface TableColumn {
121
+ key: string;
122
+ header: string;
123
+ width?: number;
124
+ align?: "left" | "right" | "center";
125
+ }
126
+
127
+ /**
128
+ * Print a simple table
129
+ */
130
+ export function table<T extends Record<string, unknown>>(data: T[], columns: TableColumn[]): void {
131
+ if (data.length === 0) {
132
+ dim(" No items to display");
133
+ return;
134
+ }
135
+
136
+ // Calculate column widths
137
+ const widths = columns.map((col) => {
138
+ const headerWidth = col.header.length;
139
+ const maxDataWidth = Math.max(...data.map((row) => String(row[col.key] ?? "").length));
140
+ return col.width ?? Math.max(headerWidth, maxDataWidth);
141
+ });
142
+
143
+ // Print header
144
+ const headerLine = columns
145
+ .map((col, i) => pad(col.header, widths[i] ?? col.header.length, col.align))
146
+ .join(" ");
147
+ console.log(colors.bold(headerLine));
148
+ console.log(colors.dim("─".repeat(headerLine.length)));
149
+
150
+ // Print rows
151
+ for (const row of data) {
152
+ const line = columns
153
+ .map((col, i) => pad(String(row[col.key] ?? ""), widths[i] ?? 10, col.align))
154
+ .join(" ");
155
+ console.log(line);
156
+ }
157
+ }
158
+
159
+ function pad(text: string, width: number, align: "left" | "right" | "center" = "left"): string {
160
+ const padding = width - text.length;
161
+ if (padding <= 0) return text.slice(0, width);
162
+
163
+ switch (align) {
164
+ case "right":
165
+ return " ".repeat(padding) + text;
166
+ case "center": {
167
+ const left = Math.floor(padding / 2);
168
+ const right = padding - left;
169
+ return " ".repeat(left) + text + " ".repeat(right);
170
+ }
171
+ default:
172
+ return text + " ".repeat(padding);
173
+ }
174
+ }
175
+
176
+ // ============================================================================
177
+ // JSON Output
178
+ // ============================================================================
179
+
180
+ /**
181
+ * Print data as JSON (for --json flag)
182
+ */
183
+ export function json(data: unknown): void {
184
+ console.log(JSON.stringify(data, null, 2));
185
+ }
186
+
187
+ /**
188
+ * Print data as compact JSON
189
+ */
190
+ export function jsonCompact(data: unknown): void {
191
+ console.log(JSON.stringify(data));
192
+ }
193
+
194
+ // ============================================================================
195
+ // Error Formatting
196
+ // ============================================================================
197
+
198
+ /**
199
+ * Format an error for display
200
+ */
201
+ export function formatError(err: unknown): string {
202
+ if (err instanceof Error) {
203
+ return err.message;
204
+ }
205
+ return String(err);
206
+ }
207
+
208
+ /**
209
+ * Print an error with details
210
+ */
211
+ export function errorWithDetails(message: string, details?: string): void {
212
+ error(message);
213
+ if (details) {
214
+ console.error(colors.dim(` ${details}`));
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Print a suggestion after an error
220
+ */
221
+ export function suggest(message: string): void {
222
+ console.log();
223
+ console.log(`${colors.info("Suggestion:")} ${message}`);
224
+ }
225
+
226
+ // ============================================================================
227
+ // Progress / Status
228
+ // ============================================================================
229
+
230
+ /**
231
+ * Print a status line that can be updated
232
+ */
233
+ export function status(message: string): void {
234
+ process.stdout.write(`\r${symbols.info} ${message}`);
235
+ }
236
+
237
+ /**
238
+ * Clear the current line
239
+ */
240
+ export function clearLine(): void {
241
+ process.stdout.write("\r\x1b[K");
242
+ }
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Spinner utility using @clack/prompts
3
+ *
4
+ * Provides loading spinners for long-running operations
5
+ */
6
+
7
+ import * as p from "@clack/prompts";
8
+
9
+ export interface SpinnerInstance {
10
+ start: (message?: string) => void;
11
+ stop: (message?: string, code?: number) => void;
12
+ message: (message: string) => void;
13
+ }
14
+
15
+ /**
16
+ * Create a spinner for long-running operations
17
+ */
18
+ export function createSpinner(): SpinnerInstance {
19
+ const spinner = p.spinner();
20
+
21
+ return {
22
+ start(message = "Loading...") {
23
+ spinner.start(message);
24
+ },
25
+ stop(message?: string, code = 0) {
26
+ spinner.stop(message, code);
27
+ },
28
+ message(message: string) {
29
+ spinner.message(message);
30
+ },
31
+ };
32
+ }
33
+
34
+ /**
35
+ * Run an async operation with a spinner
36
+ */
37
+ export async function withSpinner<T>(
38
+ message: string,
39
+ fn: () => Promise<T>,
40
+ successMessage?: string
41
+ ): Promise<T> {
42
+ const spinner = createSpinner();
43
+ spinner.start(message);
44
+
45
+ try {
46
+ const result = await fn();
47
+ spinner.stop(successMessage ?? message);
48
+ return result;
49
+ } catch (error) {
50
+ spinner.stop(`Failed: ${message}`, 1);
51
+ throw error;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Show a simple intro banner
57
+ */
58
+ export function intro(message: string): void {
59
+ p.intro(message);
60
+ }
61
+
62
+ /**
63
+ * Show an outro message
64
+ */
65
+ export function outro(message: string): void {
66
+ p.outro(message);
67
+ }
68
+
69
+ /**
70
+ * Prompt for confirmation
71
+ */
72
+ export async function confirm(message: string, initialValue = false): Promise<boolean> {
73
+ const result = await p.confirm({
74
+ message,
75
+ initialValue,
76
+ });
77
+
78
+ if (p.isCancel(result)) {
79
+ return false;
80
+ }
81
+
82
+ return result;
83
+ }
84
+
85
+ /**
86
+ * Prompt for text input
87
+ */
88
+ export async function text(
89
+ message: string,
90
+ options?: {
91
+ placeholder?: string;
92
+ defaultValue?: string;
93
+ validate?: (value: string) => string | undefined;
94
+ }
95
+ ): Promise<string | null> {
96
+ const textOptions: {
97
+ message: string;
98
+ placeholder?: string;
99
+ defaultValue?: string;
100
+ validate?: (value: string) => string | undefined;
101
+ } = {
102
+ message,
103
+ };
104
+
105
+ if (options?.placeholder) {
106
+ textOptions.placeholder = options.placeholder;
107
+ }
108
+ if (options?.defaultValue) {
109
+ textOptions.defaultValue = options.defaultValue;
110
+ }
111
+ if (options?.validate) {
112
+ textOptions.validate = options.validate;
113
+ }
114
+
115
+ const result = await p.text(textOptions);
116
+
117
+ if (p.isCancel(result)) {
118
+ return null;
119
+ }
120
+
121
+ return result;
122
+ }
123
+
124
+ /**
125
+ * Prompt for password input (masked)
126
+ */
127
+ export async function password(message: string): Promise<string | null> {
128
+ const result = await p.password({
129
+ message,
130
+ });
131
+
132
+ if (p.isCancel(result)) {
133
+ return null;
134
+ }
135
+
136
+ return result;
137
+ }
138
+
139
+ /**
140
+ * Prompt for selection from options
141
+ */
142
+ export async function select<T extends string>(
143
+ message: string,
144
+ options: Array<{ value: T; label: string; hint?: string }>
145
+ ): Promise<T | null> {
146
+ const result = await p.select({
147
+ message,
148
+ // biome-ignore lint/suspicious/noExplicitAny: clack types are strict about optional props
149
+ options: options as any,
150
+ });
151
+
152
+ if (p.isCancel(result)) {
153
+ return null;
154
+ }
155
+
156
+ return result as T;
157
+ }
158
+
159
+ /**
160
+ * Check if user cancelled
161
+ */
162
+ export function isCancel(value: unknown): boolean {
163
+ return p.isCancel(value);
164
+ }
165
+
166
+ /**
167
+ * Cancel and exit
168
+ */
169
+ export function cancel(message = "Operation cancelled"): never {
170
+ p.cancel(message);
171
+ process.exit(0);
172
+ }
173
+
174
+ /**
175
+ * Log a message (respects CI mode)
176
+ */
177
+ export function log(message: string): void {
178
+ p.log.message(message);
179
+ }
180
+
181
+ /**
182
+ * Log an info message
183
+ */
184
+ export function logInfo(message: string): void {
185
+ p.log.info(message);
186
+ }
187
+
188
+ /**
189
+ * Log a success message
190
+ */
191
+ export function logSuccess(message: string): void {
192
+ p.log.success(message);
193
+ }
194
+
195
+ /**
196
+ * Log a warning
197
+ */
198
+ export function logWarning(message: string): void {
199
+ p.log.warn(message);
200
+ }
201
+
202
+ /**
203
+ * Log an error
204
+ */
205
+ export function logError(message: string): void {
206
+ p.log.error(message);
207
+ }
208
+
209
+ /**
210
+ * Log a step
211
+ */
212
+ export function logStep(message: string): void {
213
+ p.log.step(message);
214
+ }