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,4266 @@
|
|
|
1
|
+
// ayo this migration system hits DIFFERENT
|
|
2
|
+
// handles schema evolution for MILLIONS of rows no cap
|
|
3
|
+
// partitioning, indexes, all the enterprise drip
|
|
4
|
+
//
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// EMBEDDING DIMENSION NOTE
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// DEPRECATED: SPECMEM_EMBEDDING_DIMENSIONS is no longer used.
|
|
9
|
+
//
|
|
10
|
+
// Embedding dimensions are now AUTO-DETECTED from the database pgvector column.
|
|
11
|
+
// The database pg_attribute table is the single source of truth for dimensions.
|
|
12
|
+
// The Frankenstein embedding model outputs 384-dim embeddings natively.
|
|
13
|
+
//
|
|
14
|
+
// The system auto-migrates when dimension mismatch is detected at startup.
|
|
15
|
+
// See src/dashboard/standalone.ts for auto-migration logic.
|
|
16
|
+
//
|
|
17
|
+
// For new tables, use 384 as the default (Frankenstein native dimension).
|
|
18
|
+
// =============================================================================
|
|
19
|
+
import { logger } from '../utils/logger.js';
|
|
20
|
+
import { getProjectSchema } from './projectNamespacing.js';
|
|
21
|
+
/**
|
|
22
|
+
* BigBrainMigrations - handles schema evolution like a BOSS
|
|
23
|
+
*
|
|
24
|
+
* features that absolutely SLAP:
|
|
25
|
+
* - version tracking with checksums
|
|
26
|
+
* - up/down migrations
|
|
27
|
+
* - partitioning for massive tables
|
|
28
|
+
* - proper index management
|
|
29
|
+
* - pgvector setup for semantic search
|
|
30
|
+
* - transaction-safe migrations
|
|
31
|
+
*/
|
|
32
|
+
export class BigBrainMigrations {
|
|
33
|
+
pool;
|
|
34
|
+
constructor(pool) {
|
|
35
|
+
this.pool = pool;
|
|
36
|
+
}
|
|
37
|
+
// runs all pending migrations in order
|
|
38
|
+
async runAllMigrations() {
|
|
39
|
+
logger.info('starting BigBrain migration run - LESGO');
|
|
40
|
+
const start = Date.now();
|
|
41
|
+
// SCHEMA ISOLATION: Set search_path BEFORE any CREATE TABLE
|
|
42
|
+
const schemaName = getProjectSchema();
|
|
43
|
+
await this.pool.queryWithSwag(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);
|
|
44
|
+
await this.pool.queryWithSwag(`SET search_path TO ${schemaName}, public`);
|
|
45
|
+
logger.info({ schemaName }, 'search_path set for migrations');
|
|
46
|
+
await this.ensureMigrationTable();
|
|
47
|
+
const applied = await this.getAppliedMigrations();
|
|
48
|
+
const pending = this.getMigrations().filter(m => !applied.some(a => a.version === m.version));
|
|
49
|
+
if (pending.length === 0) {
|
|
50
|
+
logger.info('no pending migrations - schema is up to date fr');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
logger.info({ pendingCount: pending.length }, 'found pending migrations');
|
|
54
|
+
let applied_count = 0;
|
|
55
|
+
let failed_count = 0;
|
|
56
|
+
for (const migration of pending.sort((a, b) => a.version - b.version)) {
|
|
57
|
+
try {
|
|
58
|
+
await this.runMigration(migration);
|
|
59
|
+
applied_count++;
|
|
60
|
+
} catch (migErr) {
|
|
61
|
+
failed_count++;
|
|
62
|
+
const errMsg = migErr instanceof Error ? migErr.message : String(migErr);
|
|
63
|
+
logger.warn({ version: migration.version, name: migration.name, error: errMsg }, 'migration failed - skipping to next');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const duration = Date.now() - start;
|
|
67
|
+
logger.info({ duration, migrationsApplied: applied_count, migrationsFailed: failed_count }, 'all migrations complete - WE DID IT');
|
|
68
|
+
}
|
|
69
|
+
// ensures the migration tracking table exists
|
|
70
|
+
async ensureMigrationTable() {
|
|
71
|
+
await this.pool.queryWithSwag(`
|
|
72
|
+
CREATE TABLE IF NOT EXISTS _specmem_migrations (
|
|
73
|
+
version INTEGER PRIMARY KEY,
|
|
74
|
+
name VARCHAR(255) NOT NULL,
|
|
75
|
+
executed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
76
|
+
duration_ms INTEGER NOT NULL,
|
|
77
|
+
checksum VARCHAR(64) NOT NULL
|
|
78
|
+
)
|
|
79
|
+
`);
|
|
80
|
+
logger.debug('migration table ready');
|
|
81
|
+
}
|
|
82
|
+
// gets all migrations that have already been applied
|
|
83
|
+
async getAppliedMigrations() {
|
|
84
|
+
const result = await this.pool.queryWithSwag('SELECT * FROM _specmem_migrations ORDER BY version');
|
|
85
|
+
return result.rows.map((row) => ({
|
|
86
|
+
version: row.version,
|
|
87
|
+
name: row.name,
|
|
88
|
+
executedAt: row.executed_at,
|
|
89
|
+
durationMs: row.duration_ms,
|
|
90
|
+
checksum: row.checksum
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
// runs a single migration in a transaction
|
|
94
|
+
async runMigration(migration) {
|
|
95
|
+
logger.info({ version: migration.version, name: migration.name }, 'running migration');
|
|
96
|
+
const start = Date.now();
|
|
97
|
+
await this.pool.transactionGang(async (client) => {
|
|
98
|
+
// run the migration SQL
|
|
99
|
+
await client.query(migration.up);
|
|
100
|
+
// record the migration
|
|
101
|
+
const duration = Date.now() - start;
|
|
102
|
+
await client.query(`INSERT INTO _specmem_migrations (version, name, duration_ms, checksum)
|
|
103
|
+
VALUES ($1, $2, $3, $4)`, [migration.version, migration.name, duration, migration.checksum]);
|
|
104
|
+
});
|
|
105
|
+
const duration = Date.now() - start;
|
|
106
|
+
logger.info({ version: migration.version, duration }, 'migration complete - fire');
|
|
107
|
+
}
|
|
108
|
+
// rolls back the last migration
|
|
109
|
+
async rollbackLast() {
|
|
110
|
+
const applied = await this.getAppliedMigrations();
|
|
111
|
+
if (applied.length === 0) {
|
|
112
|
+
logger.warn('no migrations to rollback bro');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const last = applied[applied.length - 1];
|
|
116
|
+
const migration = this.getMigrations().find(m => m.version === last.version);
|
|
117
|
+
if (!migration) {
|
|
118
|
+
throw new Error(`cant find migration ${last.version} to rollback - this is bad`);
|
|
119
|
+
}
|
|
120
|
+
logger.info({ version: migration.version, name: migration.name }, 'rolling back migration');
|
|
121
|
+
await this.pool.transactionGang(async (client) => {
|
|
122
|
+
await client.query(migration.down);
|
|
123
|
+
await client.query('DELETE FROM _specmem_migrations WHERE version = $1', [migration.version]);
|
|
124
|
+
});
|
|
125
|
+
logger.info({ version: migration.version }, 'rollback complete');
|
|
126
|
+
}
|
|
127
|
+
// generates a simple checksum for migration SQL
|
|
128
|
+
generateChecksum(sql) {
|
|
129
|
+
let hash = 0;
|
|
130
|
+
for (let i = 0; i < sql.length; i++) {
|
|
131
|
+
const char = sql.charCodeAt(i);
|
|
132
|
+
hash = ((hash << 5) - hash) + char;
|
|
133
|
+
hash = hash & hash;
|
|
134
|
+
}
|
|
135
|
+
return Math.abs(hash).toString(16).padStart(8, '0');
|
|
136
|
+
}
|
|
137
|
+
// returns all migrations in order
|
|
138
|
+
getMigrations() {
|
|
139
|
+
return [
|
|
140
|
+
// migration 1: install required extensions
|
|
141
|
+
{
|
|
142
|
+
version: 1,
|
|
143
|
+
name: 'install_extensions',
|
|
144
|
+
up: `
|
|
145
|
+
-- yo pgvector is the GOAT for semantic search
|
|
146
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
147
|
+
|
|
148
|
+
-- trigram for fuzzy text search
|
|
149
|
+
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
150
|
+
|
|
151
|
+
-- btree_gin for composite indexes
|
|
152
|
+
CREATE EXTENSION IF NOT EXISTS btree_gin;
|
|
153
|
+
|
|
154
|
+
-- uuid-ossp for generating uuids
|
|
155
|
+
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
156
|
+
`,
|
|
157
|
+
down: `
|
|
158
|
+
-- nah we cant really uninstall extensions safely
|
|
159
|
+
-- other tables might depend on them
|
|
160
|
+
SELECT 1;
|
|
161
|
+
`,
|
|
162
|
+
checksum: this.generateChecksum('install_extensions_v1')
|
|
163
|
+
},
|
|
164
|
+
// migration 2: create core enum types
|
|
165
|
+
{
|
|
166
|
+
version: 2,
|
|
167
|
+
name: 'create_enum_types',
|
|
168
|
+
up: `
|
|
169
|
+
-- memory types - episodic, semantic, etc
|
|
170
|
+
DO $$ BEGIN
|
|
171
|
+
CREATE TYPE memory_type AS ENUM (
|
|
172
|
+
'episodic', -- specific events/experiences
|
|
173
|
+
'semantic', -- facts and knowledge
|
|
174
|
+
'procedural', -- how to do stuff
|
|
175
|
+
'working', -- temporary/short-term
|
|
176
|
+
'consolidated' -- merged from multiple memories
|
|
177
|
+
);
|
|
178
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
179
|
+
END $$;
|
|
180
|
+
|
|
181
|
+
-- importance levels for prioritization
|
|
182
|
+
DO $$ BEGIN
|
|
183
|
+
CREATE TYPE importance_level AS ENUM (
|
|
184
|
+
'critical', -- NEVER forget this
|
|
185
|
+
'high', -- pretty important
|
|
186
|
+
'medium', -- normal stuff
|
|
187
|
+
'low', -- meh
|
|
188
|
+
'trivial' -- who cares
|
|
189
|
+
);
|
|
190
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
191
|
+
END $$;
|
|
192
|
+
`,
|
|
193
|
+
down: `
|
|
194
|
+
DROP TYPE IF EXISTS importance_level;
|
|
195
|
+
DROP TYPE IF EXISTS memory_type;
|
|
196
|
+
`,
|
|
197
|
+
checksum: this.generateChecksum('create_enum_types_v2')
|
|
198
|
+
},
|
|
199
|
+
// migration 3: create main memories table with partitioning
|
|
200
|
+
{
|
|
201
|
+
version: 3,
|
|
202
|
+
name: 'create_memories_table',
|
|
203
|
+
up: `
|
|
204
|
+
-- main memories table - THE BIG ONE
|
|
205
|
+
-- partitioned by created_at for handling MILLIONS of rows
|
|
206
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
207
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
208
|
+
|
|
209
|
+
-- content and search
|
|
210
|
+
content TEXT NOT NULL,
|
|
211
|
+
-- MED-18 FIX: Use convert_to() for proper UTF-8 to bytea conversion
|
|
212
|
+
-- The ::bytea cast can fail with "invalid input syntax for type bytea"
|
|
213
|
+
-- on content containing special characters like backslashes or non-ASCII
|
|
214
|
+
-- See yeetStuffInDb.ts computeContentHash() for consistent approach
|
|
215
|
+
content_hash VARCHAR(64) GENERATED ALWAYS AS (
|
|
216
|
+
encode(sha256(convert_to(content, 'UTF8')), 'hex')
|
|
217
|
+
) STORED,
|
|
218
|
+
content_tsv TSVECTOR GENERATED ALWAYS AS (
|
|
219
|
+
to_tsvector('english', content)
|
|
220
|
+
) STORED,
|
|
221
|
+
|
|
222
|
+
-- classification
|
|
223
|
+
memory_type memory_type NOT NULL DEFAULT 'semantic',
|
|
224
|
+
importance importance_level NOT NULL DEFAULT 'medium',
|
|
225
|
+
|
|
226
|
+
-- tags stored as array - supports millions of tags
|
|
227
|
+
tags TEXT[] NOT NULL DEFAULT '{}',
|
|
228
|
+
|
|
229
|
+
-- flexible metadata as JSONB - way faster than TEXT
|
|
230
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
231
|
+
|
|
232
|
+
-- EMBEDDINGS - the secret sauce
|
|
233
|
+
-- Dimension is auto-detected from memories table, unbounded initially
|
|
234
|
+
embedding vector(384),
|
|
235
|
+
|
|
236
|
+
-- image support
|
|
237
|
+
image_data BYTEA,
|
|
238
|
+
image_mime_type VARCHAR(50),
|
|
239
|
+
|
|
240
|
+
-- timestamps
|
|
241
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
242
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
243
|
+
|
|
244
|
+
-- access tracking for consolidation
|
|
245
|
+
access_count INTEGER NOT NULL DEFAULT 0,
|
|
246
|
+
last_accessed_at TIMESTAMPTZ,
|
|
247
|
+
|
|
248
|
+
-- expiration for auto-cleanup
|
|
249
|
+
expires_at TIMESTAMPTZ,
|
|
250
|
+
|
|
251
|
+
-- consolidation tracking
|
|
252
|
+
consolidated_from UUID[] DEFAULT '{}',
|
|
253
|
+
|
|
254
|
+
-- constraints
|
|
255
|
+
CONSTRAINT content_not_empty CHECK (length(content) > 0),
|
|
256
|
+
CONSTRAINT content_not_too_big CHECK (length(content) <= 1000000),
|
|
257
|
+
CONSTRAINT valid_image CHECK (
|
|
258
|
+
(image_data IS NULL AND image_mime_type IS NULL) OR
|
|
259
|
+
(image_data IS NOT NULL AND image_mime_type IS NOT NULL)
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
-- index for content hash deduplication
|
|
264
|
+
CREATE INDEX IF NOT EXISTS idx_memories_content_hash
|
|
265
|
+
ON memories(content_hash);
|
|
266
|
+
|
|
267
|
+
-- full-text search index - GIN goes CRAZY
|
|
268
|
+
CREATE INDEX IF NOT EXISTS idx_memories_content_tsv
|
|
269
|
+
ON memories USING GIN(content_tsv);
|
|
270
|
+
|
|
271
|
+
-- tag search - also GIN because arrays
|
|
272
|
+
CREATE INDEX IF NOT EXISTS idx_memories_tags
|
|
273
|
+
ON memories USING GIN(tags);
|
|
274
|
+
|
|
275
|
+
-- JSONB metadata search
|
|
276
|
+
CREATE INDEX IF NOT EXISTS idx_memories_metadata
|
|
277
|
+
ON memories USING GIN(metadata jsonb_path_ops);
|
|
278
|
+
|
|
279
|
+
-- type and importance filtering
|
|
280
|
+
CREATE INDEX IF NOT EXISTS idx_memories_type
|
|
281
|
+
ON memories(memory_type);
|
|
282
|
+
CREATE INDEX IF NOT EXISTS idx_memories_importance
|
|
283
|
+
ON memories(importance);
|
|
284
|
+
|
|
285
|
+
-- time-based queries
|
|
286
|
+
CREATE INDEX IF NOT EXISTS idx_memories_created
|
|
287
|
+
ON memories(created_at DESC);
|
|
288
|
+
CREATE INDEX IF NOT EXISTS idx_memories_updated
|
|
289
|
+
ON memories(updated_at DESC);
|
|
290
|
+
|
|
291
|
+
-- expiration cleanup
|
|
292
|
+
CREATE INDEX IF NOT EXISTS idx_memories_expires
|
|
293
|
+
ON memories(expires_at)
|
|
294
|
+
WHERE expires_at IS NOT NULL;
|
|
295
|
+
|
|
296
|
+
-- access pattern tracking
|
|
297
|
+
CREATE INDEX IF NOT EXISTS idx_memories_access
|
|
298
|
+
ON memories(last_accessed_at DESC NULLS LAST);
|
|
299
|
+
`,
|
|
300
|
+
down: `
|
|
301
|
+
DROP TABLE IF EXISTS memories CASCADE;
|
|
302
|
+
`,
|
|
303
|
+
checksum: this.generateChecksum('create_memories_table_v3')
|
|
304
|
+
},
|
|
305
|
+
// migration 4: create HNSW index for vector search
|
|
306
|
+
{
|
|
307
|
+
version: 4,
|
|
308
|
+
name: 'create_vector_index',
|
|
309
|
+
up: `
|
|
310
|
+
-- HNSW index for vector similarity search
|
|
311
|
+
-- this is the FAST one - O(log n) search time
|
|
312
|
+
-- ef_construction and m affect build time vs search quality
|
|
313
|
+
CREATE INDEX IF NOT EXISTS idx_memories_embedding_hnsw
|
|
314
|
+
ON memories
|
|
315
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
316
|
+
WITH (m = 16, ef_construction = 64);
|
|
317
|
+
|
|
318
|
+
-- also create IVFFlat for comparison (legacy compatibility)
|
|
319
|
+
-- IVFFlat is faster to build but slower to search
|
|
320
|
+
CREATE INDEX IF NOT EXISTS idx_memories_embedding_ivfflat
|
|
321
|
+
ON memories
|
|
322
|
+
USING ivfflat (embedding vector_cosine_ops)
|
|
323
|
+
WITH (lists = 100);
|
|
324
|
+
`,
|
|
325
|
+
down: `
|
|
326
|
+
DROP INDEX IF EXISTS idx_memories_embedding_hnsw;
|
|
327
|
+
DROP INDEX IF EXISTS idx_memories_embedding_ivfflat;
|
|
328
|
+
`,
|
|
329
|
+
checksum: this.generateChecksum('create_vector_index_v4')
|
|
330
|
+
},
|
|
331
|
+
// migration 5: create memory relations table
|
|
332
|
+
{
|
|
333
|
+
version: 5,
|
|
334
|
+
name: 'create_memory_relations',
|
|
335
|
+
up: `
|
|
336
|
+
-- tracks relationships between memories
|
|
337
|
+
CREATE TABLE IF NOT EXISTS memory_relations (
|
|
338
|
+
source_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
339
|
+
target_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
340
|
+
relation_type VARCHAR(50) NOT NULL DEFAULT 'related',
|
|
341
|
+
strength FLOAT NOT NULL DEFAULT 1.0 CHECK (strength >= 0 AND strength <= 1),
|
|
342
|
+
metadata JSONB DEFAULT '{}',
|
|
343
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
344
|
+
|
|
345
|
+
PRIMARY KEY (source_id, target_id, relation_type),
|
|
346
|
+
CONSTRAINT no_self_relation CHECK (source_id != target_id)
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
-- index for finding related memories
|
|
350
|
+
CREATE INDEX IF NOT EXISTS idx_memory_relations_source
|
|
351
|
+
ON memory_relations(source_id);
|
|
352
|
+
CREATE INDEX IF NOT EXISTS idx_memory_relations_target
|
|
353
|
+
ON memory_relations(target_id);
|
|
354
|
+
CREATE INDEX IF NOT EXISTS idx_memory_relations_type
|
|
355
|
+
ON memory_relations(relation_type);
|
|
356
|
+
`,
|
|
357
|
+
down: `
|
|
358
|
+
DROP TABLE IF EXISTS memory_relations CASCADE;
|
|
359
|
+
`,
|
|
360
|
+
checksum: this.generateChecksum('create_memory_relations_v5')
|
|
361
|
+
},
|
|
362
|
+
// migration 6: create normalized tags table
|
|
363
|
+
{
|
|
364
|
+
version: 6,
|
|
365
|
+
name: 'create_tags_table',
|
|
366
|
+
up: `
|
|
367
|
+
-- normalized tags for better query performance
|
|
368
|
+
-- this is in addition to the array column
|
|
369
|
+
CREATE TABLE IF NOT EXISTS tags (
|
|
370
|
+
id SERIAL PRIMARY KEY,
|
|
371
|
+
name VARCHAR(255) NOT NULL UNIQUE,
|
|
372
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
373
|
+
usage_count INTEGER NOT NULL DEFAULT 0
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
-- junction table for memory-tag relationships
|
|
377
|
+
CREATE TABLE IF NOT EXISTS memory_tags (
|
|
378
|
+
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
379
|
+
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
380
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
381
|
+
PRIMARY KEY (memory_id, tag_id)
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
CREATE INDEX IF NOT EXISTS idx_tags_name ON tags(name);
|
|
385
|
+
CREATE INDEX IF NOT EXISTS idx_tags_usage ON tags(usage_count DESC);
|
|
386
|
+
CREATE INDEX IF NOT EXISTS idx_memory_tags_memory ON memory_tags(memory_id);
|
|
387
|
+
CREATE INDEX IF NOT EXISTS idx_memory_tags_tag ON memory_tags(tag_id);
|
|
388
|
+
`,
|
|
389
|
+
down: `
|
|
390
|
+
DROP TABLE IF EXISTS memory_tags CASCADE;
|
|
391
|
+
DROP TABLE IF EXISTS tags CASCADE;
|
|
392
|
+
`,
|
|
393
|
+
checksum: this.generateChecksum('create_tags_table_v6')
|
|
394
|
+
},
|
|
395
|
+
// migration 7: create consolidation history
|
|
396
|
+
{
|
|
397
|
+
version: 7,
|
|
398
|
+
name: 'create_consolidation_history',
|
|
399
|
+
up: `
|
|
400
|
+
-- tracks consolidation runs for debugging and optimization
|
|
401
|
+
CREATE TABLE IF NOT EXISTS consolidation_history (
|
|
402
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
403
|
+
strategy VARCHAR(50) NOT NULL,
|
|
404
|
+
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
405
|
+
completed_at TIMESTAMPTZ,
|
|
406
|
+
memories_processed INTEGER DEFAULT 0,
|
|
407
|
+
memories_consolidated INTEGER DEFAULT 0,
|
|
408
|
+
clusters_found INTEGER DEFAULT 0,
|
|
409
|
+
duration_ms INTEGER,
|
|
410
|
+
error_message TEXT,
|
|
411
|
+
metadata JSONB DEFAULT '{}'
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
CREATE INDEX IF NOT EXISTS idx_consolidation_started
|
|
415
|
+
ON consolidation_history(started_at DESC);
|
|
416
|
+
`,
|
|
417
|
+
down: `
|
|
418
|
+
DROP TABLE IF EXISTS consolidation_history CASCADE;
|
|
419
|
+
`,
|
|
420
|
+
checksum: this.generateChecksum('create_consolidation_history_v7')
|
|
421
|
+
},
|
|
422
|
+
// migration 8: create updated_at trigger
|
|
423
|
+
{
|
|
424
|
+
version: 8,
|
|
425
|
+
name: 'create_updated_at_trigger',
|
|
426
|
+
up: `
|
|
427
|
+
-- auto-update updated_at on any row change
|
|
428
|
+
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
429
|
+
RETURNS TRIGGER AS $$
|
|
430
|
+
BEGIN
|
|
431
|
+
NEW.updated_at = NOW();
|
|
432
|
+
RETURN NEW;
|
|
433
|
+
END;
|
|
434
|
+
$$ LANGUAGE plpgsql;
|
|
435
|
+
|
|
436
|
+
-- apply to memories table
|
|
437
|
+
DROP TRIGGER IF EXISTS memories_updated_at ON memories;
|
|
438
|
+
CREATE TRIGGER memories_updated_at
|
|
439
|
+
BEFORE UPDATE ON memories
|
|
440
|
+
FOR EACH ROW
|
|
441
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
442
|
+
`,
|
|
443
|
+
down: `
|
|
444
|
+
DROP TRIGGER IF EXISTS memories_updated_at ON memories;
|
|
445
|
+
DROP FUNCTION IF EXISTS update_updated_at_column();
|
|
446
|
+
`,
|
|
447
|
+
checksum: this.generateChecksum('create_updated_at_trigger_v8')
|
|
448
|
+
},
|
|
449
|
+
// migration 9: create partitioning for memories (for massive scale)
|
|
450
|
+
{
|
|
451
|
+
version: 9,
|
|
452
|
+
name: 'create_partitions_prep',
|
|
453
|
+
up: `
|
|
454
|
+
-- nah we're keeping the table as-is for now
|
|
455
|
+
-- partitioning requires recreating the table and that's risky
|
|
456
|
+
-- but we'll add a view for time-based access patterns
|
|
457
|
+
|
|
458
|
+
CREATE OR REPLACE VIEW memories_recent AS
|
|
459
|
+
SELECT * FROM memories
|
|
460
|
+
WHERE created_at > NOW() - INTERVAL '30 days'
|
|
461
|
+
AND (expires_at IS NULL OR expires_at > NOW());
|
|
462
|
+
|
|
463
|
+
CREATE OR REPLACE VIEW memories_active AS
|
|
464
|
+
SELECT * FROM memories
|
|
465
|
+
WHERE (expires_at IS NULL OR expires_at > NOW())
|
|
466
|
+
AND memory_type != 'consolidated';
|
|
467
|
+
`,
|
|
468
|
+
down: `
|
|
469
|
+
DROP VIEW IF EXISTS memories_active;
|
|
470
|
+
DROP VIEW IF EXISTS memories_recent;
|
|
471
|
+
`,
|
|
472
|
+
checksum: this.generateChecksum('create_partitions_prep_v9')
|
|
473
|
+
},
|
|
474
|
+
// migration 10: create embedding cache table
|
|
475
|
+
{
|
|
476
|
+
version: 10,
|
|
477
|
+
name: 'create_embedding_cache',
|
|
478
|
+
up: `
|
|
479
|
+
-- cache embeddings to avoid recomputing them
|
|
480
|
+
-- content_hash -> embedding mapping
|
|
481
|
+
-- NOTE: Dimension is auto-detected, unbounded initially
|
|
482
|
+
CREATE TABLE IF NOT EXISTS embedding_cache (
|
|
483
|
+
content_hash VARCHAR(64) PRIMARY KEY,
|
|
484
|
+
embedding vector(384) NOT NULL,
|
|
485
|
+
model VARCHAR(100) NOT NULL DEFAULT 'text-embedding-3-small',
|
|
486
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
487
|
+
last_used_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
488
|
+
hit_count INTEGER NOT NULL DEFAULT 0
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
CREATE INDEX IF NOT EXISTS idx_embedding_cache_model
|
|
492
|
+
ON embedding_cache(model);
|
|
493
|
+
CREATE INDEX IF NOT EXISTS idx_embedding_cache_used
|
|
494
|
+
ON embedding_cache(last_used_at);
|
|
495
|
+
`,
|
|
496
|
+
down: `
|
|
497
|
+
DROP TABLE IF EXISTS embedding_cache CASCADE;
|
|
498
|
+
`,
|
|
499
|
+
checksum: this.generateChecksum('create_embedding_cache_v10')
|
|
500
|
+
},
|
|
501
|
+
// migration 11: add composite indexes for common queries
|
|
502
|
+
{
|
|
503
|
+
version: 11,
|
|
504
|
+
name: 'create_composite_indexes',
|
|
505
|
+
up: `
|
|
506
|
+
-- composite indexes for common query patterns
|
|
507
|
+
|
|
508
|
+
-- search by type + importance
|
|
509
|
+
CREATE INDEX IF NOT EXISTS idx_memories_type_importance
|
|
510
|
+
ON memories(memory_type, importance);
|
|
511
|
+
|
|
512
|
+
-- search by type + created
|
|
513
|
+
CREATE INDEX IF NOT EXISTS idx_memories_type_created
|
|
514
|
+
ON memories(memory_type, created_at DESC);
|
|
515
|
+
|
|
516
|
+
-- non-expired memories ordered by access (no NOW() - not IMMUTABLE)
|
|
517
|
+
-- use expires_at IS NULL for permanent memories - expiring ones filtered at query time
|
|
518
|
+
CREATE INDEX IF NOT EXISTS idx_memories_active_access
|
|
519
|
+
ON memories(access_count DESC, last_accessed_at DESC)
|
|
520
|
+
WHERE expires_at IS NULL;
|
|
521
|
+
|
|
522
|
+
-- separate index for memories with expiration (for cleanup queries)
|
|
523
|
+
CREATE INDEX IF NOT EXISTS idx_memories_expiring
|
|
524
|
+
ON memories(expires_at)
|
|
525
|
+
WHERE expires_at IS NOT NULL;
|
|
526
|
+
|
|
527
|
+
-- content length for analytics (length() is IMMUTABLE)
|
|
528
|
+
CREATE INDEX IF NOT EXISTS idx_memories_content_length
|
|
529
|
+
ON memories(length(content));
|
|
530
|
+
`,
|
|
531
|
+
down: `
|
|
532
|
+
DROP INDEX IF EXISTS idx_memories_type_importance;
|
|
533
|
+
DROP INDEX IF EXISTS idx_memories_type_created;
|
|
534
|
+
DROP INDEX IF EXISTS idx_memories_active_access;
|
|
535
|
+
DROP INDEX IF EXISTS idx_memories_expiring;
|
|
536
|
+
DROP INDEX IF EXISTS idx_memories_content_length;
|
|
537
|
+
`,
|
|
538
|
+
checksum: this.generateChecksum('create_composite_indexes_v11_fixed')
|
|
539
|
+
},
|
|
540
|
+
// migration 12: create stats materialized view
|
|
541
|
+
{
|
|
542
|
+
version: 12,
|
|
543
|
+
name: 'create_stats_view',
|
|
544
|
+
up: `
|
|
545
|
+
-- materialized view for fast stats queries
|
|
546
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS memory_stats AS
|
|
547
|
+
SELECT
|
|
548
|
+
COUNT(*) as total_memories,
|
|
549
|
+
COUNT(*) FILTER (WHERE memory_type = 'episodic') as episodic_count,
|
|
550
|
+
COUNT(*) FILTER (WHERE memory_type = 'semantic') as semantic_count,
|
|
551
|
+
COUNT(*) FILTER (WHERE memory_type = 'procedural') as procedural_count,
|
|
552
|
+
COUNT(*) FILTER (WHERE memory_type = 'working') as working_count,
|
|
553
|
+
COUNT(*) FILTER (WHERE memory_type = 'consolidated') as consolidated_count,
|
|
554
|
+
COUNT(*) FILTER (WHERE importance = 'critical') as critical_count,
|
|
555
|
+
COUNT(*) FILTER (WHERE importance = 'high') as high_count,
|
|
556
|
+
COUNT(*) FILTER (WHERE image_data IS NOT NULL) as with_images,
|
|
557
|
+
COUNT(*) FILTER (WHERE embedding IS NOT NULL) as with_embeddings,
|
|
558
|
+
COUNT(*) FILTER (WHERE expires_at IS NOT NULL AND expires_at < NOW()) as expired_count,
|
|
559
|
+
AVG(access_count)::FLOAT as avg_access_count,
|
|
560
|
+
AVG(length(content))::FLOAT as avg_content_length,
|
|
561
|
+
MIN(created_at) as oldest_memory,
|
|
562
|
+
MAX(created_at) as newest_memory,
|
|
563
|
+
NOW() as computed_at
|
|
564
|
+
FROM memories;
|
|
565
|
+
|
|
566
|
+
-- index on the materialized view
|
|
567
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_stats_singleton
|
|
568
|
+
ON memory_stats(computed_at);
|
|
569
|
+
|
|
570
|
+
-- function to refresh stats
|
|
571
|
+
CREATE OR REPLACE FUNCTION refresh_memory_stats()
|
|
572
|
+
RETURNS void AS $$
|
|
573
|
+
BEGIN
|
|
574
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY memory_stats;
|
|
575
|
+
END;
|
|
576
|
+
$$ LANGUAGE plpgsql;
|
|
577
|
+
`,
|
|
578
|
+
down: `
|
|
579
|
+
DROP FUNCTION IF EXISTS refresh_memory_stats();
|
|
580
|
+
DROP MATERIALIZED VIEW IF EXISTS memory_stats;
|
|
581
|
+
`,
|
|
582
|
+
checksum: this.generateChecksum('create_stats_view_v12')
|
|
583
|
+
},
|
|
584
|
+
// migration 13: create codebase_files table for ingestThisWholeAssMfCodebase
|
|
585
|
+
{
|
|
586
|
+
version: 13,
|
|
587
|
+
name: 'create_codebase_files_table',
|
|
588
|
+
up: `
|
|
589
|
+
-- yooo this table holds ENTIRE CODEBASES in memory
|
|
590
|
+
-- we about to store MILLIONS of lines of code fr fr
|
|
591
|
+
CREATE TABLE IF NOT EXISTS codebase_files (
|
|
592
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
593
|
+
|
|
594
|
+
-- file identification
|
|
595
|
+
file_path TEXT NOT NULL, -- relative path from root
|
|
596
|
+
absolute_path TEXT NOT NULL, -- full system path
|
|
597
|
+
file_name VARCHAR(255) NOT NULL, -- just the filename
|
|
598
|
+
extension VARCHAR(50), -- file extension
|
|
599
|
+
|
|
600
|
+
-- language detection
|
|
601
|
+
language_id VARCHAR(50) NOT NULL DEFAULT 'unknown',
|
|
602
|
+
language_name VARCHAR(100) NOT NULL DEFAULT 'Unknown',
|
|
603
|
+
language_type VARCHAR(50) NOT NULL DEFAULT 'data',
|
|
604
|
+
|
|
605
|
+
-- content storage
|
|
606
|
+
content TEXT NOT NULL,
|
|
607
|
+
content_hash VARCHAR(64), -- computed by application, not GENERATED (avoids bytea cast issues)
|
|
608
|
+
content_tsv TSVECTOR GENERATED ALWAYS AS (
|
|
609
|
+
to_tsvector('english', content)
|
|
610
|
+
) STORED,
|
|
611
|
+
|
|
612
|
+
-- file stats
|
|
613
|
+
size_bytes INTEGER NOT NULL DEFAULT 0,
|
|
614
|
+
line_count INTEGER NOT NULL DEFAULT 0,
|
|
615
|
+
char_count INTEGER NOT NULL DEFAULT 0,
|
|
616
|
+
last_modified TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
617
|
+
|
|
618
|
+
-- chunking support for MASSIVE files
|
|
619
|
+
chunk_index INTEGER, -- null = not chunked, 0+ = chunk number
|
|
620
|
+
total_chunks INTEGER, -- total chunks if chunked
|
|
621
|
+
original_file_id UUID, -- parent file if this is a chunk
|
|
622
|
+
|
|
623
|
+
-- EMBEDDINGS for semantic code search
|
|
624
|
+
-- NOTE: Dimension is auto-detected, unbounded initially
|
|
625
|
+
embedding vector(384),
|
|
626
|
+
|
|
627
|
+
-- timestamps
|
|
628
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
629
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
630
|
+
|
|
631
|
+
-- constraints
|
|
632
|
+
CONSTRAINT content_not_empty CHECK (length(content) > 0),
|
|
633
|
+
CONSTRAINT valid_chunk CHECK (
|
|
634
|
+
(chunk_index IS NULL AND total_chunks IS NULL AND original_file_id IS NULL) OR
|
|
635
|
+
(chunk_index IS NOT NULL AND total_chunks IS NOT NULL AND original_file_id IS NOT NULL)
|
|
636
|
+
)
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
-- index for content hash deduplication
|
|
640
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_codebase_files_content_hash
|
|
641
|
+
ON codebase_files(content_hash);
|
|
642
|
+
|
|
643
|
+
-- full-text search index for code search
|
|
644
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_content_tsv
|
|
645
|
+
ON codebase_files USING GIN(content_tsv);
|
|
646
|
+
|
|
647
|
+
-- file path searches
|
|
648
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_path
|
|
649
|
+
ON codebase_files(file_path);
|
|
650
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_path_trgm
|
|
651
|
+
ON codebase_files USING GIN(file_path gin_trgm_ops);
|
|
652
|
+
|
|
653
|
+
-- language filtering
|
|
654
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_language
|
|
655
|
+
ON codebase_files(language_id);
|
|
656
|
+
|
|
657
|
+
-- chunk lookups
|
|
658
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_original
|
|
659
|
+
ON codebase_files(original_file_id)
|
|
660
|
+
WHERE original_file_id IS NOT NULL;
|
|
661
|
+
|
|
662
|
+
-- time-based queries
|
|
663
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_modified
|
|
664
|
+
ON codebase_files(last_modified DESC);
|
|
665
|
+
|
|
666
|
+
-- HNSW index for FAST semantic code search
|
|
667
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_embedding_hnsw
|
|
668
|
+
ON codebase_files
|
|
669
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
670
|
+
WITH (m = 16, ef_construction = 64);
|
|
671
|
+
|
|
672
|
+
-- trigger for updated_at
|
|
673
|
+
DROP TRIGGER IF EXISTS codebase_files_updated_at ON codebase_files;
|
|
674
|
+
CREATE TRIGGER codebase_files_updated_at
|
|
675
|
+
BEFORE UPDATE ON codebase_files
|
|
676
|
+
FOR EACH ROW
|
|
677
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
678
|
+
`,
|
|
679
|
+
down: `
|
|
680
|
+
DROP TRIGGER IF EXISTS codebase_files_updated_at ON codebase_files;
|
|
681
|
+
DROP TABLE IF EXISTS codebase_files CASCADE;
|
|
682
|
+
`,
|
|
683
|
+
checksum: this.generateChecksum('create_codebase_files_table_v13')
|
|
684
|
+
},
|
|
685
|
+
// migration 14: create codebase stats materialized view
|
|
686
|
+
{
|
|
687
|
+
version: 14,
|
|
688
|
+
name: 'create_codebase_stats_view',
|
|
689
|
+
up: `
|
|
690
|
+
-- materialized view for codebase stats - codebaseStatsGoCrazy
|
|
691
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS codebase_stats AS
|
|
692
|
+
SELECT
|
|
693
|
+
COUNT(*) as total_files,
|
|
694
|
+
COUNT(*) FILTER (WHERE chunk_index IS NOT NULL) as total_chunks,
|
|
695
|
+
COUNT(*) FILTER (WHERE chunk_index IS NULL) as unique_files,
|
|
696
|
+
SUM(line_count) as total_lines,
|
|
697
|
+
SUM(size_bytes) as total_bytes,
|
|
698
|
+
COUNT(DISTINCT language_id) as language_count,
|
|
699
|
+
COUNT(*) FILTER (WHERE embedding IS NOT NULL) as files_with_embeddings,
|
|
700
|
+
MIN(last_modified) as oldest_file,
|
|
701
|
+
MAX(last_modified) as newest_file,
|
|
702
|
+
NOW() as computed_at
|
|
703
|
+
FROM codebase_files;
|
|
704
|
+
|
|
705
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_codebase_stats_singleton
|
|
706
|
+
ON codebase_stats(computed_at);
|
|
707
|
+
|
|
708
|
+
-- function to refresh codebase stats
|
|
709
|
+
CREATE OR REPLACE FUNCTION refresh_codebase_stats()
|
|
710
|
+
RETURNS void AS $$
|
|
711
|
+
BEGIN
|
|
712
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY codebase_stats;
|
|
713
|
+
END;
|
|
714
|
+
$$ LANGUAGE plpgsql;
|
|
715
|
+
`,
|
|
716
|
+
down: `
|
|
717
|
+
DROP FUNCTION IF EXISTS refresh_codebase_stats();
|
|
718
|
+
DROP MATERIALIZED VIEW IF EXISTS codebase_stats;
|
|
719
|
+
`,
|
|
720
|
+
checksum: this.generateChecksum('create_codebase_stats_view_v14')
|
|
721
|
+
},
|
|
722
|
+
// migration 15: create dependency_history table
|
|
723
|
+
{
|
|
724
|
+
version: 15,
|
|
725
|
+
name: 'create_dependency_history_table',
|
|
726
|
+
up: `
|
|
727
|
+
-- yooo tracking package.json changes without indexing node_modules
|
|
728
|
+
-- this is the BIG BRAIN move fr fr
|
|
729
|
+
CREATE TABLE IF NOT EXISTS dependency_history (
|
|
730
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
731
|
+
|
|
732
|
+
-- package identification
|
|
733
|
+
package_name VARCHAR(255) NOT NULL,
|
|
734
|
+
version VARCHAR(100),
|
|
735
|
+
|
|
736
|
+
-- event tracking
|
|
737
|
+
event_type VARCHAR(20) NOT NULL CHECK (event_type IN ('added', 'updated', 'removed')),
|
|
738
|
+
package_type VARCHAR(20) NOT NULL CHECK (package_type IN (
|
|
739
|
+
'dependency',
|
|
740
|
+
'devDependency',
|
|
741
|
+
'peerDependency',
|
|
742
|
+
'optionalDependency'
|
|
743
|
+
)),
|
|
744
|
+
|
|
745
|
+
-- timestamp
|
|
746
|
+
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
747
|
+
|
|
748
|
+
-- source context
|
|
749
|
+
package_json_path TEXT NOT NULL,
|
|
750
|
+
project_name VARCHAR(255),
|
|
751
|
+
|
|
752
|
+
-- metadata for storing old/new versions during updates
|
|
753
|
+
metadata JSONB,
|
|
754
|
+
|
|
755
|
+
-- timestamps
|
|
756
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
-- index for package name lookups - whenDidWeAddThisPackage
|
|
760
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_package_name
|
|
761
|
+
ON dependency_history(package_name);
|
|
762
|
+
|
|
763
|
+
-- index for event type filtering
|
|
764
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_event_type
|
|
765
|
+
ON dependency_history(event_type);
|
|
766
|
+
|
|
767
|
+
-- index for package type filtering
|
|
768
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_package_type
|
|
769
|
+
ON dependency_history(package_type);
|
|
770
|
+
|
|
771
|
+
-- index for timestamp-based queries - recent changes
|
|
772
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_timestamp
|
|
773
|
+
ON dependency_history(timestamp DESC);
|
|
774
|
+
|
|
775
|
+
-- index for project lookups
|
|
776
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_project
|
|
777
|
+
ON dependency_history(project_name)
|
|
778
|
+
WHERE project_name IS NOT NULL;
|
|
779
|
+
|
|
780
|
+
-- composite index for package + path lookups
|
|
781
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_package_path
|
|
782
|
+
ON dependency_history(package_name, package_json_path);
|
|
783
|
+
|
|
784
|
+
-- composite index for common queries
|
|
785
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_event_timestamp
|
|
786
|
+
ON dependency_history(event_type, timestamp DESC);
|
|
787
|
+
|
|
788
|
+
-- GIN index for JSONB metadata queries
|
|
789
|
+
CREATE INDEX IF NOT EXISTS idx_dependency_history_metadata
|
|
790
|
+
ON dependency_history USING GIN(metadata);
|
|
791
|
+
`,
|
|
792
|
+
down: `
|
|
793
|
+
DROP TABLE IF EXISTS dependency_history CASCADE;
|
|
794
|
+
`,
|
|
795
|
+
checksum: this.generateChecksum('create_dependency_history_table_v15')
|
|
796
|
+
},
|
|
797
|
+
// migration 16: create claude_code_history table
|
|
798
|
+
// yooo about to remember EVERYTHING it writes
|
|
799
|
+
// no more massive explores needed fr
|
|
800
|
+
{
|
|
801
|
+
version: 16,
|
|
802
|
+
name: 'create_claude_code_history',
|
|
803
|
+
up: `
|
|
804
|
+
-- yooo about to remember EVERYTHING it writes
|
|
805
|
+
-- no more massive explores needed fr
|
|
806
|
+
|
|
807
|
+
-- main table for tracking 's code
|
|
808
|
+
CREATE TABLE IF NOT EXISTS claude_code_history (
|
|
809
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
810
|
+
|
|
811
|
+
-- what did write?
|
|
812
|
+
file_path TEXT NOT NULL,
|
|
813
|
+
file_name VARCHAR(255) NOT NULL,
|
|
814
|
+
code_content TEXT NOT NULL,
|
|
815
|
+
code_hash VARCHAR(64) GENERATED ALWAYS AS (
|
|
816
|
+
encode(sha256(code_content::bytea), 'hex')
|
|
817
|
+
) STORED,
|
|
818
|
+
|
|
819
|
+
-- why did write it?
|
|
820
|
+
purpose TEXT NOT NULL,
|
|
821
|
+
conversation_context TEXT,
|
|
822
|
+
|
|
823
|
+
-- classification
|
|
824
|
+
operation_type VARCHAR(50) NOT NULL DEFAULT 'write',
|
|
825
|
+
language VARCHAR(50) NOT NULL DEFAULT 'unknown',
|
|
826
|
+
|
|
827
|
+
-- relationships
|
|
828
|
+
related_files TEXT[] NOT NULL DEFAULT '{}',
|
|
829
|
+
related_memory_ids UUID[] DEFAULT '{}',
|
|
830
|
+
parent_code_id UUID REFERENCES claude_code_history(id),
|
|
831
|
+
|
|
832
|
+
-- tagging for searchability
|
|
833
|
+
tags TEXT[] NOT NULL DEFAULT '{}',
|
|
834
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
835
|
+
|
|
836
|
+
-- EMBEDDINGS for semantic search
|
|
837
|
+
-- NOTE: Dimension is auto-detected, unbounded initially
|
|
838
|
+
embedding vector(384),
|
|
839
|
+
|
|
840
|
+
-- full text search
|
|
841
|
+
content_tsv TSVECTOR GENERATED ALWAYS AS (
|
|
842
|
+
to_tsvector('english', code_content || ' ' || purpose)
|
|
843
|
+
) STORED,
|
|
844
|
+
|
|
845
|
+
-- timestamps
|
|
846
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
847
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
848
|
+
|
|
849
|
+
-- version tracking for same file
|
|
850
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
851
|
+
|
|
852
|
+
-- constraints
|
|
853
|
+
CONSTRAINT code_not_empty CHECK (length(code_content) > 0),
|
|
854
|
+
CONSTRAINT purpose_not_empty CHECK (length(purpose) > 0),
|
|
855
|
+
CONSTRAINT valid_operation CHECK (
|
|
856
|
+
operation_type IN ('write', 'edit', 'notebook_edit', 'create', 'update', 'delete')
|
|
857
|
+
)
|
|
858
|
+
);
|
|
859
|
+
|
|
860
|
+
-- indexes for FAST lookups
|
|
861
|
+
|
|
862
|
+
-- file path searches
|
|
863
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_file_path
|
|
864
|
+
ON claude_code_history(file_path);
|
|
865
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_file_path_trgm
|
|
866
|
+
ON claude_code_history USING GIN(file_path gin_trgm_ops);
|
|
867
|
+
|
|
868
|
+
-- content hash for deduplication
|
|
869
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_hash
|
|
870
|
+
ON claude_code_history(code_hash);
|
|
871
|
+
|
|
872
|
+
-- full-text search on code + purpose
|
|
873
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_tsv
|
|
874
|
+
ON claude_code_history USING GIN(content_tsv);
|
|
875
|
+
|
|
876
|
+
-- tag searches
|
|
877
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_tags
|
|
878
|
+
ON claude_code_history USING GIN(tags);
|
|
879
|
+
|
|
880
|
+
-- metadata JSONB searches
|
|
881
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_metadata
|
|
882
|
+
ON claude_code_history USING GIN(metadata jsonb_path_ops);
|
|
883
|
+
|
|
884
|
+
-- language filtering
|
|
885
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_language
|
|
886
|
+
ON claude_code_history(language);
|
|
887
|
+
|
|
888
|
+
-- operation type filtering
|
|
889
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_operation
|
|
890
|
+
ON claude_code_history(operation_type);
|
|
891
|
+
|
|
892
|
+
-- time-based queries
|
|
893
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_created
|
|
894
|
+
ON claude_code_history(created_at DESC);
|
|
895
|
+
|
|
896
|
+
-- version tracking for same file
|
|
897
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_file_version
|
|
898
|
+
ON claude_code_history(file_path, version DESC);
|
|
899
|
+
|
|
900
|
+
-- HNSW vector index for semantic code search
|
|
901
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_embedding_hnsw
|
|
902
|
+
ON claude_code_history
|
|
903
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
904
|
+
WITH (m = 16, ef_construction = 64);
|
|
905
|
+
|
|
906
|
+
-- related files search
|
|
907
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_related
|
|
908
|
+
ON claude_code_history USING GIN(related_files);
|
|
909
|
+
|
|
910
|
+
-- parent-child relationship
|
|
911
|
+
CREATE INDEX IF NOT EXISTS idx_claude_code_parent
|
|
912
|
+
ON claude_code_history(parent_code_id)
|
|
913
|
+
WHERE parent_code_id IS NOT NULL;
|
|
914
|
+
|
|
915
|
+
-- trigger for updated_at
|
|
916
|
+
DROP TRIGGER IF EXISTS claude_code_history_updated_at ON claude_code_history;
|
|
917
|
+
CREATE TRIGGER claude_code_history_updated_at
|
|
918
|
+
BEFORE UPDATE ON claude_code_history
|
|
919
|
+
FOR EACH ROW
|
|
920
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
921
|
+
|
|
922
|
+
-- materialized view for code stats
|
|
923
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS claude_code_stats AS
|
|
924
|
+
SELECT
|
|
925
|
+
COUNT(*) as total_code_entries,
|
|
926
|
+
COUNT(DISTINCT file_path) as unique_files,
|
|
927
|
+
COUNT(*) FILTER (WHERE operation_type = 'write') as writes,
|
|
928
|
+
COUNT(*) FILTER (WHERE operation_type = 'edit') as edits,
|
|
929
|
+
COUNT(*) FILTER (WHERE operation_type = 'create') as creates,
|
|
930
|
+
COUNT(*) FILTER (WHERE embedding IS NOT NULL) as with_embeddings,
|
|
931
|
+
SUM(length(code_content)) as total_characters,
|
|
932
|
+
AVG(length(code_content))::INTEGER as avg_code_length,
|
|
933
|
+
MIN(created_at) as oldest_code,
|
|
934
|
+
MAX(created_at) as newest_code,
|
|
935
|
+
NOW() as computed_at
|
|
936
|
+
FROM claude_code_history;
|
|
937
|
+
|
|
938
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_claude_code_stats_singleton
|
|
939
|
+
ON claude_code_stats(computed_at);
|
|
940
|
+
|
|
941
|
+
-- function to refresh claude code stats
|
|
942
|
+
CREATE OR REPLACE FUNCTION refresh_claude_code_stats()
|
|
943
|
+
RETURNS void AS $$
|
|
944
|
+
BEGIN
|
|
945
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY claude_code_stats;
|
|
946
|
+
END;
|
|
947
|
+
$$ LANGUAGE plpgsql;
|
|
948
|
+
`,
|
|
949
|
+
down: `
|
|
950
|
+
DROP FUNCTION IF EXISTS refresh_claude_code_stats();
|
|
951
|
+
DROP MATERIALIZED VIEW IF EXISTS claude_code_stats;
|
|
952
|
+
DROP TRIGGER IF EXISTS claude_code_history_updated_at ON claude_code_history;
|
|
953
|
+
DROP TABLE IF EXISTS claude_code_history CASCADE;
|
|
954
|
+
`,
|
|
955
|
+
checksum: this.generateChecksum('create_claude_code_history_v16')
|
|
956
|
+
},
|
|
957
|
+
// migration 17: create code_chunks table for semantic search
|
|
958
|
+
// yooo this is where the MAGIC happens
|
|
959
|
+
// chunks of code with embeddings for findSimilarCode
|
|
960
|
+
{
|
|
961
|
+
version: 17,
|
|
962
|
+
name: 'create_code_chunks_table',
|
|
963
|
+
up: `
|
|
964
|
+
-- code_chunks - SEMANTIC CODE SEARCH goes CRAZY here
|
|
965
|
+
-- stores code chunks with embeddings for similarity search
|
|
966
|
+
-- this is how we find similar code across the ENTIRE codebase
|
|
967
|
+
CREATE TABLE IF NOT EXISTS code_chunks (
|
|
968
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
969
|
+
|
|
970
|
+
-- reference to parent file
|
|
971
|
+
file_id UUID NOT NULL REFERENCES codebase_files(id) ON DELETE CASCADE,
|
|
972
|
+
file_path TEXT NOT NULL,
|
|
973
|
+
|
|
974
|
+
-- chunk positioning
|
|
975
|
+
chunk_index INTEGER NOT NULL DEFAULT 0,
|
|
976
|
+
start_line INTEGER NOT NULL,
|
|
977
|
+
end_line INTEGER NOT NULL,
|
|
978
|
+
start_char INTEGER NOT NULL DEFAULT 0,
|
|
979
|
+
end_char INTEGER NOT NULL DEFAULT 0,
|
|
980
|
+
|
|
981
|
+
-- chunk content and metadata
|
|
982
|
+
content TEXT NOT NULL,
|
|
983
|
+
content_hash VARCHAR(64) GENERATED ALWAYS AS (
|
|
984
|
+
encode(sha256(content::bytea), 'hex')
|
|
985
|
+
) STORED,
|
|
986
|
+
|
|
987
|
+
-- language and context
|
|
988
|
+
language VARCHAR(50) NOT NULL DEFAULT 'unknown',
|
|
989
|
+
chunk_type VARCHAR(50) NOT NULL DEFAULT 'code', -- code, comment, docstring, mixed
|
|
990
|
+
|
|
991
|
+
-- semantic context
|
|
992
|
+
context_before TEXT, -- few lines before for context
|
|
993
|
+
context_after TEXT, -- few lines after for context
|
|
994
|
+
|
|
995
|
+
-- EMBEDDINGS - the secret sauce for semantic search
|
|
996
|
+
-- NOTE: Dimension is auto-detected, unbounded initially
|
|
997
|
+
embedding vector(384),
|
|
998
|
+
|
|
999
|
+
-- full text search
|
|
1000
|
+
content_tsv TSVECTOR GENERATED ALWAYS AS (
|
|
1001
|
+
to_tsvector('english', content)
|
|
1002
|
+
) STORED,
|
|
1003
|
+
|
|
1004
|
+
-- metadata
|
|
1005
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
1006
|
+
|
|
1007
|
+
-- timestamps
|
|
1008
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1009
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1010
|
+
|
|
1011
|
+
-- constraints
|
|
1012
|
+
CONSTRAINT chunk_not_empty CHECK (length(content) > 0),
|
|
1013
|
+
CONSTRAINT valid_lines CHECK (end_line >= start_line),
|
|
1014
|
+
CONSTRAINT valid_chunk_type CHECK (
|
|
1015
|
+
chunk_type IN ('code', 'comment', 'docstring', 'mixed', 'import', 'definition')
|
|
1016
|
+
)
|
|
1017
|
+
);
|
|
1018
|
+
|
|
1019
|
+
-- indexes for BLAZING FAST lookups
|
|
1020
|
+
|
|
1021
|
+
-- file lookups
|
|
1022
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_file_id
|
|
1023
|
+
ON code_chunks(file_id);
|
|
1024
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_file_path
|
|
1025
|
+
ON code_chunks(file_path);
|
|
1026
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_file_path_trgm
|
|
1027
|
+
ON code_chunks USING GIN(file_path gin_trgm_ops);
|
|
1028
|
+
|
|
1029
|
+
-- chunk ordering within file
|
|
1030
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_file_order
|
|
1031
|
+
ON code_chunks(file_id, chunk_index);
|
|
1032
|
+
|
|
1033
|
+
-- line range queries
|
|
1034
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_lines
|
|
1035
|
+
ON code_chunks(file_id, start_line, end_line);
|
|
1036
|
+
|
|
1037
|
+
-- content hash for deduplication
|
|
1038
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_hash
|
|
1039
|
+
ON code_chunks(content_hash);
|
|
1040
|
+
|
|
1041
|
+
-- language filtering
|
|
1042
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_language
|
|
1043
|
+
ON code_chunks(language);
|
|
1044
|
+
|
|
1045
|
+
-- chunk type filtering
|
|
1046
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_type
|
|
1047
|
+
ON code_chunks(chunk_type);
|
|
1048
|
+
|
|
1049
|
+
-- full-text search
|
|
1050
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_tsv
|
|
1051
|
+
ON code_chunks USING GIN(content_tsv);
|
|
1052
|
+
|
|
1053
|
+
-- HNSW vector index for FAST semantic search
|
|
1054
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_embedding_hnsw
|
|
1055
|
+
ON code_chunks
|
|
1056
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
1057
|
+
WITH (m = 16, ef_construction = 64);
|
|
1058
|
+
|
|
1059
|
+
-- metadata queries
|
|
1060
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_metadata
|
|
1061
|
+
ON code_chunks USING GIN(metadata jsonb_path_ops);
|
|
1062
|
+
|
|
1063
|
+
-- time-based queries
|
|
1064
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_created
|
|
1065
|
+
ON code_chunks(created_at DESC);
|
|
1066
|
+
|
|
1067
|
+
-- trigger for updated_at
|
|
1068
|
+
DROP TRIGGER IF EXISTS code_chunks_updated_at ON code_chunks;
|
|
1069
|
+
CREATE TRIGGER code_chunks_updated_at
|
|
1070
|
+
BEFORE UPDATE ON code_chunks
|
|
1071
|
+
FOR EACH ROW
|
|
1072
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
1073
|
+
`,
|
|
1074
|
+
down: `
|
|
1075
|
+
DROP TRIGGER IF EXISTS code_chunks_updated_at ON code_chunks;
|
|
1076
|
+
DROP TABLE IF EXISTS code_chunks CASCADE;
|
|
1077
|
+
`,
|
|
1078
|
+
checksum: this.generateChecksum('create_code_chunks_table_v17')
|
|
1079
|
+
},
|
|
1080
|
+
// migration 18: create code_definitions table
|
|
1081
|
+
// tracks all function/class/variable definitions
|
|
1082
|
+
// this is how we know WHAT code exists in the codebase
|
|
1083
|
+
{
|
|
1084
|
+
version: 18,
|
|
1085
|
+
name: 'create_code_definitions_table',
|
|
1086
|
+
up: `
|
|
1087
|
+
-- code_definitions - EVERY function, class, variable, etc
|
|
1088
|
+
-- this is your codebase's BRAIN MAP fr fr
|
|
1089
|
+
-- tracks signatures, types, exports, everything
|
|
1090
|
+
CREATE TABLE IF NOT EXISTS code_definitions (
|
|
1091
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
1092
|
+
|
|
1093
|
+
-- reference to parent file
|
|
1094
|
+
file_id UUID NOT NULL REFERENCES codebase_files(id) ON DELETE CASCADE,
|
|
1095
|
+
file_path TEXT NOT NULL,
|
|
1096
|
+
|
|
1097
|
+
-- definition identification
|
|
1098
|
+
name VARCHAR(500) NOT NULL,
|
|
1099
|
+
qualified_name TEXT, -- full path like module.class.method
|
|
1100
|
+
definition_type VARCHAR(50) NOT NULL, -- function, class, method, variable, interface, type, enum, constant
|
|
1101
|
+
|
|
1102
|
+
-- location
|
|
1103
|
+
start_line INTEGER NOT NULL,
|
|
1104
|
+
end_line INTEGER NOT NULL,
|
|
1105
|
+
start_column INTEGER DEFAULT 0,
|
|
1106
|
+
end_column INTEGER DEFAULT 0,
|
|
1107
|
+
|
|
1108
|
+
-- signature and documentation
|
|
1109
|
+
signature TEXT, -- full function/class signature
|
|
1110
|
+
docstring TEXT, -- extracted documentation
|
|
1111
|
+
return_type VARCHAR(255), -- for functions
|
|
1112
|
+
|
|
1113
|
+
-- visibility and scope
|
|
1114
|
+
visibility VARCHAR(20) DEFAULT 'public', -- public, private, protected, internal
|
|
1115
|
+
is_exported BOOLEAN DEFAULT false,
|
|
1116
|
+
is_async BOOLEAN DEFAULT false,
|
|
1117
|
+
is_static BOOLEAN DEFAULT false,
|
|
1118
|
+
is_abstract BOOLEAN DEFAULT false,
|
|
1119
|
+
|
|
1120
|
+
-- parent relationship (for nested definitions)
|
|
1121
|
+
parent_definition_id UUID REFERENCES code_definitions(id) ON DELETE CASCADE,
|
|
1122
|
+
|
|
1123
|
+
-- parameters (for functions/methods)
|
|
1124
|
+
parameters JSONB DEFAULT '[]', -- [{name, type, default, optional}]
|
|
1125
|
+
|
|
1126
|
+
-- language specific
|
|
1127
|
+
language VARCHAR(50) NOT NULL DEFAULT 'unknown',
|
|
1128
|
+
|
|
1129
|
+
-- decorators/annotations
|
|
1130
|
+
decorators TEXT[] DEFAULT '{}',
|
|
1131
|
+
|
|
1132
|
+
-- EMBEDDINGS for semantic search on definitions
|
|
1133
|
+
-- NOTE: Dimension is auto-detected, unbounded initially
|
|
1134
|
+
embedding vector(384),
|
|
1135
|
+
|
|
1136
|
+
-- full text search on name + signature + docstring
|
|
1137
|
+
definition_tsv TSVECTOR GENERATED ALWAYS AS (
|
|
1138
|
+
to_tsvector('english',
|
|
1139
|
+
COALESCE(name, '') || ' ' ||
|
|
1140
|
+
COALESCE(signature, '') || ' ' ||
|
|
1141
|
+
COALESCE(docstring, '')
|
|
1142
|
+
)
|
|
1143
|
+
) STORED,
|
|
1144
|
+
|
|
1145
|
+
-- metadata
|
|
1146
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
1147
|
+
|
|
1148
|
+
-- timestamps
|
|
1149
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1150
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1151
|
+
|
|
1152
|
+
-- constraints
|
|
1153
|
+
CONSTRAINT name_not_empty CHECK (length(name) > 0),
|
|
1154
|
+
CONSTRAINT valid_definition_type CHECK (
|
|
1155
|
+
definition_type IN (
|
|
1156
|
+
'function', 'method', 'class', 'interface', 'type', 'enum',
|
|
1157
|
+
'variable', 'constant', 'property', 'getter', 'setter',
|
|
1158
|
+
'constructor', 'decorator', 'module', 'namespace', 'trait',
|
|
1159
|
+
'struct', 'protocol', 'extension', 'mixin', 'alias'
|
|
1160
|
+
)
|
|
1161
|
+
),
|
|
1162
|
+
CONSTRAINT valid_visibility CHECK (
|
|
1163
|
+
visibility IN ('public', 'private', 'protected', 'internal', 'package')
|
|
1164
|
+
)
|
|
1165
|
+
);
|
|
1166
|
+
|
|
1167
|
+
-- indexes for LIGHTNING lookups
|
|
1168
|
+
|
|
1169
|
+
-- file lookups
|
|
1170
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_file_id
|
|
1171
|
+
ON code_definitions(file_id);
|
|
1172
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_file_path
|
|
1173
|
+
ON code_definitions(file_path);
|
|
1174
|
+
|
|
1175
|
+
-- name searches (the main use case)
|
|
1176
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_name
|
|
1177
|
+
ON code_definitions(name);
|
|
1178
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_name_trgm
|
|
1179
|
+
ON code_definitions USING GIN(name gin_trgm_ops);
|
|
1180
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_qualified
|
|
1181
|
+
ON code_definitions(qualified_name)
|
|
1182
|
+
WHERE qualified_name IS NOT NULL;
|
|
1183
|
+
|
|
1184
|
+
-- type filtering
|
|
1185
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_type
|
|
1186
|
+
ON code_definitions(definition_type);
|
|
1187
|
+
|
|
1188
|
+
-- language filtering
|
|
1189
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_language
|
|
1190
|
+
ON code_definitions(language);
|
|
1191
|
+
|
|
1192
|
+
-- exported definitions (for API surface)
|
|
1193
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_exported
|
|
1194
|
+
ON code_definitions(is_exported)
|
|
1195
|
+
WHERE is_exported = true;
|
|
1196
|
+
|
|
1197
|
+
-- parent-child relationships
|
|
1198
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_parent
|
|
1199
|
+
ON code_definitions(parent_definition_id)
|
|
1200
|
+
WHERE parent_definition_id IS NOT NULL;
|
|
1201
|
+
|
|
1202
|
+
-- full-text search
|
|
1203
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_tsv
|
|
1204
|
+
ON code_definitions USING GIN(definition_tsv);
|
|
1205
|
+
|
|
1206
|
+
-- HNSW vector index for semantic definition search
|
|
1207
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_embedding_hnsw
|
|
1208
|
+
ON code_definitions
|
|
1209
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
1210
|
+
WITH (m = 16, ef_construction = 64);
|
|
1211
|
+
|
|
1212
|
+
-- line lookups (for finding definition at cursor)
|
|
1213
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_lines
|
|
1214
|
+
ON code_definitions(file_id, start_line, end_line);
|
|
1215
|
+
|
|
1216
|
+
-- composite for common queries
|
|
1217
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_type_name
|
|
1218
|
+
ON code_definitions(definition_type, name);
|
|
1219
|
+
|
|
1220
|
+
-- time-based queries
|
|
1221
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_created
|
|
1222
|
+
ON code_definitions(created_at DESC);
|
|
1223
|
+
|
|
1224
|
+
-- trigger for updated_at
|
|
1225
|
+
DROP TRIGGER IF EXISTS code_definitions_updated_at ON code_definitions;
|
|
1226
|
+
CREATE TRIGGER code_definitions_updated_at
|
|
1227
|
+
BEFORE UPDATE ON code_definitions
|
|
1228
|
+
FOR EACH ROW
|
|
1229
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
1230
|
+
`,
|
|
1231
|
+
down: `
|
|
1232
|
+
DROP TRIGGER IF EXISTS code_definitions_updated_at ON code_definitions;
|
|
1233
|
+
DROP TABLE IF EXISTS code_definitions CASCADE;
|
|
1234
|
+
`,
|
|
1235
|
+
checksum: this.generateChecksum('create_code_definitions_table_v18')
|
|
1236
|
+
},
|
|
1237
|
+
// migration 19: create code_dependencies table
|
|
1238
|
+
// tracks ALL imports, requires, includes across the codebase
|
|
1239
|
+
// builds the full dependency graph fr fr
|
|
1240
|
+
{
|
|
1241
|
+
version: 19,
|
|
1242
|
+
name: 'create_code_dependencies_table',
|
|
1243
|
+
up: `
|
|
1244
|
+
-- code_dependencies - the DEPENDENCY GRAPH
|
|
1245
|
+
-- tracks every import, require, include in the codebase
|
|
1246
|
+
-- we can trace dependencies through the ENTIRE project
|
|
1247
|
+
CREATE TABLE IF NOT EXISTS code_dependencies (
|
|
1248
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
1249
|
+
|
|
1250
|
+
-- source file (the file doing the importing)
|
|
1251
|
+
source_file_id UUID NOT NULL REFERENCES codebase_files(id) ON DELETE CASCADE,
|
|
1252
|
+
source_file_path TEXT NOT NULL,
|
|
1253
|
+
|
|
1254
|
+
-- target (what's being imported)
|
|
1255
|
+
target_path TEXT NOT NULL, -- could be relative, absolute, or package name
|
|
1256
|
+
resolved_path TEXT, -- resolved absolute path if local file
|
|
1257
|
+
target_file_id UUID REFERENCES codebase_files(id) ON DELETE SET NULL,
|
|
1258
|
+
|
|
1259
|
+
-- import details
|
|
1260
|
+
import_type VARCHAR(50) NOT NULL DEFAULT 'import', -- import, require, include, from, dynamic
|
|
1261
|
+
import_statement TEXT NOT NULL, -- the full import statement
|
|
1262
|
+
|
|
1263
|
+
-- what's being imported
|
|
1264
|
+
imported_names TEXT[] DEFAULT '{}', -- specific names: ['foo', 'bar']
|
|
1265
|
+
imported_as TEXT[] DEFAULT '{}', -- aliases: ['f', 'b']
|
|
1266
|
+
is_default_import BOOLEAN DEFAULT false,
|
|
1267
|
+
is_namespace_import BOOLEAN DEFAULT false, -- import * as
|
|
1268
|
+
is_type_import BOOLEAN DEFAULT false, -- TypeScript type imports
|
|
1269
|
+
is_side_effect_import BOOLEAN DEFAULT false, -- import 'polyfill'
|
|
1270
|
+
|
|
1271
|
+
-- location in source file
|
|
1272
|
+
line_number INTEGER NOT NULL,
|
|
1273
|
+
column_number INTEGER DEFAULT 0,
|
|
1274
|
+
|
|
1275
|
+
-- dependency classification
|
|
1276
|
+
is_external BOOLEAN DEFAULT false, -- from node_modules or external package
|
|
1277
|
+
is_builtin BOOLEAN DEFAULT false, -- built-in module (fs, path, etc)
|
|
1278
|
+
is_relative BOOLEAN DEFAULT false, -- ./foo or ../bar
|
|
1279
|
+
is_absolute BOOLEAN DEFAULT false, -- /abs/path
|
|
1280
|
+
is_dynamic BOOLEAN DEFAULT false, -- dynamic import()
|
|
1281
|
+
|
|
1282
|
+
-- package info (for external deps)
|
|
1283
|
+
package_name VARCHAR(255), -- extracted package name
|
|
1284
|
+
package_version VARCHAR(50), -- from package.json if available
|
|
1285
|
+
|
|
1286
|
+
-- language
|
|
1287
|
+
language VARCHAR(50) NOT NULL DEFAULT 'unknown',
|
|
1288
|
+
|
|
1289
|
+
-- metadata
|
|
1290
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
1291
|
+
|
|
1292
|
+
-- timestamps
|
|
1293
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1294
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1295
|
+
|
|
1296
|
+
-- constraints
|
|
1297
|
+
CONSTRAINT target_not_empty CHECK (length(target_path) > 0),
|
|
1298
|
+
CONSTRAINT valid_import_type CHECK (
|
|
1299
|
+
import_type IN (
|
|
1300
|
+
'import', 'require', 'include', 'from', 'dynamic',
|
|
1301
|
+
'import_type', 'import_value', 'reexport', 'side_effect'
|
|
1302
|
+
)
|
|
1303
|
+
)
|
|
1304
|
+
);
|
|
1305
|
+
|
|
1306
|
+
-- indexes for CRAZY FAST dependency lookups
|
|
1307
|
+
|
|
1308
|
+
-- source file lookups (what does this file import?)
|
|
1309
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_source_file
|
|
1310
|
+
ON code_dependencies(source_file_id);
|
|
1311
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_source_path
|
|
1312
|
+
ON code_dependencies(source_file_path);
|
|
1313
|
+
|
|
1314
|
+
-- target lookups (what imports this file?)
|
|
1315
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_target_file
|
|
1316
|
+
ON code_dependencies(target_file_id)
|
|
1317
|
+
WHERE target_file_id IS NOT NULL;
|
|
1318
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_target_path
|
|
1319
|
+
ON code_dependencies(target_path);
|
|
1320
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_resolved_path
|
|
1321
|
+
ON code_dependencies(resolved_path)
|
|
1322
|
+
WHERE resolved_path IS NOT NULL;
|
|
1323
|
+
|
|
1324
|
+
-- package lookups
|
|
1325
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_package
|
|
1326
|
+
ON code_dependencies(package_name)
|
|
1327
|
+
WHERE package_name IS NOT NULL;
|
|
1328
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_package_trgm
|
|
1329
|
+
ON code_dependencies USING GIN(package_name gin_trgm_ops)
|
|
1330
|
+
WHERE package_name IS NOT NULL;
|
|
1331
|
+
|
|
1332
|
+
-- external vs internal deps
|
|
1333
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_external
|
|
1334
|
+
ON code_dependencies(is_external);
|
|
1335
|
+
|
|
1336
|
+
-- import type filtering
|
|
1337
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_type
|
|
1338
|
+
ON code_dependencies(import_type);
|
|
1339
|
+
|
|
1340
|
+
-- language filtering
|
|
1341
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_language
|
|
1342
|
+
ON code_dependencies(language);
|
|
1343
|
+
|
|
1344
|
+
-- imported names search
|
|
1345
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_names
|
|
1346
|
+
ON code_dependencies USING GIN(imported_names);
|
|
1347
|
+
|
|
1348
|
+
-- composite for dependency graph traversal
|
|
1349
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_graph
|
|
1350
|
+
ON code_dependencies(source_file_id, target_file_id)
|
|
1351
|
+
WHERE target_file_id IS NOT NULL;
|
|
1352
|
+
|
|
1353
|
+
-- time-based queries
|
|
1354
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_created
|
|
1355
|
+
ON code_dependencies(created_at DESC);
|
|
1356
|
+
|
|
1357
|
+
-- trigger for updated_at
|
|
1358
|
+
DROP TRIGGER IF EXISTS code_dependencies_updated_at ON code_dependencies;
|
|
1359
|
+
CREATE TRIGGER code_dependencies_updated_at
|
|
1360
|
+
BEFORE UPDATE ON code_dependencies
|
|
1361
|
+
FOR EACH ROW
|
|
1362
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
1363
|
+
`,
|
|
1364
|
+
down: `
|
|
1365
|
+
DROP TRIGGER IF EXISTS code_dependencies_updated_at ON code_dependencies;
|
|
1366
|
+
DROP TABLE IF EXISTS code_dependencies CASCADE;
|
|
1367
|
+
`,
|
|
1368
|
+
checksum: this.generateChecksum('create_code_dependencies_table_v19')
|
|
1369
|
+
},
|
|
1370
|
+
// migration 20: create code_complexity table
|
|
1371
|
+
// tracks code complexity metrics for analysis
|
|
1372
|
+
// cyclomatic complexity, lines of code, maintainability index, etc
|
|
1373
|
+
{
|
|
1374
|
+
version: 20,
|
|
1375
|
+
name: 'create_code_complexity_table',
|
|
1376
|
+
up: `
|
|
1377
|
+
-- code_complexity - CODE QUALITY METRICS
|
|
1378
|
+
-- tracks complexity, maintainability, and other metrics
|
|
1379
|
+
-- helps identify code that needs refactoring fr
|
|
1380
|
+
CREATE TABLE IF NOT EXISTS code_complexity (
|
|
1381
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
1382
|
+
|
|
1383
|
+
-- reference to file
|
|
1384
|
+
file_id UUID NOT NULL REFERENCES codebase_files(id) ON DELETE CASCADE,
|
|
1385
|
+
file_path TEXT NOT NULL,
|
|
1386
|
+
|
|
1387
|
+
-- optional reference to specific definition
|
|
1388
|
+
definition_id UUID REFERENCES code_definitions(id) ON DELETE CASCADE,
|
|
1389
|
+
definition_name VARCHAR(500),
|
|
1390
|
+
|
|
1391
|
+
-- scope of measurement
|
|
1392
|
+
scope_type VARCHAR(50) NOT NULL DEFAULT 'file', -- file, function, class, method
|
|
1393
|
+
|
|
1394
|
+
-- basic metrics
|
|
1395
|
+
lines_of_code INTEGER NOT NULL DEFAULT 0,
|
|
1396
|
+
logical_lines INTEGER NOT NULL DEFAULT 0,
|
|
1397
|
+
comment_lines INTEGER NOT NULL DEFAULT 0,
|
|
1398
|
+
blank_lines INTEGER NOT NULL DEFAULT 0,
|
|
1399
|
+
|
|
1400
|
+
-- complexity metrics
|
|
1401
|
+
cyclomatic_complexity INTEGER, -- McCabe complexity
|
|
1402
|
+
cognitive_complexity INTEGER, -- SonarSource cognitive complexity
|
|
1403
|
+
halstead_difficulty FLOAT, -- Halstead difficulty
|
|
1404
|
+
halstead_effort FLOAT, -- Halstead effort
|
|
1405
|
+
halstead_volume FLOAT, -- Halstead volume
|
|
1406
|
+
maintainability_index FLOAT, -- Microsoft maintainability index
|
|
1407
|
+
|
|
1408
|
+
-- function/class specific metrics
|
|
1409
|
+
parameter_count INTEGER,
|
|
1410
|
+
return_statement_count INTEGER,
|
|
1411
|
+
nesting_depth INTEGER,
|
|
1412
|
+
coupling_score INTEGER, -- dependencies count
|
|
1413
|
+
|
|
1414
|
+
-- code smells and issues
|
|
1415
|
+
issues_count INTEGER DEFAULT 0,
|
|
1416
|
+
issues JSONB DEFAULT '[]', -- [{type, severity, message, line}]
|
|
1417
|
+
|
|
1418
|
+
-- duplicate code detection
|
|
1419
|
+
duplicate_blocks INTEGER DEFAULT 0,
|
|
1420
|
+
duplicate_lines INTEGER DEFAULT 0,
|
|
1421
|
+
|
|
1422
|
+
-- language
|
|
1423
|
+
language VARCHAR(50) NOT NULL DEFAULT 'unknown',
|
|
1424
|
+
|
|
1425
|
+
-- metadata
|
|
1426
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
1427
|
+
|
|
1428
|
+
-- when was this analyzed?
|
|
1429
|
+
analyzed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1430
|
+
analyzer_version VARCHAR(50),
|
|
1431
|
+
|
|
1432
|
+
-- timestamps
|
|
1433
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1434
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1435
|
+
|
|
1436
|
+
-- constraints
|
|
1437
|
+
CONSTRAINT valid_scope_type CHECK (
|
|
1438
|
+
scope_type IN ('file', 'function', 'method', 'class', 'module', 'chunk')
|
|
1439
|
+
),
|
|
1440
|
+
CONSTRAINT valid_lines CHECK (lines_of_code >= 0)
|
|
1441
|
+
);
|
|
1442
|
+
|
|
1443
|
+
-- indexes for complexity analysis
|
|
1444
|
+
|
|
1445
|
+
-- file lookups
|
|
1446
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_file_id
|
|
1447
|
+
ON code_complexity(file_id);
|
|
1448
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_file_path
|
|
1449
|
+
ON code_complexity(file_path);
|
|
1450
|
+
|
|
1451
|
+
-- definition lookups
|
|
1452
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_definition
|
|
1453
|
+
ON code_complexity(definition_id)
|
|
1454
|
+
WHERE definition_id IS NOT NULL;
|
|
1455
|
+
|
|
1456
|
+
-- scope filtering
|
|
1457
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_scope
|
|
1458
|
+
ON code_complexity(scope_type);
|
|
1459
|
+
|
|
1460
|
+
-- complexity ranking (find most complex code)
|
|
1461
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_cyclomatic
|
|
1462
|
+
ON code_complexity(cyclomatic_complexity DESC)
|
|
1463
|
+
WHERE cyclomatic_complexity IS NOT NULL;
|
|
1464
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_cognitive
|
|
1465
|
+
ON code_complexity(cognitive_complexity DESC)
|
|
1466
|
+
WHERE cognitive_complexity IS NOT NULL;
|
|
1467
|
+
|
|
1468
|
+
-- maintainability ranking (find code needing work)
|
|
1469
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_maintainability
|
|
1470
|
+
ON code_complexity(maintainability_index)
|
|
1471
|
+
WHERE maintainability_index IS NOT NULL;
|
|
1472
|
+
|
|
1473
|
+
-- issue tracking
|
|
1474
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_issues
|
|
1475
|
+
ON code_complexity(issues_count DESC)
|
|
1476
|
+
WHERE issues_count > 0;
|
|
1477
|
+
|
|
1478
|
+
-- language filtering
|
|
1479
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_language
|
|
1480
|
+
ON code_complexity(language);
|
|
1481
|
+
|
|
1482
|
+
-- time-based queries
|
|
1483
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_analyzed
|
|
1484
|
+
ON code_complexity(analyzed_at DESC);
|
|
1485
|
+
|
|
1486
|
+
-- composite for common queries
|
|
1487
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_scope_cyclomatic
|
|
1488
|
+
ON code_complexity(scope_type, cyclomatic_complexity DESC)
|
|
1489
|
+
WHERE cyclomatic_complexity IS NOT NULL;
|
|
1490
|
+
|
|
1491
|
+
-- trigger for updated_at
|
|
1492
|
+
DROP TRIGGER IF EXISTS code_complexity_updated_at ON code_complexity;
|
|
1493
|
+
CREATE TRIGGER code_complexity_updated_at
|
|
1494
|
+
BEFORE UPDATE ON code_complexity
|
|
1495
|
+
FOR EACH ROW
|
|
1496
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
1497
|
+
|
|
1498
|
+
-- materialized view for codebase health overview
|
|
1499
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS codebase_health_stats AS
|
|
1500
|
+
SELECT
|
|
1501
|
+
COUNT(*) as total_files_analyzed,
|
|
1502
|
+
SUM(lines_of_code) as total_lines,
|
|
1503
|
+
SUM(comment_lines) as total_comments,
|
|
1504
|
+
AVG(cyclomatic_complexity)::FLOAT as avg_cyclomatic_complexity,
|
|
1505
|
+
AVG(cognitive_complexity)::FLOAT as avg_cognitive_complexity,
|
|
1506
|
+
AVG(maintainability_index)::FLOAT as avg_maintainability_index,
|
|
1507
|
+
MAX(cyclomatic_complexity) as max_cyclomatic_complexity,
|
|
1508
|
+
MAX(cognitive_complexity) as max_cognitive_complexity,
|
|
1509
|
+
MIN(maintainability_index) as min_maintainability_index,
|
|
1510
|
+
SUM(issues_count) as total_issues,
|
|
1511
|
+
SUM(duplicate_lines) as total_duplicate_lines,
|
|
1512
|
+
COUNT(*) FILTER (WHERE cyclomatic_complexity > 10) as high_complexity_count,
|
|
1513
|
+
COUNT(*) FILTER (WHERE maintainability_index < 20) as low_maintainability_count,
|
|
1514
|
+
NOW() as computed_at
|
|
1515
|
+
FROM code_complexity
|
|
1516
|
+
WHERE scope_type = 'file';
|
|
1517
|
+
|
|
1518
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_codebase_health_stats_singleton
|
|
1519
|
+
ON codebase_health_stats(computed_at);
|
|
1520
|
+
|
|
1521
|
+
-- function to refresh health stats
|
|
1522
|
+
CREATE OR REPLACE FUNCTION refresh_codebase_health_stats()
|
|
1523
|
+
RETURNS void AS $$
|
|
1524
|
+
BEGIN
|
|
1525
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY codebase_health_stats;
|
|
1526
|
+
END;
|
|
1527
|
+
$$ LANGUAGE plpgsql;
|
|
1528
|
+
`,
|
|
1529
|
+
down: `
|
|
1530
|
+
DROP FUNCTION IF EXISTS refresh_codebase_health_stats();
|
|
1531
|
+
DROP MATERIALIZED VIEW IF EXISTS codebase_health_stats;
|
|
1532
|
+
DROP TRIGGER IF EXISTS code_complexity_updated_at ON code_complexity;
|
|
1533
|
+
DROP TABLE IF EXISTS code_complexity CASCADE;
|
|
1534
|
+
`,
|
|
1535
|
+
checksum: this.generateChecksum('create_code_complexity_table_v20')
|
|
1536
|
+
},
|
|
1537
|
+
// migration 21: create team_member_sessions table
|
|
1538
|
+
// tracks all team member sessions for the communication dashboard
|
|
1539
|
+
// this is where we track EVERY team member that connects fr
|
|
1540
|
+
{
|
|
1541
|
+
version: 21,
|
|
1542
|
+
name: 'create_team_member_sessions_table',
|
|
1543
|
+
up: `
|
|
1544
|
+
-- team_member_sessions - TEAM_MEMBER COMMUNICATION DASHBOARD
|
|
1545
|
+
-- tracks every team member session for live monitoring
|
|
1546
|
+
-- stores session lifecycle, status, and metadata
|
|
1547
|
+
CREATE TABLE IF NOT EXISTS team_member_sessions (
|
|
1548
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
1549
|
+
|
|
1550
|
+
-- team member identification
|
|
1551
|
+
team_member_id VARCHAR(255) NOT NULL,
|
|
1552
|
+
team_member_name VARCHAR(255) NOT NULL,
|
|
1553
|
+
team_member_type VARCHAR(100) NOT NULL DEFAULT 'assistant',
|
|
1554
|
+
|
|
1555
|
+
-- session lifecycle
|
|
1556
|
+
status VARCHAR(50) NOT NULL DEFAULT 'active',
|
|
1557
|
+
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1558
|
+
ended_at TIMESTAMPTZ,
|
|
1559
|
+
last_heartbeat TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1560
|
+
|
|
1561
|
+
-- connection info
|
|
1562
|
+
connection_type VARCHAR(50) DEFAULT 'websocket',
|
|
1563
|
+
client_ip VARCHAR(45),
|
|
1564
|
+
user_agent TEXT,
|
|
1565
|
+
|
|
1566
|
+
-- task context
|
|
1567
|
+
current_task TEXT,
|
|
1568
|
+
working_directory TEXT,
|
|
1569
|
+
project_name VARCHAR(255),
|
|
1570
|
+
|
|
1571
|
+
-- metrics
|
|
1572
|
+
message_count INTEGER NOT NULL DEFAULT 0,
|
|
1573
|
+
tool_calls INTEGER NOT NULL DEFAULT 0,
|
|
1574
|
+
errors_count INTEGER NOT NULL DEFAULT 0,
|
|
1575
|
+
tokens_used INTEGER DEFAULT 0,
|
|
1576
|
+
|
|
1577
|
+
-- parent session for sub-team-members
|
|
1578
|
+
parent_session_id UUID REFERENCES team_member_sessions(id) ON DELETE SET NULL,
|
|
1579
|
+
|
|
1580
|
+
-- flexible metadata
|
|
1581
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
1582
|
+
capabilities JSONB DEFAULT '[]',
|
|
1583
|
+
environment JSONB DEFAULT '{}',
|
|
1584
|
+
|
|
1585
|
+
-- timestamps
|
|
1586
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1587
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1588
|
+
|
|
1589
|
+
-- constraints
|
|
1590
|
+
CONSTRAINT valid_status CHECK (
|
|
1591
|
+
status IN ('active', 'idle', 'busy', 'disconnected', 'terminated', 'error')
|
|
1592
|
+
),
|
|
1593
|
+
CONSTRAINT valid_connection_type CHECK (
|
|
1594
|
+
connection_type IN ('websocket', 'http', 'grpc', 'stdio')
|
|
1595
|
+
)
|
|
1596
|
+
);
|
|
1597
|
+
|
|
1598
|
+
-- indexes for FAST session lookups
|
|
1599
|
+
|
|
1600
|
+
-- team member lookups
|
|
1601
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_team_member_id
|
|
1602
|
+
ON team_member_sessions(team_member_id);
|
|
1603
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_team_member_name
|
|
1604
|
+
ON team_member_sessions(team_member_name);
|
|
1605
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_team_member_type
|
|
1606
|
+
ON team_member_sessions(team_member_type);
|
|
1607
|
+
|
|
1608
|
+
-- status filtering (active team members)
|
|
1609
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_status
|
|
1610
|
+
ON team_member_sessions(status);
|
|
1611
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_active
|
|
1612
|
+
ON team_member_sessions(team_member_id, last_heartbeat)
|
|
1613
|
+
WHERE status = 'active';
|
|
1614
|
+
|
|
1615
|
+
-- time-based queries
|
|
1616
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_started
|
|
1617
|
+
ON team_member_sessions(started_at DESC);
|
|
1618
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_ended
|
|
1619
|
+
ON team_member_sessions(ended_at DESC)
|
|
1620
|
+
WHERE ended_at IS NOT NULL;
|
|
1621
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_heartbeat
|
|
1622
|
+
ON team_member_sessions(last_heartbeat DESC);
|
|
1623
|
+
|
|
1624
|
+
-- parent-child relationships
|
|
1625
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_parent
|
|
1626
|
+
ON team_member_sessions(parent_session_id)
|
|
1627
|
+
WHERE parent_session_id IS NOT NULL;
|
|
1628
|
+
|
|
1629
|
+
-- project filtering
|
|
1630
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_project
|
|
1631
|
+
ON team_member_sessions(project_name)
|
|
1632
|
+
WHERE project_name IS NOT NULL;
|
|
1633
|
+
|
|
1634
|
+
-- metadata queries
|
|
1635
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_sessions_metadata
|
|
1636
|
+
ON team_member_sessions USING GIN(metadata jsonb_path_ops);
|
|
1637
|
+
|
|
1638
|
+
-- trigger for updated_at
|
|
1639
|
+
DROP TRIGGER IF EXISTS team_member_sessions_updated_at ON team_member_sessions;
|
|
1640
|
+
CREATE TRIGGER team_member_sessions_updated_at
|
|
1641
|
+
BEFORE UPDATE ON team_member_sessions
|
|
1642
|
+
FOR EACH ROW
|
|
1643
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
1644
|
+
`,
|
|
1645
|
+
down: `
|
|
1646
|
+
DROP TRIGGER IF EXISTS team_member_sessions_updated_at ON team_member_sessions;
|
|
1647
|
+
DROP TABLE IF EXISTS team_member_sessions CASCADE;
|
|
1648
|
+
`,
|
|
1649
|
+
checksum: this.generateChecksum('create_team_member_sessions_table_v21')
|
|
1650
|
+
},
|
|
1651
|
+
// migration 22: create team_member_messages table
|
|
1652
|
+
// stores all messages between team members and the system
|
|
1653
|
+
// this is the FULL communication log no cap
|
|
1654
|
+
{
|
|
1655
|
+
version: 22,
|
|
1656
|
+
name: 'create_team_member_messages_table',
|
|
1657
|
+
up: `
|
|
1658
|
+
-- team_member_messages - FULL COMMUNICATION LOG
|
|
1659
|
+
-- stores every message for replay and analysis
|
|
1660
|
+
-- supports streaming, tool calls, and responses
|
|
1661
|
+
CREATE TABLE IF NOT EXISTS team_member_messages (
|
|
1662
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
1663
|
+
|
|
1664
|
+
-- session reference
|
|
1665
|
+
session_id UUID NOT NULL REFERENCES team_member_sessions(id) ON DELETE CASCADE,
|
|
1666
|
+
|
|
1667
|
+
-- message identification
|
|
1668
|
+
message_type VARCHAR(50) NOT NULL DEFAULT 'text',
|
|
1669
|
+
direction VARCHAR(20) NOT NULL DEFAULT 'inbound',
|
|
1670
|
+
sequence_number INTEGER NOT NULL DEFAULT 0,
|
|
1671
|
+
|
|
1672
|
+
-- message content
|
|
1673
|
+
content TEXT NOT NULL,
|
|
1674
|
+
content_preview VARCHAR(500) GENERATED ALWAYS AS (
|
|
1675
|
+
CASE WHEN LENGTH(content) > 500 THEN LEFT(content, 497) || '...' ELSE content END
|
|
1676
|
+
) STORED,
|
|
1677
|
+
|
|
1678
|
+
-- for tool calls
|
|
1679
|
+
tool_name VARCHAR(255),
|
|
1680
|
+
tool_input JSONB,
|
|
1681
|
+
tool_output JSONB,
|
|
1682
|
+
tool_error TEXT,
|
|
1683
|
+
tool_duration_ms INTEGER,
|
|
1684
|
+
|
|
1685
|
+
-- for streaming
|
|
1686
|
+
is_streaming BOOLEAN DEFAULT false,
|
|
1687
|
+
stream_complete BOOLEAN DEFAULT true,
|
|
1688
|
+
parent_message_id UUID REFERENCES team_member_messages(id) ON DELETE SET NULL,
|
|
1689
|
+
|
|
1690
|
+
-- classification
|
|
1691
|
+
role VARCHAR(50) NOT NULL DEFAULT 'assistant',
|
|
1692
|
+
importance VARCHAR(20) DEFAULT 'normal',
|
|
1693
|
+
|
|
1694
|
+
-- tokens and cost tracking
|
|
1695
|
+
input_tokens INTEGER DEFAULT 0,
|
|
1696
|
+
output_tokens INTEGER DEFAULT 0,
|
|
1697
|
+
estimated_cost_cents FLOAT DEFAULT 0,
|
|
1698
|
+
|
|
1699
|
+
-- error tracking
|
|
1700
|
+
is_error BOOLEAN DEFAULT false,
|
|
1701
|
+
error_code VARCHAR(100),
|
|
1702
|
+
error_message TEXT,
|
|
1703
|
+
|
|
1704
|
+
-- timestamps
|
|
1705
|
+
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1706
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1707
|
+
|
|
1708
|
+
-- constraints
|
|
1709
|
+
CONSTRAINT valid_message_type CHECK (
|
|
1710
|
+
message_type IN (
|
|
1711
|
+
'text', 'tool_call', 'tool_result', 'system', 'error',
|
|
1712
|
+
'thinking', 'code', 'file_edit', 'command', 'response'
|
|
1713
|
+
)
|
|
1714
|
+
),
|
|
1715
|
+
CONSTRAINT valid_direction CHECK (
|
|
1716
|
+
direction IN ('inbound', 'outbound', 'internal')
|
|
1717
|
+
),
|
|
1718
|
+
CONSTRAINT valid_role CHECK (
|
|
1719
|
+
role IN ('user', 'assistant', 'system', 'tool')
|
|
1720
|
+
),
|
|
1721
|
+
CONSTRAINT valid_importance CHECK (
|
|
1722
|
+
importance IN ('critical', 'high', 'normal', 'low', 'debug')
|
|
1723
|
+
)
|
|
1724
|
+
);
|
|
1725
|
+
|
|
1726
|
+
-- indexes for BLAZING FAST message queries
|
|
1727
|
+
|
|
1728
|
+
-- session lookups (primary query pattern)
|
|
1729
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_session
|
|
1730
|
+
ON team_member_messages(session_id, sequence_number);
|
|
1731
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_session_time
|
|
1732
|
+
ON team_member_messages(session_id, timestamp DESC);
|
|
1733
|
+
|
|
1734
|
+
-- message type filtering
|
|
1735
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_type
|
|
1736
|
+
ON team_member_messages(message_type);
|
|
1737
|
+
|
|
1738
|
+
-- tool call queries
|
|
1739
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_tool
|
|
1740
|
+
ON team_member_messages(tool_name)
|
|
1741
|
+
WHERE tool_name IS NOT NULL;
|
|
1742
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_tool_session
|
|
1743
|
+
ON team_member_messages(session_id, tool_name)
|
|
1744
|
+
WHERE message_type = 'tool_call';
|
|
1745
|
+
|
|
1746
|
+
-- error queries
|
|
1747
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_errors
|
|
1748
|
+
ON team_member_messages(session_id, timestamp)
|
|
1749
|
+
WHERE is_error = true;
|
|
1750
|
+
|
|
1751
|
+
-- streaming queries
|
|
1752
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_streaming
|
|
1753
|
+
ON team_member_messages(session_id, parent_message_id)
|
|
1754
|
+
WHERE is_streaming = true;
|
|
1755
|
+
|
|
1756
|
+
-- time-based queries
|
|
1757
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_timestamp
|
|
1758
|
+
ON team_member_messages(timestamp DESC);
|
|
1759
|
+
|
|
1760
|
+
-- direction filtering
|
|
1761
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_direction
|
|
1762
|
+
ON team_member_messages(direction);
|
|
1763
|
+
|
|
1764
|
+
-- role filtering
|
|
1765
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_role
|
|
1766
|
+
ON team_member_messages(role);
|
|
1767
|
+
|
|
1768
|
+
-- content search (full-text)
|
|
1769
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_content_tsv
|
|
1770
|
+
ON team_member_messages USING GIN(to_tsvector('english', content));
|
|
1771
|
+
|
|
1772
|
+
-- JSONB indexes for tool input/output
|
|
1773
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_messages_tool_input
|
|
1774
|
+
ON team_member_messages USING GIN(tool_input)
|
|
1775
|
+
WHERE tool_input IS NOT NULL;
|
|
1776
|
+
`,
|
|
1777
|
+
down: `
|
|
1778
|
+
DROP TABLE IF EXISTS team_member_messages CASCADE;
|
|
1779
|
+
`,
|
|
1780
|
+
checksum: this.generateChecksum('create_team_member_messages_table_v22')
|
|
1781
|
+
},
|
|
1782
|
+
// migration 23: create team_member_deployments table
|
|
1783
|
+
// tracks deployment configurations and environments
|
|
1784
|
+
// supports multi-team member coordination and deployment history
|
|
1785
|
+
{
|
|
1786
|
+
version: 23,
|
|
1787
|
+
name: 'create_team_member_deployments_table',
|
|
1788
|
+
up: `
|
|
1789
|
+
-- team_member_deployments - DEPLOYMENT TRACKING
|
|
1790
|
+
-- tracks team member deployment configurations
|
|
1791
|
+
-- supports multi-environment and orchestration
|
|
1792
|
+
CREATE TABLE IF NOT EXISTS team_member_deployments (
|
|
1793
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
1794
|
+
|
|
1795
|
+
-- deployment identification
|
|
1796
|
+
deployment_name VARCHAR(255) NOT NULL,
|
|
1797
|
+
deployment_type VARCHAR(100) NOT NULL DEFAULT 'single',
|
|
1798
|
+
environment VARCHAR(100) NOT NULL DEFAULT 'development',
|
|
1799
|
+
|
|
1800
|
+
-- team member configuration
|
|
1801
|
+
team_member_config JSONB NOT NULL DEFAULT '{}',
|
|
1802
|
+
team_member_count INTEGER NOT NULL DEFAULT 1,
|
|
1803
|
+
team_member_template VARCHAR(255),
|
|
1804
|
+
|
|
1805
|
+
-- deployment status
|
|
1806
|
+
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
|
1807
|
+
health VARCHAR(50) DEFAULT 'unknown',
|
|
1808
|
+
|
|
1809
|
+
-- scheduling and lifecycle
|
|
1810
|
+
scheduled_at TIMESTAMPTZ,
|
|
1811
|
+
started_at TIMESTAMPTZ,
|
|
1812
|
+
completed_at TIMESTAMPTZ,
|
|
1813
|
+
timeout_seconds INTEGER DEFAULT 3600,
|
|
1814
|
+
|
|
1815
|
+
-- task configuration
|
|
1816
|
+
task_description TEXT,
|
|
1817
|
+
task_config JSONB DEFAULT '{}',
|
|
1818
|
+
input_data JSONB DEFAULT '{}',
|
|
1819
|
+
output_data JSONB DEFAULT '{}',
|
|
1820
|
+
|
|
1821
|
+
-- coordination
|
|
1822
|
+
coordinator_session_id UUID REFERENCES team_member_sessions(id) ON DELETE SET NULL,
|
|
1823
|
+
parent_deployment_id UUID REFERENCES team_member_deployments(id) ON DELETE SET NULL,
|
|
1824
|
+
child_deployment_count INTEGER DEFAULT 0,
|
|
1825
|
+
|
|
1826
|
+
-- resource tracking
|
|
1827
|
+
max_tokens INTEGER,
|
|
1828
|
+
max_cost_cents INTEGER,
|
|
1829
|
+
actual_tokens_used INTEGER DEFAULT 0,
|
|
1830
|
+
actual_cost_cents FLOAT DEFAULT 0,
|
|
1831
|
+
|
|
1832
|
+
-- results
|
|
1833
|
+
success BOOLEAN,
|
|
1834
|
+
result_summary TEXT,
|
|
1835
|
+
error_message TEXT,
|
|
1836
|
+
artifacts JSONB DEFAULT '[]',
|
|
1837
|
+
|
|
1838
|
+
-- version and rollback
|
|
1839
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
1840
|
+
previous_deployment_id UUID REFERENCES team_member_deployments(id) ON DELETE SET NULL,
|
|
1841
|
+
rollback_reason TEXT,
|
|
1842
|
+
|
|
1843
|
+
-- metadata
|
|
1844
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
1845
|
+
tags TEXT[] DEFAULT '{}',
|
|
1846
|
+
labels JSONB DEFAULT '{}',
|
|
1847
|
+
|
|
1848
|
+
-- timestamps
|
|
1849
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1850
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1851
|
+
|
|
1852
|
+
-- constraints
|
|
1853
|
+
CONSTRAINT valid_deployment_type CHECK (
|
|
1854
|
+
deployment_type IN (
|
|
1855
|
+
'single', 'parallel', 'sequential', 'swarm', 'pipeline', 'orchestrated'
|
|
1856
|
+
)
|
|
1857
|
+
),
|
|
1858
|
+
CONSTRAINT valid_deployment_status CHECK (
|
|
1859
|
+
status IN (
|
|
1860
|
+
'pending', 'scheduled', 'running', 'paused', 'completed',
|
|
1861
|
+
'failed', 'cancelled', 'timeout', 'rolled_back'
|
|
1862
|
+
)
|
|
1863
|
+
),
|
|
1864
|
+
CONSTRAINT valid_health CHECK (
|
|
1865
|
+
health IN ('unknown', 'healthy', 'degraded', 'unhealthy', 'critical')
|
|
1866
|
+
),
|
|
1867
|
+
CONSTRAINT valid_environment CHECK (
|
|
1868
|
+
environment IN (
|
|
1869
|
+
'development', 'staging', 'production', 'test', 'local'
|
|
1870
|
+
)
|
|
1871
|
+
)
|
|
1872
|
+
);
|
|
1873
|
+
|
|
1874
|
+
-- indexes for deployment queries
|
|
1875
|
+
|
|
1876
|
+
-- name and type lookups
|
|
1877
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_name
|
|
1878
|
+
ON team_member_deployments(deployment_name);
|
|
1879
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_type
|
|
1880
|
+
ON team_member_deployments(deployment_type);
|
|
1881
|
+
|
|
1882
|
+
-- environment filtering
|
|
1883
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_env
|
|
1884
|
+
ON team_member_deployments(environment);
|
|
1885
|
+
|
|
1886
|
+
-- status queries
|
|
1887
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_status
|
|
1888
|
+
ON team_member_deployments(status);
|
|
1889
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_active
|
|
1890
|
+
ON team_member_deployments(status, started_at)
|
|
1891
|
+
WHERE status IN ('running', 'scheduled', 'pending');
|
|
1892
|
+
|
|
1893
|
+
-- health monitoring
|
|
1894
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_health
|
|
1895
|
+
ON team_member_deployments(health)
|
|
1896
|
+
WHERE status = 'running';
|
|
1897
|
+
|
|
1898
|
+
-- time-based queries
|
|
1899
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_created
|
|
1900
|
+
ON team_member_deployments(created_at DESC);
|
|
1901
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_started
|
|
1902
|
+
ON team_member_deployments(started_at DESC)
|
|
1903
|
+
WHERE started_at IS NOT NULL;
|
|
1904
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_completed
|
|
1905
|
+
ON team_member_deployments(completed_at DESC)
|
|
1906
|
+
WHERE completed_at IS NOT NULL;
|
|
1907
|
+
|
|
1908
|
+
-- coordinator lookups
|
|
1909
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_coordinator
|
|
1910
|
+
ON team_member_deployments(coordinator_session_id)
|
|
1911
|
+
WHERE coordinator_session_id IS NOT NULL;
|
|
1912
|
+
|
|
1913
|
+
-- parent-child relationships
|
|
1914
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_parent
|
|
1915
|
+
ON team_member_deployments(parent_deployment_id)
|
|
1916
|
+
WHERE parent_deployment_id IS NOT NULL;
|
|
1917
|
+
|
|
1918
|
+
-- version tracking
|
|
1919
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_version
|
|
1920
|
+
ON team_member_deployments(deployment_name, version DESC);
|
|
1921
|
+
|
|
1922
|
+
-- tag searches
|
|
1923
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_tags
|
|
1924
|
+
ON team_member_deployments USING GIN(tags);
|
|
1925
|
+
|
|
1926
|
+
-- metadata queries
|
|
1927
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_metadata
|
|
1928
|
+
ON team_member_deployments USING GIN(metadata jsonb_path_ops);
|
|
1929
|
+
|
|
1930
|
+
-- success rate queries
|
|
1931
|
+
CREATE INDEX IF NOT EXISTS idx_team_member_deployments_success
|
|
1932
|
+
ON team_member_deployments(deployment_type, success)
|
|
1933
|
+
WHERE completed_at IS NOT NULL;
|
|
1934
|
+
|
|
1935
|
+
-- trigger for updated_at
|
|
1936
|
+
DROP TRIGGER IF EXISTS team_member_deployments_updated_at ON team_member_deployments;
|
|
1937
|
+
CREATE TRIGGER team_member_deployments_updated_at
|
|
1938
|
+
BEFORE UPDATE ON team_member_deployments
|
|
1939
|
+
FOR EACH ROW
|
|
1940
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
1941
|
+
|
|
1942
|
+
-- materialized view for deployment stats
|
|
1943
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS team_member_deployment_stats AS
|
|
1944
|
+
SELECT
|
|
1945
|
+
COUNT(*) as total_deployments,
|
|
1946
|
+
COUNT(*) FILTER (WHERE status = 'running') as running_count,
|
|
1947
|
+
COUNT(*) FILTER (WHERE status = 'completed') as completed_count,
|
|
1948
|
+
COUNT(*) FILTER (WHERE status = 'failed') as failed_count,
|
|
1949
|
+
COUNT(*) FILTER (WHERE success = true) as success_count,
|
|
1950
|
+
COUNT(*) FILTER (WHERE success = false) as failure_count,
|
|
1951
|
+
AVG(EXTRACT(EPOCH FROM (completed_at - started_at)))::FLOAT as avg_duration_seconds,
|
|
1952
|
+
SUM(actual_tokens_used) as total_tokens_used,
|
|
1953
|
+
SUM(actual_cost_cents) as total_cost_cents,
|
|
1954
|
+
COUNT(DISTINCT deployment_name) as unique_deployments,
|
|
1955
|
+
COUNT(DISTINCT environment) as environments_used,
|
|
1956
|
+
NOW() as computed_at
|
|
1957
|
+
FROM team_member_deployments;
|
|
1958
|
+
|
|
1959
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_team_member_deployment_stats_singleton
|
|
1960
|
+
ON team_member_deployment_stats(computed_at);
|
|
1961
|
+
|
|
1962
|
+
-- function to refresh deployment stats
|
|
1963
|
+
CREATE OR REPLACE FUNCTION refresh_team_member_deployment_stats()
|
|
1964
|
+
RETURNS void AS $$
|
|
1965
|
+
BEGIN
|
|
1966
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY team_member_deployment_stats;
|
|
1967
|
+
END;
|
|
1968
|
+
$$ LANGUAGE plpgsql;
|
|
1969
|
+
`,
|
|
1970
|
+
down: `
|
|
1971
|
+
DROP FUNCTION IF EXISTS refresh_team_member_deployment_stats();
|
|
1972
|
+
DROP MATERIALIZED VIEW IF EXISTS team_member_deployment_stats;
|
|
1973
|
+
DROP TRIGGER IF EXISTS team_member_deployments_updated_at ON team_member_deployments;
|
|
1974
|
+
DROP TABLE IF EXISTS team_member_deployments CASCADE;
|
|
1975
|
+
`,
|
|
1976
|
+
checksum: this.generateChecksum('create_team_member_deployments_table_v23')
|
|
1977
|
+
},
|
|
1978
|
+
// migration 24: Phase 4-6 - Direct Prompting and Control tables
|
|
1979
|
+
{
|
|
1980
|
+
version: 24,
|
|
1981
|
+
name: 'create_prompt_and_trigger_tables',
|
|
1982
|
+
up: `
|
|
1983
|
+
-- Table for storing prompt/conversation history (Phase 4)
|
|
1984
|
+
CREATE TABLE IF NOT EXISTS prompt_history (
|
|
1985
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
1986
|
+
session_id VARCHAR(255) NOT NULL,
|
|
1987
|
+
prompt TEXT NOT NULL,
|
|
1988
|
+
response TEXT,
|
|
1989
|
+
context JSONB NOT NULL DEFAULT '{}',
|
|
1990
|
+
config JSONB NOT NULL DEFAULT '{}',
|
|
1991
|
+
tokens_used INTEGER DEFAULT 0,
|
|
1992
|
+
duration_ms INTEGER DEFAULT 0,
|
|
1993
|
+
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
|
1994
|
+
error_message TEXT,
|
|
1995
|
+
model VARCHAR(100),
|
|
1996
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1997
|
+
|
|
1998
|
+
CONSTRAINT valid_prompt_status CHECK (
|
|
1999
|
+
status IN ('pending', 'success', 'error')
|
|
2000
|
+
)
|
|
2001
|
+
);
|
|
2002
|
+
|
|
2003
|
+
-- Indexes for prompt history
|
|
2004
|
+
CREATE INDEX IF NOT EXISTS idx_prompt_history_session
|
|
2005
|
+
ON prompt_history(session_id);
|
|
2006
|
+
CREATE INDEX IF NOT EXISTS idx_prompt_history_created
|
|
2007
|
+
ON prompt_history(created_at DESC);
|
|
2008
|
+
CREATE INDEX IF NOT EXISTS idx_prompt_history_status
|
|
2009
|
+
ON prompt_history(status);
|
|
2010
|
+
|
|
2011
|
+
-- Table for storing trigger history (Phase 6)
|
|
2012
|
+
CREATE TABLE IF NOT EXISTS trigger_history (
|
|
2013
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
2014
|
+
action VARCHAR(50) NOT NULL,
|
|
2015
|
+
prompt TEXT NOT NULL,
|
|
2016
|
+
config JSONB NOT NULL DEFAULT '{}',
|
|
2017
|
+
context JSONB NOT NULL DEFAULT '{}',
|
|
2018
|
+
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
|
2019
|
+
result TEXT,
|
|
2020
|
+
error_message TEXT,
|
|
2021
|
+
confirmed_by VARCHAR(255),
|
|
2022
|
+
confirmed_at TIMESTAMPTZ,
|
|
2023
|
+
started_at TIMESTAMPTZ,
|
|
2024
|
+
completed_at TIMESTAMPTZ,
|
|
2025
|
+
tokens_used INTEGER DEFAULT 0,
|
|
2026
|
+
duration_ms INTEGER DEFAULT 0,
|
|
2027
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2028
|
+
|
|
2029
|
+
CONSTRAINT valid_trigger_status CHECK (
|
|
2030
|
+
status IN ('pending', 'running', 'completed', 'failed', 'cancelled')
|
|
2031
|
+
),
|
|
2032
|
+
CONSTRAINT valid_trigger_action CHECK (
|
|
2033
|
+
action IN ('fix-error', 'consolidate', 'deploy-team-member', 'analyze-codebase', 'summarize-session', 'custom')
|
|
2034
|
+
)
|
|
2035
|
+
);
|
|
2036
|
+
|
|
2037
|
+
-- Indexes for trigger history
|
|
2038
|
+
CREATE INDEX IF NOT EXISTS idx_trigger_history_action
|
|
2039
|
+
ON trigger_history(action);
|
|
2040
|
+
CREATE INDEX IF NOT EXISTS idx_trigger_history_status
|
|
2041
|
+
ON trigger_history(status);
|
|
2042
|
+
CREATE INDEX IF NOT EXISTS idx_trigger_history_created
|
|
2043
|
+
ON trigger_history(created_at DESC);
|
|
2044
|
+
|
|
2045
|
+
-- Table for scheduled triggers (Phase 6)
|
|
2046
|
+
CREATE TABLE IF NOT EXISTS scheduled_triggers (
|
|
2047
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
2048
|
+
action VARCHAR(50) NOT NULL,
|
|
2049
|
+
prompt TEXT NOT NULL,
|
|
2050
|
+
config JSONB NOT NULL DEFAULT '{}',
|
|
2051
|
+
schedule JSONB NOT NULL,
|
|
2052
|
+
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
2053
|
+
last_run TIMESTAMPTZ,
|
|
2054
|
+
next_run TIMESTAMPTZ,
|
|
2055
|
+
run_count INTEGER NOT NULL DEFAULT 0,
|
|
2056
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2057
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2058
|
+
|
|
2059
|
+
CONSTRAINT valid_scheduled_action CHECK (
|
|
2060
|
+
action IN ('fix-error', 'consolidate', 'deploy-team-member', 'analyze-codebase', 'summarize-session', 'custom')
|
|
2061
|
+
)
|
|
2062
|
+
);
|
|
2063
|
+
|
|
2064
|
+
-- Indexes for scheduled triggers
|
|
2065
|
+
CREATE INDEX IF NOT EXISTS idx_scheduled_triggers_enabled
|
|
2066
|
+
ON scheduled_triggers(enabled, next_run)
|
|
2067
|
+
WHERE enabled = true;
|
|
2068
|
+
CREATE INDEX IF NOT EXISTS idx_scheduled_triggers_next_run
|
|
2069
|
+
ON scheduled_triggers(next_run)
|
|
2070
|
+
WHERE enabled = true;
|
|
2071
|
+
|
|
2072
|
+
-- trigger for updated_at
|
|
2073
|
+
DROP TRIGGER IF EXISTS scheduled_triggers_updated_at ON scheduled_triggers;
|
|
2074
|
+
CREATE TRIGGER scheduled_triggers_updated_at
|
|
2075
|
+
BEFORE UPDATE ON scheduled_triggers
|
|
2076
|
+
FOR EACH ROW
|
|
2077
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
2078
|
+
`,
|
|
2079
|
+
down: `
|
|
2080
|
+
DROP TRIGGER IF EXISTS scheduled_triggers_updated_at ON scheduled_triggers;
|
|
2081
|
+
DROP TABLE IF EXISTS scheduled_triggers CASCADE;
|
|
2082
|
+
DROP TABLE IF EXISTS trigger_history CASCADE;
|
|
2083
|
+
DROP TABLE IF EXISTS prompt_history CASCADE;
|
|
2084
|
+
`,
|
|
2085
|
+
checksum: this.generateChecksum('create_prompt_and_trigger_tables_v24')
|
|
2086
|
+
},
|
|
2087
|
+
// migration 25: File change history tracking - ACTIVE CODE MONITORING
|
|
2088
|
+
// Tracks every file change so we can see what ACTUALLY changed over time
|
|
2089
|
+
{
|
|
2090
|
+
version: 25,
|
|
2091
|
+
name: 'create_file_change_history',
|
|
2092
|
+
up: `
|
|
2093
|
+
-- Make sure pgcrypto is available for digest function
|
|
2094
|
+
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
2095
|
+
|
|
2096
|
+
-- Add content_hash column to codebase_files if missing
|
|
2097
|
+
-- SHA256 hash of content for change detection
|
|
2098
|
+
DO $$ BEGIN
|
|
2099
|
+
ALTER TABLE codebase_files
|
|
2100
|
+
ADD COLUMN IF NOT EXISTS content_hash VARCHAR(64);
|
|
2101
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
2102
|
+
END $$;
|
|
2103
|
+
|
|
2104
|
+
-- Update existing rows with their content hash using pgcrypto digest
|
|
2105
|
+
UPDATE codebase_files
|
|
2106
|
+
SET content_hash = encode(digest(content, 'sha256'), 'hex')
|
|
2107
|
+
WHERE content_hash IS NULL;
|
|
2108
|
+
|
|
2109
|
+
-- Create index for hash lookups
|
|
2110
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_hash
|
|
2111
|
+
ON codebase_files(content_hash);
|
|
2112
|
+
|
|
2113
|
+
-- File change history table - THE MEMORY OF EVERY EDIT
|
|
2114
|
+
-- Tracks add, modify, delete events with before/after content
|
|
2115
|
+
CREATE TABLE IF NOT EXISTS file_change_history (
|
|
2116
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
2117
|
+
|
|
2118
|
+
-- File identification
|
|
2119
|
+
file_path TEXT NOT NULL,
|
|
2120
|
+
absolute_path TEXT NOT NULL,
|
|
2121
|
+
file_id UUID, -- Reference to codebase_files (null if deleted)
|
|
2122
|
+
|
|
2123
|
+
-- Change type
|
|
2124
|
+
change_type VARCHAR(20) NOT NULL,
|
|
2125
|
+
|
|
2126
|
+
-- Content tracking - stores diffs for efficiency
|
|
2127
|
+
previous_hash VARCHAR(64),
|
|
2128
|
+
new_hash VARCHAR(64),
|
|
2129
|
+
previous_content TEXT, -- Stored for small files or on demand
|
|
2130
|
+
new_content TEXT, -- Stored for small files or on demand
|
|
2131
|
+
content_diff TEXT, -- Unified diff format
|
|
2132
|
+
|
|
2133
|
+
-- Metadata
|
|
2134
|
+
size_before INTEGER,
|
|
2135
|
+
size_after INTEGER,
|
|
2136
|
+
line_count_before INTEGER,
|
|
2137
|
+
line_count_after INTEGER,
|
|
2138
|
+
lines_added INTEGER DEFAULT 0,
|
|
2139
|
+
lines_removed INTEGER DEFAULT 0,
|
|
2140
|
+
|
|
2141
|
+
-- Timestamps
|
|
2142
|
+
detected_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2143
|
+
file_modified_at TIMESTAMPTZ,
|
|
2144
|
+
|
|
2145
|
+
-- Context
|
|
2146
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
2147
|
+
|
|
2148
|
+
CONSTRAINT valid_change_type CHECK (
|
|
2149
|
+
change_type IN ('add', 'modify', 'delete', 'rename', 'move')
|
|
2150
|
+
)
|
|
2151
|
+
);
|
|
2152
|
+
|
|
2153
|
+
-- Indexes for history queries
|
|
2154
|
+
CREATE INDEX IF NOT EXISTS idx_file_change_history_path
|
|
2155
|
+
ON file_change_history(file_path);
|
|
2156
|
+
CREATE INDEX IF NOT EXISTS idx_file_change_history_file_id
|
|
2157
|
+
ON file_change_history(file_id)
|
|
2158
|
+
WHERE file_id IS NOT NULL;
|
|
2159
|
+
CREATE INDEX IF NOT EXISTS idx_file_change_history_detected
|
|
2160
|
+
ON file_change_history(detected_at DESC);
|
|
2161
|
+
CREATE INDEX IF NOT EXISTS idx_file_change_history_type
|
|
2162
|
+
ON file_change_history(change_type);
|
|
2163
|
+
CREATE INDEX IF NOT EXISTS idx_file_change_history_hash
|
|
2164
|
+
ON file_change_history(new_hash)
|
|
2165
|
+
WHERE new_hash IS NOT NULL;
|
|
2166
|
+
|
|
2167
|
+
-- Full text search on file paths in history
|
|
2168
|
+
CREATE INDEX IF NOT EXISTS idx_file_change_history_path_trgm
|
|
2169
|
+
ON file_change_history USING gin (file_path gin_trgm_ops);
|
|
2170
|
+
|
|
2171
|
+
-- Composite index for file timeline queries
|
|
2172
|
+
CREATE INDEX IF NOT EXISTS idx_file_change_history_timeline
|
|
2173
|
+
ON file_change_history(file_path, detected_at DESC);
|
|
2174
|
+
|
|
2175
|
+
-- Function to record file changes automatically using pgcrypto digest
|
|
2176
|
+
CREATE OR REPLACE FUNCTION record_file_change()
|
|
2177
|
+
RETURNS TRIGGER AS $$
|
|
2178
|
+
BEGIN
|
|
2179
|
+
IF TG_OP = 'INSERT' THEN
|
|
2180
|
+
INSERT INTO file_change_history (
|
|
2181
|
+
file_path, absolute_path, file_id, change_type,
|
|
2182
|
+
new_hash, new_content, size_after, line_count_after,
|
|
2183
|
+
file_modified_at, metadata
|
|
2184
|
+
) VALUES (
|
|
2185
|
+
NEW.file_path, NEW.absolute_path, NEW.id, 'add',
|
|
2186
|
+
encode(digest(NEW.content, 'sha256'), 'hex'),
|
|
2187
|
+
CASE WHEN length(NEW.content) < 50000 THEN NEW.content ELSE NULL END,
|
|
2188
|
+
NEW.size_bytes, NEW.line_count,
|
|
2189
|
+
NEW.last_modified,
|
|
2190
|
+
jsonb_build_object('language', NEW.language_id, 'trigger', 'insert')
|
|
2191
|
+
);
|
|
2192
|
+
RETURN NEW;
|
|
2193
|
+
ELSIF TG_OP = 'UPDATE' THEN
|
|
2194
|
+
-- Only record if content actually changed
|
|
2195
|
+
IF OLD.content IS DISTINCT FROM NEW.content THEN
|
|
2196
|
+
INSERT INTO file_change_history (
|
|
2197
|
+
file_path, absolute_path, file_id, change_type,
|
|
2198
|
+
previous_hash, new_hash,
|
|
2199
|
+
previous_content, new_content,
|
|
2200
|
+
size_before, size_after,
|
|
2201
|
+
line_count_before, line_count_after,
|
|
2202
|
+
file_modified_at, metadata
|
|
2203
|
+
) VALUES (
|
|
2204
|
+
NEW.file_path, NEW.absolute_path, NEW.id, 'modify',
|
|
2205
|
+
encode(digest(OLD.content, 'sha256'), 'hex'),
|
|
2206
|
+
encode(digest(NEW.content, 'sha256'), 'hex'),
|
|
2207
|
+
CASE WHEN length(OLD.content) < 50000 THEN OLD.content ELSE NULL END,
|
|
2208
|
+
CASE WHEN length(NEW.content) < 50000 THEN NEW.content ELSE NULL END,
|
|
2209
|
+
OLD.size_bytes, NEW.size_bytes,
|
|
2210
|
+
OLD.line_count, NEW.line_count,
|
|
2211
|
+
NEW.last_modified,
|
|
2212
|
+
jsonb_build_object('language', NEW.language_id, 'trigger', 'update')
|
|
2213
|
+
);
|
|
2214
|
+
END IF;
|
|
2215
|
+
RETURN NEW;
|
|
2216
|
+
ELSIF TG_OP = 'DELETE' THEN
|
|
2217
|
+
INSERT INTO file_change_history (
|
|
2218
|
+
file_path, absolute_path, file_id, change_type,
|
|
2219
|
+
previous_hash, previous_content,
|
|
2220
|
+
size_before, line_count_before,
|
|
2221
|
+
file_modified_at, metadata
|
|
2222
|
+
) VALUES (
|
|
2223
|
+
OLD.file_path, OLD.absolute_path, NULL, 'delete',
|
|
2224
|
+
encode(digest(OLD.content, 'sha256'), 'hex'),
|
|
2225
|
+
CASE WHEN length(OLD.content) < 50000 THEN OLD.content ELSE NULL END,
|
|
2226
|
+
OLD.size_bytes, OLD.line_count,
|
|
2227
|
+
NOW(),
|
|
2228
|
+
jsonb_build_object('language', OLD.language_id, 'trigger', 'delete')
|
|
2229
|
+
);
|
|
2230
|
+
RETURN OLD;
|
|
2231
|
+
END IF;
|
|
2232
|
+
RETURN NULL;
|
|
2233
|
+
END;
|
|
2234
|
+
$$ LANGUAGE plpgsql;
|
|
2235
|
+
|
|
2236
|
+
-- Attach trigger to codebase_files
|
|
2237
|
+
DROP TRIGGER IF EXISTS codebase_files_change_history ON codebase_files;
|
|
2238
|
+
CREATE TRIGGER codebase_files_change_history
|
|
2239
|
+
AFTER INSERT OR UPDATE OR DELETE ON codebase_files
|
|
2240
|
+
FOR EACH ROW
|
|
2241
|
+
EXECUTE FUNCTION record_file_change();
|
|
2242
|
+
|
|
2243
|
+
-- View for recent changes summary
|
|
2244
|
+
CREATE OR REPLACE VIEW recent_file_changes AS
|
|
2245
|
+
SELECT
|
|
2246
|
+
fch.id,
|
|
2247
|
+
fch.file_path,
|
|
2248
|
+
fch.change_type,
|
|
2249
|
+
fch.detected_at,
|
|
2250
|
+
fch.lines_added,
|
|
2251
|
+
fch.lines_removed,
|
|
2252
|
+
fch.size_before,
|
|
2253
|
+
fch.size_after,
|
|
2254
|
+
cf.language_id
|
|
2255
|
+
FROM file_change_history fch
|
|
2256
|
+
LEFT JOIN codebase_files cf ON cf.id = fch.file_id
|
|
2257
|
+
ORDER BY fch.detected_at DESC
|
|
2258
|
+
LIMIT 100;
|
|
2259
|
+
`,
|
|
2260
|
+
down: `
|
|
2261
|
+
DROP VIEW IF EXISTS recent_file_changes;
|
|
2262
|
+
DROP TRIGGER IF EXISTS codebase_files_change_history ON codebase_files;
|
|
2263
|
+
DROP FUNCTION IF EXISTS record_file_change();
|
|
2264
|
+
DROP TABLE IF EXISTS file_change_history CASCADE;
|
|
2265
|
+
ALTER TABLE codebase_files DROP COLUMN IF EXISTS content_hash;
|
|
2266
|
+
`,
|
|
2267
|
+
checksum: this.generateChecksum('create_file_change_history_v25_fixed')
|
|
2268
|
+
},
|
|
2269
|
+
// migration 26: SPATIAL MEMORY EVOLUTION - Quadrants, Clusters, Hot Paths
|
|
2270
|
+
// Makes 's memory ACTUALLY INTELLIGENT through spatial organization
|
|
2271
|
+
// This is where memory becomes self-organizing fr fr
|
|
2272
|
+
{
|
|
2273
|
+
version: 26,
|
|
2274
|
+
name: 'create_spatial_memory_tables',
|
|
2275
|
+
up: `
|
|
2276
|
+
-- ============================================================
|
|
2277
|
+
-- SEMANTIC QUADRANTS - Organize memories in 2D semantic space
|
|
2278
|
+
-- Memories are assigned to quadrants based on embedding clusters
|
|
2279
|
+
-- Enables region-based searching like "find all memories in Q1"
|
|
2280
|
+
-- ============================================================
|
|
2281
|
+
CREATE TABLE IF NOT EXISTS semantic_quadrants (
|
|
2282
|
+
id SERIAL PRIMARY KEY,
|
|
2283
|
+
|
|
2284
|
+
-- Quadrant identification
|
|
2285
|
+
name VARCHAR(100) NOT NULL,
|
|
2286
|
+
description TEXT,
|
|
2287
|
+
quadrant_code VARCHAR(20) NOT NULL UNIQUE, -- e.g., 'Q1', 'Q2-A', 'tech-backend'
|
|
2288
|
+
|
|
2289
|
+
-- Centroid embedding for the quadrant
|
|
2290
|
+
-- NOTE: Dimension is auto-detected, unbounded initially
|
|
2291
|
+
centroid vector(384),
|
|
2292
|
+
|
|
2293
|
+
-- Bounding box in reduced dimension space (for fast filtering)
|
|
2294
|
+
-- Using 2D projection of embeddings (UMAP/t-SNE style)
|
|
2295
|
+
min_x FLOAT,
|
|
2296
|
+
max_x FLOAT,
|
|
2297
|
+
min_y FLOAT,
|
|
2298
|
+
max_y FLOAT,
|
|
2299
|
+
|
|
2300
|
+
-- Hierarchical structure support
|
|
2301
|
+
parent_quadrant_id INTEGER REFERENCES semantic_quadrants(id) ON DELETE SET NULL,
|
|
2302
|
+
depth INTEGER NOT NULL DEFAULT 0,
|
|
2303
|
+
|
|
2304
|
+
-- Statistics
|
|
2305
|
+
memory_count INTEGER NOT NULL DEFAULT 0,
|
|
2306
|
+
max_capacity INTEGER DEFAULT 1000, -- Triggers split when exceeded
|
|
2307
|
+
avg_similarity FLOAT, -- Average similarity within quadrant
|
|
2308
|
+
last_rebalanced_at TIMESTAMPTZ,
|
|
2309
|
+
|
|
2310
|
+
-- Metadata
|
|
2311
|
+
auto_generated BOOLEAN DEFAULT true,
|
|
2312
|
+
tags TEXT[] DEFAULT '{}',
|
|
2313
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
2314
|
+
|
|
2315
|
+
-- Timestamps
|
|
2316
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2317
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
2318
|
+
);
|
|
2319
|
+
|
|
2320
|
+
-- Indexes for quadrant lookups
|
|
2321
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_quadrants_code
|
|
2322
|
+
ON semantic_quadrants(quadrant_code);
|
|
2323
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_quadrants_parent
|
|
2324
|
+
ON semantic_quadrants(parent_quadrant_id)
|
|
2325
|
+
WHERE parent_quadrant_id IS NOT NULL;
|
|
2326
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_quadrants_bounds
|
|
2327
|
+
ON semantic_quadrants(min_x, max_x, min_y, max_y)
|
|
2328
|
+
WHERE min_x IS NOT NULL;
|
|
2329
|
+
|
|
2330
|
+
-- Memory to quadrant assignments
|
|
2331
|
+
CREATE TABLE IF NOT EXISTS memory_quadrant_assignments (
|
|
2332
|
+
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
2333
|
+
quadrant_id INTEGER NOT NULL REFERENCES semantic_quadrants(id) ON DELETE CASCADE,
|
|
2334
|
+
|
|
2335
|
+
-- Position within quadrant (reduced 2D space)
|
|
2336
|
+
pos_x FLOAT,
|
|
2337
|
+
pos_y FLOAT,
|
|
2338
|
+
|
|
2339
|
+
-- Distance from centroid (for ranking within quadrant)
|
|
2340
|
+
distance_from_centroid FLOAT,
|
|
2341
|
+
|
|
2342
|
+
-- Assignment metadata
|
|
2343
|
+
assigned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2344
|
+
assignment_method VARCHAR(50) DEFAULT 'auto', -- auto, manual, migration
|
|
2345
|
+
|
|
2346
|
+
PRIMARY KEY (memory_id, quadrant_id)
|
|
2347
|
+
);
|
|
2348
|
+
|
|
2349
|
+
CREATE INDEX IF NOT EXISTS idx_memory_quadrant_memory
|
|
2350
|
+
ON memory_quadrant_assignments(memory_id);
|
|
2351
|
+
CREATE INDEX IF NOT EXISTS idx_memory_quadrant_quadrant
|
|
2352
|
+
ON memory_quadrant_assignments(quadrant_id);
|
|
2353
|
+
CREATE INDEX IF NOT EXISTS idx_memory_quadrant_position
|
|
2354
|
+
ON memory_quadrant_assignments(quadrant_id, pos_x, pos_y);
|
|
2355
|
+
|
|
2356
|
+
-- ============================================================
|
|
2357
|
+
-- SEMANTIC CLUSTERS - Auto-forming memory neighborhoods
|
|
2358
|
+
-- Groups related memories using clustering algorithms
|
|
2359
|
+
-- Clusters get auto-generated labels from content themes
|
|
2360
|
+
-- ============================================================
|
|
2361
|
+
CREATE TABLE IF NOT EXISTS memory_clusters (
|
|
2362
|
+
id SERIAL PRIMARY KEY,
|
|
2363
|
+
|
|
2364
|
+
-- Cluster identification
|
|
2365
|
+
name VARCHAR(255), -- Auto-generated from top tags/content
|
|
2366
|
+
description TEXT, -- Summary of what this cluster contains
|
|
2367
|
+
cluster_type VARCHAR(50) NOT NULL DEFAULT 'semantic', -- semantic, temporal, tag_based, manual
|
|
2368
|
+
|
|
2369
|
+
-- Centroid for the cluster
|
|
2370
|
+
-- NOTE: Dimension is auto-detected, unbounded initially
|
|
2371
|
+
centroid vector(384),
|
|
2372
|
+
|
|
2373
|
+
-- Statistics
|
|
2374
|
+
memory_count INTEGER NOT NULL DEFAULT 0,
|
|
2375
|
+
coherence_score FLOAT, -- 0-1 how tight the cluster is
|
|
2376
|
+
silhouette_score FLOAT, -- Cluster quality metric
|
|
2377
|
+
|
|
2378
|
+
-- Top terms/tags in this cluster (auto-extracted)
|
|
2379
|
+
top_tags TEXT[] DEFAULT '{}',
|
|
2380
|
+
top_terms TEXT[] DEFAULT '{}',
|
|
2381
|
+
|
|
2382
|
+
-- Hierarchy support (clusters can nest)
|
|
2383
|
+
parent_cluster_id INTEGER REFERENCES memory_clusters(id) ON DELETE SET NULL,
|
|
2384
|
+
depth INTEGER NOT NULL DEFAULT 0,
|
|
2385
|
+
|
|
2386
|
+
-- Lifecycle
|
|
2387
|
+
last_updated_at TIMESTAMPTZ,
|
|
2388
|
+
last_recomputed_at TIMESTAMPTZ,
|
|
2389
|
+
is_stable BOOLEAN DEFAULT false, -- True if cluster hasn't changed recently
|
|
2390
|
+
|
|
2391
|
+
-- Metadata
|
|
2392
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
2393
|
+
|
|
2394
|
+
-- Timestamps
|
|
2395
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2396
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
2397
|
+
);
|
|
2398
|
+
|
|
2399
|
+
CREATE INDEX IF NOT EXISTS idx_memory_clusters_type
|
|
2400
|
+
ON memory_clusters(cluster_type);
|
|
2401
|
+
CREATE INDEX IF NOT EXISTS idx_memory_clusters_parent
|
|
2402
|
+
ON memory_clusters(parent_cluster_id)
|
|
2403
|
+
WHERE parent_cluster_id IS NOT NULL;
|
|
2404
|
+
CREATE INDEX IF NOT EXISTS idx_memory_clusters_coherence
|
|
2405
|
+
ON memory_clusters(coherence_score DESC)
|
|
2406
|
+
WHERE coherence_score IS NOT NULL;
|
|
2407
|
+
|
|
2408
|
+
-- Memory to cluster assignments (many-to-many - soft clustering)
|
|
2409
|
+
CREATE TABLE IF NOT EXISTS memory_cluster_assignments (
|
|
2410
|
+
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
2411
|
+
cluster_id INTEGER NOT NULL REFERENCES memory_clusters(id) ON DELETE CASCADE,
|
|
2412
|
+
|
|
2413
|
+
-- Membership strength (0-1, supports soft clustering)
|
|
2414
|
+
membership_score FLOAT NOT NULL DEFAULT 1.0,
|
|
2415
|
+
|
|
2416
|
+
-- Distance from cluster centroid
|
|
2417
|
+
distance_to_centroid FLOAT,
|
|
2418
|
+
|
|
2419
|
+
-- Assignment metadata
|
|
2420
|
+
assigned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2421
|
+
assignment_method VARCHAR(50) DEFAULT 'auto',
|
|
2422
|
+
|
|
2423
|
+
PRIMARY KEY (memory_id, cluster_id)
|
|
2424
|
+
);
|
|
2425
|
+
|
|
2426
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cluster_assign_memory
|
|
2427
|
+
ON memory_cluster_assignments(memory_id);
|
|
2428
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cluster_assign_cluster
|
|
2429
|
+
ON memory_cluster_assignments(cluster_id);
|
|
2430
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cluster_assign_score
|
|
2431
|
+
ON memory_cluster_assignments(cluster_id, membership_score DESC);
|
|
2432
|
+
|
|
2433
|
+
-- Cluster relationships (which clusters are related)
|
|
2434
|
+
CREATE TABLE IF NOT EXISTS cluster_relations (
|
|
2435
|
+
source_cluster_id INTEGER NOT NULL REFERENCES memory_clusters(id) ON DELETE CASCADE,
|
|
2436
|
+
target_cluster_id INTEGER NOT NULL REFERENCES memory_clusters(id) ON DELETE CASCADE,
|
|
2437
|
+
|
|
2438
|
+
relation_type VARCHAR(50) NOT NULL DEFAULT 'similar', -- similar, parent, child, overlapping, adjacent
|
|
2439
|
+
strength FLOAT NOT NULL DEFAULT 1.0,
|
|
2440
|
+
|
|
2441
|
+
-- Shared memories count
|
|
2442
|
+
shared_memory_count INTEGER DEFAULT 0,
|
|
2443
|
+
|
|
2444
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2445
|
+
|
|
2446
|
+
PRIMARY KEY (source_cluster_id, target_cluster_id, relation_type),
|
|
2447
|
+
CONSTRAINT no_self_cluster_relation CHECK (source_cluster_id != target_cluster_id)
|
|
2448
|
+
);
|
|
2449
|
+
|
|
2450
|
+
CREATE INDEX IF NOT EXISTS idx_cluster_relations_source
|
|
2451
|
+
ON cluster_relations(source_cluster_id);
|
|
2452
|
+
CREATE INDEX IF NOT EXISTS idx_cluster_relations_target
|
|
2453
|
+
ON cluster_relations(target_cluster_id);
|
|
2454
|
+
|
|
2455
|
+
-- ============================================================
|
|
2456
|
+
-- HOT PATH ACCELERATION - Frequently accessed memory chains
|
|
2457
|
+
-- Tracks which memories get accessed together
|
|
2458
|
+
-- Pre-fetches and caches common access patterns
|
|
2459
|
+
-- ============================================================
|
|
2460
|
+
CREATE TABLE IF NOT EXISTS memory_hot_paths (
|
|
2461
|
+
id SERIAL PRIMARY KEY,
|
|
2462
|
+
|
|
2463
|
+
-- Path identification
|
|
2464
|
+
path_name VARCHAR(255),
|
|
2465
|
+
path_hash VARCHAR(64) UNIQUE, -- Hash of ordered memory IDs
|
|
2466
|
+
|
|
2467
|
+
-- Ordered list of memories in this path
|
|
2468
|
+
memory_ids UUID[] NOT NULL,
|
|
2469
|
+
memory_count INTEGER NOT NULL,
|
|
2470
|
+
|
|
2471
|
+
-- Usage statistics
|
|
2472
|
+
access_count INTEGER NOT NULL DEFAULT 0,
|
|
2473
|
+
last_accessed_at TIMESTAMPTZ,
|
|
2474
|
+
first_accessed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2475
|
+
|
|
2476
|
+
-- Heat score (decays over time, increases with access)
|
|
2477
|
+
heat_score FLOAT NOT NULL DEFAULT 1.0,
|
|
2478
|
+
peak_heat_score FLOAT NOT NULL DEFAULT 1.0,
|
|
2479
|
+
|
|
2480
|
+
-- Cache status
|
|
2481
|
+
is_cached BOOLEAN DEFAULT false,
|
|
2482
|
+
cached_at TIMESTAMPTZ,
|
|
2483
|
+
cache_hits INTEGER DEFAULT 0,
|
|
2484
|
+
|
|
2485
|
+
-- Path characteristics
|
|
2486
|
+
avg_transition_similarity FLOAT, -- How similar adjacent memories are
|
|
2487
|
+
path_coherence FLOAT, -- Overall semantic coherence
|
|
2488
|
+
dominant_tags TEXT[] DEFAULT '{}',
|
|
2489
|
+
|
|
2490
|
+
-- Metadata
|
|
2491
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
2492
|
+
|
|
2493
|
+
-- Timestamps
|
|
2494
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2495
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
2496
|
+
);
|
|
2497
|
+
|
|
2498
|
+
CREATE INDEX IF NOT EXISTS idx_hot_paths_hash
|
|
2499
|
+
ON memory_hot_paths(path_hash);
|
|
2500
|
+
CREATE INDEX IF NOT EXISTS idx_hot_paths_heat
|
|
2501
|
+
ON memory_hot_paths(heat_score DESC);
|
|
2502
|
+
CREATE INDEX IF NOT EXISTS idx_hot_paths_cached
|
|
2503
|
+
ON memory_hot_paths(is_cached)
|
|
2504
|
+
WHERE is_cached = true;
|
|
2505
|
+
CREATE INDEX IF NOT EXISTS idx_hot_paths_accessed
|
|
2506
|
+
ON memory_hot_paths(last_accessed_at DESC);
|
|
2507
|
+
CREATE INDEX IF NOT EXISTS idx_hot_paths_memory_ids
|
|
2508
|
+
ON memory_hot_paths USING GIN(memory_ids);
|
|
2509
|
+
|
|
2510
|
+
-- Access pattern tracking (individual transitions)
|
|
2511
|
+
CREATE TABLE IF NOT EXISTS memory_access_transitions (
|
|
2512
|
+
id BIGSERIAL PRIMARY KEY,
|
|
2513
|
+
|
|
2514
|
+
-- The transition
|
|
2515
|
+
from_memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
2516
|
+
to_memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
2517
|
+
|
|
2518
|
+
-- Statistics
|
|
2519
|
+
transition_count INTEGER NOT NULL DEFAULT 1,
|
|
2520
|
+
last_transition_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2521
|
+
|
|
2522
|
+
-- Context
|
|
2523
|
+
session_id VARCHAR(255), -- Track transitions within sessions
|
|
2524
|
+
time_between_ms INTEGER, -- Time between accesses
|
|
2525
|
+
|
|
2526
|
+
-- Timestamps
|
|
2527
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2528
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
2529
|
+
);
|
|
2530
|
+
|
|
2531
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_access_transitions_pair
|
|
2532
|
+
ON memory_access_transitions(from_memory_id, to_memory_id);
|
|
2533
|
+
CREATE INDEX IF NOT EXISTS idx_access_transitions_from
|
|
2534
|
+
ON memory_access_transitions(from_memory_id);
|
|
2535
|
+
CREATE INDEX IF NOT EXISTS idx_access_transitions_to
|
|
2536
|
+
ON memory_access_transitions(to_memory_id);
|
|
2537
|
+
CREATE INDEX IF NOT EXISTS idx_access_transitions_count
|
|
2538
|
+
ON memory_access_transitions(transition_count DESC);
|
|
2539
|
+
CREATE INDEX IF NOT EXISTS idx_access_transitions_session
|
|
2540
|
+
ON memory_access_transitions(session_id)
|
|
2541
|
+
WHERE session_id IS NOT NULL;
|
|
2542
|
+
|
|
2543
|
+
-- ============================================================
|
|
2544
|
+
-- ENHANCED MEMORY GRAPH - Typed relationships with inference
|
|
2545
|
+
-- Extends basic memory_relations with more graph features
|
|
2546
|
+
-- ============================================================
|
|
2547
|
+
|
|
2548
|
+
-- Add new columns to memory_relations if they don't exist
|
|
2549
|
+
DO $$ BEGIN
|
|
2550
|
+
ALTER TABLE memory_relations
|
|
2551
|
+
ADD COLUMN IF NOT EXISTS relation_category VARCHAR(50) DEFAULT 'explicit'; -- explicit, inferred, temporal
|
|
2552
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
2553
|
+
END $$;
|
|
2554
|
+
|
|
2555
|
+
DO $$ BEGIN
|
|
2556
|
+
ALTER TABLE memory_relations
|
|
2557
|
+
ADD COLUMN IF NOT EXISTS confidence FLOAT DEFAULT 1.0; -- For inferred relations
|
|
2558
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
2559
|
+
END $$;
|
|
2560
|
+
|
|
2561
|
+
DO $$ BEGIN
|
|
2562
|
+
ALTER TABLE memory_relations
|
|
2563
|
+
ADD COLUMN IF NOT EXISTS access_count INTEGER DEFAULT 0;
|
|
2564
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
2565
|
+
END $$;
|
|
2566
|
+
|
|
2567
|
+
DO $$ BEGIN
|
|
2568
|
+
ALTER TABLE memory_relations
|
|
2569
|
+
ADD COLUMN IF NOT EXISTS last_accessed_at TIMESTAMPTZ;
|
|
2570
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
2571
|
+
END $$;
|
|
2572
|
+
|
|
2573
|
+
-- Inferred relationships table (for transitive closure)
|
|
2574
|
+
CREATE TABLE IF NOT EXISTS memory_inferred_relations (
|
|
2575
|
+
source_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
2576
|
+
target_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
2577
|
+
|
|
2578
|
+
-- Inference path (how we got here)
|
|
2579
|
+
inference_path UUID[] NOT NULL, -- Path of IDs from source to target
|
|
2580
|
+
hop_count INTEGER NOT NULL, -- Number of hops
|
|
2581
|
+
|
|
2582
|
+
-- Inference details
|
|
2583
|
+
relation_type VARCHAR(50) NOT NULL DEFAULT 'inferred',
|
|
2584
|
+
confidence FLOAT NOT NULL, -- Product of path confidences
|
|
2585
|
+
inference_method VARCHAR(50), -- transitive, similarity, temporal
|
|
2586
|
+
|
|
2587
|
+
-- Timestamps
|
|
2588
|
+
inferred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2589
|
+
expires_at TIMESTAMPTZ, -- Inferences can expire
|
|
2590
|
+
|
|
2591
|
+
PRIMARY KEY (source_id, target_id),
|
|
2592
|
+
CONSTRAINT no_self_inference CHECK (source_id != target_id),
|
|
2593
|
+
CONSTRAINT valid_confidence CHECK (confidence >= 0 AND confidence <= 1)
|
|
2594
|
+
);
|
|
2595
|
+
|
|
2596
|
+
CREATE INDEX IF NOT EXISTS idx_inferred_relations_source
|
|
2597
|
+
ON memory_inferred_relations(source_id);
|
|
2598
|
+
CREATE INDEX IF NOT EXISTS idx_inferred_relations_target
|
|
2599
|
+
ON memory_inferred_relations(target_id);
|
|
2600
|
+
CREATE INDEX IF NOT EXISTS idx_inferred_relations_confidence
|
|
2601
|
+
ON memory_inferred_relations(confidence DESC);
|
|
2602
|
+
CREATE INDEX IF NOT EXISTS idx_inferred_relations_expires
|
|
2603
|
+
ON memory_inferred_relations(expires_at)
|
|
2604
|
+
WHERE expires_at IS NOT NULL;
|
|
2605
|
+
|
|
2606
|
+
-- ============================================================
|
|
2607
|
+
-- SPATIAL MEMORY STATS - Materialized view for quick stats
|
|
2608
|
+
-- ============================================================
|
|
2609
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS spatial_memory_stats AS
|
|
2610
|
+
SELECT
|
|
2611
|
+
(SELECT COUNT(*) FROM semantic_quadrants) as total_quadrants,
|
|
2612
|
+
(SELECT COUNT(*) FROM memory_clusters) as total_clusters,
|
|
2613
|
+
(SELECT COUNT(*) FROM memory_hot_paths) as total_hot_paths,
|
|
2614
|
+
(SELECT COUNT(*) FROM memory_hot_paths WHERE is_cached = true) as cached_hot_paths,
|
|
2615
|
+
(SELECT COUNT(*) FROM memory_access_transitions) as total_transitions,
|
|
2616
|
+
(SELECT AVG(memory_count) FROM semantic_quadrants)::FLOAT as avg_memories_per_quadrant,
|
|
2617
|
+
(SELECT AVG(memory_count) FROM memory_clusters)::FLOAT as avg_memories_per_cluster,
|
|
2618
|
+
(SELECT AVG(heat_score) FROM memory_hot_paths)::FLOAT as avg_heat_score,
|
|
2619
|
+
(SELECT COUNT(*) FROM memory_inferred_relations) as total_inferred_relations,
|
|
2620
|
+
NOW() as computed_at
|
|
2621
|
+
;
|
|
2622
|
+
|
|
2623
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_spatial_memory_stats_singleton
|
|
2624
|
+
ON spatial_memory_stats(computed_at);
|
|
2625
|
+
|
|
2626
|
+
-- Function to refresh spatial stats
|
|
2627
|
+
CREATE OR REPLACE FUNCTION refresh_spatial_memory_stats()
|
|
2628
|
+
RETURNS void AS $$
|
|
2629
|
+
BEGIN
|
|
2630
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY spatial_memory_stats;
|
|
2631
|
+
END;
|
|
2632
|
+
$$ LANGUAGE plpgsql;
|
|
2633
|
+
|
|
2634
|
+
-- ============================================================
|
|
2635
|
+
-- TRIGGERS for automatic maintenance
|
|
2636
|
+
-- ============================================================
|
|
2637
|
+
|
|
2638
|
+
-- Update quadrant memory count on assignment changes
|
|
2639
|
+
CREATE OR REPLACE FUNCTION update_quadrant_count()
|
|
2640
|
+
RETURNS TRIGGER AS $$
|
|
2641
|
+
BEGIN
|
|
2642
|
+
IF TG_OP = 'INSERT' THEN
|
|
2643
|
+
UPDATE semantic_quadrants
|
|
2644
|
+
SET memory_count = memory_count + 1, updated_at = NOW()
|
|
2645
|
+
WHERE id = NEW.quadrant_id;
|
|
2646
|
+
RETURN NEW;
|
|
2647
|
+
ELSIF TG_OP = 'DELETE' THEN
|
|
2648
|
+
UPDATE semantic_quadrants
|
|
2649
|
+
SET memory_count = memory_count - 1, updated_at = NOW()
|
|
2650
|
+
WHERE id = OLD.quadrant_id;
|
|
2651
|
+
RETURN OLD;
|
|
2652
|
+
END IF;
|
|
2653
|
+
RETURN NULL;
|
|
2654
|
+
END;
|
|
2655
|
+
$$ LANGUAGE plpgsql;
|
|
2656
|
+
|
|
2657
|
+
DROP TRIGGER IF EXISTS quadrant_count_trigger ON memory_quadrant_assignments;
|
|
2658
|
+
CREATE TRIGGER quadrant_count_trigger
|
|
2659
|
+
AFTER INSERT OR DELETE ON memory_quadrant_assignments
|
|
2660
|
+
FOR EACH ROW
|
|
2661
|
+
EXECUTE FUNCTION update_quadrant_count();
|
|
2662
|
+
|
|
2663
|
+
-- Update cluster memory count on assignment changes
|
|
2664
|
+
CREATE OR REPLACE FUNCTION update_cluster_count()
|
|
2665
|
+
RETURNS TRIGGER AS $$
|
|
2666
|
+
BEGIN
|
|
2667
|
+
IF TG_OP = 'INSERT' THEN
|
|
2668
|
+
UPDATE memory_clusters
|
|
2669
|
+
SET memory_count = memory_count + 1, updated_at = NOW()
|
|
2670
|
+
WHERE id = NEW.cluster_id;
|
|
2671
|
+
RETURN NEW;
|
|
2672
|
+
ELSIF TG_OP = 'DELETE' THEN
|
|
2673
|
+
UPDATE memory_clusters
|
|
2674
|
+
SET memory_count = memory_count - 1, updated_at = NOW()
|
|
2675
|
+
WHERE id = OLD.cluster_id;
|
|
2676
|
+
RETURN OLD;
|
|
2677
|
+
END IF;
|
|
2678
|
+
RETURN NULL;
|
|
2679
|
+
END;
|
|
2680
|
+
$$ LANGUAGE plpgsql;
|
|
2681
|
+
|
|
2682
|
+
DROP TRIGGER IF EXISTS cluster_count_trigger ON memory_cluster_assignments;
|
|
2683
|
+
CREATE TRIGGER cluster_count_trigger
|
|
2684
|
+
AFTER INSERT OR DELETE ON memory_cluster_assignments
|
|
2685
|
+
FOR EACH ROW
|
|
2686
|
+
EXECUTE FUNCTION update_cluster_count();
|
|
2687
|
+
|
|
2688
|
+
-- Decay hot path heat scores periodically (run via cron/background job)
|
|
2689
|
+
CREATE OR REPLACE FUNCTION decay_hot_path_heat()
|
|
2690
|
+
RETURNS INTEGER AS $$
|
|
2691
|
+
DECLARE
|
|
2692
|
+
updated_count INTEGER;
|
|
2693
|
+
BEGIN
|
|
2694
|
+
-- Decay factor: multiply by 0.95 for each day since last access
|
|
2695
|
+
UPDATE memory_hot_paths
|
|
2696
|
+
SET heat_score = heat_score * POWER(0.95,
|
|
2697
|
+
EXTRACT(EPOCH FROM (NOW() - COALESCE(last_accessed_at, created_at))) / 86400
|
|
2698
|
+
),
|
|
2699
|
+
updated_at = NOW()
|
|
2700
|
+
WHERE heat_score > 0.01; -- Don't bother with near-zero scores
|
|
2701
|
+
|
|
2702
|
+
GET DIAGNOSTICS updated_count = ROW_COUNT;
|
|
2703
|
+
RETURN updated_count;
|
|
2704
|
+
END;
|
|
2705
|
+
$$ LANGUAGE plpgsql;
|
|
2706
|
+
|
|
2707
|
+
-- updated_at triggers
|
|
2708
|
+
DROP TRIGGER IF EXISTS semantic_quadrants_updated_at ON semantic_quadrants;
|
|
2709
|
+
CREATE TRIGGER semantic_quadrants_updated_at
|
|
2710
|
+
BEFORE UPDATE ON semantic_quadrants
|
|
2711
|
+
FOR EACH ROW
|
|
2712
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
2713
|
+
|
|
2714
|
+
DROP TRIGGER IF EXISTS memory_clusters_updated_at ON memory_clusters;
|
|
2715
|
+
CREATE TRIGGER memory_clusters_updated_at
|
|
2716
|
+
BEFORE UPDATE ON memory_clusters
|
|
2717
|
+
FOR EACH ROW
|
|
2718
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
2719
|
+
|
|
2720
|
+
DROP TRIGGER IF EXISTS memory_hot_paths_updated_at ON memory_hot_paths;
|
|
2721
|
+
CREATE TRIGGER memory_hot_paths_updated_at
|
|
2722
|
+
BEFORE UPDATE ON memory_hot_paths
|
|
2723
|
+
FOR EACH ROW
|
|
2724
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
2725
|
+
|
|
2726
|
+
DROP TRIGGER IF EXISTS memory_access_transitions_updated_at ON memory_access_transitions;
|
|
2727
|
+
CREATE TRIGGER memory_access_transitions_updated_at
|
|
2728
|
+
BEFORE UPDATE ON memory_access_transitions
|
|
2729
|
+
FOR EACH ROW
|
|
2730
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
2731
|
+
`,
|
|
2732
|
+
down: `
|
|
2733
|
+
DROP FUNCTION IF EXISTS decay_hot_path_heat();
|
|
2734
|
+
DROP FUNCTION IF EXISTS update_cluster_count();
|
|
2735
|
+
DROP FUNCTION IF EXISTS update_quadrant_count();
|
|
2736
|
+
DROP FUNCTION IF EXISTS refresh_spatial_memory_stats();
|
|
2737
|
+
DROP TRIGGER IF EXISTS memory_access_transitions_updated_at ON memory_access_transitions;
|
|
2738
|
+
DROP TRIGGER IF EXISTS memory_hot_paths_updated_at ON memory_hot_paths;
|
|
2739
|
+
DROP TRIGGER IF EXISTS memory_clusters_updated_at ON memory_clusters;
|
|
2740
|
+
DROP TRIGGER IF EXISTS semantic_quadrants_updated_at ON semantic_quadrants;
|
|
2741
|
+
DROP TRIGGER IF EXISTS cluster_count_trigger ON memory_cluster_assignments;
|
|
2742
|
+
DROP TRIGGER IF EXISTS quadrant_count_trigger ON memory_quadrant_assignments;
|
|
2743
|
+
DROP MATERIALIZED VIEW IF EXISTS spatial_memory_stats;
|
|
2744
|
+
DROP TABLE IF EXISTS memory_inferred_relations CASCADE;
|
|
2745
|
+
DROP TABLE IF EXISTS memory_access_transitions CASCADE;
|
|
2746
|
+
DROP TABLE IF EXISTS memory_hot_paths CASCADE;
|
|
2747
|
+
DROP TABLE IF EXISTS cluster_relations CASCADE;
|
|
2748
|
+
DROP TABLE IF EXISTS memory_cluster_assignments CASCADE;
|
|
2749
|
+
DROP TABLE IF EXISTS memory_clusters CASCADE;
|
|
2750
|
+
DROP TABLE IF EXISTS memory_quadrant_assignments CASCADE;
|
|
2751
|
+
DROP TABLE IF EXISTS semantic_quadrants CASCADE;
|
|
2752
|
+
ALTER TABLE memory_relations DROP COLUMN IF EXISTS relation_category;
|
|
2753
|
+
ALTER TABLE memory_relations DROP COLUMN IF EXISTS confidence;
|
|
2754
|
+
ALTER TABLE memory_relations DROP COLUMN IF EXISTS access_count;
|
|
2755
|
+
ALTER TABLE memory_relations DROP COLUMN IF EXISTS last_accessed_at;
|
|
2756
|
+
`,
|
|
2757
|
+
checksum: this.generateChecksum('create_spatial_memory_tables_v26')
|
|
2758
|
+
},
|
|
2759
|
+
// migration 27: Dashboard Query Optimizations
|
|
2760
|
+
// Adds indexes and materialized views for the SpecMem dashboard
|
|
2761
|
+
// Makes dashboard queries BLAZING fast no cap
|
|
2762
|
+
{
|
|
2763
|
+
version: 27,
|
|
2764
|
+
name: 'dashboard_query_optimizations',
|
|
2765
|
+
up: `
|
|
2766
|
+
-- ============================================================
|
|
2767
|
+
-- DASHBOARD-SPECIFIC INDEXES
|
|
2768
|
+
-- Optimized for common dashboard query patterns
|
|
2769
|
+
-- ============================================================
|
|
2770
|
+
|
|
2771
|
+
-- Composite index for filtered pagination by type + time
|
|
2772
|
+
-- Note: WHERE clause removed - NOW() is not IMMUTABLE and cannot be used in index predicates
|
|
2773
|
+
CREATE INDEX IF NOT EXISTS idx_memories_dashboard_type_time
|
|
2774
|
+
ON memories(memory_type, created_at DESC);
|
|
2775
|
+
|
|
2776
|
+
-- Composite index for importance filtering + time
|
|
2777
|
+
-- Note: WHERE clause removed - NOW() is not IMMUTABLE and cannot be used in index predicates
|
|
2778
|
+
CREATE INDEX IF NOT EXISTS idx_memories_dashboard_importance_time
|
|
2779
|
+
ON memories(importance, created_at DESC);
|
|
2780
|
+
|
|
2781
|
+
-- Index for recent activity queries (last 24h)
|
|
2782
|
+
-- Note: WHERE clause removed - NOW() is not IMMUTABLE and cannot be used in index predicates
|
|
2783
|
+
-- The index still improves performance for time-based queries
|
|
2784
|
+
CREATE INDEX IF NOT EXISTS idx_memories_recent_24h
|
|
2785
|
+
ON memories(created_at DESC);
|
|
2786
|
+
|
|
2787
|
+
-- Covering index for memory list queries (avoids table lookups)
|
|
2788
|
+
-- Includes commonly selected columns for list views
|
|
2789
|
+
-- Note: WHERE clause removed - NOW() is not IMMUTABLE and cannot be used in index predicates
|
|
2790
|
+
CREATE INDEX IF NOT EXISTS idx_memories_dashboard_list
|
|
2791
|
+
ON memories(created_at DESC, id, memory_type, importance)
|
|
2792
|
+
INCLUDE (tags, access_count, updated_at);
|
|
2793
|
+
|
|
2794
|
+
-- Index for tag + type combined filtering
|
|
2795
|
+
CREATE INDEX IF NOT EXISTS idx_memories_tags_type
|
|
2796
|
+
ON memories USING GIN(tags, memory_type);
|
|
2797
|
+
|
|
2798
|
+
-- ============================================================
|
|
2799
|
+
-- ENHANCED MATERIALIZED VIEW FOR DASHBOARD STATS
|
|
2800
|
+
-- More comprehensive than basic memory_stats view
|
|
2801
|
+
-- ============================================================
|
|
2802
|
+
|
|
2803
|
+
DROP MATERIALIZED VIEW IF EXISTS dashboard_stats;
|
|
2804
|
+
CREATE MATERIALIZED VIEW dashboard_stats AS
|
|
2805
|
+
SELECT
|
|
2806
|
+
-- Total counts
|
|
2807
|
+
COUNT(*) as total_memories,
|
|
2808
|
+
COUNT(*) FILTER (WHERE expires_at IS NULL OR expires_at > NOW()) as active_memories,
|
|
2809
|
+
|
|
2810
|
+
-- Type distribution
|
|
2811
|
+
COUNT(*) FILTER (WHERE memory_type = 'episodic') as episodic_count,
|
|
2812
|
+
COUNT(*) FILTER (WHERE memory_type = 'semantic') as semantic_count,
|
|
2813
|
+
COUNT(*) FILTER (WHERE memory_type = 'procedural') as procedural_count,
|
|
2814
|
+
COUNT(*) FILTER (WHERE memory_type = 'working') as working_count,
|
|
2815
|
+
COUNT(*) FILTER (WHERE memory_type = 'consolidated') as consolidated_count,
|
|
2816
|
+
|
|
2817
|
+
-- Importance distribution
|
|
2818
|
+
COUNT(*) FILTER (WHERE importance = 'critical') as critical_count,
|
|
2819
|
+
COUNT(*) FILTER (WHERE importance = 'high') as high_count,
|
|
2820
|
+
COUNT(*) FILTER (WHERE importance = 'medium') as medium_count,
|
|
2821
|
+
COUNT(*) FILTER (WHERE importance = 'low') as low_count,
|
|
2822
|
+
COUNT(*) FILTER (WHERE importance = 'trivial') as trivial_count,
|
|
2823
|
+
|
|
2824
|
+
-- Feature usage
|
|
2825
|
+
COUNT(*) FILTER (WHERE embedding IS NOT NULL) as with_embeddings,
|
|
2826
|
+
COUNT(*) FILTER (WHERE image_data IS NOT NULL) as with_images,
|
|
2827
|
+
COUNT(*) FILTER (WHERE array_length(tags, 1) > 0) as with_tags,
|
|
2828
|
+
COUNT(*) FILTER (WHERE array_length(consolidated_from, 1) > 0) as consolidated,
|
|
2829
|
+
|
|
2830
|
+
-- Expiration stats
|
|
2831
|
+
COUNT(*) FILTER (WHERE expires_at IS NOT NULL AND expires_at < NOW()) as expired_count,
|
|
2832
|
+
COUNT(*) FILTER (WHERE expires_at IS NOT NULL AND expires_at > NOW()) as expiring_soon,
|
|
2833
|
+
|
|
2834
|
+
-- Time-based stats
|
|
2835
|
+
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '24 hours') as created_last_24h,
|
|
2836
|
+
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '7 days') as created_last_7d,
|
|
2837
|
+
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '30 days') as created_last_30d,
|
|
2838
|
+
COUNT(*) FILTER (WHERE updated_at > NOW() - INTERVAL '24 hours') as updated_last_24h,
|
|
2839
|
+
|
|
2840
|
+
-- Aggregates
|
|
2841
|
+
COALESCE(AVG(access_count), 0)::float as avg_access_count,
|
|
2842
|
+
COALESCE(MAX(access_count), 0) as max_access_count,
|
|
2843
|
+
COALESCE(AVG(length(content)), 0)::float as avg_content_length,
|
|
2844
|
+
COALESCE(SUM(length(content)), 0)::bigint as total_content_size,
|
|
2845
|
+
|
|
2846
|
+
-- Time range
|
|
2847
|
+
MIN(created_at) as oldest_memory,
|
|
2848
|
+
MAX(created_at) as newest_memory,
|
|
2849
|
+
|
|
2850
|
+
-- Computed at timestamp
|
|
2851
|
+
NOW() as computed_at
|
|
2852
|
+
FROM memories;
|
|
2853
|
+
|
|
2854
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_dashboard_stats_singleton
|
|
2855
|
+
ON dashboard_stats(computed_at);
|
|
2856
|
+
|
|
2857
|
+
-- Function to refresh dashboard stats
|
|
2858
|
+
CREATE OR REPLACE FUNCTION refresh_dashboard_stats()
|
|
2859
|
+
RETURNS void AS $$
|
|
2860
|
+
BEGIN
|
|
2861
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY dashboard_stats;
|
|
2862
|
+
END;
|
|
2863
|
+
$$ LANGUAGE plpgsql;
|
|
2864
|
+
|
|
2865
|
+
-- ============================================================
|
|
2866
|
+
-- TIME SERIES AGGREGATION TABLE
|
|
2867
|
+
-- Pre-computed daily/weekly/monthly counts for fast charts
|
|
2868
|
+
-- ============================================================
|
|
2869
|
+
|
|
2870
|
+
CREATE TABLE IF NOT EXISTS memory_time_series (
|
|
2871
|
+
id SERIAL PRIMARY KEY,
|
|
2872
|
+
granularity VARCHAR(10) NOT NULL, -- 'hour', 'day', 'week', 'month'
|
|
2873
|
+
period_start TIMESTAMPTZ NOT NULL,
|
|
2874
|
+
period_end TIMESTAMPTZ NOT NULL,
|
|
2875
|
+
|
|
2876
|
+
-- Counts by type
|
|
2877
|
+
total_count INTEGER NOT NULL DEFAULT 0,
|
|
2878
|
+
episodic_count INTEGER DEFAULT 0,
|
|
2879
|
+
semantic_count INTEGER DEFAULT 0,
|
|
2880
|
+
procedural_count INTEGER DEFAULT 0,
|
|
2881
|
+
working_count INTEGER DEFAULT 0,
|
|
2882
|
+
consolidated_count INTEGER DEFAULT 0,
|
|
2883
|
+
|
|
2884
|
+
-- Counts by importance
|
|
2885
|
+
critical_count INTEGER DEFAULT 0,
|
|
2886
|
+
high_count INTEGER DEFAULT 0,
|
|
2887
|
+
medium_count INTEGER DEFAULT 0,
|
|
2888
|
+
low_count INTEGER DEFAULT 0,
|
|
2889
|
+
trivial_count INTEGER DEFAULT 0,
|
|
2890
|
+
|
|
2891
|
+
-- Other metrics
|
|
2892
|
+
with_embeddings INTEGER DEFAULT 0,
|
|
2893
|
+
with_images INTEGER DEFAULT 0,
|
|
2894
|
+
avg_content_length FLOAT,
|
|
2895
|
+
|
|
2896
|
+
-- Metadata
|
|
2897
|
+
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
2898
|
+
|
|
2899
|
+
CONSTRAINT unique_period UNIQUE (granularity, period_start)
|
|
2900
|
+
);
|
|
2901
|
+
|
|
2902
|
+
CREATE INDEX IF NOT EXISTS idx_time_series_lookup
|
|
2903
|
+
ON memory_time_series(granularity, period_start DESC);
|
|
2904
|
+
|
|
2905
|
+
-- Function to populate time series data
|
|
2906
|
+
CREATE OR REPLACE FUNCTION populate_memory_time_series(
|
|
2907
|
+
p_granularity VARCHAR(10),
|
|
2908
|
+
p_days_back INTEGER DEFAULT 90
|
|
2909
|
+
)
|
|
2910
|
+
RETURNS INTEGER AS $$
|
|
2911
|
+
DECLARE
|
|
2912
|
+
inserted_count INTEGER := 0;
|
|
2913
|
+
BEGIN
|
|
2914
|
+
INSERT INTO memory_time_series (
|
|
2915
|
+
granularity, period_start, period_end,
|
|
2916
|
+
total_count, episodic_count, semantic_count, procedural_count, working_count, consolidated_count,
|
|
2917
|
+
critical_count, high_count, medium_count, low_count, trivial_count,
|
|
2918
|
+
with_embeddings, with_images, avg_content_length
|
|
2919
|
+
)
|
|
2920
|
+
SELECT
|
|
2921
|
+
p_granularity,
|
|
2922
|
+
date_trunc(p_granularity, created_at) as period_start,
|
|
2923
|
+
date_trunc(p_granularity, created_at) + CASE
|
|
2924
|
+
WHEN p_granularity = 'hour' THEN INTERVAL '1 hour'
|
|
2925
|
+
WHEN p_granularity = 'day' THEN INTERVAL '1 day'
|
|
2926
|
+
WHEN p_granularity = 'week' THEN INTERVAL '1 week'
|
|
2927
|
+
WHEN p_granularity = 'month' THEN INTERVAL '1 month'
|
|
2928
|
+
END as period_end,
|
|
2929
|
+
COUNT(*),
|
|
2930
|
+
COUNT(*) FILTER (WHERE memory_type = 'episodic'),
|
|
2931
|
+
COUNT(*) FILTER (WHERE memory_type = 'semantic'),
|
|
2932
|
+
COUNT(*) FILTER (WHERE memory_type = 'procedural'),
|
|
2933
|
+
COUNT(*) FILTER (WHERE memory_type = 'working'),
|
|
2934
|
+
COUNT(*) FILTER (WHERE memory_type = 'consolidated'),
|
|
2935
|
+
COUNT(*) FILTER (WHERE importance = 'critical'),
|
|
2936
|
+
COUNT(*) FILTER (WHERE importance = 'high'),
|
|
2937
|
+
COUNT(*) FILTER (WHERE importance = 'medium'),
|
|
2938
|
+
COUNT(*) FILTER (WHERE importance = 'low'),
|
|
2939
|
+
COUNT(*) FILTER (WHERE importance = 'trivial'),
|
|
2940
|
+
COUNT(*) FILTER (WHERE embedding IS NOT NULL),
|
|
2941
|
+
COUNT(*) FILTER (WHERE image_data IS NOT NULL),
|
|
2942
|
+
AVG(length(content))::float
|
|
2943
|
+
FROM memories
|
|
2944
|
+
WHERE created_at > NOW() - (p_days_back || ' days')::INTERVAL
|
|
2945
|
+
GROUP BY date_trunc(p_granularity, created_at)
|
|
2946
|
+
ON CONFLICT (granularity, period_start)
|
|
2947
|
+
DO UPDATE SET
|
|
2948
|
+
total_count = EXCLUDED.total_count,
|
|
2949
|
+
episodic_count = EXCLUDED.episodic_count,
|
|
2950
|
+
semantic_count = EXCLUDED.semantic_count,
|
|
2951
|
+
procedural_count = EXCLUDED.procedural_count,
|
|
2952
|
+
working_count = EXCLUDED.working_count,
|
|
2953
|
+
consolidated_count = EXCLUDED.consolidated_count,
|
|
2954
|
+
critical_count = EXCLUDED.critical_count,
|
|
2955
|
+
high_count = EXCLUDED.high_count,
|
|
2956
|
+
medium_count = EXCLUDED.medium_count,
|
|
2957
|
+
low_count = EXCLUDED.low_count,
|
|
2958
|
+
trivial_count = EXCLUDED.trivial_count,
|
|
2959
|
+
with_embeddings = EXCLUDED.with_embeddings,
|
|
2960
|
+
with_images = EXCLUDED.with_images,
|
|
2961
|
+
avg_content_length = EXCLUDED.avg_content_length,
|
|
2962
|
+
computed_at = NOW();
|
|
2963
|
+
|
|
2964
|
+
GET DIAGNOSTICS inserted_count = ROW_COUNT;
|
|
2965
|
+
RETURN inserted_count;
|
|
2966
|
+
END;
|
|
2967
|
+
$$ LANGUAGE plpgsql;
|
|
2968
|
+
|
|
2969
|
+
-- ============================================================
|
|
2970
|
+
-- TAG STATISTICS TABLE
|
|
2971
|
+
-- Pre-aggregated tag stats for fast dashboard queries
|
|
2972
|
+
-- ============================================================
|
|
2973
|
+
|
|
2974
|
+
CREATE TABLE IF NOT EXISTS tag_statistics (
|
|
2975
|
+
tag_name VARCHAR(255) PRIMARY KEY,
|
|
2976
|
+
memory_count INTEGER NOT NULL DEFAULT 0,
|
|
2977
|
+
first_used TIMESTAMPTZ,
|
|
2978
|
+
last_used TIMESTAMPTZ,
|
|
2979
|
+
avg_importance_rank FLOAT, -- 1=critical, 5=trivial
|
|
2980
|
+
top_memory_types TEXT[],
|
|
2981
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
2982
|
+
);
|
|
2983
|
+
|
|
2984
|
+
CREATE INDEX IF NOT EXISTS idx_tag_stats_count
|
|
2985
|
+
ON tag_statistics(memory_count DESC);
|
|
2986
|
+
|
|
2987
|
+
-- Function to refresh tag statistics
|
|
2988
|
+
CREATE OR REPLACE FUNCTION refresh_tag_statistics()
|
|
2989
|
+
RETURNS INTEGER AS $$
|
|
2990
|
+
DECLARE
|
|
2991
|
+
updated_count INTEGER := 0;
|
|
2992
|
+
BEGIN
|
|
2993
|
+
INSERT INTO tag_statistics (tag_name, memory_count, first_used, last_used, updated_at)
|
|
2994
|
+
SELECT
|
|
2995
|
+
unnest(tags) as tag_name,
|
|
2996
|
+
COUNT(*),
|
|
2997
|
+
MIN(created_at),
|
|
2998
|
+
MAX(created_at),
|
|
2999
|
+
NOW()
|
|
3000
|
+
FROM memories
|
|
3001
|
+
WHERE array_length(tags, 1) > 0
|
|
3002
|
+
GROUP BY unnest(tags)
|
|
3003
|
+
ON CONFLICT (tag_name)
|
|
3004
|
+
DO UPDATE SET
|
|
3005
|
+
memory_count = EXCLUDED.memory_count,
|
|
3006
|
+
first_used = EXCLUDED.first_used,
|
|
3007
|
+
last_used = EXCLUDED.last_used,
|
|
3008
|
+
updated_at = NOW();
|
|
3009
|
+
|
|
3010
|
+
GET DIAGNOSTICS updated_count = ROW_COUNT;
|
|
3011
|
+
RETURN updated_count;
|
|
3012
|
+
END;
|
|
3013
|
+
$$ LANGUAGE plpgsql;
|
|
3014
|
+
|
|
3015
|
+
-- ============================================================
|
|
3016
|
+
-- DASHBOARD CACHE TABLE
|
|
3017
|
+
-- For caching expensive dashboard query results
|
|
3018
|
+
-- ============================================================
|
|
3019
|
+
|
|
3020
|
+
CREATE TABLE IF NOT EXISTS dashboard_cache (
|
|
3021
|
+
cache_key VARCHAR(255) PRIMARY KEY,
|
|
3022
|
+
cache_value JSONB NOT NULL,
|
|
3023
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3024
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
3025
|
+
hit_count INTEGER DEFAULT 0,
|
|
3026
|
+
last_accessed_at TIMESTAMPTZ
|
|
3027
|
+
);
|
|
3028
|
+
|
|
3029
|
+
CREATE INDEX IF NOT EXISTS idx_dashboard_cache_expires
|
|
3030
|
+
ON dashboard_cache(expires_at);
|
|
3031
|
+
|
|
3032
|
+
-- Function to get or set cache
|
|
3033
|
+
CREATE OR REPLACE FUNCTION dashboard_cache_get(
|
|
3034
|
+
p_key VARCHAR(255)
|
|
3035
|
+
)
|
|
3036
|
+
RETURNS JSONB AS $$
|
|
3037
|
+
DECLARE
|
|
3038
|
+
v_result JSONB;
|
|
3039
|
+
BEGIN
|
|
3040
|
+
UPDATE dashboard_cache
|
|
3041
|
+
SET hit_count = hit_count + 1, last_accessed_at = NOW()
|
|
3042
|
+
WHERE cache_key = p_key AND expires_at > NOW()
|
|
3043
|
+
RETURNING cache_value INTO v_result;
|
|
3044
|
+
|
|
3045
|
+
RETURN v_result;
|
|
3046
|
+
END;
|
|
3047
|
+
$$ LANGUAGE plpgsql;
|
|
3048
|
+
|
|
3049
|
+
CREATE OR REPLACE FUNCTION dashboard_cache_set(
|
|
3050
|
+
p_key VARCHAR(255),
|
|
3051
|
+
p_value JSONB,
|
|
3052
|
+
p_ttl_seconds INTEGER DEFAULT 300
|
|
3053
|
+
)
|
|
3054
|
+
RETURNS void AS $$
|
|
3055
|
+
BEGIN
|
|
3056
|
+
INSERT INTO dashboard_cache (cache_key, cache_value, expires_at)
|
|
3057
|
+
VALUES (p_key, p_value, NOW() + (p_ttl_seconds || ' seconds')::INTERVAL)
|
|
3058
|
+
ON CONFLICT (cache_key)
|
|
3059
|
+
DO UPDATE SET
|
|
3060
|
+
cache_value = EXCLUDED.cache_value,
|
|
3061
|
+
expires_at = EXCLUDED.expires_at,
|
|
3062
|
+
created_at = NOW(),
|
|
3063
|
+
hit_count = 0;
|
|
3064
|
+
END;
|
|
3065
|
+
$$ LANGUAGE plpgsql;
|
|
3066
|
+
|
|
3067
|
+
-- Cleanup expired cache entries
|
|
3068
|
+
CREATE OR REPLACE FUNCTION dashboard_cache_cleanup()
|
|
3069
|
+
RETURNS INTEGER AS $$
|
|
3070
|
+
DECLARE
|
|
3071
|
+
deleted_count INTEGER;
|
|
3072
|
+
BEGIN
|
|
3073
|
+
DELETE FROM dashboard_cache WHERE expires_at < NOW();
|
|
3074
|
+
GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
|
3075
|
+
RETURN deleted_count;
|
|
3076
|
+
END;
|
|
3077
|
+
$$ LANGUAGE plpgsql;
|
|
3078
|
+
|
|
3079
|
+
-- Initial population
|
|
3080
|
+
SELECT populate_memory_time_series('day', 90);
|
|
3081
|
+
SELECT populate_memory_time_series('week', 365);
|
|
3082
|
+
SELECT refresh_tag_statistics();
|
|
3083
|
+
`,
|
|
3084
|
+
down: `
|
|
3085
|
+
DROP FUNCTION IF EXISTS dashboard_cache_cleanup();
|
|
3086
|
+
DROP FUNCTION IF EXISTS dashboard_cache_set(VARCHAR, JSONB, INTEGER);
|
|
3087
|
+
DROP FUNCTION IF EXISTS dashboard_cache_get(VARCHAR);
|
|
3088
|
+
DROP TABLE IF EXISTS dashboard_cache CASCADE;
|
|
3089
|
+
DROP FUNCTION IF EXISTS refresh_tag_statistics();
|
|
3090
|
+
DROP TABLE IF EXISTS tag_statistics CASCADE;
|
|
3091
|
+
DROP FUNCTION IF EXISTS populate_memory_time_series(VARCHAR, INTEGER);
|
|
3092
|
+
DROP TABLE IF EXISTS memory_time_series CASCADE;
|
|
3093
|
+
DROP FUNCTION IF EXISTS refresh_dashboard_stats();
|
|
3094
|
+
DROP MATERIALIZED VIEW IF EXISTS dashboard_stats;
|
|
3095
|
+
DROP INDEX IF EXISTS idx_memories_tags_type;
|
|
3096
|
+
DROP INDEX IF EXISTS idx_memories_dashboard_list;
|
|
3097
|
+
DROP INDEX IF EXISTS idx_memories_recent_24h;
|
|
3098
|
+
DROP INDEX IF EXISTS idx_memories_dashboard_importance_time;
|
|
3099
|
+
DROP INDEX IF EXISTS idx_memories_dashboard_type_time;
|
|
3100
|
+
`,
|
|
3101
|
+
checksum: this.generateChecksum('dashboard_query_optimizations_v27')
|
|
3102
|
+
},
|
|
3103
|
+
// migration 28: API Endpoint Data Migration
|
|
3104
|
+
// Moves all JSON-based API data storage to PostgreSQL
|
|
3105
|
+
// Includes: endpoints, bans, oauth, security events, admin sessions
|
|
3106
|
+
{
|
|
3107
|
+
version: 28,
|
|
3108
|
+
name: 'create_api_data_tables',
|
|
3109
|
+
up: `
|
|
3110
|
+
-- ============================================================
|
|
3111
|
+
-- API ENDPOINTS TABLE
|
|
3112
|
+
-- Stores endpoint configuration, rate limits, and access control
|
|
3113
|
+
-- Replaces data/api-endpoints/endpoints.json
|
|
3114
|
+
-- ============================================================
|
|
3115
|
+
CREATE TABLE IF NOT EXISTS api_endpoints (
|
|
3116
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
3117
|
+
|
|
3118
|
+
-- Endpoint identification
|
|
3119
|
+
path VARCHAR(500) NOT NULL,
|
|
3120
|
+
method VARCHAR(10) NOT NULL DEFAULT 'GET',
|
|
3121
|
+
name VARCHAR(255) NOT NULL,
|
|
3122
|
+
description TEXT,
|
|
3123
|
+
|
|
3124
|
+
-- Rate limiting configuration
|
|
3125
|
+
rate_limit_max INTEGER NOT NULL DEFAULT 100,
|
|
3126
|
+
rate_limit_window_ms INTEGER NOT NULL DEFAULT 60000,
|
|
3127
|
+
rate_limit_skip_localhost BOOLEAN DEFAULT true,
|
|
3128
|
+
|
|
3129
|
+
-- Authentication and access control
|
|
3130
|
+
requires_auth BOOLEAN DEFAULT true,
|
|
3131
|
+
allowed_roles TEXT[] DEFAULT '{}',
|
|
3132
|
+
allowed_ips TEXT[] DEFAULT '{}',
|
|
3133
|
+
blocked_ips TEXT[] DEFAULT '{}',
|
|
3134
|
+
|
|
3135
|
+
-- Status and monitoring
|
|
3136
|
+
is_enabled BOOLEAN DEFAULT true,
|
|
3137
|
+
is_deprecated BOOLEAN DEFAULT false,
|
|
3138
|
+
deprecation_message TEXT,
|
|
3139
|
+
|
|
3140
|
+
-- Usage statistics
|
|
3141
|
+
total_requests BIGINT DEFAULT 0,
|
|
3142
|
+
successful_requests BIGINT DEFAULT 0,
|
|
3143
|
+
failed_requests BIGINT DEFAULT 0,
|
|
3144
|
+
last_request_at TIMESTAMPTZ,
|
|
3145
|
+
|
|
3146
|
+
-- Metadata
|
|
3147
|
+
tags TEXT[] DEFAULT '{}',
|
|
3148
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
3149
|
+
|
|
3150
|
+
-- Timestamps
|
|
3151
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3152
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3153
|
+
|
|
3154
|
+
-- Constraints
|
|
3155
|
+
CONSTRAINT valid_method CHECK (
|
|
3156
|
+
method IN ('GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD')
|
|
3157
|
+
),
|
|
3158
|
+
CONSTRAINT unique_endpoint UNIQUE (path, method)
|
|
3159
|
+
);
|
|
3160
|
+
|
|
3161
|
+
-- Indexes for endpoint lookups
|
|
3162
|
+
CREATE INDEX IF NOT EXISTS idx_api_endpoints_path
|
|
3163
|
+
ON api_endpoints(path);
|
|
3164
|
+
CREATE INDEX IF NOT EXISTS idx_api_endpoints_method
|
|
3165
|
+
ON api_endpoints(method);
|
|
3166
|
+
CREATE INDEX IF NOT EXISTS idx_api_endpoints_enabled
|
|
3167
|
+
ON api_endpoints(is_enabled)
|
|
3168
|
+
WHERE is_enabled = true;
|
|
3169
|
+
CREATE INDEX IF NOT EXISTS idx_api_endpoints_auth
|
|
3170
|
+
ON api_endpoints(requires_auth);
|
|
3171
|
+
CREATE INDEX IF NOT EXISTS idx_api_endpoints_tags
|
|
3172
|
+
ON api_endpoints USING GIN(tags);
|
|
3173
|
+
|
|
3174
|
+
-- Trigger for updated_at
|
|
3175
|
+
DROP TRIGGER IF EXISTS api_endpoints_updated_at ON api_endpoints;
|
|
3176
|
+
CREATE TRIGGER api_endpoints_updated_at
|
|
3177
|
+
BEFORE UPDATE ON api_endpoints
|
|
3178
|
+
FOR EACH ROW
|
|
3179
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
3180
|
+
|
|
3181
|
+
-- ============================================================
|
|
3182
|
+
-- BANS TABLE
|
|
3183
|
+
-- Stores IP bans and autoban configuration
|
|
3184
|
+
-- Replaces data/bans/data.json and data/bans/autoban-config.json
|
|
3185
|
+
-- ============================================================
|
|
3186
|
+
CREATE TABLE IF NOT EXISTS ip_bans (
|
|
3187
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
3188
|
+
|
|
3189
|
+
-- Ban identification
|
|
3190
|
+
ip_address VARCHAR(45) NOT NULL, -- Supports IPv4 and IPv6
|
|
3191
|
+
ip_range VARCHAR(50), -- CIDR notation for range bans
|
|
3192
|
+
|
|
3193
|
+
-- Ban details
|
|
3194
|
+
reason TEXT NOT NULL,
|
|
3195
|
+
ban_type VARCHAR(50) NOT NULL DEFAULT 'manual',
|
|
3196
|
+
severity VARCHAR(20) DEFAULT 'medium',
|
|
3197
|
+
|
|
3198
|
+
-- Duration
|
|
3199
|
+
is_permanent BOOLEAN DEFAULT false,
|
|
3200
|
+
expires_at TIMESTAMPTZ,
|
|
3201
|
+
|
|
3202
|
+
-- Context
|
|
3203
|
+
user_agent TEXT,
|
|
3204
|
+
fingerprint VARCHAR(255),
|
|
3205
|
+
country VARCHAR(100),
|
|
3206
|
+
|
|
3207
|
+
-- Violation tracking
|
|
3208
|
+
violation_count INTEGER DEFAULT 1,
|
|
3209
|
+
violations JSONB DEFAULT '[]',
|
|
3210
|
+
|
|
3211
|
+
-- Status
|
|
3212
|
+
is_active BOOLEAN DEFAULT true,
|
|
3213
|
+
lifted_at TIMESTAMPTZ,
|
|
3214
|
+
lifted_by VARCHAR(255),
|
|
3215
|
+
lift_reason TEXT,
|
|
3216
|
+
|
|
3217
|
+
-- Metadata
|
|
3218
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
3219
|
+
|
|
3220
|
+
-- Timestamps
|
|
3221
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3222
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3223
|
+
|
|
3224
|
+
-- Constraints
|
|
3225
|
+
CONSTRAINT valid_ban_type CHECK (
|
|
3226
|
+
ban_type IN ('manual', 'auto', 'vpn', 'rate_limit', 'security', 'abuse')
|
|
3227
|
+
),
|
|
3228
|
+
CONSTRAINT valid_severity CHECK (
|
|
3229
|
+
severity IN ('low', 'medium', 'high', 'critical')
|
|
3230
|
+
)
|
|
3231
|
+
);
|
|
3232
|
+
|
|
3233
|
+
-- Indexes for ban lookups
|
|
3234
|
+
CREATE INDEX IF NOT EXISTS idx_ip_bans_ip
|
|
3235
|
+
ON ip_bans(ip_address);
|
|
3236
|
+
CREATE INDEX IF NOT EXISTS idx_ip_bans_active
|
|
3237
|
+
ON ip_bans(is_active)
|
|
3238
|
+
WHERE is_active = true;
|
|
3239
|
+
CREATE INDEX IF NOT EXISTS idx_ip_bans_expires
|
|
3240
|
+
ON ip_bans(expires_at)
|
|
3241
|
+
WHERE expires_at IS NOT NULL AND is_active = true;
|
|
3242
|
+
CREATE INDEX IF NOT EXISTS idx_ip_bans_type
|
|
3243
|
+
ON ip_bans(ban_type);
|
|
3244
|
+
CREATE INDEX IF NOT EXISTS idx_ip_bans_created
|
|
3245
|
+
ON ip_bans(created_at DESC);
|
|
3246
|
+
|
|
3247
|
+
-- Trigger for updated_at
|
|
3248
|
+
DROP TRIGGER IF EXISTS ip_bans_updated_at ON ip_bans;
|
|
3249
|
+
CREATE TRIGGER ip_bans_updated_at
|
|
3250
|
+
BEFORE UPDATE ON ip_bans
|
|
3251
|
+
FOR EACH ROW
|
|
3252
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
3253
|
+
|
|
3254
|
+
-- Autoban configuration table
|
|
3255
|
+
CREATE TABLE IF NOT EXISTS autoban_config (
|
|
3256
|
+
id SERIAL PRIMARY KEY,
|
|
3257
|
+
|
|
3258
|
+
-- Configuration
|
|
3259
|
+
is_enabled BOOLEAN DEFAULT true,
|
|
3260
|
+
threshold INTEGER NOT NULL DEFAULT 10,
|
|
3261
|
+
duration_ms INTEGER NOT NULL DEFAULT 300000,
|
|
3262
|
+
window_ms INTEGER NOT NULL DEFAULT 86400000,
|
|
3263
|
+
|
|
3264
|
+
-- Violation types to track
|
|
3265
|
+
tracked_violations TEXT[] DEFAULT ARRAY['vpn', 'rate_limit', 'security'],
|
|
3266
|
+
|
|
3267
|
+
-- Exclusions
|
|
3268
|
+
excluded_ips TEXT[] DEFAULT '{}',
|
|
3269
|
+
excluded_countries TEXT[] DEFAULT '{}',
|
|
3270
|
+
|
|
3271
|
+
-- Metadata
|
|
3272
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
3273
|
+
|
|
3274
|
+
-- Timestamps
|
|
3275
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3276
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
3277
|
+
);
|
|
3278
|
+
|
|
3279
|
+
-- Trigger for updated_at
|
|
3280
|
+
DROP TRIGGER IF EXISTS autoban_config_updated_at ON autoban_config;
|
|
3281
|
+
CREATE TRIGGER autoban_config_updated_at
|
|
3282
|
+
BEFORE UPDATE ON autoban_config
|
|
3283
|
+
FOR EACH ROW
|
|
3284
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
3285
|
+
|
|
3286
|
+
-- Insert default autoban config
|
|
3287
|
+
INSERT INTO autoban_config (is_enabled, threshold, duration_ms, window_ms)
|
|
3288
|
+
VALUES (true, 10, 300000, 86400000)
|
|
3289
|
+
ON CONFLICT DO NOTHING;
|
|
3290
|
+
|
|
3291
|
+
-- ============================================================
|
|
3292
|
+
-- OAUTH PROVIDERS TABLE
|
|
3293
|
+
-- Stores OAuth provider configurations
|
|
3294
|
+
-- Replaces data/oauth/providers.json
|
|
3295
|
+
-- ============================================================
|
|
3296
|
+
CREATE TABLE IF NOT EXISTS oauth_providers (
|
|
3297
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
3298
|
+
|
|
3299
|
+
-- Provider identification
|
|
3300
|
+
provider_name VARCHAR(100) NOT NULL UNIQUE,
|
|
3301
|
+
display_name VARCHAR(255),
|
|
3302
|
+
|
|
3303
|
+
-- OAuth configuration (encrypted in application layer)
|
|
3304
|
+
client_id TEXT,
|
|
3305
|
+
client_secret_encrypted TEXT,
|
|
3306
|
+
authorization_url TEXT,
|
|
3307
|
+
token_url TEXT,
|
|
3308
|
+
userinfo_url TEXT,
|
|
3309
|
+
scope TEXT DEFAULT 'openid profile email',
|
|
3310
|
+
|
|
3311
|
+
-- Provider settings
|
|
3312
|
+
is_enabled BOOLEAN DEFAULT false,
|
|
3313
|
+
is_configured BOOLEAN DEFAULT false,
|
|
3314
|
+
|
|
3315
|
+
-- Callback configuration
|
|
3316
|
+
redirect_uri TEXT,
|
|
3317
|
+
|
|
3318
|
+
-- Metadata
|
|
3319
|
+
icon_url TEXT,
|
|
3320
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
3321
|
+
|
|
3322
|
+
-- Timestamps
|
|
3323
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3324
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
3325
|
+
);
|
|
3326
|
+
|
|
3327
|
+
-- Trigger for updated_at
|
|
3328
|
+
DROP TRIGGER IF EXISTS oauth_providers_updated_at ON oauth_providers;
|
|
3329
|
+
CREATE TRIGGER oauth_providers_updated_at
|
|
3330
|
+
BEFORE UPDATE ON oauth_providers
|
|
3331
|
+
FOR EACH ROW
|
|
3332
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
3333
|
+
|
|
3334
|
+
-- ============================================================
|
|
3335
|
+
-- SECURITY EVENTS TABLE
|
|
3336
|
+
-- Stores VPN violations, security events, and audit logs
|
|
3337
|
+
-- Replaces data/events/vpn.json and data/vpn_violations/*.json
|
|
3338
|
+
-- ============================================================
|
|
3339
|
+
CREATE TABLE IF NOT EXISTS security_events (
|
|
3340
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
3341
|
+
|
|
3342
|
+
-- Event identification
|
|
3343
|
+
event_type VARCHAR(50) NOT NULL,
|
|
3344
|
+
event_action VARCHAR(255) NOT NULL,
|
|
3345
|
+
category VARCHAR(50) NOT NULL DEFAULT 'violation',
|
|
3346
|
+
|
|
3347
|
+
-- Source identification
|
|
3348
|
+
ip_address VARCHAR(45),
|
|
3349
|
+
user_agent TEXT,
|
|
3350
|
+
fingerprint VARCHAR(255),
|
|
3351
|
+
session_id VARCHAR(255),
|
|
3352
|
+
|
|
3353
|
+
-- Event details
|
|
3354
|
+
details JSONB NOT NULL DEFAULT '{}',
|
|
3355
|
+
|
|
3356
|
+
-- Classification
|
|
3357
|
+
severity VARCHAR(20) NOT NULL DEFAULT 'medium',
|
|
3358
|
+
threat_score INTEGER DEFAULT 0,
|
|
3359
|
+
|
|
3360
|
+
-- Geographic info
|
|
3361
|
+
country VARCHAR(100),
|
|
3362
|
+
region VARCHAR(255),
|
|
3363
|
+
city VARCHAR(255),
|
|
3364
|
+
|
|
3365
|
+
-- Detection flags
|
|
3366
|
+
is_vpn BOOLEAN DEFAULT false,
|
|
3367
|
+
is_proxy BOOLEAN DEFAULT false,
|
|
3368
|
+
is_tor BOOLEAN DEFAULT false,
|
|
3369
|
+
is_data_center BOOLEAN DEFAULT false,
|
|
3370
|
+
is_government BOOLEAN DEFAULT false,
|
|
3371
|
+
is_federal_facility BOOLEAN DEFAULT false,
|
|
3372
|
+
|
|
3373
|
+
-- Resolution
|
|
3374
|
+
is_resolved BOOLEAN DEFAULT false,
|
|
3375
|
+
resolved_at TIMESTAMPTZ,
|
|
3376
|
+
resolved_by VARCHAR(255),
|
|
3377
|
+
resolution_notes TEXT,
|
|
3378
|
+
|
|
3379
|
+
-- Metadata
|
|
3380
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
3381
|
+
|
|
3382
|
+
-- Timestamps
|
|
3383
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3384
|
+
|
|
3385
|
+
-- Constraints
|
|
3386
|
+
CONSTRAINT valid_event_category CHECK (
|
|
3387
|
+
category IN ('violation', 'warning', 'info', 'audit', 'error')
|
|
3388
|
+
),
|
|
3389
|
+
CONSTRAINT valid_event_severity CHECK (
|
|
3390
|
+
severity IN ('low', 'medium', 'high', 'critical')
|
|
3391
|
+
)
|
|
3392
|
+
);
|
|
3393
|
+
|
|
3394
|
+
-- Indexes for security event queries
|
|
3395
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_type
|
|
3396
|
+
ON security_events(event_type);
|
|
3397
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_category
|
|
3398
|
+
ON security_events(category);
|
|
3399
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_ip
|
|
3400
|
+
ON security_events(ip_address)
|
|
3401
|
+
WHERE ip_address IS NOT NULL;
|
|
3402
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_severity
|
|
3403
|
+
ON security_events(severity);
|
|
3404
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_created
|
|
3405
|
+
ON security_events(created_at DESC);
|
|
3406
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_vpn
|
|
3407
|
+
ON security_events(is_vpn)
|
|
3408
|
+
WHERE is_vpn = true;
|
|
3409
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_unresolved
|
|
3410
|
+
ON security_events(is_resolved, created_at DESC)
|
|
3411
|
+
WHERE is_resolved = false;
|
|
3412
|
+
CREATE INDEX IF NOT EXISTS idx_security_events_details
|
|
3413
|
+
ON security_events USING GIN(details jsonb_path_ops);
|
|
3414
|
+
|
|
3415
|
+
-- Partitioning for security events (by month for efficient cleanup)
|
|
3416
|
+
-- Note: Partitioning requires PostgreSQL 10+
|
|
3417
|
+
|
|
3418
|
+
-- ============================================================
|
|
3419
|
+
-- ADMIN SESSIONS TABLE
|
|
3420
|
+
-- Stores admin session data
|
|
3421
|
+
-- Replaces data/admin_sessions/data.json
|
|
3422
|
+
-- ============================================================
|
|
3423
|
+
CREATE TABLE IF NOT EXISTS admin_sessions (
|
|
3424
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
3425
|
+
|
|
3426
|
+
-- Session identification
|
|
3427
|
+
session_token VARCHAR(255) NOT NULL UNIQUE,
|
|
3428
|
+
|
|
3429
|
+
-- User identification
|
|
3430
|
+
username VARCHAR(255),
|
|
3431
|
+
ip_address VARCHAR(45),
|
|
3432
|
+
user_agent TEXT,
|
|
3433
|
+
|
|
3434
|
+
-- Session details
|
|
3435
|
+
is_active BOOLEAN DEFAULT true,
|
|
3436
|
+
|
|
3437
|
+
-- Timestamps
|
|
3438
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3439
|
+
last_activity_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3440
|
+
expires_at TIMESTAMPTZ,
|
|
3441
|
+
ended_at TIMESTAMPTZ,
|
|
3442
|
+
|
|
3443
|
+
-- Session data
|
|
3444
|
+
session_data JSONB NOT NULL DEFAULT '{}'
|
|
3445
|
+
);
|
|
3446
|
+
|
|
3447
|
+
-- Indexes for admin session queries
|
|
3448
|
+
CREATE INDEX IF NOT EXISTS idx_admin_sessions_token
|
|
3449
|
+
ON admin_sessions(session_token);
|
|
3450
|
+
CREATE INDEX IF NOT EXISTS idx_admin_sessions_active
|
|
3451
|
+
ON admin_sessions(is_active)
|
|
3452
|
+
WHERE is_active = true;
|
|
3453
|
+
CREATE INDEX IF NOT EXISTS idx_admin_sessions_expires
|
|
3454
|
+
ON admin_sessions(expires_at)
|
|
3455
|
+
WHERE expires_at IS NOT NULL;
|
|
3456
|
+
|
|
3457
|
+
-- ============================================================
|
|
3458
|
+
-- GOVERNMENT FACILITIES TABLE
|
|
3459
|
+
-- Stores known government IP ranges and facilities
|
|
3460
|
+
-- Replaces data/security/government-facilities.json
|
|
3461
|
+
-- ============================================================
|
|
3462
|
+
CREATE TABLE IF NOT EXISTS government_facilities (
|
|
3463
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
3464
|
+
|
|
3465
|
+
-- Facility identification
|
|
3466
|
+
name VARCHAR(255) NOT NULL,
|
|
3467
|
+
facility_type VARCHAR(100),
|
|
3468
|
+
country VARCHAR(100),
|
|
3469
|
+
|
|
3470
|
+
-- IP ranges
|
|
3471
|
+
ip_ranges TEXT[] DEFAULT '{}',
|
|
3472
|
+
|
|
3473
|
+
-- Classification
|
|
3474
|
+
classification VARCHAR(50) DEFAULT 'government',
|
|
3475
|
+
threat_level VARCHAR(20) DEFAULT 'high',
|
|
3476
|
+
|
|
3477
|
+
-- Detection settings
|
|
3478
|
+
should_block BOOLEAN DEFAULT false,
|
|
3479
|
+
should_log BOOLEAN DEFAULT true,
|
|
3480
|
+
alert_on_access BOOLEAN DEFAULT true,
|
|
3481
|
+
|
|
3482
|
+
-- Metadata
|
|
3483
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
3484
|
+
|
|
3485
|
+
-- Timestamps
|
|
3486
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3487
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
3488
|
+
);
|
|
3489
|
+
|
|
3490
|
+
-- Trigger for updated_at
|
|
3491
|
+
DROP TRIGGER IF EXISTS government_facilities_updated_at ON government_facilities;
|
|
3492
|
+
CREATE TRIGGER government_facilities_updated_at
|
|
3493
|
+
BEFORE UPDATE ON government_facilities
|
|
3494
|
+
FOR EACH ROW
|
|
3495
|
+
EXECUTE FUNCTION update_updated_at_column();
|
|
3496
|
+
|
|
3497
|
+
-- ============================================================
|
|
3498
|
+
-- API STATS MATERIALIZED VIEW
|
|
3499
|
+
-- Pre-computed statistics for API usage
|
|
3500
|
+
-- ============================================================
|
|
3501
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS api_stats AS
|
|
3502
|
+
SELECT
|
|
3503
|
+
COUNT(*) as total_endpoints,
|
|
3504
|
+
COUNT(*) FILTER (WHERE is_enabled = true) as enabled_endpoints,
|
|
3505
|
+
COUNT(*) FILTER (WHERE requires_auth = true) as auth_required_endpoints,
|
|
3506
|
+
COUNT(*) FILTER (WHERE is_deprecated = true) as deprecated_endpoints,
|
|
3507
|
+
SUM(total_requests) as total_api_requests,
|
|
3508
|
+
SUM(successful_requests) as total_successful_requests,
|
|
3509
|
+
SUM(failed_requests) as total_failed_requests,
|
|
3510
|
+
MAX(last_request_at) as last_api_request,
|
|
3511
|
+
NOW() as computed_at
|
|
3512
|
+
FROM api_endpoints;
|
|
3513
|
+
|
|
3514
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_api_stats_singleton
|
|
3515
|
+
ON api_stats(computed_at);
|
|
3516
|
+
|
|
3517
|
+
-- Function to refresh API stats
|
|
3518
|
+
CREATE OR REPLACE FUNCTION refresh_api_stats()
|
|
3519
|
+
RETURNS void AS $$
|
|
3520
|
+
BEGIN
|
|
3521
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY api_stats;
|
|
3522
|
+
END;
|
|
3523
|
+
$$ LANGUAGE plpgsql;
|
|
3524
|
+
|
|
3525
|
+
-- ============================================================
|
|
3526
|
+
-- SECURITY STATS MATERIALIZED VIEW
|
|
3527
|
+
-- Pre-computed security event statistics
|
|
3528
|
+
-- ============================================================
|
|
3529
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS security_stats AS
|
|
3530
|
+
SELECT
|
|
3531
|
+
COUNT(*) as total_events,
|
|
3532
|
+
COUNT(*) FILTER (WHERE event_type = 'vpn') as vpn_events,
|
|
3533
|
+
COUNT(*) FILTER (WHERE severity = 'critical') as critical_events,
|
|
3534
|
+
COUNT(*) FILTER (WHERE severity = 'high') as high_severity_events,
|
|
3535
|
+
COUNT(*) FILTER (WHERE is_resolved = false) as unresolved_events,
|
|
3536
|
+
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '24 hours') as events_last_24h,
|
|
3537
|
+
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '7 days') as events_last_7d,
|
|
3538
|
+
COUNT(DISTINCT ip_address) as unique_ips,
|
|
3539
|
+
COUNT(DISTINCT country) as unique_countries,
|
|
3540
|
+
NOW() as computed_at
|
|
3541
|
+
FROM security_events;
|
|
3542
|
+
|
|
3543
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_security_stats_singleton
|
|
3544
|
+
ON security_stats(computed_at);
|
|
3545
|
+
|
|
3546
|
+
-- Function to refresh security stats
|
|
3547
|
+
CREATE OR REPLACE FUNCTION refresh_security_stats()
|
|
3548
|
+
RETURNS void AS $$
|
|
3549
|
+
BEGIN
|
|
3550
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY security_stats;
|
|
3551
|
+
END;
|
|
3552
|
+
$$ LANGUAGE plpgsql;
|
|
3553
|
+
|
|
3554
|
+
-- ============================================================
|
|
3555
|
+
-- BAN STATS MATERIALIZED VIEW
|
|
3556
|
+
-- Pre-computed ban statistics
|
|
3557
|
+
-- ============================================================
|
|
3558
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS ban_stats AS
|
|
3559
|
+
SELECT
|
|
3560
|
+
COUNT(*) as total_bans,
|
|
3561
|
+
COUNT(*) FILTER (WHERE is_active = true) as active_bans,
|
|
3562
|
+
COUNT(*) FILTER (WHERE is_permanent = true) as permanent_bans,
|
|
3563
|
+
COUNT(*) FILTER (WHERE ban_type = 'auto') as auto_bans,
|
|
3564
|
+
COUNT(*) FILTER (WHERE ban_type = 'manual') as manual_bans,
|
|
3565
|
+
COUNT(*) FILTER (WHERE ban_type = 'vpn') as vpn_bans,
|
|
3566
|
+
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '24 hours') as bans_last_24h,
|
|
3567
|
+
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '7 days') as bans_last_7d,
|
|
3568
|
+
NOW() as computed_at
|
|
3569
|
+
FROM ip_bans;
|
|
3570
|
+
|
|
3571
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_ban_stats_singleton
|
|
3572
|
+
ON ban_stats(computed_at);
|
|
3573
|
+
|
|
3574
|
+
-- Function to refresh ban stats
|
|
3575
|
+
CREATE OR REPLACE FUNCTION refresh_ban_stats()
|
|
3576
|
+
RETURNS void AS $$
|
|
3577
|
+
BEGIN
|
|
3578
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY ban_stats;
|
|
3579
|
+
END;
|
|
3580
|
+
$$ LANGUAGE plpgsql;
|
|
3581
|
+
|
|
3582
|
+
-- ============================================================
|
|
3583
|
+
-- CLEANUP FUNCTION FOR EXPIRED DATA
|
|
3584
|
+
-- ============================================================
|
|
3585
|
+
CREATE OR REPLACE FUNCTION cleanup_expired_api_data()
|
|
3586
|
+
RETURNS TABLE(
|
|
3587
|
+
expired_bans INTEGER,
|
|
3588
|
+
expired_sessions INTEGER,
|
|
3589
|
+
old_events INTEGER
|
|
3590
|
+
) AS $$
|
|
3591
|
+
DECLARE
|
|
3592
|
+
v_bans INTEGER;
|
|
3593
|
+
v_sessions INTEGER;
|
|
3594
|
+
v_events INTEGER;
|
|
3595
|
+
BEGIN
|
|
3596
|
+
-- Deactivate expired bans
|
|
3597
|
+
UPDATE ip_bans
|
|
3598
|
+
SET is_active = false, updated_at = NOW()
|
|
3599
|
+
WHERE is_active = true
|
|
3600
|
+
AND is_permanent = false
|
|
3601
|
+
AND expires_at IS NOT NULL
|
|
3602
|
+
AND expires_at < NOW();
|
|
3603
|
+
GET DIAGNOSTICS v_bans = ROW_COUNT;
|
|
3604
|
+
|
|
3605
|
+
-- End expired admin sessions
|
|
3606
|
+
UPDATE admin_sessions
|
|
3607
|
+
SET is_active = false, ended_at = NOW()
|
|
3608
|
+
WHERE is_active = true
|
|
3609
|
+
AND expires_at IS NOT NULL
|
|
3610
|
+
AND expires_at < NOW();
|
|
3611
|
+
GET DIAGNOSTICS v_sessions = ROW_COUNT;
|
|
3612
|
+
|
|
3613
|
+
-- Delete very old security events (> 90 days) that are resolved
|
|
3614
|
+
DELETE FROM security_events
|
|
3615
|
+
WHERE is_resolved = true
|
|
3616
|
+
AND created_at < NOW() - INTERVAL '90 days';
|
|
3617
|
+
GET DIAGNOSTICS v_events = ROW_COUNT;
|
|
3618
|
+
|
|
3619
|
+
RETURN QUERY SELECT v_bans, v_sessions, v_events;
|
|
3620
|
+
END;
|
|
3621
|
+
$$ LANGUAGE plpgsql;
|
|
3622
|
+
`,
|
|
3623
|
+
down: `
|
|
3624
|
+
DROP FUNCTION IF EXISTS cleanup_expired_api_data();
|
|
3625
|
+
DROP FUNCTION IF EXISTS refresh_ban_stats();
|
|
3626
|
+
DROP MATERIALIZED VIEW IF EXISTS ban_stats;
|
|
3627
|
+
DROP FUNCTION IF EXISTS refresh_security_stats();
|
|
3628
|
+
DROP MATERIALIZED VIEW IF EXISTS security_stats;
|
|
3629
|
+
DROP FUNCTION IF EXISTS refresh_api_stats();
|
|
3630
|
+
DROP MATERIALIZED VIEW IF EXISTS api_stats;
|
|
3631
|
+
DROP TRIGGER IF EXISTS government_facilities_updated_at ON government_facilities;
|
|
3632
|
+
DROP TABLE IF EXISTS government_facilities CASCADE;
|
|
3633
|
+
DROP TABLE IF EXISTS admin_sessions CASCADE;
|
|
3634
|
+
DROP TABLE IF EXISTS security_events CASCADE;
|
|
3635
|
+
DROP TRIGGER IF EXISTS oauth_providers_updated_at ON oauth_providers;
|
|
3636
|
+
DROP TABLE IF EXISTS oauth_providers CASCADE;
|
|
3637
|
+
DROP TRIGGER IF EXISTS autoban_config_updated_at ON autoban_config;
|
|
3638
|
+
DROP TABLE IF EXISTS autoban_config CASCADE;
|
|
3639
|
+
DROP TRIGGER IF EXISTS ip_bans_updated_at ON ip_bans;
|
|
3640
|
+
DROP TABLE IF EXISTS ip_bans CASCADE;
|
|
3641
|
+
DROP TRIGGER IF EXISTS api_endpoints_updated_at ON api_endpoints;
|
|
3642
|
+
DROP TABLE IF EXISTS api_endpoints CASCADE;
|
|
3643
|
+
`,
|
|
3644
|
+
checksum: this.generateChecksum('create_api_data_tables_v28')
|
|
3645
|
+
},
|
|
3646
|
+
// migration 29: Add unique constraint on codebase_files.absolute_path
|
|
3647
|
+
// Prevents duplicate entries for the same file path
|
|
3648
|
+
{
|
|
3649
|
+
version: 29,
|
|
3650
|
+
name: 'add_codebase_files_absolute_path_unique',
|
|
3651
|
+
up: `
|
|
3652
|
+
-- Remove any duplicate entries first (keep the most recently updated one)
|
|
3653
|
+
DELETE FROM codebase_files a USING codebase_files b
|
|
3654
|
+
WHERE a.id < b.id AND a.absolute_path = b.absolute_path;
|
|
3655
|
+
|
|
3656
|
+
-- Create unique index on absolute_path to prevent duplicates
|
|
3657
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_codebase_files_absolute_path_unique
|
|
3658
|
+
ON codebase_files(absolute_path);
|
|
3659
|
+
`,
|
|
3660
|
+
down: `
|
|
3661
|
+
DROP INDEX IF EXISTS idx_codebase_files_absolute_path_unique;
|
|
3662
|
+
`,
|
|
3663
|
+
checksum: this.generateChecksum('add_codebase_files_absolute_path_unique_v29')
|
|
3664
|
+
},
|
|
3665
|
+
// migration 30: Add indexes for session pairing metadata fields
|
|
3666
|
+
// Required for efficient find_memory Strategies 1-8 (user/claude message pairing)
|
|
3667
|
+
{
|
|
3668
|
+
version: 30,
|
|
3669
|
+
name: 'add_session_pairing_indexes',
|
|
3670
|
+
up: `
|
|
3671
|
+
-- Index for sessionId lookups (Strategy 1: same session pairing)
|
|
3672
|
+
CREATE INDEX IF NOT EXISTS idx_memories_metadata_session_id
|
|
3673
|
+
ON memories ((metadata->>'sessionId'))
|
|
3674
|
+
WHERE metadata->>'sessionId' IS NOT NULL;
|
|
3675
|
+
|
|
3676
|
+
-- Index for role filtering (all strategies use role filtering)
|
|
3677
|
+
CREATE INDEX IF NOT EXISTS idx_memories_metadata_role
|
|
3678
|
+
ON memories ((metadata->>'role'))
|
|
3679
|
+
WHERE metadata->>'role' IS NOT NULL;
|
|
3680
|
+
|
|
3681
|
+
-- Index for timestamp ordering (Strategies 1-8 use timestamp-based ordering)
|
|
3682
|
+
CREATE INDEX IF NOT EXISTS idx_memories_metadata_timestamp
|
|
3683
|
+
ON memories ((metadata->>'timestamp'))
|
|
3684
|
+
WHERE metadata->>'timestamp' IS NOT NULL;
|
|
3685
|
+
|
|
3686
|
+
-- Index for project_path filtering (Strategies 2-6 use project_path)
|
|
3687
|
+
CREATE INDEX IF NOT EXISTS idx_memories_metadata_project_path
|
|
3688
|
+
ON memories ((metadata->>'project_path'))
|
|
3689
|
+
WHERE metadata->>'project_path' IS NOT NULL;
|
|
3690
|
+
|
|
3691
|
+
-- Composite index for efficient session+role+timestamp queries (Strategy 1)
|
|
3692
|
+
CREATE INDEX IF NOT EXISTS idx_memories_session_role_timestamp
|
|
3693
|
+
ON memories (
|
|
3694
|
+
(metadata->>'sessionId'),
|
|
3695
|
+
(metadata->>'role'),
|
|
3696
|
+
(metadata->>'timestamp')
|
|
3697
|
+
)
|
|
3698
|
+
WHERE metadata->>'sessionId' IS NOT NULL
|
|
3699
|
+
AND metadata->>'role' IS NOT NULL
|
|
3700
|
+
AND metadata->>'timestamp' IS NOT NULL;
|
|
3701
|
+
|
|
3702
|
+
-- Composite index for project+role+timestamp queries (Strategies 2-6)
|
|
3703
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_role_timestamp
|
|
3704
|
+
ON memories (
|
|
3705
|
+
(metadata->>'project_path'),
|
|
3706
|
+
(metadata->>'role'),
|
|
3707
|
+
(metadata->>'timestamp')
|
|
3708
|
+
)
|
|
3709
|
+
WHERE metadata->>'project_path' IS NOT NULL
|
|
3710
|
+
AND metadata->>'role' IS NOT NULL
|
|
3711
|
+
AND metadata->>'timestamp' IS NOT NULL;
|
|
3712
|
+
`,
|
|
3713
|
+
down: `
|
|
3714
|
+
DROP INDEX IF EXISTS idx_memories_project_role_timestamp;
|
|
3715
|
+
DROP INDEX IF EXISTS idx_memories_session_role_timestamp;
|
|
3716
|
+
DROP INDEX IF EXISTS idx_memories_metadata_project_path;
|
|
3717
|
+
DROP INDEX IF EXISTS idx_memories_metadata_timestamp;
|
|
3718
|
+
DROP INDEX IF EXISTS idx_memories_metadata_role;
|
|
3719
|
+
DROP INDEX IF EXISTS idx_memories_metadata_session_id;
|
|
3720
|
+
`,
|
|
3721
|
+
checksum: this.generateChecksum('add_session_pairing_indexes_v30')
|
|
3722
|
+
},
|
|
3723
|
+
// migration 31: Project Namespacing - Per-Instance Database Isolation
|
|
3724
|
+
// Adds project_id FK column to ALL data tables for multi-project isolation
|
|
3725
|
+
// CRITICAL: This enables separate SpecMem instances to share one PostgreSQL
|
|
3726
|
+
// without leaking memories, team messages, or claims across projects
|
|
3727
|
+
{
|
|
3728
|
+
version: 31,
|
|
3729
|
+
name: 'project_namespacing_isolation',
|
|
3730
|
+
up: `
|
|
3731
|
+
-- ============================================================================
|
|
3732
|
+
-- PROJECTS REGISTRY TABLE
|
|
3733
|
+
-- ============================================================================
|
|
3734
|
+
-- Central registry mapping project paths to UUIDs
|
|
3735
|
+
-- Uses UPSERT pattern for race-condition-free registration
|
|
3736
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
3737
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
3738
|
+
path VARCHAR(500) NOT NULL UNIQUE,
|
|
3739
|
+
name VARCHAR(255),
|
|
3740
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
3741
|
+
last_accessed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
3742
|
+
);
|
|
3743
|
+
|
|
3744
|
+
CREATE INDEX IF NOT EXISTS idx_projects_path ON projects(path);
|
|
3745
|
+
CREATE INDEX IF NOT EXISTS idx_projects_created_at ON projects(created_at);
|
|
3746
|
+
|
|
3747
|
+
-- Insert default project for backfilling existing data
|
|
3748
|
+
INSERT INTO projects (id, path, name, created_at, last_accessed_at)
|
|
3749
|
+
VALUES (
|
|
3750
|
+
'00000000-0000-0000-0000-000000000000'::uuid,
|
|
3751
|
+
'/',
|
|
3752
|
+
'Default Project',
|
|
3753
|
+
NOW(),
|
|
3754
|
+
NOW()
|
|
3755
|
+
)
|
|
3756
|
+
ON CONFLICT (path) DO NOTHING;
|
|
3757
|
+
|
|
3758
|
+
-- ============================================================================
|
|
3759
|
+
-- ADD project_id TO memories TABLE
|
|
3760
|
+
-- ============================================================================
|
|
3761
|
+
DO $$ BEGIN
|
|
3762
|
+
ALTER TABLE memories
|
|
3763
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3764
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3765
|
+
END $$;
|
|
3766
|
+
|
|
3767
|
+
DO $$ BEGIN
|
|
3768
|
+
ALTER TABLE memories
|
|
3769
|
+
ADD CONSTRAINT fk_memories_project_id
|
|
3770
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3771
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3772
|
+
END $$;
|
|
3773
|
+
|
|
3774
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_id ON memories(project_id);
|
|
3775
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_created ON memories(project_id, created_at DESC);
|
|
3776
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_importance ON memories(project_id, importance);
|
|
3777
|
+
|
|
3778
|
+
-- ============================================================================
|
|
3779
|
+
-- ADD project_id TO codebase_files TABLE
|
|
3780
|
+
-- ============================================================================
|
|
3781
|
+
DO $$ BEGIN
|
|
3782
|
+
ALTER TABLE codebase_files
|
|
3783
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3784
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3785
|
+
END $$;
|
|
3786
|
+
|
|
3787
|
+
DO $$ BEGIN
|
|
3788
|
+
ALTER TABLE codebase_files
|
|
3789
|
+
ADD CONSTRAINT fk_codebase_files_project_id
|
|
3790
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3791
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3792
|
+
END $$;
|
|
3793
|
+
|
|
3794
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_project_id ON codebase_files(project_id);
|
|
3795
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_project_path ON codebase_files(project_id, file_path);
|
|
3796
|
+
|
|
3797
|
+
-- ============================================================================
|
|
3798
|
+
-- ADD project_id TO code_definitions TABLE
|
|
3799
|
+
-- ============================================================================
|
|
3800
|
+
DO $$ BEGIN
|
|
3801
|
+
ALTER TABLE code_definitions
|
|
3802
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3803
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3804
|
+
END $$;
|
|
3805
|
+
|
|
3806
|
+
DO $$ BEGIN
|
|
3807
|
+
ALTER TABLE code_definitions
|
|
3808
|
+
ADD CONSTRAINT fk_code_definitions_project_id
|
|
3809
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3810
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3811
|
+
END $$;
|
|
3812
|
+
|
|
3813
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_project_id ON code_definitions(project_id);
|
|
3814
|
+
CREATE INDEX IF NOT EXISTS idx_code_definitions_project_name ON code_definitions(project_id, name);
|
|
3815
|
+
|
|
3816
|
+
-- ============================================================================
|
|
3817
|
+
-- ADD project_id TO code_dependencies TABLE
|
|
3818
|
+
-- ============================================================================
|
|
3819
|
+
DO $$ BEGIN
|
|
3820
|
+
ALTER TABLE code_dependencies
|
|
3821
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3822
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3823
|
+
END $$;
|
|
3824
|
+
|
|
3825
|
+
DO $$ BEGIN
|
|
3826
|
+
ALTER TABLE code_dependencies
|
|
3827
|
+
ADD CONSTRAINT fk_code_dependencies_project_id
|
|
3828
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3829
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3830
|
+
END $$;
|
|
3831
|
+
|
|
3832
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_project_id ON code_dependencies(project_id);
|
|
3833
|
+
|
|
3834
|
+
-- ============================================================================
|
|
3835
|
+
-- ADD project_id TO codebase_pointers TABLE (if exists)
|
|
3836
|
+
-- ============================================================================
|
|
3837
|
+
DO $$ BEGIN
|
|
3838
|
+
ALTER TABLE codebase_pointers
|
|
3839
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3840
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3841
|
+
WHEN undefined_table THEN NULL;
|
|
3842
|
+
END $$;
|
|
3843
|
+
|
|
3844
|
+
DO $$ BEGIN
|
|
3845
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'codebase_pointers') THEN
|
|
3846
|
+
ALTER TABLE codebase_pointers
|
|
3847
|
+
ADD CONSTRAINT fk_codebase_pointers_project_id
|
|
3848
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3849
|
+
END IF;
|
|
3850
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3851
|
+
END $$;
|
|
3852
|
+
|
|
3853
|
+
DO $$ BEGIN
|
|
3854
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'codebase_pointers') THEN
|
|
3855
|
+
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_codebase_pointers_project_id ON codebase_pointers(project_id)';
|
|
3856
|
+
END IF;
|
|
3857
|
+
END $$;
|
|
3858
|
+
|
|
3859
|
+
-- ============================================================================
|
|
3860
|
+
-- ADD pointer_type TO codebase_pointers TABLE (if exists)
|
|
3861
|
+
-- ============================================================================
|
|
3862
|
+
DO $$ BEGIN
|
|
3863
|
+
ALTER TABLE codebase_pointers
|
|
3864
|
+
ADD COLUMN IF NOT EXISTS pointer_type VARCHAR(50) DEFAULT 'reference';
|
|
3865
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3866
|
+
WHEN undefined_table THEN NULL;
|
|
3867
|
+
END $$;
|
|
3868
|
+
|
|
3869
|
+
-- ============================================================================
|
|
3870
|
+
-- ADD project_id TO team_messages TABLE (if exists)
|
|
3871
|
+
-- ============================================================================
|
|
3872
|
+
DO $$ BEGIN
|
|
3873
|
+
ALTER TABLE team_messages
|
|
3874
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3875
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3876
|
+
WHEN undefined_table THEN NULL;
|
|
3877
|
+
END $$;
|
|
3878
|
+
|
|
3879
|
+
DO $$ BEGIN
|
|
3880
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_messages') THEN
|
|
3881
|
+
ALTER TABLE team_messages
|
|
3882
|
+
ADD CONSTRAINT fk_team_messages_project_id
|
|
3883
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3884
|
+
END IF;
|
|
3885
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3886
|
+
END $$;
|
|
3887
|
+
|
|
3888
|
+
DO $$ BEGIN
|
|
3889
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_messages') THEN
|
|
3890
|
+
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_team_messages_project_id ON team_messages(project_id)';
|
|
3891
|
+
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_team_messages_project_channel ON team_messages(project_id, channel_id, created_at DESC)';
|
|
3892
|
+
END IF;
|
|
3893
|
+
END $$;
|
|
3894
|
+
|
|
3895
|
+
-- ============================================================================
|
|
3896
|
+
-- ADD project_id TO task_claims TABLE (if exists)
|
|
3897
|
+
-- ============================================================================
|
|
3898
|
+
DO $$ BEGIN
|
|
3899
|
+
ALTER TABLE task_claims
|
|
3900
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3901
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3902
|
+
WHEN undefined_table THEN NULL;
|
|
3903
|
+
END $$;
|
|
3904
|
+
|
|
3905
|
+
DO $$ BEGIN
|
|
3906
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'task_claims') THEN
|
|
3907
|
+
ALTER TABLE task_claims
|
|
3908
|
+
ADD CONSTRAINT fk_task_claims_project_id
|
|
3909
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3910
|
+
END IF;
|
|
3911
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3912
|
+
END $$;
|
|
3913
|
+
|
|
3914
|
+
DO $$ BEGIN
|
|
3915
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'task_claims') THEN
|
|
3916
|
+
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_task_claims_project_id ON task_claims(project_id)';
|
|
3917
|
+
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_task_claims_project_status ON task_claims(project_id, status)';
|
|
3918
|
+
END IF;
|
|
3919
|
+
END $$;
|
|
3920
|
+
|
|
3921
|
+
-- ============================================================================
|
|
3922
|
+
-- ADD project_id TO team_channels TABLE (if exists)
|
|
3923
|
+
-- ============================================================================
|
|
3924
|
+
DO $$ BEGIN
|
|
3925
|
+
ALTER TABLE team_channels
|
|
3926
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3927
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3928
|
+
WHEN undefined_table THEN NULL;
|
|
3929
|
+
END $$;
|
|
3930
|
+
|
|
3931
|
+
DO $$ BEGIN
|
|
3932
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_channels') THEN
|
|
3933
|
+
ALTER TABLE team_channels
|
|
3934
|
+
ADD CONSTRAINT fk_team_channels_project_id
|
|
3935
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3936
|
+
END IF;
|
|
3937
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3938
|
+
END $$;
|
|
3939
|
+
|
|
3940
|
+
DO $$ BEGIN
|
|
3941
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_channels') THEN
|
|
3942
|
+
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_team_channels_project_id ON team_channels(project_id)';
|
|
3943
|
+
END IF;
|
|
3944
|
+
END $$;
|
|
3945
|
+
|
|
3946
|
+
-- ============================================================================
|
|
3947
|
+
-- ADD project_id TO help_requests TABLE (if exists)
|
|
3948
|
+
-- ============================================================================
|
|
3949
|
+
DO $$ BEGIN
|
|
3950
|
+
ALTER TABLE help_requests
|
|
3951
|
+
ADD COLUMN IF NOT EXISTS project_id UUID DEFAULT '00000000-0000-0000-0000-000000000000'::uuid;
|
|
3952
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
3953
|
+
WHEN undefined_table THEN NULL;
|
|
3954
|
+
END $$;
|
|
3955
|
+
|
|
3956
|
+
DO $$ BEGIN
|
|
3957
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'help_requests') THEN
|
|
3958
|
+
ALTER TABLE help_requests
|
|
3959
|
+
ADD CONSTRAINT fk_help_requests_project_id
|
|
3960
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET DEFAULT;
|
|
3961
|
+
END IF;
|
|
3962
|
+
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
3963
|
+
END $$;
|
|
3964
|
+
|
|
3965
|
+
DO $$ BEGIN
|
|
3966
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'help_requests') THEN
|
|
3967
|
+
EXECUTE 'CREATE INDEX IF NOT EXISTS idx_help_requests_project_id ON help_requests(project_id)';
|
|
3968
|
+
END IF;
|
|
3969
|
+
END $$;
|
|
3970
|
+
|
|
3971
|
+
-- ============================================================================
|
|
3972
|
+
-- RACE-CONDITION-FREE PROJECT REGISTRATION FUNCTION
|
|
3973
|
+
-- ============================================================================
|
|
3974
|
+
CREATE OR REPLACE FUNCTION register_project(
|
|
3975
|
+
p_path VARCHAR(500),
|
|
3976
|
+
p_name VARCHAR(255) DEFAULT NULL
|
|
3977
|
+
)
|
|
3978
|
+
RETURNS UUID AS $$
|
|
3979
|
+
DECLARE
|
|
3980
|
+
v_project_id UUID;
|
|
3981
|
+
BEGIN
|
|
3982
|
+
INSERT INTO projects (path, name)
|
|
3983
|
+
VALUES (p_path, COALESCE(p_name, p_path))
|
|
3984
|
+
ON CONFLICT (path) DO UPDATE SET
|
|
3985
|
+
last_accessed_at = NOW(),
|
|
3986
|
+
name = COALESCE(EXCLUDED.name, projects.name)
|
|
3987
|
+
RETURNING id INTO v_project_id;
|
|
3988
|
+
|
|
3989
|
+
RETURN v_project_id;
|
|
3990
|
+
END;
|
|
3991
|
+
$$ LANGUAGE plpgsql;
|
|
3992
|
+
|
|
3993
|
+
-- ============================================================================
|
|
3994
|
+
-- HELPER: Get project ID by path
|
|
3995
|
+
-- ============================================================================
|
|
3996
|
+
CREATE OR REPLACE FUNCTION get_project_id(p_path VARCHAR(500))
|
|
3997
|
+
RETURNS UUID AS $$
|
|
3998
|
+
DECLARE
|
|
3999
|
+
v_project_id UUID;
|
|
4000
|
+
BEGIN
|
|
4001
|
+
SELECT id INTO v_project_id
|
|
4002
|
+
FROM projects
|
|
4003
|
+
WHERE path = p_path;
|
|
4004
|
+
|
|
4005
|
+
IF v_project_id IS NULL THEN
|
|
4006
|
+
v_project_id := register_project(p_path);
|
|
4007
|
+
ELSE
|
|
4008
|
+
UPDATE projects SET last_accessed_at = NOW() WHERE id = v_project_id;
|
|
4009
|
+
END IF;
|
|
4010
|
+
|
|
4011
|
+
RETURN v_project_id;
|
|
4012
|
+
END;
|
|
4013
|
+
$$ LANGUAGE plpgsql;
|
|
4014
|
+
|
|
4015
|
+
-- ============================================================================
|
|
4016
|
+
-- BACKFILL: Assign all existing data to default project
|
|
4017
|
+
-- ============================================================================
|
|
4018
|
+
UPDATE memories SET project_id = '00000000-0000-0000-0000-000000000000'::uuid WHERE project_id IS NULL;
|
|
4019
|
+
UPDATE codebase_files SET project_id = '00000000-0000-0000-0000-000000000000'::uuid WHERE project_id IS NULL;
|
|
4020
|
+
UPDATE code_definitions SET project_id = '00000000-0000-0000-0000-000000000000'::uuid WHERE project_id IS NULL;
|
|
4021
|
+
UPDATE code_dependencies SET project_id = '00000000-0000-0000-0000-000000000000'::uuid WHERE project_id IS NULL;
|
|
4022
|
+
|
|
4023
|
+
-- Backfill codebase_pointers if it exists
|
|
4024
|
+
DO $$ BEGIN
|
|
4025
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'codebase_pointers') THEN
|
|
4026
|
+
EXECUTE 'UPDATE codebase_pointers SET project_id = ''00000000-0000-0000-0000-000000000000''::uuid WHERE project_id IS NULL';
|
|
4027
|
+
END IF;
|
|
4028
|
+
END $$;
|
|
4029
|
+
|
|
4030
|
+
-- Backfill team tables if they exist
|
|
4031
|
+
DO $$ BEGIN
|
|
4032
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_messages') THEN
|
|
4033
|
+
EXECUTE 'UPDATE team_messages SET project_id = ''00000000-0000-0000-0000-000000000000''::uuid WHERE project_id IS NULL';
|
|
4034
|
+
END IF;
|
|
4035
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'task_claims') THEN
|
|
4036
|
+
EXECUTE 'UPDATE task_claims SET project_id = ''00000000-0000-0000-0000-000000000000''::uuid WHERE project_id IS NULL';
|
|
4037
|
+
END IF;
|
|
4038
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_channels') THEN
|
|
4039
|
+
EXECUTE 'UPDATE team_channels SET project_id = ''00000000-0000-0000-0000-000000000000''::uuid WHERE project_id IS NULL';
|
|
4040
|
+
END IF;
|
|
4041
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'help_requests') THEN
|
|
4042
|
+
EXECUTE 'UPDATE help_requests SET project_id = ''00000000-0000-0000-0000-000000000000''::uuid WHERE project_id IS NULL';
|
|
4043
|
+
END IF;
|
|
4044
|
+
END $$;
|
|
4045
|
+
`,
|
|
4046
|
+
down: `
|
|
4047
|
+
-- WARNING: Rolling back project namespacing may break multi-project isolation!
|
|
4048
|
+
-- We only drop the FK constraints and indexes, keeping the data intact
|
|
4049
|
+
|
|
4050
|
+
-- Drop FK constraints
|
|
4051
|
+
ALTER TABLE memories DROP CONSTRAINT IF EXISTS fk_memories_project_id;
|
|
4052
|
+
ALTER TABLE codebase_files DROP CONSTRAINT IF EXISTS fk_codebase_files_project_id;
|
|
4053
|
+
ALTER TABLE code_definitions DROP CONSTRAINT IF EXISTS fk_code_definitions_project_id;
|
|
4054
|
+
ALTER TABLE code_dependencies DROP CONSTRAINT IF EXISTS fk_code_dependencies_project_id;
|
|
4055
|
+
ALTER TABLE codebase_pointers DROP CONSTRAINT IF EXISTS fk_codebase_pointers_project_id;
|
|
4056
|
+
|
|
4057
|
+
DO $$ BEGIN
|
|
4058
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_messages') THEN
|
|
4059
|
+
ALTER TABLE team_messages DROP CONSTRAINT IF EXISTS fk_team_messages_project_id;
|
|
4060
|
+
END IF;
|
|
4061
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'task_claims') THEN
|
|
4062
|
+
ALTER TABLE task_claims DROP CONSTRAINT IF EXISTS fk_task_claims_project_id;
|
|
4063
|
+
END IF;
|
|
4064
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_channels') THEN
|
|
4065
|
+
ALTER TABLE team_channels DROP CONSTRAINT IF EXISTS fk_team_channels_project_id;
|
|
4066
|
+
END IF;
|
|
4067
|
+
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'help_requests') THEN
|
|
4068
|
+
ALTER TABLE help_requests DROP CONSTRAINT IF EXISTS fk_help_requests_project_id;
|
|
4069
|
+
END IF;
|
|
4070
|
+
END $$;
|
|
4071
|
+
|
|
4072
|
+
-- Drop indexes
|
|
4073
|
+
DROP INDEX IF EXISTS idx_memories_project_id;
|
|
4074
|
+
DROP INDEX IF EXISTS idx_memories_project_created;
|
|
4075
|
+
DROP INDEX IF EXISTS idx_memories_project_importance;
|
|
4076
|
+
DROP INDEX IF EXISTS idx_codebase_files_project_id;
|
|
4077
|
+
DROP INDEX IF EXISTS idx_codebase_files_project_path;
|
|
4078
|
+
DROP INDEX IF EXISTS idx_code_definitions_project_id;
|
|
4079
|
+
DROP INDEX IF EXISTS idx_code_definitions_project_name;
|
|
4080
|
+
DROP INDEX IF EXISTS idx_code_dependencies_project_id;
|
|
4081
|
+
DROP INDEX IF EXISTS idx_codebase_pointers_project_id;
|
|
4082
|
+
DROP INDEX IF EXISTS idx_team_messages_project_id;
|
|
4083
|
+
DROP INDEX IF EXISTS idx_team_messages_project_channel;
|
|
4084
|
+
DROP INDEX IF EXISTS idx_task_claims_project_id;
|
|
4085
|
+
DROP INDEX IF EXISTS idx_task_claims_project_status;
|
|
4086
|
+
DROP INDEX IF EXISTS idx_team_channels_project_id;
|
|
4087
|
+
DROP INDEX IF EXISTS idx_help_requests_project_id;
|
|
4088
|
+
|
|
4089
|
+
-- Drop functions
|
|
4090
|
+
DROP FUNCTION IF EXISTS register_project(VARCHAR, VARCHAR);
|
|
4091
|
+
DROP FUNCTION IF EXISTS get_project_id(VARCHAR);
|
|
4092
|
+
|
|
4093
|
+
-- NOTE: We intentionally keep the project_id columns and projects table
|
|
4094
|
+
-- to preserve data. Remove them manually if needed:
|
|
4095
|
+
-- ALTER TABLE memories DROP COLUMN IF EXISTS project_id;
|
|
4096
|
+
-- DROP TABLE IF EXISTS projects;
|
|
4097
|
+
`,
|
|
4098
|
+
checksum: this.generateChecksum('project_namespacing_isolation_v31')
|
|
4099
|
+
},
|
|
4100
|
+
// migration 32: Add project_path to code_chunks for per-project isolation
|
|
4101
|
+
// CRITICAL: code_chunks was missed in the original project namespacing migration
|
|
4102
|
+
// This enables find_code_pointers to work correctly per-project
|
|
4103
|
+
{
|
|
4104
|
+
version: 32,
|
|
4105
|
+
name: 'code_chunks_project_path',
|
|
4106
|
+
up: `
|
|
4107
|
+
-- Add project_path to code_chunks for project isolation
|
|
4108
|
+
DO $$ BEGIN
|
|
4109
|
+
ALTER TABLE code_chunks
|
|
4110
|
+
ADD COLUMN IF NOT EXISTS project_path TEXT DEFAULT '/';
|
|
4111
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
4112
|
+
END $$;
|
|
4113
|
+
|
|
4114
|
+
-- Index for project_path filtering - critical for per-project queries
|
|
4115
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_project_path
|
|
4116
|
+
ON code_chunks(project_path);
|
|
4117
|
+
|
|
4118
|
+
-- Composite index for project + file lookups
|
|
4119
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_project_file
|
|
4120
|
+
ON code_chunks(project_path, file_path);
|
|
4121
|
+
`,
|
|
4122
|
+
down: `
|
|
4123
|
+
DROP INDEX IF EXISTS idx_code_chunks_project_file;
|
|
4124
|
+
DROP INDEX IF EXISTS idx_code_chunks_project_path;
|
|
4125
|
+
ALTER TABLE code_chunks DROP COLUMN IF EXISTS project_path;
|
|
4126
|
+
`,
|
|
4127
|
+
checksum: this.generateChecksum('code_chunks_project_path_v32')
|
|
4128
|
+
},
|
|
4129
|
+
// migration 33: Add project_path to code_dependencies for per-project isolation
|
|
4130
|
+
// CRITICAL: This table also needs project_path for codebase indexer to work per-project
|
|
4131
|
+
{
|
|
4132
|
+
version: 33,
|
|
4133
|
+
name: 'code_dependencies_project_path',
|
|
4134
|
+
up: `
|
|
4135
|
+
-- Add project_path to code_dependencies for project isolation
|
|
4136
|
+
DO $$ BEGIN
|
|
4137
|
+
ALTER TABLE code_dependencies
|
|
4138
|
+
ADD COLUMN IF NOT EXISTS project_path TEXT DEFAULT '/';
|
|
4139
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
4140
|
+
END $$;
|
|
4141
|
+
|
|
4142
|
+
-- Index for project_path filtering
|
|
4143
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_project_path
|
|
4144
|
+
ON code_dependencies(project_path);
|
|
4145
|
+
|
|
4146
|
+
-- Composite index for project + source lookups
|
|
4147
|
+
CREATE INDEX IF NOT EXISTS idx_code_dependencies_project_source
|
|
4148
|
+
ON code_dependencies(project_path, source_file_id);
|
|
4149
|
+
`,
|
|
4150
|
+
down: `
|
|
4151
|
+
DROP INDEX IF EXISTS idx_code_dependencies_project_source;
|
|
4152
|
+
DROP INDEX IF EXISTS idx_code_dependencies_project_path;
|
|
4153
|
+
ALTER TABLE code_dependencies DROP COLUMN IF EXISTS project_path;
|
|
4154
|
+
`,
|
|
4155
|
+
checksum: this.generateChecksum('code_dependencies_project_path_v33')
|
|
4156
|
+
},
|
|
4157
|
+
// migration 34: Add project_path to code_complexity for per-project isolation
|
|
4158
|
+
// CRITICAL: This table also needs project_path for codebase metrics per-project
|
|
4159
|
+
{
|
|
4160
|
+
version: 34,
|
|
4161
|
+
name: 'code_complexity_project_path',
|
|
4162
|
+
up: `
|
|
4163
|
+
-- Add project_path to code_complexity for project isolation
|
|
4164
|
+
DO $$ BEGIN
|
|
4165
|
+
ALTER TABLE code_complexity
|
|
4166
|
+
ADD COLUMN IF NOT EXISTS project_path TEXT DEFAULT '/';
|
|
4167
|
+
EXCEPTION WHEN duplicate_column THEN NULL;
|
|
4168
|
+
END $$;
|
|
4169
|
+
|
|
4170
|
+
-- Index for project_path filtering
|
|
4171
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_project_path
|
|
4172
|
+
ON code_complexity(project_path);
|
|
4173
|
+
|
|
4174
|
+
-- Composite index for project + file lookups
|
|
4175
|
+
CREATE INDEX IF NOT EXISTS idx_code_complexity_project_file
|
|
4176
|
+
ON code_complexity(project_path, file_id);
|
|
4177
|
+
`,
|
|
4178
|
+
down: `
|
|
4179
|
+
DROP INDEX IF EXISTS idx_code_complexity_project_file;
|
|
4180
|
+
DROP INDEX IF EXISTS idx_code_complexity_project_path;
|
|
4181
|
+
ALTER TABLE code_complexity DROP COLUMN IF EXISTS project_path;
|
|
4182
|
+
`,
|
|
4183
|
+
checksum: this.generateChecksum('code_complexity_project_path_v34')
|
|
4184
|
+
},
|
|
4185
|
+
// migration 35: Add composite indexes for common project_path query patterns
|
|
4186
|
+
// CRITICAL: Queries use project_path (TEXT) not project_id (UUID) - need matching indexes
|
|
4187
|
+
{
|
|
4188
|
+
version: 35,
|
|
4189
|
+
name: 'composite_project_path_indexes',
|
|
4190
|
+
up: `
|
|
4191
|
+
-- Composite index for project + created_at (recent memories query)
|
|
4192
|
+
-- Used by: find_memory with recencyBoost, getStatsRealtime
|
|
4193
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_path_created
|
|
4194
|
+
ON memories(project_path, created_at DESC);
|
|
4195
|
+
|
|
4196
|
+
-- Composite index for project + importance (priority lookup)
|
|
4197
|
+
-- Used by: find_memory with importance filter
|
|
4198
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_path_importance
|
|
4199
|
+
ON memories(project_path, importance);
|
|
4200
|
+
|
|
4201
|
+
-- Composite index for project + memory_type (filtered searches)
|
|
4202
|
+
-- Used by: find_memory with memoryTypes filter
|
|
4203
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_path_type
|
|
4204
|
+
ON memories(project_path, memory_type);
|
|
4205
|
+
|
|
4206
|
+
-- Composite index for codebase_files project + file_path
|
|
4207
|
+
-- Used by: codebaseTools queries filtering by project_path and file_path
|
|
4208
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_project_path_file
|
|
4209
|
+
ON codebase_files(project_path, file_path);
|
|
4210
|
+
|
|
4211
|
+
-- Composite index for codebase_files project + content_hash (dedup check)
|
|
4212
|
+
-- Used by: codebaseIndexer for hash lookups per project
|
|
4213
|
+
CREATE INDEX IF NOT EXISTS idx_codebase_files_project_path_hash
|
|
4214
|
+
ON codebase_files(project_path, content_hash);
|
|
4215
|
+
|
|
4216
|
+
-- Composite index for memories project + content_hash (dedup check)
|
|
4217
|
+
-- Used by: yeetStuffInDb for duplicate memory detection
|
|
4218
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_path_hash
|
|
4219
|
+
ON memories(project_path, content_hash);
|
|
4220
|
+
`,
|
|
4221
|
+
down: `
|
|
4222
|
+
DROP INDEX IF EXISTS idx_memories_project_path_created;
|
|
4223
|
+
DROP INDEX IF EXISTS idx_memories_project_path_importance;
|
|
4224
|
+
DROP INDEX IF EXISTS idx_memories_project_path_type;
|
|
4225
|
+
DROP INDEX IF EXISTS idx_codebase_files_project_path_file;
|
|
4226
|
+
DROP INDEX IF EXISTS idx_codebase_files_project_path_hash;
|
|
4227
|
+
DROP INDEX IF EXISTS idx_memories_project_path_hash;
|
|
4228
|
+
`,
|
|
4229
|
+
checksum: this.generateChecksum('composite_project_path_indexes_v35')
|
|
4230
|
+
}
|
|
4231
|
+
];
|
|
4232
|
+
}
|
|
4233
|
+
// validates all migration checksums to detect tampering
|
|
4234
|
+
async validateMigrations() {
|
|
4235
|
+
const applied = await this.getAppliedMigrations();
|
|
4236
|
+
const migrations = this.getMigrations();
|
|
4237
|
+
const issues = [];
|
|
4238
|
+
for (const record of applied) {
|
|
4239
|
+
const migration = migrations.find(m => m.version === record.version);
|
|
4240
|
+
if (!migration) {
|
|
4241
|
+
issues.push(`migration ${record.version} (${record.name}) not found in codebase`);
|
|
4242
|
+
continue;
|
|
4243
|
+
}
|
|
4244
|
+
if (migration.checksum !== record.checksum) {
|
|
4245
|
+
issues.push(`checksum mismatch for migration ${record.version}: ` +
|
|
4246
|
+
`expected ${record.checksum}, got ${migration.checksum}`);
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
return {
|
|
4250
|
+
valid: issues.length === 0,
|
|
4251
|
+
issues
|
|
4252
|
+
};
|
|
4253
|
+
}
|
|
4254
|
+
// gets migration status
|
|
4255
|
+
async getStatus() {
|
|
4256
|
+
await this.ensureMigrationTable();
|
|
4257
|
+
const applied = await this.getAppliedMigrations();
|
|
4258
|
+
const allMigrations = this.getMigrations();
|
|
4259
|
+
return {
|
|
4260
|
+
applied,
|
|
4261
|
+
pending: allMigrations.filter(m => !applied.some(a => a.version === m.version)),
|
|
4262
|
+
lastApplied: applied[applied.length - 1] ?? null
|
|
4263
|
+
};
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
//# sourceMappingURL=bigBrainMigrations.js.map
|