@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.
- package/BRAIN_PLAN.md +3324 -3324
- package/LICENSE +21 -21
- package/README.md +194 -188
- package/dist/brain.js +2 -0
- package/dist/brain.js.map +1 -1
- package/dist/cli/colors.d.ts +50 -0
- package/dist/cli/colors.js +106 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/commands/config.d.ts +2 -0
- package/dist/cli/commands/config.js +165 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/dashboard.js +222 -8
- package/dist/cli/commands/dashboard.js.map +1 -1
- package/dist/cli/commands/export.js +3 -0
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/import.js +24 -15
- package/dist/cli/commands/import.js.map +1 -1
- package/dist/cli/commands/insights.js +33 -6
- package/dist/cli/commands/insights.js.map +1 -1
- package/dist/cli/commands/learn.d.ts +2 -0
- package/dist/cli/commands/learn.js +22 -0
- package/dist/cli/commands/learn.js.map +1 -0
- package/dist/cli/commands/modules.js +25 -6
- package/dist/cli/commands/modules.js.map +1 -1
- package/dist/cli/commands/network.js +15 -9
- package/dist/cli/commands/network.js.map +1 -1
- package/dist/cli/commands/query.js +92 -25
- package/dist/cli/commands/query.js.map +1 -1
- package/dist/cli/commands/start.js +5 -4
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.js +19 -16
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/stop.js +5 -4
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/ipc-helper.js +4 -3
- package/dist/cli/ipc-helper.js.map +1 -1
- package/dist/db/migrations/001_core_schema.js +115 -115
- package/dist/db/migrations/002_learning_schema.js +33 -33
- package/dist/db/migrations/003_code_schema.js +48 -48
- package/dist/db/migrations/004_synapses_schema.js +52 -52
- package/dist/db/migrations/005_fts_indexes.js +73 -73
- package/dist/db/migrations/index.js +6 -6
- package/dist/db/repositories/antipattern.repository.js +3 -3
- package/dist/db/repositories/code-module.repository.d.ts +1 -0
- package/dist/db/repositories/code-module.repository.js +8 -0
- package/dist/db/repositories/code-module.repository.js.map +1 -1
- package/dist/db/repositories/error.repository.js +46 -46
- package/dist/db/repositories/insight.repository.js +3 -3
- package/dist/db/repositories/notification.repository.js +3 -3
- package/dist/db/repositories/project.repository.js +21 -21
- package/dist/db/repositories/rule.repository.js +24 -24
- package/dist/db/repositories/solution.repository.js +50 -50
- package/dist/db/repositories/synapse.repository.js +18 -18
- package/dist/db/repositories/terminal.repository.js +24 -24
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/ipc/router.d.ts +2 -0
- package/dist/ipc/router.js +7 -1
- package/dist/ipc/router.js.map +1 -1
- package/dist/services/code.service.d.ts +1 -1
- package/dist/services/code.service.js +5 -2
- package/dist/services/code.service.js.map +1 -1
- package/package.json +5 -4
- package/src/brain.ts +3 -0
- package/src/cli/colors.ts +116 -0
- package/src/cli/commands/config.ts +169 -0
- package/src/cli/commands/dashboard.ts +231 -8
- package/src/cli/commands/export.ts +4 -0
- package/src/cli/commands/import.ts +24 -15
- package/src/cli/commands/insights.ts +37 -5
- package/src/cli/commands/learn.ts +24 -0
- package/src/cli/commands/modules.ts +28 -5
- package/src/cli/commands/network.ts +15 -9
- package/src/cli/commands/query.ts +103 -26
- package/src/cli/commands/start.ts +5 -4
- package/src/cli/commands/status.ts +19 -16
- package/src/cli/commands/stop.ts +5 -4
- package/src/cli/ipc-helper.ts +4 -3
- package/src/code/analyzer.ts +77 -77
- package/src/code/fingerprint.ts +87 -87
- package/src/code/matcher.ts +64 -64
- package/src/code/parsers/generic.ts +29 -29
- package/src/code/parsers/python.ts +54 -54
- package/src/code/parsers/typescript.ts +65 -65
- package/src/code/registry.ts +60 -60
- package/src/code/scorer.ts +108 -108
- package/src/config.ts +111 -111
- package/src/db/connection.ts +22 -22
- package/src/db/migrations/001_core_schema.ts +120 -120
- package/src/db/migrations/002_learning_schema.ts +38 -38
- package/src/db/migrations/003_code_schema.ts +53 -53
- package/src/db/migrations/004_synapses_schema.ts +57 -57
- package/src/db/migrations/005_fts_indexes.ts +78 -78
- package/src/db/migrations/006_synapses_phase3.ts +17 -17
- package/src/db/migrations/index.ts +64 -64
- package/src/db/repositories/antipattern.repository.ts +66 -66
- package/src/db/repositories/code-module.repository.ts +9 -0
- package/src/db/repositories/error.repository.ts +149 -149
- package/src/db/repositories/insight.repository.ts +78 -78
- package/src/db/repositories/notification.repository.ts +66 -66
- package/src/db/repositories/project.repository.ts +93 -93
- package/src/db/repositories/rule.repository.ts +108 -108
- package/src/db/repositories/solution.repository.ts +154 -154
- package/src/db/repositories/synapse.repository.ts +153 -153
- package/src/db/repositories/terminal.repository.ts +101 -101
- package/src/hooks/post-tool-use.ts +90 -90
- package/src/hooks/post-write.ts +117 -117
- package/src/index.ts +4 -0
- package/src/ipc/client.ts +118 -118
- package/src/ipc/protocol.ts +35 -35
- package/src/ipc/router.ts +9 -1
- package/src/ipc/server.ts +110 -110
- package/src/learning/confidence-scorer.ts +47 -47
- package/src/learning/decay.ts +46 -46
- package/src/learning/learning-engine.ts +162 -162
- package/src/learning/pattern-extractor.ts +90 -90
- package/src/learning/rule-generator.ts +74 -74
- package/src/matching/error-matcher.ts +115 -115
- package/src/matching/fingerprint.ts +29 -29
- package/src/matching/similarity.ts +61 -61
- package/src/matching/tfidf.ts +74 -74
- package/src/matching/tokenizer.ts +41 -41
- package/src/mcp/auto-detect.ts +93 -93
- package/src/mcp/server.ts +73 -73
- package/src/mcp/tools.ts +290 -290
- package/src/parsing/error-parser.ts +28 -28
- package/src/parsing/parsers/compiler.ts +93 -93
- package/src/parsing/parsers/generic.ts +28 -28
- package/src/parsing/parsers/go.ts +97 -97
- package/src/parsing/parsers/node.ts +69 -69
- package/src/parsing/parsers/python.ts +62 -62
- package/src/parsing/parsers/rust.ts +50 -50
- package/src/parsing/parsers/shell.ts +42 -42
- package/src/parsing/types.ts +47 -47
- package/src/research/gap-analyzer.ts +135 -135
- package/src/research/insight-generator.ts +123 -123
- package/src/research/research-engine.ts +116 -116
- package/src/research/synergy-detector.ts +126 -126
- package/src/research/template-extractor.ts +130 -130
- package/src/research/trend-analyzer.ts +127 -127
- package/src/services/analytics.service.ts +87 -87
- package/src/services/code.service.ts +5 -2
- package/src/services/error.service.ts +164 -164
- package/src/services/notification.service.ts +41 -41
- package/src/services/prevention.service.ts +119 -119
- package/src/services/research.service.ts +93 -93
- package/src/services/solution.service.ts +116 -116
- package/src/services/synapse.service.ts +59 -59
- package/src/services/terminal.service.ts +81 -81
- package/src/synapses/activation.ts +80 -80
- package/src/synapses/decay.ts +38 -38
- package/src/synapses/hebbian.ts +69 -69
- package/src/synapses/pathfinder.ts +81 -81
- package/src/synapses/synapse-manager.ts +109 -109
- package/src/types/code.types.ts +52 -52
- package/src/types/config.types.ts +79 -79
- package/src/types/error.types.ts +67 -67
- package/src/types/ipc.types.ts +8 -8
- package/src/types/mcp.types.ts +53 -53
- package/src/types/research.types.ts +28 -28
- package/src/types/solution.types.ts +30 -30
- package/src/types/synapse.types.ts +49 -49
- package/src/utils/events.ts +45 -45
- package/src/utils/hash.ts +5 -5
- package/src/utils/logger.ts +48 -48
- package/src/utils/paths.ts +19 -19
- package/tests/fixtures/code-modules/modules.ts +83 -83
- package/tests/fixtures/errors/go.ts +9 -9
- package/tests/fixtures/errors/node.ts +24 -24
- package/tests/fixtures/errors/python.ts +21 -21
- package/tests/fixtures/errors/rust.ts +25 -25
- package/tests/fixtures/errors/shell.ts +15 -15
- package/tests/fixtures/solutions/solutions.ts +27 -27
- package/tests/helpers/setup-db.ts +52 -52
- package/tests/integration/code-flow.test.ts +86 -86
- package/tests/integration/error-flow.test.ts +83 -83
- package/tests/integration/ipc-flow.test.ts +166 -166
- package/tests/integration/learning-cycle.test.ts +82 -82
- package/tests/integration/synapse-flow.test.ts +117 -117
- package/tests/unit/code/analyzer.test.ts +58 -58
- package/tests/unit/code/fingerprint.test.ts +51 -51
- package/tests/unit/code/scorer.test.ts +55 -55
- package/tests/unit/learning/confidence-scorer.test.ts +60 -60
- package/tests/unit/learning/decay.test.ts +45 -45
- package/tests/unit/learning/pattern-extractor.test.ts +50 -50
- package/tests/unit/matching/error-matcher.test.ts +69 -69
- package/tests/unit/matching/fingerprint.test.ts +47 -47
- package/tests/unit/matching/similarity.test.ts +65 -65
- package/tests/unit/matching/tfidf.test.ts +71 -71
- package/tests/unit/matching/tokenizer.test.ts +83 -83
- package/tests/unit/parsing/parsers.test.ts +113 -113
- package/tests/unit/research/gap-analyzer.test.ts +45 -45
- package/tests/unit/research/trend-analyzer.test.ts +45 -45
- package/tests/unit/synapses/activation.test.ts +80 -80
- package/tests/unit/synapses/decay.test.ts +27 -27
- package/tests/unit/synapses/hebbian.test.ts +96 -96
- package/tests/unit/synapses/pathfinder.test.ts +72 -72
- package/tsconfig.json +18 -18
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
|
-
|
|
3
|
-
export function up(db: Database.Database): void {
|
|
4
|
-
db.exec(`
|
|
5
|
-
-- Full-text search for errors
|
|
6
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS errors_fts USING fts5(
|
|
7
|
-
type, message, raw_output, context, file_path,
|
|
8
|
-
content='errors',
|
|
9
|
-
content_rowid='id'
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
-- Sync triggers for errors_fts
|
|
13
|
-
CREATE TRIGGER IF NOT EXISTS errors_ai AFTER INSERT ON errors BEGIN
|
|
14
|
-
INSERT INTO errors_fts(rowid, type, message, raw_output, context, file_path)
|
|
15
|
-
VALUES (new.id, new.type, new.message, new.raw_output, new.context, new.file_path);
|
|
16
|
-
END;
|
|
17
|
-
|
|
18
|
-
CREATE TRIGGER IF NOT EXISTS errors_ad AFTER DELETE ON errors BEGIN
|
|
19
|
-
INSERT INTO errors_fts(errors_fts, rowid, type, message, raw_output, context, file_path)
|
|
20
|
-
VALUES ('delete', old.id, old.type, old.message, old.raw_output, old.context, old.file_path);
|
|
21
|
-
END;
|
|
22
|
-
|
|
23
|
-
CREATE TRIGGER IF NOT EXISTS errors_au AFTER UPDATE ON errors BEGIN
|
|
24
|
-
INSERT INTO errors_fts(errors_fts, rowid, type, message, raw_output, context, file_path)
|
|
25
|
-
VALUES ('delete', old.id, old.type, old.message, old.raw_output, old.context, old.file_path);
|
|
26
|
-
INSERT INTO errors_fts(rowid, type, message, raw_output, context, file_path)
|
|
27
|
-
VALUES (new.id, new.type, new.message, new.raw_output, new.context, new.file_path);
|
|
28
|
-
END;
|
|
29
|
-
|
|
30
|
-
-- Full-text search for solutions
|
|
31
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS solutions_fts USING fts5(
|
|
32
|
-
description, commands, code_change,
|
|
33
|
-
content='solutions',
|
|
34
|
-
content_rowid='id'
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
CREATE TRIGGER IF NOT EXISTS solutions_ai AFTER INSERT ON solutions BEGIN
|
|
38
|
-
INSERT INTO solutions_fts(rowid, description, commands, code_change)
|
|
39
|
-
VALUES (new.id, new.description, new.commands, new.code_change);
|
|
40
|
-
END;
|
|
41
|
-
|
|
42
|
-
CREATE TRIGGER IF NOT EXISTS solutions_ad AFTER DELETE ON solutions BEGIN
|
|
43
|
-
INSERT INTO solutions_fts(solutions_fts, rowid, description, commands, code_change)
|
|
44
|
-
VALUES ('delete', old.id, old.description, old.commands, old.code_change);
|
|
45
|
-
END;
|
|
46
|
-
|
|
47
|
-
CREATE TRIGGER IF NOT EXISTS solutions_au AFTER UPDATE ON solutions BEGIN
|
|
48
|
-
INSERT INTO solutions_fts(solutions_fts, rowid, description, commands, code_change)
|
|
49
|
-
VALUES ('delete', old.id, old.description, old.commands, old.code_change);
|
|
50
|
-
INSERT INTO solutions_fts(rowid, description, commands, code_change)
|
|
51
|
-
VALUES (new.id, new.description, new.commands, new.code_change);
|
|
52
|
-
END;
|
|
53
|
-
|
|
54
|
-
-- Full-text search for code modules
|
|
55
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS code_modules_fts USING fts5(
|
|
56
|
-
name, file_path, description, language,
|
|
57
|
-
content='code_modules',
|
|
58
|
-
content_rowid='id'
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
CREATE TRIGGER IF NOT EXISTS code_modules_ai AFTER INSERT ON code_modules BEGIN
|
|
62
|
-
INSERT INTO code_modules_fts(rowid, name, file_path, description, language)
|
|
63
|
-
VALUES (new.id, new.name, new.file_path, new.description, new.language);
|
|
64
|
-
END;
|
|
65
|
-
|
|
66
|
-
CREATE TRIGGER IF NOT EXISTS code_modules_ad AFTER DELETE ON code_modules BEGIN
|
|
67
|
-
INSERT INTO code_modules_fts(code_modules_fts, rowid, name, file_path, description, language)
|
|
68
|
-
VALUES ('delete', old.id, old.name, old.file_path, old.description, old.language);
|
|
69
|
-
END;
|
|
70
|
-
|
|
71
|
-
CREATE TRIGGER IF NOT EXISTS code_modules_au AFTER UPDATE ON code_modules BEGIN
|
|
72
|
-
INSERT INTO code_modules_fts(code_modules_fts, rowid, name, file_path, description, language)
|
|
73
|
-
VALUES ('delete', old.id, old.name, old.file_path, old.description, old.language);
|
|
74
|
-
INSERT INTO code_modules_fts(rowid, name, file_path, description, language)
|
|
75
|
-
VALUES (new.id, new.name, new.file_path, new.description, new.language);
|
|
76
|
-
END;
|
|
77
|
-
`);
|
|
78
|
-
}
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
|
|
3
|
+
export function up(db: Database.Database): void {
|
|
4
|
+
db.exec(`
|
|
5
|
+
-- Full-text search for errors
|
|
6
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS errors_fts USING fts5(
|
|
7
|
+
type, message, raw_output, context, file_path,
|
|
8
|
+
content='errors',
|
|
9
|
+
content_rowid='id'
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
-- Sync triggers for errors_fts
|
|
13
|
+
CREATE TRIGGER IF NOT EXISTS errors_ai AFTER INSERT ON errors BEGIN
|
|
14
|
+
INSERT INTO errors_fts(rowid, type, message, raw_output, context, file_path)
|
|
15
|
+
VALUES (new.id, new.type, new.message, new.raw_output, new.context, new.file_path);
|
|
16
|
+
END;
|
|
17
|
+
|
|
18
|
+
CREATE TRIGGER IF NOT EXISTS errors_ad AFTER DELETE ON errors BEGIN
|
|
19
|
+
INSERT INTO errors_fts(errors_fts, rowid, type, message, raw_output, context, file_path)
|
|
20
|
+
VALUES ('delete', old.id, old.type, old.message, old.raw_output, old.context, old.file_path);
|
|
21
|
+
END;
|
|
22
|
+
|
|
23
|
+
CREATE TRIGGER IF NOT EXISTS errors_au AFTER UPDATE ON errors BEGIN
|
|
24
|
+
INSERT INTO errors_fts(errors_fts, rowid, type, message, raw_output, context, file_path)
|
|
25
|
+
VALUES ('delete', old.id, old.type, old.message, old.raw_output, old.context, old.file_path);
|
|
26
|
+
INSERT INTO errors_fts(rowid, type, message, raw_output, context, file_path)
|
|
27
|
+
VALUES (new.id, new.type, new.message, new.raw_output, new.context, new.file_path);
|
|
28
|
+
END;
|
|
29
|
+
|
|
30
|
+
-- Full-text search for solutions
|
|
31
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS solutions_fts USING fts5(
|
|
32
|
+
description, commands, code_change,
|
|
33
|
+
content='solutions',
|
|
34
|
+
content_rowid='id'
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
CREATE TRIGGER IF NOT EXISTS solutions_ai AFTER INSERT ON solutions BEGIN
|
|
38
|
+
INSERT INTO solutions_fts(rowid, description, commands, code_change)
|
|
39
|
+
VALUES (new.id, new.description, new.commands, new.code_change);
|
|
40
|
+
END;
|
|
41
|
+
|
|
42
|
+
CREATE TRIGGER IF NOT EXISTS solutions_ad AFTER DELETE ON solutions BEGIN
|
|
43
|
+
INSERT INTO solutions_fts(solutions_fts, rowid, description, commands, code_change)
|
|
44
|
+
VALUES ('delete', old.id, old.description, old.commands, old.code_change);
|
|
45
|
+
END;
|
|
46
|
+
|
|
47
|
+
CREATE TRIGGER IF NOT EXISTS solutions_au AFTER UPDATE ON solutions BEGIN
|
|
48
|
+
INSERT INTO solutions_fts(solutions_fts, rowid, description, commands, code_change)
|
|
49
|
+
VALUES ('delete', old.id, old.description, old.commands, old.code_change);
|
|
50
|
+
INSERT INTO solutions_fts(rowid, description, commands, code_change)
|
|
51
|
+
VALUES (new.id, new.description, new.commands, new.code_change);
|
|
52
|
+
END;
|
|
53
|
+
|
|
54
|
+
-- Full-text search for code modules
|
|
55
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS code_modules_fts USING fts5(
|
|
56
|
+
name, file_path, description, language,
|
|
57
|
+
content='code_modules',
|
|
58
|
+
content_rowid='id'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
CREATE TRIGGER IF NOT EXISTS code_modules_ai AFTER INSERT ON code_modules BEGIN
|
|
62
|
+
INSERT INTO code_modules_fts(rowid, name, file_path, description, language)
|
|
63
|
+
VALUES (new.id, new.name, new.file_path, new.description, new.language);
|
|
64
|
+
END;
|
|
65
|
+
|
|
66
|
+
CREATE TRIGGER IF NOT EXISTS code_modules_ad AFTER DELETE ON code_modules BEGIN
|
|
67
|
+
INSERT INTO code_modules_fts(code_modules_fts, rowid, name, file_path, description, language)
|
|
68
|
+
VALUES ('delete', old.id, old.name, old.file_path, old.description, old.language);
|
|
69
|
+
END;
|
|
70
|
+
|
|
71
|
+
CREATE TRIGGER IF NOT EXISTS code_modules_au AFTER UPDATE ON code_modules BEGIN
|
|
72
|
+
INSERT INTO code_modules_fts(code_modules_fts, rowid, name, file_path, description, language)
|
|
73
|
+
VALUES ('delete', old.id, old.name, old.file_path, old.description, old.language);
|
|
74
|
+
INSERT INTO code_modules_fts(rowid, name, file_path, description, language)
|
|
75
|
+
VALUES (new.id, new.name, new.file_path, new.description, new.language);
|
|
76
|
+
END;
|
|
77
|
+
`);
|
|
78
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
|
-
|
|
3
|
-
export function up(db: Database.Database): void {
|
|
4
|
-
// Add activation_count and last_activated_at columns
|
|
5
|
-
const columns = db.pragma('table_info(synapses)') as Array<{ name: string }>;
|
|
6
|
-
const colNames = columns.map(c => c.name);
|
|
7
|
-
|
|
8
|
-
if (!colNames.includes('activation_count')) {
|
|
9
|
-
db.exec(`ALTER TABLE synapses ADD COLUMN activation_count INTEGER NOT NULL DEFAULT 1`);
|
|
10
|
-
}
|
|
11
|
-
if (!colNames.includes('last_activated_at')) {
|
|
12
|
-
db.exec(`ALTER TABLE synapses ADD COLUMN last_activated_at TEXT NOT NULL DEFAULT (datetime('now'))`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Add index for decay queries
|
|
16
|
-
db.exec(`CREATE INDEX IF NOT EXISTS idx_synapses_last_activated ON synapses(last_activated_at)`);
|
|
17
|
-
}
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
|
|
3
|
+
export function up(db: Database.Database): void {
|
|
4
|
+
// Add activation_count and last_activated_at columns
|
|
5
|
+
const columns = db.pragma('table_info(synapses)') as Array<{ name: string }>;
|
|
6
|
+
const colNames = columns.map(c => c.name);
|
|
7
|
+
|
|
8
|
+
if (!colNames.includes('activation_count')) {
|
|
9
|
+
db.exec(`ALTER TABLE synapses ADD COLUMN activation_count INTEGER NOT NULL DEFAULT 1`);
|
|
10
|
+
}
|
|
11
|
+
if (!colNames.includes('last_activated_at')) {
|
|
12
|
+
db.exec(`ALTER TABLE synapses ADD COLUMN last_activated_at TEXT NOT NULL DEFAULT (datetime('now'))`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Add index for decay queries
|
|
16
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_synapses_last_activated ON synapses(last_activated_at)`);
|
|
17
|
+
}
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
|
-
import { getLogger } from '../../utils/logger.js';
|
|
3
|
-
import { up as coreSchema } from './001_core_schema.js';
|
|
4
|
-
import { up as learningSchema } from './002_learning_schema.js';
|
|
5
|
-
import { up as codeSchema } from './003_code_schema.js';
|
|
6
|
-
import { up as synapsesSchema } from './004_synapses_schema.js';
|
|
7
|
-
import { up as ftsIndexes } from './005_fts_indexes.js';
|
|
8
|
-
import { up as synapsesPhase3 } from './006_synapses_phase3.js';
|
|
9
|
-
|
|
10
|
-
interface Migration {
|
|
11
|
-
version: number;
|
|
12
|
-
name: string;
|
|
13
|
-
up: (db: Database.Database) => void;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const migrations: Migration[] = [
|
|
17
|
-
{ version: 1, name: '001_core_schema', up: coreSchema },
|
|
18
|
-
{ version: 2, name: '002_learning_schema', up: learningSchema },
|
|
19
|
-
{ version: 3, name: '003_code_schema', up: codeSchema },
|
|
20
|
-
{ version: 4, name: '004_synapses_schema', up: synapsesSchema },
|
|
21
|
-
{ version: 5, name: '005_fts_indexes', up: ftsIndexes },
|
|
22
|
-
{ version: 6, name: '006_synapses_phase3', up: synapsesPhase3 },
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
function ensureMigrationsTable(db: Database.Database): void {
|
|
26
|
-
db.exec(`
|
|
27
|
-
CREATE TABLE IF NOT EXISTS migrations (
|
|
28
|
-
version INTEGER PRIMARY KEY,
|
|
29
|
-
name TEXT NOT NULL,
|
|
30
|
-
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
31
|
-
);
|
|
32
|
-
`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function getCurrentVersion(db: Database.Database): number {
|
|
36
|
-
const row = db.prepare('SELECT MAX(version) as version FROM migrations').get() as { version: number | null } | undefined;
|
|
37
|
-
return row?.version ?? 0;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function runMigrations(db: Database.Database): void {
|
|
41
|
-
const logger = getLogger();
|
|
42
|
-
ensureMigrationsTable(db);
|
|
43
|
-
|
|
44
|
-
const currentVersion = getCurrentVersion(db);
|
|
45
|
-
const pending = migrations.filter(m => m.version > currentVersion);
|
|
46
|
-
|
|
47
|
-
if (pending.length === 0) {
|
|
48
|
-
logger.info('Database is up to date');
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
logger.info(`Running ${pending.length} migration(s) from version ${currentVersion}`);
|
|
53
|
-
|
|
54
|
-
const runAll = db.transaction(() => {
|
|
55
|
-
for (const migration of pending) {
|
|
56
|
-
logger.info(`Applying migration ${migration.name}`);
|
|
57
|
-
migration.up(db);
|
|
58
|
-
db.prepare('INSERT INTO migrations (version, name) VALUES (?, ?)').run(migration.version, migration.name);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
runAll();
|
|
63
|
-
logger.info(`Migrations complete. Now at version ${pending[pending.length - 1]!.version}`);
|
|
64
|
-
}
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import { getLogger } from '../../utils/logger.js';
|
|
3
|
+
import { up as coreSchema } from './001_core_schema.js';
|
|
4
|
+
import { up as learningSchema } from './002_learning_schema.js';
|
|
5
|
+
import { up as codeSchema } from './003_code_schema.js';
|
|
6
|
+
import { up as synapsesSchema } from './004_synapses_schema.js';
|
|
7
|
+
import { up as ftsIndexes } from './005_fts_indexes.js';
|
|
8
|
+
import { up as synapsesPhase3 } from './006_synapses_phase3.js';
|
|
9
|
+
|
|
10
|
+
interface Migration {
|
|
11
|
+
version: number;
|
|
12
|
+
name: string;
|
|
13
|
+
up: (db: Database.Database) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const migrations: Migration[] = [
|
|
17
|
+
{ version: 1, name: '001_core_schema', up: coreSchema },
|
|
18
|
+
{ version: 2, name: '002_learning_schema', up: learningSchema },
|
|
19
|
+
{ version: 3, name: '003_code_schema', up: codeSchema },
|
|
20
|
+
{ version: 4, name: '004_synapses_schema', up: synapsesSchema },
|
|
21
|
+
{ version: 5, name: '005_fts_indexes', up: ftsIndexes },
|
|
22
|
+
{ version: 6, name: '006_synapses_phase3', up: synapsesPhase3 },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
function ensureMigrationsTable(db: Database.Database): void {
|
|
26
|
+
db.exec(`
|
|
27
|
+
CREATE TABLE IF NOT EXISTS migrations (
|
|
28
|
+
version INTEGER PRIMARY KEY,
|
|
29
|
+
name TEXT NOT NULL,
|
|
30
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
31
|
+
);
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getCurrentVersion(db: Database.Database): number {
|
|
36
|
+
const row = db.prepare('SELECT MAX(version) as version FROM migrations').get() as { version: number | null } | undefined;
|
|
37
|
+
return row?.version ?? 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function runMigrations(db: Database.Database): void {
|
|
41
|
+
const logger = getLogger();
|
|
42
|
+
ensureMigrationsTable(db);
|
|
43
|
+
|
|
44
|
+
const currentVersion = getCurrentVersion(db);
|
|
45
|
+
const pending = migrations.filter(m => m.version > currentVersion);
|
|
46
|
+
|
|
47
|
+
if (pending.length === 0) {
|
|
48
|
+
logger.info('Database is up to date');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
logger.info(`Running ${pending.length} migration(s) from version ${currentVersion}`);
|
|
53
|
+
|
|
54
|
+
const runAll = db.transaction(() => {
|
|
55
|
+
for (const migration of pending) {
|
|
56
|
+
logger.info(`Applying migration ${migration.name}`);
|
|
57
|
+
migration.up(db);
|
|
58
|
+
db.prepare('INSERT INTO migrations (version, name) VALUES (?, ?)').run(migration.version, migration.name);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
runAll();
|
|
63
|
+
logger.info(`Migrations complete. Now at version ${pending[pending.length - 1]!.version}`);
|
|
64
|
+
}
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
|
-
import type { Statement } from 'better-sqlite3';
|
|
3
|
-
|
|
4
|
-
export interface AntipatternRecord {
|
|
5
|
-
id: number;
|
|
6
|
-
pattern: string;
|
|
7
|
-
description: string;
|
|
8
|
-
severity: string;
|
|
9
|
-
suggestion: string | null;
|
|
10
|
-
occurrences: number;
|
|
11
|
-
project_id: number | null;
|
|
12
|
-
global: number;
|
|
13
|
-
created_at: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type AntipatternCreate = Omit<AntipatternRecord, 'id' | 'created_at'>;
|
|
17
|
-
type AntipatternUpdate = Partial<Omit<AntipatternRecord, 'id' | 'created_at'>>;
|
|
18
|
-
|
|
19
|
-
export class AntipatternRepository {
|
|
20
|
-
private stmts: Record<string, Statement>;
|
|
21
|
-
|
|
22
|
-
constructor(private db: Database.Database) {
|
|
23
|
-
this.stmts = {
|
|
24
|
-
create: db.prepare(`
|
|
25
|
-
INSERT INTO antipatterns (pattern, description, severity, suggestion, occurrences, project_id, global)
|
|
26
|
-
VALUES (@pattern, @description, @severity, @suggestion, @occurrences, @project_id, @global)
|
|
27
|
-
`),
|
|
28
|
-
getById: db.prepare('SELECT * FROM antipatterns WHERE id = ?'),
|
|
29
|
-
delete: db.prepare('DELETE FROM antipatterns WHERE id = ?'),
|
|
30
|
-
findByProject: db.prepare('SELECT * FROM antipatterns WHERE project_id = ? ORDER BY occurrences DESC'),
|
|
31
|
-
findGlobal: db.prepare('SELECT * FROM antipatterns WHERE global = 1 ORDER BY occurrences DESC'),
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
create(data: AntipatternCreate): number {
|
|
36
|
-
const result = this.stmts.create.run(data);
|
|
37
|
-
return result.lastInsertRowid as number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
getById(id: number): AntipatternRecord | undefined {
|
|
41
|
-
return this.stmts.getById.get(id) as AntipatternRecord | undefined;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
update(id: number, data: AntipatternUpdate): boolean {
|
|
45
|
-
const fields = Object.keys(data).filter((key) => (data as Record<string, unknown>)[key] !== undefined);
|
|
46
|
-
if (fields.length === 0) return false;
|
|
47
|
-
|
|
48
|
-
const setClauses = fields.map((field) => `${field} = @${field}`).join(', ');
|
|
49
|
-
const stmt = this.db.prepare(`UPDATE antipatterns SET ${setClauses} WHERE id = @id`);
|
|
50
|
-
const result = stmt.run({ ...data, id });
|
|
51
|
-
return result.changes > 0;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
delete(id: number): boolean {
|
|
55
|
-
const result = this.stmts.delete.run(id);
|
|
56
|
-
return result.changes > 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
findByProject(projectId: number): AntipatternRecord[] {
|
|
60
|
-
return this.stmts.findByProject.all(projectId) as AntipatternRecord[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
findGlobal(): AntipatternRecord[] {
|
|
64
|
-
return this.stmts.findGlobal.all() as AntipatternRecord[];
|
|
65
|
-
}
|
|
66
|
-
}
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { Statement } from 'better-sqlite3';
|
|
3
|
+
|
|
4
|
+
export interface AntipatternRecord {
|
|
5
|
+
id: number;
|
|
6
|
+
pattern: string;
|
|
7
|
+
description: string;
|
|
8
|
+
severity: string;
|
|
9
|
+
suggestion: string | null;
|
|
10
|
+
occurrences: number;
|
|
11
|
+
project_id: number | null;
|
|
12
|
+
global: number;
|
|
13
|
+
created_at: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type AntipatternCreate = Omit<AntipatternRecord, 'id' | 'created_at'>;
|
|
17
|
+
type AntipatternUpdate = Partial<Omit<AntipatternRecord, 'id' | 'created_at'>>;
|
|
18
|
+
|
|
19
|
+
export class AntipatternRepository {
|
|
20
|
+
private stmts: Record<string, Statement>;
|
|
21
|
+
|
|
22
|
+
constructor(private db: Database.Database) {
|
|
23
|
+
this.stmts = {
|
|
24
|
+
create: db.prepare(`
|
|
25
|
+
INSERT INTO antipatterns (pattern, description, severity, suggestion, occurrences, project_id, global)
|
|
26
|
+
VALUES (@pattern, @description, @severity, @suggestion, @occurrences, @project_id, @global)
|
|
27
|
+
`),
|
|
28
|
+
getById: db.prepare('SELECT * FROM antipatterns WHERE id = ?'),
|
|
29
|
+
delete: db.prepare('DELETE FROM antipatterns WHERE id = ?'),
|
|
30
|
+
findByProject: db.prepare('SELECT * FROM antipatterns WHERE project_id = ? ORDER BY occurrences DESC'),
|
|
31
|
+
findGlobal: db.prepare('SELECT * FROM antipatterns WHERE global = 1 ORDER BY occurrences DESC'),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
create(data: AntipatternCreate): number {
|
|
36
|
+
const result = this.stmts.create.run(data);
|
|
37
|
+
return result.lastInsertRowid as number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getById(id: number): AntipatternRecord | undefined {
|
|
41
|
+
return this.stmts.getById.get(id) as AntipatternRecord | undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
update(id: number, data: AntipatternUpdate): boolean {
|
|
45
|
+
const fields = Object.keys(data).filter((key) => (data as Record<string, unknown>)[key] !== undefined);
|
|
46
|
+
if (fields.length === 0) return false;
|
|
47
|
+
|
|
48
|
+
const setClauses = fields.map((field) => `${field} = @${field}`).join(', ');
|
|
49
|
+
const stmt = this.db.prepare(`UPDATE antipatterns SET ${setClauses} WHERE id = @id`);
|
|
50
|
+
const result = stmt.run({ ...data, id });
|
|
51
|
+
return result.changes > 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
delete(id: number): boolean {
|
|
55
|
+
const result = this.stmts.delete.run(id);
|
|
56
|
+
return result.changes > 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
findByProject(projectId: number): AntipatternRecord[] {
|
|
60
|
+
return this.stmts.findByProject.all(projectId) as AntipatternRecord[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
findGlobal(): AntipatternRecord[] {
|
|
64
|
+
return this.stmts.findGlobal.all() as AntipatternRecord[];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -18,6 +18,7 @@ export class CodeModuleRepository {
|
|
|
18
18
|
delete: db.prepare('DELETE FROM code_modules WHERE id = ?'),
|
|
19
19
|
findByFingerprint: db.prepare('SELECT * FROM code_modules WHERE fingerprint = ?'),
|
|
20
20
|
findByProject: db.prepare('SELECT * FROM code_modules WHERE project_id = ? ORDER BY name ASC'),
|
|
21
|
+
findAll: db.prepare('SELECT * FROM code_modules ORDER BY name ASC'),
|
|
21
22
|
countAll: db.prepare('SELECT COUNT(*) as count FROM code_modules'),
|
|
22
23
|
search: db.prepare(`
|
|
23
24
|
SELECT cm.* FROM code_modules cm
|
|
@@ -74,6 +75,14 @@ export class CodeModuleRepository {
|
|
|
74
75
|
return this.stmts.search.all(query) as CodeModuleRecord[];
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
findAll(limit?: number): CodeModuleRecord[] {
|
|
79
|
+
if (limit) {
|
|
80
|
+
const stmt = this.db.prepare('SELECT * FROM code_modules ORDER BY name ASC LIMIT ?');
|
|
81
|
+
return stmt.all(limit) as CodeModuleRecord[];
|
|
82
|
+
}
|
|
83
|
+
return this.stmts.findAll.all() as CodeModuleRecord[];
|
|
84
|
+
}
|
|
85
|
+
|
|
77
86
|
countAll(): number {
|
|
78
87
|
return (this.stmts.countAll.get() as { count: number }).count;
|
|
79
88
|
}
|