tlc-claude-code 1.2.29 → 1.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 (80) hide show
  1. package/dashboard/dist/components/UsagePane.d.ts +13 -0
  2. package/dashboard/dist/components/UsagePane.js +51 -0
  3. package/dashboard/dist/components/UsagePane.test.d.ts +1 -0
  4. package/dashboard/dist/components/UsagePane.test.js +142 -0
  5. package/dashboard/dist/components/WorkspaceDocsPane.d.ts +19 -0
  6. package/dashboard/dist/components/WorkspaceDocsPane.js +146 -0
  7. package/dashboard/dist/components/WorkspaceDocsPane.test.d.ts +1 -0
  8. package/dashboard/dist/components/WorkspaceDocsPane.test.js +242 -0
  9. package/dashboard/dist/components/WorkspacePane.d.ts +18 -0
  10. package/dashboard/dist/components/WorkspacePane.js +17 -0
  11. package/dashboard/dist/components/WorkspacePane.test.d.ts +1 -0
  12. package/dashboard/dist/components/WorkspacePane.test.js +84 -0
  13. package/package.json +1 -1
  14. package/server/lib/architecture-command.js +450 -0
  15. package/server/lib/architecture-command.test.js +754 -0
  16. package/server/lib/ast-analyzer.js +324 -0
  17. package/server/lib/ast-analyzer.test.js +437 -0
  18. package/server/lib/auth-system.test.js +4 -1
  19. package/server/lib/boundary-detector.js +427 -0
  20. package/server/lib/boundary-detector.test.js +320 -0
  21. package/server/lib/budget-alerts.js +138 -0
  22. package/server/lib/budget-alerts.test.js +235 -0
  23. package/server/lib/candidates-tracker.js +210 -0
  24. package/server/lib/candidates-tracker.test.js +300 -0
  25. package/server/lib/checkpoint-manager.js +251 -0
  26. package/server/lib/checkpoint-manager.test.js +474 -0
  27. package/server/lib/circular-detector.js +337 -0
  28. package/server/lib/circular-detector.test.js +353 -0
  29. package/server/lib/cohesion-analyzer.js +310 -0
  30. package/server/lib/cohesion-analyzer.test.js +447 -0
  31. package/server/lib/contract-testing.js +625 -0
  32. package/server/lib/contract-testing.test.js +342 -0
  33. package/server/lib/conversion-planner.js +469 -0
  34. package/server/lib/conversion-planner.test.js +361 -0
  35. package/server/lib/convert-command.js +351 -0
  36. package/server/lib/convert-command.test.js +608 -0
  37. package/server/lib/coupling-calculator.js +189 -0
  38. package/server/lib/coupling-calculator.test.js +509 -0
  39. package/server/lib/dependency-graph.js +367 -0
  40. package/server/lib/dependency-graph.test.js +516 -0
  41. package/server/lib/duplication-detector.js +349 -0
  42. package/server/lib/duplication-detector.test.js +401 -0
  43. package/server/lib/example-service.js +616 -0
  44. package/server/lib/example-service.test.js +397 -0
  45. package/server/lib/impact-scorer.js +184 -0
  46. package/server/lib/impact-scorer.test.js +211 -0
  47. package/server/lib/mermaid-generator.js +358 -0
  48. package/server/lib/mermaid-generator.test.js +301 -0
  49. package/server/lib/messaging-patterns.js +750 -0
  50. package/server/lib/messaging-patterns.test.js +213 -0
  51. package/server/lib/microservice-template.js +386 -0
  52. package/server/lib/microservice-template.test.js +325 -0
  53. package/server/lib/new-project-microservice.js +450 -0
  54. package/server/lib/new-project-microservice.test.js +600 -0
  55. package/server/lib/refactor-command.js +326 -0
  56. package/server/lib/refactor-command.test.js +528 -0
  57. package/server/lib/refactor-executor.js +254 -0
  58. package/server/lib/refactor-executor.test.js +305 -0
  59. package/server/lib/refactor-observer.js +292 -0
  60. package/server/lib/refactor-observer.test.js +422 -0
  61. package/server/lib/refactor-progress.js +193 -0
  62. package/server/lib/refactor-progress.test.js +251 -0
  63. package/server/lib/refactor-reporter.js +237 -0
  64. package/server/lib/refactor-reporter.test.js +247 -0
  65. package/server/lib/semantic-analyzer.js +198 -0
  66. package/server/lib/semantic-analyzer.test.js +474 -0
  67. package/server/lib/service-scaffold.js +486 -0
  68. package/server/lib/service-scaffold.test.js +373 -0
  69. package/server/lib/shared-kernel.js +578 -0
  70. package/server/lib/shared-kernel.test.js +255 -0
  71. package/server/lib/traefik-config.js +282 -0
  72. package/server/lib/traefik-config.test.js +312 -0
  73. package/server/lib/usage-command.js +218 -0
  74. package/server/lib/usage-command.test.js +391 -0
  75. package/server/lib/usage-formatter.js +192 -0
  76. package/server/lib/usage-formatter.test.js +267 -0
  77. package/server/lib/usage-history.js +122 -0
  78. package/server/lib/usage-history.test.js +206 -0
  79. package/server/package-lock.json +14 -0
  80. package/server/package.json +1 -0
@@ -0,0 +1,255 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ SharedKernel,
4
+ createSharedKernel,
5
+ generatePackageJson,
6
+ generateTypes,
7
+ generateContracts,
8
+ generateEvents,
9
+ generateUtils,
10
+ } from './shared-kernel.js';
11
+
12
+ describe('shared-kernel', () => {
13
+ describe('SharedKernel', () => {
14
+ describe('generate', () => {
15
+ it('creates shared directory structure', () => {
16
+ const kernel = new SharedKernel({ projectName: 'myapp' });
17
+ const result = kernel.generate({
18
+ services: ['user', 'order'],
19
+ events: ['UserCreated', 'OrderPlaced'],
20
+ });
21
+
22
+ expect(result.directories).toBeDefined();
23
+ expect(result.directories).toContain('shared');
24
+ });
25
+
26
+ it('creates types/, contracts/, events/, utils/ subdirectories', () => {
27
+ const kernel = new SharedKernel({ projectName: 'myapp' });
28
+ const result = kernel.generate({
29
+ services: ['user'],
30
+ events: ['UserCreated'],
31
+ });
32
+
33
+ expect(result.directories).toContain('shared/types');
34
+ expect(result.directories).toContain('shared/contracts');
35
+ expect(result.directories).toContain('shared/events');
36
+ expect(result.directories).toContain('shared/utils');
37
+ });
38
+
39
+ it('returns files array with generated content', () => {
40
+ const kernel = new SharedKernel({ projectName: 'myapp' });
41
+ const result = kernel.generate({
42
+ services: ['user'],
43
+ events: ['UserCreated'],
44
+ });
45
+
46
+ expect(result.files).toBeDefined();
47
+ expect(Array.isArray(result.files)).toBe(true);
48
+ expect(result.files.length).toBeGreaterThan(0);
49
+ });
50
+
51
+ it('handles empty services array', () => {
52
+ const kernel = new SharedKernel({ projectName: 'myapp' });
53
+ const result = kernel.generate({
54
+ services: [],
55
+ events: ['SomeEvent'],
56
+ });
57
+
58
+ expect(result.directories).toContain('shared');
59
+ expect(result.files).toBeDefined();
60
+ });
61
+
62
+ it('handles empty events array', () => {
63
+ const kernel = new SharedKernel({ projectName: 'myapp' });
64
+ const result = kernel.generate({
65
+ services: ['user'],
66
+ events: [],
67
+ });
68
+
69
+ expect(result.directories).toContain('shared');
70
+ expect(result.files).toBeDefined();
71
+ });
72
+ });
73
+ });
74
+
75
+ describe('generatePackageJson', () => {
76
+ it('has correct name format', () => {
77
+ const pkg = generatePackageJson({ projectName: 'myapp' });
78
+
79
+ expect(pkg.name).toBe('@myapp/shared');
80
+ });
81
+
82
+ it('has exports field', () => {
83
+ const pkg = generatePackageJson({ projectName: 'myapp' });
84
+
85
+ expect(pkg.exports).toBeDefined();
86
+ expect(pkg.exports['./types']).toBeDefined();
87
+ expect(pkg.exports['./contracts']).toBeDefined();
88
+ expect(pkg.exports['./events']).toBeDefined();
89
+ expect(pkg.exports['./utils']).toBeDefined();
90
+ });
91
+
92
+ it('includes version and description', () => {
93
+ const pkg = generatePackageJson({ projectName: 'myapp' });
94
+
95
+ expect(pkg.version).toBeDefined();
96
+ expect(pkg.description).toBeDefined();
97
+ });
98
+ });
99
+
100
+ describe('generateTypes', () => {
101
+ it('includes common types', () => {
102
+ const types = generateTypes({ services: ['user'] });
103
+
104
+ expect(types).toContain('ID');
105
+ expect(types).toContain('Timestamp');
106
+ expect(types).toContain('PaginatedResponse');
107
+ });
108
+
109
+ it('includes service-specific types', () => {
110
+ const types = generateTypes({ services: ['user', 'order'] });
111
+
112
+ expect(types).toContain('User');
113
+ expect(types).toContain('Order');
114
+ });
115
+
116
+ it('generates syntactically valid TypeScript', () => {
117
+ const types = generateTypes({ services: ['user'] });
118
+
119
+ // Should have proper export statements
120
+ expect(types).toContain('export');
121
+ // Should have type or interface declarations
122
+ expect(types).toMatch(/export\s+(type|interface)/);
123
+ // Should not have obvious syntax errors (unbalanced braces)
124
+ const openBraces = (types.match(/\{/g) || []).length;
125
+ const closeBraces = (types.match(/\}/g) || []).length;
126
+ expect(openBraces).toBe(closeBraces);
127
+ });
128
+
129
+ it('handles empty services array', () => {
130
+ const types = generateTypes({ services: [] });
131
+
132
+ expect(types).toContain('ID');
133
+ expect(types).toContain('Timestamp');
134
+ });
135
+ });
136
+
137
+ describe('generateContracts', () => {
138
+ it('generates valid JSON Schema for services', () => {
139
+ const contracts = generateContracts(['user', 'order']);
140
+
141
+ expect(contracts.user).toBeDefined();
142
+ expect(contracts.order).toBeDefined();
143
+ expect(contracts.user.$schema).toContain('json-schema');
144
+ });
145
+
146
+ it('has request/response schemas', () => {
147
+ const contracts = generateContracts(['user']);
148
+
149
+ expect(contracts.user.definitions).toBeDefined();
150
+ expect(contracts.user.definitions.Request).toBeDefined();
151
+ expect(contracts.user.definitions.Response).toBeDefined();
152
+ });
153
+
154
+ it('includes error response schema', () => {
155
+ const contracts = generateContracts(['user']);
156
+
157
+ expect(contracts.user.definitions.ErrorResponse).toBeDefined();
158
+ expect(contracts.user.definitions.ErrorResponse.properties.error).toBeDefined();
159
+ });
160
+
161
+ it('handles empty services array', () => {
162
+ const contracts = generateContracts([]);
163
+
164
+ expect(contracts).toBeDefined();
165
+ expect(Object.keys(contracts).length).toBe(0);
166
+ });
167
+ });
168
+
169
+ describe('generateEvents', () => {
170
+ it('includes metadata fields', () => {
171
+ const events = generateEvents(['UserCreated', 'OrderPlaced']);
172
+
173
+ expect(events.base).toBeDefined();
174
+ expect(events.base).toContain('id');
175
+ expect(events.base).toContain('timestamp');
176
+ expect(events.base).toContain('source');
177
+ });
178
+
179
+ it('generates per-event schema with payload types', () => {
180
+ const events = generateEvents(['UserCreated', 'OrderPlaced']);
181
+
182
+ expect(events.schemas.UserCreated).toBeDefined();
183
+ expect(events.schemas.OrderPlaced).toBeDefined();
184
+ expect(events.schemas.UserCreated).toContain('payload');
185
+ });
186
+
187
+ it('generates event catalog listing all events', () => {
188
+ const events = generateEvents(['UserCreated', 'OrderPlaced']);
189
+
190
+ expect(events.catalog).toBeDefined();
191
+ expect(events.catalog).toContain('UserCreated');
192
+ expect(events.catalog).toContain('OrderPlaced');
193
+ });
194
+
195
+ it('handles empty events array', () => {
196
+ const events = generateEvents([]);
197
+
198
+ expect(events.base).toBeDefined();
199
+ expect(events.catalog).toBeDefined();
200
+ });
201
+ });
202
+
203
+ describe('generateUtils', () => {
204
+ it('includes logger utility', () => {
205
+ const utils = generateUtils();
206
+
207
+ expect(utils.logger).toBeDefined();
208
+ expect(utils.logger).toContain('log');
209
+ });
210
+
211
+ it('includes error classes', () => {
212
+ const utils = generateUtils();
213
+
214
+ expect(utils.errors).toBeDefined();
215
+ expect(utils.errors).toContain('AppError');
216
+ expect(utils.errors).toContain('ValidationError');
217
+ expect(utils.errors).toContain('NotFoundError');
218
+ });
219
+
220
+ it('error classes extend base AppError', () => {
221
+ const utils = generateUtils();
222
+
223
+ expect(utils.errors).toContain('extends AppError');
224
+ });
225
+
226
+ it('includes validation helpers', () => {
227
+ const utils = generateUtils();
228
+
229
+ expect(utils.validation).toBeDefined();
230
+ expect(utils.validation).toContain('validate');
231
+ });
232
+ });
233
+
234
+ describe('createSharedKernel', () => {
235
+ it('creates kernel instance with methods', () => {
236
+ const kernel = createSharedKernel({ projectName: 'myapp' });
237
+
238
+ expect(kernel.generate).toBeDefined();
239
+ expect(typeof kernel.generate).toBe('function');
240
+ });
241
+
242
+ it('uses provided options', () => {
243
+ const kernel = createSharedKernel({ projectName: 'customapp' });
244
+ const result = kernel.generate({
245
+ services: ['user'],
246
+ events: [],
247
+ });
248
+
249
+ // Find the package.json file in result
250
+ const pkgFile = result.files.find(f => f.path === 'shared/package.json');
251
+ expect(pkgFile).toBeDefined();
252
+ expect(pkgFile.content).toContain('@customapp/shared');
253
+ });
254
+ });
255
+ });
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Traefik API Gateway Configuration Generator
3
+ * Generates Traefik configuration files for microservice routing
4
+ */
5
+
6
+ class TraefikConfig {
7
+ constructor(options = {}) {
8
+ this.options = options;
9
+ }
10
+
11
+ /**
12
+ * Generate main traefik.yml static configuration
13
+ * @param {Object} config - Configuration options
14
+ * @param {string[]} config.services - List of service names
15
+ * @param {string} config.domain - Domain for routing
16
+ * @param {boolean} config.tls - Enable TLS/HTTPS
17
+ * @returns {string} YAML configuration
18
+ */
19
+ generateTraefikYml(config) {
20
+ const { services = [], domain = 'localhost', tls = false } = config;
21
+
22
+ const traefikConfig = {
23
+ entryPoints: {
24
+ web: {
25
+ address: ':80',
26
+ },
27
+ },
28
+ api: {
29
+ dashboard: true,
30
+ insecure: true,
31
+ },
32
+ providers: {
33
+ docker: {
34
+ exposedByDefault: false,
35
+ network: 'traefik-net',
36
+ },
37
+ file: {
38
+ directory: '/etc/traefik/dynamic',
39
+ watch: true,
40
+ },
41
+ },
42
+ };
43
+
44
+ // Add websecure entrypoint if TLS enabled
45
+ if (tls) {
46
+ traefikConfig.entryPoints.websecure = {
47
+ address: ':443',
48
+ };
49
+ }
50
+
51
+ return this.toYaml(traefikConfig);
52
+ }
53
+
54
+ /**
55
+ * Generate dynamic routing configuration
56
+ * @param {Object} config - Configuration options
57
+ * @param {string[]} config.services - List of service names
58
+ * @param {string} config.domain - Domain for routing
59
+ * @param {boolean} config.tls - Enable TLS/HTTPS
60
+ * @returns {string} YAML configuration
61
+ */
62
+ generateDynamicConfig(config) {
63
+ const { services = [], domain = 'localhost', tls = false } = config;
64
+
65
+ const dynamicConfig = {
66
+ http: {
67
+ routers: {},
68
+ services: {},
69
+ middlewares: {},
70
+ },
71
+ };
72
+
73
+ // Generate routers and services for each service
74
+ for (const service of services) {
75
+ const serviceName = service.toLowerCase();
76
+ const defaultPort = 3000;
77
+
78
+ // Router
79
+ dynamicConfig.http.routers[`${serviceName}-router`] = {
80
+ rule: `PathPrefix(\`/api/${serviceName}\`)`,
81
+ service: `${serviceName}-service`,
82
+ entryPoints: ['web'],
83
+ middlewares: [`strip-${serviceName}`, 'rate-limit'],
84
+ };
85
+
86
+ // Service
87
+ dynamicConfig.http.services[`${serviceName}-service`] = {
88
+ loadBalancer: {
89
+ servers: [
90
+ { url: `http://${serviceName}-service:${defaultPort}` },
91
+ ],
92
+ healthCheck: {
93
+ path: '/health',
94
+ interval: '10s',
95
+ timeout: '3s',
96
+ },
97
+ },
98
+ };
99
+
100
+ // Strip prefix middleware for this service
101
+ dynamicConfig.http.middlewares[`strip-${serviceName}`] = {
102
+ stripPrefix: {
103
+ prefixes: [`/api/${serviceName}`],
104
+ },
105
+ };
106
+ }
107
+
108
+ // Add common middlewares
109
+ dynamicConfig.http.middlewares['rate-limit'] = {
110
+ rateLimit: {
111
+ average: 100,
112
+ burst: 50,
113
+ },
114
+ };
115
+
116
+ dynamicConfig.http.middlewares['secure-headers'] = {
117
+ headers: {
118
+ customResponseHeaders: {
119
+ 'X-Frame-Options': 'DENY',
120
+ 'X-Content-Type-Options': 'nosniff',
121
+ 'X-XSS-Protection': '1; mode=block',
122
+ },
123
+ },
124
+ };
125
+
126
+ return this.toYaml(dynamicConfig);
127
+ }
128
+
129
+ /**
130
+ * Generate router configuration for a single service
131
+ * @param {string} serviceName - Service name
132
+ * @param {number} port - Service port
133
+ * @returns {string} YAML configuration
134
+ */
135
+ generateServiceRouter(serviceName, port) {
136
+ const name = serviceName.toLowerCase();
137
+
138
+ const routerConfig = {
139
+ http: {
140
+ routers: {
141
+ [`${name}-router`]: {
142
+ rule: `PathPrefix(\`/api/${name}\`)`,
143
+ service: `${name}-service`,
144
+ entryPoints: ['web'],
145
+ middlewares: [`strip-${name}`],
146
+ },
147
+ },
148
+ services: {
149
+ [`${name}-service`]: {
150
+ loadBalancer: {
151
+ servers: [
152
+ { url: `http://${name}-service:${port}` },
153
+ ],
154
+ },
155
+ },
156
+ },
157
+ middlewares: {
158
+ [`strip-${name}`]: {
159
+ stripPrefix: {
160
+ prefixes: [`/api/${name}`],
161
+ },
162
+ },
163
+ },
164
+ },
165
+ };
166
+
167
+ return this.toYaml(routerConfig);
168
+ }
169
+
170
+ /**
171
+ * Generate common middlewares configuration
172
+ * @returns {string} YAML configuration
173
+ */
174
+ generateMiddlewares() {
175
+ const middlewaresConfig = {
176
+ http: {
177
+ middlewares: {
178
+ 'rate-limit': {
179
+ rateLimit: {
180
+ average: 100,
181
+ burst: 50,
182
+ },
183
+ },
184
+ 'strip-api': {
185
+ stripPrefix: {
186
+ prefixes: ['/api'],
187
+ },
188
+ },
189
+ 'secure-headers': {
190
+ headers: {
191
+ customResponseHeaders: {
192
+ 'X-Frame-Options': 'DENY',
193
+ 'X-Content-Type-Options': 'nosniff',
194
+ 'X-XSS-Protection': '1; mode=block',
195
+ 'Referrer-Policy': 'strict-origin-when-cross-origin',
196
+ },
197
+ },
198
+ },
199
+ },
200
+ },
201
+ };
202
+
203
+ return this.toYaml(middlewaresConfig);
204
+ }
205
+
206
+ /**
207
+ * Generate TLS configuration with Let's Encrypt
208
+ * @param {string} domain - Domain for certificate
209
+ * @returns {string} YAML configuration
210
+ */
211
+ generateTlsConfig(domain) {
212
+ const tlsConfig = {
213
+ certificatesResolvers: {
214
+ letsencrypt: {
215
+ acme: {
216
+ email: `admin@${domain}`,
217
+ storage: '/etc/traefik/acme.json',
218
+ httpChallenge: {
219
+ entryPoint: 'web',
220
+ },
221
+ },
222
+ },
223
+ },
224
+ tls: {
225
+ options: {
226
+ default: {
227
+ minVersion: 'VersionTLS12',
228
+ sniStrict: true,
229
+ },
230
+ },
231
+ certificates: [
232
+ {
233
+ certFile: `/etc/traefik/certs/${domain}.crt`,
234
+ keyFile: `/etc/traefik/certs/${domain}.key`,
235
+ },
236
+ ],
237
+ },
238
+ };
239
+
240
+ return this.toYaml(tlsConfig);
241
+ }
242
+
243
+ /**
244
+ * Simple YAML serializer
245
+ * @param {Object} obj - Object to serialize
246
+ * @param {number} indent - Current indentation level
247
+ * @returns {string} YAML string
248
+ */
249
+ toYaml(obj, indent = 0) {
250
+ const spaces = ' '.repeat(indent);
251
+ let yaml = '';
252
+
253
+ for (const [key, value] of Object.entries(obj)) {
254
+ if (value === null || value === undefined) continue;
255
+
256
+ if (Array.isArray(value)) {
257
+ yaml += `${spaces}${key}:\n`;
258
+ for (const item of value) {
259
+ if (typeof item === 'object') {
260
+ // For array of objects, use dash notation
261
+ const itemYaml = this.toYaml(item, 0).trim().split('\n');
262
+ yaml += `${spaces} - ${itemYaml[0]}\n`;
263
+ for (let i = 1; i < itemYaml.length; i++) {
264
+ yaml += `${spaces} ${itemYaml[i]}\n`;
265
+ }
266
+ } else {
267
+ yaml += `${spaces} - ${item}\n`;
268
+ }
269
+ }
270
+ } else if (typeof value === 'object') {
271
+ yaml += `${spaces}${key}:\n`;
272
+ yaml += this.toYaml(value, indent + 1);
273
+ } else {
274
+ yaml += `${spaces}${key}: ${value}\n`;
275
+ }
276
+ }
277
+
278
+ return yaml;
279
+ }
280
+ }
281
+
282
+ module.exports = { TraefikConfig };