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
@@ -4,759 +4,11 @@
4
4
  * Extracted from hooks.ts to reduce file size.
5
5
  */
6
6
  import { output } from '../output.js';
7
- import { callMCPTool, MCPClientError } from '../mcp-client.js';
8
- import { readCoverageFromDisk, classifyCoverageGap, suggestAgentsForFile, } from './hooks-coverage-utils.js';
9
- // ============================================================================
10
- // Coverage-Aware Routing Commands
11
- // ============================================================================
12
- // Coverage route subcommand
13
- export const coverageRouteCommand = {
14
- name: 'coverage-route',
15
- description: 'Route task to agents based on test coverage gaps (monovector integration)',
16
- options: [
17
- {
18
- name: 'task',
19
- short: 't',
20
- description: 'Task description to route',
21
- type: 'string',
22
- required: true
23
- },
24
- {
25
- name: 'threshold',
26
- description: 'Coverage threshold percentage (default: 80)',
27
- type: 'number',
28
- default: 80
29
- },
30
- {
31
- name: 'no-monovector',
32
- description: 'Disable monovector integration',
33
- type: 'boolean',
34
- default: false
35
- }
36
- ],
37
- examples: [
38
- { command: 'monomind hooks coverage-route -t "fix bug in auth"', description: 'Route with coverage awareness' },
39
- { command: 'monomind hooks coverage-route -t "add tests" --threshold 90', description: 'Route with custom threshold' }
40
- ],
41
- action: async (ctx) => {
42
- const task = ctx.args[0] || ctx.flags.task;
43
- const threshold = ctx.flags.threshold || 80;
44
- const useMonovector = !ctx.flags['no-monovector'];
45
- if (!task) {
46
- output.printError('Task description is required. Use --task or -t flag.');
47
- return { success: false, exitCode: 1 };
48
- }
49
- const spinner = output.createSpinner({ text: 'Analyzing coverage and routing task...' });
50
- spinner.start();
51
- // Try reading coverage from disk first
52
- const diskCoverage = readCoverageFromDisk();
53
- if (diskCoverage.found) {
54
- spinner.succeed(`Coverage data loaded from ${diskCoverage.source}`);
55
- // Find files with lowest coverage that may relate to the task
56
- const taskLower = task.toLowerCase();
57
- const taskWords = taskLower.split(/\s+/).filter(w => w.length > 2);
58
- // Score each file by relevance to the task and how low its coverage is
59
- const scoredFiles = diskCoverage.entries
60
- .filter(e => e.lines < threshold)
61
- .map(e => {
62
- const fileNameLower = e.filePath.toLowerCase();
63
- let relevance = 0;
64
- for (const word of taskWords) {
65
- if (fileNameLower.includes(word))
66
- relevance += 2;
67
- }
68
- // Penalize high coverage (we care about low coverage)
69
- const coveragePenalty = e.lines / 100;
70
- return { ...e, relevance, score: relevance + (1 - coveragePenalty) };
71
- })
72
- .sort((a, b) => b.score - a.score);
73
- const gaps = scoredFiles.slice(0, 8).map(e => {
74
- const { gapType, priority } = classifyCoverageGap(e.lines, threshold);
75
- return {
76
- filePath: e.filePath,
77
- coveragePercent: e.lines,
78
- gapType,
79
- priority,
80
- suggestedAgents: suggestAgentsForFile(e.filePath),
81
- reason: `${e.lines.toFixed(1)}% coverage, below ${threshold}%`,
82
- };
83
- });
84
- const criticalGaps = gaps.filter(g => g.gapType === 'critical').length;
85
- const primaryAgent = taskLower.includes('test') ? 'tester' :
86
- taskLower.includes('security') || taskLower.includes('auth') ? 'security-auditor' :
87
- taskLower.includes('fix') || taskLower.includes('bug') ? 'coder' : 'tester';
88
- const suggestions = [];
89
- if (criticalGaps > 0)
90
- suggestions.push(`${criticalGaps} critical coverage gaps need immediate attention`);
91
- if (diskCoverage.summary.overallLineCoverage < threshold) {
92
- suggestions.push(`Overall line coverage (${diskCoverage.summary.overallLineCoverage.toFixed(1)}%) is below ${threshold}% threshold`);
93
- }
94
- if (scoredFiles.length > 8)
95
- suggestions.push(`${scoredFiles.length - 8} additional files with low coverage`);
96
- const result = {
97
- success: true,
98
- task,
99
- coverageAware: true,
100
- gaps,
101
- routing: {
102
- primaryAgent,
103
- confidence: gaps.length > 0 ? 0.85 : 0.6,
104
- reason: gaps.length > 0
105
- ? `Routing to ${primaryAgent} based on ${gaps.length} coverage gaps related to task`
106
- : `No coverage gaps found related to task, routing to ${primaryAgent}`,
107
- coverageImpact: gaps.length > 0 ? 'high' : 'low',
108
- },
109
- suggestions,
110
- metrics: {
111
- filesAnalyzed: diskCoverage.summary.totalFiles,
112
- totalGaps: scoredFiles.length,
113
- criticalGaps,
114
- avgCoverage: diskCoverage.summary.overallLineCoverage,
115
- },
116
- source: diskCoverage.source,
117
- };
118
- if (ctx.flags.format === 'json') {
119
- output.printJson(result);
120
- return { success: true, data: result };
121
- }
122
- output.writeln();
123
- output.printBox([
124
- `Agent: ${output.highlight(result.routing.primaryAgent)}`,
125
- `Confidence: ${(result.routing.confidence * 100).toFixed(1)}%`,
126
- `Coverage-Aware: ${output.success('Yes')} (from ${diskCoverage.source})`,
127
- `Reason: ${result.routing.reason}`
128
- ].join('\n'), 'Coverage-Aware Routing');
129
- if (gaps.length > 0) {
130
- output.writeln();
131
- output.writeln(output.bold('Priority Coverage Gaps'));
132
- output.printTable({
133
- columns: [
134
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
135
- const s = String(v);
136
- return s.length > 32 ? '...' + s.slice(-32) : s;
137
- } },
138
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
139
- { key: 'gapType', header: 'Type', width: 10 },
140
- { key: 'suggestedAgents', header: 'Agent', width: 15, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
141
- ],
142
- data: gaps.slice(0, 8)
143
- });
144
- }
145
- if (result.metrics.filesAnalyzed > 0) {
146
- output.writeln();
147
- output.writeln(output.bold('Coverage Metrics'));
148
- output.printList([
149
- `Files Analyzed: ${result.metrics.filesAnalyzed}`,
150
- `Total Gaps: ${result.metrics.totalGaps}`,
151
- `Critical Gaps: ${result.metrics.criticalGaps}`,
152
- `Average Coverage: ${result.metrics.avgCoverage.toFixed(1)}%`
153
- ]);
154
- }
155
- if (suggestions.length > 0) {
156
- output.writeln();
157
- output.writeln(output.bold('Suggestions'));
158
- output.printList(suggestions.map(s => output.dim(s)));
159
- }
160
- return { success: true, data: result };
161
- }
162
- // No disk coverage - fall back to MCP tool
163
- try {
164
- const result = await callMCPTool('hooks_coverage-route', {
165
- task,
166
- threshold,
167
- useMonovector,
168
- });
169
- spinner.stop();
170
- if (ctx.flags.format === 'json') {
171
- output.printJson(result);
172
- return { success: true, data: result };
173
- }
174
- output.writeln();
175
- output.printBox([
176
- `Agent: ${output.highlight(result.routing.primaryAgent)}`,
177
- `Confidence: ${(result.routing.confidence * 100).toFixed(1)}%`,
178
- `Coverage-Aware: ${result.coverageAware ? output.success('Yes') : output.dim('No coverage data')}`,
179
- `Reason: ${result.routing.reason}`
180
- ].join('\n'), 'Coverage-Aware Routing');
181
- if (result.gaps.length > 0) {
182
- output.writeln();
183
- output.writeln(output.bold('Priority Coverage Gaps'));
184
- output.printTable({
185
- columns: [
186
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
187
- const s = String(v);
188
- return s.length > 32 ? '...' + s.slice(-32) : s;
189
- } },
190
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
191
- { key: 'gapType', header: 'Type', width: 10 },
192
- { key: 'suggestedAgents', header: 'Agent', width: 15, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
193
- ],
194
- data: result.gaps.slice(0, 8)
195
- });
196
- }
197
- if (result.metrics.filesAnalyzed > 0) {
198
- output.writeln();
199
- output.writeln(output.bold('Coverage Metrics'));
200
- output.printList([
201
- `Files Analyzed: ${result.metrics.filesAnalyzed}`,
202
- `Total Gaps: ${result.metrics.totalGaps}`,
203
- `Critical Gaps: ${result.metrics.criticalGaps}`,
204
- `Average Coverage: ${result.metrics.avgCoverage.toFixed(1)}%`
205
- ]);
206
- }
207
- if (result.suggestions.length > 0) {
208
- output.writeln();
209
- output.writeln(output.bold('Suggestions'));
210
- output.printList(result.suggestions.map(s => output.dim(s)));
211
- }
212
- return { success: true, data: result };
213
- }
214
- catch (error) {
215
- spinner.fail('No coverage data found');
216
- output.writeln();
217
- output.printWarning('No coverage data found. Run your test suite with coverage first.');
218
- output.writeln();
219
- output.printList([
220
- 'Jest: npx jest --coverage',
221
- 'Vitest: npx vitest --coverage',
222
- 'nyc: npx nyc npm test',
223
- 'c8: npx c8 npm test',
224
- ]);
225
- output.writeln();
226
- output.writeln(output.dim('Expected files: coverage/coverage-summary.json, coverage/lcov.info, or .nyc_output/out.json'));
227
- return { success: false, exitCode: 1 };
228
- }
229
- }
230
- };
231
- // Coverage suggest subcommand
232
- export const coverageSuggestCommand = {
233
- name: 'coverage-suggest',
234
- description: 'Suggest coverage improvements for a path (monovector integration)',
235
- options: [
236
- {
237
- name: 'path',
238
- short: 'p',
239
- description: 'Path to analyze for coverage suggestions',
240
- type: 'string',
241
- required: true
242
- },
243
- {
244
- name: 'threshold',
245
- description: 'Coverage threshold percentage (default: 80)',
246
- type: 'number',
247
- default: 80
248
- },
249
- {
250
- name: 'limit',
251
- short: 'l',
252
- description: 'Maximum number of suggestions (default: 20)',
253
- type: 'number',
254
- default: 20
255
- }
256
- ],
257
- examples: [
258
- { command: 'monomind hooks coverage-suggest -p src/', description: 'Suggest improvements for src/' },
259
- { command: 'monomind hooks coverage-suggest -p src/services --threshold 90', description: 'Stricter threshold' }
260
- ],
261
- action: async (ctx) => {
262
- const targetPath = ctx.args[0] || ctx.flags.path;
263
- const threshold = ctx.flags.threshold || 80;
264
- const limit = ctx.flags.limit || 20;
265
- if (!targetPath) {
266
- output.printError('Path is required. Use --path or -p flag.');
267
- return { success: false, exitCode: 1 };
268
- }
269
- const spinner = output.createSpinner({ text: `Analyzing coverage for ${targetPath}...` });
270
- spinner.start();
271
- // Try reading coverage from disk first
272
- const diskCoverage = readCoverageFromDisk();
273
- if (diskCoverage.found) {
274
- spinner.succeed(`Coverage data loaded from ${diskCoverage.source}`);
275
- // Filter entries to those matching the target path
276
- const pathLower = targetPath.toLowerCase().replace(/\\/g, '/');
277
- const matchingEntries = diskCoverage.entries.filter(e => {
278
- const fileLower = e.filePath.toLowerCase().replace(/\\/g, '/');
279
- return fileLower.includes(pathLower);
280
- });
281
- const belowThreshold = matchingEntries.filter(e => e.lines < threshold);
282
- const suggestions = belowThreshold.slice(0, limit).map(e => {
283
- const { gapType, priority } = classifyCoverageGap(e.lines, threshold);
284
- return {
285
- filePath: e.filePath,
286
- coveragePercent: e.lines,
287
- gapType,
288
- priority,
289
- suggestedAgents: suggestAgentsForFile(e.filePath),
290
- reason: e.lines === 0 ? 'No coverage at all' :
291
- e.lines < 20 ? 'Very low coverage, needs tests' :
292
- e.lines < 50 ? 'Below 50%, add more tests' :
293
- `Below ${threshold}% threshold`,
294
- };
295
- });
296
- const totalLinesCov = matchingEntries.length > 0
297
- ? matchingEntries.reduce((acc, e) => acc + e.lines, 0) / matchingEntries.length
298
- : 0;
299
- const totalBranchesCov = matchingEntries.length > 0
300
- ? matchingEntries.reduce((acc, e) => acc + e.branches, 0) / matchingEntries.length
301
- : 0;
302
- const prioritizedFiles = belowThreshold.slice(0, 5).map(e => e.filePath);
303
- const result = {
304
- success: true,
305
- path: targetPath,
306
- suggestions,
307
- summary: {
308
- totalFiles: matchingEntries.length,
309
- overallLineCoverage: totalLinesCov,
310
- overallBranchCoverage: totalBranchesCov,
311
- filesBelowThreshold: belowThreshold.length,
312
- },
313
- prioritizedFiles,
314
- monovectorAvailable: false,
315
- source: diskCoverage.source,
316
- };
317
- if (ctx.flags.format === 'json') {
318
- output.printJson(result);
319
- return { success: true, data: result };
320
- }
321
- output.writeln();
322
- output.printBox([
323
- `Path: ${output.highlight(targetPath)}`,
324
- `Files Analyzed: ${result.summary.totalFiles}`,
325
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
326
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
327
- `Below Threshold: ${result.summary.filesBelowThreshold} files`,
328
- `Source: ${output.highlight(diskCoverage.source)}`
329
- ].join('\n'), 'Coverage Summary');
330
- if (suggestions.length > 0) {
331
- output.writeln();
332
- output.writeln(output.bold('Coverage Improvement Suggestions'));
333
- output.printTable({
334
- columns: [
335
- { key: 'filePath', header: 'File', width: 40, format: (v) => {
336
- const s = String(v);
337
- return s.length > 37 ? '...' + s.slice(-37) : s;
338
- } },
339
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
340
- { key: 'gapType', header: 'Priority', width: 10 },
341
- { key: 'reason', header: 'Reason', width: 25 }
342
- ],
343
- data: suggestions.slice(0, 15)
344
- });
345
- }
346
- else {
347
- output.writeln();
348
- output.printSuccess('All files meet coverage threshold!');
349
- }
350
- if (prioritizedFiles.length > 0) {
351
- output.writeln();
352
- output.writeln(output.bold('Priority Files (Top 5)'));
353
- output.printList(prioritizedFiles.slice(0, 5).map(f => output.highlight(f)));
354
- }
355
- return { success: true, data: result };
356
- }
357
- // No disk coverage - fall back to MCP tool
358
- try {
359
- const result = await callMCPTool('hooks_coverage-suggest', {
360
- path: targetPath,
361
- threshold,
362
- limit,
363
- });
364
- spinner.stop();
365
- if (ctx.flags.format === 'json') {
366
- output.printJson(result);
367
- return { success: true, data: result };
368
- }
369
- output.writeln();
370
- output.printBox([
371
- `Path: ${output.highlight(result.path)}`,
372
- `Files Analyzed: ${result.summary.totalFiles}`,
373
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
374
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
375
- `Below Threshold: ${result.summary.filesBelowThreshold} files`,
376
- `Keyword routing: ${result.monovectorAvailable ? output.success('Available') : output.dim('Unavailable')}`
377
- ].join('\n'), 'Coverage Summary');
378
- if (result.suggestions.length > 0) {
379
- output.writeln();
380
- output.writeln(output.bold('Coverage Improvement Suggestions'));
381
- output.printTable({
382
- columns: [
383
- { key: 'filePath', header: 'File', width: 40, format: (v) => {
384
- const s = String(v);
385
- return s.length > 37 ? '...' + s.slice(-37) : s;
386
- } },
387
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
388
- { key: 'gapType', header: 'Priority', width: 10 },
389
- { key: 'reason', header: 'Reason', width: 25 }
390
- ],
391
- data: result.suggestions.slice(0, 15)
392
- });
393
- }
394
- else {
395
- output.writeln();
396
- output.printSuccess('All files meet coverage threshold!');
397
- }
398
- if (result.prioritizedFiles.length > 0) {
399
- output.writeln();
400
- output.writeln(output.bold('Priority Files (Top 5)'));
401
- output.printList(result.prioritizedFiles.slice(0, 5).map(f => output.highlight(f)));
402
- }
403
- return { success: true, data: result };
404
- }
405
- catch (error) {
406
- spinner.fail('No coverage data found');
407
- output.writeln();
408
- output.printWarning('No coverage data found. Run your test suite with coverage first.');
409
- output.writeln();
410
- output.printList([
411
- 'Jest: npx jest --coverage',
412
- 'Vitest: npx vitest --coverage',
413
- 'nyc: npx nyc npm test',
414
- 'c8: npx c8 npm test',
415
- ]);
416
- output.writeln();
417
- output.writeln(output.dim('Expected files: coverage/coverage-summary.json, coverage/lcov.info, or .nyc_output/out.json'));
418
- return { success: false, exitCode: 1 };
419
- }
420
- }
421
- };
422
- // Coverage gaps subcommand
423
- export const coverageGapsCommand = {
424
- name: 'coverage-gaps',
425
- description: 'List all coverage gaps with priority scoring and agent assignments',
426
- options: [
427
- {
428
- name: 'threshold',
429
- description: 'Coverage threshold percentage (default: 80)',
430
- type: 'number',
431
- default: 80
432
- },
433
- {
434
- name: 'group-by-agent',
435
- description: 'Group gaps by suggested agent (default: true)',
436
- type: 'boolean',
437
- default: true
438
- },
439
- {
440
- name: 'critical-only',
441
- description: 'Show only critical gaps',
442
- type: 'boolean',
443
- default: false
444
- }
445
- ],
446
- examples: [
447
- { command: 'monomind hooks coverage-gaps', description: 'List all coverage gaps' },
448
- { command: 'monomind hooks coverage-gaps --critical-only', description: 'Only critical gaps' },
449
- { command: 'monomind hooks coverage-gaps --threshold 90', description: 'Stricter threshold' }
450
- ],
451
- action: async (ctx) => {
452
- const threshold = ctx.flags.threshold || 80;
453
- const groupByAgent = ctx.flags['group-by-agent'] !== false;
454
- const criticalOnly = ctx.flags['critical-only'] || false;
455
- const spinner = output.createSpinner({ text: 'Analyzing project coverage gaps...' });
456
- spinner.start();
457
- // Try reading coverage from disk first
458
- const diskCoverage = readCoverageFromDisk();
459
- if (diskCoverage.found) {
460
- spinner.succeed(`Coverage data loaded from ${diskCoverage.source}`);
461
- // Build gaps from disk data
462
- const allGaps = diskCoverage.entries
463
- .filter(e => e.lines < threshold)
464
- .map(e => {
465
- const { gapType, priority } = classifyCoverageGap(e.lines, threshold);
466
- return {
467
- filePath: e.filePath,
468
- coveragePercent: e.lines,
469
- gapType,
470
- complexity: Math.round((100 - e.lines) / 10),
471
- priority,
472
- suggestedAgents: suggestAgentsForFile(e.filePath),
473
- reason: `Line coverage ${e.lines.toFixed(1)}% below ${threshold}% threshold`,
474
- };
475
- });
476
- const gaps = criticalOnly
477
- ? allGaps.filter(g => g.gapType === 'critical')
478
- : allGaps;
479
- // Build agent assignments
480
- const agentAssignments = {};
481
- if (groupByAgent) {
482
- for (const gap of gaps) {
483
- const agent = gap.suggestedAgents[0] || 'tester';
484
- if (!agentAssignments[agent])
485
- agentAssignments[agent] = [];
486
- agentAssignments[agent].push(gap.filePath);
487
- }
488
- }
489
- const result = {
490
- success: true,
491
- gaps,
492
- summary: {
493
- totalFiles: diskCoverage.summary.totalFiles,
494
- overallLineCoverage: diskCoverage.summary.overallLineCoverage,
495
- overallBranchCoverage: diskCoverage.summary.overallBranchCoverage,
496
- filesBelowThreshold: gaps.length,
497
- coverageThreshold: threshold,
498
- },
499
- agentAssignments,
500
- monovectorAvailable: false,
501
- source: diskCoverage.source,
502
- };
503
- if (ctx.flags.format === 'json') {
504
- output.printJson(result);
505
- return { success: true, data: result };
506
- }
507
- output.writeln();
508
- output.printBox([
509
- `Total Files: ${result.summary.totalFiles}`,
510
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
511
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
512
- `Below ${threshold}%: ${result.summary.filesBelowThreshold} files`,
513
- `Source: ${output.highlight(diskCoverage.source)}`
514
- ].join('\n'), 'Coverage Gap Analysis');
515
- if (gaps.length > 0) {
516
- output.writeln();
517
- output.writeln(output.bold(`Coverage Gaps (${gaps.length} files)`));
518
- output.printTable({
519
- columns: [
520
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
521
- const s = String(v);
522
- return s.length > 32 ? '...' + s.slice(-32) : s;
523
- } },
524
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
525
- { key: 'gapType', header: 'Type', width: 10, format: (v) => {
526
- const t = String(v);
527
- if (t === 'critical')
528
- return output.error(t);
529
- if (t === 'high')
530
- return output.warning(t);
531
- return t;
532
- } },
533
- { key: 'priority', header: 'Priority', width: 8, align: 'right' },
534
- { key: 'suggestedAgents', header: 'Agent', width: 12, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
535
- ],
536
- data: gaps.slice(0, 20)
537
- });
538
- }
539
- else {
540
- output.writeln();
541
- output.printSuccess('No coverage gaps found! All files meet threshold.');
542
- }
543
- if (groupByAgent && Object.keys(agentAssignments).length > 0) {
544
- output.writeln();
545
- output.writeln(output.bold('Agent Assignments'));
546
- for (const [agent, files] of Object.entries(agentAssignments)) {
547
- output.writeln();
548
- output.writeln(` ${output.highlight(agent)} (${files.length} files)`);
549
- files.slice(0, 3).forEach(f => {
550
- output.writeln(` - ${output.dim(f)}`);
551
- });
552
- if (files.length > 3) {
553
- output.writeln(` ... and ${files.length - 3} more`);
554
- }
555
- }
556
- }
557
- return { success: true, data: result };
558
- }
559
- // No coverage files on disk - try MCP tool as fallback
560
- try {
561
- const result = await callMCPTool('hooks_coverage-gaps', {
562
- threshold,
563
- groupByAgent,
564
- });
565
- spinner.stop();
566
- const gaps = criticalOnly
567
- ? result.gaps.filter(g => g.gapType === 'critical')
568
- : result.gaps;
569
- if (ctx.flags.format === 'json') {
570
- output.printJson({ ...result, gaps });
571
- return { success: true, data: result };
572
- }
573
- output.writeln();
574
- output.printBox([
575
- `Total Files: ${result.summary.totalFiles}`,
576
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
577
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
578
- `Below ${result.summary.coverageThreshold}%: ${result.summary.filesBelowThreshold} files`,
579
- `Keyword routing: ${result.monovectorAvailable ? output.success('Available') : output.dim('Unavailable')}`
580
- ].join('\n'), 'Coverage Gap Analysis');
581
- if (gaps.length > 0) {
582
- output.writeln();
583
- output.writeln(output.bold(`Coverage Gaps (${gaps.length} files)`));
584
- output.printTable({
585
- columns: [
586
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
587
- const s = String(v);
588
- return s.length > 32 ? '...' + s.slice(-32) : s;
589
- } },
590
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
591
- { key: 'gapType', header: 'Type', width: 10, format: (v) => {
592
- const t = String(v);
593
- if (t === 'critical')
594
- return output.error(t);
595
- if (t === 'high')
596
- return output.warning(t);
597
- return t;
598
- } },
599
- { key: 'priority', header: 'Priority', width: 8, align: 'right' },
600
- { key: 'suggestedAgents', header: 'Agent', width: 12, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
601
- ],
602
- data: gaps.slice(0, 20)
603
- });
604
- }
605
- else {
606
- output.writeln();
607
- output.printSuccess('No coverage gaps found! All files meet threshold.');
608
- }
609
- if (groupByAgent && Object.keys(result.agentAssignments).length > 0) {
610
- output.writeln();
611
- output.writeln(output.bold('Agent Assignments'));
612
- for (const [agent, files] of Object.entries(result.agentAssignments)) {
613
- output.writeln();
614
- output.writeln(` ${output.highlight(agent)} (${files.length} files)`);
615
- files.slice(0, 3).forEach(f => {
616
- output.writeln(` - ${output.dim(f)}`);
617
- });
618
- if (files.length > 3) {
619
- output.writeln(` ... and ${files.length - 3} more`);
620
- }
621
- }
622
- }
623
- return { success: true, data: result };
624
- }
625
- catch (error) {
626
- spinner.fail('No coverage data found');
627
- output.writeln();
628
- output.printWarning('No coverage data found. Run your test suite with coverage first.');
629
- output.writeln();
630
- output.printList([
631
- 'Jest: npx jest --coverage',
632
- 'Vitest: npx vitest --coverage',
633
- 'nyc: npx nyc npm test',
634
- 'c8: npx c8 npm test',
635
- ]);
636
- output.writeln();
637
- output.writeln(output.dim('Expected files: coverage/coverage-summary.json, coverage/lcov.info, or .nyc_output/out.json'));
638
- return { success: false, exitCode: 1 };
639
- }
640
- }
641
- };
642
- // Progress hook command
643
- export const progressHookCommand = {
644
- name: 'progress',
645
- description: 'Check implementation progress via hooks',
646
- options: [
647
- {
648
- name: 'detailed',
649
- short: 'd',
650
- description: 'Show detailed breakdown by category',
651
- type: 'boolean',
652
- default: false
653
- },
654
- {
655
- name: 'sync',
656
- short: 's',
657
- description: 'Sync and persist progress to file',
658
- type: 'boolean',
659
- default: false
660
- },
661
- {
662
- name: 'summary',
663
- description: 'Show human-readable summary',
664
- type: 'boolean',
665
- default: false
666
- }
667
- ],
668
- examples: [
669
- { command: 'monomind hooks progress', description: 'Check current progress' },
670
- { command: 'monomind hooks progress -d', description: 'Detailed breakdown' },
671
- { command: 'monomind hooks progress --sync', description: 'Sync progress to file' },
672
- { command: 'monomind hooks progress --summary', description: 'Human-readable summary' }
673
- ],
674
- action: async (ctx) => {
675
- const detailed = ctx.flags.detailed;
676
- const sync = ctx.flags.sync;
677
- const summary = ctx.flags.summary;
678
- try {
679
- if (summary) {
680
- const spinner = output.createSpinner({ text: 'Getting progress summary...' });
681
- spinner.start();
682
- const result = await callMCPTool('progress_summary', {});
683
- spinner.stop();
684
- if (ctx.flags.format === 'json') {
685
- output.printJson(result);
686
- return { success: true, data: result };
687
- }
688
- output.writeln();
689
- output.writeln(result.summary);
690
- return { success: true, data: result };
691
- }
692
- if (sync) {
693
- const spinner = output.createSpinner({ text: 'Syncing progress...' });
694
- spinner.start();
695
- const result = await callMCPTool('progress_sync', {});
696
- spinner.stop();
697
- if (ctx.flags.format === 'json') {
698
- output.printJson(result);
699
- return { success: true, data: result };
700
- }
701
- output.writeln();
702
- output.printSuccess(`Progress synced: ${result.progress}%`);
703
- output.writeln(output.dim(` Persisted to .monomind/metrics/v1-progress.json`));
704
- output.writeln(output.dim(` Last updated: ${result.lastUpdated}`));
705
- return { success: true, data: result };
706
- }
707
- // Default: check progress
708
- const spinner = output.createSpinner({ text: 'Checking v1 progress...' });
709
- spinner.start();
710
- const result = await callMCPTool('progress_check', { detailed });
711
- spinner.stop();
712
- if (ctx.flags.format === 'json') {
713
- output.printJson(result);
714
- return { success: true, data: result };
715
- }
716
- output.writeln();
717
- const progressValue = result.overall ?? result.progress ?? 0;
718
- // Create progress bar
719
- const barWidth = 30;
720
- const filled = Math.round((progressValue / 100) * barWidth);
721
- const empty = barWidth - filled;
722
- const bar = output.success('█'.repeat(filled)) + output.dim('░'.repeat(empty));
723
- output.writeln(output.bold('v1 Implementation Progress'));
724
- output.writeln();
725
- output.writeln(`[${bar}] ${progressValue}%`);
726
- output.writeln();
727
- if (detailed && result.cli) {
728
- output.writeln(output.highlight('CLI Commands:') + ` ${result.cli.progress}% (${result.cli.commands}/${result.cli.target})`);
729
- output.writeln(output.highlight('MCP Tools:') + ` ${result.mcp?.progress ?? 0}% (${result.mcp?.tools ?? 0}/${result.mcp?.target ?? 0})`);
730
- output.writeln(output.highlight('Hooks:') + ` ${result.hooks?.progress ?? 0}% (${result.hooks?.subcommands ?? 0}/${result.hooks?.target ?? 0})`);
731
- output.writeln(output.highlight('Packages:') + ` ${result.packages?.progress ?? 0}% (${result.packages?.total ?? 0}/${result.packages?.target ?? 0})`);
732
- output.writeln(output.highlight('DDD Structure:') + ` ${result.ddd?.progress ?? 0}% (${result.packages?.withDDD ?? 0}/${result.packages?.total ?? 0})`);
733
- output.writeln();
734
- if (result.codebase) {
735
- output.writeln(output.dim(`Codebase: ${result.codebase.totalFiles} files, ${result.codebase.totalLines.toLocaleString()} lines`));
736
- }
737
- }
738
- else if (result.breakdown) {
739
- output.writeln('Breakdown:');
740
- for (const [category, value] of Object.entries(result.breakdown)) {
741
- output.writeln(` ${output.highlight(category)}: ${value}`);
742
- }
743
- }
744
- if (result.lastUpdated) {
745
- output.writeln(output.dim(`Last updated: ${result.lastUpdated}`));
746
- }
747
- return { success: true, data: result };
748
- }
749
- catch (error) {
750
- if (error instanceof MCPClientError) {
751
- output.printError(`Progress check failed: ${error.message}`);
752
- }
753
- else {
754
- output.printError(`Progress check failed: ${String(error)}`);
755
- }
756
- return { success: false, exitCode: 1 };
757
- }
758
- }
759
- };
7
+ // Re-export commands from sub-modules so hooks.ts import stays unchanged
8
+ export { coverageRouteCommand } from './hooks-coverage-routing.js';
9
+ export { coverageSuggestCommand } from './hooks-coverage-routing.js';
10
+ export { coverageGapsCommand } from './hooks-coverage-gaps.js';
11
+ export { progressHookCommand } from './hooks-coverage-gaps.js';
760
12
  // Statusline subcommand - generates dynamic status display
761
13
  export const statuslineCommand = {
762
14
  name: 'statusline',
@@ -790,7 +42,6 @@ export const statuslineCommand = {
790
42
  const fs = await import('fs');
791
43
  const path = await import('path');
792
44
  const { execSync } = await import('child_process');
793
- // Get learning stats from memory database
794
45
  function getLearningStats() {
795
46
  const memoryPaths = [
796
47
  path.join(process.cwd(), '.swarm', 'memory.db'),
@@ -809,9 +60,7 @@ export const statuslineCommand = {
809
60
  trajectories = Math.floor(patterns / 5);
810
61
  break;
811
62
  }
812
- catch {
813
- // Ignore
814
- }
63
+ catch { /* ignore */ }
815
64
  }
816
65
  }
817
66
  const sessionsPath = path.join(process.cwd(), '.claude', 'sessions');
@@ -820,13 +69,10 @@ export const statuslineCommand = {
820
69
  const sessionFiles = fs.readdirSync(sessionsPath).filter((f) => f.endsWith('.json'));
821
70
  sessions = Math.max(sessions, sessionFiles.length);
822
71
  }
823
- catch {
824
- // Ignore
825
- }
72
+ catch { /* ignore */ }
826
73
  }
827
74
  return { patterns, sessions, trajectories };
828
75
  }
829
- // Get v1 progress
830
76
  function getv1Progress() {
831
77
  const learning = getLearningStats();
832
78
  let domainsCompleted = 0;
@@ -844,7 +90,6 @@ export const statuslineCommand = {
844
90
  const dddProgress = Math.min(100, Math.floor((domainsCompleted / totalDomains) * 100));
845
91
  return { domainsCompleted, totalDomains, dddProgress, patternsLearned: learning.patterns, sessionsCompleted: learning.sessions };
846
92
  }
847
- // Get security status
848
93
  function getSecurityStatus() {
849
94
  const scanResultsPath = path.join(process.cwd(), '.claude', 'security-scans');
850
95
  let cvesFixed = 0;
@@ -854,9 +99,7 @@ export const statuslineCommand = {
854
99
  const scans = fs.readdirSync(scanResultsPath).filter((f) => f.endsWith('.json'));
855
100
  cvesFixed = Math.min(totalCves, scans.length);
856
101
  }
857
- catch {
858
- // Ignore
859
- }
102
+ catch { /* ignore */ }
860
103
  }
861
104
  const auditPath = path.join(process.cwd(), '.swarm', 'security');
862
105
  if (fs.existsSync(auditPath)) {
@@ -864,14 +107,11 @@ export const statuslineCommand = {
864
107
  const audits = fs.readdirSync(auditPath).filter((f) => f.includes('audit'));
865
108
  cvesFixed = Math.min(totalCves, Math.max(cvesFixed, audits.length));
866
109
  }
867
- catch {
868
- // Ignore
869
- }
110
+ catch { /* ignore */ }
870
111
  }
871
112
  const status = cvesFixed >= totalCves ? 'CLEAN' : cvesFixed > 0 ? 'IN_PROGRESS' : 'PENDING';
872
113
  return { status, cvesFixed, totalCves };
873
114
  }
874
- // Get swarm status
875
115
  function getSwarmStatus() {
876
116
  let activeAgents = 0;
877
117
  let coordinationActive = false;
@@ -886,12 +126,9 @@ export const statuslineCommand = {
886
126
  activeAgents = Math.max(0, isWindows ? raw : raw - 1);
887
127
  coordinationActive = activeAgents > 0;
888
128
  }
889
- catch {
890
- // Ignore
891
- }
129
+ catch { /* ignore */ }
892
130
  return { activeAgents, maxAgents, coordinationActive };
893
131
  }
894
- // Get system metrics
895
132
  function getSystemMetrics() {
896
133
  let memoryMB = 0;
897
134
  let subAgents = 0;
@@ -899,12 +136,8 @@ export const statuslineCommand = {
899
136
  try {
900
137
  memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
901
138
  }
902
- catch {
903
- // Ignore
904
- }
905
- // Calculate intelligence from multiple sources (matching statusline-generator.ts)
139
+ catch { /* ignore */ }
906
140
  let intelligencePct = 0;
907
- // 1. Check learning.json for REAL intelligence metrics first
908
141
  const learningJsonPaths = [
909
142
  path.join(process.cwd(), '.monomind', 'learning.json'),
910
143
  path.join(process.cwd(), '.claude', '.monomind', 'learning.json'),
@@ -924,16 +157,11 @@ export const statuslineCommand = {
924
157
  catch { /* ignore */ }
925
158
  }
926
159
  }
927
- // 2. Fallback: calculate from patterns and vectors
928
160
  if (intelligencePct === 0) {
929
- const fromPatterns = learning.patterns > 0 ? Math.min(100, Math.floor(learning.patterns / 10)) : 0;
930
- // Will be updated later with vector count
931
- intelligencePct = fromPatterns;
161
+ intelligencePct = learning.patterns > 0 ? Math.min(100, Math.floor(learning.patterns / 10)) : 0;
932
162
  }
933
- // 3. Fallback: calculate maturity score from project indicators
934
163
  if (intelligencePct === 0) {
935
164
  let maturityScore = 0;
936
- // Check for key project files/dirs
937
165
  if (fs.existsSync(path.join(process.cwd(), '.claude')))
938
166
  maturityScore += 15;
939
167
  if (fs.existsSync(path.join(process.cwd(), '.monomind')))
@@ -944,7 +172,6 @@ export const statuslineCommand = {
944
172
  maturityScore += 10;
945
173
  if (fs.existsSync(path.join(process.cwd(), '.swarm')))
946
174
  maturityScore += 10;
947
- // Check for test files
948
175
  const testDirs = ['tests', '__tests__', 'test', 'v1/__tests__'];
949
176
  for (const dir of testDirs) {
950
177
  if (fs.existsSync(path.join(process.cwd(), dir))) {
@@ -952,7 +179,6 @@ export const statuslineCommand = {
952
179
  break;
953
180
  }
954
181
  }
955
- // Check for hooks config
956
182
  if (fs.existsSync(path.join(process.cwd(), '.claude', 'settings.json')))
957
183
  maturityScore += 10;
958
184
  intelligencePct = Math.min(100, maturityScore);
@@ -960,30 +186,22 @@ export const statuslineCommand = {
960
186
  const contextPct = Math.min(100, Math.floor(learning.sessions * 5));
961
187
  return { memoryMB, contextPct, intelligencePct, subAgents };
962
188
  }
963
- // Get user info
964
189
  function getUserInfo() {
965
190
  let name = 'user';
966
191
  let gitBranch = '';
967
192
  const modelName = 'Opus 4.6 (1M context)';
968
193
  const isWindows = process.platform === 'win32';
969
194
  try {
970
- const nameCmd = isWindows
971
- ? 'git config user.name 2>NUL || echo user'
972
- : 'git config user.name 2>/dev/null || echo "user"';
973
- const branchCmd = isWindows
974
- ? 'git branch --show-current 2>NUL || echo.'
975
- : 'git branch --show-current 2>/dev/null || echo ""';
195
+ const nameCmd = isWindows ? 'git config user.name 2>NUL || echo user' : 'git config user.name 2>/dev/null || echo "user"';
196
+ const branchCmd = isWindows ? 'git branch --show-current 2>NUL || echo.' : 'git branch --show-current 2>/dev/null || echo ""';
976
197
  name = execSync(nameCmd, { encoding: 'utf-8' }).trim();
977
198
  gitBranch = execSync(branchCmd, { encoding: 'utf-8' }).trim();
978
199
  if (gitBranch === '.')
979
200
  gitBranch = '';
980
201
  }
981
- catch {
982
- // Ignore
983
- }
202
+ catch { /* ignore */ }
984
203
  return { name, gitBranch, modelName };
985
204
  }
986
- // Collect all status
987
205
  const progress = getv1Progress();
988
206
  const security = getSecurityStatus();
989
207
  const swarm = getSwarmStatus();
@@ -997,18 +215,15 @@ export const statuslineCommand = {
997
215
  system,
998
216
  timestamp: new Date().toISOString()
999
217
  };
1000
- // JSON output
1001
218
  if (ctx.flags.json || ctx.flags.format === 'json') {
1002
219
  output.printJson(statusData);
1003
220
  return { success: true, data: statusData };
1004
221
  }
1005
- // Compact output
1006
222
  if (ctx.flags.compact) {
1007
223
  const line = `DDD:${progress.domainsCompleted}/${progress.totalDomains} CVE:${security.cvesFixed}/${security.totalCves} Swarm:${swarm.activeAgents}/${swarm.maxAgents} Ctx:${system.contextPct}% Int:${system.intelligencePct}%`;
1008
224
  output.writeln(line);
1009
225
  return { success: true, data: statusData };
1010
226
  }
1011
- // Full colored output
1012
227
  const noColor = ctx.flags['no-color'] || ctx.flags.noColor;
1013
228
  const c = noColor ? {
1014
229
  reset: '', bold: '', dim: '', red: '', green: '', yellow: '', blue: '',
@@ -1021,13 +236,11 @@ export const statuslineCommand = {
1021
236
  brightGreen: '\x1b[1;32m', brightYellow: '\x1b[1;33m', brightBlue: '\x1b[1;34m',
1022
237
  brightPurple: '\x1b[1;35m', brightCyan: '\x1b[1;36m', brightWhite: '\x1b[1;37m'
1023
238
  };
1024
- // Progress bar helper
1025
239
  const progressBar = (current, total) => {
1026
240
  const filled = Math.round((current / total) * 5);
1027
241
  const empty = 5 - filled;
1028
242
  return '[' + '●'.repeat(filled) + '○'.repeat(empty) + ']';
1029
243
  };
1030
- // Generate lines
1031
244
  let header = `${c.bold}${c.brightPurple}▊ Monomind ${c.reset}`;
1032
245
  header += `${swarm.coordinationActive ? c.brightCyan : c.dim}● ${c.brightCyan}${user.name}${c.reset}`;
1033
246
  if (user.gitBranch) {
@@ -1035,7 +248,6 @@ export const statuslineCommand = {
1035
248
  }
1036
249
  header += ` ${c.dim}│${c.reset} ${c.purple}${user.modelName}${c.reset}`;
1037
250
  const separator = `${c.dim}─────────────────────────────────────────────────────${c.reset}`;
1038
- // Get hooks stats
1039
251
  const hooksStats = { enabled: 0, total: 17 };
1040
252
  const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
1041
253
  if (fs.existsSync(settingsPath)) {
@@ -1049,9 +261,7 @@ export const statuslineCommand = {
1049
261
  }
1050
262
  catch { /* ignore */ }
1051
263
  }
1052
- // Get memory backend stats
1053
264
  const memoryStats = { vectorCount: 0, dbSizeKB: 0, hasHnsw: false };
1054
- // Check for direct database files first
1055
265
  const dbPaths = [
1056
266
  path.join(process.cwd(), '.swarm', 'memory.db'),
1057
267
  path.join(process.cwd(), '.monomind', 'memory.db'),
@@ -1073,13 +283,11 @@ export const statuslineCommand = {
1073
283
  catch { /* ignore */ }
1074
284
  }
1075
285
  }
1076
- // Check for LanceDB directories if no direct db found
1077
286
  if (memoryStats.vectorCount === 0) {
1078
287
  const lancedbDirs = [
1079
288
  path.join(process.cwd(), ".monomind", "lancedb"),
1080
289
  path.join(process.cwd(), ".swarm", "lancedb"),
1081
290
  path.join(process.cwd(), "data", "lancedb"),
1082
- path.join(process.cwd(), ".swarm", "lancedb"),
1083
291
  ];
1084
292
  for (const dir of lancedbDirs) {
1085
293
  if (fs.existsSync(dir)) {
@@ -1087,8 +295,7 @@ export const statuslineCommand = {
1087
295
  const files = fs.readdirSync(dir);
1088
296
  for (const f of files) {
1089
297
  if (f.endsWith('.db') || f.endsWith('.sqlite')) {
1090
- const filePath = path.join(dir, f);
1091
- const fileStat = fs.statSync(filePath);
298
+ const fileStat = fs.statSync(path.join(dir, f));
1092
299
  memoryStats.dbSizeKB += Math.round(fileStat.size / 1024);
1093
300
  }
1094
301
  }
@@ -1101,7 +308,6 @@ export const statuslineCommand = {
1101
308
  }
1102
309
  }
1103
310
  }
1104
- // Check for HNSW index files
1105
311
  const hnswPaths = [
1106
312
  path.join(process.cwd(), '.monomind', 'hnsw'),
1107
313
  path.join(process.cwd(), '.swarm', 'hnsw'),
@@ -1115,15 +321,13 @@ export const statuslineCommand = {
1115
321
  const indexFile = hnswFiles.find(f => f.endsWith('.index'));
1116
322
  if (indexFile) {
1117
323
  const indexStat = fs.statSync(path.join(hnswPath, indexFile));
1118
- const hnswVectors = Math.floor(indexStat.size / 512);
1119
- memoryStats.vectorCount = Math.max(memoryStats.vectorCount, hnswVectors);
324
+ memoryStats.vectorCount = Math.max(memoryStats.vectorCount, Math.floor(indexStat.size / 512));
1120
325
  }
1121
326
  }
1122
327
  catch { /* ignore */ }
1123
328
  break;
1124
329
  }
1125
330
  }
1126
- // Check for vectors.json file
1127
331
  const vectorsPath = path.join(process.cwd(), '.monomind', 'vectors.json');
1128
332
  if (fs.existsSync(vectorsPath) && memoryStats.vectorCount === 0) {
1129
333
  try {
@@ -1139,21 +343,18 @@ export const statuslineCommand = {
1139
343
  }
1140
344
  catch { /* ignore */ }
1141
345
  }
1142
- // Get test stats
1143
346
  const testStats = { testFiles: 0, testCases: 0 };
1144
- const testPaths = ['tests', '__tests__', 'test', 'spec'];
1145
- for (const testPath of testPaths) {
347
+ for (const testPath of ['tests', '__tests__', 'test', 'spec']) {
1146
348
  const fullPath = path.join(process.cwd(), testPath);
1147
349
  if (fs.existsSync(fullPath)) {
1148
350
  try {
1149
351
  const files = fs.readdirSync(fullPath, { recursive: true });
1150
352
  testStats.testFiles = files.filter((f) => /\.(test|spec)\.(ts|js|tsx|jsx)$/.test(f)).length;
1151
- testStats.testCases = testStats.testFiles * 28; // Estimate
353
+ testStats.testCases = testStats.testFiles * 28;
1152
354
  }
1153
355
  catch { /* ignore */ }
1154
356
  }
1155
357
  }
1156
- // Get MCP stats
1157
358
  const mcpStats = { enabled: 0, total: 0 };
1158
359
  const mcpPath = path.join(process.cwd(), '.mcp.json');
1159
360
  if (fs.existsSync(mcpPath)) {
@@ -1167,7 +368,6 @@ export const statuslineCommand = {
1167
368
  catch { /* ignore */ }
1168
369
  }
1169
370
  const domainsColor = progress.domainsCompleted >= 3 ? c.brightGreen : progress.domainsCompleted > 0 ? c.yellow : c.red;
1170
- // Dynamic perf indicator based on patterns/HNSW
1171
371
  let perfIndicator = `${c.dim}⚡ HNSW: idle${c.reset}`;
1172
372
  if (memoryStats.hasHnsw && memoryStats.vectorCount > 0) {
1173
373
  perfIndicator = `${c.brightGreen}⚡ HNSW ${memoryStats.vectorCount.toLocaleString()} vec${c.reset}`;