@timmeck/brain 1.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/BRAIN_PLAN.md +3324 -0
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/brain.d.ts +11 -0
- package/dist/brain.js +166 -0
- package/dist/brain.js.map +1 -0
- package/dist/cli/commands/dashboard.d.ts +2 -0
- package/dist/cli/commands/dashboard.js +457 -0
- package/dist/cli/commands/dashboard.js.map +1 -0
- package/dist/cli/commands/export.d.ts +2 -0
- package/dist/cli/commands/export.js +25 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/import.d.ts +2 -0
- package/dist/cli/commands/import.js +173 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/insights.d.ts +2 -0
- package/dist/cli/commands/insights.js +32 -0
- package/dist/cli/commands/insights.js.map +1 -0
- package/dist/cli/commands/modules.d.ts +2 -0
- package/dist/cli/commands/modules.js +29 -0
- package/dist/cli/commands/modules.js.map +1 -0
- package/dist/cli/commands/network.d.ts +2 -0
- package/dist/cli/commands/network.js +56 -0
- package/dist/cli/commands/network.js.map +1 -0
- package/dist/cli/commands/query.d.ts +2 -0
- package/dist/cli/commands/query.js +40 -0
- package/dist/cli/commands/query.js.map +1 -0
- package/dist/cli/commands/start.d.ts +2 -0
- package/dist/cli/commands/start.js +56 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +2 -0
- package/dist/cli/commands/status.js +60 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +2 -0
- package/dist/cli/commands/stop.js +34 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/ipc-helper.d.ts +2 -0
- package/dist/cli/ipc-helper.js +25 -0
- package/dist/cli/ipc-helper.js.map +1 -0
- package/dist/code/analyzer.d.ts +12 -0
- package/dist/code/analyzer.js +58 -0
- package/dist/code/analyzer.js.map +1 -0
- package/dist/code/fingerprint.d.ts +2 -0
- package/dist/code/fingerprint.js +84 -0
- package/dist/code/fingerprint.js.map +1 -0
- package/dist/code/matcher.d.ts +9 -0
- package/dist/code/matcher.js +37 -0
- package/dist/code/matcher.js.map +1 -0
- package/dist/code/parsers/generic.d.ts +7 -0
- package/dist/code/parsers/generic.js +22 -0
- package/dist/code/parsers/generic.js.map +1 -0
- package/dist/code/parsers/python.d.ts +7 -0
- package/dist/code/parsers/python.js +45 -0
- package/dist/code/parsers/python.js.map +1 -0
- package/dist/code/parsers/typescript.d.ts +7 -0
- package/dist/code/parsers/typescript.js +58 -0
- package/dist/code/parsers/typescript.js.map +1 -0
- package/dist/code/registry.d.ts +22 -0
- package/dist/code/registry.js +31 -0
- package/dist/code/registry.js.map +1 -0
- package/dist/code/scorer.d.ts +15 -0
- package/dist/code/scorer.js +103 -0
- package/dist/code/scorer.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +110 -0
- package/dist/config.js.map +1 -0
- package/dist/db/connection.d.ts +2 -0
- package/dist/db/connection.js +19 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrations/001_core_schema.d.ts +2 -0
- package/dist/db/migrations/001_core_schema.js +119 -0
- package/dist/db/migrations/001_core_schema.js.map +1 -0
- package/dist/db/migrations/002_learning_schema.d.ts +2 -0
- package/dist/db/migrations/002_learning_schema.js +37 -0
- package/dist/db/migrations/002_learning_schema.js.map +1 -0
- package/dist/db/migrations/003_code_schema.d.ts +2 -0
- package/dist/db/migrations/003_code_schema.js +52 -0
- package/dist/db/migrations/003_code_schema.js.map +1 -0
- package/dist/db/migrations/004_synapses_schema.d.ts +2 -0
- package/dist/db/migrations/004_synapses_schema.js +56 -0
- package/dist/db/migrations/004_synapses_schema.js.map +1 -0
- package/dist/db/migrations/005_fts_indexes.d.ts +2 -0
- package/dist/db/migrations/005_fts_indexes.js +77 -0
- package/dist/db/migrations/005_fts_indexes.js.map +1 -0
- package/dist/db/migrations/006_synapses_phase3.d.ts +2 -0
- package/dist/db/migrations/006_synapses_phase3.js +14 -0
- package/dist/db/migrations/006_synapses_phase3.js.map +1 -0
- package/dist/db/migrations/index.d.ts +2 -0
- package/dist/db/migrations/index.js +49 -0
- package/dist/db/migrations/index.js.map +1 -0
- package/dist/db/repositories/antipattern.repository.d.ts +26 -0
- package/dist/db/repositories/antipattern.repository.js +44 -0
- package/dist/db/repositories/antipattern.repository.js.map +1 -0
- package/dist/db/repositories/code-module.repository.d.ts +19 -0
- package/dist/db/repositories/code-module.repository.js +64 -0
- package/dist/db/repositories/code-module.repository.js.map +1 -0
- package/dist/db/repositories/error.repository.d.ts +20 -0
- package/dist/db/repositories/error.repository.js +134 -0
- package/dist/db/repositories/error.repository.js.map +1 -0
- package/dist/db/repositories/insight.repository.d.ts +18 -0
- package/dist/db/repositories/insight.repository.js +57 -0
- package/dist/db/repositories/insight.repository.js.map +1 -0
- package/dist/db/repositories/notification.repository.d.ts +24 -0
- package/dist/db/repositories/notification.repository.js +40 -0
- package/dist/db/repositories/notification.repository.js.map +1 -0
- package/dist/db/repositories/project.repository.d.ts +25 -0
- package/dist/db/repositories/project.repository.js +72 -0
- package/dist/db/repositories/project.repository.js.map +1 -0
- package/dist/db/repositories/rule.repository.d.ts +31 -0
- package/dist/db/repositories/rule.repository.js +81 -0
- package/dist/db/repositories/rule.repository.js.map +1 -0
- package/dist/db/repositories/solution.repository.d.ts +27 -0
- package/dist/db/repositories/solution.repository.js +132 -0
- package/dist/db/repositories/solution.repository.js.map +1 -0
- package/dist/db/repositories/synapse.repository.d.ts +25 -0
- package/dist/db/repositories/synapse.repository.js +115 -0
- package/dist/db/repositories/synapse.repository.js.map +1 -0
- package/dist/db/repositories/terminal.repository.d.ts +27 -0
- package/dist/db/repositories/terminal.repository.js +78 -0
- package/dist/db/repositories/terminal.repository.js.map +1 -0
- package/dist/hooks/post-tool-use.d.ts +2 -0
- package/dist/hooks/post-tool-use.js +77 -0
- package/dist/hooks/post-tool-use.js.map +1 -0
- package/dist/hooks/post-write.d.ts +2 -0
- package/dist/hooks/post-write.js +102 -0
- package/dist/hooks/post-write.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc/client.d.ts +16 -0
- package/dist/ipc/client.js +101 -0
- package/dist/ipc/client.js.map +1 -0
- package/dist/ipc/protocol.d.ts +8 -0
- package/dist/ipc/protocol.js +29 -0
- package/dist/ipc/protocol.js.map +1 -0
- package/dist/ipc/router.d.ts +28 -0
- package/dist/ipc/router.js +70 -0
- package/dist/ipc/router.js.map +1 -0
- package/dist/ipc/server.d.ts +14 -0
- package/dist/ipc/server.js +98 -0
- package/dist/ipc/server.js.map +1 -0
- package/dist/learning/confidence-scorer.d.ts +13 -0
- package/dist/learning/confidence-scorer.js +35 -0
- package/dist/learning/confidence-scorer.js.map +1 -0
- package/dist/learning/decay.d.ts +13 -0
- package/dist/learning/decay.js +37 -0
- package/dist/learning/decay.js.map +1 -0
- package/dist/learning/learning-engine.d.ts +30 -0
- package/dist/learning/learning-engine.js +121 -0
- package/dist/learning/learning-engine.js.map +1 -0
- package/dist/learning/pattern-extractor.d.ts +16 -0
- package/dist/learning/pattern-extractor.js +61 -0
- package/dist/learning/pattern-extractor.js.map +1 -0
- package/dist/learning/rule-generator.d.ts +18 -0
- package/dist/learning/rule-generator.js +50 -0
- package/dist/learning/rule-generator.js.map +1 -0
- package/dist/matching/error-matcher.d.ts +13 -0
- package/dist/matching/error-matcher.js +84 -0
- package/dist/matching/error-matcher.js.map +1 -0
- package/dist/matching/fingerprint.d.ts +3 -0
- package/dist/matching/fingerprint.js +23 -0
- package/dist/matching/fingerprint.js.map +1 -0
- package/dist/matching/similarity.d.ts +3 -0
- package/dist/matching/similarity.js +53 -0
- package/dist/matching/similarity.js.map +1 -0
- package/dist/matching/tfidf.d.ts +15 -0
- package/dist/matching/tfidf.js +68 -0
- package/dist/matching/tfidf.js.map +1 -0
- package/dist/matching/tokenizer.d.ts +4 -0
- package/dist/matching/tokenizer.js +36 -0
- package/dist/matching/tokenizer.js.map +1 -0
- package/dist/mcp/auto-detect.d.ts +1 -0
- package/dist/mcp/auto-detect.js +81 -0
- package/dist/mcp/auto-detect.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +68 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +3 -0
- package/dist/mcp/tools.js +201 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/parsing/error-parser.d.ts +3 -0
- package/dist/parsing/error-parser.js +26 -0
- package/dist/parsing/error-parser.js.map +1 -0
- package/dist/parsing/parsers/compiler.d.ts +2 -0
- package/dist/parsing/parsers/compiler.js +83 -0
- package/dist/parsing/parsers/compiler.js.map +1 -0
- package/dist/parsing/parsers/generic.d.ts +2 -0
- package/dist/parsing/parsers/generic.js +23 -0
- package/dist/parsing/parsers/generic.js.map +1 -0
- package/dist/parsing/parsers/go.d.ts +2 -0
- package/dist/parsing/parsers/go.js +85 -0
- package/dist/parsing/parsers/go.js.map +1 -0
- package/dist/parsing/parsers/node.d.ts +2 -0
- package/dist/parsing/parsers/node.js +61 -0
- package/dist/parsing/parsers/node.js.map +1 -0
- package/dist/parsing/parsers/python.d.ts +2 -0
- package/dist/parsing/parsers/python.js +50 -0
- package/dist/parsing/parsers/python.js.map +1 -0
- package/dist/parsing/parsers/rust.d.ts +2 -0
- package/dist/parsing/parsers/rust.js +43 -0
- package/dist/parsing/parsers/rust.js.map +1 -0
- package/dist/parsing/parsers/shell.d.ts +2 -0
- package/dist/parsing/parsers/shell.js +36 -0
- package/dist/parsing/parsers/shell.js.map +1 -0
- package/dist/parsing/types.d.ts +28 -0
- package/dist/parsing/types.js +21 -0
- package/dist/parsing/types.js.map +1 -0
- package/dist/research/gap-analyzer.d.ts +23 -0
- package/dist/research/gap-analyzer.js +119 -0
- package/dist/research/gap-analyzer.js.map +1 -0
- package/dist/research/insight-generator.d.ts +23 -0
- package/dist/research/insight-generator.js +107 -0
- package/dist/research/insight-generator.js.map +1 -0
- package/dist/research/research-engine.d.ts +31 -0
- package/dist/research/research-engine.js +97 -0
- package/dist/research/research-engine.js.map +1 -0
- package/dist/research/synergy-detector.d.ts +24 -0
- package/dist/research/synergy-detector.js +109 -0
- package/dist/research/synergy-detector.js.map +1 -0
- package/dist/research/template-extractor.d.ts +18 -0
- package/dist/research/template-extractor.js +116 -0
- package/dist/research/template-extractor.js.map +1 -0
- package/dist/research/trend-analyzer.d.ts +20 -0
- package/dist/research/trend-analyzer.js +111 -0
- package/dist/research/trend-analyzer.js.map +1 -0
- package/dist/services/analytics.service.d.ts +52 -0
- package/dist/services/analytics.service.js +59 -0
- package/dist/services/analytics.service.js.map +1 -0
- package/dist/services/code.service.d.ts +39 -0
- package/dist/services/code.service.js +98 -0
- package/dist/services/code.service.js.map +1 -0
- package/dist/services/error.service.d.ts +35 -0
- package/dist/services/error.service.js +118 -0
- package/dist/services/error.service.js.map +1 -0
- package/dist/services/notification.service.d.ts +17 -0
- package/dist/services/notification.service.js +29 -0
- package/dist/services/notification.service.js.map +1 -0
- package/dist/services/prevention.service.d.ts +35 -0
- package/dist/services/prevention.service.js +82 -0
- package/dist/services/prevention.service.js.map +1 -0
- package/dist/services/research.service.d.ts +35 -0
- package/dist/services/research.service.js +60 -0
- package/dist/services/research.service.js.map +1 -0
- package/dist/services/solution.service.d.ts +30 -0
- package/dist/services/solution.service.js +73 -0
- package/dist/services/solution.service.js.map +1 -0
- package/dist/services/synapse.service.d.ts +30 -0
- package/dist/services/synapse.service.js +25 -0
- package/dist/services/synapse.service.js.map +1 -0
- package/dist/services/terminal.service.d.ts +20 -0
- package/dist/services/terminal.service.js +66 -0
- package/dist/services/terminal.service.js.map +1 -0
- package/dist/synapses/activation.d.ts +13 -0
- package/dist/synapses/activation.js +50 -0
- package/dist/synapses/activation.js.map +1 -0
- package/dist/synapses/decay.d.ts +11 -0
- package/dist/synapses/decay.js +27 -0
- package/dist/synapses/decay.js.map +1 -0
- package/dist/synapses/hebbian.d.ts +13 -0
- package/dist/synapses/hebbian.js +36 -0
- package/dist/synapses/hebbian.js.map +1 -0
- package/dist/synapses/pathfinder.d.ts +14 -0
- package/dist/synapses/pathfinder.js +50 -0
- package/dist/synapses/pathfinder.js.map +1 -0
- package/dist/synapses/synapse-manager.d.ts +30 -0
- package/dist/synapses/synapse-manager.js +72 -0
- package/dist/synapses/synapse-manager.js.map +1 -0
- package/dist/types/code.types.d.ts +47 -0
- package/dist/types/code.types.js +2 -0
- package/dist/types/code.types.js.map +1 -0
- package/dist/types/config.types.d.ts +70 -0
- package/dist/types/config.types.js +2 -0
- package/dist/types/config.types.js.map +1 -0
- package/dist/types/error.types.d.ts +60 -0
- package/dist/types/error.types.js +2 -0
- package/dist/types/error.types.js.map +1 -0
- package/dist/types/ipc.types.d.ts +11 -0
- package/dist/types/ipc.types.js +2 -0
- package/dist/types/ipc.types.js.map +1 -0
- package/dist/types/mcp.types.d.ts +46 -0
- package/dist/types/mcp.types.js +2 -0
- package/dist/types/mcp.types.js.map +1 -0
- package/dist/types/research.types.d.ts +25 -0
- package/dist/types/research.types.js +2 -0
- package/dist/types/research.types.js.map +1 -0
- package/dist/types/solution.types.d.ts +28 -0
- package/dist/types/solution.types.js +2 -0
- package/dist/types/solution.types.js.map +1 -0
- package/dist/types/synapse.types.d.ts +37 -0
- package/dist/types/synapse.types.js +2 -0
- package/dist/types/synapse.types.js.map +1 -0
- package/dist/utils/events.d.ts +59 -0
- package/dist/utils/events.js +23 -0
- package/dist/utils/events.js.map +1 -0
- package/dist/utils/hash.d.ts +1 -0
- package/dist/utils/hash.js +5 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.js +39 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +3 -0
- package/dist/utils/paths.js +18 -0
- package/dist/utils/paths.js.map +1 -0
- package/package.json +43 -0
- package/src/brain.ts +220 -0
- package/src/cli/commands/dashboard.ts +495 -0
- package/src/cli/commands/export.ts +27 -0
- package/src/cli/commands/import.ts +190 -0
- package/src/cli/commands/insights.ts +33 -0
- package/src/cli/commands/modules.ts +30 -0
- package/src/cli/commands/network.ts +61 -0
- package/src/cli/commands/query.ts +43 -0
- package/src/cli/commands/start.ts +59 -0
- package/src/cli/commands/status.ts +69 -0
- package/src/cli/commands/stop.ts +33 -0
- package/src/cli/ipc-helper.ts +21 -0
- package/src/code/analyzer.ts +77 -0
- package/src/code/fingerprint.ts +87 -0
- package/src/code/matcher.ts +64 -0
- package/src/code/parsers/generic.ts +29 -0
- package/src/code/parsers/python.ts +54 -0
- package/src/code/parsers/typescript.ts +65 -0
- package/src/code/registry.ts +60 -0
- package/src/code/scorer.ts +108 -0
- package/src/config.ts +111 -0
- package/src/db/connection.ts +22 -0
- package/src/db/migrations/001_core_schema.ts +120 -0
- package/src/db/migrations/002_learning_schema.ts +38 -0
- package/src/db/migrations/003_code_schema.ts +53 -0
- package/src/db/migrations/004_synapses_schema.ts +57 -0
- package/src/db/migrations/005_fts_indexes.ts +78 -0
- package/src/db/migrations/006_synapses_phase3.ts +17 -0
- package/src/db/migrations/index.ts +64 -0
- package/src/db/repositories/antipattern.repository.ts +66 -0
- package/src/db/repositories/code-module.repository.ts +80 -0
- package/src/db/repositories/error.repository.ts +149 -0
- package/src/db/repositories/insight.repository.ts +78 -0
- package/src/db/repositories/notification.repository.ts +66 -0
- package/src/db/repositories/project.repository.ts +93 -0
- package/src/db/repositories/rule.repository.ts +108 -0
- package/src/db/repositories/solution.repository.ts +154 -0
- package/src/db/repositories/synapse.repository.ts +153 -0
- package/src/db/repositories/terminal.repository.ts +101 -0
- package/src/hooks/post-tool-use.ts +90 -0
- package/src/hooks/post-write.ts +117 -0
- package/src/index.ts +53 -0
- package/src/ipc/client.ts +118 -0
- package/src/ipc/protocol.ts +35 -0
- package/src/ipc/router.ts +106 -0
- package/src/ipc/server.ts +110 -0
- package/src/learning/confidence-scorer.ts +47 -0
- package/src/learning/decay.ts +46 -0
- package/src/learning/learning-engine.ts +162 -0
- package/src/learning/pattern-extractor.ts +90 -0
- package/src/learning/rule-generator.ts +74 -0
- package/src/main.rs:10:5 +0 -0
- package/src/matching/error-matcher.ts +115 -0
- package/src/matching/fingerprint.ts +29 -0
- package/src/matching/similarity.ts +61 -0
- package/src/matching/tfidf.ts +74 -0
- package/src/matching/tokenizer.ts +41 -0
- package/src/mcp/auto-detect.ts +93 -0
- package/src/mcp/server.ts +73 -0
- package/src/mcp/tools.ts +290 -0
- package/src/parsing/error-parser.ts +28 -0
- package/src/parsing/parsers/compiler.ts +93 -0
- package/src/parsing/parsers/generic.ts +28 -0
- package/src/parsing/parsers/go.ts +97 -0
- package/src/parsing/parsers/node.ts +69 -0
- package/src/parsing/parsers/python.ts +62 -0
- package/src/parsing/parsers/rust.ts +50 -0
- package/src/parsing/parsers/shell.ts +42 -0
- package/src/parsing/types.ts +47 -0
- package/src/research/gap-analyzer.ts +135 -0
- package/src/research/insight-generator.ts +123 -0
- package/src/research/research-engine.ts +116 -0
- package/src/research/synergy-detector.ts +126 -0
- package/src/research/template-extractor.ts +130 -0
- package/src/research/trend-analyzer.ts +127 -0
- package/src/services/analytics.service.ts +87 -0
- package/src/services/code.service.ts +140 -0
- package/src/services/error.service.ts +164 -0
- package/src/services/notification.service.ts +41 -0
- package/src/services/prevention.service.ts +119 -0
- package/src/services/research.service.ts +93 -0
- package/src/services/solution.service.ts +116 -0
- package/src/services/synapse.service.ts +59 -0
- package/src/services/terminal.service.ts +81 -0
- package/src/synapses/activation.ts +80 -0
- package/src/synapses/decay.ts +38 -0
- package/src/synapses/hebbian.ts +69 -0
- package/src/synapses/pathfinder.ts +81 -0
- package/src/synapses/synapse-manager.ts +109 -0
- package/src/types/code.types.ts +52 -0
- package/src/types/config.types.ts +79 -0
- package/src/types/error.types.ts +67 -0
- package/src/types/ipc.types.ts +8 -0
- package/src/types/mcp.types.ts +53 -0
- package/src/types/research.types.ts +28 -0
- package/src/types/solution.types.ts +30 -0
- package/src/types/synapse.types.ts +49 -0
- package/src/utils/events.ts +45 -0
- package/src/utils/hash.ts +5 -0
- package/src/utils/logger.ts +48 -0
- package/src/utils/paths.ts +19 -0
- package/tests/fixtures/code-modules/modules.ts +83 -0
- package/tests/fixtures/errors/go.ts +9 -0
- package/tests/fixtures/errors/node.ts +24 -0
- package/tests/fixtures/errors/python.ts +21 -0
- package/tests/fixtures/errors/rust.ts +25 -0
- package/tests/fixtures/errors/shell.ts +15 -0
- package/tests/fixtures/solutions/solutions.ts +27 -0
- package/tests/helpers/setup-db.ts +52 -0
- package/tests/integration/code-flow.test.ts +86 -0
- package/tests/integration/error-flow.test.ts +83 -0
- package/tests/integration/ipc-flow.test.ts +166 -0
- package/tests/integration/learning-cycle.test.ts +82 -0
- package/tests/integration/synapse-flow.test.ts +117 -0
- package/tests/unit/code/analyzer.test.ts +58 -0
- package/tests/unit/code/fingerprint.test.ts +51 -0
- package/tests/unit/code/scorer.test.ts +55 -0
- package/tests/unit/learning/confidence-scorer.test.ts +60 -0
- package/tests/unit/learning/decay.test.ts +45 -0
- package/tests/unit/learning/pattern-extractor.test.ts +50 -0
- package/tests/unit/matching/error-matcher.test.ts +69 -0
- package/tests/unit/matching/fingerprint.test.ts +47 -0
- package/tests/unit/matching/similarity.test.ts +65 -0
- package/tests/unit/matching/tfidf.test.ts +71 -0
- package/tests/unit/matching/tokenizer.test.ts +83 -0
- package/tests/unit/parsing/parsers.test.ts +113 -0
- package/tests/unit/research/gap-analyzer.test.ts +45 -0
- package/tests/unit/research/trend-analyzer.test.ts +45 -0
- package/tests/unit/synapses/activation.test.ts +80 -0
- package/tests/unit/synapses/decay.test.ts +27 -0
- package/tests/unit/synapses/hebbian.test.ts +96 -0
- package/tests/unit/synapses/pathfinder.test.ts +72 -0
- package/tsconfig.json +18 -0
package/BRAIN_PLAN.md
ADDED
|
@@ -0,0 +1,3324 @@
|
|
|
1
|
+
# Brain - Lernfähiges Wissens-System für Multi-Terminal Claude
|
|
2
|
+
|
|
3
|
+
## Vision
|
|
4
|
+
|
|
5
|
+
Brain ist ein intelligentes Speicher-System das als Daemon-Prozess läuft und mehrere Claude-Terminal-Sessions verbindet. Es besteht aus vier Systemen:
|
|
6
|
+
|
|
7
|
+
1. **Error Brain** - Erfasst automatisch Fehler, speichert Lösungen, lernt Muster und warnt Terminals bevor sie bekannte Fehler wiederholen.
|
|
8
|
+
2. **Code Brain** - Modulare Code-Bibliothek die projektübergreifend wiederverwendbaren Code trackt, ähnlichen Code erkennt und bei neuen Projekten passende Module vorschlägt.
|
|
9
|
+
3. **Synapsen-Netzwerk** - Verbindet ALLES miteinander: Errors, Solutions, Code-Module, Patterns, Projekte. Jede Synapse hat ein Gewicht das stärker wird je öfter die Verbindung bestätigt wird - wie echte Neuronen. Oft benutzte Pfade werden stärker, unbenutzte verblassen.
|
|
10
|
+
4. **Research Brain** - Meta-Learning Layer der über allen Daten und Synapsen sitzt. Analysiert das Gesamtnetzwerk, erkennt höhere Muster, schlägt Verbesserungen und neue Projekt-Ideen vor. Forscht autonom in den gesammelten Daten.
|
|
11
|
+
|
|
12
|
+
Das Synapsen-Netzwerk ist das Bindegewebe: Error Brain und Code Brain speichern Wissen, Synapsen verbinden es, und das Research Brain zieht Schlüsse daraus.
|
|
13
|
+
|
|
14
|
+
## Architektur-Übersicht
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
18
|
+
│ Claude Sessions │
|
|
19
|
+
│ │
|
|
20
|
+
│ Terminal 1 Terminal 2 Terminal 3 Terminal 4│
|
|
21
|
+
│ (Projekt A) (Projekt B) (Projekt C) (Proj D) │
|
|
22
|
+
│ │ │ │ │ │
|
|
23
|
+
│ │ ┌──────────┐ │ ┌──────────┐ │ ┌──────────┐ │ │
|
|
24
|
+
│ ├──┤MCP Server├ ├──┤MCP Server├ ├──┤MCP Server├ │ │
|
|
25
|
+
│ │ │ (stdio) │ │ │ (stdio) │ │ │ (stdio) │ │ │
|
|
26
|
+
│ │ └────┬─────┘ │ └────┬─────┘ │ └────┬─────┘ │ │
|
|
27
|
+
│ │ │ │ │ │ │ │ │
|
|
28
|
+
│ ┌───┴──┐ │ ┌───┴──┐ │ ┌───┴──┐ │ ┌───┴──┐ │
|
|
29
|
+
│ │Hooks │ │ │Hooks │ │ │Hooks │ │ │Hooks │ │
|
|
30
|
+
│ │(auto)│ │ │(auto)│ │ │(auto)│ │ │(auto)│ │
|
|
31
|
+
│ └───┬──┘ │ └───┬──┘ │ └───┬──┘ │ └───┬──┘ │
|
|
32
|
+
└──────┼───────┼─────────┼───────┼─────────┼───────┼─────────┼────┘
|
|
33
|
+
│ │ │ │ │ │ │
|
|
34
|
+
└───────┴─────────┴───────┴─────────┴───────┴─────────┘
|
|
35
|
+
│
|
|
36
|
+
┌─────────┴─────────┐
|
|
37
|
+
│ Named Pipe IPC │
|
|
38
|
+
│ \\.\pipe\brain-ipc │
|
|
39
|
+
└─────────┬─────────┘
|
|
40
|
+
│
|
|
41
|
+
┌──────────────┴──────────────┐
|
|
42
|
+
│ Brain Daemon │
|
|
43
|
+
│ │
|
|
44
|
+
│ ┌────────────────────────┐ │
|
|
45
|
+
│ │ BrainCore │ │
|
|
46
|
+
│ │ (Orchestrierung) │ │
|
|
47
|
+
│ └──────────┬─────────────┘ │
|
|
48
|
+
│ │ │
|
|
49
|
+
│ ┌──────────┴─────────────┐ │
|
|
50
|
+
│ │ Services │ │
|
|
51
|
+
│ │ error, solution, │ │
|
|
52
|
+
│ │ code, prevention, │ │
|
|
53
|
+
│ │ synapse, terminal │ │
|
|
54
|
+
│ └──────────┬─────────────┘ │
|
|
55
|
+
│ │ │
|
|
56
|
+
│ ┌──────────┼─────────────┐ │
|
|
57
|
+
│ │ │ │ │
|
|
58
|
+
│ │ ┌───────┴────────┐ │ │
|
|
59
|
+
│ │ │Learning Engine │ │ │
|
|
60
|
+
│ │ │(15 min cycles) │ │ │
|
|
61
|
+
│ │ └───────┬────────┘ │ │
|
|
62
|
+
│ │ │ │ │
|
|
63
|
+
│ │ ┌───────┴────────┐ │ │
|
|
64
|
+
│ │ │Research Engine │ │ │
|
|
65
|
+
│ │ │ (60 min cycles)│ │ │
|
|
66
|
+
│ │ └───────┬────────┘ │ │
|
|
67
|
+
│ │ │ │ │
|
|
68
|
+
│ └──────────┼─────────────┘ │
|
|
69
|
+
│ │ │
|
|
70
|
+
│ ┌──────────┴─────────────┐ │
|
|
71
|
+
│ │ ┌──────────────────┐ │ │
|
|
72
|
+
│ │ │ Synapse Network │ │ │
|
|
73
|
+
│ │ │ (gewichteter │ │ │
|
|
74
|
+
│ │ │ Knowledge Graph)│ │ │
|
|
75
|
+
│ │ └────────┬─────────┘ │ │
|
|
76
|
+
│ │ │ │ │
|
|
77
|
+
│ │ ┌────────┴─────────┐ │ │
|
|
78
|
+
│ │ │ SQLite+WAL+FTS5 │ │ │
|
|
79
|
+
│ │ │ brain.db │ │ │
|
|
80
|
+
│ │ └─────────────────┘ │ │
|
|
81
|
+
│ └────────────────────────┘ │
|
|
82
|
+
└──────────────────────────────┘
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Integrations-Strategie
|
|
86
|
+
|
|
87
|
+
**MCP Server** (pro Claude-Session, stdio): Claude kann Brain-Tools direkt aufrufen - Fehler melden, Lösungen suchen, Code-Module finden. Der MCP Server ist ein Thin Client der via Named Pipe mit dem Daemon kommuniziert.
|
|
88
|
+
|
|
89
|
+
**Claude Code Hooks** (automatisch, unsichtbar): PostToolUse-Hook auf Bash erkennt Fehler automatisch aus der Tool-Ausgabe (Exit-Code != 0, Stack-Traces, Error-Patterns) und sendet sie an den Daemon. Der User muss nichts manuell melden.
|
|
90
|
+
|
|
91
|
+
**CLAUDE.md Integration**: Jedes Projekt bekommt Instruktionen die Claude anweisen, bei Fehlern Brain zu konsultieren und bei erfolgreich gelösten Fehlern die Lösung zu melden.
|
|
92
|
+
|
|
93
|
+
## Technologie-Stack
|
|
94
|
+
|
|
95
|
+
- **TypeScript** mit Node.js v20+
|
|
96
|
+
- **better-sqlite3** (synchron, 2-10x schneller als async sqlite3, WAL-Modus für concurrent reads)
|
|
97
|
+
- **Named Pipes** (Windows `\\.\pipe\brain-ipc`) / Unix Sockets (`/tmp/brain.sock`) für IPC
|
|
98
|
+
- **FTS5** für Volltext-Suche in Fehlern, Lösungen und Code-Modulen
|
|
99
|
+
- **@modelcontextprotocol/sdk** für MCP Server
|
|
100
|
+
- **commander** für CLI
|
|
101
|
+
- **vitest** für Tests
|
|
102
|
+
- **winston** für File-Logging
|
|
103
|
+
|
|
104
|
+
## Projektstruktur
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
brain/
|
|
108
|
+
├── package.json
|
|
109
|
+
├── tsconfig.json
|
|
110
|
+
├── .gitignore
|
|
111
|
+
├── src/
|
|
112
|
+
│ ├── index.ts # CLI Einstiegspunkt (commander)
|
|
113
|
+
│ ├── brain.ts # BrainCore - zentrale Orchestrierung
|
|
114
|
+
│ ├── config.ts # Konfiguration mit Defaults
|
|
115
|
+
│ │
|
|
116
|
+
│ ├── db/
|
|
117
|
+
│ │ ├── connection.ts # SQLite Verbindung (WAL, Pragmas)
|
|
118
|
+
│ │ ├── migrations/
|
|
119
|
+
│ │ │ ├── 001_core_schema.ts # projects, terminals, errors, solutions
|
|
120
|
+
│ │ │ ├── 002_learning_schema.ts # rules, error_chains, antipatterns
|
|
121
|
+
│ │ │ ├── 003_code_schema.ts # code_modules, module_usages, module_similarities
|
|
122
|
+
│ │ │ ├── 004_synapses_schema.ts # synapses, insights
|
|
123
|
+
│ │ │ ├── 005_fts_indexes.ts # FTS5 Tabellen + Sync-Trigger
|
|
124
|
+
│ │ │ └── index.ts # Migration-Runner
|
|
125
|
+
│ │ └── repositories/
|
|
126
|
+
│ │ ├── error.repository.ts # Jedes Repo compiled eigene Prepared Statements
|
|
127
|
+
│ │ ├── solution.repository.ts
|
|
128
|
+
│ │ ├── rule.repository.ts
|
|
129
|
+
│ │ ├── terminal.repository.ts
|
|
130
|
+
│ │ ├── project.repository.ts
|
|
131
|
+
│ │ ├── notification.repository.ts
|
|
132
|
+
│ │ ├── code-module.repository.ts
|
|
133
|
+
│ │ ├── antipattern.repository.ts
|
|
134
|
+
│ │ ├── synapse.repository.ts
|
|
135
|
+
│ │ └── insight.repository.ts
|
|
136
|
+
│ │
|
|
137
|
+
│ ├── matching/
|
|
138
|
+
│ │ ├── similarity.ts # Levenshtein, Cosine, Jaccard
|
|
139
|
+
│ │ ├── error-matcher.ts # Multi-Signal Error Matching Engine
|
|
140
|
+
│ │ ├── fingerprint.ts # Strukturelles Error-Hashing
|
|
141
|
+
│ │ ├── tokenizer.ts # Text-Tokenisierung
|
|
142
|
+
│ │ └── tfidf.ts # TF-IDF Index (inkrementell)
|
|
143
|
+
│ │
|
|
144
|
+
│ ├── parsing/
|
|
145
|
+
│ │ ├── types.ts # Parser-Interfaces
|
|
146
|
+
│ │ ├── error-parser.ts # Registry-basierter Dispatcher
|
|
147
|
+
│ │ └── parsers/
|
|
148
|
+
│ │ ├── node.ts # Node.js/TypeScript Errors
|
|
149
|
+
│ │ ├── python.ts # Python Tracebacks
|
|
150
|
+
│ │ ├── rust.ts # Rust Compiler Errors
|
|
151
|
+
│ │ ├── go.ts # Go Errors
|
|
152
|
+
│ │ ├── shell.ts # Shell/Bash Errors (exit codes, command not found)
|
|
153
|
+
│ │ ├── compiler.ts # Generische Compiler Errors (gcc, javac, etc.)
|
|
154
|
+
│ │ └── generic.ts # Regex-basierter Fallback
|
|
155
|
+
│ │
|
|
156
|
+
│ ├── code/
|
|
157
|
+
│ │ ├── analyzer.ts # Code-Analyse (Exports, Purity, Cohesion)
|
|
158
|
+
│ │ ├── fingerprint.ts # Strukturelles Code-Hashing
|
|
159
|
+
│ │ ├── matcher.ts # Ähnlichen Code finden
|
|
160
|
+
│ │ ├── registry.ts # Module registrieren/verwalten
|
|
161
|
+
│ │ ├── scorer.ts # Reusability-Scoring
|
|
162
|
+
│ │ └── parsers/
|
|
163
|
+
│ │ ├── typescript.ts # TS/JS Export/Import Extraction
|
|
164
|
+
│ │ ├── python.ts # Python def/class/import Extraction
|
|
165
|
+
│ │ └── generic.ts # Regex-basierter Fallback
|
|
166
|
+
│ │
|
|
167
|
+
│ ├── learning/
|
|
168
|
+
│ │ ├── learning-engine.ts # Lern-Zyklus Orchestrierung
|
|
169
|
+
│ │ ├── pattern-extractor.ts # Centroid-basiertes Clustering
|
|
170
|
+
│ │ ├── rule-generator.ts # Regeln aus Mustern generieren
|
|
171
|
+
│ │ ├── confidence-scorer.ts # Wilson Score Intervall
|
|
172
|
+
│ │ └── decay.ts # Zeitbasierte Relevanz
|
|
173
|
+
│ │
|
|
174
|
+
│ ├── synapses/
|
|
175
|
+
│ │ ├── synapse-manager.ts # Synapsen erstellen, stärken, schwächen
|
|
176
|
+
│ │ ├── hebbian.ts # Hebbsches Lernen (fire together → wire together)
|
|
177
|
+
│ │ ├── pathfinder.ts # Multi-Hop-Pfade durch das Netzwerk finden
|
|
178
|
+
│ │ ├── activation.ts # Spreading Activation Algorithmus
|
|
179
|
+
│ │ └── decay.ts # Synaptische Abschwächung bei Nicht-Nutzung
|
|
180
|
+
│ │
|
|
181
|
+
│ ├── research/
|
|
182
|
+
│ │ ├── research-engine.ts # Forschungs-Zyklus Orchestrierung
|
|
183
|
+
│ │ ├── trend-analyzer.ts # Trends erkennen (was wird besser/schlechter)
|
|
184
|
+
│ │ ├── gap-analyzer.ts # Lücken finden (wiederkehrende ungelöste Probleme)
|
|
185
|
+
│ │ ├── synergy-detector.ts # Synergien zwischen Projekten erkennen
|
|
186
|
+
│ │ ├── template-extractor.ts # Wiederholte Patterns zu Templates generalisieren
|
|
187
|
+
│ │ └── insight-generator.ts # Insights generieren und priorisieren
|
|
188
|
+
│ │
|
|
189
|
+
│ ├── ipc/
|
|
190
|
+
│ │ ├── server.ts # Named Pipe IPC Server
|
|
191
|
+
│ │ ├── client.ts # Client für MCP Server → Daemon
|
|
192
|
+
│ │ ├── protocol.ts # Length-prefixed JSON Framing
|
|
193
|
+
│ │ └── router.ts # Methoden-Routing
|
|
194
|
+
│ │
|
|
195
|
+
│ ├── mcp/
|
|
196
|
+
│ │ ├── server.ts # MCP Server Entry (stdio Transport)
|
|
197
|
+
│ │ ├── tools.ts # Tool-Definitionen für Claude
|
|
198
|
+
│ │ └── auto-detect.ts # Error-Pattern-Erkennung aus Output
|
|
199
|
+
│ │
|
|
200
|
+
│ ├── services/
|
|
201
|
+
│ │ ├── error.service.ts
|
|
202
|
+
│ │ ├── solution.service.ts
|
|
203
|
+
│ │ ├── terminal.service.ts
|
|
204
|
+
│ │ ├── prevention.service.ts
|
|
205
|
+
│ │ ├── code.service.ts
|
|
206
|
+
│ │ ├── synapse.service.ts
|
|
207
|
+
│ │ ├── research.service.ts
|
|
208
|
+
│ │ ├── notification.service.ts
|
|
209
|
+
│ │ └── analytics.service.ts
|
|
210
|
+
│ │
|
|
211
|
+
│ ├── cli/
|
|
212
|
+
│ │ └── commands/
|
|
213
|
+
│ │ ├── start.ts # brain start - Daemon starten
|
|
214
|
+
│ │ ├── stop.ts # brain stop - Daemon stoppen
|
|
215
|
+
│ │ ├── status.ts # brain status - Textbasierter Status
|
|
216
|
+
│ │ ├── query.ts # brain query "error" - Fehler suchen
|
|
217
|
+
│ │ ├── modules.ts # brain modules - Code-Module auflisten
|
|
218
|
+
│ │ └── export.ts # brain export - Daten exportieren
|
|
219
|
+
│ │
|
|
220
|
+
│ ├── hooks/
|
|
221
|
+
│ │ ├── post-tool-use.ts # Hook-Script für automatische Error-Erkennung
|
|
222
|
+
│ │ └── post-write.ts # Hook-Script für automatische Code-Analyse
|
|
223
|
+
│ │
|
|
224
|
+
│ ├── types/
|
|
225
|
+
│ │ ├── error.types.ts
|
|
226
|
+
│ │ ├── solution.types.ts
|
|
227
|
+
│ │ ├── code.types.ts
|
|
228
|
+
│ │ ├── ipc.types.ts
|
|
229
|
+
│ │ ├── mcp.types.ts
|
|
230
|
+
│ │ └── config.types.ts
|
|
231
|
+
│ │
|
|
232
|
+
│ └── utils/
|
|
233
|
+
│ ├── logger.ts # Winston File-Logger
|
|
234
|
+
│ ├── hash.ts # SHA-256 Hashing
|
|
235
|
+
│ ├── paths.ts # Pfad-Normalisierung
|
|
236
|
+
│ └── events.ts # Typisierter EventBus
|
|
237
|
+
│
|
|
238
|
+
├── tests/
|
|
239
|
+
│ ├── unit/
|
|
240
|
+
│ │ ├── matching/
|
|
241
|
+
│ │ ├── parsing/
|
|
242
|
+
│ │ ├── code/
|
|
243
|
+
│ │ └── learning/
|
|
244
|
+
│ ├── integration/
|
|
245
|
+
│ │ ├── error-flow.test.ts # Error → Match → Solution → Learn
|
|
246
|
+
│ │ ├── code-flow.test.ts # Code → Analyze → Register → Match
|
|
247
|
+
│ │ └── ipc-flow.test.ts # MCP → IPC → Daemon → Response
|
|
248
|
+
│ └── fixtures/
|
|
249
|
+
│ ├── errors/ # Beispiel-Errors pro Sprache
|
|
250
|
+
│ ├── solutions/
|
|
251
|
+
│ └── code-modules/ # Beispiel-Code für Matching-Tests
|
|
252
|
+
│
|
|
253
|
+
└── data/ # Runtime (gitignored)
|
|
254
|
+
├── brain.db
|
|
255
|
+
└── brain.log
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Datenbank-Schema
|
|
259
|
+
|
|
260
|
+
### projects
|
|
261
|
+
```sql
|
|
262
|
+
CREATE TABLE projects (
|
|
263
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
264
|
+
name TEXT NOT NULL UNIQUE,
|
|
265
|
+
root_path TEXT NOT NULL,
|
|
266
|
+
languages TEXT, -- JSON Array: ["typescript", "python"]
|
|
267
|
+
frameworks TEXT, -- JSON Array: ["express", "react"]
|
|
268
|
+
description TEXT, -- Kurzbeschreibung des Projekts
|
|
269
|
+
error_count INTEGER NOT NULL DEFAULT 0,
|
|
270
|
+
solution_count INTEGER NOT NULL DEFAULT 0,
|
|
271
|
+
module_count INTEGER NOT NULL DEFAULT 0,
|
|
272
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
273
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
274
|
+
);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### terminals
|
|
278
|
+
```sql
|
|
279
|
+
CREATE TABLE terminals (
|
|
280
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
281
|
+
uuid TEXT NOT NULL UNIQUE,
|
|
282
|
+
pid INTEGER,
|
|
283
|
+
project_id INTEGER REFERENCES projects(id),
|
|
284
|
+
status TEXT NOT NULL DEFAULT 'connected'
|
|
285
|
+
CHECK(status IN ('connected', 'disconnected', 'stale')),
|
|
286
|
+
connected_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
287
|
+
last_heartbeat TEXT NOT NULL DEFAULT (datetime('now')),
|
|
288
|
+
metadata TEXT -- JSON: Shell, OS, etc.
|
|
289
|
+
);
|
|
290
|
+
CREATE INDEX idx_terminals_status ON terminals(status);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### errors
|
|
294
|
+
```sql
|
|
295
|
+
CREATE TABLE errors (
|
|
296
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
297
|
+
fingerprint TEXT NOT NULL,
|
|
298
|
+
error_type TEXT NOT NULL, -- "TypeError", "ENOENT", "SyntaxError", etc.
|
|
299
|
+
message TEXT NOT NULL,
|
|
300
|
+
message_template TEXT, -- Templatisierte Version
|
|
301
|
+
stack_trace TEXT,
|
|
302
|
+
source_file TEXT,
|
|
303
|
+
source_line INTEGER,
|
|
304
|
+
|
|
305
|
+
-- Was wir wirklich haben (statt generischem "context" JSON)
|
|
306
|
+
raw_output TEXT, -- Tatsächlicher Terminal-Output
|
|
307
|
+
command TEXT, -- Befehl der den Error auslöste
|
|
308
|
+
working_directory TEXT,
|
|
309
|
+
task_context TEXT, -- Was der User versuchte zu tun
|
|
310
|
+
|
|
311
|
+
-- Auto-Labels statt separater Tag-Tabellen
|
|
312
|
+
labels TEXT, -- JSON Array: ["typescript", "import", "node_modules"]
|
|
313
|
+
|
|
314
|
+
project_id INTEGER REFERENCES projects(id),
|
|
315
|
+
terminal_id INTEGER REFERENCES terminals(id),
|
|
316
|
+
occurrence_count INTEGER NOT NULL DEFAULT 1,
|
|
317
|
+
first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
318
|
+
last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
319
|
+
resolved INTEGER NOT NULL DEFAULT 0
|
|
320
|
+
);
|
|
321
|
+
CREATE INDEX idx_errors_fingerprint ON errors(fingerprint);
|
|
322
|
+
CREATE INDEX idx_errors_type ON errors(error_type);
|
|
323
|
+
CREATE INDEX idx_errors_project ON errors(project_id);
|
|
324
|
+
CREATE INDEX idx_errors_resolved ON errors(resolved);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### stack_frames
|
|
328
|
+
```sql
|
|
329
|
+
CREATE TABLE stack_frames (
|
|
330
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
331
|
+
error_id INTEGER NOT NULL REFERENCES errors(id) ON DELETE CASCADE,
|
|
332
|
+
position INTEGER NOT NULL,
|
|
333
|
+
function_name TEXT,
|
|
334
|
+
file_path TEXT,
|
|
335
|
+
line_number INTEGER,
|
|
336
|
+
column_number INTEGER,
|
|
337
|
+
normalized TEXT -- Pfad/Zeile normalisiert für Matching
|
|
338
|
+
);
|
|
339
|
+
CREATE INDEX idx_stack_frames_error ON stack_frames(error_id);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### solutions
|
|
343
|
+
```sql
|
|
344
|
+
CREATE TABLE solutions (
|
|
345
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
346
|
+
title TEXT NOT NULL,
|
|
347
|
+
description TEXT,
|
|
348
|
+
labels TEXT, -- JSON Array: ["config", "tsconfig", "path-mapping"]
|
|
349
|
+
steps TEXT, -- JSON Array von Schritten
|
|
350
|
+
code_before TEXT,
|
|
351
|
+
code_after TEXT,
|
|
352
|
+
diff TEXT,
|
|
353
|
+
confidence_score REAL NOT NULL DEFAULT 0.0,
|
|
354
|
+
success_count INTEGER NOT NULL DEFAULT 0,
|
|
355
|
+
failure_count INTEGER NOT NULL DEFAULT 0,
|
|
356
|
+
project_id INTEGER REFERENCES projects(id),
|
|
357
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
358
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
359
|
+
);
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### error_solutions
|
|
363
|
+
```sql
|
|
364
|
+
CREATE TABLE error_solutions (
|
|
365
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
366
|
+
error_id INTEGER NOT NULL REFERENCES errors(id) ON DELETE CASCADE,
|
|
367
|
+
solution_id INTEGER NOT NULL REFERENCES solutions(id) ON DELETE CASCADE,
|
|
368
|
+
outcome TEXT CHECK(outcome IN ('success', 'failure', 'partial', 'pending')),
|
|
369
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
370
|
+
applied_by_terminal INTEGER REFERENCES terminals(id),
|
|
371
|
+
notes TEXT,
|
|
372
|
+
UNIQUE(error_id, solution_id, applied_at)
|
|
373
|
+
);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### solution_attempts (was NICHT funktioniert hat)
|
|
377
|
+
```sql
|
|
378
|
+
CREATE TABLE solution_attempts (
|
|
379
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
380
|
+
error_id INTEGER NOT NULL REFERENCES errors(id) ON DELETE CASCADE,
|
|
381
|
+
description TEXT NOT NULL,
|
|
382
|
+
outcome TEXT NOT NULL CHECK(outcome IN ('failure', 'partial')),
|
|
383
|
+
reason TEXT, -- Warum hat es nicht funktioniert
|
|
384
|
+
attempted_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
385
|
+
terminal_id INTEGER REFERENCES terminals(id)
|
|
386
|
+
);
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### error_chains (Fehler A verursacht Fehler B)
|
|
390
|
+
```sql
|
|
391
|
+
CREATE TABLE error_chains (
|
|
392
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
393
|
+
session_id TEXT NOT NULL, -- Gruppiert Fehler einer Session
|
|
394
|
+
error_id INTEGER NOT NULL REFERENCES errors(id) ON DELETE CASCADE,
|
|
395
|
+
position INTEGER NOT NULL, -- Reihenfolge in der Chain
|
|
396
|
+
time_delta_ms INTEGER, -- Zeit seit vorigem Fehler in der Chain
|
|
397
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
398
|
+
);
|
|
399
|
+
CREATE INDEX idx_error_chains_session ON error_chains(session_id);
|
|
400
|
+
CREATE INDEX idx_error_chains_error ON error_chains(error_id);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### synapses (das neuronale Netzwerk)
|
|
404
|
+
Verbindet ALLES miteinander. Jede Synapse hat ein Gewicht das durch Hebbsches Lernen stärker oder schwächer wird.
|
|
405
|
+
|
|
406
|
+
```sql
|
|
407
|
+
CREATE TABLE synapses (
|
|
408
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
409
|
+
|
|
410
|
+
-- Source-Knoten
|
|
411
|
+
source_type TEXT NOT NULL CHECK(source_type IN (
|
|
412
|
+
'error', 'solution', 'code_module', 'rule', 'antipattern', 'project', 'insight'
|
|
413
|
+
)),
|
|
414
|
+
source_id INTEGER NOT NULL,
|
|
415
|
+
|
|
416
|
+
-- Target-Knoten
|
|
417
|
+
target_type TEXT NOT NULL CHECK(target_type IN (
|
|
418
|
+
'error', 'solution', 'code_module', 'rule', 'antipattern', 'project', 'insight'
|
|
419
|
+
)),
|
|
420
|
+
target_id INTEGER NOT NULL,
|
|
421
|
+
|
|
422
|
+
-- Verbindungs-Typ
|
|
423
|
+
synapse_type TEXT NOT NULL CHECK(synapse_type IN (
|
|
424
|
+
'solves', -- Solution löst Error
|
|
425
|
+
'causes', -- Error verursacht Error
|
|
426
|
+
'similar_to', -- Ähnlichkeit (Error↔Error, Code↔Code)
|
|
427
|
+
'uses_module', -- Solution/Project nutzt Code-Module
|
|
428
|
+
'derived_from', -- Abgeleitet von (Rule aus Error, Insight aus Pattern)
|
|
429
|
+
'co_occurs', -- Tritt gemeinsam auf (zeitliche Korrelation)
|
|
430
|
+
'prevents', -- Rule/Antipattern verhindert Error
|
|
431
|
+
'improves', -- Insight verbessert Projekt/Code
|
|
432
|
+
'generalizes', -- Pattern ist Generalisierung von Einzelfällen
|
|
433
|
+
'cross_project' -- Verbindung zwischen Projekten (gleicher Fehler, gleicher Code)
|
|
434
|
+
)),
|
|
435
|
+
|
|
436
|
+
-- Synaptisches Gewicht (Hebbsches Lernen)
|
|
437
|
+
weight REAL NOT NULL DEFAULT 0.1, -- Startet schwach, wird stärker
|
|
438
|
+
activation_count INTEGER NOT NULL DEFAULT 1, -- Wie oft wurde dieser Pfad benutzt
|
|
439
|
+
last_activated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
440
|
+
|
|
441
|
+
-- Kontext
|
|
442
|
+
context TEXT, -- JSON: Warum diese Verbindung existiert
|
|
443
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
444
|
+
|
|
445
|
+
UNIQUE(source_type, source_id, target_type, target_id, synapse_type)
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
CREATE INDEX idx_synapses_source ON synapses(source_type, source_id);
|
|
449
|
+
CREATE INDEX idx_synapses_target ON synapses(target_type, target_id);
|
|
450
|
+
CREATE INDEX idx_synapses_type ON synapses(synapse_type);
|
|
451
|
+
CREATE INDEX idx_synapses_weight ON synapses(weight DESC);
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### insights (Erkenntnisse des Research Brain)
|
|
455
|
+
```sql
|
|
456
|
+
CREATE TABLE insights (
|
|
457
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
458
|
+
|
|
459
|
+
-- Klassifikation
|
|
460
|
+
insight_type TEXT NOT NULL CHECK(insight_type IN (
|
|
461
|
+
'trend', -- "Error-Rate in Projekt A sinkt seit 2 Wochen"
|
|
462
|
+
'pattern', -- "Du baust in jedem Projekt einen API-Client"
|
|
463
|
+
'gap', -- "Kein Projekt hat ordentliches Error-Handling für X"
|
|
464
|
+
'synergy', -- "Module A + Module B = vollständiges Auth-System"
|
|
465
|
+
'optimization', -- "retry.ts aus Projekt A ist 30% effizienter als Projekt B's Version"
|
|
466
|
+
'template_candidate', -- "Dieser Code-Pattern wiederholt sich - Template erstellen?"
|
|
467
|
+
'project_suggestion', -- "Basierend auf deinen Modulen könntest du X bauen"
|
|
468
|
+
'warning' -- "Dependency X verursacht Fehler in 3 von 4 Projekten"
|
|
469
|
+
)),
|
|
470
|
+
|
|
471
|
+
title TEXT NOT NULL,
|
|
472
|
+
description TEXT NOT NULL,
|
|
473
|
+
evidence TEXT NOT NULL, -- JSON: Welche Daten stützen diesen Insight
|
|
474
|
+
confidence REAL NOT NULL DEFAULT 0.5,
|
|
475
|
+
|
|
476
|
+
-- Aktionierbarkeit
|
|
477
|
+
actionable INTEGER NOT NULL DEFAULT 0, -- Hat dieser Insight eine konkrete Aktion?
|
|
478
|
+
suggested_action TEXT, -- JSON: Was sollte man tun
|
|
479
|
+
action_taken INTEGER NOT NULL DEFAULT 0, -- Wurde darauf reagiert?
|
|
480
|
+
action_outcome TEXT, -- Ergebnis der Aktion
|
|
481
|
+
|
|
482
|
+
-- Relevanz
|
|
483
|
+
affected_project_ids TEXT, -- JSON Array
|
|
484
|
+
priority TEXT NOT NULL DEFAULT 'medium'
|
|
485
|
+
CHECK(priority IN ('low', 'medium', 'high', 'critical')),
|
|
486
|
+
|
|
487
|
+
-- Lifecycle
|
|
488
|
+
status TEXT NOT NULL DEFAULT 'active'
|
|
489
|
+
CHECK(status IN ('active', 'acknowledged', 'acted_upon', 'dismissed', 'expired')),
|
|
490
|
+
expires_at TEXT, -- Manche Insights sind zeitgebunden
|
|
491
|
+
|
|
492
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
493
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
494
|
+
);
|
|
495
|
+
CREATE INDEX idx_insights_type ON insights(insight_type);
|
|
496
|
+
CREATE INDEX idx_insights_status ON insights(status);
|
|
497
|
+
CREATE INDEX idx_insights_priority ON insights(priority);
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### rules
|
|
501
|
+
```sql
|
|
502
|
+
CREATE TABLE rules (
|
|
503
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
504
|
+
name TEXT NOT NULL,
|
|
505
|
+
description TEXT,
|
|
506
|
+
pattern TEXT NOT NULL, -- JSON: Matching-Kriterien
|
|
507
|
+
action TEXT NOT NULL, -- JSON: Was tun wenn Pattern matcht
|
|
508
|
+
rule_type TEXT NOT NULL CHECK(rule_type IN ('prevention', 'suggestion', 'warning', 'auto_fix')),
|
|
509
|
+
confidence REAL NOT NULL DEFAULT 0.0,
|
|
510
|
+
trigger_count INTEGER NOT NULL DEFAULT 0,
|
|
511
|
+
success_count INTEGER NOT NULL DEFAULT 0,
|
|
512
|
+
rejection_count INTEGER NOT NULL DEFAULT 0,
|
|
513
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
514
|
+
source_error_ids TEXT, -- JSON Array
|
|
515
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
516
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
517
|
+
);
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### antipatterns (explizites "Tu das NICHT")
|
|
521
|
+
```sql
|
|
522
|
+
CREATE TABLE antipatterns (
|
|
523
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
524
|
+
description TEXT NOT NULL, -- "Nie X mit Y Config kombinieren"
|
|
525
|
+
trigger_pattern TEXT NOT NULL, -- JSON: Wann warnen
|
|
526
|
+
severity TEXT NOT NULL DEFAULT 'warning'
|
|
527
|
+
CHECK(severity IN ('info', 'warning', 'critical')),
|
|
528
|
+
learned_from_error_ids TEXT, -- JSON Array
|
|
529
|
+
project_id INTEGER REFERENCES projects(id), -- NULL = global
|
|
530
|
+
confidence REAL NOT NULL DEFAULT 0.5,
|
|
531
|
+
trigger_count INTEGER NOT NULL DEFAULT 0,
|
|
532
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
533
|
+
);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### notifications (statt Inter-Terminal-Chat)
|
|
537
|
+
```sql
|
|
538
|
+
CREATE TABLE notifications (
|
|
539
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
540
|
+
target_terminal_id INTEGER REFERENCES terminals(id), -- NULL = alle Terminals
|
|
541
|
+
notification_type TEXT NOT NULL CHECK(notification_type IN (
|
|
542
|
+
'solution_available', -- "Diesen Fehler hatten wir schon, Lösung existiert"
|
|
543
|
+
'error_recurring', -- "Dieser Fehler tritt gerade in Projekt B auch auf"
|
|
544
|
+
'rule_triggered', -- "Prevention-Rule hat angeschlagen"
|
|
545
|
+
'learning_insight', -- "Neues Muster erkannt"
|
|
546
|
+
'module_suggested', -- "Wiederverwendbarer Code verfügbar"
|
|
547
|
+
'antipattern_warning' -- "Bekanntes Anti-Pattern erkannt"
|
|
548
|
+
)),
|
|
549
|
+
reference_type TEXT, -- 'error', 'solution', 'rule', 'code_module', 'antipattern'
|
|
550
|
+
reference_id INTEGER,
|
|
551
|
+
summary TEXT NOT NULL,
|
|
552
|
+
acknowledged INTEGER NOT NULL DEFAULT 0,
|
|
553
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
554
|
+
);
|
|
555
|
+
CREATE INDEX idx_notifications_terminal ON notifications(target_terminal_id);
|
|
556
|
+
CREATE INDEX idx_notifications_ack ON notifications(acknowledged);
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### code_modules
|
|
560
|
+
```sql
|
|
561
|
+
CREATE TABLE code_modules (
|
|
562
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
563
|
+
|
|
564
|
+
-- Identität
|
|
565
|
+
name TEXT NOT NULL, -- "retry", "logger", "AuthMiddleware"
|
|
566
|
+
module_type TEXT NOT NULL CHECK(module_type IN (
|
|
567
|
+
'file', -- Ganze Datei als Modul
|
|
568
|
+
'function', -- Einzelne Funktion
|
|
569
|
+
'class', -- Klasse
|
|
570
|
+
'pattern' -- Architektur-Pattern
|
|
571
|
+
)),
|
|
572
|
+
|
|
573
|
+
-- Herkunft
|
|
574
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
575
|
+
file_path TEXT NOT NULL, -- Relativ zu project root
|
|
576
|
+
start_line INTEGER, -- NULL bei file-level Modulen
|
|
577
|
+
end_line INTEGER,
|
|
578
|
+
|
|
579
|
+
-- Code
|
|
580
|
+
source_code TEXT NOT NULL,
|
|
581
|
+
fingerprint TEXT NOT NULL, -- Struktureller Hash
|
|
582
|
+
language TEXT NOT NULL,
|
|
583
|
+
|
|
584
|
+
-- Klassifikation
|
|
585
|
+
category TEXT, -- "utility", "middleware", "config", "hook", "component", "service"
|
|
586
|
+
purpose TEXT NOT NULL, -- "Retry wrapper with exponential backoff and jitter"
|
|
587
|
+
interface_signature TEXT, -- "retry<T>(fn: () => Promise<T>, opts?: RetryOpts): Promise<T>"
|
|
588
|
+
dependencies TEXT, -- JSON: Externe Packages ["axios", "lodash"]
|
|
589
|
+
internal_imports TEXT, -- JSON: Interne Abhängigkeiten ["./logger", "./types"]
|
|
590
|
+
labels TEXT, -- JSON: Auto-Labels ["async", "error-handling", "http"]
|
|
591
|
+
|
|
592
|
+
-- Qualitätssignale
|
|
593
|
+
reuse_count INTEGER NOT NULL DEFAULT 0,
|
|
594
|
+
adaptation_count INTEGER NOT NULL DEFAULT 0,
|
|
595
|
+
confidence REAL NOT NULL DEFAULT 0.5, -- Wie wiederverwendbar ist das
|
|
596
|
+
is_pure INTEGER NOT NULL DEFAULT 0, -- Keine Side-Effects?
|
|
597
|
+
complexity_score REAL, -- Niedrig = besser wiederverwendbar
|
|
598
|
+
|
|
599
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
600
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
601
|
+
);
|
|
602
|
+
CREATE INDEX idx_modules_fingerprint ON code_modules(fingerprint);
|
|
603
|
+
CREATE INDEX idx_modules_language ON code_modules(language);
|
|
604
|
+
CREATE INDEX idx_modules_category ON code_modules(category);
|
|
605
|
+
CREATE INDEX idx_modules_project ON code_modules(project_id);
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### module_usages
|
|
609
|
+
```sql
|
|
610
|
+
CREATE TABLE module_usages (
|
|
611
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
612
|
+
module_id INTEGER NOT NULL REFERENCES code_modules(id) ON DELETE CASCADE,
|
|
613
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
614
|
+
file_path TEXT NOT NULL, -- Wo wurde es eingesetzt
|
|
615
|
+
usage_type TEXT NOT NULL CHECK(usage_type IN (
|
|
616
|
+
'exact', -- 1:1 kopiert
|
|
617
|
+
'adapted', -- Angepasst
|
|
618
|
+
'pattern_based' -- Gleiches Pattern, andere Implementierung
|
|
619
|
+
)),
|
|
620
|
+
adaptations TEXT, -- JSON: Was wurde geändert
|
|
621
|
+
outcome TEXT NOT NULL DEFAULT 'unknown'
|
|
622
|
+
CHECK(outcome IN ('success', 'failure', 'unknown')),
|
|
623
|
+
used_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
624
|
+
);
|
|
625
|
+
CREATE INDEX idx_module_usages_module ON module_usages(module_id);
|
|
626
|
+
CREATE INDEX idx_module_usages_project ON module_usages(project_id);
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### module_similarities
|
|
630
|
+
```sql
|
|
631
|
+
CREATE TABLE module_similarities (
|
|
632
|
+
module_id_1 INTEGER NOT NULL REFERENCES code_modules(id) ON DELETE CASCADE,
|
|
633
|
+
module_id_2 INTEGER NOT NULL REFERENCES code_modules(id) ON DELETE CASCADE,
|
|
634
|
+
similarity_score REAL NOT NULL,
|
|
635
|
+
similarity_type TEXT NOT NULL CHECK(similarity_type IN (
|
|
636
|
+
'exact', -- Identischer Code (anderes Projekt)
|
|
637
|
+
'structural', -- Gleiche Struktur, andere Namen
|
|
638
|
+
'semantic' -- Gleicher Zweck, andere Implementierung
|
|
639
|
+
)),
|
|
640
|
+
detected_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
641
|
+
PRIMARY KEY (module_id_1, module_id_2)
|
|
642
|
+
);
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### FTS5 Volltext-Suche
|
|
646
|
+
```sql
|
|
647
|
+
-- Error-Suche
|
|
648
|
+
CREATE VIRTUAL TABLE errors_fts USING fts5(
|
|
649
|
+
message, message_template, stack_trace, raw_output, task_context,
|
|
650
|
+
content=errors, content_rowid=id
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
-- Solution-Suche
|
|
654
|
+
CREATE VIRTUAL TABLE solutions_fts USING fts5(
|
|
655
|
+
title, description, steps, code_before, code_after,
|
|
656
|
+
content=solutions, content_rowid=id
|
|
657
|
+
);
|
|
658
|
+
|
|
659
|
+
-- Code-Modul-Suche
|
|
660
|
+
CREATE VIRTUAL TABLE code_modules_fts USING fts5(
|
|
661
|
+
name, purpose, source_code, interface_signature,
|
|
662
|
+
content=code_modules, content_rowid=id
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
-- Sync-Trigger für errors_fts
|
|
666
|
+
CREATE TRIGGER errors_ai AFTER INSERT ON errors BEGIN
|
|
667
|
+
INSERT INTO errors_fts(rowid, message, message_template, stack_trace, raw_output, task_context)
|
|
668
|
+
VALUES (new.id, new.message, new.message_template, new.stack_trace, new.raw_output, new.task_context);
|
|
669
|
+
END;
|
|
670
|
+
|
|
671
|
+
CREATE TRIGGER errors_ad AFTER DELETE ON errors BEGIN
|
|
672
|
+
INSERT INTO errors_fts(errors_fts, rowid, message, message_template, stack_trace, raw_output, task_context)
|
|
673
|
+
VALUES ('delete', old.id, old.message, old.message_template, old.stack_trace, old.raw_output, old.task_context);
|
|
674
|
+
END;
|
|
675
|
+
|
|
676
|
+
CREATE TRIGGER errors_au AFTER UPDATE ON errors BEGIN
|
|
677
|
+
INSERT INTO errors_fts(errors_fts, rowid, message, message_template, stack_trace, raw_output, task_context)
|
|
678
|
+
VALUES ('delete', old.id, old.message, old.message_template, old.stack_trace, old.raw_output, old.task_context);
|
|
679
|
+
INSERT INTO errors_fts(rowid, message, message_template, stack_trace, raw_output, task_context)
|
|
680
|
+
VALUES (new.id, new.message, new.message_template, new.stack_trace, new.raw_output, new.task_context);
|
|
681
|
+
END;
|
|
682
|
+
|
|
683
|
+
-- Sync-Trigger für solutions_fts
|
|
684
|
+
CREATE TRIGGER solutions_ai AFTER INSERT ON solutions BEGIN
|
|
685
|
+
INSERT INTO solutions_fts(rowid, title, description, steps, code_before, code_after)
|
|
686
|
+
VALUES (new.id, new.title, new.description, new.steps, new.code_before, new.code_after);
|
|
687
|
+
END;
|
|
688
|
+
|
|
689
|
+
CREATE TRIGGER solutions_ad AFTER DELETE ON solutions BEGIN
|
|
690
|
+
INSERT INTO solutions_fts(solutions_fts, rowid, title, description, steps, code_before, code_after)
|
|
691
|
+
VALUES ('delete', old.id, old.title, old.description, old.steps, old.code_before, old.code_after);
|
|
692
|
+
END;
|
|
693
|
+
|
|
694
|
+
CREATE TRIGGER solutions_au AFTER UPDATE ON solutions BEGIN
|
|
695
|
+
INSERT INTO solutions_fts(solutions_fts, rowid, title, description, steps, code_before, code_after)
|
|
696
|
+
VALUES ('delete', old.id, old.title, old.description, old.steps, old.code_before, old.code_after);
|
|
697
|
+
INSERT INTO solutions_fts(rowid, title, description, steps, code_before, code_after)
|
|
698
|
+
VALUES (new.id, new.title, new.description, new.steps, new.code_before, new.code_after);
|
|
699
|
+
END;
|
|
700
|
+
|
|
701
|
+
-- Sync-Trigger für code_modules_fts
|
|
702
|
+
CREATE TRIGGER code_modules_ai AFTER INSERT ON code_modules BEGIN
|
|
703
|
+
INSERT INTO code_modules_fts(rowid, name, purpose, source_code, interface_signature)
|
|
704
|
+
VALUES (new.id, new.name, new.purpose, new.source_code, new.interface_signature);
|
|
705
|
+
END;
|
|
706
|
+
|
|
707
|
+
CREATE TRIGGER code_modules_ad AFTER DELETE ON code_modules BEGIN
|
|
708
|
+
INSERT INTO code_modules_fts(code_modules_fts, rowid, name, purpose, source_code, interface_signature)
|
|
709
|
+
VALUES ('delete', old.id, old.name, old.purpose, old.source_code, old.interface_signature);
|
|
710
|
+
END;
|
|
711
|
+
|
|
712
|
+
CREATE TRIGGER code_modules_au AFTER UPDATE ON code_modules BEGIN
|
|
713
|
+
INSERT INTO code_modules_fts(code_modules_fts, rowid, name, purpose, source_code, interface_signature)
|
|
714
|
+
VALUES ('delete', old.id, old.name, old.purpose, old.source_code, old.interface_signature);
|
|
715
|
+
INSERT INTO code_modules_fts(rowid, name, purpose, source_code, interface_signature)
|
|
716
|
+
VALUES (new.id, new.name, new.purpose, new.source_code, new.interface_signature);
|
|
717
|
+
END;
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
## Kern-Algorithmen
|
|
721
|
+
|
|
722
|
+
### Error-Fingerprinting
|
|
723
|
+
|
|
724
|
+
Struktureller Hash: error_type + templatisierte Message + Top-3 Stack-Frames → SHA-256.
|
|
725
|
+
|
|
726
|
+
**Templatisierung:** Variable Teile werden durch Platzhalter ersetzt:
|
|
727
|
+
- Dateipfade → `<PATH>`
|
|
728
|
+
- Zeilennummern → `<LINE>`
|
|
729
|
+
- Variablennamen in Fehlermessages → bleiben (oft key info)
|
|
730
|
+
- Zahlen in generischen Kontexten → `<NUM>`
|
|
731
|
+
- Hex-Adressen → `<ADDR>`
|
|
732
|
+
- UUIDs → `<UUID>`
|
|
733
|
+
- URLs → `<URL>`
|
|
734
|
+
- Timestamps → `<TIMESTAMP>`
|
|
735
|
+
|
|
736
|
+
```typescript
|
|
737
|
+
function templateMessage(msg: string): string {
|
|
738
|
+
return msg
|
|
739
|
+
.replace(/[A-Z]:\\[\w\-\.\\]+\.\w+/g, '<PATH>') // Windows-Pfade
|
|
740
|
+
.replace(/\/[\w\-\.\/]+\.\w+/g, '<PATH>') // Unix-Pfade
|
|
741
|
+
.replace(/:\d+:\d+/g, ':<LINE>:<COL>') // Zeile:Spalte
|
|
742
|
+
.replace(/line \d+/gi, 'line <LINE>') // "line 42"
|
|
743
|
+
.replace(/0x[0-9a-fA-F]+/g, '<ADDR>') // Hex
|
|
744
|
+
.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '<UUID>')
|
|
745
|
+
.replace(/https?:\/\/[^\s]+/g, '<URL>') // URLs
|
|
746
|
+
.replace(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}/g, '<TIMESTAMP>');
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function generateFingerprint(errorType: string, message: string, frames: StackFrame[]): string {
|
|
750
|
+
const template = templateMessage(message);
|
|
751
|
+
const topFrames = frames.slice(0, 3).map(f =>
|
|
752
|
+
`${f.function_name || '<anon>'}@${basename(f.file_path || '<unknown>')}`
|
|
753
|
+
).join('|');
|
|
754
|
+
const input = `${errorType}::${template}::${topFrames}`;
|
|
755
|
+
return createHash('sha256').update(input).digest('hex');
|
|
756
|
+
}
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
### Multi-Signal Error-Matching
|
|
760
|
+
|
|
761
|
+
```typescript
|
|
762
|
+
interface MatchSignal {
|
|
763
|
+
name: string;
|
|
764
|
+
weight: number;
|
|
765
|
+
compute: (a: ErrorRecord, b: ErrorRecord) => number; // 0.0 - 1.0
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const SIGNALS: MatchSignal[] = [
|
|
769
|
+
{ name: 'fingerprint', weight: 0.30, compute: fingerprintMatch },
|
|
770
|
+
{ name: 'message_similarity', weight: 0.20, compute: messageSimilarity },
|
|
771
|
+
{ name: 'type_match', weight: 0.15, compute: typeMatch },
|
|
772
|
+
{ name: 'stack_similarity', weight: 0.15, compute: stackSimilarity },
|
|
773
|
+
{ name: 'file_similarity', weight: 0.10, compute: fileSimilarity },
|
|
774
|
+
{ name: 'fts_score', weight: 0.10, compute: ftsScore },
|
|
775
|
+
];
|
|
776
|
+
|
|
777
|
+
const MATCH_THRESHOLD = 0.70;
|
|
778
|
+
const STRONG_MATCH_THRESHOLD = 0.90;
|
|
779
|
+
|
|
780
|
+
function matchError(incoming: ErrorRecord, candidates: ErrorRecord[]): MatchResult[] {
|
|
781
|
+
return candidates
|
|
782
|
+
.map(candidate => {
|
|
783
|
+
const scores = SIGNALS.map(signal => {
|
|
784
|
+
const score = signal.compute(incoming, candidate);
|
|
785
|
+
return {
|
|
786
|
+
signal: signal.name,
|
|
787
|
+
score,
|
|
788
|
+
weighted: score * signal.weight,
|
|
789
|
+
};
|
|
790
|
+
});
|
|
791
|
+
const totalScore = scores.reduce((sum, s) => sum + s.weighted, 0);
|
|
792
|
+
return { candidate, scores, totalScore, isMatch: totalScore >= MATCH_THRESHOLD };
|
|
793
|
+
})
|
|
794
|
+
.filter(r => r.isMatch)
|
|
795
|
+
.sort((a, b) => b.totalScore - a.totalScore);
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### Similarity-Funktionen
|
|
800
|
+
|
|
801
|
+
```typescript
|
|
802
|
+
// Levenshtein Distanz (normalisiert auf 0-1 Similarity)
|
|
803
|
+
function levenshteinSimilarity(a: string, b: string): number {
|
|
804
|
+
if (a === b) return 1.0;
|
|
805
|
+
const maxLen = Math.max(a.length, b.length);
|
|
806
|
+
if (maxLen === 0) return 1.0;
|
|
807
|
+
return 1 - levenshteinDistance(a, b) / maxLen;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// Cosine Similarity auf Token-Vektoren
|
|
811
|
+
function cosineSimilarity(tokensA: string[], tokensB: string[]): number {
|
|
812
|
+
const vocab = new Set([...tokensA, ...tokensB]);
|
|
813
|
+
const vecA = new Map<string, number>();
|
|
814
|
+
const vecB = new Map<string, number>();
|
|
815
|
+
tokensA.forEach(t => vecA.set(t, (vecA.get(t) || 0) + 1));
|
|
816
|
+
tokensB.forEach(t => vecB.set(t, (vecB.get(t) || 0) + 1));
|
|
817
|
+
|
|
818
|
+
let dot = 0, magA = 0, magB = 0;
|
|
819
|
+
for (const word of vocab) {
|
|
820
|
+
const a = vecA.get(word) || 0;
|
|
821
|
+
const b = vecB.get(word) || 0;
|
|
822
|
+
dot += a * b;
|
|
823
|
+
magA += a * a;
|
|
824
|
+
magB += b * b;
|
|
825
|
+
}
|
|
826
|
+
const denom = Math.sqrt(magA) * Math.sqrt(magB);
|
|
827
|
+
return denom === 0 ? 0 : dot / denom;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Jaccard Similarity auf Token-Sets
|
|
831
|
+
function jaccardSimilarity(tokensA: string[], tokensB: string[]): number {
|
|
832
|
+
const setA = new Set(tokensA);
|
|
833
|
+
const setB = new Set(tokensB);
|
|
834
|
+
const intersection = new Set([...setA].filter(x => setB.has(x)));
|
|
835
|
+
const union = new Set([...setA, ...setB]);
|
|
836
|
+
return union.size === 0 ? 0 : intersection.size / union.size;
|
|
837
|
+
}
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
### TF-IDF (Inkrementell)
|
|
841
|
+
|
|
842
|
+
```typescript
|
|
843
|
+
class TfIdfIndex {
|
|
844
|
+
private documents: Map<number, string[]> = new Map();
|
|
845
|
+
private df: Map<string, number> = new Map(); // Document Frequency Cache
|
|
846
|
+
private idf: Map<string, number> = new Map();
|
|
847
|
+
private documentCount = 0;
|
|
848
|
+
|
|
849
|
+
addDocument(id: number, tokens: string[]): void {
|
|
850
|
+
// Inkrementelles DF-Update statt Full-Recompute
|
|
851
|
+
const unique = new Set(tokens);
|
|
852
|
+
for (const token of unique) {
|
|
853
|
+
this.df.set(token, (this.df.get(token) || 0) + 1);
|
|
854
|
+
}
|
|
855
|
+
this.documents.set(id, tokens);
|
|
856
|
+
this.documentCount++;
|
|
857
|
+
this.recomputeIdfForTerms(unique);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
removeDocument(id: number): void {
|
|
861
|
+
const tokens = this.documents.get(id);
|
|
862
|
+
if (!tokens) return;
|
|
863
|
+
|
|
864
|
+
const unique = new Set(tokens);
|
|
865
|
+
for (const token of unique) {
|
|
866
|
+
const count = (this.df.get(token) || 1) - 1;
|
|
867
|
+
if (count <= 0) {
|
|
868
|
+
this.df.delete(token);
|
|
869
|
+
this.idf.delete(token);
|
|
870
|
+
} else {
|
|
871
|
+
this.df.set(token, count);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
this.documents.delete(id);
|
|
875
|
+
this.documentCount--;
|
|
876
|
+
this.recomputeIdfForTerms(unique);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
private recomputeIdfForTerms(terms: Set<string>): void {
|
|
880
|
+
const N = this.documentCount;
|
|
881
|
+
for (const term of terms) {
|
|
882
|
+
const count = this.df.get(term);
|
|
883
|
+
if (count) {
|
|
884
|
+
this.idf.set(term, Math.log((N + 1) / (count + 1)) + 1);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
search(queryTokens: string[], topK = 10): Array<{ id: number; score: number }> {
|
|
890
|
+
const results: Array<{ id: number; score: number }> = [];
|
|
891
|
+
|
|
892
|
+
for (const [id, docTokens] of this.documents) {
|
|
893
|
+
let score = 0;
|
|
894
|
+
const tf = new Map<string, number>();
|
|
895
|
+
docTokens.forEach(t => tf.set(t, (tf.get(t) || 0) + 1));
|
|
896
|
+
|
|
897
|
+
for (const qt of queryTokens) {
|
|
898
|
+
const termFreq = (tf.get(qt) || 0) / docTokens.length;
|
|
899
|
+
const inverseDocFreq = this.idf.get(qt) || 0;
|
|
900
|
+
score += termFreq * inverseDocFreq;
|
|
901
|
+
}
|
|
902
|
+
if (score > 0) results.push({ id, score });
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
return results.sort((a, b) => b.score - a.score).slice(0, topK);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// Persistenz: Zustand in SQLite speichern/laden für schnelle Daemon-Neustarts
|
|
909
|
+
serialize(): { documents: [number, string[]][]; df: [string, number][] } {
|
|
910
|
+
return {
|
|
911
|
+
documents: [...this.documents.entries()],
|
|
912
|
+
df: [...this.df.entries()],
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
static deserialize(data: ReturnType<TfIdfIndex['serialize']>): TfIdfIndex {
|
|
917
|
+
const index = new TfIdfIndex();
|
|
918
|
+
index.documents = new Map(data.documents);
|
|
919
|
+
index.df = new Map(data.df);
|
|
920
|
+
index.documentCount = index.documents.size;
|
|
921
|
+
// IDF aus DF recomputen
|
|
922
|
+
const N = index.documentCount;
|
|
923
|
+
for (const [term, count] of index.df) {
|
|
924
|
+
index.idf.set(term, Math.log((N + 1) / (count + 1)) + 1);
|
|
925
|
+
}
|
|
926
|
+
return index;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
### Confidence-Scoring (Wilson Score Intervall)
|
|
932
|
+
|
|
933
|
+
```typescript
|
|
934
|
+
// Wilson Score Interval - Lower Bound
|
|
935
|
+
// Besser als Durchschnitt: berücksichtigt Stichprobengröße
|
|
936
|
+
function wilsonScore(successes: number, total: number, z = 1.96): number {
|
|
937
|
+
if (total === 0) return 0;
|
|
938
|
+
|
|
939
|
+
const p = successes / total;
|
|
940
|
+
const denominator = 1 + z * z / total;
|
|
941
|
+
const centre = p + z * z / (2 * total);
|
|
942
|
+
const adjustment = z * Math.sqrt((p * (1 - p) + z * z / (4 * total)) / total);
|
|
943
|
+
|
|
944
|
+
return (centre - adjustment) / denominator;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// Zeitbasierter Decay
|
|
948
|
+
function timeDecay(timestamp: Date, halfLifeDays = 30): number {
|
|
949
|
+
const now = new Date();
|
|
950
|
+
const ageMs = now.getTime() - timestamp.getTime();
|
|
951
|
+
const ageDays = ageMs / (1000 * 60 * 60 * 24);
|
|
952
|
+
return Math.pow(0.5, ageDays / halfLifeDays);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Kombinierter Score
|
|
956
|
+
function computeConfidence(
|
|
957
|
+
successes: number,
|
|
958
|
+
failures: number,
|
|
959
|
+
lastUsed: Date,
|
|
960
|
+
halfLifeDays = 30
|
|
961
|
+
): number {
|
|
962
|
+
const total = successes + failures;
|
|
963
|
+
const wilson = wilsonScore(successes, total);
|
|
964
|
+
const decay = timeDecay(lastUsed, halfLifeDays);
|
|
965
|
+
return wilson * decay;
|
|
966
|
+
}
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
### Code-Fingerprinting (Strukturell)
|
|
970
|
+
|
|
971
|
+
```typescript
|
|
972
|
+
function fingerprintCode(source: string, language: string): string {
|
|
973
|
+
// 1. Comments entfernen
|
|
974
|
+
let normalized = stripComments(source, language);
|
|
975
|
+
|
|
976
|
+
// 2. Whitespace normalisieren
|
|
977
|
+
normalized = normalized.replace(/\s+/g, ' ').trim();
|
|
978
|
+
|
|
979
|
+
// 3. Identifier normalisieren (aber Import-Names und API-Calls behalten)
|
|
980
|
+
normalized = normalizeIdentifiers(normalized, language);
|
|
981
|
+
|
|
982
|
+
// 4. String-Literale normalisieren
|
|
983
|
+
normalized = normalized.replace(/'[^']*'/g, "'<STR>'");
|
|
984
|
+
normalized = normalized.replace(/"[^"]*"/g, '"<STR>"');
|
|
985
|
+
normalized = normalized.replace(/`[^`]*`/g, '`<STR>`');
|
|
986
|
+
|
|
987
|
+
// 5. Zahlen normalisieren
|
|
988
|
+
normalized = normalized.replace(/\b\d+\b/g, '<NUM>');
|
|
989
|
+
|
|
990
|
+
return createHash('sha256').update(normalized).digest('hex');
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
function stripComments(source: string, language: string): string {
|
|
994
|
+
switch (language) {
|
|
995
|
+
case 'typescript':
|
|
996
|
+
case 'javascript':
|
|
997
|
+
case 'java':
|
|
998
|
+
case 'go':
|
|
999
|
+
case 'rust':
|
|
1000
|
+
return source
|
|
1001
|
+
.replace(/\/\/.*$/gm, '') // Single-line
|
|
1002
|
+
.replace(/\/\*[\s\S]*?\*\//g, ''); // Multi-line
|
|
1003
|
+
case 'python':
|
|
1004
|
+
return source
|
|
1005
|
+
.replace(/#.*$/gm, '') // Single-line
|
|
1006
|
+
.replace(/"""[\s\S]*?"""/g, '') // Docstrings
|
|
1007
|
+
.replace(/'''[\s\S]*?'''/g, '');
|
|
1008
|
+
default:
|
|
1009
|
+
return source.replace(/\/\/.*$/gm, '').replace(/#.*$/gm, '');
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
function normalizeIdentifiers(source: string, language: string): string {
|
|
1014
|
+
// Lokale Variablen normalisieren, aber importierte Namen behalten
|
|
1015
|
+
// Einfache Heuristik: camelCase/snake_case Wörter die nicht in Import-Statements stehen
|
|
1016
|
+
const imports = extractImportNames(source, language);
|
|
1017
|
+
const keywords = getLanguageKeywords(language);
|
|
1018
|
+
const preserve = new Set([...imports, ...keywords]);
|
|
1019
|
+
|
|
1020
|
+
return source.replace(/\b[a-zA-Z_]\w*\b/g, (match) => {
|
|
1021
|
+
if (preserve.has(match)) return match;
|
|
1022
|
+
// Behalte den ersten Buchstaben als Typ-Hint (großbuchstabe = Klasse)
|
|
1023
|
+
if (match[0] === match[0].toUpperCase()) return '<CLASS>';
|
|
1024
|
+
return '<VAR>';
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
### Code-Reusability-Scoring
|
|
1030
|
+
|
|
1031
|
+
```typescript
|
|
1032
|
+
interface ReusabilitySignal {
|
|
1033
|
+
name: string;
|
|
1034
|
+
weight: number;
|
|
1035
|
+
check: (code: CodeUnit) => number; // 0.0 - 1.0
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
const REUSABILITY_SIGNALS: ReusabilitySignal[] = [
|
|
1039
|
+
{
|
|
1040
|
+
name: 'single_responsibility',
|
|
1041
|
+
weight: 0.25,
|
|
1042
|
+
// Datei hat EINEN klaren Zweck (1-3 Exports, kohärente Naming)
|
|
1043
|
+
check: (code) => {
|
|
1044
|
+
const exports = code.exports.length;
|
|
1045
|
+
if (exports === 0) return 0;
|
|
1046
|
+
if (exports <= 3) return 1.0;
|
|
1047
|
+
if (exports <= 6) return 0.6;
|
|
1048
|
+
return 0.3;
|
|
1049
|
+
}
|
|
1050
|
+
},
|
|
1051
|
+
{
|
|
1052
|
+
name: 'pure_function',
|
|
1053
|
+
weight: 0.20,
|
|
1054
|
+
// Keine Side-Effects: kein fs, kein process, kein console, kein fetch
|
|
1055
|
+
check: (code) => {
|
|
1056
|
+
const sideEffects = ['fs.', 'process.', 'console.', 'fetch(', 'XMLHttpRequest',
|
|
1057
|
+
'document.', 'window.', 'global.', 'require('];
|
|
1058
|
+
const found = sideEffects.filter(se => code.source.includes(se));
|
|
1059
|
+
return found.length === 0 ? 1.0 : Math.max(0, 1 - found.length * 0.3);
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
name: 'clear_interface',
|
|
1064
|
+
weight: 0.20,
|
|
1065
|
+
// Typisierte Parameter, klarer Return-Type, keine any
|
|
1066
|
+
check: (code) => {
|
|
1067
|
+
let score = 0.5; // Baseline
|
|
1068
|
+
if (code.hasTypeAnnotations) score += 0.3;
|
|
1069
|
+
if (!code.source.includes(': any')) score += 0.2;
|
|
1070
|
+
return Math.min(1.0, score);
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
name: 'low_coupling',
|
|
1075
|
+
weight: 0.15,
|
|
1076
|
+
// Wenig interne Imports, wenig externe Dependencies
|
|
1077
|
+
check: (code) => {
|
|
1078
|
+
const internalImports = code.internalImports.length;
|
|
1079
|
+
const externalImports = code.externalImports.length;
|
|
1080
|
+
const total = internalImports + externalImports;
|
|
1081
|
+
if (total === 0) return 1.0;
|
|
1082
|
+
if (total <= 3) return 0.8;
|
|
1083
|
+
if (total <= 6) return 0.5;
|
|
1084
|
+
return 0.2;
|
|
1085
|
+
}
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
name: 'generic_utility',
|
|
1089
|
+
weight: 0.10,
|
|
1090
|
+
// Pfad enthält utils/, helpers/, lib/, shared/
|
|
1091
|
+
// Oder: Funktion nutzt Generics
|
|
1092
|
+
check: (code) => {
|
|
1093
|
+
const utilPaths = ['utils/', 'helpers/', 'lib/', 'shared/', 'common/'];
|
|
1094
|
+
const isUtilPath = utilPaths.some(p => code.filePath.includes(p));
|
|
1095
|
+
const hasGenerics = /\<[A-Z]\w*\>/.test(code.source);
|
|
1096
|
+
let score = 0;
|
|
1097
|
+
if (isUtilPath) score += 0.6;
|
|
1098
|
+
if (hasGenerics) score += 0.4;
|
|
1099
|
+
return Math.min(1.0, score || 0.2);
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
1102
|
+
{
|
|
1103
|
+
name: 'documentation',
|
|
1104
|
+
weight: 0.10,
|
|
1105
|
+
// JSDoc/TSDoc/Docstring vorhanden
|
|
1106
|
+
check: (code) => {
|
|
1107
|
+
const hasJsdoc = /\/\*\*[\s\S]*?\*\//.test(code.source);
|
|
1108
|
+
const hasDocstring = /"""[\s\S]*?"""/.test(code.source) || /'''[\s\S]*?'''/.test(code.source);
|
|
1109
|
+
const hasInlineComments = (code.source.match(/\/\/ /g) || []).length >= 2;
|
|
1110
|
+
if (hasJsdoc || hasDocstring) return 1.0;
|
|
1111
|
+
if (hasInlineComments) return 0.5;
|
|
1112
|
+
return 0.1;
|
|
1113
|
+
}
|
|
1114
|
+
},
|
|
1115
|
+
];
|
|
1116
|
+
|
|
1117
|
+
const MODULE_THRESHOLD = 0.60;
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
### Smart Granularity Detection
|
|
1121
|
+
|
|
1122
|
+
```typescript
|
|
1123
|
+
function detectGranularity(filePath: string, source: string, language: string): ModuleType {
|
|
1124
|
+
const exports = extractExports(source, language);
|
|
1125
|
+
|
|
1126
|
+
// Datei mit 1 Default-Export → Ganzes File ist das Modul
|
|
1127
|
+
if (exports.default && exports.named.length <= 2) {
|
|
1128
|
+
return 'file';
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// Datei mit einer Klasse → Klasse ist das Modul
|
|
1132
|
+
if (exports.classes.length === 1 && exports.named.length <= 3) {
|
|
1133
|
+
return 'class';
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Datei mit vielen unzusammenhängenden Exports → Einzeln tracken
|
|
1137
|
+
if (exports.named.length > 3) {
|
|
1138
|
+
const cohesion = measureExportCohesion(exports, source);
|
|
1139
|
+
if (cohesion < 0.5) {
|
|
1140
|
+
return 'function'; // Jeder Export wird einzeln als Modul registriert
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// Default: Ganze Datei
|
|
1145
|
+
return 'file';
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function measureExportCohesion(exports: ExportInfo, source: string): number {
|
|
1149
|
+
// Messe ob die Exports thematisch zusammengehören
|
|
1150
|
+
// Heuristik: Teilen sie gemeinsame Tokens in ihren Namen?
|
|
1151
|
+
const names = exports.named.map(e => tokenizeCamelCase(e.name));
|
|
1152
|
+
if (names.length <= 1) return 1.0;
|
|
1153
|
+
|
|
1154
|
+
let sharedTokens = 0;
|
|
1155
|
+
let totalPairs = 0;
|
|
1156
|
+
for (let i = 0; i < names.length; i++) {
|
|
1157
|
+
for (let j = i + 1; j < names.length; j++) {
|
|
1158
|
+
const shared = names[i].filter(t => names[j].includes(t)).length;
|
|
1159
|
+
const total = new Set([...names[i], ...names[j]]).size;
|
|
1160
|
+
sharedTokens += total > 0 ? shared / total : 0;
|
|
1161
|
+
totalPairs++;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return totalPairs > 0 ? sharedTokens / totalPairs : 0;
|
|
1165
|
+
}
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
### Pattern-Extraktion (Centroid-basiert)
|
|
1169
|
+
|
|
1170
|
+
```typescript
|
|
1171
|
+
class PatternExtractor {
|
|
1172
|
+
extractPatterns(pairs: ErrorSolutionPair[]): Pattern[] {
|
|
1173
|
+
const clusters: { pairs: ErrorSolutionPair[]; centroid: number[] }[] = [];
|
|
1174
|
+
|
|
1175
|
+
for (const pair of pairs) {
|
|
1176
|
+
const tokens = tokenize(pair.error.message_template || pair.error.message);
|
|
1177
|
+
const vector = this.tokensToVector(tokens);
|
|
1178
|
+
|
|
1179
|
+
let bestCluster: typeof clusters[number] | null = null;
|
|
1180
|
+
let bestSim = 0;
|
|
1181
|
+
|
|
1182
|
+
for (const cluster of clusters) {
|
|
1183
|
+
const sim = this.vectorCosineSimilarity(vector, cluster.centroid);
|
|
1184
|
+
if (sim >= 0.75 && sim > bestSim) {
|
|
1185
|
+
bestSim = sim;
|
|
1186
|
+
bestCluster = cluster;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
if (bestCluster) {
|
|
1191
|
+
bestCluster.pairs.push(pair);
|
|
1192
|
+
// Centroid aktualisieren (Running Average)
|
|
1193
|
+
bestCluster.centroid = this.updateCentroid(bestCluster.centroid, vector, bestCluster.pairs.length);
|
|
1194
|
+
} else {
|
|
1195
|
+
clusters.push({ pairs: [pair], centroid: vector });
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
return clusters
|
|
1200
|
+
.filter(c => c.pairs.length >= 2)
|
|
1201
|
+
.map(cluster => ({
|
|
1202
|
+
errorTemplate: this.findCommonTemplate(cluster.pairs),
|
|
1203
|
+
solutionSummary: this.findCommonSolution(cluster.pairs),
|
|
1204
|
+
occurrences: cluster.pairs.length,
|
|
1205
|
+
confidence: this.computeClusterConfidence(cluster.pairs),
|
|
1206
|
+
successRate: this.computeSuccessRate(cluster.pairs),
|
|
1207
|
+
errorIds: cluster.pairs.map(p => p.error.id),
|
|
1208
|
+
solutionIds: [...new Set(cluster.pairs.map(p => p.solution.id))],
|
|
1209
|
+
}));
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
private updateCentroid(current: number[], newVec: number[], count: number): number[] {
|
|
1213
|
+
// Inkrementeller Centroid: new_centroid = old + (new_vec - old) / count
|
|
1214
|
+
return current.map((v, i) => v + ((newVec[i] || 0) - v) / count);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
### Rule-Generation
|
|
1220
|
+
|
|
1221
|
+
```typescript
|
|
1222
|
+
class RuleGenerator {
|
|
1223
|
+
generateRules(patterns: Pattern[], config: LearningConfig): Rule[] {
|
|
1224
|
+
return patterns
|
|
1225
|
+
.filter(p =>
|
|
1226
|
+
p.occurrences >= config.minOccurrences &&
|
|
1227
|
+
p.confidence >= config.minConfidence &&
|
|
1228
|
+
p.successRate >= config.minSuccessRate
|
|
1229
|
+
)
|
|
1230
|
+
.map(pattern => ({
|
|
1231
|
+
name: `Auto: ${pattern.errorTemplate.substring(0, 50)}`,
|
|
1232
|
+
description: `Automatisch generiert aus ${pattern.occurrences} Vorkommen`,
|
|
1233
|
+
pattern: {
|
|
1234
|
+
error_type: pattern.errorType,
|
|
1235
|
+
message_pattern: pattern.messageRegex,
|
|
1236
|
+
file_pattern: pattern.filePattern,
|
|
1237
|
+
},
|
|
1238
|
+
action: {
|
|
1239
|
+
type: pattern.confidence >= 0.90 ? 'auto_fix' : 'suggestion',
|
|
1240
|
+
solution_ids: pattern.solutionIds,
|
|
1241
|
+
message: pattern.solutionSummary,
|
|
1242
|
+
},
|
|
1243
|
+
rule_type: pattern.confidence >= 0.90 ? 'auto_fix' : 'suggestion',
|
|
1244
|
+
confidence: pattern.confidence,
|
|
1245
|
+
source_error_ids: pattern.errorIds,
|
|
1246
|
+
}));
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
### Lern-Zyklus
|
|
1252
|
+
|
|
1253
|
+
```typescript
|
|
1254
|
+
class LearningEngine {
|
|
1255
|
+
private timer: NodeJS.Timeout | null = null;
|
|
1256
|
+
|
|
1257
|
+
startSchedule(intervalMs: number): void {
|
|
1258
|
+
this.timer = setInterval(() => this.runCycle(), intervalMs);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
stop(): void {
|
|
1262
|
+
if (this.timer) clearInterval(this.timer);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
async runCycle(): Promise<LearningCycleResult> {
|
|
1266
|
+
const result: LearningCycleResult = {
|
|
1267
|
+
newPatterns: 0,
|
|
1268
|
+
updatedRules: 0,
|
|
1269
|
+
prunedRules: 0,
|
|
1270
|
+
crossProjectInsights: 0,
|
|
1271
|
+
newAntipatterns: 0,
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
// Phase 1: Neue Error-Solution-Paare sammeln (seit letztem Cycle)
|
|
1275
|
+
const newPairs = this.collectNewErrorSolutionPairs();
|
|
1276
|
+
|
|
1277
|
+
// Phase 2: Confidence-Scores aller Solutions aktualisieren
|
|
1278
|
+
this.updateConfidenceScores();
|
|
1279
|
+
|
|
1280
|
+
// Phase 3: Muster extrahieren (Centroid-basiertes Clustering)
|
|
1281
|
+
const patterns = this.patternExtractor.extractPatterns(newPairs);
|
|
1282
|
+
result.newPatterns = patterns.length;
|
|
1283
|
+
|
|
1284
|
+
// Phase 4: Regeln generieren aus Mustern
|
|
1285
|
+
const newRules = this.ruleGenerator.generateRules(patterns, this.config);
|
|
1286
|
+
result.updatedRules = newRules.length;
|
|
1287
|
+
|
|
1288
|
+
// Phase 5: Schwache Regeln beschneiden
|
|
1289
|
+
// Entferne: Confidence < 0.20 ODER Ablehnungsrate > 50%
|
|
1290
|
+
result.prunedRules = this.pruneRules();
|
|
1291
|
+
|
|
1292
|
+
// Phase 6: Anti-Patterns erkennen
|
|
1293
|
+
// Wiederholte Fehler OHNE erfolgreiche Lösung → Anti-Pattern Kandidat
|
|
1294
|
+
result.newAntipatterns = this.detectAntipatterns();
|
|
1295
|
+
|
|
1296
|
+
// Phase 7: Cross-Projekt Analyse
|
|
1297
|
+
// Gleiche Fehler in verschiedenen Projekten → Lösung übertragbar?
|
|
1298
|
+
result.crossProjectInsights = this.analyzeCrossProject();
|
|
1299
|
+
|
|
1300
|
+
// Phase 8: Code-Module Confidence aktualisieren
|
|
1301
|
+
// Reuse-Count, Adaptation-Outcomes → Confidence-Score
|
|
1302
|
+
this.updateModuleConfidence();
|
|
1303
|
+
|
|
1304
|
+
// Phase 9: Notifications senden
|
|
1305
|
+
this.emitNotifications(result);
|
|
1306
|
+
|
|
1307
|
+
return result;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
private detectAntipatterns(): number {
|
|
1311
|
+
// Finde Fehler die >= 3x aufgetreten sind, aber keine erfolgreiche Lösung haben
|
|
1312
|
+
// → Kandidat für "Tu das nicht"-Regel
|
|
1313
|
+
const candidates = this.services.error.findUnresolvedRecurring(3);
|
|
1314
|
+
let count = 0;
|
|
1315
|
+
|
|
1316
|
+
for (const error of candidates) {
|
|
1317
|
+
const failedAttempts = this.services.solution.getFailedAttempts(error.id);
|
|
1318
|
+
if (failedAttempts.length >= 2) {
|
|
1319
|
+
this.services.antipattern.create({
|
|
1320
|
+
description: `Wiederkehrender Fehler ohne Lösung: ${error.message_template || error.message}`,
|
|
1321
|
+
trigger_pattern: JSON.stringify({
|
|
1322
|
+
error_type: error.error_type,
|
|
1323
|
+
message_pattern: error.message_template,
|
|
1324
|
+
}),
|
|
1325
|
+
severity: failedAttempts.length >= 4 ? 'critical' : 'warning',
|
|
1326
|
+
learned_from_error_ids: JSON.stringify([error.id]),
|
|
1327
|
+
project_id: error.project_id,
|
|
1328
|
+
confidence: Math.min(0.9, 0.3 + failedAttempts.length * 0.15),
|
|
1329
|
+
});
|
|
1330
|
+
count++;
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
return count;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
```
|
|
1337
|
+
|
|
1338
|
+
## Synapsen-Netzwerk
|
|
1339
|
+
|
|
1340
|
+
### Hebbsches Lernen: "Neurons that fire together, wire together"
|
|
1341
|
+
|
|
1342
|
+
Jede Aktion im System stärkt oder schwächt Synapsen:
|
|
1343
|
+
|
|
1344
|
+
```typescript
|
|
1345
|
+
class SynapseManager {
|
|
1346
|
+
// Synapse erstellen oder stärken
|
|
1347
|
+
strengthen(
|
|
1348
|
+
source: { type: NodeType; id: number },
|
|
1349
|
+
target: { type: NodeType; id: number },
|
|
1350
|
+
synapseType: SynapseType,
|
|
1351
|
+
context?: Record<string, unknown>
|
|
1352
|
+
): void {
|
|
1353
|
+
const existing = this.repo.find(source, target, synapseType);
|
|
1354
|
+
|
|
1355
|
+
if (existing) {
|
|
1356
|
+
// Hebbsche Verstärkung: Gewicht wächst logarithmisch (nie über 1.0)
|
|
1357
|
+
const newWeight = Math.min(1.0,
|
|
1358
|
+
existing.weight + (1.0 - existing.weight) * this.config.learningRate
|
|
1359
|
+
);
|
|
1360
|
+
this.repo.update(existing.id, {
|
|
1361
|
+
weight: newWeight,
|
|
1362
|
+
activation_count: existing.activation_count + 1,
|
|
1363
|
+
last_activated_at: new Date().toISOString(),
|
|
1364
|
+
});
|
|
1365
|
+
} else {
|
|
1366
|
+
this.repo.create({
|
|
1367
|
+
source_type: source.type,
|
|
1368
|
+
source_id: source.id,
|
|
1369
|
+
target_type: target.type,
|
|
1370
|
+
target_id: target.id,
|
|
1371
|
+
synapse_type: synapseType,
|
|
1372
|
+
weight: this.config.initialWeight, // Default: 0.1
|
|
1373
|
+
context: context ? JSON.stringify(context) : null,
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
// Synapse schwächen (bei Fehlschlag oder Ablehnung)
|
|
1379
|
+
weaken(synapseId: number, factor = 0.5): void {
|
|
1380
|
+
const synapse = this.repo.getById(synapseId);
|
|
1381
|
+
if (!synapse) return;
|
|
1382
|
+
|
|
1383
|
+
const newWeight = synapse.weight * factor;
|
|
1384
|
+
if (newWeight < this.config.pruneThreshold) {
|
|
1385
|
+
// Zu schwach → Synapse entfernen
|
|
1386
|
+
this.repo.delete(synapseId);
|
|
1387
|
+
} else {
|
|
1388
|
+
this.repo.update(synapseId, { weight: newWeight });
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// Zeitbasierter Verfall aller Synapsen (im Learning Cycle)
|
|
1393
|
+
decayAll(): number {
|
|
1394
|
+
// Gewicht *= decay_factor für alle Synapsen die seit X Tagen nicht aktiviert wurden
|
|
1395
|
+
const cutoff = new Date();
|
|
1396
|
+
cutoff.setDate(cutoff.getDate() - this.config.decayAfterDays);
|
|
1397
|
+
|
|
1398
|
+
const stale = this.repo.findInactiveSince(cutoff.toISOString());
|
|
1399
|
+
let pruned = 0;
|
|
1400
|
+
|
|
1401
|
+
for (const synapse of stale) {
|
|
1402
|
+
const decay = timeDecay(
|
|
1403
|
+
new Date(synapse.last_activated_at),
|
|
1404
|
+
this.config.decayHalfLifeDays
|
|
1405
|
+
);
|
|
1406
|
+
const newWeight = synapse.weight * decay;
|
|
1407
|
+
|
|
1408
|
+
if (newWeight < this.config.pruneThreshold) {
|
|
1409
|
+
this.repo.delete(synapse.id);
|
|
1410
|
+
pruned++;
|
|
1411
|
+
} else {
|
|
1412
|
+
this.repo.update(synapse.id, { weight: newWeight });
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
return pruned;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
```
|
|
1419
|
+
|
|
1420
|
+
### Wann werden Synapsen erstellt?
|
|
1421
|
+
|
|
1422
|
+
```typescript
|
|
1423
|
+
// In den Event-Listeners des BrainCore:
|
|
1424
|
+
|
|
1425
|
+
// Error gemeldet → Synapse zu Projekt
|
|
1426
|
+
eventBus.on('error:reported', ({ errorId, projectId }) => {
|
|
1427
|
+
synapseManager.strengthen(
|
|
1428
|
+
{ type: 'error', id: errorId },
|
|
1429
|
+
{ type: 'project', id: projectId },
|
|
1430
|
+
'co_occurs'
|
|
1431
|
+
);
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
// Solution löst Error → starke Synapse
|
|
1435
|
+
eventBus.on('solution:applied', ({ solutionId, errorId, outcome }) => {
|
|
1436
|
+
if (outcome === 'success') {
|
|
1437
|
+
synapseManager.strengthen(
|
|
1438
|
+
{ type: 'solution', id: solutionId },
|
|
1439
|
+
{ type: 'error', id: errorId },
|
|
1440
|
+
'solves',
|
|
1441
|
+
{ outcome: 'success' }
|
|
1442
|
+
);
|
|
1443
|
+
} else if (outcome === 'failure') {
|
|
1444
|
+
// Schwäche die Synapse bei Fehlschlag
|
|
1445
|
+
const synapse = synapseManager.find(
|
|
1446
|
+
{ type: 'solution', id: solutionId },
|
|
1447
|
+
{ type: 'error', id: errorId },
|
|
1448
|
+
'solves'
|
|
1449
|
+
);
|
|
1450
|
+
if (synapse) synapseManager.weaken(synapse.id, 0.7);
|
|
1451
|
+
}
|
|
1452
|
+
});
|
|
1453
|
+
|
|
1454
|
+
// Gleicher Error in zwei Projekten → cross_project Synapse
|
|
1455
|
+
eventBus.on('error:cross_project_match', ({ errorId1, errorId2, projectId1, projectId2 }) => {
|
|
1456
|
+
synapseManager.strengthen(
|
|
1457
|
+
{ type: 'error', id: errorId1 },
|
|
1458
|
+
{ type: 'error', id: errorId2 },
|
|
1459
|
+
'similar_to'
|
|
1460
|
+
);
|
|
1461
|
+
synapseManager.strengthen(
|
|
1462
|
+
{ type: 'project', id: projectId1 },
|
|
1463
|
+
{ type: 'project', id: projectId2 },
|
|
1464
|
+
'cross_project'
|
|
1465
|
+
);
|
|
1466
|
+
});
|
|
1467
|
+
|
|
1468
|
+
// Code-Modul wiederverwendet → starke Synapse
|
|
1469
|
+
eventBus.on('module:reused', ({ moduleId, projectId, outcome }) => {
|
|
1470
|
+
synapseManager.strengthen(
|
|
1471
|
+
{ type: 'code_module', id: moduleId },
|
|
1472
|
+
{ type: 'project', id: projectId },
|
|
1473
|
+
'uses_module',
|
|
1474
|
+
{ outcome }
|
|
1475
|
+
);
|
|
1476
|
+
});
|
|
1477
|
+
|
|
1478
|
+
// Solution nutzt Code-Modul → Synapse
|
|
1479
|
+
eventBus.on('solution:uses_code', ({ solutionId, moduleId }) => {
|
|
1480
|
+
synapseManager.strengthen(
|
|
1481
|
+
{ type: 'solution', id: solutionId },
|
|
1482
|
+
{ type: 'code_module', id: moduleId },
|
|
1483
|
+
'uses_module'
|
|
1484
|
+
);
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
// Rule verhindert Error → Synapse stärken
|
|
1488
|
+
eventBus.on('rule:prevented', ({ ruleId, errorId }) => {
|
|
1489
|
+
synapseManager.strengthen(
|
|
1490
|
+
{ type: 'rule', id: ruleId },
|
|
1491
|
+
{ type: 'error', id: errorId },
|
|
1492
|
+
'prevents'
|
|
1493
|
+
);
|
|
1494
|
+
});
|
|
1495
|
+
|
|
1496
|
+
// Error tritt kurz nach anderem Error auf → causal Synapse
|
|
1497
|
+
eventBus.on('error:chain_detected', ({ causeErrorId, effectErrorId }) => {
|
|
1498
|
+
synapseManager.strengthen(
|
|
1499
|
+
{ type: 'error', id: causeErrorId },
|
|
1500
|
+
{ type: 'error', id: effectErrorId },
|
|
1501
|
+
'causes'
|
|
1502
|
+
);
|
|
1503
|
+
});
|
|
1504
|
+
```
|
|
1505
|
+
|
|
1506
|
+
### Spreading Activation (Pfade durch das Netzwerk finden)
|
|
1507
|
+
|
|
1508
|
+
```typescript
|
|
1509
|
+
class SpreadingActivation {
|
|
1510
|
+
// Finde alles was mit einem Knoten zusammenhängt, gewichtet nach Stärke
|
|
1511
|
+
activate(
|
|
1512
|
+
startNode: { type: NodeType; id: number },
|
|
1513
|
+
maxDepth = 3,
|
|
1514
|
+
minWeight = 0.2
|
|
1515
|
+
): ActivationResult[] {
|
|
1516
|
+
const visited = new Set<string>();
|
|
1517
|
+
const results: ActivationResult[] = [];
|
|
1518
|
+
const queue: Array<{
|
|
1519
|
+
node: { type: NodeType; id: number };
|
|
1520
|
+
depth: number;
|
|
1521
|
+
pathWeight: number;
|
|
1522
|
+
path: string[];
|
|
1523
|
+
}> = [{ node: startNode, depth: 0, pathWeight: 1.0, path: [] }];
|
|
1524
|
+
|
|
1525
|
+
while (queue.length > 0) {
|
|
1526
|
+
const current = queue.shift()!;
|
|
1527
|
+
const key = `${current.node.type}:${current.node.id}`;
|
|
1528
|
+
|
|
1529
|
+
if (visited.has(key)) continue;
|
|
1530
|
+
if (current.depth > maxDepth) continue;
|
|
1531
|
+
if (current.pathWeight < minWeight) continue;
|
|
1532
|
+
|
|
1533
|
+
visited.add(key);
|
|
1534
|
+
|
|
1535
|
+
if (current.depth > 0) {
|
|
1536
|
+
results.push({
|
|
1537
|
+
node: current.node,
|
|
1538
|
+
activation: current.pathWeight,
|
|
1539
|
+
depth: current.depth,
|
|
1540
|
+
path: current.path,
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// Alle Synapsen von diesem Knoten holen
|
|
1545
|
+
const synapses = this.repo.getOutgoing(current.node.type, current.node.id);
|
|
1546
|
+
|
|
1547
|
+
for (const synapse of synapses) {
|
|
1548
|
+
const nextWeight = current.pathWeight * synapse.weight;
|
|
1549
|
+
if (nextWeight >= minWeight) {
|
|
1550
|
+
queue.push({
|
|
1551
|
+
node: { type: synapse.target_type, id: synapse.target_id },
|
|
1552
|
+
depth: current.depth + 1,
|
|
1553
|
+
pathWeight: nextWeight,
|
|
1554
|
+
path: [...current.path, `--${synapse.synapse_type}-->`],
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
// Sortiere nach Aktivierungsstärke
|
|
1561
|
+
return results.sort((a, b) => b.activation - a.activation);
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
// Finde den stärksten Pfad zwischen zwei Knoten
|
|
1565
|
+
findPath(
|
|
1566
|
+
from: { type: NodeType; id: number },
|
|
1567
|
+
to: { type: NodeType; id: number },
|
|
1568
|
+
maxDepth = 5
|
|
1569
|
+
): SynapsePath | null {
|
|
1570
|
+
// BFS mit Gewichts-Tracking
|
|
1571
|
+
const visited = new Set<string>();
|
|
1572
|
+
const queue: Array<{
|
|
1573
|
+
node: { type: NodeType; id: number };
|
|
1574
|
+
path: SynapseRecord[];
|
|
1575
|
+
totalWeight: number;
|
|
1576
|
+
}> = [{ node: from, path: [], totalWeight: 1.0 }];
|
|
1577
|
+
|
|
1578
|
+
let bestPath: SynapsePath | null = null;
|
|
1579
|
+
|
|
1580
|
+
while (queue.length > 0) {
|
|
1581
|
+
const current = queue.shift()!;
|
|
1582
|
+
const key = `${current.node.type}:${current.node.id}`;
|
|
1583
|
+
|
|
1584
|
+
if (visited.has(key)) continue;
|
|
1585
|
+
visited.add(key);
|
|
1586
|
+
|
|
1587
|
+
if (current.node.type === to.type && current.node.id === to.id) {
|
|
1588
|
+
if (!bestPath || current.totalWeight > bestPath.totalWeight) {
|
|
1589
|
+
bestPath = {
|
|
1590
|
+
from, to,
|
|
1591
|
+
synapses: current.path,
|
|
1592
|
+
totalWeight: current.totalWeight,
|
|
1593
|
+
hops: current.path.length,
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
continue;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
if (current.path.length >= maxDepth) continue;
|
|
1600
|
+
|
|
1601
|
+
const synapses = this.repo.getOutgoing(current.node.type, current.node.id);
|
|
1602
|
+
for (const synapse of synapses) {
|
|
1603
|
+
queue.push({
|
|
1604
|
+
node: { type: synapse.target_type, id: synapse.target_id },
|
|
1605
|
+
path: [...current.path, synapse],
|
|
1606
|
+
totalWeight: current.totalWeight * synapse.weight,
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
return bestPath;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
```
|
|
1615
|
+
|
|
1616
|
+
### Synapse-Queries (häufige Abfragen)
|
|
1617
|
+
|
|
1618
|
+
```typescript
|
|
1619
|
+
class SynapseService {
|
|
1620
|
+
// "Was weiß Brain alles über diesen Error?"
|
|
1621
|
+
getErrorContext(errorId: number): ErrorContext {
|
|
1622
|
+
const activation = this.spreading.activate(
|
|
1623
|
+
{ type: 'error', id: errorId },
|
|
1624
|
+
maxDepth: 3
|
|
1625
|
+
);
|
|
1626
|
+
|
|
1627
|
+
return {
|
|
1628
|
+
solutions: activation.filter(a => a.node.type === 'solution'),
|
|
1629
|
+
relatedErrors: activation.filter(a => a.node.type === 'error'),
|
|
1630
|
+
relevantModules: activation.filter(a => a.node.type === 'code_module'),
|
|
1631
|
+
preventionRules: activation.filter(a => a.node.type === 'rule'),
|
|
1632
|
+
insights: activation.filter(a => a.node.type === 'insight'),
|
|
1633
|
+
antipatterns: activation.filter(a => a.node.type === 'antipattern'),
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
// "Wie hängen Projekt A und Projekt B zusammen?"
|
|
1638
|
+
getProjectRelation(projectIdA: number, projectIdB: number): ProjectRelation {
|
|
1639
|
+
const path = this.spreading.findPath(
|
|
1640
|
+
{ type: 'project', id: projectIdA },
|
|
1641
|
+
{ type: 'project', id: projectIdB }
|
|
1642
|
+
);
|
|
1643
|
+
|
|
1644
|
+
const sharedErrors = this.repo.findConnected('project', projectIdA, 'project', projectIdB, 'error');
|
|
1645
|
+
const sharedModules = this.repo.findConnected('project', projectIdA, 'project', projectIdB, 'code_module');
|
|
1646
|
+
|
|
1647
|
+
return { path, sharedErrors, sharedModules };
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// "Was sind die stärksten Verbindungen im ganzen Netzwerk?"
|
|
1651
|
+
getStrongestSynapses(limit = 20): SynapseRecord[] {
|
|
1652
|
+
return this.repo.findByWeight(limit);
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// Netzwerk-Statistiken
|
|
1656
|
+
getNetworkStats(): NetworkStats {
|
|
1657
|
+
return {
|
|
1658
|
+
totalNodes: this.repo.countNodes(),
|
|
1659
|
+
totalSynapses: this.repo.countSynapses(),
|
|
1660
|
+
avgWeight: this.repo.avgWeight(),
|
|
1661
|
+
strongSynapses: this.repo.countByWeightThreshold(0.7),
|
|
1662
|
+
weakSynapses: this.repo.countByWeightThreshold(0.2, 'below'),
|
|
1663
|
+
synapsesByType: this.repo.countByType(),
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
```
|
|
1668
|
+
|
|
1669
|
+
## Research Brain (Forscher-Hirn)
|
|
1670
|
+
|
|
1671
|
+
Das Research Brain läuft als eigener Scheduled Cycle (langsamer als Learning Engine, z.B. alle 60 Minuten) und analysiert das Gesamtnetzwerk aus Errors, Solutions, Code-Modulen und Synapsen.
|
|
1672
|
+
|
|
1673
|
+
### Forschungs-Zyklus
|
|
1674
|
+
|
|
1675
|
+
```typescript
|
|
1676
|
+
class ResearchEngine {
|
|
1677
|
+
private timer: NodeJS.Timeout | null = null;
|
|
1678
|
+
|
|
1679
|
+
startSchedule(intervalMs: number): void {
|
|
1680
|
+
// Erster Cycle nach 5 Minuten (Brain soll erstmal Daten sammeln)
|
|
1681
|
+
setTimeout(() => {
|
|
1682
|
+
this.runCycle();
|
|
1683
|
+
this.timer = setInterval(() => this.runCycle(), intervalMs);
|
|
1684
|
+
}, 5 * 60_000);
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
stop(): void {
|
|
1688
|
+
if (this.timer) clearInterval(this.timer);
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
async runCycle(): Promise<ResearchCycleResult> {
|
|
1692
|
+
const result: ResearchCycleResult = {
|
|
1693
|
+
trendsFound: 0,
|
|
1694
|
+
patternsFound: 0,
|
|
1695
|
+
gapsFound: 0,
|
|
1696
|
+
synergiesFound: 0,
|
|
1697
|
+
templatesFound: 0,
|
|
1698
|
+
suggestionsGenerated: 0,
|
|
1699
|
+
};
|
|
1700
|
+
|
|
1701
|
+
// Phase 1: Trend-Analyse
|
|
1702
|
+
// Was wird besser? Was wird schlechter? Zeitreihen über Error-Frequenz, Solution-Erfolgsrate
|
|
1703
|
+
result.trendsFound = await this.analyzeTrends();
|
|
1704
|
+
|
|
1705
|
+
// Phase 2: Gap-Analyse
|
|
1706
|
+
// Wiederkehrende ungelöste Probleme, fehlende Module, schwache Synapsen
|
|
1707
|
+
result.gapsFound = await this.analyzeGaps();
|
|
1708
|
+
|
|
1709
|
+
// Phase 3: Synergie-Detektion
|
|
1710
|
+
// Module die zusammen stark sind, Projekte die voneinander lernen können
|
|
1711
|
+
result.synergiesFound = await this.detectSynergies();
|
|
1712
|
+
|
|
1713
|
+
// Phase 4: Template-Extraktion
|
|
1714
|
+
// Wiederholte Code-Patterns die zu Templates generalisiert werden können
|
|
1715
|
+
result.templatesFound = await this.extractTemplates();
|
|
1716
|
+
|
|
1717
|
+
// Phase 5: Projekt-Vorschläge
|
|
1718
|
+
// Basierend auf vorhandenen Modulen und Patterns: was könnte man noch bauen?
|
|
1719
|
+
result.suggestionsGenerated = await this.generateSuggestions();
|
|
1720
|
+
|
|
1721
|
+
// Phase 6: Insight-Prioritisierung
|
|
1722
|
+
// Bestehende Insights neu bewerten, abgelaufene entfernen
|
|
1723
|
+
await this.prioritizeInsights();
|
|
1724
|
+
|
|
1725
|
+
// Phase 7: Synapsen-Pflege
|
|
1726
|
+
// Schwache Synapsen prunen, starke Cluster identifizieren
|
|
1727
|
+
await this.synapseManager.decayAll();
|
|
1728
|
+
|
|
1729
|
+
return result;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
```
|
|
1733
|
+
|
|
1734
|
+
### Trend-Analyse
|
|
1735
|
+
|
|
1736
|
+
```typescript
|
|
1737
|
+
class TrendAnalyzer {
|
|
1738
|
+
analyze(): Insight[] {
|
|
1739
|
+
const insights: Insight[] = [];
|
|
1740
|
+
const projects = this.projectRepo.getAll();
|
|
1741
|
+
|
|
1742
|
+
for (const project of projects) {
|
|
1743
|
+
// Error-Frequenz über Zeit (letzte 7 Tage vs. 7 Tage davor)
|
|
1744
|
+
const recentErrors = this.errorRepo.countSince(project.id, 7);
|
|
1745
|
+
const previousErrors = this.errorRepo.countBetween(project.id, 14, 7);
|
|
1746
|
+
|
|
1747
|
+
if (previousErrors > 0) {
|
|
1748
|
+
const changeRate = (recentErrors - previousErrors) / previousErrors;
|
|
1749
|
+
|
|
1750
|
+
if (changeRate < -0.3) {
|
|
1751
|
+
insights.push({
|
|
1752
|
+
insight_type: 'trend',
|
|
1753
|
+
title: `Error-Rate in ${project.name} sinkt`,
|
|
1754
|
+
description: `${Math.round(-changeRate * 100)}% weniger Fehler in den letzten 7 Tagen vs. Vorwoche. Was auch immer du machst - es funktioniert.`,
|
|
1755
|
+
evidence: JSON.stringify({ recentErrors, previousErrors, changeRate }),
|
|
1756
|
+
confidence: Math.min(0.9, 0.5 + Math.abs(changeRate) * 0.5),
|
|
1757
|
+
priority: 'low',
|
|
1758
|
+
});
|
|
1759
|
+
} else if (changeRate > 0.5) {
|
|
1760
|
+
insights.push({
|
|
1761
|
+
insight_type: 'trend',
|
|
1762
|
+
title: `Error-Rate in ${project.name} steigt stark`,
|
|
1763
|
+
description: `${Math.round(changeRate * 100)}% mehr Fehler. Mögliche Ursachen prüfen: neue Dependencies, Refactoring, API-Änderungen.`,
|
|
1764
|
+
evidence: JSON.stringify({ recentErrors, previousErrors, changeRate }),
|
|
1765
|
+
confidence: Math.min(0.9, 0.5 + changeRate * 0.3),
|
|
1766
|
+
priority: 'high',
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
// Solution-Erfolgsrate-Trend
|
|
1772
|
+
const recentSuccessRate = this.solutionRepo.successRate(project.id, 14);
|
|
1773
|
+
const overallSuccessRate = this.solutionRepo.successRate(project.id);
|
|
1774
|
+
|
|
1775
|
+
if (recentSuccessRate < overallSuccessRate - 0.15) {
|
|
1776
|
+
insights.push({
|
|
1777
|
+
insight_type: 'trend',
|
|
1778
|
+
title: `Lösungsqualität in ${project.name} sinkt`,
|
|
1779
|
+
description: `Aktuelle Erfolgsrate ${Math.round(recentSuccessRate * 100)}% vs. Durchschnitt ${Math.round(overallSuccessRate * 100)}%. Lösungen werden weniger effektiv.`,
|
|
1780
|
+
evidence: JSON.stringify({ recentSuccessRate, overallSuccessRate }),
|
|
1781
|
+
confidence: 0.7,
|
|
1782
|
+
priority: 'medium',
|
|
1783
|
+
actionable: true,
|
|
1784
|
+
suggested_action: JSON.stringify({
|
|
1785
|
+
action: 'review_recent_solutions',
|
|
1786
|
+
message: 'Letzte Lösungen prüfen - stimmen die Ansätze noch?',
|
|
1787
|
+
}),
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
return insights;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
```
|
|
1796
|
+
|
|
1797
|
+
### Gap-Analyse
|
|
1798
|
+
|
|
1799
|
+
```typescript
|
|
1800
|
+
class GapAnalyzer {
|
|
1801
|
+
analyze(): Insight[] {
|
|
1802
|
+
const insights: Insight[] = [];
|
|
1803
|
+
|
|
1804
|
+
// 1. Wiederkehrende ungelöste Errors
|
|
1805
|
+
const unresolvedRecurring = this.errorRepo.findUnresolvedRecurring(5);
|
|
1806
|
+
for (const error of unresolvedRecurring) {
|
|
1807
|
+
insights.push({
|
|
1808
|
+
insight_type: 'gap',
|
|
1809
|
+
title: `Ungelöster wiederkehrender Fehler: ${error.error_type}`,
|
|
1810
|
+
description: `"${error.message.substring(0, 80)}..." ist ${error.occurrence_count}x aufgetreten und hat keine erfolgreiche Lösung. Das kostet Zeit.`,
|
|
1811
|
+
evidence: JSON.stringify({ errorId: error.id, occurrences: error.occurrence_count }),
|
|
1812
|
+
confidence: Math.min(0.95, 0.5 + error.occurrence_count * 0.1),
|
|
1813
|
+
priority: error.occurrence_count >= 10 ? 'critical' : 'high',
|
|
1814
|
+
actionable: true,
|
|
1815
|
+
suggested_action: JSON.stringify({
|
|
1816
|
+
action: 'investigate_error',
|
|
1817
|
+
error_id: error.id,
|
|
1818
|
+
message: 'Grundursache untersuchen und nachhaltige Lösung finden',
|
|
1819
|
+
}),
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
// 2. Fehlende Code-Module (Funktionalität die in mehreren Projekten gebraucht wird)
|
|
1824
|
+
const commonErrors = this.findCommonErrorPatternsAcrossProjects();
|
|
1825
|
+
for (const pattern of commonErrors) {
|
|
1826
|
+
if (pattern.projectCount >= 2 && !pattern.hasSolution) {
|
|
1827
|
+
insights.push({
|
|
1828
|
+
insight_type: 'gap',
|
|
1829
|
+
title: `Gemeinsames Problem ohne gemeinsame Lösung`,
|
|
1830
|
+
description: `${pattern.projectCount} Projekte haben "${pattern.errorTemplate}" - aber kein geteiltes Modul löst das.`,
|
|
1831
|
+
confidence: 0.7,
|
|
1832
|
+
priority: 'medium',
|
|
1833
|
+
actionable: true,
|
|
1834
|
+
suggested_action: JSON.stringify({
|
|
1835
|
+
action: 'create_shared_module',
|
|
1836
|
+
message: `Shared utility erstellen das ${pattern.errorTemplate} in allen Projekten verhindert`,
|
|
1837
|
+
}),
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// 3. Schwache Synapsen-Cluster (isolierte Knoten ohne Verbindungen)
|
|
1843
|
+
const isolated = this.synapseRepo.findIsolatedNodes();
|
|
1844
|
+
if (isolated.errors.length > 5) {
|
|
1845
|
+
insights.push({
|
|
1846
|
+
insight_type: 'gap',
|
|
1847
|
+
title: `${isolated.errors.length} Fehler ohne Vernetzung`,
|
|
1848
|
+
description: `Diese Fehler haben keine Synapsen zu Lösungen, Modulen oder anderen Fehlern. Brain kann sie nicht einordnen.`,
|
|
1849
|
+
confidence: 0.6,
|
|
1850
|
+
priority: 'low',
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
return insights;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
```
|
|
1858
|
+
|
|
1859
|
+
### Synergie-Detektion
|
|
1860
|
+
|
|
1861
|
+
```typescript
|
|
1862
|
+
class SynergyDetector {
|
|
1863
|
+
detect(): Insight[] {
|
|
1864
|
+
const insights: Insight[] = [];
|
|
1865
|
+
|
|
1866
|
+
// 1. Module die zusammen genutzt werden (starke co_occurs Synapsen)
|
|
1867
|
+
const modulePairs = this.synapseRepo.findStrongPairs('code_module', 'code_module', 'co_occurs', 0.5);
|
|
1868
|
+
for (const pair of modulePairs) {
|
|
1869
|
+
insights.push({
|
|
1870
|
+
insight_type: 'synergy',
|
|
1871
|
+
title: `Module "${pair.sourceName}" + "${pair.targetName}" sind ein starkes Team`,
|
|
1872
|
+
description: `Diese Module werden in ${pair.coUsageCount} Projekten zusammen genutzt. Zusammen als Package veröffentlichen?`,
|
|
1873
|
+
evidence: JSON.stringify(pair),
|
|
1874
|
+
confidence: Math.min(0.9, pair.weight),
|
|
1875
|
+
priority: 'medium',
|
|
1876
|
+
actionable: true,
|
|
1877
|
+
suggested_action: JSON.stringify({
|
|
1878
|
+
action: 'combine_modules',
|
|
1879
|
+
module_ids: [pair.sourceId, pair.targetId],
|
|
1880
|
+
message: 'Zu einem kombinierten Package zusammenfassen',
|
|
1881
|
+
}),
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
// 2. Projekte die voneinander lernen können
|
|
1886
|
+
const projectPairs = this.findProjectSynergies();
|
|
1887
|
+
for (const pair of projectPairs) {
|
|
1888
|
+
if (pair.transferableSolutions.length >= 2) {
|
|
1889
|
+
insights.push({
|
|
1890
|
+
insight_type: 'synergy',
|
|
1891
|
+
title: `${pair.projectA.name} hat Lösungen die ${pair.projectB.name} braucht`,
|
|
1892
|
+
description: `${pair.transferableSolutions.length} Lösungen aus ${pair.projectA.name} könnten in ${pair.projectB.name} helfen.`,
|
|
1893
|
+
evidence: JSON.stringify(pair.transferableSolutions.map(s => s.id)),
|
|
1894
|
+
confidence: 0.7,
|
|
1895
|
+
priority: 'medium',
|
|
1896
|
+
actionable: true,
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// 3. Error-Solution-Chains die sich zu einem Workflow zusammensetzen lassen
|
|
1902
|
+
const workflows = this.findWorkflowPatterns();
|
|
1903
|
+
for (const wf of workflows) {
|
|
1904
|
+
insights.push({
|
|
1905
|
+
insight_type: 'synergy',
|
|
1906
|
+
title: `Wiederkehrender Workflow erkannt: ${wf.name}`,
|
|
1907
|
+
description: `Die Sequenz ${wf.steps.join(' → ')} wiederholt sich. Automatisierung möglich?`,
|
|
1908
|
+
evidence: JSON.stringify(wf),
|
|
1909
|
+
confidence: wf.occurrences >= 3 ? 0.8 : 0.5,
|
|
1910
|
+
priority: wf.occurrences >= 5 ? 'high' : 'medium',
|
|
1911
|
+
actionable: true,
|
|
1912
|
+
suggested_action: JSON.stringify({
|
|
1913
|
+
action: 'automate_workflow',
|
|
1914
|
+
steps: wf.steps,
|
|
1915
|
+
message: 'Script oder Template erstellen das diese Sequenz automatisiert',
|
|
1916
|
+
}),
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
return insights;
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
```
|
|
1924
|
+
|
|
1925
|
+
### Template-Extraktion
|
|
1926
|
+
|
|
1927
|
+
```typescript
|
|
1928
|
+
class TemplateExtractor {
|
|
1929
|
+
extract(): Insight[] {
|
|
1930
|
+
const insights: Insight[] = [];
|
|
1931
|
+
|
|
1932
|
+
// Finde Code-Module die in >= 3 Projekten in adaptierter Form existieren
|
|
1933
|
+
const adaptedModules = this.codeModuleRepo.findWithMultipleAdaptations(3);
|
|
1934
|
+
|
|
1935
|
+
for (const group of adaptedModules) {
|
|
1936
|
+
// Extrahiere das Gemeinsame aus allen Adaptationen
|
|
1937
|
+
const commonStructure = this.findCommonStructure(group.modules);
|
|
1938
|
+
|
|
1939
|
+
if (commonStructure.similarity >= 0.6) {
|
|
1940
|
+
insights.push({
|
|
1941
|
+
insight_type: 'template_candidate',
|
|
1942
|
+
title: `Template-Kandidat: "${group.baseName}"`,
|
|
1943
|
+
description: `${group.modules.length} Varianten in ${group.projectCount} Projekten. Gemeinsame Struktur: ${Math.round(commonStructure.similarity * 100)}%. Ein parametrisiertes Template würde Duplikation eliminieren.`,
|
|
1944
|
+
evidence: JSON.stringify({
|
|
1945
|
+
moduleIds: group.modules.map(m => m.id),
|
|
1946
|
+
commonParts: commonStructure.commonParts,
|
|
1947
|
+
variableParts: commonStructure.variableParts,
|
|
1948
|
+
}),
|
|
1949
|
+
confidence: commonStructure.similarity,
|
|
1950
|
+
priority: group.projectCount >= 3 ? 'high' : 'medium',
|
|
1951
|
+
actionable: true,
|
|
1952
|
+
suggested_action: JSON.stringify({
|
|
1953
|
+
action: 'create_template',
|
|
1954
|
+
base_module_id: group.bestModule.id,
|
|
1955
|
+
parameters: commonStructure.variableParts,
|
|
1956
|
+
message: `Template erstellen mit Parametern: ${commonStructure.variableParts.join(', ')}`,
|
|
1957
|
+
}),
|
|
1958
|
+
});
|
|
1959
|
+
|
|
1960
|
+
// Synapse: Template-Insight → alle beteiligten Module
|
|
1961
|
+
for (const mod of group.modules) {
|
|
1962
|
+
this.synapseManager.strengthen(
|
|
1963
|
+
{ type: 'insight', id: insights[insights.length - 1].id! },
|
|
1964
|
+
{ type: 'code_module', id: mod.id },
|
|
1965
|
+
'generalizes'
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
return insights;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
```
|
|
1975
|
+
|
|
1976
|
+
### Projekt-Vorschläge
|
|
1977
|
+
|
|
1978
|
+
```typescript
|
|
1979
|
+
class ProjectSuggestionGenerator {
|
|
1980
|
+
generate(): Insight[] {
|
|
1981
|
+
const insights: Insight[] = [];
|
|
1982
|
+
const modules = this.codeModuleRepo.getAll();
|
|
1983
|
+
const projects = this.projectRepo.getAll();
|
|
1984
|
+
|
|
1985
|
+
// 1. Analyse: Welche Funktionalität existiert bereits verteilt?
|
|
1986
|
+
const capabilities = this.categorizeModules(modules);
|
|
1987
|
+
|
|
1988
|
+
// Beispiel: Wenn du auth, database, api-client, validation hast → "Du könntest ein Backend-Template bauen"
|
|
1989
|
+
const templateSuggestions = this.checkForProjectTemplates(capabilities);
|
|
1990
|
+
for (const suggestion of templateSuggestions) {
|
|
1991
|
+
insights.push({
|
|
1992
|
+
insight_type: 'project_suggestion',
|
|
1993
|
+
title: suggestion.title,
|
|
1994
|
+
description: suggestion.description,
|
|
1995
|
+
evidence: JSON.stringify(suggestion.modules),
|
|
1996
|
+
confidence: suggestion.coverage,
|
|
1997
|
+
priority: suggestion.coverage >= 0.7 ? 'medium' : 'low',
|
|
1998
|
+
actionable: true,
|
|
1999
|
+
suggested_action: JSON.stringify({
|
|
2000
|
+
action: 'create_project_template',
|
|
2001
|
+
modules: suggestion.modules,
|
|
2002
|
+
message: suggestion.description,
|
|
2003
|
+
}),
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// 2. Schwachstellen die ein eigenes Tool verdienen
|
|
2008
|
+
const recurringPain = this.findRecurringPainPoints();
|
|
2009
|
+
for (const pain of recurringPain) {
|
|
2010
|
+
insights.push({
|
|
2011
|
+
insight_type: 'project_suggestion',
|
|
2012
|
+
title: `Tool-Idee: ${pain.suggestedToolName}`,
|
|
2013
|
+
description: `Du verbringst wiederholt Zeit mit "${pain.description}". Ein dediziertes Tool könnte das automatisieren.`,
|
|
2014
|
+
evidence: JSON.stringify(pain.evidence),
|
|
2015
|
+
confidence: pain.confidence,
|
|
2016
|
+
priority: pain.timeWasted >= 10 ? 'high' : 'medium',
|
|
2017
|
+
actionable: true,
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
return insights;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
private checkForProjectTemplates(
|
|
2025
|
+
capabilities: Map<string, CodeModule[]>
|
|
2026
|
+
): ProjectTemplateSuggestion[] {
|
|
2027
|
+
const suggestions: ProjectTemplateSuggestion[] = [];
|
|
2028
|
+
|
|
2029
|
+
// Bekannte Kombinationen die ein Projekt ergeben
|
|
2030
|
+
const templates: Array<{ name: string; required: string[]; optional: string[] }> = [
|
|
2031
|
+
{
|
|
2032
|
+
name: 'REST API Template',
|
|
2033
|
+
required: ['http-server', 'routing', 'database', 'validation'],
|
|
2034
|
+
optional: ['auth', 'logging', 'rate-limiting', 'caching'],
|
|
2035
|
+
},
|
|
2036
|
+
{
|
|
2037
|
+
name: 'CLI Tool Template',
|
|
2038
|
+
required: ['argument-parsing', 'config', 'logging'],
|
|
2039
|
+
optional: ['interactive-prompts', 'progress-bar', 'file-operations'],
|
|
2040
|
+
},
|
|
2041
|
+
{
|
|
2042
|
+
name: 'Data Pipeline Template',
|
|
2043
|
+
required: ['file-reading', 'data-transformation', 'output-writing'],
|
|
2044
|
+
optional: ['validation', 'error-handling', 'progress-tracking'],
|
|
2045
|
+
},
|
|
2046
|
+
];
|
|
2047
|
+
|
|
2048
|
+
for (const template of templates) {
|
|
2049
|
+
const foundRequired = template.required.filter(r => capabilities.has(r));
|
|
2050
|
+
const foundOptional = template.optional.filter(o => capabilities.has(o));
|
|
2051
|
+
const coverage = foundRequired.length / template.required.length;
|
|
2052
|
+
|
|
2053
|
+
if (coverage >= 0.5) {
|
|
2054
|
+
suggestions.push({
|
|
2055
|
+
title: template.name,
|
|
2056
|
+
description: `Du hast ${foundRequired.length}/${template.required.length} Kern-Module und ${foundOptional.length} Extras. ${coverage >= 0.75 ? 'Fast komplett!' : 'Guter Anfang.'}`,
|
|
2057
|
+
modules: [...foundRequired, ...foundOptional].flatMap(c => capabilities.get(c) || []),
|
|
2058
|
+
coverage,
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
return suggestions;
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
```
|
|
2067
|
+
|
|
2068
|
+
## Error-Parser Registry
|
|
2069
|
+
|
|
2070
|
+
```typescript
|
|
2071
|
+
interface ErrorParser {
|
|
2072
|
+
name: string;
|
|
2073
|
+
priority: number; // Höher = wird zuerst versucht
|
|
2074
|
+
canParse: (input: string) => boolean; // Kann dieser Parser den Input verarbeiten?
|
|
2075
|
+
parse: (input: string) => ParsedError | null;
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
interface ParsedError {
|
|
2079
|
+
errorType: string;
|
|
2080
|
+
message: string;
|
|
2081
|
+
stackTrace?: string;
|
|
2082
|
+
frames: StackFrame[];
|
|
2083
|
+
sourceFile?: string;
|
|
2084
|
+
sourceLine?: number;
|
|
2085
|
+
language?: string;
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
class ErrorParserRegistry {
|
|
2089
|
+
private parsers: ErrorParser[] = [];
|
|
2090
|
+
|
|
2091
|
+
register(parser: ErrorParser): void {
|
|
2092
|
+
this.parsers.push(parser);
|
|
2093
|
+
this.parsers.sort((a, b) => b.priority - a.priority);
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
parse(input: string): ParsedError | null {
|
|
2097
|
+
for (const parser of this.parsers) {
|
|
2098
|
+
if (parser.canParse(input)) {
|
|
2099
|
+
const result = parser.parse(input);
|
|
2100
|
+
if (result) return result;
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
return null;
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
// Beispiel: Node.js Parser
|
|
2108
|
+
const nodeParser: ErrorParser = {
|
|
2109
|
+
name: 'node',
|
|
2110
|
+
priority: 10,
|
|
2111
|
+
canParse: (input) =>
|
|
2112
|
+
/at .+ \(.+:\d+:\d+\)/.test(input) || // V8 Stack-Trace
|
|
2113
|
+
/^\w*Error:/.test(input) || // Error: ...
|
|
2114
|
+
/^\w*TypeError:/.test(input), // TypeError: ...
|
|
2115
|
+
parse: (input) => {
|
|
2116
|
+
const messageMatch = input.match(/^(\w+(?:Error|Exception)?): (.+)$/m);
|
|
2117
|
+
if (!messageMatch) return null;
|
|
2118
|
+
|
|
2119
|
+
const frames: StackFrame[] = [];
|
|
2120
|
+
const frameRegex = /at (?:(.+?) )?\((.+?):(\d+):(\d+)\)/g;
|
|
2121
|
+
let match;
|
|
2122
|
+
while ((match = frameRegex.exec(input)) !== null) {
|
|
2123
|
+
frames.push({
|
|
2124
|
+
function_name: match[1] || '<anonymous>',
|
|
2125
|
+
file_path: match[2],
|
|
2126
|
+
line_number: parseInt(match[3]),
|
|
2127
|
+
column_number: parseInt(match[4]),
|
|
2128
|
+
});
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
return {
|
|
2132
|
+
errorType: messageMatch[1],
|
|
2133
|
+
message: messageMatch[2],
|
|
2134
|
+
stackTrace: input,
|
|
2135
|
+
frames,
|
|
2136
|
+
sourceFile: frames[0]?.file_path,
|
|
2137
|
+
sourceLine: frames[0]?.line_number,
|
|
2138
|
+
language: 'javascript',
|
|
2139
|
+
};
|
|
2140
|
+
}
|
|
2141
|
+
};
|
|
2142
|
+
|
|
2143
|
+
// Beispiel: Python Parser
|
|
2144
|
+
const pythonParser: ErrorParser = {
|
|
2145
|
+
name: 'python',
|
|
2146
|
+
priority: 10,
|
|
2147
|
+
canParse: (input) =>
|
|
2148
|
+
/Traceback \(most recent call last\)/.test(input) ||
|
|
2149
|
+
/File ".+", line \d+/.test(input),
|
|
2150
|
+
parse: (input) => {
|
|
2151
|
+
const frames: StackFrame[] = [];
|
|
2152
|
+
const frameRegex = /File "(.+?)", line (\d+), in (.+)/g;
|
|
2153
|
+
let match;
|
|
2154
|
+
while ((match = frameRegex.exec(input)) !== null) {
|
|
2155
|
+
frames.push({
|
|
2156
|
+
function_name: match[3],
|
|
2157
|
+
file_path: match[1],
|
|
2158
|
+
line_number: parseInt(match[2]),
|
|
2159
|
+
});
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
const errorMatch = input.match(/^(\w+(?:Error|Exception)?): (.+)$/m);
|
|
2163
|
+
return {
|
|
2164
|
+
errorType: errorMatch?.[1] || 'Error',
|
|
2165
|
+
message: errorMatch?.[2] || input.split('\n').pop() || input,
|
|
2166
|
+
stackTrace: input,
|
|
2167
|
+
frames,
|
|
2168
|
+
sourceFile: frames[frames.length - 1]?.file_path,
|
|
2169
|
+
sourceLine: frames[frames.length - 1]?.line_number,
|
|
2170
|
+
language: 'python',
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
|
|
2175
|
+
// Beispiel: Shell Parser
|
|
2176
|
+
const shellParser: ErrorParser = {
|
|
2177
|
+
name: 'shell',
|
|
2178
|
+
priority: 5,
|
|
2179
|
+
canParse: (input) =>
|
|
2180
|
+
/command not found/.test(input) ||
|
|
2181
|
+
/Permission denied/.test(input) ||
|
|
2182
|
+
/No such file or directory/.test(input) ||
|
|
2183
|
+
/ENOENT|EACCES|ECONNREFUSED/.test(input),
|
|
2184
|
+
parse: (input) => {
|
|
2185
|
+
const message = input.split('\n')[0].trim();
|
|
2186
|
+
let errorType = 'ShellError';
|
|
2187
|
+
if (/command not found/.test(input)) errorType = 'CommandNotFound';
|
|
2188
|
+
if (/Permission denied|EACCES/.test(input)) errorType = 'PermissionError';
|
|
2189
|
+
if (/No such file|ENOENT/.test(input)) errorType = 'FileNotFound';
|
|
2190
|
+
if (/ECONNREFUSED/.test(input)) errorType = 'ConnectionRefused';
|
|
2191
|
+
|
|
2192
|
+
return {
|
|
2193
|
+
errorType,
|
|
2194
|
+
message,
|
|
2195
|
+
frames: [],
|
|
2196
|
+
language: 'shell',
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
};
|
|
2200
|
+
|
|
2201
|
+
// Generischer Fallback
|
|
2202
|
+
const genericParser: ErrorParser = {
|
|
2203
|
+
name: 'generic',
|
|
2204
|
+
priority: 0,
|
|
2205
|
+
canParse: () => true, // Fängt alles auf
|
|
2206
|
+
parse: (input) => {
|
|
2207
|
+
const firstLine = input.split('\n')[0].trim();
|
|
2208
|
+
const errorMatch = firstLine.match(/^(?:error|Error|ERROR)[\s:]+(.+)/i);
|
|
2209
|
+
return {
|
|
2210
|
+
errorType: 'GenericError',
|
|
2211
|
+
message: errorMatch?.[1] || firstLine,
|
|
2212
|
+
stackTrace: input.includes('\n') ? input : undefined,
|
|
2213
|
+
frames: [],
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
};
|
|
2217
|
+
```
|
|
2218
|
+
|
|
2219
|
+
## IPC-Architektur
|
|
2220
|
+
|
|
2221
|
+
### Protocol (Length-prefixed JSON Framing)
|
|
2222
|
+
```typescript
|
|
2223
|
+
// Framing: [4 Byte Length (Big Endian)][JSON Payload]
|
|
2224
|
+
// Kein Delimiter-Problem, keine partielle Message Issues
|
|
2225
|
+
|
|
2226
|
+
interface IpcMessage {
|
|
2227
|
+
id: string; // Request-ID für Response-Zuordnung
|
|
2228
|
+
type: 'request' | 'response' | 'notification';
|
|
2229
|
+
method?: string; // z.B. 'error.report', 'code.find'
|
|
2230
|
+
params?: unknown;
|
|
2231
|
+
result?: unknown;
|
|
2232
|
+
error?: { code: number; message: string };
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
function encodeMessage(msg: IpcMessage): Buffer {
|
|
2236
|
+
const json = JSON.stringify(msg);
|
|
2237
|
+
const payload = Buffer.from(json, 'utf8');
|
|
2238
|
+
const frame = Buffer.alloc(4 + payload.length);
|
|
2239
|
+
frame.writeUInt32BE(payload.length, 0);
|
|
2240
|
+
payload.copy(frame, 4);
|
|
2241
|
+
return frame;
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
class MessageDecoder {
|
|
2245
|
+
private buffer = Buffer.alloc(0);
|
|
2246
|
+
|
|
2247
|
+
feed(chunk: Buffer): IpcMessage[] {
|
|
2248
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
2249
|
+
const messages: IpcMessage[] = [];
|
|
2250
|
+
|
|
2251
|
+
while (this.buffer.length >= 4) {
|
|
2252
|
+
const length = this.buffer.readUInt32BE(0);
|
|
2253
|
+
if (this.buffer.length < 4 + length) break;
|
|
2254
|
+
|
|
2255
|
+
const json = this.buffer.subarray(4, 4 + length).toString('utf8');
|
|
2256
|
+
this.buffer = this.buffer.subarray(4 + length);
|
|
2257
|
+
messages.push(JSON.parse(json));
|
|
2258
|
+
}
|
|
2259
|
+
return messages;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
```
|
|
2263
|
+
|
|
2264
|
+
### IPC Router
|
|
2265
|
+
```typescript
|
|
2266
|
+
const methods = {
|
|
2267
|
+
// Terminal Lifecycle
|
|
2268
|
+
'terminal.register': (p) => terminalService.register(p),
|
|
2269
|
+
'terminal.heartbeat': (p) => terminalService.heartbeat(p),
|
|
2270
|
+
'terminal.disconnect': (p) => terminalService.disconnect(p),
|
|
2271
|
+
|
|
2272
|
+
// Error Brain
|
|
2273
|
+
'error.report': (p) => errorService.report(p),
|
|
2274
|
+
'error.query': (p) => errorService.query(p),
|
|
2275
|
+
'error.match': (p) => errorService.matchSimilar(p),
|
|
2276
|
+
'solution.report': (p) => solutionService.report(p),
|
|
2277
|
+
'solution.query': (p) => solutionService.query(p),
|
|
2278
|
+
'solution.rate': (p) => solutionService.rateOutcome(p),
|
|
2279
|
+
'solution.attempt': (p) => solutionService.reportAttempt(p),
|
|
2280
|
+
|
|
2281
|
+
// Code Brain
|
|
2282
|
+
'code.analyze': (p) => codeService.analyzeAndRegister(p),
|
|
2283
|
+
'code.find': (p) => codeService.findReusable(p),
|
|
2284
|
+
'code.similarity': (p) => codeService.checkSimilarity(p),
|
|
2285
|
+
'code.modules': (p) => codeService.listModules(p),
|
|
2286
|
+
'code.usage': (p) => codeService.reportUsage(p),
|
|
2287
|
+
|
|
2288
|
+
// Prevention
|
|
2289
|
+
'prevention.check': (p) => preventionService.checkRules(p),
|
|
2290
|
+
'prevention.antipatterns': (p) => preventionService.checkAntipatterns(p),
|
|
2291
|
+
|
|
2292
|
+
// Synapsen
|
|
2293
|
+
'synapse.context': (p) => synapseService.getErrorContext(p),
|
|
2294
|
+
'synapse.path': (p) => synapseService.findPath(p),
|
|
2295
|
+
'synapse.related': (p) => synapseService.getRelated(p),
|
|
2296
|
+
'synapse.stats': (p) => synapseService.getNetworkStats(),
|
|
2297
|
+
|
|
2298
|
+
// Research / Insights
|
|
2299
|
+
'research.insights': (p) => researchService.getInsights(p),
|
|
2300
|
+
'research.suggest': (p) => researchService.getSuggestions(p),
|
|
2301
|
+
'research.trends': (p) => researchService.getTrends(p),
|
|
2302
|
+
|
|
2303
|
+
// Notifications
|
|
2304
|
+
'notification.list': (p) => notificationService.list(p),
|
|
2305
|
+
'notification.ack': (p) => notificationService.acknowledge(p),
|
|
2306
|
+
|
|
2307
|
+
// Analytics
|
|
2308
|
+
'analytics.summary': (p) => analyticsService.getSummary(p),
|
|
2309
|
+
'analytics.network': (p) => analyticsService.getNetworkOverview(p),
|
|
2310
|
+
};
|
|
2311
|
+
```
|
|
2312
|
+
|
|
2313
|
+
### Named Pipe Server
|
|
2314
|
+
```typescript
|
|
2315
|
+
import net from 'net';
|
|
2316
|
+
|
|
2317
|
+
class IpcServer {
|
|
2318
|
+
private server: net.Server;
|
|
2319
|
+
private clients = new Map<string, net.Socket>();
|
|
2320
|
+
|
|
2321
|
+
constructor(
|
|
2322
|
+
private router: IpcRouter,
|
|
2323
|
+
private config: IpcConfig
|
|
2324
|
+
) {}
|
|
2325
|
+
|
|
2326
|
+
start(): void {
|
|
2327
|
+
this.server = net.createServer((socket) => {
|
|
2328
|
+
const clientId = randomUUID();
|
|
2329
|
+
this.clients.set(clientId, socket);
|
|
2330
|
+
const decoder = new MessageDecoder();
|
|
2331
|
+
|
|
2332
|
+
socket.on('data', (chunk) => {
|
|
2333
|
+
const messages = decoder.feed(chunk);
|
|
2334
|
+
for (const msg of messages) {
|
|
2335
|
+
this.handleMessage(clientId, msg, socket);
|
|
2336
|
+
}
|
|
2337
|
+
});
|
|
2338
|
+
|
|
2339
|
+
socket.on('close', () => {
|
|
2340
|
+
this.clients.delete(clientId);
|
|
2341
|
+
});
|
|
2342
|
+
|
|
2343
|
+
socket.on('error', (err) => {
|
|
2344
|
+
logger.error(`Client ${clientId} error:`, err);
|
|
2345
|
+
this.clients.delete(clientId);
|
|
2346
|
+
});
|
|
2347
|
+
});
|
|
2348
|
+
|
|
2349
|
+
this.server.listen(this.config.pipeName);
|
|
2350
|
+
logger.info(`IPC server listening on ${this.config.pipeName}`);
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
private async handleMessage(clientId: string, msg: IpcMessage, socket: net.Socket): Promise<void> {
|
|
2354
|
+
if (msg.type !== 'request' || !msg.method) return;
|
|
2355
|
+
|
|
2356
|
+
try {
|
|
2357
|
+
const result = await this.router.handle(msg.method, msg.params);
|
|
2358
|
+
socket.write(encodeMessage({
|
|
2359
|
+
id: msg.id,
|
|
2360
|
+
type: 'response',
|
|
2361
|
+
result,
|
|
2362
|
+
}));
|
|
2363
|
+
} catch (err) {
|
|
2364
|
+
socket.write(encodeMessage({
|
|
2365
|
+
id: msg.id,
|
|
2366
|
+
type: 'response',
|
|
2367
|
+
error: { code: -1, message: String(err) },
|
|
2368
|
+
}));
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
notify(terminalId: string | null, notification: IpcMessage): void {
|
|
2373
|
+
if (terminalId) {
|
|
2374
|
+
const socket = this.clients.get(terminalId);
|
|
2375
|
+
if (socket && !socket.destroyed) socket.write(encodeMessage(notification));
|
|
2376
|
+
} else {
|
|
2377
|
+
for (const socket of this.clients.values()) {
|
|
2378
|
+
if (!socket.destroyed) socket.write(encodeMessage(notification));
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
stop(): void {
|
|
2384
|
+
for (const socket of this.clients.values()) {
|
|
2385
|
+
socket.destroy();
|
|
2386
|
+
}
|
|
2387
|
+
this.server.close();
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
```
|
|
2391
|
+
|
|
2392
|
+
## MCP Server
|
|
2393
|
+
|
|
2394
|
+
Der MCP Server läuft als eigener Prozess pro Claude-Session (stdio Transport). Er ist ein Thin Client der alle Anfragen via Named Pipe an den Brain Daemon weiterleitet.
|
|
2395
|
+
|
|
2396
|
+
### MCP Tool-Definitionen
|
|
2397
|
+
|
|
2398
|
+
```typescript
|
|
2399
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2400
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2401
|
+
|
|
2402
|
+
const server = new McpServer({
|
|
2403
|
+
name: 'brain',
|
|
2404
|
+
version: '1.0.0',
|
|
2405
|
+
});
|
|
2406
|
+
|
|
2407
|
+
// === Error Brain Tools ===
|
|
2408
|
+
|
|
2409
|
+
server.tool(
|
|
2410
|
+
'brain_report_error',
|
|
2411
|
+
'Report an error that occurred. Brain will store it, match it against known errors, and return solutions if available.',
|
|
2412
|
+
{
|
|
2413
|
+
error_output: { type: 'string', description: 'The raw error output from the terminal' },
|
|
2414
|
+
command: { type: 'string', description: 'The command that caused the error' },
|
|
2415
|
+
task_context: { type: 'string', description: 'What was the user trying to accomplish' },
|
|
2416
|
+
working_directory: { type: 'string', description: 'Working directory when error occurred' },
|
|
2417
|
+
},
|
|
2418
|
+
async (params) => {
|
|
2419
|
+
const result = await ipcClient.request('error.report', params);
|
|
2420
|
+
// Sofort nach ähnlichen Fehlern suchen
|
|
2421
|
+
const matches = await ipcClient.request('error.match', { error_id: result.error_id });
|
|
2422
|
+
return formatErrorReportResponse(result, matches);
|
|
2423
|
+
}
|
|
2424
|
+
);
|
|
2425
|
+
|
|
2426
|
+
server.tool(
|
|
2427
|
+
'brain_query_error',
|
|
2428
|
+
'Search for similar errors and their solutions in the Brain database.',
|
|
2429
|
+
{
|
|
2430
|
+
query: { type: 'string', description: 'Error message or description to search for' },
|
|
2431
|
+
project_only: { type: 'boolean', description: 'Only search in current project (default: false)' },
|
|
2432
|
+
},
|
|
2433
|
+
async (params) => {
|
|
2434
|
+
const results = await ipcClient.request('error.query', params);
|
|
2435
|
+
return formatErrorQueryResponse(results);
|
|
2436
|
+
}
|
|
2437
|
+
);
|
|
2438
|
+
|
|
2439
|
+
server.tool(
|
|
2440
|
+
'brain_report_solution',
|
|
2441
|
+
'Report a successful solution for an error. Brain will learn from this.',
|
|
2442
|
+
{
|
|
2443
|
+
error_id: { type: 'number', description: 'The error ID this solution fixes' },
|
|
2444
|
+
title: { type: 'string', description: 'Short title of the solution' },
|
|
2445
|
+
description: { type: 'string', description: 'What was done to fix the error' },
|
|
2446
|
+
code_before: { type: 'string', description: 'Code before the fix (optional)' },
|
|
2447
|
+
code_after: { type: 'string', description: 'Code after the fix (optional)' },
|
|
2448
|
+
diff: { type: 'string', description: 'Diff of the changes (optional)' },
|
|
2449
|
+
},
|
|
2450
|
+
async (params) => {
|
|
2451
|
+
const result = await ipcClient.request('solution.report', params);
|
|
2452
|
+
return formatSolutionReportResponse(result);
|
|
2453
|
+
}
|
|
2454
|
+
);
|
|
2455
|
+
|
|
2456
|
+
server.tool(
|
|
2457
|
+
'brain_report_attempt',
|
|
2458
|
+
'Report a failed solution attempt. Brain learns what does NOT work.',
|
|
2459
|
+
{
|
|
2460
|
+
error_id: { type: 'number', description: 'The error ID' },
|
|
2461
|
+
description: { type: 'string', description: 'What was tried' },
|
|
2462
|
+
reason: { type: 'string', description: 'Why it did not work' },
|
|
2463
|
+
},
|
|
2464
|
+
async (params) => {
|
|
2465
|
+
const result = await ipcClient.request('solution.attempt', params);
|
|
2466
|
+
return formatAttemptResponse(result);
|
|
2467
|
+
}
|
|
2468
|
+
);
|
|
2469
|
+
|
|
2470
|
+
// === Code Brain Tools ===
|
|
2471
|
+
|
|
2472
|
+
server.tool(
|
|
2473
|
+
'brain_find_reusable_code',
|
|
2474
|
+
'Search for reusable code modules from other projects. Use when starting new functionality.',
|
|
2475
|
+
{
|
|
2476
|
+
purpose: { type: 'string', description: 'What the code should do (e.g., "retry with backoff", "JWT authentication")' },
|
|
2477
|
+
language: { type: 'string', description: 'Programming language' },
|
|
2478
|
+
category: { type: 'string', description: 'Category: utility, middleware, config, hook, component, service (optional)' },
|
|
2479
|
+
},
|
|
2480
|
+
async (params) => {
|
|
2481
|
+
const results = await ipcClient.request('code.find', params);
|
|
2482
|
+
return formatCodeSearchResponse(results);
|
|
2483
|
+
}
|
|
2484
|
+
);
|
|
2485
|
+
|
|
2486
|
+
server.tool(
|
|
2487
|
+
'brain_register_code',
|
|
2488
|
+
'Register a code module as reusable. Brain will analyze it and make it available to other projects.',
|
|
2489
|
+
{
|
|
2490
|
+
source_code: { type: 'string', description: 'The source code' },
|
|
2491
|
+
file_path: { type: 'string', description: 'File path relative to project root' },
|
|
2492
|
+
name: { type: 'string', description: 'Module name (optional - Brain will auto-detect)' },
|
|
2493
|
+
purpose: { type: 'string', description: 'What this code does (optional - Brain will analyze)' },
|
|
2494
|
+
},
|
|
2495
|
+
async (params) => {
|
|
2496
|
+
const result = await ipcClient.request('code.analyze', params);
|
|
2497
|
+
return formatCodeRegisterResponse(result);
|
|
2498
|
+
}
|
|
2499
|
+
);
|
|
2500
|
+
|
|
2501
|
+
server.tool(
|
|
2502
|
+
'brain_check_code_similarity',
|
|
2503
|
+
'Check if similar code already exists in other projects before writing new code.',
|
|
2504
|
+
{
|
|
2505
|
+
source_code: { type: 'string', description: 'The code to check' },
|
|
2506
|
+
file_path: { type: 'string', description: 'File path for context' },
|
|
2507
|
+
},
|
|
2508
|
+
async (params) => {
|
|
2509
|
+
const results = await ipcClient.request('code.similarity', params);
|
|
2510
|
+
return formatSimilarityResponse(results);
|
|
2511
|
+
}
|
|
2512
|
+
);
|
|
2513
|
+
|
|
2514
|
+
// === Synapsen-Netzwerk Tools ===
|
|
2515
|
+
|
|
2516
|
+
server.tool(
|
|
2517
|
+
'brain_explore',
|
|
2518
|
+
'Explore what Brain knows about a topic. Uses spreading activation through the synapse network to find connected errors, solutions, modules, and insights.',
|
|
2519
|
+
{
|
|
2520
|
+
node_type: { type: 'string', description: 'Type: error, solution, code_module, project' },
|
|
2521
|
+
node_id: { type: 'number', description: 'ID of the node to explore from' },
|
|
2522
|
+
max_depth: { type: 'number', description: 'How many hops to follow (default: 3)' },
|
|
2523
|
+
},
|
|
2524
|
+
async (params) => {
|
|
2525
|
+
const context = await ipcClient.request('synapse.context', params);
|
|
2526
|
+
return formatExploreResponse(context);
|
|
2527
|
+
}
|
|
2528
|
+
);
|
|
2529
|
+
|
|
2530
|
+
server.tool(
|
|
2531
|
+
'brain_connections',
|
|
2532
|
+
'Find how two things are connected in Brain (e.g., how an error relates to a code module).',
|
|
2533
|
+
{
|
|
2534
|
+
from_type: { type: 'string', description: 'Source type: error, solution, code_module, project' },
|
|
2535
|
+
from_id: { type: 'number', description: 'Source ID' },
|
|
2536
|
+
to_type: { type: 'string', description: 'Target type' },
|
|
2537
|
+
to_id: { type: 'number', description: 'Target ID' },
|
|
2538
|
+
},
|
|
2539
|
+
async (params) => {
|
|
2540
|
+
const path = await ipcClient.request('synapse.path', params);
|
|
2541
|
+
return formatPathResponse(path);
|
|
2542
|
+
}
|
|
2543
|
+
);
|
|
2544
|
+
|
|
2545
|
+
// === Research Brain Tools ===
|
|
2546
|
+
|
|
2547
|
+
server.tool(
|
|
2548
|
+
'brain_insights',
|
|
2549
|
+
'Get research insights: trends, gaps, synergies, template candidates, and project suggestions.',
|
|
2550
|
+
{
|
|
2551
|
+
type: { type: 'string', description: 'Filter by type: trend, pattern, gap, synergy, optimization, template_candidate, project_suggestion, warning (optional)' },
|
|
2552
|
+
priority: { type: 'string', description: 'Minimum priority: low, medium, high, critical (optional)' },
|
|
2553
|
+
},
|
|
2554
|
+
async (params) => {
|
|
2555
|
+
const insights = await ipcClient.request('research.insights', params);
|
|
2556
|
+
return formatInsightsResponse(insights);
|
|
2557
|
+
}
|
|
2558
|
+
);
|
|
2559
|
+
|
|
2560
|
+
server.tool(
|
|
2561
|
+
'brain_suggest',
|
|
2562
|
+
'Ask Brain for suggestions: what to build next, what to improve, what patterns to extract.',
|
|
2563
|
+
{
|
|
2564
|
+
context: { type: 'string', description: 'Current context or question (e.g., "starting new project", "looking for optimizations")' },
|
|
2565
|
+
},
|
|
2566
|
+
async (params) => {
|
|
2567
|
+
const suggestions = await ipcClient.request('research.suggest', params);
|
|
2568
|
+
return formatSuggestionsResponse(suggestions);
|
|
2569
|
+
}
|
|
2570
|
+
);
|
|
2571
|
+
|
|
2572
|
+
// === Status & Notifications ===
|
|
2573
|
+
|
|
2574
|
+
server.tool(
|
|
2575
|
+
'brain_status',
|
|
2576
|
+
'Get current Brain status: connected terminals, error count, solutions, code modules, synapse network, and research insights.',
|
|
2577
|
+
{},
|
|
2578
|
+
async () => {
|
|
2579
|
+
const summary = await ipcClient.request('analytics.summary', {});
|
|
2580
|
+
const network = await ipcClient.request('synapse.stats', {});
|
|
2581
|
+
const notifications = await ipcClient.request('notification.list', { unacknowledged: true });
|
|
2582
|
+
return formatStatusResponse(summary, network, notifications);
|
|
2583
|
+
}
|
|
2584
|
+
);
|
|
2585
|
+
|
|
2586
|
+
server.tool(
|
|
2587
|
+
'brain_notifications',
|
|
2588
|
+
'Get pending notifications (new solutions, recurring errors, research insights, synergy suggestions).',
|
|
2589
|
+
{},
|
|
2590
|
+
async () => {
|
|
2591
|
+
const notifications = await ipcClient.request('notification.list', { unacknowledged: true });
|
|
2592
|
+
return formatNotificationsResponse(notifications);
|
|
2593
|
+
}
|
|
2594
|
+
);
|
|
2595
|
+
|
|
2596
|
+
// Server starten
|
|
2597
|
+
const transport = new StdioServerTransport();
|
|
2598
|
+
await server.connect(transport);
|
|
2599
|
+
```
|
|
2600
|
+
|
|
2601
|
+
## Claude Code Hooks
|
|
2602
|
+
|
|
2603
|
+
### Hook-Konfiguration
|
|
2604
|
+
|
|
2605
|
+
In jeder Projekt-`.claude/settings.json`:
|
|
2606
|
+
```json
|
|
2607
|
+
{
|
|
2608
|
+
"hooks": {
|
|
2609
|
+
"PostToolUse": [
|
|
2610
|
+
{
|
|
2611
|
+
"matcher": { "tool_name": "Bash" },
|
|
2612
|
+
"command": "node /path/to/brain/dist/hooks/post-tool-use.js"
|
|
2613
|
+
}
|
|
2614
|
+
]
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
```
|
|
2618
|
+
|
|
2619
|
+
Oder global in `~/.claude/settings.json`:
|
|
2620
|
+
```json
|
|
2621
|
+
{
|
|
2622
|
+
"hooks": {
|
|
2623
|
+
"PostToolUse": [
|
|
2624
|
+
{
|
|
2625
|
+
"matcher": { "tool_name": "Bash" },
|
|
2626
|
+
"command": "node /path/to/brain/dist/hooks/post-tool-use.js"
|
|
2627
|
+
}
|
|
2628
|
+
]
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
```
|
|
2632
|
+
|
|
2633
|
+
### Hook-Script (auto-detect.ts)
|
|
2634
|
+
|
|
2635
|
+
```typescript
|
|
2636
|
+
// hooks/post-tool-use.ts
|
|
2637
|
+
// Wird nach jedem Bash-Tool-Aufruf ausgeführt
|
|
2638
|
+
// Erhält Tool-Input und Output via stdin als JSON
|
|
2639
|
+
|
|
2640
|
+
import { IpcClient } from '../ipc/client.js';
|
|
2641
|
+
|
|
2642
|
+
interface HookInput {
|
|
2643
|
+
tool_name: string;
|
|
2644
|
+
tool_input: { command: string };
|
|
2645
|
+
tool_output: string;
|
|
2646
|
+
exit_code?: number;
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
async function main() {
|
|
2650
|
+
// Hook-Input von stdin lesen
|
|
2651
|
+
const input: HookInput = JSON.parse(await readStdin());
|
|
2652
|
+
|
|
2653
|
+
// Nur bei Fehlern reagieren
|
|
2654
|
+
if (!isError(input)) return;
|
|
2655
|
+
|
|
2656
|
+
const client = new IpcClient();
|
|
2657
|
+
try {
|
|
2658
|
+
await client.connect();
|
|
2659
|
+
|
|
2660
|
+
// Error an Brain melden
|
|
2661
|
+
const result = await client.request('error.report', {
|
|
2662
|
+
raw_output: input.tool_output,
|
|
2663
|
+
command: input.tool_input.command,
|
|
2664
|
+
auto_detected: true,
|
|
2665
|
+
});
|
|
2666
|
+
|
|
2667
|
+
// Wenn Brain eine Lösung kennt, als Feedback ausgeben
|
|
2668
|
+
if (result.matches?.length > 0) {
|
|
2669
|
+
const best = result.matches[0];
|
|
2670
|
+
console.log(`Brain: Similar error found (#${best.error_id}, ${Math.round(best.score * 100)}% match)`);
|
|
2671
|
+
if (best.solutions?.length > 0) {
|
|
2672
|
+
console.log(`Brain: Solution available - use brain_query_error to see details`);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
// Anti-Pattern Check
|
|
2677
|
+
const antipatterns = await client.request('prevention.antipatterns', {
|
|
2678
|
+
error_output: input.tool_output,
|
|
2679
|
+
});
|
|
2680
|
+
if (antipatterns?.length > 0) {
|
|
2681
|
+
console.log(`Brain WARNING: Known anti-pattern detected: ${antipatterns[0].description}`);
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
} catch {
|
|
2685
|
+
// Hook darf nie den Workflow blockieren - stille Fehler
|
|
2686
|
+
} finally {
|
|
2687
|
+
client.disconnect();
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
function isError(input: HookInput): boolean {
|
|
2692
|
+
// Exit-Code Check
|
|
2693
|
+
if (input.exit_code !== undefined && input.exit_code !== 0) return true;
|
|
2694
|
+
|
|
2695
|
+
// Pattern-Check im Output
|
|
2696
|
+
const errorPatterns = [
|
|
2697
|
+
/Error:/i,
|
|
2698
|
+
/error\[E\d+\]/, // Rust errors
|
|
2699
|
+
/Traceback \(most recent call last\)/,
|
|
2700
|
+
/FATAL|PANIC/i,
|
|
2701
|
+
/npm ERR!/,
|
|
2702
|
+
/SyntaxError|TypeError|ReferenceError|RangeError/,
|
|
2703
|
+
/ENOENT|EACCES|ECONNREFUSED|ETIMEDOUT/,
|
|
2704
|
+
/ModuleNotFoundError|ImportError/,
|
|
2705
|
+
/failed to compile/i,
|
|
2706
|
+
/BUILD FAILED/i,
|
|
2707
|
+
/Cannot find module/,
|
|
2708
|
+
/command not found/,
|
|
2709
|
+
/Permission denied/,
|
|
2710
|
+
];
|
|
2711
|
+
|
|
2712
|
+
return errorPatterns.some(p => p.test(input.tool_output));
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
function readStdin(): Promise<string> {
|
|
2716
|
+
return new Promise((resolve) => {
|
|
2717
|
+
let data = '';
|
|
2718
|
+
process.stdin.on('data', (chunk) => data += chunk);
|
|
2719
|
+
process.stdin.on('end', () => resolve(data));
|
|
2720
|
+
});
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
main();
|
|
2724
|
+
```
|
|
2725
|
+
|
|
2726
|
+
### Auto-Detection für Code Brain (PostToolUse auf Write/Edit)
|
|
2727
|
+
|
|
2728
|
+
```json
|
|
2729
|
+
{
|
|
2730
|
+
"hooks": {
|
|
2731
|
+
"PostToolUse": [
|
|
2732
|
+
{
|
|
2733
|
+
"matcher": { "tool_name": "Bash" },
|
|
2734
|
+
"command": "node /path/to/brain/dist/hooks/post-tool-use.js"
|
|
2735
|
+
},
|
|
2736
|
+
{
|
|
2737
|
+
"matcher": { "tool_name": "Write" },
|
|
2738
|
+
"command": "node /path/to/brain/dist/hooks/post-write.js"
|
|
2739
|
+
},
|
|
2740
|
+
{
|
|
2741
|
+
"matcher": { "tool_name": "Edit" },
|
|
2742
|
+
"command": "node /path/to/brain/dist/hooks/post-edit.js"
|
|
2743
|
+
}
|
|
2744
|
+
]
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
```
|
|
2748
|
+
|
|
2749
|
+
```typescript
|
|
2750
|
+
// hooks/post-write.ts
|
|
2751
|
+
// Analysiert geschriebene Dateien auf Wiederverwendbarkeit
|
|
2752
|
+
|
|
2753
|
+
async function main() {
|
|
2754
|
+
const input = JSON.parse(await readStdin());
|
|
2755
|
+
const filePath = input.tool_input?.file_path;
|
|
2756
|
+
if (!filePath) return;
|
|
2757
|
+
|
|
2758
|
+
// Nur Source-Code-Dateien analysieren
|
|
2759
|
+
if (!isSourceFile(filePath)) return;
|
|
2760
|
+
|
|
2761
|
+
const client = new IpcClient();
|
|
2762
|
+
try {
|
|
2763
|
+
await client.connect();
|
|
2764
|
+
|
|
2765
|
+
// Code auf Ähnlichkeit prüfen
|
|
2766
|
+
const similarities = await client.request('code.similarity', {
|
|
2767
|
+
file_path: filePath,
|
|
2768
|
+
source_code: input.tool_input.content,
|
|
2769
|
+
});
|
|
2770
|
+
|
|
2771
|
+
if (similarities?.length > 0) {
|
|
2772
|
+
const best = similarities[0];
|
|
2773
|
+
console.log(`Brain: Similar code exists in ${best.project_name}/${best.file_path} (${Math.round(best.score * 100)}% match)`);
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
// Reusability-Check
|
|
2777
|
+
const analysis = await client.request('code.analyze', {
|
|
2778
|
+
file_path: filePath,
|
|
2779
|
+
source_code: input.tool_input.content,
|
|
2780
|
+
dry_run: true, // Nur analysieren, nicht registrieren
|
|
2781
|
+
});
|
|
2782
|
+
|
|
2783
|
+
if (analysis?.reusability_score >= 0.60) {
|
|
2784
|
+
console.log(`Brain: This code looks reusable (score: ${Math.round(analysis.reusability_score * 100)}%). Consider registering it.`);
|
|
2785
|
+
}
|
|
2786
|
+
} catch {
|
|
2787
|
+
// Stille Fehler
|
|
2788
|
+
} finally {
|
|
2789
|
+
client.disconnect();
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
```
|
|
2793
|
+
|
|
2794
|
+
## Terminal-Lifecycle
|
|
2795
|
+
|
|
2796
|
+
```
|
|
2797
|
+
┌─────────────┐ register ┌──────────────┐
|
|
2798
|
+
│ Connecting │ ─────────────► │ Connected │
|
|
2799
|
+
└─────────────┘ └──────┬───────┘
|
|
2800
|
+
│
|
|
2801
|
+
heartbeat (30s) │
|
|
2802
|
+
│
|
|
2803
|
+
┌──────▼───────┐
|
|
2804
|
+
│ Active │◄── error.report
|
|
2805
|
+
│ │◄── solution.report
|
|
2806
|
+
│ │◄── code.analyze
|
|
2807
|
+
│ │◄── prevention.check
|
|
2808
|
+
└──────┬───────┘
|
|
2809
|
+
│
|
|
2810
|
+
disconnect/timeout │
|
|
2811
|
+
│
|
|
2812
|
+
┌──────▼───────┐
|
|
2813
|
+
│ Disconnected │
|
|
2814
|
+
└──────────────┘
|
|
2815
|
+
│
|
|
2816
|
+
300s no heartbeat │ (5 min statt 90s)
|
|
2817
|
+
│
|
|
2818
|
+
┌──────▼───────┐
|
|
2819
|
+
│ Stale │ → Cleanup
|
|
2820
|
+
└──────────────┘
|
|
2821
|
+
```
|
|
2822
|
+
|
|
2823
|
+
## BrainCore Orchestrierung
|
|
2824
|
+
|
|
2825
|
+
```typescript
|
|
2826
|
+
class BrainCore {
|
|
2827
|
+
private db: Database;
|
|
2828
|
+
private ipcServer: IpcServer;
|
|
2829
|
+
private learningEngine: LearningEngine;
|
|
2830
|
+
private researchEngine: ResearchEngine;
|
|
2831
|
+
private synapseManager: SynapseManager;
|
|
2832
|
+
private services: Services;
|
|
2833
|
+
private config: BrainConfig;
|
|
2834
|
+
private eventBus: TypedEventBus;
|
|
2835
|
+
|
|
2836
|
+
async start(): Promise<void> {
|
|
2837
|
+
// 1. Config laden (Datei + Env-Overrides)
|
|
2838
|
+
this.config = loadConfig();
|
|
2839
|
+
|
|
2840
|
+
// 2. Logger initialisieren
|
|
2841
|
+
initLogger(this.config.log);
|
|
2842
|
+
|
|
2843
|
+
// 3. DB initialisieren + Migrationen
|
|
2844
|
+
this.db = createConnection(this.config.dbPath);
|
|
2845
|
+
runMigrations(this.db);
|
|
2846
|
+
|
|
2847
|
+
// 4. EventBus
|
|
2848
|
+
this.eventBus = new TypedEventBus();
|
|
2849
|
+
|
|
2850
|
+
// 5. Synapse Manager (muss vor Services stehen, die ihn nutzen)
|
|
2851
|
+
this.synapseManager = new SynapseManager(
|
|
2852
|
+
new SynapseRepository(this.db),
|
|
2853
|
+
this.config.synapses
|
|
2854
|
+
);
|
|
2855
|
+
|
|
2856
|
+
// 6. Services initialisieren (inkl. SynapseService und ResearchService)
|
|
2857
|
+
this.services = createServices(this.db, this.eventBus, this.synapseManager);
|
|
2858
|
+
|
|
2859
|
+
// 7. Learning Engine starten (alle 15 Minuten)
|
|
2860
|
+
this.learningEngine = new LearningEngine(this.services, this.synapseManager, this.config.learning);
|
|
2861
|
+
this.learningEngine.startSchedule(this.config.learning.intervalMs);
|
|
2862
|
+
|
|
2863
|
+
// 8. Research Engine starten (alle 60 Minuten, erster Cycle nach 5 min)
|
|
2864
|
+
this.researchEngine = new ResearchEngine(this.services, this.synapseManager, this.config.research);
|
|
2865
|
+
this.researchEngine.startSchedule(this.config.research.intervalMs);
|
|
2866
|
+
|
|
2867
|
+
// 9. IPC Server starten
|
|
2868
|
+
const router = new IpcRouter(this.services);
|
|
2869
|
+
this.ipcServer = new IpcServer(router, this.config.ipc);
|
|
2870
|
+
this.ipcServer.start();
|
|
2871
|
+
|
|
2872
|
+
// 10. Terminal-Cleanup-Timer (stale nach 5 Minuten)
|
|
2873
|
+
setInterval(
|
|
2874
|
+
() => this.services.terminal.cleanupStale(this.config.terminal.staleTimeoutMs),
|
|
2875
|
+
this.config.terminal.cleanupIntervalMs
|
|
2876
|
+
);
|
|
2877
|
+
|
|
2878
|
+
// 11. PID-File schreiben
|
|
2879
|
+
writePidFile(process.pid);
|
|
2880
|
+
|
|
2881
|
+
// 12. Event-Listeners (Synapsen werden hier verdrahtet)
|
|
2882
|
+
this.setupEventListeners();
|
|
2883
|
+
|
|
2884
|
+
// 13. Graceful Shutdown
|
|
2885
|
+
process.on('SIGINT', () => this.stop());
|
|
2886
|
+
process.on('SIGTERM', () => this.stop());
|
|
2887
|
+
|
|
2888
|
+
logger.info(`Brain daemon started (PID: ${process.pid})`);
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2891
|
+
async stop(): Promise<void> {
|
|
2892
|
+
logger.info('Shutting down...');
|
|
2893
|
+
this.researchEngine.stop();
|
|
2894
|
+
this.learningEngine.stop();
|
|
2895
|
+
this.ipcServer.stop();
|
|
2896
|
+
this.db.close();
|
|
2897
|
+
removePidFile();
|
|
2898
|
+
logger.info('Brain daemon stopped');
|
|
2899
|
+
process.exit(0);
|
|
2900
|
+
}
|
|
2901
|
+
|
|
2902
|
+
private setupEventListeners(): void {
|
|
2903
|
+
// === Error Events + Synapsen ===
|
|
2904
|
+
|
|
2905
|
+
this.eventBus.on('error:reported', async ({ errorId, terminalId, projectId }) => {
|
|
2906
|
+
// Synapse: Error → Projekt
|
|
2907
|
+
this.synapseManager.strengthen(
|
|
2908
|
+
{ type: 'error', id: errorId },
|
|
2909
|
+
{ type: 'project', id: projectId },
|
|
2910
|
+
'co_occurs'
|
|
2911
|
+
);
|
|
2912
|
+
|
|
2913
|
+
// Sofort nach Matches suchen
|
|
2914
|
+
const matches = await this.services.error.matchSimilar(errorId);
|
|
2915
|
+
if (matches.length > 0) {
|
|
2916
|
+
const bestMatch = matches[0];
|
|
2917
|
+
|
|
2918
|
+
// Synapse: Error → ähnlicher Error
|
|
2919
|
+
this.synapseManager.strengthen(
|
|
2920
|
+
{ type: 'error', id: errorId },
|
|
2921
|
+
{ type: 'error', id: bestMatch.candidate.id },
|
|
2922
|
+
'similar_to'
|
|
2923
|
+
);
|
|
2924
|
+
|
|
2925
|
+
const solutions = await this.services.solution.getForError(bestMatch.candidate.id);
|
|
2926
|
+
if (solutions.length > 0) {
|
|
2927
|
+
this.services.notification.create({
|
|
2928
|
+
target_terminal_id: terminalId,
|
|
2929
|
+
notification_type: 'solution_available',
|
|
2930
|
+
reference_type: 'solution',
|
|
2931
|
+
reference_id: solutions[0].id,
|
|
2932
|
+
summary: `Known error: "${bestMatch.candidate.message.substring(0, 60)}..." - ${solutions.length} solution(s) available`,
|
|
2933
|
+
});
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
});
|
|
2937
|
+
|
|
2938
|
+
// === Solution Events + Synapsen ===
|
|
2939
|
+
|
|
2940
|
+
this.eventBus.on('solution:applied', async ({ solutionId, errorId, outcome }) => {
|
|
2941
|
+
if (outcome === 'success') {
|
|
2942
|
+
// Starke Synapse: Solution löst Error
|
|
2943
|
+
this.synapseManager.strengthen(
|
|
2944
|
+
{ type: 'solution', id: solutionId },
|
|
2945
|
+
{ type: 'error', id: errorId },
|
|
2946
|
+
'solves',
|
|
2947
|
+
{ outcome: 'success' }
|
|
2948
|
+
);
|
|
2949
|
+
} else if (outcome === 'failure') {
|
|
2950
|
+
// Synapse schwächen
|
|
2951
|
+
const synapse = this.synapseManager.find(
|
|
2952
|
+
{ type: 'solution', id: solutionId },
|
|
2953
|
+
{ type: 'error', id: errorId },
|
|
2954
|
+
'solves'
|
|
2955
|
+
);
|
|
2956
|
+
if (synapse) this.synapseManager.weaken(synapse.id, 0.7);
|
|
2957
|
+
}
|
|
2958
|
+
});
|
|
2959
|
+
|
|
2960
|
+
// Cross-Projekt: Fehler gelöst → prüfe ob andere Projekte profitieren
|
|
2961
|
+
this.eventBus.on('solution:reported', async ({ solutionId, errorId }) => {
|
|
2962
|
+
const error = await this.services.error.getById(errorId);
|
|
2963
|
+
if (!error) return;
|
|
2964
|
+
|
|
2965
|
+
const crossProjectErrors = await this.services.error.findCrossProject(
|
|
2966
|
+
error.fingerprint,
|
|
2967
|
+
error.project_id
|
|
2968
|
+
);
|
|
2969
|
+
|
|
2970
|
+
for (const otherError of crossProjectErrors) {
|
|
2971
|
+
// Cross-Project Synapsen
|
|
2972
|
+
this.synapseManager.strengthen(
|
|
2973
|
+
{ type: 'error', id: error.id },
|
|
2974
|
+
{ type: 'error', id: otherError.id },
|
|
2975
|
+
'cross_project'
|
|
2976
|
+
);
|
|
2977
|
+
this.synapseManager.strengthen(
|
|
2978
|
+
{ type: 'project', id: error.project_id! },
|
|
2979
|
+
{ type: 'project', id: otherError.project_id! },
|
|
2980
|
+
'cross_project'
|
|
2981
|
+
);
|
|
2982
|
+
|
|
2983
|
+
this.services.notification.create({
|
|
2984
|
+
notification_type: 'solution_available',
|
|
2985
|
+
reference_type: 'solution',
|
|
2986
|
+
reference_id: solutionId,
|
|
2987
|
+
summary: `Solution from project ${error.project_id} may fix error #${otherError.id}`,
|
|
2988
|
+
});
|
|
2989
|
+
}
|
|
2990
|
+
});
|
|
2991
|
+
|
|
2992
|
+
// === Code Events + Synapsen ===
|
|
2993
|
+
|
|
2994
|
+
this.eventBus.on('module:registered', async ({ moduleId, projectId }) => {
|
|
2995
|
+
this.synapseManager.strengthen(
|
|
2996
|
+
{ type: 'code_module', id: moduleId },
|
|
2997
|
+
{ type: 'project', id: projectId },
|
|
2998
|
+
'co_occurs'
|
|
2999
|
+
);
|
|
3000
|
+
});
|
|
3001
|
+
|
|
3002
|
+
this.eventBus.on('module:reused', async ({ moduleId, projectId, outcome }) => {
|
|
3003
|
+
this.synapseManager.strengthen(
|
|
3004
|
+
{ type: 'code_module', id: moduleId },
|
|
3005
|
+
{ type: 'project', id: projectId },
|
|
3006
|
+
'uses_module',
|
|
3007
|
+
{ outcome }
|
|
3008
|
+
);
|
|
3009
|
+
});
|
|
3010
|
+
|
|
3011
|
+
// === Rule Events + Synapsen ===
|
|
3012
|
+
|
|
3013
|
+
this.eventBus.on('rule:triggered', async ({ ruleId, errorId, outcome }) => {
|
|
3014
|
+
if (outcome === 'prevented') {
|
|
3015
|
+
this.synapseManager.strengthen(
|
|
3016
|
+
{ type: 'rule', id: ruleId },
|
|
3017
|
+
{ type: 'error', id: errorId },
|
|
3018
|
+
'prevents'
|
|
3019
|
+
);
|
|
3020
|
+
}
|
|
3021
|
+
});
|
|
3022
|
+
|
|
3023
|
+
// === Error Chain Detection ===
|
|
3024
|
+
|
|
3025
|
+
this.eventBus.on('error:chain_detected', async ({ causeErrorId, effectErrorId }) => {
|
|
3026
|
+
this.synapseManager.strengthen(
|
|
3027
|
+
{ type: 'error', id: causeErrorId },
|
|
3028
|
+
{ type: 'error', id: effectErrorId },
|
|
3029
|
+
'causes'
|
|
3030
|
+
);
|
|
3031
|
+
});
|
|
3032
|
+
|
|
3033
|
+
// === Research Insights + Synapsen ===
|
|
3034
|
+
|
|
3035
|
+
this.eventBus.on('insight:created', async ({ insightId, relatedNodeIds }) => {
|
|
3036
|
+
// Insight mit allen beteiligten Knoten verbinden
|
|
3037
|
+
for (const node of relatedNodeIds) {
|
|
3038
|
+
this.synapseManager.strengthen(
|
|
3039
|
+
{ type: 'insight', id: insightId },
|
|
3040
|
+
{ type: node.type, id: node.id },
|
|
3041
|
+
'derived_from'
|
|
3042
|
+
);
|
|
3043
|
+
}
|
|
3044
|
+
});
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
```
|
|
3048
|
+
|
|
3049
|
+
## CLI Commands
|
|
3050
|
+
|
|
3051
|
+
```bash
|
|
3052
|
+
brain start # Daemon starten (Hintergrund via detached child_process)
|
|
3053
|
+
brain stop # Daemon stoppen (PID-File lesen, SIGTERM senden)
|
|
3054
|
+
brain status # Status: Terminals, Errors, Code, Synapsen, Research
|
|
3055
|
+
brain query "error message" # Ähnliche Fehler + Lösungen suchen
|
|
3056
|
+
brain modules [--language ts] # Code-Module auflisten
|
|
3057
|
+
brain insights [--type trend] # Research Insights anzeigen
|
|
3058
|
+
brain network [--node error:42] # Synapsen-Netzwerk um einen Knoten erkunden
|
|
3059
|
+
brain export [--format json] # Daten exportieren
|
|
3060
|
+
brain reset [--confirm] # Datenbank zurücksetzen
|
|
3061
|
+
brain logs [--tail 50] # Log-Datei anzeigen
|
|
3062
|
+
```
|
|
3063
|
+
|
|
3064
|
+
### Beispiel: `brain status` Output
|
|
3065
|
+
```
|
|
3066
|
+
Brain Daemon: RUNNING (PID 12345, uptime 2h 34m)
|
|
3067
|
+
Database: brain.db (2.4 MB)
|
|
3068
|
+
|
|
3069
|
+
Terminals (3 connected):
|
|
3070
|
+
T1: my-api (PID 1234) Active 5s ago
|
|
3071
|
+
T2: frontend (PID 5678) Active 12s ago
|
|
3072
|
+
T3: data-tools (PID 9012) Idle 45s ago
|
|
3073
|
+
|
|
3074
|
+
Error Brain:
|
|
3075
|
+
Errors: 42 total, 8 unresolved
|
|
3076
|
+
Solutions: 31 (avg confidence: 0.74)
|
|
3077
|
+
Rules: 8 active, 2 pending
|
|
3078
|
+
Anti-Patterns: 3
|
|
3079
|
+
|
|
3080
|
+
Code Brain:
|
|
3081
|
+
Modules: 23 registered
|
|
3082
|
+
Reuses: 14 total (9 exact, 3 adapted, 2 pattern-based)
|
|
3083
|
+
Top module: retry.ts (4 reuses, confidence 0.92)
|
|
3084
|
+
|
|
3085
|
+
Synapse Network:
|
|
3086
|
+
Nodes: 98 Synapses: 247
|
|
3087
|
+
Avg weight: 0.43 Strong (>0.7): 31
|
|
3088
|
+
Top connection: Solution#7 --solves--> Error#42 (weight: 0.96)
|
|
3089
|
+
|
|
3090
|
+
Research Brain:
|
|
3091
|
+
Insights: 12 active (3 high priority)
|
|
3092
|
+
Last cycle: 18m ago Next: in 42m
|
|
3093
|
+
Latest: "Template-Kandidat: API-Client Pattern (3 Projekte)"
|
|
3094
|
+
|
|
3095
|
+
Learning:
|
|
3096
|
+
Last cycle: 5m ago (3 patterns, 1 new rule)
|
|
3097
|
+
Next cycle: in 10m
|
|
3098
|
+
```
|
|
3099
|
+
|
|
3100
|
+
## Konfiguration
|
|
3101
|
+
|
|
3102
|
+
```typescript
|
|
3103
|
+
interface BrainConfig {
|
|
3104
|
+
dbPath: string; // Default: ~/.brain/brain.db
|
|
3105
|
+
ipc: {
|
|
3106
|
+
pipeName: string; // Default: \\.\pipe\brain-ipc (Win) / /tmp/brain.sock (Unix)
|
|
3107
|
+
maxConnections: number; // Default: 50
|
|
3108
|
+
};
|
|
3109
|
+
learning: {
|
|
3110
|
+
intervalMs: number; // Default: 900_000 (15 min)
|
|
3111
|
+
minOccurrences: number; // Default: 3
|
|
3112
|
+
minSuccessRate: number; // Default: 0.70
|
|
3113
|
+
minConfidence: number; // Default: 0.60
|
|
3114
|
+
pruneThreshold: number; // Default: 0.20
|
|
3115
|
+
maxRejectionRate: number; // Default: 0.50
|
|
3116
|
+
decayHalfLifeDays: number; // Default: 30
|
|
3117
|
+
};
|
|
3118
|
+
terminal: {
|
|
3119
|
+
heartbeatIntervalMs: number; // Default: 30_000
|
|
3120
|
+
staleTimeoutMs: number; // Default: 300_000 (5 min)
|
|
3121
|
+
cleanupIntervalMs: number; // Default: 60_000
|
|
3122
|
+
};
|
|
3123
|
+
matching: {
|
|
3124
|
+
threshold: number; // Default: 0.70
|
|
3125
|
+
strongThreshold: number; // Default: 0.90
|
|
3126
|
+
maxCandidates: number; // Default: 100
|
|
3127
|
+
};
|
|
3128
|
+
code: {
|
|
3129
|
+
moduleThreshold: number; // Default: 0.60 (Reusability Score minimum)
|
|
3130
|
+
similarityThreshold: number; // Default: 0.70
|
|
3131
|
+
autoAnalyze: boolean; // Default: true
|
|
3132
|
+
ignorePaths: string[]; // Default: ["node_modules", "dist", ".git", "__pycache__"]
|
|
3133
|
+
};
|
|
3134
|
+
synapses: {
|
|
3135
|
+
initialWeight: number; // Default: 0.1
|
|
3136
|
+
learningRate: number; // Default: 0.15 (wie schnell Synapsen stärker werden)
|
|
3137
|
+
decayHalfLifeDays: number; // Default: 45 (Synapsen verblassen langsamer als Solutions)
|
|
3138
|
+
pruneThreshold: number; // Default: 0.05 (unter diesem Gewicht → löschen)
|
|
3139
|
+
decayAfterDays: number; // Default: 14 (Decay erst nach 14 Tagen Inaktivität)
|
|
3140
|
+
maxDepth: number; // Default: 3 (Spreading Activation Tiefe)
|
|
3141
|
+
minActivationWeight: number; // Default: 0.2 (Minimum für Pfad-Traversierung)
|
|
3142
|
+
};
|
|
3143
|
+
research: {
|
|
3144
|
+
intervalMs: number; // Default: 3_600_000 (60 min)
|
|
3145
|
+
initialDelayMs: number; // Default: 300_000 (5 min, Brain soll erstmal Daten sammeln)
|
|
3146
|
+
minDataPoints: number; // Default: 10 (Minimum Errors/Solutions bevor geforscht wird)
|
|
3147
|
+
trendWindowDays: number; // Default: 7
|
|
3148
|
+
gapMinOccurrences: number; // Default: 5 (Fehler muss 5x auftreten für Gap-Erkennung)
|
|
3149
|
+
synergyMinWeight: number; // Default: 0.5 (Minimum Synapse-Gewicht für Synergie)
|
|
3150
|
+
templateMinAdaptations: number; // Default: 3 (Minimum Adaptationen für Template-Vorschlag)
|
|
3151
|
+
insightExpiryDays: number; // Default: 30 (Insights verfallen nach 30 Tagen)
|
|
3152
|
+
};
|
|
3153
|
+
log: {
|
|
3154
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
3155
|
+
file: string; // Default: ~/.brain/brain.log
|
|
3156
|
+
maxSizeMb: number; // Default: 10
|
|
3157
|
+
maxFiles: number; // Default: 3 (Rotation)
|
|
3158
|
+
};
|
|
3159
|
+
retention: {
|
|
3160
|
+
maxErrorAgeDays: number; // Default: 90
|
|
3161
|
+
maxResolvedErrorAgeDays: number; // Default: 180
|
|
3162
|
+
maxLogAgeDays: number; // Default: 30
|
|
3163
|
+
cleanupIntervalMs: number; // Default: 86_400_000 (24h)
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3166
|
+
```
|
|
3167
|
+
|
|
3168
|
+
## Implementierungsreihenfolge (8 Phasen)
|
|
3169
|
+
|
|
3170
|
+
### Phase 1: Foundation
|
|
3171
|
+
**Ziel:** Projekt-Skeleton, DB, Config - alles was andere Phasen brauchen.
|
|
3172
|
+
|
|
3173
|
+
- `package.json` mit allen Dependencies
|
|
3174
|
+
- `tsconfig.json` (strict, ES2022, NodeNext module resolution)
|
|
3175
|
+
- `.gitignore` (node_modules, data/, dist/, *.db, *.log)
|
|
3176
|
+
- `src/config.ts` - Konfiguration mit Defaults + Env-Overrides
|
|
3177
|
+
- `src/types/` - Alle TypeScript Interfaces (inkl. synapse.types.ts, research.types.ts)
|
|
3178
|
+
- `src/utils/logger.ts` - Winston File-Logger mit Rotation
|
|
3179
|
+
- `src/utils/hash.ts` - SHA-256 Wrapper
|
|
3180
|
+
- `src/utils/paths.ts` - Pfad-Normalisierung (Windows/Unix)
|
|
3181
|
+
- `src/utils/events.ts` - Typisierter EventBus
|
|
3182
|
+
- `src/db/connection.ts` - SQLite Connection (WAL, journal_mode, synchronous, cache_size Pragmas)
|
|
3183
|
+
- `src/db/migrations/` - Alle 5 Migrations + Runner
|
|
3184
|
+
- `src/db/repositories/` - Alle 10 Repository-Klassen (jede mit eigenen Prepared Statements)
|
|
3185
|
+
|
|
3186
|
+
### Phase 2: Parsing, Matching & Code Analysis
|
|
3187
|
+
**Ziel:** Die "Intelligenz" - Error-Erkennung, Matching, Code-Analyse.
|
|
3188
|
+
|
|
3189
|
+
- `src/parsing/types.ts` - Parser Interfaces
|
|
3190
|
+
- `src/parsing/error-parser.ts` - Registry-basierter Dispatcher
|
|
3191
|
+
- `src/parsing/parsers/` - Node, Python, Rust, Go, Shell, Compiler, Generic
|
|
3192
|
+
- `src/matching/tokenizer.ts` - Text-Tokenisierung (splitCamelCase, splitSnakeCase, stopwords)
|
|
3193
|
+
- `src/matching/similarity.ts` - Levenshtein, Cosine, Jaccard
|
|
3194
|
+
- `src/matching/tfidf.ts` - Inkrementeller TF-IDF Index mit Persistenz
|
|
3195
|
+
- `src/matching/fingerprint.ts` - Error-Fingerprinting mit Templatisierung
|
|
3196
|
+
- `src/matching/error-matcher.ts` - Multi-Signal Matching Engine
|
|
3197
|
+
- `src/code/analyzer.ts` - Export-Extraction, Purity-Check, Cohesion-Messung
|
|
3198
|
+
- `src/code/fingerprint.ts` - Strukturelles Code-Hashing
|
|
3199
|
+
- `src/code/matcher.ts` - Code-Similarity-Matching
|
|
3200
|
+
- `src/code/registry.ts` - Module-Registration + Granularity-Detection
|
|
3201
|
+
- `src/code/scorer.ts` - Reusability-Scoring (6 Signals)
|
|
3202
|
+
- `src/code/parsers/` - TypeScript, Python, Generic Code-Parser
|
|
3203
|
+
|
|
3204
|
+
### Phase 3: Synapsen-Netzwerk
|
|
3205
|
+
**Ziel:** Das neuronale Netzwerk das alles verbindet.
|
|
3206
|
+
|
|
3207
|
+
- `src/synapses/synapse-manager.ts` - Erstellen, Stärken, Schwächen von Synapsen
|
|
3208
|
+
- `src/synapses/hebbian.ts` - Hebbsches Lerngesetz (logarithmische Verstärkung, Sättigung)
|
|
3209
|
+
- `src/synapses/pathfinder.ts` - BFS-Pfadsuche mit Gewichts-Tracking
|
|
3210
|
+
- `src/synapses/activation.ts` - Spreading Activation (Multi-Hop Netzwerk-Traversierung)
|
|
3211
|
+
- `src/synapses/decay.ts` - Synaptische Abschwächung + Pruning inaktiver Verbindungen
|
|
3212
|
+
|
|
3213
|
+
### Phase 4: Services
|
|
3214
|
+
**Ziel:** Business-Logik über den Repositories.
|
|
3215
|
+
|
|
3216
|
+
- `src/services/error.service.ts` - Report, Query, Match, Auto-Label
|
|
3217
|
+
- `src/services/solution.service.ts` - Report, Rate, Track Attempts
|
|
3218
|
+
- `src/services/terminal.service.ts` - Register, Heartbeat, Cleanup
|
|
3219
|
+
- `src/services/prevention.service.ts` - Rule-Check, Antipattern-Check
|
|
3220
|
+
- `src/services/code.service.ts` - Analyze, Find, Similarity, Register
|
|
3221
|
+
- `src/services/synapse.service.ts` - Context-Queries, Pfadsuche, Netzwerk-Stats
|
|
3222
|
+
- `src/services/research.service.ts` - Insights abfragen, Suggestions generieren
|
|
3223
|
+
- `src/services/notification.service.ts` - Create, List, Acknowledge
|
|
3224
|
+
- `src/services/analytics.service.ts` - Summary, Trends, Network Overview
|
|
3225
|
+
|
|
3226
|
+
### Phase 5: Learning Engine + Research Brain
|
|
3227
|
+
**Ziel:** Das System wird über Zeit besser UND forscht eigenständig.
|
|
3228
|
+
|
|
3229
|
+
- `src/learning/confidence-scorer.ts` - Wilson Score + Time Decay
|
|
3230
|
+
- `src/learning/decay.ts` - Zeitbasierte Relevanz-Berechnung
|
|
3231
|
+
- `src/learning/pattern-extractor.ts` - Centroid-basiertes Error-Clustering
|
|
3232
|
+
- `src/learning/rule-generator.ts` - Regeln aus Mustern generieren
|
|
3233
|
+
- `src/learning/learning-engine.ts` - Lern-Zyklus + Scheduling
|
|
3234
|
+
- `src/research/research-engine.ts` - Forschungs-Zyklus Orchestrierung (7 Phasen)
|
|
3235
|
+
- `src/research/trend-analyzer.ts` - Error-Frequenz, Solution-Erfolgsrate über Zeit
|
|
3236
|
+
- `src/research/gap-analyzer.ts` - Ungelöste recurring Errors, isolierte Knoten
|
|
3237
|
+
- `src/research/synergy-detector.ts` - Module-Paare, transferierbare Solutions, Workflow-Patterns
|
|
3238
|
+
- `src/research/template-extractor.ts` - Adaptierte Module → parametrisierte Templates
|
|
3239
|
+
- `src/research/insight-generator.ts` - Projekt-Vorschläge, Tool-Ideen, Optimierungen
|
|
3240
|
+
|
|
3241
|
+
### Phase 6: IPC + MCP
|
|
3242
|
+
**Ziel:** Kommunikation - Daemon erreichbar für Terminals und Claude.
|
|
3243
|
+
|
|
3244
|
+
- `src/ipc/protocol.ts` - Length-prefixed JSON Framing (Encode/Decode)
|
|
3245
|
+
- `src/ipc/router.ts` - Method-Routing mit Error-Handling
|
|
3246
|
+
- `src/ipc/server.ts` - Named Pipe Server
|
|
3247
|
+
- `src/ipc/client.ts` - IPC Client (für MCP Server → Daemon)
|
|
3248
|
+
- `src/mcp/server.ts` - MCP Server (stdio Transport, Tool Registration)
|
|
3249
|
+
- `src/mcp/tools.ts` - Alle 13 MCP Tool-Definitionen
|
|
3250
|
+
- `src/mcp/auto-detect.ts` - Error-Pattern-Erkennung für Hooks
|
|
3251
|
+
|
|
3252
|
+
### Phase 7: BrainCore + CLI + Hooks
|
|
3253
|
+
**Ziel:** Alles zusammenbinden, benutzbar machen.
|
|
3254
|
+
|
|
3255
|
+
- `src/brain.ts` - BrainCore (Start, Stop, Service-Wiring, Synapse-Events, Engine-Scheduling)
|
|
3256
|
+
- `src/index.ts` - Commander CLI Setup
|
|
3257
|
+
- `src/cli/commands/start.ts` - Daemon als detached child_process starten
|
|
3258
|
+
- `src/cli/commands/stop.ts` - PID lesen, SIGTERM senden
|
|
3259
|
+
- `src/cli/commands/status.ts` - Text-basierter Status (inkl. Synapse-Stats + Research-Insights)
|
|
3260
|
+
- `src/cli/commands/query.ts` - Error-Suche via CLI
|
|
3261
|
+
- `src/cli/commands/modules.ts` - Code-Module auflisten
|
|
3262
|
+
- `src/cli/commands/insights.ts` - Research Insights anzeigen
|
|
3263
|
+
- `src/cli/commands/network.ts` - Synapsen-Netzwerk erkunden
|
|
3264
|
+
- `src/cli/commands/export.ts` - JSON/CSV Export
|
|
3265
|
+
- `src/hooks/post-tool-use.ts` - Auto Error Detection Hook
|
|
3266
|
+
- `src/hooks/post-write.ts` - Auto Code Analysis Hook
|
|
3267
|
+
|
|
3268
|
+
### Phase 8: Tests
|
|
3269
|
+
**Ziel:** Alles getestet, produktionsreif.
|
|
3270
|
+
|
|
3271
|
+
- Unit-Tests:
|
|
3272
|
+
- `tests/unit/matching/` - Fingerprinting, Similarity, TF-IDF, Error-Matcher
|
|
3273
|
+
- `tests/unit/parsing/` - Jeder Parser einzeln mit Fixtures
|
|
3274
|
+
- `tests/unit/code/` - Analyzer, Fingerprint, Scorer, Granularity
|
|
3275
|
+
- `tests/unit/learning/` - Wilson Score, Decay, Pattern-Extraktion, Rule-Gen
|
|
3276
|
+
- `tests/unit/synapses/` - Hebbian Learning, Spreading Activation, Decay, Pathfinding
|
|
3277
|
+
- `tests/unit/research/` - Trend-Analyse, Gap-Analyse, Synergie-Detektion, Template-Extraktion
|
|
3278
|
+
- Integration-Tests:
|
|
3279
|
+
- `tests/integration/error-flow.test.ts` - Error → Parse → Store → Match → Solution → Synapse
|
|
3280
|
+
- `tests/integration/code-flow.test.ts` - Write → Analyze → Register → Find → Reuse → Synapse
|
|
3281
|
+
- `tests/integration/synapse-flow.test.ts` - Events → Synapsen bilden → Spreading Activation → Kontext
|
|
3282
|
+
- `tests/integration/research-cycle.test.ts` - Daten sammeln → Forschen → Insights → Notifications
|
|
3283
|
+
- `tests/integration/learning-cycle.test.ts` - Voller Lern-Zyklus inkl. Synapse-Decay
|
|
3284
|
+
- `tests/integration/ipc-flow.test.ts` - MCP → IPC → Daemon → Response
|
|
3285
|
+
- Fixtures:
|
|
3286
|
+
- `tests/fixtures/errors/` - Beispiel-Errors pro Sprache (node, python, rust, go, shell)
|
|
3287
|
+
- `tests/fixtures/solutions/` - Beispiel-Lösungen
|
|
3288
|
+
- `tests/fixtures/code-modules/` - Beispiel-Code für Matching-Tests
|
|
3289
|
+
- `tests/fixtures/synapses/` - Vorkonfigurierte Netzwerke für Pfadsuche-Tests
|
|
3290
|
+
|
|
3291
|
+
## Verifikation
|
|
3292
|
+
|
|
3293
|
+
1. `npm run build` - TypeScript kompiliert ohne Fehler
|
|
3294
|
+
2. `npm test` - Alle Tests grün
|
|
3295
|
+
3. `brain start` - Daemon startet, PID-File wird geschrieben
|
|
3296
|
+
4. `brain status` - Zeigt laufenden Brain mit 0 Terminals, leeres Netzwerk
|
|
3297
|
+
5. **Error-Flow:** Error melden → Brain matcht → Lösung vorschlagen → Feedback → Confidence steigt → Synapse stärkt sich
|
|
3298
|
+
6. **Code-Flow:** Code schreiben → Brain analysiert → Modul registriert → In anderem Projekt vorgeschlagen → Synapse zu Projekt
|
|
3299
|
+
7. **Hook-Flow:** Bash-Fehler → Hook erkennt → Brain speichert → Nächstes Mal: Warnung
|
|
3300
|
+
8. **Cross-Projekt:** Fehler in Projekt A lösen → Synapse cross_project → Brain schlägt Lösung für Projekt B vor
|
|
3301
|
+
9. **Synapse-Flow:** Mehrere Aktionen → Synapsen bilden sich → Spreading Activation findet Zusammenhänge → Context-Query zeigt vernetztes Wissen
|
|
3302
|
+
10. **Research-Flow:** Nach genug Daten → Research Engine läuft → Trends, Gaps, Synergien erkannt → Insights mit konkreten Vorschlägen
|
|
3303
|
+
11. **Learning + Decay:** Synapsen die nicht bestätigt werden verblassen → Schwache Regeln werden gepruned → Netzwerk bleibt relevant
|
|
3304
|
+
|
|
3305
|
+
## Wichtige Entscheidungen
|
|
3306
|
+
|
|
3307
|
+
- **better-sqlite3 statt async**: Synchron ist für diesen Use-Case besser (kein Web-Server, lokaler Daemon). WAL-Modus erlaubt concurrent reads von mehreren MCP Server Prozessen.
|
|
3308
|
+
- **Named Pipes + MCP Dual-Layer**: Named Pipes für performante Daemon-Kommunikation, MCP für saubere Claude-Integration. MCP Server sind Thin Clients, keine eigene Logik.
|
|
3309
|
+
- **Hooks für automatische Erkennung**: PostToolUse-Hooks sind der unsichtbare Kanal. Der User muss nichts manuell melden, Brain läuft im Hintergrund. Hooks dürfen NIE den Workflow blockieren (silent catch).
|
|
3310
|
+
- **Wilson Score statt Durchschnitt**: Bei wenigen Datenpunkten (1/0 = 100%) unrealistisch. Wilson Score berücksichtigt Stichprobengröße.
|
|
3311
|
+
- **Centroid-basiertes Clustering statt Single-Pass**: Ordnungsunabhängig, findet Cluster besser, Running Average für effiziente Updates.
|
|
3312
|
+
- **Parser-Registry statt Hardcoded Dispatch**: Neue Sprachen = neue Datei registrieren. Open/Closed Principle.
|
|
3313
|
+
- **Labels statt Tag-Tabellen**: Auto-generierte JSON-Labels direkt am Record. Kein 3-Tabellen-Overhead für Tags die niemand manuell pflegt.
|
|
3314
|
+
- **Notifications statt Inter-Terminal-Chat**: Ein User, ein Bildschirm. Brain informiert, es chattet nicht.
|
|
3315
|
+
- **Synapsen-Netzwerk statt isolierter Relationen**: Statt `related_errors`, `cross_project_solutions` als separate Tabellen ein einheitliches Synapse-System das ALLES verbindet. Typed + weighted + decaying. Ermöglicht Spreading Activation und Multi-Hop-Entdeckungen die mit isolierten Tabellen unmöglich wären.
|
|
3316
|
+
- **Hebbsches Lernen für Synapsen**: "Neurons that fire together, wire together". Wenn Solution X Error Y löst, wird die Synapse stärker. Bei Fehlschlag schwächer. Logarithmische Sättigung verhindert Übergewichtung. Natürlicher als binäre Relationen.
|
|
3317
|
+
- **Research Brain als eigener Engine**: Getrennt von der Learning Engine (die taktisch lernt) forscht das Research Brain strategisch. Längere Intervalle (60 min vs 15 min), höhere Abstraktion (Trends, Synergien, Templates statt Error-Patterns). Generiert Insights die über einzelne Fehler/Lösungen hinausgehen.
|
|
3318
|
+
- **Synapse-Decay statt Deletion**: Unbenutzte Verbindungen verblassen langsam (halfLife 45 Tage) statt hart gelöscht zu werden. Ermöglicht "Wiederentdeckung" wenn ein Pfad nach langer Zeit wieder relevant wird. Erst unter pruneThreshold (0.05) wird tatsächlich gelöscht.
|
|
3319
|
+
- **Insights als first-class Citizens**: Nicht nur Notifications, sondern persistente, priorisierte, aktionierbare Erkenntnisse mit Lifecycle (active → acknowledged → acted_upon → expired). Das Research Brain wird über Zeit klüger weil es auf Insight-Outcomes lernen kann.
|
|
3320
|
+
- **Kein ink Dashboard**: Claude IST das Dashboard. MCP-Tools liefern reichhaltige, formatierte Informationen. CLI gibt simplen Text-Status. Die UI-Komplexität von ink lohnt nicht für einen Daemon der primär durch Claude bedient wird.
|
|
3321
|
+
- **Prepared Statements pro Repository**: Jedes Repository compiled seine eigenen Statements bei Init. Kein God-File mit 50+ Statements.
|
|
3322
|
+
- **File-Logging statt DB-Event-Log**: Audit/Debug-Daten gehören in Log-Dateien mit Rotation, nicht in die Datenbank. Die DB bleibt für strukturierte, abfragbare Daten.
|
|
3323
|
+
- **300s statt 90s stale Timeout**: Claude denkt manchmal minutenlang. 90s ist zu aggressiv.
|
|
3324
|
+
- **Code-Fingerprinting normalisiert Identifier**: Lokale Variablennamen werden ersetzt, aber Import-Names und API-Calls bleiben. So matcht `const result = await fetch(url)` mit `const response = await fetch(endpoint)`.
|