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,547 @@
1
+ /**
2
+ * Workspace Docs Command - CLI interface for workspace documentation generation
3
+ *
4
+ * Commands:
5
+ * --docs readme - Generate READMEs for all repos
6
+ * --docs flow - Generate cross-repo flow diagrams
7
+ * --docs summary - Generate service summaries
8
+ * --docs adr - Create new ADR or list existing
9
+ * --docs all - Generate all documentation
10
+ * --output <dir> - Specify output directory
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const { ReadmeGenerator } = require('./readme-generator.js');
16
+ const { FlowDiagramGenerator } = require('./flow-diagram-generator.js');
17
+ const { ServiceSummaryGenerator } = require('./service-summary.js');
18
+ const { createAdr, listAdrs } = require('./adr-generator.js');
19
+
20
+ const CONFIG_FILENAME = '.tlc-workspace.json';
21
+
22
+ /**
23
+ * WorkspaceDocsCommand class for CLI documentation generation
24
+ */
25
+ class WorkspaceDocsCommand {
26
+ /**
27
+ * Create a WorkspaceDocsCommand instance
28
+ * @param {string} rootDir - Workspace root directory
29
+ */
30
+ constructor(rootDir) {
31
+ this.rootDir = rootDir;
32
+ this.configPath = path.join(rootDir, CONFIG_FILENAME);
33
+ this.config = null;
34
+ this._loadConfig();
35
+ }
36
+
37
+ /**
38
+ * Load existing workspace config
39
+ * @private
40
+ */
41
+ _loadConfig() {
42
+ if (fs.existsSync(this.configPath)) {
43
+ try {
44
+ this.config = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'));
45
+ } catch (err) {
46
+ this.config = null;
47
+ }
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Check if workspace is initialized
53
+ * @returns {boolean}
54
+ */
55
+ isWorkspaceInitialized() {
56
+ return this.config !== null;
57
+ }
58
+
59
+ /**
60
+ * Ensure workspace is initialized, throw if not
61
+ * @private
62
+ */
63
+ _ensureInitialized() {
64
+ if (!this.isWorkspaceInitialized()) {
65
+ throw new Error('Workspace not initialized. Run /tlc:workspace init first.');
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Generate READMEs for all workspace repos
71
+ * @param {Object} options - Options
72
+ * @param {string} [options.outputDir] - Custom output directory
73
+ * @returns {Promise<Object>} Result with generated repos list
74
+ */
75
+ async readme(options = {}) {
76
+ this._ensureInitialized();
77
+
78
+ const repos = this.config.repos || [];
79
+ const generated = [];
80
+ const errors = [];
81
+
82
+ if (repos.length === 0) {
83
+ return {
84
+ success: true,
85
+ generated: [],
86
+ errors: [],
87
+ message: 'No repos found in workspace. Nothing to generate.',
88
+ };
89
+ }
90
+
91
+ for (const repoName of repos) {
92
+ const repoPath = path.join(this.rootDir, repoName);
93
+
94
+ // Check if repo exists
95
+ if (!fs.existsSync(repoPath)) {
96
+ errors.push(`Repo not found: ${repoName}`);
97
+ continue;
98
+ }
99
+
100
+ try {
101
+ const generator = new ReadmeGenerator(repoPath);
102
+ const readmeContent = generator.generate();
103
+
104
+ // Determine output path
105
+ let outputPath;
106
+ if (options.outputDir) {
107
+ const outputRepoDir = path.join(options.outputDir, repoName);
108
+ fs.mkdirSync(outputRepoDir, { recursive: true });
109
+ outputPath = path.join(outputRepoDir, 'README.md');
110
+ } else {
111
+ outputPath = path.join(repoPath, 'README.md');
112
+ }
113
+
114
+ fs.writeFileSync(outputPath, readmeContent, 'utf-8');
115
+ generated.push(repoName);
116
+ } catch (err) {
117
+ errors.push(`Error generating README for ${repoName}: ${err.message}`);
118
+ }
119
+ }
120
+
121
+ return {
122
+ success: true,
123
+ generated,
124
+ errors,
125
+ message: `Generated ${generated.length} README(s)`,
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Generate cross-repo flow diagrams
131
+ * @param {Object} options - Options
132
+ * @param {string} [options.outputDir] - Custom output directory
133
+ * @returns {Promise<Object>} Result with diagram
134
+ */
135
+ async flow(options = {}) {
136
+ this._ensureInitialized();
137
+
138
+ const repos = this.config.repos || [];
139
+ const generator = new FlowDiagramGenerator();
140
+
141
+ // Collect files from all repos
142
+ const files = {};
143
+
144
+ for (const repoName of repos) {
145
+ const repoPath = path.join(this.rootDir, repoName);
146
+
147
+ if (!fs.existsSync(repoPath)) {
148
+ continue;
149
+ }
150
+
151
+ // Find JS/TS files (non-recursively for simplicity, check src and root)
152
+ const filesToCheck = [
153
+ path.join(repoPath, 'src', 'index.js'),
154
+ path.join(repoPath, 'src', 'index.ts'),
155
+ path.join(repoPath, 'index.js'),
156
+ path.join(repoPath, 'index.ts'),
157
+ ];
158
+
159
+ for (const filePath of filesToCheck) {
160
+ if (fs.existsSync(filePath)) {
161
+ try {
162
+ const content = fs.readFileSync(filePath, 'utf-8');
163
+ // Use workspace-relative path for proper repo detection
164
+ const relativePath = `/workspace/${repoName}/${path.relative(repoPath, filePath)}`;
165
+ files[relativePath] = content;
166
+ } catch (err) {
167
+ // Skip files that can't be read
168
+ }
169
+ }
170
+ }
171
+ }
172
+
173
+ // Analyze files and generate diagram
174
+ const analysisResult = generator.analyzeFiles(files);
175
+ const diagram = generator.generateMermaid(analysisResult);
176
+
177
+ // Wrap in markdown
178
+ const diagramContent = `# Workspace Flow Diagram
179
+
180
+ \`\`\`mermaid
181
+ ${diagram}
182
+ \`\`\`
183
+
184
+ *Generated at: ${new Date().toISOString()}*
185
+ `;
186
+
187
+ // Determine output path
188
+ let outputPath;
189
+ if (options.outputDir) {
190
+ fs.mkdirSync(options.outputDir, { recursive: true });
191
+ outputPath = path.join(options.outputDir, 'workspace-flow.md');
192
+ } else {
193
+ const planningDir = path.join(this.rootDir, '.planning');
194
+ fs.mkdirSync(planningDir, { recursive: true });
195
+ outputPath = path.join(planningDir, 'workspace-flow.md');
196
+ }
197
+
198
+ fs.writeFileSync(outputPath, diagramContent, 'utf-8');
199
+
200
+ return {
201
+ success: true,
202
+ diagram,
203
+ outputPath,
204
+ message: `Generated flow diagram at ${outputPath}`,
205
+ };
206
+ }
207
+
208
+ /**
209
+ * Generate service summaries for all repos
210
+ * @param {Object} options - Options
211
+ * @param {string} [options.outputDir] - Custom output directory
212
+ * @returns {Promise<Object>} Result with summaries list
213
+ */
214
+ async summary(options = {}) {
215
+ this._ensureInitialized();
216
+
217
+ const repos = this.config.repos || [];
218
+ const summaries = [];
219
+ const errors = [];
220
+
221
+ if (repos.length === 0) {
222
+ return {
223
+ success: true,
224
+ summaries: [],
225
+ errors: [],
226
+ message: 'No repos found in workspace. Nothing to generate.',
227
+ };
228
+ }
229
+
230
+ // Create workspace context for dependency tracking
231
+ const workspaceContext = this._createWorkspaceContext();
232
+
233
+ for (const repoName of repos) {
234
+ const repoPath = path.join(this.rootDir, repoName);
235
+
236
+ // Check if repo exists
237
+ if (!fs.existsSync(repoPath)) {
238
+ errors.push(`Repo not found: ${repoName}`);
239
+ continue;
240
+ }
241
+
242
+ try {
243
+ const generator = new ServiceSummaryGenerator(repoPath);
244
+ generator.setWorkspaceContext(workspaceContext);
245
+ const summaryContent = generator.generate();
246
+
247
+ // Determine output path
248
+ let outputPath;
249
+ if (options.outputDir) {
250
+ const outputRepoDir = path.join(options.outputDir, repoName);
251
+ fs.mkdirSync(outputRepoDir, { recursive: true });
252
+ outputPath = path.join(outputRepoDir, 'SERVICE-SUMMARY.md');
253
+ } else {
254
+ outputPath = path.join(repoPath, 'SERVICE-SUMMARY.md');
255
+ }
256
+
257
+ fs.writeFileSync(outputPath, summaryContent, 'utf-8');
258
+ summaries.push({
259
+ repo: repoName,
260
+ outputPath,
261
+ });
262
+ } catch (err) {
263
+ errors.push(`Error generating summary for ${repoName}: ${err.message}`);
264
+ }
265
+ }
266
+
267
+ return {
268
+ success: true,
269
+ summaries,
270
+ errors,
271
+ message: `Generated ${summaries.length} service summary(ies)`,
272
+ };
273
+ }
274
+
275
+ /**
276
+ * Create workspace context for dependency tracking
277
+ * @private
278
+ * @returns {Object} Workspace context with dependency methods
279
+ */
280
+ _createWorkspaceContext() {
281
+ const repos = this.config.repos || [];
282
+ const dependencies = {};
283
+ const dependents = {};
284
+
285
+ // Build dependency graph from package.json files
286
+ for (const repoName of repos) {
287
+ const pkgPath = path.join(this.rootDir, repoName, 'package.json');
288
+
289
+ if (fs.existsSync(pkgPath)) {
290
+ try {
291
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
292
+ const allDeps = {
293
+ ...pkg.dependencies,
294
+ ...pkg.devDependencies,
295
+ };
296
+
297
+ dependencies[repoName] = [];
298
+ for (const [depName, version] of Object.entries(allDeps)) {
299
+ if (version && version.startsWith('workspace:')) {
300
+ dependencies[repoName].push(depName);
301
+
302
+ // Track reverse dependency
303
+ if (!dependents[depName]) {
304
+ dependents[depName] = [];
305
+ }
306
+ dependents[depName].push(repoName);
307
+ }
308
+ }
309
+ } catch (err) {
310
+ // Ignore parse errors
311
+ }
312
+ }
313
+ }
314
+
315
+ return {
316
+ getDependencies: (repoName) => dependencies[repoName] || [],
317
+ getDependents: (repoName) => dependents[repoName] || [],
318
+ };
319
+ }
320
+
321
+ /**
322
+ * Create or list ADRs
323
+ * @param {Object} options - Options
324
+ * @param {string} [options.action='list'] - 'create' or 'list'
325
+ * @param {string} [options.title] - ADR title (for create)
326
+ * @param {string} [options.context] - ADR context (for create)
327
+ * @param {string} [options.decision] - ADR decision (for create)
328
+ * @param {string} [options.consequences] - ADR consequences (for create)
329
+ * @returns {Promise<Object>} Result
330
+ */
331
+ async adr(options = {}) {
332
+ const action = options.action || 'list';
333
+
334
+ if (action === 'create') {
335
+ const adrResult = await createAdr(this.rootDir, {
336
+ title: options.title || 'Untitled Decision',
337
+ context: options.context || 'No context provided.',
338
+ decision: options.decision || 'No decision provided.',
339
+ consequences: options.consequences || 'No consequences provided.',
340
+ status: 'proposed',
341
+ });
342
+
343
+ return {
344
+ success: true,
345
+ adr: adrResult,
346
+ message: `Created ADR ${adrResult.number}: ${adrResult.title}`,
347
+ };
348
+ } else {
349
+ // List ADRs
350
+ const adrs = await listAdrs(this.rootDir);
351
+
352
+ return {
353
+ success: true,
354
+ adrs,
355
+ message: adrs.length > 0
356
+ ? `Found ${adrs.length} ADR(s)`
357
+ : 'No ADRs found',
358
+ };
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Generate all documentation at once
364
+ * @param {Object} options - Options
365
+ * @param {string} [options.outputDir] - Custom output directory
366
+ * @returns {Promise<Object>} Combined result
367
+ */
368
+ async all(options = {}) {
369
+ this._ensureInitialized();
370
+
371
+ const readmeResult = await this.readme(options);
372
+
373
+ // For flow diagram, use outputDir directly (not nested in repos)
374
+ const flowOptions = {
375
+ outputDir: options.outputDir || undefined,
376
+ };
377
+ const flowResult = await this.flow(flowOptions);
378
+
379
+ const summaryResult = await this.summary(options);
380
+
381
+ return {
382
+ success: true,
383
+ readme: readmeResult,
384
+ flow: flowResult,
385
+ summary: summaryResult,
386
+ message: 'Generated all documentation',
387
+ };
388
+ }
389
+
390
+ /**
391
+ * Parse command line arguments
392
+ * @param {string} argsString - Command arguments string
393
+ * @returns {Object} Parsed options
394
+ */
395
+ parseArgs(argsString) {
396
+ const options = {};
397
+ const args = argsString.trim();
398
+
399
+ if (!args) {
400
+ return options;
401
+ }
402
+
403
+ // Parse --docs type
404
+ const docsMatch = args.match(/--docs\s+(\w+)/);
405
+ if (docsMatch) {
406
+ options.docsType = docsMatch[1];
407
+ }
408
+
409
+ // Parse --output or -o
410
+ const outputMatch = args.match(/(?:--output|-o)\s+([^\s]+)/);
411
+ if (outputMatch) {
412
+ options.outputDir = outputMatch[1];
413
+ }
414
+
415
+ // Parse --help or -h
416
+ if (args.includes('--help') || args.match(/\s-h\b/) || args === '-h') {
417
+ options.help = true;
418
+ }
419
+
420
+ // Parse ADR action flags
421
+ if (args.includes('--create')) {
422
+ options.adrAction = 'create';
423
+ }
424
+ if (args.includes('--list')) {
425
+ options.adrAction = 'list';
426
+ }
427
+
428
+ // Parse ADR create options
429
+ const titleMatch = args.match(/--title\s+"([^"]+)"/);
430
+ if (titleMatch) {
431
+ options.title = titleMatch[1];
432
+ }
433
+
434
+ const contextMatch = args.match(/--context\s+"([^"]+)"/);
435
+ if (contextMatch) {
436
+ options.context = contextMatch[1];
437
+ }
438
+
439
+ const decisionMatch = args.match(/--decision\s+"([^"]+)"/);
440
+ if (decisionMatch) {
441
+ options.decision = decisionMatch[1];
442
+ }
443
+
444
+ const consequencesMatch = args.match(/--consequences\s+"([^"]+)"/);
445
+ if (consequencesMatch) {
446
+ options.consequences = consequencesMatch[1];
447
+ }
448
+
449
+ return options;
450
+ }
451
+
452
+ /**
453
+ * Run command based on parsed arguments
454
+ * @param {string} argsString - Command arguments string
455
+ * @returns {Promise<Object>} Command result
456
+ */
457
+ async run(argsString) {
458
+ const options = this.parseArgs(argsString);
459
+
460
+ // Handle help
461
+ if (options.help || !argsString.trim()) {
462
+ return {
463
+ success: true,
464
+ message: this.getHelpText(),
465
+ };
466
+ }
467
+
468
+ const docsType = options.docsType;
469
+
470
+ if (!docsType) {
471
+ return {
472
+ success: true,
473
+ message: this.getHelpText(),
474
+ };
475
+ }
476
+
477
+ switch (docsType) {
478
+ case 'readme':
479
+ return this.readme({ outputDir: options.outputDir });
480
+
481
+ case 'flow':
482
+ return this.flow({ outputDir: options.outputDir });
483
+
484
+ case 'summary':
485
+ return this.summary({ outputDir: options.outputDir });
486
+
487
+ case 'adr':
488
+ return this.adr({
489
+ action: options.adrAction || 'list',
490
+ title: options.title,
491
+ context: options.context,
492
+ decision: options.decision,
493
+ consequences: options.consequences,
494
+ });
495
+
496
+ case 'all':
497
+ return this.all({ outputDir: options.outputDir });
498
+
499
+ default:
500
+ return {
501
+ success: false,
502
+ error: `Unknown docs type: ${docsType}. Use readme, flow, summary, adr, or all.`,
503
+ };
504
+ }
505
+ }
506
+
507
+ /**
508
+ * Get help text
509
+ * @returns {string} Help text
510
+ */
511
+ getHelpText() {
512
+ return `
513
+ Usage: /tlc:workspace --docs <type> [options]
514
+
515
+ Documentation Types:
516
+ readme Generate README.md for all repos
517
+ flow Generate cross-repo flow diagrams
518
+ summary Generate SERVICE-SUMMARY.md for all repos
519
+ adr Create or list Architecture Decision Records
520
+ all Generate all documentation at once
521
+
522
+ Options:
523
+ --output <dir>, -o <dir> Specify output directory
524
+ --help, -h Show this help message
525
+
526
+ ADR Options (when using --docs adr):
527
+ --create Create a new ADR
528
+ --list List existing ADRs (default)
529
+ --title "Title" ADR title
530
+ --context "Context" ADR context section
531
+ --decision "Decision" ADR decision section
532
+ --consequences "Impact" ADR consequences section
533
+
534
+ Examples:
535
+ /tlc:workspace --docs readme
536
+ /tlc:workspace --docs flow --output ./docs
537
+ /tlc:workspace --docs summary
538
+ /tlc:workspace --docs adr --list
539
+ /tlc:workspace --docs adr --create --title "Use PostgreSQL" --context "Need a database" --decision "PostgreSQL" --consequences "Need to manage DB"
540
+ /tlc:workspace --docs all --output ./generated-docs
541
+ `.trim();
542
+ }
543
+ }
544
+
545
+ module.exports = {
546
+ WorkspaceDocsCommand,
547
+ };