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.
- package/dashboard/dist/components/AuditPane.d.ts +30 -0
- package/dashboard/dist/components/AuditPane.js +127 -0
- package/dashboard/dist/components/AuditPane.test.d.ts +1 -0
- package/dashboard/dist/components/AuditPane.test.js +339 -0
- package/dashboard/dist/components/CompliancePane.d.ts +39 -0
- package/dashboard/dist/components/CompliancePane.js +96 -0
- package/dashboard/dist/components/CompliancePane.test.d.ts +1 -0
- package/dashboard/dist/components/CompliancePane.test.js +183 -0
- package/dashboard/dist/components/SSOPane.d.ts +36 -0
- package/dashboard/dist/components/SSOPane.js +71 -0
- package/dashboard/dist/components/SSOPane.test.d.ts +1 -0
- package/dashboard/dist/components/SSOPane.test.js +155 -0
- package/dashboard/dist/components/WorkspaceDocsPane.js +0 -16
- package/dashboard/dist/components/WorkspacePane.d.ts +1 -1
- package/dashboard/dist/components/ZeroRetentionPane.d.ts +44 -0
- package/dashboard/dist/components/ZeroRetentionPane.js +83 -0
- package/dashboard/dist/components/ZeroRetentionPane.test.d.ts +1 -0
- package/dashboard/dist/components/ZeroRetentionPane.test.js +160 -0
- package/package.json +1 -1
- package/server/lib/access-control-doc.js +541 -0
- package/server/lib/access-control-doc.test.js +672 -0
- package/server/lib/adr-generator.js +423 -0
- package/server/lib/adr-generator.test.js +586 -0
- package/server/lib/agent-progress-monitor.js +223 -0
- package/server/lib/agent-progress-monitor.test.js +202 -0
- package/server/lib/audit-attribution.js +191 -0
- package/server/lib/audit-attribution.test.js +359 -0
- package/server/lib/audit-classifier.js +202 -0
- package/server/lib/audit-classifier.test.js +209 -0
- package/server/lib/audit-command.js +275 -0
- package/server/lib/audit-command.test.js +325 -0
- package/server/lib/audit-exporter.js +380 -0
- package/server/lib/audit-exporter.test.js +464 -0
- package/server/lib/audit-logger.js +236 -0
- package/server/lib/audit-logger.test.js +364 -0
- package/server/lib/audit-query.js +257 -0
- package/server/lib/audit-query.test.js +352 -0
- package/server/lib/audit-storage.js +269 -0
- package/server/lib/audit-storage.test.js +272 -0
- package/server/lib/bulk-repo-init.js +342 -0
- package/server/lib/bulk-repo-init.test.js +388 -0
- package/server/lib/compliance-checklist.js +866 -0
- package/server/lib/compliance-checklist.test.js +476 -0
- package/server/lib/compliance-command.js +616 -0
- package/server/lib/compliance-command.test.js +551 -0
- package/server/lib/compliance-reporter.js +692 -0
- package/server/lib/compliance-reporter.test.js +707 -0
- package/server/lib/data-flow-doc.js +665 -0
- package/server/lib/data-flow-doc.test.js +659 -0
- package/server/lib/ephemeral-storage.js +249 -0
- package/server/lib/ephemeral-storage.test.js +254 -0
- package/server/lib/evidence-collector.js +627 -0
- package/server/lib/evidence-collector.test.js +901 -0
- package/server/lib/flow-diagram-generator.js +474 -0
- package/server/lib/flow-diagram-generator.test.js +446 -0
- package/server/lib/idp-manager.js +626 -0
- package/server/lib/idp-manager.test.js +587 -0
- package/server/lib/memory-exclusion.js +326 -0
- package/server/lib/memory-exclusion.test.js +241 -0
- package/server/lib/mfa-handler.js +452 -0
- package/server/lib/mfa-handler.test.js +490 -0
- package/server/lib/oauth-flow.js +375 -0
- package/server/lib/oauth-flow.test.js +487 -0
- package/server/lib/oauth-registry.js +190 -0
- package/server/lib/oauth-registry.test.js +306 -0
- package/server/lib/readme-generator.js +490 -0
- package/server/lib/readme-generator.test.js +493 -0
- package/server/lib/repo-dependency-tracker.js +261 -0
- package/server/lib/repo-dependency-tracker.test.js +350 -0
- package/server/lib/retention-policy.js +281 -0
- package/server/lib/retention-policy.test.js +486 -0
- package/server/lib/role-mapper.js +236 -0
- package/server/lib/role-mapper.test.js +395 -0
- package/server/lib/saml-provider.js +765 -0
- package/server/lib/saml-provider.test.js +643 -0
- package/server/lib/security-policy-generator.js +682 -0
- package/server/lib/security-policy-generator.test.js +544 -0
- package/server/lib/sensitive-detector.js +112 -0
- package/server/lib/sensitive-detector.test.js +209 -0
- package/server/lib/service-interaction-diagram.js +700 -0
- package/server/lib/service-interaction-diagram.test.js +638 -0
- package/server/lib/service-summary.js +553 -0
- package/server/lib/service-summary.test.js +619 -0
- package/server/lib/session-purge.js +460 -0
- package/server/lib/session-purge.test.js +312 -0
- package/server/lib/sso-command.js +544 -0
- package/server/lib/sso-command.test.js +552 -0
- package/server/lib/sso-session.js +492 -0
- package/server/lib/sso-session.test.js +670 -0
- package/server/lib/workspace-command.js +249 -0
- package/server/lib/workspace-command.test.js +264 -0
- package/server/lib/workspace-config.js +270 -0
- package/server/lib/workspace-config.test.js +312 -0
- package/server/lib/workspace-docs-command.js +547 -0
- package/server/lib/workspace-docs-command.test.js +692 -0
- package/server/lib/workspace-memory.js +451 -0
- package/server/lib/workspace-memory.test.js +403 -0
- package/server/lib/workspace-scanner.js +452 -0
- package/server/lib/workspace-scanner.test.js +677 -0
- package/server/lib/workspace-test-runner.js +315 -0
- package/server/lib/workspace-test-runner.test.js +294 -0
- package/server/lib/zero-retention-command.js +439 -0
- package/server/lib/zero-retention-command.test.js +448 -0
- package/server/lib/zero-retention.js +322 -0
- 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
|
+
};
|