@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.
- package/README.md +10 -6
- package/dist/src/cli/claude-sm.js +33 -4
- package/dist/src/cli/codex-sm-danger.js +4 -1
- package/dist/src/cli/codex-sm.js +6 -8
- package/dist/src/cli/commands/config.js +0 -81
- package/dist/src/cli/commands/context-rehydrate.js +133 -47
- package/dist/src/cli/commands/db.js +35 -8
- package/dist/src/cli/commands/handoff.js +1 -1
- package/dist/src/cli/commands/linear.js +9 -0
- package/dist/src/cli/commands/ralph.js +2 -2
- package/dist/src/cli/commands/setup.js +2 -2
- package/dist/src/cli/commands/signup.js +3 -1
- package/dist/src/cli/commands/skills.js +108 -1
- package/dist/src/cli/commands/storage-tier.js +26 -8
- package/dist/src/cli/index.js +1 -57
- package/dist/src/core/config/feature-flags.js +0 -4
- package/dist/src/core/context/dual-stack-manager.js +10 -3
- package/dist/src/core/context/frame-database.js +32 -0
- package/dist/src/core/context/frame-handoff-manager.js +2 -2
- package/dist/src/core/context/{refactored-frame-manager.js → frame-manager.js} +3 -3
- package/dist/src/core/context/index.js +2 -2
- package/dist/src/core/database/sqlite-adapter.js +161 -1
- package/dist/src/core/digest/frame-digest-integration.js +1 -1
- package/dist/src/core/digest/index.js +1 -1
- package/dist/src/core/execution/parallel-executor.js +5 -1
- package/dist/src/core/projects/project-isolation.js +18 -4
- package/dist/src/core/security/index.js +2 -0
- package/dist/src/core/security/input-sanitizer.js +23 -0
- package/dist/src/core/utils/update-checker.js +10 -6
- package/dist/src/daemon/daemon-config.js +2 -1
- package/dist/src/daemon/services/auto-save-service.js +121 -0
- package/dist/src/daemon/services/maintenance-service.js +76 -1
- package/dist/src/features/sweep/prompt-builder.js +2 -2
- package/dist/src/hooks/daemon.js +0 -8
- package/dist/src/integrations/linear/config.js +3 -1
- package/dist/src/integrations/linear/sync.js +18 -5
- package/dist/src/integrations/linear/webhook.js +0 -16
- package/dist/src/integrations/mcp/handlers/code-execution-handlers.js +33 -7
- package/dist/src/integrations/mcp/handlers/cord-handlers.js +397 -0
- package/dist/src/integrations/mcp/handlers/index.js +55 -9
- package/dist/src/integrations/mcp/handlers/task-handlers.js +55 -12
- package/dist/src/integrations/mcp/handlers/team-handlers.js +211 -0
- package/dist/src/integrations/mcp/handlers/trace-handlers.js +28 -9
- package/dist/src/integrations/mcp/index.js +2 -2
- package/dist/src/integrations/mcp/refactored-server.js +31 -10
- package/dist/src/integrations/mcp/server.js +0 -130
- package/dist/src/integrations/mcp/tool-definitions.js +196 -67
- package/dist/src/integrations/ralph/context/context-budget-manager.js +10 -2
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +54 -22
- package/dist/src/integrations/ralph/learning/pattern-learner.js +59 -24
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +81 -35
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +12 -4
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +32 -9
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +25 -8
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +17 -5
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +73 -22
- package/dist/src/skills/claude-skills.js +37 -103
- package/dist/src/skills/theory-skill.js +191 -0
- package/dist/src/utils/hook-installer.js +16 -0
- package/package.json +6 -6
- package/scripts/install-claude-hooks-auto.js +8 -0
- package/templates/claude-hooks/cord-trace.js +225 -0
- package/templates/claude-hooks/theory-capture.js +100 -0
- package/dist/src/core/config/storage-config.js +0 -114
- package/dist/src/core/storage/chromadb-adapter.js +0 -379
- package/dist/src/hooks/graphiti-hooks.js +0 -253
- package/dist/src/integrations/claude-code/enhanced-pre-clear-hooks.js +0 -458
- package/dist/src/integrations/graphiti/client.js +0 -115
- package/dist/src/integrations/graphiti/config.js +0 -17
- package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +0 -115
- package/dist/src/integrations/graphiti/types.js +0 -4
- package/dist/src/integrations/ralph/coordination/enhanced-coordination.js +0 -409
- package/dist/src/skills/repo-ingestion-skill.js +0 -631
- package/templates/claude-hooks/chromadb-wrapper +0 -21
- /package/dist/src/core/context/{enhanced-rehydration.js → rehydration.js} +0 -0
- /package/dist/src/core/digest/{enhanced-hybrid-digest.js → hybrid-digest.js} +0 -0
- /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 {
|
|
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(
|
|
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(
|
|
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", {
|
|
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(
|
|
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(
|
|
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(
|
|
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", {
|
|
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(
|
|
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(
|
|
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 = [
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
376
|
+
const server = new StackMemoryMCP(config);
|
|
359
377
|
await server.start();
|
|
360
378
|
} catch (error) {
|
|
361
|
-
logger.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
|
-
|
|
393
|
+
StackMemoryMCP
|
|
373
394
|
};
|