@stackmemoryai/stackmemory 1.2.2 → 1.2.6

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.
Files changed (77) hide show
  1. package/README.md +10 -6
  2. package/dist/src/cli/claude-sm.js +33 -4
  3. package/dist/src/cli/codex-sm-danger.js +4 -1
  4. package/dist/src/cli/codex-sm.js +6 -8
  5. package/dist/src/cli/commands/config.js +0 -81
  6. package/dist/src/cli/commands/context-rehydrate.js +133 -47
  7. package/dist/src/cli/commands/db.js +35 -8
  8. package/dist/src/cli/commands/handoff.js +1 -1
  9. package/dist/src/cli/commands/linear.js +9 -0
  10. package/dist/src/cli/commands/ralph.js +2 -2
  11. package/dist/src/cli/commands/setup.js +2 -2
  12. package/dist/src/cli/commands/signup.js +3 -1
  13. package/dist/src/cli/commands/skills.js +108 -1
  14. package/dist/src/cli/commands/storage-tier.js +26 -8
  15. package/dist/src/cli/index.js +1 -57
  16. package/dist/src/core/config/feature-flags.js +0 -4
  17. package/dist/src/core/context/dual-stack-manager.js +10 -3
  18. package/dist/src/core/context/frame-database.js +32 -0
  19. package/dist/src/core/context/frame-handoff-manager.js +2 -2
  20. package/dist/src/core/context/{refactored-frame-manager.js → frame-manager.js} +3 -3
  21. package/dist/src/core/context/index.js +2 -2
  22. package/dist/src/core/database/sqlite-adapter.js +161 -1
  23. package/dist/src/core/digest/frame-digest-integration.js +1 -1
  24. package/dist/src/core/digest/index.js +1 -1
  25. package/dist/src/core/execution/parallel-executor.js +5 -1
  26. package/dist/src/core/projects/project-isolation.js +18 -4
  27. package/dist/src/core/security/index.js +2 -0
  28. package/dist/src/core/security/input-sanitizer.js +23 -0
  29. package/dist/src/core/utils/update-checker.js +10 -6
  30. package/dist/src/daemon/daemon-config.js +2 -1
  31. package/dist/src/daemon/services/auto-save-service.js +121 -0
  32. package/dist/src/daemon/services/maintenance-service.js +76 -1
  33. package/dist/src/features/sweep/prompt-builder.js +2 -2
  34. package/dist/src/hooks/daemon.js +0 -8
  35. package/dist/src/integrations/linear/config.js +3 -1
  36. package/dist/src/integrations/linear/sync.js +18 -5
  37. package/dist/src/integrations/linear/webhook.js +0 -16
  38. package/dist/src/integrations/mcp/handlers/code-execution-handlers.js +33 -7
  39. package/dist/src/integrations/mcp/handlers/cord-handlers.js +397 -0
  40. package/dist/src/integrations/mcp/handlers/index.js +55 -9
  41. package/dist/src/integrations/mcp/handlers/task-handlers.js +55 -12
  42. package/dist/src/integrations/mcp/handlers/team-handlers.js +211 -0
  43. package/dist/src/integrations/mcp/handlers/trace-handlers.js +28 -9
  44. package/dist/src/integrations/mcp/index.js +2 -2
  45. package/dist/src/integrations/mcp/refactored-server.js +31 -10
  46. package/dist/src/integrations/mcp/server.js +0 -130
  47. package/dist/src/integrations/mcp/tool-definitions.js +196 -67
  48. package/dist/src/integrations/ralph/context/context-budget-manager.js +10 -2
  49. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +54 -22
  50. package/dist/src/integrations/ralph/learning/pattern-learner.js +59 -24
  51. package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +81 -35
  52. package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +12 -4
  53. package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +32 -9
  54. package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +25 -8
  55. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +17 -5
  56. package/dist/src/integrations/ralph/visualization/ralph-debugger.js +73 -22
  57. package/dist/src/skills/claude-skills.js +37 -103
  58. package/dist/src/skills/theory-skill.js +191 -0
  59. package/dist/src/utils/hook-installer.js +16 -0
  60. package/package.json +6 -6
  61. package/scripts/install-claude-hooks-auto.js +8 -0
  62. package/templates/claude-hooks/cord-trace.js +225 -0
  63. package/templates/claude-hooks/theory-capture.js +100 -0
  64. package/dist/src/core/config/storage-config.js +0 -114
  65. package/dist/src/core/storage/chromadb-adapter.js +0 -379
  66. package/dist/src/hooks/graphiti-hooks.js +0 -253
  67. package/dist/src/integrations/claude-code/enhanced-pre-clear-hooks.js +0 -458
  68. package/dist/src/integrations/graphiti/client.js +0 -115
  69. package/dist/src/integrations/graphiti/config.js +0 -17
  70. package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +0 -115
  71. package/dist/src/integrations/graphiti/types.js +0 -4
  72. package/dist/src/integrations/ralph/coordination/enhanced-coordination.js +0 -409
  73. package/dist/src/skills/repo-ingestion-skill.js +0 -631
  74. package/templates/claude-hooks/chromadb-wrapper +0 -21
  75. /package/dist/src/core/context/{enhanced-rehydration.js → rehydration.js} +0 -0
  76. /package/dist/src/core/digest/{enhanced-hybrid-digest.js → hybrid-digest.js} +0 -0
  77. /package/dist/src/core/session/{enhanced-handoff.js → handoff.js} +0 -0
@@ -12,7 +12,13 @@ class TaskHandlers {
12
12
  */
13
13
  async handleCreateTask(args) {
14
14
  try {
15
- const { title, description, priority = "medium", tags = [], parent_id } = args;
15
+ const {
16
+ title,
17
+ description,
18
+ priority = "medium",
19
+ tags = [],
20
+ parent_id
21
+ } = args;
16
22
  if (!title) {
17
23
  throw new Error("Task title is required");
18
24
  }
@@ -40,7 +46,10 @@ class TaskHandlers {
40
46
  }
41
47
  };
42
48
  } catch (error) {
43
- logger.error("Error creating task", error instanceof Error ? error : new Error(String(error)));
49
+ logger.error(
50
+ "Error creating task",
51
+ error instanceof Error ? error : new Error(String(error))
52
+ );
44
53
  throw error;
45
54
  }
46
55
  }
@@ -57,12 +66,20 @@ class TaskHandlers {
57
66
  throw new Error("Status is required");
58
67
  }
59
68
  const validStatus = this.validateStatus(status);
60
- await this.deps.taskStore.updateTaskStatus(task_id, validStatus, progress);
69
+ await this.deps.taskStore.updateTaskStatus(
70
+ task_id,
71
+ validStatus,
72
+ progress
73
+ );
61
74
  const task = await this.deps.taskStore.getTask(task_id);
62
75
  if (!task) {
63
76
  throw new Error(`Task not found: ${task_id}`);
64
77
  }
65
- logger.info("Updated task status", { taskId: task_id, status: validStatus, progress });
78
+ logger.info("Updated task status", {
79
+ taskId: task_id,
80
+ status: validStatus,
81
+ progress
82
+ });
66
83
  return {
67
84
  content: [
68
85
  {
@@ -77,7 +94,10 @@ class TaskHandlers {
77
94
  }
78
95
  };
79
96
  } catch (error) {
80
- logger.error("Error updating task status", error instanceof Error ? error : new Error(String(error)));
97
+ logger.error(
98
+ "Error updating task status",
99
+ error instanceof Error ? error : new Error(String(error))
100
+ );
81
101
  throw error;
82
102
  }
83
103
  }
@@ -138,7 +158,10 @@ ${summaryText}`
138
158
  }
139
159
  };
140
160
  } catch (error) {
141
- logger.error("Error getting active tasks", error instanceof Error ? error : new Error(String(error)));
161
+ logger.error(
162
+ "Error getting active tasks",
163
+ error instanceof Error ? error : new Error(String(error))
164
+ );
142
165
  throw error;
143
166
  }
144
167
  }
@@ -172,7 +195,10 @@ ${Object.entries(metrics.by_status || {}).map(([status, count]) => `- ${status}:
172
195
  metadata: metrics
173
196
  };
174
197
  } catch (error) {
175
- logger.error("Error getting task metrics", error instanceof Error ? error : new Error(String(error)));
198
+ logger.error(
199
+ "Error getting task metrics",
200
+ error instanceof Error ? error : new Error(String(error))
201
+ );
176
202
  throw error;
177
203
  }
178
204
  }
@@ -191,7 +217,11 @@ ${Object.entries(metrics.by_status || {}).map(([status, count]) => `- ${status}:
191
217
  if (!task || !dependencyTask) {
192
218
  throw new Error("One or both tasks not found");
193
219
  }
194
- logger.info("Added task dependency", { taskId: task_id, dependsOn: depends_on, type: dependency_type });
220
+ logger.info("Added task dependency", {
221
+ taskId: task_id,
222
+ dependsOn: depends_on,
223
+ type: dependency_type
224
+ });
195
225
  return {
196
226
  content: [
197
227
  {
@@ -206,7 +236,10 @@ ${Object.entries(metrics.by_status || {}).map(([status, count]) => `- ${status}:
206
236
  }
207
237
  };
208
238
  } catch (error) {
209
- logger.error("Error adding task dependency", error instanceof Error ? error : new Error(String(error)));
239
+ logger.error(
240
+ "Error adding task dependency",
241
+ error instanceof Error ? error : new Error(String(error))
242
+ );
210
243
  throw error;
211
244
  }
212
245
  }
@@ -217,7 +250,9 @@ ${Object.entries(metrics.by_status || {}).map(([status, count]) => `- ${status}:
217
250
  const validPriorities = ["low", "medium", "high", "urgent"];
218
251
  const normalizedPriority = priority.toLowerCase();
219
252
  if (!validPriorities.includes(normalizedPriority)) {
220
- throw new Error(`Invalid priority: ${priority}. Must be one of: ${validPriorities.join(", ")}`);
253
+ throw new Error(
254
+ `Invalid priority: ${priority}. Must be one of: ${validPriorities.join(", ")}`
255
+ );
221
256
  }
222
257
  return normalizedPriority;
223
258
  }
@@ -225,10 +260,18 @@ ${Object.entries(metrics.by_status || {}).map(([status, count]) => `- ${status}:
225
260
  * Validate task status
226
261
  */
227
262
  validateStatus(status) {
228
- const validStatuses = ["pending", "in_progress", "blocked", "completed", "cancelled"];
263
+ const validStatuses = [
264
+ "pending",
265
+ "in_progress",
266
+ "blocked",
267
+ "completed",
268
+ "cancelled"
269
+ ];
229
270
  const normalizedStatus = status.toLowerCase().replace("_", "-");
230
271
  if (!validStatuses.includes(normalizedStatus)) {
231
- throw new Error(`Invalid status: ${status}. Must be one of: ${validStatuses.join(", ")}`);
272
+ throw new Error(
273
+ `Invalid status: ${status}. Must be one of: ${validStatuses.join(", ")}`
274
+ );
232
275
  }
233
276
  return normalizedStatus;
234
277
  }
@@ -0,0 +1,211 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import { logger } from "../../../core/monitoring/logger.js";
6
+ class TeamHandlers {
7
+ constructor(deps) {
8
+ this.deps = deps;
9
+ }
10
+ /**
11
+ * Get context from other agents working on the same project.
12
+ * Returns recent frames and shared anchors from other sessions.
13
+ */
14
+ async handleTeamContextGet(args) {
15
+ try {
16
+ const limit = args.limit ?? 10;
17
+ const types = args.types;
18
+ const since = args.since;
19
+ const projectId = this.getProjectId();
20
+ const runId = this.getRunId();
21
+ const frames = await this.deps.dbAdapter.getRecentFramesExcludingRun(
22
+ projectId,
23
+ runId,
24
+ { limit, types, since }
25
+ );
26
+ const sharedAnchors = await this.deps.dbAdapter.getSharedAnchors(
27
+ projectId,
28
+ { limit, since }
29
+ );
30
+ if (frames.length === 0 && sharedAnchors.length === 0) {
31
+ return {
32
+ content: [
33
+ {
34
+ type: "text",
35
+ text: "No context from other agents found in this project."
36
+ }
37
+ ]
38
+ };
39
+ }
40
+ const frameSummaries = frames.map((f) => ({
41
+ frame_id: f.frame_id,
42
+ run_id: f.run_id,
43
+ name: f.name,
44
+ type: f.type,
45
+ state: f.state,
46
+ created_at: f.created_at,
47
+ digest_text: f.digest_text || null,
48
+ anchors: f.anchors.map((a) => ({
49
+ type: a.type,
50
+ text: a.text,
51
+ priority: a.priority
52
+ }))
53
+ }));
54
+ const sharedSummaries = sharedAnchors.map((a) => ({
55
+ type: a.type,
56
+ text: a.text,
57
+ priority: a.priority,
58
+ frame_name: a.frame_name,
59
+ run_id: a.run_id,
60
+ shared_by: a.metadata?.sharedBy
61
+ }));
62
+ const text = `Team Context (${frames.length} frames, ${sharedAnchors.length} shared anchors):
63
+
64
+ ` + frameSummaries.map(
65
+ (f) => `[${f.run_id?.slice(0, 8)}] ${f.name} (${f.type}, ${f.state})` + (f.digest_text ? `
66
+ ${f.digest_text}` : "") + (f.anchors.length > 0 ? "\n Anchors: " + f.anchors.map((a) => `${a.type}: ${a.text}`).join("; ") : "")
67
+ ).join("\n") + (sharedSummaries.length > 0 ? "\n\nShared Anchors:\n" + sharedSummaries.map((a) => ` [${a.type}] ${a.text} (priority: ${a.priority})`).join("\n") : "");
68
+ return {
69
+ content: [{ type: "text", text }],
70
+ metadata: { frames: frameSummaries, sharedAnchors: sharedSummaries }
71
+ };
72
+ } catch (error) {
73
+ logger.error(
74
+ "Error getting team context",
75
+ error instanceof Error ? error : new Error(String(error))
76
+ );
77
+ throw error;
78
+ }
79
+ }
80
+ /**
81
+ * Share a piece of context with other agents.
82
+ * Creates a high-priority anchor tagged with shared=true.
83
+ */
84
+ async handleTeamContextShare(args) {
85
+ try {
86
+ const { content, type = "FACT", priority = 8 } = args;
87
+ if (!content) {
88
+ throw new Error("content is required");
89
+ }
90
+ const validTypes = [
91
+ "FACT",
92
+ "DECISION",
93
+ "CONSTRAINT",
94
+ "INTERFACE_CONTRACT",
95
+ "TODO",
96
+ "RISK"
97
+ ];
98
+ if (!validTypes.includes(type)) {
99
+ throw new Error(
100
+ `Invalid type. Must be one of: ${validTypes.join(", ")}`
101
+ );
102
+ }
103
+ let frameId = this.deps.frameManager.getCurrentFrameId();
104
+ if (!frameId) {
105
+ frameId = this.deps.frameManager.createFrame({
106
+ type: "tool_scope",
107
+ name: "team_context_share"
108
+ });
109
+ }
110
+ const runId = this.getRunId();
111
+ this.deps.frameManager.addAnchor(type, content, priority, {
112
+ shared: true,
113
+ sharedBy: runId,
114
+ sharedAt: Date.now()
115
+ });
116
+ logger.info("Shared team context", { type, priority });
117
+ return {
118
+ content: [
119
+ {
120
+ type: "text",
121
+ text: `Shared ${type}: ${content}`
122
+ }
123
+ ]
124
+ };
125
+ } catch (error) {
126
+ logger.error(
127
+ "Error sharing team context",
128
+ error instanceof Error ? error : new Error(String(error))
129
+ );
130
+ throw error;
131
+ }
132
+ }
133
+ /**
134
+ * Search across all agents' context in the project.
135
+ * Uses FTS5 search without run_id filtering.
136
+ */
137
+ async handleTeamSearch(args) {
138
+ try {
139
+ const { query, limit = 20, include_events = false } = args;
140
+ if (!query) {
141
+ throw new Error("query is required");
142
+ }
143
+ const projectId = this.getProjectId();
144
+ const results = await this.deps.dbAdapter.search({
145
+ query,
146
+ projectId,
147
+ limit
148
+ });
149
+ if (results.length === 0) {
150
+ return {
151
+ content: [
152
+ {
153
+ type: "text",
154
+ text: `No results found for "${query}" across team sessions.`
155
+ }
156
+ ]
157
+ };
158
+ }
159
+ const frameResults = results.map((f) => ({
160
+ frame_id: f.frame_id,
161
+ run_id: f.run_id,
162
+ name: f.name,
163
+ type: f.type,
164
+ state: f.state,
165
+ score: f.score,
166
+ digest_text: f.digest_text || null,
167
+ created_at: f.created_at,
168
+ events: []
169
+ }));
170
+ if (include_events) {
171
+ for (const fr of frameResults) {
172
+ const events = await this.deps.dbAdapter.getFrameEvents(fr.frame_id, {
173
+ limit: 5
174
+ });
175
+ fr.events = events.map((e) => ({
176
+ event_type: e.event_type,
177
+ payload: e.payload,
178
+ ts: e.ts
179
+ }));
180
+ }
181
+ }
182
+ const text = `Team Search: ${results.length} results for "${query}":
183
+
184
+ ` + frameResults.map(
185
+ (f) => `[${f.run_id?.slice(0, 8)}] ${f.name} (score: ${f.score?.toFixed(3)})` + (f.digest_text ? `
186
+ ${f.digest_text}` : "")
187
+ ).join("\n");
188
+ return {
189
+ content: [{ type: "text", text }],
190
+ metadata: { results: frameResults, total: results.length }
191
+ };
192
+ } catch (error) {
193
+ logger.error(
194
+ "Error in team search",
195
+ error instanceof Error ? error : new Error(String(error))
196
+ );
197
+ throw error;
198
+ }
199
+ }
200
+ /** Extract projectId from the dbAdapter (protected field on DatabaseAdapter) */
201
+ getProjectId() {
202
+ return this.deps.dbAdapter.projectId;
203
+ }
204
+ /** Extract current runId from frameManager (private field) */
205
+ getRunId() {
206
+ return this.deps.frameManager.currentRunId;
207
+ }
208
+ }
209
+ export {
210
+ TeamHandlers
211
+ };
@@ -11,6 +11,9 @@ class TraceHandlers {
11
11
  * Get traces with optional filtering
12
12
  */
13
13
  async handleGetTraces(args) {
14
+ if (args.analyze) {
15
+ return this.handleAnalyzeTraces(args);
16
+ }
14
17
  try {
15
18
  const {
16
19
  limit = 20,
@@ -73,7 +76,10 @@ ${summaryText}`
73
76
  }
74
77
  return result;
75
78
  } catch (error) {
76
- logger.error("Error getting traces", error instanceof Error ? error : new Error(String(error)));
79
+ logger.error(
80
+ "Error getting traces",
81
+ error instanceof Error ? error : new Error(String(error))
82
+ );
77
83
  throw error;
78
84
  }
79
85
  }
@@ -129,9 +135,7 @@ ${summaryText}`
129
135
  }
130
136
  if (include_recommendations && analysis.recommendations) {
131
137
  analysisText += "\n\nRecommendations:\n";
132
- analysisText += analysis.recommendations.map(
133
- (rec, i) => `${i + 1}. ${rec}`
134
- ).join("\n");
138
+ analysisText += analysis.recommendations.map((rec, i) => `${i + 1}. ${rec}`).join("\n");
135
139
  }
136
140
  return {
137
141
  content: [
@@ -147,7 +151,10 @@ ${summaryText}`
147
151
  }
148
152
  };
149
153
  } catch (error) {
150
- logger.error("Error analyzing traces", error instanceof Error ? error : new Error(String(error)));
154
+ logger.error(
155
+ "Error analyzing traces",
156
+ error instanceof Error ? error : new Error(String(error))
157
+ );
151
158
  throw error;
152
159
  }
153
160
  }
@@ -184,7 +191,10 @@ Navigated to: ${url}`
184
191
  }
185
192
  };
186
193
  } catch (error) {
187
- logger.error("Error starting browser debug session", error instanceof Error ? error : new Error(String(error)));
194
+ logger.error(
195
+ "Error starting browser debug session",
196
+ error instanceof Error ? error : new Error(String(error))
197
+ );
188
198
  throw error;
189
199
  }
190
200
  }
@@ -218,7 +228,10 @@ Navigated to: ${url}`
218
228
  }
219
229
  };
220
230
  } catch (error) {
221
- logger.error("Error taking screenshot", error instanceof Error ? error : new Error(String(error)));
231
+ logger.error(
232
+ "Error taking screenshot",
233
+ error instanceof Error ? error : new Error(String(error))
234
+ );
222
235
  throw error;
223
236
  }
224
237
  }
@@ -251,7 +264,10 @@ Result: ${JSON.stringify(result, null, 2)}`
251
264
  }
252
265
  };
253
266
  } catch (error) {
254
- logger.error("Error executing script", error instanceof Error ? error : new Error(String(error)));
267
+ logger.error(
268
+ "Error executing script",
269
+ error instanceof Error ? error : new Error(String(error))
270
+ );
255
271
  throw error;
256
272
  }
257
273
  }
@@ -279,7 +295,10 @@ Result: ${JSON.stringify(result, null, 2)}`
279
295
  }
280
296
  };
281
297
  } catch (error) {
282
- logger.error("Error stopping browser debug session", error instanceof Error ? error : new Error(String(error)));
298
+ logger.error(
299
+ "Error stopping browser debug session",
300
+ error instanceof Error ? error : new Error(String(error))
301
+ );
283
302
  throw error;
284
303
  }
285
304
  }
@@ -2,7 +2,7 @@ import { fileURLToPath as __fileURLToPath } from 'url';
2
2
  import { dirname as __pathDirname } from 'path';
3
3
  const __filename = __fileURLToPath(import.meta.url);
4
4
  const __dirname = __pathDirname(__filename);
5
- import { RefactoredStackMemoryMCP } from "./refactored-server.js";
5
+ import { StackMemoryMCP } from "./refactored-server.js";
6
6
  import { MCPHandlerFactory } from "./handlers/index.js";
7
7
  import { ContextHandlers } from "./handlers/context-handlers.js";
8
8
  import { TaskHandlers } from "./handlers/task-handlers.js";
@@ -16,7 +16,7 @@ export {
16
16
  LinearHandlers,
17
17
  MCPHandlerFactory,
18
18
  MCPToolDefinitions,
19
- RefactoredStackMemoryMCP as StackMemoryMCP,
19
+ StackMemoryMCP,
20
20
  TaskHandlers,
21
21
  TraceHandlers
22
22
  };
@@ -11,13 +11,14 @@ import { existsSync, mkdirSync } from "fs";
11
11
  import { join, dirname } from "path";
12
12
  import { execSync } from "child_process";
13
13
  import { v4 as uuidv4 } from "uuid";
14
- import { RefactoredFrameManager } from "../../core/context/refactored-frame-manager.js";
14
+ import { FrameManager } from "../../core/context/frame-manager.js";
15
15
  import { LinearTaskManager } from "../../features/tasks/linear-task-manager.js";
16
16
  import { LinearAuthManager } from "../linear/auth.js";
17
17
  import { LinearSyncEngine, DEFAULT_SYNC_CONFIG } from "../linear/sync.js";
18
18
  import { BrowserMCPIntegration } from "../../features/browser/browser-mcp.js";
19
19
  import { TraceDetector } from "../../core/trace/trace-detector.js";
20
20
  import { LLMContextRetrieval } from "../../core/retrieval/index.js";
21
+ import { SQLiteAdapter } from "../../core/database/sqlite-adapter.js";
21
22
  import { ConfigManager } from "../../core/config/config-manager.js";
22
23
  import { logger } from "../../core/monitoring/logger.js";
23
24
  import { MCPHandlerFactory } from "./handlers/index.js";
@@ -34,7 +35,7 @@ function getEnv(key, defaultValue) {
34
35
  function getOptionalEnv(key) {
35
36
  return process.env[key];
36
37
  }
37
- class RefactoredStackMemoryMCP {
38
+ class StackMemoryMCP {
38
39
  server;
39
40
  db;
40
41
  projectRoot;
@@ -47,6 +48,7 @@ class RefactoredStackMemoryMCP {
47
48
  browserMCP;
48
49
  traceDetector;
49
50
  contextRetrieval;
51
+ dbAdapter;
50
52
  configManager;
51
53
  toolScoringMiddleware;
52
54
  // Handler factory
@@ -70,6 +72,7 @@ class RefactoredStackMemoryMCP {
70
72
  }
71
73
  const dbPath = join(dbDir, "context.db");
72
74
  this.db = new Database(dbPath);
75
+ this.dbAdapter = new SQLiteAdapter(this.projectId, { dbPath });
73
76
  logger.info("Database initialized", { dbPath });
74
77
  }
75
78
  /**
@@ -78,7 +81,7 @@ class RefactoredStackMemoryMCP {
78
81
  initializeComponents(config) {
79
82
  const configPath = join(this.projectRoot, ".stackmemory", "config.yaml");
80
83
  this.configManager = new ConfigManager(configPath);
81
- this.frameManager = new RefactoredFrameManager(this.db, this.projectId);
84
+ this.frameManager = new FrameManager(this.db, this.projectId);
82
85
  this.taskStore = new LinearTaskManager(this.projectRoot, this.db);
83
86
  this.linearAuthManager = new LinearAuthManager(this.projectRoot);
84
87
  this.linearSync = new LinearSyncEngine(
@@ -140,7 +143,8 @@ class RefactoredStackMemoryMCP {
140
143
  linearAuthManager: this.linearAuthManager,
141
144
  linearSync: this.linearSync,
142
145
  traceDetector: this.traceDetector,
143
- browserMCP: this.browserMCP
146
+ browserMCP: this.browserMCP,
147
+ dbAdapter: this.dbAdapter
144
148
  };
145
149
  this.handlerFactory = new MCPHandlerFactory(dependencies);
146
150
  this.toolDefinitions = new MCPToolDefinitions();
@@ -275,6 +279,8 @@ class RefactoredStackMemoryMCP {
275
279
  */
276
280
  async start() {
277
281
  try {
282
+ await this.dbAdapter.connect();
283
+ await this.dbAdapter.initializeSchema();
278
284
  await this.frameManager.initialize();
279
285
  const transport = new StdioServerTransport();
280
286
  await this.server.connect(transport);
@@ -285,7 +291,10 @@ class RefactoredStackMemoryMCP {
285
291
  });
286
292
  this.setupCleanup();
287
293
  } catch (error) {
288
- logger.error("Failed to start MCP server", error instanceof Error ? error : new Error(String(error)));
294
+ logger.error(
295
+ "Failed to start MCP server",
296
+ error instanceof Error ? error : new Error(String(error))
297
+ );
289
298
  throw error;
290
299
  }
291
300
  }
@@ -299,19 +308,28 @@ class RefactoredStackMemoryMCP {
299
308
  if (this.browserMCP) {
300
309
  await this.browserMCP.cleanup();
301
310
  }
311
+ if (this.dbAdapter) {
312
+ await this.dbAdapter.disconnect();
313
+ }
302
314
  if (this.db) {
303
315
  this.db.close();
304
316
  }
305
317
  logger.info("MCP server shutdown complete");
306
318
  } catch (error) {
307
- logger.error("Error during cleanup", error instanceof Error ? error : new Error(String(error)));
319
+ logger.error(
320
+ "Error during cleanup",
321
+ error instanceof Error ? error : new Error(String(error))
322
+ );
308
323
  }
309
324
  process.exit(0);
310
325
  };
311
326
  process.on("SIGINT", cleanup);
312
327
  process.on("SIGTERM", cleanup);
313
328
  process.on("uncaughtException", (error) => {
314
- logger.error("Uncaught exception", error instanceof Error ? error : new Error(String(error)));
329
+ logger.error(
330
+ "Uncaught exception",
331
+ error instanceof Error ? error : new Error(String(error))
332
+ );
315
333
  cleanup();
316
334
  });
317
335
  }
@@ -355,10 +373,13 @@ async function main() {
355
373
  enableTracing: process.env["DISABLE_TRACING"] !== "true",
356
374
  enableBrowser: process.env["DISABLE_BROWSER"] !== "true"
357
375
  };
358
- const server = new RefactoredStackMemoryMCP(config);
376
+ const server = new StackMemoryMCP(config);
359
377
  await server.start();
360
378
  } catch (error) {
361
- logger.error("Failed to start server", error instanceof Error ? error : new Error(String(error)));
379
+ logger.error(
380
+ "Failed to start server",
381
+ error instanceof Error ? error : new Error(String(error))
382
+ );
362
383
  process.exit(1);
363
384
  }
364
385
  }
@@ -369,5 +390,5 @@ if (import.meta.url === `file://${process.argv[1]}`) {
369
390
  });
370
391
  }
371
392
  export {
372
- RefactoredStackMemoryMCP
393
+ StackMemoryMCP
373
394
  };