@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
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ErrorParser, ParsedError, StackFrame } from '../types.js';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const RUST_ERROR_RE = /error(?:\[E(\d+)\])?: (.+)/;
|
|
5
|
+
const RUST_LOCATION_RE = /^\s*--> (.+):(\d+):(\d+)/m;
|
|
6
|
+
const RUST_NOTE_RE = /^\s*= note: (.+)/gm;
|
|
7
|
+
|
|
8
|
+
export const rustParser: ErrorParser = {
|
|
9
|
+
name: 'rust',
|
|
10
|
+
priority: 10,
|
|
11
|
+
|
|
12
|
+
canParse(input: string): boolean {
|
|
13
|
+
return /error\[E\d+\]:/.test(input) || /^error:/.test(input);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
parse(input: string): ParsedError | null {
|
|
17
|
+
const errMatch = RUST_ERROR_RE.exec(input);
|
|
18
|
+
if (!errMatch) return null;
|
|
19
|
+
|
|
20
|
+
const message = errMatch[2]!.trim();
|
|
21
|
+
const errorType = errMatch[1] ? `E${errMatch[1]}` : 'CompilerError';
|
|
22
|
+
|
|
23
|
+
const frames: StackFrame[] = [];
|
|
24
|
+
let sourceFile: string | null = null;
|
|
25
|
+
let sourceLine: number | null = null;
|
|
26
|
+
|
|
27
|
+
const locMatch = RUST_LOCATION_RE.exec(input);
|
|
28
|
+
if (locMatch) {
|
|
29
|
+
sourceFile = locMatch[1]!;
|
|
30
|
+
sourceLine = parseInt(locMatch[2]!, 10);
|
|
31
|
+
frames.push({
|
|
32
|
+
function_name: null,
|
|
33
|
+
file_path: locMatch[1]!,
|
|
34
|
+
line_number: parseInt(locMatch[2]!, 10),
|
|
35
|
+
column_number: parseInt(locMatch[3]!, 10),
|
|
36
|
+
normalized: `<compiler>@${path.basename(locMatch[1]!)}`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
errorType,
|
|
42
|
+
message,
|
|
43
|
+
stackTrace: input,
|
|
44
|
+
frames,
|
|
45
|
+
sourceFile,
|
|
46
|
+
sourceLine,
|
|
47
|
+
language: 'rust',
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ErrorParser, ParsedError } from '../types.js';
|
|
2
|
+
|
|
3
|
+
const ERROR_MAP: Array<{ pattern: RegExp; type: string }> = [
|
|
4
|
+
{ pattern: /command not found/i, type: 'CommandNotFound' },
|
|
5
|
+
{ pattern: /Permission denied|EACCES/i, type: 'PermissionError' },
|
|
6
|
+
{ pattern: /No such file or directory|ENOENT/i, type: 'FileNotFound' },
|
|
7
|
+
{ pattern: /ECONNREFUSED/i, type: 'ConnectionRefused' },
|
|
8
|
+
{ pattern: /EADDRINUSE/i, type: 'AddressInUse' },
|
|
9
|
+
{ pattern: /ETIMEDOUT|ESOCKETTIMEDOUT/i, type: 'Timeout' },
|
|
10
|
+
{ pattern: /ENOMEM/i, type: 'OutOfMemory' },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const shellParser: ErrorParser = {
|
|
14
|
+
name: 'shell',
|
|
15
|
+
priority: 5,
|
|
16
|
+
|
|
17
|
+
canParse(input: string): boolean {
|
|
18
|
+
return ERROR_MAP.some(e => e.pattern.test(input));
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
parse(input: string): ParsedError | null {
|
|
22
|
+
let errorType = 'ShellError';
|
|
23
|
+
for (const entry of ERROR_MAP) {
|
|
24
|
+
if (entry.pattern.test(input)) {
|
|
25
|
+
errorType = entry.type;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const firstLine = input.trim().split('\n')[0] ?? input;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
errorType,
|
|
34
|
+
message: firstLine,
|
|
35
|
+
stackTrace: null,
|
|
36
|
+
frames: [],
|
|
37
|
+
sourceFile: null,
|
|
38
|
+
sourceLine: null,
|
|
39
|
+
language: 'shell',
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface StackFrame {
|
|
2
|
+
function_name: string | null;
|
|
3
|
+
file_path: string | null;
|
|
4
|
+
line_number: number | null;
|
|
5
|
+
column_number: number | null;
|
|
6
|
+
normalized: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ParsedError {
|
|
10
|
+
errorType: string;
|
|
11
|
+
message: string;
|
|
12
|
+
stackTrace: string | null;
|
|
13
|
+
frames: StackFrame[];
|
|
14
|
+
sourceFile: string | null;
|
|
15
|
+
sourceLine: number | null;
|
|
16
|
+
language: string | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ErrorParser {
|
|
20
|
+
name: string;
|
|
21
|
+
priority: number;
|
|
22
|
+
canParse(input: string): boolean;
|
|
23
|
+
parse(input: string): ParsedError | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class ErrorParserRegistry {
|
|
27
|
+
private parsers: ErrorParser[] = [];
|
|
28
|
+
|
|
29
|
+
register(parser: ErrorParser): void {
|
|
30
|
+
this.parsers.push(parser);
|
|
31
|
+
this.parsers.sort((a, b) => b.priority - a.priority);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
parse(input: string): ParsedError | null {
|
|
35
|
+
for (const parser of this.parsers) {
|
|
36
|
+
if (parser.canParse(input)) {
|
|
37
|
+
const result = parser.parse(input);
|
|
38
|
+
if (result) return result;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getRegistered(): string[] {
|
|
45
|
+
return this.parsers.map(p => p.name);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { ResearchConfig } from '../types/config.types.js';
|
|
2
|
+
import type { ErrorRepository } from '../db/repositories/error.repository.js';
|
|
3
|
+
import type { SolutionRepository } from '../db/repositories/solution.repository.js';
|
|
4
|
+
import type { SynapseRepository } from '../db/repositories/synapse.repository.js';
|
|
5
|
+
import type { ProjectRepository } from '../db/repositories/project.repository.js';
|
|
6
|
+
import type { InsightRepository } from '../db/repositories/insight.repository.js';
|
|
7
|
+
import { getLogger } from '../utils/logger.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Identifies gaps: unresolved recurring errors, missing solutions, isolated synapse nodes.
|
|
11
|
+
*/
|
|
12
|
+
export class GapAnalyzer {
|
|
13
|
+
private logger = getLogger();
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
private errorRepo: ErrorRepository,
|
|
17
|
+
private solutionRepo: SolutionRepository,
|
|
18
|
+
private synapseRepo: SynapseRepository,
|
|
19
|
+
private projectRepo: ProjectRepository,
|
|
20
|
+
private insightRepo: InsightRepository,
|
|
21
|
+
private config: ResearchConfig,
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
analyze(): number {
|
|
25
|
+
let insightsCreated = 0;
|
|
26
|
+
|
|
27
|
+
insightsCreated += this.findUnresolvedRecurring();
|
|
28
|
+
insightsCreated += this.findFailedSolutions();
|
|
29
|
+
insightsCreated += this.findIsolatedNodes();
|
|
30
|
+
|
|
31
|
+
this.logger.info(`Gap analysis complete: ${insightsCreated} insights`);
|
|
32
|
+
return insightsCreated;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private findUnresolvedRecurring(): number {
|
|
36
|
+
const unresolved = this.errorRepo.findUnresolved();
|
|
37
|
+
const recurring = unresolved.filter(e => e.occurrence_count >= this.config.gapMinOccurrences);
|
|
38
|
+
let count = 0;
|
|
39
|
+
const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
|
|
40
|
+
|
|
41
|
+
for (const error of recurring) {
|
|
42
|
+
const solutions = this.solutionRepo.findForError(error.id);
|
|
43
|
+
if (solutions.length === 0) {
|
|
44
|
+
this.insightRepo.create({
|
|
45
|
+
type: 'warning',
|
|
46
|
+
title: `Unresolved recurring error: ${error.type}`,
|
|
47
|
+
description: `"${error.message.substring(0, 80)}..." has occurred ${error.occurrence_count} times with no solution.`,
|
|
48
|
+
evidence: JSON.stringify({ errorId: error.id, occurrences: error.occurrence_count, type: error.type }),
|
|
49
|
+
priority: Math.min(95, 40 + error.occurrence_count * 5),
|
|
50
|
+
project_id: error.project_id,
|
|
51
|
+
active: 1,
|
|
52
|
+
expires_at: expiresAt,
|
|
53
|
+
});
|
|
54
|
+
count++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return count;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private findFailedSolutions(): number {
|
|
62
|
+
const projects = this.projectRepo.getAll();
|
|
63
|
+
let count = 0;
|
|
64
|
+
const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
|
|
65
|
+
|
|
66
|
+
for (const project of projects) {
|
|
67
|
+
const errors = this.errorRepo.findUnresolved(project.id);
|
|
68
|
+
for (const error of errors) {
|
|
69
|
+
if (error.occurrence_count < this.config.gapMinOccurrences) continue;
|
|
70
|
+
|
|
71
|
+
const solutions = this.solutionRepo.findForError(error.id);
|
|
72
|
+
if (solutions.length < 2) continue;
|
|
73
|
+
|
|
74
|
+
const allFailed = solutions.every(s => {
|
|
75
|
+
const rate = this.solutionRepo.successRate(s.id);
|
|
76
|
+
return rate < 0.3;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (allFailed) {
|
|
80
|
+
this.insightRepo.create({
|
|
81
|
+
type: 'warning',
|
|
82
|
+
title: `All solutions failing for: ${error.type}`,
|
|
83
|
+
description: `${solutions.length} solutions tried for "${error.message.substring(0, 60)}..." but all have <30% success rate.`,
|
|
84
|
+
evidence: JSON.stringify({
|
|
85
|
+
errorId: error.id,
|
|
86
|
+
solutionCount: solutions.length,
|
|
87
|
+
solutionIds: solutions.map(s => s.id),
|
|
88
|
+
}),
|
|
89
|
+
priority: Math.min(90, 50 + solutions.length * 10),
|
|
90
|
+
project_id: project.id,
|
|
91
|
+
active: 1,
|
|
92
|
+
expires_at: expiresAt,
|
|
93
|
+
});
|
|
94
|
+
count++;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return count;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private findIsolatedNodes(): number {
|
|
103
|
+
const projects = this.projectRepo.getAll();
|
|
104
|
+
let count = 0;
|
|
105
|
+
const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
|
|
106
|
+
|
|
107
|
+
for (const project of projects) {
|
|
108
|
+
const errors = this.errorRepo.findByProject(project.id);
|
|
109
|
+
let projectIsolated = 0;
|
|
110
|
+
|
|
111
|
+
for (const error of errors) {
|
|
112
|
+
const connections = this.synapseRepo.findConnected('error', error.id);
|
|
113
|
+
if (connections.length === 0) {
|
|
114
|
+
projectIsolated++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (projectIsolated > 5) {
|
|
119
|
+
this.insightRepo.create({
|
|
120
|
+
type: 'optimization',
|
|
121
|
+
title: `${projectIsolated} errors without connections in ${project.name}`,
|
|
122
|
+
description: `These errors have no synapses to solutions, modules, or other errors. Brain cannot contextualize them.`,
|
|
123
|
+
evidence: JSON.stringify({ projectId: project.id, isolatedCount: projectIsolated }),
|
|
124
|
+
priority: 25,
|
|
125
|
+
project_id: project.id,
|
|
126
|
+
active: 1,
|
|
127
|
+
expires_at: expiresAt,
|
|
128
|
+
});
|
|
129
|
+
count++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return count;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { ResearchConfig } from '../types/config.types.js';
|
|
2
|
+
import type { ProjectRepository } from '../db/repositories/project.repository.js';
|
|
3
|
+
import type { ErrorRepository } from '../db/repositories/error.repository.js';
|
|
4
|
+
import type { SolutionRepository } from '../db/repositories/solution.repository.js';
|
|
5
|
+
import type { CodeModuleRepository } from '../db/repositories/code-module.repository.js';
|
|
6
|
+
import type { InsightRepository } from '../db/repositories/insight.repository.js';
|
|
7
|
+
import { getLogger } from '../utils/logger.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generates project suggestions, tool ideas, and optimization hints.
|
|
11
|
+
*/
|
|
12
|
+
export class InsightGenerator {
|
|
13
|
+
private logger = getLogger();
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
private projectRepo: ProjectRepository,
|
|
17
|
+
private errorRepo: ErrorRepository,
|
|
18
|
+
private solutionRepo: SolutionRepository,
|
|
19
|
+
private codeModuleRepo: CodeModuleRepository,
|
|
20
|
+
private insightRepo: InsightRepository,
|
|
21
|
+
private config: ResearchConfig,
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
generate(): number {
|
|
25
|
+
let insightsCreated = 0;
|
|
26
|
+
|
|
27
|
+
insightsCreated += this.suggestRefactoring();
|
|
28
|
+
insightsCreated += this.suggestErrorTypeTools();
|
|
29
|
+
this.reprioritizeInsights();
|
|
30
|
+
|
|
31
|
+
this.logger.info(`Insight generation complete: ${insightsCreated} new insights`);
|
|
32
|
+
return insightsCreated;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private suggestRefactoring(): number {
|
|
36
|
+
const projects = this.projectRepo.getAll();
|
|
37
|
+
let count = 0;
|
|
38
|
+
const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
|
|
39
|
+
|
|
40
|
+
for (const project of projects) {
|
|
41
|
+
const modules = this.codeModuleRepo.findByProject(project.id);
|
|
42
|
+
const problematic = modules.filter(m =>
|
|
43
|
+
(m.complexity ?? 0) > 10 && m.reusability_score < 0.3 && m.lines_of_code > 50,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (problematic.length > 0) {
|
|
47
|
+
this.insightRepo.create({
|
|
48
|
+
type: 'optimization',
|
|
49
|
+
title: `${problematic.length} complex modules need refactoring in ${project.name}`,
|
|
50
|
+
description: `These modules have high complexity (>10), low reusability (<30%), and are non-trivial (>50 LOC). Refactoring would improve maintainability.`,
|
|
51
|
+
evidence: JSON.stringify({
|
|
52
|
+
modules: problematic.map(m => ({
|
|
53
|
+
id: m.id,
|
|
54
|
+
name: m.name,
|
|
55
|
+
complexity: m.complexity,
|
|
56
|
+
reusability: m.reusability_score,
|
|
57
|
+
loc: m.lines_of_code,
|
|
58
|
+
})),
|
|
59
|
+
}),
|
|
60
|
+
priority: Math.min(70, 30 + problematic.length * 10),
|
|
61
|
+
project_id: project.id,
|
|
62
|
+
active: 1,
|
|
63
|
+
expires_at: expiresAt,
|
|
64
|
+
});
|
|
65
|
+
count++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return count;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private suggestErrorTypeTools(): number {
|
|
73
|
+
const projects = this.projectRepo.getAll();
|
|
74
|
+
let count = 0;
|
|
75
|
+
const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
|
|
76
|
+
|
|
77
|
+
for (const project of projects) {
|
|
78
|
+
const errors = this.errorRepo.findByProject(project.id);
|
|
79
|
+
if (errors.length < this.config.minDataPoints) continue;
|
|
80
|
+
|
|
81
|
+
// Group errors by type
|
|
82
|
+
const byType = new Map<string, number>();
|
|
83
|
+
for (const error of errors) {
|
|
84
|
+
byType.set(error.type, (byType.get(error.type) ?? 0) + error.occurrence_count);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Find dominant error types
|
|
88
|
+
for (const [errorType, totalOccurrences] of byType) {
|
|
89
|
+
if (totalOccurrences >= this.config.gapMinOccurrences * 3) {
|
|
90
|
+
this.insightRepo.create({
|
|
91
|
+
type: 'suggestion',
|
|
92
|
+
title: `Frequent error type: ${errorType} in ${project.name}`,
|
|
93
|
+
description: `${errorType} has ${totalOccurrences} total occurrences. Consider adding linting rules, type checking, or tooling to prevent this class of errors.`,
|
|
94
|
+
evidence: JSON.stringify({ errorType, totalOccurrences, projectId: project.id }),
|
|
95
|
+
priority: Math.min(65, 30 + Math.round(totalOccurrences / 5)),
|
|
96
|
+
project_id: project.id,
|
|
97
|
+
active: 1,
|
|
98
|
+
expires_at: expiresAt,
|
|
99
|
+
});
|
|
100
|
+
count++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return count;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private reprioritizeInsights(): void {
|
|
109
|
+
const activeInsights = this.insightRepo.findActive();
|
|
110
|
+
|
|
111
|
+
for (const insight of activeInsights) {
|
|
112
|
+
if (insight.type === 'warning') {
|
|
113
|
+
const ageMs = Date.now() - new Date(insight.created_at).getTime();
|
|
114
|
+
const ageDays = ageMs / 86400000;
|
|
115
|
+
if (ageDays > 3 && insight.priority < 80) {
|
|
116
|
+
this.insightRepo.update(insight.id, {
|
|
117
|
+
priority: Math.min(85, insight.priority + 10),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { ResearchConfig } from '../types/config.types.js';
|
|
2
|
+
import type { ErrorRepository } from '../db/repositories/error.repository.js';
|
|
3
|
+
import type { SolutionRepository } from '../db/repositories/solution.repository.js';
|
|
4
|
+
import type { ProjectRepository } from '../db/repositories/project.repository.js';
|
|
5
|
+
import type { CodeModuleRepository } from '../db/repositories/code-module.repository.js';
|
|
6
|
+
import type { SynapseRepository } from '../db/repositories/synapse.repository.js';
|
|
7
|
+
import type { InsightRepository } from '../db/repositories/insight.repository.js';
|
|
8
|
+
import type { SynapseManager } from '../synapses/synapse-manager.js';
|
|
9
|
+
import type { ResearchCycleResult } from '../types/research.types.js';
|
|
10
|
+
import { TrendAnalyzer } from './trend-analyzer.js';
|
|
11
|
+
import { GapAnalyzer } from './gap-analyzer.js';
|
|
12
|
+
import { SynergyDetector } from './synergy-detector.js';
|
|
13
|
+
import { TemplateExtractor } from './template-extractor.js';
|
|
14
|
+
import { InsightGenerator } from './insight-generator.js';
|
|
15
|
+
import { getLogger } from '../utils/logger.js';
|
|
16
|
+
|
|
17
|
+
export class ResearchEngine {
|
|
18
|
+
private timer: ReturnType<typeof setInterval> | null = null;
|
|
19
|
+
private delayTimer: ReturnType<typeof setTimeout> | null = null;
|
|
20
|
+
private logger = getLogger();
|
|
21
|
+
|
|
22
|
+
private trendAnalyzer: TrendAnalyzer;
|
|
23
|
+
private gapAnalyzer: GapAnalyzer;
|
|
24
|
+
private synergyDetector: SynergyDetector;
|
|
25
|
+
private templateExtractor: TemplateExtractor;
|
|
26
|
+
private insightGenerator: InsightGenerator;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
private config: ResearchConfig,
|
|
30
|
+
private errorRepo: ErrorRepository,
|
|
31
|
+
private solutionRepo: SolutionRepository,
|
|
32
|
+
private projectRepo: ProjectRepository,
|
|
33
|
+
private codeModuleRepo: CodeModuleRepository,
|
|
34
|
+
private synapseRepo: SynapseRepository,
|
|
35
|
+
private insightRepo: InsightRepository,
|
|
36
|
+
private synapseManager: SynapseManager,
|
|
37
|
+
) {
|
|
38
|
+
this.trendAnalyzer = new TrendAnalyzer(errorRepo, solutionRepo, projectRepo, insightRepo, config);
|
|
39
|
+
this.gapAnalyzer = new GapAnalyzer(errorRepo, solutionRepo, synapseRepo, projectRepo, insightRepo, config);
|
|
40
|
+
this.synergyDetector = new SynergyDetector(synapseRepo, codeModuleRepo, solutionRepo, errorRepo, projectRepo, insightRepo, config);
|
|
41
|
+
this.templateExtractor = new TemplateExtractor(codeModuleRepo, projectRepo, insightRepo, config);
|
|
42
|
+
this.insightGenerator = new InsightGenerator(projectRepo, errorRepo, solutionRepo, codeModuleRepo, insightRepo, config);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
start(): void {
|
|
46
|
+
this.logger.info(`Research engine starting (interval: ${this.config.intervalMs}ms, initial delay: ${this.config.initialDelayMs}ms)`);
|
|
47
|
+
this.delayTimer = setTimeout(() => {
|
|
48
|
+
this.runCycle();
|
|
49
|
+
this.timer = setInterval(() => this.runCycle(), this.config.intervalMs);
|
|
50
|
+
}, this.config.initialDelayMs);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
stop(): void {
|
|
54
|
+
if (this.delayTimer) {
|
|
55
|
+
clearTimeout(this.delayTimer);
|
|
56
|
+
this.delayTimer = null;
|
|
57
|
+
}
|
|
58
|
+
if (this.timer) {
|
|
59
|
+
clearInterval(this.timer);
|
|
60
|
+
this.timer = null;
|
|
61
|
+
}
|
|
62
|
+
this.logger.info('Research engine stopped');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
runCycle(): ResearchCycleResult {
|
|
66
|
+
const start = Date.now();
|
|
67
|
+
this.logger.info('Research cycle starting');
|
|
68
|
+
|
|
69
|
+
const result: ResearchCycleResult = {
|
|
70
|
+
insightsGenerated: 0,
|
|
71
|
+
patternsFound: 0,
|
|
72
|
+
correlationsFound: 0,
|
|
73
|
+
duration: 0,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Phase 1: Trend analysis
|
|
77
|
+
const trends = this.trendAnalyzer.analyze();
|
|
78
|
+
result.patternsFound += trends;
|
|
79
|
+
result.insightsGenerated += trends;
|
|
80
|
+
|
|
81
|
+
// Phase 2: Gap analysis
|
|
82
|
+
const gaps = this.gapAnalyzer.analyze();
|
|
83
|
+
result.insightsGenerated += gaps;
|
|
84
|
+
|
|
85
|
+
// Phase 3: Synergy detection
|
|
86
|
+
const synergies = this.synergyDetector.detect();
|
|
87
|
+
result.correlationsFound += synergies;
|
|
88
|
+
result.insightsGenerated += synergies;
|
|
89
|
+
|
|
90
|
+
// Phase 4: Template extraction
|
|
91
|
+
const templates = this.templateExtractor.extract();
|
|
92
|
+
result.patternsFound += templates;
|
|
93
|
+
result.insightsGenerated += templates;
|
|
94
|
+
|
|
95
|
+
// Phase 5: Insight generation
|
|
96
|
+
const generated = this.insightGenerator.generate();
|
|
97
|
+
result.insightsGenerated += generated;
|
|
98
|
+
|
|
99
|
+
// Phase 6: Insight prioritization (expire old insights)
|
|
100
|
+
const expired = this.insightRepo.expire();
|
|
101
|
+
if (expired > 0) {
|
|
102
|
+
this.logger.info(`Expired ${expired} outdated insights`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Phase 7: Synapse maintenance
|
|
106
|
+
const decay = this.synapseManager.runDecay();
|
|
107
|
+
this.logger.debug(`Synapse maintenance: ${decay.decayed} decayed, ${decay.pruned} pruned`);
|
|
108
|
+
|
|
109
|
+
result.duration = Date.now() - start;
|
|
110
|
+
this.logger.info(
|
|
111
|
+
`Research cycle complete: ${result.insightsGenerated} insights, ${result.patternsFound} patterns, ${result.correlationsFound} correlations (${result.duration}ms)`,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { ResearchConfig } from '../types/config.types.js';
|
|
2
|
+
import type { SynapseRepository } from '../db/repositories/synapse.repository.js';
|
|
3
|
+
import type { CodeModuleRepository } from '../db/repositories/code-module.repository.js';
|
|
4
|
+
import type { SolutionRepository } from '../db/repositories/solution.repository.js';
|
|
5
|
+
import type { ErrorRepository } from '../db/repositories/error.repository.js';
|
|
6
|
+
import type { ProjectRepository } from '../db/repositories/project.repository.js';
|
|
7
|
+
import type { InsightRepository } from '../db/repositories/insight.repository.js';
|
|
8
|
+
import { getLogger } from '../utils/logger.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detects synergies: module pairs, transferable solutions, workflow patterns.
|
|
12
|
+
*/
|
|
13
|
+
export class SynergyDetector {
|
|
14
|
+
private logger = getLogger();
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private synapseRepo: SynapseRepository,
|
|
18
|
+
private codeModuleRepo: CodeModuleRepository,
|
|
19
|
+
private solutionRepo: SolutionRepository,
|
|
20
|
+
private errorRepo: ErrorRepository,
|
|
21
|
+
private projectRepo: ProjectRepository,
|
|
22
|
+
private insightRepo: InsightRepository,
|
|
23
|
+
private config: ResearchConfig,
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
detect(): number {
|
|
27
|
+
let insightsCreated = 0;
|
|
28
|
+
|
|
29
|
+
insightsCreated += this.findModuleSynergies();
|
|
30
|
+
insightsCreated += this.findTransferableSolutions();
|
|
31
|
+
|
|
32
|
+
this.logger.info(`Synergy detection complete: ${insightsCreated} insights`);
|
|
33
|
+
return insightsCreated;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private findModuleSynergies(): number {
|
|
37
|
+
const strongSynapses = this.synapseRepo.findByWeight(this.config.synergyMinWeight);
|
|
38
|
+
const modulePairs = strongSynapses.filter(s =>
|
|
39
|
+
s.source_type === 'code_module' &&
|
|
40
|
+
s.target_type === 'code_module' &&
|
|
41
|
+
s.synapse_type === 'co_occurs',
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
let count = 0;
|
|
45
|
+
const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
|
|
46
|
+
|
|
47
|
+
for (const synapse of modulePairs) {
|
|
48
|
+
const sourceModule = this.codeModuleRepo.getById(synapse.source_id);
|
|
49
|
+
const targetModule = this.codeModuleRepo.getById(synapse.target_id);
|
|
50
|
+
if (!sourceModule || !targetModule) continue;
|
|
51
|
+
|
|
52
|
+
this.insightRepo.create({
|
|
53
|
+
type: 'correlation',
|
|
54
|
+
title: `Strong module pair: ${sourceModule.name} + ${targetModule.name}`,
|
|
55
|
+
description: `These modules co-occur with weight ${synapse.weight.toFixed(2)}. Consider combining into a shared package.`,
|
|
56
|
+
evidence: JSON.stringify({
|
|
57
|
+
sourceId: sourceModule.id,
|
|
58
|
+
targetId: targetModule.id,
|
|
59
|
+
sourceName: sourceModule.name,
|
|
60
|
+
targetName: targetModule.name,
|
|
61
|
+
weight: synapse.weight,
|
|
62
|
+
}),
|
|
63
|
+
priority: Math.min(70, Math.round(synapse.weight * 70)),
|
|
64
|
+
project_id: sourceModule.project_id,
|
|
65
|
+
active: 1,
|
|
66
|
+
expires_at: expiresAt,
|
|
67
|
+
});
|
|
68
|
+
count++;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return count;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private findTransferableSolutions(): number {
|
|
75
|
+
const projects = this.projectRepo.getAll();
|
|
76
|
+
if (projects.length < 2) return 0;
|
|
77
|
+
|
|
78
|
+
let count = 0;
|
|
79
|
+
const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < projects.length; i++) {
|
|
82
|
+
for (let j = i + 1; j < projects.length; j++) {
|
|
83
|
+
const projectA = projects[i]!;
|
|
84
|
+
const projectB = projects[j]!;
|
|
85
|
+
|
|
86
|
+
const errorsA = this.errorRepo.findByProject(projectA.id);
|
|
87
|
+
const errorsB = this.errorRepo.findUnresolved(projectB.id);
|
|
88
|
+
|
|
89
|
+
const transferable: number[] = [];
|
|
90
|
+
|
|
91
|
+
for (const errorB of errorsB) {
|
|
92
|
+
const matchingA = errorsA.filter(a => a.type === errorB.type && a.resolved);
|
|
93
|
+
for (const matchA of matchingA) {
|
|
94
|
+
const solutions = this.solutionRepo.findForError(matchA.id);
|
|
95
|
+
for (const sol of solutions) {
|
|
96
|
+
const rate = this.solutionRepo.successRate(sol.id);
|
|
97
|
+
if (rate >= 0.5 && !transferable.includes(sol.id)) {
|
|
98
|
+
transferable.push(sol.id);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (transferable.length >= 2) {
|
|
105
|
+
this.insightRepo.create({
|
|
106
|
+
type: 'suggestion',
|
|
107
|
+
title: `${projectA.name} has solutions for ${projectB.name}`,
|
|
108
|
+
description: `${transferable.length} successful solutions from ${projectA.name} could help resolve errors in ${projectB.name}.`,
|
|
109
|
+
evidence: JSON.stringify({
|
|
110
|
+
sourceProject: projectA.id,
|
|
111
|
+
targetProject: projectB.id,
|
|
112
|
+
solutionIds: transferable,
|
|
113
|
+
}),
|
|
114
|
+
priority: 50,
|
|
115
|
+
project_id: projectB.id,
|
|
116
|
+
active: 1,
|
|
117
|
+
expires_at: expiresAt,
|
|
118
|
+
});
|
|
119
|
+
count++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return count;
|
|
125
|
+
}
|
|
126
|
+
}
|