@settlemint/sdk-utils 2.6.3-pr5145c8e4 → 2.6.3-pr8949506b

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/dist/terminal.cjs CHANGED
@@ -35,10 +35,18 @@ console_table_printer = __toESM(console_table_printer);
35
35
  //#region src/terminal/should-print.ts
36
36
  /**
37
37
  * Returns true if the terminal should print, false otherwise.
38
+ * When CLAUDECODE, REPL_ID, or AGENT env vars are set, suppresses info/debug output
39
+ * but warnings and errors will still be displayed.
38
40
  * @returns true if the terminal should print, false otherwise.
39
41
  */
40
42
  function shouldPrint() {
41
- return process.env.SETTLEMINT_DISABLE_TERMINAL !== "true";
43
+ if (process.env.SETTLEMINT_DISABLE_TERMINAL === "true") {
44
+ return false;
45
+ }
46
+ if (process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT) {
47
+ return false;
48
+ }
49
+ return true;
42
50
  }
43
51
 
44
52
  //#endregion
@@ -131,9 +139,17 @@ var CommandError = class extends Error {
131
139
  }
132
140
  };
133
141
  /**
142
+ * Checks if we're in quiet mode (Claude Code environment)
143
+ */
144
+ function isQuietMode() {
145
+ return !!(process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT);
146
+ }
147
+ /**
134
148
  * Executes a command with the given arguments in a child process.
135
149
  * Pipes stdin to the child process and captures stdout/stderr output.
136
150
  * Masks any sensitive tokens in the output before displaying or returning.
151
+ * In quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set),
152
+ * output is suppressed unless the command errors out.
137
153
  *
138
154
  * @param command - The command to execute
139
155
  * @param args - Array of arguments to pass to the command
@@ -151,6 +167,8 @@ var CommandError = class extends Error {
151
167
  */
152
168
  async function executeCommand(command, args, options) {
153
169
  const { silent,...spawnOptions } = options ?? {};
170
+ const quietMode = isQuietMode();
171
+ const shouldSuppressOutput = quietMode ? silent !== false : !!silent;
154
172
  const child = (0, node_child_process.spawn)(command, args, {
155
173
  ...spawnOptions,
156
174
  env: {
@@ -160,23 +178,38 @@ async function executeCommand(command, args, options) {
160
178
  });
161
179
  process.stdin.pipe(child.stdin);
162
180
  const output = [];
181
+ const stdoutOutput = [];
182
+ const stderrOutput = [];
163
183
  return new Promise((resolve, reject) => {
164
184
  child.stdout.on("data", (data) => {
165
185
  const maskedData = maskTokens(data.toString());
166
- if (!silent) {
186
+ if (!shouldSuppressOutput) {
167
187
  process.stdout.write(maskedData);
168
188
  }
169
189
  output.push(maskedData);
190
+ stdoutOutput.push(maskedData);
170
191
  });
171
192
  child.stderr.on("data", (data) => {
172
193
  const maskedData = maskTokens(data.toString());
173
- if (!silent) {
194
+ if (!shouldSuppressOutput) {
174
195
  process.stderr.write(maskedData);
175
196
  }
176
197
  output.push(maskedData);
198
+ stderrOutput.push(maskedData);
177
199
  });
200
+ const showErrorOutput = () => {
201
+ if (quietMode && shouldSuppressOutput && output.length > 0) {
202
+ if (stdoutOutput.length > 0) {
203
+ process.stdout.write(stdoutOutput.join(""));
204
+ }
205
+ if (stderrOutput.length > 0) {
206
+ process.stderr.write(stderrOutput.join(""));
207
+ }
208
+ }
209
+ };
178
210
  child.on("error", (err) => {
179
211
  process.stdin.unpipe(child.stdin);
212
+ showErrorOutput();
180
213
  reject(new CommandError(err.message, "code" in err && typeof err.code === "number" ? err.code : 1, output));
181
214
  });
182
215
  child.on("close", (code) => {
@@ -185,6 +218,7 @@ async function executeCommand(command, args, options) {
185
218
  resolve(output);
186
219
  return;
187
220
  }
221
+ showErrorOutput();
188
222
  reject(new CommandError(`Command "${command}" exited with code ${code}`, code, output));
189
223
  });
190
224
  });
@@ -215,12 +249,14 @@ const intro = (msg) => {
215
249
  //#endregion
216
250
  //#region src/terminal/note.ts
217
251
  /**
218
- * Displays a note message with optional warning level formatting.
219
- * Regular notes are displayed in normal text, while warnings are shown in yellow.
252
+ * Displays a note message with optional warning or error level formatting.
253
+ * Regular notes are displayed in normal text, warnings are shown in yellow, and errors in red.
220
254
  * Any sensitive tokens in the message are masked before display.
255
+ * Warnings and errors are always displayed, even in quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set).
256
+ * When an Error object is provided with level "error", the stack trace is automatically included.
221
257
  *
222
- * @param message - The message to display as a note
223
- * @param level - The note level: "info" (default) or "warn" for warning styling
258
+ * @param message - The message to display as a note, or an Error object
259
+ * @param level - The note level: "info" (default), "warn" for warning styling, or "error" for error styling
224
260
  * @example
225
261
  * import { note } from "@settlemint/sdk-utils/terminal";
226
262
  *
@@ -229,17 +265,46 @@ const intro = (msg) => {
229
265
  *
230
266
  * // Display warning note
231
267
  * note("Low disk space remaining", "warn");
268
+ *
269
+ * // Display error note
270
+ * note("Operation failed", "error");
271
+ *
272
+ * // Display error with stack trace automatically
273
+ * try {
274
+ * // some operation
275
+ * } catch (error) {
276
+ * note(error, "error");
277
+ * }
232
278
  */
233
279
  const note = (message, level = "info") => {
234
- if (!shouldPrint()) {
280
+ let messageText;
281
+ let _error;
282
+ if (message instanceof Error) {
283
+ _error = message;
284
+ messageText = message.message;
285
+ if (level === "error" && message.stack) {
286
+ messageText = `${messageText}\n\n${message.stack}`;
287
+ }
288
+ } else {
289
+ messageText = message;
290
+ }
291
+ const maskedMessage = maskTokens(messageText);
292
+ const _isQuietMode = process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT;
293
+ if (level === "warn" || level === "error") {
294
+ console.log("");
295
+ if (level === "warn") {
296
+ const coloredMessage = maskedMessage.includes("\x1B[") ? maskedMessage : (0, yoctocolors.yellowBright)(maskedMessage);
297
+ console.warn(coloredMessage);
298
+ } else {
299
+ const coloredMessage = maskedMessage.includes("\x1B[") ? maskedMessage : (0, yoctocolors.redBright)(maskedMessage);
300
+ console.error(coloredMessage);
301
+ }
235
302
  return;
236
303
  }
237
- const maskedMessage = maskTokens(message);
238
- console.log("");
239
- if (level === "warn") {
240
- console.warn((0, yoctocolors.yellowBright)(maskedMessage));
304
+ if (!shouldPrint()) {
241
305
  return;
242
306
  }
307
+ console.log("");
243
308
  console.log(maskedMessage);
244
309
  };
245
310
 
@@ -335,8 +400,8 @@ var SpinnerError = class extends Error {
335
400
  */
336
401
  const spinner = async (options) => {
337
402
  const handleError = (error) => {
403
+ note(error, "error");
338
404
  const errorMessage = maskTokens(error.message);
339
- note((0, yoctocolors.redBright)(`${errorMessage}\n\n${error.stack}`));
340
405
  throw new SpinnerError(errorMessage, error);
341
406
  };
342
407
  if (is_in_ci.default || !shouldPrint()) {
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.cjs","names":["code: number","output: string[]","items","originalError: Error","isInCi","spinner","table","Table"],"sources":["../src/terminal/should-print.ts","../src/terminal/ascii.ts","../src/logging/mask-tokens.ts","../src/terminal/cancel.ts","../src/terminal/execute-command.ts","../src/terminal/intro.ts","../src/terminal/note.ts","../src/terminal/list.ts","../src/terminal/outro.ts","../src/terminal/spinner.ts","../src/string.ts","../src/terminal/table.ts"],"sourcesContent":["/**\n * Returns true if the terminal should print, false otherwise.\n * @returns true if the terminal should print, false otherwise.\n */\nexport function shouldPrint() {\n return process.env.SETTLEMINT_DISABLE_TERMINAL !== \"true\";\n}\n","import { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Prints the SettleMint ASCII art logo to the console in magenta color.\n * Used for CLI branding and visual identification.\n *\n * @example\n * import { ascii } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Prints the SettleMint logo\n * ascii();\n */\nexport const ascii = (): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\n/_________/\\\\_____>__| |__| |____/\\\\_____>____|____/__|___|__/__|\n`),\n );\n};\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { inverse, redBright } from \"yoctocolors\";\n\n/**\n * Error class used to indicate that the operation was cancelled.\n * This error is used to signal that the operation should be aborted.\n */\nexport class CancelError extends Error {}\n\n/**\n * Displays an error message in red inverse text and throws a CancelError.\n * Used to terminate execution with a visible error message.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The error message to display\n * @returns never - Function does not return as it throws an error\n * @example\n * import { cancel } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Exits process with error message\n * cancel(\"An error occurred\");\n */\nexport const cancel = (msg: string): never => {\n console.log(\"\");\n console.log(inverse(redBright(maskTokens(msg))));\n console.log(\"\");\n throw new CancelError(msg);\n};\n","import { type SpawnOptionsWithoutStdio, spawn } from \"node:child_process\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\n\n/**\n * Options for executing a command, extending SpawnOptionsWithoutStdio\n */\nexport interface ExecuteCommandOptions extends SpawnOptionsWithoutStdio {\n /** Whether to suppress output to stdout/stderr */\n silent?: boolean;\n}\n\n/**\n * Error class for command execution errors\n * @extends Error\n */\nexport class CommandError extends Error {\n /**\n * Constructs a new CommandError\n * @param message - The error message\n * @param code - The exit code of the command\n * @param output - The output of the command\n */\n constructor(\n message: string,\n public readonly code: number,\n public readonly output: string[],\n ) {\n super(message);\n }\n}\n\n/**\n * Executes a command with the given arguments in a child process.\n * Pipes stdin to the child process and captures stdout/stderr output.\n * Masks any sensitive tokens in the output before displaying or returning.\n *\n * @param command - The command to execute\n * @param args - Array of arguments to pass to the command\n * @param options - Options for customizing command execution\n * @returns Array of output strings from stdout and stderr\n * @throws {CommandError} If the process fails to start or exits with non-zero code\n * @example\n * import { executeCommand } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Execute git clone\n * await executeCommand(\"git\", [\"clone\", \"repo-url\"]);\n *\n * // Execute silently\n * await executeCommand(\"npm\", [\"install\"], { silent: true });\n */\nexport async function executeCommand(\n command: string,\n args: string[],\n options?: ExecuteCommandOptions,\n): Promise<string[]> {\n const { silent, ...spawnOptions } = options ?? {};\n const child = spawn(command, args, { ...spawnOptions, env: { ...process.env, ...options?.env } });\n process.stdin.pipe(child.stdin);\n const output: string[] = [];\n return new Promise((resolve, reject) => {\n child.stdout.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stdout.write(maskedData);\n }\n output.push(maskedData);\n });\n child.stderr.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => {\n process.stdin.unpipe(child.stdin);\n reject(new CommandError(err.message, \"code\" in err && typeof err.code === \"number\" ? err.code : 1, output));\n });\n child.on(\"close\", (code) => {\n process.stdin.unpipe(child.stdin);\n if (code === 0 || code === null || code === 143) {\n resolve(output);\n return;\n }\n reject(new CommandError(`Command \"${command}\" exited with code ${code}`, code, output));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays an introductory message in magenta text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as introduction\n * @example\n * import { intro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display intro message\n * intro(\"Starting deployment...\");\n */\nexport const intro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays a note message with optional warning level formatting.\n * Regular notes are displayed in normal text, while warnings are shown in yellow.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param message - The message to display as a note\n * @param level - The note level: \"info\" (default) or \"warn\" for warning styling\n * @example\n * import { note } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display info note\n * note(\"Operation completed successfully\");\n *\n * // Display warning note\n * note(\"Low disk space remaining\", \"warn\");\n */\nexport const note = (message: string, level: \"info\" | \"warn\" = \"info\"): void => {\n if (!shouldPrint()) {\n return;\n }\n const maskedMessage = maskTokens(message);\n\n console.log(\"\");\n if (level === \"warn\") {\n console.warn(yellowBright(maskedMessage));\n return;\n }\n\n console.log(maskedMessage);\n};\n","import { note } from \"./note.js\";\n\n/**\n * Displays a list of items in a formatted manner, supporting nested items.\n *\n * @param title - The title of the list\n * @param items - The items to display, can be strings or arrays for nested items\n * @returns The formatted list\n * @example\n * import { list } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Simple list\n * list(\"Use cases\", [\"use case 1\", \"use case 2\", \"use case 3\"]);\n *\n * // Nested list\n * list(\"Providers\", [\n * \"AWS\",\n * [\"us-east-1\", \"eu-west-1\"],\n * \"Azure\",\n * [\"eastus\", \"westeurope\"]\n * ]);\n */\nexport function list(title: string, items: Array<string | string[]>) {\n const formatItems = (items: Array<string | string[]>): string => {\n return items\n .map((item) => {\n if (Array.isArray(item)) {\n return item.map((subItem) => ` • ${subItem}`).join(\"\\n\");\n }\n return ` • ${item}`;\n })\n .join(\"\\n\");\n };\n\n return note(`${title}:\\n\\n${formatItems(items)}`);\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { shouldPrint } from \"@/terminal/should-print.js\";\nimport { greenBright, inverse } from \"yoctocolors\";\n\n/**\n * Displays a closing message in green inverted text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as conclusion\n * @example\n * import { outro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display outro message\n * outro(\"Deployment completed successfully!\");\n */\nexport const outro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(inverse(greenBright(maskTokens(msg))));\n console.log(\"\");\n};\n","import isInCi from \"is-in-ci\";\nimport yoctoSpinner, { type Spinner } from \"yocto-spinner\";\nimport { redBright } from \"yoctocolors\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Error class used to indicate that the spinner operation failed.\n * This error is used to signal that the operation should be aborted.\n */\nexport class SpinnerError extends Error {\n constructor(\n message: string,\n public readonly originalError: Error,\n ) {\n super(message);\n this.name = \"SpinnerError\";\n }\n}\n\n/**\n * Options for configuring the spinner behavior\n */\nexport interface SpinnerOptions<R> {\n /** Message to display when spinner starts */\n startMessage: string;\n /** Async task to execute while spinner is active */\n task: (spinner?: Spinner) => Promise<R>;\n /** Message to display when spinner completes successfully */\n stopMessage: string;\n}\n\n/**\n * Displays a loading spinner while executing an async task.\n * Shows progress with start/stop messages and handles errors.\n * Spinner is disabled in CI environments.\n *\n * @param options - Configuration options for the spinner\n * @returns The result from the executed task\n * @throws Will exit process with code 1 if task fails\n * @example\n * import { spinner } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Show spinner during async task\n * const result = await spinner({\n * startMessage: \"Deploying...\",\n * task: async () => {\n * // Async work here\n * return \"success\";\n * },\n * stopMessage: \"Deployed successfully!\"\n * });\n */\nexport const spinner = async <R>(options: SpinnerOptions<R>): Promise<R> => {\n const handleError = (error: Error) => {\n const errorMessage = maskTokens(error.message);\n note(redBright(`${errorMessage}\\n\\n${error.stack}`));\n throw new SpinnerError(errorMessage, error);\n };\n if (isInCi || !shouldPrint()) {\n try {\n return await options.task();\n } catch (err) {\n return handleError(err as Error);\n }\n }\n const spinner = yoctoSpinner({ stream: process.stdout }).start(options.startMessage);\n try {\n const result = await options.task(spinner);\n spinner.success(options.stopMessage);\n // Ensure spinner success message renders before proceeding to avoid\n // terminal output overlap issues with subsequent messages\n await new Promise((resolve) => process.nextTick(resolve));\n return result;\n } catch (err) {\n spinner.error(redBright(`${options.startMessage} --> Error!`));\n return handleError(err as Error);\n }\n};\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { camelCaseToWords } from \"@/string.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n/**\n * Displays data in a formatted table in the terminal.\n *\n * @param title - Title to display above the table\n * @param data - Array of objects to display in table format\n * @example\n * import { table } from \"@settlemint/sdk-utils/terminal\";\n *\n * const data = [\n * { name: \"Item 1\", value: 100 },\n * { name: \"Item 2\", value: 200 }\n * ];\n *\n * table(\"My Table\", data);\n */\nexport function table(title: string, data: unknown[]): void {\n if (!shouldPrint()) {\n return;\n }\n\n note(title);\n\n if (!data || data.length === 0) {\n note(\"No data to display\");\n return;\n }\n\n const columnKeys = Object.keys(data[0] as Record<string, unknown>);\n const table = new Table({\n columns: columnKeys.map((key) => ({\n name: key,\n title: whiteBright(camelCaseToWords(key)),\n alignment: \"left\",\n })),\n });\n // biome-ignore lint/suspicious/noExplicitAny: Data structure varies based on table content\n table.addRows(data as Array<Record<string, any>>);\n table.printTable();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"terminal.cjs","names":["code: number","output: string[]","stdoutOutput: string[]","stderrOutput: string[]","messageText: string","_error: Error | undefined","items","originalError: Error","isInCi","spinner","table","Table"],"sources":["../src/terminal/should-print.ts","../src/terminal/ascii.ts","../src/logging/mask-tokens.ts","../src/terminal/cancel.ts","../src/terminal/execute-command.ts","../src/terminal/intro.ts","../src/terminal/note.ts","../src/terminal/list.ts","../src/terminal/outro.ts","../src/terminal/spinner.ts","../src/string.ts","../src/terminal/table.ts"],"sourcesContent":["/**\n * Returns true if the terminal should print, false otherwise.\n * When CLAUDECODE, REPL_ID, or AGENT env vars are set, suppresses info/debug output\n * but warnings and errors will still be displayed.\n * @returns true if the terminal should print, false otherwise.\n */\nexport function shouldPrint() {\n if (process.env.SETTLEMINT_DISABLE_TERMINAL === \"true\") {\n return false;\n }\n // In quiet mode (Claude Code), suppress info/debug/status messages\n // Warnings and errors will still be displayed via note() with appropriate levels\n if (process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT) {\n return false;\n }\n return true;\n}\n","import { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Prints the SettleMint ASCII art logo to the console in magenta color.\n * Used for CLI branding and visual identification.\n *\n * @example\n * import { ascii } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Prints the SettleMint logo\n * ascii();\n */\nexport const ascii = (): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\n/_________/\\\\_____>__| |__| |____/\\\\_____>____|____/__|___|__/__|\n`),\n );\n};\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { inverse, redBright } from \"yoctocolors\";\n\n/**\n * Error class used to indicate that the operation was cancelled.\n * This error is used to signal that the operation should be aborted.\n */\nexport class CancelError extends Error {}\n\n/**\n * Displays an error message in red inverse text and throws a CancelError.\n * Used to terminate execution with a visible error message.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The error message to display\n * @returns never - Function does not return as it throws an error\n * @example\n * import { cancel } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Exits process with error message\n * cancel(\"An error occurred\");\n */\nexport const cancel = (msg: string): never => {\n console.log(\"\");\n console.log(inverse(redBright(maskTokens(msg))));\n console.log(\"\");\n throw new CancelError(msg);\n};\n","import { type SpawnOptionsWithoutStdio, spawn } from \"node:child_process\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\n\n/**\n * Options for executing a command, extending SpawnOptionsWithoutStdio\n */\nexport interface ExecuteCommandOptions extends SpawnOptionsWithoutStdio {\n /** Whether to suppress output to stdout/stderr */\n silent?: boolean;\n}\n\n/**\n * Error class for command execution errors\n * @extends Error\n */\nexport class CommandError extends Error {\n /**\n * Constructs a new CommandError\n * @param message - The error message\n * @param code - The exit code of the command\n * @param output - The output of the command\n */\n constructor(\n message: string,\n public readonly code: number,\n public readonly output: string[],\n ) {\n super(message);\n }\n}\n\n/**\n * Checks if we're in quiet mode (Claude Code environment)\n */\nfunction isQuietMode(): boolean {\n return !!(process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT);\n}\n\n/**\n * Executes a command with the given arguments in a child process.\n * Pipes stdin to the child process and captures stdout/stderr output.\n * Masks any sensitive tokens in the output before displaying or returning.\n * In quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set),\n * output is suppressed unless the command errors out.\n *\n * @param command - The command to execute\n * @param args - Array of arguments to pass to the command\n * @param options - Options for customizing command execution\n * @returns Array of output strings from stdout and stderr\n * @throws {CommandError} If the process fails to start or exits with non-zero code\n * @example\n * import { executeCommand } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Execute git clone\n * await executeCommand(\"git\", [\"clone\", \"repo-url\"]);\n *\n * // Execute silently\n * await executeCommand(\"npm\", [\"install\"], { silent: true });\n */\nexport async function executeCommand(\n command: string,\n args: string[],\n options?: ExecuteCommandOptions,\n): Promise<string[]> {\n const { silent, ...spawnOptions } = options ?? {};\n const quietMode = isQuietMode();\n // In quiet mode, suppress output unless explicitly overridden with silent: false\n const shouldSuppressOutput = quietMode ? silent !== false : !!silent;\n\n const child = spawn(command, args, { ...spawnOptions, env: { ...process.env, ...options?.env } });\n process.stdin.pipe(child.stdin);\n const output: string[] = [];\n const stdoutOutput: string[] = [];\n const stderrOutput: string[] = [];\n\n return new Promise((resolve, reject) => {\n child.stdout.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!shouldSuppressOutput) {\n process.stdout.write(maskedData);\n }\n output.push(maskedData);\n stdoutOutput.push(maskedData);\n });\n child.stderr.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!shouldSuppressOutput) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n stderrOutput.push(maskedData);\n });\n\n const showErrorOutput = () => {\n // In quiet mode, show output on error\n if (quietMode && shouldSuppressOutput && output.length > 0) {\n // Write stdout to stdout and stderr to stderr\n if (stdoutOutput.length > 0) {\n process.stdout.write(stdoutOutput.join(\"\"));\n }\n if (stderrOutput.length > 0) {\n process.stderr.write(stderrOutput.join(\"\"));\n }\n }\n };\n\n child.on(\"error\", (err) => {\n process.stdin.unpipe(child.stdin);\n showErrorOutput();\n reject(new CommandError(err.message, \"code\" in err && typeof err.code === \"number\" ? err.code : 1, output));\n });\n child.on(\"close\", (code) => {\n process.stdin.unpipe(child.stdin);\n if (code === 0 || code === null || code === 143) {\n resolve(output);\n return;\n }\n // In quiet mode, show output on error\n showErrorOutput();\n reject(new CommandError(`Command \"${command}\" exited with code ${code}`, code, output));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays an introductory message in magenta text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as introduction\n * @example\n * import { intro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display intro message\n * intro(\"Starting deployment...\");\n */\nexport const intro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { redBright, yellowBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays a note message with optional warning or error level formatting.\n * Regular notes are displayed in normal text, warnings are shown in yellow, and errors in red.\n * Any sensitive tokens in the message are masked before display.\n * Warnings and errors are always displayed, even in quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set).\n * When an Error object is provided with level \"error\", the stack trace is automatically included.\n *\n * @param message - The message to display as a note, or an Error object\n * @param level - The note level: \"info\" (default), \"warn\" for warning styling, or \"error\" for error styling\n * @example\n * import { note } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display info note\n * note(\"Operation completed successfully\");\n *\n * // Display warning note\n * note(\"Low disk space remaining\", \"warn\");\n *\n * // Display error note\n * note(\"Operation failed\", \"error\");\n *\n * // Display error with stack trace automatically\n * try {\n * // some operation\n * } catch (error) {\n * note(error, \"error\");\n * }\n */\nexport const note = (message: string | Error, level: \"info\" | \"warn\" | \"error\" = \"info\"): void => {\n let messageText: string;\n let _error: Error | undefined;\n\n if (message instanceof Error) {\n _error = message;\n messageText = message.message;\n // For errors, automatically include stack trace\n if (level === \"error\" && message.stack) {\n messageText = `${messageText}\\n\\n${message.stack}`;\n }\n } else {\n messageText = message;\n }\n\n const maskedMessage = maskTokens(messageText);\n const _isQuietMode = process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT;\n\n // Always print warnings and errors, even in quiet mode\n if (level === \"warn\" || level === \"error\") {\n console.log(\"\");\n if (level === \"warn\") {\n // Apply yellow color if not already colored (check if message contains ANSI codes)\n const coloredMessage = maskedMessage.includes(\"\\u001b[\") ? maskedMessage : yellowBright(maskedMessage);\n console.warn(coloredMessage);\n } else {\n // Apply red color if not already colored (check if message contains ANSI codes)\n const coloredMessage = maskedMessage.includes(\"\\u001b[\") ? maskedMessage : redBright(maskedMessage);\n console.error(coloredMessage);\n }\n return;\n }\n\n // For info messages, check if we should print\n if (!shouldPrint()) {\n return;\n }\n\n console.log(\"\");\n console.log(maskedMessage);\n};\n","import { note } from \"./note.js\";\n\n/**\n * Displays a list of items in a formatted manner, supporting nested items.\n *\n * @param title - The title of the list\n * @param items - The items to display, can be strings or arrays for nested items\n * @returns The formatted list\n * @example\n * import { list } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Simple list\n * list(\"Use cases\", [\"use case 1\", \"use case 2\", \"use case 3\"]);\n *\n * // Nested list\n * list(\"Providers\", [\n * \"AWS\",\n * [\"us-east-1\", \"eu-west-1\"],\n * \"Azure\",\n * [\"eastus\", \"westeurope\"]\n * ]);\n */\nexport function list(title: string, items: Array<string | string[]>) {\n const formatItems = (items: Array<string | string[]>): string => {\n return items\n .map((item) => {\n if (Array.isArray(item)) {\n return item.map((subItem) => ` • ${subItem}`).join(\"\\n\");\n }\n return ` • ${item}`;\n })\n .join(\"\\n\");\n };\n\n return note(`${title}:\\n\\n${formatItems(items)}`);\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { shouldPrint } from \"@/terminal/should-print.js\";\nimport { greenBright, inverse } from \"yoctocolors\";\n\n/**\n * Displays a closing message in green inverted text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as conclusion\n * @example\n * import { outro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display outro message\n * outro(\"Deployment completed successfully!\");\n */\nexport const outro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(inverse(greenBright(maskTokens(msg))));\n console.log(\"\");\n};\n","import isInCi from \"is-in-ci\";\nimport yoctoSpinner, { type Spinner } from \"yocto-spinner\";\nimport { redBright } from \"yoctocolors\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Error class used to indicate that the spinner operation failed.\n * This error is used to signal that the operation should be aborted.\n */\nexport class SpinnerError extends Error {\n constructor(\n message: string,\n public readonly originalError: Error,\n ) {\n super(message);\n this.name = \"SpinnerError\";\n }\n}\n\n/**\n * Options for configuring the spinner behavior\n */\nexport interface SpinnerOptions<R> {\n /** Message to display when spinner starts */\n startMessage: string;\n /** Async task to execute while spinner is active */\n task: (spinner?: Spinner) => Promise<R>;\n /** Message to display when spinner completes successfully */\n stopMessage: string;\n}\n\n/**\n * Displays a loading spinner while executing an async task.\n * Shows progress with start/stop messages and handles errors.\n * Spinner is disabled in CI environments.\n *\n * @param options - Configuration options for the spinner\n * @returns The result from the executed task\n * @throws Will exit process with code 1 if task fails\n * @example\n * import { spinner } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Show spinner during async task\n * const result = await spinner({\n * startMessage: \"Deploying...\",\n * task: async () => {\n * // Async work here\n * return \"success\";\n * },\n * stopMessage: \"Deployed successfully!\"\n * });\n */\nexport const spinner = async <R>(options: SpinnerOptions<R>): Promise<R> => {\n const handleError = (error: Error) => {\n note(error, \"error\");\n const errorMessage = maskTokens(error.message);\n throw new SpinnerError(errorMessage, error);\n };\n if (isInCi || !shouldPrint()) {\n try {\n return await options.task();\n } catch (err) {\n return handleError(err as Error);\n }\n }\n const spinner = yoctoSpinner({ stream: process.stdout }).start(options.startMessage);\n try {\n const result = await options.task(spinner);\n spinner.success(options.stopMessage);\n // Ensure spinner success message renders before proceeding to avoid\n // terminal output overlap issues with subsequent messages\n await new Promise((resolve) => process.nextTick(resolve));\n return result;\n } catch (err) {\n spinner.error(redBright(`${options.startMessage} --> Error!`));\n return handleError(err as Error);\n }\n};\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { camelCaseToWords } from \"@/string.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n/**\n * Displays data in a formatted table in the terminal.\n *\n * @param title - Title to display above the table\n * @param data - Array of objects to display in table format\n * @example\n * import { table } from \"@settlemint/sdk-utils/terminal\";\n *\n * const data = [\n * { name: \"Item 1\", value: 100 },\n * { name: \"Item 2\", value: 200 }\n * ];\n *\n * table(\"My Table\", data);\n */\nexport function table(title: string, data: unknown[]): void {\n if (!shouldPrint()) {\n return;\n }\n\n note(title);\n\n if (!data || data.length === 0) {\n note(\"No data to display\");\n return;\n }\n\n const columnKeys = Object.keys(data[0] as Record<string, unknown>);\n const table = new Table({\n columns: columnKeys.map((key) => ({\n name: key,\n title: whiteBright(camelCaseToWords(key)),\n alignment: \"left\",\n })),\n });\n // biome-ignore lint/suspicious/noExplicitAny: Data structure varies based on table content\n table.addRows(data as Array<Record<string, any>>);\n table.printTable();\n}\n"],"mappings":"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"}
@@ -63,6 +63,8 @@ declare class CommandError extends Error {
63
63
  * Executes a command with the given arguments in a child process.
64
64
  * Pipes stdin to the child process and captures stdout/stderr output.
65
65
  * Masks any sensitive tokens in the output before displaying or returning.
66
+ * In quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set),
67
+ * output is suppressed unless the command errors out.
66
68
  *
67
69
  * @param command - The command to execute
68
70
  * @param args - Array of arguments to pass to the command
@@ -119,12 +121,14 @@ declare function list(title: string, items: Array<string | string[]>): void;
119
121
  //#endregion
120
122
  //#region src/terminal/note.d.ts
121
123
  /**
122
- * Displays a note message with optional warning level formatting.
123
- * Regular notes are displayed in normal text, while warnings are shown in yellow.
124
+ * Displays a note message with optional warning or error level formatting.
125
+ * Regular notes are displayed in normal text, warnings are shown in yellow, and errors in red.
124
126
  * Any sensitive tokens in the message are masked before display.
127
+ * Warnings and errors are always displayed, even in quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set).
128
+ * When an Error object is provided with level "error", the stack trace is automatically included.
125
129
  *
126
- * @param message - The message to display as a note
127
- * @param level - The note level: "info" (default) or "warn" for warning styling
130
+ * @param message - The message to display as a note, or an Error object
131
+ * @param level - The note level: "info" (default), "warn" for warning styling, or "error" for error styling
128
132
  * @example
129
133
  * import { note } from "@settlemint/sdk-utils/terminal";
130
134
  *
@@ -133,8 +137,18 @@ declare function list(title: string, items: Array<string | string[]>): void;
133
137
  *
134
138
  * // Display warning note
135
139
  * note("Low disk space remaining", "warn");
140
+ *
141
+ * // Display error note
142
+ * note("Operation failed", "error");
143
+ *
144
+ * // Display error with stack trace automatically
145
+ * try {
146
+ * // some operation
147
+ * } catch (error) {
148
+ * note(error, "error");
149
+ * }
136
150
  */
137
- declare const note: (message: string, level?: "info" | "warn") => void;
151
+ declare const note: (message: string | Error, level?: "info" | "warn" | "error") => void;
138
152
  //#endregion
139
153
  //#region src/terminal/outro.d.ts
140
154
  /**
@@ -63,6 +63,8 @@ declare class CommandError extends Error {
63
63
  * Executes a command with the given arguments in a child process.
64
64
  * Pipes stdin to the child process and captures stdout/stderr output.
65
65
  * Masks any sensitive tokens in the output before displaying or returning.
66
+ * In quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set),
67
+ * output is suppressed unless the command errors out.
66
68
  *
67
69
  * @param command - The command to execute
68
70
  * @param args - Array of arguments to pass to the command
@@ -119,12 +121,14 @@ declare function list(title: string, items: Array<string | string[]>): void;
119
121
  //#endregion
120
122
  //#region src/terminal/note.d.ts
121
123
  /**
122
- * Displays a note message with optional warning level formatting.
123
- * Regular notes are displayed in normal text, while warnings are shown in yellow.
124
+ * Displays a note message with optional warning or error level formatting.
125
+ * Regular notes are displayed in normal text, warnings are shown in yellow, and errors in red.
124
126
  * Any sensitive tokens in the message are masked before display.
127
+ * Warnings and errors are always displayed, even in quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set).
128
+ * When an Error object is provided with level "error", the stack trace is automatically included.
125
129
  *
126
- * @param message - The message to display as a note
127
- * @param level - The note level: "info" (default) or "warn" for warning styling
130
+ * @param message - The message to display as a note, or an Error object
131
+ * @param level - The note level: "info" (default), "warn" for warning styling, or "error" for error styling
128
132
  * @example
129
133
  * import { note } from "@settlemint/sdk-utils/terminal";
130
134
  *
@@ -133,8 +137,18 @@ declare function list(title: string, items: Array<string | string[]>): void;
133
137
  *
134
138
  * // Display warning note
135
139
  * note("Low disk space remaining", "warn");
140
+ *
141
+ * // Display error note
142
+ * note("Operation failed", "error");
143
+ *
144
+ * // Display error with stack trace automatically
145
+ * try {
146
+ * // some operation
147
+ * } catch (error) {
148
+ * note(error, "error");
149
+ * }
136
150
  */
137
- declare const note: (message: string, level?: "info" | "warn") => void;
151
+ declare const note: (message: string | Error, level?: "info" | "warn" | "error") => void;
138
152
  //#endregion
139
153
  //#region src/terminal/outro.d.ts
140
154
  /**
package/dist/terminal.js CHANGED
@@ -7,10 +7,18 @@ import { Table } from "console-table-printer";
7
7
  //#region src/terminal/should-print.ts
8
8
  /**
9
9
  * Returns true if the terminal should print, false otherwise.
10
+ * When CLAUDECODE, REPL_ID, or AGENT env vars are set, suppresses info/debug output
11
+ * but warnings and errors will still be displayed.
10
12
  * @returns true if the terminal should print, false otherwise.
11
13
  */
12
14
  function shouldPrint() {
13
- return process.env.SETTLEMINT_DISABLE_TERMINAL !== "true";
15
+ if (process.env.SETTLEMINT_DISABLE_TERMINAL === "true") {
16
+ return false;
17
+ }
18
+ if (process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT) {
19
+ return false;
20
+ }
21
+ return true;
14
22
  }
15
23
 
16
24
  //#endregion
@@ -103,9 +111,17 @@ var CommandError = class extends Error {
103
111
  }
104
112
  };
105
113
  /**
114
+ * Checks if we're in quiet mode (Claude Code environment)
115
+ */
116
+ function isQuietMode() {
117
+ return !!(process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT);
118
+ }
119
+ /**
106
120
  * Executes a command with the given arguments in a child process.
107
121
  * Pipes stdin to the child process and captures stdout/stderr output.
108
122
  * Masks any sensitive tokens in the output before displaying or returning.
123
+ * In quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set),
124
+ * output is suppressed unless the command errors out.
109
125
  *
110
126
  * @param command - The command to execute
111
127
  * @param args - Array of arguments to pass to the command
@@ -123,6 +139,8 @@ var CommandError = class extends Error {
123
139
  */
124
140
  async function executeCommand(command, args, options) {
125
141
  const { silent,...spawnOptions } = options ?? {};
142
+ const quietMode = isQuietMode();
143
+ const shouldSuppressOutput = quietMode ? silent !== false : !!silent;
126
144
  const child = spawn(command, args, {
127
145
  ...spawnOptions,
128
146
  env: {
@@ -132,23 +150,38 @@ async function executeCommand(command, args, options) {
132
150
  });
133
151
  process.stdin.pipe(child.stdin);
134
152
  const output = [];
153
+ const stdoutOutput = [];
154
+ const stderrOutput = [];
135
155
  return new Promise((resolve, reject) => {
136
156
  child.stdout.on("data", (data) => {
137
157
  const maskedData = maskTokens(data.toString());
138
- if (!silent) {
158
+ if (!shouldSuppressOutput) {
139
159
  process.stdout.write(maskedData);
140
160
  }
141
161
  output.push(maskedData);
162
+ stdoutOutput.push(maskedData);
142
163
  });
143
164
  child.stderr.on("data", (data) => {
144
165
  const maskedData = maskTokens(data.toString());
145
- if (!silent) {
166
+ if (!shouldSuppressOutput) {
146
167
  process.stderr.write(maskedData);
147
168
  }
148
169
  output.push(maskedData);
170
+ stderrOutput.push(maskedData);
149
171
  });
172
+ const showErrorOutput = () => {
173
+ if (quietMode && shouldSuppressOutput && output.length > 0) {
174
+ if (stdoutOutput.length > 0) {
175
+ process.stdout.write(stdoutOutput.join(""));
176
+ }
177
+ if (stderrOutput.length > 0) {
178
+ process.stderr.write(stderrOutput.join(""));
179
+ }
180
+ }
181
+ };
150
182
  child.on("error", (err) => {
151
183
  process.stdin.unpipe(child.stdin);
184
+ showErrorOutput();
152
185
  reject(new CommandError(err.message, "code" in err && typeof err.code === "number" ? err.code : 1, output));
153
186
  });
154
187
  child.on("close", (code) => {
@@ -157,6 +190,7 @@ async function executeCommand(command, args, options) {
157
190
  resolve(output);
158
191
  return;
159
192
  }
193
+ showErrorOutput();
160
194
  reject(new CommandError(`Command "${command}" exited with code ${code}`, code, output));
161
195
  });
162
196
  });
@@ -187,12 +221,14 @@ const intro = (msg) => {
187
221
  //#endregion
188
222
  //#region src/terminal/note.ts
189
223
  /**
190
- * Displays a note message with optional warning level formatting.
191
- * Regular notes are displayed in normal text, while warnings are shown in yellow.
224
+ * Displays a note message with optional warning or error level formatting.
225
+ * Regular notes are displayed in normal text, warnings are shown in yellow, and errors in red.
192
226
  * Any sensitive tokens in the message are masked before display.
227
+ * Warnings and errors are always displayed, even in quiet mode (when CLAUDECODE, REPL_ID, or AGENT env vars are set).
228
+ * When an Error object is provided with level "error", the stack trace is automatically included.
193
229
  *
194
- * @param message - The message to display as a note
195
- * @param level - The note level: "info" (default) or "warn" for warning styling
230
+ * @param message - The message to display as a note, or an Error object
231
+ * @param level - The note level: "info" (default), "warn" for warning styling, or "error" for error styling
196
232
  * @example
197
233
  * import { note } from "@settlemint/sdk-utils/terminal";
198
234
  *
@@ -201,17 +237,46 @@ const intro = (msg) => {
201
237
  *
202
238
  * // Display warning note
203
239
  * note("Low disk space remaining", "warn");
240
+ *
241
+ * // Display error note
242
+ * note("Operation failed", "error");
243
+ *
244
+ * // Display error with stack trace automatically
245
+ * try {
246
+ * // some operation
247
+ * } catch (error) {
248
+ * note(error, "error");
249
+ * }
204
250
  */
205
251
  const note = (message, level = "info") => {
206
- if (!shouldPrint()) {
252
+ let messageText;
253
+ let _error;
254
+ if (message instanceof Error) {
255
+ _error = message;
256
+ messageText = message.message;
257
+ if (level === "error" && message.stack) {
258
+ messageText = `${messageText}\n\n${message.stack}`;
259
+ }
260
+ } else {
261
+ messageText = message;
262
+ }
263
+ const maskedMessage = maskTokens(messageText);
264
+ const _isQuietMode = process.env.CLAUDECODE || process.env.REPL_ID || process.env.AGENT;
265
+ if (level === "warn" || level === "error") {
266
+ console.log("");
267
+ if (level === "warn") {
268
+ const coloredMessage = maskedMessage.includes("\x1B[") ? maskedMessage : yellowBright(maskedMessage);
269
+ console.warn(coloredMessage);
270
+ } else {
271
+ const coloredMessage = maskedMessage.includes("\x1B[") ? maskedMessage : redBright(maskedMessage);
272
+ console.error(coloredMessage);
273
+ }
207
274
  return;
208
275
  }
209
- const maskedMessage = maskTokens(message);
210
- console.log("");
211
- if (level === "warn") {
212
- console.warn(yellowBright(maskedMessage));
276
+ if (!shouldPrint()) {
213
277
  return;
214
278
  }
279
+ console.log("");
215
280
  console.log(maskedMessage);
216
281
  };
217
282
 
@@ -307,8 +372,8 @@ var SpinnerError = class extends Error {
307
372
  */
308
373
  const spinner = async (options) => {
309
374
  const handleError = (error) => {
375
+ note(error, "error");
310
376
  const errorMessage = maskTokens(error.message);
311
- note(redBright(`${errorMessage}\n\n${error.stack}`));
312
377
  throw new SpinnerError(errorMessage, error);
313
378
  };
314
379
  if (isInCi || !shouldPrint()) {