@timmeck/brain 1.0.0 → 1.1.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.
Files changed (198) hide show
  1. package/BRAIN_PLAN.md +3324 -3324
  2. package/LICENSE +21 -21
  3. package/README.md +194 -188
  4. package/dist/brain.js +2 -0
  5. package/dist/brain.js.map +1 -1
  6. package/dist/cli/colors.d.ts +50 -0
  7. package/dist/cli/colors.js +106 -0
  8. package/dist/cli/colors.js.map +1 -0
  9. package/dist/cli/commands/config.d.ts +2 -0
  10. package/dist/cli/commands/config.js +165 -0
  11. package/dist/cli/commands/config.js.map +1 -0
  12. package/dist/cli/commands/dashboard.js +222 -8
  13. package/dist/cli/commands/dashboard.js.map +1 -1
  14. package/dist/cli/commands/export.js +3 -0
  15. package/dist/cli/commands/export.js.map +1 -1
  16. package/dist/cli/commands/import.js +24 -15
  17. package/dist/cli/commands/import.js.map +1 -1
  18. package/dist/cli/commands/insights.js +33 -6
  19. package/dist/cli/commands/insights.js.map +1 -1
  20. package/dist/cli/commands/learn.d.ts +2 -0
  21. package/dist/cli/commands/learn.js +22 -0
  22. package/dist/cli/commands/learn.js.map +1 -0
  23. package/dist/cli/commands/modules.js +25 -6
  24. package/dist/cli/commands/modules.js.map +1 -1
  25. package/dist/cli/commands/network.js +15 -9
  26. package/dist/cli/commands/network.js.map +1 -1
  27. package/dist/cli/commands/query.js +92 -25
  28. package/dist/cli/commands/query.js.map +1 -1
  29. package/dist/cli/commands/start.js +5 -4
  30. package/dist/cli/commands/start.js.map +1 -1
  31. package/dist/cli/commands/status.js +19 -16
  32. package/dist/cli/commands/status.js.map +1 -1
  33. package/dist/cli/commands/stop.js +5 -4
  34. package/dist/cli/commands/stop.js.map +1 -1
  35. package/dist/cli/ipc-helper.js +4 -3
  36. package/dist/cli/ipc-helper.js.map +1 -1
  37. package/dist/db/migrations/001_core_schema.js +115 -115
  38. package/dist/db/migrations/002_learning_schema.js +33 -33
  39. package/dist/db/migrations/003_code_schema.js +48 -48
  40. package/dist/db/migrations/004_synapses_schema.js +52 -52
  41. package/dist/db/migrations/005_fts_indexes.js +73 -73
  42. package/dist/db/migrations/index.js +6 -6
  43. package/dist/db/repositories/antipattern.repository.js +3 -3
  44. package/dist/db/repositories/code-module.repository.d.ts +1 -0
  45. package/dist/db/repositories/code-module.repository.js +8 -0
  46. package/dist/db/repositories/code-module.repository.js.map +1 -1
  47. package/dist/db/repositories/error.repository.js +46 -46
  48. package/dist/db/repositories/insight.repository.js +3 -3
  49. package/dist/db/repositories/notification.repository.js +3 -3
  50. package/dist/db/repositories/project.repository.js +21 -21
  51. package/dist/db/repositories/rule.repository.js +24 -24
  52. package/dist/db/repositories/solution.repository.js +50 -50
  53. package/dist/db/repositories/synapse.repository.js +18 -18
  54. package/dist/db/repositories/terminal.repository.js +24 -24
  55. package/dist/index.js +4 -0
  56. package/dist/index.js.map +1 -1
  57. package/dist/ipc/router.d.ts +2 -0
  58. package/dist/ipc/router.js +7 -1
  59. package/dist/ipc/router.js.map +1 -1
  60. package/dist/services/code.service.d.ts +1 -1
  61. package/dist/services/code.service.js +5 -2
  62. package/dist/services/code.service.js.map +1 -1
  63. package/package.json +5 -4
  64. package/src/brain.ts +3 -0
  65. package/src/cli/colors.ts +116 -0
  66. package/src/cli/commands/config.ts +169 -0
  67. package/src/cli/commands/dashboard.ts +231 -8
  68. package/src/cli/commands/export.ts +4 -0
  69. package/src/cli/commands/import.ts +24 -15
  70. package/src/cli/commands/insights.ts +37 -5
  71. package/src/cli/commands/learn.ts +24 -0
  72. package/src/cli/commands/modules.ts +28 -5
  73. package/src/cli/commands/network.ts +15 -9
  74. package/src/cli/commands/query.ts +103 -26
  75. package/src/cli/commands/start.ts +5 -4
  76. package/src/cli/commands/status.ts +19 -16
  77. package/src/cli/commands/stop.ts +5 -4
  78. package/src/cli/ipc-helper.ts +4 -3
  79. package/src/code/analyzer.ts +77 -77
  80. package/src/code/fingerprint.ts +87 -87
  81. package/src/code/matcher.ts +64 -64
  82. package/src/code/parsers/generic.ts +29 -29
  83. package/src/code/parsers/python.ts +54 -54
  84. package/src/code/parsers/typescript.ts +65 -65
  85. package/src/code/registry.ts +60 -60
  86. package/src/code/scorer.ts +108 -108
  87. package/src/config.ts +111 -111
  88. package/src/db/connection.ts +22 -22
  89. package/src/db/migrations/001_core_schema.ts +120 -120
  90. package/src/db/migrations/002_learning_schema.ts +38 -38
  91. package/src/db/migrations/003_code_schema.ts +53 -53
  92. package/src/db/migrations/004_synapses_schema.ts +57 -57
  93. package/src/db/migrations/005_fts_indexes.ts +78 -78
  94. package/src/db/migrations/006_synapses_phase3.ts +17 -17
  95. package/src/db/migrations/index.ts +64 -64
  96. package/src/db/repositories/antipattern.repository.ts +66 -66
  97. package/src/db/repositories/code-module.repository.ts +9 -0
  98. package/src/db/repositories/error.repository.ts +149 -149
  99. package/src/db/repositories/insight.repository.ts +78 -78
  100. package/src/db/repositories/notification.repository.ts +66 -66
  101. package/src/db/repositories/project.repository.ts +93 -93
  102. package/src/db/repositories/rule.repository.ts +108 -108
  103. package/src/db/repositories/solution.repository.ts +154 -154
  104. package/src/db/repositories/synapse.repository.ts +153 -153
  105. package/src/db/repositories/terminal.repository.ts +101 -101
  106. package/src/hooks/post-tool-use.ts +90 -90
  107. package/src/hooks/post-write.ts +117 -117
  108. package/src/index.ts +4 -0
  109. package/src/ipc/client.ts +118 -118
  110. package/src/ipc/protocol.ts +35 -35
  111. package/src/ipc/router.ts +9 -1
  112. package/src/ipc/server.ts +110 -110
  113. package/src/learning/confidence-scorer.ts +47 -47
  114. package/src/learning/decay.ts +46 -46
  115. package/src/learning/learning-engine.ts +162 -162
  116. package/src/learning/pattern-extractor.ts +90 -90
  117. package/src/learning/rule-generator.ts +74 -74
  118. package/src/matching/error-matcher.ts +115 -115
  119. package/src/matching/fingerprint.ts +29 -29
  120. package/src/matching/similarity.ts +61 -61
  121. package/src/matching/tfidf.ts +74 -74
  122. package/src/matching/tokenizer.ts +41 -41
  123. package/src/mcp/auto-detect.ts +93 -93
  124. package/src/mcp/server.ts +73 -73
  125. package/src/mcp/tools.ts +290 -290
  126. package/src/parsing/error-parser.ts +28 -28
  127. package/src/parsing/parsers/compiler.ts +93 -93
  128. package/src/parsing/parsers/generic.ts +28 -28
  129. package/src/parsing/parsers/go.ts +97 -97
  130. package/src/parsing/parsers/node.ts +69 -69
  131. package/src/parsing/parsers/python.ts +62 -62
  132. package/src/parsing/parsers/rust.ts +50 -50
  133. package/src/parsing/parsers/shell.ts +42 -42
  134. package/src/parsing/types.ts +47 -47
  135. package/src/research/gap-analyzer.ts +135 -135
  136. package/src/research/insight-generator.ts +123 -123
  137. package/src/research/research-engine.ts +116 -116
  138. package/src/research/synergy-detector.ts +126 -126
  139. package/src/research/template-extractor.ts +130 -130
  140. package/src/research/trend-analyzer.ts +127 -127
  141. package/src/services/analytics.service.ts +87 -87
  142. package/src/services/code.service.ts +5 -2
  143. package/src/services/error.service.ts +164 -164
  144. package/src/services/notification.service.ts +41 -41
  145. package/src/services/prevention.service.ts +119 -119
  146. package/src/services/research.service.ts +93 -93
  147. package/src/services/solution.service.ts +116 -116
  148. package/src/services/synapse.service.ts +59 -59
  149. package/src/services/terminal.service.ts +81 -81
  150. package/src/synapses/activation.ts +80 -80
  151. package/src/synapses/decay.ts +38 -38
  152. package/src/synapses/hebbian.ts +69 -69
  153. package/src/synapses/pathfinder.ts +81 -81
  154. package/src/synapses/synapse-manager.ts +109 -109
  155. package/src/types/code.types.ts +52 -52
  156. package/src/types/config.types.ts +79 -79
  157. package/src/types/error.types.ts +67 -67
  158. package/src/types/ipc.types.ts +8 -8
  159. package/src/types/mcp.types.ts +53 -53
  160. package/src/types/research.types.ts +28 -28
  161. package/src/types/solution.types.ts +30 -30
  162. package/src/types/synapse.types.ts +49 -49
  163. package/src/utils/events.ts +45 -45
  164. package/src/utils/hash.ts +5 -5
  165. package/src/utils/logger.ts +48 -48
  166. package/src/utils/paths.ts +19 -19
  167. package/tests/fixtures/code-modules/modules.ts +83 -83
  168. package/tests/fixtures/errors/go.ts +9 -9
  169. package/tests/fixtures/errors/node.ts +24 -24
  170. package/tests/fixtures/errors/python.ts +21 -21
  171. package/tests/fixtures/errors/rust.ts +25 -25
  172. package/tests/fixtures/errors/shell.ts +15 -15
  173. package/tests/fixtures/solutions/solutions.ts +27 -27
  174. package/tests/helpers/setup-db.ts +52 -52
  175. package/tests/integration/code-flow.test.ts +86 -86
  176. package/tests/integration/error-flow.test.ts +83 -83
  177. package/tests/integration/ipc-flow.test.ts +166 -166
  178. package/tests/integration/learning-cycle.test.ts +82 -82
  179. package/tests/integration/synapse-flow.test.ts +117 -117
  180. package/tests/unit/code/analyzer.test.ts +58 -58
  181. package/tests/unit/code/fingerprint.test.ts +51 -51
  182. package/tests/unit/code/scorer.test.ts +55 -55
  183. package/tests/unit/learning/confidence-scorer.test.ts +60 -60
  184. package/tests/unit/learning/decay.test.ts +45 -45
  185. package/tests/unit/learning/pattern-extractor.test.ts +50 -50
  186. package/tests/unit/matching/error-matcher.test.ts +69 -69
  187. package/tests/unit/matching/fingerprint.test.ts +47 -47
  188. package/tests/unit/matching/similarity.test.ts +65 -65
  189. package/tests/unit/matching/tfidf.test.ts +71 -71
  190. package/tests/unit/matching/tokenizer.test.ts +83 -83
  191. package/tests/unit/parsing/parsers.test.ts +113 -113
  192. package/tests/unit/research/gap-analyzer.test.ts +45 -45
  193. package/tests/unit/research/trend-analyzer.test.ts +45 -45
  194. package/tests/unit/synapses/activation.test.ts +80 -80
  195. package/tests/unit/synapses/decay.test.ts +27 -27
  196. package/tests/unit/synapses/hebbian.test.ts +96 -96
  197. package/tests/unit/synapses/pathfinder.test.ts +72 -72
  198. package/tsconfig.json +18 -18
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function configCommand(): Command;
@@ -0,0 +1,165 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { getDataDir } from '../../utils/paths.js';
5
+ import { c, icons, header, divider } from '../colors.js';
6
+ function getConfigPath() {
7
+ return path.join(getDataDir(), 'config.json');
8
+ }
9
+ function readConfig() {
10
+ const configPath = getConfigPath();
11
+ if (fs.existsSync(configPath)) {
12
+ return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
13
+ }
14
+ return {};
15
+ }
16
+ function writeConfig(config) {
17
+ const configPath = getConfigPath();
18
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
19
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
20
+ }
21
+ function getNestedValue(obj, keyPath) {
22
+ const parts = keyPath.split('.');
23
+ let current = obj;
24
+ for (const part of parts) {
25
+ if (current === null || current === undefined || typeof current !== 'object')
26
+ return undefined;
27
+ current = current[part];
28
+ }
29
+ return current;
30
+ }
31
+ function setNestedValue(obj, keyPath, value) {
32
+ const parts = keyPath.split('.');
33
+ let current = obj;
34
+ for (let i = 0; i < parts.length - 1; i++) {
35
+ const part = parts[i];
36
+ if (!current[part] || typeof current[part] !== 'object') {
37
+ current[part] = {};
38
+ }
39
+ current = current[part];
40
+ }
41
+ current[parts[parts.length - 1]] = value;
42
+ }
43
+ function deleteNestedValue(obj, keyPath) {
44
+ const parts = keyPath.split('.');
45
+ let current = obj;
46
+ for (let i = 0; i < parts.length - 1; i++) {
47
+ const part = parts[i];
48
+ if (!current[part] || typeof current[part] !== 'object')
49
+ return false;
50
+ current = current[part];
51
+ }
52
+ const last = parts[parts.length - 1];
53
+ if (last in current) {
54
+ delete current[last];
55
+ return true;
56
+ }
57
+ return false;
58
+ }
59
+ function parseValue(value) {
60
+ if (value === 'true')
61
+ return true;
62
+ if (value === 'false')
63
+ return false;
64
+ if (value === 'null')
65
+ return null;
66
+ const num = Number(value);
67
+ if (!isNaN(num) && value.trim() !== '')
68
+ return num;
69
+ // Try JSON for arrays/objects
70
+ if ((value.startsWith('[') && value.endsWith(']')) || (value.startsWith('{') && value.endsWith('}'))) {
71
+ try {
72
+ return JSON.parse(value);
73
+ }
74
+ catch { /* fall through */ }
75
+ }
76
+ return value;
77
+ }
78
+ function printObject(obj, indent = 0) {
79
+ const pad = ' '.repeat(indent);
80
+ if (obj === null || obj === undefined) {
81
+ console.log(`${pad}${c.dim('(not set)')}`);
82
+ return;
83
+ }
84
+ if (typeof obj !== 'object') {
85
+ console.log(`${pad}${c.value(String(obj))}`);
86
+ return;
87
+ }
88
+ for (const [key, val] of Object.entries(obj)) {
89
+ if (val && typeof val === 'object' && !Array.isArray(val)) {
90
+ console.log(`${pad}${c.cyan(key + ':')}`);
91
+ printObject(val, indent + 2);
92
+ }
93
+ else {
94
+ const display = Array.isArray(val) ? JSON.stringify(val) : String(val);
95
+ console.log(`${pad}${c.label(key + ':')} ${c.value(display)}`);
96
+ }
97
+ }
98
+ }
99
+ export function configCommand() {
100
+ const cmd = new Command('config')
101
+ .description('View and modify Brain configuration');
102
+ cmd
103
+ .command('show')
104
+ .description('Show current configuration')
105
+ .argument('[key]', 'Specific config key (e.g., learning.intervalMs)')
106
+ .action((key) => {
107
+ const config = readConfig();
108
+ if (key) {
109
+ const value = getNestedValue(config, key);
110
+ if (value === undefined) {
111
+ console.log(`${c.dim(`Key "${key}" is not set in config overrides.`)}`);
112
+ }
113
+ else {
114
+ console.log(`${c.label(key + ':')} ${c.value(typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value))}`);
115
+ }
116
+ return;
117
+ }
118
+ console.log(header('Brain Configuration', icons.gear));
119
+ console.log(` ${c.label('Config file:')} ${c.dim(getConfigPath())}\n`);
120
+ if (Object.keys(config).length === 0) {
121
+ console.log(` ${c.dim('No custom overrides. Using defaults.')}`);
122
+ console.log(` ${c.dim('Set values with:')} ${c.cyan('brain config set <key> <value>')}`);
123
+ }
124
+ else {
125
+ printObject(config, 2);
126
+ }
127
+ console.log(`\n${divider()}`);
128
+ });
129
+ cmd
130
+ .command('set')
131
+ .description('Set a configuration value')
132
+ .argument('<key>', 'Config key path (e.g., learning.intervalMs)')
133
+ .argument('<value>', 'Value to set')
134
+ .action((key, value) => {
135
+ const config = readConfig();
136
+ const parsed = parseValue(value);
137
+ setNestedValue(config, key, parsed);
138
+ writeConfig(config);
139
+ console.log(`${icons.ok} ${c.label(key)} ${c.dim(icons.arrow)} ${c.value(String(parsed))}`);
140
+ console.log(` ${c.dim('Restart the daemon for changes to take effect:')} ${c.cyan('brain stop && brain start')}`);
141
+ });
142
+ cmd
143
+ .command('delete')
144
+ .description('Remove a configuration override (revert to default)')
145
+ .argument('<key>', 'Config key path to remove')
146
+ .action((key) => {
147
+ const config = readConfig();
148
+ if (deleteNestedValue(config, key)) {
149
+ writeConfig(config);
150
+ console.log(`${icons.ok} ${c.dim(`Removed "${key}" — will use default value.`)}`);
151
+ console.log(` ${c.dim('Restart the daemon for changes to take effect:')} ${c.cyan('brain stop && brain start')}`);
152
+ }
153
+ else {
154
+ console.log(`${c.dim(`Key "${key}" not found in config overrides.`)}`);
155
+ }
156
+ });
157
+ cmd
158
+ .command('path')
159
+ .description('Show the config file path')
160
+ .action(() => {
161
+ console.log(getConfigPath());
162
+ });
163
+ return cmd;
164
+ }
165
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { Command } from 'commander';
2
2
  import { withIpc } from '../ipc-helper.js';
3
3
  import { writeFileSync } from 'fs';
4
4
  import { resolve } from 'path';
5
+ import { c, icons } from '../colors.js';
5
6
  export function dashboardCommand() {
6
7
  return new Command('dashboard')
7
8
  .description('Generate and open the Brain dashboard with live data')
@@ -9,12 +10,14 @@ export function dashboardCommand() {
9
10
  .option('--no-open', 'Generate without opening in browser')
10
11
  .action(async (opts) => {
11
12
  await withIpc(async (client) => {
12
- console.log('Fetching data from Brain...');
13
+ console.log(`${icons.chart} ${c.info('Fetching data from Brain...')}`);
13
14
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
15
  const summary = await client.request('analytics.summary', {});
15
16
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
17
  const network = await client.request('synapse.stats', {});
17
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ const networkOverview = await client.request('analytics.network', { limit: 50 });
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
21
  const insights = await client.request('research.insights', {
19
22
  activeOnly: true,
20
23
  limit: 500,
@@ -40,6 +43,8 @@ export function dashboardCommand() {
40
43
  const gaps = insightList.filter((i) => i.type === 'gap');
41
44
  const warnings = insightList.filter((i) => i.type === 'warning');
42
45
  const synergies = insightList.filter((i) => i.type === 'synergy' || i.type === 'optimization');
46
+ // Build synapse graph data
47
+ const synapseEdges = Array.isArray(networkOverview?.strongestSynapses) ? networkOverview.strongestSynapses : [];
43
48
  const data = {
44
49
  stats: {
45
50
  modules: summary.modules?.total ?? 0,
@@ -51,16 +56,15 @@ export function dashboardCommand() {
51
56
  },
52
57
  langStats,
53
58
  insights: { templates, suggestions, trends, gaps, warnings, synergies },
59
+ synapseEdges,
54
60
  };
55
61
  const html = generateHtml(data);
56
62
  const outPath = opts.output
57
63
  ? resolve(opts.output)
58
64
  : resolve(import.meta.dirname, '../../../dashboard.html');
59
65
  writeFileSync(outPath, html, 'utf-8');
60
- console.log(`Dashboard written to ${outPath}`);
61
- console.log(` Modules: ${data.stats.modules}`);
62
- console.log(` Synapses: ${data.stats.synapses}`);
63
- console.log(` Insights: ${data.stats.insights}`);
66
+ console.log(`${icons.ok} ${c.success('Dashboard written to')} ${c.dim(outPath)}`);
67
+ console.log(` ${c.label('Modules:')} ${c.value(data.stats.modules)} ${c.label('Synapses:')} ${c.value(data.stats.synapses)} ${c.label('Insights:')} ${c.value(data.stats.insights)}`);
64
68
  if (opts.open !== false) {
65
69
  const { exec } = await import('child_process');
66
70
  exec(`start "" "${outPath}"`);
@@ -72,7 +76,7 @@ function esc(s) {
72
76
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
73
77
  }
74
78
  function generateHtml(data) {
75
- const { stats, langStats, insights } = data;
79
+ const { stats, langStats, insights, synapseEdges } = data;
76
80
  // Build language chart bars
77
81
  const sortedLangs = Object.entries(langStats).sort((a, b) => b[1] - a[1]);
78
82
  const maxLang = sortedLangs[0]?.[1] || 1;
@@ -237,6 +241,14 @@ function generateHtml(data) {
237
241
  .prio-low{background:rgba(139,143,176,.1);color:var(--text2);border:1px solid rgba(139,143,176,.2)}
238
242
  .empty{color:var(--text3);font-style:italic;padding:24px}
239
243
 
244
+ /* Graph */
245
+ .graph-container{position:relative;background:var(--glass);border:1px solid var(--glass-border);border-radius:var(--radius);overflow:hidden;backdrop-filter:blur(20px)}
246
+ #synapse-graph{width:100%;height:500px;display:block;cursor:grab}
247
+ #synapse-graph:active{cursor:grabbing}
248
+ .graph-legend{display:flex;gap:16px;flex-wrap:wrap;padding:12px 20px;border-top:1px solid var(--glass-border);font-size:.8rem;color:var(--text2)}
249
+ .legend-dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:6px;vertical-align:middle}
250
+ .graph-tooltip{position:absolute;display:none;background:var(--bg2);border:1px solid var(--glass-border);border-radius:8px;padding:8px 14px;font-size:.8rem;color:var(--text);pointer-events:none;z-index:10;backdrop-filter:blur(20px);box-shadow:0 8px 30px rgba(0,0,0,.3)}
251
+
240
252
  /* Footer */
241
253
  footer{text-align:center;padding:40px 0;border-top:1px solid var(--glass-border)}
242
254
  footer p{color:var(--text3);font-size:.8rem}
@@ -271,7 +283,8 @@ function generateHtml(data) {
271
283
  <nav class="reveal reveal-delay-1">
272
284
  <a href="#stats">Stats</a>
273
285
  <a href="#languages">Languages</a>
274
- <a href="#research" class="research">&#128300; Research</a>
286
+ <a href="#network">&#128300; Network</a>
287
+ <a href="#research" class="research">&#128161; Research</a>
275
288
  </nav>
276
289
 
277
290
  <section id="stats" class="reveal reveal-delay-2">
@@ -291,7 +304,22 @@ function generateHtml(data) {
291
304
  <div class="lang-chart">${langBars}</div>
292
305
  </section>
293
306
 
294
- <section id="research" class="reveal reveal-delay-4">
307
+ <section id="network" class="reveal reveal-delay-4">
308
+ <div class="section-title"><div class="icon" style="background:rgba(71,229,255,.1)">&#128300;</div> Synapse Network</div>
309
+ <div class="graph-container">
310
+ <canvas id="synapse-graph"></canvas>
311
+ <div class="graph-legend">
312
+ <span><span class="legend-dot" style="background:var(--blue)"></span> error</span>
313
+ <span><span class="legend-dot" style="background:var(--green)"></span> solution</span>
314
+ <span><span class="legend-dot" style="background:var(--purple)"></span> code_module</span>
315
+ <span><span class="legend-dot" style="background:var(--orange)"></span> project</span>
316
+ <span><span class="legend-dot" style="background:var(--cyan)"></span> other</span>
317
+ </div>
318
+ <div id="graph-tooltip" class="graph-tooltip"></div>
319
+ </div>
320
+ </section>
321
+
322
+ <section id="research" class="reveal reveal-delay-5">
295
323
  <div class="section-title"><div class="icon" style="background:rgba(71,229,255,.1)">&#128300;</div> Research Insights</div>
296
324
  <div class="tab-bar">
297
325
  <button class="tab-btn active" data-tab="templates">&#127912; Templates <span class="count">${insights.templates.length}</span></button>
@@ -450,6 +478,192 @@ setTimeout(() => {
450
478
  el.style.width = el.dataset.target + '%';
451
479
  });
452
480
  }, 500);
481
+
482
+ // --- Synapse Force-Directed Graph ---
483
+ (function(){
484
+ const edges = ${JSON.stringify(synapseEdges.map((e) => ({ s: e.source, t: e.target, type: e.type, w: e.weight })))};
485
+ const canvas = document.getElementById('synapse-graph');
486
+ if (!canvas || !edges.length) return;
487
+ const ctx = canvas.getContext('2d');
488
+ const container = canvas.parentElement;
489
+ let W, H, dpr;
490
+
491
+ const NODE_COLORS = {
492
+ error: '#ff5577', solution: '#3dffa0', code_module: '#b47aff',
493
+ project: '#ffb347', rule: '#5b9cff', antipattern: '#ff5577'
494
+ };
495
+ const DEFAULT_COLOR = '#47e5ff';
496
+
497
+ // Build graph nodes & edges
498
+ const nodeMap = new Map();
499
+ const graphEdges = [];
500
+ for (const e of edges) {
501
+ if (!nodeMap.has(e.s)) nodeMap.set(e.s, { id: e.s, type: e.s.split(':')[0], x: 0, y: 0, vx: 0, vy: 0, connections: 0 });
502
+ if (!nodeMap.has(e.t)) nodeMap.set(e.t, { id: e.t, type: e.t.split(':')[0], x: 0, y: 0, vx: 0, vy: 0, connections: 0 });
503
+ nodeMap.get(e.s).connections++;
504
+ nodeMap.get(e.t).connections++;
505
+ graphEdges.push({ source: nodeMap.get(e.s), target: nodeMap.get(e.t), type: e.type, weight: e.w });
506
+ }
507
+ const nodes = [...nodeMap.values()];
508
+
509
+ function resize() {
510
+ dpr = window.devicePixelRatio || 1;
511
+ W = container.clientWidth;
512
+ H = 500;
513
+ canvas.width = W * dpr;
514
+ canvas.height = H * dpr;
515
+ canvas.style.width = W + 'px';
516
+ canvas.style.height = H + 'px';
517
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
518
+ }
519
+ resize();
520
+ window.addEventListener('resize', resize);
521
+
522
+ // Random initial positions
523
+ for (const n of nodes) {
524
+ n.x = W * 0.2 + Math.random() * W * 0.6;
525
+ n.y = H * 0.2 + Math.random() * H * 0.6;
526
+ }
527
+
528
+ // Force simulation
529
+ const REPULSION = 3000;
530
+ const ATTRACTION = 0.008;
531
+ const DAMPING = 0.85;
532
+ const CENTER_GRAVITY = 0.002;
533
+ let hovered = null;
534
+ let dragging = null;
535
+ let dragOff = {x:0,y:0};
536
+
537
+ function simulate() {
538
+ // Repulsion
539
+ for (let i = 0; i < nodes.length; i++) {
540
+ for (let j = i + 1; j < nodes.length; j++) {
541
+ let dx = nodes[i].x - nodes[j].x;
542
+ let dy = nodes[i].y - nodes[j].y;
543
+ let dist = Math.sqrt(dx*dx + dy*dy) || 1;
544
+ let force = REPULSION / (dist * dist);
545
+ let fx = (dx / dist) * force;
546
+ let fy = (dy / dist) * force;
547
+ nodes[i].vx += fx; nodes[i].vy += fy;
548
+ nodes[j].vx -= fx; nodes[j].vy -= fy;
549
+ }
550
+ }
551
+ // Attraction along edges
552
+ for (const e of graphEdges) {
553
+ let dx = e.target.x - e.source.x;
554
+ let dy = e.target.y - e.source.y;
555
+ let dist = Math.sqrt(dx*dx + dy*dy) || 1;
556
+ let force = (dist - 100) * ATTRACTION * e.weight;
557
+ let fx = (dx / dist) * force;
558
+ let fy = (dy / dist) * force;
559
+ e.source.vx += fx; e.source.vy += fy;
560
+ e.target.vx -= fx; e.target.vy -= fy;
561
+ }
562
+ // Center gravity
563
+ for (const n of nodes) {
564
+ n.vx += (W/2 - n.x) * CENTER_GRAVITY;
565
+ n.vy += (H/2 - n.y) * CENTER_GRAVITY;
566
+ }
567
+ // Apply & damp
568
+ for (const n of nodes) {
569
+ if (n === dragging) continue;
570
+ n.vx *= DAMPING; n.vy *= DAMPING;
571
+ n.x += n.vx; n.y += n.vy;
572
+ n.x = Math.max(20, Math.min(W - 20, n.x));
573
+ n.y = Math.max(20, Math.min(H - 20, n.y));
574
+ }
575
+ }
576
+
577
+ function getNodeRadius(n) { return Math.min(16, 5 + n.connections * 1.5); }
578
+
579
+ function draw() {
580
+ ctx.clearRect(0, 0, W, H);
581
+ // Edges
582
+ for (const e of graphEdges) {
583
+ const alpha = 0.15 + e.weight * 0.5;
584
+ ctx.strokeStyle = 'rgba(91,156,255,' + Math.min(0.8, alpha) + ')';
585
+ ctx.lineWidth = 0.5 + e.weight * 2;
586
+ ctx.beginPath();
587
+ ctx.moveTo(e.source.x, e.source.y);
588
+ ctx.lineTo(e.target.x, e.target.y);
589
+ ctx.stroke();
590
+ }
591
+ // Nodes
592
+ for (const n of nodes) {
593
+ const r = getNodeRadius(n);
594
+ const color = NODE_COLORS[n.type] || DEFAULT_COLOR;
595
+ const isHover = n === hovered || n === dragging;
596
+ // Glow
597
+ if (isHover) {
598
+ ctx.shadowColor = color;
599
+ ctx.shadowBlur = 20;
600
+ }
601
+ ctx.fillStyle = color;
602
+ ctx.globalAlpha = isHover ? 1 : 0.8;
603
+ ctx.beginPath();
604
+ ctx.arc(n.x, n.y, r, 0, Math.PI * 2);
605
+ ctx.fill();
606
+ ctx.globalAlpha = 1;
607
+ ctx.shadowBlur = 0;
608
+ // Label for hovered or large nodes
609
+ if (isHover || n.connections >= 4) {
610
+ ctx.fillStyle = '#e8eaf6';
611
+ ctx.font = (isHover ? 'bold ' : '') + '11px Inter, system-ui, sans-serif';
612
+ ctx.textAlign = 'center';
613
+ ctx.fillText(n.id, n.x, n.y - r - 6);
614
+ }
615
+ }
616
+ simulate();
617
+ requestAnimationFrame(draw);
618
+ }
619
+ draw();
620
+
621
+ // Interaction
622
+ const tooltip = document.getElementById('graph-tooltip');
623
+ function getNodeAt(mx, my) {
624
+ for (let i = nodes.length - 1; i >= 0; i--) {
625
+ const n = nodes[i], r = getNodeRadius(n);
626
+ if (Math.hypot(mx - n.x, my - n.y) <= r + 4) return n;
627
+ }
628
+ return null;
629
+ }
630
+ function getPos(e) {
631
+ const rect = canvas.getBoundingClientRect();
632
+ return { x: e.clientX - rect.left, y: e.clientY - rect.top };
633
+ }
634
+ canvas.addEventListener('mousemove', function(e) {
635
+ const p = getPos(e);
636
+ if (dragging) {
637
+ dragging.x = p.x + dragOff.x;
638
+ dragging.y = p.y + dragOff.y;
639
+ dragging.vx = 0; dragging.vy = 0;
640
+ return;
641
+ }
642
+ const n = getNodeAt(p.x, p.y);
643
+ hovered = n;
644
+ canvas.style.cursor = n ? 'pointer' : 'grab';
645
+ if (n) {
646
+ const conns = graphEdges.filter(e => e.source === n || e.target === n);
647
+ tooltip.innerHTML = '<strong>' + n.id + '</strong><br>' + conns.length + ' connections';
648
+ tooltip.style.display = 'block';
649
+ tooltip.style.left = (p.x + 15) + 'px';
650
+ tooltip.style.top = (p.y - 10) + 'px';
651
+ } else {
652
+ tooltip.style.display = 'none';
653
+ }
654
+ });
655
+ canvas.addEventListener('mousedown', function(e) {
656
+ const p = getPos(e);
657
+ const n = getNodeAt(p.x, p.y);
658
+ if (n) {
659
+ dragging = n;
660
+ dragOff = { x: n.x - p.x, y: n.y - p.y };
661
+ canvas.style.cursor = 'grabbing';
662
+ }
663
+ });
664
+ canvas.addEventListener('mouseup', function() { dragging = null; });
665
+ canvas.addEventListener('mouseleave', function() { dragging = null; hovered = null; tooltip.style.display = 'none'; });
666
+ })();
453
667
  </script>
454
668
  </body>
455
669
  </html>`;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/cli/commands/dashboard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/cli/commands/dashboard.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,13 @@
1
1
  import { Command } from 'commander';
2
2
  import { withIpc } from '../ipc-helper.js';
3
+ import { c, icons } from '../colors.js';
3
4
  export function exportCommand() {
4
5
  return new Command('export')
5
6
  .description('Export Brain data')
6
7
  .option('--format <fmt>', 'Output format: json (default)', 'json')
7
8
  .action(async () => {
8
9
  await withIpc(async (client) => {
10
+ process.stderr.write(`${icons.gear} ${c.info('Exporting Brain data...')}\n`);
9
11
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
12
  const summary = await client.request('analytics.summary', {});
11
13
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -19,6 +21,7 @@ export function exportCommand() {
19
21
  insights,
20
22
  };
21
23
  console.log(JSON.stringify(data, null, 2));
24
+ process.stderr.write(`${icons.ok} ${c.success('Export complete.')}\n`);
22
25
  });
23
26
  });
24
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/cli/commands/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;SACzB,WAAW,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,gBAAgB,EAAE,+BAA+B,EAAE,MAAM,CAAC;SACjE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAC7B,8DAA8D;YAC9D,MAAM,OAAO,GAAQ,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;YACnE,8DAA8D;YAC9D,MAAM,OAAO,GAAQ,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAC/E,8DAA8D;YAC9D,MAAM,QAAQ,GAAQ,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAElG,MAAM,IAAI,GAAG;gBACX,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACpC,OAAO;gBACP,OAAO;gBACP,QAAQ;aACT,CAAC;YAEF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/cli/commands/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;SACzB,WAAW,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,gBAAgB,EAAE,+BAA+B,EAAE,MAAM,CAAC;SACjE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC;YAE9E,8DAA8D;YAC9D,MAAM,OAAO,GAAQ,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;YACnE,8DAA8D;YAC9D,MAAM,OAAO,GAAQ,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAC/E,8DAA8D;YAC9D,MAAM,QAAQ,GAAQ,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAElG,MAAM,IAAI,GAAG;gBACX,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACpC,OAAO;gBACP,OAAO;gBACP,QAAQ;aACT,CAAC;YAEF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -2,9 +2,12 @@ import { Command } from 'commander';
2
2
  import { withIpc } from '../ipc-helper.js';
3
3
  import { readdirSync, readFileSync, statSync } from 'fs';
4
4
  import { resolve, basename, relative, extname } from 'path';
5
+ import { c, icons, header, divider, progressBar } from '../colors.js';
5
6
  const DEFAULT_EXTENSIONS = new Set([
6
7
  '.ts', '.tsx', '.js', '.jsx', '.py', '.rs', '.go',
7
8
  '.java', '.c', '.cpp', '.h', '.hpp', '.rb', '.sh',
9
+ '.html', '.css', '.scss', '.json', '.yaml', '.yml', '.toml',
10
+ '.md', '.sql', '.php', '.svelte', '.vue', '.astro',
8
11
  ]);
9
12
  const EXCLUDE_DIRS = new Set([
10
13
  'node_modules', 'dist', 'build', '.git', '.next',
@@ -18,6 +21,10 @@ const LANG_MAP = {
18
21
  py: 'python', rs: 'rust', go: 'go', java: 'java',
19
22
  c: 'c', cpp: 'cpp', h: 'c', hpp: 'cpp',
20
23
  rb: 'ruby', sh: 'shell', bash: 'shell',
24
+ html: 'html', css: 'css', scss: 'scss',
25
+ json: 'json', yaml: 'yaml', yml: 'yaml', toml: 'toml',
26
+ md: 'markdown', sql: 'sql', php: 'php',
27
+ svelte: 'svelte', vue: 'vue', astro: 'astro',
21
28
  };
22
29
  function detectLanguage(filePath) {
23
30
  const ext = extname(filePath).slice(1).toLowerCase();
@@ -67,7 +74,7 @@ export function importCommand() {
67
74
  .description('Import source files from a project directory into Brain')
68
75
  .argument('<directory>', 'Project directory to scan')
69
76
  .option('-p, --project <name>', 'Project name (default: directory basename)')
70
- .option('-e, --extensions <list>', 'Comma-separated extensions (default: ts,tsx,js,jsx,py,rs,go,java,c,cpp,h,hpp,rb,sh)')
77
+ .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)')
71
78
  .option('--dry-run', 'List files that would be imported without importing')
72
79
  .option('--max-size <kb>', 'Skip files larger than N KB', '100')
73
80
  .action(async (directory, opts) => {
@@ -95,20 +102,20 @@ export function importCommand() {
95
102
  console.error(`Directory not found: ${dir}`);
96
103
  process.exit(1);
97
104
  }
98
- console.log(`Scanning ${dir} ...`);
105
+ console.log(`${icons.search} ${c.info('Scanning')} ${c.value(dir)} ...`);
99
106
  const files = findSourceFiles(dir, extensions, maxSizeBytes);
100
107
  if (files.length === 0) {
101
- console.log('No source files found.');
108
+ console.log(`${c.dim('No source files found.')}`);
102
109
  return;
103
110
  }
104
- console.log(`Found ${files.length} source files.\n`);
111
+ console.log(`${icons.ok} Found ${c.value(files.length)} source files.\n`);
105
112
  if (opts.dryRun) {
106
113
  for (const f of files) {
107
114
  const rel = relative(dir, f);
108
115
  const lang = detectLanguage(f);
109
- console.log(` [${lang}] ${rel}`);
116
+ console.log(` ${c.cyan(`[${lang}]`)} ${c.dim(rel)}`);
110
117
  }
111
- console.log(`\n${files.length} files would be imported as project "${projectName}".`);
118
+ console.log(`\n${c.value(files.length)} files would be imported as project ${c.cyan(`"${projectName}"`)}.`);
112
119
  return;
113
120
  }
114
121
  // Import via IPC
@@ -129,7 +136,7 @@ export function importCommand() {
129
136
  }
130
137
  catch {
131
138
  failedCount++;
132
- process.stdout.write(` [${i + 1}/${files.length}] ${rel} — read error\n`);
139
+ process.stdout.write(` ${c.dim(`[${i + 1}/${files.length}]`)} ${c.dim(rel)} ${c.red('— read error')}\n`);
133
140
  continue;
134
141
  }
135
142
  // Skip empty files
@@ -145,28 +152,30 @@ export function importCommand() {
145
152
  source,
146
153
  });
147
154
  const score = result.reusabilityScore ?? 0;
148
- const status = result.isNew ? 'new' : 'existing';
155
+ const scoreColor = score >= 0.7 ? c.green : score >= 0.4 ? c.orange : c.red;
156
+ const statusTag = result.isNew ? c.green('new') : c.dim('existing');
149
157
  totalScore += score;
150
158
  imported++;
151
159
  if (result.isNew)
152
160
  newCount++;
153
161
  else
154
162
  existingCount++;
155
- process.stdout.write(` [${i + 1}/${files.length}] ${rel} score: ${score.toFixed(2)} (${status})\n`);
163
+ process.stdout.write(` ${c.dim(`[${i + 1}/${files.length}]`)} ${c.dim(rel)} ${c.dim(icons.arrow)} ${scoreColor(score.toFixed(2))} (${statusTag})\n`);
156
164
  }
157
165
  catch (err) {
158
166
  failedCount++;
159
167
  const msg = err instanceof Error ? err.message : String(err);
160
- process.stdout.write(` [${i + 1}/${files.length}] ${rel} failed: ${msg.slice(0, 80)}\n`);
168
+ process.stdout.write(` ${c.dim(`[${i + 1}/${files.length}]`)} ${c.dim(rel)} ${c.red(`— ${msg.slice(0, 80)}`)}\n`);
161
169
  }
162
170
  }
163
171
  const avgScore = imported > 0 ? (totalScore / imported).toFixed(2) : '0';
164
- console.log(`\n--- Import Summary ---`);
165
- console.log(` Project: ${projectName}`);
166
- console.log(` Imported: ${imported} (${newCount} new, ${existingCount} existing)`);
172
+ console.log(header('Import Summary', icons.module));
173
+ console.log(` ${c.label('Project:')} ${c.cyan(projectName)}`);
174
+ console.log(` ${c.label('Imported:')} ${c.value(imported)} (${c.green(`${newCount} new`)}, ${c.dim(`${existingCount} existing`)})`);
167
175
  if (failedCount > 0)
168
- console.log(` Failed: ${failedCount}`);
169
- console.log(` Avg reusability score: ${avgScore}`);
176
+ console.log(` ${c.label('Failed:')} ${c.red(failedCount)}`);
177
+ console.log(` ${c.label('Avg score:')} ${c.value(avgScore)} ${progressBar(parseFloat(avgScore), 1)}`);
178
+ console.log(divider());
170
179
  });
171
180
  });
172
181
  }