@stackmemoryai/stackmemory 0.3.24 → 0.3.25
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/integrations/ralph/swarm/git-workflow-manager.js +309 -0
- package/dist/integrations/ralph/swarm/git-workflow-manager.js.map +7 -0
- package/dist/integrations/ralph/swarm/swarm-coordinator.js +169 -0
- package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +2 -2
- package/package.json +1 -1
- package/scripts/test-pre-publish-quick.sh +4 -2
- package/scripts/test-swarm-git-workflow.js +338 -0
- package/scripts/validate-swarm-implementation.js +467 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { logger } from "../../../core/monitoring/logger.js";
|
|
3
|
+
class GitWorkflowManager {
|
|
4
|
+
config;
|
|
5
|
+
agentBranches = /* @__PURE__ */ new Map();
|
|
6
|
+
baselineBranch;
|
|
7
|
+
mainBranch;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.config = {
|
|
10
|
+
enableGitWorkflow: true,
|
|
11
|
+
branchStrategy: "agent",
|
|
12
|
+
autoCommit: true,
|
|
13
|
+
commitFrequency: 5,
|
|
14
|
+
mergStrategy: "squash",
|
|
15
|
+
requirePR: false,
|
|
16
|
+
...config
|
|
17
|
+
};
|
|
18
|
+
try {
|
|
19
|
+
this.baselineBranch = this.getCurrentBranch();
|
|
20
|
+
this.mainBranch = this.getMainBranch();
|
|
21
|
+
} catch (error) {
|
|
22
|
+
logger.warn("Git not initialized, workflow features disabled");
|
|
23
|
+
this.config.enableGitWorkflow = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Initialize git workflow for an agent
|
|
28
|
+
*/
|
|
29
|
+
async initializeAgentWorkflow(agent, task) {
|
|
30
|
+
if (!this.config.enableGitWorkflow) return;
|
|
31
|
+
const branchName = this.generateBranchName(agent, task);
|
|
32
|
+
try {
|
|
33
|
+
this.createBranch(branchName);
|
|
34
|
+
this.agentBranches.set(agent.id, branchName);
|
|
35
|
+
logger.info(`Created git branch for agent ${agent.role}: ${branchName}`);
|
|
36
|
+
if (this.config.autoCommit) {
|
|
37
|
+
this.scheduleAutoCommit(agent, task);
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
logger.error(`Failed to initialize git workflow for agent ${agent.role}`, error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Commit agent work
|
|
45
|
+
*/
|
|
46
|
+
async commitAgentWork(agent, task, message) {
|
|
47
|
+
if (!this.config.enableGitWorkflow) return;
|
|
48
|
+
const branchName = this.agentBranches.get(agent.id);
|
|
49
|
+
if (!branchName) {
|
|
50
|
+
logger.warn(`No branch found for agent ${agent.id}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
this.checkoutBranch(branchName);
|
|
55
|
+
const hasChanges = this.hasUncommittedChanges();
|
|
56
|
+
if (!hasChanges) {
|
|
57
|
+
logger.debug(`No changes to commit for agent ${agent.role}`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
execSync("git add -A", { encoding: "utf8" });
|
|
61
|
+
const commitMessage = message || this.generateCommitMessage(agent, task);
|
|
62
|
+
execSync(`git commit -m "${commitMessage}"`, { encoding: "utf8" });
|
|
63
|
+
logger.info(`Agent ${agent.role} committed: ${commitMessage}`);
|
|
64
|
+
if (this.hasRemote()) {
|
|
65
|
+
try {
|
|
66
|
+
execSync(`git push origin ${branchName}`, { encoding: "utf8" });
|
|
67
|
+
logger.info(`Pushed branch ${branchName} to remote`);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logger.warn(`Could not push to remote: ${error}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
logger.error(`Failed to commit agent work`, error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Merge agent work back to baseline
|
|
78
|
+
*/
|
|
79
|
+
async mergeAgentWork(agent, task) {
|
|
80
|
+
if (!this.config.enableGitWorkflow) return;
|
|
81
|
+
const branchName = this.agentBranches.get(agent.id);
|
|
82
|
+
if (!branchName) {
|
|
83
|
+
logger.warn(`No branch found for agent ${agent.id}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
this.checkoutBranch(this.baselineBranch);
|
|
88
|
+
if (this.config.requirePR) {
|
|
89
|
+
await this.createPullRequest(agent, task, branchName);
|
|
90
|
+
} else {
|
|
91
|
+
this.mergeBranch(branchName);
|
|
92
|
+
logger.info(`Merged agent ${agent.role} work from ${branchName}`);
|
|
93
|
+
}
|
|
94
|
+
this.deleteBranch(branchName);
|
|
95
|
+
this.agentBranches.delete(agent.id);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
logger.error(`Failed to merge agent work`, error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Coordinate merges between multiple agents
|
|
102
|
+
*/
|
|
103
|
+
async coordinateMerges(agents) {
|
|
104
|
+
if (!this.config.enableGitWorkflow) return;
|
|
105
|
+
logger.info("Coordinating merges from all agents");
|
|
106
|
+
const integrationBranch = `swarm-integration-${Date.now()}`;
|
|
107
|
+
this.createBranch(integrationBranch);
|
|
108
|
+
for (const agent of agents) {
|
|
109
|
+
const branchName = this.agentBranches.get(agent.id);
|
|
110
|
+
if (branchName && this.branchExists(branchName)) {
|
|
111
|
+
try {
|
|
112
|
+
this.mergeBranch(branchName);
|
|
113
|
+
logger.info(`Integrated ${agent.role} work`);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
logger.error(`Failed to integrate ${agent.role} work: ${error}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const testsPass = await this.runIntegrationTests();
|
|
120
|
+
if (testsPass) {
|
|
121
|
+
this.checkoutBranch(this.baselineBranch);
|
|
122
|
+
this.mergeBranch(integrationBranch);
|
|
123
|
+
logger.info("Successfully integrated all agent work");
|
|
124
|
+
} else {
|
|
125
|
+
logger.warn("Integration tests failed, keeping changes in branch: " + integrationBranch);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Handle merge conflicts
|
|
130
|
+
*/
|
|
131
|
+
async resolveConflicts(agent) {
|
|
132
|
+
const conflicts = this.getConflictedFiles();
|
|
133
|
+
if (conflicts.length === 0) return;
|
|
134
|
+
logger.warn(`Agent ${agent.role} encountering merge conflicts: ${conflicts.join(", ")}`);
|
|
135
|
+
for (const file of conflicts) {
|
|
136
|
+
try {
|
|
137
|
+
if (this.isAgentFile(file, agent)) {
|
|
138
|
+
execSync(`git checkout --ours ${file}`, { encoding: "utf8" });
|
|
139
|
+
execSync(`git add ${file}`, { encoding: "utf8" });
|
|
140
|
+
} else {
|
|
141
|
+
execSync(`git checkout --theirs ${file}`, { encoding: "utf8" });
|
|
142
|
+
execSync(`git add ${file}`, { encoding: "utf8" });
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
logger.error(`Could not auto-resolve conflict in ${file}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const remainingConflicts = this.getConflictedFiles();
|
|
149
|
+
if (remainingConflicts.length === 0) {
|
|
150
|
+
execSync("git commit --no-edit", { encoding: "utf8" });
|
|
151
|
+
logger.info("All conflicts resolved automatically");
|
|
152
|
+
} else {
|
|
153
|
+
logger.error(`Manual intervention needed for: ${remainingConflicts.join(", ")}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Private helper methods
|
|
157
|
+
getCurrentBranch() {
|
|
158
|
+
return execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
|
|
159
|
+
}
|
|
160
|
+
getMainBranch() {
|
|
161
|
+
try {
|
|
162
|
+
const branches = execSync("git branch -r", { encoding: "utf8" });
|
|
163
|
+
if (branches.includes("origin/main")) return "main";
|
|
164
|
+
if (branches.includes("origin/master")) return "master";
|
|
165
|
+
} catch (error) {
|
|
166
|
+
}
|
|
167
|
+
return this.getCurrentBranch();
|
|
168
|
+
}
|
|
169
|
+
generateBranchName(agent, task) {
|
|
170
|
+
const sanitizedTitle = task.title.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").substring(0, 30);
|
|
171
|
+
switch (this.config.branchStrategy) {
|
|
172
|
+
case "feature":
|
|
173
|
+
return `feature/${sanitizedTitle}`;
|
|
174
|
+
case "task":
|
|
175
|
+
return `task/${task.id}`;
|
|
176
|
+
case "agent":
|
|
177
|
+
default:
|
|
178
|
+
return `swarm/${agent.role}-${sanitizedTitle}`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
createBranch(branchName) {
|
|
182
|
+
execSync(`git checkout -b ${branchName}`, { encoding: "utf8" });
|
|
183
|
+
}
|
|
184
|
+
checkoutBranch(branchName) {
|
|
185
|
+
execSync(`git checkout ${branchName}`, { encoding: "utf8" });
|
|
186
|
+
}
|
|
187
|
+
branchExists(branchName) {
|
|
188
|
+
try {
|
|
189
|
+
execSync(`git rev-parse --verify ${branchName}`, {
|
|
190
|
+
encoding: "utf8",
|
|
191
|
+
stdio: "pipe"
|
|
192
|
+
});
|
|
193
|
+
return true;
|
|
194
|
+
} catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
deleteBranch(branchName) {
|
|
199
|
+
try {
|
|
200
|
+
execSync(`git branch -d ${branchName}`, { encoding: "utf8" });
|
|
201
|
+
} catch (error) {
|
|
202
|
+
execSync(`git branch -D ${branchName}`, { encoding: "utf8" });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
mergeBranch(branchName) {
|
|
206
|
+
const strategy = this.config.mergStrategy;
|
|
207
|
+
switch (strategy) {
|
|
208
|
+
case "squash":
|
|
209
|
+
execSync(`git merge --squash ${branchName}`, { encoding: "utf8" });
|
|
210
|
+
execSync('git commit -m "Squashed agent changes"', { encoding: "utf8" });
|
|
211
|
+
break;
|
|
212
|
+
case "rebase":
|
|
213
|
+
execSync(`git rebase ${branchName}`, { encoding: "utf8" });
|
|
214
|
+
break;
|
|
215
|
+
case "merge":
|
|
216
|
+
default:
|
|
217
|
+
execSync(`git merge ${branchName}`, { encoding: "utf8" });
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
hasUncommittedChanges() {
|
|
222
|
+
const status = execSync("git status --porcelain", { encoding: "utf8" });
|
|
223
|
+
return status.trim().length > 0;
|
|
224
|
+
}
|
|
225
|
+
hasRemote() {
|
|
226
|
+
try {
|
|
227
|
+
execSync("git remote get-url origin", { encoding: "utf8" });
|
|
228
|
+
return true;
|
|
229
|
+
} catch {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
getConflictedFiles() {
|
|
234
|
+
try {
|
|
235
|
+
const conflicts = execSync("git diff --name-only --diff-filter=U", {
|
|
236
|
+
encoding: "utf8"
|
|
237
|
+
});
|
|
238
|
+
return conflicts.trim().split("\n").filter((f) => f.length > 0);
|
|
239
|
+
} catch {
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
isAgentFile(file, agent) {
|
|
244
|
+
return file.includes(agent.role) || file.includes(agent.id);
|
|
245
|
+
}
|
|
246
|
+
generateCommitMessage(agent, task) {
|
|
247
|
+
return `[${agent.role}] ${task.title} - Iteration ${agent.performance?.tasksCompleted || 1}`;
|
|
248
|
+
}
|
|
249
|
+
scheduleAutoCommit(agent, task) {
|
|
250
|
+
const intervalMs = this.config.commitFrequency * 60 * 1e3;
|
|
251
|
+
setInterval(async () => {
|
|
252
|
+
await this.commitAgentWork(agent, task, `[${agent.role}] Auto-commit: ${task.title}`);
|
|
253
|
+
}, intervalMs);
|
|
254
|
+
}
|
|
255
|
+
async createPullRequest(agent, task, branchName) {
|
|
256
|
+
try {
|
|
257
|
+
const title = `[Swarm ${agent.role}] ${task.title}`;
|
|
258
|
+
const body = `
|
|
259
|
+
## Agent: ${agent.role}
|
|
260
|
+
## Task: ${task.title}
|
|
261
|
+
|
|
262
|
+
### Acceptance Criteria:
|
|
263
|
+
${task.acceptanceCriteria.map((c) => `- ${c}`).join("\n")}
|
|
264
|
+
|
|
265
|
+
### Status:
|
|
266
|
+
- Tasks Completed: ${agent.performance?.tasksCompleted || 0}
|
|
267
|
+
- Success Rate: ${agent.performance?.successRate || 0}%
|
|
268
|
+
|
|
269
|
+
Generated by Swarm Coordinator
|
|
270
|
+
`;
|
|
271
|
+
execSync(`gh pr create --title "${title}" --body "${body}" --base ${this.baselineBranch}`, {
|
|
272
|
+
encoding: "utf8"
|
|
273
|
+
});
|
|
274
|
+
logger.info(`Created PR for agent ${agent.role}`);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
logger.warn(`Could not create PR: ${error}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async runIntegrationTests() {
|
|
280
|
+
try {
|
|
281
|
+
execSync("npm test", { encoding: "utf8" });
|
|
282
|
+
return true;
|
|
283
|
+
} catch {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get status of all agent branches
|
|
289
|
+
*/
|
|
290
|
+
getGitStatus() {
|
|
291
|
+
const status = {
|
|
292
|
+
enabled: this.config.enableGitWorkflow,
|
|
293
|
+
currentBranch: this.getCurrentBranch(),
|
|
294
|
+
agentBranches: Array.from(this.agentBranches.entries()).map(([agentId, branch]) => ({
|
|
295
|
+
agentId,
|
|
296
|
+
branch,
|
|
297
|
+
exists: this.branchExists(branch)
|
|
298
|
+
})),
|
|
299
|
+
hasUncommittedChanges: this.hasUncommittedChanges()
|
|
300
|
+
};
|
|
301
|
+
return status;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const gitWorkflowManager = new GitWorkflowManager();
|
|
305
|
+
export {
|
|
306
|
+
GitWorkflowManager,
|
|
307
|
+
gitWorkflowManager
|
|
308
|
+
};
|
|
309
|
+
//# sourceMappingURL=git-workflow-manager.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/integrations/ralph/swarm/git-workflow-manager.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Git Workflow Manager for Swarm Agents\n * Manages git operations, branching, and commits for each agent\n */\n\nimport { execSync } from 'child_process';\nimport { logger } from '../../../core/monitoring/logger.js';\nimport { Agent, SwarmTask } from '../types.js';\n\nexport interface GitConfig {\n enableGitWorkflow: boolean;\n branchStrategy: 'feature' | 'agent' | 'task';\n autoCommit: boolean;\n commitFrequency: number; // minutes\n mergStrategy: 'squash' | 'merge' | 'rebase';\n requirePR: boolean;\n}\n\nexport class GitWorkflowManager {\n private config: GitConfig;\n private agentBranches: Map<string, string> = new Map();\n private baselineBranch: string;\n private mainBranch: string;\n\n constructor(config?: Partial<GitConfig>) {\n this.config = {\n enableGitWorkflow: true,\n branchStrategy: 'agent',\n autoCommit: true,\n commitFrequency: 5,\n mergStrategy: 'squash',\n requirePR: false,\n ...config\n };\n\n // Get current branch as baseline\n try {\n this.baselineBranch = this.getCurrentBranch();\n this.mainBranch = this.getMainBranch();\n } catch (error) {\n logger.warn('Git not initialized, workflow features disabled');\n this.config.enableGitWorkflow = false;\n }\n }\n\n /**\n * Initialize git workflow for an agent\n */\n async initializeAgentWorkflow(agent: Agent, task: SwarmTask): Promise<void> {\n if (!this.config.enableGitWorkflow) return;\n\n const branchName = this.generateBranchName(agent, task);\n \n try {\n // Create and checkout new branch\n this.createBranch(branchName);\n this.agentBranches.set(agent.id, branchName);\n \n logger.info(`Created git branch for agent ${agent.role}: ${branchName}`);\n\n // Set up commit timer if auto-commit enabled\n if (this.config.autoCommit) {\n this.scheduleAutoCommit(agent, task);\n }\n } catch (error: unknown) {\n logger.error(`Failed to initialize git workflow for agent ${agent.role}`, error as Error);\n }\n }\n\n /**\n * Commit agent work\n */\n async commitAgentWork(\n agent: Agent, \n task: SwarmTask,\n message?: string\n ): Promise<void> {\n if (!this.config.enableGitWorkflow) return;\n\n const branchName = this.agentBranches.get(agent.id);\n if (!branchName) {\n logger.warn(`No branch found for agent ${agent.id}`);\n return;\n }\n\n try {\n // Ensure we're on the agent's branch\n this.checkoutBranch(branchName);\n\n // Check for changes\n const hasChanges = this.hasUncommittedChanges();\n if (!hasChanges) {\n logger.debug(`No changes to commit for agent ${agent.role}`);\n return;\n }\n\n // Stage all changes\n execSync('git add -A', { encoding: 'utf8' });\n\n // Generate commit message\n const commitMessage = message || this.generateCommitMessage(agent, task);\n \n // Commit changes\n execSync(`git commit -m \"${commitMessage}\"`, { encoding: 'utf8' });\n \n logger.info(`Agent ${agent.role} committed: ${commitMessage}`);\n\n // Push if remote exists\n if (this.hasRemote()) {\n try {\n execSync(`git push origin ${branchName}`, { encoding: 'utf8' });\n logger.info(`Pushed branch ${branchName} to remote`);\n } catch (error) {\n logger.warn(`Could not push to remote: ${error}`);\n }\n }\n } catch (error: unknown) {\n logger.error(`Failed to commit agent work`, error as Error);\n }\n }\n\n /**\n * Merge agent work back to baseline\n */\n async mergeAgentWork(agent: Agent, task: SwarmTask): Promise<void> {\n if (!this.config.enableGitWorkflow) return;\n\n const branchName = this.agentBranches.get(agent.id);\n if (!branchName) {\n logger.warn(`No branch found for agent ${agent.id}`);\n return;\n }\n\n try {\n // Switch to baseline branch\n this.checkoutBranch(this.baselineBranch);\n\n if (this.config.requirePR) {\n // Create pull request\n await this.createPullRequest(agent, task, branchName);\n } else {\n // Direct merge based on strategy\n this.mergeBranch(branchName);\n logger.info(`Merged agent ${agent.role} work from ${branchName}`);\n }\n\n // Clean up branch\n this.deleteBranch(branchName);\n this.agentBranches.delete(agent.id);\n\n } catch (error: unknown) {\n logger.error(`Failed to merge agent work`, error as Error);\n }\n }\n\n /**\n * Coordinate merges between multiple agents\n */\n async coordinateMerges(agents: Agent[]): Promise<void> {\n if (!this.config.enableGitWorkflow) return;\n\n logger.info('Coordinating merges from all agents');\n\n // Create integration branch\n const integrationBranch = `swarm-integration-${Date.now()}`;\n this.createBranch(integrationBranch);\n\n // Merge each agent's work\n for (const agent of agents) {\n const branchName = this.agentBranches.get(agent.id);\n if (branchName && this.branchExists(branchName)) {\n try {\n this.mergeBranch(branchName);\n logger.info(`Integrated ${agent.role} work`);\n } catch (error) {\n logger.error(`Failed to integrate ${agent.role} work: ${error}`);\n }\n }\n }\n\n // Run tests on integration branch\n const testsPass = await this.runIntegrationTests();\n \n if (testsPass) {\n // Merge to baseline\n this.checkoutBranch(this.baselineBranch);\n this.mergeBranch(integrationBranch);\n logger.info('Successfully integrated all agent work');\n } else {\n logger.warn('Integration tests failed, keeping changes in branch: ' + integrationBranch);\n }\n }\n\n /**\n * Handle merge conflicts\n */\n async resolveConflicts(agent: Agent): Promise<void> {\n const conflicts = this.getConflictedFiles();\n \n if (conflicts.length === 0) return;\n\n logger.warn(`Agent ${agent.role} encountering merge conflicts: ${conflicts.join(', ')}`);\n\n // Strategy 1: Try to auto-resolve\n for (const file of conflicts) {\n try {\n // Accept current changes for agent's own files\n if (this.isAgentFile(file, agent)) {\n execSync(`git checkout --ours ${file}`, { encoding: 'utf8' });\n execSync(`git add ${file}`, { encoding: 'utf8' });\n } else {\n // Accept incoming changes for other files\n execSync(`git checkout --theirs ${file}`, { encoding: 'utf8' });\n execSync(`git add ${file}`, { encoding: 'utf8' });\n }\n } catch (error) {\n logger.error(`Could not auto-resolve conflict in ${file}`);\n }\n }\n\n // Complete merge if all conflicts resolved\n const remainingConflicts = this.getConflictedFiles();\n if (remainingConflicts.length === 0) {\n execSync('git commit --no-edit', { encoding: 'utf8' });\n logger.info('All conflicts resolved automatically');\n } else {\n logger.error(`Manual intervention needed for: ${remainingConflicts.join(', ')}`);\n }\n }\n\n // Private helper methods\n private getCurrentBranch(): string {\n return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();\n }\n\n private getMainBranch(): string {\n try {\n // Try to detect main branch\n const branches = execSync('git branch -r', { encoding: 'utf8' });\n if (branches.includes('origin/main')) return 'main';\n if (branches.includes('origin/master')) return 'master';\n } catch (error) {\n // Fallback to current branch\n }\n return this.getCurrentBranch();\n }\n\n private generateBranchName(agent: Agent, task: SwarmTask): string {\n const sanitizedTitle = task.title.toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-]/g, '')\n .substring(0, 30);\n\n switch (this.config.branchStrategy) {\n case 'feature':\n return `feature/${sanitizedTitle}`;\n case 'task':\n return `task/${task.id}`;\n case 'agent':\n default:\n return `swarm/${agent.role}-${sanitizedTitle}`;\n }\n }\n\n private createBranch(branchName: string): void {\n execSync(`git checkout -b ${branchName}`, { encoding: 'utf8' });\n }\n\n private checkoutBranch(branchName: string): void {\n execSync(`git checkout ${branchName}`, { encoding: 'utf8' });\n }\n\n private branchExists(branchName: string): boolean {\n try {\n execSync(`git rev-parse --verify ${branchName}`, { \n encoding: 'utf8',\n stdio: 'pipe'\n });\n return true;\n } catch {\n return false;\n }\n }\n\n private deleteBranch(branchName: string): void {\n try {\n execSync(`git branch -d ${branchName}`, { encoding: 'utf8' });\n } catch (error) {\n // Force delete if needed\n execSync(`git branch -D ${branchName}`, { encoding: 'utf8' });\n }\n }\n\n private mergeBranch(branchName: string): void {\n const strategy = this.config.mergStrategy;\n \n switch (strategy) {\n case 'squash':\n execSync(`git merge --squash ${branchName}`, { encoding: 'utf8' });\n execSync('git commit -m \"Squashed agent changes\"', { encoding: 'utf8' });\n break;\n case 'rebase':\n execSync(`git rebase ${branchName}`, { encoding: 'utf8' });\n break;\n case 'merge':\n default:\n execSync(`git merge ${branchName}`, { encoding: 'utf8' });\n break;\n }\n }\n\n private hasUncommittedChanges(): boolean {\n const status = execSync('git status --porcelain', { encoding: 'utf8' });\n return status.trim().length > 0;\n }\n\n private hasRemote(): boolean {\n try {\n execSync('git remote get-url origin', { encoding: 'utf8' });\n return true;\n } catch {\n return false;\n }\n }\n\n private getConflictedFiles(): string[] {\n try {\n const conflicts = execSync('git diff --name-only --diff-filter=U', { \n encoding: 'utf8' \n });\n return conflicts.trim().split('\\n').filter(f => f.length > 0);\n } catch {\n return [];\n }\n }\n\n private isAgentFile(file: string, agent: Agent): boolean {\n // Simple heuristic: check if file is in agent's working directory\n return file.includes(agent.role) || file.includes(agent.id);\n }\n\n private generateCommitMessage(agent: Agent, task: SwarmTask): string {\n return `[${agent.role}] ${task.title} - Iteration ${agent.performance?.tasksCompleted || 1}`;\n }\n\n private scheduleAutoCommit(agent: Agent, task: SwarmTask): void {\n const intervalMs = this.config.commitFrequency * 60 * 1000;\n \n setInterval(async () => {\n await this.commitAgentWork(agent, task, `[${agent.role}] Auto-commit: ${task.title}`);\n }, intervalMs);\n }\n\n private async createPullRequest(agent: Agent, task: SwarmTask, branchName: string): Promise<void> {\n try {\n const title = `[Swarm ${agent.role}] ${task.title}`;\n const body = `\n## Agent: ${agent.role}\n## Task: ${task.title}\n\n### Acceptance Criteria:\n${task.acceptanceCriteria.map(c => `- ${c}`).join('\\n')}\n\n### Status:\n- Tasks Completed: ${agent.performance?.tasksCompleted || 0}\n- Success Rate: ${agent.performance?.successRate || 0}%\n\nGenerated by Swarm Coordinator\n `;\n\n execSync(`gh pr create --title \"${title}\" --body \"${body}\" --base ${this.baselineBranch}`, {\n encoding: 'utf8'\n });\n \n logger.info(`Created PR for agent ${agent.role}`);\n } catch (error) {\n logger.warn(`Could not create PR: ${error}`);\n }\n }\n\n private async runIntegrationTests(): Promise<boolean> {\n try {\n // Try to run tests\n execSync('npm test', { encoding: 'utf8' });\n return true;\n } catch {\n // Tests failed or not available\n return false;\n }\n }\n\n /**\n * Get status of all agent branches\n */\n getGitStatus(): object {\n const status: any = {\n enabled: this.config.enableGitWorkflow,\n currentBranch: this.getCurrentBranch(),\n agentBranches: Array.from(this.agentBranches.entries()).map(([agentId, branch]) => ({\n agentId,\n branch,\n exists: this.branchExists(branch)\n })),\n hasUncommittedChanges: this.hasUncommittedChanges()\n };\n\n return status;\n }\n}\n\nexport const gitWorkflowManager = new GitWorkflowManager();"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
2
4
|
import { logger } from "../../../core/monitoring/logger.js";
|
|
3
5
|
import { FrameManager } from "../../../core/context/frame-manager.js";
|
|
4
6
|
import { sessionManager } from "../../../core/session/index.js";
|
|
5
7
|
import { sharedContextLayer } from "../../../core/context/shared-context-layer.js";
|
|
6
8
|
import { RalphStackMemoryBridge } from "../bridge/ralph-stackmemory-bridge.js";
|
|
9
|
+
import { GitWorkflowManager } from "./git-workflow-manager.js";
|
|
7
10
|
class SwarmCoordinator {
|
|
8
11
|
frameManager;
|
|
9
12
|
activeAgents = /* @__PURE__ */ new Map();
|
|
@@ -11,6 +14,7 @@ class SwarmCoordinator {
|
|
|
11
14
|
config;
|
|
12
15
|
coordinationTimer;
|
|
13
16
|
plannerWakeupQueue = /* @__PURE__ */ new Map();
|
|
17
|
+
gitWorkflowManager;
|
|
14
18
|
constructor(config) {
|
|
15
19
|
this.config = {
|
|
16
20
|
maxAgents: 10,
|
|
@@ -42,6 +46,13 @@ class SwarmCoordinator {
|
|
|
42
46
|
coordination_overhead: 0
|
|
43
47
|
}
|
|
44
48
|
};
|
|
49
|
+
this.gitWorkflowManager = new GitWorkflowManager({
|
|
50
|
+
enableGitWorkflow: true,
|
|
51
|
+
branchStrategy: "agent",
|
|
52
|
+
autoCommit: true,
|
|
53
|
+
commitFrequency: 5,
|
|
54
|
+
mergStrategy: "squash"
|
|
55
|
+
});
|
|
45
56
|
logger.info("Swarm coordinator initialized", this.config);
|
|
46
57
|
}
|
|
47
58
|
async initialize() {
|
|
@@ -256,6 +267,7 @@ class SwarmCoordinator {
|
|
|
256
267
|
logger.info(`Agent ${agent.role} starting task: ${task.title}`);
|
|
257
268
|
try {
|
|
258
269
|
agent.status = "active";
|
|
270
|
+
await this.gitWorkflowManager.initializeAgentWorkflow(agent, task);
|
|
259
271
|
const ralph = new RalphStackMemoryBridge({
|
|
260
272
|
baseDir: path.join(agent.workingDirectory, task.id),
|
|
261
273
|
maxIterations: this.calculateMaxIterations(task),
|
|
@@ -268,7 +280,9 @@ class SwarmCoordinator {
|
|
|
268
280
|
});
|
|
269
281
|
this.setupAgentCoordination(agent, ralph, assignment);
|
|
270
282
|
await ralph.run();
|
|
283
|
+
await this.gitWorkflowManager.commitAgentWork(agent, task);
|
|
271
284
|
this.updateAgentPerformance(agent, true);
|
|
285
|
+
await this.gitWorkflowManager.mergeAgentWork(agent, task);
|
|
272
286
|
await this.notifyTaskCompletion(agent, task, true);
|
|
273
287
|
agent.status = "idle";
|
|
274
288
|
logger.info(`Agent ${agent.role} completed task: ${task.title}`);
|
|
@@ -477,6 +491,161 @@ You are a PROJECT COORDINATOR. Your role is to:
|
|
|
477
491
|
}];
|
|
478
492
|
}
|
|
479
493
|
// Implement remaining helper methods...
|
|
494
|
+
async setupAgentEnvironment(agent) {
|
|
495
|
+
try {
|
|
496
|
+
await fs.mkdir(agent.workingDirectory, { recursive: true });
|
|
497
|
+
logger.debug(`Created working directory for agent ${agent.id}: ${agent.workingDirectory}`);
|
|
498
|
+
} catch (error) {
|
|
499
|
+
logger.warn(`Could not create working directory for agent ${agent.id}`, error);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
async configureAgentPrompts(agent) {
|
|
503
|
+
logger.debug(`Configured prompts for agent ${agent.role}`);
|
|
504
|
+
}
|
|
505
|
+
topologicalSort(tasks) {
|
|
506
|
+
const sorted = [];
|
|
507
|
+
const visited = /* @__PURE__ */ new Set();
|
|
508
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
509
|
+
const visit = (task) => {
|
|
510
|
+
if (visited.has(task.id)) return;
|
|
511
|
+
if (visiting.has(task.id)) {
|
|
512
|
+
logger.warn(`Circular dependency detected for task: ${task.id}`);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
visiting.add(task.id);
|
|
516
|
+
for (const depId of task.dependencies) {
|
|
517
|
+
const depTask = tasks.find((t) => t.id === depId);
|
|
518
|
+
if (depTask) visit(depTask);
|
|
519
|
+
}
|
|
520
|
+
visiting.delete(task.id);
|
|
521
|
+
visited.add(task.id);
|
|
522
|
+
sorted.push(task);
|
|
523
|
+
};
|
|
524
|
+
tasks.forEach(visit);
|
|
525
|
+
return sorted;
|
|
526
|
+
}
|
|
527
|
+
agentCanHandle(agent, role) {
|
|
528
|
+
return agent.role === role || agent.capabilities.includes(role);
|
|
529
|
+
}
|
|
530
|
+
selectOptimalAgent(agents, task) {
|
|
531
|
+
return agents.reduce((best, current) => {
|
|
532
|
+
const bestLoad = best.currentTask ? 1 : 0;
|
|
533
|
+
const currentLoad = current.currentTask ? 1 : 0;
|
|
534
|
+
return currentLoad < bestLoad ? current : best;
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
estimateTaskDuration(task) {
|
|
538
|
+
const durations = {
|
|
539
|
+
low: 6e4,
|
|
540
|
+
// 1 minute
|
|
541
|
+
medium: 3e5,
|
|
542
|
+
// 5 minutes
|
|
543
|
+
high: 9e5
|
|
544
|
+
// 15 minutes
|
|
545
|
+
};
|
|
546
|
+
return durations[task.estimatedEffort] || 3e5;
|
|
547
|
+
}
|
|
548
|
+
findCollaborators(agent, task, agents) {
|
|
549
|
+
return agents.filter((a) => a.id !== agent.id && a.currentTask).map((a) => a.id).slice(0, 2);
|
|
550
|
+
}
|
|
551
|
+
findReviewers(agent, task, agents) {
|
|
552
|
+
return agents.filter((a) => a.role === "reviewer" && a.id !== agent.id).map((a) => a.id);
|
|
553
|
+
}
|
|
554
|
+
calculateMaxIterations(task) {
|
|
555
|
+
const iterations = {
|
|
556
|
+
low: 5,
|
|
557
|
+
medium: 10,
|
|
558
|
+
high: 20
|
|
559
|
+
};
|
|
560
|
+
return iterations[task.estimatedEffort] || 10;
|
|
561
|
+
}
|
|
562
|
+
async getSwarmContext(task) {
|
|
563
|
+
const relatedTasks = Array.from(this.activeAgents.values()).filter((a) => a.currentTask).map((a) => `- Agent ${a.role} is working on task ${a.currentTask}`).join("\n");
|
|
564
|
+
return relatedTasks || "No other agents currently active";
|
|
565
|
+
}
|
|
566
|
+
getCoordinationInstructions(agent) {
|
|
567
|
+
return `
|
|
568
|
+
- Save progress to shared context regularly
|
|
569
|
+
- Check for updates from collaborators
|
|
570
|
+
- Request help if blocked for more than 2 iterations
|
|
571
|
+
- Report completion immediately`;
|
|
572
|
+
}
|
|
573
|
+
setupAgentCoordination(agent, ralph, assignment) {
|
|
574
|
+
logger.debug(`Setting up coordination for agent ${agent.id}`);
|
|
575
|
+
}
|
|
576
|
+
updateAgentPerformance(agent, success) {
|
|
577
|
+
agent.performance.tasksCompleted++;
|
|
578
|
+
if (!success) {
|
|
579
|
+
agent.performance.successRate = agent.performance.successRate * (agent.performance.tasksCompleted - 1) / agent.performance.tasksCompleted;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async notifyTaskCompletion(agent, task, success) {
|
|
583
|
+
const event = {
|
|
584
|
+
type: "task_completion",
|
|
585
|
+
agentId: agent.id,
|
|
586
|
+
timestamp: Date.now(),
|
|
587
|
+
data: {
|
|
588
|
+
taskId: task.id,
|
|
589
|
+
success,
|
|
590
|
+
agent: agent.role
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
this.swarmState.coordination?.events.push(event);
|
|
594
|
+
logger.info(`Task ${task.id} completed by agent ${agent.role}: ${success ? "SUCCESS" : "FAILED"}`);
|
|
595
|
+
}
|
|
596
|
+
async handleTaskFailure(agent, task, error) {
|
|
597
|
+
logger.error(`Agent ${agent.role} failed task ${task.id}`, error);
|
|
598
|
+
if (this.swarmState.coordination) {
|
|
599
|
+
this.swarmState.coordination.conflicts.push({
|
|
600
|
+
type: "task_failure",
|
|
601
|
+
agents: [agent.id],
|
|
602
|
+
timestamp: Date.now(),
|
|
603
|
+
description: error.message
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
async detectTunnelVision(agent) {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
async provideAlternativeApproach(agent) {
|
|
611
|
+
logger.info(`Providing alternative approach to agent ${agent.role}`);
|
|
612
|
+
}
|
|
613
|
+
async detectExcessiveRuntime(agent) {
|
|
614
|
+
if (!agent.performance.lastFreshStart) return false;
|
|
615
|
+
return Date.now() - agent.performance.lastFreshStart > 36e5;
|
|
616
|
+
}
|
|
617
|
+
async requestCheckpoint(agent) {
|
|
618
|
+
logger.info(`Requesting checkpoint from agent ${agent.role}`);
|
|
619
|
+
}
|
|
620
|
+
async triggerFreshStart(agent) {
|
|
621
|
+
logger.info(`Triggering fresh start for agent ${agent.role}`);
|
|
622
|
+
agent.performance.lastFreshStart = Date.now();
|
|
623
|
+
agent.performance.driftDetected = false;
|
|
624
|
+
}
|
|
625
|
+
async resolveActiveConflicts() {
|
|
626
|
+
if (this.swarmState.coordination?.conflicts.length) {
|
|
627
|
+
logger.debug(`Resolving ${this.swarmState.coordination.conflicts.length} conflicts`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
async rebalanceWorkload() {
|
|
631
|
+
const activeAgents = Array.from(this.activeAgents.values()).filter((a) => a.status === "active");
|
|
632
|
+
if (activeAgents.length > 0) {
|
|
633
|
+
logger.debug(`Rebalancing workload among ${activeAgents.length} active agents`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
async triggerFreshStartsIfNeeded() {
|
|
637
|
+
for (const agent of this.activeAgents.values()) {
|
|
638
|
+
if (agent.performance.driftDetected) {
|
|
639
|
+
await this.triggerFreshStart(agent);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
updateSwarmMetrics() {
|
|
644
|
+
if (!this.swarmState.performance) return;
|
|
645
|
+
const activeCount = Array.from(this.activeAgents.values()).filter((a) => a.status === "active").length;
|
|
646
|
+
this.swarmState.performance.throughput = this.swarmState.completedTaskCount / ((Date.now() - this.swarmState.startTime) / 1e3);
|
|
647
|
+
this.swarmState.performance.efficiency = activeCount > 0 ? this.swarmState.completedTaskCount / activeCount : 0;
|
|
648
|
+
}
|
|
480
649
|
[Symbol.toStringTag] = "SwarmCoordinator";
|
|
481
650
|
}
|
|
482
651
|
const swarmCoordinator = new SwarmCoordinator();
|