specmem-hardwicksoftware 3.5.99
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/CHANGELOG.md +299 -0
- package/LICENSE.md +6406 -0
- package/README.md +539 -0
- package/bin/AegisTheme.cjs +1022 -0
- package/bin/AnsiRenderer.cjs +1055 -0
- package/bin/BoxRenderer.cjs +605 -0
- package/bin/ClaudeLiveScreen.cjs +1299 -0
- package/bin/DashboardModules.cjs +733 -0
- package/bin/LiveScreenCapture.cjs +1012 -0
- package/bin/MemoryBrowserScreen.cjs +1595 -0
- package/bin/TabManager.cjs +1414 -0
- package/bin/checkAgentStatus-fix.patch +30 -0
- package/bin/mcp-socket-client.cjs +462 -0
- package/bin/screen-utils.cjs +106 -0
- package/bin/specmem-autoclaude.cjs +663 -0
- package/bin/specmem-cleanup.cjs +421 -0
- package/bin/specmem-cli.cjs +794 -0
- package/bin/specmem-console-teamcomms-class.cjs +428 -0
- package/bin/specmem-console.cjs +8104 -0
- package/bin/specmem-statusbar.cjs +530 -0
- package/bootstrap.cjs +5065 -0
- package/claude-hooks/agent-chooser-hook.js +179 -0
- package/claude-hooks/agent-chooser-inject.js +121 -0
- package/claude-hooks/agent-loading-hook.js +990 -0
- package/claude-hooks/agent-output-fader.cjs +542 -0
- package/claude-hooks/agent-output-interceptor.js +193 -0
- package/claude-hooks/agent-type-matcher.js +419 -0
- package/claude-hooks/auto-bypass.py +74 -0
- package/claude-hooks/background-completion-silencer.js +134 -0
- package/claude-hooks/bash-auto-background.js +182 -0
- package/claude-hooks/build-cedict-dictionary.mjs +167 -0
- package/claude-hooks/bullshit-radar.cjs +323 -0
- package/claude-hooks/cedict-codes.json +270 -0
- package/claude-hooks/cedict-extracted.json +22632 -0
- package/claude-hooks/claude-watchdog.sh +401 -0
- package/claude-hooks/context-dedup.cjs +144 -0
- package/claude-hooks/context-yeeter.cjs +244 -0
- package/claude-hooks/debug-suffix.cjs +15 -0
- package/claude-hooks/debug2.cjs +7 -0
- package/claude-hooks/drilldown-enforcer.js +242 -0
- package/claude-hooks/english-morphology-standalone.cjs +149 -0
- package/claude-hooks/english-morphology.cjs +152 -0
- package/claude-hooks/extract-translations.mjs +193 -0
- package/claude-hooks/file-claim-enforcer.cjs +293 -0
- package/claude-hooks/file-claim-enforcer.js +293 -0
- package/claude-hooks/find-collisions.cjs +39 -0
- package/claude-hooks/fix-abbreviations.cjs +60 -0
- package/claude-hooks/fix-collisions.cjs +60 -0
- package/claude-hooks/fix-decompressor.cjs +79 -0
- package/claude-hooks/fix-suffixes.cjs +66 -0
- package/claude-hooks/grammar-engine.cjs +159 -0
- package/claude-hooks/input-aware-improver.js +231 -0
- package/claude-hooks/is-agent.cjs +64 -0
- package/claude-hooks/mega-test.cjs +213 -0
- package/claude-hooks/merge-dictionaries.mjs +207 -0
- package/claude-hooks/merged-codes.cjs +22675 -0
- package/claude-hooks/merged-codes.json +22676 -0
- package/claude-hooks/output-cleaner.cjs +388 -0
- package/claude-hooks/post-write-memory-hook.cjs +430 -0
- package/claude-hooks/quick-test.cjs +24 -0
- package/claude-hooks/quick-test2.cjs +24 -0
- package/claude-hooks/remove-bad-codes.cjs +23 -0
- package/claude-hooks/search-reminder-hook.js +90 -0
- package/claude-hooks/semantic-test.cjs +93 -0
- package/claude-hooks/settings.json +445 -0
- package/claude-hooks/smart-context-hook.cjs +547 -0
- package/claude-hooks/smart-context-hook.js +539 -0
- package/claude-hooks/smart-search-interceptor.js +364 -0
- package/claude-hooks/socket-connect-helper.cjs +235 -0
- package/claude-hooks/specmem/sockets/session-start.lock +1 -0
- package/claude-hooks/specmem-context-hook.cjs +357 -0
- package/claude-hooks/specmem-context-hook.js +357 -0
- package/claude-hooks/specmem-drilldown-hook.cjs +480 -0
- package/claude-hooks/specmem-drilldown-hook.js +480 -0
- package/claude-hooks/specmem-drilldown-setter.js +210 -0
- package/claude-hooks/specmem-paths.cjs +213 -0
- package/claude-hooks/specmem-precompact.js +183 -0
- package/claude-hooks/specmem-session-init.sh +33 -0
- package/claude-hooks/specmem-session-start.cjs +498 -0
- package/claude-hooks/specmem-stop-hook.cjs +73 -0
- package/claude-hooks/specmem-stop-hook.js +5 -0
- package/claude-hooks/specmem-team-comms.cjs +434 -0
- package/claude-hooks/specmem-team-member-inject.js +271 -0
- package/claude-hooks/specmem-unified-hook.py +670 -0
- package/claude-hooks/subagent-loading-hook.js +194 -0
- package/claude-hooks/sysprompt-squisher.cjs +167 -0
- package/claude-hooks/task-progress-hook.js +204 -0
- package/claude-hooks/team-comms-enforcer.cjs +585 -0
- package/claude-hooks/test-accuracy.cjs +27 -0
- package/claude-hooks/test-big.cjs +28 -0
- package/claude-hooks/test-inflectors.cjs +39 -0
- package/claude-hooks/test-pluralize.cjs +37 -0
- package/claude-hooks/test-quick.cjs +8 -0
- package/claude-hooks/test-wink.cjs +20 -0
- package/claude-hooks/token-compressor.cjs +940 -0
- package/claude-hooks/use-code-pointers.cjs +279 -0
- package/commands/COMMAND_TOOL_MAP.md +299 -0
- package/commands/specmem-agents.md +412 -0
- package/commands/specmem-autoclaude.md +295 -0
- package/commands/specmem-changes.md +247 -0
- package/commands/specmem-code.md +103 -0
- package/commands/specmem-configteammembercomms.md +322 -0
- package/commands/specmem-drilldown.md +208 -0
- package/commands/specmem-find.md +195 -0
- package/commands/specmem-getdashboard.md +243 -0
- package/commands/specmem-hooks.md +219 -0
- package/commands/specmem-pointers.md +149 -0
- package/commands/specmem-progress.md +287 -0
- package/commands/specmem-remember.md +123 -0
- package/commands/specmem-service.md +349 -0
- package/commands/specmem-stats.md +189 -0
- package/commands/specmem-team-member.md +409 -0
- package/commands/specmem-webdev.md +583 -0
- package/commands/specmem.md +363 -0
- package/dist/autoStart/index.d.ts +214 -0
- package/dist/autoStart/index.d.ts.map +1 -0
- package/dist/autoStart/index.js +883 -0
- package/dist/autoStart/index.js.map +1 -0
- package/dist/claude-sessions/contextRestorationParser.d.ts +74 -0
- package/dist/claude-sessions/contextRestorationParser.d.ts.map +1 -0
- package/dist/claude-sessions/contextRestorationParser.js +570 -0
- package/dist/claude-sessions/contextRestorationParser.js.map +1 -0
- package/dist/claude-sessions/index.d.ts +13 -0
- package/dist/claude-sessions/index.d.ts.map +1 -0
- package/dist/claude-sessions/index.js +11 -0
- package/dist/claude-sessions/index.js.map +1 -0
- package/dist/claude-sessions/sessionIntegration.d.ts +48 -0
- package/dist/claude-sessions/sessionIntegration.d.ts.map +1 -0
- package/dist/claude-sessions/sessionIntegration.js +146 -0
- package/dist/claude-sessions/sessionIntegration.js.map +1 -0
- package/dist/claude-sessions/sessionParser.d.ts +293 -0
- package/dist/claude-sessions/sessionParser.d.ts.map +1 -0
- package/dist/claude-sessions/sessionParser.js +1028 -0
- package/dist/claude-sessions/sessionParser.js.map +1 -0
- package/dist/claude-sessions/sessionWatcher.d.ts +139 -0
- package/dist/claude-sessions/sessionWatcher.d.ts.map +1 -0
- package/dist/claude-sessions/sessionWatcher.js +722 -0
- package/dist/claude-sessions/sessionWatcher.js.map +1 -0
- package/dist/cli/deploy-to-claude.d.ts +56 -0
- package/dist/cli/deploy-to-claude.d.ts.map +1 -0
- package/dist/cli/deploy-to-claude.js +576 -0
- package/dist/cli/deploy-to-claude.js.map +1 -0
- package/dist/code-explanations/explainCode.d.ts +86 -0
- package/dist/code-explanations/explainCode.d.ts.map +1 -0
- package/dist/code-explanations/explainCode.js +286 -0
- package/dist/code-explanations/explainCode.js.map +1 -0
- package/dist/code-explanations/feedback.d.ts +87 -0
- package/dist/code-explanations/feedback.d.ts.map +1 -0
- package/dist/code-explanations/feedback.js +212 -0
- package/dist/code-explanations/feedback.js.map +1 -0
- package/dist/code-explanations/getRelatedCode.d.ts +80 -0
- package/dist/code-explanations/getRelatedCode.d.ts.map +1 -0
- package/dist/code-explanations/getRelatedCode.js +262 -0
- package/dist/code-explanations/getRelatedCode.js.map +1 -0
- package/dist/code-explanations/index.d.ts +284 -0
- package/dist/code-explanations/index.d.ts.map +1 -0
- package/dist/code-explanations/index.js +249 -0
- package/dist/code-explanations/index.js.map +1 -0
- package/dist/code-explanations/linkCodeToPrompt.d.ts +79 -0
- package/dist/code-explanations/linkCodeToPrompt.d.ts.map +1 -0
- package/dist/code-explanations/linkCodeToPrompt.js +213 -0
- package/dist/code-explanations/linkCodeToPrompt.js.map +1 -0
- package/dist/code-explanations/recallExplanation.d.ts +88 -0
- package/dist/code-explanations/recallExplanation.d.ts.map +1 -0
- package/dist/code-explanations/recallExplanation.js +218 -0
- package/dist/code-explanations/recallExplanation.js.map +1 -0
- package/dist/code-explanations/schema.d.ts +32 -0
- package/dist/code-explanations/schema.d.ts.map +1 -0
- package/dist/code-explanations/schema.js +221 -0
- package/dist/code-explanations/schema.js.map +1 -0
- package/dist/code-explanations/semanticSearch.d.ts +75 -0
- package/dist/code-explanations/semanticSearch.d.ts.map +1 -0
- package/dist/code-explanations/semanticSearch.js +203 -0
- package/dist/code-explanations/semanticSearch.js.map +1 -0
- package/dist/code-explanations/types.d.ts +328 -0
- package/dist/code-explanations/types.d.ts.map +1 -0
- package/dist/code-explanations/types.js +122 -0
- package/dist/code-explanations/types.js.map +1 -0
- package/dist/codebase/codeAnalyzer.d.ts +272 -0
- package/dist/codebase/codeAnalyzer.d.ts.map +1 -0
- package/dist/codebase/codeAnalyzer.js +1353 -0
- package/dist/codebase/codeAnalyzer.js.map +1 -0
- package/dist/codebase/codebaseIndexer.d.ts +360 -0
- package/dist/codebase/codebaseIndexer.d.ts.map +1 -0
- package/dist/codebase/codebaseIndexer.js +1735 -0
- package/dist/codebase/codebaseIndexer.js.map +1 -0
- package/dist/codebase/codebaseTools.d.ts +853 -0
- package/dist/codebase/codebaseTools.d.ts.map +1 -0
- package/dist/codebase/codebaseTools.js +1279 -0
- package/dist/codebase/codebaseTools.js.map +1 -0
- package/dist/codebase/exclusions.d.ts +111 -0
- package/dist/codebase/exclusions.d.ts.map +1 -0
- package/dist/codebase/exclusions.js +771 -0
- package/dist/codebase/exclusions.js.map +1 -0
- package/dist/codebase/fileWatcher.d.ts +135 -0
- package/dist/codebase/fileWatcher.d.ts.map +1 -0
- package/dist/codebase/fileWatcher.js +309 -0
- package/dist/codebase/fileWatcher.js.map +1 -0
- package/dist/codebase/index.d.ts +33 -0
- package/dist/codebase/index.d.ts.map +1 -0
- package/dist/codebase/index.js +77 -0
- package/dist/codebase/index.js.map +1 -0
- package/dist/codebase/ingestion.d.ts +177 -0
- package/dist/codebase/ingestion.d.ts.map +1 -0
- package/dist/codebase/ingestion.js +690 -0
- package/dist/codebase/ingestion.js.map +1 -0
- package/dist/codebase/languageDetection.d.ts +75 -0
- package/dist/codebase/languageDetection.d.ts.map +1 -0
- package/dist/codebase/languageDetection.js +768 -0
- package/dist/codebase/languageDetection.js.map +1 -0
- package/dist/commands/codebaseCommands.d.ts +101 -0
- package/dist/commands/codebaseCommands.d.ts.map +1 -0
- package/dist/commands/codebaseCommands.js +911 -0
- package/dist/commands/codebaseCommands.js.map +1 -0
- package/dist/commands/commandHandler.d.ts +126 -0
- package/dist/commands/commandHandler.d.ts.map +1 -0
- package/dist/commands/commandHandler.js +296 -0
- package/dist/commands/commandHandler.js.map +1 -0
- package/dist/commands/commandLoader.d.ts +103 -0
- package/dist/commands/commandLoader.d.ts.map +1 -0
- package/dist/commands/commandLoader.js +223 -0
- package/dist/commands/commandLoader.js.map +1 -0
- package/dist/commands/contextCommands.d.ts +83 -0
- package/dist/commands/contextCommands.d.ts.map +1 -0
- package/dist/commands/contextCommands.js +512 -0
- package/dist/commands/contextCommands.js.map +1 -0
- package/dist/commands/index.d.ts +24 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +28 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/mcpResources.d.ts +50 -0
- package/dist/commands/mcpResources.d.ts.map +1 -0
- package/dist/commands/mcpResources.js +372 -0
- package/dist/commands/mcpResources.js.map +1 -0
- package/dist/commands/memoryCommands.d.ts +74 -0
- package/dist/commands/memoryCommands.d.ts.map +1 -0
- package/dist/commands/memoryCommands.js +609 -0
- package/dist/commands/memoryCommands.js.map +1 -0
- package/dist/commands/promptCommands.d.ts +91 -0
- package/dist/commands/promptCommands.d.ts.map +1 -0
- package/dist/commands/promptCommands.js +801 -0
- package/dist/commands/promptCommands.js.map +1 -0
- package/dist/commands/teamMemberCommands.d.ts +21 -0
- package/dist/commands/teamMemberCommands.d.ts.map +1 -0
- package/dist/commands/teamMemberCommands.js +137 -0
- package/dist/commands/teamMemberCommands.js.map +1 -0
- package/dist/comms/fileCommsTransport.d.ts +91 -0
- package/dist/comms/fileCommsTransport.d.ts.map +1 -0
- package/dist/comms/fileCommsTransport.js +244 -0
- package/dist/comms/fileCommsTransport.js.map +1 -0
- package/dist/comms/index.d.ts +7 -0
- package/dist/comms/index.d.ts.map +1 -0
- package/dist/comms/index.js +7 -0
- package/dist/comms/index.js.map +1 -0
- package/dist/config/apiKeyDetection.d.ts +41 -0
- package/dist/config/apiKeyDetection.d.ts.map +1 -0
- package/dist/config/apiKeyDetection.js +211 -0
- package/dist/config/apiKeyDetection.js.map +1 -0
- package/dist/config/autoConfig.d.ts +188 -0
- package/dist/config/autoConfig.d.ts.map +1 -0
- package/dist/config/autoConfig.js +850 -0
- package/dist/config/autoConfig.js.map +1 -0
- package/dist/config/configSync.d.ts +119 -0
- package/dist/config/configSync.d.ts.map +1 -0
- package/dist/config/configSync.js +878 -0
- package/dist/config/configSync.js.map +1 -0
- package/dist/config/embeddingTimeouts.d.ts +145 -0
- package/dist/config/embeddingTimeouts.d.ts.map +1 -0
- package/dist/config/embeddingTimeouts.js +255 -0
- package/dist/config/embeddingTimeouts.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +7 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/languageConfig.d.ts +68 -0
- package/dist/config/languageConfig.d.ts.map +1 -0
- package/dist/config/languageConfig.js +473 -0
- package/dist/config/languageConfig.js.map +1 -0
- package/dist/config/password.d.ts +145 -0
- package/dist/config/password.d.ts.map +1 -0
- package/dist/config/password.js +428 -0
- package/dist/config/password.js.map +1 -0
- package/dist/config.d.ts +338 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +1177 -0
- package/dist/config.js.map +1 -0
- package/dist/consolidation.d.ts +44 -0
- package/dist/consolidation.d.ts.map +1 -0
- package/dist/consolidation.js +447 -0
- package/dist/consolidation.js.map +1 -0
- package/dist/constants.d.ts +371 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +552 -0
- package/dist/constants.js.map +1 -0
- package/dist/coordination/TeamMemberRegistry.d.ts +192 -0
- package/dist/coordination/TeamMemberRegistry.d.ts.map +1 -0
- package/dist/coordination/TeamMemberRegistry.js +415 -0
- package/dist/coordination/TeamMemberRegistry.js.map +1 -0
- package/dist/coordination/events.d.ts +369 -0
- package/dist/coordination/events.d.ts.map +1 -0
- package/dist/coordination/events.js +232 -0
- package/dist/coordination/events.js.map +1 -0
- package/dist/coordination/handlers.d.ts +116 -0
- package/dist/coordination/handlers.d.ts.map +1 -0
- package/dist/coordination/handlers.js +400 -0
- package/dist/coordination/handlers.js.map +1 -0
- package/dist/coordination/index.d.ts +14 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +31 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/integration.d.ts +260 -0
- package/dist/coordination/integration.d.ts.map +1 -0
- package/dist/coordination/integration.js +472 -0
- package/dist/coordination/integration.js.map +1 -0
- package/dist/coordination/server.d.ts +266 -0
- package/dist/coordination/server.d.ts.map +1 -0
- package/dist/coordination/server.js +995 -0
- package/dist/coordination/server.js.map +1 -0
- package/dist/coordination/serviceProvider.d.ts +70 -0
- package/dist/coordination/serviceProvider.d.ts.map +1 -0
- package/dist/coordination/serviceProvider.js +273 -0
- package/dist/coordination/serviceProvider.js.map +1 -0
- package/dist/dashboard/api/claudeControl.d.ts +44 -0
- package/dist/dashboard/api/claudeControl.d.ts.map +1 -0
- package/dist/dashboard/api/claudeControl.js +650 -0
- package/dist/dashboard/api/claudeControl.js.map +1 -0
- package/dist/dashboard/api/claudeHistory.d.ts +4 -0
- package/dist/dashboard/api/claudeHistory.d.ts.map +1 -0
- package/dist/dashboard/api/claudeHistory.js +319 -0
- package/dist/dashboard/api/claudeHistory.js.map +1 -0
- package/dist/dashboard/api/dataExport.d.ts +23 -0
- package/dist/dashboard/api/dataExport.d.ts.map +1 -0
- package/dist/dashboard/api/dataExport.js +509 -0
- package/dist/dashboard/api/dataExport.js.map +1 -0
- package/dist/dashboard/api/fileManager.d.ts +39 -0
- package/dist/dashboard/api/fileManager.d.ts.map +1 -0
- package/dist/dashboard/api/fileManager.js +814 -0
- package/dist/dashboard/api/fileManager.js.map +1 -0
- package/dist/dashboard/api/hooks.d.ts +16 -0
- package/dist/dashboard/api/hooks.d.ts.map +1 -0
- package/dist/dashboard/api/hooks.js +342 -0
- package/dist/dashboard/api/hooks.js.map +1 -0
- package/dist/dashboard/api/hotReload.d.ts +14 -0
- package/dist/dashboard/api/hotReload.d.ts.map +1 -0
- package/dist/dashboard/api/hotReload.js +219 -0
- package/dist/dashboard/api/hotReload.js.map +1 -0
- package/dist/dashboard/api/liveSessionStream.d.ts +19 -0
- package/dist/dashboard/api/liveSessionStream.d.ts.map +1 -0
- package/dist/dashboard/api/liveSessionStream.js +430 -0
- package/dist/dashboard/api/liveSessionStream.js.map +1 -0
- package/dist/dashboard/api/memoryRecall.d.ts +20 -0
- package/dist/dashboard/api/memoryRecall.d.ts.map +1 -0
- package/dist/dashboard/api/memoryRecall.js +524 -0
- package/dist/dashboard/api/memoryRecall.js.map +1 -0
- package/dist/dashboard/api/promptSend.d.ts +33 -0
- package/dist/dashboard/api/promptSend.d.ts.map +1 -0
- package/dist/dashboard/api/promptSend.js +544 -0
- package/dist/dashboard/api/promptSend.js.map +1 -0
- package/dist/dashboard/api/settings.d.ts +10 -0
- package/dist/dashboard/api/settings.d.ts.map +1 -0
- package/dist/dashboard/api/settings.js +656 -0
- package/dist/dashboard/api/settings.js.map +1 -0
- package/dist/dashboard/api/setup.d.ts +21 -0
- package/dist/dashboard/api/setup.d.ts.map +1 -0
- package/dist/dashboard/api/setup.js +663 -0
- package/dist/dashboard/api/setup.js.map +1 -0
- package/dist/dashboard/api/specmemTools.d.ts +14 -0
- package/dist/dashboard/api/specmemTools.d.ts.map +1 -0
- package/dist/dashboard/api/specmemTools.js +1059 -0
- package/dist/dashboard/api/specmemTools.js.map +1 -0
- package/dist/dashboard/api/taskTeamMembers.d.ts +8 -0
- package/dist/dashboard/api/taskTeamMembers.d.ts.map +1 -0
- package/dist/dashboard/api/taskTeamMembers.js +136 -0
- package/dist/dashboard/api/taskTeamMembers.js.map +1 -0
- package/dist/dashboard/api/teamMemberDeploy.d.ts +15 -0
- package/dist/dashboard/api/teamMemberDeploy.d.ts.map +1 -0
- package/dist/dashboard/api/teamMemberDeploy.js +421 -0
- package/dist/dashboard/api/teamMemberDeploy.js.map +1 -0
- package/dist/dashboard/api/teamMemberHistory.d.ts +38 -0
- package/dist/dashboard/api/teamMemberHistory.d.ts.map +1 -0
- package/dist/dashboard/api/teamMemberHistory.js +583 -0
- package/dist/dashboard/api/teamMemberHistory.js.map +1 -0
- package/dist/dashboard/api/terminal.d.ts +12 -0
- package/dist/dashboard/api/terminal.d.ts.map +1 -0
- package/dist/dashboard/api/terminal.js +344 -0
- package/dist/dashboard/api/terminal.js.map +1 -0
- package/dist/dashboard/api/terminalInject.d.ts +17 -0
- package/dist/dashboard/api/terminalInject.d.ts.map +1 -0
- package/dist/dashboard/api/terminalInject.js +322 -0
- package/dist/dashboard/api/terminalInject.js.map +1 -0
- package/dist/dashboard/api/terminalStream.d.ts +12 -0
- package/dist/dashboard/api/terminalStream.d.ts.map +1 -0
- package/dist/dashboard/api/terminalStream.js +482 -0
- package/dist/dashboard/api/terminalStream.js.map +1 -0
- package/dist/dashboard/index.d.ts +7 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +7 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/ptyStreamer.d.ts +173 -0
- package/dist/dashboard/ptyStreamer.d.ts.map +1 -0
- package/dist/dashboard/ptyStreamer.js +661 -0
- package/dist/dashboard/ptyStreamer.js.map +1 -0
- package/dist/dashboard/public/DASHBOARD-README.md +378 -0
- package/dist/dashboard/public/INTEGRATION-GUIDE.md +395 -0
- package/dist/dashboard/public/codebase-config.html +1247 -0
- package/dist/dashboard/public/dashboard-v2.html +1942 -0
- package/dist/dashboard/public/data-export.html +819 -0
- package/dist/dashboard/public/example-page.html +164 -0
- package/dist/dashboard/public/file-explorer.html +1023 -0
- package/dist/dashboard/public/hooks.html +1103 -0
- package/dist/dashboard/public/index-improvements.css +499 -0
- package/dist/dashboard/public/index.html +5534 -0
- package/dist/dashboard/public/memory-controls.html +1959 -0
- package/dist/dashboard/public/memory-recall.html +1495 -0
- package/dist/dashboard/public/previews/skeleton-memory-graph.html +361 -0
- package/dist/dashboard/public/previews/skeleton-memory-list.html +366 -0
- package/dist/dashboard/public/previews/skeleton-search-results.html +609 -0
- package/dist/dashboard/public/previews/skeleton-stats-dashboard.html +556 -0
- package/dist/dashboard/public/prompt-console.html +2763 -0
- package/dist/dashboard/public/react-dist/assets/index-CkjobT5B.js +871 -0
- package/dist/dashboard/public/react-dist/assets/index-iRclxMst.css +1 -0
- package/dist/dashboard/public/react-dist/index.html +16 -0
- package/dist/dashboard/public/shared-header.js +325 -0
- package/dist/dashboard/public/shared-language-selector.js +626 -0
- package/dist/dashboard/public/shared-logger.js +66 -0
- package/dist/dashboard/public/shared-nav.js +325 -0
- package/dist/dashboard/public/shared-theme-blue.css +331 -0
- package/dist/dashboard/public/shared-theme.css +813 -0
- package/dist/dashboard/public/shared-toast.js +415 -0
- package/dist/dashboard/public/team-member-history.html +1291 -0
- package/dist/dashboard/public/team-member-spy.html +1199 -0
- package/dist/dashboard/public/team-members.html +3756 -0
- package/dist/dashboard/public/terminal-output.html +1013 -0
- package/dist/dashboard/public/terminal.html +372 -0
- package/dist/dashboard/sessionStore.d.ts +86 -0
- package/dist/dashboard/sessionStore.d.ts.map +1 -0
- package/dist/dashboard/sessionStore.js +262 -0
- package/dist/dashboard/sessionStore.js.map +1 -0
- package/dist/dashboard/standalone.d.ts +27 -0
- package/dist/dashboard/standalone.d.ts.map +1 -0
- package/dist/dashboard/standalone.js +380 -0
- package/dist/dashboard/standalone.js.map +1 -0
- package/dist/dashboard/webServer.d.ts +390 -0
- package/dist/dashboard/webServer.d.ts.map +1 -0
- package/dist/dashboard/webServer.js +4297 -0
- package/dist/dashboard/webServer.js.map +1 -0
- package/dist/dashboard/websocket/teamMemberStream.d.ts +87 -0
- package/dist/dashboard/websocket/teamMemberStream.d.ts.map +1 -0
- package/dist/dashboard/websocket/teamMemberStream.js +366 -0
- package/dist/dashboard/websocket/teamMemberStream.js.map +1 -0
- package/dist/dashboard/websocket/terminalStream.d.ts +130 -0
- package/dist/dashboard/websocket/terminalStream.d.ts.map +1 -0
- package/dist/dashboard/websocket/terminalStream.js +456 -0
- package/dist/dashboard/websocket/terminalStream.js.map +1 -0
- package/dist/database/embeddedPostgres.d.ts +187 -0
- package/dist/database/embeddedPostgres.d.ts.map +1 -0
- package/dist/database/embeddedPostgres.js +763 -0
- package/dist/database/embeddedPostgres.js.map +1 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +20 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/initEmbeddedPostgres.d.ts +124 -0
- package/dist/database/initEmbeddedPostgres.d.ts.map +1 -0
- package/dist/database/initEmbeddedPostgres.js +855 -0
- package/dist/database/initEmbeddedPostgres.js.map +1 -0
- package/dist/database.d.ts +256 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +1209 -0
- package/dist/database.js.map +1 -0
- package/dist/db/apiDataManager.d.ts +334 -0
- package/dist/db/apiDataManager.d.ts.map +1 -0
- package/dist/db/apiDataManager.js +631 -0
- package/dist/db/apiDataManager.js.map +1 -0
- package/dist/db/batchOperations.d.ts +154 -0
- package/dist/db/batchOperations.d.ts.map +1 -0
- package/dist/db/batchOperations.js +564 -0
- package/dist/db/batchOperations.js.map +1 -0
- package/dist/db/bigBrainMigrations.d.ts +48 -0
- package/dist/db/bigBrainMigrations.d.ts.map +1 -0
- package/dist/db/bigBrainMigrations.js +4266 -0
- package/dist/db/bigBrainMigrations.js.map +1 -0
- package/dist/db/connectionPoolGoBrrr.d.ts +94 -0
- package/dist/db/connectionPoolGoBrrr.d.ts.map +1 -0
- package/dist/db/connectionPoolGoBrrr.js +548 -0
- package/dist/db/connectionPoolGoBrrr.js.map +1 -0
- package/dist/db/dashboardQueries.d.ts +182 -0
- package/dist/db/dashboardQueries.d.ts.map +1 -0
- package/dist/db/dashboardQueries.js +821 -0
- package/dist/db/dashboardQueries.js.map +1 -0
- package/dist/db/deploymentBootstrap.d.ts +43 -0
- package/dist/db/deploymentBootstrap.d.ts.map +1 -0
- package/dist/db/deploymentBootstrap.js +329 -0
- package/dist/db/deploymentBootstrap.js.map +1 -0
- package/dist/db/dimensionService.d.ts +140 -0
- package/dist/db/dimensionService.d.ts.map +1 -0
- package/dist/db/dimensionService.js +261 -0
- package/dist/db/dimensionService.js.map +1 -0
- package/dist/db/embeddingOverflow.d.ts +69 -0
- package/dist/db/embeddingOverflow.d.ts.map +1 -0
- package/dist/db/embeddingOverflow.js +332 -0
- package/dist/db/embeddingOverflow.js.map +1 -0
- package/dist/db/embeddingOverflow.sql +221 -0
- package/dist/db/findThatShit.d.ts +145 -0
- package/dist/db/findThatShit.d.ts.map +1 -0
- package/dist/db/findThatShit.js +782 -0
- package/dist/db/findThatShit.js.map +1 -0
- package/dist/db/hotPathManager.d.ts +187 -0
- package/dist/db/hotPathManager.d.ts.map +1 -0
- package/dist/db/hotPathManager.js +504 -0
- package/dist/db/hotPathManager.js.map +1 -0
- package/dist/db/index.d.ts +85 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +219 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/memoryDrilldown.sql +99 -0
- package/dist/db/migrate.d.ts +3 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +97 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/migrateJsonToPostgres.d.ts +43 -0
- package/dist/db/migrateJsonToPostgres.d.ts.map +1 -0
- package/dist/db/migrateJsonToPostgres.js +465 -0
- package/dist/db/migrateJsonToPostgres.js.map +1 -0
- package/dist/db/nukeFromOrbit.d.ts +63 -0
- package/dist/db/nukeFromOrbit.d.ts.map +1 -0
- package/dist/db/nukeFromOrbit.js +499 -0
- package/dist/db/nukeFromOrbit.js.map +1 -0
- package/dist/db/processedTraining.sql +60 -0
- package/dist/db/projectNamespacing.d.ts +258 -0
- package/dist/db/projectNamespacing.d.ts.map +1 -0
- package/dist/db/projectNamespacing.js +920 -0
- package/dist/db/projectNamespacing.js.map +1 -0
- package/dist/db/projectNamespacing.sql +374 -0
- package/dist/db/projectSchemaInit.sql +271 -0
- package/dist/db/spatialMemory.d.ts +296 -0
- package/dist/db/spatialMemory.d.ts.map +1 -0
- package/dist/db/spatialMemory.js +818 -0
- package/dist/db/spatialMemory.js.map +1 -0
- package/dist/db/streamingQuery.d.ts +143 -0
- package/dist/db/streamingQuery.d.ts.map +1 -0
- package/dist/db/streamingQuery.js +350 -0
- package/dist/db/streamingQuery.js.map +1 -0
- package/dist/db/teamComms.sql +224 -0
- package/dist/db/yeetStuffInDb.d.ts +72 -0
- package/dist/db/yeetStuffInDb.d.ts.map +1 -0
- package/dist/db/yeetStuffInDb.js +473 -0
- package/dist/db/yeetStuffInDb.js.map +1 -0
- package/dist/embedding-providers/index.d.ts +10 -0
- package/dist/embedding-providers/index.d.ts.map +1 -0
- package/dist/embedding-providers/index.js +12 -0
- package/dist/embedding-providers/index.js.map +1 -0
- package/dist/embeddings/projectionLayer.d.ts +114 -0
- package/dist/embeddings/projectionLayer.d.ts.map +1 -0
- package/dist/embeddings/projectionLayer.js +345 -0
- package/dist/embeddings/projectionLayer.js.map +1 -0
- package/dist/events/Publisher.d.ts +193 -0
- package/dist/events/Publisher.d.ts.map +1 -0
- package/dist/events/Publisher.js +439 -0
- package/dist/events/Publisher.js.map +1 -0
- package/dist/events/config.d.ts +139 -0
- package/dist/events/config.d.ts.map +1 -0
- package/dist/events/config.js +266 -0
- package/dist/events/config.js.map +1 -0
- package/dist/events/index.d.ts +19 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +31 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/integration.d.ts +206 -0
- package/dist/events/integration.d.ts.map +1 -0
- package/dist/events/integration.js +348 -0
- package/dist/events/integration.js.map +1 -0
- package/dist/events/metrics.d.ts +147 -0
- package/dist/events/metrics.d.ts.map +1 -0
- package/dist/events/metrics.js +343 -0
- package/dist/events/metrics.js.map +1 -0
- package/dist/hooks/cli.d.ts +28 -0
- package/dist/hooks/cli.d.ts.map +1 -0
- package/dist/hooks/cli.js +118 -0
- package/dist/hooks/cli.js.map +1 -0
- package/dist/hooks/contextInjectionHook.d.ts +60 -0
- package/dist/hooks/contextInjectionHook.d.ts.map +1 -0
- package/dist/hooks/contextInjectionHook.js +294 -0
- package/dist/hooks/contextInjectionHook.js.map +1 -0
- package/dist/hooks/drilldownHook.d.ts +125 -0
- package/dist/hooks/drilldownHook.d.ts.map +1 -0
- package/dist/hooks/drilldownHook.js +181 -0
- package/dist/hooks/drilldownHook.js.map +1 -0
- package/dist/hooks/hookManager.d.ts +180 -0
- package/dist/hooks/hookManager.d.ts.map +1 -0
- package/dist/hooks/hookManager.js +782 -0
- package/dist/hooks/hookManager.js.map +1 -0
- package/dist/hooks/index.d.ts +62 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +66 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/lowContextHook.d.ts +71 -0
- package/dist/hooks/lowContextHook.d.ts.map +1 -0
- package/dist/hooks/lowContextHook.js +258 -0
- package/dist/hooks/lowContextHook.js.map +1 -0
- package/dist/hooks/simpleContextHook.d.ts +65 -0
- package/dist/hooks/simpleContextHook.d.ts.map +1 -0
- package/dist/hooks/simpleContextHook.js +194 -0
- package/dist/hooks/simpleContextHook.js.map +1 -0
- package/dist/hooks/teamFramingCli.d.ts +56 -0
- package/dist/hooks/teamFramingCli.d.ts.map +1 -0
- package/dist/hooks/teamFramingCli.js +264 -0
- package/dist/hooks/teamFramingCli.js.map +1 -0
- package/dist/hooks/teamMemberPrepromptHook.d.ts +150 -0
- package/dist/hooks/teamMemberPrepromptHook.d.ts.map +1 -0
- package/dist/hooks/teamMemberPrepromptHook.js +308 -0
- package/dist/hooks/teamMemberPrepromptHook.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4433 -0
- package/dist/index.js.map +1 -0
- package/dist/init/claudeConfigInjector.d.ts +116 -0
- package/dist/init/claudeConfigInjector.d.ts.map +1 -0
- package/dist/init/claudeConfigInjector.js +1154 -0
- package/dist/init/claudeConfigInjector.js.map +1 -0
- package/dist/installer/autoInstall.d.ts +72 -0
- package/dist/installer/autoInstall.d.ts.map +1 -0
- package/dist/installer/autoInstall.js +617 -0
- package/dist/installer/autoInstall.js.map +1 -0
- package/dist/installer/dbSetup.d.ts +84 -0
- package/dist/installer/dbSetup.d.ts.map +1 -0
- package/dist/installer/dbSetup.js +350 -0
- package/dist/installer/dbSetup.js.map +1 -0
- package/dist/installer/firstRun.d.ts +49 -0
- package/dist/installer/firstRun.d.ts.map +1 -0
- package/dist/installer/firstRun.js +207 -0
- package/dist/installer/firstRun.js.map +1 -0
- package/dist/installer/index.d.ts +10 -0
- package/dist/installer/index.d.ts.map +1 -0
- package/dist/installer/index.js +10 -0
- package/dist/installer/index.js.map +1 -0
- package/dist/installer/silentAutoInstall.d.ts +99 -0
- package/dist/installer/silentAutoInstall.d.ts.map +1 -0
- package/dist/installer/silentAutoInstall.js +491 -0
- package/dist/installer/silentAutoInstall.js.map +1 -0
- package/dist/installer/systemDeps.d.ts +54 -0
- package/dist/installer/systemDeps.d.ts.map +1 -0
- package/dist/installer/systemDeps.js +322 -0
- package/dist/installer/systemDeps.js.map +1 -0
- package/dist/mcp/cliNotifications.d.ts +133 -0
- package/dist/mcp/cliNotifications.d.ts.map +1 -0
- package/dist/mcp/cliNotifications.js +289 -0
- package/dist/mcp/cliNotifications.js.map +1 -0
- package/dist/mcp/embeddingServerManager.d.ts +307 -0
- package/dist/mcp/embeddingServerManager.d.ts.map +1 -0
- package/dist/mcp/embeddingServerManager.js +2081 -0
- package/dist/mcp/embeddingServerManager.js.map +1 -0
- package/dist/mcp/healthMonitor.d.ts +196 -0
- package/dist/mcp/healthMonitor.d.ts.map +1 -0
- package/dist/mcp/healthMonitor.js +685 -0
- package/dist/mcp/healthMonitor.js.map +1 -0
- package/dist/mcp/hotReloadManager.d.ts +101 -0
- package/dist/mcp/hotReloadManager.d.ts.map +1 -0
- package/dist/mcp/hotReloadManager.js +251 -0
- package/dist/mcp/hotReloadManager.js.map +1 -0
- package/dist/mcp/index.d.ts +16 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +22 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/mcpProtocolHandler.d.ts +64 -0
- package/dist/mcp/mcpProtocolHandler.d.ts.map +1 -0
- package/dist/mcp/mcpProtocolHandler.js +253 -0
- package/dist/mcp/mcpProtocolHandler.js.map +1 -0
- package/dist/mcp/miniCOTServerManager.d.ts +336 -0
- package/dist/mcp/miniCOTServerManager.d.ts.map +1 -0
- package/dist/mcp/miniCOTServerManager.js +1384 -0
- package/dist/mcp/miniCOTServerManager.js.map +1 -0
- package/dist/mcp/promptExecutor.d.ts +188 -0
- package/dist/mcp/promptExecutor.d.ts.map +1 -0
- package/dist/mcp/promptExecutor.js +469 -0
- package/dist/mcp/promptExecutor.js.map +1 -0
- package/dist/mcp/reloadBroadcast.d.ts +127 -0
- package/dist/mcp/reloadBroadcast.d.ts.map +1 -0
- package/dist/mcp/reloadBroadcast.js +275 -0
- package/dist/mcp/reloadBroadcast.js.map +1 -0
- package/dist/mcp/resilientTransport.d.ts +249 -0
- package/dist/mcp/resilientTransport.d.ts.map +1 -0
- package/dist/mcp/resilientTransport.js +931 -0
- package/dist/mcp/resilientTransport.js.map +1 -0
- package/dist/mcp/samplingHandler.d.ts +129 -0
- package/dist/mcp/samplingHandler.d.ts.map +1 -0
- package/dist/mcp/samplingHandler.js +276 -0
- package/dist/mcp/samplingHandler.js.map +1 -0
- package/dist/mcp/specMemServer.d.ts +305 -0
- package/dist/mcp/specMemServer.d.ts.map +1 -0
- package/dist/mcp/specMemServer.js +2048 -0
- package/dist/mcp/specMemServer.js.map +1 -0
- package/dist/mcp/toolRegistry.d.ts +122 -0
- package/dist/mcp/toolRegistry.d.ts.map +1 -0
- package/dist/mcp/toolRegistry.js +609 -0
- package/dist/mcp/toolRegistry.js.map +1 -0
- package/dist/mcp/tools/embeddingControl.d.ts +114 -0
- package/dist/mcp/tools/embeddingControl.d.ts.map +1 -0
- package/dist/mcp/tools/embeddingControl.js +222 -0
- package/dist/mcp/tools/embeddingControl.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +10 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +17 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/teamComms.d.ts +444 -0
- package/dist/mcp/tools/teamComms.d.ts.map +1 -0
- package/dist/mcp/tools/teamComms.js +1953 -0
- package/dist/mcp/tools/teamComms.js.map +1 -0
- package/dist/mcp/triggerSystem.d.ts +129 -0
- package/dist/mcp/triggerSystem.d.ts.map +1 -0
- package/dist/mcp/triggerSystem.js +363 -0
- package/dist/mcp/triggerSystem.js.map +1 -0
- package/dist/mcp/watcherIntegration.d.ts +77 -0
- package/dist/mcp/watcherIntegration.d.ts.map +1 -0
- package/dist/mcp/watcherIntegration.js +428 -0
- package/dist/mcp/watcherIntegration.js.map +1 -0
- package/dist/mcp/watcherToolWrappers.d.ts +89 -0
- package/dist/mcp/watcherToolWrappers.d.ts.map +1 -0
- package/dist/mcp/watcherToolWrappers.js +91 -0
- package/dist/mcp/watcherToolWrappers.js.map +1 -0
- package/dist/memorization/claudeCodeMigration.d.ts +34 -0
- package/dist/memorization/claudeCodeMigration.d.ts.map +1 -0
- package/dist/memorization/claudeCodeMigration.js +210 -0
- package/dist/memorization/claudeCodeMigration.js.map +1 -0
- package/dist/memorization/claudeCodeTracker.d.ts +147 -0
- package/dist/memorization/claudeCodeTracker.d.ts.map +1 -0
- package/dist/memorization/claudeCodeTracker.js +424 -0
- package/dist/memorization/claudeCodeTracker.js.map +1 -0
- package/dist/memorization/codeMemorizer.d.ts +158 -0
- package/dist/memorization/codeMemorizer.d.ts.map +1 -0
- package/dist/memorization/codeMemorizer.js +357 -0
- package/dist/memorization/codeMemorizer.js.map +1 -0
- package/dist/memorization/codeRecall.d.ts +156 -0
- package/dist/memorization/codeRecall.d.ts.map +1 -0
- package/dist/memorization/codeRecall.js +499 -0
- package/dist/memorization/codeRecall.js.map +1 -0
- package/dist/memorization/index.d.ts +55 -0
- package/dist/memorization/index.d.ts.map +1 -0
- package/dist/memorization/index.js +64 -0
- package/dist/memorization/index.js.map +1 -0
- package/dist/memorization/memorizationTools.d.ts +413 -0
- package/dist/memorization/memorizationTools.d.ts.map +1 -0
- package/dist/memorization/memorizationTools.js +513 -0
- package/dist/memorization/memorizationTools.js.map +1 -0
- package/dist/memorization/watcherIntegration.d.ts +100 -0
- package/dist/memorization/watcherIntegration.d.ts.map +1 -0
- package/dist/memorization/watcherIntegration.js +196 -0
- package/dist/memorization/watcherIntegration.js.map +1 -0
- package/dist/memory/humanLikeMemory.d.ts +206 -0
- package/dist/memory/humanLikeMemory.d.ts.map +1 -0
- package/dist/memory/humanLikeMemory.js +603 -0
- package/dist/memory/humanLikeMemory.js.map +1 -0
- package/dist/memory/index.d.ts +22 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +24 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/memoryEvolutionMigration.d.ts +36 -0
- package/dist/memory/memoryEvolutionMigration.d.ts.map +1 -0
- package/dist/memory/memoryEvolutionMigration.js +371 -0
- package/dist/memory/memoryEvolutionMigration.js.map +1 -0
- package/dist/memory/quadrantSearch.d.ts +221 -0
- package/dist/memory/quadrantSearch.d.ts.map +1 -0
- package/dist/memory/quadrantSearch.js +897 -0
- package/dist/memory/quadrantSearch.js.map +1 -0
- package/dist/middleware/apiVersioning.d.ts +83 -0
- package/dist/middleware/apiVersioning.d.ts.map +1 -0
- package/dist/middleware/apiVersioning.js +152 -0
- package/dist/middleware/apiVersioning.js.map +1 -0
- package/dist/middleware/compression.d.ts +48 -0
- package/dist/middleware/compression.d.ts.map +1 -0
- package/dist/middleware/compression.js +240 -0
- package/dist/middleware/compression.js.map +1 -0
- package/dist/middleware/csrf.d.ts +118 -0
- package/dist/middleware/csrf.d.ts.map +1 -0
- package/dist/middleware/csrf.js +300 -0
- package/dist/middleware/csrf.js.map +1 -0
- package/dist/middleware/index.d.ts +13 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +17 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/wsRateLimiter.d.ts +129 -0
- package/dist/middleware/wsRateLimiter.d.ts.map +1 -0
- package/dist/middleware/wsRateLimiter.js +279 -0
- package/dist/middleware/wsRateLimiter.js.map +1 -0
- package/dist/migrations/run.d.ts +2 -0
- package/dist/migrations/run.d.ts.map +1 -0
- package/dist/migrations/run.js +25 -0
- package/dist/migrations/run.js.map +1 -0
- package/dist/migrations/syncDimensions.d.ts +24 -0
- package/dist/migrations/syncDimensions.d.ts.map +1 -0
- package/dist/migrations/syncDimensions.js +140 -0
- package/dist/migrations/syncDimensions.js.map +1 -0
- package/dist/migrations/teamComms.d.ts +16 -0
- package/dist/migrations/teamComms.d.ts.map +1 -0
- package/dist/migrations/teamComms.js +210 -0
- package/dist/migrations/teamComms.js.map +1 -0
- package/dist/openapi/index.d.ts +10 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +10 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/spec.d.ts +902 -0
- package/dist/openapi/spec.d.ts.map +1 -0
- package/dist/openapi/spec.js +733 -0
- package/dist/openapi/spec.js.map +1 -0
- package/dist/packages/dependencyHistory.d.ts +113 -0
- package/dist/packages/dependencyHistory.d.ts.map +1 -0
- package/dist/packages/dependencyHistory.js +360 -0
- package/dist/packages/dependencyHistory.js.map +1 -0
- package/dist/packages/index.d.ts +30 -0
- package/dist/packages/index.d.ts.map +1 -0
- package/dist/packages/index.js +65 -0
- package/dist/packages/index.js.map +1 -0
- package/dist/packages/packageTools.d.ts +255 -0
- package/dist/packages/packageTools.d.ts.map +1 -0
- package/dist/packages/packageTools.js +242 -0
- package/dist/packages/packageTools.js.map +1 -0
- package/dist/packages/packageTracker.d.ts +98 -0
- package/dist/packages/packageTracker.d.ts.map +1 -0
- package/dist/packages/packageTracker.js +268 -0
- package/dist/packages/packageTracker.js.map +1 -0
- package/dist/packages/packageWatcher.d.ts +62 -0
- package/dist/packages/packageWatcher.d.ts.map +1 -0
- package/dist/packages/packageWatcher.js +146 -0
- package/dist/packages/packageWatcher.js.map +1 -0
- package/dist/providers/MiniCOTProvider.d.ts +48 -0
- package/dist/providers/MiniCOTProvider.d.ts.map +1 -0
- package/dist/providers/MiniCOTProvider.js +98 -0
- package/dist/providers/MiniCOTProvider.js.map +1 -0
- package/dist/reminders/index.d.ts +5 -0
- package/dist/reminders/index.d.ts.map +1 -0
- package/dist/reminders/index.js +5 -0
- package/dist/reminders/index.js.map +1 -0
- package/dist/reminders/skillReminder.d.ts +131 -0
- package/dist/reminders/skillReminder.d.ts.map +1 -0
- package/dist/reminders/skillReminder.js +386 -0
- package/dist/reminders/skillReminder.js.map +1 -0
- package/dist/search.d.ts +35 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +574 -0
- package/dist/search.js.map +1 -0
- package/dist/security/localhostOnly.d.ts +36 -0
- package/dist/security/localhostOnly.d.ts.map +1 -0
- package/dist/security/localhostOnly.js +101 -0
- package/dist/security/localhostOnly.js.map +1 -0
- package/dist/services/CameraZoomSearch.d.ts +206 -0
- package/dist/services/CameraZoomSearch.d.ts.map +1 -0
- package/dist/services/CameraZoomSearch.js +669 -0
- package/dist/services/CameraZoomSearch.js.map +1 -0
- package/dist/services/DataFlowPipeline.d.ts +111 -0
- package/dist/services/DataFlowPipeline.d.ts.map +1 -0
- package/dist/services/DataFlowPipeline.js +379 -0
- package/dist/services/DataFlowPipeline.js.map +1 -0
- package/dist/services/DimensionAdapter.d.ts +194 -0
- package/dist/services/DimensionAdapter.d.ts.map +1 -0
- package/dist/services/DimensionAdapter.js +566 -0
- package/dist/services/DimensionAdapter.js.map +1 -0
- package/dist/services/DimensionService.d.ts +252 -0
- package/dist/services/DimensionService.d.ts.map +1 -0
- package/dist/services/DimensionService.js +564 -0
- package/dist/services/DimensionService.js.map +1 -0
- package/dist/services/EmbeddingQueue.d.ts +71 -0
- package/dist/services/EmbeddingQueue.d.ts.map +1 -0
- package/dist/services/EmbeddingQueue.js +258 -0
- package/dist/services/EmbeddingQueue.js.map +1 -0
- package/dist/services/MemoryDrilldown.d.ts +226 -0
- package/dist/services/MemoryDrilldown.d.ts.map +1 -0
- package/dist/services/MemoryDrilldown.js +479 -0
- package/dist/services/MemoryDrilldown.js.map +1 -0
- package/dist/services/MiniCOTScorer.d.ts +140 -0
- package/dist/services/MiniCOTScorer.d.ts.map +1 -0
- package/dist/services/MiniCOTScorer.js +292 -0
- package/dist/services/MiniCOTScorer.js.map +1 -0
- package/dist/services/ProjectContext.d.ts +342 -0
- package/dist/services/ProjectContext.d.ts.map +1 -0
- package/dist/services/ProjectContext.js +667 -0
- package/dist/services/ProjectContext.js.map +1 -0
- package/dist/services/ResponseCompactor.d.ts +135 -0
- package/dist/services/ResponseCompactor.d.ts.map +1 -0
- package/dist/services/ResponseCompactor.js +501 -0
- package/dist/services/ResponseCompactor.js.map +1 -0
- package/dist/services/TeamCommsDbService.d.ts +202 -0
- package/dist/services/TeamCommsDbService.d.ts.map +1 -0
- package/dist/services/TeamCommsDbService.js +526 -0
- package/dist/services/TeamCommsDbService.js.map +1 -0
- package/dist/services/UnifiedPasswordService.d.ts +166 -0
- package/dist/services/UnifiedPasswordService.d.ts.map +1 -0
- package/dist/services/UnifiedPasswordService.js +587 -0
- package/dist/services/UnifiedPasswordService.js.map +1 -0
- package/dist/services/adaptiveSearchConfig.d.ts +64 -0
- package/dist/services/adaptiveSearchConfig.d.ts.map +1 -0
- package/dist/services/adaptiveSearchConfig.js +187 -0
- package/dist/services/adaptiveSearchConfig.js.map +1 -0
- package/dist/skills/index.d.ts +8 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +8 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skillScanner.d.ts +203 -0
- package/dist/skills/skillScanner.d.ts.map +1 -0
- package/dist/skills/skillScanner.js +559 -0
- package/dist/skills/skillScanner.js.map +1 -0
- package/dist/skills/skillsResource.d.ts +69 -0
- package/dist/skills/skillsResource.d.ts.map +1 -0
- package/dist/skills/skillsResource.js +257 -0
- package/dist/skills/skillsResource.js.map +1 -0
- package/dist/startup/index.d.ts +9 -0
- package/dist/startup/index.d.ts.map +1 -0
- package/dist/startup/index.js +12 -0
- package/dist/startup/index.js.map +1 -0
- package/dist/startup/startupIndexing.d.ts +80 -0
- package/dist/startup/startupIndexing.d.ts.map +1 -0
- package/dist/startup/startupIndexing.js +463 -0
- package/dist/startup/startupIndexing.js.map +1 -0
- package/dist/startup/validation.d.ts +89 -0
- package/dist/startup/validation.d.ts.map +1 -0
- package/dist/startup/validation.js +590 -0
- package/dist/startup/validation.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +4 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/overflowManager.d.ts +80 -0
- package/dist/storage/overflowManager.d.ts.map +1 -0
- package/dist/storage/overflowManager.js +317 -0
- package/dist/storage/overflowManager.js.map +1 -0
- package/dist/storage/overflowStorage.d.ts +69 -0
- package/dist/storage/overflowStorage.d.ts.map +1 -0
- package/dist/storage/overflowStorage.js +379 -0
- package/dist/storage/overflowStorage.js.map +1 -0
- package/dist/storage/toonFormat.d.ts +50 -0
- package/dist/storage/toonFormat.d.ts.map +1 -0
- package/dist/storage/toonFormat.js +224 -0
- package/dist/storage/toonFormat.js.map +1 -0
- package/dist/team-members/communication.d.ts +237 -0
- package/dist/team-members/communication.d.ts.map +1 -0
- package/dist/team-members/communication.js +650 -0
- package/dist/team-members/communication.js.map +1 -0
- package/dist/team-members/index.d.ts +14 -0
- package/dist/team-members/index.d.ts.map +1 -0
- package/dist/team-members/index.js +22 -0
- package/dist/team-members/index.js.map +1 -0
- package/dist/team-members/taskOrchestrator.d.ts +224 -0
- package/dist/team-members/taskOrchestrator.d.ts.map +1 -0
- package/dist/team-members/taskOrchestrator.js +574 -0
- package/dist/team-members/taskOrchestrator.js.map +1 -0
- package/dist/team-members/taskTeamMemberLogger.d.ts +157 -0
- package/dist/team-members/taskTeamMemberLogger.d.ts.map +1 -0
- package/dist/team-members/taskTeamMemberLogger.js +478 -0
- package/dist/team-members/taskTeamMemberLogger.js.map +1 -0
- package/dist/team-members/teamCommsService.d.ts +221 -0
- package/dist/team-members/teamCommsService.d.ts.map +1 -0
- package/dist/team-members/teamCommsService.js +628 -0
- package/dist/team-members/teamCommsService.js.map +1 -0
- package/dist/team-members/teamMemberChannels.d.ts +217 -0
- package/dist/team-members/teamMemberChannels.d.ts.map +1 -0
- package/dist/team-members/teamMemberChannels.js +687 -0
- package/dist/team-members/teamMemberChannels.js.map +1 -0
- package/dist/team-members/teamMemberDashboard.d.ts +222 -0
- package/dist/team-members/teamMemberDashboard.d.ts.map +1 -0
- package/dist/team-members/teamMemberDashboard.js +610 -0
- package/dist/team-members/teamMemberDashboard.js.map +1 -0
- package/dist/team-members/teamMemberDeployment.d.ts +60 -0
- package/dist/team-members/teamMemberDeployment.d.ts.map +1 -0
- package/dist/team-members/teamMemberDeployment.js +429 -0
- package/dist/team-members/teamMemberDeployment.js.map +1 -0
- package/dist/team-members/teamMemberDiscovery.d.ts +178 -0
- package/dist/team-members/teamMemberDiscovery.d.ts.map +1 -0
- package/dist/team-members/teamMemberDiscovery.js +446 -0
- package/dist/team-members/teamMemberDiscovery.js.map +1 -0
- package/dist/team-members/teamMemberHistory.d.ts +80 -0
- package/dist/team-members/teamMemberHistory.d.ts.map +1 -0
- package/dist/team-members/teamMemberHistory.js +426 -0
- package/dist/team-members/teamMemberHistory.js.map +1 -0
- package/dist/team-members/teamMemberLimits.d.ts +66 -0
- package/dist/team-members/teamMemberLimits.d.ts.map +1 -0
- package/dist/team-members/teamMemberLimits.js +259 -0
- package/dist/team-members/teamMemberLimits.js.map +1 -0
- package/dist/team-members/teamMemberRegistry.d.ts +199 -0
- package/dist/team-members/teamMemberRegistry.d.ts.map +1 -0
- package/dist/team-members/teamMemberRegistry.js +572 -0
- package/dist/team-members/teamMemberRegistry.js.map +1 -0
- package/dist/team-members/teamMemberTracker.d.ts +148 -0
- package/dist/team-members/teamMemberTracker.d.ts.map +1 -0
- package/dist/team-members/teamMemberTracker.js +828 -0
- package/dist/team-members/teamMemberTracker.js.map +1 -0
- package/dist/team-members/workers/aiWorker.d.ts +53 -0
- package/dist/team-members/workers/aiWorker.d.ts.map +1 -0
- package/dist/team-members/workers/aiWorker.js +322 -0
- package/dist/team-members/workers/aiWorker.js.map +1 -0
- package/dist/team-members/workers/baseWorker.d.ts +101 -0
- package/dist/team-members/workers/baseWorker.d.ts.map +1 -0
- package/dist/team-members/workers/baseWorker.js +179 -0
- package/dist/team-members/workers/baseWorker.js.map +1 -0
- package/dist/team-members/workers/codeReviewWorker.d.ts +3 -0
- package/dist/team-members/workers/codeReviewWorker.d.ts.map +1 -0
- package/dist/team-members/workers/codeReviewWorker.js +144 -0
- package/dist/team-members/workers/codeReviewWorker.js.map +1 -0
- package/dist/team-members/workers/index.d.ts +7 -0
- package/dist/team-members/workers/index.d.ts.map +1 -0
- package/dist/team-members/workers/index.js +7 -0
- package/dist/team-members/workers/index.js.map +1 -0
- package/dist/team-members/workers/repairWorker.d.ts +9 -0
- package/dist/team-members/workers/repairWorker.d.ts.map +1 -0
- package/dist/team-members/workers/repairWorker.js +102 -0
- package/dist/team-members/workers/repairWorker.js.map +1 -0
- package/dist/team-members/workers/sendToTeamMemberB.d.ts +9 -0
- package/dist/team-members/workers/sendToTeamMemberB.d.ts.map +1 -0
- package/dist/team-members/workers/sendToTeamMemberB.js +105 -0
- package/dist/team-members/workers/sendToTeamMemberB.js.map +1 -0
- package/dist/team-members/workers/specmemClient.d.ts +179 -0
- package/dist/team-members/workers/specmemClient.d.ts.map +1 -0
- package/dist/team-members/workers/specmemClient.js +421 -0
- package/dist/team-members/workers/specmemClient.js.map +1 -0
- package/dist/team-members/workers/testCommunication.d.ts +8 -0
- package/dist/team-members/workers/testCommunication.d.ts.map +1 -0
- package/dist/team-members/workers/testCommunication.js +136 -0
- package/dist/team-members/workers/testCommunication.js.map +1 -0
- package/dist/team-members/workers/testCommunicationSuite.d.ts +26 -0
- package/dist/team-members/workers/testCommunicationSuite.d.ts.map +1 -0
- package/dist/team-members/workers/testCommunicationSuite.js +415 -0
- package/dist/team-members/workers/testCommunicationSuite.js.map +1 -0
- package/dist/team-members/workers/testWorker.d.ts +9 -0
- package/dist/team-members/workers/testWorker.d.ts.map +1 -0
- package/dist/team-members/workers/testWorker.js +107 -0
- package/dist/team-members/workers/testWorker.js.map +1 -0
- package/dist/tools/agentDefinitions.d.ts +30 -0
- package/dist/tools/agentDefinitions.d.ts.map +1 -0
- package/dist/tools/agentDefinitions.js +166 -0
- package/dist/tools/agentDefinitions.js.map +1 -0
- package/dist/tools/goofy/checkSyncStatus.d.ts +68 -0
- package/dist/tools/goofy/checkSyncStatus.d.ts.map +1 -0
- package/dist/tools/goofy/checkSyncStatus.js +112 -0
- package/dist/tools/goofy/checkSyncStatus.js.map +1 -0
- package/dist/tools/goofy/codeMemoryLink.d.ts +82 -0
- package/dist/tools/goofy/codeMemoryLink.d.ts.map +1 -0
- package/dist/tools/goofy/codeMemoryLink.js +212 -0
- package/dist/tools/goofy/codeMemoryLink.js.map +1 -0
- package/dist/tools/goofy/compareInstanceMemory.d.ts +97 -0
- package/dist/tools/goofy/compareInstanceMemory.d.ts.map +1 -0
- package/dist/tools/goofy/compareInstanceMemory.js +218 -0
- package/dist/tools/goofy/compareInstanceMemory.js.map +1 -0
- package/dist/tools/goofy/createReasoningChain.d.ts +135 -0
- package/dist/tools/goofy/createReasoningChain.d.ts.map +1 -0
- package/dist/tools/goofy/createReasoningChain.js +257 -0
- package/dist/tools/goofy/createReasoningChain.js.map +1 -0
- package/dist/tools/goofy/deployTeamMember.d.ts +63 -0
- package/dist/tools/goofy/deployTeamMember.d.ts.map +1 -0
- package/dist/tools/goofy/deployTeamMember.js +103 -0
- package/dist/tools/goofy/deployTeamMember.js.map +1 -0
- package/dist/tools/goofy/drillDown.d.ts +143 -0
- package/dist/tools/goofy/drillDown.d.ts.map +1 -0
- package/dist/tools/goofy/drillDown.js +288 -0
- package/dist/tools/goofy/drillDown.js.map +1 -0
- package/dist/tools/goofy/extractClaudeSessions.d.ts +90 -0
- package/dist/tools/goofy/extractClaudeSessions.d.ts.map +1 -0
- package/dist/tools/goofy/extractClaudeSessions.js +277 -0
- package/dist/tools/goofy/extractClaudeSessions.js.map +1 -0
- package/dist/tools/goofy/extractContextRestorations.d.ts +70 -0
- package/dist/tools/goofy/extractContextRestorations.d.ts.map +1 -0
- package/dist/tools/goofy/extractContextRestorations.js +100 -0
- package/dist/tools/goofy/extractContextRestorations.js.map +1 -0
- package/dist/tools/goofy/findCodePointers.d.ts +364 -0
- package/dist/tools/goofy/findCodePointers.d.ts.map +1 -0
- package/dist/tools/goofy/findCodePointers.js +1764 -0
- package/dist/tools/goofy/findCodePointers.js.map +1 -0
- package/dist/tools/goofy/findMemoryGallery.d.ts +40 -0
- package/dist/tools/goofy/findMemoryGallery.d.ts.map +1 -0
- package/dist/tools/goofy/findMemoryGallery.js +66 -0
- package/dist/tools/goofy/findMemoryGallery.js.map +1 -0
- package/dist/tools/goofy/findWhatISaid.d.ts +300 -0
- package/dist/tools/goofy/findWhatISaid.d.ts.map +1 -0
- package/dist/tools/goofy/findWhatISaid.js +2547 -0
- package/dist/tools/goofy/findWhatISaid.js.map +1 -0
- package/dist/tools/goofy/forceResync.d.ts +57 -0
- package/dist/tools/goofy/forceResync.d.ts.map +1 -0
- package/dist/tools/goofy/forceResync.js +100 -0
- package/dist/tools/goofy/forceResync.js.map +1 -0
- package/dist/tools/goofy/getActiveTeamMembers.d.ts +48 -0
- package/dist/tools/goofy/getActiveTeamMembers.d.ts.map +1 -0
- package/dist/tools/goofy/getActiveTeamMembers.js +136 -0
- package/dist/tools/goofy/getActiveTeamMembers.js.map +1 -0
- package/dist/tools/goofy/getMemoryFull.d.ts +34 -0
- package/dist/tools/goofy/getMemoryFull.d.ts.map +1 -0
- package/dist/tools/goofy/getMemoryFull.js +58 -0
- package/dist/tools/goofy/getMemoryFull.js.map +1 -0
- package/dist/tools/goofy/getSessionWatcherStatus.d.ts +43 -0
- package/dist/tools/goofy/getSessionWatcherStatus.d.ts.map +1 -0
- package/dist/tools/goofy/getSessionWatcherStatus.js +92 -0
- package/dist/tools/goofy/getSessionWatcherStatus.js.map +1 -0
- package/dist/tools/goofy/getTeamMemberOutput.d.ts +35 -0
- package/dist/tools/goofy/getTeamMemberOutput.d.ts.map +1 -0
- package/dist/tools/goofy/getTeamMemberOutput.js +62 -0
- package/dist/tools/goofy/getTeamMemberOutput.js.map +1 -0
- package/dist/tools/goofy/getTeamMemberScreen.d.ts +28 -0
- package/dist/tools/goofy/getTeamMemberScreen.d.ts.map +1 -0
- package/dist/tools/goofy/getTeamMemberScreen.js +59 -0
- package/dist/tools/goofy/getTeamMemberScreen.js.map +1 -0
- package/dist/tools/goofy/getTeamMemberStatus.d.ts +33 -0
- package/dist/tools/goofy/getTeamMemberStatus.d.ts.map +1 -0
- package/dist/tools/goofy/getTeamMemberStatus.js +56 -0
- package/dist/tools/goofy/getTeamMemberStatus.js.map +1 -0
- package/dist/tools/goofy/index.d.ts +39 -0
- package/dist/tools/goofy/index.d.ts.map +1 -0
- package/dist/tools/goofy/index.js +51 -0
- package/dist/tools/goofy/index.js.map +1 -0
- package/dist/tools/goofy/interveneTeamMember.d.ts +33 -0
- package/dist/tools/goofy/interveneTeamMember.d.ts.map +1 -0
- package/dist/tools/goofy/interveneTeamMember.js +69 -0
- package/dist/tools/goofy/interveneTeamMember.js.map +1 -0
- package/dist/tools/goofy/killDeployedTeamMember.d.ts +29 -0
- package/dist/tools/goofy/killDeployedTeamMember.d.ts.map +1 -0
- package/dist/tools/goofy/killDeployedTeamMember.js +56 -0
- package/dist/tools/goofy/killDeployedTeamMember.js.map +1 -0
- package/dist/tools/goofy/linkTheVibes.d.ts +125 -0
- package/dist/tools/goofy/linkTheVibes.d.ts.map +1 -0
- package/dist/tools/goofy/linkTheVibes.js +354 -0
- package/dist/tools/goofy/linkTheVibes.js.map +1 -0
- package/dist/tools/goofy/listDeployedTeamMembers.d.ts +26 -0
- package/dist/tools/goofy/listDeployedTeamMembers.d.ts.map +1 -0
- package/dist/tools/goofy/listDeployedTeamMembers.js +52 -0
- package/dist/tools/goofy/listDeployedTeamMembers.js.map +1 -0
- package/dist/tools/goofy/listenForMessages.d.ts +56 -0
- package/dist/tools/goofy/listenForMessages.d.ts.map +1 -0
- package/dist/tools/goofy/listenForMessages.js +122 -0
- package/dist/tools/goofy/listenForMessages.js.map +1 -0
- package/dist/tools/goofy/memoryHealthCheck.d.ts +159 -0
- package/dist/tools/goofy/memoryHealthCheck.d.ts.map +1 -0
- package/dist/tools/goofy/memoryHealthCheck.js +443 -0
- package/dist/tools/goofy/memoryHealthCheck.js.map +1 -0
- package/dist/tools/goofy/rememberThisShit.d.ts +103 -0
- package/dist/tools/goofy/rememberThisShit.d.ts.map +1 -0
- package/dist/tools/goofy/rememberThisShit.js +291 -0
- package/dist/tools/goofy/rememberThisShit.js.map +1 -0
- package/dist/tools/goofy/sayToTeamMember.d.ts +55 -0
- package/dist/tools/goofy/sayToTeamMember.d.ts.map +1 -0
- package/dist/tools/goofy/sayToTeamMember.js +116 -0
- package/dist/tools/goofy/sayToTeamMember.js.map +1 -0
- package/dist/tools/goofy/selfMessage.d.ts +54 -0
- package/dist/tools/goofy/selfMessage.d.ts.map +1 -0
- package/dist/tools/goofy/selfMessage.js +111 -0
- package/dist/tools/goofy/selfMessage.js.map +1 -0
- package/dist/tools/goofy/sendHeartbeat.d.ts +53 -0
- package/dist/tools/goofy/sendHeartbeat.d.ts.map +1 -0
- package/dist/tools/goofy/sendHeartbeat.js +119 -0
- package/dist/tools/goofy/sendHeartbeat.js.map +1 -0
- package/dist/tools/goofy/showMeTheStats.d.ts +216 -0
- package/dist/tools/goofy/showMeTheStats.d.ts.map +1 -0
- package/dist/tools/goofy/showMeTheStats.js +535 -0
- package/dist/tools/goofy/showMeTheStats.js.map +1 -0
- package/dist/tools/goofy/smartRecall.d.ts +136 -0
- package/dist/tools/goofy/smartRecall.d.ts.map +1 -0
- package/dist/tools/goofy/smartRecall.js +286 -0
- package/dist/tools/goofy/smartRecall.js.map +1 -0
- package/dist/tools/goofy/smartSearch.d.ts +64 -0
- package/dist/tools/goofy/smartSearch.d.ts.map +1 -0
- package/dist/tools/goofy/smartSearch.js +89 -0
- package/dist/tools/goofy/smartSearch.js.map +1 -0
- package/dist/tools/goofy/smushMemoriesTogether.d.ts +128 -0
- package/dist/tools/goofy/smushMemoriesTogether.d.ts.map +1 -0
- package/dist/tools/goofy/smushMemoriesTogether.js +536 -0
- package/dist/tools/goofy/smushMemoriesTogether.js.map +1 -0
- package/dist/tools/goofy/spatialSearch.d.ts +198 -0
- package/dist/tools/goofy/spatialSearch.d.ts.map +1 -0
- package/dist/tools/goofy/spatialSearch.js +551 -0
- package/dist/tools/goofy/spatialSearch.js.map +1 -0
- package/dist/tools/goofy/spawnResearchTeamMember.d.ts +104 -0
- package/dist/tools/goofy/spawnResearchTeamMember.d.ts.map +1 -0
- package/dist/tools/goofy/spawnResearchTeamMember.js +290 -0
- package/dist/tools/goofy/spawnResearchTeamMember.js.map +1 -0
- package/dist/tools/goofy/spawnResearchTeamMemberTool.d.ts +121 -0
- package/dist/tools/goofy/spawnResearchTeamMemberTool.d.ts.map +1 -0
- package/dist/tools/goofy/spawnResearchTeamMemberTool.js +215 -0
- package/dist/tools/goofy/spawnResearchTeamMemberTool.js.map +1 -0
- package/dist/tools/goofy/startWatchingTheFiles.d.ts +81 -0
- package/dist/tools/goofy/startWatchingTheFiles.d.ts.map +1 -0
- package/dist/tools/goofy/startWatchingTheFiles.js +161 -0
- package/dist/tools/goofy/startWatchingTheFiles.js.map +1 -0
- package/dist/tools/goofy/stopWatchingTheFiles.d.ts +50 -0
- package/dist/tools/goofy/stopWatchingTheFiles.d.ts.map +1 -0
- package/dist/tools/goofy/stopWatchingTheFiles.js +81 -0
- package/dist/tools/goofy/stopWatchingTheFiles.js.map +1 -0
- package/dist/tools/goofy/whatDidIMean.d.ts +113 -0
- package/dist/tools/goofy/whatDidIMean.d.ts.map +1 -0
- package/dist/tools/goofy/whatDidIMean.js +401 -0
- package/dist/tools/goofy/whatDidIMean.js.map +1 -0
- package/dist/tools/goofy/yeahNahDeleteThat.d.ts +109 -0
- package/dist/tools/goofy/yeahNahDeleteThat.d.ts.map +1 -0
- package/dist/tools/goofy/yeahNahDeleteThat.js +319 -0
- package/dist/tools/goofy/yeahNahDeleteThat.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/teamMemberDeployer.d.ts +117 -0
- package/dist/tools/teamMemberDeployer.d.ts.map +1 -0
- package/dist/tools/teamMemberDeployer.js +613 -0
- package/dist/tools/teamMemberDeployer.js.map +1 -0
- package/dist/trace/index.d.ts +14 -0
- package/dist/trace/index.d.ts.map +1 -0
- package/dist/trace/index.js +16 -0
- package/dist/trace/index.js.map +1 -0
- package/dist/trace/tools/analyzeImpact.d.ts +90 -0
- package/dist/trace/tools/analyzeImpact.d.ts.map +1 -0
- package/dist/trace/tools/analyzeImpact.js +240 -0
- package/dist/trace/tools/analyzeImpact.js.map +1 -0
- package/dist/trace/tools/exploreDependencies.d.ts +81 -0
- package/dist/trace/tools/exploreDependencies.d.ts.map +1 -0
- package/dist/trace/tools/exploreDependencies.js +161 -0
- package/dist/trace/tools/exploreDependencies.js.map +1 -0
- package/dist/trace/tools/findSimilarBugs.d.ts +112 -0
- package/dist/trace/tools/findSimilarBugs.d.ts.map +1 -0
- package/dist/trace/tools/findSimilarBugs.js +216 -0
- package/dist/trace/tools/findSimilarBugs.js.map +1 -0
- package/dist/trace/tools/index.d.ts +22 -0
- package/dist/trace/tools/index.d.ts.map +1 -0
- package/dist/trace/tools/index.js +39 -0
- package/dist/trace/tools/index.js.map +1 -0
- package/dist/trace/tools/smartExplore.d.ts +126 -0
- package/dist/trace/tools/smartExplore.d.ts.map +1 -0
- package/dist/trace/tools/smartExplore.js +303 -0
- package/dist/trace/tools/smartExplore.js.map +1 -0
- package/dist/trace/tools/traceError.d.ts +101 -0
- package/dist/trace/tools/traceError.d.ts.map +1 -0
- package/dist/trace/tools/traceError.js +175 -0
- package/dist/trace/tools/traceError.js.map +1 -0
- package/dist/trace/traceExploreSystem.d.ts +271 -0
- package/dist/trace/traceExploreSystem.d.ts.map +1 -0
- package/dist/trace/traceExploreSystem.js +789 -0
- package/dist/trace/traceExploreSystem.js.map +1 -0
- package/dist/types/index.d.ts +421 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +118 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/circuitBreaker.d.ts +195 -0
- package/dist/utils/circuitBreaker.d.ts.map +1 -0
- package/dist/utils/circuitBreaker.js +374 -0
- package/dist/utils/circuitBreaker.js.map +1 -0
- package/dist/utils/cleanupHandler.d.ts +108 -0
- package/dist/utils/cleanupHandler.d.ts.map +1 -0
- package/dist/utils/cleanupHandler.js +203 -0
- package/dist/utils/cleanupHandler.js.map +1 -0
- package/dist/utils/compactXmlResponse.d.ts +60 -0
- package/dist/utils/compactXmlResponse.d.ts.map +1 -0
- package/dist/utils/compactXmlResponse.js +209 -0
- package/dist/utils/compactXmlResponse.js.map +1 -0
- package/dist/utils/cotBroadcast.d.ts +56 -0
- package/dist/utils/cotBroadcast.d.ts.map +1 -0
- package/dist/utils/cotBroadcast.js +157 -0
- package/dist/utils/cotBroadcast.js.map +1 -0
- package/dist/utils/debugLogger.d.ts +95 -0
- package/dist/utils/debugLogger.d.ts.map +1 -0
- package/dist/utils/debugLogger.js +610 -0
- package/dist/utils/debugLogger.js.map +1 -0
- package/dist/utils/fileProcessingQueue.d.ts +259 -0
- package/dist/utils/fileProcessingQueue.d.ts.map +1 -0
- package/dist/utils/fileProcessingQueue.js +714 -0
- package/dist/utils/fileProcessingQueue.js.map +1 -0
- package/dist/utils/humanReadableOutput.d.ts +124 -0
- package/dist/utils/humanReadableOutput.d.ts.map +1 -0
- package/dist/utils/humanReadableOutput.js +340 -0
- package/dist/utils/humanReadableOutput.js.map +1 -0
- package/dist/utils/index.d.ts +32 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +71 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/instanceManager.d.ts +530 -0
- package/dist/utils/instanceManager.d.ts.map +1 -0
- package/dist/utils/instanceManager.js +1784 -0
- package/dist/utils/instanceManager.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +49 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mapCleanup.d.ts +58 -0
- package/dist/utils/mapCleanup.d.ts.map +1 -0
- package/dist/utils/mapCleanup.js +150 -0
- package/dist/utils/mapCleanup.js.map +1 -0
- package/dist/utils/memoryManager.d.ts +349 -0
- package/dist/utils/memoryManager.d.ts.map +1 -0
- package/dist/utils/memoryManager.js +799 -0
- package/dist/utils/memoryManager.js.map +1 -0
- package/dist/utils/metrics.d.ts +160 -0
- package/dist/utils/metrics.d.ts.map +1 -0
- package/dist/utils/metrics.js +558 -0
- package/dist/utils/metrics.js.map +1 -0
- package/dist/utils/pathValidator.d.ts +96 -0
- package/dist/utils/pathValidator.d.ts.map +1 -0
- package/dist/utils/pathValidator.js +320 -0
- package/dist/utils/pathValidator.js.map +1 -0
- package/dist/utils/portAllocator.d.ts +296 -0
- package/dist/utils/portAllocator.d.ts.map +1 -0
- package/dist/utils/portAllocator.js +768 -0
- package/dist/utils/portAllocator.js.map +1 -0
- package/dist/utils/portUtils.d.ts +97 -0
- package/dist/utils/portUtils.d.ts.map +1 -0
- package/dist/utils/portUtils.js +285 -0
- package/dist/utils/portUtils.js.map +1 -0
- package/dist/utils/postgresAutoSetup.d.ts +55 -0
- package/dist/utils/postgresAutoSetup.d.ts.map +1 -0
- package/dist/utils/postgresAutoSetup.js +406 -0
- package/dist/utils/postgresAutoSetup.js.map +1 -0
- package/dist/utils/processHealthCheck.d.ts +61 -0
- package/dist/utils/processHealthCheck.d.ts.map +1 -0
- package/dist/utils/processHealthCheck.js +313 -0
- package/dist/utils/processHealthCheck.js.map +1 -0
- package/dist/utils/progressReporter.d.ts +151 -0
- package/dist/utils/progressReporter.d.ts.map +1 -0
- package/dist/utils/progressReporter.js +345 -0
- package/dist/utils/progressReporter.js.map +1 -0
- package/dist/utils/projectEnv.d.ts +73 -0
- package/dist/utils/projectEnv.d.ts.map +1 -0
- package/dist/utils/projectEnv.js +137 -0
- package/dist/utils/projectEnv.js.map +1 -0
- package/dist/utils/qoms.d.ts +122 -0
- package/dist/utils/qoms.d.ts.map +1 -0
- package/dist/utils/qoms.js +650 -0
- package/dist/utils/qoms.js.map +1 -0
- package/dist/utils/retryHelper.d.ts +122 -0
- package/dist/utils/retryHelper.d.ts.map +1 -0
- package/dist/utils/retryHelper.js +272 -0
- package/dist/utils/retryHelper.js.map +1 -0
- package/dist/utils/safeProcessTermination.d.ts +206 -0
- package/dist/utils/safeProcessTermination.d.ts.map +1 -0
- package/dist/utils/safeProcessTermination.js +552 -0
- package/dist/utils/safeProcessTermination.js.map +1 -0
- package/dist/utils/sessionInjector.d.ts +68 -0
- package/dist/utils/sessionInjector.d.ts.map +1 -0
- package/dist/utils/sessionInjector.js +189 -0
- package/dist/utils/sessionInjector.js.map +1 -0
- package/dist/utils/statsCache.d.ts +134 -0
- package/dist/utils/statsCache.d.ts.map +1 -0
- package/dist/utils/statsCache.js +285 -0
- package/dist/utils/statsCache.js.map +1 -0
- package/dist/utils/timeoutMiddleware.d.ts +81 -0
- package/dist/utils/timeoutMiddleware.d.ts.map +1 -0
- package/dist/utils/timeoutMiddleware.js +155 -0
- package/dist/utils/timeoutMiddleware.js.map +1 -0
- package/dist/utils/timerRegistry.d.ts +91 -0
- package/dist/utils/timerRegistry.d.ts.map +1 -0
- package/dist/utils/timerRegistry.js +187 -0
- package/dist/utils/timerRegistry.js.map +1 -0
- package/dist/utils/tokenCompressor.d.ts +332 -0
- package/dist/utils/tokenCompressor.d.ts.map +1 -0
- package/dist/utils/tokenCompressor.js +1306 -0
- package/dist/utils/tokenCompressor.js.map +1 -0
- package/dist/utils/tracing.d.ts +236 -0
- package/dist/utils/tracing.d.ts.map +1 -0
- package/dist/utils/tracing.js +378 -0
- package/dist/utils/tracing.js.map +1 -0
- package/dist/watcher/changeHandler.d.ts +123 -0
- package/dist/watcher/changeHandler.d.ts.map +1 -0
- package/dist/watcher/changeHandler.js +623 -0
- package/dist/watcher/changeHandler.js.map +1 -0
- package/dist/watcher/changeQueue.d.ts +133 -0
- package/dist/watcher/changeQueue.d.ts.map +1 -0
- package/dist/watcher/changeQueue.js +355 -0
- package/dist/watcher/changeQueue.js.map +1 -0
- package/dist/watcher/fileWatcher.d.ts +121 -0
- package/dist/watcher/fileWatcher.d.ts.map +1 -0
- package/dist/watcher/fileWatcher.js +531 -0
- package/dist/watcher/fileWatcher.js.map +1 -0
- package/dist/watcher/index.d.ts +94 -0
- package/dist/watcher/index.d.ts.map +1 -0
- package/dist/watcher/index.js +235 -0
- package/dist/watcher/index.js.map +1 -0
- package/dist/watcher/syncChecker.d.ts +93 -0
- package/dist/watcher/syncChecker.d.ts.map +1 -0
- package/dist/watcher/syncChecker.js +401 -0
- package/dist/watcher/syncChecker.js.map +1 -0
- package/dist/watcher/tsCompiler.d.ts +88 -0
- package/dist/watcher/tsCompiler.d.ts.map +1 -0
- package/dist/watcher/tsCompiler.js +212 -0
- package/dist/watcher/tsCompiler.js.map +1 -0
- package/embedding-sandbox/Dockerfile +77 -0
- package/embedding-sandbox/Dockerfile.frankenstein +91 -0
- package/embedding-sandbox/README.md +193 -0
- package/embedding-sandbox/__pycache__/frankenstein-embeddings.cpython-312.pyc +0 -0
- package/embedding-sandbox/__pycache__/frankenstein-embeddings.cpython-313.pyc +0 -0
- package/embedding-sandbox/__pycache__/qqms_v2.cpython-312.pyc +0 -0
- package/embedding-sandbox/__pycache__/qqms_v2.cpython-313.pyc +0 -0
- package/embedding-sandbox/add_js_docs.py +684 -0
- package/embedding-sandbox/build_docs_db.py +239 -0
- package/embedding-sandbox/client.cjs +376 -0
- package/embedding-sandbox/client.ts +913 -0
- package/embedding-sandbox/deploy-frankenstein.sh +240 -0
- package/embedding-sandbox/docker-compose.yml +60 -0
- package/embedding-sandbox/docker-manager.py +325 -0
- package/embedding-sandbox/docs/python_docs.db +0 -0
- package/embedding-sandbox/download-model.mjs +79 -0
- package/embedding-sandbox/download-model.py +28 -0
- package/embedding-sandbox/embedding-supervisor.sh +164 -0
- package/embedding-sandbox/frankenstein-embeddings.py +3940 -0
- package/embedding-sandbox/manage-services.sh +354 -0
- package/embedding-sandbox/overflow_queue.py +345 -0
- package/embedding-sandbox/package.json +17 -0
- package/embedding-sandbox/project_isolation.py +292 -0
- package/embedding-sandbox/qqms_v2.py +967 -0
- package/embedding-sandbox/ram-manager.sh +311 -0
- package/embedding-sandbox/requirements-frankenstein.txt +7 -0
- package/embedding-sandbox/run_js_docs.py +59 -0
- package/embedding-sandbox/seed_docs.py +885 -0
- package/embedding-sandbox/server-batch.mjs +228 -0
- package/embedding-sandbox/server.mjs +389 -0
- package/embedding-sandbox/specmem/sockets/claude-input-state.json +1 -0
- package/embedding-sandbox/specmem/sockets/embedding-death-reason.txt +3 -0
- package/embedding-sandbox/specmem/sockets/seen-sessions.json +1 -0
- package/embedding-sandbox/specmem/sockets/session-start.lock +1 -0
- package/embedding-sandbox/specmem/sockets/session-stops.log +7 -0
- package/embedding-sandbox/start-frankenstein-throttled.sh +98 -0
- package/embedding-sandbox/start-on-demand.sh +116 -0
- package/embedding-sandbox/start-sandbox.sh +237 -0
- package/embedding-sandbox/start-supervised.sh +11 -0
- package/embedding-sandbox/stop-sandbox.sh +51 -0
- package/embedding-sandbox/test-socket.mjs +61 -0
- package/embedding-sandbox/warm-start.sh +353 -0
- package/embedding-sandbox/warm_start_feeder.py +660 -0
- package/legal/README.md +31 -0
- package/legal/anthropic-privacy-center-screenshot-2026-01-30.png +0 -0
- package/legal/anthropic-tos-screenshot-2026-01-30.png +0 -0
- package/lib/codebase-bridge.cjs +308 -0
- package/package.json +136 -0
- package/plugins/specmem-agents/agents/bug-hunter.md +79 -0
- package/plugins/specmem-agents/agents/memory-explorer.md +57 -0
- package/plugins/specmem-agents/agents/team-coordinator.md +82 -0
- package/scripts/auto-updater.cjs +399 -0
- package/scripts/backfill-code-definition-embeddings.ts +440 -0
- package/scripts/backfill-code-embeddings.ts +206 -0
- package/scripts/capture-tos-screenshots.cjs +94 -0
- package/scripts/check-global-install.cjs +67 -0
- package/scripts/cleanup-embedding-servers.sh +25 -0
- package/scripts/dashboard-standalone.sh +369 -0
- package/scripts/deploy-hooks.cjs +1451 -0
- package/scripts/deploy.sh +106 -0
- package/scripts/docker-project-down.sh +83 -0
- package/scripts/docker-project-list.sh +40 -0
- package/scripts/docker-project-up.sh +79 -0
- package/scripts/fast-backfill-embeddings.ts +173 -0
- package/scripts/fast-batch-embedder.cjs +334 -0
- package/scripts/first-run-model-setup.cjs +849 -0
- package/scripts/global-postinstall.cjs +1957 -0
- package/scripts/index-codebase.js +72 -0
- package/scripts/migrate-fix-embeddings.py +110 -0
- package/scripts/migrate-to-project-schemas.ts +525 -0
- package/scripts/optimize-embedding-model.py +324 -0
- package/scripts/optimize-instructions.cjs +530 -0
- package/scripts/pack-docker-images.sh +68 -0
- package/scripts/pack-for-testing.sh +130 -0
- package/scripts/postinstall.cjs +54 -0
- package/scripts/project-env.sh +51 -0
- package/scripts/reset-db.sh +30 -0
- package/scripts/run-indexer.ts +69 -0
- package/scripts/run-migrations.js +47 -0
- package/scripts/setup-db.sh +34 -0
- package/scripts/setup-minimal-schema.sql +143 -0
- package/scripts/skills/code-review.md +44 -0
- package/scripts/skills/debugging.md +56 -0
- package/scripts/skills/specmem-deployteam.md +239 -0
- package/scripts/skills/teammemberskills/EFFICIENT_GREP.md +171 -0
- package/scripts/skills/teammemberskills/task-planning.md +67 -0
- package/scripts/specmem/sockets/session-start.lock +1 -0
- package/scripts/specmem/sockets/session-stops.log +1 -0
- package/scripts/specmem-health.sh +382 -0
- package/scripts/specmem-init.cjs +6935 -0
- package/scripts/strip-debug-logs.cjs +43 -0
- package/scripts/test-mcp-standalone.sh +365 -0
- package/scripts/test-optimized-models.py +166 -0
- package/scripts/verify-embedding-fix.sh +148 -0
- package/skills/code-review.md +44 -0
- package/skills/debugging.md +56 -0
- package/skills/specmem-deployteam.md +239 -0
- package/skills/teammemberskills/EFFICIENT_GREP.md +171 -0
- package/skills/teammemberskills/task-planning.md +67 -0
- package/specmem-health.cjs +522 -0
- package/specmem.env +216 -0
|
@@ -0,0 +1,2547 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* findWhatISaid - semantic search hitting different
|
|
3
|
+
*
|
|
4
|
+
* uses vector similarity to find relevant memories
|
|
5
|
+
* supports natural language time queries like "yesterday" or "last week"
|
|
6
|
+
* also does hybrid search combining semantic + full-text for best results
|
|
7
|
+
*
|
|
8
|
+
* Now integrated with LWJEB event bus for memory:retrieved events
|
|
9
|
+
*/
|
|
10
|
+
import { parseTimeExpression } from '../../mcp/mcpProtocolHandler.js';
|
|
11
|
+
import { logger } from '../../utils/logger.js';
|
|
12
|
+
import { getDebugLogger } from '../../utils/debugLogger.js';
|
|
13
|
+
import { getCoordinator } from '../../coordination/integration.js';
|
|
14
|
+
import { getEmbeddingSocketPath } from '../../config.js';
|
|
15
|
+
import { getEmbeddingTimeout, formatTimeout } from '../../config/embeddingTimeouts.js';
|
|
16
|
+
import { getHotPathManager } from '../../db/hotPathManager.js';
|
|
17
|
+
import { smartCompress } from '../../utils/tokenCompressor.js';
|
|
18
|
+
import { MiniCOTProvider } from '../../providers/MiniCOTProvider.js';
|
|
19
|
+
import { getDimensionService } from '../../services/DimensionService.js';
|
|
20
|
+
import { buildProjectWhereClause, getProjectContext, getProjectPathForInsert } from '../../services/ProjectContext.js';
|
|
21
|
+
import { formatAsCameraRollItem, thresholdToZoomLevel, ZOOM_CONFIGS } from '../../services/CameraZoomSearch.js';
|
|
22
|
+
import { formatHumanReadable } from '../../utils/humanReadableOutput.js';
|
|
23
|
+
import { cotStart, cotResult, cotError } from '../../utils/cotBroadcast.js';
|
|
24
|
+
// DEBUG LOGGING - only enabled when SPECMEM_DEBUG=1
|
|
25
|
+
const __debugLog = process.env['SPECMEM_DEBUG'] === '1'
|
|
26
|
+
? (...args) => console.error('[DEBUG]', ...args) // stderr, not stdout!
|
|
27
|
+
: () => { };
|
|
28
|
+
/**
|
|
29
|
+
* Extract discoverable paths from memory content
|
|
30
|
+
* This is the KEY to getting lots of info from few memories
|
|
31
|
+
*/
|
|
32
|
+
function extractDiscoverablePaths(content) {
|
|
33
|
+
const paths = {
|
|
34
|
+
filePaths: [],
|
|
35
|
+
codeBlocks: [],
|
|
36
|
+
urls: [],
|
|
37
|
+
memoryRefs: [],
|
|
38
|
+
technicalTerms: [],
|
|
39
|
+
researchQuestions: []
|
|
40
|
+
};
|
|
41
|
+
// Extract file paths (Unix and Windows style)
|
|
42
|
+
const filePathRegex = /(?:\/[\w.-]+)+\.(?:ts|js|tsx|jsx|py|go|rs|java|json|yaml|yml|md|css|html|sql|sh)/gi;
|
|
43
|
+
const fileMatches = content.match(filePathRegex);
|
|
44
|
+
if (fileMatches) {
|
|
45
|
+
paths.filePaths = [...new Set(fileMatches)].slice(0, 10);
|
|
46
|
+
}
|
|
47
|
+
// Extract code blocks with language detection
|
|
48
|
+
const codeBlockRegex = /```(\w+)?\n?([\s\S]*?)```/g;
|
|
49
|
+
let match;
|
|
50
|
+
while ((match = codeBlockRegex.exec(content)) !== null) {
|
|
51
|
+
const lang = match[1] || 'unknown';
|
|
52
|
+
const code = match[2].trim();
|
|
53
|
+
if (code.length > 10) {
|
|
54
|
+
// Try to infer file path from code content
|
|
55
|
+
let possiblePath;
|
|
56
|
+
const importMatch = code.match(/from ['"]([^'"]+)['"]/);
|
|
57
|
+
const requireMatch = code.match(/require\(['"]([^'"]+)['"]\)/);
|
|
58
|
+
if (importMatch)
|
|
59
|
+
possiblePath = importMatch[1];
|
|
60
|
+
else if (requireMatch)
|
|
61
|
+
possiblePath = requireMatch[1];
|
|
62
|
+
paths.codeBlocks.push({
|
|
63
|
+
language: lang,
|
|
64
|
+
preview: code.substring(0, 100) + (code.length > 100 ? '...' : ''),
|
|
65
|
+
fullContent: code.length > 200 ? undefined : code, // Only keep short code
|
|
66
|
+
possiblePath
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
paths.codeBlocks = paths.codeBlocks.slice(0, 5);
|
|
71
|
+
// Extract URLs
|
|
72
|
+
const urlRegex = /https?:\/\/[^\s\])"'<>]+/g;
|
|
73
|
+
const urlMatches = content.match(urlRegex);
|
|
74
|
+
if (urlMatches) {
|
|
75
|
+
paths.urls = [...new Set(urlMatches)].slice(0, 5);
|
|
76
|
+
}
|
|
77
|
+
// Extract technical terms (PascalCase classes, UPPER_CONSTANTS, function names)
|
|
78
|
+
const techTermRegex = /\b(?:[A-Z][a-z]+){2,}\b|\b[A-Z][A-Z0-9_]{2,}\b|\b\w+(?:Service|Manager|Handler|Provider|Factory|Controller|Repository)\b/g;
|
|
79
|
+
const techMatches = content.match(techTermRegex);
|
|
80
|
+
if (techMatches) {
|
|
81
|
+
paths.technicalTerms = [...new Set(techMatches)].slice(0, 10);
|
|
82
|
+
}
|
|
83
|
+
// Detect potential research questions (things that sound like external knowledge)
|
|
84
|
+
const researchIndicators = [
|
|
85
|
+
/how (?:does|do|to|can)/gi,
|
|
86
|
+
/what is (?:a |the )?[\w\s]+\?/gi,
|
|
87
|
+
/(?:documentation|docs|api|reference) for/gi,
|
|
88
|
+
/latest version of/gi,
|
|
89
|
+
/best practice for/gi
|
|
90
|
+
];
|
|
91
|
+
for (const regex of researchIndicators) {
|
|
92
|
+
const matches = content.match(regex);
|
|
93
|
+
if (matches) {
|
|
94
|
+
paths.researchQuestions.push(...matches.slice(0, 2));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
paths.researchQuestions = paths.researchQuestions.slice(0, 3);
|
|
98
|
+
return paths;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Format discoverable paths as compact Chinese-annotated hints
|
|
102
|
+
* These hints guide on what to explore next
|
|
103
|
+
*/
|
|
104
|
+
function formatDiscoverableHints(paths) {
|
|
105
|
+
const hints = [];
|
|
106
|
+
if (paths.filePaths.length > 0) {
|
|
107
|
+
hints.push(`📁 文件路徑(${paths.filePaths.length}): ${paths.filePaths.slice(0, 3).join(', ')}${paths.filePaths.length > 3 ? '...' : ''}`);
|
|
108
|
+
}
|
|
109
|
+
if (paths.codeBlocks.length > 0) {
|
|
110
|
+
const langs = [...new Set(paths.codeBlocks.map(c => c.language))].join('/');
|
|
111
|
+
hints.push(`💻 代碼塊(${paths.codeBlocks.length}): ${langs}`);
|
|
112
|
+
}
|
|
113
|
+
if (paths.urls.length > 0) {
|
|
114
|
+
hints.push(`🔗 URL(${paths.urls.length}): 可研究`);
|
|
115
|
+
}
|
|
116
|
+
if (paths.technicalTerms.length > 0) {
|
|
117
|
+
hints.push(`🔧 技術詞: ${paths.technicalTerms.slice(0, 5).join(', ')}`);
|
|
118
|
+
}
|
|
119
|
+
if (paths.researchQuestions.length > 0) {
|
|
120
|
+
hints.push(`❓ 研究問題: ${paths.researchQuestions.length}個待確認`);
|
|
121
|
+
}
|
|
122
|
+
return hints.join(' | ');
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Enrich a search result with discoverable paths
|
|
126
|
+
* This is what makes few memories yield lots of info
|
|
127
|
+
* NOW WITH CODE ORIGIN TRACKING - shows WHERE code came from!
|
|
128
|
+
*/
|
|
129
|
+
function enrichSearchResult(result) {
|
|
130
|
+
const paths = extractDiscoverablePaths(result.memory.content);
|
|
131
|
+
// CRITICAL: Add source origin info to each code block
|
|
132
|
+
// This tells you WHERE the code came from (session, timestamp, who wrote it)
|
|
133
|
+
const memoryMeta = result.memory.metadata || {};
|
|
134
|
+
paths.codeBlocks = paths.codeBlocks.map(block => ({
|
|
135
|
+
...block,
|
|
136
|
+
sourceMemoryId: result.memory.id,
|
|
137
|
+
sourceSessionId: memoryMeta.sessionId || memoryMeta.session_id,
|
|
138
|
+
sourceTimestamp: memoryMeta.timestamp || result.memory.createdAt?.toString(),
|
|
139
|
+
sourceRole: memoryMeta.role || (result.memory.tags?.includes('role:user') ? 'user' :
|
|
140
|
+
result.memory.tags?.includes('role:assistant') ? 'assistant' : undefined),
|
|
141
|
+
sourceProject: memoryMeta.project
|
|
142
|
+
}));
|
|
143
|
+
const hints = formatDiscoverableHints(paths);
|
|
144
|
+
return {
|
|
145
|
+
...result,
|
|
146
|
+
_discoverable: paths,
|
|
147
|
+
_hints: hints.length > 0 ? hints : undefined
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// Drilldown configuration - triggers intelligent prompts for user
|
|
151
|
+
const DRILLDOWN_THRESHOLDS = {
|
|
152
|
+
lowRelevance: 0.25, // Below this, suggest deeper search
|
|
153
|
+
highRelevance: 0.5, // Above this, results are good
|
|
154
|
+
fewResults: 3, // Fewer than this, suggest broader search
|
|
155
|
+
manyResults: 15 // More than this, suggest filtering
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Generate user interaction prompt based on search results
|
|
159
|
+
* Returns structured data for AskUserQuestion tool
|
|
160
|
+
*/
|
|
161
|
+
function generateUserInteractionPrompt(results, query, drilldown, aggregatedPaths) {
|
|
162
|
+
const resultCount = results.length;
|
|
163
|
+
const topSimilarity = results[0]?.similarity ?? 0;
|
|
164
|
+
// Case 1: No results - offer research options
|
|
165
|
+
if (resultCount === 0) {
|
|
166
|
+
return {
|
|
167
|
+
shouldPromptUser: true,
|
|
168
|
+
questionType: 'research',
|
|
169
|
+
question: `沒有找到關於 "${query}" 的記憶。要進行網絡研究嗎?`,
|
|
170
|
+
header: '研究選項',
|
|
171
|
+
options: [
|
|
172
|
+
{ label: '快速WebSearch', description: '1-2個來源快速查找' },
|
|
173
|
+
{ label: '深度研究', description: '3-5個來源詳細研究' },
|
|
174
|
+
{ label: '跳過', description: '不需要額外資訊' }
|
|
175
|
+
],
|
|
176
|
+
multiSelect: false,
|
|
177
|
+
contextHint: `查詢: "${query}" | 無本地記憶 | 建議網絡研究`
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
// Case 2: Very low relevance - offer drilldown
|
|
181
|
+
if (topSimilarity < DRILLDOWN_THRESHOLDS.lowRelevance) {
|
|
182
|
+
return {
|
|
183
|
+
shouldPromptUser: true,
|
|
184
|
+
questionType: 'drilldown',
|
|
185
|
+
question: `找到 ${resultCount} 條記憶,但相關性較低 (${Math.round(topSimilarity * 100)}%)。要深入搜索嗎?`,
|
|
186
|
+
header: '搜索深度',
|
|
187
|
+
options: [
|
|
188
|
+
{ label: '深入搜索(50條)', description: '150MB RAM - 徹底搜索' },
|
|
189
|
+
{ label: '擴大搜索(100條)', description: '150MB RAM - 搜索所有相關' },
|
|
190
|
+
{ label: '網絡研究', description: '使用WebSearch獲取外部資訊' },
|
|
191
|
+
{ label: '使用現有結果', description: '繼續使用當前結果' }
|
|
192
|
+
],
|
|
193
|
+
multiSelect: false,
|
|
194
|
+
contextHint: `找到: ${resultCount}條 | 最高相似度: ${Math.round(topSimilarity * 100)}% | ${drilldown.prompt}`
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// Case 3: Need research - offer research options
|
|
198
|
+
if (drilldown.needsResearch || aggregatedPaths.researchQuestions.length > 0) {
|
|
199
|
+
const researchTopics = aggregatedPaths.researchQuestions.slice(0, 2);
|
|
200
|
+
return {
|
|
201
|
+
shouldPromptUser: true,
|
|
202
|
+
questionType: 'research',
|
|
203
|
+
question: `記憶中發現需要研究的問題。要啟動研究代理嗎?`,
|
|
204
|
+
header: '研究建議',
|
|
205
|
+
options: [
|
|
206
|
+
{ label: '啟動研究代理', description: `研究: ${researchTopics[0] || query}` },
|
|
207
|
+
{ label: '快速WebSearch', description: '直接搜索不啟動代理' },
|
|
208
|
+
{ label: '跳過研究', description: '本地記憶已足夠' }
|
|
209
|
+
],
|
|
210
|
+
multiSelect: false,
|
|
211
|
+
contextHint: `研究問題: ${researchTopics.join(', ') || '無'} | ${drilldown.prompt}`
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// Case 4: Has URLs to explore - offer to fetch
|
|
215
|
+
if (aggregatedPaths.urls.length > 0) {
|
|
216
|
+
return {
|
|
217
|
+
shouldPromptUser: true,
|
|
218
|
+
questionType: 'research',
|
|
219
|
+
question: `記憶中包含 ${aggregatedPaths.urls.length} 個URL。要獲取內容嗎?`,
|
|
220
|
+
header: 'URL探索',
|
|
221
|
+
options: [
|
|
222
|
+
{ label: '獲取所有URL', description: `使用WebFetch獲取 ${aggregatedPaths.urls.length} 個URL` },
|
|
223
|
+
{ label: '僅查看列表', description: '不獲取,只顯示URL列表' },
|
|
224
|
+
{ label: '跳過', description: '不需要URL內容' }
|
|
225
|
+
],
|
|
226
|
+
multiSelect: false,
|
|
227
|
+
contextHint: `URL數量: ${aggregatedPaths.urls.length} | 技術詞: ${aggregatedPaths.technicalTerms.slice(0, 3).join(', ')}`
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
// Case 5: Many results - offer filtering
|
|
231
|
+
if (resultCount > DRILLDOWN_THRESHOLDS.manyResults) {
|
|
232
|
+
return {
|
|
233
|
+
shouldPromptUser: true,
|
|
234
|
+
questionType: 'filter',
|
|
235
|
+
question: `找到 ${resultCount} 條結果,較多。要過濾嗎?`,
|
|
236
|
+
header: '結果過濾',
|
|
237
|
+
options: [
|
|
238
|
+
{ label: '按相關性排序', description: '只保留最相關的10條' },
|
|
239
|
+
{ label: '按時間過濾', description: '只看最近的記憶' },
|
|
240
|
+
{ label: '查看全部', description: '不過濾,顯示所有結果' }
|
|
241
|
+
],
|
|
242
|
+
multiSelect: false,
|
|
243
|
+
contextHint: `找到: ${resultCount}條 | 最高: ${Math.round(topSimilarity * 100)}% | 建議過濾`
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// Case 6: Good results - no prompt needed, but still return confirmation structure
|
|
247
|
+
if (topSimilarity >= DRILLDOWN_THRESHOLDS.highRelevance) {
|
|
248
|
+
// Results are good, no user interaction needed
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
// Default: Medium relevance - let decide
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
// Chinese compacted drilldown prompts (saves ~40% tokens)
|
|
255
|
+
const DRILLDOWN_PROMPTS = {
|
|
256
|
+
// When top result has low similarity
|
|
257
|
+
lowRelevance: {
|
|
258
|
+
zh: '🔍 搜索結果相關性低 (相似度<25%) | 建議: 深度搜索或調整查詢',
|
|
259
|
+
en: 'Low relevance results - suggest deeper search or query refinement',
|
|
260
|
+
action: 'drilldown:deeper'
|
|
261
|
+
},
|
|
262
|
+
// When few results found
|
|
263
|
+
fewResults: {
|
|
264
|
+
zh: '📊 找到結果少於3條 | 建議: 擴大搜索範圍或嘗試同義詞',
|
|
265
|
+
en: 'Few results found - suggest broader search or synonyms',
|
|
266
|
+
action: 'drilldown:broader'
|
|
267
|
+
},
|
|
268
|
+
// When too many results
|
|
269
|
+
manyResults: {
|
|
270
|
+
zh: '📈 結果過多(>15條) | 建議: 添加過濾條件或更具體查詢',
|
|
271
|
+
en: 'Too many results - suggest filtering or more specific query',
|
|
272
|
+
action: 'drilldown:filter'
|
|
273
|
+
},
|
|
274
|
+
// When research might help
|
|
275
|
+
needsResearch: {
|
|
276
|
+
zh: '🌐 本地記憶不足 | 建議: WebSearch獲取最新資訊',
|
|
277
|
+
en: 'Local memory insufficient - suggest web research',
|
|
278
|
+
action: 'research:web'
|
|
279
|
+
},
|
|
280
|
+
// Good results
|
|
281
|
+
goodResults: {
|
|
282
|
+
zh: '✅ 找到相關記憶 | 上下文已壓縮保留',
|
|
283
|
+
en: 'Relevant memories found - context compressed and preserved',
|
|
284
|
+
action: 'none'
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
/**
|
|
288
|
+
* Analyze search results and generate drilldown suggestion
|
|
289
|
+
* Returns Traditional Chinese compacted prompt for token efficiency
|
|
290
|
+
*/
|
|
291
|
+
function generateDrilldownSuggestion(results, query) {
|
|
292
|
+
const resultCount = results.length;
|
|
293
|
+
const topSimilarity = results[0]?.similarity ?? 0;
|
|
294
|
+
// Priority 1: No results at all
|
|
295
|
+
if (resultCount === 0) {
|
|
296
|
+
return {
|
|
297
|
+
prompt: `${DRILLDOWN_PROMPTS.needsResearch.zh}\n查詢: "${query}" → 無本地記憶匹配`,
|
|
298
|
+
action: 'research:web',
|
|
299
|
+
needsResearch: true
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
// Priority 2: Very low relevance (might be asking about something new)
|
|
303
|
+
if (topSimilarity < DRILLDOWN_THRESHOLDS.lowRelevance) {
|
|
304
|
+
const avgSim = results.reduce((a, r) => a + r.similarity, 0) / resultCount;
|
|
305
|
+
if (avgSim < 0.15) {
|
|
306
|
+
// Very poor match - likely needs web research
|
|
307
|
+
return {
|
|
308
|
+
prompt: `${DRILLDOWN_PROMPTS.needsResearch.zh}\n最高相似度: ${Math.round(topSimilarity * 100)}% | 平均: ${Math.round(avgSim * 100)}%`,
|
|
309
|
+
action: 'research:web',
|
|
310
|
+
needsResearch: true
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
prompt: `${DRILLDOWN_PROMPTS.lowRelevance.zh}\n最高相似度: ${Math.round(topSimilarity * 100)}%`,
|
|
315
|
+
action: 'drilldown:deeper',
|
|
316
|
+
needsResearch: false
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
// Priority 3: Few results
|
|
320
|
+
if (resultCount < DRILLDOWN_THRESHOLDS.fewResults) {
|
|
321
|
+
return {
|
|
322
|
+
prompt: `${DRILLDOWN_PROMPTS.fewResults.zh}\n找到: ${resultCount}條 | 最高相似度: ${Math.round(topSimilarity * 100)}%`,
|
|
323
|
+
action: 'drilldown:broader',
|
|
324
|
+
needsResearch: false
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
// Priority 4: Too many results
|
|
328
|
+
if (resultCount > DRILLDOWN_THRESHOLDS.manyResults) {
|
|
329
|
+
return {
|
|
330
|
+
prompt: `${DRILLDOWN_PROMPTS.manyResults.zh}\n找到: ${resultCount}條 | 建議過濾標籤或類型`,
|
|
331
|
+
action: 'drilldown:filter',
|
|
332
|
+
needsResearch: false
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
// Good results!
|
|
336
|
+
return {
|
|
337
|
+
prompt: `${DRILLDOWN_PROMPTS.goodResults.zh}\n找到: ${resultCount}條 | 最高: ${Math.round(topSimilarity * 100)}%`,
|
|
338
|
+
action: 'none',
|
|
339
|
+
needsResearch: false
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
// fr fr we track search performance
|
|
343
|
+
let _searchCount = 0;
|
|
344
|
+
let _totalSearchTime = 0;
|
|
345
|
+
// ============================================================================
|
|
346
|
+
// DRILLDOWN REMINDERS - Force to actually USE the memory!
|
|
347
|
+
// ============================================================================
|
|
348
|
+
// Compact reminder - at TOP of response so sees it first
|
|
349
|
+
const DRILLDOWN_REMINDER = `⚠️ MEMORY POINTERS - DRILL DOWN BEFORE PROCEEDING:
|
|
350
|
+
1. get_memory({ id }) - get FULL content of relevant memories
|
|
351
|
+
2. find_memory({ query: "related term" }) - check related topics
|
|
352
|
+
3. find_code_pointers({ query }) - explore any code paths mentioned
|
|
353
|
+
💡 User has discussed this before - check their context!`;
|
|
354
|
+
// Compact empty results reminder
|
|
355
|
+
const EMPTY_RESULTS_REMINDER = `⚠️ NO MEMORIES FOUND - Try these:
|
|
356
|
+
1. Rephrase: try synonyms, different wording
|
|
357
|
+
2. find_code_pointers({ query }) - search code instead
|
|
358
|
+
3. Remove filters (memoryTypes, tags, dateRange)`;
|
|
359
|
+
// ============================================================================
|
|
360
|
+
// HELP OUTPUT - shown when query is empty or "help"
|
|
361
|
+
// ============================================================================
|
|
362
|
+
const HELP_OUTPUT = `
|
|
363
|
+
# find_memory - Semantic Memory Search
|
|
364
|
+
|
|
365
|
+
Search across memories using meaning-based semantic search.
|
|
366
|
+
Finds content based on concepts and context, not just keywords.
|
|
367
|
+
|
|
368
|
+
## Usage
|
|
369
|
+
|
|
370
|
+
\`\`\`
|
|
371
|
+
find_memory({ query: "your search" })
|
|
372
|
+
find_memory({ query: "authentication", galleryMode: true })
|
|
373
|
+
find_memory({ query: "last week", role: "user" })
|
|
374
|
+
\`\`\`
|
|
375
|
+
|
|
376
|
+
## Parameters
|
|
377
|
+
|
|
378
|
+
| Parameter | Type | Default | Description |
|
|
379
|
+
|-----------|------|---------|-------------|
|
|
380
|
+
| query | string | required | Natural language search query |
|
|
381
|
+
| limit | number | 10 | Max results to return (max: 1000) |
|
|
382
|
+
| threshold | number | 0.25 | Min similarity score (0-1) |
|
|
383
|
+
| role | string | - | Filter by "user" or "assistant" |
|
|
384
|
+
| memoryTypes | array | - | Filter: episodic, semantic, procedural, working |
|
|
385
|
+
| tags | array | - | Filter by tags (OR logic) |
|
|
386
|
+
| importance | array | - | Filter: critical, high, medium, low, trivial |
|
|
387
|
+
| dateRange | object | - | { start, end } ISO timestamps |
|
|
388
|
+
| galleryMode | boolean | false | Enable Mini COT analysis (falls back to basic on error) |
|
|
389
|
+
| cameraRollMode | boolean | true | DEFAULT TRUE - Returns drilldownIDs for drill_down() |
|
|
390
|
+
| zoomLevel | string | - | ultra-wide/wide/normal/close/macro |
|
|
391
|
+
| summarize | boolean | true | Truncate content to save tokens |
|
|
392
|
+
| includeRecent | number | 0 | Force include last N recent memories |
|
|
393
|
+
| recencyBoost | boolean | true | Boost recent memories in ranking |
|
|
394
|
+
| keywordFallback | boolean | true | Fallback to keyword if semantic fails |
|
|
395
|
+
|
|
396
|
+
## Examples
|
|
397
|
+
|
|
398
|
+
### Find what the user said about a topic
|
|
399
|
+
\`\`\`json
|
|
400
|
+
{
|
|
401
|
+
"query": "database migration strategy",
|
|
402
|
+
"role": "user"
|
|
403
|
+
}
|
|
404
|
+
\`\`\`
|
|
405
|
+
|
|
406
|
+
### Search with date filter
|
|
407
|
+
\`\`\`json
|
|
408
|
+
{
|
|
409
|
+
"query": "API authentication",
|
|
410
|
+
"dateRange": { "start": "2024-01-01", "end": "2024-12-31" }
|
|
411
|
+
}
|
|
412
|
+
\`\`\`
|
|
413
|
+
|
|
414
|
+
### Camera roll mode is DEFAULT (drilldownIDs included)
|
|
415
|
+
\`\`\`json
|
|
416
|
+
{
|
|
417
|
+
"query": "websocket implementation",
|
|
418
|
+
"zoomLevel": "wide"
|
|
419
|
+
}
|
|
420
|
+
\`\`\`
|
|
421
|
+
|
|
422
|
+
## Drill-Down
|
|
423
|
+
|
|
424
|
+
Results always include drilldownIDs (cameraRollMode is true by default):
|
|
425
|
+
- Use \`drill_down({ drilldownID: 123 })\` for full content + context
|
|
426
|
+
- Use \`get_memory({ id: "uuid..." })\` for raw memory
|
|
427
|
+
|
|
428
|
+
## Tips
|
|
429
|
+
|
|
430
|
+
1. **Time queries**: "yesterday", "last week", "3 days ago" are parsed automatically
|
|
431
|
+
2. **Role filter**: Use \`role: "user"\` to find what YOU said (not )
|
|
432
|
+
3. **Low results?**: Try \`keywordFallback: true\` and lower threshold
|
|
433
|
+
4. **Recent activity?**: Set \`includeRecent: 10\` to see latest memories
|
|
434
|
+
`;
|
|
435
|
+
/**
|
|
436
|
+
* FindWhatISaid - semantic search tool
|
|
437
|
+
*
|
|
438
|
+
* fr fr this semantic search hitting different
|
|
439
|
+
* combines vector similarity with optional filters for precision
|
|
440
|
+
*
|
|
441
|
+
* Emits LWJEB events: memory:retrieved
|
|
442
|
+
*/
|
|
443
|
+
export class FindWhatISaid {
|
|
444
|
+
db;
|
|
445
|
+
embeddingProvider;
|
|
446
|
+
name = 'find_memory';
|
|
447
|
+
description = 'Search across memories using semantic search - finds content based on meaning, not just keywords. Supports time queries like "yesterday" or "last week"';
|
|
448
|
+
coordinator = getCoordinator();
|
|
449
|
+
hotPathManager = null;
|
|
450
|
+
debugLogger = getDebugLogger();
|
|
451
|
+
inputSchema = {
|
|
452
|
+
type: 'object',
|
|
453
|
+
properties: {
|
|
454
|
+
query: {
|
|
455
|
+
type: 'string',
|
|
456
|
+
description: 'what you looking for - natural language works best. Leave empty for help.'
|
|
457
|
+
},
|
|
458
|
+
limit: {
|
|
459
|
+
type: 'number',
|
|
460
|
+
default: 10,
|
|
461
|
+
minimum: 1,
|
|
462
|
+
maximum: 1000,
|
|
463
|
+
description: 'how many results you want'
|
|
464
|
+
},
|
|
465
|
+
threshold: {
|
|
466
|
+
type: 'number',
|
|
467
|
+
default: 0.25,
|
|
468
|
+
minimum: 0,
|
|
469
|
+
maximum: 1,
|
|
470
|
+
description: 'minimum similarity score (0-1) - higher = more relevant. Default 0.25 filters garbage. Local embeddings: 0.2-0.5 typical for real matches.'
|
|
471
|
+
},
|
|
472
|
+
includeRecent: {
|
|
473
|
+
type: 'number',
|
|
474
|
+
default: 0,
|
|
475
|
+
minimum: 0,
|
|
476
|
+
maximum: 50,
|
|
477
|
+
description: 'Force include the last N most recent memories regardless of similarity. Use this to check recent prompts/discussions. Set to 5-10 to see recent activity.'
|
|
478
|
+
},
|
|
479
|
+
recencyBoost: {
|
|
480
|
+
type: 'boolean',
|
|
481
|
+
default: true,
|
|
482
|
+
description: 'Boost relevance of recent memories. Memories from last hour get 20% boost, last day 10% boost.'
|
|
483
|
+
},
|
|
484
|
+
keywordFallback: {
|
|
485
|
+
type: 'boolean',
|
|
486
|
+
default: true,
|
|
487
|
+
description: 'If embedding search returns no results, fallback to keyword (ILIKE) search.'
|
|
488
|
+
},
|
|
489
|
+
memoryTypes: {
|
|
490
|
+
type: 'array',
|
|
491
|
+
items: {
|
|
492
|
+
type: 'string',
|
|
493
|
+
enum: ['episodic', 'semantic', 'procedural', 'working', 'consolidated']
|
|
494
|
+
},
|
|
495
|
+
description: 'filter by memory type'
|
|
496
|
+
},
|
|
497
|
+
tags: {
|
|
498
|
+
type: 'array',
|
|
499
|
+
items: { type: 'string' },
|
|
500
|
+
description: 'filter by tags (OR logic)'
|
|
501
|
+
},
|
|
502
|
+
importance: {
|
|
503
|
+
type: 'array',
|
|
504
|
+
items: {
|
|
505
|
+
type: 'string',
|
|
506
|
+
enum: ['critical', 'high', 'medium', 'low', 'trivial']
|
|
507
|
+
},
|
|
508
|
+
description: 'filter by importance level'
|
|
509
|
+
},
|
|
510
|
+
dateRange: {
|
|
511
|
+
type: 'object',
|
|
512
|
+
properties: {
|
|
513
|
+
start: { type: 'string', format: 'date-time' },
|
|
514
|
+
end: { type: 'string', format: 'date-time' }
|
|
515
|
+
},
|
|
516
|
+
description: 'filter by creation date range'
|
|
517
|
+
},
|
|
518
|
+
includeExpired: {
|
|
519
|
+
type: 'boolean',
|
|
520
|
+
default: false,
|
|
521
|
+
description: 'include expired memories in results'
|
|
522
|
+
},
|
|
523
|
+
role: {
|
|
524
|
+
type: 'string',
|
|
525
|
+
enum: ['user', 'assistant'],
|
|
526
|
+
description: 'filter by message role - use "user" to find only things YOU said, "assistant" for responses'
|
|
527
|
+
},
|
|
528
|
+
summarize: {
|
|
529
|
+
type: 'boolean',
|
|
530
|
+
default: true,
|
|
531
|
+
description: 'DEFAULT TRUE - returns summarized content (first 500 chars) to save context. Set to false for full content. Use get_memory with the ID for drill-down'
|
|
532
|
+
},
|
|
533
|
+
galleryMode: {
|
|
534
|
+
oneOf: [
|
|
535
|
+
{ type: 'boolean' },
|
|
536
|
+
{ type: 'string', enum: ['ask'] }
|
|
537
|
+
],
|
|
538
|
+
default: false,
|
|
539
|
+
description: 'Enable Mini COT analysis. Falls back to basic semantic search on error. "ask"=show mode options'
|
|
540
|
+
},
|
|
541
|
+
maxContentLength: {
|
|
542
|
+
type: 'number',
|
|
543
|
+
default: 500,
|
|
544
|
+
description: 'DEFAULT 500 - truncate content to this many characters. Set to 0 for no truncation. Reduces context consumption'
|
|
545
|
+
},
|
|
546
|
+
zoomLevel: {
|
|
547
|
+
type: 'string',
|
|
548
|
+
enum: ['ultra-wide', 'wide', 'normal', 'close', 'macro'],
|
|
549
|
+
description: 'Camera roll zoom level: ultra-wide (50 results, 15% threshold), wide (25, 25%), normal (15, 40%), close (10, 60%), macro (5, 80%)'
|
|
550
|
+
},
|
|
551
|
+
cameraRollMode: {
|
|
552
|
+
type: 'boolean',
|
|
553
|
+
default: true,
|
|
554
|
+
description: 'DEFAULT TRUE - Returns drilldownIDs for drill_down() exploration. Set to false for raw results.'
|
|
555
|
+
},
|
|
556
|
+
projectPath: {
|
|
557
|
+
type: 'string',
|
|
558
|
+
description: 'Search memories from a specific project path instead of current project. Use absolute path like "/home/user/my-other-project"'
|
|
559
|
+
},
|
|
560
|
+
allProjects: {
|
|
561
|
+
type: 'boolean',
|
|
562
|
+
default: false,
|
|
563
|
+
description: 'Search ALL projects instead of just current project. Useful for cross-referencing code/patterns across repos.'
|
|
564
|
+
},
|
|
565
|
+
// humanReadable is always true - removed as configurable option per user request
|
|
566
|
+
},
|
|
567
|
+
required: [] // query is not required - empty shows help
|
|
568
|
+
};
|
|
569
|
+
dimensionService = null;
|
|
570
|
+
constructor(db, embeddingProvider) {
|
|
571
|
+
this.db = db;
|
|
572
|
+
this.embeddingProvider = embeddingProvider;
|
|
573
|
+
try {
|
|
574
|
+
this.dimensionService = getDimensionService(db, embeddingProvider);
|
|
575
|
+
}
|
|
576
|
+
catch {
|
|
577
|
+
// Will initialize when needed
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Build project filter condition for SQL queries
|
|
582
|
+
* Supports: current project (default), specific project (projectPath), or all projects (allProjects)
|
|
583
|
+
* Returns: { condition: string, params: unknown[], nextIndex: number }
|
|
584
|
+
*/
|
|
585
|
+
buildProjectCondition(params, startIndex = 1) {
|
|
586
|
+
const conditions = [];
|
|
587
|
+
const queryParams = [];
|
|
588
|
+
let nextIndex = startIndex;
|
|
589
|
+
// allProjects = true: skip project filtering entirely
|
|
590
|
+
if (params.allProjects) {
|
|
591
|
+
// No project condition - search ALL projects
|
|
592
|
+
return { conditions, queryParams, nextIndex };
|
|
593
|
+
}
|
|
594
|
+
// Use specified projectPath or fall back to current project
|
|
595
|
+
const targetProject = params.projectPath || getProjectContext().getProjectPath();
|
|
596
|
+
conditions.push(`project_path = $${nextIndex}`);
|
|
597
|
+
queryParams.push(targetProject);
|
|
598
|
+
nextIndex++;
|
|
599
|
+
return { conditions, queryParams, nextIndex };
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Get DimensionService (lazy initialization)
|
|
603
|
+
*/
|
|
604
|
+
getDimService() {
|
|
605
|
+
if (!this.dimensionService) {
|
|
606
|
+
this.dimensionService = getDimensionService(this.db, this.embeddingProvider);
|
|
607
|
+
}
|
|
608
|
+
return this.dimensionService;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Validate and prepare embedding for memories table search
|
|
612
|
+
*/
|
|
613
|
+
async prepareEmbedding(embedding, originalQuery) {
|
|
614
|
+
const dimService = this.getDimService();
|
|
615
|
+
const prepared = await dimService.validateAndPrepare('memories', embedding, originalQuery);
|
|
616
|
+
if (prepared.wasModified) {
|
|
617
|
+
logger.debug({ action: prepared.action }, 'Adjusted embedding dimension for memory search');
|
|
618
|
+
}
|
|
619
|
+
return prepared.embedding;
|
|
620
|
+
}
|
|
621
|
+
async execute(params) {
|
|
622
|
+
_searchCount++;
|
|
623
|
+
const startTime = Date.now();
|
|
624
|
+
// ============================================================================
|
|
625
|
+
// DEEP DEBUG: Method Entry
|
|
626
|
+
// ============================================================================
|
|
627
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'METHOD_ENTRY', {
|
|
628
|
+
query: params.query?.slice(0, 100),
|
|
629
|
+
limit: params.limit,
|
|
630
|
+
threshold: params.threshold,
|
|
631
|
+
memoryTypes: params.memoryTypes,
|
|
632
|
+
tags: params.tags,
|
|
633
|
+
galleryMode: params.galleryMode,
|
|
634
|
+
cameraRollMode: params.cameraRollMode,
|
|
635
|
+
zoomLevel: params.zoomLevel,
|
|
636
|
+
includeRecent: params.includeRecent,
|
|
637
|
+
recencyBoost: params.recencyBoost,
|
|
638
|
+
keywordFallback: params.keywordFallback,
|
|
639
|
+
startTime,
|
|
640
|
+
searchCount: _searchCount
|
|
641
|
+
});
|
|
642
|
+
// HELP MODE: No query = show help
|
|
643
|
+
if (!params.query || params.query.trim() === '' || params.query.toLowerCase() === 'help') {
|
|
644
|
+
logger.info({}, '[find_memory] Showing help - no query provided');
|
|
645
|
+
const now = new Date();
|
|
646
|
+
return [{
|
|
647
|
+
memory: {
|
|
648
|
+
id: 'help-output',
|
|
649
|
+
content: HELP_OUTPUT,
|
|
650
|
+
createdAt: now,
|
|
651
|
+
updatedAt: now,
|
|
652
|
+
tags: ['help', 'system'],
|
|
653
|
+
importance: 'medium',
|
|
654
|
+
memoryType: 'semantic',
|
|
655
|
+
metadata: { _isHelp: true }
|
|
656
|
+
},
|
|
657
|
+
similarity: 1.0,
|
|
658
|
+
highlights: []
|
|
659
|
+
}];
|
|
660
|
+
}
|
|
661
|
+
logger.debug({ query: params.query, limit: params.limit }, 'searching memories fr');
|
|
662
|
+
// Broadcast COT to dashboard
|
|
663
|
+
cotStart('find_memory', params.query || 'browsing');
|
|
664
|
+
try {
|
|
665
|
+
// Apply max result limit to prevent memory issues
|
|
666
|
+
const MAX_RESULTS = 1000;
|
|
667
|
+
const safeLimit = Math.min(params.limit ?? 10, MAX_RESULTS);
|
|
668
|
+
// humanReadable is always true - no longer configurable
|
|
669
|
+
const safeParams = {
|
|
670
|
+
...params,
|
|
671
|
+
limit: safeLimit
|
|
672
|
+
};
|
|
673
|
+
// ============================================================================
|
|
674
|
+
// DEEP DEBUG: After Parameter Validation
|
|
675
|
+
// ============================================================================
|
|
676
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'PARAMS_VALIDATED', {
|
|
677
|
+
originalLimit: params.limit,
|
|
678
|
+
safeLimit,
|
|
679
|
+
MAX_RESULTS,
|
|
680
|
+
elapsedMs: Date.now() - startTime
|
|
681
|
+
});
|
|
682
|
+
// ============================================================================
|
|
683
|
+
// MODE SELECTION - Return options if user wants to choose
|
|
684
|
+
// ============================================================================
|
|
685
|
+
if (safeParams.galleryMode === 'ask') {
|
|
686
|
+
logger.info({ query: safeParams.query }, 'Returning search mode options for user selection');
|
|
687
|
+
const now = new Date();
|
|
688
|
+
return [{
|
|
689
|
+
memory: {
|
|
690
|
+
id: 'mode-selector',
|
|
691
|
+
content: `# Search Mode Selection\n\nQuery: "${safeParams.query}"\n\nChoose your search mode:\n\n## ⚡ Basic Search (Recommended for quick lookups)\n- **Speed**: Instant (~100-500ms)\n- **Features**: Semantic similarity, keyword matching, tag filtering, drill-down hints\n- **Best for**: Quick lookups, finding specific info, browsing history\n\n## 🎨 Gallery Mode (Deep analysis)\n- **Speed**: Slower (~5-15s depending on results)\n- **Features**: Mini COT brain analyzes with Chain-of-Thought reasoning, relevance explanations, research notes for unknown terms, Traditional Chinese compression\n- **Best for**: Deep analysis, understanding complex topics, research synthesis\n- **Note**: EXPERIMENTAL - requires Mini COT service running (TinyLlama)\n\n**Recommendation**: Use BASIC for most searches. Use GALLERY when you need the AI to deeply analyze and explain the results.\n\nTo proceed, call find_memory again with:\n- \`galleryMode: false\` for Basic Search\n- \`galleryMode: true\` for Gallery Mode`,
|
|
692
|
+
createdAt: now,
|
|
693
|
+
updatedAt: now,
|
|
694
|
+
tags: ['mode-selector', 'system'],
|
|
695
|
+
importance: 'medium',
|
|
696
|
+
memoryType: 'semantic',
|
|
697
|
+
metadata: {
|
|
698
|
+
_modeOptions: {
|
|
699
|
+
query: safeParams.query,
|
|
700
|
+
basic: { galleryMode: false, description: 'Fast semantic + keyword search' },
|
|
701
|
+
gallery: { galleryMode: true, description: 'Mini COT analysis with COT reasoning' }
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
},
|
|
705
|
+
similarity: 1.0,
|
|
706
|
+
highlights: []
|
|
707
|
+
}];
|
|
708
|
+
}
|
|
709
|
+
// check for natural language time expressions
|
|
710
|
+
let dateRange = safeParams.dateRange;
|
|
711
|
+
if (!dateRange) {
|
|
712
|
+
const parsedTime = parseTimeExpression(safeParams.query);
|
|
713
|
+
if (parsedTime) {
|
|
714
|
+
dateRange = {
|
|
715
|
+
start: parsedTime.start.toISOString(),
|
|
716
|
+
end: parsedTime.end.toISOString()
|
|
717
|
+
};
|
|
718
|
+
logger.debug({ dateRange }, 'parsed time expression from query');
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
// generate query embedding with timeout protection
|
|
722
|
+
// UNIFIED TIMEOUT CONFIG: Set SPECMEM_EMBEDDING_TIMEOUT (seconds) to control ALL timeouts
|
|
723
|
+
// Or use SPECMEM_FIND_EMBEDDING_TIMEOUT_MS for specific override
|
|
724
|
+
// See src/config/embeddingTimeouts.ts for full documentation
|
|
725
|
+
const EMBEDDING_TIMEOUT_MS = getEmbeddingTimeout('search');
|
|
726
|
+
// Get socket path for error reporting
|
|
727
|
+
const socketPath = getEmbeddingSocketPath();
|
|
728
|
+
// ============================================================================
|
|
729
|
+
// DEEP DEBUG: Before Embedding Generation
|
|
730
|
+
// ============================================================================
|
|
731
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'BEFORE_EMBEDDING', {
|
|
732
|
+
query: safeParams.query?.slice(0, 100),
|
|
733
|
+
socketPath,
|
|
734
|
+
timeoutMs: EMBEDDING_TIMEOUT_MS,
|
|
735
|
+
elapsedMs: Date.now() - startTime,
|
|
736
|
+
embeddingProviderType: this.embeddingProvider?.constructor?.name || 'unknown'
|
|
737
|
+
});
|
|
738
|
+
// Debug log: Search operation starting
|
|
739
|
+
this.debugLogger.searchOperation(safeParams.query, 'start', { socketPath });
|
|
740
|
+
const embeddingStartTime = Date.now();
|
|
741
|
+
this.debugLogger.embeddingGeneration(safeParams.query, socketPath, 'start');
|
|
742
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'EMBEDDING_STARTED', {
|
|
743
|
+
embeddingStartTime,
|
|
744
|
+
socketPath,
|
|
745
|
+
query: safeParams.query?.slice(0, 50)
|
|
746
|
+
});
|
|
747
|
+
const embeddingPromise = this.embeddingProvider.generateEmbedding(safeParams.query);
|
|
748
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
749
|
+
setTimeout(() => {
|
|
750
|
+
const timeoutError = new Error(`Embedding generation timeout after ${formatTimeout(EMBEDDING_TIMEOUT_MS)}. ` +
|
|
751
|
+
`Socket: ${socketPath}. ` +
|
|
752
|
+
`Set SPECMEM_EMBEDDING_TIMEOUT env var to increase timeout.`);
|
|
753
|
+
timeoutError.socketPath = socketPath;
|
|
754
|
+
timeoutError.code = 'EMBEDDING_TIMEOUT';
|
|
755
|
+
reject(timeoutError);
|
|
756
|
+
}, EMBEDDING_TIMEOUT_MS);
|
|
757
|
+
});
|
|
758
|
+
let rawEmbedding;
|
|
759
|
+
try {
|
|
760
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'AWAITING_EMBEDDING_PROMISE', {
|
|
761
|
+
elapsedMs: Date.now() - startTime
|
|
762
|
+
});
|
|
763
|
+
rawEmbedding = await Promise.race([embeddingPromise, timeoutPromise]);
|
|
764
|
+
const embeddingDuration = Date.now() - embeddingStartTime;
|
|
765
|
+
// ============================================================================
|
|
766
|
+
// DEEP DEBUG: After Embedding Generation (Success)
|
|
767
|
+
// ============================================================================
|
|
768
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'AFTER_EMBEDDING_SUCCESS', {
|
|
769
|
+
embeddingDuration,
|
|
770
|
+
rawEmbeddingDimension: rawEmbedding?.length,
|
|
771
|
+
rawEmbeddingFirstValues: rawEmbedding?.slice(0, 3),
|
|
772
|
+
elapsedMs: Date.now() - startTime
|
|
773
|
+
});
|
|
774
|
+
this.debugLogger.embeddingGeneration(safeParams.query, socketPath, 'complete', {
|
|
775
|
+
durationMs: embeddingDuration,
|
|
776
|
+
dimension: rawEmbedding.length
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
catch (embeddingError) {
|
|
780
|
+
const embeddingDuration = Date.now() - embeddingStartTime;
|
|
781
|
+
const err = embeddingError;
|
|
782
|
+
// ============================================================================
|
|
783
|
+
// DEEP DEBUG: After Embedding Generation (Error)
|
|
784
|
+
// ============================================================================
|
|
785
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'AFTER_EMBEDDING_ERROR', {
|
|
786
|
+
embeddingDuration,
|
|
787
|
+
errorMessage: err?.message?.slice(0, 200),
|
|
788
|
+
errorCode: err?.code,
|
|
789
|
+
errorName: err?.name,
|
|
790
|
+
socketPath,
|
|
791
|
+
elapsedMs: Date.now() - startTime
|
|
792
|
+
});
|
|
793
|
+
// Enhanced error with socket path info
|
|
794
|
+
this.debugLogger.embeddingGeneration(safeParams.query, socketPath, err.message.includes('timeout') ? 'timeout' : 'error', {
|
|
795
|
+
durationMs: embeddingDuration,
|
|
796
|
+
error: err
|
|
797
|
+
});
|
|
798
|
+
// Re-throw with enhanced message including socket path
|
|
799
|
+
const enhancedError = new Error(`Embedding generation failed: ${err.message}. ` +
|
|
800
|
+
`Socket path: ${socketPath}. ` +
|
|
801
|
+
`Duration: ${embeddingDuration}ms. ` +
|
|
802
|
+
`Troubleshooting: Check if embedding service is running (ps aux | grep frankenstein), ` +
|
|
803
|
+
`verify socket exists (ls -la ${socketPath}), check SPECMEM_DEBUG=true for more logs.`);
|
|
804
|
+
enhancedError.originalError = err;
|
|
805
|
+
enhancedError.socketPath = socketPath;
|
|
806
|
+
enhancedError.durationMs = embeddingDuration;
|
|
807
|
+
enhancedError.code = err.code || 'EMBEDDING_ERROR';
|
|
808
|
+
throw enhancedError;
|
|
809
|
+
}
|
|
810
|
+
// Validate and prepare embedding dimension using DimensionService
|
|
811
|
+
const queryEmbedding = await this.prepareEmbedding(rawEmbedding, safeParams.query);
|
|
812
|
+
// Debug log: Embedding phase complete
|
|
813
|
+
this.debugLogger.searchOperation(safeParams.query, 'embedding', {
|
|
814
|
+
durationMs: Date.now() - embeddingStartTime,
|
|
815
|
+
socketPath
|
|
816
|
+
});
|
|
817
|
+
// DEBUG: Log query embedding dimension and first few values
|
|
818
|
+
logger.info({
|
|
819
|
+
queryEmbeddingDim: queryEmbedding.length,
|
|
820
|
+
query: safeParams.query,
|
|
821
|
+
firstValues: queryEmbedding.slice(0, 3),
|
|
822
|
+
socketPath
|
|
823
|
+
}, 'Generated query embedding');
|
|
824
|
+
// do the search with timeout protection
|
|
825
|
+
// UNIFIED TIMEOUT CONFIG: See src/config/embeddingTimeouts.ts
|
|
826
|
+
// Uses 'dbSearch' timeout (6x master, or SPECMEM_FIND_SEARCH_TIMEOUT_MS)
|
|
827
|
+
const SEARCH_TIMEOUT_MS = getEmbeddingTimeout('dbSearch');
|
|
828
|
+
// ============================================================================
|
|
829
|
+
// DEEP DEBUG: Before Database Query
|
|
830
|
+
// ============================================================================
|
|
831
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'BEFORE_DB_QUERY', {
|
|
832
|
+
queryEmbeddingDimension: queryEmbedding?.length,
|
|
833
|
+
searchTimeoutMs: SEARCH_TIMEOUT_MS,
|
|
834
|
+
dateRange: dateRange ? { start: dateRange.start, end: dateRange.end } : null,
|
|
835
|
+
memoryTypes: safeParams.memoryTypes,
|
|
836
|
+
tags: safeParams.tags,
|
|
837
|
+
limit: safeParams.limit,
|
|
838
|
+
threshold: safeParams.threshold,
|
|
839
|
+
elapsedMs: Date.now() - startTime
|
|
840
|
+
});
|
|
841
|
+
// Debug log: Search phase starting
|
|
842
|
+
this.debugLogger.searchOperation(safeParams.query, 'search');
|
|
843
|
+
const searchStartTime = Date.now();
|
|
844
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'DB_QUERY_STARTED', {
|
|
845
|
+
searchStartTime,
|
|
846
|
+
query: safeParams.query?.slice(0, 50)
|
|
847
|
+
});
|
|
848
|
+
const searchPromise = this.semanticSearch({
|
|
849
|
+
...safeParams,
|
|
850
|
+
dateRange
|
|
851
|
+
}, queryEmbedding);
|
|
852
|
+
const searchTimeoutPromise = new Promise((_, reject) => {
|
|
853
|
+
setTimeout(() => {
|
|
854
|
+
const timeoutError = new Error(`Search timeout after ${formatTimeout(SEARCH_TIMEOUT_MS)}. ` +
|
|
855
|
+
`Query: "${safeParams.query.slice(0, 50)}...". ` +
|
|
856
|
+
`Set SPECMEM_EMBEDDING_TIMEOUT env var to increase timeout.`);
|
|
857
|
+
timeoutError.code = 'SEARCH_TIMEOUT';
|
|
858
|
+
reject(timeoutError);
|
|
859
|
+
}, SEARCH_TIMEOUT_MS);
|
|
860
|
+
});
|
|
861
|
+
let results;
|
|
862
|
+
try {
|
|
863
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'AWAITING_DB_QUERY_PROMISE', {
|
|
864
|
+
elapsedMs: Date.now() - startTime
|
|
865
|
+
});
|
|
866
|
+
results = await Promise.race([searchPromise, searchTimeoutPromise]);
|
|
867
|
+
const searchDuration = Date.now() - searchStartTime;
|
|
868
|
+
// ============================================================================
|
|
869
|
+
// DEEP DEBUG: After Database Query (Success)
|
|
870
|
+
// ============================================================================
|
|
871
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'AFTER_DB_QUERY_SUCCESS', {
|
|
872
|
+
searchDuration,
|
|
873
|
+
resultCount: results?.length,
|
|
874
|
+
topSimilarity: results?.[0]?.similarity,
|
|
875
|
+
topMemoryId: results?.[0]?.memory?.id?.slice(0, 20),
|
|
876
|
+
elapsedMs: Date.now() - startTime
|
|
877
|
+
});
|
|
878
|
+
this.debugLogger.searchOperation(safeParams.query, 'complete', {
|
|
879
|
+
durationMs: searchDuration,
|
|
880
|
+
resultCount: results.length
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
catch (searchError) {
|
|
884
|
+
const searchDuration = Date.now() - searchStartTime;
|
|
885
|
+
const err = searchError;
|
|
886
|
+
// ============================================================================
|
|
887
|
+
// DEEP DEBUG: After Database Query (Error)
|
|
888
|
+
// ============================================================================
|
|
889
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'AFTER_DB_QUERY_ERROR', {
|
|
890
|
+
searchDuration,
|
|
891
|
+
errorMessage: err?.message?.slice(0, 200),
|
|
892
|
+
errorCode: err?.code,
|
|
893
|
+
errorName: err?.name,
|
|
894
|
+
elapsedMs: Date.now() - startTime
|
|
895
|
+
});
|
|
896
|
+
// Enhanced debug logging for search errors
|
|
897
|
+
this.debugLogger.searchOperation(safeParams.query, 'error', {
|
|
898
|
+
durationMs: searchDuration,
|
|
899
|
+
error: err,
|
|
900
|
+
socketPath
|
|
901
|
+
});
|
|
902
|
+
// Re-throw with enhanced context
|
|
903
|
+
const enhancedError = new Error(`Search failed: ${err.message}. ` +
|
|
904
|
+
`Duration: ${searchDuration}ms. ` +
|
|
905
|
+
`Query: "${safeParams.query.slice(0, 50)}...". ` +
|
|
906
|
+
`Socket: ${socketPath}. ` +
|
|
907
|
+
`Enable SPECMEM_DEBUG=true for detailed logs.`);
|
|
908
|
+
enhancedError.originalError = err;
|
|
909
|
+
enhancedError.code = err.code || 'SEARCH_ERROR';
|
|
910
|
+
enhancedError.durationMs = searchDuration;
|
|
911
|
+
throw enhancedError;
|
|
912
|
+
}
|
|
913
|
+
// ============================================================================
|
|
914
|
+
// I5 FIX: APPLY NEW SEARCH FEATURES
|
|
915
|
+
// ============================================================================
|
|
916
|
+
// ============================================================================
|
|
917
|
+
// DEEP DEBUG: Before Result Processing
|
|
918
|
+
// ============================================================================
|
|
919
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'BEFORE_RESULT_PROCESSING', {
|
|
920
|
+
rawResultCount: results?.length,
|
|
921
|
+
topRawSimilarity: results?.[0]?.similarity,
|
|
922
|
+
elapsedMs: Date.now() - startTime
|
|
923
|
+
});
|
|
924
|
+
// I5 FIX: Get includeRecent, recencyBoost, keywordFallback from params
|
|
925
|
+
const includeRecentCount = safeParams.includeRecent ?? 0;
|
|
926
|
+
const applyRecencyBoost = safeParams.recencyBoost !== false; // Default true
|
|
927
|
+
const useKeywordFallback = safeParams.keywordFallback !== false; // Default true
|
|
928
|
+
logger.info({
|
|
929
|
+
query: safeParams.query,
|
|
930
|
+
semanticResultCount: results.length,
|
|
931
|
+
includeRecent: includeRecentCount,
|
|
932
|
+
recencyBoost: applyRecencyBoost,
|
|
933
|
+
keywordFallback: useKeywordFallback
|
|
934
|
+
}, '[I5 FIX] Search phase 1 complete, applying fixes');
|
|
935
|
+
// I5 FIX: Apply recency boost to semantic results
|
|
936
|
+
if (applyRecencyBoost && results.length > 0) {
|
|
937
|
+
results = this.applyRecencyBoost(results);
|
|
938
|
+
logger.debug({ boostedCount: results.length }, '[I5 FIX] Recency boost applied');
|
|
939
|
+
}
|
|
940
|
+
// I5 FIX: Keyword fallback if semantic search returned nothing useful
|
|
941
|
+
let keywordResults = [];
|
|
942
|
+
const hasGoodSemanticResults = results.length > 0 && results[0]?.similarity >= 0.15;
|
|
943
|
+
if (useKeywordFallback && !hasGoodSemanticResults) {
|
|
944
|
+
logger.info({
|
|
945
|
+
query: safeParams.query,
|
|
946
|
+
semanticResults: results.length,
|
|
947
|
+
topSimilarity: results[0]?.similarity
|
|
948
|
+
}, '[I5 FIX] Low/no semantic results, triggering keyword fallback');
|
|
949
|
+
keywordResults = await this.keywordSearch(safeParams.query, safeParams);
|
|
950
|
+
}
|
|
951
|
+
// I5 FIX: Get recent memories if requested
|
|
952
|
+
let recentResults = [];
|
|
953
|
+
if (includeRecentCount > 0) {
|
|
954
|
+
recentResults = await this.getRecentMemories(includeRecentCount, safeParams);
|
|
955
|
+
logger.info({
|
|
956
|
+
recentRequested: includeRecentCount,
|
|
957
|
+
recentFound: recentResults.length
|
|
958
|
+
}, '[I5 FIX] Recent memories retrieved');
|
|
959
|
+
}
|
|
960
|
+
// I5 FIX: Merge all results if we have additional sources
|
|
961
|
+
if (recentResults.length > 0 || keywordResults.length > 0) {
|
|
962
|
+
const originalCount = results.length;
|
|
963
|
+
results = this.mergeAndDedupeResults(results, recentResults, keywordResults, safeParams.limit ?? 10);
|
|
964
|
+
logger.info({
|
|
965
|
+
originalSemanticCount: originalCount,
|
|
966
|
+
recentCount: recentResults.length,
|
|
967
|
+
keywordCount: keywordResults.length,
|
|
968
|
+
mergedCount: results.length
|
|
969
|
+
}, '[I5 FIX] Results merged from multiple sources');
|
|
970
|
+
}
|
|
971
|
+
const duration = Date.now() - startTime;
|
|
972
|
+
_totalSearchTime += duration;
|
|
973
|
+
// ============================================================================
|
|
974
|
+
// DEEP DEBUG: After Result Processing
|
|
975
|
+
// ============================================================================
|
|
976
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'AFTER_RESULT_PROCESSING', {
|
|
977
|
+
finalResultCount: results?.length,
|
|
978
|
+
topFinalSimilarity: results?.[0]?.similarity,
|
|
979
|
+
usedKeywordFallback: keywordResults?.length > 0,
|
|
980
|
+
keywordResultCount: keywordResults?.length,
|
|
981
|
+
usedRecentMemories: recentResults?.length > 0,
|
|
982
|
+
recentResultCount: recentResults?.length,
|
|
983
|
+
totalDurationMs: duration,
|
|
984
|
+
avgSearchTimeMs: _totalSearchTime / _searchCount,
|
|
985
|
+
elapsedMs: Date.now() - startTime
|
|
986
|
+
});
|
|
987
|
+
logger.info({
|
|
988
|
+
resultCount: results.length,
|
|
989
|
+
duration,
|
|
990
|
+
avgSearchTime: _totalSearchTime / _searchCount,
|
|
991
|
+
usedKeywordFallback: keywordResults.length > 0,
|
|
992
|
+
usedRecentMemories: recentResults.length > 0
|
|
993
|
+
}, 'search complete with I5 fixes');
|
|
994
|
+
// Log warning if search was slow
|
|
995
|
+
if (duration > 1000) {
|
|
996
|
+
logger.warn({ duration, query: safeParams.query }, 'slow search detected');
|
|
997
|
+
}
|
|
998
|
+
// Generate drilldown suggestion based on results
|
|
999
|
+
const drilldown = generateDrilldownSuggestion(results, safeParams.query);
|
|
1000
|
+
// Log drilldown analysis
|
|
1001
|
+
logger.info({
|
|
1002
|
+
query: safeParams.query,
|
|
1003
|
+
resultCount: results.length,
|
|
1004
|
+
topSimilarity: results[0]?.similarity,
|
|
1005
|
+
drilldownAction: drilldown.action,
|
|
1006
|
+
needsResearch: drilldown.needsResearch
|
|
1007
|
+
}, '[Drilldown] 分析完成');
|
|
1008
|
+
// Handle empty results with informative message
|
|
1009
|
+
if (results.length === 0) {
|
|
1010
|
+
logger.info({ query: safeParams.query, filters: { memoryTypes: safeParams.memoryTypes, tags: safeParams.tags } }, 'no results found for query');
|
|
1011
|
+
// Always use humanReadable format
|
|
1012
|
+
return formatHumanReadable('find_memory', [], {
|
|
1013
|
+
grey: true,
|
|
1014
|
+
showSimilarity: true,
|
|
1015
|
+
query: safeParams.query,
|
|
1016
|
+
emptyMessage: `No memories found for "${safeParams.query}". Try: broader terms, check_sync, or save_memory to add context.`
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
// ============================================================================
|
|
1020
|
+
// GALLERY MODE - Mini COT Decision Model creates semantic gallery
|
|
1021
|
+
// ============================================================================
|
|
1022
|
+
if (safeParams.galleryMode === true) {
|
|
1023
|
+
logger.info({ query: safeParams.query, resultCount: results.length }, 'Gallery mode enabled - sending to Mini COT');
|
|
1024
|
+
try {
|
|
1025
|
+
const miniCOT = new MiniCOTProvider();
|
|
1026
|
+
// Prepare memories for gallery creation (send ENGLISH to CoT!)
|
|
1027
|
+
const memoriesForGallery = results.map(result => ({
|
|
1028
|
+
id: result.memory.id,
|
|
1029
|
+
keywords: result.memory.metadata?._semanticHints || result.memory.tags.join(', '),
|
|
1030
|
+
snippet: result.memory.content.slice(0, 300), // First 300 chars
|
|
1031
|
+
timestamp: result.memory.metadata?.timestamp, // When it was said
|
|
1032
|
+
role: result.memory.metadata?.role // Who said it (user/assistant)
|
|
1033
|
+
}));
|
|
1034
|
+
// Call Mini COT to create gallery (CoT analyzes in ENGLISH)
|
|
1035
|
+
const gallery = await miniCOT.createGallery(safeParams.query, memoriesForGallery);
|
|
1036
|
+
// ROUND-TRIP VERIFIED compression - compress CoT OUTPUT for token efficiency
|
|
1037
|
+
// Uses smartCompress: EN→Chinese→EN comparison, keeps English where context lost
|
|
1038
|
+
// MED-40 FIX: Add null check before compression to avoid undefined errors
|
|
1039
|
+
gallery.gallery = gallery.gallery.map(item => ({
|
|
1040
|
+
...item,
|
|
1041
|
+
thumbnail: item.thumbnail ? smartCompress(item.thumbnail, { threshold: 0.75 }).result : '',
|
|
1042
|
+
cot: item.cot ? smartCompress(item.cot, { threshold: 0.75 }).result : ''
|
|
1043
|
+
}));
|
|
1044
|
+
logger.info({
|
|
1045
|
+
query: safeParams.query,
|
|
1046
|
+
galleryItems: gallery.gallery.length,
|
|
1047
|
+
researchedTerms: gallery.total_researched_terms
|
|
1048
|
+
}, 'Gallery created by Mini COT and compressed');
|
|
1049
|
+
// Always use humanReadable format
|
|
1050
|
+
const humanReadableData = gallery.gallery.map((item, idx) => ({
|
|
1051
|
+
id: item.id || `gallery-${idx}`,
|
|
1052
|
+
similarity: item.relevance ? item.relevance / 100 : 0.5,
|
|
1053
|
+
content: `[GALLERY] ${item.thumbnail || item.cot || 'No preview'}`,
|
|
1054
|
+
}));
|
|
1055
|
+
return formatHumanReadable('find_memory', humanReadableData, {
|
|
1056
|
+
grey: true,
|
|
1057
|
+
showSimilarity: true,
|
|
1058
|
+
query: safeParams.query,
|
|
1059
|
+
mode: 'gallery'
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
catch (error) {
|
|
1063
|
+
logger.error({ error, query: safeParams.query }, 'Mini COT gallery creation failed - falling back to normal results');
|
|
1064
|
+
// Fall through to normal results on error
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
// ============================================================================
|
|
1068
|
+
// CAMERA ROLL MODE - Default TRUE - zoom-based response format with drilldownIDs
|
|
1069
|
+
// ============================================================================
|
|
1070
|
+
// DEFAULT TRUE: Only disable if explicitly set to false
|
|
1071
|
+
const cameraRollModeRaw = safeParams.cameraRollMode;
|
|
1072
|
+
const cameraRollMode = cameraRollModeRaw !== false && cameraRollModeRaw !== 'false' && cameraRollModeRaw !== 0;
|
|
1073
|
+
const zoomLevelParam = safeParams.zoomLevel;
|
|
1074
|
+
logger.debug({
|
|
1075
|
+
cameraRollMode,
|
|
1076
|
+
cameraRollModeRaw,
|
|
1077
|
+
zoomLevelParam
|
|
1078
|
+
}, '[find_memory] Camera roll mode check (default: true)');
|
|
1079
|
+
if (cameraRollMode) {
|
|
1080
|
+
// Determine zoom level from parameter or threshold
|
|
1081
|
+
const zoomLevel = zoomLevelParam || thresholdToZoomLevel(safeParams.threshold ?? 0.1);
|
|
1082
|
+
const zoomConfig = ZOOM_CONFIGS[zoomLevel];
|
|
1083
|
+
logger.info({
|
|
1084
|
+
query: safeParams.query,
|
|
1085
|
+
zoomLevel,
|
|
1086
|
+
resultCount: results.length,
|
|
1087
|
+
threshold: zoomConfig.threshold
|
|
1088
|
+
}, 'Camera roll mode enabled');
|
|
1089
|
+
// Convert results to camera roll format
|
|
1090
|
+
const cameraRollItems = results.map(result => {
|
|
1091
|
+
// Try to find Response if this is a user message
|
|
1092
|
+
const metadata = result.memory.metadata || {};
|
|
1093
|
+
const claudeResponse = metadata.claudeResponse || metadata.response;
|
|
1094
|
+
return formatAsCameraRollItem({
|
|
1095
|
+
id: result.memory.id,
|
|
1096
|
+
content: result.memory.content,
|
|
1097
|
+
similarity: result.similarity,
|
|
1098
|
+
metadata,
|
|
1099
|
+
tags: result.memory.tags,
|
|
1100
|
+
createdAt: result.memory.createdAt
|
|
1101
|
+
}, zoomConfig, {
|
|
1102
|
+
claudeResponse,
|
|
1103
|
+
relatedCount: metadata.relatedCount,
|
|
1104
|
+
codePointers: metadata.codePointers
|
|
1105
|
+
});
|
|
1106
|
+
});
|
|
1107
|
+
// Always use humanReadable format
|
|
1108
|
+
const humanReadableData = cameraRollItems.map((item) => ({
|
|
1109
|
+
id: item.drilldownID || item.id,
|
|
1110
|
+
similarity: item.similarity || 0.5,
|
|
1111
|
+
content: item.preview || item.content || 'No preview',
|
|
1112
|
+
}));
|
|
1113
|
+
return formatHumanReadable('find_memory', humanReadableData, {
|
|
1114
|
+
grey: true,
|
|
1115
|
+
showSimilarity: true,
|
|
1116
|
+
query: safeParams.query,
|
|
1117
|
+
mode: 'camera_roll',
|
|
1118
|
+
zoomLevel
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
// ============================================================================
|
|
1122
|
+
// CONTEXT ENRICHMENT PIPELINE
|
|
1123
|
+
// Like human memory: fragment -> connections -> deeper recall
|
|
1124
|
+
// ONLY when NOT in summarize mode - drill-down should be MINIMAL
|
|
1125
|
+
// ============================================================================
|
|
1126
|
+
// CLEAN OUTPUT - Show conversation pairs:
|
|
1127
|
+
// : <response>
|
|
1128
|
+
// UP: <user prompt that triggered it>
|
|
1129
|
+
// Default mode (summarize=true)
|
|
1130
|
+
// User feedback: "content wayyy too trimmed" - increased default
|
|
1131
|
+
if (safeParams.summarize !== false) {
|
|
1132
|
+
const maxContentLen = safeParams.maxContentLength || 1000; // Was 500
|
|
1133
|
+
const halfLen = Math.floor(maxContentLen / 2); // 500 each for user/claude
|
|
1134
|
+
// Helper to strip [CLAUDE] and [USER] prefixes
|
|
1135
|
+
const stripPrefix = (text) => {
|
|
1136
|
+
return text.replace(/^\[CLAUDE\]\s*/i, '').replace(/^\[USER\]\s*/i, '').trim();
|
|
1137
|
+
};
|
|
1138
|
+
// Helper to check if content is tool usage noise
|
|
1139
|
+
// IMPROVED: Check for tool calls anywhere in content, not just start
|
|
1140
|
+
const isToolNoise = (text) => {
|
|
1141
|
+
if (!text)
|
|
1142
|
+
return false;
|
|
1143
|
+
// Tool call patterns to filter
|
|
1144
|
+
const toolPatterns = [
|
|
1145
|
+
/\[Tools?:\s*\w+\]/i,
|
|
1146
|
+
/\[(?:Bash|Read|Write|Edit|Grep|Glob|Task|WebFetch|WebSearch|NotebookEdit):/i,
|
|
1147
|
+
/^(?:Bash|Read|Write|Edit|Grep|Glob)\s*$/i, // Tool name only
|
|
1148
|
+
/^\s*\{[\s\S]*"tool":\s*"\w+"/ // JSON tool call format
|
|
1149
|
+
];
|
|
1150
|
+
return toolPatterns.some(p => p.test(text.slice(0, 200)));
|
|
1151
|
+
};
|
|
1152
|
+
// Helper to parse content that already contains both [USER] and [CLAUDE]
|
|
1153
|
+
const parseInlineConversation = (text) => {
|
|
1154
|
+
if (!text)
|
|
1155
|
+
return null;
|
|
1156
|
+
const userMatch = text.match(/\[USER\]\s*([^\[]*)/i);
|
|
1157
|
+
const claudeMatch = text.match(/\[CLAUDE\]\s*([\s\S]*?)(?:\[USER\]|$)/i);
|
|
1158
|
+
if (userMatch && claudeMatch && userMatch[1].trim() && claudeMatch[1].trim()) {
|
|
1159
|
+
return {
|
|
1160
|
+
user: userMatch[1].trim(),
|
|
1161
|
+
claude: claudeMatch[1].trim()
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
return null;
|
|
1165
|
+
};
|
|
1166
|
+
// Build conversation-style output
|
|
1167
|
+
const formattedResults = await Promise.all(results.map(async (r) => {
|
|
1168
|
+
// CRITICAL FIX: Ensure metadata is never null/undefined before accessing properties
|
|
1169
|
+
const metadata = r.memory.metadata ?? {};
|
|
1170
|
+
// SKIP tool noise memories entirely
|
|
1171
|
+
if (isToolNoise(r.memory.content)) {
|
|
1172
|
+
return null; // Will be filtered out
|
|
1173
|
+
}
|
|
1174
|
+
// FIRST: Check if content already has both [USER] and [CLAUDE] parts
|
|
1175
|
+
// If so, parse directly without paired lookup
|
|
1176
|
+
const inlineParsed = parseInlineConversation(r.memory.content || '');
|
|
1177
|
+
if (inlineParsed) {
|
|
1178
|
+
const userPart = inlineParsed.user.length > halfLen
|
|
1179
|
+
? inlineParsed.user.slice(0, halfLen) + '...'
|
|
1180
|
+
: inlineParsed.user;
|
|
1181
|
+
const claudePart = inlineParsed.claude.length > halfLen
|
|
1182
|
+
? inlineParsed.claude.slice(0, halfLen) + '...'
|
|
1183
|
+
: inlineParsed.claude;
|
|
1184
|
+
return {
|
|
1185
|
+
id: r.memory.id,
|
|
1186
|
+
user: userPart,
|
|
1187
|
+
claude: claudePart,
|
|
1188
|
+
relevance: Math.round(r.similarity * 100) + '%'
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
// Extract role with multiple fallback strategies
|
|
1192
|
+
const role = metadata.role
|
|
1193
|
+
|| (r.memory.tags?.includes('role:user') ? 'user' : null)
|
|
1194
|
+
|| (r.memory.tags?.includes('role:assistant') ? 'assistant' : null)
|
|
1195
|
+
// Content-based role detection as fallback
|
|
1196
|
+
|| (r.memory.content?.startsWith('[CLAUDE]') ? 'assistant' : null)
|
|
1197
|
+
|| (r.memory.content?.startsWith('[USER]') ? 'user' : null)
|
|
1198
|
+
|| undefined;
|
|
1199
|
+
// CRITICAL FIX: Check both camelCase and snake_case for sessionId
|
|
1200
|
+
// Also check tags for session info as ultimate fallback
|
|
1201
|
+
let sessionId = metadata.sessionId || metadata.session_id;
|
|
1202
|
+
// Fallback: Check tags for session info (format: "session:xxx")
|
|
1203
|
+
if (!sessionId && r.memory.tags) {
|
|
1204
|
+
const sessionTag = r.memory.tags.find((tag) => tag.startsWith('session:'));
|
|
1205
|
+
if (sessionTag) {
|
|
1206
|
+
sessionId = sessionTag.replace('session:', '');
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
// DEBUG: Log session extraction with all checked sources
|
|
1210
|
+
logger.debug({
|
|
1211
|
+
memoryId: r.memory.id,
|
|
1212
|
+
sessionId,
|
|
1213
|
+
sessionIdSource: metadata.sessionId ? 'metadata.sessionId'
|
|
1214
|
+
: metadata.session_id ? 'metadata.session_id'
|
|
1215
|
+
: sessionId ? 'tags' : 'none',
|
|
1216
|
+
role,
|
|
1217
|
+
timestamp: metadata.timestamp,
|
|
1218
|
+
hasMetadata: !!r.memory.metadata
|
|
1219
|
+
}, '[PAIRING] Session extraction for memory');
|
|
1220
|
+
let content = stripPrefix(r.memory.content || '');
|
|
1221
|
+
// Trim content to half length
|
|
1222
|
+
if (content.length > halfLen) {
|
|
1223
|
+
content = content.slice(0, halfLen) + '...';
|
|
1224
|
+
}
|
|
1225
|
+
// DYNAMIC PAIRED MESSAGE LOOKUP
|
|
1226
|
+
// Try multiple strategies to find the paired user/claude message
|
|
1227
|
+
let pairedContent;
|
|
1228
|
+
const memoryTimestamp = metadata.timestamp || r.memory.createdAt?.toISOString();
|
|
1229
|
+
const pairedRole = role === 'assistant' ? 'user' : 'assistant';
|
|
1230
|
+
// CROSS-PROJECT FIX: Use memory's own project_path for paired lookup
|
|
1231
|
+
// This ensures paired messages are found from the same project as the result
|
|
1232
|
+
const projectPath = metadata.project_path || getProjectContext().getProjectPath();
|
|
1233
|
+
try {
|
|
1234
|
+
let pairedQuery;
|
|
1235
|
+
// Track if we found a session-scoped result (prevents cross-session fallback)
|
|
1236
|
+
let foundInSession = false;
|
|
1237
|
+
// Strategy 1: Same session (if sessionId exists)
|
|
1238
|
+
// IMPORTANT: Use metadata->>'timestamp' (original time) NOT created_at (bulk import time)
|
|
1239
|
+
// EXCLUDE tool calls - they're not useful context
|
|
1240
|
+
// CRITICAL FIX: If sessionId exists, we MUST only return pairs from the SAME session
|
|
1241
|
+
// Do NOT fall through to cross-session strategies when sessionId is present
|
|
1242
|
+
// FIX: Check both camelCase 'sessionId' and snake_case 'session_id' in SQL
|
|
1243
|
+
if (sessionId && memoryTimestamp) {
|
|
1244
|
+
if (role === 'assistant') {
|
|
1245
|
+
// response -> find user prompt BEFORE it
|
|
1246
|
+
pairedQuery = await this.db.query(`
|
|
1247
|
+
SELECT content FROM memories
|
|
1248
|
+
WHERE COALESCE(metadata->>'sessionId', metadata->>'session_id') = $1
|
|
1249
|
+
AND (metadata->>'role' = 'user' OR 'role:user' = ANY(tags))
|
|
1250
|
+
AND COALESCE(metadata->>'timestamp', created_at::text)::timestamptz < $2::timestamptz
|
|
1251
|
+
AND content NOT LIKE '%[Tools:%'
|
|
1252
|
+
ORDER BY COALESCE(metadata->>'timestamp', created_at::text)::timestamptz DESC
|
|
1253
|
+
LIMIT 1
|
|
1254
|
+
`, [sessionId, memoryTimestamp]);
|
|
1255
|
+
}
|
|
1256
|
+
else {
|
|
1257
|
+
// User prompt -> find response AFTER it (skip tool calls!)
|
|
1258
|
+
pairedQuery = await this.db.query(`
|
|
1259
|
+
SELECT content FROM memories
|
|
1260
|
+
WHERE COALESCE(metadata->>'sessionId', metadata->>'session_id') = $1
|
|
1261
|
+
AND (metadata->>'role' = 'assistant' OR 'role:assistant' = ANY(tags))
|
|
1262
|
+
AND COALESCE(metadata->>'timestamp', created_at::text)::timestamptz > $2::timestamptz
|
|
1263
|
+
AND content NOT LIKE '%[Tools:%'
|
|
1264
|
+
ORDER BY COALESCE(metadata->>'timestamp', created_at::text)::timestamptz ASC
|
|
1265
|
+
LIMIT 1
|
|
1266
|
+
`, [sessionId, memoryTimestamp]);
|
|
1267
|
+
}
|
|
1268
|
+
// SIMPLIFIED PAIRING LOGIC (3 strategies max)
|
|
1269
|
+
// Pattern: user types → prompt saved → claude responds → response saved AFTER
|
|
1270
|
+
// So for user prompts: look for NEXT assistant message
|
|
1271
|
+
// For assistant responses: look for PREVIOUS user message
|
|
1272
|
+
if (pairedQuery && pairedQuery.rows.length > 0) {
|
|
1273
|
+
foundInSession = true;
|
|
1274
|
+
}
|
|
1275
|
+
else {
|
|
1276
|
+
// Strategy 1: Same session - find adjacent message with opposite role
|
|
1277
|
+
// User prompt → next assistant response in session
|
|
1278
|
+
// Assistant response → previous user prompt in session
|
|
1279
|
+
if (role === 'user') {
|
|
1280
|
+
// Find NEXT assistant message in this session ('s response to this prompt)
|
|
1281
|
+
pairedQuery = await this.db.query(`
|
|
1282
|
+
SELECT content FROM memories
|
|
1283
|
+
WHERE COALESCE(metadata->>'sessionId', metadata->>'session_id') = $1
|
|
1284
|
+
AND (metadata->>'role' = 'assistant' OR 'role:assistant' = ANY(tags))
|
|
1285
|
+
AND COALESCE(metadata->>'timestamp', created_at::text)::timestamptz > $2::timestamptz
|
|
1286
|
+
AND content NOT LIKE '%[Tools:%'
|
|
1287
|
+
ORDER BY COALESCE(metadata->>'timestamp', created_at::text)::timestamptz ASC
|
|
1288
|
+
LIMIT 1
|
|
1289
|
+
`, [sessionId, memoryTimestamp]);
|
|
1290
|
+
}
|
|
1291
|
+
else {
|
|
1292
|
+
// Find PREVIOUS user message in this session (the prompt responded to)
|
|
1293
|
+
pairedQuery = await this.db.query(`
|
|
1294
|
+
SELECT content FROM memories
|
|
1295
|
+
WHERE COALESCE(metadata->>'sessionId', metadata->>'session_id') = $1
|
|
1296
|
+
AND (metadata->>'role' = 'user' OR 'role:user' = ANY(tags))
|
|
1297
|
+
AND COALESCE(metadata->>'timestamp', created_at::text)::timestamptz < $2::timestamptz
|
|
1298
|
+
AND content NOT LIKE '%[Tools:%'
|
|
1299
|
+
ORDER BY COALESCE(metadata->>'timestamp', created_at::text)::timestamptz DESC
|
|
1300
|
+
LIMIT 1
|
|
1301
|
+
`, [sessionId, memoryTimestamp]);
|
|
1302
|
+
}
|
|
1303
|
+
if (pairedQuery && pairedQuery.rows.length > 0) {
|
|
1304
|
+
foundInSession = true;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
// ============================================================================
|
|
1309
|
+
// NO-SESSION FALLBACK (Strategies 2-3) - ONLY when NO sessionId exists
|
|
1310
|
+
// ============================================================================
|
|
1311
|
+
else if (memoryTimestamp) {
|
|
1312
|
+
// Strategy 2: Same project - find adjacent message by timestamp
|
|
1313
|
+
// Simple: user → next assistant, assistant → previous user
|
|
1314
|
+
if (!pairedQuery || pairedQuery.rows.length === 0) {
|
|
1315
|
+
if (role === 'user') {
|
|
1316
|
+
// Find NEXT assistant message in project
|
|
1317
|
+
pairedQuery = await this.db.query(`
|
|
1318
|
+
SELECT content FROM memories
|
|
1319
|
+
WHERE (metadata->>'role' = 'assistant' OR 'role:assistant' = ANY(tags))
|
|
1320
|
+
AND metadata->>'project_path' = $1
|
|
1321
|
+
AND COALESCE(metadata->>'timestamp', created_at::text)::timestamptz > $2::timestamptz
|
|
1322
|
+
AND content NOT LIKE '%[Tools:%'
|
|
1323
|
+
ORDER BY COALESCE(metadata->>'timestamp', created_at::text)::timestamptz ASC
|
|
1324
|
+
LIMIT 1
|
|
1325
|
+
`, [projectPath, memoryTimestamp]);
|
|
1326
|
+
}
|
|
1327
|
+
else {
|
|
1328
|
+
// Find PREVIOUS user message in project
|
|
1329
|
+
pairedQuery = await this.db.query(`
|
|
1330
|
+
SELECT content FROM memories
|
|
1331
|
+
WHERE (metadata->>'role' = 'user' OR 'role:user' = ANY(tags))
|
|
1332
|
+
AND metadata->>'project_path' = $1
|
|
1333
|
+
AND COALESCE(metadata->>'timestamp', created_at::text)::timestamptz < $2::timestamptz
|
|
1334
|
+
AND content NOT LIKE '%[Tools:%'
|
|
1335
|
+
ORDER BY COALESCE(metadata->>'timestamp', created_at::text)::timestamptz DESC
|
|
1336
|
+
LIMIT 1
|
|
1337
|
+
`, [projectPath, memoryTimestamp]);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
// Strategy 3: ULTIMATE FALLBACK - closest opposite role in project by timestamp
|
|
1341
|
+
// Only if strategy 2 found nothing
|
|
1342
|
+
if (!pairedQuery || pairedQuery.rows.length === 0) {
|
|
1343
|
+
pairedQuery = await this.db.query(`
|
|
1344
|
+
SELECT content FROM memories
|
|
1345
|
+
WHERE (metadata->>'role' = $1 OR $2 = ANY(tags))
|
|
1346
|
+
AND metadata->>'project_path' = $3
|
|
1347
|
+
AND id != $5
|
|
1348
|
+
AND content NOT LIKE '%[Tools:%'
|
|
1349
|
+
ORDER BY ABS(EXTRACT(EPOCH FROM (
|
|
1350
|
+
COALESCE(metadata->>'timestamp', created_at::text)::timestamptz - $4::timestamptz
|
|
1351
|
+
)))
|
|
1352
|
+
LIMIT 1
|
|
1353
|
+
`, [pairedRole, `role:${pairedRole}`, projectPath, memoryTimestamp, r.memory.id]);
|
|
1354
|
+
}
|
|
1355
|
+
} // end no-session fallback block
|
|
1356
|
+
if (pairedQuery && pairedQuery.rows.length > 0) {
|
|
1357
|
+
pairedContent = stripPrefix(pairedQuery.rows[0].content);
|
|
1358
|
+
logger.debug({
|
|
1359
|
+
memoryId: r.memory.id,
|
|
1360
|
+
sessionId,
|
|
1361
|
+
pairedContentPreview: pairedContent.slice(0, 50),
|
|
1362
|
+
pairedRole: role === 'assistant' ? 'user' : 'assistant'
|
|
1363
|
+
}, '[PAIRING] Found paired message');
|
|
1364
|
+
if (pairedContent.length > halfLen) {
|
|
1365
|
+
pairedContent = pairedContent.slice(0, halfLen) + '...';
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
else {
|
|
1369
|
+
logger.debug({
|
|
1370
|
+
memoryId: r.memory.id,
|
|
1371
|
+
sessionId,
|
|
1372
|
+
role,
|
|
1373
|
+
timestamp: metadata.timestamp
|
|
1374
|
+
}, '[PAIRING] No paired message found');
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
catch (e) {
|
|
1378
|
+
// Ignore - paired lookup is optional
|
|
1379
|
+
logger.debug({ error: e, sessionId }, 'Paired message lookup failed');
|
|
1380
|
+
}
|
|
1381
|
+
// ALWAYS show both user: and claude: fields
|
|
1382
|
+
// Format: { user: "what user said", claude: "what claude said", relevance: "X%" }
|
|
1383
|
+
if (role === 'assistant') {
|
|
1384
|
+
return {
|
|
1385
|
+
id: r.memory.id,
|
|
1386
|
+
user: pairedContent || '(no user prompt found)',
|
|
1387
|
+
claude: content,
|
|
1388
|
+
relevance: Math.round(r.similarity * 100) + '%'
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
else {
|
|
1392
|
+
// role === 'user' or undefined
|
|
1393
|
+
return {
|
|
1394
|
+
id: r.memory.id,
|
|
1395
|
+
user: content,
|
|
1396
|
+
claude: pairedContent || '', // Empty if no paired response found
|
|
1397
|
+
relevance: Math.round(r.similarity * 100) + '%'
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
})).then(results => results.filter((r) => r !== null));
|
|
1401
|
+
// Always use humanReadable format
|
|
1402
|
+
const humanReadableData = formattedResults.map(r => ({
|
|
1403
|
+
id: r.id,
|
|
1404
|
+
similarity: parseFloat(r.relevance) / 100,
|
|
1405
|
+
// Only include [CLAUDE] if there's actual content (length > 0)
|
|
1406
|
+
content: r.claude && r.claude.length > 0 ? `[USER] ${r.user}\n[CLAUDE] ${r.claude}` : `[USER] ${r.user}`,
|
|
1407
|
+
}));
|
|
1408
|
+
return formatHumanReadable('find_memory', humanReadableData, {
|
|
1409
|
+
grey: true,
|
|
1410
|
+
showSimilarity: true,
|
|
1411
|
+
maxContentLength: safeParams.maxContentLength || 500,
|
|
1412
|
+
query: safeParams.query
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
// FULL MODE: Enrich results with discoverable paths
|
|
1416
|
+
// Step 1: Enrich each result with discoverable paths
|
|
1417
|
+
const enrichedResults = results.map(enrichSearchResult);
|
|
1418
|
+
// Step 2: Aggregate all discoverable paths across results
|
|
1419
|
+
const aggregatedPaths = this.aggregateDiscoverablePaths(enrichedResults);
|
|
1420
|
+
// Step 3: Generate context enrichment summary (Chinese compacted)
|
|
1421
|
+
const contextEnrichment = this.generateContextEnrichment(safeParams.query, enrichedResults, aggregatedPaths, drilldown);
|
|
1422
|
+
// Step 4: Log enrichment for debugging
|
|
1423
|
+
logger.info({
|
|
1424
|
+
query: safeParams.query,
|
|
1425
|
+
filesFound: aggregatedPaths.filePaths.length,
|
|
1426
|
+
codeBlocksFound: aggregatedPaths.codeBlocks.length,
|
|
1427
|
+
urlsFound: aggregatedPaths.urls.length,
|
|
1428
|
+
techTermsFound: aggregatedPaths.technicalTerms.length,
|
|
1429
|
+
researchQuestionsFound: aggregatedPaths.researchQuestions.length
|
|
1430
|
+
}, '[ContextEnricher] 發現可探索路徑');
|
|
1431
|
+
// update access counts for returned memories (non-blocking)
|
|
1432
|
+
if (results.length > 0) {
|
|
1433
|
+
// Fire and forget - don't block on access count updates
|
|
1434
|
+
this.updateAccessCounts(results.map(r => r.memory.id)).catch(err => {
|
|
1435
|
+
logger.warn({ error: err }, 'failed to update access counts');
|
|
1436
|
+
});
|
|
1437
|
+
// Emit memory:retrieved event via LWJEB
|
|
1438
|
+
this.coordinator.emitMemoryRetrieved(results.map(r => r.memory.id), safeParams.query);
|
|
1439
|
+
// Record access for hot path tracking (non-blocking)
|
|
1440
|
+
// This helps build memory access patterns for prediction
|
|
1441
|
+
this.recordAccessPatterns(results.map(r => r.memory.id)).catch(err => {
|
|
1442
|
+
logger.debug({ error: err }, 'failed to record access patterns (non-critical)');
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
// Step 5: Generate user interaction prompt for CLI control
|
|
1446
|
+
const userInteractionPrompt = generateUserInteractionPrompt(results, safeParams.query, drilldown, aggregatedPaths);
|
|
1447
|
+
// Step 6: Format research spawn instructions if needed
|
|
1448
|
+
const researchSpawnInstructions = drilldown.needsResearch
|
|
1449
|
+
? this.generateResearchSpawnInstructions(safeParams.query, aggregatedPaths)
|
|
1450
|
+
: null;
|
|
1451
|
+
// ============================================================================
|
|
1452
|
+
// DEEP DEBUG: Method Exit (Success)
|
|
1453
|
+
// ============================================================================
|
|
1454
|
+
const finalDuration = Date.now() - startTime;
|
|
1455
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'METHOD_EXIT_SUCCESS', {
|
|
1456
|
+
finalDuration,
|
|
1457
|
+
enrichedResultCount: enrichedResults?.length,
|
|
1458
|
+
query: safeParams.query?.slice(0, 50)
|
|
1459
|
+
});
|
|
1460
|
+
// Broadcast COT result to dashboard
|
|
1461
|
+
cotResult('find_memory', `Found ${enrichedResults?.length || 0} memories`, enrichedResults?.length || 0);
|
|
1462
|
+
// Always use humanReadable format
|
|
1463
|
+
const humanReadableData = enrichedResults.map(r => ({
|
|
1464
|
+
id: r.memory.id,
|
|
1465
|
+
drilldownID: r.drilldownID,
|
|
1466
|
+
similarity: r.similarity,
|
|
1467
|
+
content: r.memory.content,
|
|
1468
|
+
tags: r.memory.tags,
|
|
1469
|
+
type: r.memory.memoryType,
|
|
1470
|
+
importance: r.memory.importance,
|
|
1471
|
+
createdAt: r.memory.createdAt
|
|
1472
|
+
}));
|
|
1473
|
+
return formatHumanReadable('find_memory', humanReadableData, {
|
|
1474
|
+
grey: true,
|
|
1475
|
+
showSimilarity: true,
|
|
1476
|
+
showTags: true,
|
|
1477
|
+
maxContentLength: safeParams.maxContentLength || 300,
|
|
1478
|
+
query: safeParams.query // Pass query for header display
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
catch (error) {
|
|
1482
|
+
const duration = Date.now() - startTime;
|
|
1483
|
+
// Broadcast COT error to dashboard
|
|
1484
|
+
cotError('find_memory', error?.message?.slice(0, 100) || 'Unknown error');
|
|
1485
|
+
// ============================================================================
|
|
1486
|
+
// DEEP DEBUG: Method Exit (Error)
|
|
1487
|
+
// ============================================================================
|
|
1488
|
+
__debugLog('[FIND_MEMORY DEBUG]', Date.now(), 'METHOD_EXIT_ERROR', {
|
|
1489
|
+
duration,
|
|
1490
|
+
errorMessage: error?.message?.slice(0, 200),
|
|
1491
|
+
errorCode: error?.code,
|
|
1492
|
+
errorName: error?.name,
|
|
1493
|
+
query: params.query?.slice(0, 50)
|
|
1494
|
+
});
|
|
1495
|
+
// Get socket path for error context (may fail if error occurred before socketPath was set)
|
|
1496
|
+
let errorSocketPath = 'unknown';
|
|
1497
|
+
try {
|
|
1498
|
+
errorSocketPath = getEmbeddingSocketPath();
|
|
1499
|
+
}
|
|
1500
|
+
catch {
|
|
1501
|
+
// Ignore - socket path detection may have failed
|
|
1502
|
+
}
|
|
1503
|
+
// Extract error details for comprehensive logging
|
|
1504
|
+
const err = error;
|
|
1505
|
+
// Enhanced error logging with all context
|
|
1506
|
+
logger.error({
|
|
1507
|
+
error: {
|
|
1508
|
+
message: err.message,
|
|
1509
|
+
code: err.code,
|
|
1510
|
+
stack: err.stack?.slice(0, 1000),
|
|
1511
|
+
socketPath: err.socketPath || errorSocketPath,
|
|
1512
|
+
durationMs: err.durationMs
|
|
1513
|
+
},
|
|
1514
|
+
query: params.query?.slice(0, 100),
|
|
1515
|
+
duration,
|
|
1516
|
+
socketPath: errorSocketPath,
|
|
1517
|
+
debug: process.env['SPECMEM_DEBUG'] === 'true'
|
|
1518
|
+
}, 'search failed - see error details for troubleshooting');
|
|
1519
|
+
// Debug log the error with full context
|
|
1520
|
+
this.debugLogger.searchOperation(params.query || '', 'error', {
|
|
1521
|
+
durationMs: duration,
|
|
1522
|
+
error: err,
|
|
1523
|
+
socketPath: errorSocketPath
|
|
1524
|
+
});
|
|
1525
|
+
// Build comprehensive error message for MCP response
|
|
1526
|
+
const errorCode = err.code || 'UNKNOWN_ERROR';
|
|
1527
|
+
let userMessage;
|
|
1528
|
+
switch (errorCode) {
|
|
1529
|
+
case 'EMBEDDING_TIMEOUT':
|
|
1530
|
+
userMessage = `Embedding service timeout (${duration}ms). ` +
|
|
1531
|
+
`Socket: ${err.socketPath || errorSocketPath}. ` +
|
|
1532
|
+
`Check: 1) Is embedding service running? (ps aux | grep frankenstein) ` +
|
|
1533
|
+
`2) Socket exists? (ls -la ${err.socketPath || errorSocketPath}) ` +
|
|
1534
|
+
`3) Service healthy? (check logs in /tmp/specmem-*/embedding.log)`;
|
|
1535
|
+
break;
|
|
1536
|
+
case 'SEARCH_TIMEOUT':
|
|
1537
|
+
userMessage = `Database search timeout (${duration}ms). ` +
|
|
1538
|
+
`Check: 1) Database connection (pg_isready) ` +
|
|
1539
|
+
`2) Query complexity - try simpler terms ` +
|
|
1540
|
+
`3) Database load (check pg_stat_activity)`;
|
|
1541
|
+
break;
|
|
1542
|
+
case 'EMBEDDING_ERROR':
|
|
1543
|
+
userMessage = `Embedding generation failed: ${err.message}. ` +
|
|
1544
|
+
`Socket: ${err.socketPath || errorSocketPath}. ` +
|
|
1545
|
+
`This could be: socket not found, service not running, or input too long.`;
|
|
1546
|
+
break;
|
|
1547
|
+
case 'SEARCH_ERROR':
|
|
1548
|
+
userMessage = `Search query failed: ${err.message}. ` +
|
|
1549
|
+
`Check database connection and query syntax.`;
|
|
1550
|
+
break;
|
|
1551
|
+
default:
|
|
1552
|
+
userMessage = `find_memory error: ${err.message}. ` +
|
|
1553
|
+
`Socket: ${errorSocketPath}. ` +
|
|
1554
|
+
`Duration: ${duration}ms. ` +
|
|
1555
|
+
`Enable SPECMEM_DEBUG=true for detailed logs.`;
|
|
1556
|
+
}
|
|
1557
|
+
// Create error that will be properly serialized in MCP response
|
|
1558
|
+
const mcpError = new Error(userMessage);
|
|
1559
|
+
mcpError.code = errorCode;
|
|
1560
|
+
mcpError.socketPath = err.socketPath || errorSocketPath;
|
|
1561
|
+
mcpError.durationMs = duration;
|
|
1562
|
+
mcpError.query = params.query?.slice(0, 50);
|
|
1563
|
+
mcpError.troubleshooting = {
|
|
1564
|
+
enableDebug: 'Set SPECMEM_DEBUG=true for detailed logs',
|
|
1565
|
+
checkSocket: `ls -la ${err.socketPath || errorSocketPath}`,
|
|
1566
|
+
checkService: 'ps aux | grep frankenstein',
|
|
1567
|
+
checkLogs: 'tail -f /tmp/specmem-*/mcp-startup.log'
|
|
1568
|
+
};
|
|
1569
|
+
throw mcpError;
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* semanticSearch - the main search logic
|
|
1574
|
+
*
|
|
1575
|
+
* uses pgvector for cosine similarity search
|
|
1576
|
+
* applies filters for type, tags, importance, dates
|
|
1577
|
+
*/
|
|
1578
|
+
async semanticSearch(params, queryEmbedding) {
|
|
1579
|
+
// build the query dynamically based on filters
|
|
1580
|
+
const conditions = ['embedding IS NOT NULL'];
|
|
1581
|
+
const queryParams = [];
|
|
1582
|
+
let paramIndex = 1;
|
|
1583
|
+
// IMPORTANT: Embedding MUST be $1 for the vector similarity query
|
|
1584
|
+
// Add embedding first as $1
|
|
1585
|
+
queryParams.push(`[${queryEmbedding.join(',')}]`);
|
|
1586
|
+
paramIndex++;
|
|
1587
|
+
// PROJECT NAMESPACING: Filter by current project (now $2)
|
|
1588
|
+
const projectFilter = buildProjectWhereClause(paramIndex);
|
|
1589
|
+
conditions.push(projectFilter.sql);
|
|
1590
|
+
queryParams.push(projectFilter.param);
|
|
1591
|
+
paramIndex = projectFilter.nextIndex;
|
|
1592
|
+
// expired filter
|
|
1593
|
+
if (!params.includeExpired) {
|
|
1594
|
+
conditions.push('(expires_at IS NULL OR expires_at > NOW())');
|
|
1595
|
+
}
|
|
1596
|
+
// memory type filter
|
|
1597
|
+
if (params.memoryTypes?.length) {
|
|
1598
|
+
conditions.push(`memory_type = ANY($${paramIndex}::memory_type[])`);
|
|
1599
|
+
queryParams.push(params.memoryTypes);
|
|
1600
|
+
paramIndex++;
|
|
1601
|
+
}
|
|
1602
|
+
// tags filter (OR logic)
|
|
1603
|
+
if (params.tags?.length) {
|
|
1604
|
+
conditions.push(`tags && $${paramIndex}::text[]`);
|
|
1605
|
+
queryParams.push(params.tags);
|
|
1606
|
+
paramIndex++;
|
|
1607
|
+
}
|
|
1608
|
+
// importance filter
|
|
1609
|
+
if (params.importance?.length) {
|
|
1610
|
+
conditions.push(`importance = ANY($${paramIndex}::importance_level[])`);
|
|
1611
|
+
queryParams.push(params.importance);
|
|
1612
|
+
paramIndex++;
|
|
1613
|
+
}
|
|
1614
|
+
// date range filter
|
|
1615
|
+
if (params.dateRange?.start) {
|
|
1616
|
+
conditions.push(`created_at >= $${paramIndex}::timestamptz`);
|
|
1617
|
+
queryParams.push(params.dateRange.start);
|
|
1618
|
+
paramIndex++;
|
|
1619
|
+
}
|
|
1620
|
+
if (params.dateRange?.end) {
|
|
1621
|
+
conditions.push(`created_at <= $${paramIndex}::timestamptz`);
|
|
1622
|
+
queryParams.push(params.dateRange.end);
|
|
1623
|
+
paramIndex++;
|
|
1624
|
+
}
|
|
1625
|
+
// NEW: Role filter - uses metadata->>'role' or tags
|
|
1626
|
+
if (params.role) {
|
|
1627
|
+
// Filter by role:user or role:assistant tag (more efficient with index)
|
|
1628
|
+
conditions.push(`$${paramIndex}::text = ANY(tags)`);
|
|
1629
|
+
queryParams.push(`role:${params.role}`);
|
|
1630
|
+
paramIndex++;
|
|
1631
|
+
}
|
|
1632
|
+
// ============================================================================
|
|
1633
|
+
// NOISE FILTERS: Exclude system-generated content dynamically via tags
|
|
1634
|
+
// ============================================================================
|
|
1635
|
+
// These tags are set at ingestion time by sessionParser/sessionWatcher:
|
|
1636
|
+
// - 'context-restoration' = raw context restoration summaries (not real user prompts)
|
|
1637
|
+
// - 'agent-deployment' = agent/team member deployment prompts
|
|
1638
|
+
// - 'consolidation-task' = code consolidation task prompts
|
|
1639
|
+
// Exclude these by default to avoid polluting find_memory results
|
|
1640
|
+
const noiseTags = ['context-restoration', 'agent-deployment', 'consolidation-task'];
|
|
1641
|
+
conditions.push(`NOT (tags && $${paramIndex}::text[])`);
|
|
1642
|
+
queryParams.push(noiseTags);
|
|
1643
|
+
paramIndex++;
|
|
1644
|
+
// threshold and limit - now parameterized for query plan caching
|
|
1645
|
+
// NOTE: Default 0.35 filters out noise while catching real matches
|
|
1646
|
+
// Local embeddings typically produce 0.2-0.5 similarity for relevant content
|
|
1647
|
+
const threshold = params.threshold ?? 0.35;
|
|
1648
|
+
const limit = params.limit ?? 10;
|
|
1649
|
+
// Add threshold and limit as parameters
|
|
1650
|
+
queryParams.push(threshold);
|
|
1651
|
+
const thresholdParam = paramIndex++;
|
|
1652
|
+
queryParams.push(limit);
|
|
1653
|
+
const limitParam = paramIndex;
|
|
1654
|
+
// the query - cosine similarity with pgvector
|
|
1655
|
+
// 1 - cosine_distance gives us similarity score
|
|
1656
|
+
// NOW FULLY PARAMETERIZED for better query plan caching
|
|
1657
|
+
const query = `
|
|
1658
|
+
SELECT
|
|
1659
|
+
id, content, memory_type, importance, tags, metadata,
|
|
1660
|
+
embedding, created_at, updated_at, access_count, last_accessed_at,
|
|
1661
|
+
1 - (embedding <=> $1::vector) AS similarity
|
|
1662
|
+
FROM memories
|
|
1663
|
+
WHERE ${conditions.join(' AND ')}
|
|
1664
|
+
AND 1 - (embedding <=> $1::vector) >= $${thresholdParam}
|
|
1665
|
+
ORDER BY similarity DESC
|
|
1666
|
+
LIMIT $${limitParam}
|
|
1667
|
+
`;
|
|
1668
|
+
// DEBUG: Log the first param (embedding) length before query
|
|
1669
|
+
const embeddingParamStr = queryParams[0];
|
|
1670
|
+
const embeddingParamLen = embeddingParamStr?.match(/,/g)?.length || 0;
|
|
1671
|
+
logger.info({
|
|
1672
|
+
embeddingParamLength: embeddingParamLen + 1,
|
|
1673
|
+
embeddingPreview: embeddingParamStr?.substring(0, 50),
|
|
1674
|
+
paramCount: queryParams.length
|
|
1675
|
+
}, 'About to execute semantic search query');
|
|
1676
|
+
const queryStart = Date.now();
|
|
1677
|
+
const result = await this.db.query(query, queryParams);
|
|
1678
|
+
const queryDuration = Date.now() - queryStart;
|
|
1679
|
+
// Enhanced logging with similarity score distribution for debugging relevance issues
|
|
1680
|
+
const similarityScores = result.rows.map((r) => r.similarity);
|
|
1681
|
+
const sortedScores = [...similarityScores].sort((a, b) => b - a);
|
|
1682
|
+
logger.info({
|
|
1683
|
+
queryDuration,
|
|
1684
|
+
resultCount: result.rows.length,
|
|
1685
|
+
threshold,
|
|
1686
|
+
limit,
|
|
1687
|
+
// Similarity distribution - CRITICAL for debugging relevance issues
|
|
1688
|
+
topSimilarity: sortedScores[0] || 0,
|
|
1689
|
+
minSimilarity: sortedScores[sortedScores.length - 1] || 0,
|
|
1690
|
+
avgSimilarity: similarityScores.length > 0
|
|
1691
|
+
? Math.round(similarityScores.reduce((a, b) => a + b, 0) / similarityScores.length * 1000) / 1000
|
|
1692
|
+
: 0,
|
|
1693
|
+
// Show distribution buckets
|
|
1694
|
+
above50pct: similarityScores.filter((s) => s >= 0.5).length,
|
|
1695
|
+
above30pct: similarityScores.filter((s) => s >= 0.3).length,
|
|
1696
|
+
above25pct: similarityScores.filter((s) => s >= 0.25).length,
|
|
1697
|
+
// Show top 3 scores for debugging
|
|
1698
|
+
top3Scores: sortedScores.slice(0, 3).map(s => Math.round(s * 1000) / 1000)
|
|
1699
|
+
}, '[RELEVANCE] Semantic search similarity distribution');
|
|
1700
|
+
// Apply Chinese Compactor approach: pass summarize/maxContentLength options
|
|
1701
|
+
const compactionOpts = {
|
|
1702
|
+
summarize: params.summarize,
|
|
1703
|
+
maxContentLength: params.maxContentLength
|
|
1704
|
+
};
|
|
1705
|
+
return result.rows.map((row) => this.rowToSearchResult(row, compactionOpts));
|
|
1706
|
+
}
|
|
1707
|
+
// ============================================================================
|
|
1708
|
+
// I5 FIX: NEW METHODS FOR RECENT MEMORIES, RECENCY BOOST, KEYWORD FALLBACK
|
|
1709
|
+
// ============================================================================
|
|
1710
|
+
/**
|
|
1711
|
+
* I5 FIX: Get recent memories regardless of similarity
|
|
1712
|
+
* This ensures we can always find recent prompts even if embeddings aren't ready
|
|
1713
|
+
*/
|
|
1714
|
+
async getRecentMemories(count, params) {
|
|
1715
|
+
if (count <= 0)
|
|
1716
|
+
return [];
|
|
1717
|
+
logger.info({ count, allProjects: params.allProjects, projectPath: params.projectPath }, '[I5 FIX] Fetching recent memories for includeRecent');
|
|
1718
|
+
// Use helper for project filtering (supports cross-project search)
|
|
1719
|
+
const projectFilter = this.buildProjectCondition(params, 1);
|
|
1720
|
+
const conditions = [...projectFilter.conditions];
|
|
1721
|
+
const queryParams = [...projectFilter.queryParams];
|
|
1722
|
+
let paramIndex = projectFilter.nextIndex;
|
|
1723
|
+
// Apply same filters as main search (except threshold/embedding)
|
|
1724
|
+
if (!params.includeExpired) {
|
|
1725
|
+
conditions.push('(expires_at IS NULL OR expires_at > NOW())');
|
|
1726
|
+
}
|
|
1727
|
+
if (params.memoryTypes?.length) {
|
|
1728
|
+
conditions.push(`memory_type = ANY($${paramIndex}::memory_type[])`);
|
|
1729
|
+
queryParams.push(params.memoryTypes);
|
|
1730
|
+
paramIndex++;
|
|
1731
|
+
}
|
|
1732
|
+
if (params.role) {
|
|
1733
|
+
conditions.push(`$${paramIndex}::text = ANY(tags)`);
|
|
1734
|
+
queryParams.push(`role:${params.role}`);
|
|
1735
|
+
paramIndex++;
|
|
1736
|
+
}
|
|
1737
|
+
// Exclude noise tags (same as main search)
|
|
1738
|
+
const noiseTags = ['context-restoration', 'agent-deployment', 'consolidation-task'];
|
|
1739
|
+
conditions.push(`NOT (tags && $${paramIndex}::text[])`);
|
|
1740
|
+
queryParams.push(noiseTags);
|
|
1741
|
+
paramIndex++;
|
|
1742
|
+
queryParams.push(count);
|
|
1743
|
+
const limitParam = paramIndex;
|
|
1744
|
+
// MED-38 FIX: Mark fallback results clearly - similarity is not from semantic search
|
|
1745
|
+
const query = `
|
|
1746
|
+
SELECT
|
|
1747
|
+
id, content, memory_type, importance, tags, metadata,
|
|
1748
|
+
embedding, created_at, updated_at, access_count, last_accessed_at,
|
|
1749
|
+
0.5 AS similarity, -- Fixed similarity for recent memories (not semantic)
|
|
1750
|
+
true AS is_fallback -- MED-38: Flag to indicate this is a fallback result
|
|
1751
|
+
FROM memories
|
|
1752
|
+
WHERE ${conditions.join(' AND ')}
|
|
1753
|
+
ORDER BY created_at DESC
|
|
1754
|
+
LIMIT $${limitParam}
|
|
1755
|
+
`;
|
|
1756
|
+
try {
|
|
1757
|
+
const result = await this.db.query(query, queryParams);
|
|
1758
|
+
logger.info({
|
|
1759
|
+
recentFound: result.rows.length,
|
|
1760
|
+
newestTimestamp: result.rows[0]?.created_at
|
|
1761
|
+
}, '[I5 FIX] Recent memories retrieved');
|
|
1762
|
+
const compactionOpts = {
|
|
1763
|
+
summarize: params.summarize,
|
|
1764
|
+
maxContentLength: params.maxContentLength
|
|
1765
|
+
};
|
|
1766
|
+
return result.rows.map((row) => this.rowToSearchResult(row, compactionOpts));
|
|
1767
|
+
}
|
|
1768
|
+
catch (error) {
|
|
1769
|
+
logger.error({ error }, '[I5 FIX] Failed to get recent memories');
|
|
1770
|
+
return [];
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* I5 FIX: Apply recency boost to search results
|
|
1775
|
+
* Memories from last hour: +20% similarity
|
|
1776
|
+
* Memories from last day: +10% similarity
|
|
1777
|
+
* This ensures recent discussions rank higher
|
|
1778
|
+
*/
|
|
1779
|
+
applyRecencyBoost(results) {
|
|
1780
|
+
const now = Date.now();
|
|
1781
|
+
const oneHour = 60 * 60 * 1000;
|
|
1782
|
+
const oneDay = 24 * oneHour;
|
|
1783
|
+
return results.map(result => {
|
|
1784
|
+
const createdAt = result.memory.createdAt?.getTime() || 0;
|
|
1785
|
+
const age = now - createdAt;
|
|
1786
|
+
let boostFactor = 1.0;
|
|
1787
|
+
if (age < oneHour) {
|
|
1788
|
+
boostFactor = 1.20; // 20% boost for last hour
|
|
1789
|
+
}
|
|
1790
|
+
else if (age < oneDay) {
|
|
1791
|
+
boostFactor = 1.10; // 10% boost for last day
|
|
1792
|
+
}
|
|
1793
|
+
if (boostFactor > 1.0) {
|
|
1794
|
+
logger.debug({
|
|
1795
|
+
memoryId: result.memory.id,
|
|
1796
|
+
originalSimilarity: result.similarity,
|
|
1797
|
+
boostFactor,
|
|
1798
|
+
newSimilarity: Math.min(1.0, result.similarity * boostFactor),
|
|
1799
|
+
ageMinutes: Math.round(age / 60000)
|
|
1800
|
+
}, '[I5 FIX] Applied recency boost');
|
|
1801
|
+
}
|
|
1802
|
+
return {
|
|
1803
|
+
...result,
|
|
1804
|
+
similarity: Math.min(1.0, result.similarity * boostFactor)
|
|
1805
|
+
};
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* I5 FIX: Keyword fallback search using ILIKE
|
|
1810
|
+
* When embeddings return nothing, do text-based search
|
|
1811
|
+
*/
|
|
1812
|
+
async keywordSearch(query, params) {
|
|
1813
|
+
logger.info({ query, allProjects: params.allProjects, projectPath: params.projectPath }, '[I5 FIX] Performing keyword fallback search');
|
|
1814
|
+
const limit = params.limit ?? 10;
|
|
1815
|
+
// Extract keywords from query (split on spaces, filter short words)
|
|
1816
|
+
const keywords = query.toLowerCase()
|
|
1817
|
+
.split(/\s+/)
|
|
1818
|
+
.filter(w => w.length >= 3)
|
|
1819
|
+
.slice(0, 5); // Max 5 keywords
|
|
1820
|
+
if (keywords.length === 0) {
|
|
1821
|
+
logger.warn({ query }, '[I5 FIX] No usable keywords for fallback search');
|
|
1822
|
+
return [];
|
|
1823
|
+
}
|
|
1824
|
+
// Use helper for project filtering (supports cross-project search)
|
|
1825
|
+
const projectFilter = this.buildProjectCondition(params, 1);
|
|
1826
|
+
const conditions = [...projectFilter.conditions];
|
|
1827
|
+
const queryParams = [...projectFilter.queryParams];
|
|
1828
|
+
let paramIndex = projectFilter.nextIndex;
|
|
1829
|
+
// Add keyword conditions (OR logic - any keyword matches)
|
|
1830
|
+
const keywordConditions = keywords.map((_, idx) => {
|
|
1831
|
+
queryParams.push(`%${keywords[idx]}%`);
|
|
1832
|
+
return `content ILIKE $${paramIndex + idx}`;
|
|
1833
|
+
});
|
|
1834
|
+
conditions.push(`(${keywordConditions.join(' OR ')})`);
|
|
1835
|
+
paramIndex += keywords.length;
|
|
1836
|
+
if (!params.includeExpired) {
|
|
1837
|
+
conditions.push('(expires_at IS NULL OR expires_at > NOW())');
|
|
1838
|
+
}
|
|
1839
|
+
if (params.role) {
|
|
1840
|
+
conditions.push(`$${paramIndex}::text = ANY(tags)`);
|
|
1841
|
+
queryParams.push(`role:${params.role}`);
|
|
1842
|
+
paramIndex++;
|
|
1843
|
+
}
|
|
1844
|
+
// Exclude noise tags (same as main search)
|
|
1845
|
+
const noiseTags = ['context-restoration', 'agent-deployment', 'consolidation-task'];
|
|
1846
|
+
conditions.push(`NOT (tags && $${paramIndex}::text[])`);
|
|
1847
|
+
queryParams.push(noiseTags);
|
|
1848
|
+
paramIndex++;
|
|
1849
|
+
queryParams.push(limit);
|
|
1850
|
+
const limitParam = paramIndex;
|
|
1851
|
+
// MED-38 FIX: Mark fallback results clearly - similarity is not from semantic search
|
|
1852
|
+
const searchQuery = `
|
|
1853
|
+
SELECT
|
|
1854
|
+
id, content, memory_type, importance, tags, metadata,
|
|
1855
|
+
embedding, created_at, updated_at, access_count, last_accessed_at,
|
|
1856
|
+
0.3 AS similarity, -- Fixed similarity for keyword matches (not semantic)
|
|
1857
|
+
true AS is_fallback -- MED-38: Flag to indicate this is a fallback result
|
|
1858
|
+
FROM memories
|
|
1859
|
+
WHERE ${conditions.join(' AND ')}
|
|
1860
|
+
ORDER BY created_at DESC
|
|
1861
|
+
LIMIT $${limitParam}
|
|
1862
|
+
`;
|
|
1863
|
+
try {
|
|
1864
|
+
const result = await this.db.query(searchQuery, queryParams);
|
|
1865
|
+
logger.info({
|
|
1866
|
+
keywordCount: keywords.length,
|
|
1867
|
+
resultsFound: result.rows.length,
|
|
1868
|
+
keywords
|
|
1869
|
+
}, '[I5 FIX] Keyword fallback search complete');
|
|
1870
|
+
const compactionOpts = {
|
|
1871
|
+
summarize: params.summarize,
|
|
1872
|
+
maxContentLength: params.maxContentLength
|
|
1873
|
+
};
|
|
1874
|
+
return result.rows.map((row) => this.rowToSearchResult(row, compactionOpts));
|
|
1875
|
+
}
|
|
1876
|
+
catch (error) {
|
|
1877
|
+
logger.error({ error, keywords }, '[I5 FIX] Keyword fallback search failed');
|
|
1878
|
+
return [];
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* I5 FIX: Merge and dedupe results from multiple sources
|
|
1883
|
+
* Priority: semantic results > recent results > keyword results
|
|
1884
|
+
*
|
|
1885
|
+
* REACTIVE DEDUPE: Also checks for content duplicates and queues DB cleanup
|
|
1886
|
+
*/
|
|
1887
|
+
mergeAndDedupeResults(semanticResults, recentResults, keywordResults, limit) {
|
|
1888
|
+
const seenIds = new Set();
|
|
1889
|
+
const seenContent = new Map(); // content hash -> kept memory id
|
|
1890
|
+
const duplicateIds = []; // IDs to delete from DB
|
|
1891
|
+
const merged = [];
|
|
1892
|
+
// Helper to normalize content for comparison
|
|
1893
|
+
const normalizeContent = (content) => {
|
|
1894
|
+
return content
|
|
1895
|
+
.toLowerCase()
|
|
1896
|
+
.trim()
|
|
1897
|
+
.replace(/^\[user\]\s*/i, '')
|
|
1898
|
+
.replace(/^\[claude\]\s*/i, '')
|
|
1899
|
+
.slice(0, 500); // Compare first 500 chars
|
|
1900
|
+
};
|
|
1901
|
+
// Helper to add result with content dedup check
|
|
1902
|
+
const addResult = (result, source) => {
|
|
1903
|
+
if (seenIds.has(result.memory.id))
|
|
1904
|
+
return;
|
|
1905
|
+
const contentKey = normalizeContent(result.memory.content);
|
|
1906
|
+
const existingId = seenContent.get(contentKey);
|
|
1907
|
+
if (existingId) {
|
|
1908
|
+
// Content duplicate found - queue for DB deletion
|
|
1909
|
+
duplicateIds.push(result.memory.id);
|
|
1910
|
+
logger.debug({
|
|
1911
|
+
duplicateId: result.memory.id,
|
|
1912
|
+
keptId: existingId,
|
|
1913
|
+
contentPreview: contentKey.slice(0, 50)
|
|
1914
|
+
}, '[REACTIVE DEDUPE] Content duplicate detected');
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1917
|
+
seenIds.add(result.memory.id);
|
|
1918
|
+
seenContent.set(contentKey, result.memory.id);
|
|
1919
|
+
if (source) {
|
|
1920
|
+
merged.push({
|
|
1921
|
+
...result,
|
|
1922
|
+
memory: {
|
|
1923
|
+
...result.memory,
|
|
1924
|
+
metadata: { ...result.memory.metadata, _source: source }
|
|
1925
|
+
}
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
else {
|
|
1929
|
+
merged.push(result);
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
// Add semantic results first (highest priority)
|
|
1933
|
+
for (const result of semanticResults) {
|
|
1934
|
+
addResult(result);
|
|
1935
|
+
}
|
|
1936
|
+
// Add recent results second
|
|
1937
|
+
for (const result of recentResults) {
|
|
1938
|
+
addResult(result, 'recent');
|
|
1939
|
+
}
|
|
1940
|
+
// Add keyword results last
|
|
1941
|
+
for (const result of keywordResults) {
|
|
1942
|
+
addResult(result, 'keyword');
|
|
1943
|
+
}
|
|
1944
|
+
// REACTIVE DEDUPE: Delete duplicates from DB asynchronously
|
|
1945
|
+
// MED-42 FIX: Delay deletion by 30 seconds to allow drilldown on results before deletion
|
|
1946
|
+
// This prevents race condition where user tries to drill_down on a memory that was just deleted
|
|
1947
|
+
if (duplicateIds.length > 0) {
|
|
1948
|
+
logger.info({ count: duplicateIds.length, delaySeconds: 30 }, '[REACTIVE DEDUPE] Queuing content duplicates for cleanup (30s delay)');
|
|
1949
|
+
setTimeout(() => {
|
|
1950
|
+
this.cleanupDuplicates(duplicateIds).catch(err => {
|
|
1951
|
+
logger.warn({ error: err }, '[REACTIVE DEDUPE] Failed to cleanup duplicates');
|
|
1952
|
+
});
|
|
1953
|
+
}, 30000); // 30 second delay before deletion
|
|
1954
|
+
}
|
|
1955
|
+
// Sort by similarity (descending) and take limit
|
|
1956
|
+
return merged
|
|
1957
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
1958
|
+
.slice(0, limit);
|
|
1959
|
+
}
|
|
1960
|
+
/**
|
|
1961
|
+
* REACTIVE DEDUPE: Delete duplicate memories from database
|
|
1962
|
+
* PROJECT ISOLATED: Only deletes from current project
|
|
1963
|
+
* Called asynchronously when content duplicates are detected in search results
|
|
1964
|
+
*/
|
|
1965
|
+
async cleanupDuplicates(ids) {
|
|
1966
|
+
if (ids.length === 0)
|
|
1967
|
+
return;
|
|
1968
|
+
try {
|
|
1969
|
+
const projectPath = getProjectPathForInsert();
|
|
1970
|
+
const result = await this.db.query(`DELETE FROM memories WHERE id = ANY($1::uuid[]) AND project_path = $2 RETURNING id`, [ids, projectPath]);
|
|
1971
|
+
logger.info({
|
|
1972
|
+
requested: ids.length,
|
|
1973
|
+
deleted: result.rowCount,
|
|
1974
|
+
projectPath
|
|
1975
|
+
}, '[REACTIVE DEDUPE] Duplicates cleaned from DB');
|
|
1976
|
+
}
|
|
1977
|
+
catch (error) {
|
|
1978
|
+
logger.error({ error, ids }, '[REACTIVE DEDUPE] Failed to delete duplicates');
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* hybridSearch - combines semantic + full-text search
|
|
1983
|
+
*
|
|
1984
|
+
* best of both worlds - vector similarity for meaning
|
|
1985
|
+
* plus full-text search for exact matches
|
|
1986
|
+
*/
|
|
1987
|
+
async hybridSearch(params, queryEmbedding) {
|
|
1988
|
+
const limit = params.limit ?? 10;
|
|
1989
|
+
// NOTE: Default 0.35 filters out noise while catching real matches
|
|
1990
|
+
const threshold = params.threshold ?? 0.35;
|
|
1991
|
+
// CROSS-PROJECT SUPPORT: Build project condition
|
|
1992
|
+
const allProjects = params.allProjects === true;
|
|
1993
|
+
const targetProject = params.projectPath || getProjectContext().getProjectPath();
|
|
1994
|
+
// Build project filter clause (empty if allProjects)
|
|
1995
|
+
const projectClause = allProjects ? '' : 'AND project_path = $3';
|
|
1996
|
+
// semantic search component - with optional project filter
|
|
1997
|
+
const semanticQuery = `
|
|
1998
|
+
SELECT
|
|
1999
|
+
id, content, memory_type, importance, tags, metadata,
|
|
2000
|
+
embedding, created_at, updated_at, access_count, last_accessed_at,
|
|
2001
|
+
1 - (embedding <=> $1::vector) AS similarity,
|
|
2002
|
+
0.7 AS weight
|
|
2003
|
+
FROM memories
|
|
2004
|
+
WHERE embedding IS NOT NULL
|
|
2005
|
+
AND (expires_at IS NULL OR expires_at > NOW())
|
|
2006
|
+
${projectClause}
|
|
2007
|
+
AND 1 - (embedding <=> $1::vector) >= ${threshold}
|
|
2008
|
+
`;
|
|
2009
|
+
// full-text search component - with optional project filter
|
|
2010
|
+
const ftsQuery = `
|
|
2011
|
+
SELECT
|
|
2012
|
+
id, content, memory_type, importance, tags, metadata,
|
|
2013
|
+
embedding, created_at, updated_at, access_count, last_accessed_at,
|
|
2014
|
+
ts_rank(content_tsv, plainto_tsquery('english', $2)) AS similarity,
|
|
2015
|
+
0.3 AS weight
|
|
2016
|
+
FROM memories
|
|
2017
|
+
WHERE content_tsv @@ plainto_tsquery('english', $2)
|
|
2018
|
+
AND (expires_at IS NULL OR expires_at > NOW())
|
|
2019
|
+
${projectClause}
|
|
2020
|
+
`;
|
|
2021
|
+
// combine and dedupe - semantic results get priority
|
|
2022
|
+
// NOTE: Using ON instead of USING to avoid vector type comparison issues
|
|
2023
|
+
const combinedQuery = `
|
|
2024
|
+
WITH semantic AS (${semanticQuery}),
|
|
2025
|
+
fts AS (${ftsQuery})
|
|
2026
|
+
SELECT DISTINCT ON (COALESCE(s.id, f.id))
|
|
2027
|
+
COALESCE(s.id, f.id) AS id,
|
|
2028
|
+
COALESCE(s.content, f.content) AS content,
|
|
2029
|
+
COALESCE(s.memory_type, f.memory_type) AS memory_type,
|
|
2030
|
+
COALESCE(s.importance, f.importance) AS importance,
|
|
2031
|
+
COALESCE(s.tags, f.tags) AS tags,
|
|
2032
|
+
COALESCE(s.metadata, f.metadata) AS metadata,
|
|
2033
|
+
COALESCE(s.embedding, f.embedding) AS embedding,
|
|
2034
|
+
COALESCE(s.created_at, f.created_at) AS created_at,
|
|
2035
|
+
COALESCE(s.updated_at, f.updated_at) AS updated_at,
|
|
2036
|
+
COALESCE(s.access_count, f.access_count) AS access_count,
|
|
2037
|
+
COALESCE(s.last_accessed_at, f.last_accessed_at) AS last_accessed_at,
|
|
2038
|
+
COALESCE(s.similarity * s.weight, 0) + COALESCE(f.similarity * f.weight, 0) AS similarity
|
|
2039
|
+
FROM semantic s
|
|
2040
|
+
FULL OUTER JOIN fts f ON s.id = f.id
|
|
2041
|
+
ORDER BY COALESCE(s.id, f.id), similarity DESC
|
|
2042
|
+
LIMIT ${limit}
|
|
2043
|
+
`;
|
|
2044
|
+
// Build query params - include projectPath only if not searching all projects
|
|
2045
|
+
const queryParams = allProjects
|
|
2046
|
+
? [`[${queryEmbedding.join(',')}]`, params.query]
|
|
2047
|
+
: [`[${queryEmbedding.join(',')}]`, params.query, targetProject];
|
|
2048
|
+
const result = await this.db.query(combinedQuery, queryParams);
|
|
2049
|
+
// Apply Chinese Compactor approach
|
|
2050
|
+
const compactionOpts = {
|
|
2051
|
+
summarize: params.summarize,
|
|
2052
|
+
maxContentLength: params.maxContentLength
|
|
2053
|
+
};
|
|
2054
|
+
return result.rows.map((row) => this.rowToSearchResult(row, compactionOpts));
|
|
2055
|
+
}
|
|
2056
|
+
/**
|
|
2057
|
+
* update access counts for returned memories
|
|
2058
|
+
*
|
|
2059
|
+
* helps with relevance scoring over time
|
|
2060
|
+
*/
|
|
2061
|
+
async updateAccessCounts(memoryIds) {
|
|
2062
|
+
try {
|
|
2063
|
+
await this.db.query(`UPDATE memories
|
|
2064
|
+
SET access_count = access_count + 1,
|
|
2065
|
+
last_accessed_at = NOW()
|
|
2066
|
+
WHERE id = ANY($1::uuid[])`, [memoryIds]);
|
|
2067
|
+
}
|
|
2068
|
+
catch (error) {
|
|
2069
|
+
// non-critical, just log it
|
|
2070
|
+
logger.warn({ error }, 'failed to update access counts');
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Record access patterns for hot path tracking
|
|
2075
|
+
*
|
|
2076
|
+
* When memories are accessed together, we track the transition
|
|
2077
|
+
* to build up hot paths that can be predicted/prefetched
|
|
2078
|
+
*/
|
|
2079
|
+
async recordAccessPatterns(memoryIds) {
|
|
2080
|
+
if (memoryIds.length < 2)
|
|
2081
|
+
return;
|
|
2082
|
+
try {
|
|
2083
|
+
// Lazy initialize hot path manager
|
|
2084
|
+
if (!this.hotPathManager) {
|
|
2085
|
+
try {
|
|
2086
|
+
this.hotPathManager = getHotPathManager(this.db.pool);
|
|
2087
|
+
}
|
|
2088
|
+
catch {
|
|
2089
|
+
// If hot path manager isn't initialized yet, skip
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
// Record each memory access in sequence
|
|
2094
|
+
for (const memoryId of memoryIds) {
|
|
2095
|
+
await this.hotPathManager.recordAccess(memoryId);
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
catch (error) {
|
|
2099
|
+
// Non-critical - just log
|
|
2100
|
+
logger.debug({ error }, 'hot path recording failed (tables may not exist yet)');
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
/**
|
|
2104
|
+
* highlight matching content
|
|
2105
|
+
*
|
|
2106
|
+
* shows context around matches for better UX
|
|
2107
|
+
*/
|
|
2108
|
+
getHighlights(content, query) {
|
|
2109
|
+
const highlights = [];
|
|
2110
|
+
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 2);
|
|
2111
|
+
const contentLower = content.toLowerCase();
|
|
2112
|
+
for (const word of words) {
|
|
2113
|
+
const index = contentLower.indexOf(word);
|
|
2114
|
+
if (index !== -1) {
|
|
2115
|
+
const start = Math.max(0, index - 50);
|
|
2116
|
+
const end = Math.min(content.length, index + word.length + 50);
|
|
2117
|
+
let highlight = content.substring(start, end);
|
|
2118
|
+
if (start > 0)
|
|
2119
|
+
highlight = '...' + highlight;
|
|
2120
|
+
if (end < content.length)
|
|
2121
|
+
highlight = highlight + '...';
|
|
2122
|
+
highlights.push(highlight);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
return highlights.slice(0, 3); // max 3 highlights
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Create search result with AGGRESSIVE content compaction
|
|
2129
|
+
* Uses Chinese Compactor for token savings + truncation for drill-down
|
|
2130
|
+
*
|
|
2131
|
+
* When summarize=true (DEFAULT): Returns MINIMAL structure for drill-down decision
|
|
2132
|
+
* When summarize=false: Returns full Memory object
|
|
2133
|
+
*/
|
|
2134
|
+
rowToSearchResult(row, opts = {}) {
|
|
2135
|
+
let content = row.content;
|
|
2136
|
+
let contentTruncated = false;
|
|
2137
|
+
const originalLength = row.content.length;
|
|
2138
|
+
// STEP 1: Truncate first - User feedback: "content wayyy too trimmed"
|
|
2139
|
+
const summarize = opts.summarize !== false; // Default TRUE
|
|
2140
|
+
const maxLen = opts.maxContentLength ?? 1000; // Was 500 - doubled for more context
|
|
2141
|
+
if (maxLen > 0 && content.length > maxLen) {
|
|
2142
|
+
content = content.substring(0, maxLen) + '...';
|
|
2143
|
+
contentTruncated = true;
|
|
2144
|
+
}
|
|
2145
|
+
// STEP 2: Apply Chinese compression for additional token savings
|
|
2146
|
+
// Only compress if content is long enough to benefit
|
|
2147
|
+
let compressionRatio = 1.0;
|
|
2148
|
+
if (content.length > 50) {
|
|
2149
|
+
const compressed = smartCompress(content, {
|
|
2150
|
+
threshold: 0.80, // Allow slightly lossy for big savings
|
|
2151
|
+
minLength: 30
|
|
2152
|
+
});
|
|
2153
|
+
content = compressed.result;
|
|
2154
|
+
compressionRatio = compressed.compressionRatio;
|
|
2155
|
+
}
|
|
2156
|
+
// DRILL-DOWN MODE: Return minimal but MEANINGFUL structure when summarize=true
|
|
2157
|
+
// Key: Show ACTUAL CONTENT preview, not just IDs and metadata!
|
|
2158
|
+
if (summarize) {
|
|
2159
|
+
// Extract the most meaningful part of content (skip metadata-looking text)
|
|
2160
|
+
const meaningfulContent = this.extractMeaningfulContent(content, maxLen);
|
|
2161
|
+
// Create a semantic summary in Traditional Chinese for token efficiency
|
|
2162
|
+
const semanticHint = this.createSemanticHint(row, meaningfulContent);
|
|
2163
|
+
const memory = {
|
|
2164
|
+
id: row.id,
|
|
2165
|
+
// CRITICAL: Show actual meaningful content, not just truncated raw text
|
|
2166
|
+
content: meaningfulContent,
|
|
2167
|
+
// Include semantic hint for understanding
|
|
2168
|
+
memoryType: row.memory_type,
|
|
2169
|
+
// Tags help understand context
|
|
2170
|
+
tags: row.tags.slice(0, 5),
|
|
2171
|
+
// Metadata: PRESERVE original (sessionId, timestamp, role) + add drill hints
|
|
2172
|
+
metadata: {
|
|
2173
|
+
...row.metadata, // CRITICAL: Keep sessionId, timestamp, role for pairing!
|
|
2174
|
+
_preview: semanticHint, // Chinese-compressed semantic summary
|
|
2175
|
+
_drill: `get_memory({id: "${row.id}"})`,
|
|
2176
|
+
_fullLen: originalLength,
|
|
2177
|
+
_created: row.created_at ? new Date(row.created_at).toLocaleDateString() : undefined
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
// MED-38 FIX: Include isFallback flag to indicate similarity is synthetic, not from semantic search
|
|
2181
|
+
return {
|
|
2182
|
+
memory,
|
|
2183
|
+
similarity: row.similarity,
|
|
2184
|
+
highlights: [],
|
|
2185
|
+
...(row.is_fallback ? { isFallback: true, fallbackNote: 'Similarity score is synthetic (recent/keyword), not from semantic search' } : {})
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
// FULL MODE: Return complete Memory object when summarize=false
|
|
2189
|
+
const memory = {
|
|
2190
|
+
id: row.id,
|
|
2191
|
+
content: content,
|
|
2192
|
+
memoryType: row.memory_type,
|
|
2193
|
+
importance: row.importance,
|
|
2194
|
+
tags: row.tags,
|
|
2195
|
+
metadata: {
|
|
2196
|
+
...row.metadata,
|
|
2197
|
+
...(contentTruncated ? {
|
|
2198
|
+
_truncated: true,
|
|
2199
|
+
_len: originalLength,
|
|
2200
|
+
_drill: `get_memory({id: "${row.id}"})`
|
|
2201
|
+
} : {}),
|
|
2202
|
+
...(compressionRatio < 0.9 ? { _compressed: true } : {})
|
|
2203
|
+
},
|
|
2204
|
+
embedding: undefined, // NEVER return embeddings - huge token waste
|
|
2205
|
+
createdAt: row.created_at,
|
|
2206
|
+
updatedAt: row.updated_at,
|
|
2207
|
+
accessCount: row.access_count,
|
|
2208
|
+
lastAccessedAt: row.last_accessed_at ?? undefined
|
|
2209
|
+
};
|
|
2210
|
+
// MED-38 FIX: Include isFallback flag to indicate similarity is synthetic, not from semantic search
|
|
2211
|
+
return {
|
|
2212
|
+
memory,
|
|
2213
|
+
similarity: row.similarity,
|
|
2214
|
+
highlights: [],
|
|
2215
|
+
...(row.is_fallback ? { isFallback: true, fallbackNote: 'Similarity score is synthetic (recent/keyword), not from semantic search' } : {})
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
parseEmbedding(embeddingStr) {
|
|
2219
|
+
const cleaned = embeddingStr.replace(/[\[\]]/g, '');
|
|
2220
|
+
return cleaned.split(',').map(Number);
|
|
2221
|
+
}
|
|
2222
|
+
// ============================================================================
|
|
2223
|
+
// CONTEXT ENRICHMENT METHODS
|
|
2224
|
+
// Like human memory recall - fragment leads to connections leads to deeper recall
|
|
2225
|
+
// ============================================================================
|
|
2226
|
+
/**
|
|
2227
|
+
* Aggregate discoverable paths from all enriched results
|
|
2228
|
+
* Combines and deduplicates paths for a unified exploration map
|
|
2229
|
+
*/
|
|
2230
|
+
aggregateDiscoverablePaths(results) {
|
|
2231
|
+
const aggregated = {
|
|
2232
|
+
filePaths: [],
|
|
2233
|
+
codeBlocks: [],
|
|
2234
|
+
urls: [],
|
|
2235
|
+
memoryRefs: [],
|
|
2236
|
+
technicalTerms: [],
|
|
2237
|
+
researchQuestions: []
|
|
2238
|
+
};
|
|
2239
|
+
for (const result of results) {
|
|
2240
|
+
if (!result._discoverable)
|
|
2241
|
+
continue;
|
|
2242
|
+
const paths = result._discoverable;
|
|
2243
|
+
aggregated.filePaths.push(...paths.filePaths);
|
|
2244
|
+
aggregated.codeBlocks.push(...paths.codeBlocks);
|
|
2245
|
+
aggregated.urls.push(...paths.urls);
|
|
2246
|
+
aggregated.memoryRefs.push(...paths.memoryRefs);
|
|
2247
|
+
aggregated.technicalTerms.push(...paths.technicalTerms);
|
|
2248
|
+
aggregated.researchQuestions.push(...paths.researchQuestions);
|
|
2249
|
+
}
|
|
2250
|
+
// Deduplicate
|
|
2251
|
+
aggregated.filePaths = [...new Set(aggregated.filePaths)].slice(0, 15);
|
|
2252
|
+
aggregated.urls = [...new Set(aggregated.urls)].slice(0, 10);
|
|
2253
|
+
aggregated.technicalTerms = [...new Set(aggregated.technicalTerms)].slice(0, 15);
|
|
2254
|
+
aggregated.researchQuestions = [...new Set(aggregated.researchQuestions)].slice(0, 5);
|
|
2255
|
+
return aggregated;
|
|
2256
|
+
}
|
|
2257
|
+
/**
|
|
2258
|
+
* Generate context enrichment summary
|
|
2259
|
+
* This is the KEY output that tells what to explore next
|
|
2260
|
+
* Uses Traditional Chinese for token efficiency
|
|
2261
|
+
*/
|
|
2262
|
+
generateContextEnrichment(query, results, aggregatedPaths, drilldown) {
|
|
2263
|
+
const lines = [];
|
|
2264
|
+
// Header with query context (Chinese compacted)
|
|
2265
|
+
lines.push(`<specmem-context query="${query}">`);
|
|
2266
|
+
lines.push(` 記憶召回: ${results.length}條 | ${drilldown.prompt}`);
|
|
2267
|
+
// Discoverable exploration paths
|
|
2268
|
+
if (aggregatedPaths.filePaths.length > 0) {
|
|
2269
|
+
lines.push(` 📁 可探索文件(${aggregatedPaths.filePaths.length}):`);
|
|
2270
|
+
for (const path of aggregatedPaths.filePaths.slice(0, 5)) {
|
|
2271
|
+
lines.push(` → ${path}`);
|
|
2272
|
+
}
|
|
2273
|
+
if (aggregatedPaths.filePaths.length > 5) {
|
|
2274
|
+
lines.push(` ... +${aggregatedPaths.filePaths.length - 5}個文件`);
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
if (aggregatedPaths.codeBlocks.length > 0) {
|
|
2278
|
+
const langs = [...new Set(aggregatedPaths.codeBlocks.map(c => c.language))];
|
|
2279
|
+
lines.push(` 💻 代碼塊(${aggregatedPaths.codeBlocks.length}): ${langs.join(', ')}`);
|
|
2280
|
+
// Show first code block preview
|
|
2281
|
+
const first = aggregatedPaths.codeBlocks[0];
|
|
2282
|
+
if (first.possiblePath) {
|
|
2283
|
+
lines.push(` → 可能來源: ${first.possiblePath}`);
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
if (aggregatedPaths.technicalTerms.length > 0) {
|
|
2287
|
+
lines.push(` 🔧 技術概念: ${aggregatedPaths.technicalTerms.slice(0, 8).join(', ')}`);
|
|
2288
|
+
}
|
|
2289
|
+
if (aggregatedPaths.urls.length > 0) {
|
|
2290
|
+
lines.push(` 🔗 相關URL(${aggregatedPaths.urls.length}): 可WebFetch研究`);
|
|
2291
|
+
}
|
|
2292
|
+
// Research suggestions
|
|
2293
|
+
if (drilldown.needsResearch || aggregatedPaths.researchQuestions.length > 0) {
|
|
2294
|
+
lines.push(` ❓ 研究建議:`);
|
|
2295
|
+
if (drilldown.needsResearch) {
|
|
2296
|
+
lines.push(` → 本地記憶不足,建議WebSearch: "${query}"`);
|
|
2297
|
+
}
|
|
2298
|
+
for (const q of aggregatedPaths.researchQuestions.slice(0, 2)) {
|
|
2299
|
+
lines.push(` → ${q}`);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
// Drilldown action hint
|
|
2303
|
+
if (drilldown.action !== 'none') {
|
|
2304
|
+
lines.push(` 🎯 建議操作: ${this.formatDrilldownAction(drilldown.action)}`);
|
|
2305
|
+
}
|
|
2306
|
+
lines.push(`</specmem-context>`);
|
|
2307
|
+
return lines.join('\n');
|
|
2308
|
+
}
|
|
2309
|
+
/**
|
|
2310
|
+
* Format drilldown action as Chinese instruction
|
|
2311
|
+
*/
|
|
2312
|
+
formatDrilldownAction(action) {
|
|
2313
|
+
const actions = {
|
|
2314
|
+
'drilldown:deeper': '深入搜索 - 使用get_memory獲取完整內容',
|
|
2315
|
+
'drilldown:broader': '擴大搜索 - 嘗試相關詞或增加limit',
|
|
2316
|
+
'drilldown:filter': '過濾結果 - 添加memoryTypes或tags參數',
|
|
2317
|
+
'research:web': '網絡研究 - 使用WebSearch獲取最新資訊',
|
|
2318
|
+
'none': '記憶足夠'
|
|
2319
|
+
};
|
|
2320
|
+
return actions[action] || action;
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* Generate context for empty results
|
|
2324
|
+
* Guides on what to do when no memories match
|
|
2325
|
+
*/
|
|
2326
|
+
generateEmptyResultContext(query, drilldown) {
|
|
2327
|
+
return `<specmem-context query="${query}">
|
|
2328
|
+
⚠️ 無匹配記憶
|
|
2329
|
+
${drilldown.prompt}
|
|
2330
|
+
|
|
2331
|
+
建議操作:
|
|
2332
|
+
1. WebSearch "${query}" - 獲取外部資訊
|
|
2333
|
+
2. 調整查詢 - 嘗試不同關鍵詞
|
|
2334
|
+
3. 檢查拼寫 - 確保查詢正確
|
|
2335
|
+
4. 擴大範圍 - 移除過濾條件
|
|
2336
|
+
</specmem-context>`;
|
|
2337
|
+
}
|
|
2338
|
+
/**
|
|
2339
|
+
* Generate research spawn instructions
|
|
2340
|
+
* These instructions tell how to spawn a research team member
|
|
2341
|
+
* when local memory is insufficient
|
|
2342
|
+
*/
|
|
2343
|
+
generateResearchSpawnInstructions(query, aggregatedPaths) {
|
|
2344
|
+
const hasCodePaths = aggregatedPaths.filePaths.length > 0 || aggregatedPaths.codeBlocks.length > 0;
|
|
2345
|
+
const hasResearchQuestions = aggregatedPaths.researchQuestions.length > 0;
|
|
2346
|
+
const hasUrls = aggregatedPaths.urls.length > 0;
|
|
2347
|
+
// Determine research type
|
|
2348
|
+
let researchType = 'web';
|
|
2349
|
+
if (hasCodePaths && (hasResearchQuestions || hasUrls)) {
|
|
2350
|
+
researchType = 'both';
|
|
2351
|
+
}
|
|
2352
|
+
else if (hasCodePaths) {
|
|
2353
|
+
researchType = 'code';
|
|
2354
|
+
}
|
|
2355
|
+
// Build task prompt for the research team member
|
|
2356
|
+
const taskParts = [];
|
|
2357
|
+
if (researchType === 'code' || researchType === 'both') {
|
|
2358
|
+
taskParts.push(`探索代碼路徑: ${aggregatedPaths.filePaths.slice(0, 3).join(', ')}`);
|
|
2359
|
+
if (aggregatedPaths.technicalTerms.length > 0) {
|
|
2360
|
+
taskParts.push(`技術概念: ${aggregatedPaths.technicalTerms.slice(0, 5).join(', ')}`);
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
if (researchType === 'web' || researchType === 'both') {
|
|
2364
|
+
if (hasResearchQuestions) {
|
|
2365
|
+
taskParts.push(`研究問題: ${aggregatedPaths.researchQuestions.slice(0, 2).join('; ')}`);
|
|
2366
|
+
}
|
|
2367
|
+
else {
|
|
2368
|
+
taskParts.push(`WebSearch查詢: "${query}"`);
|
|
2369
|
+
}
|
|
2370
|
+
if (hasUrls) {
|
|
2371
|
+
taskParts.push(`可WebFetch的URL: ${aggregatedPaths.urls.length}個`);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
// Context for the research team member (Chinese compacted)
|
|
2375
|
+
const contextForTeamMember = `<specmem-research-context>
|
|
2376
|
+
原始查詢: "${query}"
|
|
2377
|
+
研究類型: ${researchType}
|
|
2378
|
+
${taskParts.map(p => ` ${p}`).join('\n')}
|
|
2379
|
+
|
|
2380
|
+
指示:
|
|
2381
|
+
- 收集相關資訊後,使用save_memory保存重要發現
|
|
2382
|
+
- 研究完成後返回簡潔摘要
|
|
2383
|
+
- 使用傳統中文壓縮輸出以節省tokens
|
|
2384
|
+
</specmem-research-context>`;
|
|
2385
|
+
// Subteam member type based on research needs
|
|
2386
|
+
const subteamMemberType = researchType === 'code' ? 'Explore' : 'general-purpose';
|
|
2387
|
+
// Task prompt for spawning
|
|
2388
|
+
const taskPrompt = researchType === 'code'
|
|
2389
|
+
? `探索SpecMem代碼庫以理解: ${query}\n重點文件: ${aggregatedPaths.filePaths.slice(0, 3).join(', ')}`
|
|
2390
|
+
: `研究: ${query}\n${hasResearchQuestions ? `問題: ${aggregatedPaths.researchQuestions[0]}` : '使用WebSearch獲取最新資訊'}`;
|
|
2391
|
+
return {
|
|
2392
|
+
shouldSpawnResearch: true,
|
|
2393
|
+
researchType,
|
|
2394
|
+
taskPrompt,
|
|
2395
|
+
subteamMemberType,
|
|
2396
|
+
contextForTeamMember
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
/**
|
|
2400
|
+
* Extract meaningful preview from content
|
|
2401
|
+
* Avoids showing just metadata like session IDs and timestamps
|
|
2402
|
+
*/
|
|
2403
|
+
extractMeaningfulPreview(content) {
|
|
2404
|
+
// Skip metadata-looking lines (session IDs, timestamps, etc.)
|
|
2405
|
+
const lines = content.split('\n');
|
|
2406
|
+
let meaningfulLine = '';
|
|
2407
|
+
for (const line of lines) {
|
|
2408
|
+
const trimmed = line.trim();
|
|
2409
|
+
// Skip empty lines
|
|
2410
|
+
if (!trimmed)
|
|
2411
|
+
continue;
|
|
2412
|
+
// Skip lines that look like metadata
|
|
2413
|
+
if (/^(session|memory|created|id|timestamp|metadata)[:=]/i.test(trimmed))
|
|
2414
|
+
continue;
|
|
2415
|
+
if (/^[a-f0-9-]{36}$/i.test(trimmed))
|
|
2416
|
+
continue; // UUIDs
|
|
2417
|
+
if (/^\d{4}-\d{2}-\d{2}/.test(trimmed))
|
|
2418
|
+
continue; // Dates
|
|
2419
|
+
// Found a meaningful line
|
|
2420
|
+
meaningfulLine = trimmed;
|
|
2421
|
+
break;
|
|
2422
|
+
}
|
|
2423
|
+
// Truncate to 60 chars
|
|
2424
|
+
if (meaningfulLine.length > 60) {
|
|
2425
|
+
meaningfulLine = meaningfulLine.substring(0, 57) + '...';
|
|
2426
|
+
}
|
|
2427
|
+
return meaningfulLine || content.substring(0, 50) + '...';
|
|
2428
|
+
}
|
|
2429
|
+
/**
|
|
2430
|
+
* Extract meaningful content, skipping metadata-looking lines
|
|
2431
|
+
* Returns actual content can understand and drill down on
|
|
2432
|
+
*/
|
|
2433
|
+
extractMeaningfulContent(content, maxLen) {
|
|
2434
|
+
const lines = content.split('\n');
|
|
2435
|
+
const meaningfulLines = [];
|
|
2436
|
+
let charCount = 0;
|
|
2437
|
+
// Patterns that indicate metadata (should skip)
|
|
2438
|
+
const metadataPatterns = [
|
|
2439
|
+
/^session[_\s-]?id[:=\s]/i,
|
|
2440
|
+
/^memory[_\s-]?id[:=\s]/i,
|
|
2441
|
+
/^created[_\s-]?at[:=\s]/i,
|
|
2442
|
+
/^updated[_\s-]?at[:=\s]/i,
|
|
2443
|
+
/^timestamp[:=\s]/i,
|
|
2444
|
+
/^id[:=\s]/i,
|
|
2445
|
+
/^uuid[:=\s]/i,
|
|
2446
|
+
/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i, // UUID only line
|
|
2447
|
+
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, // ISO timestamp only line
|
|
2448
|
+
/^metadata[:=\s]*\{/i,
|
|
2449
|
+
/^tags[:=\s]*\[/i,
|
|
2450
|
+
];
|
|
2451
|
+
for (const line of lines) {
|
|
2452
|
+
const trimmed = line.trim();
|
|
2453
|
+
if (!trimmed)
|
|
2454
|
+
continue;
|
|
2455
|
+
// Skip metadata lines
|
|
2456
|
+
let isMetadata = false;
|
|
2457
|
+
for (const pattern of metadataPatterns) {
|
|
2458
|
+
if (pattern.test(trimmed)) {
|
|
2459
|
+
isMetadata = true;
|
|
2460
|
+
break;
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
if (isMetadata)
|
|
2464
|
+
continue;
|
|
2465
|
+
// Add meaningful line
|
|
2466
|
+
meaningfulLines.push(trimmed);
|
|
2467
|
+
charCount += trimmed.length;
|
|
2468
|
+
// Stop if we have enough
|
|
2469
|
+
if (charCount >= maxLen)
|
|
2470
|
+
break;
|
|
2471
|
+
}
|
|
2472
|
+
// If we found meaningful content, use it
|
|
2473
|
+
if (meaningfulLines.length > 0) {
|
|
2474
|
+
let result = meaningfulLines.join('\n');
|
|
2475
|
+
if (result.length > maxLen) {
|
|
2476
|
+
result = result.substring(0, maxLen - 3) + '...';
|
|
2477
|
+
}
|
|
2478
|
+
return result;
|
|
2479
|
+
}
|
|
2480
|
+
// Fallback: just use first maxLen chars
|
|
2481
|
+
return content.length > maxLen ? content.substring(0, maxLen - 3) + '...' : content;
|
|
2482
|
+
}
|
|
2483
|
+
/**
|
|
2484
|
+
* Create a semantic hint in Traditional Chinese for token efficiency
|
|
2485
|
+
* This gives a quick understanding of what the memory is about
|
|
2486
|
+
*/
|
|
2487
|
+
createSemanticHint(row, content) {
|
|
2488
|
+
const parts = [];
|
|
2489
|
+
// Memory type in Chinese
|
|
2490
|
+
const typeMap = {
|
|
2491
|
+
'episodic': '情節記憶', // Episode/event memory
|
|
2492
|
+
'semantic': '語義記憶', // Factual/knowledge memory
|
|
2493
|
+
'procedural': '程序記憶', // How-to memory
|
|
2494
|
+
'working': '工作記憶', // Temporary/active memory
|
|
2495
|
+
'consolidated': '長期記憶' // Consolidated/important memory
|
|
2496
|
+
};
|
|
2497
|
+
const memType = typeMap[row.memory_type] || row.memory_type;
|
|
2498
|
+
parts.push(`類型:${memType}`);
|
|
2499
|
+
// Importance in Chinese
|
|
2500
|
+
const importanceMap = {
|
|
2501
|
+
'critical': '🔴關鍵',
|
|
2502
|
+
'high': '🟠重要',
|
|
2503
|
+
'medium': '🟡一般',
|
|
2504
|
+
'low': '🟢低',
|
|
2505
|
+
'trivial': '⚪微'
|
|
2506
|
+
};
|
|
2507
|
+
const imp = importanceMap[row.importance] || row.importance;
|
|
2508
|
+
parts.push(`重要:${imp}`);
|
|
2509
|
+
// Extract key topic from content (first sentence or 50 chars)
|
|
2510
|
+
const firstSentence = content.split(/[.!?。!?\n]/)[0]?.trim() || content;
|
|
2511
|
+
const topic = firstSentence.length > 50 ? firstSentence.substring(0, 47) + '...' : firstSentence;
|
|
2512
|
+
parts.push(`主題:${topic}`);
|
|
2513
|
+
// Tags if present (max 3)
|
|
2514
|
+
if (row.tags && row.tags.length > 0) {
|
|
2515
|
+
const tagStr = row.tags.slice(0, 3).join(',');
|
|
2516
|
+
parts.push(`標籤:${tagStr}`);
|
|
2517
|
+
}
|
|
2518
|
+
return parts.join(' | ');
|
|
2519
|
+
}
|
|
2520
|
+
/**
|
|
2521
|
+
* Extract keywords from query for related searches
|
|
2522
|
+
*/
|
|
2523
|
+
extractKeywords(query) {
|
|
2524
|
+
// Remove stop words and get meaningful terms
|
|
2525
|
+
const stopWords = new Set(['the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
2526
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should',
|
|
2527
|
+
'may', 'might', 'must', 'shall', 'can', 'need', 'to', 'of', 'in', 'for', 'on',
|
|
2528
|
+
'with', 'at', 'by', 'from', 'as', 'into', 'through', 'during', 'before', 'after',
|
|
2529
|
+
'above', 'below', 'between', 'under', 'again', 'further', 'then', 'once', 'here',
|
|
2530
|
+
'there', 'when', 'where', 'why', 'how', 'all', 'each', 'few', 'more', 'most',
|
|
2531
|
+
'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than',
|
|
2532
|
+
'too', 'very', 'just', 'and', 'but', 'if', 'or', 'because', 'until', 'while',
|
|
2533
|
+
'about', 'what', 'which', 'who', 'this', 'that', 'these', 'those', 'it', 'its']);
|
|
2534
|
+
const words = query.toLowerCase().split(/\s+/);
|
|
2535
|
+
const keywords = words.filter(w => w.length > 2 && !stopWords.has(w));
|
|
2536
|
+
// Return unique keywords
|
|
2537
|
+
return [...new Set(keywords)];
|
|
2538
|
+
}
|
|
2539
|
+
static getStats() {
|
|
2540
|
+
return {
|
|
2541
|
+
searchCount: _searchCount,
|
|
2542
|
+
totalSearchTime: _totalSearchTime,
|
|
2543
|
+
averageSearchTime: _searchCount > 0 ? _totalSearchTime / _searchCount : 0
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
//# sourceMappingURL=findWhatISaid.js.map
|