tachibot-mcp 2.0.2
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/.env.example +260 -0
- package/CHANGELOG.md +54 -0
- package/CODE_OF_CONDUCT.md +56 -0
- package/CONTRIBUTING.md +54 -0
- package/Dockerfile +36 -0
- package/LICENSE +644 -0
- package/README.md +201 -0
- package/SECURITY.md +95 -0
- package/dist/personality/komaai-expressions.js +12 -0
- package/dist/profiles/balanced.json +33 -0
- package/dist/profiles/code_focus.json +33 -0
- package/dist/profiles/full.json +33 -0
- package/dist/profiles/minimal.json +33 -0
- package/dist/profiles/research_power.json +33 -0
- package/dist/scripts/build-profiles.js +46 -0
- package/dist/src/application/services/focus/FocusModeRegistry.js +46 -0
- package/dist/src/application/services/focus/FocusTool.service.js +109 -0
- package/dist/src/application/services/focus/ModeRegistry.js +46 -0
- package/dist/src/application/services/focus/modes/focus-deep.mode.js +27 -0
- package/dist/src/application/services/focus/modes/status.mode.js +50 -0
- package/dist/src/application/services/focus/modes/tachibot-status.mode.js +50 -0
- package/dist/src/collaborative-orchestrator.js +391 -0
- package/dist/src/config/model-constants.js +188 -0
- package/dist/src/config/model-defaults.js +57 -0
- package/dist/src/config/model-preferences.js +382 -0
- package/dist/src/config/timeout-config.js +130 -0
- package/dist/src/config.js +173 -0
- package/dist/src/domain/interfaces/IFocusMode.js +5 -0
- package/dist/src/domain/interfaces/IProvider.js +6 -0
- package/dist/src/domain/interfaces/ITool.js +5 -0
- package/dist/src/focus-deep.js +245 -0
- package/dist/src/infrastructure/ascii/art/robots.ascii.js +16 -0
- package/dist/src/mcp-client.js +90 -0
- package/dist/src/memory/index.js +17 -0
- package/dist/src/memory/memory-config.js +135 -0
- package/dist/src/memory/memory-interface.js +174 -0
- package/dist/src/memory/memory-manager.js +383 -0
- package/dist/src/memory/providers/devlog-provider.js +385 -0
- package/dist/src/memory/providers/hybrid-provider.js +399 -0
- package/dist/src/memory/providers/local-provider.js +388 -0
- package/dist/src/memory/providers/mem0-provider.js +337 -0
- package/dist/src/modes/architect.js +477 -0
- package/dist/src/modes/auditor.js +362 -0
- package/dist/src/modes/challenger.js +841 -0
- package/dist/src/modes/code-reviewer.js +382 -0
- package/dist/src/modes/commit-guardian.js +424 -0
- package/dist/src/modes/documentation-writer.js +572 -0
- package/dist/src/modes/scout.js +587 -0
- package/dist/src/modes/shared/helpers/challenger-helpers.js +454 -0
- package/dist/src/modes/shared/helpers/index.js +17 -0
- package/dist/src/modes/shared/helpers/scout-helpers.js +270 -0
- package/dist/src/modes/shared/helpers/verifier-helpers.js +332 -0
- package/dist/src/modes/test-architect.js +767 -0
- package/dist/src/modes/verifier.js +378 -0
- package/dist/src/monitoring/performance-monitor.js +435 -0
- package/dist/src/optimization/batch-executor.js +121 -0
- package/dist/src/optimization/context-pruner.js +196 -0
- package/dist/src/optimization/cost-monitor.js +338 -0
- package/dist/src/optimization/index.js +65 -0
- package/dist/src/optimization/model-router.js +264 -0
- package/dist/src/optimization/result-cache.js +114 -0
- package/dist/src/optimization/token-optimizer.js +257 -0
- package/dist/src/optimization/token-tracker.js +118 -0
- package/dist/src/orchestrator-instructions.js +128 -0
- package/dist/src/orchestrator-lite.js +139 -0
- package/dist/src/orchestrator.js +191 -0
- package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionEngine.js +1 -0
- package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionStrategy.js +5 -0
- package/dist/src/orchestrators/collaborative/interfaces/IVisualizationRenderer.js +1 -0
- package/dist/src/orchestrators/collaborative/registries/ModelProviderRegistry.js +95 -0
- package/dist/src/orchestrators/collaborative/registries/ToolAdapterRegistry.js +64 -0
- package/dist/src/orchestrators/collaborative/services/tool-execution/ToolExecutionService.js +502 -0
- package/dist/src/orchestrators/collaborative/services/visualization/VisualizationService.js +206 -0
- package/dist/src/orchestrators/collaborative/types/session-types.js +5 -0
- package/dist/src/profiles/balanced.js +37 -0
- package/dist/src/profiles/code_focus.js +37 -0
- package/dist/src/profiles/debug_intensive.js +59 -0
- package/dist/src/profiles/full.js +37 -0
- package/dist/src/profiles/minimal.js +37 -0
- package/dist/src/profiles/research_code.js +59 -0
- package/dist/src/profiles/research_power.js +37 -0
- package/dist/src/profiles/types.js +5 -0
- package/dist/src/profiles/workflow_builder.js +53 -0
- package/dist/src/prompt-engineer-lite.js +78 -0
- package/dist/src/prompt-engineer.js +399 -0
- package/dist/src/reasoning-chain.js +508 -0
- package/dist/src/sequential-thinking.js +291 -0
- package/dist/src/server-diagnostic.js +74 -0
- package/dist/src/server-raw.js +158 -0
- package/dist/src/server-simple.js +58 -0
- package/dist/src/server.js +514 -0
- package/dist/src/session/session-logger.js +617 -0
- package/dist/src/session/session-manager.js +571 -0
- package/dist/src/session/session-tools.js +400 -0
- package/dist/src/tools/advanced-modes.js +200 -0
- package/dist/src/tools/claude-integration.js +356 -0
- package/dist/src/tools/consolidated/ai-router.js +174 -0
- package/dist/src/tools/consolidated/ai-tool.js +48 -0
- package/dist/src/tools/consolidated/brainstorm-tool.js +87 -0
- package/dist/src/tools/consolidated/environment-detector.js +80 -0
- package/dist/src/tools/consolidated/index.js +50 -0
- package/dist/src/tools/consolidated/search-tool.js +110 -0
- package/dist/src/tools/consolidated/workflow-tool.js +238 -0
- package/dist/src/tools/gemini-tools.js +329 -0
- package/dist/src/tools/grok-enhanced.js +376 -0
- package/dist/src/tools/grok-tools.js +299 -0
- package/dist/src/tools/lmstudio-tools.js +223 -0
- package/dist/src/tools/openai-tools.js +498 -0
- package/dist/src/tools/openrouter-tools.js +317 -0
- package/dist/src/tools/optimized-wrapper.js +204 -0
- package/dist/src/tools/perplexity-tools.js +294 -0
- package/dist/src/tools/pingpong-tool.js +343 -0
- package/dist/src/tools/qwen-wrapper.js +74 -0
- package/dist/src/tools/tool-router.js +444 -0
- package/dist/src/tools/unified-ai-provider.js +260 -0
- package/dist/src/tools/workflow-runner.js +425 -0
- package/dist/src/tools/workflow-validator-tool.js +107 -0
- package/dist/src/types.js +23 -0
- package/dist/src/utils/input-validator.js +130 -0
- package/dist/src/utils/model-router.js +91 -0
- package/dist/src/utils/progress-stream.js +255 -0
- package/dist/src/utils/provider-router.js +88 -0
- package/dist/src/utils/smart-api-client.js +146 -0
- package/dist/src/utils/table-builder.js +218 -0
- package/dist/src/utils/timestamp-formatter.js +134 -0
- package/dist/src/utils/tool-compressor.js +257 -0
- package/dist/src/utils/tool-config.js +201 -0
- package/dist/src/validators/dependency-graph-validator.js +147 -0
- package/dist/src/validators/interpolation-validator.js +222 -0
- package/dist/src/validators/output-usage-validator.js +151 -0
- package/dist/src/validators/syntax-validator.js +102 -0
- package/dist/src/validators/tool-registry-validator.js +123 -0
- package/dist/src/validators/tool-types.js +97 -0
- package/dist/src/validators/types.js +8 -0
- package/dist/src/validators/workflow-validator.js +134 -0
- package/dist/src/visualizer-lite.js +42 -0
- package/dist/src/visualizer.js +179 -0
- package/dist/src/workflows/circuit-breaker.js +199 -0
- package/dist/src/workflows/custom-workflows.js +451 -0
- package/dist/src/workflows/engine/AutoSynthesizer.js +97 -0
- package/dist/src/workflows/engine/StepParameterResolver.js +74 -0
- package/dist/src/workflows/engine/VariableInterpolator.js +123 -0
- package/dist/src/workflows/engine/WorkflowDiscovery.js +125 -0
- package/dist/src/workflows/engine/WorkflowExecutionEngine.js +485 -0
- package/dist/src/workflows/engine/WorkflowExecutor.js +113 -0
- package/dist/src/workflows/engine/WorkflowFileManager.js +244 -0
- package/dist/src/workflows/engine/WorkflowHelpers.js +114 -0
- package/dist/src/workflows/engine/WorkflowOutputFormatter.js +83 -0
- package/dist/src/workflows/engine/events/WorkflowEventBus.js +132 -0
- package/dist/src/workflows/engine/events/interfaces/IEventBus.js +5 -0
- package/dist/src/workflows/engine/handlers/ErrorRecoveryHandler.js +162 -0
- package/dist/src/workflows/engine/handlers/PromptEnhancementHandler.js +115 -0
- package/dist/src/workflows/engine/handlers/SessionPersistenceHandler.js +167 -0
- package/dist/src/workflows/engine/handlers/StepExecutionHandler.js +231 -0
- package/dist/src/workflows/engine/handlers/ToolInvocationHandler.js +46 -0
- package/dist/src/workflows/engine/interfaces/IAutoSynthesizer.js +5 -0
- package/dist/src/workflows/engine/interfaces/IStepParameterResolver.js +5 -0
- package/dist/src/workflows/engine/interfaces/IVariableInterpolator.js +5 -0
- package/dist/src/workflows/engine/interfaces/IWorkflowDiscovery.js +4 -0
- package/dist/src/workflows/engine/interfaces/IWorkflowFileManager.js +5 -0
- package/dist/src/workflows/engine/interfaces/IWorkflowOutputFormatter.js +5 -0
- package/dist/src/workflows/engine/state/WorkflowStateMachine.js +194 -0
- package/dist/src/workflows/engine/state/interfaces/IStateMachine.js +17 -0
- package/dist/src/workflows/fallback-strategies.js +373 -0
- package/dist/src/workflows/message-queue.js +455 -0
- package/dist/src/workflows/model-router.js +189 -0
- package/dist/src/workflows/orchestrator-examples.js +174 -0
- package/dist/src/workflows/orchestrator-integration.js +200 -0
- package/dist/src/workflows/self-healing.js +524 -0
- package/dist/src/workflows/tool-mapper.js +407 -0
- package/dist/src/workflows/tool-orchestrator.js +796 -0
- package/dist/src/workflows/workflow-engine.js +573 -0
- package/dist/src/workflows/workflow-parser.js +283 -0
- package/dist/src/workflows/workflow-types.js +95 -0
- package/dist/src/workflows.js +568 -0
- package/dist/test-workflow-file-output.js +93 -0
- package/docs/API_KEYS.md +570 -0
- package/docs/CLAUDE_CODE_SETUP.md +181 -0
- package/docs/CLAUDE_DESKTOP_MANUAL.md +127 -0
- package/docs/CONFIGURATION.md +745 -0
- package/docs/FOCUS_MODES.md +240 -0
- package/docs/INSTALLATION_BOTH.md +145 -0
- package/docs/TERMS.md +352 -0
- package/docs/TOOLS_REFERENCE.md +1622 -0
- package/docs/TOOL_PARAMETERS.md +496 -0
- package/docs/TOOL_PROFILES.md +236 -0
- package/docs/WORKFLOWS.md +987 -0
- package/docs/WORKFLOW_OUTPUT.md +198 -0
- package/docs/WORKFLOW_PROGRESS_TRACKING.md +305 -0
- package/docs/workflows/design-brainstorm.md +335 -0
- package/package.json +97 -0
- package/profiles/balanced.json +37 -0
- package/profiles/code_focus.json +37 -0
- package/profiles/debug_intensive.json +34 -0
- package/profiles/full.json +37 -0
- package/profiles/minimal.json +37 -0
- package/profiles/research_power.json +37 -0
- package/profiles/workflow_builder.json +37 -0
- package/smithery.yaml +66 -0
- package/start.sh +8 -0
- package/tools.config.json +81 -0
- package/tsconfig.json +18 -0
- package/workflows/accessibility-code-audit.yaml +92 -0
- package/workflows/code-architecture-review.yaml +202 -0
- package/workflows/code-review.yaml +142 -0
- package/workflows/core/iterative-problem-solver.yaml +283 -0
- package/workflows/creative-brainstorm-yaml.yaml +215 -0
- package/workflows/pingpong.yaml +141 -0
- package/workflows/system/README.md +412 -0
- package/workflows/system/challenger.yaml +175 -0
- package/workflows/system/scout.yaml +164 -0
- package/workflows/system/verifier.yaml +133 -0
- package/workflows/ultra-creative-brainstorm.yaml +318 -0
- package/workflows/ux-research-flow.yaml +92 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory System Module
|
|
3
|
+
* Exports all memory-related components
|
|
4
|
+
*/
|
|
5
|
+
// Core exports
|
|
6
|
+
export * from './memory-config.js';
|
|
7
|
+
export * from './memory-interface.js';
|
|
8
|
+
export * from './memory-manager.js';
|
|
9
|
+
// Provider exports
|
|
10
|
+
export * from './providers/local-provider.js';
|
|
11
|
+
export * from './providers/mem0-provider.js';
|
|
12
|
+
// export * from './providers/devlog-provider.js';
|
|
13
|
+
// export * from './providers/hybrid-provider.js';
|
|
14
|
+
// Main API
|
|
15
|
+
export { getMemoryManager, resetMemoryManager, HierarchicalMemoryManager } from './memory-manager.js';
|
|
16
|
+
export { DEFAULT_MEMORY_CONFIG, loadMemoryConfigFromEnv, mergeMemoryConfig, validateMemoryConfig } from './memory-config.js';
|
|
17
|
+
export { BaseMemoryProvider } from './memory-interface.js';
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Configuration System
|
|
3
|
+
* Flexible memory backend configuration with support for mem0, DevLog, local, and hybrid modes
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Default configuration
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_MEMORY_CONFIG = {
|
|
9
|
+
provider: 'local',
|
|
10
|
+
local: {
|
|
11
|
+
storageType: 'json',
|
|
12
|
+
path: './.focus-memory',
|
|
13
|
+
maxSizeMB: 100,
|
|
14
|
+
enableCompression: true
|
|
15
|
+
},
|
|
16
|
+
tiers: {
|
|
17
|
+
session: true,
|
|
18
|
+
working: true,
|
|
19
|
+
project: true,
|
|
20
|
+
team: false,
|
|
21
|
+
global: false
|
|
22
|
+
},
|
|
23
|
+
maxMemoryItems: 10000,
|
|
24
|
+
ttlMinutes: {
|
|
25
|
+
session: 30,
|
|
26
|
+
working: 120,
|
|
27
|
+
project: 43200, // 30 days
|
|
28
|
+
team: 129600, // 90 days
|
|
29
|
+
global: -1 // Never expires
|
|
30
|
+
},
|
|
31
|
+
enableAutoCleanup: true,
|
|
32
|
+
enableMetrics: false
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Load configuration from environment variables
|
|
36
|
+
*/
|
|
37
|
+
export function loadMemoryConfigFromEnv() {
|
|
38
|
+
const config = {};
|
|
39
|
+
// Provider selection
|
|
40
|
+
const provider = process.env.MEMORY_PROVIDER;
|
|
41
|
+
if (provider) {
|
|
42
|
+
config.provider = provider;
|
|
43
|
+
}
|
|
44
|
+
// Mem0 configuration
|
|
45
|
+
if (process.env.MEM0_API_KEY) {
|
|
46
|
+
config.mem0 = {
|
|
47
|
+
apiKey: process.env.MEM0_API_KEY,
|
|
48
|
+
endpoint: process.env.MEM0_ENDPOINT,
|
|
49
|
+
userId: process.env.MEM0_USER_ID,
|
|
50
|
+
enableVectorSearch: process.env.MEM0_ENABLE_VECTOR !== 'false',
|
|
51
|
+
enableGraphMemory: process.env.MEM0_ENABLE_GRAPH !== 'false'
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// DevLog configuration
|
|
55
|
+
if (process.env.DEVLOG_CONNECTION) {
|
|
56
|
+
config.devlog = {
|
|
57
|
+
connectionString: process.env.DEVLOG_CONNECTION,
|
|
58
|
+
workspace: process.env.DEVLOG_WORKSPACE,
|
|
59
|
+
projectId: process.env.DEVLOG_PROJECT,
|
|
60
|
+
enableSync: process.env.DEVLOG_SYNC !== 'false'
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Local storage configuration
|
|
64
|
+
if (process.env.LOCAL_STORAGE_PATH) {
|
|
65
|
+
config.local = {
|
|
66
|
+
storageType: process.env.LOCAL_STORAGE_TYPE || 'json',
|
|
67
|
+
path: process.env.LOCAL_STORAGE_PATH,
|
|
68
|
+
maxSizeMB: parseInt(process.env.LOCAL_STORAGE_MAX_MB || '100'),
|
|
69
|
+
enableCompression: process.env.LOCAL_STORAGE_COMPRESS !== 'false'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Tier configuration
|
|
73
|
+
config.tiers = {
|
|
74
|
+
session: process.env.ENABLE_SESSION_MEMORY !== 'false',
|
|
75
|
+
working: process.env.ENABLE_WORKING_MEMORY !== 'false',
|
|
76
|
+
project: process.env.ENABLE_PROJECT_MEMORY !== 'false',
|
|
77
|
+
team: process.env.ENABLE_TEAM_MEMORY === 'true',
|
|
78
|
+
global: process.env.ENABLE_GLOBAL_MEMORY === 'true'
|
|
79
|
+
};
|
|
80
|
+
return config;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Merge configurations with defaults
|
|
84
|
+
*/
|
|
85
|
+
export function mergeMemoryConfig(userConfig, envConfig = loadMemoryConfigFromEnv()) {
|
|
86
|
+
// Priority: userConfig > envConfig > DEFAULT_MEMORY_CONFIG
|
|
87
|
+
return {
|
|
88
|
+
...DEFAULT_MEMORY_CONFIG,
|
|
89
|
+
...envConfig,
|
|
90
|
+
...userConfig,
|
|
91
|
+
tiers: {
|
|
92
|
+
...DEFAULT_MEMORY_CONFIG.tiers,
|
|
93
|
+
...(envConfig.tiers || {}),
|
|
94
|
+
...(userConfig.tiers || {})
|
|
95
|
+
},
|
|
96
|
+
ttlMinutes: {
|
|
97
|
+
...DEFAULT_MEMORY_CONFIG.ttlMinutes,
|
|
98
|
+
...(envConfig.ttlMinutes || {}),
|
|
99
|
+
...(userConfig.ttlMinutes || {})
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Validate memory configuration
|
|
105
|
+
*/
|
|
106
|
+
export function validateMemoryConfig(config) {
|
|
107
|
+
const errors = [];
|
|
108
|
+
// Validate provider-specific requirements
|
|
109
|
+
if (config.provider === 'mem0' && !config.mem0?.apiKey && !process.env.MEM0_API_KEY) {
|
|
110
|
+
errors.push('Mem0 provider requires API key (MEM0_API_KEY or config.mem0.apiKey)');
|
|
111
|
+
}
|
|
112
|
+
if (config.provider === 'devlog' && !config.devlog?.connectionString && !process.env.DEVLOG_CONNECTION) {
|
|
113
|
+
errors.push('DevLog provider requires connection string');
|
|
114
|
+
}
|
|
115
|
+
if (config.provider === 'local' && !config.local?.path) {
|
|
116
|
+
errors.push('Local provider requires storage path');
|
|
117
|
+
}
|
|
118
|
+
if (config.provider === 'hybrid') {
|
|
119
|
+
if (!config.hybrid?.primary || !config.hybrid?.fallback) {
|
|
120
|
+
errors.push('Hybrid provider requires both primary and fallback providers');
|
|
121
|
+
}
|
|
122
|
+
if (config.hybrid?.primary === config.hybrid?.fallback) {
|
|
123
|
+
errors.push('Hybrid primary and fallback must be different');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Validate at least one tier is enabled
|
|
127
|
+
const tiersEnabled = Object.values(config.tiers).some(v => v);
|
|
128
|
+
if (!tiersEnabled && config.provider !== 'none') {
|
|
129
|
+
errors.push('At least one memory tier must be enabled');
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
valid: errors.length === 0,
|
|
133
|
+
errors
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Provider Interface
|
|
3
|
+
* Common interface for all memory providers (mem0, DevLog, local, etc.)
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Abstract base class for memory providers with common functionality
|
|
7
|
+
*/
|
|
8
|
+
export class BaseMemoryProvider {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.initialized = false;
|
|
11
|
+
this.metrics = {
|
|
12
|
+
totalItems: 0,
|
|
13
|
+
itemsByTier: {
|
|
14
|
+
session: 0,
|
|
15
|
+
working: 0,
|
|
16
|
+
project: 0,
|
|
17
|
+
team: 0,
|
|
18
|
+
global: 0
|
|
19
|
+
},
|
|
20
|
+
totalTokens: 0,
|
|
21
|
+
avgRetrievalTime: 0,
|
|
22
|
+
hitRate: 0,
|
|
23
|
+
storageUsedMB: 0
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async initialize() {
|
|
27
|
+
if (this.initialized)
|
|
28
|
+
return;
|
|
29
|
+
await this.doInitialize();
|
|
30
|
+
this.initialized = true;
|
|
31
|
+
}
|
|
32
|
+
async storeBatch(items) {
|
|
33
|
+
const ids = [];
|
|
34
|
+
for (const item of items) {
|
|
35
|
+
const id = await this.store(item);
|
|
36
|
+
ids.push(id);
|
|
37
|
+
}
|
|
38
|
+
return ids;
|
|
39
|
+
}
|
|
40
|
+
async retrieveContext(query) {
|
|
41
|
+
// Default implementation - can be overridden
|
|
42
|
+
const items = await this.retrieve(query);
|
|
43
|
+
// Apply priority weights if specified
|
|
44
|
+
if (query.priorityWeights) {
|
|
45
|
+
items.sort((a, b) => {
|
|
46
|
+
const scoreA = this.calculatePriorityScore(a, query.priorityWeights);
|
|
47
|
+
const scoreB = this.calculatePriorityScore(b, query.priorityWeights);
|
|
48
|
+
return scoreB - scoreA;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Limit by context window if specified
|
|
52
|
+
let selectedItems = items;
|
|
53
|
+
if (query.contextWindow) {
|
|
54
|
+
selectedItems = this.limitByTokens(items, query.contextWindow);
|
|
55
|
+
}
|
|
56
|
+
// Calculate source distribution
|
|
57
|
+
const sources = {
|
|
58
|
+
session: 0,
|
|
59
|
+
working: 0,
|
|
60
|
+
project: 0,
|
|
61
|
+
team: 0,
|
|
62
|
+
global: 0
|
|
63
|
+
};
|
|
64
|
+
selectedItems.forEach(item => {
|
|
65
|
+
sources[item.tier]++;
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
items: selectedItems,
|
|
69
|
+
synthesis: this.synthesizeItems(selectedItems),
|
|
70
|
+
relevanceScore: this.calculateRelevanceScore(selectedItems, query),
|
|
71
|
+
tokenCount: this.estimateTokenCount(selectedItems),
|
|
72
|
+
sources
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async deleteMany(query) {
|
|
76
|
+
const items = await this.retrieve(query);
|
|
77
|
+
let deleted = 0;
|
|
78
|
+
for (const item of items) {
|
|
79
|
+
if (await this.delete(item.id)) {
|
|
80
|
+
deleted++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return deleted;
|
|
84
|
+
}
|
|
85
|
+
async cleanup() {
|
|
86
|
+
// Default implementation - remove expired items
|
|
87
|
+
const now = new Date();
|
|
88
|
+
let cleaned = 0;
|
|
89
|
+
// This would need to be implemented based on storage backend
|
|
90
|
+
// For now, return 0
|
|
91
|
+
return cleaned;
|
|
92
|
+
}
|
|
93
|
+
async getMetrics() {
|
|
94
|
+
return { ...this.metrics };
|
|
95
|
+
}
|
|
96
|
+
async isAvailable() {
|
|
97
|
+
return this.initialized;
|
|
98
|
+
}
|
|
99
|
+
async close() {
|
|
100
|
+
this.initialized = false;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Helper methods
|
|
104
|
+
*/
|
|
105
|
+
calculatePriorityScore(item, weights) {
|
|
106
|
+
const now = Date.now();
|
|
107
|
+
const age = now - item.timestamp.getTime();
|
|
108
|
+
const recencyScore = Math.exp(-age / (1000 * 60 * 60 * 24)); // Decay over days
|
|
109
|
+
const frequencyScore = Math.min(1, (item.accessCount || 0) / 10);
|
|
110
|
+
// Relevance would need to be calculated based on query
|
|
111
|
+
const relevanceScore = 0.5; // Default middle value
|
|
112
|
+
return (weights.recency * recencyScore +
|
|
113
|
+
weights.relevance * relevanceScore +
|
|
114
|
+
weights.frequency * frequencyScore);
|
|
115
|
+
}
|
|
116
|
+
limitByTokens(items, maxTokens) {
|
|
117
|
+
const selected = [];
|
|
118
|
+
let totalTokens = 0;
|
|
119
|
+
for (const item of items) {
|
|
120
|
+
const itemTokens = this.estimateTokens(item.content);
|
|
121
|
+
if (totalTokens + itemTokens <= maxTokens) {
|
|
122
|
+
selected.push(item);
|
|
123
|
+
totalTokens += itemTokens;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return selected;
|
|
130
|
+
}
|
|
131
|
+
synthesizeItems(items) {
|
|
132
|
+
if (items.length === 0)
|
|
133
|
+
return '';
|
|
134
|
+
// Group by tier
|
|
135
|
+
const byTier = {
|
|
136
|
+
session: [],
|
|
137
|
+
working: [],
|
|
138
|
+
project: [],
|
|
139
|
+
team: [],
|
|
140
|
+
global: []
|
|
141
|
+
};
|
|
142
|
+
items.forEach(item => {
|
|
143
|
+
byTier[item.tier].push(item);
|
|
144
|
+
});
|
|
145
|
+
// Create synthesis
|
|
146
|
+
const parts = [];
|
|
147
|
+
if (byTier.session.length > 0) {
|
|
148
|
+
parts.push(`Recent context: ${byTier.session.map(i => i.content).join('; ')}`);
|
|
149
|
+
}
|
|
150
|
+
if (byTier.project.length > 0) {
|
|
151
|
+
parts.push(`Project context: ${byTier.project.map(i => i.content).join('; ')}`);
|
|
152
|
+
}
|
|
153
|
+
return parts.join('\n');
|
|
154
|
+
}
|
|
155
|
+
calculateRelevanceScore(items, query) {
|
|
156
|
+
if (items.length === 0)
|
|
157
|
+
return 0;
|
|
158
|
+
// Simple implementation - can be enhanced
|
|
159
|
+
return Math.min(1, items.length / 10);
|
|
160
|
+
}
|
|
161
|
+
estimateTokenCount(items) {
|
|
162
|
+
return items.reduce((sum, item) => sum + this.estimateTokens(item.content), 0);
|
|
163
|
+
}
|
|
164
|
+
estimateTokens(text) {
|
|
165
|
+
// Rough estimate: 1 token ≈ 4 characters
|
|
166
|
+
return Math.ceil(text.length / 4);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Generate unique ID
|
|
170
|
+
*/
|
|
171
|
+
generateId() {
|
|
172
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hierarchical Memory Manager
|
|
3
|
+
* Orchestrates multiple memory providers and manages tier-based memory hierarchy
|
|
4
|
+
*/
|
|
5
|
+
import { mergeMemoryConfig, validateMemoryConfig } from './memory-config.js';
|
|
6
|
+
import { LocalProvider } from './providers/local-provider.js';
|
|
7
|
+
import { Mem0Provider } from './providers/mem0-provider.js';
|
|
8
|
+
// import { DevLogProvider } from './providers/devlog-provider.js';
|
|
9
|
+
// import { HybridProvider } from './providers/hybrid-provider.js';
|
|
10
|
+
/**
|
|
11
|
+
* Main memory manager that coordinates all providers
|
|
12
|
+
*/
|
|
13
|
+
export class HierarchicalMemoryManager {
|
|
14
|
+
constructor(userConfig) {
|
|
15
|
+
this.provider = null;
|
|
16
|
+
// Tier-based cleanup intervals
|
|
17
|
+
this.cleanupIntervals = new Map();
|
|
18
|
+
this.config = mergeMemoryConfig(userConfig || {});
|
|
19
|
+
this.sessionId = this.generateSessionId();
|
|
20
|
+
// Validate configuration
|
|
21
|
+
const validation = validateMemoryConfig(this.config);
|
|
22
|
+
if (!validation.valid) {
|
|
23
|
+
console.error('Invalid memory configuration:', validation.errors);
|
|
24
|
+
// Fall back to local provider
|
|
25
|
+
this.config.provider = 'local';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Initialize the memory manager and selected provider
|
|
30
|
+
*/
|
|
31
|
+
async initialize() {
|
|
32
|
+
console.error(`🧠 Initializing memory manager with ${this.config.provider} provider...`);
|
|
33
|
+
try {
|
|
34
|
+
// Create the appropriate provider
|
|
35
|
+
this.provider = await this.createProvider();
|
|
36
|
+
if (!this.provider) {
|
|
37
|
+
console.warn('Failed to create primary provider, falling back to local storage');
|
|
38
|
+
this.config.provider = 'local';
|
|
39
|
+
this.provider = await this.createLocalProvider();
|
|
40
|
+
}
|
|
41
|
+
// Set up automatic cleanup for each tier
|
|
42
|
+
if (this.config.enableAutoCleanup) {
|
|
43
|
+
this.setupAutoCleanup();
|
|
44
|
+
}
|
|
45
|
+
console.error(`✅ Memory manager initialized with ${this.provider.name} provider`);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.error('Failed to initialize memory manager:', error);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Store a memory item with automatic tier assignment
|
|
54
|
+
*/
|
|
55
|
+
async store(content, tier, metadata) {
|
|
56
|
+
if (!this.provider) {
|
|
57
|
+
throw new Error('Memory manager not initialized');
|
|
58
|
+
}
|
|
59
|
+
// Auto-assign tier based on context if not provided
|
|
60
|
+
if (!tier) {
|
|
61
|
+
tier = this.inferTier(content, metadata);
|
|
62
|
+
}
|
|
63
|
+
// Check if tier is enabled
|
|
64
|
+
if (!this.config.tiers[tier]) {
|
|
65
|
+
console.warn(`Tier ${tier} is disabled, upgrading to next available tier`);
|
|
66
|
+
const nextTier = this.getNextAvailableTier(tier);
|
|
67
|
+
if (!nextTier) {
|
|
68
|
+
throw new Error('No memory tiers are enabled');
|
|
69
|
+
}
|
|
70
|
+
tier = nextTier;
|
|
71
|
+
}
|
|
72
|
+
const item = {
|
|
73
|
+
id: this.generateId(),
|
|
74
|
+
content,
|
|
75
|
+
tier,
|
|
76
|
+
userId: this.userId,
|
|
77
|
+
projectId: this.projectId,
|
|
78
|
+
teamId: this.teamId,
|
|
79
|
+
timestamp: new Date(),
|
|
80
|
+
metadata: {
|
|
81
|
+
...metadata,
|
|
82
|
+
sessionId: this.sessionId
|
|
83
|
+
},
|
|
84
|
+
ttl: this.config.ttlMinutes?.[tier]
|
|
85
|
+
};
|
|
86
|
+
return await this.provider.store(item);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Retrieve memories with hierarchical context
|
|
90
|
+
*/
|
|
91
|
+
async retrieve(query) {
|
|
92
|
+
if (!this.provider) {
|
|
93
|
+
throw new Error('Memory manager not initialized');
|
|
94
|
+
}
|
|
95
|
+
// Build query with defaults
|
|
96
|
+
const fullQuery = {
|
|
97
|
+
userId: query?.userId || this.userId,
|
|
98
|
+
projectId: query?.projectId || this.projectId,
|
|
99
|
+
teamId: query?.teamId || this.teamId,
|
|
100
|
+
tiers: query?.tiers || this.getEnabledTiers(),
|
|
101
|
+
...query
|
|
102
|
+
};
|
|
103
|
+
return await this.provider.retrieve(fullQuery);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get contextual memories with synthesis
|
|
107
|
+
*/
|
|
108
|
+
async getContext(text, maxTokens, options) {
|
|
109
|
+
if (!this.provider) {
|
|
110
|
+
throw new Error('Memory manager not initialized');
|
|
111
|
+
}
|
|
112
|
+
const query = {
|
|
113
|
+
text,
|
|
114
|
+
userId: this.userId,
|
|
115
|
+
projectId: this.projectId,
|
|
116
|
+
teamId: this.teamId,
|
|
117
|
+
tiers: this.getEnabledTiers(),
|
|
118
|
+
contextWindow: maxTokens || 2000,
|
|
119
|
+
priorityWeights: {
|
|
120
|
+
recency: 0.4,
|
|
121
|
+
relevance: 0.5,
|
|
122
|
+
frequency: 0.1,
|
|
123
|
+
...options?.priorityWeights
|
|
124
|
+
},
|
|
125
|
+
...options
|
|
126
|
+
};
|
|
127
|
+
return await this.provider.retrieveContext(query);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Promote memory to higher tier
|
|
131
|
+
*/
|
|
132
|
+
async promote(itemId, newTier) {
|
|
133
|
+
if (!this.provider) {
|
|
134
|
+
throw new Error('Memory manager not initialized');
|
|
135
|
+
}
|
|
136
|
+
// Check if new tier is enabled
|
|
137
|
+
if (!this.config.tiers[newTier]) {
|
|
138
|
+
console.warn(`Cannot promote to disabled tier ${newTier}`);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return await this.provider.update(itemId, {
|
|
142
|
+
tier: newTier,
|
|
143
|
+
ttl: this.config.ttlMinutes?.[newTier]
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Clean up expired memories
|
|
148
|
+
*/
|
|
149
|
+
async cleanup() {
|
|
150
|
+
if (!this.provider) {
|
|
151
|
+
throw new Error('Memory manager not initialized');
|
|
152
|
+
}
|
|
153
|
+
return await this.provider.cleanup();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get memory metrics
|
|
157
|
+
*/
|
|
158
|
+
async getMetrics() {
|
|
159
|
+
if (!this.provider) {
|
|
160
|
+
throw new Error('Memory manager not initialized');
|
|
161
|
+
}
|
|
162
|
+
return await this.provider.getMetrics();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Semantic search across memories
|
|
166
|
+
*/
|
|
167
|
+
async search(text, limit) {
|
|
168
|
+
if (!this.provider) {
|
|
169
|
+
throw new Error('Memory manager not initialized');
|
|
170
|
+
}
|
|
171
|
+
// Use semantic search if available
|
|
172
|
+
if (this.provider.semanticSearch) {
|
|
173
|
+
return await this.provider.semanticSearch(text, limit);
|
|
174
|
+
}
|
|
175
|
+
// Fall back to text-based search
|
|
176
|
+
return await this.retrieve({ text, limit });
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Export all memories
|
|
180
|
+
*/
|
|
181
|
+
async export() {
|
|
182
|
+
if (!this.provider) {
|
|
183
|
+
throw new Error('Memory manager not initialized');
|
|
184
|
+
}
|
|
185
|
+
return await this.provider.export();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Import memories
|
|
189
|
+
*/
|
|
190
|
+
async import(items) {
|
|
191
|
+
if (!this.provider) {
|
|
192
|
+
throw new Error('Memory manager not initialized');
|
|
193
|
+
}
|
|
194
|
+
return await this.provider.import(items);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Set context (project, user, team)
|
|
198
|
+
*/
|
|
199
|
+
setContext(context) {
|
|
200
|
+
if (context.projectId)
|
|
201
|
+
this.projectId = context.projectId;
|
|
202
|
+
if (context.userId)
|
|
203
|
+
this.userId = context.userId;
|
|
204
|
+
if (context.teamId)
|
|
205
|
+
this.teamId = context.teamId;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Start a new session
|
|
209
|
+
*/
|
|
210
|
+
newSession() {
|
|
211
|
+
this.sessionId = this.generateSessionId();
|
|
212
|
+
return this.sessionId;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Close and cleanup
|
|
216
|
+
*/
|
|
217
|
+
async close() {
|
|
218
|
+
// Clear cleanup intervals
|
|
219
|
+
this.cleanupIntervals.forEach(interval => clearInterval(interval));
|
|
220
|
+
this.cleanupIntervals.clear();
|
|
221
|
+
// Close provider
|
|
222
|
+
if (this.provider) {
|
|
223
|
+
await this.provider.close();
|
|
224
|
+
this.provider = null;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Private helper methods
|
|
229
|
+
*/
|
|
230
|
+
async createProvider() {
|
|
231
|
+
switch (this.config.provider) {
|
|
232
|
+
case 'mem0':
|
|
233
|
+
if (!this.config.mem0) {
|
|
234
|
+
console.error('Mem0 configuration missing');
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const provider = new Mem0Provider(this.config.mem0);
|
|
239
|
+
await provider.initialize();
|
|
240
|
+
return provider;
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
console.error('Failed to create Mem0 provider:', error);
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
case 'devlog':
|
|
247
|
+
// TODO: Implement DevLog provider
|
|
248
|
+
console.warn('DevLog provider not yet implemented');
|
|
249
|
+
return null;
|
|
250
|
+
case 'local':
|
|
251
|
+
return await this.createLocalProvider();
|
|
252
|
+
case 'hybrid':
|
|
253
|
+
// TODO: Implement Hybrid provider
|
|
254
|
+
console.warn('Hybrid provider not yet implemented');
|
|
255
|
+
return null;
|
|
256
|
+
case 'none':
|
|
257
|
+
return null;
|
|
258
|
+
default:
|
|
259
|
+
console.warn(`Unknown provider: ${this.config.provider}`);
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async createLocalProvider() {
|
|
264
|
+
const provider = new LocalProvider(this.config.local || {
|
|
265
|
+
storageType: 'json',
|
|
266
|
+
path: './.focus-memory',
|
|
267
|
+
maxSizeMB: 100
|
|
268
|
+
});
|
|
269
|
+
await provider.initialize();
|
|
270
|
+
return provider;
|
|
271
|
+
}
|
|
272
|
+
inferTier(content, metadata) {
|
|
273
|
+
// Infer based on content and metadata
|
|
274
|
+
if (metadata?.tier)
|
|
275
|
+
return metadata.tier;
|
|
276
|
+
// Default heuristics
|
|
277
|
+
const contentLength = content.length;
|
|
278
|
+
const hasCode = /```[\s\S]*?```/.test(content);
|
|
279
|
+
const hasImportantKeywords = /critical|important|remember|always|never/i.test(content);
|
|
280
|
+
if (hasImportantKeywords && this.config.tiers.project) {
|
|
281
|
+
return 'project';
|
|
282
|
+
}
|
|
283
|
+
if (hasCode && this.config.tiers.working) {
|
|
284
|
+
return 'working';
|
|
285
|
+
}
|
|
286
|
+
if (contentLength > 500 && this.config.tiers.working) {
|
|
287
|
+
return 'working';
|
|
288
|
+
}
|
|
289
|
+
return 'session';
|
|
290
|
+
}
|
|
291
|
+
getNextAvailableTier(tier) {
|
|
292
|
+
const tierOrder = ['session', 'working', 'project', 'team', 'global'];
|
|
293
|
+
const currentIndex = tierOrder.indexOf(tier);
|
|
294
|
+
for (let i = currentIndex + 1; i < tierOrder.length; i++) {
|
|
295
|
+
if (this.config.tiers[tierOrder[i]]) {
|
|
296
|
+
return tierOrder[i];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Try lower tiers
|
|
300
|
+
for (let i = currentIndex - 1; i >= 0; i--) {
|
|
301
|
+
if (this.config.tiers[tierOrder[i]]) {
|
|
302
|
+
return tierOrder[i];
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
getEnabledTiers() {
|
|
308
|
+
const tiers = [];
|
|
309
|
+
const allTiers = ['session', 'working', 'project', 'team', 'global'];
|
|
310
|
+
allTiers.forEach(tier => {
|
|
311
|
+
if (this.config.tiers[tier]) {
|
|
312
|
+
tiers.push(tier);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
return tiers;
|
|
316
|
+
}
|
|
317
|
+
setupAutoCleanup() {
|
|
318
|
+
const tiers = ['session', 'working', 'project', 'team', 'global'];
|
|
319
|
+
tiers.forEach(tier => {
|
|
320
|
+
if (this.config.tiers[tier] && this.config.ttlMinutes?.[tier]) {
|
|
321
|
+
const ttl = this.config.ttlMinutes[tier];
|
|
322
|
+
if (ttl > 0) {
|
|
323
|
+
// Run cleanup at 1/4 of TTL interval
|
|
324
|
+
const interval = Math.max(60000, (ttl * 60 * 1000) / 4); // Min 1 minute
|
|
325
|
+
const intervalId = setInterval(async () => {
|
|
326
|
+
try {
|
|
327
|
+
await this.cleanupTier(tier);
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
console.error(`Failed to cleanup ${tier} tier:`, error);
|
|
331
|
+
}
|
|
332
|
+
}, interval);
|
|
333
|
+
this.cleanupIntervals.set(tier, intervalId);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
async cleanupTier(tier) {
|
|
339
|
+
if (!this.provider)
|
|
340
|
+
return;
|
|
341
|
+
const ttl = this.config.ttlMinutes?.[tier];
|
|
342
|
+
if (!ttl || ttl <= 0)
|
|
343
|
+
return;
|
|
344
|
+
const cutoffDate = new Date(Date.now() - (ttl * 60 * 1000));
|
|
345
|
+
const query = {
|
|
346
|
+
tiers: [tier],
|
|
347
|
+
endDate: cutoffDate
|
|
348
|
+
};
|
|
349
|
+
const deleted = await this.provider.deleteMany(query);
|
|
350
|
+
if (deleted > 0) {
|
|
351
|
+
console.error(`🗑️ Cleaned up ${deleted} expired ${tier} memories`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
generateId() {
|
|
355
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
356
|
+
}
|
|
357
|
+
generateSessionId() {
|
|
358
|
+
return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Singleton instance
|
|
363
|
+
*/
|
|
364
|
+
let memoryManager = null;
|
|
365
|
+
/**
|
|
366
|
+
* Get or create memory manager instance
|
|
367
|
+
*/
|
|
368
|
+
export async function getMemoryManager(config) {
|
|
369
|
+
if (!memoryManager) {
|
|
370
|
+
memoryManager = new HierarchicalMemoryManager(config);
|
|
371
|
+
await memoryManager.initialize();
|
|
372
|
+
}
|
|
373
|
+
return memoryManager;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Reset memory manager (useful for testing)
|
|
377
|
+
*/
|
|
378
|
+
export async function resetMemoryManager() {
|
|
379
|
+
if (memoryManager) {
|
|
380
|
+
await memoryManager.close();
|
|
381
|
+
memoryManager = null;
|
|
382
|
+
}
|
|
383
|
+
}
|