tlc-claude-code 1.3.0 → 1.4.1

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 (105) hide show
  1. package/dashboard/dist/components/AuditPane.d.ts +30 -0
  2. package/dashboard/dist/components/AuditPane.js +127 -0
  3. package/dashboard/dist/components/AuditPane.test.d.ts +1 -0
  4. package/dashboard/dist/components/AuditPane.test.js +339 -0
  5. package/dashboard/dist/components/CompliancePane.d.ts +39 -0
  6. package/dashboard/dist/components/CompliancePane.js +96 -0
  7. package/dashboard/dist/components/CompliancePane.test.d.ts +1 -0
  8. package/dashboard/dist/components/CompliancePane.test.js +183 -0
  9. package/dashboard/dist/components/SSOPane.d.ts +36 -0
  10. package/dashboard/dist/components/SSOPane.js +71 -0
  11. package/dashboard/dist/components/SSOPane.test.d.ts +1 -0
  12. package/dashboard/dist/components/SSOPane.test.js +155 -0
  13. package/dashboard/dist/components/WorkspaceDocsPane.js +0 -16
  14. package/dashboard/dist/components/WorkspacePane.d.ts +1 -1
  15. package/dashboard/dist/components/ZeroRetentionPane.d.ts +44 -0
  16. package/dashboard/dist/components/ZeroRetentionPane.js +83 -0
  17. package/dashboard/dist/components/ZeroRetentionPane.test.d.ts +1 -0
  18. package/dashboard/dist/components/ZeroRetentionPane.test.js +160 -0
  19. package/package.json +1 -1
  20. package/server/lib/access-control-doc.js +541 -0
  21. package/server/lib/access-control-doc.test.js +672 -0
  22. package/server/lib/adr-generator.js +423 -0
  23. package/server/lib/adr-generator.test.js +586 -0
  24. package/server/lib/agent-progress-monitor.js +223 -0
  25. package/server/lib/agent-progress-monitor.test.js +202 -0
  26. package/server/lib/audit-attribution.js +191 -0
  27. package/server/lib/audit-attribution.test.js +359 -0
  28. package/server/lib/audit-classifier.js +202 -0
  29. package/server/lib/audit-classifier.test.js +209 -0
  30. package/server/lib/audit-command.js +275 -0
  31. package/server/lib/audit-command.test.js +325 -0
  32. package/server/lib/audit-exporter.js +380 -0
  33. package/server/lib/audit-exporter.test.js +464 -0
  34. package/server/lib/audit-logger.js +236 -0
  35. package/server/lib/audit-logger.test.js +364 -0
  36. package/server/lib/audit-query.js +257 -0
  37. package/server/lib/audit-query.test.js +352 -0
  38. package/server/lib/audit-storage.js +269 -0
  39. package/server/lib/audit-storage.test.js +272 -0
  40. package/server/lib/bulk-repo-init.js +342 -0
  41. package/server/lib/bulk-repo-init.test.js +388 -0
  42. package/server/lib/compliance-checklist.js +866 -0
  43. package/server/lib/compliance-checklist.test.js +476 -0
  44. package/server/lib/compliance-command.js +616 -0
  45. package/server/lib/compliance-command.test.js +551 -0
  46. package/server/lib/compliance-reporter.js +692 -0
  47. package/server/lib/compliance-reporter.test.js +707 -0
  48. package/server/lib/data-flow-doc.js +665 -0
  49. package/server/lib/data-flow-doc.test.js +659 -0
  50. package/server/lib/ephemeral-storage.js +249 -0
  51. package/server/lib/ephemeral-storage.test.js +254 -0
  52. package/server/lib/evidence-collector.js +627 -0
  53. package/server/lib/evidence-collector.test.js +901 -0
  54. package/server/lib/flow-diagram-generator.js +474 -0
  55. package/server/lib/flow-diagram-generator.test.js +446 -0
  56. package/server/lib/idp-manager.js +626 -0
  57. package/server/lib/idp-manager.test.js +587 -0
  58. package/server/lib/memory-exclusion.js +326 -0
  59. package/server/lib/memory-exclusion.test.js +241 -0
  60. package/server/lib/mfa-handler.js +452 -0
  61. package/server/lib/mfa-handler.test.js +490 -0
  62. package/server/lib/oauth-flow.js +375 -0
  63. package/server/lib/oauth-flow.test.js +487 -0
  64. package/server/lib/oauth-registry.js +190 -0
  65. package/server/lib/oauth-registry.test.js +306 -0
  66. package/server/lib/readme-generator.js +490 -0
  67. package/server/lib/readme-generator.test.js +493 -0
  68. package/server/lib/repo-dependency-tracker.js +261 -0
  69. package/server/lib/repo-dependency-tracker.test.js +350 -0
  70. package/server/lib/retention-policy.js +281 -0
  71. package/server/lib/retention-policy.test.js +486 -0
  72. package/server/lib/role-mapper.js +236 -0
  73. package/server/lib/role-mapper.test.js +395 -0
  74. package/server/lib/saml-provider.js +765 -0
  75. package/server/lib/saml-provider.test.js +643 -0
  76. package/server/lib/security-policy-generator.js +682 -0
  77. package/server/lib/security-policy-generator.test.js +544 -0
  78. package/server/lib/sensitive-detector.js +112 -0
  79. package/server/lib/sensitive-detector.test.js +209 -0
  80. package/server/lib/service-interaction-diagram.js +700 -0
  81. package/server/lib/service-interaction-diagram.test.js +638 -0
  82. package/server/lib/service-summary.js +553 -0
  83. package/server/lib/service-summary.test.js +619 -0
  84. package/server/lib/session-purge.js +460 -0
  85. package/server/lib/session-purge.test.js +312 -0
  86. package/server/lib/sso-command.js +544 -0
  87. package/server/lib/sso-command.test.js +552 -0
  88. package/server/lib/sso-session.js +492 -0
  89. package/server/lib/sso-session.test.js +670 -0
  90. package/server/lib/workspace-command.js +249 -0
  91. package/server/lib/workspace-command.test.js +264 -0
  92. package/server/lib/workspace-config.js +270 -0
  93. package/server/lib/workspace-config.test.js +312 -0
  94. package/server/lib/workspace-docs-command.js +547 -0
  95. package/server/lib/workspace-docs-command.test.js +692 -0
  96. package/server/lib/workspace-memory.js +451 -0
  97. package/server/lib/workspace-memory.test.js +403 -0
  98. package/server/lib/workspace-scanner.js +452 -0
  99. package/server/lib/workspace-scanner.test.js +677 -0
  100. package/server/lib/workspace-test-runner.js +315 -0
  101. package/server/lib/workspace-test-runner.test.js +294 -0
  102. package/server/lib/zero-retention-command.js +439 -0
  103. package/server/lib/zero-retention-command.test.js +448 -0
  104. package/server/lib/zero-retention.js +322 -0
  105. package/server/lib/zero-retention.test.js +258 -0
@@ -0,0 +1,553 @@
1
+ /**
2
+ * Service Summary Generator Module
3
+ * Generates "What does this repo do" one-pager summaries
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ /**
10
+ * Directories to ignore when scanning
11
+ */
12
+ const IGNORE_DIRS = ['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.nuxt'];
13
+
14
+ /**
15
+ * Common entry point file names
16
+ */
17
+ const ENTRY_POINT_FILES = ['index.js', 'index.ts', 'main.js', 'main.ts', 'app.js', 'app.ts'];
18
+
19
+ /**
20
+ * Service Summary Generator class
21
+ */
22
+ class ServiceSummaryGenerator {
23
+ /**
24
+ * @param {string} repoPath - Path to the repository
25
+ */
26
+ constructor(repoPath) {
27
+ this.repoPath = repoPath;
28
+ this.workspaceContext = null;
29
+ }
30
+
31
+ /**
32
+ * Set workspace context for dependency information
33
+ * @param {Object} context - Workspace context with getDependents/getDependencies methods
34
+ */
35
+ setWorkspaceContext(context) {
36
+ this.workspaceContext = context;
37
+ }
38
+
39
+ /**
40
+ * Read package.json if it exists
41
+ * @returns {Object|null} Parsed package.json or null
42
+ */
43
+ readPackageJson() {
44
+ const pkgPath = path.join(this.repoPath, 'package.json');
45
+ try {
46
+ if (fs.existsSync(pkgPath)) {
47
+ return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
48
+ }
49
+ } catch (err) {
50
+ // Ignore parse errors
51
+ }
52
+ return null;
53
+ }
54
+
55
+ /**
56
+ * Read README.md if it exists
57
+ * @returns {string|null} README content or null
58
+ */
59
+ readReadme() {
60
+ const readmePaths = ['README.md', 'readme.md', 'Readme.md', 'README.markdown'];
61
+ for (const name of readmePaths) {
62
+ const readmePath = path.join(this.repoPath, name);
63
+ try {
64
+ if (fs.existsSync(readmePath)) {
65
+ return fs.readFileSync(readmePath, 'utf-8');
66
+ }
67
+ } catch (err) {
68
+ // Ignore read errors
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+
74
+ /**
75
+ * Extract purpose/description from package.json or README
76
+ * @returns {string} Purpose description
77
+ */
78
+ extractPurpose() {
79
+ const pkg = this.readPackageJson();
80
+
81
+ // First try package.json description
82
+ if (pkg?.description) {
83
+ return pkg.description;
84
+ }
85
+
86
+ // Fall back to README first paragraph
87
+ const readme = this.readReadme();
88
+ if (readme) {
89
+ const firstParagraph = this.extractFirstParagraph(readme);
90
+ if (firstParagraph) {
91
+ return firstParagraph;
92
+ }
93
+ }
94
+
95
+ return '';
96
+ }
97
+
98
+ /**
99
+ * Extract first meaningful paragraph from markdown
100
+ * @param {string} markdown - Markdown content
101
+ * @returns {string} First paragraph text
102
+ */
103
+ extractFirstParagraph(markdown) {
104
+ const lines = markdown.split('\n');
105
+ let paragraph = [];
106
+ let foundHeading = false;
107
+
108
+ for (const line of lines) {
109
+ const trimmed = line.trim();
110
+
111
+ // Skip initial title/heading
112
+ if (trimmed.startsWith('#')) {
113
+ foundHeading = true;
114
+ continue;
115
+ }
116
+
117
+ // Skip empty lines before first paragraph
118
+ if (!foundHeading && !trimmed) {
119
+ continue;
120
+ }
121
+
122
+ // Skip empty lines after heading
123
+ if (foundHeading && !trimmed && paragraph.length === 0) {
124
+ continue;
125
+ }
126
+
127
+ // End of paragraph
128
+ if (!trimmed && paragraph.length > 0) {
129
+ break;
130
+ }
131
+
132
+ // Skip subsequent headings
133
+ if (trimmed.startsWith('#') && paragraph.length > 0) {
134
+ break;
135
+ }
136
+
137
+ // Collect paragraph content
138
+ if (trimmed && !trimmed.startsWith('#')) {
139
+ paragraph.push(trimmed);
140
+ }
141
+ }
142
+
143
+ return paragraph.join(' ');
144
+ }
145
+
146
+ /**
147
+ * Identify main entry points
148
+ * @returns {Array} Array of entry point objects
149
+ */
150
+ identifyMainEntryPoints() {
151
+ const entryPoints = [];
152
+ const pkg = this.readPackageJson();
153
+
154
+ // Check package.json main field
155
+ if (pkg?.main) {
156
+ const mainPath = path.join(this.repoPath, pkg.main);
157
+ if (fs.existsSync(mainPath)) {
158
+ entryPoints.push({
159
+ file: pkg.main.replace(/^\.\//, ''),
160
+ type: 'main',
161
+ });
162
+ }
163
+ }
164
+
165
+ // Check for common entry point files (if main not specified)
166
+ if (!pkg?.main) {
167
+ for (const file of ENTRY_POINT_FILES) {
168
+ const filePath = path.join(this.repoPath, file);
169
+ if (fs.existsSync(filePath)) {
170
+ entryPoints.push({
171
+ file,
172
+ type: 'main',
173
+ });
174
+ break; // Only add first found
175
+ }
176
+
177
+ // Check in src directory
178
+ const srcPath = path.join(this.repoPath, 'src', file);
179
+ if (fs.existsSync(srcPath)) {
180
+ entryPoints.push({
181
+ file: `src/${file}`,
182
+ type: 'main',
183
+ });
184
+ break;
185
+ }
186
+ }
187
+ }
188
+
189
+ // Check for bin entry points
190
+ if (pkg?.bin) {
191
+ const bins = typeof pkg.bin === 'string'
192
+ ? { [pkg.name]: pkg.bin }
193
+ : pkg.bin;
194
+
195
+ for (const [name, binPath] of Object.entries(bins)) {
196
+ const normalizedPath = binPath.replace(/^\.\//, '');
197
+ const fullPath = path.join(this.repoPath, normalizedPath);
198
+ if (fs.existsSync(fullPath)) {
199
+ entryPoints.push({
200
+ file: normalizedPath,
201
+ type: 'bin',
202
+ name,
203
+ });
204
+ }
205
+ }
206
+ }
207
+
208
+ return entryPoints;
209
+ }
210
+
211
+ /**
212
+ * List exported functions/classes from main entry point
213
+ * @returns {Array} Array of export names
214
+ */
215
+ listExports() {
216
+ const exports = [];
217
+ const entryPoints = this.identifyMainEntryPoints();
218
+ const pkg = this.readPackageJson();
219
+
220
+ // Determine which file to analyze
221
+ let entryFile = null;
222
+
223
+ if (pkg?.main) {
224
+ entryFile = path.join(this.repoPath, pkg.main);
225
+ } else {
226
+ // Try common entry points
227
+ for (const file of ENTRY_POINT_FILES) {
228
+ const filePath = path.join(this.repoPath, file);
229
+ if (fs.existsSync(filePath)) {
230
+ entryFile = filePath;
231
+ break;
232
+ }
233
+ }
234
+ }
235
+
236
+ if (!entryFile || !fs.existsSync(entryFile)) {
237
+ return exports;
238
+ }
239
+
240
+ try {
241
+ const content = fs.readFileSync(entryFile, 'utf-8');
242
+
243
+ // Detect CommonJS exports: module.exports = { name1, name2 }
244
+ const cjsMatch = content.match(/module\.exports\s*=\s*\{([^}]+)\}/);
245
+ if (cjsMatch) {
246
+ const exportList = cjsMatch[1];
247
+ const names = exportList.match(/\b([a-zA-Z_]\w*)\b/g);
248
+ if (names) {
249
+ exports.push(...names.filter(n => n !== 'exports' && n !== 'module'));
250
+ }
251
+ }
252
+
253
+ // Detect ES module exports: export function name() {}
254
+ const esExportFnRegex = /export\s+(?:async\s+)?function\s+(\w+)/g;
255
+ let match;
256
+ while ((match = esExportFnRegex.exec(content)) !== null) {
257
+ if (!exports.includes(match[1])) {
258
+ exports.push(match[1]);
259
+ }
260
+ }
261
+
262
+ // Detect ES module class exports: export class Name {}
263
+ const esExportClassRegex = /export\s+(?:default\s+)?class\s+(\w+)/g;
264
+ while ((match = esExportClassRegex.exec(content)) !== null) {
265
+ if (!exports.includes(match[1])) {
266
+ exports.push(match[1]);
267
+ }
268
+ }
269
+
270
+ // Detect ES module const exports: export const NAME = ...
271
+ const esExportConstRegex = /export\s+const\s+(\w+)\s*=/g;
272
+ while ((match = esExportConstRegex.exec(content)) !== null) {
273
+ if (!exports.includes(match[1])) {
274
+ exports.push(match[1]);
275
+ }
276
+ }
277
+
278
+ // Detect default class: export default class Name {}
279
+ const defaultClassRegex = /export\s+default\s+class\s+(\w+)/g;
280
+ while ((match = defaultClassRegex.exec(content)) !== null) {
281
+ if (!exports.includes(match[1])) {
282
+ exports.push(match[1]);
283
+ }
284
+ }
285
+
286
+ } catch (err) {
287
+ // Ignore read errors
288
+ }
289
+
290
+ return exports;
291
+ }
292
+
293
+ /**
294
+ * Get repos that consume/depend on this repo
295
+ * @returns {Array} Array of consumer repo names
296
+ */
297
+ getConsumerRepos() {
298
+ if (!this.workspaceContext?.getDependents) {
299
+ return [];
300
+ }
301
+
302
+ const pkg = this.readPackageJson();
303
+ const repoName = path.basename(this.repoPath);
304
+
305
+ return this.workspaceContext.getDependents(repoName) || [];
306
+ }
307
+
308
+ /**
309
+ * Get repos that this repo depends on
310
+ * @returns {Array} Array of dependency repo names
311
+ */
312
+ getDependencyRepos() {
313
+ if (!this.workspaceContext?.getDependencies) {
314
+ return [];
315
+ }
316
+
317
+ const repoName = path.basename(this.repoPath);
318
+
319
+ return this.workspaceContext.getDependencies(repoName) || [];
320
+ }
321
+
322
+ /**
323
+ * Analyze file structure to infer service type
324
+ * @returns {Object} Analysis result with type and indicators
325
+ */
326
+ analyzeFileStructure() {
327
+ const indicators = [];
328
+ let type = 'unknown';
329
+ const pkg = this.readPackageJson();
330
+
331
+ // Check for bin entry (CLI tool)
332
+ if (pkg?.bin) {
333
+ indicators.push('bin entry');
334
+ type = 'cli';
335
+ }
336
+
337
+ // Check for routes directory (API service)
338
+ const routesDirs = [
339
+ path.join(this.repoPath, 'routes'),
340
+ path.join(this.repoPath, 'src', 'routes'),
341
+ path.join(this.repoPath, 'api'),
342
+ path.join(this.repoPath, 'src', 'api'),
343
+ ];
344
+ for (const routesDir of routesDirs) {
345
+ if (fs.existsSync(routesDir) && fs.statSync(routesDir).isDirectory()) {
346
+ indicators.push('routes directory');
347
+ type = 'api';
348
+ break;
349
+ }
350
+ }
351
+
352
+ // Check for components directory (web app)
353
+ const componentsDirs = [
354
+ path.join(this.repoPath, 'components'),
355
+ path.join(this.repoPath, 'src', 'components'),
356
+ ];
357
+ for (const compDir of componentsDirs) {
358
+ if (fs.existsSync(compDir) && fs.statSync(compDir).isDirectory()) {
359
+ indicators.push('components directory');
360
+ if (type === 'unknown') {
361
+ type = 'web-app';
362
+ }
363
+ break;
364
+ }
365
+ }
366
+
367
+ // Check for library pattern (src with index exports)
368
+ if (type === 'unknown') {
369
+ const srcDir = path.join(this.repoPath, 'src');
370
+ if (fs.existsSync(srcDir) && fs.statSync(srcDir).isDirectory()) {
371
+ for (const file of ['index.js', 'index.ts']) {
372
+ if (fs.existsSync(path.join(srcDir, file))) {
373
+ indicators.push('src directory with index');
374
+ type = 'library';
375
+ break;
376
+ }
377
+ }
378
+ }
379
+ }
380
+
381
+ // Check root index for library pattern
382
+ if (type === 'unknown') {
383
+ for (const file of ['index.js', 'index.ts']) {
384
+ if (fs.existsSync(path.join(this.repoPath, file))) {
385
+ indicators.push('root index file');
386
+ type = 'library';
387
+ break;
388
+ }
389
+ }
390
+ }
391
+
392
+ return { type, indicators };
393
+ }
394
+
395
+ /**
396
+ * Generate the full service summary
397
+ * @returns {string} Complete markdown summary
398
+ */
399
+ generate() {
400
+ const pkg = this.readPackageJson();
401
+ const name = pkg?.name || path.basename(this.repoPath);
402
+ const purpose = this.extractPurpose();
403
+ const entryPoints = this.identifyMainEntryPoints();
404
+ const exports = this.listExports();
405
+ const consumers = this.getConsumerRepos();
406
+ const dependencies = this.getDependencyRepos();
407
+ const analysis = this.analyzeFileStructure();
408
+
409
+ const sections = [];
410
+
411
+ // Title
412
+ sections.push(`# ${name}`);
413
+ sections.push('');
414
+
415
+ // Overview section
416
+ sections.push('## Overview');
417
+ sections.push('');
418
+
419
+ if (purpose) {
420
+ sections.push(purpose);
421
+ sections.push('');
422
+ }
423
+
424
+ if (analysis.type !== 'unknown') {
425
+ sections.push(`**Type:** ${this.formatType(analysis.type)}`);
426
+ sections.push('');
427
+ }
428
+
429
+ if (pkg?.version) {
430
+ sections.push(`**Version:** ${pkg.version}`);
431
+ sections.push('');
432
+ }
433
+
434
+ // Entry Points section
435
+ if (entryPoints.length > 0) {
436
+ sections.push('## Entry Points');
437
+ sections.push('');
438
+ for (const entry of entryPoints) {
439
+ if (entry.type === 'bin') {
440
+ sections.push(`- \`${entry.file}\` (CLI: \`${entry.name}\`)`);
441
+ } else {
442
+ sections.push(`- \`${entry.file}\``);
443
+ }
444
+ }
445
+ sections.push('');
446
+ }
447
+
448
+ // Exports section
449
+ if (exports.length > 0) {
450
+ sections.push('## Exports');
451
+ sections.push('');
452
+ for (const exp of exports) {
453
+ sections.push(`- \`${exp}\``);
454
+ }
455
+ sections.push('');
456
+ }
457
+
458
+ // Consumers section
459
+ if (consumers.length > 0) {
460
+ sections.push('## Consumers');
461
+ sections.push('');
462
+ sections.push('The following repos depend on this service:');
463
+ sections.push('');
464
+ for (const consumer of consumers) {
465
+ sections.push(`- ${consumer}`);
466
+ }
467
+ sections.push('');
468
+ }
469
+
470
+ // Dependencies section
471
+ if (dependencies.length > 0) {
472
+ sections.push('## Dependencies');
473
+ sections.push('');
474
+ sections.push('This service depends on:');
475
+ sections.push('');
476
+ for (const dep of dependencies) {
477
+ sections.push(`- ${dep}`);
478
+ }
479
+ sections.push('');
480
+ }
481
+
482
+ return sections.join('\n').trim() + '\n';
483
+ }
484
+
485
+ /**
486
+ * Format type for display
487
+ * @param {string} type - Type identifier
488
+ * @returns {string} Formatted type name
489
+ */
490
+ formatType(type) {
491
+ const typeNames = {
492
+ 'api': 'API Service',
493
+ 'cli': 'CLI Tool',
494
+ 'library': 'Library',
495
+ 'web-app': 'Web Application',
496
+ 'unknown': 'Unknown',
497
+ };
498
+ return typeNames[type] || type;
499
+ }
500
+
501
+ /**
502
+ * Write summary to disk
503
+ * @param {string} outputPath - Custom output path (defaults to SERVICE-SUMMARY.md)
504
+ */
505
+ write(outputPath) {
506
+ const summary = this.generate();
507
+ const target = outputPath || path.join(this.repoPath, 'SERVICE-SUMMARY.md');
508
+ fs.writeFileSync(target, summary, 'utf-8');
509
+ }
510
+ }
511
+
512
+ /**
513
+ * Convenience function to generate service summary for a path
514
+ * @param {string} repoPath - Path to repository
515
+ * @param {Object} workspaceContext - Optional workspace context
516
+ * @returns {string} Generated summary content
517
+ */
518
+ function generateServiceSummary(repoPath, workspaceContext) {
519
+ const generator = new ServiceSummaryGenerator(repoPath);
520
+ if (workspaceContext) {
521
+ generator.setWorkspaceContext(workspaceContext);
522
+ }
523
+ return generator.generate();
524
+ }
525
+
526
+ /**
527
+ * Factory function to create a service summary generator
528
+ * @param {string} repoPath - Path to repository
529
+ * @returns {Object} Generator instance with bound methods
530
+ */
531
+ function createServiceSummaryGenerator(repoPath) {
532
+ const generator = new ServiceSummaryGenerator(repoPath);
533
+
534
+ return {
535
+ generate: () => generator.generate(),
536
+ write: (outputPath) => generator.write(outputPath),
537
+ extractPurpose: () => generator.extractPurpose(),
538
+ identifyMainEntryPoints: () => generator.identifyMainEntryPoints(),
539
+ listExports: () => generator.listExports(),
540
+ getConsumerRepos: () => generator.getConsumerRepos(),
541
+ getDependencyRepos: () => generator.getDependencyRepos(),
542
+ analyzeFileStructure: () => generator.analyzeFileStructure(),
543
+ setWorkspaceContext: (ctx) => generator.setWorkspaceContext(ctx),
544
+ };
545
+ }
546
+
547
+ module.exports = {
548
+ ServiceSummaryGenerator,
549
+ generateServiceSummary,
550
+ createServiceSummaryGenerator,
551
+ IGNORE_DIRS,
552
+ ENTRY_POINT_FILES,
553
+ };