@stackmemoryai/stackmemory 1.2.1 → 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/skills.js +123 -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/graphiti-hooks.js +149 -0
- package/dist/src/hooks/session-summary.js +30 -0
- package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +115 -0
- package/dist/src/integrations/greptile/client.js +101 -0
- package/dist/src/integrations/greptile/config.js +14 -0
- package/dist/src/integrations/greptile/index.js +11 -0
- package/dist/src/integrations/greptile/types.js +4 -0
- 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 +16 -0
- 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/greptile-handlers.js +456 -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/server.js +27 -0
- 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 +46 -103
- package/dist/src/skills/parallel-agent-skill.js +514 -0
- package/dist/src/utils/hook-installer.js +8 -0
- package/package.json +5 -5
- package/scripts/gepa/.before-optimize.md +140 -159
- package/scripts/gepa/config.json +7 -1
- package/scripts/gepa/evals/fixtures/api-endpoint.ts +31 -0
- package/scripts/gepa/evals/fixtures/brittle-integration.ts +38 -0
- package/scripts/gepa/evals/fixtures/fts5-triggers.sql +23 -0
- package/scripts/gepa/evals/fixtures/leaky-service.ts +70 -0
- package/scripts/gepa/evals/fixtures/mcp-dispatch-stub.ts +39 -0
- package/scripts/gepa/evals/fixtures/pr-diff.txt +24 -0
- package/scripts/gepa/evals/fixtures/unsafe-webhook.ts +34 -0
- package/scripts/gepa/evals/fixtures/unwrapped-db-op.ts +42 -0
- package/scripts/gepa/evals/stackmemory-tasks.jsonl +8 -0
- package/scripts/gepa/generations/gen-000/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/variant-a.md +156 -146
- package/scripts/gepa/generations/gen-001/variant-b.md +199 -170
- package/scripts/gepa/generations/gen-001/variant-c.md +127 -46
- package/scripts/gepa/generations/gen-001/variant-d.md +160 -107
- package/scripts/gepa/hooks/reflect.js +44 -5
- package/scripts/gepa/optimize.js +281 -39
- package/scripts/gepa/results/eval-1-baseline.json +187 -10
- package/scripts/gepa/results/eval-1-variant-a.json +188 -11
- package/scripts/gepa/results/eval-1-variant-b.json +188 -11
- package/scripts/gepa/results/eval-1-variant-c.json +168 -11
- package/scripts/gepa/results/eval-1-variant-d.json +169 -12
- package/scripts/gepa/state.json +18 -18
- 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
|
@@ -29,7 +29,10 @@ class MultiLoopOrchestrator {
|
|
|
29
29
|
await sessionManager.initialize();
|
|
30
30
|
const session = await sessionManager.getOrCreateSession({});
|
|
31
31
|
if (session.database) {
|
|
32
|
-
this.frameManager = new FrameManager(
|
|
32
|
+
this.frameManager = new FrameManager(
|
|
33
|
+
session.database,
|
|
34
|
+
session.projectId
|
|
35
|
+
);
|
|
33
36
|
}
|
|
34
37
|
logger.info("Orchestrator initialized successfully");
|
|
35
38
|
} catch (error) {
|
|
@@ -92,11 +95,15 @@ class MultiLoopOrchestrator {
|
|
|
92
95
|
results: /* @__PURE__ */ new Map(),
|
|
93
96
|
sharedState: coordination?.sharedState || {}
|
|
94
97
|
};
|
|
95
|
-
const promises = tasks.map(
|
|
98
|
+
const promises = tasks.map(
|
|
99
|
+
(task) => this.executeParallelTask(task, execution)
|
|
100
|
+
);
|
|
96
101
|
try {
|
|
97
102
|
await Promise.allSettled(promises);
|
|
98
103
|
execution.endTime = Date.now();
|
|
99
|
-
execution.status = Array.from(execution.results.values()).every(
|
|
104
|
+
execution.status = Array.from(execution.results.values()).every(
|
|
105
|
+
(r) => r.success
|
|
106
|
+
) ? "success" : "partial";
|
|
100
107
|
return execution;
|
|
101
108
|
} catch (error) {
|
|
102
109
|
logger.error("Parallel execution failed", error);
|
|
@@ -111,16 +118,18 @@ class MultiLoopOrchestrator {
|
|
|
111
118
|
async analyzeAndBreakdownTask(description, criteria) {
|
|
112
119
|
const complexity = this.assessTaskComplexity(description);
|
|
113
120
|
if (complexity.score < 5) {
|
|
114
|
-
return [
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
return [
|
|
122
|
+
{
|
|
123
|
+
id: uuidv4(),
|
|
124
|
+
title: description,
|
|
125
|
+
description,
|
|
126
|
+
criteria,
|
|
127
|
+
priority: 1,
|
|
128
|
+
estimatedIterations: 3,
|
|
129
|
+
dependencies: [],
|
|
130
|
+
type: "single"
|
|
131
|
+
}
|
|
132
|
+
];
|
|
124
133
|
}
|
|
125
134
|
const subtasks = [];
|
|
126
135
|
if (this.needsSetup(description)) {
|
|
@@ -141,7 +150,9 @@ class MultiLoopOrchestrator {
|
|
|
141
150
|
id: uuidv4(),
|
|
142
151
|
title: "Core Implementation",
|
|
143
152
|
description: coreTask,
|
|
144
|
-
criteria: criteria.filter(
|
|
153
|
+
criteria: criteria.filter(
|
|
154
|
+
(c) => c.toLowerCase().includes("function") || c.toLowerCase().includes("implement")
|
|
155
|
+
),
|
|
145
156
|
priority: 2,
|
|
146
157
|
estimatedIterations: 5,
|
|
147
158
|
dependencies: subtasks.length > 0 ? [subtasks[0].id] : [],
|
|
@@ -172,16 +183,18 @@ class MultiLoopOrchestrator {
|
|
|
172
183
|
type: "documentation"
|
|
173
184
|
});
|
|
174
185
|
}
|
|
175
|
-
return subtasks.length > 0 ? subtasks : [
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
return subtasks.length > 0 ? subtasks : [
|
|
187
|
+
{
|
|
188
|
+
id: uuidv4(),
|
|
189
|
+
title: description,
|
|
190
|
+
description,
|
|
191
|
+
criteria,
|
|
192
|
+
priority: 1,
|
|
193
|
+
estimatedIterations: Math.min(8, Math.max(3, complexity.score)),
|
|
194
|
+
dependencies: [],
|
|
195
|
+
type: "single"
|
|
196
|
+
}
|
|
197
|
+
];
|
|
185
198
|
}
|
|
186
199
|
/**
|
|
187
200
|
* Create execution plan from breakdown
|
|
@@ -225,14 +238,19 @@ class MultiLoopOrchestrator {
|
|
|
225
238
|
try {
|
|
226
239
|
task.status = "executing";
|
|
227
240
|
for (const phase of task.executionPlan.phases) {
|
|
228
|
-
logger.info(
|
|
241
|
+
logger.info(
|
|
242
|
+
`Executing phase ${phase.id} with ${phase.tasks.length} tasks`
|
|
243
|
+
);
|
|
229
244
|
if (phase.parallelExecution && phase.tasks.length > 1) {
|
|
230
245
|
const parallelResult = await this.executeParallelLoops(phase.tasks);
|
|
231
246
|
for (const [taskId, taskResult] of parallelResult.results) {
|
|
232
247
|
if (taskResult.success) {
|
|
233
248
|
result.completedLoops.push(taskResult.loopId);
|
|
234
249
|
} else {
|
|
235
|
-
result.failedLoops.push({
|
|
250
|
+
result.failedLoops.push({
|
|
251
|
+
loopId: taskResult.loopId,
|
|
252
|
+
error: taskResult.error || "Unknown error"
|
|
253
|
+
});
|
|
236
254
|
}
|
|
237
255
|
}
|
|
238
256
|
} else {
|
|
@@ -244,7 +262,10 @@ class MultiLoopOrchestrator {
|
|
|
244
262
|
await this.updateSharedContext(task, loopResult);
|
|
245
263
|
}
|
|
246
264
|
} else {
|
|
247
|
-
result.failedLoops.push({
|
|
265
|
+
result.failedLoops.push({
|
|
266
|
+
loopId: loopResult.loopId,
|
|
267
|
+
error: loopResult.error || "Unknown error"
|
|
268
|
+
});
|
|
248
269
|
if (this.config.fallbackStrategy === "abort") {
|
|
249
270
|
throw new Error(`Task failed: ${loopResult.error}`);
|
|
250
271
|
}
|
|
@@ -302,7 +323,11 @@ class MultiLoopOrchestrator {
|
|
|
302
323
|
loopInfo.endTime = Date.now();
|
|
303
324
|
}
|
|
304
325
|
this.activeLoops.delete(taskBreakdown.id);
|
|
305
|
-
return {
|
|
326
|
+
return {
|
|
327
|
+
success: false,
|
|
328
|
+
loopId: taskBreakdown.id,
|
|
329
|
+
error: error.message
|
|
330
|
+
};
|
|
306
331
|
}
|
|
307
332
|
}
|
|
308
333
|
/**
|
|
@@ -314,7 +339,11 @@ class MultiLoopOrchestrator {
|
|
|
314
339
|
id: execution.id,
|
|
315
340
|
description: `Parallel task: ${task.title}`,
|
|
316
341
|
breakdown: [task],
|
|
317
|
-
executionPlan: {
|
|
342
|
+
executionPlan: {
|
|
343
|
+
phases: [],
|
|
344
|
+
totalEstimatedTime: 0,
|
|
345
|
+
parallelizable: false
|
|
346
|
+
},
|
|
318
347
|
status: "executing",
|
|
319
348
|
startTime: execution.startTime,
|
|
320
349
|
loops: /* @__PURE__ */ new Map(),
|
|
@@ -333,7 +362,10 @@ class MultiLoopOrchestrator {
|
|
|
333
362
|
* Update shared context between tasks
|
|
334
363
|
*/
|
|
335
364
|
async updateSharedContext(orchestratedTask, loopResult) {
|
|
336
|
-
logger.debug("Updating shared context", {
|
|
365
|
+
logger.debug("Updating shared context", {
|
|
366
|
+
orchestrationId: orchestratedTask.id,
|
|
367
|
+
loopId: loopResult.loopId
|
|
368
|
+
});
|
|
337
369
|
}
|
|
338
370
|
/**
|
|
339
371
|
* Generate insights from orchestration
|
|
@@ -342,12 +374,16 @@ class MultiLoopOrchestrator {
|
|
|
342
374
|
const insights = [];
|
|
343
375
|
const avgLoopDuration = Array.from(task.loops.values()).filter((l) => l.endTime && l.startTime).map((l) => l.endTime - l.startTime).reduce((sum, duration) => sum + duration, 0) / task.loops.size;
|
|
344
376
|
if (avgLoopDuration > 0) {
|
|
345
|
-
insights.push(
|
|
377
|
+
insights.push(
|
|
378
|
+
`Average loop duration: ${Math.round(avgLoopDuration / 1e3)}s`
|
|
379
|
+
);
|
|
346
380
|
}
|
|
347
381
|
const successRate = result.completedLoops.length / (result.completedLoops.length + result.failedLoops.length);
|
|
348
382
|
insights.push(`Success rate: ${Math.round(successRate * 100)}%`);
|
|
349
383
|
if (task.breakdown.length > 3) {
|
|
350
|
-
insights.push(
|
|
384
|
+
insights.push(
|
|
385
|
+
"Complex task benefited from breakdown into multiple loops"
|
|
386
|
+
);
|
|
351
387
|
}
|
|
352
388
|
return insights;
|
|
353
389
|
}
|
|
@@ -378,8 +414,16 @@ class MultiLoopOrchestrator {
|
|
|
378
414
|
return { score, factors };
|
|
379
415
|
}
|
|
380
416
|
needsSetup(description) {
|
|
381
|
-
const setupKeywords = [
|
|
382
|
-
|
|
417
|
+
const setupKeywords = [
|
|
418
|
+
"project",
|
|
419
|
+
"initialize",
|
|
420
|
+
"setup",
|
|
421
|
+
"scaffold",
|
|
422
|
+
"create structure"
|
|
423
|
+
];
|
|
424
|
+
return setupKeywords.some(
|
|
425
|
+
(keyword) => description.toLowerCase().includes(keyword)
|
|
426
|
+
);
|
|
383
427
|
}
|
|
384
428
|
needsTesting(criteria) {
|
|
385
429
|
return criteria.some((c) => c.toLowerCase().includes("test"));
|
|
@@ -389,7 +433,9 @@ class MultiLoopOrchestrator {
|
|
|
389
433
|
}
|
|
390
434
|
extractCoreTask(description) {
|
|
391
435
|
const sentences = description.split(".");
|
|
392
|
-
return sentences.find(
|
|
436
|
+
return sentences.find(
|
|
437
|
+
(s) => s.toLowerCase().includes("implement") || s.toLowerCase().includes("create") || s.toLowerCase().includes("add")
|
|
438
|
+
) || null;
|
|
393
439
|
}
|
|
394
440
|
canExecuteInParallel(breakdown) {
|
|
395
441
|
return breakdown.some((task) => task.dependencies.length === 0);
|
|
@@ -160,7 +160,9 @@ class CompoundingEngineeringManager {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
if (sessionData.codeStructure) {
|
|
163
|
-
const structurePattern = this.analyzeCodeStructurePattern(
|
|
163
|
+
const structurePattern = this.analyzeCodeStructurePattern(
|
|
164
|
+
sessionData.codeStructure
|
|
165
|
+
);
|
|
164
166
|
if (structurePattern) {
|
|
165
167
|
patterns.push(structurePattern);
|
|
166
168
|
}
|
|
@@ -228,7 +230,9 @@ class CompoundingEngineeringManager {
|
|
|
228
230
|
* Update compounded knowledge with new learning
|
|
229
231
|
*/
|
|
230
232
|
async updateCompoundedKnowledge(learning) {
|
|
231
|
-
this.knowledgeBase.learningsByCategory[learning.developmentPhase].push(
|
|
233
|
+
this.knowledgeBase.learningsByCategory[learning.developmentPhase].push(
|
|
234
|
+
learning
|
|
235
|
+
);
|
|
232
236
|
this.knowledgeBase.totalFeatures++;
|
|
233
237
|
await this.updateBestPractices(learning);
|
|
234
238
|
await this.updateMetrics(learning);
|
|
@@ -246,7 +250,9 @@ class CompoundingEngineeringManager {
|
|
|
246
250
|
* Generate automation hooks
|
|
247
251
|
*/
|
|
248
252
|
async generateHooks() {
|
|
249
|
-
const allOpportunities = Object.values(
|
|
253
|
+
const allOpportunities = Object.values(
|
|
254
|
+
this.knowledgeBase.learningsByCategory
|
|
255
|
+
).flat().flatMap((learning) => learning.automationOpportunities).filter((opp) => opp.implementation === "hook");
|
|
250
256
|
const hookCounts = /* @__PURE__ */ new Map();
|
|
251
257
|
for (const opp of allOpportunities) {
|
|
252
258
|
hookCounts.set(opp.task, (hookCounts.get(opp.task) || 0) + 1);
|
|
@@ -305,7 +311,9 @@ export async function ${hookName.replace(/-/g, "")}Hook() {
|
|
|
305
311
|
* Get current compounding metrics
|
|
306
312
|
*/
|
|
307
313
|
getCompoundingMetrics() {
|
|
308
|
-
const totalLearnings = Object.values(
|
|
314
|
+
const totalLearnings = Object.values(
|
|
315
|
+
this.knowledgeBase.learningsByCategory
|
|
316
|
+
).flat().length;
|
|
309
317
|
const automationLevel = this.knowledgeBase.automatedHooks.length / Math.max(totalLearnings, 1);
|
|
310
318
|
const recentLearnings = totalLearnings > 5 ? totalLearnings / 5 : totalLearnings;
|
|
311
319
|
return {
|
|
@@ -35,7 +35,9 @@ class ExtendedCoherenceManager {
|
|
|
35
35
|
*/
|
|
36
36
|
async startCoherenceSession(agentConfig, taskConfig, sessionConfig) {
|
|
37
37
|
const sessionId = uuidv4();
|
|
38
|
-
const defaultConfig = this.generateConfigForComplexity(
|
|
38
|
+
const defaultConfig = this.generateConfigForComplexity(
|
|
39
|
+
taskConfig.complexity
|
|
40
|
+
);
|
|
39
41
|
const config = { ...defaultConfig, ...sessionConfig };
|
|
40
42
|
const session = {
|
|
41
43
|
id: sessionId,
|
|
@@ -150,7 +152,11 @@ class ExtendedCoherenceManager {
|
|
|
150
152
|
duration: metrics.duration
|
|
151
153
|
});
|
|
152
154
|
if (overallCoherence < session.config.coherenceThreshold) {
|
|
153
|
-
await this.interventeInSession(
|
|
155
|
+
await this.interventeInSession(
|
|
156
|
+
session,
|
|
157
|
+
"coherence_degradation",
|
|
158
|
+
overallCoherence
|
|
159
|
+
);
|
|
154
160
|
}
|
|
155
161
|
const timeSinceCheckpoint = Date.now() - session.state.lastCheckpoint;
|
|
156
162
|
const checkpointDue = timeSinceCheckpoint > session.config.checkpointInterval * 60 * 1e3;
|
|
@@ -166,10 +172,16 @@ class ExtendedCoherenceManager {
|
|
|
166
172
|
const duration = (now - session.metrics[0]?.startTime || now) / (1e3 * 60);
|
|
167
173
|
const recentOutputs = await this.getRecentAgentOutputs(session);
|
|
168
174
|
const outputQuality = this.assessOutputQuality(recentOutputs);
|
|
169
|
-
const contextRetention = this.assessContextRetention(
|
|
175
|
+
const contextRetention = this.assessContextRetention(
|
|
176
|
+
recentOutputs,
|
|
177
|
+
session.task
|
|
178
|
+
);
|
|
170
179
|
const taskRelevance = this.assessTaskRelevance(recentOutputs, session.task);
|
|
171
180
|
const repetitionRate = this.calculateRepetitionRate(recentOutputs);
|
|
172
|
-
const divergenceRate = this.calculateDivergenceRate(
|
|
181
|
+
const divergenceRate = this.calculateDivergenceRate(
|
|
182
|
+
recentOutputs,
|
|
183
|
+
session.task
|
|
184
|
+
);
|
|
173
185
|
const errorRate = this.calculateErrorRate(recentOutputs);
|
|
174
186
|
const progressRate = this.calculateProgressRate(session);
|
|
175
187
|
return {
|
|
@@ -186,7 +198,9 @@ class ExtendedCoherenceManager {
|
|
|
186
198
|
errorRate,
|
|
187
199
|
memoryUsage: await this.getMemoryUsage(session),
|
|
188
200
|
contextWindowUsage: await this.getContextWindowUsage(session),
|
|
189
|
-
stateCheckpoints: session.interventions.filter(
|
|
201
|
+
stateCheckpoints: session.interventions.filter(
|
|
202
|
+
(i) => i.type === "checkpoint"
|
|
203
|
+
).length
|
|
190
204
|
};
|
|
191
205
|
}
|
|
192
206
|
/**
|
|
@@ -293,7 +307,9 @@ class ExtendedCoherenceManager {
|
|
|
293
307
|
* Restart session from last good checkpoint
|
|
294
308
|
*/
|
|
295
309
|
async restartSession(session) {
|
|
296
|
-
logger.info("Restarting session from checkpoint", {
|
|
310
|
+
logger.info("Restarting session from checkpoint", {
|
|
311
|
+
sessionId: session.id
|
|
312
|
+
});
|
|
297
313
|
const checkpoint = await this.loadLatestCheckpoint(session);
|
|
298
314
|
if (checkpoint) {
|
|
299
315
|
session.state = { ...checkpoint.state };
|
|
@@ -455,13 +471,20 @@ Begin your extended coherence work session now.
|
|
|
455
471
|
getCoherenceCapabilities() {
|
|
456
472
|
const activeSessions = Array.from(this.activeSessions.values());
|
|
457
473
|
return {
|
|
458
|
-
maxSessionDuration: Math.max(
|
|
459
|
-
|
|
474
|
+
maxSessionDuration: Math.max(
|
|
475
|
+
...activeSessions.map((s) => s.config.maxDuration)
|
|
476
|
+
),
|
|
477
|
+
activeSessionCount: activeSessions.filter(
|
|
478
|
+
(s) => s.state.status === "active"
|
|
479
|
+
).length,
|
|
460
480
|
averageCoherence: activeSessions.reduce((sum, s) => {
|
|
461
481
|
const recent = s.metrics.slice(-1)[0];
|
|
462
482
|
return sum + (recent ? this.calculateOverallCoherence(recent) : 0);
|
|
463
483
|
}, 0) / activeSessions.length,
|
|
464
|
-
totalInterventions: activeSessions.reduce(
|
|
484
|
+
totalInterventions: activeSessions.reduce(
|
|
485
|
+
(sum, s) => sum + s.interventions.length,
|
|
486
|
+
0
|
|
487
|
+
)
|
|
465
488
|
};
|
|
466
489
|
}
|
|
467
490
|
}
|
|
@@ -195,7 +195,9 @@ class GitWorkflowManager {
|
|
|
195
195
|
// Private helper methods
|
|
196
196
|
getCurrentBranch() {
|
|
197
197
|
try {
|
|
198
|
-
return execSync("git rev-parse --abbrev-ref HEAD", {
|
|
198
|
+
return execSync("git rev-parse --abbrev-ref HEAD", {
|
|
199
|
+
encoding: "utf8"
|
|
200
|
+
}).trim();
|
|
199
201
|
} catch (error) {
|
|
200
202
|
logger.warn("Failed to get current branch", error);
|
|
201
203
|
return "main";
|
|
@@ -229,7 +231,9 @@ class GitWorkflowManager {
|
|
|
229
231
|
createBranch(branchName) {
|
|
230
232
|
try {
|
|
231
233
|
try {
|
|
232
|
-
const currentBranch = execSync("git branch --show-current", {
|
|
234
|
+
const currentBranch = execSync("git branch --show-current", {
|
|
235
|
+
encoding: "utf8"
|
|
236
|
+
}).trim();
|
|
233
237
|
if (currentBranch === branchName) {
|
|
234
238
|
try {
|
|
235
239
|
execSync("git checkout main", { encoding: "utf8" });
|
|
@@ -238,17 +242,26 @@ class GitWorkflowManager {
|
|
|
238
242
|
}
|
|
239
243
|
}
|
|
240
244
|
try {
|
|
241
|
-
const worktrees = execSync("git worktree list --porcelain", {
|
|
245
|
+
const worktrees = execSync("git worktree list --porcelain", {
|
|
246
|
+
encoding: "utf8"
|
|
247
|
+
});
|
|
242
248
|
const lines = worktrees.split("\n");
|
|
243
249
|
for (let i = 0; i < lines.length; i++) {
|
|
244
250
|
if (lines[i].startsWith("branch ") && lines[i].includes(branchName)) {
|
|
245
251
|
const worktreetPath = lines[i - 1].replace("worktree ", "");
|
|
246
|
-
execSync(`git worktree remove --force "${worktreetPath}"`, {
|
|
247
|
-
|
|
252
|
+
execSync(`git worktree remove --force "${worktreetPath}"`, {
|
|
253
|
+
encoding: "utf8"
|
|
254
|
+
});
|
|
255
|
+
logger.info(
|
|
256
|
+
`Removed worktree at ${worktreetPath} for branch ${branchName}`
|
|
257
|
+
);
|
|
248
258
|
}
|
|
249
259
|
}
|
|
250
260
|
} catch (worktreeError) {
|
|
251
|
-
logger.warn(
|
|
261
|
+
logger.warn(
|
|
262
|
+
"Failed to check/remove worktrees",
|
|
263
|
+
worktreeError
|
|
264
|
+
);
|
|
252
265
|
}
|
|
253
266
|
execSync(`git branch -D ${branchName}`, { encoding: "utf8" });
|
|
254
267
|
logger.info(`Deleted existing branch ${branchName} for fresh start`);
|
|
@@ -257,7 +270,9 @@ class GitWorkflowManager {
|
|
|
257
270
|
execSync(`git checkout -b ${branchName}`, { encoding: "utf8" });
|
|
258
271
|
} catch (error) {
|
|
259
272
|
logger.error(`Failed to create branch ${branchName}`, error);
|
|
260
|
-
throw new GitWorkflowError(`Failed to create branch: ${branchName}`, {
|
|
273
|
+
throw new GitWorkflowError(`Failed to create branch: ${branchName}`, {
|
|
274
|
+
branchName
|
|
275
|
+
});
|
|
261
276
|
}
|
|
262
277
|
}
|
|
263
278
|
checkoutBranch(branchName) {
|
|
@@ -265,7 +280,9 @@ class GitWorkflowManager {
|
|
|
265
280
|
execSync(`git checkout ${branchName}`, { encoding: "utf8" });
|
|
266
281
|
} catch (error) {
|
|
267
282
|
logger.error(`Failed to checkout branch ${branchName}`, error);
|
|
268
|
-
throw new GitWorkflowError(`Failed to checkout branch: ${branchName}`, {
|
|
283
|
+
throw new GitWorkflowError(`Failed to checkout branch: ${branchName}`, {
|
|
284
|
+
branchName
|
|
285
|
+
});
|
|
269
286
|
}
|
|
270
287
|
}
|
|
271
288
|
branchExists(branchName) {
|
|
@@ -907,10 +907,15 @@ You are a PROJECT COORDINATOR. Your role is to:
|
|
|
907
907
|
await fs.rmdir(agent.workingDirectory, { recursive: true });
|
|
908
908
|
logger.debug(`Cleaned up working directory for agent ${agent.id}`);
|
|
909
909
|
} catch (error) {
|
|
910
|
-
logger.warn(
|
|
910
|
+
logger.warn(
|
|
911
|
+
`Could not clean up directory for agent ${agent.id}`,
|
|
912
|
+
error
|
|
913
|
+
);
|
|
911
914
|
}
|
|
912
915
|
}
|
|
913
|
-
await this.gitWorkflowManager.coordinateMerges(
|
|
916
|
+
await this.gitWorkflowManager.coordinateMerges(
|
|
917
|
+
Array.from(this.activeAgents.values())
|
|
918
|
+
);
|
|
914
919
|
this.activeAgents.clear();
|
|
915
920
|
this.swarmState = {
|
|
916
921
|
id: uuidv4(),
|
|
@@ -932,7 +937,10 @@ You are a PROJECT COORDINATOR. Your role is to:
|
|
|
932
937
|
logger.info("Swarm cleanup completed successfully");
|
|
933
938
|
} catch (error) {
|
|
934
939
|
logger.error("Failed to cleanup completed swarm", error);
|
|
935
|
-
throw new SwarmCoordinationError("Cleanup failed", {
|
|
940
|
+
throw new SwarmCoordinationError("Cleanup failed", {
|
|
941
|
+
swarmId: this.swarmState.id,
|
|
942
|
+
error
|
|
943
|
+
});
|
|
936
944
|
}
|
|
937
945
|
}
|
|
938
946
|
/**
|
|
@@ -958,14 +966,18 @@ You are a PROJECT COORDINATOR. Your role is to:
|
|
|
958
966
|
* Get swarm resource usage and cleanup recommendations
|
|
959
967
|
*/
|
|
960
968
|
getResourceUsage() {
|
|
961
|
-
const workingDirs = Array.from(this.activeAgents.values()).map(
|
|
969
|
+
const workingDirs = Array.from(this.activeAgents.values()).map(
|
|
970
|
+
(a) => a.workingDirectory
|
|
971
|
+
);
|
|
962
972
|
const memoryEstimate = this.activeAgents.size * 50;
|
|
963
973
|
const isStale = Date.now() - this.swarmState.startTime > 36e5;
|
|
964
974
|
const hasCompletedTasks = this.swarmState.completedTaskCount > 0 && this.swarmState.activeTaskCount === 0;
|
|
965
975
|
const recommendations = [];
|
|
966
976
|
let cleanupRecommended = false;
|
|
967
977
|
if (isStale) {
|
|
968
|
-
recommendations.push(
|
|
978
|
+
recommendations.push(
|
|
979
|
+
"Swarm has been running for over 1 hour - consider cleanup"
|
|
980
|
+
);
|
|
969
981
|
cleanupRecommended = true;
|
|
970
982
|
}
|
|
971
983
|
if (hasCompletedTasks) {
|
|
@@ -27,7 +27,10 @@ class RalphDebugger {
|
|
|
27
27
|
await sessionManager.initialize();
|
|
28
28
|
const session = await sessionManager.getOrCreateSession({});
|
|
29
29
|
if (session.database) {
|
|
30
|
-
this.frameManager = new FrameManager(
|
|
30
|
+
this.frameManager = new FrameManager(
|
|
31
|
+
session.database,
|
|
32
|
+
session.projectId
|
|
33
|
+
);
|
|
31
34
|
}
|
|
32
35
|
logger.info("Debugger initialized successfully");
|
|
33
36
|
} catch (error) {
|
|
@@ -111,7 +114,10 @@ class RalphDebugger {
|
|
|
111
114
|
contextSize: iter.contextSize,
|
|
112
115
|
phase: iter.phase
|
|
113
116
|
})),
|
|
114
|
-
totalDuration: session.performance.iterationTimes.reduce(
|
|
117
|
+
totalDuration: session.performance.iterationTimes.reduce(
|
|
118
|
+
(sum, time) => sum + time,
|
|
119
|
+
0
|
|
120
|
+
)
|
|
115
121
|
};
|
|
116
122
|
const html = await this.generateTimelineHTML(timeline);
|
|
117
123
|
const timelinePath = path.join(".ralph-debug", `timeline-${loopId}.html`);
|
|
@@ -165,7 +171,10 @@ class RalphDebugger {
|
|
|
165
171
|
diagram.metrics = {
|
|
166
172
|
totalNodes: diagram.nodes.length,
|
|
167
173
|
totalEdges: diagram.edges.length,
|
|
168
|
-
avgContextSize: session.performance.contextSizes.length > 0 ? session.performance.contextSizes.reduce(
|
|
174
|
+
avgContextSize: session.performance.contextSizes.length > 0 ? session.performance.contextSizes.reduce(
|
|
175
|
+
(sum, size) => sum + size,
|
|
176
|
+
0
|
|
177
|
+
) / session.performance.contextSizes.length : 0,
|
|
169
178
|
maxContextSize: Math.max(...session.performance.contextSizes)
|
|
170
179
|
};
|
|
171
180
|
return diagram;
|
|
@@ -230,15 +239,24 @@ class RalphDebugger {
|
|
|
230
239
|
async updatePerformanceMetrics(session) {
|
|
231
240
|
const currentMemory = process.memoryUsage().heapUsed;
|
|
232
241
|
session.performance.memoryUsage.push(currentMemory);
|
|
233
|
-
session.performance.peakMemory = Math.max(
|
|
242
|
+
session.performance.peakMemory = Math.max(
|
|
243
|
+
session.performance.peakMemory,
|
|
244
|
+
currentMemory
|
|
245
|
+
);
|
|
234
246
|
const contextSize = await this.calculateContextSize(session.ralphDir);
|
|
235
247
|
session.performance.contextSizes.push(contextSize);
|
|
236
248
|
if (session.performance.iterationTimes.length > 0) {
|
|
237
|
-
session.performance.averageIterationTime = session.performance.iterationTimes.reduce(
|
|
249
|
+
session.performance.averageIterationTime = session.performance.iterationTimes.reduce(
|
|
250
|
+
(sum, time) => sum + time,
|
|
251
|
+
0
|
|
252
|
+
) / session.performance.iterationTimes.length;
|
|
238
253
|
}
|
|
239
254
|
if (session.performance.contextSizes.length > 0) {
|
|
240
255
|
const avgContextSize = session.performance.contextSizes.reduce((sum, size) => sum + size, 0) / session.performance.contextSizes.length;
|
|
241
|
-
session.performance.contextEfficiency = Math.max(
|
|
256
|
+
session.performance.contextEfficiency = Math.max(
|
|
257
|
+
0,
|
|
258
|
+
1 - avgContextSize / 1e4
|
|
259
|
+
);
|
|
242
260
|
}
|
|
243
261
|
}
|
|
244
262
|
/**
|
|
@@ -246,8 +264,13 @@ class RalphDebugger {
|
|
|
246
264
|
*/
|
|
247
265
|
async generateSummary(session) {
|
|
248
266
|
const totalIterations = session.iterations.length;
|
|
249
|
-
const successfulIterations = session.iterations.filter(
|
|
250
|
-
|
|
267
|
+
const successfulIterations = session.iterations.filter(
|
|
268
|
+
(i) => i.success
|
|
269
|
+
).length;
|
|
270
|
+
const totalDuration = session.performance.iterationTimes.reduce(
|
|
271
|
+
(sum, time) => sum + time,
|
|
272
|
+
0
|
|
273
|
+
);
|
|
251
274
|
return {
|
|
252
275
|
loopId: session.loopId,
|
|
253
276
|
totalIterations,
|
|
@@ -271,18 +294,26 @@ class RalphDebugger {
|
|
|
271
294
|
const avgDuration = durations.reduce((sum, d) => sum + d, 0) / durations.length;
|
|
272
295
|
if (durations.some((d) => d > avgDuration * 2)) {
|
|
273
296
|
patterns.push("Variable iteration times detected");
|
|
274
|
-
insights.push(
|
|
297
|
+
insights.push(
|
|
298
|
+
"Some iterations took significantly longer than average - investigate bottlenecks"
|
|
299
|
+
);
|
|
275
300
|
}
|
|
276
|
-
const consecutiveFailures = this.findConsecutiveFailures(
|
|
301
|
+
const consecutiveFailures = this.findConsecutiveFailures(
|
|
302
|
+
session.iterations
|
|
303
|
+
);
|
|
277
304
|
if (consecutiveFailures.length > 2) {
|
|
278
305
|
patterns.push("Multiple consecutive failures detected");
|
|
279
|
-
insights.push(
|
|
306
|
+
insights.push(
|
|
307
|
+
"Consider adjusting approach or criteria after consecutive failures"
|
|
308
|
+
);
|
|
280
309
|
}
|
|
281
310
|
if (session.performance.contextSizes.length > 1) {
|
|
282
311
|
const contextGrowth = session.performance.contextSizes[session.performance.contextSizes.length - 1] - session.performance.contextSizes[0];
|
|
283
312
|
if (contextGrowth > 1e3) {
|
|
284
313
|
patterns.push("Significant context growth");
|
|
285
|
-
insights.push(
|
|
314
|
+
insights.push(
|
|
315
|
+
"Context is growing rapidly - consider context pruning strategies"
|
|
316
|
+
);
|
|
286
317
|
}
|
|
287
318
|
}
|
|
288
319
|
return { patterns, insights };
|
|
@@ -292,9 +323,14 @@ class RalphDebugger {
|
|
|
292
323
|
*/
|
|
293
324
|
async analyzeContextFlow(session) {
|
|
294
325
|
return {
|
|
295
|
-
avgContextSize: session.performance.contextSizes.length > 0 ? session.performance.contextSizes.reduce(
|
|
326
|
+
avgContextSize: session.performance.contextSizes.length > 0 ? session.performance.contextSizes.reduce(
|
|
327
|
+
(sum, size) => sum + size,
|
|
328
|
+
0
|
|
329
|
+
) / session.performance.contextSizes.length : 0,
|
|
296
330
|
maxContextSize: Math.max(...session.performance.contextSizes),
|
|
297
|
-
contextGrowthRate: this.calculateGrowthRate(
|
|
331
|
+
contextGrowthRate: this.calculateGrowthRate(
|
|
332
|
+
session.performance.contextSizes
|
|
333
|
+
),
|
|
298
334
|
efficiency: session.performance.contextEfficiency
|
|
299
335
|
};
|
|
300
336
|
}
|
|
@@ -303,7 +339,9 @@ class RalphDebugger {
|
|
|
303
339
|
*/
|
|
304
340
|
async analyzePerformance(session) {
|
|
305
341
|
return {
|
|
306
|
-
memoryEfficiency: this.calculateMemoryEfficiency(
|
|
342
|
+
memoryEfficiency: this.calculateMemoryEfficiency(
|
|
343
|
+
session.performance.memoryUsage
|
|
344
|
+
),
|
|
307
345
|
iterationEfficiency: session.performance.averageIterationTime,
|
|
308
346
|
resourceUtilization: {
|
|
309
347
|
cpu: "N/A",
|
|
@@ -318,7 +356,10 @@ class RalphDebugger {
|
|
|
318
356
|
*/
|
|
319
357
|
async generateVisualization(session) {
|
|
320
358
|
const htmlContent = await this.generateVisualizationHTML(session);
|
|
321
|
-
const vizPath = path.join(
|
|
359
|
+
const vizPath = path.join(
|
|
360
|
+
".ralph-debug",
|
|
361
|
+
`visualization-${session.loopId}.html`
|
|
362
|
+
);
|
|
322
363
|
await fs.mkdir(path.dirname(vizPath), { recursive: true });
|
|
323
364
|
await fs.writeFile(vizPath, htmlContent);
|
|
324
365
|
return {
|
|
@@ -343,17 +384,25 @@ class RalphDebugger {
|
|
|
343
384
|
async generateRecommendations(session) {
|
|
344
385
|
const recommendations = [];
|
|
345
386
|
if (session.performance.averageIterationTime > 3e4) {
|
|
346
|
-
recommendations.push(
|
|
387
|
+
recommendations.push(
|
|
388
|
+
"Consider breaking down complex tasks into smaller iterations"
|
|
389
|
+
);
|
|
347
390
|
}
|
|
348
391
|
if (session.performance.contextEfficiency < 0.7) {
|
|
349
|
-
recommendations.push(
|
|
392
|
+
recommendations.push(
|
|
393
|
+
"Optimize context management - consider using context budgeting"
|
|
394
|
+
);
|
|
350
395
|
}
|
|
351
396
|
const successRate = session.iterations.filter((i) => i.success).length / Math.max(1, session.iterations.length);
|
|
352
397
|
if (successRate < 0.5) {
|
|
353
|
-
recommendations.push(
|
|
398
|
+
recommendations.push(
|
|
399
|
+
"Low success rate detected - review task criteria and approach"
|
|
400
|
+
);
|
|
354
401
|
}
|
|
355
402
|
if (session.performance.peakMemory > 500 * 1024 * 1024) {
|
|
356
|
-
recommendations.push(
|
|
403
|
+
recommendations.push(
|
|
404
|
+
"High memory usage detected - investigate memory leaks"
|
|
405
|
+
);
|
|
357
406
|
}
|
|
358
407
|
return recommendations;
|
|
359
408
|
}
|
|
@@ -450,14 +499,16 @@ class RalphDebugger {
|
|
|
450
499
|
<body>
|
|
451
500
|
<h1>${timeline.title}</h1>
|
|
452
501
|
<div class="timeline">
|
|
453
|
-
${timeline.iterations.map(
|
|
502
|
+
${timeline.iterations.map(
|
|
503
|
+
(iter) => `
|
|
454
504
|
<div class="iteration ${iter.success ? "success" : "failure"}">
|
|
455
505
|
<h3>Iteration ${iter.iteration}</h3>
|
|
456
506
|
<p>Duration: ${iter.duration}ms</p>
|
|
457
507
|
<p>Changes: ${iter.changes} | Errors: ${iter.errors}</p>
|
|
458
508
|
<p>Context Size: ${iter.contextSize}</p>
|
|
459
509
|
</div>
|
|
460
|
-
`
|
|
510
|
+
`
|
|
511
|
+
).join("")}
|
|
461
512
|
</div>
|
|
462
513
|
</body>
|
|
463
514
|
</html>
|