@stackmemoryai/stackmemory 1.2.2 → 1.2.4
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/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/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/integrations/linear/config.js +3 -1
- package/dist/src/integrations/linear/sync.js +18 -5
- 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 -1
- 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 +25 -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/tool-definitions.js +215 -1
- 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 +0 -102
- package/dist/src/utils/hook-installer.js +8 -0
- package/package.json +5 -5
- package/scripts/install-claude-hooks-auto.js +8 -0
- package/templates/claude-hooks/cord-trace.js +225 -0
- package/dist/src/core/config/storage-config.js +0 -114
- package/dist/src/core/storage/chromadb-adapter.js +0 -379
- package/dist/src/integrations/claude-code/enhanced-pre-clear-hooks.js +0 -458
- 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
|
@@ -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
|
+
};
|
|
@@ -73,7 +73,10 @@ ${summaryText}`
|
|
|
73
73
|
}
|
|
74
74
|
return result;
|
|
75
75
|
} catch (error) {
|
|
76
|
-
logger.error(
|
|
76
|
+
logger.error(
|
|
77
|
+
"Error getting traces",
|
|
78
|
+
error instanceof Error ? error : new Error(String(error))
|
|
79
|
+
);
|
|
77
80
|
throw error;
|
|
78
81
|
}
|
|
79
82
|
}
|
|
@@ -129,9 +132,7 @@ ${summaryText}`
|
|
|
129
132
|
}
|
|
130
133
|
if (include_recommendations && analysis.recommendations) {
|
|
131
134
|
analysisText += "\n\nRecommendations:\n";
|
|
132
|
-
analysisText += analysis.recommendations.map(
|
|
133
|
-
(rec, i) => `${i + 1}. ${rec}`
|
|
134
|
-
).join("\n");
|
|
135
|
+
analysisText += analysis.recommendations.map((rec, i) => `${i + 1}. ${rec}`).join("\n");
|
|
135
136
|
}
|
|
136
137
|
return {
|
|
137
138
|
content: [
|
|
@@ -147,7 +148,10 @@ ${summaryText}`
|
|
|
147
148
|
}
|
|
148
149
|
};
|
|
149
150
|
} catch (error) {
|
|
150
|
-
logger.error(
|
|
151
|
+
logger.error(
|
|
152
|
+
"Error analyzing traces",
|
|
153
|
+
error instanceof Error ? error : new Error(String(error))
|
|
154
|
+
);
|
|
151
155
|
throw error;
|
|
152
156
|
}
|
|
153
157
|
}
|
|
@@ -184,7 +188,10 @@ Navigated to: ${url}`
|
|
|
184
188
|
}
|
|
185
189
|
};
|
|
186
190
|
} catch (error) {
|
|
187
|
-
logger.error(
|
|
191
|
+
logger.error(
|
|
192
|
+
"Error starting browser debug session",
|
|
193
|
+
error instanceof Error ? error : new Error(String(error))
|
|
194
|
+
);
|
|
188
195
|
throw error;
|
|
189
196
|
}
|
|
190
197
|
}
|
|
@@ -218,7 +225,10 @@ Navigated to: ${url}`
|
|
|
218
225
|
}
|
|
219
226
|
};
|
|
220
227
|
} catch (error) {
|
|
221
|
-
logger.error(
|
|
228
|
+
logger.error(
|
|
229
|
+
"Error taking screenshot",
|
|
230
|
+
error instanceof Error ? error : new Error(String(error))
|
|
231
|
+
);
|
|
222
232
|
throw error;
|
|
223
233
|
}
|
|
224
234
|
}
|
|
@@ -251,7 +261,10 @@ Result: ${JSON.stringify(result, null, 2)}`
|
|
|
251
261
|
}
|
|
252
262
|
};
|
|
253
263
|
} catch (error) {
|
|
254
|
-
logger.error(
|
|
264
|
+
logger.error(
|
|
265
|
+
"Error executing script",
|
|
266
|
+
error instanceof Error ? error : new Error(String(error))
|
|
267
|
+
);
|
|
255
268
|
throw error;
|
|
256
269
|
}
|
|
257
270
|
}
|
|
@@ -279,7 +292,10 @@ Result: ${JSON.stringify(result, null, 2)}`
|
|
|
279
292
|
}
|
|
280
293
|
};
|
|
281
294
|
} catch (error) {
|
|
282
|
-
logger.error(
|
|
295
|
+
logger.error(
|
|
296
|
+
"Error stopping browser debug session",
|
|
297
|
+
error instanceof Error ? error : new Error(String(error))
|
|
298
|
+
);
|
|
283
299
|
throw error;
|
|
284
300
|
}
|
|
285
301
|
}
|
|
@@ -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
|
};
|
|
@@ -14,7 +14,9 @@ class MCPToolDefinitions {
|
|
|
14
14
|
...this.getTraceTools(),
|
|
15
15
|
...this.getDiscoveryTools(),
|
|
16
16
|
...this.getEditTools(),
|
|
17
|
-
...this.getGraphitiTools()
|
|
17
|
+
...this.getGraphitiTools(),
|
|
18
|
+
...this.getTeamTools(),
|
|
19
|
+
...this.getCordTools()
|
|
18
20
|
];
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
@@ -755,6 +757,214 @@ class MCPToolDefinitions {
|
|
|
755
757
|
}
|
|
756
758
|
];
|
|
757
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Multi-agent team collaboration tools
|
|
762
|
+
*/
|
|
763
|
+
getTeamTools() {
|
|
764
|
+
return [
|
|
765
|
+
{
|
|
766
|
+
name: "team_context_get",
|
|
767
|
+
description: "Get context from other agents working on the same project. Returns recent frames and shared anchors from other sessions.",
|
|
768
|
+
inputSchema: {
|
|
769
|
+
type: "object",
|
|
770
|
+
properties: {
|
|
771
|
+
limit: {
|
|
772
|
+
type: "number",
|
|
773
|
+
default: 10,
|
|
774
|
+
description: "Max frames to return"
|
|
775
|
+
},
|
|
776
|
+
types: {
|
|
777
|
+
type: "array",
|
|
778
|
+
items: { type: "string" },
|
|
779
|
+
description: "Filter by frame types"
|
|
780
|
+
},
|
|
781
|
+
since: {
|
|
782
|
+
type: "number",
|
|
783
|
+
description: "Only frames created after this timestamp (epoch ms)"
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
name: "team_context_share",
|
|
790
|
+
description: "Share a piece of context with other agents working on the same project. Creates a high-priority anchor visible to team_context_get.",
|
|
791
|
+
inputSchema: {
|
|
792
|
+
type: "object",
|
|
793
|
+
properties: {
|
|
794
|
+
content: {
|
|
795
|
+
type: "string",
|
|
796
|
+
description: "The context to share"
|
|
797
|
+
},
|
|
798
|
+
type: {
|
|
799
|
+
type: "string",
|
|
800
|
+
enum: [
|
|
801
|
+
"FACT",
|
|
802
|
+
"DECISION",
|
|
803
|
+
"CONSTRAINT",
|
|
804
|
+
"INTERFACE_CONTRACT",
|
|
805
|
+
"TODO",
|
|
806
|
+
"RISK"
|
|
807
|
+
],
|
|
808
|
+
default: "FACT",
|
|
809
|
+
description: "Type of context"
|
|
810
|
+
},
|
|
811
|
+
priority: {
|
|
812
|
+
type: "number",
|
|
813
|
+
minimum: 1,
|
|
814
|
+
maximum: 10,
|
|
815
|
+
default: 8,
|
|
816
|
+
description: "Priority level (1-10)"
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
required: ["content"]
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
name: "team_search",
|
|
824
|
+
description: "Search across all agents' context in the project. Uses full-text search across all sessions.",
|
|
825
|
+
inputSchema: {
|
|
826
|
+
type: "object",
|
|
827
|
+
properties: {
|
|
828
|
+
query: {
|
|
829
|
+
type: "string",
|
|
830
|
+
description: "Search query"
|
|
831
|
+
},
|
|
832
|
+
limit: {
|
|
833
|
+
type: "number",
|
|
834
|
+
default: 20,
|
|
835
|
+
description: "Maximum results to return"
|
|
836
|
+
},
|
|
837
|
+
include_events: {
|
|
838
|
+
type: "boolean",
|
|
839
|
+
default: false,
|
|
840
|
+
description: "Include events in results"
|
|
841
|
+
}
|
|
842
|
+
},
|
|
843
|
+
required: ["query"]
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
];
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Cord task orchestration tools
|
|
850
|
+
*/
|
|
851
|
+
getCordTools() {
|
|
852
|
+
return [
|
|
853
|
+
{
|
|
854
|
+
name: "cord_spawn",
|
|
855
|
+
description: "Create a subtask with clean context (spawn). Child sees only its prompt and completed blocker results.",
|
|
856
|
+
inputSchema: {
|
|
857
|
+
type: "object",
|
|
858
|
+
properties: {
|
|
859
|
+
goal: {
|
|
860
|
+
type: "string",
|
|
861
|
+
description: "What this task should accomplish"
|
|
862
|
+
},
|
|
863
|
+
prompt: {
|
|
864
|
+
type: "string",
|
|
865
|
+
description: "Detailed instructions for the task"
|
|
866
|
+
},
|
|
867
|
+
blocked_by: {
|
|
868
|
+
type: "array",
|
|
869
|
+
items: { type: "string" },
|
|
870
|
+
description: "Task IDs that must complete before this can start"
|
|
871
|
+
},
|
|
872
|
+
parent_id: {
|
|
873
|
+
type: "string",
|
|
874
|
+
description: "Parent task ID"
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
required: ["goal"]
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
name: "cord_fork",
|
|
882
|
+
description: "Create a subtask with full sibling context (fork). Child sees its prompt, blocker results, AND completed sibling results.",
|
|
883
|
+
inputSchema: {
|
|
884
|
+
type: "object",
|
|
885
|
+
properties: {
|
|
886
|
+
goal: {
|
|
887
|
+
type: "string",
|
|
888
|
+
description: "What this task should accomplish"
|
|
889
|
+
},
|
|
890
|
+
prompt: {
|
|
891
|
+
type: "string",
|
|
892
|
+
description: "Detailed instructions for the task"
|
|
893
|
+
},
|
|
894
|
+
blocked_by: {
|
|
895
|
+
type: "array",
|
|
896
|
+
items: { type: "string" },
|
|
897
|
+
description: "Task IDs that must complete before this can start"
|
|
898
|
+
},
|
|
899
|
+
parent_id: {
|
|
900
|
+
type: "string",
|
|
901
|
+
description: "Parent task ID"
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
required: ["goal"]
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
name: "cord_complete",
|
|
909
|
+
description: "Mark a cord task as completed with a result. Automatically unblocks dependent tasks.",
|
|
910
|
+
inputSchema: {
|
|
911
|
+
type: "object",
|
|
912
|
+
properties: {
|
|
913
|
+
task_id: {
|
|
914
|
+
type: "string",
|
|
915
|
+
description: "Task ID to complete"
|
|
916
|
+
},
|
|
917
|
+
result: {
|
|
918
|
+
type: "string",
|
|
919
|
+
description: "The result/output of this task"
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
required: ["task_id", "result"]
|
|
923
|
+
}
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
name: "cord_ask",
|
|
927
|
+
description: "Create an ask task \u2014 a question that needs an answer before dependent tasks can proceed.",
|
|
928
|
+
inputSchema: {
|
|
929
|
+
type: "object",
|
|
930
|
+
properties: {
|
|
931
|
+
question: {
|
|
932
|
+
type: "string",
|
|
933
|
+
description: "The question to ask"
|
|
934
|
+
},
|
|
935
|
+
options: {
|
|
936
|
+
type: "array",
|
|
937
|
+
items: { type: "string" },
|
|
938
|
+
description: "Optional list of answer choices"
|
|
939
|
+
},
|
|
940
|
+
parent_id: {
|
|
941
|
+
type: "string",
|
|
942
|
+
description: "Parent task ID"
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
required: ["question"]
|
|
946
|
+
}
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
name: "cord_tree",
|
|
950
|
+
description: "View the cord task tree with context scoping. Shows which tasks are active, blocked, or completed.",
|
|
951
|
+
inputSchema: {
|
|
952
|
+
type: "object",
|
|
953
|
+
properties: {
|
|
954
|
+
task_id: {
|
|
955
|
+
type: "string",
|
|
956
|
+
description: "Root task ID to show subtree (omit for full project tree)"
|
|
957
|
+
},
|
|
958
|
+
include_results: {
|
|
959
|
+
type: "boolean",
|
|
960
|
+
default: false,
|
|
961
|
+
description: "Include task results in output"
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
];
|
|
967
|
+
}
|
|
758
968
|
/**
|
|
759
969
|
* Get tool definition by name
|
|
760
970
|
*/
|
|
@@ -780,6 +990,10 @@ class MCPToolDefinitions {
|
|
|
780
990
|
return this.getEditTools();
|
|
781
991
|
case "graphiti":
|
|
782
992
|
return this.getGraphitiTools();
|
|
993
|
+
case "team":
|
|
994
|
+
return this.getTeamTools();
|
|
995
|
+
case "cord":
|
|
996
|
+
return this.getCordTools();
|
|
783
997
|
default:
|
|
784
998
|
return [];
|
|
785
999
|
}
|
|
@@ -115,14 +115,22 @@ class ContextBudgetManager {
|
|
|
115
115
|
const reductionRatio = this.config.maxTokens / currentTokens;
|
|
116
116
|
const phase = this.determinePhase(context.task.currentIteration);
|
|
117
117
|
const adjustedWeights = this.getPhaseAdjustedWeights(phase);
|
|
118
|
-
return this.applyWeightedReduction(
|
|
118
|
+
return this.applyWeightedReduction(
|
|
119
|
+
context,
|
|
120
|
+
reductionRatio,
|
|
121
|
+
adjustedWeights
|
|
122
|
+
);
|
|
119
123
|
}
|
|
120
124
|
/**
|
|
121
125
|
* Priority-based allocation using fixed weights
|
|
122
126
|
*/
|
|
123
127
|
priorityBasedAllocation(context, currentTokens) {
|
|
124
128
|
const reductionRatio = this.config.maxTokens / currentTokens;
|
|
125
|
-
return this.applyWeightedReduction(
|
|
129
|
+
return this.applyWeightedReduction(
|
|
130
|
+
context,
|
|
131
|
+
reductionRatio,
|
|
132
|
+
this.config.priorityWeights
|
|
133
|
+
);
|
|
126
134
|
}
|
|
127
135
|
/**
|
|
128
136
|
* Apply weighted reduction to context
|