monomind 1.17.0 → 1.17.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 (94) hide show
  1. package/.claude/agents/engineering/engineering-security-engineer.md +1 -1
  2. package/.claude/commands/mastermind/_repeat.md +4 -0
  3. package/.claude/commands/mastermind/master.md +52 -1
  4. package/.claude/scheduled_tasks.lock +1 -1
  5. package/.claude/skills/mastermind/_repeat.md +2 -0
  6. package/package.json +1 -1
  7. package/packages/@monomind/cli/.claude/agents/engineering/engineering-security-engineer.md +1 -1
  8. package/packages/@monomind/cli/.claude/commands/mastermind/_repeat.md +4 -0
  9. package/packages/@monomind/cli/.claude/commands/mastermind/master.md +52 -1
  10. package/packages/@monomind/cli/.claude/skills/mastermind/_repeat.md +2 -0
  11. package/packages/@monomind/cli/dist/src/__tests__/browse-analyzer.test.js +42 -59
  12. package/packages/@monomind/cli/dist/src/agents/registry-builder.d.ts +8 -0
  13. package/packages/@monomind/cli/dist/src/agents/registry-builder.js +22 -0
  14. package/packages/@monomind/cli/dist/src/browser/dashboard/server.js +18 -0
  15. package/packages/@monomind/cli/dist/src/browser/dashboard/ui.html +37 -125
  16. package/packages/@monomind/cli/dist/src/commands/agent-lifecycle.d.ts +17 -0
  17. package/packages/@monomind/cli/dist/src/commands/agent-lifecycle.js +320 -0
  18. package/packages/@monomind/cli/dist/src/commands/agent-ops.d.ts +9 -0
  19. package/packages/@monomind/cli/dist/src/commands/agent-ops.js +329 -0
  20. package/packages/@monomind/cli/dist/src/commands/agent.js +5 -907
  21. package/packages/@monomind/cli/dist/src/commands/analyze-ast.d.ts +26 -0
  22. package/packages/@monomind/cli/dist/src/commands/analyze-ast.js +284 -0
  23. package/packages/@monomind/cli/dist/src/commands/analyze-boundaries.d.ts +14 -0
  24. package/packages/@monomind/cli/dist/src/commands/analyze-boundaries.js +295 -0
  25. package/packages/@monomind/cli/dist/src/commands/analyze-diff.d.ts +8 -0
  26. package/packages/@monomind/cli/dist/src/commands/analyze-diff.js +395 -0
  27. package/packages/@monomind/cli/dist/src/commands/analyze-graph.d.ts +14 -0
  28. package/packages/@monomind/cli/dist/src/commands/analyze-graph.js +304 -0
  29. package/packages/@monomind/cli/dist/src/commands/analyze-imports.d.ts +11 -0
  30. package/packages/@monomind/cli/dist/src/commands/analyze-imports.js +287 -0
  31. package/packages/@monomind/cli/dist/src/commands/analyze-symbols.d.ts +14 -0
  32. package/packages/@monomind/cli/dist/src/commands/analyze-symbols.js +302 -0
  33. package/packages/@monomind/cli/dist/src/commands/analyze.d.ts +38 -0
  34. package/packages/@monomind/cli/dist/src/commands/analyze.js +12 -1827
  35. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.d.ts +26 -0
  36. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +189 -0
  37. package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.d.ts +20 -0
  38. package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.js +432 -0
  39. package/packages/@monomind/cli/dist/src/commands/doctor.js +54 -943
  40. package/packages/@monomind/cli/dist/src/commands/hive-mind-comms.d.ts +11 -0
  41. package/packages/@monomind/cli/dist/src/commands/hive-mind-comms.js +242 -0
  42. package/packages/@monomind/cli/dist/src/commands/hive-mind-helpers.d.ts +35 -0
  43. package/packages/@monomind/cli/dist/src/commands/hive-mind-helpers.js +203 -0
  44. package/packages/@monomind/cli/dist/src/commands/hive-mind-ops.d.ts +8 -0
  45. package/packages/@monomind/cli/dist/src/commands/hive-mind-ops.js +233 -0
  46. package/packages/@monomind/cli/dist/src/commands/hive-mind-spawn.d.ts +12 -0
  47. package/packages/@monomind/cli/dist/src/commands/hive-mind-spawn.js +274 -0
  48. package/packages/@monomind/cli/dist/src/commands/hive-mind.js +10 -1129
  49. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.d.ts +4 -4
  50. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.js +19 -819
  51. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-gaps.d.ts +7 -0
  52. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-gaps.js +334 -0
  53. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-routing.d.ts +7 -0
  54. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-routing.js +399 -0
  55. package/packages/@monomind/cli/dist/src/commands/init-subcommands.d.ts +8 -0
  56. package/packages/@monomind/cli/dist/src/commands/init-subcommands.js +156 -0
  57. package/packages/@monomind/cli/dist/src/commands/init-upgrade.d.ts +6 -0
  58. package/packages/@monomind/cli/dist/src/commands/init-upgrade.js +203 -0
  59. package/packages/@monomind/cli/dist/src/commands/init-wizard.d.ts +6 -0
  60. package/packages/@monomind/cli/dist/src/commands/init-wizard.js +246 -0
  61. package/packages/@monomind/cli/dist/src/commands/init.js +6 -623
  62. package/packages/@monomind/cli/dist/src/commands/memory-admin.d.ts +10 -0
  63. package/packages/@monomind/cli/dist/src/commands/memory-admin.js +433 -0
  64. package/packages/@monomind/cli/dist/src/commands/memory-crud.d.ts +9 -0
  65. package/packages/@monomind/cli/dist/src/commands/memory-crud.js +342 -0
  66. package/packages/@monomind/cli/dist/src/commands/memory-list.d.ts +10 -0
  67. package/packages/@monomind/cli/dist/src/commands/memory-list.js +321 -0
  68. package/packages/@monomind/cli/dist/src/commands/memory-transfer.d.ts +9 -0
  69. package/packages/@monomind/cli/dist/src/commands/memory-transfer.js +372 -0
  70. package/packages/@monomind/cli/dist/src/commands/memory.d.ts +6 -0
  71. package/packages/@monomind/cli/dist/src/commands/memory.js +10 -1441
  72. package/packages/@monomind/cli/dist/src/commands/neural-core.d.ts +8 -0
  73. package/packages/@monomind/cli/dist/src/commands/neural-core.js +274 -0
  74. package/packages/@monomind/cli/dist/src/commands/neural-optimize.d.ts +7 -0
  75. package/packages/@monomind/cli/dist/src/commands/neural-optimize.js +332 -0
  76. package/packages/@monomind/cli/dist/src/commands/neural-registry.d.ts +7 -0
  77. package/packages/@monomind/cli/dist/src/commands/neural-registry.js +290 -0
  78. package/packages/@monomind/cli/dist/src/commands/neural.js +3 -974
  79. package/packages/@monomind/cli/dist/src/commands/platforms.js +327 -7
  80. package/packages/@monomind/cli/dist/src/commands/security-cve.d.ts +6 -0
  81. package/packages/@monomind/cli/dist/src/commands/security-cve.js +310 -0
  82. package/packages/@monomind/cli/dist/src/commands/security-misc.d.ts +9 -0
  83. package/packages/@monomind/cli/dist/src/commands/security-misc.js +293 -0
  84. package/packages/@monomind/cli/dist/src/commands/security-scan.d.ts +18 -0
  85. package/packages/@monomind/cli/dist/src/commands/security-scan.js +328 -0
  86. package/packages/@monomind/cli/dist/src/commands/security.js +3 -958
  87. package/packages/@monomind/cli/dist/src/commands/session.js +1 -1
  88. package/packages/@monomind/cli/dist/src/commands/swarm.js +23 -17
  89. package/packages/@monomind/cli/dist/src/index.js +8 -37
  90. package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +77 -0
  91. package/packages/@monomind/cli/dist/src/parser.js +11 -6
  92. package/packages/@monomind/cli/dist/src/routing/llm-caller.js +1 -2
  93. package/packages/@monomind/cli/package.json +2 -3
  94. package/packages/@monomind/cli/scripts/understand-analyze.mjs +1 -1
@@ -0,0 +1,395 @@
1
+ /**
2
+ * Analyze diff and code subcommands
3
+ * Handles git diff risk assessment and static code quality analysis
4
+ */
5
+ import { output } from '../output.js';
6
+ import { callMCPTool, MCPClientError } from '../mcp-client.js';
7
+ import * as path from 'path';
8
+ import * as fs from 'fs/promises';
9
+ import { resolve } from 'path';
10
+ import { scanSourceFiles } from './analyze.js';
11
+ function getRiskDisplay(risk) {
12
+ switch (risk) {
13
+ case 'critical':
14
+ return output.color(output.bold('CRITICAL'), 'bgRed', 'white');
15
+ case 'high-risk':
16
+ return output.error('HIGH');
17
+ case 'medium-risk':
18
+ return output.warning('MEDIUM');
19
+ case 'low-risk':
20
+ return output.success('LOW');
21
+ default:
22
+ return risk;
23
+ }
24
+ }
25
+ function getStatusDisplay(status) {
26
+ switch (status) {
27
+ case 'added':
28
+ return output.success('A');
29
+ case 'modified':
30
+ return output.warning('M');
31
+ case 'deleted':
32
+ return output.error('D');
33
+ case 'renamed':
34
+ return output.info('R');
35
+ default:
36
+ return status;
37
+ }
38
+ }
39
+ // Diff subcommand
40
+ export const diffCommand = {
41
+ name: 'diff',
42
+ description: 'Analyze git diff for change risk assessment and classification',
43
+ options: [
44
+ {
45
+ name: 'risk',
46
+ short: 'r',
47
+ description: 'Show risk assessment',
48
+ type: 'boolean',
49
+ default: false,
50
+ },
51
+ {
52
+ name: 'classify',
53
+ short: 'c',
54
+ description: 'Classify change type',
55
+ type: 'boolean',
56
+ default: false,
57
+ },
58
+ {
59
+ name: 'reviewers',
60
+ description: 'Show recommended reviewers',
61
+ type: 'boolean',
62
+ default: false,
63
+ },
64
+ {
65
+ name: 'format',
66
+ short: 'f',
67
+ description: 'Output format: text, json, table',
68
+ type: 'string',
69
+ default: 'text',
70
+ choices: ['text', 'json', 'table'],
71
+ },
72
+ {
73
+ name: 'verbose',
74
+ short: 'v',
75
+ description: 'Show detailed file-level analysis',
76
+ type: 'boolean',
77
+ default: false,
78
+ },
79
+ ],
80
+ examples: [
81
+ { command: 'monomind analyze diff --risk', description: 'Analyze current diff with risk assessment' },
82
+ { command: 'monomind analyze diff HEAD~1 --classify', description: 'Classify changes from last commit' },
83
+ { command: 'monomind analyze diff main..feature --format json', description: 'Compare branches with JSON output' },
84
+ { command: 'monomind analyze diff --reviewers', description: 'Get recommended reviewers for changes' },
85
+ ],
86
+ action: async (ctx) => {
87
+ const ref = ctx.args[0] || 'HEAD';
88
+ const showRisk = ctx.flags.risk;
89
+ const showClassify = ctx.flags.classify;
90
+ const showReviewers = ctx.flags.reviewers;
91
+ const formatType = ctx.flags.format || 'text';
92
+ const verbose = ctx.flags.verbose;
93
+ // If no specific flag, show all
94
+ const showAll = !showRisk && !showClassify && !showReviewers;
95
+ output.printInfo(`Analyzing diff: ${output.highlight(ref)}`);
96
+ try {
97
+ // Call MCP tool for diff analysis
98
+ const result = await callMCPTool('analyze_diff', {
99
+ ref,
100
+ includeFileRisks: verbose,
101
+ includeReviewers: showReviewers || showAll,
102
+ });
103
+ // JSON output
104
+ if (formatType === 'json') {
105
+ output.printJson(result);
106
+ return { success: true, data: result };
107
+ }
108
+ output.writeln();
109
+ // Summary box
110
+ const files = result.files || [];
111
+ const risk = result.risk || { overall: 'unknown', score: 0, breakdown: { fileCount: 0, totalChanges: 0, highRiskFiles: [], securityConcerns: [], breakingChanges: [], testCoverage: 'unknown' } };
112
+ const classification = result.classification || { category: 'unknown', confidence: 0, reasoning: '' };
113
+ output.printBox([
114
+ `Ref: ${result.ref || 'HEAD'}`,
115
+ `Files: ${files.length}`,
116
+ `Risk: ${getRiskDisplay(risk.overall)} (${risk.score}/100)`,
117
+ `Type: ${classification.category}${classification.subcategory ? ` (${classification.subcategory})` : ''}`,
118
+ ``,
119
+ result.summary || 'No summary available',
120
+ ].join('\n'), 'Diff Analysis');
121
+ // Risk assessment
122
+ if (showRisk || showAll) {
123
+ output.writeln();
124
+ output.writeln(output.bold('Risk Assessment'));
125
+ output.writeln(output.dim('-'.repeat(50)));
126
+ output.printTable({
127
+ columns: [
128
+ { key: 'metric', header: 'Metric', width: 25 },
129
+ { key: 'value', header: 'Value', width: 30 },
130
+ ],
131
+ data: [
132
+ { metric: 'Overall Risk', value: getRiskDisplay(risk.overall) },
133
+ { metric: 'Risk Score', value: `${risk.score}/100` },
134
+ { metric: 'Files Changed', value: risk.breakdown.fileCount },
135
+ { metric: 'Total Lines Changed', value: risk.breakdown.totalChanges },
136
+ { metric: 'Test Coverage', value: risk.breakdown.testCoverage },
137
+ ],
138
+ });
139
+ // Security concerns
140
+ if (risk.breakdown.securityConcerns.length > 0) {
141
+ output.writeln();
142
+ output.writeln(output.bold(output.warning('Security Concerns')));
143
+ output.printList(risk.breakdown.securityConcerns.map(c => output.warning(c)));
144
+ }
145
+ // Breaking changes
146
+ if (risk.breakdown.breakingChanges.length > 0) {
147
+ output.writeln();
148
+ output.writeln(output.bold(output.error('Potential Breaking Changes')));
149
+ output.printList(risk.breakdown.breakingChanges.map(c => output.error(c)));
150
+ }
151
+ // High risk files
152
+ if (risk.breakdown.highRiskFiles.length > 0) {
153
+ output.writeln();
154
+ output.writeln(output.bold('High Risk Files'));
155
+ output.printList(risk.breakdown.highRiskFiles.map(f => output.warning(f)));
156
+ }
157
+ }
158
+ // Classification
159
+ if (showClassify || showAll) {
160
+ output.writeln();
161
+ output.writeln(output.bold('Classification'));
162
+ output.writeln(output.dim('-'.repeat(50)));
163
+ output.printTable({
164
+ columns: [
165
+ { key: 'field', header: 'Field', width: 15 },
166
+ { key: 'value', header: 'Value', width: 40 },
167
+ ],
168
+ data: [
169
+ { field: 'Category', value: classification.category },
170
+ { field: 'Subcategory', value: classification.subcategory || '-' },
171
+ { field: 'Confidence', value: `${(classification.confidence * 100).toFixed(0)}%` },
172
+ ],
173
+ });
174
+ output.writeln();
175
+ output.writeln(output.dim(`Reasoning: ${classification.reasoning}`));
176
+ }
177
+ // Reviewers
178
+ if (showReviewers || showAll) {
179
+ output.writeln();
180
+ output.writeln(output.bold('Recommended Reviewers'));
181
+ output.writeln(output.dim('-'.repeat(50)));
182
+ const reviewers = result.recommendedReviewers || [];
183
+ if (reviewers.length > 0) {
184
+ output.printNumberedList(reviewers.map(r => output.highlight(r)));
185
+ }
186
+ else {
187
+ output.writeln(output.dim('No specific reviewers recommended'));
188
+ }
189
+ }
190
+ // Verbose file-level details
191
+ if (verbose && result.fileRisks) {
192
+ output.writeln();
193
+ output.writeln(output.bold('File-Level Analysis'));
194
+ output.writeln(output.dim('-'.repeat(50)));
195
+ output.printTable({
196
+ columns: [
197
+ { key: 'path', header: 'File', width: 40 },
198
+ { key: 'risk', header: 'Risk', width: 12, format: (v) => getRiskDisplay(String(v)) },
199
+ { key: 'score', header: 'Score', width: 8, align: 'right' },
200
+ { key: 'reasons', header: 'Reasons', width: 30, format: (v) => {
201
+ const reasons = v;
202
+ return reasons.slice(0, 2).join('; ');
203
+ } },
204
+ ],
205
+ data: result.fileRisks,
206
+ });
207
+ }
208
+ // Files changed table
209
+ if (formatType === 'table' || showAll) {
210
+ output.writeln();
211
+ output.writeln(output.bold('Files Changed'));
212
+ output.writeln(output.dim('-'.repeat(50)));
213
+ output.printTable({
214
+ columns: [
215
+ { key: 'status', header: 'Status', width: 10, format: (v) => getStatusDisplay(String(v)) },
216
+ { key: 'path', header: 'File', width: 45 },
217
+ { key: 'additions', header: '+', width: 8, align: 'right', format: (v) => output.success(`+${v}`) },
218
+ { key: 'deletions', header: '-', width: 8, align: 'right', format: (v) => output.error(`-${v}`) },
219
+ ],
220
+ data: files.slice(0, 20),
221
+ });
222
+ if (files.length > 20) {
223
+ output.writeln(output.dim(` ... and ${files.length - 20} more files`));
224
+ }
225
+ }
226
+ return { success: true, data: result };
227
+ }
228
+ catch (error) {
229
+ if (error instanceof MCPClientError) {
230
+ output.printError(`Diff analysis failed: ${error.message}`);
231
+ }
232
+ else {
233
+ output.printError(`Unexpected error: ${String(error)}`);
234
+ }
235
+ return { success: false, exitCode: 1 };
236
+ }
237
+ },
238
+ };
239
+ // Code subcommand (placeholder for future code analysis)
240
+ export const codeCommand = {
241
+ name: 'code',
242
+ description: 'Static code analysis and quality assessment',
243
+ options: [
244
+ { name: 'path', short: 'p', type: 'string', description: 'Path to analyze', default: '.' },
245
+ { name: 'type', short: 't', type: 'string', description: 'Analysis type: quality, complexity, security', default: 'quality' },
246
+ { name: 'format', short: 'f', type: 'string', description: 'Output format: text, json', default: 'text' },
247
+ ],
248
+ examples: [
249
+ { command: 'monomind analyze code -p ./src', description: 'Analyze source directory' },
250
+ { command: 'monomind analyze code --type complexity', description: 'Run complexity analysis' },
251
+ ],
252
+ action: async (ctx) => {
253
+ const targetPath = resolve(ctx.flags.path || '.');
254
+ const analysisType = ctx.flags.type || 'quality';
255
+ const formatJson = ctx.flags.format === 'json';
256
+ output.writeln();
257
+ output.writeln(output.bold('Code Analysis'));
258
+ output.writeln(output.dim('-'.repeat(50)));
259
+ const spinner = output.createSpinner({ text: `Analyzing ${targetPath}...`, spinner: 'dots' });
260
+ spinner.start();
261
+ try {
262
+ const files = await scanSourceFiles(targetPath);
263
+ if (files.length === 0) {
264
+ spinner.stop();
265
+ output.printWarning('No source files found');
266
+ return { success: true };
267
+ }
268
+ const fileStats = [];
269
+ for (const filePath of files) {
270
+ const content = await fs.readFile(filePath, 'utf-8');
271
+ const lines = content.split('\n');
272
+ const nonEmpty = lines.filter(l => l.trim().length > 0 && !/^\s*(\/\/|\/\*|\*\s|#)/.test(l)).length;
273
+ const todos = (content.match(/\b(TODO|FIXME|HACK|XXX)\b/gi) || []).length;
274
+ const fns = (content.match(/(?:export\s+)?(?:async\s+)?function\s+\w+|(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?\([^)]*\)\s*=>/g) || []).length;
275
+ const imps = (content.match(/^import\s+/gm) || []).length + (content.match(/require\s*\(/g) || []).length;
276
+ let maxNesting = 0;
277
+ let nesting = 0;
278
+ for (const line of lines) {
279
+ nesting += (line.match(/\{/g) || []).length;
280
+ nesting -= (line.match(/\}/g) || []).length;
281
+ if (nesting > maxNesting)
282
+ maxNesting = nesting;
283
+ }
284
+ const securityIssues = [];
285
+ if (/\beval\s*\(/.test(content))
286
+ securityIssues.push('eval()');
287
+ if (/\bexec\s*\(/.test(content))
288
+ securityIssues.push('exec()');
289
+ if (/\.innerHTML\s*=/.test(content))
290
+ securityIssues.push('innerHTML');
291
+ if (/dangerouslySetInnerHTML/.test(content))
292
+ securityIssues.push('dangerouslySetInnerHTML');
293
+ if (/['"](?:password|secret|api[_-]?key|token)\s*[:=]\s*['"][^'"]{3,}['"]/i.test(content))
294
+ securityIssues.push('hardcoded secret');
295
+ if (/new\s+Function\s*\(/.test(content))
296
+ securityIssues.push('new Function()');
297
+ fileStats.push({
298
+ file: filePath,
299
+ loc: nonEmpty,
300
+ todos,
301
+ functions: fns,
302
+ imports: imps,
303
+ maxNesting,
304
+ securityIssues,
305
+ });
306
+ }
307
+ spinner.stop();
308
+ const totalLoc = fileStats.reduce((s, f) => s + f.loc, 0);
309
+ const totalTodos = fileStats.reduce((s, f) => s + f.todos, 0);
310
+ const totalFunctions = fileStats.reduce((s, f) => s + f.functions, 0);
311
+ const totalImports = fileStats.reduce((s, f) => s + f.imports, 0);
312
+ const avgFileSize = Math.round(totalLoc / files.length);
313
+ const longestFile = fileStats.reduce((a, b) => a.loc > b.loc ? a : b);
314
+ const avgFnPerFile = (totalFunctions / files.length).toFixed(1);
315
+ const deepestNesting = fileStats.reduce((a, b) => a.maxNesting > b.maxNesting ? a : b);
316
+ const allSecurityIssues = fileStats.filter(f => f.securityIssues.length > 0);
317
+ if (formatJson) {
318
+ const jsonData = { type: analysisType, path: targetPath, files: files.length, totalLoc, totalTodos, totalFunctions, totalImports, avgFileSize, fileStats: fileStats.map(f => ({ relativePath: path.relative(targetPath, f.file), loc: f.loc, todos: f.todos, functions: f.functions, imports: f.imports, maxNesting: f.maxNesting, securityIssues: f.securityIssues })) };
319
+ output.printJson(jsonData);
320
+ return { success: true, data: jsonData };
321
+ }
322
+ if (analysisType === 'quality') {
323
+ output.printBox([`Files: ${files.length}`, `Lines of Code: ${totalLoc.toLocaleString()}`, `Avg File Size: ${avgFileSize} LOC`, `TODO/FIXME: ${totalTodos}`, `Functions: ${totalFunctions}`, `Imports: ${totalImports}`].join('\n'), 'Quality Summary');
324
+ output.writeln();
325
+ output.writeln(output.bold('Largest Files'));
326
+ output.writeln(output.dim('-'.repeat(60)));
327
+ const top10 = [...fileStats].sort((a, b) => b.loc - a.loc).slice(0, 10);
328
+ output.printTable({
329
+ columns: [
330
+ { key: 'file', header: 'File', width: 45 },
331
+ { key: 'loc', header: 'LOC', width: 8, align: 'right' },
332
+ { key: 'fns', header: 'Fns', width: 6, align: 'right' },
333
+ { key: 'todos', header: 'TODOs', width: 7, align: 'right' },
334
+ ],
335
+ data: top10.map(f => ({ file: path.relative(targetPath, f.file), loc: f.loc, fns: f.functions, todos: f.todos })),
336
+ });
337
+ if (totalTodos > 0) {
338
+ output.writeln();
339
+ output.printWarning(`${totalTodos} TODO/FIXME comments found across ${fileStats.filter(f => f.todos > 0).length} files`);
340
+ }
341
+ }
342
+ else if (analysisType === 'complexity') {
343
+ output.printBox([`Files: ${files.length}`, `Total Functions: ${totalFunctions}`, `Avg Functions/File: ${avgFnPerFile}`, `Deepest Nesting: ${deepestNesting.maxNesting} levels (${path.relative(targetPath, deepestNesting.file)})`, `Longest File: ${longestFile.loc} LOC (${path.relative(targetPath, longestFile.file)})`].join('\n'), 'Complexity Summary');
344
+ output.writeln();
345
+ output.writeln(output.bold('High Complexity Files (nesting > 5)'));
346
+ output.writeln(output.dim('-'.repeat(60)));
347
+ const complex = fileStats.filter(f => f.maxNesting > 5).sort((a, b) => b.maxNesting - a.maxNesting);
348
+ if (complex.length === 0) {
349
+ output.printSuccess('No files with excessive nesting detected');
350
+ }
351
+ else {
352
+ output.printTable({
353
+ columns: [
354
+ { key: 'file', header: 'File', width: 45 },
355
+ { key: 'nesting', header: 'Max Nest', width: 10, align: 'right' },
356
+ { key: 'fns', header: 'Fns', width: 6, align: 'right' },
357
+ { key: 'loc', header: 'LOC', width: 8, align: 'right' },
358
+ ],
359
+ data: complex.slice(0, 15).map(f => ({ file: path.relative(targetPath, f.file), nesting: f.maxNesting, fns: f.functions, loc: f.loc })),
360
+ });
361
+ }
362
+ }
363
+ else if (analysisType === 'security') {
364
+ output.printBox([`Files Scanned: ${files.length}`, `Files with Issues: ${allSecurityIssues.length}`, `Total Issues: ${allSecurityIssues.reduce((s, f) => s + f.securityIssues.length, 0)}`].join('\n'), 'Security Summary');
365
+ if (allSecurityIssues.length === 0) {
366
+ output.writeln();
367
+ output.printSuccess('No common security patterns detected');
368
+ }
369
+ else {
370
+ output.writeln();
371
+ output.writeln(output.bold('Security Concerns'));
372
+ output.writeln(output.dim('-'.repeat(60)));
373
+ output.printTable({
374
+ columns: [
375
+ { key: 'file', header: 'File', width: 40 },
376
+ { key: 'issues', header: 'Issues', width: 35 },
377
+ ],
378
+ data: allSecurityIssues.map(f => ({ file: path.relative(targetPath, f.file), issues: f.securityIssues.join(', ') })),
379
+ });
380
+ }
381
+ }
382
+ else {
383
+ output.printWarning(`Unknown analysis type: ${analysisType}. Use quality, complexity, or security.`);
384
+ }
385
+ return { success: true };
386
+ }
387
+ catch (error) {
388
+ spinner.stop();
389
+ const message = error instanceof Error ? error.message : String(error);
390
+ output.printError(`Code analysis failed: ${message}`);
391
+ return { success: false, exitCode: 1 };
392
+ }
393
+ },
394
+ };
395
+ //# sourceMappingURL=analyze-diff.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Analyze dependencies and circular subcommands
3
+ * Full dependency graph building and circular dependency detection
4
+ */
5
+ import type { Command } from '../types.js';
6
+ /**
7
+ * Build and export dependency graph
8
+ */
9
+ export declare const dependenciesCommand: Command;
10
+ /**
11
+ * Detect circular dependencies
12
+ */
13
+ export declare const circularCommand: Command;
14
+ //# sourceMappingURL=analyze-graph.d.ts.map