@uluops/cli 0.2.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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +825 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +93 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/analytics.d.ts +6 -0
  8. package/dist/commands/analytics.d.ts.map +1 -0
  9. package/dist/commands/analytics.js +445 -0
  10. package/dist/commands/analytics.js.map +1 -0
  11. package/dist/commands/auth.d.ts +6 -0
  12. package/dist/commands/auth.d.ts.map +1 -0
  13. package/dist/commands/auth.js +496 -0
  14. package/dist/commands/auth.js.map +1 -0
  15. package/dist/commands/completion.d.ts +7 -0
  16. package/dist/commands/completion.d.ts.map +1 -0
  17. package/dist/commands/completion.js +188 -0
  18. package/dist/commands/completion.js.map +1 -0
  19. package/dist/commands/config.d.ts +6 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +279 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/definitions.d.ts +6 -0
  24. package/dist/commands/definitions.d.ts.map +1 -0
  25. package/dist/commands/definitions.js +229 -0
  26. package/dist/commands/definitions.js.map +1 -0
  27. package/dist/commands/deps.d.ts +6 -0
  28. package/dist/commands/deps.d.ts.map +1 -0
  29. package/dist/commands/deps.js +87 -0
  30. package/dist/commands/deps.js.map +1 -0
  31. package/dist/commands/exec.d.ts +6 -0
  32. package/dist/commands/exec.d.ts.map +1 -0
  33. package/dist/commands/exec.js +334 -0
  34. package/dist/commands/exec.js.map +1 -0
  35. package/dist/commands/executions.d.ts +6 -0
  36. package/dist/commands/executions.d.ts.map +1 -0
  37. package/dist/commands/executions.js +63 -0
  38. package/dist/commands/executions.js.map +1 -0
  39. package/dist/commands/forks.d.ts +6 -0
  40. package/dist/commands/forks.d.ts.map +1 -0
  41. package/dist/commands/forks.js +145 -0
  42. package/dist/commands/forks.js.map +1 -0
  43. package/dist/commands/issues.d.ts +6 -0
  44. package/dist/commands/issues.d.ts.map +1 -0
  45. package/dist/commands/issues.js +458 -0
  46. package/dist/commands/issues.js.map +1 -0
  47. package/dist/commands/models.d.ts +6 -0
  48. package/dist/commands/models.d.ts.map +1 -0
  49. package/dist/commands/models.js +156 -0
  50. package/dist/commands/models.js.map +1 -0
  51. package/dist/commands/projects.d.ts +6 -0
  52. package/dist/commands/projects.d.ts.map +1 -0
  53. package/dist/commands/projects.js +262 -0
  54. package/dist/commands/projects.js.map +1 -0
  55. package/dist/commands/render.d.ts +6 -0
  56. package/dist/commands/render.d.ts.map +1 -0
  57. package/dist/commands/render.js +59 -0
  58. package/dist/commands/render.js.map +1 -0
  59. package/dist/commands/runs.d.ts +6 -0
  60. package/dist/commands/runs.d.ts.map +1 -0
  61. package/dist/commands/runs.js +442 -0
  62. package/dist/commands/runs.js.map +1 -0
  63. package/dist/commands/taxonomy.d.ts +6 -0
  64. package/dist/commands/taxonomy.d.ts.map +1 -0
  65. package/dist/commands/taxonomy.js +45 -0
  66. package/dist/commands/taxonomy.js.map +1 -0
  67. package/dist/commands/translation.d.ts +6 -0
  68. package/dist/commands/translation.d.ts.map +1 -0
  69. package/dist/commands/translation.js +85 -0
  70. package/dist/commands/translation.js.map +1 -0
  71. package/dist/commands/versions.d.ts +6 -0
  72. package/dist/commands/versions.d.ts.map +1 -0
  73. package/dist/commands/versions.js +61 -0
  74. package/dist/commands/versions.js.map +1 -0
  75. package/dist/context.d.ts +85 -0
  76. package/dist/context.d.ts.map +1 -0
  77. package/dist/context.js +386 -0
  78. package/dist/context.js.map +1 -0
  79. package/dist/formatters/core.d.ts +31 -0
  80. package/dist/formatters/core.d.ts.map +1 -0
  81. package/dist/formatters/core.js +176 -0
  82. package/dist/formatters/core.js.map +1 -0
  83. package/dist/formatters/ops.d.ts +43 -0
  84. package/dist/formatters/ops.d.ts.map +1 -0
  85. package/dist/formatters/ops.js +112 -0
  86. package/dist/formatters/ops.js.map +1 -0
  87. package/dist/formatters/registry.d.ts +41 -0
  88. package/dist/formatters/registry.d.ts.map +1 -0
  89. package/dist/formatters/registry.js +167 -0
  90. package/dist/formatters/registry.js.map +1 -0
  91. package/dist/formatters/table.d.ts +18 -0
  92. package/dist/formatters/table.d.ts.map +1 -0
  93. package/dist/formatters/table.js +76 -0
  94. package/dist/formatters/table.js.map +1 -0
  95. package/dist/utils.d.ts +99 -0
  96. package/dist/utils.d.ts.map +1 -0
  97. package/dist/utils.js +201 -0
  98. package/dist/utils.js.map +1 -0
  99. package/package.json +57 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Pad a cell value to the specified width
3
+ */
4
+ function padCell(text, width, align) {
5
+ const truncated = text.length > width ? text.slice(0, width - 1) + '\u2026' : text;
6
+ const padding = width - truncated.length;
7
+ if (padding <= 0)
8
+ return truncated;
9
+ if (align === 'right') {
10
+ return ' '.repeat(padding) + truncated;
11
+ }
12
+ else if (align === 'center') {
13
+ const left = Math.floor(padding / 2);
14
+ return ' '.repeat(left) + truncated + ' '.repeat(padding - left);
15
+ }
16
+ return truncated + ' '.repeat(padding);
17
+ }
18
+ /**
19
+ * Get value from row using accessor
20
+ */
21
+ function getValue(row, accessor) {
22
+ if (typeof accessor === 'function') {
23
+ return accessor(row);
24
+ }
25
+ const val = row[accessor];
26
+ if (val === null || val === undefined)
27
+ return '';
28
+ return String(val);
29
+ }
30
+ /**
31
+ * Format data as a table
32
+ */
33
+ export function formatTable(data, columns) {
34
+ if (data.length === 0) {
35
+ return 'No data';
36
+ }
37
+ // Calculate column widths
38
+ const widths = columns.map((col) => {
39
+ const headerLen = col.header.length;
40
+ const maxDataLen = Math.max(...data.map((row) => getValue(row, col.accessor).length));
41
+ return col.width ?? Math.min(Math.max(headerLen, maxDataLen), 50);
42
+ });
43
+ // Build header
44
+ const header = columns
45
+ .map((col, i) => padCell(col.header, widths[i] ?? col.header.length, col.align ?? 'left'))
46
+ .join(' ');
47
+ const separator = widths.map((w) => '-'.repeat(w ?? 10)).join('--');
48
+ // Build rows
49
+ const rows = data.map((row) => columns
50
+ .map((col, i) => {
51
+ const val = getValue(row, col.accessor);
52
+ return padCell(val, widths[i] ?? 10, col.align ?? 'left');
53
+ })
54
+ .join(' '));
55
+ return [header, separator, ...rows].join('\n');
56
+ }
57
+ /**
58
+ * Format a simple key-value display
59
+ */
60
+ export function formatKeyValue(data, indent = 0) {
61
+ const prefix = ' '.repeat(indent);
62
+ return Object.entries(data)
63
+ .filter(([, v]) => v !== undefined && v !== null)
64
+ .map(([k, v]) => {
65
+ // Only transform camelCase if key doesn't already contain spaces
66
+ const label = k.includes(' ')
67
+ ? k
68
+ : k.replace(/([A-Z])/g, ' $1').replace(/^./, (s) => s.toUpperCase());
69
+ if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
70
+ return `${prefix}${label}:\n${formatKeyValue(v, indent + 2)}`;
71
+ }
72
+ return `${prefix}${label}: ${v}`;
73
+ })
74
+ .join('\n');
75
+ }
76
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/formatters/table.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import { type Ora } from 'ora';
2
+ /**
3
+ * Create a spinner for long-running operations
4
+ */
5
+ export declare function createSpinner(text: string): Ora;
6
+ /**
7
+ * Options for withSpinner utility
8
+ */
9
+ export interface WithSpinnerOptions {
10
+ /** Message shown while operation is in progress */
11
+ start: string;
12
+ /** Message shown on success (optional - uses start message if not provided) */
13
+ success?: string;
14
+ /** Message shown on failure */
15
+ failure: string;
16
+ }
17
+ /**
18
+ * Execute an async operation with spinner feedback
19
+ */
20
+ export declare function withSpinner<T>(ctx: {
21
+ quiet: boolean;
22
+ json?: boolean;
23
+ }, options: WithSpinnerOptions, fn: () => Promise<T>): Promise<T>;
24
+ /**
25
+ * Format a date for human-readable CLI display
26
+ */
27
+ export declare function formatDisplayDate(date: string | Date | undefined | null): string;
28
+ /**
29
+ * Truncate a string with ellipsis
30
+ */
31
+ export declare function truncate(str: string, maxLength: number): string;
32
+ /**
33
+ * Format JSON output
34
+ */
35
+ export declare function formatJson(data: unknown): string;
36
+ /**
37
+ * Print error message and exit
38
+ */
39
+ export declare function exitWithError(message: string, code?: number): never;
40
+ /**
41
+ * Redact sensitive values for display
42
+ */
43
+ export declare function redact(value: string, showLast?: number): string;
44
+ /**
45
+ * Read a file with user-friendly error messages for common failures.
46
+ * Use this for CLI --file options instead of raw readFileSync.
47
+ */
48
+ export declare function readFileOption(filePath: string): string;
49
+ /**
50
+ * Write a file atomically by writing to a temp file then renaming.
51
+ * Prevents corruption if the process crashes mid-write.
52
+ */
53
+ export declare function writeFileAtomic(filePath: string, content: string): void;
54
+ /**
55
+ * Parse a string as an integer, exiting with a clear error if it's not a valid number.
56
+ * Use this instead of raw parseInt() for CLI option values.
57
+ */
58
+ export declare function parseIntOption(value: string, name: string): number;
59
+ /**
60
+ * Parse a string as a float, exiting with a clear error if it's not a valid number.
61
+ * Use this instead of raw parseFloat() for CLI option values.
62
+ */
63
+ export declare function parseFloatOption(value: string, name: string): number;
64
+ /**
65
+ * Cast SDK response to a flexible record for handling API/SDK type mismatches.
66
+ * Provides a runtime safety check instead of double assertions (as unknown as Record).
67
+ */
68
+ export declare function asFlexibleResponse(value: unknown): Record<string, unknown>;
69
+ /**
70
+ * Convert camelCase string to snake_case.
71
+ * @param str - The camelCase string to convert (e.g. "someField" → "some_field")
72
+ */
73
+ export declare function toSnakeCase(str: string): string;
74
+ /**
75
+ * Convert snake_case string to camelCase.
76
+ * @param str - The snake_case string to convert (e.g. "some_field" → "someField")
77
+ */
78
+ export declare function toCamelCase(str: string): string;
79
+ /**
80
+ * Recursively normalize object keys from snake_case to camelCase.
81
+ * Accepts both formats — keys already in camelCase pass through unchanged.
82
+ * Primitives and null values are returned as-is.
83
+ * @param input - The value to normalize (object, array, or primitive)
84
+ * @returns A deep copy with all object keys converted to camelCase
85
+ */
86
+ export declare function normalizeKeys(input: unknown): unknown;
87
+ /**
88
+ * Get a property from an object, trying camelCase first then snake_case.
89
+ *
90
+ * The UluOps API returns snake_case keys, but the SDK normalizes them to camelCase.
91
+ * Some responses (especially nested/dynamic objects) may arrive in either format
92
+ * depending on whether they've been normalized. This helper abstracts that away.
93
+ *
94
+ * @param obj - The object to read from
95
+ * @param camelCaseKey - The property name in camelCase (snake_case is derived automatically)
96
+ * @param defaultValue - Fallback if neither key exists or is undefined
97
+ */
98
+ export declare function getFlexibleProperty<T, O extends object = object>(obj: O, camelCaseKey: string, defaultValue: T): T;
99
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAGpC;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAK/C;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,GAAG,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,EACvC,OAAO,EAAE,kBAAkB,EAC3B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAYZ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAIhF;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAEhD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,KAAK,CAG9D;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAG1D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAsBvD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CASvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAG1E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAYrD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAC9D,GAAG,EAAE,CAAC,EACN,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,CAAC,GACd,CAAC,CAYH"}
package/dist/utils.js ADDED
@@ -0,0 +1,201 @@
1
+ import ora from 'ora';
2
+ import { readFileSync, existsSync, writeFileSync, renameSync, unlinkSync } from 'node:fs';
3
+ /**
4
+ * Create a spinner for long-running operations
5
+ */
6
+ export function createSpinner(text) {
7
+ return ora({
8
+ text,
9
+ spinner: 'dots',
10
+ });
11
+ }
12
+ /**
13
+ * Execute an async operation with spinner feedback
14
+ */
15
+ export async function withSpinner(ctx, options, fn) {
16
+ const spinner = (ctx.quiet || ctx.json) ? null : createSpinner(options.start);
17
+ try {
18
+ spinner?.start();
19
+ const result = await fn();
20
+ spinner?.succeed(options.success);
21
+ return result;
22
+ }
23
+ catch (error) {
24
+ spinner?.fail(options.failure);
25
+ throw error;
26
+ }
27
+ }
28
+ /**
29
+ * Format a date for human-readable CLI display
30
+ */
31
+ export function formatDisplayDate(date) {
32
+ if (!date)
33
+ return 'N/A';
34
+ const d = typeof date === 'string' ? new Date(date) : date;
35
+ return d.toLocaleString();
36
+ }
37
+ /**
38
+ * Truncate a string with ellipsis
39
+ */
40
+ export function truncate(str, maxLength) {
41
+ if (str.length <= maxLength)
42
+ return str;
43
+ return str.slice(0, maxLength - 3) + '...';
44
+ }
45
+ /**
46
+ * Format JSON output
47
+ */
48
+ export function formatJson(data) {
49
+ return JSON.stringify(data, null, 2);
50
+ }
51
+ /**
52
+ * Print error message and exit
53
+ */
54
+ export function exitWithError(message, code = 1) {
55
+ console.error(`Error: ${message}`);
56
+ process.exit(code);
57
+ }
58
+ /**
59
+ * Redact sensitive values for display
60
+ */
61
+ export function redact(value, showLast = 4) {
62
+ if (value.length <= showLast)
63
+ return '[REDACTED]';
64
+ return `${'*'.repeat(value.length - showLast)}${value.slice(-showLast)}`;
65
+ }
66
+ /**
67
+ * Read a file with user-friendly error messages for common failures.
68
+ * Use this for CLI --file options instead of raw readFileSync.
69
+ */
70
+ export function readFileOption(filePath) {
71
+ if (!existsSync(filePath)) {
72
+ console.error(`Error: File not found: ${filePath}`);
73
+ console.error('\nHint: Check the path passed to --file. Use an absolute path or a path relative to the current directory.');
74
+ process.exit(1);
75
+ }
76
+ try {
77
+ return readFileSync(filePath, 'utf-8');
78
+ }
79
+ catch (error) {
80
+ const code = error.code;
81
+ if (code === 'EISDIR') {
82
+ console.error(`Error: ${filePath} is a directory, not a file`);
83
+ console.error('\nHint: The --file option requires a path to a YAML file, not a directory.');
84
+ process.exit(1);
85
+ }
86
+ if (code === 'EACCES') {
87
+ console.error(`Error: Permission denied: ${filePath}`);
88
+ console.error('\nHint: Check file permissions. Run "chmod +r" on the file if needed.');
89
+ process.exit(1);
90
+ }
91
+ exitWithError(`Cannot read file: ${filePath}`);
92
+ }
93
+ }
94
+ /**
95
+ * Write a file atomically by writing to a temp file then renaming.
96
+ * Prevents corruption if the process crashes mid-write.
97
+ */
98
+ export function writeFileAtomic(filePath, content) {
99
+ const tmpPath = `${filePath}.tmp`;
100
+ try {
101
+ writeFileSync(tmpPath, content, { mode: 0o600 });
102
+ renameSync(tmpPath, filePath);
103
+ }
104
+ catch (error) {
105
+ try {
106
+ unlinkSync(tmpPath);
107
+ }
108
+ catch { /* tmp may not exist */ }
109
+ throw error;
110
+ }
111
+ }
112
+ /**
113
+ * Parse a string as an integer, exiting with a clear error if it's not a valid number.
114
+ * Use this instead of raw parseInt() for CLI option values.
115
+ */
116
+ export function parseIntOption(value, name) {
117
+ const parsed = parseInt(value, 10);
118
+ if (Number.isNaN(parsed)) {
119
+ exitWithError(`Invalid number for ${name}: "${value}"`);
120
+ }
121
+ return parsed;
122
+ }
123
+ /**
124
+ * Parse a string as a float, exiting with a clear error if it's not a valid number.
125
+ * Use this instead of raw parseFloat() for CLI option values.
126
+ */
127
+ export function parseFloatOption(value, name) {
128
+ const parsed = parseFloat(value);
129
+ if (Number.isNaN(parsed)) {
130
+ exitWithError(`Invalid number for ${name}: "${value}"`);
131
+ }
132
+ return parsed;
133
+ }
134
+ /**
135
+ * Cast SDK response to a flexible record for handling API/SDK type mismatches.
136
+ * Provides a runtime safety check instead of double assertions (as unknown as Record).
137
+ */
138
+ export function asFlexibleResponse(value) {
139
+ if (typeof value !== 'object' || value === null)
140
+ return {};
141
+ return value;
142
+ }
143
+ /**
144
+ * Convert camelCase string to snake_case.
145
+ * @param str - The camelCase string to convert (e.g. "someField" → "some_field")
146
+ */
147
+ export function toSnakeCase(str) {
148
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
149
+ }
150
+ /**
151
+ * Convert snake_case string to camelCase.
152
+ * @param str - The snake_case string to convert (e.g. "some_field" → "someField")
153
+ */
154
+ export function toCamelCase(str) {
155
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
156
+ }
157
+ /**
158
+ * Recursively normalize object keys from snake_case to camelCase.
159
+ * Accepts both formats — keys already in camelCase pass through unchanged.
160
+ * Primitives and null values are returned as-is.
161
+ * @param input - The value to normalize (object, array, or primitive)
162
+ * @returns A deep copy with all object keys converted to camelCase
163
+ */
164
+ export function normalizeKeys(input) {
165
+ if (Array.isArray(input)) {
166
+ return input.map(normalizeKeys);
167
+ }
168
+ if (input !== null && typeof input === 'object') {
169
+ const result = {};
170
+ for (const [key, value] of Object.entries(input)) {
171
+ result[toCamelCase(key)] = normalizeKeys(value);
172
+ }
173
+ return result;
174
+ }
175
+ return input;
176
+ }
177
+ /**
178
+ * Get a property from an object, trying camelCase first then snake_case.
179
+ *
180
+ * The UluOps API returns snake_case keys, but the SDK normalizes them to camelCase.
181
+ * Some responses (especially nested/dynamic objects) may arrive in either format
182
+ * depending on whether they've been normalized. This helper abstracts that away.
183
+ *
184
+ * @param obj - The object to read from
185
+ * @param camelCaseKey - The property name in camelCase (snake_case is derived automatically)
186
+ * @param defaultValue - Fallback if neither key exists or is undefined
187
+ */
188
+ export function getFlexibleProperty(obj, camelCaseKey, defaultValue) {
189
+ const record = obj;
190
+ // Try camelCase first
191
+ if (camelCaseKey in record && record[camelCaseKey] !== undefined) {
192
+ return record[camelCaseKey];
193
+ }
194
+ // Try snake_case
195
+ const snakeKey = toSnakeCase(camelCaseKey);
196
+ if (snakeKey in record && record[snakeKey] !== undefined) {
197
+ return record[snakeKey];
198
+ }
199
+ return defaultValue;
200
+ }
201
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@uluops/cli",
3
+ "version": "0.2.0",
4
+ "description": "Unified CLI for UluOps - validation tracking and registry management",
5
+ "type": "module",
6
+ "bin": {
7
+ "ulu": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "LICENSE"
12
+ ],
13
+ "exports": {
14
+ "./cli": "./dist/cli.js"
15
+ },
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "dev": "NODE_ENV=development tsx src/cli.ts",
19
+ "typecheck": "tsc --noEmit",
20
+ "test": "vitest run",
21
+ "test:watch": "vitest watch",
22
+ "test:coverage": "vitest run --coverage",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "uluops",
27
+ "cli",
28
+ "validation",
29
+ "registry",
30
+ "agents",
31
+ "workflows"
32
+ ],
33
+ "author": "UluOps",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/Uluops/-uluops-cli.git"
37
+ },
38
+ "license": "MIT",
39
+ "dependencies": {
40
+ "@uluops/core": "^0.13.0",
41
+ "@uluops/ops-sdk": "file:../-uluops-ops-sdk",
42
+ "@uluops/registry-sdk": "file:../-uluops-registry-sdk",
43
+ "@uluops/sdk-core": "file:../-uluops-sdk-core",
44
+ "commander": "^13.1.0",
45
+ "ora": "^8.1.1"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^22.12.0",
49
+ "@vitest/coverage-v8": "^3.0.4",
50
+ "tsx": "^4.19.2",
51
+ "typescript": "^5.7.3",
52
+ "vitest": "^3.0.4"
53
+ },
54
+ "engines": {
55
+ "node": ">=18.0.0"
56
+ }
57
+ }