opencode-swarm-plugin 0.21.0 → 0.23.0
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/.turbo/turbo-build.log +9 -0
- package/CHANGELOG.md +12 -0
- package/README.md +111 -166
- package/dist/agent-mail.d.ts +480 -0
- package/dist/agent-mail.d.ts.map +1 -0
- package/dist/anti-patterns.d.ts +257 -0
- package/dist/anti-patterns.d.ts.map +1 -0
- package/dist/beads.d.ts +377 -0
- package/dist/beads.d.ts.map +1 -0
- package/dist/eval-capture.d.ts +206 -0
- package/dist/eval-capture.d.ts.map +1 -0
- package/dist/index.d.ts +1299 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +776 -4387
- package/dist/learning.d.ts +670 -0
- package/dist/learning.d.ts.map +1 -0
- package/dist/mandate-promotion.d.ts +93 -0
- package/dist/mandate-promotion.d.ts.map +1 -0
- package/dist/mandate-storage.d.ts +209 -0
- package/dist/mandate-storage.d.ts.map +1 -0
- package/dist/mandates.d.ts +230 -0
- package/dist/mandates.d.ts.map +1 -0
- package/dist/output-guardrails.d.ts +125 -0
- package/dist/output-guardrails.d.ts.map +1 -0
- package/dist/pattern-maturity.d.ts +246 -0
- package/dist/pattern-maturity.d.ts.map +1 -0
- package/dist/plugin.d.ts +22 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +755 -4375
- package/dist/rate-limiter.d.ts +218 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/repo-crawl.d.ts +146 -0
- package/dist/repo-crawl.d.ts.map +1 -0
- package/dist/schemas/bead.d.ts +255 -0
- package/dist/schemas/bead.d.ts.map +1 -0
- package/dist/schemas/evaluation.d.ts +161 -0
- package/dist/schemas/evaluation.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +34 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/mandate.d.ts +336 -0
- package/dist/schemas/mandate.d.ts.map +1 -0
- package/dist/schemas/swarm-context.d.ts +131 -0
- package/dist/schemas/swarm-context.d.ts.map +1 -0
- package/dist/schemas/task.d.ts +188 -0
- package/dist/schemas/task.d.ts.map +1 -0
- package/dist/skills.d.ts +471 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/storage.d.ts +260 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/structured.d.ts +196 -0
- package/dist/structured.d.ts.map +1 -0
- package/dist/swarm-decompose.d.ts +201 -0
- package/dist/swarm-decompose.d.ts.map +1 -0
- package/dist/swarm-mail.d.ts +240 -0
- package/dist/swarm-mail.d.ts.map +1 -0
- package/dist/swarm-orchestrate.d.ts +708 -0
- package/dist/swarm-orchestrate.d.ts.map +1 -0
- package/dist/swarm-prompts.d.ts +292 -0
- package/dist/swarm-prompts.d.ts.map +1 -0
- package/dist/swarm-strategies.d.ts +100 -0
- package/dist/swarm-strategies.d.ts.map +1 -0
- package/dist/swarm.d.ts +455 -0
- package/dist/swarm.d.ts.map +1 -0
- package/dist/tool-availability.d.ts +91 -0
- package/dist/tool-availability.d.ts.map +1 -0
- package/docs/planning/ADR-001-monorepo-structure.md +171 -0
- package/docs/planning/ADR-002-package-extraction.md +393 -0
- package/docs/planning/ADR-003-performance-improvements.md +451 -0
- package/docs/planning/ADR-004-message-queue-features.md +187 -0
- package/docs/planning/ADR-005-devtools-observability.md +202 -0
- package/docs/planning/ROADMAP.md +368 -0
- package/docs/semantic-memory-cli-syntax.md +123 -0
- package/docs/swarm-mail-architecture.md +1147 -0
- package/package.json +13 -24
- package/scripts/cleanup-test-memories.ts +346 -0
- package/src/agent-mail.ts +1 -1
- package/src/beads.ts +1 -2
- package/src/index.ts +2 -2
- package/src/learning.integration.test.ts +80 -10
- package/src/mandate-storage.test.ts +3 -3
- package/src/storage.ts +189 -9
- package/src/swarm-mail.ts +3 -3
- package/src/swarm-orchestrate.ts +399 -246
- package/src/swarm.integration.test.ts +124 -0
- package/src/tool-availability.ts +1 -1
- package/tsconfig.json +1 -1
- package/.beads/.local_version +0 -1
- package/.beads/README.md +0 -81
- package/.beads/analysis/skill-architecture-meta-skills.md +0 -1562
- package/.beads/config.yaml +0 -62
- package/.beads/issues.jsonl +0 -2186
- package/.beads/metadata.json +0 -4
- package/.gitattributes +0 -3
- package/.github/workflows/ci.yml +0 -30
- package/.github/workflows/opencode.yml +0 -31
- package/.opencode/skills/tdd/SKILL.md +0 -182
- package/INTEGRATION_EXAMPLE.md +0 -66
- package/VERIFICATION_QUALITY_PATTERNS.md +0 -565
- package/bun.lock +0 -286
- package/dist/pglite.data +0 -0
- package/dist/pglite.wasm +0 -0
- package/src/streams/agent-mail.test.ts +0 -777
- package/src/streams/agent-mail.ts +0 -535
- package/src/streams/debug.test.ts +0 -500
- package/src/streams/debug.ts +0 -727
- package/src/streams/effect/ask.integration.test.ts +0 -314
- package/src/streams/effect/ask.ts +0 -202
- package/src/streams/effect/cursor.integration.test.ts +0 -418
- package/src/streams/effect/cursor.ts +0 -288
- package/src/streams/effect/deferred.test.ts +0 -357
- package/src/streams/effect/deferred.ts +0 -445
- package/src/streams/effect/index.ts +0 -17
- package/src/streams/effect/layers.ts +0 -73
- package/src/streams/effect/lock.test.ts +0 -385
- package/src/streams/effect/lock.ts +0 -399
- package/src/streams/effect/mailbox.test.ts +0 -260
- package/src/streams/effect/mailbox.ts +0 -318
- package/src/streams/events.test.ts +0 -924
- package/src/streams/events.ts +0 -329
- package/src/streams/index.test.ts +0 -229
- package/src/streams/index.ts +0 -578
- package/src/streams/migrations.test.ts +0 -359
- package/src/streams/migrations.ts +0 -362
- package/src/streams/projections.test.ts +0 -611
- package/src/streams/projections.ts +0 -504
- package/src/streams/store.integration.test.ts +0 -658
- package/src/streams/store.ts +0 -1075
- package/src/streams/swarm-mail.ts +0 -552
- package/test-bug-fixes.ts +0 -86
- package/vitest.integration.config.ts +0 -13
- package/workflow-integration-analysis.md +0 -876
package/src/swarm-orchestrate.ts
CHANGED
|
@@ -36,10 +36,10 @@ import {
|
|
|
36
36
|
getSwarmInbox,
|
|
37
37
|
releaseSwarmFiles,
|
|
38
38
|
sendSwarmMessage,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
getAgent,
|
|
40
|
+
createEvent,
|
|
41
|
+
appendEvent,
|
|
42
|
+
} from "swarm-mail";
|
|
43
43
|
import {
|
|
44
44
|
addStrike,
|
|
45
45
|
clearStrikes,
|
|
@@ -872,7 +872,7 @@ export const swarm_progress = tool({
|
|
|
872
872
|
await appendEvent(event, args.project_key);
|
|
873
873
|
|
|
874
874
|
// Update swarm_contexts table
|
|
875
|
-
const { getDatabase } = await import("
|
|
875
|
+
const { getDatabase } = await import("swarm-mail");
|
|
876
876
|
const db = await getDatabase(args.project_key);
|
|
877
877
|
const now = Date.now();
|
|
878
878
|
await db.query(
|
|
@@ -1054,22 +1054,30 @@ export const swarm_complete = tool({
|
|
|
1054
1054
|
.describe("Number of retry attempts during task"),
|
|
1055
1055
|
},
|
|
1056
1056
|
async execute(args) {
|
|
1057
|
-
//
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
let registrationWarning = "";
|
|
1057
|
+
// Extract epic ID early for error notifications
|
|
1058
|
+
const epicId = args.bead_id.includes(".")
|
|
1059
|
+
? args.bead_id.split(".")[0]
|
|
1060
|
+
: args.bead_id;
|
|
1062
1061
|
|
|
1063
1062
|
try {
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
agentRegistered =
|
|
1063
|
+
// Verify agent is registered in swarm-mail
|
|
1064
|
+
// This catches agents who skipped swarmmail_init
|
|
1065
|
+
const projectKey = args.project_key
|
|
1066
|
+
.replace(/\//g, "-")
|
|
1067
|
+
.replace(/\\/g, "-");
|
|
1068
|
+
let agentRegistered = false;
|
|
1069
|
+
let registrationWarning = "";
|
|
1070
|
+
|
|
1071
|
+
try {
|
|
1072
|
+
const agent = await getAgent(
|
|
1073
|
+
projectKey,
|
|
1074
|
+
args.agent_name,
|
|
1075
|
+
args.project_key,
|
|
1076
|
+
);
|
|
1077
|
+
agentRegistered = agent !== null;
|
|
1070
1078
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1079
|
+
if (!agentRegistered) {
|
|
1080
|
+
registrationWarning = `⚠️ WARNING: Agent '${args.agent_name}' was NOT registered in swarm-mail for project '${projectKey}'.
|
|
1073
1081
|
|
|
1074
1082
|
This usually means you skipped the MANDATORY swarmmail_init step.
|
|
1075
1083
|
|
|
@@ -1083,251 +1091,301 @@ This usually means you skipped the MANDATORY swarmmail_init step.
|
|
|
1083
1091
|
|
|
1084
1092
|
Continuing with completion, but this should be fixed for future subtasks.`;
|
|
1085
1093
|
|
|
1086
|
-
|
|
1094
|
+
console.warn(`[swarm_complete] ${registrationWarning}`);
|
|
1095
|
+
}
|
|
1096
|
+
} catch (error) {
|
|
1097
|
+
// Non-fatal - agent might be using legacy workflow
|
|
1098
|
+
console.warn(
|
|
1099
|
+
`[swarm_complete] Could not verify agent registration:`,
|
|
1100
|
+
error,
|
|
1101
|
+
);
|
|
1102
|
+
registrationWarning = `ℹ️ Could not verify swarm-mail registration (database may not be available). Consider running swarmmail_init next time.`;
|
|
1087
1103
|
}
|
|
1088
|
-
} catch (error) {
|
|
1089
|
-
// Non-fatal - agent might be using legacy workflow
|
|
1090
|
-
console.warn(
|
|
1091
|
-
`[swarm_complete] Could not verify agent registration:`,
|
|
1092
|
-
error,
|
|
1093
|
-
);
|
|
1094
|
-
registrationWarning = `ℹ️ Could not verify swarm-mail registration (database may not be available). Consider running swarmmail_init next time.`;
|
|
1095
|
-
}
|
|
1096
1104
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1105
|
+
// Run Verification Gate unless explicitly skipped
|
|
1106
|
+
let verificationResult: VerificationGateResult | null = null;
|
|
1099
1107
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1108
|
+
if (!args.skip_verification && args.files_touched?.length) {
|
|
1109
|
+
verificationResult = await runVerificationGate(
|
|
1110
|
+
args.files_touched,
|
|
1111
|
+
args.skip_ubs_scan ?? false,
|
|
1112
|
+
);
|
|
1105
1113
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1114
|
+
// Block completion if verification failed
|
|
1115
|
+
if (!verificationResult.passed) {
|
|
1116
|
+
return JSON.stringify(
|
|
1117
|
+
{
|
|
1118
|
+
success: false,
|
|
1119
|
+
error: "Verification Gate FAILED - fix issues before completing",
|
|
1120
|
+
verification: {
|
|
1121
|
+
passed: false,
|
|
1122
|
+
summary: verificationResult.summary,
|
|
1123
|
+
blockers: verificationResult.blockers,
|
|
1124
|
+
steps: verificationResult.steps.map((s) => ({
|
|
1125
|
+
name: s.name,
|
|
1126
|
+
passed: s.passed,
|
|
1127
|
+
skipped: s.skipped,
|
|
1128
|
+
skipReason: s.skipReason,
|
|
1129
|
+
error: s.error?.slice(0, 200),
|
|
1130
|
+
})),
|
|
1131
|
+
},
|
|
1132
|
+
hint:
|
|
1133
|
+
verificationResult.blockers.length > 0
|
|
1134
|
+
? `Fix these issues: ${verificationResult.blockers.map((b, i) => `${i + 1}. ${b}`).join(", ")}. Use skip_verification=true only as last resort.`
|
|
1135
|
+
: "Fix the failing checks and try again. Use skip_verification=true only as last resort.",
|
|
1136
|
+
gate_function:
|
|
1137
|
+
"IDENTIFY → RUN → READ → VERIFY → CLAIM (you are at VERIFY, claim blocked)",
|
|
1123
1138
|
},
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
gate_function:
|
|
1129
|
-
"IDENTIFY → RUN → READ → VERIFY → CLAIM (you are at VERIFY, claim blocked)",
|
|
1130
|
-
},
|
|
1131
|
-
null,
|
|
1132
|
-
2,
|
|
1133
|
-
);
|
|
1139
|
+
null,
|
|
1140
|
+
2,
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1134
1143
|
}
|
|
1135
|
-
}
|
|
1136
1144
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1145
|
+
// Legacy UBS-only path for backward compatibility (when no files_touched)
|
|
1146
|
+
let ubsResult: UbsScanResult | null = null;
|
|
1147
|
+
if (
|
|
1148
|
+
!args.skip_verification &&
|
|
1149
|
+
!verificationResult &&
|
|
1150
|
+
args.files_touched?.length &&
|
|
1151
|
+
!args.skip_ubs_scan
|
|
1152
|
+
) {
|
|
1153
|
+
ubsResult = await runUbsScan(args.files_touched);
|
|
1154
|
+
|
|
1155
|
+
// Block completion if critical bugs found
|
|
1156
|
+
if (ubsResult && ubsResult.summary.critical > 0) {
|
|
1157
|
+
return JSON.stringify(
|
|
1158
|
+
{
|
|
1159
|
+
success: false,
|
|
1160
|
+
error: `UBS found ${ubsResult.summary.critical} critical bug(s) that must be fixed before completing`,
|
|
1161
|
+
ubs_scan: {
|
|
1162
|
+
critical_count: ubsResult.summary.critical,
|
|
1163
|
+
bugs: ubsResult.bugs.filter((b) => b.severity === "critical"),
|
|
1164
|
+
},
|
|
1165
|
+
hint: `Fix these critical bugs: ${ubsResult.bugs
|
|
1166
|
+
.filter((b) => b.severity === "critical")
|
|
1167
|
+
.map((b) => `${b.file}:${b.line} - ${b.message}`)
|
|
1168
|
+
.slice(0, 3)
|
|
1169
|
+
.join(
|
|
1170
|
+
"; ",
|
|
1171
|
+
)}. Try: Run 'ubs scan ${args.files_touched?.join(" ") || "."} --json' for full report, fix reported issues, or use skip_ubs_scan=true to bypass (not recommended).`,
|
|
1172
|
+
},
|
|
1173
|
+
null,
|
|
1174
|
+
2,
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1146
1178
|
|
|
1147
|
-
//
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1179
|
+
// Parse and validate evaluation if provided
|
|
1180
|
+
let parsedEvaluation: Evaluation | undefined;
|
|
1181
|
+
if (args.evaluation) {
|
|
1182
|
+
try {
|
|
1183
|
+
parsedEvaluation = EvaluationSchema.parse(
|
|
1184
|
+
JSON.parse(args.evaluation),
|
|
1185
|
+
);
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
return JSON.stringify(
|
|
1188
|
+
{
|
|
1189
|
+
success: false,
|
|
1190
|
+
error: "Invalid evaluation format",
|
|
1191
|
+
details:
|
|
1192
|
+
error instanceof z.ZodError ? error.issues : String(error),
|
|
1156
1193
|
},
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1194
|
+
null,
|
|
1195
|
+
2,
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// If evaluation failed, don't complete
|
|
1200
|
+
if (!parsedEvaluation.passed) {
|
|
1201
|
+
return JSON.stringify(
|
|
1202
|
+
{
|
|
1203
|
+
success: false,
|
|
1204
|
+
error: "Self-evaluation failed",
|
|
1205
|
+
retry_suggestion: parsedEvaluation.retry_suggestion,
|
|
1206
|
+
feedback: parsedEvaluation.overall_feedback,
|
|
1207
|
+
},
|
|
1208
|
+
null,
|
|
1209
|
+
2,
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1168
1212
|
}
|
|
1169
|
-
}
|
|
1170
1213
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
error: "Invalid evaluation format",
|
|
1181
|
-
details: error instanceof z.ZodError ? error.issues : String(error),
|
|
1182
|
-
},
|
|
1183
|
-
null,
|
|
1184
|
-
2,
|
|
1214
|
+
// Close the bead
|
|
1215
|
+
const closeResult =
|
|
1216
|
+
await Bun.$`bd close ${args.bead_id} --reason ${args.summary} --json`
|
|
1217
|
+
.quiet()
|
|
1218
|
+
.nothrow();
|
|
1219
|
+
|
|
1220
|
+
if (closeResult.exitCode !== 0) {
|
|
1221
|
+
throw new Error(
|
|
1222
|
+
`Failed to close bead because bd close command failed: ${closeResult.stderr.toString()}. Try: Verify bead exists and is not already closed with 'bd show ${args.bead_id}', check if bead ID is correct with 'beads_query()', or use beads_close tool directly.`,
|
|
1185
1223
|
);
|
|
1186
1224
|
}
|
|
1187
1225
|
|
|
1188
|
-
//
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1226
|
+
// Emit SubtaskOutcomeEvent for learning system
|
|
1227
|
+
try {
|
|
1228
|
+
const epicId = args.bead_id.includes(".")
|
|
1229
|
+
? args.bead_id.split(".")[0]
|
|
1230
|
+
: args.bead_id;
|
|
1231
|
+
|
|
1232
|
+
const durationMs = args.start_time ? Date.now() - args.start_time : 0;
|
|
1233
|
+
|
|
1234
|
+
const event = createEvent("subtask_outcome", {
|
|
1235
|
+
project_key: args.project_key,
|
|
1236
|
+
epic_id: epicId,
|
|
1237
|
+
bead_id: args.bead_id,
|
|
1238
|
+
planned_files: args.planned_files || [],
|
|
1239
|
+
actual_files: args.files_touched || [],
|
|
1240
|
+
duration_ms: durationMs,
|
|
1241
|
+
error_count: args.error_count || 0,
|
|
1242
|
+
retry_count: args.retry_count || 0,
|
|
1243
|
+
success: true,
|
|
1244
|
+
});
|
|
1245
|
+
await appendEvent(event, args.project_key);
|
|
1246
|
+
} catch (error) {
|
|
1247
|
+
// Non-fatal - log and continue
|
|
1248
|
+
console.warn(
|
|
1249
|
+
"[swarm_complete] Failed to emit SubtaskOutcomeEvent:",
|
|
1250
|
+
error,
|
|
1199
1251
|
);
|
|
1200
1252
|
}
|
|
1201
|
-
}
|
|
1202
1253
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
.nothrow();
|
|
1254
|
+
// Automatic memory capture (MANDATORY on successful completion)
|
|
1255
|
+
// Extract strategy from bead metadata if available
|
|
1256
|
+
let capturedStrategy: LearningDecompositionStrategy | undefined;
|
|
1257
|
+
const durationMs = args.start_time ? Date.now() - args.start_time : 0;
|
|
1208
1258
|
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1259
|
+
// Build memory information from task completion
|
|
1260
|
+
const memoryInfo = formatMemoryStoreOnSuccess(
|
|
1261
|
+
args.bead_id,
|
|
1262
|
+
args.summary,
|
|
1263
|
+
args.files_touched || [],
|
|
1264
|
+
capturedStrategy,
|
|
1212
1265
|
);
|
|
1213
|
-
}
|
|
1214
1266
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1267
|
+
let memoryStored = false;
|
|
1268
|
+
let memoryError: string | undefined;
|
|
1269
|
+
|
|
1270
|
+
// Attempt to store in semantic-memory (non-blocking)
|
|
1271
|
+
try {
|
|
1272
|
+
const memoryAvailable = await isToolAvailable("semantic-memory");
|
|
1273
|
+
if (memoryAvailable) {
|
|
1274
|
+
// Call semantic-memory store command
|
|
1275
|
+
const storeResult =
|
|
1276
|
+
await Bun.$`semantic-memory store ${memoryInfo.information} --metadata ${memoryInfo.metadata}`
|
|
1277
|
+
.quiet()
|
|
1278
|
+
.nothrow();
|
|
1279
|
+
|
|
1280
|
+
if (storeResult.exitCode === 0) {
|
|
1281
|
+
memoryStored = true;
|
|
1282
|
+
console.log(
|
|
1283
|
+
`[swarm_complete] Stored learning for ${args.bead_id} in semantic-memory`,
|
|
1284
|
+
);
|
|
1285
|
+
} else {
|
|
1286
|
+
memoryError = `semantic-memory store failed: ${storeResult.stderr.toString().slice(0, 200)}`;
|
|
1287
|
+
console.warn(`[swarm_complete] ${memoryError}`);
|
|
1288
|
+
}
|
|
1289
|
+
} else {
|
|
1290
|
+
memoryError =
|
|
1291
|
+
"semantic-memory not available - learning stored in-memory only";
|
|
1292
|
+
warnMissingTool("semantic-memory");
|
|
1293
|
+
}
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
memoryError = `Failed to store memory: ${error instanceof Error ? error.message : String(error)}`;
|
|
1296
|
+
console.warn(`[swarm_complete] ${memoryError}`);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Release file reservations for this agent using embedded swarm-mail
|
|
1300
|
+
try {
|
|
1301
|
+
await releaseSwarmFiles({
|
|
1302
|
+
projectPath: args.project_key,
|
|
1303
|
+
agentName: args.agent_name,
|
|
1304
|
+
// Release all reservations for this agent
|
|
1305
|
+
});
|
|
1306
|
+
} catch (error) {
|
|
1307
|
+
// Release might fail (e.g., no reservations existed)
|
|
1308
|
+
// This is non-fatal - log and continue
|
|
1309
|
+
console.warn(
|
|
1310
|
+
`[swarm] Failed to release file reservations for ${args.agent_name}:`,
|
|
1311
|
+
error,
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// Extract epic ID
|
|
1217
1316
|
const epicId = args.bead_id.includes(".")
|
|
1218
1317
|
? args.bead_id.split(".")[0]
|
|
1219
1318
|
: args.bead_id;
|
|
1220
1319
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
);
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
// Release file reservations for this agent using embedded swarm-mail
|
|
1244
|
-
try {
|
|
1245
|
-
await releaseSwarmFiles({
|
|
1320
|
+
// Send completion message using embedded swarm-mail with memory capture status
|
|
1321
|
+
const completionBody = [
|
|
1322
|
+
`## Subtask Complete: ${args.bead_id}`,
|
|
1323
|
+
"",
|
|
1324
|
+
`**Summary**: ${args.summary}`,
|
|
1325
|
+
"",
|
|
1326
|
+
parsedEvaluation
|
|
1327
|
+
? `**Self-Evaluation**: ${parsedEvaluation.passed ? "PASSED" : "FAILED"}`
|
|
1328
|
+
: "",
|
|
1329
|
+
parsedEvaluation?.overall_feedback
|
|
1330
|
+
? `**Feedback**: ${parsedEvaluation.overall_feedback}`
|
|
1331
|
+
: "",
|
|
1332
|
+
"",
|
|
1333
|
+
`**Memory Capture**: ${memoryStored ? "✓ Stored in semantic-memory" : `✗ ${memoryError || "Failed"}`}`,
|
|
1334
|
+
]
|
|
1335
|
+
.filter(Boolean)
|
|
1336
|
+
.join("\n");
|
|
1337
|
+
|
|
1338
|
+
await sendSwarmMessage({
|
|
1246
1339
|
projectPath: args.project_key,
|
|
1247
|
-
|
|
1248
|
-
|
|
1340
|
+
fromAgent: args.agent_name,
|
|
1341
|
+
toAgents: [], // Thread broadcast
|
|
1342
|
+
subject: `Complete: ${args.bead_id}`,
|
|
1343
|
+
body: completionBody,
|
|
1344
|
+
threadId: epicId,
|
|
1345
|
+
importance: "normal",
|
|
1249
1346
|
});
|
|
1250
|
-
} catch (error) {
|
|
1251
|
-
// Release might fail (e.g., no reservations existed)
|
|
1252
|
-
// This is non-fatal - log and continue
|
|
1253
|
-
console.warn(
|
|
1254
|
-
`[swarm] Failed to release file reservations for ${args.agent_name}:`,
|
|
1255
|
-
error,
|
|
1256
|
-
);
|
|
1257
|
-
}
|
|
1258
1347
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
},
|
|
1301
|
-
verification_gate: verificationResult
|
|
1302
|
-
? {
|
|
1303
|
-
passed: true,
|
|
1304
|
-
summary: verificationResult.summary,
|
|
1305
|
-
steps: verificationResult.steps.map((s) => ({
|
|
1306
|
-
name: s.name,
|
|
1307
|
-
passed: s.passed,
|
|
1308
|
-
skipped: s.skipped,
|
|
1309
|
-
skipReason: s.skipReason,
|
|
1310
|
-
})),
|
|
1311
|
-
}
|
|
1312
|
-
: args.skip_verification
|
|
1313
|
-
? { skipped: true, reason: "skip_verification=true" }
|
|
1314
|
-
: { skipped: true, reason: "no files_touched provided" },
|
|
1315
|
-
ubs_scan: ubsResult
|
|
1316
|
-
? {
|
|
1317
|
-
ran: true,
|
|
1318
|
-
bugs_found: ubsResult.summary.total,
|
|
1319
|
-
summary: ubsResult.summary,
|
|
1320
|
-
warnings: ubsResult.bugs.filter((b) => b.severity !== "critical"),
|
|
1321
|
-
}
|
|
1322
|
-
: verificationResult
|
|
1323
|
-
? { ran: true, included_in_verification_gate: true }
|
|
1324
|
-
: {
|
|
1325
|
-
ran: false,
|
|
1326
|
-
reason: args.skip_ubs_scan
|
|
1327
|
-
? "skipped"
|
|
1328
|
-
: "no files or ubs unavailable",
|
|
1329
|
-
},
|
|
1330
|
-
learning_prompt: `## Reflection
|
|
1348
|
+
// Build success response with semantic-memory integration
|
|
1349
|
+
const response = {
|
|
1350
|
+
success: true,
|
|
1351
|
+
bead_id: args.bead_id,
|
|
1352
|
+
closed: true,
|
|
1353
|
+
reservations_released: true,
|
|
1354
|
+
message_sent: true,
|
|
1355
|
+
agent_registration: {
|
|
1356
|
+
verified: agentRegistered,
|
|
1357
|
+
warning: registrationWarning || undefined,
|
|
1358
|
+
},
|
|
1359
|
+
verification_gate: verificationResult
|
|
1360
|
+
? {
|
|
1361
|
+
passed: true,
|
|
1362
|
+
summary: verificationResult.summary,
|
|
1363
|
+
steps: verificationResult.steps.map((s) => ({
|
|
1364
|
+
name: s.name,
|
|
1365
|
+
passed: s.passed,
|
|
1366
|
+
skipped: s.skipped,
|
|
1367
|
+
skipReason: s.skipReason,
|
|
1368
|
+
})),
|
|
1369
|
+
}
|
|
1370
|
+
: args.skip_verification
|
|
1371
|
+
? { skipped: true, reason: "skip_verification=true" }
|
|
1372
|
+
: { skipped: true, reason: "no files_touched provided" },
|
|
1373
|
+
ubs_scan: ubsResult
|
|
1374
|
+
? {
|
|
1375
|
+
ran: true,
|
|
1376
|
+
bugs_found: ubsResult.summary.total,
|
|
1377
|
+
summary: ubsResult.summary,
|
|
1378
|
+
warnings: ubsResult.bugs.filter((b) => b.severity !== "critical"),
|
|
1379
|
+
}
|
|
1380
|
+
: verificationResult
|
|
1381
|
+
? { ran: true, included_in_verification_gate: true }
|
|
1382
|
+
: {
|
|
1383
|
+
ran: false,
|
|
1384
|
+
reason: args.skip_ubs_scan
|
|
1385
|
+
? "skipped"
|
|
1386
|
+
: "no files or ubs unavailable",
|
|
1387
|
+
},
|
|
1388
|
+
learning_prompt: `## Reflection
|
|
1331
1389
|
|
|
1332
1390
|
Did you learn anything reusable during this subtask? Consider:
|
|
1333
1391
|
|
|
@@ -1339,15 +1397,110 @@ Did you learn anything reusable during this subtask? Consider:
|
|
|
1339
1397
|
If you discovered something valuable, use \`swarm_learn\` or \`skills_create\` to preserve it as a skill for future swarms.
|
|
1340
1398
|
|
|
1341
1399
|
Files touched: ${args.files_touched?.join(", ") || "none recorded"}`,
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1400
|
+
// Automatic memory capture (MANDATORY)
|
|
1401
|
+
memory_capture: {
|
|
1402
|
+
attempted: true,
|
|
1403
|
+
stored: memoryStored,
|
|
1404
|
+
error: memoryError,
|
|
1405
|
+
information: memoryInfo.information,
|
|
1406
|
+
metadata: memoryInfo.metadata,
|
|
1407
|
+
note: memoryStored
|
|
1408
|
+
? "Learning automatically stored in semantic-memory"
|
|
1409
|
+
: `Failed to store: ${memoryError}. Learning lost unless semantic-memory is available.`,
|
|
1410
|
+
},
|
|
1411
|
+
};
|
|
1412
|
+
|
|
1413
|
+
return JSON.stringify(response, null, 2);
|
|
1414
|
+
} catch (error) {
|
|
1415
|
+
// CRITICAL: Notify coordinator of failure via swarm mail
|
|
1416
|
+
const errorMessage =
|
|
1417
|
+
error instanceof Error ? error.message : String(error);
|
|
1418
|
+
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
1419
|
+
|
|
1420
|
+
// Determine which step failed
|
|
1421
|
+
let failedStep = "unknown";
|
|
1422
|
+
if (errorMessage.includes("verification")) {
|
|
1423
|
+
failedStep = "Verification Gate (UBS/typecheck/tests)";
|
|
1424
|
+
} else if (errorMessage.includes("UBS") || errorMessage.includes("ubs")) {
|
|
1425
|
+
failedStep = "UBS scan";
|
|
1426
|
+
} else if (errorMessage.includes("evaluation")) {
|
|
1427
|
+
failedStep = "Self-evaluation parsing";
|
|
1428
|
+
} else if (
|
|
1429
|
+
errorMessage.includes("bead") ||
|
|
1430
|
+
errorMessage.includes("close")
|
|
1431
|
+
) {
|
|
1432
|
+
failedStep = "Bead close";
|
|
1433
|
+
} else if (
|
|
1434
|
+
errorMessage.includes("memory") ||
|
|
1435
|
+
errorMessage.includes("semantic")
|
|
1436
|
+
) {
|
|
1437
|
+
failedStep = "Memory storage (non-fatal)";
|
|
1438
|
+
} else if (
|
|
1439
|
+
errorMessage.includes("reservation") ||
|
|
1440
|
+
errorMessage.includes("release")
|
|
1441
|
+
) {
|
|
1442
|
+
failedStep = "File reservation release";
|
|
1443
|
+
} else if (
|
|
1444
|
+
errorMessage.includes("message") ||
|
|
1445
|
+
errorMessage.includes("mail")
|
|
1446
|
+
) {
|
|
1447
|
+
failedStep = "Swarm mail notification";
|
|
1448
|
+
}
|
|
1349
1449
|
|
|
1350
|
-
|
|
1450
|
+
// Build error notification body
|
|
1451
|
+
const errorBody = [
|
|
1452
|
+
`## ⚠️ SWARM_COMPLETE FAILED`,
|
|
1453
|
+
"",
|
|
1454
|
+
`**Bead**: ${args.bead_id}`,
|
|
1455
|
+
`**Agent**: ${args.agent_name}`,
|
|
1456
|
+
`**Failed Step**: ${failedStep}`,
|
|
1457
|
+
"",
|
|
1458
|
+
`### Error Message`,
|
|
1459
|
+
"```",
|
|
1460
|
+
errorMessage,
|
|
1461
|
+
"```",
|
|
1462
|
+
"",
|
|
1463
|
+
errorStack
|
|
1464
|
+
? `### Stack Trace\n\`\`\`\n${errorStack.slice(0, 1000)}\n\`\`\`\n`
|
|
1465
|
+
: "",
|
|
1466
|
+
`### Context`,
|
|
1467
|
+
`- **Summary**: ${args.summary}`,
|
|
1468
|
+
`- **Files touched**: ${args.files_touched?.length ? args.files_touched.join(", ") : "none"}`,
|
|
1469
|
+
`- **Skip UBS**: ${args.skip_ubs_scan ?? false}`,
|
|
1470
|
+
`- **Skip verification**: ${args.skip_verification ?? false}`,
|
|
1471
|
+
"",
|
|
1472
|
+
`### Recovery Actions`,
|
|
1473
|
+
"1. Check error message for specific issue",
|
|
1474
|
+
"2. Review failed step (UBS scan, typecheck, bead close, etc.)",
|
|
1475
|
+
"3. Fix underlying issue or use skip flags if appropriate",
|
|
1476
|
+
"4. Retry swarm_complete after fixing",
|
|
1477
|
+
]
|
|
1478
|
+
.filter(Boolean)
|
|
1479
|
+
.join("\n");
|
|
1480
|
+
|
|
1481
|
+
// Send urgent notification to coordinator
|
|
1482
|
+
try {
|
|
1483
|
+
await sendSwarmMessage({
|
|
1484
|
+
projectPath: args.project_key,
|
|
1485
|
+
fromAgent: args.agent_name,
|
|
1486
|
+
toAgents: [], // Thread broadcast to coordinator
|
|
1487
|
+
subject: `FAILED: swarm_complete for ${args.bead_id}`,
|
|
1488
|
+
body: errorBody,
|
|
1489
|
+
threadId: epicId,
|
|
1490
|
+
importance: "urgent",
|
|
1491
|
+
});
|
|
1492
|
+
} catch (mailError) {
|
|
1493
|
+
// Even swarm mail failed - log to console as last resort
|
|
1494
|
+
console.error(
|
|
1495
|
+
`[swarm_complete] CRITICAL: Failed to notify coordinator of failure for ${args.bead_id}:`,
|
|
1496
|
+
mailError,
|
|
1497
|
+
);
|
|
1498
|
+
console.error(`[swarm_complete] Original error:`, error);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// Re-throw the original error after notifying
|
|
1502
|
+
throw error;
|
|
1503
|
+
}
|
|
1351
1504
|
},
|
|
1352
1505
|
});
|
|
1353
1506
|
|
|
@@ -1909,7 +2062,7 @@ export const swarm_checkpoint = tool({
|
|
|
1909
2062
|
await appendEvent(event, args.project_key);
|
|
1910
2063
|
|
|
1911
2064
|
// Update swarm_contexts table for fast recovery
|
|
1912
|
-
const { getDatabase } = await import("
|
|
2065
|
+
const { getDatabase } = await import("swarm-mail");
|
|
1913
2066
|
const db = await getDatabase(args.project_key);
|
|
1914
2067
|
|
|
1915
2068
|
const now = Date.now();
|
|
@@ -1985,7 +2138,7 @@ export const swarm_recover = tool({
|
|
|
1985
2138
|
},
|
|
1986
2139
|
async execute(args) {
|
|
1987
2140
|
try {
|
|
1988
|
-
const { getDatabase } = await import("
|
|
2141
|
+
const { getDatabase } = await import("swarm-mail");
|
|
1989
2142
|
const db = await getDatabase(args.project_key);
|
|
1990
2143
|
|
|
1991
2144
|
// Query most recent checkpoint for this epic
|