@timmeck/brain 1.9.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/brain.log +1164 -0
- package/{src/cli/commands/dashboard.ts → dashboard.html} +688 -807
- package/dist/api/server.d.ts +4 -18
- package/dist/api/server.js +4 -173
- package/dist/api/server.js.map +1 -1
- package/dist/brain.d.ts +1 -0
- package/dist/brain.js +6 -1
- package/dist/brain.js.map +1 -1
- package/dist/cli/colors.d.ts +4 -25
- package/dist/cli/colors.js +3 -89
- package/dist/cli/colors.js.map +1 -1
- package/dist/cli/commands/peers.d.ts +2 -0
- package/dist/cli/commands/peers.js +38 -0
- package/dist/cli/commands/peers.js.map +1 -0
- package/dist/db/connection.d.ts +1 -2
- package/dist/db/connection.js +1 -18
- package/dist/db/connection.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/ipc/__tests__/protocol.test.d.ts +1 -0
- package/dist/ipc/__tests__/protocol.test.js +117 -0
- package/dist/ipc/__tests__/protocol.test.js.map +1 -0
- package/dist/ipc/client.d.ts +1 -16
- package/dist/ipc/client.js +1 -100
- package/dist/ipc/client.js.map +1 -1
- package/dist/ipc/protocol.d.ts +1 -8
- package/dist/ipc/protocol.js +1 -28
- package/dist/ipc/protocol.js.map +1 -1
- package/dist/ipc/router.js +8 -0
- package/dist/ipc/router.js.map +1 -1
- package/dist/ipc/server.d.ts +1 -22
- package/dist/ipc/server.js +1 -163
- package/dist/ipc/server.js.map +1 -1
- package/dist/mcp/http-server.d.ts +1 -7
- package/dist/mcp/http-server.js +6 -117
- package/dist/mcp/http-server.js.map +1 -1
- package/dist/mcp/server.js +5 -61
- package/dist/mcp/server.js.map +1 -1
- package/dist/signals/__tests__/fingerprint.test.d.ts +1 -0
- package/dist/signals/__tests__/fingerprint.test.js +118 -0
- package/dist/signals/__tests__/fingerprint.test.js.map +1 -0
- package/dist/types/ipc.types.d.ts +1 -11
- package/dist/utils/__tests__/hash.test.d.ts +1 -0
- package/dist/utils/__tests__/hash.test.js +32 -0
- package/dist/utils/__tests__/hash.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.d.ts +1 -0
- package/dist/utils/__tests__/paths.test.js +75 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -0
- package/dist/utils/events.d.ts +4 -8
- package/dist/utils/events.js +2 -14
- package/dist/utils/events.js.map +1 -1
- package/dist/utils/hash.d.ts +1 -1
- package/dist/utils/hash.js +1 -4
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/logger.d.ts +3 -2
- package/dist/utils/logger.js +8 -35
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/paths.d.ts +2 -1
- package/dist/utils/paths.js +4 -13
- package/dist/utils/paths.js.map +1 -1
- package/package.json +2 -1
- package/BRAIN_PLAN.md +0 -3324
- package/reddit_post.md +0 -45
- package/src/api/server.ts +0 -395
- package/src/brain.ts +0 -313
- package/src/cli/colors.ts +0 -116
- package/src/cli/commands/config.ts +0 -169
- package/src/cli/commands/doctor.ts +0 -124
- package/src/cli/commands/explain.ts +0 -83
- package/src/cli/commands/export.ts +0 -31
- package/src/cli/commands/import.ts +0 -199
- package/src/cli/commands/insights.ts +0 -65
- package/src/cli/commands/learn.ts +0 -24
- package/src/cli/commands/modules.ts +0 -53
- package/src/cli/commands/network.ts +0 -67
- package/src/cli/commands/projects.ts +0 -42
- package/src/cli/commands/query.ts +0 -120
- package/src/cli/commands/start.ts +0 -105
- package/src/cli/commands/status.ts +0 -75
- package/src/cli/commands/stop.ts +0 -34
- package/src/cli/ipc-helper.ts +0 -22
- package/src/cli/update-check.ts +0 -63
- package/src/code/analyzer.ts +0 -117
- package/src/code/fingerprint.ts +0 -87
- package/src/code/matcher.ts +0 -129
- package/src/code/parsers/generic.ts +0 -29
- package/src/code/parsers/python.ts +0 -54
- package/src/code/parsers/typescript.ts +0 -65
- package/src/code/registry.ts +0 -60
- package/src/code/scorer.ts +0 -120
- package/src/config.ts +0 -135
- package/src/dashboard/server.ts +0 -142
- package/src/db/connection.ts +0 -22
- package/src/db/migrations/001_core_schema.ts +0 -120
- package/src/db/migrations/002_learning_schema.ts +0 -38
- package/src/db/migrations/003_code_schema.ts +0 -53
- package/src/db/migrations/004_synapses_schema.ts +0 -57
- package/src/db/migrations/005_fts_indexes.ts +0 -78
- package/src/db/migrations/006_synapses_phase3.ts +0 -17
- package/src/db/migrations/007_feedback.ts +0 -13
- package/src/db/migrations/008_git_integration.ts +0 -38
- package/src/db/migrations/009_embeddings.ts +0 -8
- package/src/db/migrations/index.ts +0 -70
- package/src/db/repositories/antipattern.repository.ts +0 -66
- package/src/db/repositories/code-module.repository.ts +0 -142
- package/src/db/repositories/error.repository.ts +0 -189
- package/src/db/repositories/insight.repository.ts +0 -99
- package/src/db/repositories/notification.repository.ts +0 -66
- package/src/db/repositories/project.repository.ts +0 -93
- package/src/db/repositories/rule.repository.ts +0 -108
- package/src/db/repositories/solution.repository.ts +0 -154
- package/src/db/repositories/synapse.repository.ts +0 -163
- package/src/db/repositories/terminal.repository.ts +0 -101
- package/src/embeddings/engine.ts +0 -238
- package/src/hooks/post-tool-use.ts +0 -92
- package/src/hooks/post-write.ts +0 -129
- package/src/index.ts +0 -63
- package/src/ipc/client.ts +0 -118
- package/src/ipc/protocol.ts +0 -35
- package/src/ipc/router.ts +0 -133
- package/src/ipc/server.ts +0 -176
- package/src/learning/confidence-scorer.ts +0 -80
- package/src/learning/decay.ts +0 -46
- package/src/learning/learning-engine.ts +0 -170
- package/src/learning/pattern-extractor.ts +0 -90
- package/src/learning/rule-generator.ts +0 -74
- package/src/main.rs:10:5 +0 -0
- package/src/matching/error-matcher.ts +0 -166
- package/src/matching/fingerprint.ts +0 -34
- package/src/matching/similarity.ts +0 -61
- package/src/matching/tfidf.ts +0 -74
- package/src/matching/tokenizer.ts +0 -41
- package/src/mcp/auto-detect.ts +0 -93
- package/src/mcp/http-server.ts +0 -140
- package/src/mcp/server.ts +0 -73
- package/src/mcp/tools.ts +0 -328
- package/src/parsing/error-parser.ts +0 -28
- package/src/parsing/parsers/compiler.ts +0 -93
- package/src/parsing/parsers/generic.ts +0 -28
- package/src/parsing/parsers/go.ts +0 -97
- package/src/parsing/parsers/node.ts +0 -69
- package/src/parsing/parsers/python.ts +0 -62
- package/src/parsing/parsers/rust.ts +0 -50
- package/src/parsing/parsers/shell.ts +0 -42
- package/src/parsing/types.ts +0 -47
- package/src/research/gap-analyzer.ts +0 -135
- package/src/research/insight-generator.ts +0 -123
- package/src/research/research-engine.ts +0 -116
- package/src/research/synergy-detector.ts +0 -126
- package/src/research/template-extractor.ts +0 -130
- package/src/research/trend-analyzer.ts +0 -127
- package/src/services/analytics.service.ts +0 -226
- package/src/services/code.service.ts +0 -271
- package/src/services/error.service.ts +0 -266
- package/src/services/git.service.ts +0 -132
- package/src/services/notification.service.ts +0 -41
- package/src/services/prevention.service.ts +0 -159
- package/src/services/research.service.ts +0 -98
- package/src/services/solution.service.ts +0 -174
- package/src/services/synapse.service.ts +0 -59
- package/src/services/terminal.service.ts +0 -81
- package/src/synapses/activation.ts +0 -80
- package/src/synapses/decay.ts +0 -38
- package/src/synapses/hebbian.ts +0 -69
- package/src/synapses/pathfinder.ts +0 -81
- package/src/synapses/synapse-manager.ts +0 -113
- package/src/types/code.types.ts +0 -52
- package/src/types/config.types.ts +0 -103
- package/src/types/error.types.ts +0 -67
- package/src/types/ipc.types.ts +0 -8
- package/src/types/mcp.types.ts +0 -53
- package/src/types/research.types.ts +0 -28
- package/src/types/solution.types.ts +0 -30
- package/src/types/synapse.types.ts +0 -50
- package/src/utils/events.ts +0 -45
- package/src/utils/hash.ts +0 -5
- package/src/utils/logger.ts +0 -48
- package/src/utils/paths.ts +0 -19
- package/tests/e2e/test_code_intelligence.py +0 -1015
- package/tests/e2e/test_error_memory.py +0 -451
- package/tests/e2e/test_full_integration.py +0 -534
- package/tests/fixtures/code-modules/modules.ts +0 -83
- package/tests/fixtures/errors/go.ts +0 -9
- package/tests/fixtures/errors/node.ts +0 -24
- package/tests/fixtures/errors/python.ts +0 -21
- package/tests/fixtures/errors/rust.ts +0 -25
- package/tests/fixtures/errors/shell.ts +0 -15
- package/tests/fixtures/solutions/solutions.ts +0 -27
- package/tests/helpers/setup-db.ts +0 -52
- package/tests/integration/code-flow.test.ts +0 -86
- package/tests/integration/error-flow.test.ts +0 -83
- package/tests/integration/ipc-flow.test.ts +0 -166
- package/tests/integration/learning-cycle.test.ts +0 -82
- package/tests/integration/synapse-flow.test.ts +0 -117
- package/tests/unit/code/analyzer.test.ts +0 -58
- package/tests/unit/code/fingerprint.test.ts +0 -51
- package/tests/unit/code/scorer.test.ts +0 -55
- package/tests/unit/learning/confidence-scorer.test.ts +0 -60
- package/tests/unit/learning/decay.test.ts +0 -45
- package/tests/unit/learning/pattern-extractor.test.ts +0 -50
- package/tests/unit/matching/error-matcher.test.ts +0 -69
- package/tests/unit/matching/fingerprint.test.ts +0 -47
- package/tests/unit/matching/similarity.test.ts +0 -65
- package/tests/unit/matching/tfidf.test.ts +0 -71
- package/tests/unit/matching/tokenizer.test.ts +0 -83
- package/tests/unit/parsing/parsers.test.ts +0 -113
- package/tests/unit/research/gap-analyzer.test.ts +0 -45
- package/tests/unit/research/trend-analyzer.test.ts +0 -45
- package/tests/unit/synapses/activation.test.ts +0 -80
- package/tests/unit/synapses/decay.test.ts +0 -27
- package/tests/unit/synapses/hebbian.test.ts +0 -96
- package/tests/unit/synapses/pathfinder.test.ts +0 -72
- package/tsconfig.json +0 -18
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import { getDataDir } from '../../utils/paths.js';
|
|
6
|
-
import { IpcClient } from '../../ipc/client.js';
|
|
7
|
-
import { getPipeName } from '../../utils/paths.js';
|
|
8
|
-
import { c, icons, header, divider } from '../colors.js';
|
|
9
|
-
|
|
10
|
-
function pass(label: string, detail?: string): void {
|
|
11
|
-
const extra = detail ? ` ${c.dim(detail)}` : '';
|
|
12
|
-
console.log(` ${c.green(icons.check)} ${label}${extra}`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function fail(label: string, detail?: string): void {
|
|
16
|
-
const extra = detail ? ` ${c.dim(detail)}` : '';
|
|
17
|
-
console.log(` ${c.red(icons.cross)} ${label}${extra}`);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function doctorCommand(): Command {
|
|
21
|
-
return new Command('doctor')
|
|
22
|
-
.description('Check Brain health: daemon, DB, MCP, hooks')
|
|
23
|
-
.action(async () => {
|
|
24
|
-
console.log(header('Brain Doctor', icons.brain));
|
|
25
|
-
console.log();
|
|
26
|
-
|
|
27
|
-
let allGood = true;
|
|
28
|
-
|
|
29
|
-
// 1. Daemon running?
|
|
30
|
-
const pidPath = path.join(getDataDir(), 'brain.pid');
|
|
31
|
-
let daemonRunning = false;
|
|
32
|
-
if (fs.existsSync(pidPath)) {
|
|
33
|
-
const pid = parseInt(fs.readFileSync(pidPath, 'utf8').trim(), 10);
|
|
34
|
-
try {
|
|
35
|
-
process.kill(pid, 0);
|
|
36
|
-
daemonRunning = true;
|
|
37
|
-
pass('Daemon running', `PID ${pid}`);
|
|
38
|
-
} catch {
|
|
39
|
-
fail('Daemon not running', 'stale PID file');
|
|
40
|
-
allGood = false;
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
fail('Daemon not running', 'no PID file');
|
|
44
|
-
allGood = false;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 2. DB reachable? (only if daemon running)
|
|
48
|
-
if (daemonRunning) {
|
|
49
|
-
const client = new IpcClient(getPipeName(), 3000);
|
|
50
|
-
try {
|
|
51
|
-
await client.connect();
|
|
52
|
-
await client.request('analytics.summary', {});
|
|
53
|
-
pass('Database reachable');
|
|
54
|
-
} catch {
|
|
55
|
-
fail('Database not reachable');
|
|
56
|
-
allGood = false;
|
|
57
|
-
} finally {
|
|
58
|
-
client.disconnect();
|
|
59
|
-
}
|
|
60
|
-
} else {
|
|
61
|
-
fail('Database not reachable', 'daemon not running');
|
|
62
|
-
allGood = false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 3. MCP configured?
|
|
66
|
-
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
67
|
-
let mcpConfigured = false;
|
|
68
|
-
try {
|
|
69
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
70
|
-
if (settings.mcpServers?.brain || settings.mcpServers?.['brain-mcp']) {
|
|
71
|
-
mcpConfigured = true;
|
|
72
|
-
pass('MCP server configured');
|
|
73
|
-
} else {
|
|
74
|
-
fail('MCP server not configured', `edit ${settingsPath}`);
|
|
75
|
-
allGood = false;
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
fail('MCP server not configured', 'settings.json not found');
|
|
79
|
-
allGood = false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 4. Hook active?
|
|
83
|
-
try {
|
|
84
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
85
|
-
const hooks = settings.hooks;
|
|
86
|
-
const hasPostToolUse = hooks?.PostToolUse?.some(
|
|
87
|
-
(h: { command?: string; hooks?: Array<{ command?: string }> }) => {
|
|
88
|
-
// Support both flat format (h.command) and nested format (h.hooks[].command)
|
|
89
|
-
if (h.command?.includes('brain') || h.command?.includes('post-tool-use')) return true;
|
|
90
|
-
return h.hooks?.some(
|
|
91
|
-
(inner) => inner.command?.includes('brain') || inner.command?.includes('post-tool-use'),
|
|
92
|
-
);
|
|
93
|
-
},
|
|
94
|
-
);
|
|
95
|
-
if (hasPostToolUse) {
|
|
96
|
-
pass('Auto-detect hook active');
|
|
97
|
-
} else {
|
|
98
|
-
fail('Auto-detect hook not configured', 'errors won\'t be tracked automatically');
|
|
99
|
-
allGood = false;
|
|
100
|
-
}
|
|
101
|
-
} catch {
|
|
102
|
-
fail('Auto-detect hook not configured');
|
|
103
|
-
allGood = false;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// 5. DB file size
|
|
107
|
-
const dbPath = path.join(getDataDir(), 'brain.db');
|
|
108
|
-
try {
|
|
109
|
-
const stat = fs.statSync(dbPath);
|
|
110
|
-
pass('Database file', `${(stat.size / 1024 / 1024).toFixed(1)} MB at ${dbPath}`);
|
|
111
|
-
} catch {
|
|
112
|
-
fail('Database file not found');
|
|
113
|
-
allGood = false;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
console.log();
|
|
117
|
-
if (allGood) {
|
|
118
|
-
console.log(` ${icons.ok} ${c.success('All checks passed!')}`);
|
|
119
|
-
} else {
|
|
120
|
-
console.log(` ${icons.warn} ${c.warn('Some checks failed.')} Run ${c.cyan('brain start')} and check your MCP config.`);
|
|
121
|
-
}
|
|
122
|
-
console.log(`\n${divider()}`);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { withIpc } from '../ipc-helper.js';
|
|
3
|
-
import { c, icons } from '../colors.js';
|
|
4
|
-
|
|
5
|
-
export function explainCommand(): Command {
|
|
6
|
-
return new Command('explain')
|
|
7
|
-
.description('Show everything Brain knows about an error')
|
|
8
|
-
.argument('<errorId>', 'Error ID to explain')
|
|
9
|
-
.action(async (errorId) => {
|
|
10
|
-
const id = parseInt(errorId, 10);
|
|
11
|
-
if (isNaN(id)) {
|
|
12
|
-
console.error(`${icons.error} Invalid error ID: ${errorId}`);
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
await withIpc(async (client) => {
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
-
const result: any = await client.request('analytics.explain', { errorId: id });
|
|
19
|
-
|
|
20
|
-
if (!result.error) {
|
|
21
|
-
console.error(`${icons.error} Error #${id} not found.`);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const err = result.error;
|
|
26
|
-
console.log();
|
|
27
|
-
console.log(`${icons.brain} ${c.heading(`Error #${err.id} — ${err.type}`)}`);
|
|
28
|
-
console.log(`${c.dim('─'.repeat(60))}`);
|
|
29
|
-
console.log(` ${c.label('Message:')} ${err.message}`);
|
|
30
|
-
console.log(` ${c.label('File:')} ${err.file_path ?? 'unknown'}`);
|
|
31
|
-
console.log(` ${c.label('Context:')} ${err.context ?? 'none'}`);
|
|
32
|
-
console.log(` ${c.label('Seen:')} ${err.occurrence_count}x (first: ${err.first_seen}, last: ${err.last_seen})`);
|
|
33
|
-
console.log(` ${c.label('Resolved:')} ${err.resolved ? c.success('Yes') : c.error('No')}`);
|
|
34
|
-
console.log(` ${c.label('Synapses:')} ${result.synapseConnections} connections`);
|
|
35
|
-
|
|
36
|
-
// Error Chain
|
|
37
|
-
if (result.chain.parents.length > 0 || result.chain.children.length > 0) {
|
|
38
|
-
console.log();
|
|
39
|
-
console.log(` ${c.heading('Error Chain:')}`);
|
|
40
|
-
for (const p of result.chain.parents) {
|
|
41
|
-
console.log(` ${c.dim('↑')} Caused by: #${p.id} ${p.type}: ${p.message.slice(0, 60)}`);
|
|
42
|
-
}
|
|
43
|
-
console.log(` ${c.info('→')} #${err.id} ${err.type}`);
|
|
44
|
-
for (const ch of result.chain.children) {
|
|
45
|
-
console.log(` ${c.dim('↓')} Led to: #${ch.id} ${ch.type}: ${ch.message.slice(0, 60)}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Solutions
|
|
50
|
-
if (result.solutions.length > 0) {
|
|
51
|
-
console.log();
|
|
52
|
-
console.log(` ${c.heading('Solutions:')}`);
|
|
53
|
-
for (const s of result.solutions) {
|
|
54
|
-
const rate = `${Math.round(s.successRate * 100)}%`;
|
|
55
|
-
console.log(` ${icons.ok} #${s.id}: ${s.description.slice(0, 80)} (success: ${rate}, confidence: ${s.confidence.toFixed(2)})`);
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
console.log();
|
|
59
|
-
console.log(` ${c.dim('No solutions found.')}`);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Related Errors
|
|
63
|
-
if (result.relatedErrors.length > 0) {
|
|
64
|
-
console.log();
|
|
65
|
-
console.log(` ${c.heading('Related Errors:')}`);
|
|
66
|
-
for (const r of result.relatedErrors.slice(0, 5)) {
|
|
67
|
-
console.log(` ${c.dim('~')} #${r.id} ${r.type}: ${r.message.slice(0, 60)} (${Math.round(r.similarity * 100)}%)`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Rules
|
|
72
|
-
if (result.rules.length > 0) {
|
|
73
|
-
console.log();
|
|
74
|
-
console.log(` ${c.heading('Applicable Rules:')}`);
|
|
75
|
-
for (const r of result.rules) {
|
|
76
|
-
console.log(` ${icons.gear} #${r.id}: ${r.action} (confidence: ${r.confidence.toFixed(2)})`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log();
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { withIpc } from '../ipc-helper.js';
|
|
3
|
-
import { c, icons } from '../colors.js';
|
|
4
|
-
|
|
5
|
-
export function exportCommand(): Command {
|
|
6
|
-
return new Command('export')
|
|
7
|
-
.description('Export Brain data')
|
|
8
|
-
.option('--format <fmt>', 'Output format: json (default)', 'json')
|
|
9
|
-
.action(async () => {
|
|
10
|
-
await withIpc(async (client) => {
|
|
11
|
-
process.stderr.write(`${icons.gear} ${c.info('Exporting Brain data...')}\n`);
|
|
12
|
-
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
-
const summary: any = await client.request('analytics.summary', {});
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
-
const network: any = await client.request('analytics.network', { limit: 100 });
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
-
const insights: any = await client.request('research.insights', { activeOnly: true, limit: 100 });
|
|
19
|
-
|
|
20
|
-
const data = {
|
|
21
|
-
exportedAt: new Date().toISOString(),
|
|
22
|
-
summary,
|
|
23
|
-
network,
|
|
24
|
-
insights,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
console.log(JSON.stringify(data, null, 2));
|
|
28
|
-
process.stderr.write(`${icons.ok} ${c.success('Export complete.')}\n`);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
}
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { withIpc } from '../ipc-helper.js';
|
|
3
|
-
import { readdirSync, readFileSync, statSync } from 'fs';
|
|
4
|
-
import { resolve, basename, relative, extname } from 'path';
|
|
5
|
-
import { c, icons, header, divider, progressBar } from '../colors.js';
|
|
6
|
-
|
|
7
|
-
const DEFAULT_EXTENSIONS = new Set([
|
|
8
|
-
'.ts', '.tsx', '.js', '.jsx', '.py', '.rs', '.go',
|
|
9
|
-
'.java', '.c', '.cpp', '.h', '.hpp', '.rb', '.sh',
|
|
10
|
-
'.html', '.css', '.scss', '.json', '.yaml', '.yml', '.toml',
|
|
11
|
-
'.md', '.sql', '.php', '.svelte', '.vue', '.astro',
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
const EXCLUDE_DIRS = new Set([
|
|
15
|
-
'node_modules', 'dist', 'build', '.git', '.next',
|
|
16
|
-
'__pycache__', 'vendor', 'coverage', '.cache', '.turbo',
|
|
17
|
-
'.nuxt', '.output', 'target', 'out', 'venv', '.venv',
|
|
18
|
-
'env', '.env', 'site-packages',
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
const EXCLUDE_PATTERNS = [/\.min\./, /\.bundle\./, /\.d\.ts$/];
|
|
22
|
-
|
|
23
|
-
const LANG_MAP: Record<string, string> = {
|
|
24
|
-
ts: 'typescript', tsx: 'typescript', js: 'javascript', jsx: 'javascript',
|
|
25
|
-
py: 'python', rs: 'rust', go: 'go', java: 'java',
|
|
26
|
-
c: 'c', cpp: 'cpp', h: 'c', hpp: 'cpp',
|
|
27
|
-
rb: 'ruby', sh: 'shell', bash: 'shell',
|
|
28
|
-
html: 'html', css: 'css', scss: 'scss',
|
|
29
|
-
json: 'json', yaml: 'yaml', yml: 'yaml', toml: 'toml',
|
|
30
|
-
md: 'markdown', sql: 'sql', php: 'php',
|
|
31
|
-
svelte: 'svelte', vue: 'vue', astro: 'astro',
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
function detectLanguage(filePath: string): string {
|
|
35
|
-
const ext = extname(filePath).slice(1).toLowerCase();
|
|
36
|
-
return LANG_MAP[ext] ?? ext;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function findSourceFiles(dir: string, extensions: Set<string>, maxSizeBytes: number): string[] {
|
|
40
|
-
const files: string[] = [];
|
|
41
|
-
|
|
42
|
-
function walk(current: string): void {
|
|
43
|
-
let entries;
|
|
44
|
-
try {
|
|
45
|
-
entries = readdirSync(current, { withFileTypes: true });
|
|
46
|
-
} catch {
|
|
47
|
-
return; // skip unreadable directories
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
for (const entry of entries) {
|
|
51
|
-
const fullPath = resolve(current, entry.name);
|
|
52
|
-
|
|
53
|
-
if (entry.isDirectory()) {
|
|
54
|
-
if (!EXCLUDE_DIRS.has(entry.name)) {
|
|
55
|
-
walk(fullPath);
|
|
56
|
-
}
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!entry.isFile()) continue;
|
|
61
|
-
|
|
62
|
-
const ext = extname(entry.name).toLowerCase();
|
|
63
|
-
if (!extensions.has(ext)) continue;
|
|
64
|
-
if (EXCLUDE_PATTERNS.some(p => p.test(entry.name))) continue;
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const stat = statSync(fullPath);
|
|
68
|
-
if (stat.size > maxSizeBytes) continue;
|
|
69
|
-
files.push(fullPath);
|
|
70
|
-
} catch {
|
|
71
|
-
// skip unreadable files
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
walk(dir);
|
|
77
|
-
return files.sort();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function importCommand(): Command {
|
|
81
|
-
return new Command('import')
|
|
82
|
-
.description('Import source files from a project directory into Brain')
|
|
83
|
-
.argument('<directory>', 'Project directory to scan')
|
|
84
|
-
.option('-p, --project <name>', 'Project name (default: directory basename)')
|
|
85
|
-
.option('-e, --extensions <list>', 'Comma-separated extensions (default: ts,tsx,js,jsx,py,rs,go,java,c,cpp,h,hpp,rb,sh,html,css,scss,json,yaml,yml,toml,md,sql,php,svelte,vue,astro)')
|
|
86
|
-
.option('--dry-run', 'List files that would be imported without importing')
|
|
87
|
-
.option('--max-size <kb>', 'Skip files larger than N KB', '100')
|
|
88
|
-
.action(async (directory: string, opts) => {
|
|
89
|
-
const dir = resolve(directory);
|
|
90
|
-
const projectName = opts.project ?? basename(dir);
|
|
91
|
-
const maxSizeKb = parseInt(opts.maxSize, 10) || 100;
|
|
92
|
-
const maxSizeBytes = maxSizeKb * 1024;
|
|
93
|
-
|
|
94
|
-
// Parse extensions
|
|
95
|
-
let extensions = DEFAULT_EXTENSIONS;
|
|
96
|
-
if (opts.extensions) {
|
|
97
|
-
extensions = new Set(
|
|
98
|
-
opts.extensions.split(',').map((e: string) => {
|
|
99
|
-
const trimmed = e.trim();
|
|
100
|
-
return trimmed.startsWith('.') ? trimmed : `.${trimmed}`;
|
|
101
|
-
})
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Verify directory exists
|
|
106
|
-
try {
|
|
107
|
-
const stat = statSync(dir);
|
|
108
|
-
if (!stat.isDirectory()) {
|
|
109
|
-
console.error(`Not a directory: ${dir}`);
|
|
110
|
-
process.exit(1);
|
|
111
|
-
}
|
|
112
|
-
} catch {
|
|
113
|
-
console.error(`Directory not found: ${dir}`);
|
|
114
|
-
process.exit(1);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
console.log(`${icons.search} ${c.info('Scanning')} ${c.value(dir)} ...`);
|
|
118
|
-
const files = findSourceFiles(dir, extensions, maxSizeBytes);
|
|
119
|
-
|
|
120
|
-
if (files.length === 0) {
|
|
121
|
-
console.log(`${c.dim('No source files found.')}`);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
console.log(`${icons.ok} Found ${c.value(files.length)} source files.\n`);
|
|
126
|
-
|
|
127
|
-
if (opts.dryRun) {
|
|
128
|
-
for (const f of files) {
|
|
129
|
-
const rel = relative(dir, f);
|
|
130
|
-
const lang = detectLanguage(f);
|
|
131
|
-
console.log(` ${c.cyan(`[${lang}]`)} ${c.dim(rel)}`);
|
|
132
|
-
}
|
|
133
|
-
console.log(`\n${c.value(files.length)} files would be imported as project ${c.cyan(`"${projectName}"`)}.`);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Import via IPC
|
|
138
|
-
await withIpc(async (client) => {
|
|
139
|
-
let imported = 0;
|
|
140
|
-
let newCount = 0;
|
|
141
|
-
let existingCount = 0;
|
|
142
|
-
let failedCount = 0;
|
|
143
|
-
let totalScore = 0;
|
|
144
|
-
|
|
145
|
-
for (let i = 0; i < files.length; i++) {
|
|
146
|
-
const filePath = files[i];
|
|
147
|
-
const rel = relative(dir, filePath);
|
|
148
|
-
const fileName = basename(filePath);
|
|
149
|
-
const language = detectLanguage(filePath);
|
|
150
|
-
|
|
151
|
-
let source: string;
|
|
152
|
-
try {
|
|
153
|
-
source = readFileSync(filePath, 'utf-8');
|
|
154
|
-
} catch {
|
|
155
|
-
failedCount++;
|
|
156
|
-
process.stdout.write(` ${c.dim(`[${i + 1}/${files.length}]`)} ${c.dim(rel)} ${c.red('— read error')}\n`);
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Skip empty files
|
|
161
|
-
if (!source.trim()) continue;
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
165
|
-
const result: any = await client.request('code.analyze', {
|
|
166
|
-
project: projectName,
|
|
167
|
-
name: fileName,
|
|
168
|
-
filePath: rel,
|
|
169
|
-
language,
|
|
170
|
-
source,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const score = result.reusabilityScore ?? 0;
|
|
174
|
-
const scoreColor = score >= 0.7 ? c.green : score >= 0.4 ? c.orange : c.red;
|
|
175
|
-
const statusTag = result.isNew ? c.green('new') : c.dim('existing');
|
|
176
|
-
totalScore += score;
|
|
177
|
-
imported++;
|
|
178
|
-
|
|
179
|
-
if (result.isNew) newCount++;
|
|
180
|
-
else existingCount++;
|
|
181
|
-
|
|
182
|
-
process.stdout.write(` ${c.dim(`[${i + 1}/${files.length}]`)} ${c.dim(rel)} ${c.dim(icons.arrow)} ${scoreColor(score.toFixed(2))} (${statusTag})\n`);
|
|
183
|
-
} catch (err) {
|
|
184
|
-
failedCount++;
|
|
185
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
186
|
-
process.stdout.write(` ${c.dim(`[${i + 1}/${files.length}]`)} ${c.dim(rel)} ${c.red(`— ${msg.slice(0, 80)}`)}\n`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const avgScore = imported > 0 ? (totalScore / imported).toFixed(2) : '0';
|
|
191
|
-
console.log(header('Import Summary', icons.module));
|
|
192
|
-
console.log(` ${c.label('Project:')} ${c.cyan(projectName)}`);
|
|
193
|
-
console.log(` ${c.label('Imported:')} ${c.value(imported)} (${c.green(`${newCount} new`)}, ${c.dim(`${existingCount} existing`)})`);
|
|
194
|
-
if (failedCount > 0) console.log(` ${c.label('Failed:')} ${c.red(failedCount)}`);
|
|
195
|
-
console.log(` ${c.label('Avg score:')} ${c.value(avgScore)} ${progressBar(parseFloat(avgScore), 1)}`);
|
|
196
|
-
console.log(divider());
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { withIpc } from '../ipc-helper.js';
|
|
3
|
-
import { c, icons, header, priorityBadge, divider } from '../colors.js';
|
|
4
|
-
|
|
5
|
-
const TYPE_ICONS: Record<string, string> = {
|
|
6
|
-
trend: '📈',
|
|
7
|
-
pattern: '🔄',
|
|
8
|
-
gap: '⚠',
|
|
9
|
-
synergy: '⚡',
|
|
10
|
-
optimization: '🎯',
|
|
11
|
-
template_candidate: '🎨',
|
|
12
|
-
project_suggestion: '💡',
|
|
13
|
-
warning: '🚨',
|
|
14
|
-
suggestion: '💡',
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export function insightsCommand(): Command {
|
|
18
|
-
return new Command('insights')
|
|
19
|
-
.description('Show research insights')
|
|
20
|
-
.option('--type <type>', 'Filter by type: trend, pattern, gap, synergy, optimization, template_candidate, project_suggestion, warning')
|
|
21
|
-
.option('-l, --limit <n>', 'Maximum results', '20')
|
|
22
|
-
.action(async (opts) => {
|
|
23
|
-
await withIpc(async (client) => {
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
-
const insights: any = await client.request('research.insights', {
|
|
26
|
-
type: opts.type,
|
|
27
|
-
activeOnly: true,
|
|
28
|
-
limit: parseInt(opts.limit, 10),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
if (!insights?.length) {
|
|
32
|
-
console.log(`${icons.insight} ${c.dim('No active insights.')}`);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log(header(`${insights.length} Insights`, icons.insight));
|
|
37
|
-
|
|
38
|
-
// Group by type
|
|
39
|
-
const byType: Record<string, number> = {};
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
-
for (const ins of insights as any[]) {
|
|
42
|
-
byType[ins.type] = (byType[ins.type] || 0) + 1;
|
|
43
|
-
}
|
|
44
|
-
const typeSummary = Object.entries(byType)
|
|
45
|
-
.sort((a, b) => b[1] - a[1])
|
|
46
|
-
.map(([t, count]) => `${TYPE_ICONS[t] ?? '•'} ${c.cyan(t)} ${c.dim(`(${count})`)}`)
|
|
47
|
-
.join(' ');
|
|
48
|
-
console.log(` ${typeSummary}\n`);
|
|
49
|
-
|
|
50
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
-
for (const ins of insights as any[]) {
|
|
52
|
-
const typeIcon = TYPE_ICONS[ins.type] ?? '•';
|
|
53
|
-
const pBadge = priorityBadge(ins.priority ?? 0);
|
|
54
|
-
const typeTag = c.cyan(`[${ins.type}]`);
|
|
55
|
-
|
|
56
|
-
console.log(` ${typeIcon} ${typeTag} ${pBadge} ${c.value(ins.title)}`);
|
|
57
|
-
if (ins.description) {
|
|
58
|
-
console.log(` ${c.dim(ins.description.slice(0, 150))}`);
|
|
59
|
-
}
|
|
60
|
-
console.log();
|
|
61
|
-
}
|
|
62
|
-
console.log(divider());
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { withIpc } from '../ipc-helper.js';
|
|
3
|
-
import { c, icons, header, keyValue, divider } from '../colors.js';
|
|
4
|
-
|
|
5
|
-
export function learnCommand(): Command {
|
|
6
|
-
return new Command('learn')
|
|
7
|
-
.description('Trigger a learning cycle manually (pattern extraction + rule generation)')
|
|
8
|
-
.action(async () => {
|
|
9
|
-
await withIpc(async (client) => {
|
|
10
|
-
console.log(`${icons.brain} ${c.info('Running learning cycle...')}`);
|
|
11
|
-
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
const result: any = await client.request('learning.run', {});
|
|
14
|
-
|
|
15
|
-
console.log(header('Learning Cycle Complete', icons.bolt));
|
|
16
|
-
console.log(keyValue('New patterns', result.newPatterns ?? 0));
|
|
17
|
-
console.log(keyValue('Updated rules', result.updatedRules ?? 0));
|
|
18
|
-
console.log(keyValue('Pruned rules', result.prunedRules ?? 0));
|
|
19
|
-
console.log(keyValue('New anti-patterns', result.newAntipatterns ?? 0));
|
|
20
|
-
console.log(keyValue('Duration', `${result.duration ?? 0}ms`));
|
|
21
|
-
console.log(`\n${divider()}`);
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { withIpc } from '../ipc-helper.js';
|
|
3
|
-
import { c, icons, header, divider } from '../colors.js';
|
|
4
|
-
|
|
5
|
-
export function modulesCommand(): Command {
|
|
6
|
-
return new Command('modules')
|
|
7
|
-
.description('List registered code modules')
|
|
8
|
-
.option('--language <lang>', 'Filter by language')
|
|
9
|
-
.option('-l, --limit <n>', 'Maximum results')
|
|
10
|
-
.action(async (opts) => {
|
|
11
|
-
await withIpc(async (client) => {
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
const modules: any = await client.request('code.modules', {
|
|
14
|
-
language: opts.language,
|
|
15
|
-
limit: opts.limit ? parseInt(opts.limit, 10) : undefined,
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
if (!modules?.length) {
|
|
19
|
-
console.log(`${icons.module} ${c.dim('No code modules registered.')}`);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
console.log(header(`${modules.length} Code Modules`, icons.module));
|
|
24
|
-
|
|
25
|
-
// Group by language
|
|
26
|
-
const byLang: Record<string, number> = {};
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
-
for (const mod of modules as any[]) {
|
|
29
|
-
byLang[mod.language] = (byLang[mod.language] || 0) + 1;
|
|
30
|
-
}
|
|
31
|
-
const langSummary = Object.entries(byLang)
|
|
32
|
-
.sort((a, b) => b[1] - a[1])
|
|
33
|
-
.map(([lang, count]) => `${c.cyan(lang)} ${c.dim(`(${count})`)}`)
|
|
34
|
-
.join(' ');
|
|
35
|
-
console.log(` ${langSummary}\n`);
|
|
36
|
-
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
-
for (const mod of modules as any[]) {
|
|
39
|
-
const score = mod.reusabilityScore ?? mod.reusability_score ?? 0;
|
|
40
|
-
const scoreColor = score >= 0.7 ? c.green : score >= 0.4 ? c.orange : c.red;
|
|
41
|
-
const langTag = c.cyan(`[${mod.language}]`);
|
|
42
|
-
|
|
43
|
-
console.log(` ${c.dim(`#${mod.id}`)} ${langTag} ${c.value(mod.name)}`);
|
|
44
|
-
if (mod.description) {
|
|
45
|
-
console.log(` ${c.dim(mod.description.slice(0, 120))}`);
|
|
46
|
-
}
|
|
47
|
-
console.log(` ${c.label('File:')} ${c.dim(mod.filePath ?? mod.file_path)} ${c.label('Score:')} ${scoreColor(typeof score === 'number' ? score.toFixed(2) : score)}`);
|
|
48
|
-
console.log();
|
|
49
|
-
}
|
|
50
|
-
console.log(divider());
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { withIpc } from '../ipc-helper.js';
|
|
3
|
-
import { c, icons, header, keyValue, divider } from '../colors.js';
|
|
4
|
-
|
|
5
|
-
export function networkCommand(): Command {
|
|
6
|
-
return new Command('network')
|
|
7
|
-
.description('Explore the synapse network')
|
|
8
|
-
.option('--node <type:id>', 'Node to explore (e.g., error:42)')
|
|
9
|
-
.option('-l, --limit <n>', 'Max synapses to show', '20')
|
|
10
|
-
.action(async (opts) => {
|
|
11
|
-
await withIpc(async (client) => {
|
|
12
|
-
if (opts.node) {
|
|
13
|
-
const [nodeType, nodeIdStr] = opts.node.split(':');
|
|
14
|
-
const nodeId = parseInt(nodeIdStr, 10);
|
|
15
|
-
|
|
16
|
-
if (!nodeType || isNaN(nodeId)) {
|
|
17
|
-
console.error(c.error('Invalid node format. Use: --node error:42'));
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
-
const related: any = await client.request('synapse.related', {
|
|
23
|
-
nodeType,
|
|
24
|
-
nodeId,
|
|
25
|
-
maxDepth: 2,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (!related?.length) {
|
|
29
|
-
console.log(`${c.dim('No connections found for')} ${c.cyan(`${nodeType}:${nodeId}`)}`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
console.log(header(`Connections from ${nodeType}:${nodeId}`, icons.synapse));
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
-
for (const r of related as any[]) {
|
|
36
|
-
const weight = (r.activation ?? r.weight ?? 0);
|
|
37
|
-
const weightColor = weight >= 0.7 ? c.green : weight >= 0.3 ? c.orange : c.dim;
|
|
38
|
-
console.log(` ${c.cyan(icons.arrow)} ${c.value(`${r.nodeType}:${r.nodeId}`)} ${c.label('weight:')} ${weightColor(weight.toFixed(3))}`);
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
// Show general network stats
|
|
42
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
-
const stats: any = await client.request('synapse.stats', {});
|
|
44
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
-
const overview: any = await client.request('analytics.network', {
|
|
46
|
-
limit: parseInt(opts.limit, 10),
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
console.log(header('Synapse Network', icons.synapse));
|
|
50
|
-
console.log(keyValue('Total synapses', stats.totalSynapses ?? 0));
|
|
51
|
-
console.log(keyValue('Average weight', (stats.avgWeight ?? 0).toFixed(3)));
|
|
52
|
-
console.log();
|
|
53
|
-
|
|
54
|
-
if (overview?.strongestSynapses?.length) {
|
|
55
|
-
console.log(` ${c.purple.bold('Strongest connections:')}`);
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
-
for (const s of overview.strongestSynapses as any[]) {
|
|
58
|
-
const weight = (s.weight ?? 0);
|
|
59
|
-
const weightColor = weight >= 0.7 ? c.green : weight >= 0.3 ? c.orange : c.dim;
|
|
60
|
-
console.log(` ${c.dim(s.source)} ${c.cyan(icons.arrow)} ${c.dim(s.target)} ${c.label(`[${s.type}]`)} ${weightColor(weight.toFixed(3))}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
console.log(`\n${divider()}`);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
}
|