tlc-claude-code 1.4.9 → 1.5.2

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 (122) hide show
  1. package/CLAUDE.md +23 -0
  2. package/CODING-STANDARDS.md +408 -0
  3. package/bin/install.js +2 -0
  4. package/dashboard/dist/components/QualityGatePane.d.ts +38 -0
  5. package/dashboard/dist/components/QualityGatePane.js +31 -0
  6. package/dashboard/dist/components/QualityGatePane.test.d.ts +1 -0
  7. package/dashboard/dist/components/QualityGatePane.test.js +147 -0
  8. package/dashboard/dist/components/orchestration/AgentCard.d.ts +26 -0
  9. package/dashboard/dist/components/orchestration/AgentCard.js +60 -0
  10. package/dashboard/dist/components/orchestration/AgentCard.test.d.ts +1 -0
  11. package/dashboard/dist/components/orchestration/AgentCard.test.js +63 -0
  12. package/dashboard/dist/components/orchestration/AgentControls.d.ts +11 -0
  13. package/dashboard/dist/components/orchestration/AgentControls.js +20 -0
  14. package/dashboard/dist/components/orchestration/AgentControls.test.d.ts +1 -0
  15. package/dashboard/dist/components/orchestration/AgentControls.test.js +52 -0
  16. package/dashboard/dist/components/orchestration/AgentDetail.d.ts +35 -0
  17. package/dashboard/dist/components/orchestration/AgentDetail.js +37 -0
  18. package/dashboard/dist/components/orchestration/AgentDetail.test.d.ts +1 -0
  19. package/dashboard/dist/components/orchestration/AgentDetail.test.js +79 -0
  20. package/dashboard/dist/components/orchestration/AgentList.d.ts +31 -0
  21. package/dashboard/dist/components/orchestration/AgentList.js +47 -0
  22. package/dashboard/dist/components/orchestration/AgentList.test.d.ts +1 -0
  23. package/dashboard/dist/components/orchestration/AgentList.test.js +64 -0
  24. package/dashboard/dist/components/orchestration/CostMeter.d.ts +11 -0
  25. package/dashboard/dist/components/orchestration/CostMeter.js +28 -0
  26. package/dashboard/dist/components/orchestration/CostMeter.test.d.ts +1 -0
  27. package/dashboard/dist/components/orchestration/CostMeter.test.js +50 -0
  28. package/dashboard/dist/components/orchestration/ModelSelector.d.ts +20 -0
  29. package/dashboard/dist/components/orchestration/ModelSelector.js +12 -0
  30. package/dashboard/dist/components/orchestration/ModelSelector.test.d.ts +1 -0
  31. package/dashboard/dist/components/orchestration/ModelSelector.test.js +56 -0
  32. package/dashboard/dist/components/orchestration/OrchestrationDashboard.d.ts +28 -0
  33. package/dashboard/dist/components/orchestration/OrchestrationDashboard.js +28 -0
  34. package/dashboard/dist/components/orchestration/OrchestrationDashboard.test.d.ts +1 -0
  35. package/dashboard/dist/components/orchestration/OrchestrationDashboard.test.js +56 -0
  36. package/dashboard/dist/components/orchestration/QualityIndicator.d.ts +11 -0
  37. package/dashboard/dist/components/orchestration/QualityIndicator.js +37 -0
  38. package/dashboard/dist/components/orchestration/QualityIndicator.test.d.ts +1 -0
  39. package/dashboard/dist/components/orchestration/QualityIndicator.test.js +52 -0
  40. package/dashboard/dist/components/orchestration/index.d.ts +8 -0
  41. package/dashboard/dist/components/orchestration/index.js +8 -0
  42. package/package.json +1 -1
  43. package/server/lib/access-control.js +352 -0
  44. package/server/lib/access-control.test.js +322 -0
  45. package/server/lib/agents-cancel-command.js +139 -0
  46. package/server/lib/agents-cancel-command.test.js +180 -0
  47. package/server/lib/agents-get-command.js +159 -0
  48. package/server/lib/agents-get-command.test.js +167 -0
  49. package/server/lib/agents-list-command.js +150 -0
  50. package/server/lib/agents-list-command.test.js +149 -0
  51. package/server/lib/agents-logs-command.js +126 -0
  52. package/server/lib/agents-logs-command.test.js +198 -0
  53. package/server/lib/agents-retry-command.js +117 -0
  54. package/server/lib/agents-retry-command.test.js +192 -0
  55. package/server/lib/budget-limits.js +222 -0
  56. package/server/lib/budget-limits.test.js +214 -0
  57. package/server/lib/code-generator.js +291 -0
  58. package/server/lib/code-generator.test.js +307 -0
  59. package/server/lib/cost-command.js +290 -0
  60. package/server/lib/cost-command.test.js +202 -0
  61. package/server/lib/cost-optimizer.js +404 -0
  62. package/server/lib/cost-optimizer.test.js +232 -0
  63. package/server/lib/cost-projections.js +302 -0
  64. package/server/lib/cost-projections.test.js +217 -0
  65. package/server/lib/cost-reports.js +277 -0
  66. package/server/lib/cost-reports.test.js +254 -0
  67. package/server/lib/cost-tracker.js +216 -0
  68. package/server/lib/cost-tracker.test.js +302 -0
  69. package/server/lib/crypto-patterns.js +433 -0
  70. package/server/lib/crypto-patterns.test.js +346 -0
  71. package/server/lib/design-command.js +385 -0
  72. package/server/lib/design-command.test.js +249 -0
  73. package/server/lib/design-parser.js +237 -0
  74. package/server/lib/design-parser.test.js +290 -0
  75. package/server/lib/gemini-vision.js +377 -0
  76. package/server/lib/gemini-vision.test.js +282 -0
  77. package/server/lib/input-validator.js +360 -0
  78. package/server/lib/input-validator.test.js +295 -0
  79. package/server/lib/litellm-client.js +232 -0
  80. package/server/lib/litellm-client.test.js +267 -0
  81. package/server/lib/litellm-command.js +291 -0
  82. package/server/lib/litellm-command.test.js +260 -0
  83. package/server/lib/litellm-config.js +273 -0
  84. package/server/lib/litellm-config.test.js +212 -0
  85. package/server/lib/model-pricing.js +189 -0
  86. package/server/lib/model-pricing.test.js +178 -0
  87. package/server/lib/models-command.js +223 -0
  88. package/server/lib/models-command.test.js +193 -0
  89. package/server/lib/optimize-command.js +197 -0
  90. package/server/lib/optimize-command.test.js +193 -0
  91. package/server/lib/orchestration-integration.js +206 -0
  92. package/server/lib/orchestration-integration.test.js +235 -0
  93. package/server/lib/output-encoder.js +308 -0
  94. package/server/lib/output-encoder.test.js +312 -0
  95. package/server/lib/quality-evaluator.js +396 -0
  96. package/server/lib/quality-evaluator.test.js +337 -0
  97. package/server/lib/quality-gate-command.js +340 -0
  98. package/server/lib/quality-gate-command.test.js +321 -0
  99. package/server/lib/quality-gate-scorer.js +378 -0
  100. package/server/lib/quality-gate-scorer.test.js +376 -0
  101. package/server/lib/quality-history.js +265 -0
  102. package/server/lib/quality-history.test.js +359 -0
  103. package/server/lib/quality-presets.js +288 -0
  104. package/server/lib/quality-presets.test.js +269 -0
  105. package/server/lib/quality-retry.js +323 -0
  106. package/server/lib/quality-retry.test.js +325 -0
  107. package/server/lib/quality-thresholds.js +255 -0
  108. package/server/lib/quality-thresholds.test.js +237 -0
  109. package/server/lib/secure-auth.js +333 -0
  110. package/server/lib/secure-auth.test.js +288 -0
  111. package/server/lib/secure-code-command.js +540 -0
  112. package/server/lib/secure-code-command.test.js +309 -0
  113. package/server/lib/secure-errors.js +521 -0
  114. package/server/lib/secure-errors.test.js +298 -0
  115. package/server/lib/vision-command.js +372 -0
  116. package/server/lib/vision-command.test.js +255 -0
  117. package/server/lib/visual-command.js +350 -0
  118. package/server/lib/visual-command.test.js +256 -0
  119. package/server/lib/visual-testing.js +315 -0
  120. package/server/lib/visual-testing.test.js +357 -0
  121. package/server/package-lock.json +2 -2
  122. package/server/package.json +1 -1
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Secure Errors Tests
3
+ *
4
+ * Secure error handling patterns for code generation
5
+ */
6
+
7
+ const { describe, it, beforeEach } = require('node:test');
8
+ const assert = require('node:assert');
9
+
10
+ const {
11
+ createSecureErrors,
12
+ generateErrorHandler,
13
+ generateStructuredLogging,
14
+ generateGracefulDegradation,
15
+ sanitizeErrorMessage,
16
+ generateErrorCode,
17
+ } = require('./secure-errors.js');
18
+
19
+ describe('Secure Errors', () => {
20
+ let errorHandler;
21
+
22
+ beforeEach(() => {
23
+ errorHandler = createSecureErrors();
24
+ });
25
+
26
+ describe('createSecureErrors', () => {
27
+ it('creates handler with default config', () => {
28
+ assert.ok(errorHandler);
29
+ assert.ok(errorHandler.production !== undefined);
30
+ });
31
+
32
+ it('hides stack traces in production', () => {
33
+ const prod = createSecureErrors({ production: true });
34
+
35
+ assert.strictEqual(prod.showStack, false);
36
+ });
37
+
38
+ it('shows stack traces in development', () => {
39
+ const dev = createSecureErrors({ production: false });
40
+
41
+ assert.strictEqual(dev.showStack, true);
42
+ });
43
+ });
44
+
45
+ describe('generateErrorHandler', () => {
46
+ it('generates Express error handler', () => {
47
+ const code = generateErrorHandler({
48
+ framework: 'express',
49
+ language: 'javascript',
50
+ });
51
+
52
+ assert.ok(code.includes('err') && code.includes('req') && code.includes('res'));
53
+ });
54
+
55
+ it('hides internal errors in production', () => {
56
+ const code = generateErrorHandler({
57
+ production: true,
58
+ });
59
+
60
+ assert.ok(code.includes('Internal') || code.includes('generic') || code.includes('production'));
61
+ });
62
+
63
+ it('includes error ID for support', () => {
64
+ const code = generateErrorHandler({
65
+ includeErrorId: true,
66
+ });
67
+
68
+ assert.ok(code.includes('errorId') || code.includes('requestId') || code.includes('uuid'));
69
+ });
70
+
71
+ it('generates status code mapping', () => {
72
+ const code = generateErrorHandler({
73
+ statusCodes: true,
74
+ });
75
+
76
+ assert.ok(code.includes('400') || code.includes('500') || code.includes('status'));
77
+ });
78
+
79
+ it('generates Fastify error handler', () => {
80
+ const code = generateErrorHandler({
81
+ framework: 'fastify',
82
+ });
83
+
84
+ assert.ok(code.includes('request') || code.includes('reply'));
85
+ });
86
+
87
+ it('generates async error handler', () => {
88
+ const code = generateErrorHandler({
89
+ async: true,
90
+ });
91
+
92
+ assert.ok(code.includes('async') || code.includes('Promise'));
93
+ });
94
+ });
95
+
96
+ describe('generateStructuredLogging', () => {
97
+ it('generates JSON log format', () => {
98
+ const code = generateStructuredLogging({
99
+ format: 'json',
100
+ });
101
+
102
+ assert.ok(code.includes('JSON') || code.includes('stringify'));
103
+ });
104
+
105
+ it('excludes sensitive fields', () => {
106
+ const code = generateStructuredLogging({
107
+ excludeFields: ['password', 'token', 'secret'],
108
+ });
109
+
110
+ assert.ok(code.includes('password') || code.includes('redact') || code.includes('exclude'));
111
+ });
112
+
113
+ it('includes request context', () => {
114
+ const code = generateStructuredLogging({
115
+ includeContext: true,
116
+ });
117
+
118
+ assert.ok(code.includes('requestId') || code.includes('userId') || code.includes('context'));
119
+ });
120
+
121
+ it('generates log levels', () => {
122
+ const code = generateStructuredLogging({
123
+ levels: ['error', 'warn', 'info', 'debug'],
124
+ });
125
+
126
+ assert.ok(code.includes('error') && code.includes('warn'));
127
+ });
128
+
129
+ it('generates Pino logger', () => {
130
+ const code = generateStructuredLogging({
131
+ library: 'pino',
132
+ });
133
+
134
+ assert.ok(code.includes('pino'));
135
+ });
136
+
137
+ it('generates Winston logger', () => {
138
+ const code = generateStructuredLogging({
139
+ library: 'winston',
140
+ });
141
+
142
+ assert.ok(code.includes('winston'));
143
+ });
144
+
145
+ it('redacts PII', () => {
146
+ const code = generateStructuredLogging({
147
+ redactPii: true,
148
+ });
149
+
150
+ assert.ok(code.includes('email') || code.includes('redact') || code.includes('mask'));
151
+ });
152
+ });
153
+
154
+ describe('generateGracefulDegradation', () => {
155
+ it('generates fallback response', () => {
156
+ const code = generateGracefulDegradation({
157
+ type: 'fallback',
158
+ });
159
+
160
+ assert.ok(code.includes('fallback') || code.includes('default'));
161
+ });
162
+
163
+ it('generates circuit breaker', () => {
164
+ const code = generateGracefulDegradation({
165
+ type: 'circuit-breaker',
166
+ });
167
+
168
+ assert.ok(code.includes('circuit') || code.includes('breaker') || code.includes('state'));
169
+ });
170
+
171
+ it('generates retry logic', () => {
172
+ const code = generateGracefulDegradation({
173
+ type: 'retry',
174
+ maxRetries: 3,
175
+ });
176
+
177
+ assert.ok(code.includes('retry') || code.includes('attempt'));
178
+ });
179
+
180
+ it('generates timeout handling', () => {
181
+ const code = generateGracefulDegradation({
182
+ type: 'timeout',
183
+ timeoutMs: 5000,
184
+ });
185
+
186
+ assert.ok(code.includes('timeout') || code.includes('5000'));
187
+ });
188
+
189
+ it('generates cache fallback', () => {
190
+ const code = generateGracefulDegradation({
191
+ type: 'cache-fallback',
192
+ });
193
+
194
+ assert.ok(code.includes('cache') || code.includes('stale'));
195
+ });
196
+
197
+ it('generates health check based routing', () => {
198
+ const code = generateGracefulDegradation({
199
+ type: 'health-routing',
200
+ });
201
+
202
+ assert.ok(code.includes('health') || code.includes('healthy'));
203
+ });
204
+ });
205
+
206
+ describe('sanitizeErrorMessage', () => {
207
+ it('removes file paths', () => {
208
+ const message = 'Error at /home/user/app/src/index.js:42';
209
+
210
+ const result = sanitizeErrorMessage(message);
211
+
212
+ assert.ok(!result.includes('/home/user'));
213
+ });
214
+
215
+ it('removes IP addresses', () => {
216
+ const message = 'Connection from 192.168.1.100 failed';
217
+
218
+ const result = sanitizeErrorMessage(message);
219
+
220
+ assert.ok(!result.includes('192.168.1.100'));
221
+ });
222
+
223
+ it('removes database connection strings', () => {
224
+ const message = 'postgres://user:pass@localhost:5432/db connection failed';
225
+
226
+ const result = sanitizeErrorMessage(message);
227
+
228
+ assert.ok(!result.includes('pass'));
229
+ });
230
+
231
+ it('removes email addresses', () => {
232
+ const message = 'User user@example.com not found';
233
+
234
+ const result = sanitizeErrorMessage(message);
235
+
236
+ assert.ok(!result.includes('user@example.com'));
237
+ });
238
+
239
+ it('removes stack traces', () => {
240
+ const message = 'Error\n at Function.Module._load\n at Object.<anonymous>';
241
+
242
+ const result = sanitizeErrorMessage(message);
243
+
244
+ assert.ok(!result.includes('Module._load'));
245
+ });
246
+
247
+ it('preserves error type', () => {
248
+ const message = 'TypeError: Cannot read property';
249
+
250
+ const result = sanitizeErrorMessage(message);
251
+
252
+ assert.ok(result.includes('TypeError') || result.includes('error'));
253
+ });
254
+ });
255
+
256
+ describe('generateErrorCode', () => {
257
+ it('generates complete error handling module', () => {
258
+ const code = generateErrorCode({
259
+ language: 'javascript',
260
+ features: ['handler', 'logging', 'degradation'],
261
+ });
262
+
263
+ assert.ok(code.includes('function') || code.includes('class'));
264
+ });
265
+
266
+ it('generates TypeScript error handling', () => {
267
+ const code = generateErrorCode({
268
+ language: 'typescript',
269
+ });
270
+
271
+ assert.ok(code.includes('interface') || code.includes(':'));
272
+ });
273
+
274
+ it('generates Python error handling', () => {
275
+ const code = generateErrorCode({
276
+ language: 'python',
277
+ });
278
+
279
+ assert.ok(code.includes('def') || code.includes('class'));
280
+ });
281
+
282
+ it('includes error types', () => {
283
+ const code = generateErrorCode({
284
+ errorTypes: ['ValidationError', 'AuthError', 'NotFoundError'],
285
+ });
286
+
287
+ assert.ok(code.includes('ValidationError') || code.includes('Error'));
288
+ });
289
+
290
+ it('generates HTTP error responses', () => {
291
+ const code = generateErrorCode({
292
+ httpErrors: true,
293
+ });
294
+
295
+ assert.ok(code.includes('400') || code.includes('404') || code.includes('500'));
296
+ });
297
+ });
298
+ });
@@ -0,0 +1,372 @@
1
+ /**
2
+ * Vision Command Module
3
+ *
4
+ * CLI commands for vision operations
5
+ */
6
+
7
+ const {
8
+ analyzeImage,
9
+ compareImages,
10
+ extractComponents,
11
+ auditAccessibility,
12
+ } = require('./gemini-vision.js');
13
+
14
+ /**
15
+ * Parse command line arguments
16
+ * @param {string} input - Command input
17
+ * @returns {Object} Parsed arguments
18
+ */
19
+ function parseArgs(input) {
20
+ const parts = [];
21
+ let current = '';
22
+ let inQuotes = false;
23
+
24
+ for (const char of input) {
25
+ if (char === '"' && !inQuotes) {
26
+ inQuotes = true;
27
+ } else if (char === '"' && inQuotes) {
28
+ inQuotes = false;
29
+ } else if (char === ' ' && !inQuotes) {
30
+ if (current) {
31
+ parts.push(current);
32
+ current = '';
33
+ }
34
+ } else {
35
+ current += char;
36
+ }
37
+ }
38
+ if (current) parts.push(current);
39
+
40
+ const result = {
41
+ command: parts[0] || 'analyze',
42
+ };
43
+
44
+ let argIndex = 1;
45
+
46
+ // Handle positional arguments based on command
47
+ if (result.command === 'analyze' || result.command === 'a11y' || result.command === 'extract') {
48
+ if (parts[1] && !parts[1].startsWith('--')) {
49
+ result.imagePath = parts[1];
50
+ argIndex = 2;
51
+ }
52
+ } else if (result.command === 'compare') {
53
+ if (parts[1] && !parts[1].startsWith('--')) {
54
+ result.beforeImage = parts[1];
55
+ argIndex = 2;
56
+ }
57
+ if (parts[2] && !parts[2].startsWith('--')) {
58
+ result.afterImage = parts[2];
59
+ argIndex = 3;
60
+ }
61
+ }
62
+
63
+ // Parse flags
64
+ for (let i = argIndex; i < parts.length; i++) {
65
+ const part = parts[i];
66
+
67
+ if (part === '--prompt' && parts[i + 1]) {
68
+ result.prompt = parts[i + 1];
69
+ i++;
70
+ } else if (part === '--type' && parts[i + 1]) {
71
+ result.type = parts[i + 1];
72
+ i++;
73
+ } else if (part === '--format' && parts[i + 1]) {
74
+ result.format = parts[i + 1];
75
+ i++;
76
+ }
77
+ }
78
+
79
+ return result;
80
+ }
81
+
82
+ /**
83
+ * Format analysis output
84
+ * @param {Object} analysis - Analysis result
85
+ * @returns {string} Formatted output
86
+ */
87
+ function formatAnalysis(analysis) {
88
+ const lines = [
89
+ 'Image Analysis',
90
+ '═'.repeat(40),
91
+ '',
92
+ 'Description:',
93
+ analysis.description || 'No description available',
94
+ '',
95
+ ];
96
+
97
+ if (analysis.elements && analysis.elements.length > 0) {
98
+ lines.push('Elements Found:');
99
+ for (const element of analysis.elements) {
100
+ lines.push(` - ${element}`);
101
+ }
102
+ }
103
+
104
+ return lines.join('\n');
105
+ }
106
+
107
+ /**
108
+ * Format comparison output
109
+ * @param {Object} comparison - Comparison result
110
+ * @returns {string} Formatted output
111
+ */
112
+ function formatComparison(comparison) {
113
+ const lines = [
114
+ 'Image Comparison',
115
+ '═'.repeat(40),
116
+ '',
117
+ `Similarity: ${Math.round(comparison.similarity * 100)}%`,
118
+ '',
119
+ ];
120
+
121
+ if (comparison.differences.length === 0) {
122
+ lines.push('Images are identical - no differences found.');
123
+ } else {
124
+ lines.push(`Found ${comparison.differences.length} difference(s):`);
125
+ lines.push('');
126
+
127
+ for (const diff of comparison.differences) {
128
+ const icon = diff.type === 'added' ? '+' : diff.type === 'removed' ? '-' : '~';
129
+ lines.push(` ${icon} [${diff.type.toUpperCase()}] ${diff.description}`);
130
+ }
131
+ }
132
+
133
+ return lines.join('\n');
134
+ }
135
+
136
+ /**
137
+ * Format accessibility report
138
+ * @param {Object} audit - Accessibility audit
139
+ * @returns {string} Formatted output
140
+ */
141
+ function formatAccessibilityReport(audit) {
142
+ const lines = [
143
+ 'Accessibility Audit',
144
+ '═'.repeat(40),
145
+ '',
146
+ `Score: ${audit.score}/100`,
147
+ '',
148
+ ];
149
+
150
+ if (audit.issues.length === 0) {
151
+ lines.push('No accessibility issues found!');
152
+ } else {
153
+ // Group by severity
154
+ const bySeverity = {
155
+ high: [],
156
+ medium: [],
157
+ low: [],
158
+ };
159
+
160
+ for (const issue of audit.issues) {
161
+ const severity = issue.severity || 'medium';
162
+ if (!bySeverity[severity]) bySeverity[severity] = [];
163
+ bySeverity[severity].push(issue);
164
+ }
165
+
166
+ if (bySeverity.high.length > 0) {
167
+ lines.push('HIGH Severity:');
168
+ for (const issue of bySeverity.high) {
169
+ lines.push(` - [${issue.type}] ${issue.description}`);
170
+ }
171
+ lines.push('');
172
+ }
173
+
174
+ if (bySeverity.medium.length > 0) {
175
+ lines.push('MEDIUM Severity:');
176
+ for (const issue of bySeverity.medium) {
177
+ lines.push(` - [${issue.type}] ${issue.description}`);
178
+ }
179
+ lines.push('');
180
+ }
181
+
182
+ if (bySeverity.low.length > 0) {
183
+ lines.push('LOW Severity:');
184
+ for (const issue of bySeverity.low) {
185
+ lines.push(` - [${issue.type}] ${issue.description}`);
186
+ }
187
+ }
188
+ }
189
+
190
+ return lines.join('\n');
191
+ }
192
+
193
+ /**
194
+ * Format components output
195
+ * @param {Array} components - Extracted components
196
+ * @returns {string} Formatted output
197
+ */
198
+ function formatComponents(components) {
199
+ const lines = [
200
+ 'Extracted Components',
201
+ '═'.repeat(40),
202
+ '',
203
+ `Found ${components.length} component(s):`,
204
+ '',
205
+ ];
206
+
207
+ for (const comp of components) {
208
+ let line = ` - [${comp.type}]`;
209
+ if (comp.label) line += ` "${comp.label}"`;
210
+ else if (comp.placeholder) line += ` (placeholder: "${comp.placeholder}")`;
211
+ else if (comp.content) line += ` "${comp.content.substring(0, 30)}..."`;
212
+ lines.push(line);
213
+ }
214
+
215
+ return lines.join('\n');
216
+ }
217
+
218
+ /**
219
+ * Vision Command class
220
+ */
221
+ class VisionCommand {
222
+ /**
223
+ * Create a vision command handler
224
+ * @param {Object} options - Dependencies
225
+ * @param {Object} options.client - Gemini vision client
226
+ */
227
+ constructor(options) {
228
+ this.client = options.client;
229
+ }
230
+
231
+ /**
232
+ * Execute a command
233
+ * @param {string} input - Command input
234
+ * @returns {Promise<Object>} Execution result
235
+ */
236
+ async execute(input) {
237
+ const args = parseArgs(input);
238
+
239
+ switch (args.command) {
240
+ case 'analyze':
241
+ return this.executeAnalyze(args);
242
+
243
+ case 'compare':
244
+ return this.executeCompare(args);
245
+
246
+ case 'a11y':
247
+ return this.executeA11y(args);
248
+
249
+ case 'extract':
250
+ return this.executeExtract(args);
251
+
252
+ default:
253
+ return {
254
+ success: false,
255
+ output: `Unknown command: ${args.command}`,
256
+ };
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Execute analyze command
262
+ * @param {Object} args - Parsed arguments
263
+ * @returns {Promise<Object>} Analysis result
264
+ */
265
+ async executeAnalyze(args) {
266
+ try {
267
+ const analysis = await analyzeImage(this.client, {
268
+ imagePath: args.imagePath,
269
+ prompt: args.prompt,
270
+ });
271
+
272
+ return {
273
+ success: true,
274
+ output: formatAnalysis(analysis),
275
+ analysis,
276
+ };
277
+ } catch (error) {
278
+ return {
279
+ success: false,
280
+ output: `Analysis failed: ${error.message}`,
281
+ error: error.message,
282
+ };
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Execute compare command
288
+ * @param {Object} args - Parsed arguments
289
+ * @returns {Promise<Object>} Comparison result
290
+ */
291
+ async executeCompare(args) {
292
+ try {
293
+ const comparison = await compareImages(this.client, {
294
+ beforeImage: args.beforeImage,
295
+ afterImage: args.afterImage,
296
+ });
297
+
298
+ return {
299
+ success: true,
300
+ output: formatComparison(comparison),
301
+ comparison,
302
+ };
303
+ } catch (error) {
304
+ return {
305
+ success: false,
306
+ output: `Comparison failed: ${error.message}`,
307
+ error: error.message,
308
+ };
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Execute accessibility audit command
314
+ * @param {Object} args - Parsed arguments
315
+ * @returns {Promise<Object>} Audit result
316
+ */
317
+ async executeA11y(args) {
318
+ try {
319
+ const audit = await auditAccessibility(this.client, {
320
+ imagePath: args.imagePath,
321
+ });
322
+
323
+ return {
324
+ success: true,
325
+ output: formatAccessibilityReport(audit),
326
+ audit,
327
+ };
328
+ } catch (error) {
329
+ return {
330
+ success: false,
331
+ output: `Audit failed: ${error.message}`,
332
+ error: error.message,
333
+ };
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Execute component extraction command
339
+ * @param {Object} args - Parsed arguments
340
+ * @returns {Promise<Object>} Extraction result
341
+ */
342
+ async executeExtract(args) {
343
+ try {
344
+ const types = args.type ? [args.type] : undefined;
345
+ const result = await extractComponents(this.client, {
346
+ imagePath: args.imagePath,
347
+ types,
348
+ });
349
+
350
+ return {
351
+ success: true,
352
+ output: formatComponents(result.components),
353
+ components: result.components,
354
+ };
355
+ } catch (error) {
356
+ return {
357
+ success: false,
358
+ output: `Extraction failed: ${error.message}`,
359
+ error: error.message,
360
+ };
361
+ }
362
+ }
363
+ }
364
+
365
+ module.exports = {
366
+ VisionCommand,
367
+ parseArgs,
368
+ formatAnalysis,
369
+ formatComparison,
370
+ formatAccessibilityReport,
371
+ formatComponents,
372
+ };