opencode-swarm-plugin 0.23.6 → 0.24.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 +4 -4
- package/CHANGELOG.md +27 -0
- package/README.md +155 -3
- package/bin/swarm.ts +497 -187
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +620 -89
- package/dist/plugin.js +548 -89
- package/dist/schemas/bead-events.d.ts +698 -0
- package/dist/schemas/bead-events.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/swarm-decompose.d.ts +74 -0
- package/dist/swarm-decompose.d.ts.map +1 -1
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +1 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm.d.ts +27 -0
- package/dist/swarm.d.ts.map +1 -1
- package/docs/testing/context-recovery-test.md +470 -0
- package/examples/commands/swarm.md +92 -20
- package/global-skills/swarm-coordination/SKILL.md +380 -10
- package/package.json +1 -1
- package/src/schemas/bead-events.test.ts +341 -0
- package/src/schemas/bead-events.ts +583 -0
- package/src/schemas/index.ts +51 -0
- package/src/skills.ts +10 -3
- package/src/swarm-decompose.ts +337 -0
- package/src/swarm-orchestrate.ts +15 -51
- package/src/swarm-prompts.ts +144 -42
- package/src/swarm.integration.test.ts +581 -31
package/src/swarm-decompose.ts
CHANGED
|
@@ -905,8 +905,345 @@ export class DecompositionError extends SwarmError {
|
|
|
905
905
|
}
|
|
906
906
|
}
|
|
907
907
|
|
|
908
|
+
/**
|
|
909
|
+
* Planning phase state machine for Socratic planning
|
|
910
|
+
*/
|
|
911
|
+
type PlanningPhase = "questioning" | "alternatives" | "recommendation" | "ready";
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Planning mode that determines interaction level
|
|
915
|
+
*/
|
|
916
|
+
type PlanningMode = "socratic" | "fast" | "auto" | "confirm-only";
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Socratic planning output structure
|
|
920
|
+
*/
|
|
921
|
+
interface SocraticPlanOutput {
|
|
922
|
+
mode: PlanningMode;
|
|
923
|
+
phase: PlanningPhase;
|
|
924
|
+
questions?: Array<{ question: string; options?: string[] }>;
|
|
925
|
+
alternatives?: Array<{
|
|
926
|
+
name: string;
|
|
927
|
+
description: string;
|
|
928
|
+
tradeoffs: string;
|
|
929
|
+
}>;
|
|
930
|
+
recommendation?: { approach: string; reasoning: string };
|
|
931
|
+
memory_context?: string;
|
|
932
|
+
codebase_context?: {
|
|
933
|
+
git_status?: string;
|
|
934
|
+
relevant_files?: string[];
|
|
935
|
+
};
|
|
936
|
+
ready_to_decompose: boolean;
|
|
937
|
+
next_action?: string;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Interactive planning tool with Socratic questioning
|
|
942
|
+
*
|
|
943
|
+
* Implements a planning phase BEFORE decomposition that:
|
|
944
|
+
* 1. Gathers context (git, files, semantic memory)
|
|
945
|
+
* 2. Asks clarifying questions (socratic mode)
|
|
946
|
+
* 3. Explores alternatives with tradeoffs
|
|
947
|
+
* 4. Recommends an approach with reasoning
|
|
948
|
+
* 5. Confirms before proceeding to decomposition
|
|
949
|
+
*
|
|
950
|
+
* Modes:
|
|
951
|
+
* - socratic: Full interactive planning with questions, alternatives, recommendations
|
|
952
|
+
* - fast: Skip brainstorming, go straight to decomposition with memory context
|
|
953
|
+
* - auto: Auto-select best approach based on task keywords, minimal interaction
|
|
954
|
+
* - confirm-only: Show decomposition, wait for yes/no confirmation
|
|
955
|
+
*
|
|
956
|
+
* Based on the Socratic Planner Pattern from obra/superpowers.
|
|
957
|
+
*
|
|
958
|
+
* @see docs/analysis-socratic-planner-pattern.md
|
|
959
|
+
*/
|
|
960
|
+
export const swarm_plan_interactive = tool({
|
|
961
|
+
description:
|
|
962
|
+
"Interactive planning phase with Socratic questioning before decomposition. Supports multiple modes from full interactive to auto-proceed.",
|
|
963
|
+
args: {
|
|
964
|
+
task: tool.schema.string().min(1).describe("The task to plan"),
|
|
965
|
+
mode: tool.schema
|
|
966
|
+
.enum(["socratic", "fast", "auto", "confirm-only"])
|
|
967
|
+
.default("socratic")
|
|
968
|
+
.describe("Planning mode: socratic (full), fast (skip questions), auto (minimal), confirm-only (single yes/no)"),
|
|
969
|
+
context: tool.schema
|
|
970
|
+
.string()
|
|
971
|
+
.optional()
|
|
972
|
+
.describe("Optional additional context about the task"),
|
|
973
|
+
user_response: tool.schema
|
|
974
|
+
.string()
|
|
975
|
+
.optional()
|
|
976
|
+
.describe("User's response to a previous question (for multi-turn socratic mode)"),
|
|
977
|
+
phase: tool.schema
|
|
978
|
+
.enum(["questioning", "alternatives", "recommendation", "ready"])
|
|
979
|
+
.optional()
|
|
980
|
+
.describe("Current planning phase (for resuming multi-turn interaction)"),
|
|
981
|
+
},
|
|
982
|
+
async execute(args): Promise<string> {
|
|
983
|
+
// Import needed modules
|
|
984
|
+
const { selectStrategy, formatStrategyGuidelines, STRATEGIES } =
|
|
985
|
+
await import("./swarm-strategies");
|
|
986
|
+
const { formatMemoryQueryForDecomposition } = await import("./learning");
|
|
987
|
+
|
|
988
|
+
// Determine current phase
|
|
989
|
+
const currentPhase: PlanningPhase = args.phase || "questioning";
|
|
990
|
+
const mode: PlanningMode = args.mode || "socratic";
|
|
991
|
+
|
|
992
|
+
// Gather context - always do this regardless of mode
|
|
993
|
+
let memoryContext = "";
|
|
994
|
+
let codebaseContext: { git_status?: string; relevant_files?: string[] } = {};
|
|
995
|
+
|
|
996
|
+
// Generate semantic memory query instruction
|
|
997
|
+
// Note: Semantic memory is accessed via OpenCode's global tools, not as a direct import
|
|
998
|
+
// The coordinator should call semantic-memory_find before calling this tool
|
|
999
|
+
// and pass results in the context parameter
|
|
1000
|
+
try {
|
|
1001
|
+
const memoryQuery = formatMemoryQueryForDecomposition(args.task, 3);
|
|
1002
|
+
memoryContext = `[Memory Query Instruction]\n${memoryQuery.instruction}\nQuery: "${memoryQuery.query}"\nLimit: ${memoryQuery.limit}`;
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
console.warn("[swarm_plan_interactive] Memory query formatting failed:", error);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// Get git context for codebase awareness
|
|
1008
|
+
try {
|
|
1009
|
+
const gitResult = await Bun.$`git status --short`.quiet().nothrow();
|
|
1010
|
+
if (gitResult.exitCode === 0) {
|
|
1011
|
+
codebaseContext.git_status = gitResult.stdout.toString().trim();
|
|
1012
|
+
}
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
// Git not available or not in a git repo - continue without it
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Fast mode: Skip to recommendation
|
|
1018
|
+
if (mode === "fast") {
|
|
1019
|
+
const strategyResult = selectStrategy(args.task);
|
|
1020
|
+
const guidelines = formatStrategyGuidelines(strategyResult.strategy);
|
|
1021
|
+
|
|
1022
|
+
const output: SocraticPlanOutput = {
|
|
1023
|
+
mode: "fast",
|
|
1024
|
+
phase: "ready",
|
|
1025
|
+
recommendation: {
|
|
1026
|
+
approach: strategyResult.strategy,
|
|
1027
|
+
reasoning: `${strategyResult.reasoning}\n\n${guidelines}`,
|
|
1028
|
+
},
|
|
1029
|
+
memory_context: memoryContext || undefined,
|
|
1030
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1031
|
+
ready_to_decompose: true,
|
|
1032
|
+
next_action: "Proceed to swarm_decompose or swarm_delegate_planning",
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
return JSON.stringify(output, null, 2);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// Auto mode: Auto-select and proceed
|
|
1039
|
+
if (mode === "auto") {
|
|
1040
|
+
const strategyResult = selectStrategy(args.task);
|
|
1041
|
+
|
|
1042
|
+
const output: SocraticPlanOutput = {
|
|
1043
|
+
mode: "auto",
|
|
1044
|
+
phase: "ready",
|
|
1045
|
+
recommendation: {
|
|
1046
|
+
approach: strategyResult.strategy,
|
|
1047
|
+
reasoning: `Auto-selected based on task keywords: ${strategyResult.reasoning}`,
|
|
1048
|
+
},
|
|
1049
|
+
memory_context: memoryContext || undefined,
|
|
1050
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1051
|
+
ready_to_decompose: true,
|
|
1052
|
+
next_action: "Auto-proceeding to decomposition",
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
return JSON.stringify(output, null, 2);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// Confirm-only mode: Generate decomposition, show it, wait for yes/no
|
|
1059
|
+
if (mode === "confirm-only") {
|
|
1060
|
+
// This mode will be handled by calling swarm_delegate_planning
|
|
1061
|
+
// and then asking for confirmation on the result
|
|
1062
|
+
const output: SocraticPlanOutput = {
|
|
1063
|
+
mode: "confirm-only",
|
|
1064
|
+
phase: "ready",
|
|
1065
|
+
recommendation: {
|
|
1066
|
+
approach: "Will generate decomposition for your review",
|
|
1067
|
+
reasoning: "Use swarm_delegate_planning to generate the plan, then present it for yes/no confirmation",
|
|
1068
|
+
},
|
|
1069
|
+
memory_context: memoryContext || undefined,
|
|
1070
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1071
|
+
ready_to_decompose: false,
|
|
1072
|
+
next_action: "Call swarm_delegate_planning, then show result and ask for confirmation",
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
return JSON.stringify(output, null, 2);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// Socratic mode: Full interactive planning
|
|
1079
|
+
// Phase 1: Questioning
|
|
1080
|
+
if (currentPhase === "questioning") {
|
|
1081
|
+
// Analyze task to identify what needs clarification
|
|
1082
|
+
const taskLower = args.task.toLowerCase();
|
|
1083
|
+
const questions: Array<{ question: string; options?: string[] }> = [];
|
|
1084
|
+
|
|
1085
|
+
// Check for vague task signals from skill
|
|
1086
|
+
const isVague = {
|
|
1087
|
+
noFiles: !taskLower.includes("src/") && !taskLower.includes("file"),
|
|
1088
|
+
vagueVerb:
|
|
1089
|
+
taskLower.includes("improve") ||
|
|
1090
|
+
taskLower.includes("fix") ||
|
|
1091
|
+
taskLower.includes("update") ||
|
|
1092
|
+
taskLower.includes("make better"),
|
|
1093
|
+
noSuccessCriteria: !taskLower.includes("test") && !taskLower.includes("verify"),
|
|
1094
|
+
};
|
|
1095
|
+
|
|
1096
|
+
// Generate clarifying questions (one at a time)
|
|
1097
|
+
if (isVague.noFiles) {
|
|
1098
|
+
questions.push({
|
|
1099
|
+
question: "Which part of the codebase should this change affect?",
|
|
1100
|
+
options: [
|
|
1101
|
+
"Core functionality (src/)",
|
|
1102
|
+
"UI components (components/)",
|
|
1103
|
+
"API routes (app/api/)",
|
|
1104
|
+
"Configuration and tooling",
|
|
1105
|
+
"Tests",
|
|
1106
|
+
],
|
|
1107
|
+
});
|
|
1108
|
+
} else if (isVague.vagueVerb) {
|
|
1109
|
+
questions.push({
|
|
1110
|
+
question: "What specific change are you looking for?",
|
|
1111
|
+
options: [
|
|
1112
|
+
"Add new functionality",
|
|
1113
|
+
"Modify existing behavior",
|
|
1114
|
+
"Remove/deprecate something",
|
|
1115
|
+
"Refactor without behavior change",
|
|
1116
|
+
"Fix a bug",
|
|
1117
|
+
],
|
|
1118
|
+
});
|
|
1119
|
+
} else if (isVague.noSuccessCriteria) {
|
|
1120
|
+
questions.push({
|
|
1121
|
+
question: "How will we know this task is complete?",
|
|
1122
|
+
options: [
|
|
1123
|
+
"All tests pass",
|
|
1124
|
+
"Feature works as demonstrated",
|
|
1125
|
+
"Code review approved",
|
|
1126
|
+
"Documentation updated",
|
|
1127
|
+
"Performance target met",
|
|
1128
|
+
],
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// If task seems clear, move to alternatives phase
|
|
1133
|
+
if (questions.length === 0) {
|
|
1134
|
+
const output: SocraticPlanOutput = {
|
|
1135
|
+
mode: "socratic",
|
|
1136
|
+
phase: "alternatives",
|
|
1137
|
+
memory_context: memoryContext || undefined,
|
|
1138
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1139
|
+
ready_to_decompose: false,
|
|
1140
|
+
next_action: "Task is clear. Call again with phase=alternatives to explore approaches",
|
|
1141
|
+
};
|
|
1142
|
+
return JSON.stringify(output, null, 2);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// Return first question only (Socratic principle: one at a time)
|
|
1146
|
+
const output: SocraticPlanOutput = {
|
|
1147
|
+
mode: "socratic",
|
|
1148
|
+
phase: "questioning",
|
|
1149
|
+
questions: [questions[0]],
|
|
1150
|
+
memory_context: memoryContext || undefined,
|
|
1151
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1152
|
+
ready_to_decompose: false,
|
|
1153
|
+
next_action: "User should answer this question, then call again with user_response",
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
return JSON.stringify(output, null, 2);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// Phase 2: Alternatives
|
|
1160
|
+
if (currentPhase === "alternatives") {
|
|
1161
|
+
const strategyResult = selectStrategy(args.task);
|
|
1162
|
+
|
|
1163
|
+
// Build 2-3 alternative approaches
|
|
1164
|
+
const alternatives: Array<{
|
|
1165
|
+
name: string;
|
|
1166
|
+
description: string;
|
|
1167
|
+
tradeoffs: string;
|
|
1168
|
+
}> = [];
|
|
1169
|
+
|
|
1170
|
+
// Primary recommendation
|
|
1171
|
+
alternatives.push({
|
|
1172
|
+
name: strategyResult.strategy,
|
|
1173
|
+
description: strategyResult.reasoning,
|
|
1174
|
+
tradeoffs: `Confidence: ${(strategyResult.confidence * 100).toFixed(0)}%. ${STRATEGIES[strategyResult.strategy].description}`,
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
// Add top 2 alternatives
|
|
1178
|
+
for (let i = 0; i < Math.min(2, strategyResult.alternatives.length); i++) {
|
|
1179
|
+
const alt = strategyResult.alternatives[i];
|
|
1180
|
+
alternatives.push({
|
|
1181
|
+
name: alt.strategy,
|
|
1182
|
+
description: STRATEGIES[alt.strategy].description,
|
|
1183
|
+
tradeoffs: `Match score: ${alt.score}. ${STRATEGIES[alt.strategy].antiPatterns[0] || "Consider trade-offs carefully"}`,
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
const output: SocraticPlanOutput = {
|
|
1188
|
+
mode: "socratic",
|
|
1189
|
+
phase: "alternatives",
|
|
1190
|
+
alternatives,
|
|
1191
|
+
memory_context: memoryContext || undefined,
|
|
1192
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1193
|
+
ready_to_decompose: false,
|
|
1194
|
+
next_action: "User should choose an approach, then call again with phase=recommendation",
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
return JSON.stringify(output, null, 2);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// Phase 3: Recommendation
|
|
1201
|
+
if (currentPhase === "recommendation") {
|
|
1202
|
+
const strategyResult = selectStrategy(args.task);
|
|
1203
|
+
const guidelines = formatStrategyGuidelines(strategyResult.strategy);
|
|
1204
|
+
|
|
1205
|
+
const output: SocraticPlanOutput = {
|
|
1206
|
+
mode: "socratic",
|
|
1207
|
+
phase: "recommendation",
|
|
1208
|
+
recommendation: {
|
|
1209
|
+
approach: strategyResult.strategy,
|
|
1210
|
+
reasoning: `Based on your input and task analysis:\n\n${strategyResult.reasoning}\n\n${guidelines}`,
|
|
1211
|
+
},
|
|
1212
|
+
memory_context: memoryContext || undefined,
|
|
1213
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1214
|
+
ready_to_decompose: false,
|
|
1215
|
+
next_action: "User should confirm to proceed. Then call again with phase=ready",
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1218
|
+
return JSON.stringify(output, null, 2);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
// Phase 4: Ready
|
|
1222
|
+
if (currentPhase === "ready") {
|
|
1223
|
+
const output: SocraticPlanOutput = {
|
|
1224
|
+
mode: "socratic",
|
|
1225
|
+
phase: "ready",
|
|
1226
|
+
recommendation: {
|
|
1227
|
+
approach: "Confirmed by user",
|
|
1228
|
+
reasoning: "Ready to proceed with decomposition",
|
|
1229
|
+
},
|
|
1230
|
+
memory_context: memoryContext || undefined,
|
|
1231
|
+
codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
|
|
1232
|
+
ready_to_decompose: true,
|
|
1233
|
+
next_action: "Proceed to swarm_decompose or swarm_delegate_planning",
|
|
1234
|
+
};
|
|
1235
|
+
|
|
1236
|
+
return JSON.stringify(output, null, 2);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// Should never reach here
|
|
1240
|
+
throw new Error(`Invalid planning phase: ${currentPhase}`);
|
|
1241
|
+
},
|
|
1242
|
+
});
|
|
1243
|
+
|
|
908
1244
|
export const decomposeTools = {
|
|
909
1245
|
swarm_decompose,
|
|
910
1246
|
swarm_validate_decomposition,
|
|
911
1247
|
swarm_delegate_planning,
|
|
1248
|
+
swarm_plan_interactive,
|
|
912
1249
|
};
|
package/src/swarm-orchestrate.ts
CHANGED
|
@@ -871,30 +871,8 @@ export const swarm_progress = tool({
|
|
|
871
871
|
});
|
|
872
872
|
await appendEvent(event, args.project_key);
|
|
873
873
|
|
|
874
|
-
//
|
|
875
|
-
|
|
876
|
-
const db = await getDatabase(args.project_key);
|
|
877
|
-
const now = Date.now();
|
|
878
|
-
await db.query(
|
|
879
|
-
`INSERT INTO swarm_contexts (id, epic_id, bead_id, strategy, files, dependencies, directives, recovery, created_at, updated_at)
|
|
880
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
881
|
-
ON CONFLICT (id) DO UPDATE SET
|
|
882
|
-
files = EXCLUDED.files,
|
|
883
|
-
recovery = EXCLUDED.recovery,
|
|
884
|
-
updated_at = EXCLUDED.updated_at`,
|
|
885
|
-
[
|
|
886
|
-
args.bead_id,
|
|
887
|
-
epicId,
|
|
888
|
-
args.bead_id,
|
|
889
|
-
checkpoint.strategy,
|
|
890
|
-
JSON.stringify(checkpoint.files),
|
|
891
|
-
JSON.stringify(checkpoint.dependencies),
|
|
892
|
-
JSON.stringify(checkpoint.directives),
|
|
893
|
-
JSON.stringify(checkpoint.recovery),
|
|
894
|
-
now,
|
|
895
|
-
now,
|
|
896
|
-
],
|
|
897
|
-
);
|
|
874
|
+
// NOTE: The event handler (handleSwarmCheckpointed in store.ts) updates
|
|
875
|
+
// the swarm_contexts table. We follow event sourcing pattern here.
|
|
898
876
|
checkpointCreated = true;
|
|
899
877
|
} catch (error) {
|
|
900
878
|
// Non-fatal - log and continue
|
|
@@ -2114,31 +2092,11 @@ export const swarm_checkpoint = tool({
|
|
|
2114
2092
|
|
|
2115
2093
|
await appendEvent(event, args.project_key);
|
|
2116
2094
|
|
|
2117
|
-
//
|
|
2118
|
-
|
|
2119
|
-
|
|
2095
|
+
// NOTE: The event handler (handleSwarmCheckpointed in store.ts) updates
|
|
2096
|
+
// the swarm_contexts table. We don't write directly here to follow
|
|
2097
|
+
// event sourcing pattern - single source of truth is the event log.
|
|
2120
2098
|
|
|
2121
2099
|
const now = Date.now();
|
|
2122
|
-
await db.query(
|
|
2123
|
-
`INSERT INTO swarm_contexts (id, epic_id, bead_id, strategy, files, dependencies, directives, recovery, created_at, updated_at)
|
|
2124
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
2125
|
-
ON CONFLICT (id) DO UPDATE SET
|
|
2126
|
-
files = EXCLUDED.files,
|
|
2127
|
-
recovery = EXCLUDED.recovery,
|
|
2128
|
-
updated_at = EXCLUDED.updated_at`,
|
|
2129
|
-
[
|
|
2130
|
-
args.bead_id, // Use bead_id as unique ID
|
|
2131
|
-
args.epic_id,
|
|
2132
|
-
args.bead_id,
|
|
2133
|
-
checkpoint.strategy,
|
|
2134
|
-
JSON.stringify(checkpoint.files),
|
|
2135
|
-
JSON.stringify(checkpoint.dependencies),
|
|
2136
|
-
JSON.stringify(checkpoint.directives),
|
|
2137
|
-
JSON.stringify(checkpoint.recovery),
|
|
2138
|
-
now,
|
|
2139
|
-
now,
|
|
2140
|
-
],
|
|
2141
|
-
);
|
|
2142
2100
|
|
|
2143
2101
|
return JSON.stringify(
|
|
2144
2102
|
{
|
|
@@ -2227,15 +2185,21 @@ export const swarm_recover = tool({
|
|
|
2227
2185
|
}
|
|
2228
2186
|
|
|
2229
2187
|
const row = result.rows[0];
|
|
2188
|
+
// PGLite auto-parses JSON columns, so we need to handle both cases
|
|
2189
|
+
const parseIfString = <T>(val: unknown): T =>
|
|
2190
|
+
typeof val === "string" ? JSON.parse(val) : (val as T);
|
|
2191
|
+
|
|
2230
2192
|
const context: SwarmBeadContext = {
|
|
2231
2193
|
id: row.id,
|
|
2232
2194
|
epic_id: row.epic_id,
|
|
2233
2195
|
bead_id: row.bead_id,
|
|
2234
2196
|
strategy: row.strategy as SwarmBeadContext["strategy"],
|
|
2235
|
-
files:
|
|
2236
|
-
dependencies:
|
|
2237
|
-
directives:
|
|
2238
|
-
|
|
2197
|
+
files: parseIfString<string[]>(row.files),
|
|
2198
|
+
dependencies: parseIfString<string[]>(row.dependencies),
|
|
2199
|
+
directives: parseIfString<SwarmBeadContext["directives"]>(
|
|
2200
|
+
row.directives,
|
|
2201
|
+
),
|
|
2202
|
+
recovery: parseIfString<SwarmBeadContext["recovery"]>(row.recovery),
|
|
2239
2203
|
created_at: row.created_at,
|
|
2240
2204
|
updated_at: row.updated_at,
|
|
2241
2205
|
};
|
package/src/swarm-prompts.ts
CHANGED
|
@@ -273,13 +273,11 @@ Only modify these files. Need others? Message the coordinator.
|
|
|
273
273
|
|
|
274
274
|
{error_context}
|
|
275
275
|
|
|
276
|
-
## [MANDATORY
|
|
276
|
+
## [MANDATORY SURVIVAL CHECKLIST]
|
|
277
277
|
|
|
278
|
-
**CRITICAL:
|
|
278
|
+
**CRITICAL: Follow this checklist IN ORDER. Each step builds on the previous.**
|
|
279
279
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
### Step 1: Initialize (REQUIRED - DO THIS FIRST)
|
|
280
|
+
### Step 1: Initialize Coordination (REQUIRED - DO THIS FIRST)
|
|
283
281
|
\`\`\`
|
|
284
282
|
swarmmail_init(project_path="{project_path}", task_description="{bead_id}: {subtask_title}")
|
|
285
283
|
\`\`\`
|
|
@@ -292,26 +290,124 @@ swarmmail_init(project_path="{project_path}", task_description="{bead_id}: {subt
|
|
|
292
290
|
|
|
293
291
|
**If you skip this step, your work will not be tracked and swarm_complete will fail.**
|
|
294
292
|
|
|
295
|
-
|
|
293
|
+
### Step 2: Query Past Learnings (BEFORE starting work)
|
|
294
|
+
\`\`\`
|
|
295
|
+
semantic-memory_find(query="<keywords from your task>", limit=5)
|
|
296
|
+
\`\`\`
|
|
296
297
|
|
|
297
|
-
|
|
298
|
+
**Check if past agents solved similar problems.** Search for:
|
|
299
|
+
- Error messages if debugging
|
|
300
|
+
- Domain concepts (e.g., "authentication", "caching")
|
|
301
|
+
- Technology stack (e.g., "Next.js", "React")
|
|
302
|
+
- Patterns (e.g., "event sourcing", "validation")
|
|
298
303
|
|
|
299
|
-
|
|
304
|
+
**Past learnings save time and prevent repeating mistakes.**
|
|
305
|
+
|
|
306
|
+
### Step 3: Load Relevant Skills (if available)
|
|
300
307
|
\`\`\`
|
|
301
|
-
|
|
302
|
-
|
|
308
|
+
skills_list() # See what skills exist
|
|
309
|
+
skills_use(name="<relevant-skill>", context="<your task>") # Load skill
|
|
303
310
|
\`\`\`
|
|
304
311
|
|
|
305
|
-
|
|
312
|
+
**Common skill triggers:**
|
|
313
|
+
- Writing tests? → \`skills_use(name="testing-patterns")\`
|
|
314
|
+
- Breaking dependencies? → \`skills_use(name="testing-patterns")\`
|
|
315
|
+
- Multi-agent coordination? → \`skills_use(name="swarm-coordination")\`
|
|
316
|
+
- Building a CLI? → \`skills_use(name="cli-builder")\`
|
|
317
|
+
|
|
318
|
+
### Step 4: Reserve Your Files (YOU reserve, not coordinator)
|
|
306
319
|
\`\`\`
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
320
|
+
swarmmail_reserve(
|
|
321
|
+
paths=[{file_list}],
|
|
322
|
+
reason="{bead_id}: {subtask_title}",
|
|
323
|
+
exclusive=true
|
|
324
|
+
)
|
|
325
|
+
\`\`\`
|
|
326
|
+
|
|
327
|
+
**Workers reserve their own files.** This prevents edit conflicts with other agents.
|
|
328
|
+
|
|
329
|
+
### Step 5: Do the Work
|
|
330
|
+
- Read your assigned files
|
|
331
|
+
- Implement changes
|
|
332
|
+
- Verify (typecheck if applicable)
|
|
333
|
+
|
|
334
|
+
### Step 6: Report Progress at Milestones
|
|
335
|
+
\`\`\`
|
|
336
|
+
swarm_progress(
|
|
337
|
+
project_key="{project_path}",
|
|
338
|
+
agent_name="<your-agent-name>",
|
|
339
|
+
bead_id="{bead_id}",
|
|
340
|
+
status="in_progress",
|
|
341
|
+
progress_percent=25, # or 50, 75
|
|
342
|
+
message="<what you just completed>"
|
|
312
343
|
)
|
|
313
344
|
\`\`\`
|
|
314
345
|
|
|
346
|
+
**Report at 25%, 50%, 75% completion.** This:
|
|
347
|
+
- Triggers auto-checkpoint (saves context)
|
|
348
|
+
- Keeps coordinator informed
|
|
349
|
+
- Prevents silent failures
|
|
350
|
+
|
|
351
|
+
### Step 7: Manual Checkpoint BEFORE Risky Operations
|
|
352
|
+
\`\`\`
|
|
353
|
+
swarm_checkpoint(
|
|
354
|
+
project_key="{project_path}",
|
|
355
|
+
agent_name="<your-agent-name>",
|
|
356
|
+
bead_id="{bead_id}"
|
|
357
|
+
)
|
|
358
|
+
\`\`\`
|
|
359
|
+
|
|
360
|
+
**Call BEFORE:**
|
|
361
|
+
- Large refactors
|
|
362
|
+
- File deletions
|
|
363
|
+
- Breaking API changes
|
|
364
|
+
- Anything that might fail catastrophically
|
|
365
|
+
|
|
366
|
+
**Checkpoints preserve context so you can recover if things go wrong.**
|
|
367
|
+
|
|
368
|
+
### Step 8: Store Learnings (if you discovered something)
|
|
369
|
+
\`\`\`
|
|
370
|
+
semantic-memory_store(
|
|
371
|
+
information="<what you learned, WHY it matters, how to apply it>",
|
|
372
|
+
metadata="<tags: domain, tech-stack, pattern-type>"
|
|
373
|
+
)
|
|
374
|
+
\`\`\`
|
|
375
|
+
|
|
376
|
+
**Store:**
|
|
377
|
+
- Tricky bugs you solved (root cause + solution)
|
|
378
|
+
- Project-specific patterns or domain rules
|
|
379
|
+
- Tool/library gotchas and workarounds
|
|
380
|
+
- Failed approaches (anti-patterns to avoid)
|
|
381
|
+
|
|
382
|
+
**Don't store generic knowledge.** Store the WHY, not just the WHAT.
|
|
383
|
+
|
|
384
|
+
### Step 9: Complete (REQUIRED - releases reservations)
|
|
385
|
+
\`\`\`
|
|
386
|
+
swarm_complete(
|
|
387
|
+
project_key="{project_path}",
|
|
388
|
+
agent_name="<your-agent-name>",
|
|
389
|
+
bead_id="{bead_id}",
|
|
390
|
+
summary="<what you accomplished>",
|
|
391
|
+
files_touched=["list", "of", "files"]
|
|
392
|
+
)
|
|
393
|
+
\`\`\`
|
|
394
|
+
|
|
395
|
+
**This automatically:**
|
|
396
|
+
- Runs UBS bug scan
|
|
397
|
+
- Releases file reservations
|
|
398
|
+
- Records learning signals
|
|
399
|
+
- Notifies coordinator
|
|
400
|
+
|
|
401
|
+
**DO NOT manually close the bead with beads_close.** Use swarm_complete.
|
|
402
|
+
|
|
403
|
+
## [SWARM MAIL COMMUNICATION]
|
|
404
|
+
|
|
405
|
+
### Check Inbox Regularly
|
|
406
|
+
\`\`\`
|
|
407
|
+
swarmmail_inbox() # Check for coordinator messages
|
|
408
|
+
swarmmail_read_message(message_id=N) # Read specific message
|
|
409
|
+
\`\`\`
|
|
410
|
+
|
|
315
411
|
### When Blocked
|
|
316
412
|
\`\`\`
|
|
317
413
|
swarmmail_send(
|
|
@@ -324,42 +420,48 @@ swarmmail_send(
|
|
|
324
420
|
beads_update(id="{bead_id}", status="blocked")
|
|
325
421
|
\`\`\`
|
|
326
422
|
|
|
327
|
-
###
|
|
423
|
+
### Report Issues to Other Agents
|
|
424
|
+
\`\`\`
|
|
425
|
+
swarmmail_send(
|
|
426
|
+
to=["OtherAgent", "coordinator"],
|
|
427
|
+
subject="Issue in {bead_id}",
|
|
428
|
+
body="<describe problem, don't fix their code>",
|
|
429
|
+
thread_id="{epic_id}"
|
|
430
|
+
)
|
|
431
|
+
\`\`\`
|
|
432
|
+
|
|
433
|
+
### Manual Release (if needed)
|
|
328
434
|
\`\`\`
|
|
329
|
-
swarmmail_release() #
|
|
435
|
+
swarmmail_release() # Manually release reservations
|
|
330
436
|
\`\`\`
|
|
331
437
|
|
|
438
|
+
**Note:** \`swarm_complete\` automatically releases reservations. Only use manual release if aborting work.
|
|
439
|
+
|
|
332
440
|
## [OTHER TOOLS]
|
|
333
441
|
### Beads
|
|
334
442
|
- beads_update(id, status) - Mark blocked if stuck
|
|
335
443
|
- beads_create(title, type) - Log new bugs found
|
|
336
444
|
|
|
337
|
-
### Skills
|
|
445
|
+
### Skills
|
|
338
446
|
- skills_list() - Discover available skills
|
|
339
447
|
- skills_use(name) - Activate skill for specialized guidance
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
6. **swarm_complete** - Mark done, release reservations
|
|
358
|
-
|
|
359
|
-
**CRITICAL REQUIREMENTS:**
|
|
360
|
-
- Step 1 (swarmmail_init) is NON-NEGOTIABLE - do it before anything else
|
|
361
|
-
- Never work silently - send progress updates via swarmmail_send every significant milestone
|
|
362
|
-
- If you complete without initializing, swarm_complete will detect this and warn/fail
|
|
448
|
+
- skills_create(name) - Create new skill (if you found a reusable pattern)
|
|
449
|
+
|
|
450
|
+
## [CRITICAL REQUIREMENTS]
|
|
451
|
+
|
|
452
|
+
**NON-NEGOTIABLE:**
|
|
453
|
+
1. Step 1 (swarmmail_init) MUST be first - do it before anything else
|
|
454
|
+
2. Step 2 (semantic-memory_find) MUST happen before starting work
|
|
455
|
+
3. Step 4 (swarmmail_reserve) - YOU reserve files, not coordinator
|
|
456
|
+
4. Step 6 (swarm_progress) - Report at milestones, don't work silently
|
|
457
|
+
5. Step 9 (swarm_complete) - Use this to close, NOT beads_close
|
|
458
|
+
|
|
459
|
+
**If you skip these steps:**
|
|
460
|
+
- Your work won't be tracked (swarm_complete will fail)
|
|
461
|
+
- You'll waste time repeating solved problems (no semantic memory query)
|
|
462
|
+
- Edit conflicts with other agents (no file reservation)
|
|
463
|
+
- Lost work if you crash (no checkpoints)
|
|
464
|
+
- Future agents repeat your mistakes (no learnings stored)
|
|
363
465
|
|
|
364
466
|
Begin now.`;
|
|
365
467
|
|