opencode-swarm-plugin 0.56.0 → 0.57.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/README.md +21 -0
- package/claude-plugin/.claude-plugin/plugin.json +1 -4
- package/claude-plugin/agents/background-worker.md +1 -0
- package/claude-plugin/agents/coordinator.md +1 -0
- package/claude-plugin/agents/worker.md +1 -0
- package/claude-plugin/bin/swarm-mcp-server.ts +47 -8
- package/claude-plugin/commands/hive.md +1 -1
- package/claude-plugin/commands/swarm.md +5 -1
- package/claude-plugin/dist/agent-mail.d.ts +480 -0
- package/claude-plugin/dist/agent-mail.d.ts.map +1 -0
- package/claude-plugin/dist/anti-patterns.d.ts +257 -0
- package/claude-plugin/dist/anti-patterns.d.ts.map +1 -0
- package/claude-plugin/dist/bin/swarm.js +373128 -0
- package/claude-plugin/dist/cass-tools.d.ts +74 -0
- package/claude-plugin/dist/cass-tools.d.ts.map +1 -0
- package/claude-plugin/dist/claude-plugin/claude-plugin-assets.d.ts +10 -0
- package/claude-plugin/dist/claude-plugin/claude-plugin-assets.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-hook.d.ts +178 -0
- package/claude-plugin/dist/compaction-hook.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-observability.d.ts +173 -0
- package/claude-plugin/dist/compaction-observability.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-prompt-scoring.d.ts +125 -0
- package/claude-plugin/dist/compaction-prompt-scoring.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-prompt-scoring.js +139 -0
- package/claude-plugin/dist/contributor-tools.d.ts +42 -0
- package/claude-plugin/dist/contributor-tools.d.ts.map +1 -0
- package/claude-plugin/dist/coordinator-guard.d.ts +79 -0
- package/claude-plugin/dist/coordinator-guard.d.ts.map +1 -0
- package/claude-plugin/dist/dashboard.d.ts +82 -0
- package/claude-plugin/dist/dashboard.d.ts.map +1 -0
- package/claude-plugin/dist/decision-trace-integration.d.ts +204 -0
- package/claude-plugin/dist/decision-trace-integration.d.ts.map +1 -0
- package/claude-plugin/dist/error-enrichment.d.ts +49 -0
- package/claude-plugin/dist/error-enrichment.d.ts.map +1 -0
- package/claude-plugin/dist/eval-capture.d.ts +494 -0
- package/claude-plugin/dist/eval-capture.d.ts.map +1 -0
- package/claude-plugin/dist/eval-capture.js +12844 -0
- package/claude-plugin/dist/eval-gates.d.ts +84 -0
- package/claude-plugin/dist/eval-gates.d.ts.map +1 -0
- package/claude-plugin/dist/eval-history.d.ts +117 -0
- package/claude-plugin/dist/eval-history.d.ts.map +1 -0
- package/claude-plugin/dist/eval-learning.d.ts +216 -0
- package/claude-plugin/dist/eval-learning.d.ts.map +1 -0
- package/claude-plugin/dist/eval-runner.d.ts +134 -0
- package/claude-plugin/dist/eval-runner.d.ts.map +1 -0
- package/claude-plugin/dist/examples/plugin-wrapper-template.ts +3341 -0
- package/claude-plugin/dist/export-tools.d.ts +76 -0
- package/claude-plugin/dist/export-tools.d.ts.map +1 -0
- package/claude-plugin/dist/hive.d.ts +949 -0
- package/claude-plugin/dist/hive.d.ts.map +1 -0
- package/claude-plugin/dist/hive.js +15009 -0
- package/claude-plugin/dist/hivemind-tools.d.ts +479 -0
- package/claude-plugin/dist/hivemind-tools.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/atomic-write.d.ts +21 -0
- package/claude-plugin/dist/hooks/atomic-write.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/constants.d.ts +28 -0
- package/claude-plugin/dist/hooks/constants.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/index.d.ts +16 -0
- package/claude-plugin/dist/hooks/index.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/session-start.d.ts +30 -0
- package/claude-plugin/dist/hooks/session-start.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/tool-complete.d.ts +54 -0
- package/claude-plugin/dist/hooks/tool-complete.d.ts.map +1 -0
- package/claude-plugin/dist/index.d.ts +2017 -0
- package/claude-plugin/dist/index.d.ts.map +1 -0
- package/claude-plugin/dist/index.js +73453 -0
- package/claude-plugin/dist/learning.d.ts +700 -0
- package/claude-plugin/dist/learning.d.ts.map +1 -0
- package/claude-plugin/dist/logger.d.ts +38 -0
- package/claude-plugin/dist/logger.d.ts.map +1 -0
- package/claude-plugin/dist/mandate-promotion.d.ts +93 -0
- package/claude-plugin/dist/mandate-promotion.d.ts.map +1 -0
- package/claude-plugin/dist/mandate-storage.d.ts +209 -0
- package/claude-plugin/dist/mandate-storage.d.ts.map +1 -0
- package/claude-plugin/dist/mandates.d.ts +230 -0
- package/claude-plugin/dist/mandates.d.ts.map +1 -0
- package/claude-plugin/dist/memory-tools.d.ts +281 -0
- package/claude-plugin/dist/memory-tools.d.ts.map +1 -0
- package/claude-plugin/dist/memory.d.ts +164 -0
- package/claude-plugin/dist/memory.d.ts.map +1 -0
- package/claude-plugin/dist/model-selection.d.ts +37 -0
- package/claude-plugin/dist/model-selection.d.ts.map +1 -0
- package/claude-plugin/dist/observability-health.d.ts +87 -0
- package/claude-plugin/dist/observability-health.d.ts.map +1 -0
- package/claude-plugin/dist/observability-tools.d.ts +184 -0
- package/claude-plugin/dist/observability-tools.d.ts.map +1 -0
- package/claude-plugin/dist/output-guardrails.d.ts +125 -0
- package/claude-plugin/dist/output-guardrails.d.ts.map +1 -0
- package/claude-plugin/dist/pattern-maturity.d.ts +246 -0
- package/claude-plugin/dist/pattern-maturity.d.ts.map +1 -0
- package/claude-plugin/dist/planning-guardrails.d.ts +183 -0
- package/claude-plugin/dist/planning-guardrails.d.ts.map +1 -0
- package/claude-plugin/dist/plugin.d.ts +22 -0
- package/claude-plugin/dist/plugin.d.ts.map +1 -0
- package/claude-plugin/dist/plugin.js +72295 -0
- package/claude-plugin/dist/post-compaction-tracker.d.ts +133 -0
- package/claude-plugin/dist/post-compaction-tracker.d.ts.map +1 -0
- package/claude-plugin/dist/query-tools.d.ts +90 -0
- package/claude-plugin/dist/query-tools.d.ts.map +1 -0
- package/claude-plugin/dist/rate-limiter.d.ts +218 -0
- package/claude-plugin/dist/rate-limiter.d.ts.map +1 -0
- package/claude-plugin/dist/regression-detection.d.ts +58 -0
- package/claude-plugin/dist/regression-detection.d.ts.map +1 -0
- package/claude-plugin/dist/replay-tools.d.ts +28 -0
- package/claude-plugin/dist/replay-tools.d.ts.map +1 -0
- package/claude-plugin/dist/repo-crawl.d.ts +146 -0
- package/claude-plugin/dist/repo-crawl.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/cell-events.d.ts +1352 -0
- package/claude-plugin/dist/schemas/cell-events.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/cell.d.ts +413 -0
- package/claude-plugin/dist/schemas/cell.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/evaluation.d.ts +161 -0
- package/claude-plugin/dist/schemas/evaluation.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/index.d.ts +46 -0
- package/claude-plugin/dist/schemas/index.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/mandate.d.ts +336 -0
- package/claude-plugin/dist/schemas/mandate.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/swarm-context.d.ts +131 -0
- package/claude-plugin/dist/schemas/swarm-context.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/task.d.ts +189 -0
- package/claude-plugin/dist/schemas/task.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/worker-handoff.d.ts +78 -0
- package/claude-plugin/dist/schemas/worker-handoff.d.ts.map +1 -0
- package/claude-plugin/dist/sessions/agent-discovery.d.ts +59 -0
- package/claude-plugin/dist/sessions/agent-discovery.d.ts.map +1 -0
- package/claude-plugin/dist/sessions/index.d.ts +10 -0
- package/claude-plugin/dist/sessions/index.d.ts.map +1 -0
- package/claude-plugin/dist/skills.d.ts +490 -0
- package/claude-plugin/dist/skills.d.ts.map +1 -0
- package/claude-plugin/dist/storage.d.ts +260 -0
- package/claude-plugin/dist/storage.d.ts.map +1 -0
- package/claude-plugin/dist/structured.d.ts +206 -0
- package/claude-plugin/dist/structured.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-adversarial-review.d.ts +104 -0
- package/claude-plugin/dist/swarm-adversarial-review.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-decompose.d.ts +297 -0
- package/claude-plugin/dist/swarm-decompose.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-insights.d.ts +390 -0
- package/claude-plugin/dist/swarm-insights.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-mail.d.ts +274 -0
- package/claude-plugin/dist/swarm-mail.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-orchestrate.d.ts +924 -0
- package/claude-plugin/dist/swarm-orchestrate.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-prompts.d.ts +467 -0
- package/claude-plugin/dist/swarm-prompts.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-prompts.js +45283 -0
- package/claude-plugin/dist/swarm-research.d.ts +125 -0
- package/claude-plugin/dist/swarm-research.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-review.d.ts +214 -0
- package/claude-plugin/dist/swarm-review.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-signature.d.ts +106 -0
- package/claude-plugin/dist/swarm-signature.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-strategies.d.ts +113 -0
- package/claude-plugin/dist/swarm-strategies.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-validation.d.ts +127 -0
- package/claude-plugin/dist/swarm-validation.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-worktree.d.ts +185 -0
- package/claude-plugin/dist/swarm-worktree.d.ts.map +1 -0
- package/claude-plugin/dist/swarm.d.ts +590 -0
- package/claude-plugin/dist/swarm.d.ts.map +1 -0
- package/claude-plugin/dist/tool-availability.d.ts +91 -0
- package/claude-plugin/dist/tool-availability.d.ts.map +1 -0
- package/claude-plugin/dist/utils/tree-renderer.d.ts +61 -0
- package/claude-plugin/dist/utils/tree-renderer.d.ts.map +1 -0
- package/claude-plugin/dist/validators/index.d.ts +7 -0
- package/claude-plugin/dist/validators/index.d.ts.map +1 -0
- package/claude-plugin/dist/validators/schema-validator.d.ts +58 -0
- package/claude-plugin/dist/validators/schema-validator.d.ts.map +1 -0
- package/claude-plugin/skills/always-on-guidance/SKILL.md +44 -0
- package/dist/agent-mail.d.ts +4 -4
- package/dist/agent-mail.d.ts.map +1 -1
- package/dist/bin/swarm.js +477 -22
- package/dist/claude-plugin/claude-plugin-assets.d.ts +10 -0
- package/dist/claude-plugin/claude-plugin-assets.d.ts.map +1 -0
- package/dist/compaction-hook.d.ts +1 -1
- package/dist/compaction-hook.d.ts.map +1 -1
- package/dist/index.js +375 -265
- package/dist/plugin.js +374 -264
- package/dist/skills.d.ts +15 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/swarm-mail.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +4 -2
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-prompts.js +84 -7
- package/global-skills/swarm-coordination/SKILL.md +21 -20
- package/package.json +2 -1
package/dist/plugin.js
CHANGED
|
@@ -26934,6 +26934,7 @@ __export(exports_skills, {
|
|
|
26934
26934
|
invalidateSkillsCache: () => invalidateSkillsCache,
|
|
26935
26935
|
getSkillsContextForSwarm: () => getSkillsContextForSwarm,
|
|
26936
26936
|
getSkill: () => getSkill,
|
|
26937
|
+
getAlwaysOnGuidanceSkill: () => getAlwaysOnGuidanceSkill,
|
|
26937
26938
|
findRelevantSkills: () => findRelevantSkills,
|
|
26938
26939
|
discoverSkills: () => discoverSkills
|
|
26939
26940
|
});
|
|
@@ -26949,6 +26950,44 @@ import {
|
|
|
26949
26950
|
} from "path";
|
|
26950
26951
|
import { fileURLToPath } from "url";
|
|
26951
26952
|
import { getSwarmMailLibSQL as getSwarmMailLibSQL3, createEvent as createEvent2 } from "swarm-mail";
|
|
26953
|
+
function resolveGuidanceModel(model) {
|
|
26954
|
+
if (!model)
|
|
26955
|
+
return "unknown";
|
|
26956
|
+
const normalized = model.toLowerCase();
|
|
26957
|
+
if (normalized.includes("gpt-5.2")) {
|
|
26958
|
+
return "gpt-5.2-code";
|
|
26959
|
+
}
|
|
26960
|
+
if (normalized.includes("opus-4-5") || normalized.includes("opus 4.5")) {
|
|
26961
|
+
return "opus-4.5";
|
|
26962
|
+
}
|
|
26963
|
+
return "unknown";
|
|
26964
|
+
}
|
|
26965
|
+
function getAlwaysOnGuidanceSkill(options2) {
|
|
26966
|
+
const roleGuidance = ALWAYS_ON_ROLE_GUIDANCE[options2.role];
|
|
26967
|
+
const modelBucket = resolveGuidanceModel(options2.model);
|
|
26968
|
+
let modelGuidance = "";
|
|
26969
|
+
if (modelBucket === "gpt-5.2-code") {
|
|
26970
|
+
modelGuidance = `### Model-Specific Guidance
|
|
26971
|
+
${GPT_5_2_GUIDANCE}`;
|
|
26972
|
+
} else if (modelBucket === "opus-4.5") {
|
|
26973
|
+
modelGuidance = `### Model-Specific Guidance
|
|
26974
|
+
${OPUS_4_5_GUIDANCE}`;
|
|
26975
|
+
} else {
|
|
26976
|
+
modelGuidance = `### Model-Specific Guidance
|
|
26977
|
+
${GPT_5_2_GUIDANCE}
|
|
26978
|
+
|
|
26979
|
+
${OPUS_4_5_GUIDANCE}`;
|
|
26980
|
+
}
|
|
26981
|
+
return [
|
|
26982
|
+
ALWAYS_ON_GUIDANCE_HEADER,
|
|
26983
|
+
ALWAYS_ON_TOOL_PRIORITY,
|
|
26984
|
+
ALWAYS_ON_RULE_FOLLOWING,
|
|
26985
|
+
roleGuidance,
|
|
26986
|
+
modelGuidance
|
|
26987
|
+
].join(`
|
|
26988
|
+
|
|
26989
|
+
`);
|
|
26990
|
+
}
|
|
26952
26991
|
async function emitSkillLoadedEvent(data) {
|
|
26953
26992
|
try {
|
|
26954
26993
|
const projectPath = skillsProjectDirectory;
|
|
@@ -27348,10 +27387,38 @@ async function findRelevantSkills(taskDescription) {
|
|
|
27348
27387
|
}
|
|
27349
27388
|
return relevant;
|
|
27350
27389
|
}
|
|
27351
|
-
var import_gray_matter,
|
|
27390
|
+
var import_gray_matter, ALWAYS_ON_GUIDANCE_HEADER = "## Always-On Guidance Skill", ALWAYS_ON_TOOL_PRIORITY = `### Tool Priority Order
|
|
27391
|
+
1. Swarm plugin tools (\`hive_*\`, \`swarm_*\`, \`swarmmail_*\`, \`structured_*\`)
|
|
27392
|
+
2. \`Read\`/\`Edit\` for file operations
|
|
27393
|
+
3. \`ast-grep\` for structural search
|
|
27394
|
+
4. \`Glob\`/\`Grep\` for discovery
|
|
27395
|
+
5. \`Task\` subagents for exploration
|
|
27396
|
+
6. \`Bash\` only for system commands
|
|
27397
|
+
|
|
27398
|
+
**Never use Bash for file read/write/edit/search.**`, ALWAYS_ON_RULE_FOLLOWING = `### Rule-Following Guardrails
|
|
27399
|
+
- Follow explicit tool constraints and approval modes
|
|
27400
|
+
- Do not invent tool output or files; ask when unsure
|
|
27401
|
+
- Keep changes scoped to assigned files and requirements`, ALWAYS_ON_ROLE_GUIDANCE, GPT_5_2_GUIDANCE = `#### GPT-5.2-code (Strict)
|
|
27402
|
+
- Follow instructions literally and exactly
|
|
27403
|
+
- Enforce tool priority order; fail closed if a tool is missing
|
|
27404
|
+
- Read before Edit; no speculative changes or output`, OPUS_4_5_GUIDANCE = `#### Opus 4.5 (Concise)
|
|
27405
|
+
- Be concise and deliberate while obeying mandates
|
|
27406
|
+
- Follow tool priorities without shortcuts
|
|
27407
|
+
- Prefer direct answers over speculation`, skillsProjectDirectory, skillsCache = null, PROJECT_SKILL_DIRECTORIES, skills_list, skills_use, skills_execute, skills_read, DEFAULT_SKILLS_DIR = ".opencode/skill", skills_create, skills_update, skills_delete, skills_add_script, skills_init, skillsTools;
|
|
27352
27408
|
var init_skills = __esm(() => {
|
|
27353
27409
|
init_dist();
|
|
27354
27410
|
import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
27411
|
+
ALWAYS_ON_ROLE_GUIDANCE = {
|
|
27412
|
+
coordinator: `### Coordinator Enforcement
|
|
27413
|
+
- Coordinator role: orchestrate, decompose, spawn workers
|
|
27414
|
+
- **Never** edit files or reserve locks directly
|
|
27415
|
+
- Coordinator override: use \`swarmmail_release_all\` only for stale/orphaned reservations (announce in Swarm Mail)
|
|
27416
|
+
- Review work with \`swarm_review\` before accepting`,
|
|
27417
|
+
worker: `### Worker Enforcement
|
|
27418
|
+
- Worker role: implement changes within reserved files
|
|
27419
|
+
- Reserve files before edits and follow TDD (RED → GREEN → REFACTOR)
|
|
27420
|
+
- Complete with \`swarm_complete\`, not \`hive_close\``
|
|
27421
|
+
};
|
|
27355
27422
|
skillsProjectDirectory = process.cwd();
|
|
27356
27423
|
PROJECT_SKILL_DIRECTORIES = [
|
|
27357
27424
|
".opencode/skill",
|
|
@@ -60206,8 +60273,8 @@ import {
|
|
|
60206
60273
|
import { join as join4 } from "path";
|
|
60207
60274
|
import { tmpdir } from "os";
|
|
60208
60275
|
var AGENT_MAIL_URL = "http://127.0.0.1:8765";
|
|
60209
|
-
var DEFAULT_TTL_SECONDS = 3600;
|
|
60210
60276
|
var MAX_INBOX_LIMIT = 5;
|
|
60277
|
+
var DEFAULT_OPENCODE_MODEL = "openai/gpt-5.2-codex";
|
|
60211
60278
|
var agentMailProjectDirectory = null;
|
|
60212
60279
|
function setAgentMailProjectDirectory(directory) {
|
|
60213
60280
|
agentMailProjectDirectory = directory;
|
|
@@ -60626,7 +60693,7 @@ var agentmail_init = tool({
|
|
|
60626
60693
|
const agent = await mcpCall("register_agent", {
|
|
60627
60694
|
project_key: projectPath,
|
|
60628
60695
|
program: "opencode",
|
|
60629
|
-
model:
|
|
60696
|
+
model: DEFAULT_OPENCODE_MODEL,
|
|
60630
60697
|
name: args.agent_name,
|
|
60631
60698
|
task_description: args.task_description || ""
|
|
60632
60699
|
});
|
|
@@ -60769,18 +60836,21 @@ var agentmail_reserve = tool({
|
|
|
60769
60836
|
description: "Reserve file paths for exclusive editing",
|
|
60770
60837
|
args: {
|
|
60771
60838
|
paths: tool.schema.array(tool.schema.string()).describe("File paths or globs to reserve (e.g., src/auth/**)"),
|
|
60772
|
-
ttl_seconds: tool.schema.number().
|
|
60839
|
+
ttl_seconds: tool.schema.number().int().positive().describe("Time to live in seconds (required)"),
|
|
60773
60840
|
exclusive: tool.schema.boolean().optional().describe("Exclusive lock (default: true)"),
|
|
60774
60841
|
reason: tool.schema.string().optional().describe("Reason for reservation (include bead ID)")
|
|
60775
60842
|
},
|
|
60776
60843
|
async execute(args, ctx) {
|
|
60777
60844
|
const state = requireState(ctx.sessionID);
|
|
60778
60845
|
await checkRateLimit(state.agentName, "reserve");
|
|
60846
|
+
if (!args.ttl_seconds || args.ttl_seconds <= 0) {
|
|
60847
|
+
throw new AgentMailError("ttl_seconds is required for file reservations", "file_reservation_paths");
|
|
60848
|
+
}
|
|
60779
60849
|
const result = await mcpCall("file_reservation_paths", {
|
|
60780
60850
|
project_key: state.projectKey,
|
|
60781
60851
|
agent_name: state.agentName,
|
|
60782
60852
|
paths: args.paths,
|
|
60783
|
-
ttl_seconds: args.ttl_seconds
|
|
60853
|
+
ttl_seconds: args.ttl_seconds,
|
|
60784
60854
|
exclusive: args.exclusive ?? true,
|
|
60785
60855
|
reason: args.reason || ""
|
|
60786
60856
|
});
|
|
@@ -60818,11 +60888,13 @@ var agentmail_release = tool({
|
|
|
60818
60888
|
async execute(args, ctx) {
|
|
60819
60889
|
const state = requireState(ctx.sessionID);
|
|
60820
60890
|
await checkRateLimit(state.agentName, "release");
|
|
60891
|
+
const shouldUseStoredIds = !args.paths && (!args.reservation_ids || args.reservation_ids.length === 0);
|
|
60892
|
+
const reservationIds = shouldUseStoredIds && state.reservations.length > 0 ? state.reservations : args.reservation_ids;
|
|
60821
60893
|
const result = await mcpCall("release_file_reservations", {
|
|
60822
60894
|
project_key: state.projectKey,
|
|
60823
60895
|
agent_name: state.agentName,
|
|
60824
60896
|
paths: args.paths,
|
|
60825
|
-
file_reservation_ids:
|
|
60897
|
+
file_reservation_ids: reservationIds
|
|
60826
60898
|
});
|
|
60827
60899
|
state.reservations = [];
|
|
60828
60900
|
setState(ctx.sessionID, state);
|
|
@@ -60935,6 +61007,260 @@ import {
|
|
|
60935
61007
|
checkSwarmHealth as checkSwarmHealth2,
|
|
60936
61008
|
getActiveReservations
|
|
60937
61009
|
} from "swarm-mail";
|
|
61010
|
+
|
|
61011
|
+
// src/planning-guardrails.ts
|
|
61012
|
+
init_eval_capture();
|
|
61013
|
+
var FILE_MODIFICATION_PATTERNS = [
|
|
61014
|
+
/\bimplement\b/i,
|
|
61015
|
+
/\bcreate\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
61016
|
+
/\badd\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
61017
|
+
/\bupdate\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
61018
|
+
/\bmodify\b/i,
|
|
61019
|
+
/\brefactor\b/i,
|
|
61020
|
+
/\bextract\b/i,
|
|
61021
|
+
/\bmigrate\b/i,
|
|
61022
|
+
/\bconvert\b/i,
|
|
61023
|
+
/\brewrite\b/i,
|
|
61024
|
+
/\bfix\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
61025
|
+
/\bwrite\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
61026
|
+
/src\//i,
|
|
61027
|
+
/lib\//i,
|
|
61028
|
+
/packages?\//i,
|
|
61029
|
+
/components?\//i
|
|
61030
|
+
];
|
|
61031
|
+
var TRACKING_PATTERNS = [
|
|
61032
|
+
/\breview\b/i,
|
|
61033
|
+
/\bcheck\b/i,
|
|
61034
|
+
/\bverify\b/i,
|
|
61035
|
+
/\btest\b.*pass/i,
|
|
61036
|
+
/\brun\b.*test/i,
|
|
61037
|
+
/\bdeploy\b/i,
|
|
61038
|
+
/\bmerge\b/i,
|
|
61039
|
+
/\bpr\b/i,
|
|
61040
|
+
/\bpush\b/i,
|
|
61041
|
+
/\bcommit\b/i
|
|
61042
|
+
];
|
|
61043
|
+
function analyzeTodoWrite(args) {
|
|
61044
|
+
const todos = args.todos;
|
|
61045
|
+
if (!todos || !Array.isArray(todos) || todos.length < 6) {
|
|
61046
|
+
return {
|
|
61047
|
+
looksLikeParallelWork: false,
|
|
61048
|
+
fileModificationCount: 0,
|
|
61049
|
+
totalCount: todos?.length ?? 0
|
|
61050
|
+
};
|
|
61051
|
+
}
|
|
61052
|
+
let fileModificationCount = 0;
|
|
61053
|
+
for (const todo of todos) {
|
|
61054
|
+
if (typeof todo !== "object" || todo === null)
|
|
61055
|
+
continue;
|
|
61056
|
+
const content = todo.content ?? "";
|
|
61057
|
+
const isFileModification = FILE_MODIFICATION_PATTERNS.some((pattern) => pattern.test(content));
|
|
61058
|
+
const isTracking = TRACKING_PATTERNS.some((pattern) => pattern.test(content));
|
|
61059
|
+
if (isFileModification && !isTracking) {
|
|
61060
|
+
fileModificationCount++;
|
|
61061
|
+
}
|
|
61062
|
+
}
|
|
61063
|
+
const ratio = fileModificationCount / todos.length;
|
|
61064
|
+
const looksLikeParallelWork = ratio >= 0.5 && fileModificationCount >= 4;
|
|
61065
|
+
if (looksLikeParallelWork) {
|
|
61066
|
+
return {
|
|
61067
|
+
looksLikeParallelWork: true,
|
|
61068
|
+
fileModificationCount,
|
|
61069
|
+
totalCount: todos.length,
|
|
61070
|
+
warning: `⚠️ This looks like a multi-file implementation plan (${fileModificationCount}/${todos.length} items are file modifications).
|
|
61071
|
+
|
|
61072
|
+
Consider using swarm instead:
|
|
61073
|
+
swarm_decompose → hive_create_epic → parallel task spawns
|
|
61074
|
+
|
|
61075
|
+
TodoWrite is for tracking progress, not parallelizable implementation work.
|
|
61076
|
+
Swarm workers can complete these ${fileModificationCount} tasks in parallel.
|
|
61077
|
+
|
|
61078
|
+
(Continuing with todowrite - this is just a suggestion)`
|
|
61079
|
+
};
|
|
61080
|
+
}
|
|
61081
|
+
return {
|
|
61082
|
+
looksLikeParallelWork: false,
|
|
61083
|
+
fileModificationCount,
|
|
61084
|
+
totalCount: todos.length
|
|
61085
|
+
};
|
|
61086
|
+
}
|
|
61087
|
+
function shouldAnalyzeTool(toolName) {
|
|
61088
|
+
return toolName === "todowrite" || toolName === "TodoWrite";
|
|
61089
|
+
}
|
|
61090
|
+
var VIOLATION_PATTERNS = {
|
|
61091
|
+
FILE_MODIFICATION_TOOLS: ["edit", "write"],
|
|
61092
|
+
RESERVATION_TOOLS: ["swarmmail_reserve", "agentmail_reserve"],
|
|
61093
|
+
TEST_EXECUTION_PATTERNS: [
|
|
61094
|
+
/\bbun\s+test\b/i,
|
|
61095
|
+
/\bnpm\s+(run\s+)?test/i,
|
|
61096
|
+
/\byarn\s+(run\s+)?test/i,
|
|
61097
|
+
/\bpnpm\s+(run\s+)?test/i,
|
|
61098
|
+
/\bjest\b/i,
|
|
61099
|
+
/\bvitest\b/i,
|
|
61100
|
+
/\bmocha\b/i,
|
|
61101
|
+
/\bava\b/i,
|
|
61102
|
+
/\btape\b/i,
|
|
61103
|
+
/\.test\.(ts|js|tsx|jsx)\b/i,
|
|
61104
|
+
/\.spec\.(ts|js|tsx|jsx)\b/i
|
|
61105
|
+
]
|
|
61106
|
+
};
|
|
61107
|
+
function detectCoordinatorViolation(params) {
|
|
61108
|
+
const { sessionId, epicId, toolName, toolArgs, agentContext, checkNoSpawn = false } = params;
|
|
61109
|
+
if (agentContext !== "coordinator") {
|
|
61110
|
+
return { isViolation: false };
|
|
61111
|
+
}
|
|
61112
|
+
if (VIOLATION_PATTERNS.FILE_MODIFICATION_TOOLS.includes(toolName)) {
|
|
61113
|
+
const file2 = toolArgs.filePath || "";
|
|
61114
|
+
const payload = { tool: toolName, file: file2 };
|
|
61115
|
+
captureCoordinatorEvent({
|
|
61116
|
+
session_id: sessionId,
|
|
61117
|
+
epic_id: epicId,
|
|
61118
|
+
timestamp: new Date().toISOString(),
|
|
61119
|
+
event_type: "VIOLATION",
|
|
61120
|
+
violation_type: "coordinator_edited_file",
|
|
61121
|
+
payload
|
|
61122
|
+
});
|
|
61123
|
+
return {
|
|
61124
|
+
isViolation: true,
|
|
61125
|
+
violationType: "coordinator_edited_file",
|
|
61126
|
+
message: `⚠️ Coordinator should not edit files directly. Coordinators should spawn workers to implement changes.`,
|
|
61127
|
+
payload
|
|
61128
|
+
};
|
|
61129
|
+
}
|
|
61130
|
+
if (toolName === "bash") {
|
|
61131
|
+
const command = toolArgs.command || "";
|
|
61132
|
+
const isTestCommand = VIOLATION_PATTERNS.TEST_EXECUTION_PATTERNS.some((pattern) => pattern.test(command));
|
|
61133
|
+
if (isTestCommand) {
|
|
61134
|
+
const payload = { tool: toolName, command };
|
|
61135
|
+
captureCoordinatorEvent({
|
|
61136
|
+
session_id: sessionId,
|
|
61137
|
+
epic_id: epicId,
|
|
61138
|
+
timestamp: new Date().toISOString(),
|
|
61139
|
+
event_type: "VIOLATION",
|
|
61140
|
+
violation_type: "coordinator_ran_tests",
|
|
61141
|
+
payload
|
|
61142
|
+
});
|
|
61143
|
+
return {
|
|
61144
|
+
isViolation: true,
|
|
61145
|
+
violationType: "coordinator_ran_tests",
|
|
61146
|
+
message: `⚠️ Coordinator should not run tests directly. Workers run tests as part of their implementation verification.`,
|
|
61147
|
+
payload
|
|
61148
|
+
};
|
|
61149
|
+
}
|
|
61150
|
+
}
|
|
61151
|
+
if (VIOLATION_PATTERNS.RESERVATION_TOOLS.includes(toolName)) {
|
|
61152
|
+
const paths = toolArgs.paths || [];
|
|
61153
|
+
const payload = { tool: toolName, paths };
|
|
61154
|
+
captureCoordinatorEvent({
|
|
61155
|
+
session_id: sessionId,
|
|
61156
|
+
epic_id: epicId,
|
|
61157
|
+
timestamp: new Date().toISOString(),
|
|
61158
|
+
event_type: "VIOLATION",
|
|
61159
|
+
violation_type: "coordinator_reserved_files",
|
|
61160
|
+
payload
|
|
61161
|
+
});
|
|
61162
|
+
return {
|
|
61163
|
+
isViolation: true,
|
|
61164
|
+
violationType: "coordinator_reserved_files",
|
|
61165
|
+
message: `⚠️ Coordinator should not reserve files. Workers reserve files before editing to prevent conflicts.`,
|
|
61166
|
+
payload
|
|
61167
|
+
};
|
|
61168
|
+
}
|
|
61169
|
+
if (toolName === "hive_create_epic" && checkNoSpawn) {
|
|
61170
|
+
const epicTitle = toolArgs.epic_title || "";
|
|
61171
|
+
const subtasks = toolArgs.subtasks || [];
|
|
61172
|
+
const payload = { epic_title: epicTitle, subtask_count: subtasks.length };
|
|
61173
|
+
captureCoordinatorEvent({
|
|
61174
|
+
session_id: sessionId,
|
|
61175
|
+
epic_id: epicId,
|
|
61176
|
+
timestamp: new Date().toISOString(),
|
|
61177
|
+
event_type: "VIOLATION",
|
|
61178
|
+
violation_type: "no_worker_spawned",
|
|
61179
|
+
payload
|
|
61180
|
+
});
|
|
61181
|
+
return {
|
|
61182
|
+
isViolation: true,
|
|
61183
|
+
violationType: "no_worker_spawned",
|
|
61184
|
+
message: `⚠️ Coordinator created decomposition without spawning workers. After hive_create_epic, use swarm_spawn_subtask for each task.`,
|
|
61185
|
+
payload
|
|
61186
|
+
};
|
|
61187
|
+
}
|
|
61188
|
+
if (toolName === "swarm_complete" || toolName === "hive_close") {
|
|
61189
|
+
const payload = { tool: toolName };
|
|
61190
|
+
captureCoordinatorEvent({
|
|
61191
|
+
session_id: sessionId,
|
|
61192
|
+
epic_id: epicId,
|
|
61193
|
+
timestamp: new Date().toISOString(),
|
|
61194
|
+
event_type: "VIOLATION",
|
|
61195
|
+
violation_type: "worker_completed_without_review",
|
|
61196
|
+
payload
|
|
61197
|
+
});
|
|
61198
|
+
return {
|
|
61199
|
+
isViolation: true,
|
|
61200
|
+
violationType: "worker_completed_without_review",
|
|
61201
|
+
message: `⚠️ Coordinator should not complete worker tasks directly. Coordinators should review worker output using swarm_review and swarm_review_feedback.`,
|
|
61202
|
+
payload
|
|
61203
|
+
};
|
|
61204
|
+
}
|
|
61205
|
+
return { isViolation: false };
|
|
61206
|
+
}
|
|
61207
|
+
var coordinatorContexts = new Map;
|
|
61208
|
+
var globalCoordinatorContext = {
|
|
61209
|
+
isCoordinator: false
|
|
61210
|
+
};
|
|
61211
|
+
function setCoordinatorContext(ctx) {
|
|
61212
|
+
const sessionId = ctx.sessionId;
|
|
61213
|
+
if (sessionId) {
|
|
61214
|
+
const existing = coordinatorContexts.get(sessionId) || { isCoordinator: false };
|
|
61215
|
+
coordinatorContexts.set(sessionId, {
|
|
61216
|
+
...existing,
|
|
61217
|
+
...ctx,
|
|
61218
|
+
activatedAt: ctx.isCoordinator ? Date.now() : existing.activatedAt
|
|
61219
|
+
});
|
|
61220
|
+
} else {
|
|
61221
|
+
globalCoordinatorContext = {
|
|
61222
|
+
...globalCoordinatorContext,
|
|
61223
|
+
...ctx,
|
|
61224
|
+
activatedAt: ctx.isCoordinator ? Date.now() : globalCoordinatorContext.activatedAt
|
|
61225
|
+
};
|
|
61226
|
+
}
|
|
61227
|
+
}
|
|
61228
|
+
function getCoordinatorContext(sessionId) {
|
|
61229
|
+
if (sessionId) {
|
|
61230
|
+
return { ...coordinatorContexts.get(sessionId) || { isCoordinator: false } };
|
|
61231
|
+
}
|
|
61232
|
+
return { ...globalCoordinatorContext };
|
|
61233
|
+
}
|
|
61234
|
+
function clearCoordinatorContext(sessionId) {
|
|
61235
|
+
if (sessionId) {
|
|
61236
|
+
coordinatorContexts.delete(sessionId);
|
|
61237
|
+
} else {
|
|
61238
|
+
globalCoordinatorContext = {
|
|
61239
|
+
isCoordinator: false
|
|
61240
|
+
};
|
|
61241
|
+
}
|
|
61242
|
+
}
|
|
61243
|
+
function isInCoordinatorContext(sessionId) {
|
|
61244
|
+
const ctx = sessionId ? coordinatorContexts.get(sessionId) : globalCoordinatorContext;
|
|
61245
|
+
if (!ctx || !ctx.isCoordinator) {
|
|
61246
|
+
return false;
|
|
61247
|
+
}
|
|
61248
|
+
const COORDINATOR_TIMEOUT_MS = 4 * 60 * 60 * 1000;
|
|
61249
|
+
if (ctx.activatedAt) {
|
|
61250
|
+
const elapsed = Date.now() - ctx.activatedAt;
|
|
61251
|
+
if (elapsed > COORDINATOR_TIMEOUT_MS) {
|
|
61252
|
+
if (sessionId) {
|
|
61253
|
+
coordinatorContexts.delete(sessionId);
|
|
61254
|
+
} else {
|
|
61255
|
+
globalCoordinatorContext = { isCoordinator: false };
|
|
61256
|
+
}
|
|
61257
|
+
return false;
|
|
61258
|
+
}
|
|
61259
|
+
}
|
|
61260
|
+
return true;
|
|
61261
|
+
}
|
|
61262
|
+
|
|
61263
|
+
// src/swarm-mail.ts
|
|
60938
61264
|
import {
|
|
60939
61265
|
existsSync as existsSync5,
|
|
60940
61266
|
mkdirSync as mkdirSync4,
|
|
@@ -60982,6 +61308,21 @@ function saveSessionState2(sessionID, state) {
|
|
|
60982
61308
|
return false;
|
|
60983
61309
|
}
|
|
60984
61310
|
}
|
|
61311
|
+
function hasCoordinatorOverride(sessionID) {
|
|
61312
|
+
return isInCoordinatorContext(sessionID) || isInCoordinatorContext();
|
|
61313
|
+
}
|
|
61314
|
+
function formatCoordinatorOverrideError(params) {
|
|
61315
|
+
return JSON.stringify({
|
|
61316
|
+
error: "Coordinator-only override. Ask the coordinator to use this tool for stale or orphaned reservations.",
|
|
61317
|
+
guard: "coordinator_only",
|
|
61318
|
+
required_context: "coordinator",
|
|
61319
|
+
tool: params.tool,
|
|
61320
|
+
agent_name: params.state.agentName,
|
|
61321
|
+
project_key: params.state.projectKey,
|
|
61322
|
+
session_id: params.sessionID,
|
|
61323
|
+
suggestion: "If reservations are stale, notify the coordinator via swarmmail_send before releasing."
|
|
61324
|
+
}, null, 2);
|
|
61325
|
+
}
|
|
60985
61326
|
var swarmmail_init = tool({
|
|
60986
61327
|
description: "Initialize Swarm Mail session. Creates agent identity and registers with the embedded event store.",
|
|
60987
61328
|
args: {
|
|
@@ -61236,6 +61577,13 @@ var swarmmail_release_all = tool({
|
|
|
61236
61577
|
if (!state) {
|
|
61237
61578
|
return JSON.stringify({ error: "Session not initialized. Call swarmmail_init first." }, null, 2);
|
|
61238
61579
|
}
|
|
61580
|
+
if (!hasCoordinatorOverride(sessionID)) {
|
|
61581
|
+
return formatCoordinatorOverrideError({
|
|
61582
|
+
tool: "swarmmail_release_all",
|
|
61583
|
+
state,
|
|
61584
|
+
sessionID
|
|
61585
|
+
});
|
|
61586
|
+
}
|
|
61239
61587
|
try {
|
|
61240
61588
|
const result = await releaseAllSwarmFiles({
|
|
61241
61589
|
projectPath: state.projectKey,
|
|
@@ -61266,6 +61614,13 @@ var swarmmail_release_agent = tool({
|
|
|
61266
61614
|
if (!state) {
|
|
61267
61615
|
return JSON.stringify({ error: "Session not initialized. Call swarmmail_init first." }, null, 2);
|
|
61268
61616
|
}
|
|
61617
|
+
if (!hasCoordinatorOverride(sessionID)) {
|
|
61618
|
+
return formatCoordinatorOverrideError({
|
|
61619
|
+
tool: "swarmmail_release_agent",
|
|
61620
|
+
state,
|
|
61621
|
+
sessionID
|
|
61622
|
+
});
|
|
61623
|
+
}
|
|
61269
61624
|
try {
|
|
61270
61625
|
const result = await releaseSwarmFilesForAgent({
|
|
61271
61626
|
projectPath: state.projectKey,
|
|
@@ -66674,7 +67029,7 @@ var STRATEGY_DECOMPOSITION_PROMPT2 = `You are decomposing a task into paralleliz
|
|
|
66674
67029
|
|
|
66675
67030
|
{context_section}
|
|
66676
67031
|
|
|
66677
|
-
{
|
|
67032
|
+
{hivemind_history}
|
|
66678
67033
|
|
|
66679
67034
|
{skills_context}
|
|
66680
67035
|
|
|
@@ -67596,7 +67951,8 @@ var swarm_spawn_subtask = tool({
|
|
|
67596
67951
|
files: args2.files,
|
|
67597
67952
|
shared_context: args2.shared_context,
|
|
67598
67953
|
project_path: args2.project_path,
|
|
67599
|
-
recovery_context: args2.recovery_context
|
|
67954
|
+
recovery_context: args2.recovery_context,
|
|
67955
|
+
model: args2.model
|
|
67600
67956
|
});
|
|
67601
67957
|
const { selectWorkerModel: selectWorkerModel2 } = await Promise.resolve().then(() => exports_model_selection);
|
|
67602
67958
|
const subtask = {
|
|
@@ -67857,13 +68213,13 @@ var swarm_evaluation_prompt = tool({
|
|
|
67857
68213
|
}
|
|
67858
68214
|
});
|
|
67859
68215
|
var swarm_plan_prompt = tool({
|
|
67860
|
-
description: "Generate strategy-specific decomposition prompt. Auto-selects strategy or uses provided one. Queries
|
|
68216
|
+
description: "Generate strategy-specific decomposition prompt. Auto-selects strategy or uses provided one. Queries Hivemind sessions for similar tasks.",
|
|
67861
68217
|
args: {
|
|
67862
68218
|
task: tool.schema.string().min(1).describe("Task description to decompose"),
|
|
67863
68219
|
strategy: tool.schema.enum(["file-based", "feature-based", "risk-based", "auto"]).optional().describe("Decomposition strategy (default: auto-detect)"),
|
|
67864
68220
|
context: tool.schema.string().optional().describe("Additional context (codebase info, constraints, etc.)"),
|
|
67865
|
-
query_cass: tool.schema.boolean().optional().describe("Query
|
|
67866
|
-
cass_limit: tool.schema.number().int().min(1).optional().describe("Max
|
|
68221
|
+
query_cass: tool.schema.boolean().optional().describe("Query Hivemind sessions for similar past tasks (default: true)"),
|
|
68222
|
+
cass_limit: tool.schema.number().int().min(1).optional().describe("Max Hivemind session results to include (default: 3)"),
|
|
67867
68223
|
include_skills: tool.schema.boolean().optional().describe("Include available skills in context (default: true)")
|
|
67868
68224
|
},
|
|
67869
68225
|
async execute(args2) {
|
|
@@ -67911,7 +68267,7 @@ ${insights}` : insights ? `## Additional Context
|
|
|
67911
68267
|
|
|
67912
68268
|
${insights}` : `## Additional Context
|
|
67913
68269
|
(none provided)`;
|
|
67914
|
-
const prompt = STRATEGY_DECOMPOSITION_PROMPT2.replace("{task}", args2.task).replace("{strategy_guidelines}", strategyGuidelines).replace("{context_section}", contextSection).replace("{
|
|
68270
|
+
const prompt = STRATEGY_DECOMPOSITION_PROMPT2.replace("{task}", args2.task).replace("{strategy_guidelines}", strategyGuidelines).replace("{context_section}", contextSection).replace("{hivemind_history}", "").replace("{skills_context}", skillsContext || "");
|
|
67915
68271
|
return JSON.stringify({
|
|
67916
68272
|
prompt,
|
|
67917
68273
|
strategy: {
|
|
@@ -70306,258 +70662,6 @@ function guardrailOutput(toolName, output, config2 = DEFAULT_GUARDRAIL_CONFIG) {
|
|
|
70306
70662
|
};
|
|
70307
70663
|
}
|
|
70308
70664
|
|
|
70309
|
-
// src/planning-guardrails.ts
|
|
70310
|
-
init_eval_capture();
|
|
70311
|
-
var FILE_MODIFICATION_PATTERNS = [
|
|
70312
|
-
/\bimplement\b/i,
|
|
70313
|
-
/\bcreate\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
70314
|
-
/\badd\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
70315
|
-
/\bupdate\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
70316
|
-
/\bmodify\b/i,
|
|
70317
|
-
/\brefactor\b/i,
|
|
70318
|
-
/\bextract\b/i,
|
|
70319
|
-
/\bmigrate\b/i,
|
|
70320
|
-
/\bconvert\b/i,
|
|
70321
|
-
/\brewrite\b/i,
|
|
70322
|
-
/\bfix\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
70323
|
-
/\bwrite\b.*\.(ts|js|tsx|jsx|py|rs|go|java|rb|swift|kt)/i,
|
|
70324
|
-
/src\//i,
|
|
70325
|
-
/lib\//i,
|
|
70326
|
-
/packages?\//i,
|
|
70327
|
-
/components?\//i
|
|
70328
|
-
];
|
|
70329
|
-
var TRACKING_PATTERNS = [
|
|
70330
|
-
/\breview\b/i,
|
|
70331
|
-
/\bcheck\b/i,
|
|
70332
|
-
/\bverify\b/i,
|
|
70333
|
-
/\btest\b.*pass/i,
|
|
70334
|
-
/\brun\b.*test/i,
|
|
70335
|
-
/\bdeploy\b/i,
|
|
70336
|
-
/\bmerge\b/i,
|
|
70337
|
-
/\bpr\b/i,
|
|
70338
|
-
/\bpush\b/i,
|
|
70339
|
-
/\bcommit\b/i
|
|
70340
|
-
];
|
|
70341
|
-
function analyzeTodoWrite(args2) {
|
|
70342
|
-
const todos = args2.todos;
|
|
70343
|
-
if (!todos || !Array.isArray(todos) || todos.length < 6) {
|
|
70344
|
-
return {
|
|
70345
|
-
looksLikeParallelWork: false,
|
|
70346
|
-
fileModificationCount: 0,
|
|
70347
|
-
totalCount: todos?.length ?? 0
|
|
70348
|
-
};
|
|
70349
|
-
}
|
|
70350
|
-
let fileModificationCount = 0;
|
|
70351
|
-
for (const todo of todos) {
|
|
70352
|
-
if (typeof todo !== "object" || todo === null)
|
|
70353
|
-
continue;
|
|
70354
|
-
const content = todo.content ?? "";
|
|
70355
|
-
const isFileModification = FILE_MODIFICATION_PATTERNS.some((pattern2) => pattern2.test(content));
|
|
70356
|
-
const isTracking = TRACKING_PATTERNS.some((pattern2) => pattern2.test(content));
|
|
70357
|
-
if (isFileModification && !isTracking) {
|
|
70358
|
-
fileModificationCount++;
|
|
70359
|
-
}
|
|
70360
|
-
}
|
|
70361
|
-
const ratio = fileModificationCount / todos.length;
|
|
70362
|
-
const looksLikeParallelWork = ratio >= 0.5 && fileModificationCount >= 4;
|
|
70363
|
-
if (looksLikeParallelWork) {
|
|
70364
|
-
return {
|
|
70365
|
-
looksLikeParallelWork: true,
|
|
70366
|
-
fileModificationCount,
|
|
70367
|
-
totalCount: todos.length,
|
|
70368
|
-
warning: `⚠️ This looks like a multi-file implementation plan (${fileModificationCount}/${todos.length} items are file modifications).
|
|
70369
|
-
|
|
70370
|
-
Consider using swarm instead:
|
|
70371
|
-
swarm_decompose → hive_create_epic → parallel task spawns
|
|
70372
|
-
|
|
70373
|
-
TodoWrite is for tracking progress, not parallelizable implementation work.
|
|
70374
|
-
Swarm workers can complete these ${fileModificationCount} tasks in parallel.
|
|
70375
|
-
|
|
70376
|
-
(Continuing with todowrite - this is just a suggestion)`
|
|
70377
|
-
};
|
|
70378
|
-
}
|
|
70379
|
-
return {
|
|
70380
|
-
looksLikeParallelWork: false,
|
|
70381
|
-
fileModificationCount,
|
|
70382
|
-
totalCount: todos.length
|
|
70383
|
-
};
|
|
70384
|
-
}
|
|
70385
|
-
function shouldAnalyzeTool(toolName) {
|
|
70386
|
-
return toolName === "todowrite" || toolName === "TodoWrite";
|
|
70387
|
-
}
|
|
70388
|
-
var VIOLATION_PATTERNS = {
|
|
70389
|
-
FILE_MODIFICATION_TOOLS: ["edit", "write"],
|
|
70390
|
-
RESERVATION_TOOLS: ["swarmmail_reserve", "agentmail_reserve"],
|
|
70391
|
-
TEST_EXECUTION_PATTERNS: [
|
|
70392
|
-
/\bbun\s+test\b/i,
|
|
70393
|
-
/\bnpm\s+(run\s+)?test/i,
|
|
70394
|
-
/\byarn\s+(run\s+)?test/i,
|
|
70395
|
-
/\bpnpm\s+(run\s+)?test/i,
|
|
70396
|
-
/\bjest\b/i,
|
|
70397
|
-
/\bvitest\b/i,
|
|
70398
|
-
/\bmocha\b/i,
|
|
70399
|
-
/\bava\b/i,
|
|
70400
|
-
/\btape\b/i,
|
|
70401
|
-
/\.test\.(ts|js|tsx|jsx)\b/i,
|
|
70402
|
-
/\.spec\.(ts|js|tsx|jsx)\b/i
|
|
70403
|
-
]
|
|
70404
|
-
};
|
|
70405
|
-
function detectCoordinatorViolation(params) {
|
|
70406
|
-
const { sessionId, epicId, toolName, toolArgs, agentContext, checkNoSpawn = false } = params;
|
|
70407
|
-
if (agentContext !== "coordinator") {
|
|
70408
|
-
return { isViolation: false };
|
|
70409
|
-
}
|
|
70410
|
-
if (VIOLATION_PATTERNS.FILE_MODIFICATION_TOOLS.includes(toolName)) {
|
|
70411
|
-
const file2 = toolArgs.filePath || "";
|
|
70412
|
-
const payload = { tool: toolName, file: file2 };
|
|
70413
|
-
captureCoordinatorEvent({
|
|
70414
|
-
session_id: sessionId,
|
|
70415
|
-
epic_id: epicId,
|
|
70416
|
-
timestamp: new Date().toISOString(),
|
|
70417
|
-
event_type: "VIOLATION",
|
|
70418
|
-
violation_type: "coordinator_edited_file",
|
|
70419
|
-
payload
|
|
70420
|
-
});
|
|
70421
|
-
return {
|
|
70422
|
-
isViolation: true,
|
|
70423
|
-
violationType: "coordinator_edited_file",
|
|
70424
|
-
message: `⚠️ Coordinator should not edit files directly. Coordinators should spawn workers to implement changes.`,
|
|
70425
|
-
payload
|
|
70426
|
-
};
|
|
70427
|
-
}
|
|
70428
|
-
if (toolName === "bash") {
|
|
70429
|
-
const command = toolArgs.command || "";
|
|
70430
|
-
const isTestCommand = VIOLATION_PATTERNS.TEST_EXECUTION_PATTERNS.some((pattern2) => pattern2.test(command));
|
|
70431
|
-
if (isTestCommand) {
|
|
70432
|
-
const payload = { tool: toolName, command };
|
|
70433
|
-
captureCoordinatorEvent({
|
|
70434
|
-
session_id: sessionId,
|
|
70435
|
-
epic_id: epicId,
|
|
70436
|
-
timestamp: new Date().toISOString(),
|
|
70437
|
-
event_type: "VIOLATION",
|
|
70438
|
-
violation_type: "coordinator_ran_tests",
|
|
70439
|
-
payload
|
|
70440
|
-
});
|
|
70441
|
-
return {
|
|
70442
|
-
isViolation: true,
|
|
70443
|
-
violationType: "coordinator_ran_tests",
|
|
70444
|
-
message: `⚠️ Coordinator should not run tests directly. Workers run tests as part of their implementation verification.`,
|
|
70445
|
-
payload
|
|
70446
|
-
};
|
|
70447
|
-
}
|
|
70448
|
-
}
|
|
70449
|
-
if (VIOLATION_PATTERNS.RESERVATION_TOOLS.includes(toolName)) {
|
|
70450
|
-
const paths = toolArgs.paths || [];
|
|
70451
|
-
const payload = { tool: toolName, paths };
|
|
70452
|
-
captureCoordinatorEvent({
|
|
70453
|
-
session_id: sessionId,
|
|
70454
|
-
epic_id: epicId,
|
|
70455
|
-
timestamp: new Date().toISOString(),
|
|
70456
|
-
event_type: "VIOLATION",
|
|
70457
|
-
violation_type: "coordinator_reserved_files",
|
|
70458
|
-
payload
|
|
70459
|
-
});
|
|
70460
|
-
return {
|
|
70461
|
-
isViolation: true,
|
|
70462
|
-
violationType: "coordinator_reserved_files",
|
|
70463
|
-
message: `⚠️ Coordinator should not reserve files. Workers reserve files before editing to prevent conflicts.`,
|
|
70464
|
-
payload
|
|
70465
|
-
};
|
|
70466
|
-
}
|
|
70467
|
-
if (toolName === "hive_create_epic" && checkNoSpawn) {
|
|
70468
|
-
const epicTitle = toolArgs.epic_title || "";
|
|
70469
|
-
const subtasks = toolArgs.subtasks || [];
|
|
70470
|
-
const payload = { epic_title: epicTitle, subtask_count: subtasks.length };
|
|
70471
|
-
captureCoordinatorEvent({
|
|
70472
|
-
session_id: sessionId,
|
|
70473
|
-
epic_id: epicId,
|
|
70474
|
-
timestamp: new Date().toISOString(),
|
|
70475
|
-
event_type: "VIOLATION",
|
|
70476
|
-
violation_type: "no_worker_spawned",
|
|
70477
|
-
payload
|
|
70478
|
-
});
|
|
70479
|
-
return {
|
|
70480
|
-
isViolation: true,
|
|
70481
|
-
violationType: "no_worker_spawned",
|
|
70482
|
-
message: `⚠️ Coordinator created decomposition without spawning workers. After hive_create_epic, use swarm_spawn_subtask for each task.`,
|
|
70483
|
-
payload
|
|
70484
|
-
};
|
|
70485
|
-
}
|
|
70486
|
-
if (toolName === "swarm_complete" || toolName === "hive_close") {
|
|
70487
|
-
const payload = { tool: toolName };
|
|
70488
|
-
captureCoordinatorEvent({
|
|
70489
|
-
session_id: sessionId,
|
|
70490
|
-
epic_id: epicId,
|
|
70491
|
-
timestamp: new Date().toISOString(),
|
|
70492
|
-
event_type: "VIOLATION",
|
|
70493
|
-
violation_type: "worker_completed_without_review",
|
|
70494
|
-
payload
|
|
70495
|
-
});
|
|
70496
|
-
return {
|
|
70497
|
-
isViolation: true,
|
|
70498
|
-
violationType: "worker_completed_without_review",
|
|
70499
|
-
message: `⚠️ Coordinator should not complete worker tasks directly. Coordinators should review worker output using swarm_review and swarm_review_feedback.`,
|
|
70500
|
-
payload
|
|
70501
|
-
};
|
|
70502
|
-
}
|
|
70503
|
-
return { isViolation: false };
|
|
70504
|
-
}
|
|
70505
|
-
var coordinatorContexts = new Map;
|
|
70506
|
-
var globalCoordinatorContext = {
|
|
70507
|
-
isCoordinator: false
|
|
70508
|
-
};
|
|
70509
|
-
function setCoordinatorContext(ctx) {
|
|
70510
|
-
const sessionId = ctx.sessionId;
|
|
70511
|
-
if (sessionId) {
|
|
70512
|
-
const existing = coordinatorContexts.get(sessionId) || { isCoordinator: false };
|
|
70513
|
-
coordinatorContexts.set(sessionId, {
|
|
70514
|
-
...existing,
|
|
70515
|
-
...ctx,
|
|
70516
|
-
activatedAt: ctx.isCoordinator ? Date.now() : existing.activatedAt
|
|
70517
|
-
});
|
|
70518
|
-
} else {
|
|
70519
|
-
globalCoordinatorContext = {
|
|
70520
|
-
...globalCoordinatorContext,
|
|
70521
|
-
...ctx,
|
|
70522
|
-
activatedAt: ctx.isCoordinator ? Date.now() : globalCoordinatorContext.activatedAt
|
|
70523
|
-
};
|
|
70524
|
-
}
|
|
70525
|
-
}
|
|
70526
|
-
function getCoordinatorContext(sessionId) {
|
|
70527
|
-
if (sessionId) {
|
|
70528
|
-
return { ...coordinatorContexts.get(sessionId) || { isCoordinator: false } };
|
|
70529
|
-
}
|
|
70530
|
-
return { ...globalCoordinatorContext };
|
|
70531
|
-
}
|
|
70532
|
-
function clearCoordinatorContext(sessionId) {
|
|
70533
|
-
if (sessionId) {
|
|
70534
|
-
coordinatorContexts.delete(sessionId);
|
|
70535
|
-
} else {
|
|
70536
|
-
globalCoordinatorContext = {
|
|
70537
|
-
isCoordinator: false
|
|
70538
|
-
};
|
|
70539
|
-
}
|
|
70540
|
-
}
|
|
70541
|
-
function isInCoordinatorContext(sessionId) {
|
|
70542
|
-
const ctx = sessionId ? coordinatorContexts.get(sessionId) : globalCoordinatorContext;
|
|
70543
|
-
if (!ctx || !ctx.isCoordinator) {
|
|
70544
|
-
return false;
|
|
70545
|
-
}
|
|
70546
|
-
const COORDINATOR_TIMEOUT_MS = 4 * 60 * 60 * 1000;
|
|
70547
|
-
if (ctx.activatedAt) {
|
|
70548
|
-
const elapsed = Date.now() - ctx.activatedAt;
|
|
70549
|
-
if (elapsed > COORDINATOR_TIMEOUT_MS) {
|
|
70550
|
-
if (sessionId) {
|
|
70551
|
-
coordinatorContexts.delete(sessionId);
|
|
70552
|
-
} else {
|
|
70553
|
-
globalCoordinatorContext = { isCoordinator: false };
|
|
70554
|
-
}
|
|
70555
|
-
return false;
|
|
70556
|
-
}
|
|
70557
|
-
}
|
|
70558
|
-
return true;
|
|
70559
|
-
}
|
|
70560
|
-
|
|
70561
70665
|
// src/coordinator-guard.ts
|
|
70562
70666
|
class CoordinatorGuardError extends Error {
|
|
70563
70667
|
violationType;
|
|
@@ -70809,6 +70913,7 @@ var logger = getLogger();
|
|
|
70809
70913
|
|
|
70810
70914
|
// src/compaction-hook.ts
|
|
70811
70915
|
init_eval_capture();
|
|
70916
|
+
init_skills();
|
|
70812
70917
|
var _logger;
|
|
70813
70918
|
function getLog() {
|
|
70814
70919
|
if (!_logger) {
|
|
@@ -70830,6 +70935,9 @@ Context was compacted but the swarm is still running. **YOU ARE THE COORDINATOR.
|
|
|
70830
70935
|
|
|
70831
70936
|
Your role is ORCHESTRATION, not implementation. The resume steps above (if present) tell you exactly what to do first.
|
|
70832
70937
|
|
|
70938
|
+
## \uD83D\uDD27 ALWAYS-ON GUIDANCE
|
|
70939
|
+
${getAlwaysOnGuidanceSkill({ role: "coordinator" })}
|
|
70940
|
+
|
|
70833
70941
|
---
|
|
70834
70942
|
|
|
70835
70943
|
## \uD83C\uDFAF WHAT GOOD LOOKS LIKE (Behavioral Examples)
|
|
@@ -70886,10 +70994,12 @@ You are the **COORDINATOR**. Your job is ORCHESTRATION, not implementation.
|
|
|
70886
70994
|
### What Coordinators Do:
|
|
70887
70995
|
- ✅ Spawn workers for implementation tasks
|
|
70888
70996
|
- ✅ Monitor worker progress via \`swarm_status\` and \`swarmmail_inbox\`
|
|
70997
|
+
- ✅ Use \`swarmmail_release_all\` to clear stale/orphaned reservations (coordinator override)
|
|
70889
70998
|
- ✅ Review completed work with \`swarm_review\`
|
|
70890
70999
|
- ✅ Unblock dependencies and resolve conflicts
|
|
70891
71000
|
- ✅ Close the loop when epics complete
|
|
70892
71001
|
|
|
71002
|
+
|
|
70893
71003
|
### What Coordinators NEVER Do:
|
|
70894
71004
|
- ❌ **NEVER** edit or write files directly
|
|
70895
71005
|
- ❌ **NEVER** run tests with \`bash\`
|