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,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Memory Provider
|
|
3
|
+
* Local storage implementation using JSON, SQLite, or LevelDB
|
|
4
|
+
*/
|
|
5
|
+
import { BaseMemoryProvider } from '../memory-interface.js';
|
|
6
|
+
import * as fs from 'fs/promises';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
/**
|
|
9
|
+
* Local provider implementation
|
|
10
|
+
*/
|
|
11
|
+
export class LocalProvider extends BaseMemoryProvider {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super();
|
|
14
|
+
this.name = 'local';
|
|
15
|
+
this.memoryStore = new Map();
|
|
16
|
+
this.indexByTier = new Map();
|
|
17
|
+
this.indexByProject = new Map();
|
|
18
|
+
this.indexByUser = new Map();
|
|
19
|
+
this.autosaveInterval = null;
|
|
20
|
+
this.config = {
|
|
21
|
+
...config,
|
|
22
|
+
storageType: config.storageType || 'json',
|
|
23
|
+
path: config.path || './.focus-memory',
|
|
24
|
+
maxSizeMB: config.maxSizeMB || 100,
|
|
25
|
+
enableCompression: config.enableCompression !== false
|
|
26
|
+
};
|
|
27
|
+
this.storagePath = path.resolve(this.config.path);
|
|
28
|
+
// Initialize indexes
|
|
29
|
+
const tiers = ['session', 'working', 'project', 'team', 'global'];
|
|
30
|
+
tiers.forEach(tier => this.indexByTier.set(tier, new Set()));
|
|
31
|
+
}
|
|
32
|
+
async doInitialize() {
|
|
33
|
+
try {
|
|
34
|
+
// Ensure storage directory exists
|
|
35
|
+
await fs.mkdir(path.dirname(this.storagePath), { recursive: true });
|
|
36
|
+
// Load existing data
|
|
37
|
+
await this.loadFromDisk();
|
|
38
|
+
// Set up autosave
|
|
39
|
+
this.autosaveInterval = setInterval(() => {
|
|
40
|
+
this.saveToDisk().catch(console.error);
|
|
41
|
+
}, 30000); // Save every 30 seconds
|
|
42
|
+
console.error(`Local provider initialized at ${this.storagePath}`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Failed to initialize local provider:', error);
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async store(item) {
|
|
50
|
+
// Generate ID if not provided
|
|
51
|
+
if (!item.id) {
|
|
52
|
+
item.id = this.generateId();
|
|
53
|
+
}
|
|
54
|
+
// Check storage limits
|
|
55
|
+
if (await this.isStorageFull()) {
|
|
56
|
+
// Remove oldest session memories to make space
|
|
57
|
+
await this.cleanupOldestMemories();
|
|
58
|
+
}
|
|
59
|
+
// Store in memory
|
|
60
|
+
this.memoryStore.set(item.id, item);
|
|
61
|
+
// Update indexes
|
|
62
|
+
this.indexByTier.get(item.tier)?.add(item.id);
|
|
63
|
+
if (item.projectId) {
|
|
64
|
+
if (!this.indexByProject.has(item.projectId)) {
|
|
65
|
+
this.indexByProject.set(item.projectId, new Set());
|
|
66
|
+
}
|
|
67
|
+
this.indexByProject.get(item.projectId)?.add(item.id);
|
|
68
|
+
}
|
|
69
|
+
if (item.userId) {
|
|
70
|
+
if (!this.indexByUser.has(item.userId)) {
|
|
71
|
+
this.indexByUser.set(item.userId, new Set());
|
|
72
|
+
}
|
|
73
|
+
this.indexByUser.get(item.userId)?.add(item.id);
|
|
74
|
+
}
|
|
75
|
+
// Update metrics
|
|
76
|
+
this.metrics.totalItems++;
|
|
77
|
+
this.metrics.itemsByTier[item.tier]++;
|
|
78
|
+
// Save to disk (async, don't wait)
|
|
79
|
+
this.saveToDisk().catch(console.error);
|
|
80
|
+
return item.id;
|
|
81
|
+
}
|
|
82
|
+
async retrieve(query) {
|
|
83
|
+
const startTime = Date.now();
|
|
84
|
+
let candidates = new Set();
|
|
85
|
+
// Start with all items if no specific filters
|
|
86
|
+
if (!query.userId && !query.projectId && !query.tiers) {
|
|
87
|
+
candidates = new Set(this.memoryStore.keys());
|
|
88
|
+
}
|
|
89
|
+
// Filter by tier
|
|
90
|
+
if (query.tiers && query.tiers.length > 0) {
|
|
91
|
+
for (const tier of query.tiers) {
|
|
92
|
+
const tierItems = this.indexByTier.get(tier);
|
|
93
|
+
if (tierItems) {
|
|
94
|
+
tierItems.forEach(id => candidates.add(id));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Filter by project
|
|
99
|
+
if (query.projectId) {
|
|
100
|
+
const projectItems = this.indexByProject.get(query.projectId) || new Set();
|
|
101
|
+
if (candidates.size > 0) {
|
|
102
|
+
// Intersection
|
|
103
|
+
candidates = new Set([...candidates].filter(id => projectItems.has(id)));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
candidates = projectItems;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Filter by user
|
|
110
|
+
if (query.userId) {
|
|
111
|
+
const userItems = this.indexByUser.get(query.userId) || new Set();
|
|
112
|
+
if (candidates.size > 0) {
|
|
113
|
+
// Intersection
|
|
114
|
+
candidates = new Set([...candidates].filter(id => userItems.has(id)));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
candidates = userItems;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Convert to items
|
|
121
|
+
let items = [];
|
|
122
|
+
candidates.forEach(id => {
|
|
123
|
+
const item = this.memoryStore.get(id);
|
|
124
|
+
if (item) {
|
|
125
|
+
items.push(item);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
// Filter by date range
|
|
129
|
+
if (query.startDate || query.endDate) {
|
|
130
|
+
items = items.filter(item => {
|
|
131
|
+
const itemDate = item.timestamp.getTime();
|
|
132
|
+
if (query.startDate && itemDate < query.startDate.getTime())
|
|
133
|
+
return false;
|
|
134
|
+
if (query.endDate && itemDate > query.endDate.getTime())
|
|
135
|
+
return false;
|
|
136
|
+
return true;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Filter by tags
|
|
140
|
+
if (query.tags && query.tags.length > 0) {
|
|
141
|
+
items = items.filter(item => {
|
|
142
|
+
if (!item.tags)
|
|
143
|
+
return false;
|
|
144
|
+
return query.tags.some(tag => item.tags.includes(tag));
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// Text search (simple substring match)
|
|
148
|
+
if (query.text) {
|
|
149
|
+
const searchText = query.text.toLowerCase();
|
|
150
|
+
items = items.filter(item => item.content.toLowerCase().includes(searchText));
|
|
151
|
+
}
|
|
152
|
+
// Sort by recency
|
|
153
|
+
items.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
154
|
+
// Apply limit and offset
|
|
155
|
+
if (query.offset) {
|
|
156
|
+
items = items.slice(query.offset);
|
|
157
|
+
}
|
|
158
|
+
if (query.limit) {
|
|
159
|
+
items = items.slice(0, query.limit);
|
|
160
|
+
}
|
|
161
|
+
// Update metrics
|
|
162
|
+
const retrievalTime = Date.now() - startTime;
|
|
163
|
+
this.metrics.avgRetrievalTime =
|
|
164
|
+
(this.metrics.avgRetrievalTime + retrievalTime) / 2;
|
|
165
|
+
// Update access counts
|
|
166
|
+
items.forEach(item => {
|
|
167
|
+
item.accessCount = (item.accessCount || 0) + 1;
|
|
168
|
+
item.lastAccessed = new Date();
|
|
169
|
+
});
|
|
170
|
+
return items;
|
|
171
|
+
}
|
|
172
|
+
async update(id, updates) {
|
|
173
|
+
const item = this.memoryStore.get(id);
|
|
174
|
+
if (!item)
|
|
175
|
+
return false;
|
|
176
|
+
// Update the item
|
|
177
|
+
Object.assign(item, updates);
|
|
178
|
+
// Update indexes if tier changed
|
|
179
|
+
if (updates.tier && updates.tier !== item.tier) {
|
|
180
|
+
this.indexByTier.get(item.tier)?.delete(id);
|
|
181
|
+
this.indexByTier.get(updates.tier)?.add(id);
|
|
182
|
+
}
|
|
183
|
+
// Save to disk
|
|
184
|
+
await this.saveToDisk();
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
async delete(id) {
|
|
188
|
+
const item = this.memoryStore.get(id);
|
|
189
|
+
if (!item)
|
|
190
|
+
return false;
|
|
191
|
+
// Remove from store
|
|
192
|
+
this.memoryStore.delete(id);
|
|
193
|
+
// Remove from indexes
|
|
194
|
+
this.indexByTier.get(item.tier)?.delete(id);
|
|
195
|
+
if (item.projectId) {
|
|
196
|
+
this.indexByProject.get(item.projectId)?.delete(id);
|
|
197
|
+
}
|
|
198
|
+
if (item.userId) {
|
|
199
|
+
this.indexByUser.get(item.userId)?.delete(id);
|
|
200
|
+
}
|
|
201
|
+
// Update metrics
|
|
202
|
+
this.metrics.totalItems--;
|
|
203
|
+
this.metrics.itemsByTier[item.tier]--;
|
|
204
|
+
// Save to disk
|
|
205
|
+
await this.saveToDisk();
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
async cleanup() {
|
|
209
|
+
const now = Date.now();
|
|
210
|
+
let cleaned = 0;
|
|
211
|
+
// Clean up expired items based on TTL
|
|
212
|
+
const itemsToDelete = [];
|
|
213
|
+
this.memoryStore.forEach((item, id) => {
|
|
214
|
+
if (item.ttl && item.ttl > 0) {
|
|
215
|
+
const expiryTime = item.timestamp.getTime() + (item.ttl * 60 * 1000);
|
|
216
|
+
if (now > expiryTime) {
|
|
217
|
+
itemsToDelete.push(id);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// Delete expired items
|
|
222
|
+
for (const id of itemsToDelete) {
|
|
223
|
+
if (await this.delete(id)) {
|
|
224
|
+
cleaned++;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Save to disk after cleanup
|
|
228
|
+
await this.saveToDisk();
|
|
229
|
+
return cleaned;
|
|
230
|
+
}
|
|
231
|
+
async export() {
|
|
232
|
+
return Array.from(this.memoryStore.values());
|
|
233
|
+
}
|
|
234
|
+
async import(items) {
|
|
235
|
+
let imported = 0;
|
|
236
|
+
for (const item of items) {
|
|
237
|
+
try {
|
|
238
|
+
await this.store(item);
|
|
239
|
+
imported++;
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
console.error(`Failed to import item ${item.id}:`, error);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return imported;
|
|
246
|
+
}
|
|
247
|
+
async close() {
|
|
248
|
+
// Save final state
|
|
249
|
+
await this.saveToDisk();
|
|
250
|
+
// Clear autosave interval
|
|
251
|
+
if (this.autosaveInterval) {
|
|
252
|
+
clearInterval(this.autosaveInterval);
|
|
253
|
+
this.autosaveInterval = null;
|
|
254
|
+
}
|
|
255
|
+
// Clear memory
|
|
256
|
+
this.memoryStore.clear();
|
|
257
|
+
this.indexByTier.clear();
|
|
258
|
+
this.indexByProject.clear();
|
|
259
|
+
this.indexByUser.clear();
|
|
260
|
+
await super.close();
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Persistence methods
|
|
264
|
+
*/
|
|
265
|
+
async loadFromDisk() {
|
|
266
|
+
try {
|
|
267
|
+
const dataFile = this.getDataFilePath();
|
|
268
|
+
// Check if file exists
|
|
269
|
+
try {
|
|
270
|
+
await fs.access(dataFile);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
// File doesn't exist, start fresh
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// Read and parse data
|
|
277
|
+
const data = await fs.readFile(dataFile, 'utf-8');
|
|
278
|
+
let parsedData;
|
|
279
|
+
if (this.config.enableCompression) {
|
|
280
|
+
// Decompress if needed (simplified - real implementation would use zlib)
|
|
281
|
+
parsedData = JSON.parse(data);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
parsedData = JSON.parse(data);
|
|
285
|
+
}
|
|
286
|
+
// Restore memory store
|
|
287
|
+
if (parsedData.items) {
|
|
288
|
+
for (const item of parsedData.items) {
|
|
289
|
+
// Convert dates
|
|
290
|
+
item.timestamp = new Date(item.timestamp);
|
|
291
|
+
if (item.lastAccessed) {
|
|
292
|
+
item.lastAccessed = new Date(item.lastAccessed);
|
|
293
|
+
}
|
|
294
|
+
// Store without triggering save
|
|
295
|
+
this.memoryStore.set(item.id, item);
|
|
296
|
+
// Rebuild indexes
|
|
297
|
+
this.indexByTier.get(item.tier)?.add(item.id);
|
|
298
|
+
if (item.projectId) {
|
|
299
|
+
if (!this.indexByProject.has(item.projectId)) {
|
|
300
|
+
this.indexByProject.set(item.projectId, new Set());
|
|
301
|
+
}
|
|
302
|
+
this.indexByProject.get(item.projectId)?.add(item.id);
|
|
303
|
+
}
|
|
304
|
+
if (item.userId) {
|
|
305
|
+
if (!this.indexByUser.has(item.userId)) {
|
|
306
|
+
this.indexByUser.set(item.userId, new Set());
|
|
307
|
+
}
|
|
308
|
+
this.indexByUser.get(item.userId)?.add(item.id);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// Restore metrics
|
|
313
|
+
if (parsedData.metrics) {
|
|
314
|
+
this.metrics = parsedData.metrics;
|
|
315
|
+
}
|
|
316
|
+
console.error(`Loaded ${this.memoryStore.size} memories from disk`);
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
console.error('Failed to load from disk:', error);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async saveToDisk() {
|
|
323
|
+
try {
|
|
324
|
+
const dataFile = this.getDataFilePath();
|
|
325
|
+
// Prepare data
|
|
326
|
+
const data = {
|
|
327
|
+
version: '1.0',
|
|
328
|
+
timestamp: new Date().toISOString(),
|
|
329
|
+
items: Array.from(this.memoryStore.values()),
|
|
330
|
+
metrics: this.metrics
|
|
331
|
+
};
|
|
332
|
+
// Serialize
|
|
333
|
+
let serialized = JSON.stringify(data, null, 2);
|
|
334
|
+
if (this.config.enableCompression) {
|
|
335
|
+
// Compress if needed (simplified - real implementation would use zlib)
|
|
336
|
+
// For now, just use regular JSON
|
|
337
|
+
}
|
|
338
|
+
// Write to temp file first
|
|
339
|
+
const tempFile = `${dataFile}.tmp`;
|
|
340
|
+
await fs.writeFile(tempFile, serialized, 'utf-8');
|
|
341
|
+
// Atomic rename
|
|
342
|
+
await fs.rename(tempFile, dataFile);
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
console.error('Failed to save to disk:', error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
getDataFilePath() {
|
|
349
|
+
if (this.config.storageType === 'json') {
|
|
350
|
+
return `${this.storagePath}.json`;
|
|
351
|
+
}
|
|
352
|
+
// For SQLite or LevelDB, would return appropriate file
|
|
353
|
+
return `${this.storagePath}.db`;
|
|
354
|
+
}
|
|
355
|
+
async isStorageFull() {
|
|
356
|
+
if (!this.config.maxSizeMB)
|
|
357
|
+
return false;
|
|
358
|
+
try {
|
|
359
|
+
const dataFile = this.getDataFilePath();
|
|
360
|
+
const stats = await fs.stat(dataFile);
|
|
361
|
+
const sizeMB = stats.size / (1024 * 1024);
|
|
362
|
+
return sizeMB >= this.config.maxSizeMB;
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async cleanupOldestMemories() {
|
|
369
|
+
// Remove oldest session memories first
|
|
370
|
+
const sessionMemories = Array.from(this.indexByTier.get('session') || [])
|
|
371
|
+
.map(id => this.memoryStore.get(id))
|
|
372
|
+
.filter(item => item)
|
|
373
|
+
.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
374
|
+
// Remove oldest 10% of session memories
|
|
375
|
+
const toRemove = Math.ceil(sessionMemories.length * 0.1);
|
|
376
|
+
for (let i = 0; i < toRemove && i < sessionMemories.length; i++) {
|
|
377
|
+
await this.delete(sessionMemories[i].id);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Factory function to create local provider
|
|
383
|
+
*/
|
|
384
|
+
export async function createLocalProvider(config) {
|
|
385
|
+
const provider = new LocalProvider(config);
|
|
386
|
+
await provider.initialize();
|
|
387
|
+
return provider;
|
|
388
|
+
}
|