monomind 1.17.0 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) 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/browser/dashboard/server.js +18 -0
  13. package/packages/@monomind/cli/dist/src/browser/dashboard/ui.html +37 -125
  14. package/packages/@monomind/cli/dist/src/commands/agent-lifecycle.d.ts +17 -0
  15. package/packages/@monomind/cli/dist/src/commands/agent-lifecycle.js +320 -0
  16. package/packages/@monomind/cli/dist/src/commands/agent-ops.d.ts +9 -0
  17. package/packages/@monomind/cli/dist/src/commands/agent-ops.js +329 -0
  18. package/packages/@monomind/cli/dist/src/commands/agent.js +5 -907
  19. package/packages/@monomind/cli/dist/src/commands/analyze-ast.d.ts +26 -0
  20. package/packages/@monomind/cli/dist/src/commands/analyze-ast.js +284 -0
  21. package/packages/@monomind/cli/dist/src/commands/analyze-boundaries.d.ts +14 -0
  22. package/packages/@monomind/cli/dist/src/commands/analyze-boundaries.js +295 -0
  23. package/packages/@monomind/cli/dist/src/commands/analyze-diff.d.ts +8 -0
  24. package/packages/@monomind/cli/dist/src/commands/analyze-diff.js +395 -0
  25. package/packages/@monomind/cli/dist/src/commands/analyze-graph.d.ts +14 -0
  26. package/packages/@monomind/cli/dist/src/commands/analyze-graph.js +304 -0
  27. package/packages/@monomind/cli/dist/src/commands/analyze-imports.d.ts +11 -0
  28. package/packages/@monomind/cli/dist/src/commands/analyze-imports.js +287 -0
  29. package/packages/@monomind/cli/dist/src/commands/analyze-symbols.d.ts +14 -0
  30. package/packages/@monomind/cli/dist/src/commands/analyze-symbols.js +302 -0
  31. package/packages/@monomind/cli/dist/src/commands/analyze.d.ts +38 -0
  32. package/packages/@monomind/cli/dist/src/commands/analyze.js +12 -1827
  33. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.d.ts +26 -0
  34. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +189 -0
  35. package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.d.ts +19 -0
  36. package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.js +388 -0
  37. package/packages/@monomind/cli/dist/src/commands/doctor.js +51 -942
  38. package/packages/@monomind/cli/dist/src/commands/hive-mind-comms.d.ts +11 -0
  39. package/packages/@monomind/cli/dist/src/commands/hive-mind-comms.js +242 -0
  40. package/packages/@monomind/cli/dist/src/commands/hive-mind-helpers.d.ts +35 -0
  41. package/packages/@monomind/cli/dist/src/commands/hive-mind-helpers.js +203 -0
  42. package/packages/@monomind/cli/dist/src/commands/hive-mind-ops.d.ts +8 -0
  43. package/packages/@monomind/cli/dist/src/commands/hive-mind-ops.js +233 -0
  44. package/packages/@monomind/cli/dist/src/commands/hive-mind-spawn.d.ts +12 -0
  45. package/packages/@monomind/cli/dist/src/commands/hive-mind-spawn.js +274 -0
  46. package/packages/@monomind/cli/dist/src/commands/hive-mind.js +10 -1129
  47. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.d.ts +4 -4
  48. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.js +19 -819
  49. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-gaps.d.ts +7 -0
  50. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-gaps.js +334 -0
  51. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-routing.d.ts +7 -0
  52. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-routing.js +399 -0
  53. package/packages/@monomind/cli/dist/src/commands/init-subcommands.d.ts +8 -0
  54. package/packages/@monomind/cli/dist/src/commands/init-subcommands.js +156 -0
  55. package/packages/@monomind/cli/dist/src/commands/init-upgrade.d.ts +6 -0
  56. package/packages/@monomind/cli/dist/src/commands/init-upgrade.js +203 -0
  57. package/packages/@monomind/cli/dist/src/commands/init-wizard.d.ts +6 -0
  58. package/packages/@monomind/cli/dist/src/commands/init-wizard.js +246 -0
  59. package/packages/@monomind/cli/dist/src/commands/init.js +6 -623
  60. package/packages/@monomind/cli/dist/src/commands/memory-admin.d.ts +10 -0
  61. package/packages/@monomind/cli/dist/src/commands/memory-admin.js +433 -0
  62. package/packages/@monomind/cli/dist/src/commands/memory-crud.d.ts +9 -0
  63. package/packages/@monomind/cli/dist/src/commands/memory-crud.js +342 -0
  64. package/packages/@monomind/cli/dist/src/commands/memory-list.d.ts +10 -0
  65. package/packages/@monomind/cli/dist/src/commands/memory-list.js +321 -0
  66. package/packages/@monomind/cli/dist/src/commands/memory-transfer.d.ts +9 -0
  67. package/packages/@monomind/cli/dist/src/commands/memory-transfer.js +372 -0
  68. package/packages/@monomind/cli/dist/src/commands/memory.d.ts +6 -0
  69. package/packages/@monomind/cli/dist/src/commands/memory.js +10 -1441
  70. package/packages/@monomind/cli/dist/src/commands/neural-core.d.ts +8 -0
  71. package/packages/@monomind/cli/dist/src/commands/neural-core.js +274 -0
  72. package/packages/@monomind/cli/dist/src/commands/neural-optimize.d.ts +7 -0
  73. package/packages/@monomind/cli/dist/src/commands/neural-optimize.js +332 -0
  74. package/packages/@monomind/cli/dist/src/commands/neural-registry.d.ts +7 -0
  75. package/packages/@monomind/cli/dist/src/commands/neural-registry.js +290 -0
  76. package/packages/@monomind/cli/dist/src/commands/neural.js +3 -974
  77. package/packages/@monomind/cli/dist/src/commands/platforms.js +327 -7
  78. package/packages/@monomind/cli/dist/src/commands/security-cve.d.ts +6 -0
  79. package/packages/@monomind/cli/dist/src/commands/security-cve.js +310 -0
  80. package/packages/@monomind/cli/dist/src/commands/security-misc.d.ts +9 -0
  81. package/packages/@monomind/cli/dist/src/commands/security-misc.js +293 -0
  82. package/packages/@monomind/cli/dist/src/commands/security-scan.d.ts +18 -0
  83. package/packages/@monomind/cli/dist/src/commands/security-scan.js +328 -0
  84. package/packages/@monomind/cli/dist/src/commands/security.js +3 -958
  85. package/packages/@monomind/cli/dist/src/commands/session.js +1 -1
  86. package/packages/@monomind/cli/dist/src/commands/swarm.js +23 -17
  87. package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +77 -0
  88. package/packages/@monomind/cli/dist/src/parser.js +11 -6
  89. package/packages/@monomind/cli/dist/src/routing/llm-caller.js +1 -2
  90. package/packages/@monomind/cli/package.json +2 -3
  91. package/packages/@monomind/cli/scripts/understand-analyze.mjs +1 -1
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Security scan commands — code/dep/container scanning and secret detection
3
+ */
4
+ import { output } from '../output.js';
5
+ import { statSync, readFileSync, readdirSync, realpathSync } from 'fs';
6
+ import { join, resolve, sep, relative } from 'path';
7
+ // ─── Shared secret scanning ─────────────────────────────────────────────────
8
+ export const SECRET_PATTERNS = [
9
+ { pattern: /['"](?:sk-|sk_live_|sk_test_)[a-zA-Z0-9]{20,}['"]/g, type: 'API Key (Stripe/OpenAI)' },
10
+ { pattern: /['"]AKIA[A-Z0-9]{16}['"]/g, type: 'AWS Access Key' },
11
+ { pattern: /['"]ghp_[a-zA-Z0-9]{36}['"]/g, type: 'GitHub Token' },
12
+ { pattern: /['"]xox[baprs]-[a-zA-Z0-9-]+['"]/g, type: 'Slack Token' },
13
+ { pattern: /password\s*[:=]\s*['"][^'"]{8,}['"]/gi, type: 'Hardcoded Password' },
14
+ ];
15
+ export function findSecretsInDir(dir, depthLimit, baseDir, findings) {
16
+ if (depthLimit <= 0)
17
+ return;
18
+ try {
19
+ const entries = readdirSync(dir, { withFileTypes: true });
20
+ for (const entry of entries) {
21
+ const isDotEnv = /^\.env(\..+)?$/.test(entry.name);
22
+ if ((entry.name.startsWith('.') && !isDotEnv) || entry.name === 'node_modules' || entry.name === 'dist')
23
+ continue;
24
+ const fullPath = join(dir, entry.name);
25
+ if (entry.isDirectory()) {
26
+ findSecretsInDir(fullPath, depthLimit - 1, baseDir, findings);
27
+ }
28
+ else if (entry.isFile() && (/\.(ts|js|json|yml|yaml)$/.test(entry.name) || isDotEnv) && !entry.name.endsWith('.d.ts')) {
29
+ try {
30
+ if (statSync(fullPath).size > 1024 * 1024)
31
+ continue;
32
+ const content = readFileSync(fullPath, 'utf-8');
33
+ const lines = content.split('\n');
34
+ for (let i = 0; i < lines.length; i++) {
35
+ for (const { pattern, type } of SECRET_PATTERNS) {
36
+ pattern.lastIndex = 0;
37
+ let m;
38
+ while ((m = pattern.exec(lines[i])) !== null) {
39
+ findings.push({
40
+ severity: output.warning('HIGH'),
41
+ type: 'Hardcoded Secret',
42
+ location: `${relative(baseDir, fullPath)}:${i + 1}`,
43
+ description: type,
44
+ });
45
+ }
46
+ }
47
+ }
48
+ }
49
+ catch { /* file read error */ }
50
+ }
51
+ }
52
+ }
53
+ catch { /* dir read error */ }
54
+ }
55
+ // ─── scan subcommand ─────────────────────────────────────────────────────────
56
+ export const scanCommand = {
57
+ name: 'scan',
58
+ description: 'Run security scan on target (code, dependencies, containers)',
59
+ options: [
60
+ { name: 'target', short: 't', type: 'string', description: 'Target path or URL to scan', default: '.' },
61
+ { name: 'depth', short: 'd', type: 'string', description: 'Scan depth: quick, standard, deep', default: 'standard' },
62
+ { name: 'type', type: 'string', description: 'Scan type: code, deps, container, all', default: 'all' },
63
+ { name: 'output', short: 'o', type: 'string', description: 'Output format: text, json, sarif', default: 'text' },
64
+ { name: 'fix', short: 'f', type: 'boolean', description: 'Auto-fix vulnerabilities where possible' },
65
+ ],
66
+ examples: [
67
+ { command: 'monomind security scan -t ./src', description: 'Scan source directory' },
68
+ { command: 'monomind security scan --depth deep --fix', description: 'Deep scan with auto-fix' },
69
+ ],
70
+ action: async (ctx) => {
71
+ const target = ctx.flags.target || '.';
72
+ const depth = ctx.flags.depth || 'standard';
73
+ const scanType = ctx.flags.type || 'all';
74
+ const fix = ctx.flags.fix;
75
+ if (target !== '.') {
76
+ try {
77
+ const resolvedTgt = realpathSync(resolve(target));
78
+ const cwd = realpathSync(process.cwd());
79
+ if (!resolvedTgt.startsWith(cwd + sep) && resolvedTgt !== cwd) {
80
+ output.printError('--target must be within the current working directory');
81
+ return { success: false };
82
+ }
83
+ }
84
+ catch {
85
+ output.printError(`--target path does not exist or is not accessible: ${target}`);
86
+ return { success: false };
87
+ }
88
+ }
89
+ output.writeln();
90
+ output.writeln(output.bold('Security Scan'));
91
+ output.writeln(output.dim('─'.repeat(50)));
92
+ const spinner = output.createSpinner({ text: `Scanning ${target}...`, spinner: 'dots' });
93
+ spinner.start();
94
+ const findings = [];
95
+ let criticalCount = 0, highCount = 0, mediumCount = 0, lowCount = 0;
96
+ try {
97
+ const fs = await import('fs');
98
+ const path = await import('path');
99
+ const { execSync } = await import('child_process');
100
+ if (scanType === 'all' || scanType === 'deps') {
101
+ spinner.setText('Checking dependencies with npm audit...');
102
+ try {
103
+ const packageJsonPath = path.resolve(target, 'package.json');
104
+ if (fs.existsSync(packageJsonPath)) {
105
+ let auditResult;
106
+ try {
107
+ auditResult = execSync('npm audit --json', {
108
+ cwd: path.resolve(target),
109
+ encoding: 'utf-8',
110
+ maxBuffer: 10 * 1024 * 1024,
111
+ stdio: ['pipe', 'pipe', 'pipe'],
112
+ timeout: 30_000,
113
+ });
114
+ }
115
+ catch (auditErr) {
116
+ auditResult = auditErr.stdout || '{}';
117
+ }
118
+ try {
119
+ const audit = JSON.parse(auditResult);
120
+ if (audit.vulnerabilities) {
121
+ for (const [pkg, vuln] of Object.entries(audit.vulnerabilities)) {
122
+ const sev = vuln.severity || 'low';
123
+ const firstVia = Array.isArray(vuln.via) ? vuln.via[0] : undefined;
124
+ const title = firstVia && typeof firstVia === 'object' && firstVia.title ? firstVia.title : 'Vulnerability';
125
+ if (sev === 'critical')
126
+ criticalCount++;
127
+ else if (sev === 'high')
128
+ highCount++;
129
+ else if (sev === 'moderate' || sev === 'medium')
130
+ mediumCount++;
131
+ else
132
+ lowCount++;
133
+ findings.push({
134
+ severity: sev === 'critical' ? output.error('CRITICAL') :
135
+ sev === 'high' ? output.warning('HIGH') :
136
+ sev === 'moderate' || sev === 'medium' ? output.warning('MEDIUM') : output.info('LOW'),
137
+ type: 'Dependency CVE',
138
+ location: `package.json:${pkg}`,
139
+ description: title.substring(0, 35),
140
+ });
141
+ }
142
+ }
143
+ }
144
+ catch { /* JSON parse failed */ }
145
+ }
146
+ }
147
+ catch { /* npm audit failed */ }
148
+ }
149
+ if (scanType === 'all' || scanType === 'code') {
150
+ spinner.setText('Scanning for hardcoded secrets...');
151
+ const scanDepth = depth === 'deep' ? 10 : depth === 'standard' ? 5 : 3;
152
+ const prevCount = findings.length;
153
+ findSecretsInDir(path.resolve(target), scanDepth, path.resolve(target), findings);
154
+ highCount += findings.length - prevCount;
155
+ }
156
+ if ((scanType === 'all' || scanType === 'code') && depth !== 'quick') {
157
+ spinner.setText('Analyzing code patterns...');
158
+ const codePatterns = [
159
+ { pattern: /eval\s*\(/g, type: 'Eval Usage', severity: 'medium', desc: 'eval() can execute arbitrary code' },
160
+ { pattern: /innerHTML\s*=/g, type: 'innerHTML', severity: 'medium', desc: 'XSS risk with innerHTML' },
161
+ { pattern: /dangerouslySetInnerHTML/g, type: 'React XSS', severity: 'medium', desc: 'React XSS risk' },
162
+ { pattern: /child_process.*exec[^S]/g, type: 'Command Injection', severity: 'high', desc: 'Possible command injection' },
163
+ { pattern: /\$\{.*\}.*sql|sql.*\$\{/gi, type: 'SQL Injection', severity: 'high', desc: 'Possible SQL injection' },
164
+ ];
165
+ const scanCodeDir = (dir, depthLimit) => {
166
+ if (depthLimit <= 0)
167
+ return;
168
+ try {
169
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
170
+ for (const entry of entries) {
171
+ if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'dist')
172
+ continue;
173
+ const fullPath = path.join(dir, entry.name);
174
+ if (entry.isDirectory()) {
175
+ scanCodeDir(fullPath, depthLimit - 1);
176
+ }
177
+ else if (entry.isFile() && /\.(ts|js|tsx|jsx)$/.test(entry.name) && !entry.name.endsWith('.d.ts')) {
178
+ try {
179
+ if (fs.statSync(fullPath).size > 1024 * 1024)
180
+ continue;
181
+ const content = fs.readFileSync(fullPath, 'utf-8');
182
+ const lines = content.split('\n');
183
+ for (let i = 0; i < lines.length; i++) {
184
+ for (const { pattern, type, severity, desc } of codePatterns) {
185
+ pattern.lastIndex = 0;
186
+ let m;
187
+ while ((m = pattern.exec(lines[i])) !== null) {
188
+ if (severity === 'high')
189
+ highCount++;
190
+ else
191
+ mediumCount++;
192
+ findings.push({
193
+ severity: severity === 'high' ? output.warning('HIGH') : output.warning('MEDIUM'),
194
+ type,
195
+ location: `${path.relative(target, fullPath)}:${i + 1}`,
196
+ description: desc,
197
+ });
198
+ }
199
+ }
200
+ }
201
+ }
202
+ catch { /* file read error */ }
203
+ }
204
+ }
205
+ }
206
+ catch { /* dir read error */ }
207
+ };
208
+ const scanDepth = depth === 'deep' ? 10 : 5;
209
+ scanCodeDir(path.resolve(target), scanDepth);
210
+ }
211
+ spinner.succeed('Scan complete');
212
+ output.writeln();
213
+ if (findings.length > 0) {
214
+ output.printTable({
215
+ columns: [
216
+ { key: 'severity', header: 'Severity', width: 12 },
217
+ { key: 'type', header: 'Type', width: 18 },
218
+ { key: 'location', header: 'Location', width: 25 },
219
+ { key: 'description', header: 'Description', width: 35 },
220
+ ],
221
+ data: findings.slice(0, 20),
222
+ });
223
+ if (findings.length > 20)
224
+ output.writeln(output.dim(`... and ${findings.length - 20} more issues`));
225
+ }
226
+ else {
227
+ output.writeln(output.success('No security issues found!'));
228
+ }
229
+ output.writeln();
230
+ output.printBox([
231
+ `Target: ${target}`,
232
+ `Depth: ${depth}`,
233
+ `Type: ${scanType}`,
234
+ ``,
235
+ `Critical: ${criticalCount} High: ${highCount} Medium: ${mediumCount} Low: ${lowCount}`,
236
+ `Total Issues: ${findings.length}`,
237
+ ].join('\n'), 'Scan Summary');
238
+ if (fix && criticalCount + highCount > 0) {
239
+ const resolvedTarget = realpathSync(path.resolve(target));
240
+ const cwd = realpathSync(process.cwd());
241
+ if (!resolvedTarget.startsWith(cwd + path.sep) && resolvedTarget !== cwd) {
242
+ output.writeln();
243
+ output.printError('--fix is only allowed when --target is within the current working directory');
244
+ return { success: false };
245
+ }
246
+ output.writeln();
247
+ const fixSpinner = output.createSpinner({ text: 'Attempting to fix vulnerabilities...', spinner: 'dots' });
248
+ fixSpinner.start();
249
+ try {
250
+ try {
251
+ execSync('npm audit fix', { cwd: resolvedTarget, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
252
+ }
253
+ catch { /* npm audit fix may exit non-zero */ }
254
+ fixSpinner.succeed('Applied available fixes (run scan again to verify)');
255
+ }
256
+ catch {
257
+ fixSpinner.fail('Some fixes could not be applied automatically');
258
+ }
259
+ }
260
+ return { success: findings.length === 0 || (criticalCount === 0 && highCount === 0) };
261
+ }
262
+ catch (error) {
263
+ spinner.fail('Scan failed');
264
+ output.printError(`Error: ${error}`);
265
+ return { success: false };
266
+ }
267
+ },
268
+ };
269
+ // ─── secrets subcommand ──────────────────────────────────────────────────────
270
+ export const secretsCommand = {
271
+ name: 'secrets',
272
+ description: 'Detect hardcoded secrets in codebase',
273
+ options: [
274
+ { name: 'path', short: 'p', type: 'string', description: 'Path to scan', default: '.' },
275
+ { name: 'depth', short: 'd', type: 'string', description: 'Scan depth: quick, standard, deep', default: 'standard' },
276
+ ],
277
+ examples: [
278
+ { command: 'monomind security secrets', description: 'Scan current directory for secrets' },
279
+ { command: 'monomind security secrets -p ./src --depth deep', description: 'Deep scan of src directory' },
280
+ ],
281
+ action: async (ctx) => {
282
+ const targetPath = ctx.flags.path || '.';
283
+ const depth = ctx.flags.depth || 'standard';
284
+ if (targetPath !== '.') {
285
+ try {
286
+ const resolvedTgt = realpathSync(resolve(targetPath));
287
+ const cwd = realpathSync(process.cwd());
288
+ if (!resolvedTgt.startsWith(cwd + sep) && resolvedTgt !== cwd) {
289
+ output.printError('--path must be within the current working directory');
290
+ return { success: false };
291
+ }
292
+ }
293
+ catch {
294
+ output.printError(`--path does not exist or is not accessible: ${targetPath}`);
295
+ return { success: false };
296
+ }
297
+ }
298
+ output.writeln();
299
+ output.writeln(output.bold('Secret Detection'));
300
+ output.writeln(output.dim('─'.repeat(50)));
301
+ const spinner = output.createSpinner({ text: `Scanning ${targetPath}...`, spinner: 'dots' });
302
+ spinner.start();
303
+ const findings = [];
304
+ const scanDepth = depth === 'deep' ? 10 : depth === 'standard' ? 5 : 3;
305
+ findSecretsInDir(resolve(targetPath), scanDepth, resolve(targetPath), findings);
306
+ spinner.succeed('Scan complete');
307
+ output.writeln();
308
+ if (findings.length === 0) {
309
+ output.writeln(output.success('No secrets found.'));
310
+ }
311
+ else {
312
+ output.printTable({
313
+ columns: [
314
+ { key: 'severity', header: 'Severity', width: 12 },
315
+ { key: 'description', header: 'Description', width: 25 },
316
+ { key: 'location', header: 'Location', width: 40 },
317
+ ],
318
+ data: findings.slice(0, 20),
319
+ });
320
+ if (findings.length > 20)
321
+ output.writeln(output.dim(`... and ${findings.length - 20} more`));
322
+ }
323
+ output.writeln();
324
+ output.writeln(output.bold('Summary: ') + `${findings.length} secret(s) found in ${targetPath}`);
325
+ return { success: findings.length === 0 };
326
+ },
327
+ };
328
+ //# sourceMappingURL=security-scan.js.map