@tailor-platform/sdk 2.1.0 → 2.3.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 (98) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/{dist/cli/index.mjs → bin/tailor.mjs} +1 -1
  3. package/dist/application-BZfk4HKm.mjs +3 -0
  4. package/dist/{application-D77KJFKD.mjs → application-F-nl107y.mjs} +121 -27
  5. package/dist/application-F-nl107y.mjs.map +1 -0
  6. package/dist/cli/commands/deploy/tailordb/index.d.mts +2 -1
  7. package/dist/cli/commands/deploy/types.d.mts +2 -1
  8. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +52 -22
  9. package/dist/cli/commands/tailordb/migrate/file-state.d.mts +1 -0
  10. package/dist/cli/commands/tailordb/migrate/generate.d.mts +6 -0
  11. package/dist/cli/commands/tailordb/migrate/rename-detection.d.mts +22 -0
  12. package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +2 -2
  13. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +9 -2
  14. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +30 -9
  15. package/dist/cli/lib.d.mts +4 -4
  16. package/dist/cli/lib.mjs +3 -482
  17. package/dist/cli/lib.mjs.map +1 -1
  18. package/dist/cli/main.mjs +1151 -208
  19. package/dist/cli/main.mjs.map +1 -1
  20. package/dist/cli/ts-hook.mjs +52 -7
  21. package/dist/completion/zsh-worker.zsh +167 -4
  22. package/dist/configure/index.d.mts +3 -3
  23. package/dist/configure/index.mjs +90 -23
  24. package/dist/configure/index.mjs.map +1 -1
  25. package/dist/configure/services/index.d.mts +3 -2
  26. package/dist/configure/services/tailordb/index.d.mts +2 -1
  27. package/dist/configure/services/tailordb/schema.d.mts +46 -46
  28. package/dist/configure/services/tailordb/types.d.mts +30 -4
  29. package/dist/configure/services/workflow/index.d.mts +2 -2
  30. package/dist/configure/services/workflow/wait-point.d.mts +72 -13
  31. package/dist/{crashreport-B5LqCTfF.mjs → crashreport-CIIfLnoO.mjs} +2 -2
  32. package/dist/{crashreport-B5LqCTfF.mjs.map → crashreport-CIIfLnoO.mjs.map} +1 -1
  33. package/dist/{crashreport-eI7ty7ok.mjs → crashreport-CINZ5dVN.mjs} +1 -1
  34. package/dist/errors-BVb6vYGy.mjs +89 -0
  35. package/dist/errors-BVb6vYGy.mjs.map +1 -0
  36. package/dist/kysely/index.d.mts +53 -5
  37. package/dist/kysely/index.mjs +7 -2
  38. package/dist/kysely/index.mjs.map +1 -1
  39. package/dist/{logger-CXQq9YIp.mjs → logger-DSdExfor.mjs} +83 -42
  40. package/dist/logger-DSdExfor.mjs.map +1 -0
  41. package/dist/plugin/builtin/seed/index.mjs +1 -1
  42. package/dist/{register-ts-hook-BU18uU44.mjs → register-ts-hook-ClI226n2.mjs} +3541 -703
  43. package/dist/register-ts-hook-ClI226n2.mjs.map +1 -0
  44. package/dist/schema--xYWRGfe.mjs.map +1 -1
  45. package/dist/seed/index.d.mts +52 -3
  46. package/dist/seed/index.mjs +200 -44
  47. package/dist/seed/index.mjs.map +1 -1
  48. package/dist/{seed-B-yckgQY.mjs → seed-xqM9WIHP.mjs} +8 -8
  49. package/dist/seed-xqM9WIHP.mjs.map +1 -0
  50. package/dist/{service-k1xy_A5G.mjs → service-C_WpbKHu.mjs} +39 -5
  51. package/dist/service-C_WpbKHu.mjs.map +1 -0
  52. package/dist/service-D1RCdzIL.mjs +3 -0
  53. package/dist/{service-B5WynBHQ.mjs → service-hZskxZmg.mjs} +3 -3
  54. package/dist/{service-B5WynBHQ.mjs.map → service-hZskxZmg.mjs.map} +1 -1
  55. package/dist/{service_pb-D5--My_M.mjs → service_pb-BEWj1pOV.mjs} +2 -2
  56. package/dist/{service_pb-D5--My_M.mjs.map → service_pb-BEWj1pOV.mjs.map} +1 -1
  57. package/dist/{service_pb-i8CmnQP4.mjs → service_pb-BjlhvK9E.mjs} +1 -1
  58. package/dist/utils/test/index.d.mts +6 -3
  59. package/dist/utils/test/index.mjs +25 -13
  60. package/dist/utils/test/index.mjs.map +1 -1
  61. package/dist/vitest/index.d.mts +2 -1
  62. package/dist/vitest/index.mjs +167 -3
  63. package/dist/vitest/index.mjs.map +1 -1
  64. package/dist/vitest/mocks/workflow.d.mts +13 -1
  65. package/dist/vitest/pglite-kysely.d.mts +43 -0
  66. package/dist/wait-point-invoker-__oE88_P.mjs +148 -0
  67. package/dist/wait-point-invoker-__oE88_P.mjs.map +1 -0
  68. package/dist/wait-point-registry-TL99zotw.mjs +47 -0
  69. package/dist/wait-point-registry-TL99zotw.mjs.map +1 -0
  70. package/dist/{workspace_resource_pb-DXnO2AT-.mjs → workspace_resource_pb-HNIL_Vfj.mjs} +10 -2
  71. package/dist/{workspace_resource_pb-DXnO2AT-.mjs.map → workspace_resource_pb-HNIL_Vfj.mjs.map} +1 -1
  72. package/docs/cli/setup.md +14 -1
  73. package/docs/cli/tailordb.md +96 -28
  74. package/docs/cli-reference.md +15 -12
  75. package/docs/configuration.md +1 -1
  76. package/docs/github-actions.md +73 -28
  77. package/docs/migration/v2.md +55 -1
  78. package/docs/plugin/custom.md +48 -48
  79. package/docs/plugin/index.md +24 -24
  80. package/docs/services/auth.md +10 -10
  81. package/docs/services/executor.md +1 -1
  82. package/docs/services/resolver.md +2 -2
  83. package/docs/services/tailordb-migration.md +485 -84
  84. package/docs/services/tailordb.md +28 -28
  85. package/docs/services/workflow.md +52 -2
  86. package/docs/testing.md +14 -0
  87. package/package.json +12 -7
  88. package/dist/application-Af1zIqSI.mjs +0 -3
  89. package/dist/application-D77KJFKD.mjs.map +0 -1
  90. package/dist/errors-D7583Zz7.mjs +0 -58
  91. package/dist/errors-D7583Zz7.mjs.map +0 -1
  92. package/dist/logger-CXQq9YIp.mjs.map +0 -1
  93. package/dist/register-ts-hook-BU18uU44.mjs.map +0 -1
  94. package/dist/seed-B-yckgQY.mjs.map +0 -1
  95. package/dist/service-M7OYziQP.mjs +0 -3
  96. package/dist/service-k1xy_A5G.mjs.map +0 -1
  97. package/dist/test-env-key-D7UkZp99.mjs +0 -75
  98. package/dist/test-env-key-D7UkZp99.mjs.map +0 -1
@@ -1,58 +0,0 @@
1
- import chalk from "chalk";
2
-
3
- //#region src/cli/shared/errors.ts
4
- function shellQuote(value) {
5
- if (process.platform === "win32") {
6
- if (/^[A-Za-z0-9_./:=@+\\-]+$/.test(value)) return value;
7
- return `"${value.replaceAll("\"", "\\\"")}"`;
8
- }
9
- if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;
10
- return `'${value.replaceAll("'", `'"'"'`)}'`;
11
- }
12
- function formatNextAction(next) {
13
- const argv = [next.command, ...next.args];
14
- if (process.platform === "win32" && argv.some((value) => /[%$!]/.test(value))) return `with argv ${JSON.stringify(argv)}`;
15
- return `\`${argv.map(shellQuote).join(" ")}\``;
16
- }
17
- /**
18
- * Format CLI error for output
19
- * @param error - CLIError instance to format
20
- * @returns Formatted error message
21
- */
22
- function formatError(error) {
23
- const parts = [chalk.red(`Error${error.code ? ` [${error.code}]` : ""}: ${error.message}`)];
24
- if (error.details) parts.push(`\n ${chalk.gray("Details:")} ${error.details}`);
25
- if (error.suggestion) parts.push(`\n ${chalk.cyan("Suggestion:")} ${error.suggestion}`);
26
- if (error.command) parts.push(`\n ${chalk.gray("Help:")} Run \`tailor ${error.command} --help\` for usage information.`);
27
- if (error.next) parts.push(`\n ${chalk.cyan("Next:")} Run ${formatNextAction(error.next)}.`);
28
- return parts.join("");
29
- }
30
- /**
31
- * Create a CLI error with formatted output
32
- * @param options - Options to construct a CLIError
33
- * @returns Constructed CLIError instance
34
- */
35
- function createCLIError(options) {
36
- const error = new Error(options.message);
37
- error.name = "CLIError";
38
- error.code = options.code;
39
- error.details = options.details;
40
- error.suggestion = options.suggestion;
41
- error.command = options.command;
42
- error.next = options.next;
43
- error.context = options.context;
44
- error.format = () => formatError(error);
45
- return error;
46
- }
47
- /**
48
- * Type guard to check if an error is a CLIError
49
- * @param error - Error to check
50
- * @returns True if the error is a CLIError
51
- */
52
- function isCLIError(error) {
53
- return error instanceof Error && error.name === "CLIError";
54
- }
55
-
56
- //#endregion
57
- export { isCLIError as n, createCLIError as t };
58
- //# sourceMappingURL=errors-D7583Zz7.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors-D7583Zz7.mjs","names":[],"sources":["../src/cli/shared/errors.ts"],"sourcesContent":["import chalk from \"chalk\";\n\n/**\n * Options for creating a CLI error\n */\nexport interface CLIErrorOptions {\n message: string;\n details?: string;\n suggestion?: string;\n command?: string;\n code?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, unknown>>;\n}\n\nexport interface CLIErrorNextAction {\n /** Executable name, such as `tailor`. */\n command: string;\n /** Arguments passed directly to the executable. */\n args: readonly string[];\n}\n\n/**\n * CLI error interface with formatted output\n */\nexport interface CLIError extends Error {\n readonly code?: string;\n readonly details?: string;\n readonly suggestion?: string;\n readonly command?: string;\n readonly next?: CLIErrorNextAction;\n readonly context?: Readonly<Record<string, unknown>>;\n format(): string;\n}\n\ntype CLIErrorInternal = Error & {\n code?: string;\n details?: string;\n suggestion?: string;\n command?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, unknown>>;\n format(): string;\n};\n\nfunction shellQuote(value: string): string {\n if (process.platform === \"win32\") {\n if (/^[A-Za-z0-9_./:=@+\\\\-]+$/.test(value)) return value;\n return `\"${value.replaceAll('\"', '\\\\\"')}\"`;\n }\n if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nfunction formatNextAction(next: CLIErrorNextAction): string {\n const argv = [next.command, ...next.args];\n if (process.platform === \"win32\" && argv.some((value) => /[%$!]/.test(value))) {\n return `with argv ${JSON.stringify(argv)}`;\n }\n return `\\`${argv.map(shellQuote).join(\" \")}\\``;\n}\n\n/**\n * Format CLI error for output\n * @param error - CLIError instance to format\n * @returns Formatted error message\n */\nfunction formatError(error: CLIError): string {\n const parts: string[] = [\n chalk.red(`Error${error.code ? ` [${error.code}]` : \"\"}: ${error.message}`),\n ];\n\n if (error.details) {\n parts.push(`\\n ${chalk.gray(\"Details:\")} ${error.details}`);\n }\n\n if (error.suggestion) {\n parts.push(`\\n ${chalk.cyan(\"Suggestion:\")} ${error.suggestion}`);\n }\n\n if (error.command) {\n parts.push(\n `\\n ${chalk.gray(\"Help:\")} Run \\`tailor ${error.command} --help\\` for usage information.`,\n );\n }\n\n if (error.next) {\n parts.push(`\\n ${chalk.cyan(\"Next:\")} Run ${formatNextAction(error.next)}.`);\n }\n\n return parts.join(\"\");\n}\n\n/**\n * Create a CLI error with formatted output\n * @param options - Options to construct a CLIError\n * @returns Constructed CLIError instance\n */\nfunction createCLIError(options: CLIErrorOptions): CLIError {\n const error = new Error(options.message) as CLIErrorInternal;\n error.name = \"CLIError\";\n error.code = options.code;\n error.details = options.details;\n error.suggestion = options.suggestion;\n error.command = options.command;\n error.next = options.next;\n error.context = options.context;\n error.format = () => formatError(error);\n return error;\n}\n\n/**\n * Type guard to check if an error is a CLIError\n * @param error - Error to check\n * @returns True if the error is a CLIError\n */\nexport function isCLIError(error: unknown): error is CLIError {\n return error instanceof Error && error.name === \"CLIError\";\n}\n\n// Re-export createCLIError as CLIError for backward compatibility\nexport { createCLIError as CLIError };\n"],"mappings":";;;AA6CA,SAAS,WAAW,OAAuB;CACzC,IAAI,QAAQ,aAAa,SAAS;EAChC,IAAI,2BAA2B,KAAK,KAAK,GAAG,OAAO;EACnD,OAAO,IAAI,MAAM,WAAW,MAAK,MAAK,EAAE;CAC1C;CACA,IAAI,yBAAyB,KAAK,KAAK,GAAG,OAAO;CACjD,OAAO,IAAI,MAAM,WAAW,KAAK,OAAO,EAAE;AAC5C;AAEA,SAAS,iBAAiB,MAAkC;CAC1D,MAAM,OAAO,CAAC,KAAK,SAAS,GAAG,KAAK,IAAI;CACxC,IAAI,QAAQ,aAAa,WAAW,KAAK,MAAM,UAAU,QAAQ,KAAK,KAAK,CAAC,GAC1E,OAAO,aAAa,KAAK,UAAU,IAAI;CAEzC,OAAO,KAAK,KAAK,IAAI,UAAU,CAAC,CAAC,KAAK,GAAG,EAAE;AAC7C;;;;;;AAOA,SAAS,YAAY,OAAyB;CAC5C,MAAM,QAAkB,CACtB,MAAM,IAAI,QAAQ,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK,GAAG,IAAI,MAAM,SAAS,CAC5E;CAEA,IAAI,MAAM,SACR,MAAM,KAAK,OAAO,MAAM,KAAK,UAAU,EAAE,GAAG,MAAM,SAAS;CAG7D,IAAI,MAAM,YACR,MAAM,KAAK,OAAO,MAAM,KAAK,aAAa,EAAE,GAAG,MAAM,YAAY;CAGnE,IAAI,MAAM,SACR,MAAM,KACJ,OAAO,MAAM,KAAK,OAAO,EAAE,gBAAgB,MAAM,QAAQ,iCAC3D;CAGF,IAAI,MAAM,MACR,MAAM,KAAK,OAAO,MAAM,KAAK,OAAO,EAAE,OAAO,iBAAiB,MAAM,IAAI,EAAE,EAAE;CAG9E,OAAO,MAAM,KAAK,EAAE;AACtB;;;;;;AAOA,SAAS,eAAe,SAAoC;CAC1D,MAAM,QAAQ,IAAI,MAAM,QAAQ,OAAO;CACvC,MAAM,OAAO;CACb,MAAM,OAAO,QAAQ;CACrB,MAAM,UAAU,QAAQ;CACxB,MAAM,aAAa,QAAQ;CAC3B,MAAM,UAAU,QAAQ;CACxB,MAAM,OAAO,QAAQ;CACrB,MAAM,UAAU,QAAQ;CACxB,MAAM,eAAe,YAAY,KAAK;CACtC,OAAO;AACT;;;;;;AAOA,SAAgB,WAAW,OAAmC;CAC5D,OAAO,iBAAiB,SAAS,MAAM,SAAS;AAClD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger-CXQq9YIp.mjs","names":[],"sources":["../src/cli/shared/ascii-table.ts","../src/cli/shared/parse-boolean.ts","../src/cli/shared/logger.ts"],"sourcesContent":["import { eastAsianWidth } from \"get-east-asian-width\";\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_ESCAPE_PATTERN = /\\x1b\\[[0-9;]*m/g;\nconst CARRIAGE_RETURN_PATTERN = /\\r\\n?/g;\n\nconst graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n\nexport interface AsciiTableConfig {\n /** Suppress horizontal lines between rows, keeping only the outer border. */\n singleLine?: boolean;\n /** Decide whether to draw the horizontal line at `lineIndex` (range `[0, rowCount]` inclusive). */\n drawHorizontalLine?: (lineIndex: number, rowCount: number) => boolean;\n}\n\ninterface CellLine {\n text: string;\n width: number;\n}\n\nfunction maxOf(values: number[], fallback = 0): number {\n return values.reduce((max, value) => (value > max ? value : max), fallback);\n}\n\nconst TAB_WIDTH = 8;\n\nfunction isStrippableControlCharacter(char: string): boolean {\n const codePoint = char.codePointAt(0) ?? 0;\n if (char === \"\\n\") {\n return false;\n }\n return codePoint <= 0x1f || codePoint === 0x7f;\n}\n\n// Only SGR (color/style) escape sequences are meant to survive; a bare ESC\n// that isn't part of a recognized SGR sequence (e.g. a screen-clear CSI\n// sequence, or a BEL-terminated OSC sequence) is treated like any other\n// control character below and stripped, rather than passed through to the\n// terminal or left with its terminator removed.\nfunction normalizeControlCharacters(value: string): string {\n const sgrSequences = value.match(ANSI_ESCAPE_PATTERN) ?? [];\n return value\n .split(ANSI_ESCAPE_PATTERN)\n .map((segment) => {\n const chars: string[] = [];\n for (const char of segment) {\n if (char === \"\\t\") {\n chars.push(\" \".repeat(TAB_WIDTH));\n } else if (!isStrippableControlCharacter(char)) {\n chars.push(char);\n }\n }\n return chars.join(\"\");\n })\n .reduce((result, segment, i) => result + segment + (sgrSequences[i] ?? \"\"), \"\");\n}\n\nfunction sanitizeCell(cell: unknown): string {\n return normalizeControlCharacters(String(cell ?? \"\").replace(CARRIAGE_RETURN_PATTERN, \"\\n\"));\n}\n\n// Clusters made up entirely of non-printing code points (lone joiners,\n// variation selectors, combining marks, etc.) render with no visible glyph.\nconst ZERO_WIDTH_CLUSTER_PATTERN =\n /^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Format}|\\p{Nonspacing_Mark}|\\p{Enclosing_Mark}|\\p{Surrogate})+$/v;\n// RGI_Emoji covers flags, keycaps, and VS16-forced presentation sequences,\n// which render as 2 columns in terminals even though their first code point\n// alone would measure as narrow/neutral.\nconst RGI_EMOJI_PATTERN = /^\\p{RGI_Emoji}$/v;\n\nfunction displayWidth(value: string): number {\n let width = 0;\n for (const { segment } of graphemeSegmenter.segment(value.replace(ANSI_ESCAPE_PATTERN, \"\"))) {\n if (ZERO_WIDTH_CLUSTER_PATTERN.test(segment)) {\n continue;\n }\n if (RGI_EMOJI_PATTERN.test(segment)) {\n width += 2;\n continue;\n }\n const codePoint = segment.codePointAt(0);\n width += codePoint === undefined ? 0 : eastAsianWidth(codePoint);\n }\n return width;\n}\n\nfunction toCellLines(cell: string): CellLine[] {\n return cell.split(\"\\n\").map((text) => ({ text, width: displayWidth(text) }));\n}\n\nfunction padCell(cellLine: CellLine, width: number): string {\n return cellLine.text + \" \".repeat(Math.max(0, width - cellLine.width));\n}\n\nfunction renderBorder(left: string, join: string, right: string, columnWidths: number[]): string {\n return left + columnWidths.map((width) => \"─\".repeat(width + 2)).join(join) + right;\n}\n\nfunction validateConsistentColumnCount(rows: string[][]): void {\n const columnCount = rows[0]?.length;\n if (columnCount === undefined) {\n return;\n }\n rows.forEach((row, index) => {\n if (row.length !== columnCount) {\n throw new Error(\n `renderTable: all rows must have the same number of columns (expected ${columnCount}, row ${index} has ${row.length}).`,\n );\n }\n });\n}\n\n/**\n * Renders a 2D array of values as a table using single-line Unicode box-drawing borders.\n * Column widths account for East Asian wide characters (measured per grapheme cluster,\n * so combining marks and ZWJ emoji sequences aren't overcounted, non-printing clusters\n * such as a lone joiner or combining mark measure as 0, and flags, keycaps, and\n * VS16-forced emoji presentation are measured as 2 columns) and strip ANSI SGR (color/style)\n * escape codes before measuring. Use this instead of importing a table-rendering package\n * directly.\n * @param data - Table rows; every row must have the same number of columns. Each cell is\n * stringified (`null`/`undefined` become an empty string rather than the literal text\n * \"null\"/\"undefined\"), may contain embedded newlines, has `\\r`/`\\r\\n` normalized to `\\n`,\n * has tabs expanded to spaces, and has other control characters stripped.\n * @param config - Rendering options\n * @returns The rendered table terminated with a trailing newline, or `\"\"` when there are no\n * rows or no columns to display\n */\nexport function renderTable(data: unknown[][], config: AsciiTableConfig = {}): string {\n const rows = data.map((row) => row.map(sanitizeCell));\n validateConsistentColumnCount(rows);\n\n const rowCount = rows.length;\n const columnCount = rows[0]?.length ?? 0;\n if (rowCount === 0 || columnCount === 0) {\n return \"\";\n }\n\n const rowsCellLines = rows.map((row) =>\n Array.from({ length: columnCount }, (_, col) => toCellLines(row[col] ?? \"\")),\n );\n const columnWidths = Array.from({ length: columnCount }, (_, col) =>\n maxOf(rowsCellLines.map((row) => maxOf((row[col] ?? []).map((line) => line.width)))),\n );\n\n const shouldDrawLine = (lineIndex: number): boolean =>\n config.singleLine\n ? lineIndex === 0 || lineIndex === rowCount\n : (config.drawHorizontalLine ?? (() => true))(lineIndex, rowCount);\n\n const lines: string[] = [];\n if (shouldDrawLine(0)) {\n lines.push(renderBorder(\"┌\", \"┬\", \"┐\", columnWidths));\n }\n\n rowsCellLines.forEach((cellLines, rowIndex) => {\n const rowHeight = maxOf(\n cellLines.map((columnLines) => columnLines.length),\n 1,\n );\n for (let line = 0; line < rowHeight; line++) {\n const cells = cellLines.map((columnLines, col) =>\n padCell(columnLines[line] ?? { text: \"\", width: 0 }, columnWidths[col] ?? 0),\n );\n lines.push(`│ ${cells.join(\" │ \")} │`);\n }\n if (rowIndex < rowCount - 1 && shouldDrawLine(rowIndex + 1)) {\n lines.push(renderBorder(\"├\", \"┼\", \"┤\", columnWidths));\n }\n });\n\n if (shouldDrawLine(rowCount)) {\n lines.push(renderBorder(\"└\", \"┴\", \"┘\", columnWidths));\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n","const TRUTHY_VALUES = new Set([\"true\", \"t\", \"yes\", \"y\", \"on\", \"1\"]);\nconst FALSY_VALUES = new Set([\"false\", \"f\", \"no\", \"n\", \"off\", \"0\"]);\n\n/**\n * Parse a string value as a boolean.\n *\n * Recognized values (case-insensitive, trimmed) follow Python's\n * `distutils.util.strtobool` convention:\n * - truthy: `true, t, yes, y, on, 1`\n * - falsy: `false, f, no, n, off, 0`\n *\n * Undefined, empty strings, and unrecognized values return `undefined` so\n * that callers can fall back to their own defaults.\n * @param value - The input string (e.g. an environment variable or CLI flag value)\n * @returns `true`, `false`, or `undefined` when the value is unset or unrecognized\n */\nexport function parseBoolean(value: string | undefined): boolean | undefined {\n if (value === undefined) return undefined;\n const normalized = value.trim().toLowerCase();\n if (normalized === \"\") return undefined;\n if (TRUTHY_VALUES.has(normalized)) return true;\n if (FALSY_VALUES.has(normalized)) return false;\n return undefined;\n}\n","import { formatWithOptions, type InspectOptions } from \"node:util\";\nimport chalk from \"chalk\";\nimport { formatDistanceToNowStrict } from \"date-fns\";\nimport { renderTable } from \"./ascii-table\";\nimport { parseBoolean } from \"./parse-boolean\";\n\n/**\n * Error thrown when a prompt is attempted in a non-interactive environment\n */\nexport class CIPromptError extends Error {\n constructor(message?: string) {\n super(\n message ??\n \"Interactive prompts are not available in this environment. Provide the required options explicitly.\",\n );\n this.name = \"CIPromptError\";\n }\n}\n\n/**\n * Semantic style functions for inline text styling\n */\nexport const styles = {\n // Status colors\n success: chalk.green,\n error: chalk.red,\n warning: chalk.yellow,\n info: chalk.cyan,\n\n // Action colors (for change sets)\n create: chalk.green,\n update: chalk.yellow,\n delete: chalk.red,\n unchanged: chalk.gray,\n\n // Emphasis\n bold: chalk.bold,\n dim: chalk.gray,\n highlight: chalk.cyanBright,\n successBright: chalk.greenBright,\n errorBright: chalk.redBright,\n\n // Resource types\n resourceType: chalk.bold,\n resourceName: chalk.cyan,\n\n // File paths\n path: chalk.cyan,\n\n // Values\n value: chalk.white,\n placeholder: chalk.gray.italic,\n};\n\n/**\n * Standardized symbols for CLI output\n */\nexport const symbols = {\n success: chalk.green(\"\\u2713\"),\n error: chalk.red(\"\\u2716\"),\n warning: chalk.yellow(\"\\u26a0\"),\n info: chalk.cyan(\"i\"),\n create: chalk.green(\"+\"),\n update: chalk.yellow(\"~\"),\n delete: chalk.red(\"-\"),\n replace: chalk.magenta(\"\\u00b1\"),\n bullet: chalk.gray(\"\\u2022\"),\n arrow: chalk.gray(\"\\u2192\"),\n};\n\n/**\n * Log output modes\n */\nexport type LogMode = \"default\" | \"stream\" | \"plain\";\n\nexport interface LogOptions {\n /** Output mode (default: \"default\") */\n mode?: LogMode;\n /** Number of spaces to indent the entire line (default: 0) */\n indent?: number;\n}\n\n/** Field transformer function. null excludes the field from table output. */\nexport type FieldTransformer = ((value: unknown, item: object) => string) | null;\n\nexport interface OutOptions {\n /** Table display field transform/exclude settings. Only applied in table mode (not JSON). */\n display?: Record<string, FieldTransformer>;\n\n /** Show null values in table output (default: false) */\n showNull?: boolean;\n}\n\n// In JSON mode, all logs go to stderr to keep stdout clean for JSON data\nlet _jsonMode = false;\n\n// Type icons for log output\nconst TYPE_ICONS: Record<string, string> = {\n info: \"ℹ\",\n success: \"✔\",\n warn: \"⚠\",\n error: \"✖\",\n debug: \"⚙\",\n trace: \"→\",\n log: \"\",\n};\n\n// Color functions for icon and message text\nconst TYPE_COLORS: Record<string, (text: string) => string> = {\n info: chalk.cyan,\n success: chalk.green,\n warn: chalk.yellow,\n error: chalk.red,\n debug: chalk.gray,\n trace: chalk.gray,\n log: (text) => text,\n};\n\ninterface FormatLogLineOptions {\n mode: string;\n indent: number;\n type: string;\n message: string;\n timestamp?: string;\n}\n\n/**\n * Formats a log line with the appropriate prefix and indentation\n * @param opts - Formatting options\n * @returns Formatted log line\n */\nexport function formatLogLine(opts: FormatLogLineOptions): string {\n const { mode, indent, type, message, timestamp } = opts;\n const indentPrefix = indent > 0 ? \" \".repeat(indent) : \"\";\n const colorFn = TYPE_COLORS[type] || ((text: string) => text);\n\n // Plain mode: color only, no icon, no timestamp\n if (mode === \"plain\") {\n return `${indentPrefix}${colorFn(message)}\\n`;\n }\n\n // Default/Stream mode: with icon and color\n const icon = TYPE_ICONS[type] || \"\";\n const prefix = icon ? `${icon} ` : \"\";\n const coloredOutput = colorFn(`${prefix}${message}`);\n const timestampPrefix = timestamp ?? \"\";\n\n return `${indentPrefix}${timestampPrefix}${coloredOutput}\\n`;\n}\n\n/**\n * Writes a formatted log line to stderr.\n * @param type - Log type (info, success, warn, error, log)\n * @param message - Log message\n * @param opts - Log options (mode and indent)\n */\nfunction writeLog(type: string, message: string, opts?: LogOptions): void {\n const mode = opts?.mode ?? \"default\";\n const indent = opts?.indent ?? 0;\n const inspectOpts: InspectOptions = {\n breakLength: process.stdout.columns || 80,\n };\n const formattedMessage = formatWithOptions(inspectOpts, message);\n const timestamp = mode === \"stream\" ? `${new Date().toLocaleTimeString()} ` : \"\";\n const output = formatLogLine({ mode, indent, type, message: formattedMessage, timestamp });\n process.stderr.write(output);\n}\n\nexport const logger = {\n get jsonMode(): boolean {\n return _jsonMode;\n },\n set jsonMode(value: boolean) {\n _jsonMode = value;\n },\n\n info(message: string, opts?: LogOptions): void {\n writeLog(\"info\", message, opts);\n },\n\n success(message: string, opts?: LogOptions): void {\n writeLog(\"success\", message, opts);\n },\n\n warn(message: string, opts?: LogOptions): void {\n writeLog(\"warn\", message, opts);\n },\n\n error(message: string, opts?: LogOptions): void {\n writeLog(\"error\", message, opts);\n },\n\n log(message: string): void {\n writeLog(\"log\", message, { mode: \"plain\" });\n },\n\n newline(): void {\n process.stderr.write(\"\\n\");\n },\n\n debug(message: string): void {\n if (parseBoolean(process.env.DEBUG) === true) {\n writeLog(\"log\", styles.dim(message), { mode: \"plain\" });\n }\n },\n\n out(data: string | object | object[], options?: OutOptions): void {\n if (typeof data === \"string\") {\n process.stdout.write(data.endsWith(\"\\n\") ? data : data + \"\\n\");\n return;\n }\n\n if (this.jsonMode) {\n // eslint-disable-next-line no-restricted-syntax\n console.log(JSON.stringify(data));\n return;\n }\n\n const display = options?.display;\n\n // Helper to format a value for table display\n const formatValue = (value: unknown, pretty = false): string => {\n if (options?.showNull && value === null) return \"NULL\";\n if (value === null || value === undefined) return \"N/A\";\n if (value instanceof Date) {\n return formatDistanceToNowStrict(value, { addSuffix: true });\n }\n if (typeof value === \"object\") {\n return pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);\n }\n return String(value);\n };\n\n // Helper to check if field should be excluded\n const isExcluded = (key: string): boolean => {\n return display !== undefined && key in display && display[key] === null;\n };\n\n // Helper to apply transformer or default formatting\n const transformValue = (key: string, value: unknown, item: object, pretty = false): string => {\n if (display && key in display) {\n const transformer = display[key];\n if (transformer) {\n return transformer(value, item);\n }\n }\n return formatValue(value, pretty);\n };\n\n if (!Array.isArray(data)) {\n const entries = Object.entries(data).filter(([key]) => !isExcluded(key));\n const formattedEntries = entries.map(([key, value]) => [\n key,\n transformValue(key, value, data, true),\n ]);\n const t = renderTable(formattedEntries, { singleLine: false });\n process.stdout.write(t);\n return;\n }\n\n if (data.length === 0) {\n return;\n }\n\n const allHeaders = Array.from(new Set(data.flatMap((item) => Object.keys(item))));\n const headers = allHeaders.filter((h) => !isExcluded(h));\n if (headers.length === 0) {\n return;\n }\n const rows = data.map((item) =>\n headers.map((header) =>\n transformValue(header, (item as Record<string, unknown>)[header], item),\n ),\n );\n\n const t = renderTable([headers, ...rows], {\n drawHorizontalLine: (lineIndex, rowCount) => {\n return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount;\n },\n });\n process.stdout.write(t);\n },\n};\n"],"mappings":"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"}