universal-agent-protocol 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +462 -0
- package/dist/analyzers/index.d.ts +3 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +656 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +506 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/bin/tool-calls.d.ts +3 -0
- package/dist/bin/tool-calls.d.ts.map +1 -0
- package/dist/bin/tool-calls.js +4 -0
- package/dist/bin/tool-calls.js.map +1 -0
- package/dist/cli/agent.d.ts +20 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +434 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/analyze.d.ts +7 -0
- package/dist/cli/analyze.d.ts.map +1 -0
- package/dist/cli/analyze.js +103 -0
- package/dist/cli/analyze.js.map +1 -0
- package/dist/cli/coord.d.ts +7 -0
- package/dist/cli/coord.d.ts.map +1 -0
- package/dist/cli/coord.js +138 -0
- package/dist/cli/coord.js.map +1 -0
- package/dist/cli/dashboard.d.ts +8 -0
- package/dist/cli/dashboard.d.ts.map +1 -0
- package/dist/cli/dashboard.js +704 -0
- package/dist/cli/dashboard.js.map +1 -0
- package/dist/cli/deploy.d.ts +19 -0
- package/dist/cli/deploy.d.ts.map +1 -0
- package/dist/cli/deploy.js +267 -0
- package/dist/cli/deploy.js.map +1 -0
- package/dist/cli/droids.d.ts +9 -0
- package/dist/cli/droids.d.ts.map +1 -0
- package/dist/cli/droids.js +227 -0
- package/dist/cli/droids.js.map +1 -0
- package/dist/cli/generate.d.ts +17 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +432 -0
- package/dist/cli/generate.js.map +1 -0
- package/dist/cli/hooks.d.ts +9 -0
- package/dist/cli/hooks.d.ts.map +1 -0
- package/dist/cli/hooks.js +374 -0
- package/dist/cli/hooks.js.map +1 -0
- package/dist/cli/init.d.ts +11 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +316 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/mcp-router.d.ts +16 -0
- package/dist/cli/mcp-router.d.ts.map +1 -0
- package/dist/cli/mcp-router.js +143 -0
- package/dist/cli/mcp-router.js.map +1 -0
- package/dist/cli/memory.d.ts +24 -0
- package/dist/cli/memory.d.ts.map +1 -0
- package/dist/cli/memory.js +877 -0
- package/dist/cli/memory.js.map +1 -0
- package/dist/cli/model.d.ts +15 -0
- package/dist/cli/model.d.ts.map +1 -0
- package/dist/cli/model.js +270 -0
- package/dist/cli/model.js.map +1 -0
- package/dist/cli/patterns.d.ts +26 -0
- package/dist/cli/patterns.d.ts.map +1 -0
- package/dist/cli/patterns.js +587 -0
- package/dist/cli/patterns.js.map +1 -0
- package/dist/cli/setup-mcp-router.d.ts +8 -0
- package/dist/cli/setup-mcp-router.d.ts.map +1 -0
- package/dist/cli/setup-mcp-router.js +163 -0
- package/dist/cli/setup-mcp-router.js.map +1 -0
- package/dist/cli/setup.d.ts +13 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +146 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli/sync.d.ts +7 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +26 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli/task.d.ts +33 -0
- package/dist/cli/task.d.ts.map +1 -0
- package/dist/cli/task.js +616 -0
- package/dist/cli/task.js.map +1 -0
- package/dist/cli/tool-calls.d.ts +8 -0
- package/dist/cli/tool-calls.d.ts.map +1 -0
- package/dist/cli/tool-calls.js +239 -0
- package/dist/cli/tool-calls.js.map +1 -0
- package/dist/cli/update.d.ts +10 -0
- package/dist/cli/update.d.ts.map +1 -0
- package/dist/cli/update.js +300 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/cli/visualize.d.ts +77 -0
- package/dist/cli/visualize.d.ts.map +1 -0
- package/dist/cli/visualize.js +287 -0
- package/dist/cli/visualize.js.map +1 -0
- package/dist/cli/worktree.d.ts +9 -0
- package/dist/cli/worktree.d.ts.map +1 -0
- package/dist/cli/worktree.js +175 -0
- package/dist/cli/worktree.js.map +1 -0
- package/dist/coordination/capability-router.d.ts +79 -0
- package/dist/coordination/capability-router.d.ts.map +1 -0
- package/dist/coordination/capability-router.js +324 -0
- package/dist/coordination/capability-router.js.map +1 -0
- package/dist/coordination/database.d.ts +13 -0
- package/dist/coordination/database.d.ts.map +1 -0
- package/dist/coordination/database.js +131 -0
- package/dist/coordination/database.js.map +1 -0
- package/dist/coordination/deploy-batcher.d.ts +101 -0
- package/dist/coordination/deploy-batcher.d.ts.map +1 -0
- package/dist/coordination/deploy-batcher.js +565 -0
- package/dist/coordination/deploy-batcher.js.map +1 -0
- package/dist/coordination/index.d.ts +5 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +5 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/service.d.ts +81 -0
- package/dist/coordination/service.d.ts.map +1 -0
- package/dist/coordination/service.js +603 -0
- package/dist/coordination/service.js.map +1 -0
- package/dist/generators/claude-md.d.ts +3 -0
- package/dist/generators/claude-md.d.ts.map +1 -0
- package/dist/generators/claude-md.js +977 -0
- package/dist/generators/claude-md.js.map +1 -0
- package/dist/generators/template-loader.d.ts +105 -0
- package/dist/generators/template-loader.d.ts.map +1 -0
- package/dist/generators/template-loader.js +291 -0
- package/dist/generators/template-loader.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-router/config/parser.d.ts +9 -0
- package/dist/mcp-router/config/parser.d.ts.map +1 -0
- package/dist/mcp-router/config/parser.js +174 -0
- package/dist/mcp-router/config/parser.js.map +1 -0
- package/dist/mcp-router/executor/client.d.ts +31 -0
- package/dist/mcp-router/executor/client.d.ts.map +1 -0
- package/dist/mcp-router/executor/client.js +187 -0
- package/dist/mcp-router/executor/client.js.map +1 -0
- package/dist/mcp-router/index.d.ts +22 -0
- package/dist/mcp-router/index.d.ts.map +1 -0
- package/dist/mcp-router/index.js +18 -0
- package/dist/mcp-router/index.js.map +1 -0
- package/dist/mcp-router/output-compressor.d.ts +26 -0
- package/dist/mcp-router/output-compressor.d.ts.map +1 -0
- package/dist/mcp-router/output-compressor.js +236 -0
- package/dist/mcp-router/output-compressor.js.map +1 -0
- package/dist/mcp-router/search/fuzzy.d.ts +26 -0
- package/dist/mcp-router/search/fuzzy.d.ts.map +1 -0
- package/dist/mcp-router/search/fuzzy.js +94 -0
- package/dist/mcp-router/search/fuzzy.js.map +1 -0
- package/dist/mcp-router/server.d.ts +50 -0
- package/dist/mcp-router/server.d.ts.map +1 -0
- package/dist/mcp-router/server.js +229 -0
- package/dist/mcp-router/server.js.map +1 -0
- package/dist/mcp-router/session-stats.d.ts +37 -0
- package/dist/mcp-router/session-stats.d.ts.map +1 -0
- package/dist/mcp-router/session-stats.js +56 -0
- package/dist/mcp-router/session-stats.js.map +1 -0
- package/dist/mcp-router/tools/discover.d.ts +37 -0
- package/dist/mcp-router/tools/discover.d.ts.map +1 -0
- package/dist/mcp-router/tools/discover.js +65 -0
- package/dist/mcp-router/tools/discover.js.map +1 -0
- package/dist/mcp-router/tools/execute.d.ts +43 -0
- package/dist/mcp-router/tools/execute.d.ts.map +1 -0
- package/dist/mcp-router/tools/execute.js +103 -0
- package/dist/mcp-router/tools/execute.js.map +1 -0
- package/dist/mcp-router/types.d.ts +62 -0
- package/dist/mcp-router/types.d.ts.map +1 -0
- package/dist/mcp-router/types.js +6 -0
- package/dist/mcp-router/types.js.map +1 -0
- package/dist/memory/adaptive-context.d.ts +146 -0
- package/dist/memory/adaptive-context.d.ts.map +1 -0
- package/dist/memory/adaptive-context.js +1022 -0
- package/dist/memory/adaptive-context.js.map +1 -0
- package/dist/memory/agent-scoped-memory.d.ts +67 -0
- package/dist/memory/agent-scoped-memory.d.ts.map +1 -0
- package/dist/memory/agent-scoped-memory.js +126 -0
- package/dist/memory/agent-scoped-memory.js.map +1 -0
- package/dist/memory/backends/base.d.ts +18 -0
- package/dist/memory/backends/base.d.ts.map +1 -0
- package/dist/memory/backends/base.js +2 -0
- package/dist/memory/backends/base.js.map +1 -0
- package/dist/memory/backends/factory.d.ts +4 -0
- package/dist/memory/backends/factory.d.ts.map +1 -0
- package/dist/memory/backends/factory.js +53 -0
- package/dist/memory/backends/factory.js.map +1 -0
- package/dist/memory/backends/github.d.ts +22 -0
- package/dist/memory/backends/github.d.ts.map +1 -0
- package/dist/memory/backends/github.js +118 -0
- package/dist/memory/backends/github.js.map +1 -0
- package/dist/memory/backends/qdrant-cloud.d.ts +32 -0
- package/dist/memory/backends/qdrant-cloud.d.ts.map +1 -0
- package/dist/memory/backends/qdrant-cloud.js +168 -0
- package/dist/memory/backends/qdrant-cloud.js.map +1 -0
- package/dist/memory/context-compressor.d.ts +74 -0
- package/dist/memory/context-compressor.d.ts.map +1 -0
- package/dist/memory/context-compressor.js +289 -0
- package/dist/memory/context-compressor.js.map +1 -0
- package/dist/memory/correction-propagator.d.ts +44 -0
- package/dist/memory/correction-propagator.d.ts.map +1 -0
- package/dist/memory/correction-propagator.js +156 -0
- package/dist/memory/correction-propagator.js.map +1 -0
- package/dist/memory/daily-log.d.ts +67 -0
- package/dist/memory/daily-log.d.ts.map +1 -0
- package/dist/memory/daily-log.js +143 -0
- package/dist/memory/daily-log.js.map +1 -0
- package/dist/memory/dynamic-retrieval.d.ts +110 -0
- package/dist/memory/dynamic-retrieval.d.ts.map +1 -0
- package/dist/memory/dynamic-retrieval.js +688 -0
- package/dist/memory/dynamic-retrieval.js.map +1 -0
- package/dist/memory/embeddings.d.ts +116 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +461 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/hierarchical-memory.d.ts +141 -0
- package/dist/memory/hierarchical-memory.d.ts.map +1 -0
- package/dist/memory/hierarchical-memory.js +477 -0
- package/dist/memory/hierarchical-memory.js.map +1 -0
- package/dist/memory/memory-consolidator.d.ts +124 -0
- package/dist/memory/memory-consolidator.d.ts.map +1 -0
- package/dist/memory/memory-consolidator.js +514 -0
- package/dist/memory/memory-consolidator.js.map +1 -0
- package/dist/memory/memory-maintenance.d.ts +39 -0
- package/dist/memory/memory-maintenance.d.ts.map +1 -0
- package/dist/memory/memory-maintenance.js +305 -0
- package/dist/memory/memory-maintenance.js.map +1 -0
- package/dist/memory/model-router.d.ts +102 -0
- package/dist/memory/model-router.d.ts.map +1 -0
- package/dist/memory/model-router.js +448 -0
- package/dist/memory/model-router.js.map +1 -0
- package/dist/memory/multi-view-memory.d.ts +134 -0
- package/dist/memory/multi-view-memory.d.ts.map +1 -0
- package/dist/memory/multi-view-memory.js +420 -0
- package/dist/memory/multi-view-memory.js.map +1 -0
- package/dist/memory/prepopulate.d.ts +76 -0
- package/dist/memory/prepopulate.d.ts.map +1 -0
- package/dist/memory/prepopulate.js +815 -0
- package/dist/memory/prepopulate.js.map +1 -0
- package/dist/memory/semantic-compression.d.ts +77 -0
- package/dist/memory/semantic-compression.d.ts.map +1 -0
- package/dist/memory/semantic-compression.js +348 -0
- package/dist/memory/semantic-compression.js.map +1 -0
- package/dist/memory/serverless-qdrant.d.ts +102 -0
- package/dist/memory/serverless-qdrant.d.ts.map +1 -0
- package/dist/memory/serverless-qdrant.js +369 -0
- package/dist/memory/serverless-qdrant.js.map +1 -0
- package/dist/memory/short-term/factory.d.ts +26 -0
- package/dist/memory/short-term/factory.d.ts.map +1 -0
- package/dist/memory/short-term/factory.js +28 -0
- package/dist/memory/short-term/factory.js.map +1 -0
- package/dist/memory/short-term/indexeddb.d.ts +25 -0
- package/dist/memory/short-term/indexeddb.d.ts.map +1 -0
- package/dist/memory/short-term/indexeddb.js +64 -0
- package/dist/memory/short-term/indexeddb.js.map +1 -0
- package/dist/memory/short-term/schema.d.ts +6 -0
- package/dist/memory/short-term/schema.d.ts.map +1 -0
- package/dist/memory/short-term/schema.js +119 -0
- package/dist/memory/short-term/schema.js.map +1 -0
- package/dist/memory/short-term/sqlite.d.ts +50 -0
- package/dist/memory/short-term/sqlite.d.ts.map +1 -0
- package/dist/memory/short-term/sqlite.js +221 -0
- package/dist/memory/short-term/sqlite.js.map +1 -0
- package/dist/memory/speculative-cache.d.ts +111 -0
- package/dist/memory/speculative-cache.d.ts.map +1 -0
- package/dist/memory/speculative-cache.js +409 -0
- package/dist/memory/speculative-cache.js.map +1 -0
- package/dist/memory/task-classifier.d.ts +34 -0
- package/dist/memory/task-classifier.d.ts.map +1 -0
- package/dist/memory/task-classifier.js +300 -0
- package/dist/memory/task-classifier.js.map +1 -0
- package/dist/memory/terminal-bench-knowledge.d.ts +48 -0
- package/dist/memory/terminal-bench-knowledge.d.ts.map +1 -0
- package/dist/memory/terminal-bench-knowledge.js +399 -0
- package/dist/memory/terminal-bench-knowledge.js.map +1 -0
- package/dist/memory/write-gate.d.ts +39 -0
- package/dist/memory/write-gate.d.ts.map +1 -0
- package/dist/memory/write-gate.js +190 -0
- package/dist/memory/write-gate.js.map +1 -0
- package/dist/models/executor.d.ts +130 -0
- package/dist/models/executor.d.ts.map +1 -0
- package/dist/models/executor.js +383 -0
- package/dist/models/executor.js.map +1 -0
- package/dist/models/index.d.ts +15 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +17 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/planner.d.ts +71 -0
- package/dist/models/planner.d.ts.map +1 -0
- package/dist/models/planner.js +344 -0
- package/dist/models/planner.js.map +1 -0
- package/dist/models/router.d.ts +75 -0
- package/dist/models/router.d.ts.map +1 -0
- package/dist/models/router.js +344 -0
- package/dist/models/router.js.map +1 -0
- package/dist/models/types.d.ts +370 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +181 -0
- package/dist/models/types.js.map +1 -0
- package/dist/tasks/coordination.d.ts +74 -0
- package/dist/tasks/coordination.d.ts.map +1 -0
- package/dist/tasks/coordination.js +237 -0
- package/dist/tasks/coordination.js.map +1 -0
- package/dist/tasks/database.d.ts +14 -0
- package/dist/tasks/database.d.ts.map +1 -0
- package/dist/tasks/database.js +128 -0
- package/dist/tasks/database.js.map +1 -0
- package/dist/tasks/index.d.ts +5 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +5 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/service.d.ts +39 -0
- package/dist/tasks/service.d.ts.map +1 -0
- package/dist/tasks/service.js +582 -0
- package/dist/tasks/service.js.map +1 -0
- package/dist/tasks/types.d.ts +224 -0
- package/dist/tasks/types.d.ts.map +1 -0
- package/dist/tasks/types.js +64 -0
- package/dist/tasks/types.js.map +1 -0
- package/dist/types/analysis.d.ts +82 -0
- package/dist/types/analysis.d.ts.map +1 -0
- package/dist/types/analysis.js +2 -0
- package/dist/types/analysis.js.map +1 -0
- package/dist/types/config.d.ts +3023 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +292 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/coordination.d.ts +240 -0
- package/dist/types/coordination.d.ts.map +1 -0
- package/dist/types/coordination.js +43 -0
- package/dist/types/coordination.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/calculate-average.d.ts +15 -0
- package/dist/utils/calculate-average.d.ts.map +1 -0
- package/dist/utils/calculate-average.js +21 -0
- package/dist/utils/calculate-average.js.map +1 -0
- package/dist/utils/config-manager.d.ts +30 -0
- package/dist/utils/config-manager.d.ts.map +1 -0
- package/dist/utils/config-manager.js +41 -0
- package/dist/utils/config-manager.js.map +1 -0
- package/dist/utils/dijkstra.d.ts +17 -0
- package/dist/utils/dijkstra.d.ts.map +1 -0
- package/dist/utils/dijkstra.js +91 -0
- package/dist/utils/dijkstra.js.map +1 -0
- package/dist/utils/fetch-with-retry.d.ts +5 -0
- package/dist/utils/fetch-with-retry.d.ts.map +1 -0
- package/dist/utils/fetch-with-retry.js +61 -0
- package/dist/utils/fetch-with-retry.js.map +1 -0
- package/dist/utils/merge-claude-md.d.ts +28 -0
- package/dist/utils/merge-claude-md.d.ts.map +1 -0
- package/dist/utils/merge-claude-md.js +342 -0
- package/dist/utils/merge-claude-md.js.map +1 -0
- package/dist/utils/order-processor-refactored.d.ts +126 -0
- package/dist/utils/order-processor-refactored.d.ts.map +1 -0
- package/dist/utils/order-processor-refactored.js +165 -0
- package/dist/utils/order-processor-refactored.js.map +1 -0
- package/dist/utils/order-processor-strategy.d.ts +72 -0
- package/dist/utils/order-processor-strategy.d.ts.map +1 -0
- package/dist/utils/order-processor-strategy.js +158 -0
- package/dist/utils/order-processor-strategy.js.map +1 -0
- package/dist/utils/order-processor.d.ts +242 -0
- package/dist/utils/order-processor.d.ts.map +1 -0
- package/dist/utils/order-processor.js +370 -0
- package/dist/utils/order-processor.js.map +1 -0
- package/dist/utils/rate-limiter-simple.d.ts +58 -0
- package/dist/utils/rate-limiter-simple.d.ts.map +1 -0
- package/dist/utils/rate-limiter-simple.js +100 -0
- package/dist/utils/rate-limiter-simple.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +62 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +150 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/string-similarity.d.ts +37 -0
- package/dist/utils/string-similarity.d.ts.map +1 -0
- package/dist/utils/string-similarity.js +114 -0
- package/dist/utils/string-similarity.js.map +1 -0
- package/dist/utils/validate-json.d.ts +51 -0
- package/dist/utils/validate-json.d.ts.map +1 -0
- package/dist/utils/validate-json.js +99 -0
- package/dist/utils/validate-json.js.map +1 -0
- package/package.json +96 -0
- package/templates/CLAUDE.template.md +11 -0
- package/templates/CLAUDE_ARCHITECTURE.template.md +103 -0
- package/templates/CLAUDE_CODING.template.md +125 -0
- package/templates/CLAUDE_DROIDS.template.md +109 -0
- package/templates/CLAUDE_MEMORY.template.md +130 -0
- package/templates/CLAUDE_WORKFLOWS.template.md +136 -0
- package/templates/PROJECT.template.md +209 -0
- package/templates/SCHEMA.md +57 -0
- package/templates/archive/CLAUDE.template.root-v6.md +762 -0
- package/templates/archive/CLAUDE.template.v6.md +762 -0
- package/templates/hooks/pre-compact.sh +68 -0
- package/templates/hooks/session-start.sh +106 -0
- package/tools/agents/README.md +224 -0
- package/tools/agents/UAP/README.md +351 -0
- package/tools/agents/UAP/__init__.py +9 -0
- package/tools/agents/UAP/cli.py +675 -0
- package/tools/agents/UAP/version.py +2 -0
- package/tools/agents/benchmarks/benchmark_memory_systems.py +637 -0
- package/tools/agents/benchmarks/results/benchmark_20260106_064817.json +170 -0
- package/tools/agents/benchmarks/results/benchmark_20260106_064817.md +51 -0
- package/tools/agents/config/chat_template.jinja +172 -0
- package/tools/agents/docker-compose.qdrant.yml +24 -0
- package/tools/agents/migrations/apply.py +256 -0
- package/tools/agents/scripts/fix_qwen_chat_template.py +314 -0
- package/tools/agents/scripts/init_qdrant.py +151 -0
- package/tools/agents/scripts/memory_migration.py +518 -0
- package/tools/agents/scripts/migrate_memory_to_qdrant.py +113 -0
- package/tools/agents/scripts/query_memory.py +189 -0
- package/tools/agents/scripts/qwen_tool_call_test.py +419 -0
- package/tools/agents/scripts/qwen_tool_call_wrapper.py +517 -0
- package/tools/agents/scripts/start-services.sh +96 -0
- package/tools/agents/tests/test_uap_compliance.py +257 -0
|
@@ -0,0 +1,877 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import Database from 'better-sqlite3';
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, statSync } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
import { QdrantClient } from '@qdrant/js-client-rest';
|
|
9
|
+
import { prepopulateMemory } from '../memory/prepopulate.js';
|
|
10
|
+
import { SQLiteShortTermMemory } from '../memory/short-term/sqlite.js';
|
|
11
|
+
import { ensureKnowledgeSchema, ensureSessionSchema } from '../memory/short-term/schema.js';
|
|
12
|
+
import { AgentContextConfigSchema } from '../types/index.js';
|
|
13
|
+
import { statusBadge, miniGauge, divider, keyValue, tree } from './visualize.js';
|
|
14
|
+
import { evaluateWriteGate, formatGateResult } from '../memory/write-gate.js';
|
|
15
|
+
import { DailyLog } from '../memory/daily-log.js';
|
|
16
|
+
import { propagateCorrection } from '../memory/correction-propagator.js';
|
|
17
|
+
import { runMaintenance } from '../memory/memory-maintenance.js';
|
|
18
|
+
export async function memoryCommand(action, options = {}) {
|
|
19
|
+
const cwd = process.cwd();
|
|
20
|
+
switch (action) {
|
|
21
|
+
case 'status':
|
|
22
|
+
await showStatus(cwd);
|
|
23
|
+
break;
|
|
24
|
+
case 'start':
|
|
25
|
+
await startServices(cwd);
|
|
26
|
+
break;
|
|
27
|
+
case 'stop':
|
|
28
|
+
await stopServices(cwd);
|
|
29
|
+
break;
|
|
30
|
+
case 'query':
|
|
31
|
+
await queryMemory(cwd, options.search, parseInt(options.limit || '10'));
|
|
32
|
+
break;
|
|
33
|
+
case 'store':
|
|
34
|
+
await storeMemory(cwd, options.content, options.tags, parseInt(options.importance || '5'), options.force);
|
|
35
|
+
break;
|
|
36
|
+
case 'prepopulate':
|
|
37
|
+
await prepopulateFromSources(cwd, options);
|
|
38
|
+
break;
|
|
39
|
+
case 'promote':
|
|
40
|
+
await promoteFromDailyLog(cwd, options);
|
|
41
|
+
break;
|
|
42
|
+
case 'correct':
|
|
43
|
+
await correctMemory(cwd, options);
|
|
44
|
+
break;
|
|
45
|
+
case 'maintain':
|
|
46
|
+
await maintainMemory(cwd, options);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function showStatus(cwd) {
|
|
51
|
+
console.log('');
|
|
52
|
+
console.log(chalk.bold.cyan(' Memory System Status'));
|
|
53
|
+
console.log(divider(50));
|
|
54
|
+
console.log('');
|
|
55
|
+
let sqliteActive = false;
|
|
56
|
+
let qdrantActive = false;
|
|
57
|
+
// Short-term memory
|
|
58
|
+
const shortTermPath = join(cwd, 'agents/data/memory/short_term.db');
|
|
59
|
+
if (existsSync(shortTermPath)) {
|
|
60
|
+
sqliteActive = true;
|
|
61
|
+
const stats = statSync(shortTermPath);
|
|
62
|
+
const sizeKB = Math.round(stats.size / 1024);
|
|
63
|
+
let entryCount = 0;
|
|
64
|
+
try {
|
|
65
|
+
const db = new SQLiteShortTermMemory({
|
|
66
|
+
dbPath: shortTermPath,
|
|
67
|
+
projectId: 'status-check',
|
|
68
|
+
maxEntries: 9999,
|
|
69
|
+
});
|
|
70
|
+
entryCount = await db.count();
|
|
71
|
+
await db.close();
|
|
72
|
+
}
|
|
73
|
+
catch { /* ignore */ }
|
|
74
|
+
console.log(` ${statusBadge('active')} ${chalk.bold('Short-term Memory')}`);
|
|
75
|
+
for (const line of keyValue([
|
|
76
|
+
['Size', `${sizeKB} KB`],
|
|
77
|
+
['Entries', entryCount],
|
|
78
|
+
['Modified', stats.mtime.toLocaleDateString()],
|
|
79
|
+
], { indent: 4 }))
|
|
80
|
+
console.log(line);
|
|
81
|
+
console.log(` ${'Capacity'.padEnd(18)} ${miniGauge(entryCount, 50, 15)} ${chalk.dim(`${entryCount}/50`)}`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
console.log(` ${statusBadge('not_available')} ${chalk.bold('Short-term Memory')} ${chalk.dim('Not initialized')}`);
|
|
85
|
+
}
|
|
86
|
+
console.log('');
|
|
87
|
+
// Qdrant
|
|
88
|
+
try {
|
|
89
|
+
const dockerStatus = execSync('docker ps --filter name=qdrant --format "{{.Status}}"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
90
|
+
if (dockerStatus) {
|
|
91
|
+
qdrantActive = true;
|
|
92
|
+
console.log(` ${statusBadge('running')} ${chalk.bold('Qdrant')} ${chalk.dim(dockerStatus)}`);
|
|
93
|
+
console.log(chalk.dim(' Endpoint: http://localhost:6333'));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
console.log(` ${statusBadge('stopped')} ${chalk.bold('Qdrant')} ${chalk.dim('Container not running')}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
console.log(` ${statusBadge('not_available')} ${chalk.bold('Qdrant')} ${chalk.dim('Docker not available')}`);
|
|
101
|
+
}
|
|
102
|
+
console.log('');
|
|
103
|
+
// Ollama
|
|
104
|
+
try {
|
|
105
|
+
const ollamaResponse = await fetch('http://localhost:11434/api/tags', {
|
|
106
|
+
method: 'GET',
|
|
107
|
+
signal: AbortSignal.timeout(2000),
|
|
108
|
+
});
|
|
109
|
+
if (ollamaResponse.ok) {
|
|
110
|
+
const ollamaData = await ollamaResponse.json();
|
|
111
|
+
const embedModels = ollamaData.models?.filter(m => m.name.includes('embed') || m.name.includes('nomic')) || [];
|
|
112
|
+
if (embedModels.length > 0) {
|
|
113
|
+
console.log(` ${statusBadge('active')} ${chalk.bold('Embeddings')}`);
|
|
114
|
+
for (const model of embedModels) {
|
|
115
|
+
const sizeMB = Math.round((model.size || 0) / 1024 / 1024);
|
|
116
|
+
console.log(` ${chalk.cyan(model.name)} ${chalk.dim(`${sizeMB} MB`)}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log(` ${statusBadge('not_available')} ${chalk.bold('Embeddings')} ${chalk.dim('No embed models')}`);
|
|
121
|
+
console.log(chalk.dim(' Run: ollama pull nomic-embed-text'));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
console.log(` ${statusBadge('stopped')} ${chalk.bold('Embeddings')} ${chalk.dim('Not responding')}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
console.log(` ${statusBadge('not_available')} ${chalk.bold('Embeddings')} ${chalk.dim('Ollama not running')}`);
|
|
130
|
+
}
|
|
131
|
+
// Architecture tree
|
|
132
|
+
console.log('');
|
|
133
|
+
const layers = {
|
|
134
|
+
label: chalk.bold('Memory Layers'),
|
|
135
|
+
children: [
|
|
136
|
+
{ label: 'L1 Working', status: sqliteActive ? chalk.green('ON') : chalk.red('--'), meta: 'SQLite, <1ms' },
|
|
137
|
+
{ label: 'L2 Session', status: sqliteActive ? chalk.green('ON') : chalk.red('--'), meta: 'SQLite, <5ms' },
|
|
138
|
+
{ label: 'L3 Semantic', status: qdrantActive ? chalk.green('ON') : chalk.yellow('--'), meta: 'Qdrant, ~50ms' },
|
|
139
|
+
{ label: 'L4 Graph', status: sqliteActive ? chalk.green('ON') : chalk.red('--'), meta: 'SQLite entities' },
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
for (const line of tree(layers))
|
|
143
|
+
console.log(line);
|
|
144
|
+
console.log('');
|
|
145
|
+
}
|
|
146
|
+
export async function startServices(cwd) {
|
|
147
|
+
const spinner = ora('Starting memory services...').start();
|
|
148
|
+
// Check for docker-compose file
|
|
149
|
+
const composePaths = [
|
|
150
|
+
join(cwd, 'agents/docker-compose.yml'),
|
|
151
|
+
join(cwd, 'docker/docker-compose.yml'),
|
|
152
|
+
];
|
|
153
|
+
let composePath = null;
|
|
154
|
+
for (const path of composePaths) {
|
|
155
|
+
if (existsSync(path)) {
|
|
156
|
+
composePath = path;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!composePath) {
|
|
161
|
+
// Create default docker-compose
|
|
162
|
+
spinner.text = 'Creating docker-compose.yml...';
|
|
163
|
+
const defaultCompose = `version: '3.8'
|
|
164
|
+
|
|
165
|
+
services:
|
|
166
|
+
qdrant:
|
|
167
|
+
image: qdrant/qdrant:latest
|
|
168
|
+
container_name: uap-qdrant
|
|
169
|
+
ports:
|
|
170
|
+
- "6333:6333"
|
|
171
|
+
- "6334:6334"
|
|
172
|
+
volumes:
|
|
173
|
+
- ./qdrant_data:/qdrant/storage
|
|
174
|
+
environment:
|
|
175
|
+
- QDRANT__SERVICE__GRPC_PORT=6334
|
|
176
|
+
restart: unless-stopped
|
|
177
|
+
`;
|
|
178
|
+
const agentsDir = join(cwd, 'agents');
|
|
179
|
+
if (!existsSync(agentsDir)) {
|
|
180
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
181
|
+
}
|
|
182
|
+
composePath = join(agentsDir, 'docker-compose.yml');
|
|
183
|
+
writeFileSync(composePath, defaultCompose);
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
execSync(`docker-compose -f "${composePath}" up -d`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
187
|
+
spinner.succeed('Memory services started');
|
|
188
|
+
console.log(chalk.dim(' Qdrant available at http://localhost:6333'));
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
spinner.fail('Failed to start memory services');
|
|
192
|
+
console.error(chalk.red('Make sure Docker is installed and running'));
|
|
193
|
+
console.error(error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Check if Qdrant is reachable by polling its health endpoint.
|
|
198
|
+
* Optionally waits up to `timeoutMs` for it to become available.
|
|
199
|
+
*/
|
|
200
|
+
export async function isQdrantReachable(endpoint = 'http://localhost:6333', timeoutMs = 0) {
|
|
201
|
+
const url = endpoint.startsWith('http') ? endpoint : `http://${endpoint}`;
|
|
202
|
+
const deadline = Date.now() + timeoutMs;
|
|
203
|
+
const pollInterval = 1000;
|
|
204
|
+
do {
|
|
205
|
+
try {
|
|
206
|
+
const res = await fetch(`${url}/healthz`, { signal: AbortSignal.timeout(2000) });
|
|
207
|
+
if (res.ok)
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Not yet available
|
|
212
|
+
}
|
|
213
|
+
if (Date.now() + pollInterval > deadline)
|
|
214
|
+
break;
|
|
215
|
+
await new Promise(r => setTimeout(r, pollInterval));
|
|
216
|
+
} while (Date.now() < deadline);
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
async function stopServices(cwd) {
|
|
220
|
+
const spinner = ora('Stopping memory services...').start();
|
|
221
|
+
const composePaths = [
|
|
222
|
+
join(cwd, 'agents/docker-compose.yml'),
|
|
223
|
+
join(cwd, 'docker/docker-compose.yml'),
|
|
224
|
+
];
|
|
225
|
+
let composePath = null;
|
|
226
|
+
for (const path of composePaths) {
|
|
227
|
+
if (existsSync(path)) {
|
|
228
|
+
composePath = path;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (!composePath) {
|
|
233
|
+
spinner.fail('No docker-compose.yml found');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
execSync(`docker-compose -f "${composePath}" down`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
238
|
+
spinner.succeed('Memory services stopped');
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
spinner.fail('Failed to stop memory services');
|
|
242
|
+
console.error(error);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function queryMemory(cwd, search, limit) {
|
|
246
|
+
console.log(chalk.bold(`\nš Searching for: "${search}" (limit: ${limit})\n`));
|
|
247
|
+
// Load config
|
|
248
|
+
const configPath = join(cwd, '.uap.json');
|
|
249
|
+
let config;
|
|
250
|
+
if (existsSync(configPath)) {
|
|
251
|
+
try {
|
|
252
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
253
|
+
config = AgentContextConfigSchema.parse(raw);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
config = {
|
|
257
|
+
version: '1.0.0',
|
|
258
|
+
project: { name: 'project', defaultBranch: 'main' },
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
config = {
|
|
264
|
+
version: '1.0.0',
|
|
265
|
+
project: { name: 'project', defaultBranch: 'main' },
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Query short-term memory (SQLite) first
|
|
269
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
270
|
+
if (existsSync(dbPath)) {
|
|
271
|
+
try {
|
|
272
|
+
const shortTermDb = new SQLiteShortTermMemory({
|
|
273
|
+
dbPath,
|
|
274
|
+
projectId: config.project.name,
|
|
275
|
+
maxEntries: config.memory?.shortTerm?.maxEntries || 50,
|
|
276
|
+
});
|
|
277
|
+
const results = await shortTermDb.query(search, limit);
|
|
278
|
+
await shortTermDb.close();
|
|
279
|
+
if (results.length > 0) {
|
|
280
|
+
console.log(chalk.green(`Found ${results.length} results in short-term memory:\n`));
|
|
281
|
+
for (const r of results) {
|
|
282
|
+
const typeColor = r.type === 'action' ? chalk.blue :
|
|
283
|
+
r.type === 'observation' ? chalk.cyan :
|
|
284
|
+
r.type === 'thought' ? chalk.magenta :
|
|
285
|
+
chalk.yellow;
|
|
286
|
+
console.log(` ${typeColor(`[${r.type}]`)} ${chalk.dim(r.timestamp.slice(0, 10))}`);
|
|
287
|
+
console.log(` ${r.content.slice(0, 150)}${r.content.length > 150 ? '...' : ''}\n`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
console.log(chalk.dim('No results in short-term memory'));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
console.log(chalk.yellow('Could not query short-term memory:'), error);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Query long-term memory (Qdrant) if available
|
|
299
|
+
await queryQdrant(cwd, config, search, limit);
|
|
300
|
+
}
|
|
301
|
+
async function queryQdrant(_cwd, config, search, limit) {
|
|
302
|
+
const endpoint = config.memory?.longTerm?.endpoint || 'localhost:6333';
|
|
303
|
+
const url = endpoint.startsWith('http://') || endpoint.startsWith('https://') ? endpoint : `http://${endpoint}`;
|
|
304
|
+
const apiKey = config.memory?.longTerm?.qdrantCloud?.apiKey || process.env.QDRANT_API_KEY;
|
|
305
|
+
const collection = config.memory?.longTerm?.collection || 'agent_memory';
|
|
306
|
+
try {
|
|
307
|
+
const client = new QdrantClient({ url, apiKey });
|
|
308
|
+
await client.getCollections();
|
|
309
|
+
// Try collection variants (main and prepopulated)
|
|
310
|
+
const collections = await client.getCollections();
|
|
311
|
+
const candidates = [collection, `${collection}_prepopulated`];
|
|
312
|
+
const availableCollections = candidates.filter(c => collections.collections.some(col => col.name === c));
|
|
313
|
+
if (availableCollections.length === 0) {
|
|
314
|
+
console.log(chalk.dim('\nNo Qdrant collections found. Run `uap memory prepopulate` first.'));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// Use deterministic embedding for search (same as storage)
|
|
318
|
+
const searchVector = createDeterministicEmbedding(`${search}`);
|
|
319
|
+
let allResults = [];
|
|
320
|
+
for (const col of availableCollections) {
|
|
321
|
+
try {
|
|
322
|
+
const results = await client.search(col, {
|
|
323
|
+
vector: searchVector,
|
|
324
|
+
limit,
|
|
325
|
+
with_payload: true,
|
|
326
|
+
});
|
|
327
|
+
for (const r of results) {
|
|
328
|
+
const payload = r.payload;
|
|
329
|
+
if (payload) {
|
|
330
|
+
allResults.push({
|
|
331
|
+
content: payload.content || '',
|
|
332
|
+
type: payload.type || 'unknown',
|
|
333
|
+
score: r.score,
|
|
334
|
+
tags: payload.tags,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// Collection might have incompatible vector size
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Deduplicate and sort by score
|
|
344
|
+
const seen = new Set();
|
|
345
|
+
allResults = allResults.filter(r => {
|
|
346
|
+
const key = r.content.slice(0, 100);
|
|
347
|
+
if (seen.has(key))
|
|
348
|
+
return false;
|
|
349
|
+
seen.add(key);
|
|
350
|
+
return true;
|
|
351
|
+
}).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
352
|
+
if (allResults.length > 0) {
|
|
353
|
+
console.log(chalk.green(`\nFound ${allResults.length} results in long-term memory (Qdrant):\n`));
|
|
354
|
+
for (const r of allResults) {
|
|
355
|
+
const typeColor = r.type === 'action' ? chalk.blue :
|
|
356
|
+
r.type === 'observation' ? chalk.cyan :
|
|
357
|
+
r.type === 'thought' ? chalk.magenta :
|
|
358
|
+
chalk.yellow;
|
|
359
|
+
const scoreStr = chalk.dim(`(${(r.score * 100).toFixed(0)}%)`);
|
|
360
|
+
console.log(` ${typeColor(`[${r.type}]`)} ${scoreStr}`);
|
|
361
|
+
console.log(` ${r.content.slice(0, 150)}${r.content.length > 150 ? '...' : ''}`);
|
|
362
|
+
if (r.tags && r.tags.length > 0) {
|
|
363
|
+
console.log(` ${chalk.dim(`tags: ${r.tags.join(', ')}`)}`);
|
|
364
|
+
}
|
|
365
|
+
console.log('');
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
console.log(chalk.dim('\nNo results in long-term memory'));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
console.log(chalk.dim('\nQdrant not available for long-term search. Run `uap memory start` first.'));
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async function storeMemory(cwd, content, tags, importance = 5, force = false) {
|
|
377
|
+
// Apply write gate unless --force is used
|
|
378
|
+
if (!force) {
|
|
379
|
+
const gateResult = evaluateWriteGate(content);
|
|
380
|
+
if (!gateResult.passed) {
|
|
381
|
+
console.log(chalk.bold('\nš« Write Gate: REJECTED\n'));
|
|
382
|
+
console.log(chalk.dim(formatGateResult(gateResult)));
|
|
383
|
+
console.log('');
|
|
384
|
+
console.log(chalk.yellow(' This memory does not meet the write gate criteria.'));
|
|
385
|
+
console.log(chalk.yellow(' Use --force to bypass the write gate.'));
|
|
386
|
+
console.log('');
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
console.log(chalk.bold('\nā Write Gate: PASSED') + chalk.dim(` (score: ${gateResult.score.toFixed(2)})`));
|
|
390
|
+
const matchedCriteria = gateResult.criteria.filter(c => c.matched);
|
|
391
|
+
if (matchedCriteria.length > 0) {
|
|
392
|
+
console.log(chalk.dim(` Matched: ${matchedCriteria.map(c => c.name).join(', ')}`));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
console.log(chalk.dim('\n Write gate bypassed (--force)'));
|
|
397
|
+
}
|
|
398
|
+
console.log(chalk.bold('\nš¾ Storing memory...\n'));
|
|
399
|
+
console.log(chalk.dim(`Content: ${content}`));
|
|
400
|
+
console.log(chalk.dim(`Tags: ${tags || 'none'}`));
|
|
401
|
+
console.log(chalk.dim(`Importance: ${importance}/10`));
|
|
402
|
+
// Load config
|
|
403
|
+
const configPath = join(cwd, '.uap.json');
|
|
404
|
+
let config;
|
|
405
|
+
if (existsSync(configPath)) {
|
|
406
|
+
try {
|
|
407
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
408
|
+
config = AgentContextConfigSchema.parse(raw);
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
config = {
|
|
412
|
+
version: '1.0.0',
|
|
413
|
+
project: { name: 'project', defaultBranch: 'main' },
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
config = {
|
|
419
|
+
version: '1.0.0',
|
|
420
|
+
project: { name: 'project', defaultBranch: 'main' },
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
// Determine memory type based on importance
|
|
424
|
+
const memoryType = importance >= 8 ? 'goal' :
|
|
425
|
+
importance >= 6 ? 'thought' :
|
|
426
|
+
tags?.includes('observation') ? 'observation' : 'action';
|
|
427
|
+
// Always write to daily log first (staging area)
|
|
428
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
429
|
+
const gateScore = force ? 1.0 : evaluateWriteGate(content).score;
|
|
430
|
+
try {
|
|
431
|
+
const dailyLog = new DailyLog(dbPath);
|
|
432
|
+
dailyLog.write(content, memoryType, gateScore);
|
|
433
|
+
dailyLog.close();
|
|
434
|
+
console.log(chalk.green('\nā Written to daily log (staging area)'));
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
console.log(chalk.yellow('Could not write to daily log:'), error);
|
|
438
|
+
}
|
|
439
|
+
// Also store in short-term memory (SQLite) for immediate availability
|
|
440
|
+
try {
|
|
441
|
+
const shortTermDb = new SQLiteShortTermMemory({
|
|
442
|
+
dbPath,
|
|
443
|
+
projectId: config.project.name,
|
|
444
|
+
maxEntries: config.memory?.shortTerm?.maxEntries || 50,
|
|
445
|
+
});
|
|
446
|
+
await shortTermDb.store(memoryType, content);
|
|
447
|
+
await shortTermDb.close();
|
|
448
|
+
console.log(chalk.green('ā Stored in short-term memory (SQLite)'));
|
|
449
|
+
console.log(chalk.dim(` Type: ${memoryType}`));
|
|
450
|
+
console.log(chalk.dim(` Path: ${dbPath}`));
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
console.log(chalk.red('Failed to store in short-term memory:'), error);
|
|
454
|
+
}
|
|
455
|
+
// Note about long-term storage
|
|
456
|
+
if (importance >= 7) {
|
|
457
|
+
console.log(chalk.dim('\nNote: High-importance memories should also be stored in long-term memory.'));
|
|
458
|
+
console.log(chalk.dim('Long-term semantic storage requires Qdrant + embedding service (not yet integrated).'));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
async function prepopulateFromSources(cwd, options) {
|
|
462
|
+
console.log(chalk.bold('\nš§ Prepopulating Memory from Project Sources\n'));
|
|
463
|
+
// Load config
|
|
464
|
+
const configPath = join(cwd, '.uap.json');
|
|
465
|
+
let config;
|
|
466
|
+
if (existsSync(configPath)) {
|
|
467
|
+
try {
|
|
468
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
469
|
+
config = AgentContextConfigSchema.parse(raw);
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
config = {
|
|
473
|
+
version: '1.0.0',
|
|
474
|
+
project: { name: 'project', defaultBranch: 'main' },
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
config = {
|
|
480
|
+
version: '1.0.0',
|
|
481
|
+
project: { name: 'project', defaultBranch: 'main' },
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
const sources = [];
|
|
485
|
+
if (options.docs)
|
|
486
|
+
sources.push('documentation');
|
|
487
|
+
if (options.git)
|
|
488
|
+
sources.push('git history');
|
|
489
|
+
if (sources.length === 0)
|
|
490
|
+
sources.push('documentation', 'git history');
|
|
491
|
+
console.log(chalk.dim(`Sources: ${sources.join(', ')}`));
|
|
492
|
+
if (options.limit)
|
|
493
|
+
console.log(chalk.dim(`Git commit limit: ${options.limit}`));
|
|
494
|
+
if (options.since)
|
|
495
|
+
console.log(chalk.dim(`Git commits since: ${options.since}`));
|
|
496
|
+
console.log('');
|
|
497
|
+
const spinner = ora('Extracting knowledge from project...').start();
|
|
498
|
+
try {
|
|
499
|
+
const { shortTerm, longTerm, skills } = await prepopulateMemory(cwd, {
|
|
500
|
+
docs: options.docs || (!options.docs && !options.git),
|
|
501
|
+
git: options.git || (!options.docs && !options.git),
|
|
502
|
+
skills: true, // Always discover skills
|
|
503
|
+
limit: options.limit ? parseInt(options.limit) : 500,
|
|
504
|
+
since: options.since,
|
|
505
|
+
verbose: options.verbose,
|
|
506
|
+
});
|
|
507
|
+
spinner.succeed(`Extracted ${shortTerm.length} short-term, ${longTerm.length} long-term memories, ${skills.length} skills/artifacts`);
|
|
508
|
+
// Store short-term memories to SQLite
|
|
509
|
+
if (shortTerm.length > 0) {
|
|
510
|
+
const stSpinner = ora('Storing short-term memories...').start();
|
|
511
|
+
try {
|
|
512
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
513
|
+
const shortTermDb = new SQLiteShortTermMemory({
|
|
514
|
+
dbPath,
|
|
515
|
+
projectId: config.project.name,
|
|
516
|
+
maxEntries: config.memory?.shortTerm?.maxEntries || 50,
|
|
517
|
+
});
|
|
518
|
+
// Store memories in batch
|
|
519
|
+
const entries = shortTerm.map(m => ({
|
|
520
|
+
type: m.type,
|
|
521
|
+
content: m.content,
|
|
522
|
+
timestamp: m.timestamp,
|
|
523
|
+
}));
|
|
524
|
+
await shortTermDb.storeBatch(entries);
|
|
525
|
+
await shortTermDb.close();
|
|
526
|
+
stSpinner.succeed(`Stored ${shortTerm.length} short-term memories to SQLite`);
|
|
527
|
+
console.log(chalk.dim(` Database: ${dbPath}`));
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
stSpinner.fail('Failed to store short-term memories');
|
|
531
|
+
console.error(chalk.red(error));
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
let sessionInserted = 0;
|
|
535
|
+
let graphStats = { entities: 0, relationships: 0 };
|
|
536
|
+
if (shortTerm.length > 0 || longTerm.length > 0) {
|
|
537
|
+
const sessionSpinner = ora('Storing session memories...').start();
|
|
538
|
+
try {
|
|
539
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
540
|
+
sessionInserted = storeSessionMemories(dbPath, config.project.name, shortTerm, longTerm);
|
|
541
|
+
sessionSpinner.succeed(`Stored ${sessionInserted} session memories`);
|
|
542
|
+
}
|
|
543
|
+
catch (error) {
|
|
544
|
+
sessionSpinner.fail('Failed to store session memories');
|
|
545
|
+
console.error(chalk.red(error));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (longTerm.length > 0 || skills.length > 0) {
|
|
549
|
+
const graphSpinner = ora('Building knowledge graph...').start();
|
|
550
|
+
try {
|
|
551
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
552
|
+
graphStats = storeKnowledgeGraph(dbPath, config.project.name, longTerm, skills);
|
|
553
|
+
graphSpinner.succeed(`Stored ${graphStats.entities} entities, ${graphStats.relationships} relationships`);
|
|
554
|
+
}
|
|
555
|
+
catch (error) {
|
|
556
|
+
graphSpinner.fail('Failed to build knowledge graph');
|
|
557
|
+
console.error(chalk.red(error));
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
// Store long-term memories (Qdrant + export)
|
|
561
|
+
if (longTerm.length > 0) {
|
|
562
|
+
console.log(chalk.dim(`\n Long-term memories ready: ${longTerm.length} entries`));
|
|
563
|
+
const ltSpinner = ora('Storing long-term memories to Qdrant...').start();
|
|
564
|
+
const ltResult = await storeLongTermToQdrant(longTerm, config);
|
|
565
|
+
if (ltResult.stored > 0) {
|
|
566
|
+
ltSpinner.succeed(`Stored ${ltResult.stored} long-term memories to ${ltResult.backend}`);
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
ltSpinner.warn(`Skipped long-term store: ${ltResult.reason || 'Qdrant not available'}`);
|
|
570
|
+
}
|
|
571
|
+
// Save long-term memories as JSON for manual import or Qdrant storage
|
|
572
|
+
const ltPath = join(cwd, 'agents/data/memory/long_term_prepopulated.json');
|
|
573
|
+
const ltDir = join(cwd, 'agents/data/memory');
|
|
574
|
+
if (!existsSync(ltDir)) {
|
|
575
|
+
mkdirSync(ltDir, { recursive: true });
|
|
576
|
+
}
|
|
577
|
+
writeFileSync(ltPath, JSON.stringify(longTerm, null, 2));
|
|
578
|
+
console.log(chalk.dim(` Exported to: ${ltPath}`));
|
|
579
|
+
}
|
|
580
|
+
// Summary by type
|
|
581
|
+
console.log(chalk.bold('\nš Memory Summary:\n'));
|
|
582
|
+
const byType = {
|
|
583
|
+
observations: longTerm.filter(m => m.type === 'observation').length,
|
|
584
|
+
thoughts: longTerm.filter(m => m.type === 'thought').length,
|
|
585
|
+
actions: longTerm.filter(m => m.type === 'action').length,
|
|
586
|
+
goals: longTerm.filter(m => m.type === 'goal').length,
|
|
587
|
+
};
|
|
588
|
+
console.log(chalk.dim(` Observations: ${byType.observations}`));
|
|
589
|
+
console.log(chalk.dim(` Thoughts: ${byType.thoughts}`));
|
|
590
|
+
console.log(chalk.dim(` Actions: ${byType.actions}`));
|
|
591
|
+
console.log(chalk.dim(` Goals: ${byType.goals}`));
|
|
592
|
+
console.log(chalk.dim(` Session memories: ${sessionInserted}`));
|
|
593
|
+
console.log(chalk.dim(` Graph entities: ${graphStats.entities}`));
|
|
594
|
+
console.log(chalk.dim(` Graph relationships: ${graphStats.relationships}`));
|
|
595
|
+
// Show sample memories
|
|
596
|
+
if (options.verbose && shortTerm.length > 0) {
|
|
597
|
+
console.log(chalk.bold('\nš Sample Memories:\n'));
|
|
598
|
+
for (const mem of shortTerm.slice(0, 3)) {
|
|
599
|
+
console.log(chalk.cyan(` [${mem.type}] `) + chalk.dim(mem.content.substring(0, 100) + '...'));
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
console.log(chalk.green('\nā
Memory prepopulation complete!\n'));
|
|
603
|
+
}
|
|
604
|
+
catch (error) {
|
|
605
|
+
spinner.fail('Failed to prepopulate memory');
|
|
606
|
+
console.error(chalk.red(error));
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function storeSessionMemories(dbPath, projectId, shortTerm, longTerm) {
|
|
610
|
+
const db = new Database(dbPath);
|
|
611
|
+
ensureSessionSchema(db);
|
|
612
|
+
const entries = [...shortTerm, ...longTerm.filter((m) => (m.importance || 0) >= 7)];
|
|
613
|
+
const unique = new Map(entries.map((m) => [m.content, m]));
|
|
614
|
+
const stmt = db.prepare(`
|
|
615
|
+
INSERT OR IGNORE INTO session_memories (session_id, timestamp, type, content, importance)
|
|
616
|
+
VALUES (?, ?, ?, ?, ?)
|
|
617
|
+
`);
|
|
618
|
+
const insertMany = db.transaction((items) => {
|
|
619
|
+
let inserted = 0;
|
|
620
|
+
for (const entry of items) {
|
|
621
|
+
inserted += stmt.run(projectId, entry.timestamp, entry.type, entry.content, entry.importance ?? 5).changes;
|
|
622
|
+
}
|
|
623
|
+
return inserted;
|
|
624
|
+
});
|
|
625
|
+
const inserted = insertMany([...unique.values()]);
|
|
626
|
+
db.close();
|
|
627
|
+
return inserted;
|
|
628
|
+
}
|
|
629
|
+
function storeKnowledgeGraph(dbPath, projectName, longTerm, skills) {
|
|
630
|
+
const db = new Database(dbPath);
|
|
631
|
+
ensureKnowledgeSchema(db);
|
|
632
|
+
const now = new Date().toISOString();
|
|
633
|
+
const projectEntity = upsertEntity(db, 'project', projectName, now);
|
|
634
|
+
let entities = projectEntity.inserted;
|
|
635
|
+
let relationships = 0;
|
|
636
|
+
const filePaths = new Set();
|
|
637
|
+
for (const entry of longTerm) {
|
|
638
|
+
const file = entry.metadata?.file;
|
|
639
|
+
if (typeof file === 'string')
|
|
640
|
+
filePaths.add(file);
|
|
641
|
+
const files = entry.metadata?.files;
|
|
642
|
+
if (Array.isArray(files)) {
|
|
643
|
+
for (const item of files) {
|
|
644
|
+
if (typeof item === 'string')
|
|
645
|
+
filePaths.add(item);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
for (const file of filePaths) {
|
|
650
|
+
const fileEntity = upsertEntity(db, 'file', file, now);
|
|
651
|
+
entities += fileEntity.inserted;
|
|
652
|
+
relationships += insertRelationship(db, projectEntity.id, fileEntity.id, 'contains', now);
|
|
653
|
+
}
|
|
654
|
+
for (const skill of skills) {
|
|
655
|
+
const skillEntity = upsertEntity(db, skill.type, skill.name, now);
|
|
656
|
+
entities += skillEntity.inserted;
|
|
657
|
+
relationships += insertRelationship(db, projectEntity.id, skillEntity.id, 'contains', now);
|
|
658
|
+
}
|
|
659
|
+
db.close();
|
|
660
|
+
return { entities, relationships };
|
|
661
|
+
}
|
|
662
|
+
function upsertEntity(db, type, name, now) {
|
|
663
|
+
const existing = db.prepare('SELECT id, mention_count FROM entities WHERE type = ? AND name = ?').get(type, name);
|
|
664
|
+
if (existing) {
|
|
665
|
+
db.prepare('UPDATE entities SET last_seen = ?, mention_count = ? WHERE id = ?').run(now, existing.mention_count + 1, existing.id);
|
|
666
|
+
return { id: existing.id, inserted: 0 };
|
|
667
|
+
}
|
|
668
|
+
const result = db.prepare('INSERT INTO entities (type, name, first_seen, last_seen, mention_count) VALUES (?, ?, ?, ?, 1)').run(type, name, now, now);
|
|
669
|
+
return { id: Number(result.lastInsertRowid), inserted: 1 };
|
|
670
|
+
}
|
|
671
|
+
function insertRelationship(db, sourceId, targetId, relation, now) {
|
|
672
|
+
const result = db.prepare('INSERT OR IGNORE INTO relationships (source_id, target_id, relation, timestamp) VALUES (?, ?, ?, ?)').run(sourceId, targetId, relation, now);
|
|
673
|
+
return result.changes;
|
|
674
|
+
}
|
|
675
|
+
function createDeterministicEmbedding(input, size = 384) {
|
|
676
|
+
const hash = createHash('sha256').update(input).digest();
|
|
677
|
+
let seed = hash.readUInt32LE(0);
|
|
678
|
+
const vector = new Array(size);
|
|
679
|
+
for (let i = 0; i < size; i += 1) {
|
|
680
|
+
seed ^= seed << 13;
|
|
681
|
+
seed ^= seed >> 17;
|
|
682
|
+
seed ^= seed << 5;
|
|
683
|
+
const normalized = (seed >>> 0) / 0xffffffff;
|
|
684
|
+
vector[i] = normalized * 2 - 1;
|
|
685
|
+
}
|
|
686
|
+
return vector;
|
|
687
|
+
}
|
|
688
|
+
function toDeterministicUuid(value) {
|
|
689
|
+
const hash = createHash('sha256').update(value).digest('hex');
|
|
690
|
+
const timeLow = hash.slice(0, 8);
|
|
691
|
+
const timeMid = hash.slice(8, 12);
|
|
692
|
+
const timeHighAndVersion = `5${hash.slice(13, 16)}`;
|
|
693
|
+
const clockSeq = ((parseInt(hash.slice(16, 18), 16) & 0x3f) | 0x80).toString(16).padStart(2, '0');
|
|
694
|
+
const clockSeqLow = hash.slice(18, 20);
|
|
695
|
+
const node = hash.slice(20, 32);
|
|
696
|
+
return `${timeLow}-${timeMid}-${timeHighAndVersion}-${clockSeq}${clockSeqLow}-${node}`;
|
|
697
|
+
}
|
|
698
|
+
async function storeLongTermToQdrant(longTerm, config) {
|
|
699
|
+
if (longTerm.length === 0) {
|
|
700
|
+
return { stored: 0, backend: 'qdrant', reason: 'No long-term entries' };
|
|
701
|
+
}
|
|
702
|
+
if (config.memory?.longTerm?.provider === 'github') {
|
|
703
|
+
return { stored: 0, backend: 'github', reason: 'Long-term provider set to github' };
|
|
704
|
+
}
|
|
705
|
+
const endpoint = config.memory?.longTerm?.endpoint || 'localhost:6333';
|
|
706
|
+
const url = endpoint.startsWith('http://') || endpoint.startsWith('https://') ? endpoint : `http://${endpoint}`;
|
|
707
|
+
const apiKey = config.memory?.longTerm?.qdrantCloud?.apiKey || process.env.QDRANT_API_KEY;
|
|
708
|
+
const collection = config.memory?.longTerm?.collection || 'agent_memory';
|
|
709
|
+
const client = new QdrantClient({ url, apiKey });
|
|
710
|
+
try {
|
|
711
|
+
await client.getCollections();
|
|
712
|
+
}
|
|
713
|
+
catch {
|
|
714
|
+
return { stored: 0, backend: 'qdrant', reason: 'Qdrant not reachable' };
|
|
715
|
+
}
|
|
716
|
+
try {
|
|
717
|
+
const collections = await client.getCollections();
|
|
718
|
+
let collectionName = collection;
|
|
719
|
+
const exists = collections.collections.some((c) => c.name === collectionName);
|
|
720
|
+
if (exists) {
|
|
721
|
+
const info = await client.getCollection(collectionName);
|
|
722
|
+
const size = info.config.params?.vectors?.size;
|
|
723
|
+
if (size && size !== 384) {
|
|
724
|
+
collectionName = `${collectionName}_prepopulated`;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
const finalExists = collections.collections.some((c) => c.name === collectionName);
|
|
728
|
+
if (!finalExists) {
|
|
729
|
+
await client.createCollection(collectionName, { vectors: { size: 384, distance: 'Cosine' } });
|
|
730
|
+
}
|
|
731
|
+
const batchSize = 64;
|
|
732
|
+
for (let i = 0; i < longTerm.length; i += batchSize) {
|
|
733
|
+
const batch = longTerm.slice(i, i + batchSize);
|
|
734
|
+
const points = batch.map((entry) => ({
|
|
735
|
+
id: toDeterministicUuid(entry.id),
|
|
736
|
+
vector: createDeterministicEmbedding(`${entry.content} ${entry.tags?.join(' ') || ''}`),
|
|
737
|
+
payload: {
|
|
738
|
+
timestamp: entry.timestamp,
|
|
739
|
+
type: entry.type,
|
|
740
|
+
content: entry.content,
|
|
741
|
+
tags: entry.tags,
|
|
742
|
+
importance: entry.importance,
|
|
743
|
+
...entry.metadata,
|
|
744
|
+
},
|
|
745
|
+
}));
|
|
746
|
+
await client.upsert(collectionName, { points });
|
|
747
|
+
}
|
|
748
|
+
return { stored: longTerm.length, backend: `qdrant (${url}, ${collectionName})` };
|
|
749
|
+
}
|
|
750
|
+
catch (error) {
|
|
751
|
+
return { stored: 0, backend: `qdrant (${url})`, reason: error instanceof Error ? error.message : 'Qdrant error' };
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
async function promoteFromDailyLog(cwd, _options) {
|
|
755
|
+
console.log(chalk.bold('\nš Daily Log Promotion Review\n'));
|
|
756
|
+
const configPath = join(cwd, '.uap.json');
|
|
757
|
+
let config;
|
|
758
|
+
try {
|
|
759
|
+
config = existsSync(configPath)
|
|
760
|
+
? AgentContextConfigSchema.parse(JSON.parse(readFileSync(configPath, 'utf-8')))
|
|
761
|
+
: { version: '1.0.0', project: { name: 'project', defaultBranch: 'main' } };
|
|
762
|
+
}
|
|
763
|
+
catch {
|
|
764
|
+
config = { version: '1.0.0', project: { name: 'project', defaultBranch: 'main' } };
|
|
765
|
+
}
|
|
766
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
767
|
+
try {
|
|
768
|
+
const dailyLog = new DailyLog(dbPath);
|
|
769
|
+
const candidates = dailyLog.getPromotionCandidates();
|
|
770
|
+
if (candidates.length === 0) {
|
|
771
|
+
console.log(chalk.dim(' No candidates for promotion. All entries are either already promoted or below threshold.'));
|
|
772
|
+
dailyLog.close();
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
console.log(chalk.dim(` Found ${candidates.length} candidates for promotion:\n`));
|
|
776
|
+
const shortTermDb = new SQLiteShortTermMemory({
|
|
777
|
+
dbPath,
|
|
778
|
+
projectId: config.project.name,
|
|
779
|
+
maxEntries: config.memory?.shortTerm?.maxEntries || 50,
|
|
780
|
+
});
|
|
781
|
+
let promoted = 0;
|
|
782
|
+
for (const candidate of candidates) {
|
|
783
|
+
const { entry, suggestedTier, reason } = candidate;
|
|
784
|
+
console.log(` ${chalk.cyan(`[${entry.date}]`)} ${entry.content.slice(0, 100)}${entry.content.length > 100 ? '...' : ''}`);
|
|
785
|
+
console.log(chalk.dim(` ā ${suggestedTier} (score: ${entry.gateScore.toFixed(2)}) - ${reason}`));
|
|
786
|
+
// Auto-promote based on score
|
|
787
|
+
if (suggestedTier === 'working') {
|
|
788
|
+
const memType = entry.type === 'goal' || entry.type === 'action' || entry.type === 'observation' || entry.type === 'thought'
|
|
789
|
+
? entry.type
|
|
790
|
+
: 'observation';
|
|
791
|
+
await shortTermDb.store(memType, entry.content, Math.round(entry.gateScore * 10));
|
|
792
|
+
dailyLog.markPromoted(entry.id, 'working');
|
|
793
|
+
promoted++;
|
|
794
|
+
console.log(chalk.green(` ā Promoted to working memory`));
|
|
795
|
+
}
|
|
796
|
+
else {
|
|
797
|
+
dailyLog.markPromoted(entry.id, 'semantic');
|
|
798
|
+
promoted++;
|
|
799
|
+
console.log(chalk.green(` ā Marked for semantic storage`));
|
|
800
|
+
}
|
|
801
|
+
console.log('');
|
|
802
|
+
}
|
|
803
|
+
await shortTermDb.close();
|
|
804
|
+
dailyLog.close();
|
|
805
|
+
console.log(chalk.bold.green(`\n Promoted ${promoted} entries.\n`));
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
console.log(chalk.red('Failed to promote:'), error);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
async function correctMemory(cwd, options) {
|
|
812
|
+
console.log(chalk.bold('\nš Correction Propagation\n'));
|
|
813
|
+
if (!options.search || !options.correction) {
|
|
814
|
+
console.log(chalk.red(' Usage: uap memory correct <search> --correction <corrected> [--reason <reason>]'));
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const configPath = join(cwd, '.uap.json');
|
|
818
|
+
let config;
|
|
819
|
+
try {
|
|
820
|
+
config = existsSync(configPath)
|
|
821
|
+
? AgentContextConfigSchema.parse(JSON.parse(readFileSync(configPath, 'utf-8')))
|
|
822
|
+
: { version: '1.0.0', project: { name: 'project', defaultBranch: 'main' } };
|
|
823
|
+
}
|
|
824
|
+
catch {
|
|
825
|
+
config = { version: '1.0.0', project: { name: 'project', defaultBranch: 'main' } };
|
|
826
|
+
}
|
|
827
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
828
|
+
const result = propagateCorrection(dbPath, options.search, options.correction, options.reason || 'user correction');
|
|
829
|
+
if (result.originalFound) {
|
|
830
|
+
console.log(chalk.green(` ā Found and corrected across ${result.tiersUpdated.length} tiers`));
|
|
831
|
+
console.log(chalk.dim(` Tiers updated: ${result.tiersUpdated.join(', ')}`));
|
|
832
|
+
console.log(chalk.dim(` Superseded entries: ${result.supersededCount}`));
|
|
833
|
+
if (result.originalContent) {
|
|
834
|
+
console.log(chalk.dim(` Original: ${result.originalContent.slice(0, 100)}...`));
|
|
835
|
+
}
|
|
836
|
+
console.log(chalk.dim(` Corrected: ${options.correction}`));
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
839
|
+
console.log(chalk.yellow(` No matching entries found for: "${options.search}"`));
|
|
840
|
+
console.log(chalk.dim(' The correction was still logged to the daily log for reference.'));
|
|
841
|
+
}
|
|
842
|
+
console.log('');
|
|
843
|
+
}
|
|
844
|
+
async function maintainMemory(cwd, _options) {
|
|
845
|
+
console.log(chalk.bold('\nš§ Memory Maintenance\n'));
|
|
846
|
+
const configPath = join(cwd, '.uap.json');
|
|
847
|
+
let config;
|
|
848
|
+
try {
|
|
849
|
+
config = existsSync(configPath)
|
|
850
|
+
? AgentContextConfigSchema.parse(JSON.parse(readFileSync(configPath, 'utf-8')))
|
|
851
|
+
: { version: '1.0.0', project: { name: 'project', defaultBranch: 'main' } };
|
|
852
|
+
}
|
|
853
|
+
catch {
|
|
854
|
+
config = { version: '1.0.0', project: { name: 'project', defaultBranch: 'main' } };
|
|
855
|
+
}
|
|
856
|
+
const dbPath = config.memory?.shortTerm?.path || join(cwd, 'agents/data/memory/short_term.db');
|
|
857
|
+
const spinner = ora('Running maintenance cycle...').start();
|
|
858
|
+
const result = runMaintenance(dbPath);
|
|
859
|
+
spinner.succeed('Maintenance complete');
|
|
860
|
+
console.log('');
|
|
861
|
+
console.log(chalk.dim(` Decayed entries updated: ${result.decayedEntriesUpdated}`));
|
|
862
|
+
console.log(chalk.dim(` Stale entries pruned: ${result.staleEntriesPruned}`));
|
|
863
|
+
console.log(chalk.dim(` Daily logs archived: ${result.dailyLogsArchived}`));
|
|
864
|
+
console.log(chalk.dim(` Duplicates removed: ${result.duplicatesRemoved}`));
|
|
865
|
+
if (result.staleWorktrees.length > 0) {
|
|
866
|
+
console.log(chalk.yellow(` Stale worktrees: ${result.staleWorktrees.length}`));
|
|
867
|
+
}
|
|
868
|
+
console.log('');
|
|
869
|
+
if (result.recommendations.length > 0) {
|
|
870
|
+
console.log(chalk.bold(' Recommendations:'));
|
|
871
|
+
for (const rec of result.recommendations) {
|
|
872
|
+
console.log(` ${chalk.yellow('ā¢')} ${rec}`);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
console.log('');
|
|
876
|
+
}
|
|
877
|
+
//# sourceMappingURL=memory.js.map
|