opencode-swarm-plugin 0.57.6 → 0.59.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/bin/swarm.ts +350 -8
- package/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/claude-plugin/README.md +187 -0
- package/claude-plugin/agents/worker.md +1 -0
- package/claude-plugin/dist/index.js +467 -178
- package/claude-plugin/hooks/hooks.json +67 -0
- package/claude-plugin/skills/release/SKILL.md +101 -0
- package/claude-plugin/skills/swarm-cli/SKILL.md +82 -0
- package/dist/bin/swarm.js +1200 -328
- package/dist/decision-trace-integration.d.ts +18 -0
- package/dist/decision-trace-integration.d.ts.map +1 -1
- package/dist/hive.d.ts.map +1 -1
- package/dist/hive.js +34 -8
- package/dist/index.js +447 -181
- package/dist/marketplace/index.js +467 -178
- package/dist/plugin.js +447 -181
- package/dist/query-tools.d.ts +4 -4
- package/dist/query-tools.d.ts.map +1 -1
- package/dist/rate-limiter.d.ts +2 -0
- package/dist/rate-limiter.d.ts.map +1 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/storage.d.ts.map +1 -1
- 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-prompts.js +395 -124
- package/dist/tool-availability.d.ts.map +1 -1
- package/package.json +2 -2
package/bin/swarm.ts
CHANGED
|
@@ -63,11 +63,12 @@ import { tmpdir } from "os";
|
|
|
63
63
|
|
|
64
64
|
// Query & observability tools
|
|
65
65
|
import {
|
|
66
|
-
|
|
66
|
+
executeQueryCLI,
|
|
67
67
|
executePreset,
|
|
68
68
|
formatAsTable,
|
|
69
69
|
formatAsCSV,
|
|
70
70
|
formatAsJSON,
|
|
71
|
+
type QueryResult,
|
|
71
72
|
} from "../src/query-tools.js";
|
|
72
73
|
import {
|
|
73
74
|
getWorkerStatus,
|
|
@@ -2831,12 +2832,27 @@ async function claudeCommand() {
|
|
|
2831
2832
|
case "user-prompt":
|
|
2832
2833
|
await claudeUserPrompt();
|
|
2833
2834
|
break;
|
|
2835
|
+
case "pre-edit":
|
|
2836
|
+
await claudePreEdit();
|
|
2837
|
+
break;
|
|
2838
|
+
case "pre-complete":
|
|
2839
|
+
await claudePreComplete();
|
|
2840
|
+
break;
|
|
2841
|
+
case "post-complete":
|
|
2842
|
+
await claudePostComplete();
|
|
2843
|
+
break;
|
|
2834
2844
|
case "pre-compact":
|
|
2835
2845
|
await claudePreCompact();
|
|
2836
2846
|
break;
|
|
2837
2847
|
case "session-end":
|
|
2838
2848
|
await claudeSessionEnd();
|
|
2839
2849
|
break;
|
|
2850
|
+
case "track-tool":
|
|
2851
|
+
await claudeTrackTool(Bun.argv[4]); // tool name is 4th arg
|
|
2852
|
+
break;
|
|
2853
|
+
case "compliance":
|
|
2854
|
+
await claudeCompliance();
|
|
2855
|
+
break;
|
|
2840
2856
|
default:
|
|
2841
2857
|
console.error(`Unknown subcommand: ${subcommand}`);
|
|
2842
2858
|
showClaudeHelp();
|
|
@@ -2855,6 +2871,9 @@ Commands:
|
|
|
2855
2871
|
init Create project-local .claude/ config
|
|
2856
2872
|
session-start Hook: session start context (JSON output)
|
|
2857
2873
|
user-prompt Hook: prompt submit context (JSON output)
|
|
2874
|
+
pre-edit Hook: pre-Edit/Write reminder (hivemind check)
|
|
2875
|
+
pre-complete Hook: pre-swarm_complete checklist
|
|
2876
|
+
post-complete Hook: post-swarm_complete learnings reminder
|
|
2858
2877
|
pre-compact Hook: pre-compaction handler
|
|
2859
2878
|
session-end Hook: session cleanup
|
|
2860
2879
|
`);
|
|
@@ -3286,6 +3305,319 @@ async function claudeSessionEnd() {
|
|
|
3286
3305
|
}
|
|
3287
3306
|
}
|
|
3288
3307
|
|
|
3308
|
+
/**
|
|
3309
|
+
* Claude hook: pre-edit reminder for workers
|
|
3310
|
+
*
|
|
3311
|
+
* Runs BEFORE Edit/Write tool calls. Reminds worker to query hivemind first.
|
|
3312
|
+
* This is a gentle nudge, not a blocker.
|
|
3313
|
+
*/
|
|
3314
|
+
async function claudePreEdit() {
|
|
3315
|
+
try {
|
|
3316
|
+
const input = await readHookInput<ClaudeHookInput & { tool_name?: string; tool_input?: Record<string, unknown> }>();
|
|
3317
|
+
|
|
3318
|
+
// Only inject reminder if this looks like a worker context
|
|
3319
|
+
// (workers have initialized via swarmmail_init)
|
|
3320
|
+
const projectPath = resolveClaudeProjectPath(input);
|
|
3321
|
+
|
|
3322
|
+
// Check if we've seen hivemind_find in this session
|
|
3323
|
+
// For now, we always remind - tracking will come later
|
|
3324
|
+
const contextLines: string[] = [];
|
|
3325
|
+
|
|
3326
|
+
contextLines.push("⚠️ **Before this edit**: Did you run `hivemind_find` to check for existing solutions?");
|
|
3327
|
+
contextLines.push("If you haven't queried hivemind yet, consider doing so to avoid re-solving problems.");
|
|
3328
|
+
|
|
3329
|
+
writeClaudeHookOutput("PreToolUse:Edit", contextLines.join("\n"), { suppressOutput: true });
|
|
3330
|
+
} catch (error) {
|
|
3331
|
+
// Non-fatal - don't block the edit
|
|
3332
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
/**
|
|
3337
|
+
* Claude hook: pre-complete check for workers
|
|
3338
|
+
*
|
|
3339
|
+
* Runs BEFORE swarm_complete. Checks compliance with mandatory steps
|
|
3340
|
+
* and warns if any were skipped.
|
|
3341
|
+
*/
|
|
3342
|
+
async function claudePreComplete() {
|
|
3343
|
+
try {
|
|
3344
|
+
const input = await readHookInput<ClaudeHookInput & { tool_input?: Record<string, unknown> }>();
|
|
3345
|
+
const projectPath = resolveClaudeProjectPath(input);
|
|
3346
|
+
const contextLines: string[] = [];
|
|
3347
|
+
|
|
3348
|
+
// Check session tracking markers
|
|
3349
|
+
const trackingDir = join(projectPath, ".claude", ".worker-tracking");
|
|
3350
|
+
const sessionId = (input as { session_id?: string }).session_id || "";
|
|
3351
|
+
const sessionDir = join(trackingDir, sessionId.slice(0, 8));
|
|
3352
|
+
|
|
3353
|
+
const mandatoryTools = [
|
|
3354
|
+
{ name: "swarmmail_init", label: "Initialize coordination" },
|
|
3355
|
+
{ name: "hivemind_find", label: "Query past learnings" },
|
|
3356
|
+
];
|
|
3357
|
+
const recommendedTools = [
|
|
3358
|
+
{ name: "skills_use", label: "Load relevant skills" },
|
|
3359
|
+
{ name: "hivemind_store", label: "Store new learnings" },
|
|
3360
|
+
];
|
|
3361
|
+
|
|
3362
|
+
const missing: string[] = [];
|
|
3363
|
+
const skippedRecommended: string[] = [];
|
|
3364
|
+
|
|
3365
|
+
for (const tool of mandatoryTools) {
|
|
3366
|
+
const markerPath = join(sessionDir, `${tool.name}.marker`);
|
|
3367
|
+
if (!existsSync(markerPath)) {
|
|
3368
|
+
missing.push(tool.label);
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
for (const tool of recommendedTools) {
|
|
3373
|
+
const markerPath = join(sessionDir, `${tool.name}.marker`);
|
|
3374
|
+
if (!existsSync(markerPath)) {
|
|
3375
|
+
skippedRecommended.push(tool.label);
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3379
|
+
if (missing.length > 0) {
|
|
3380
|
+
contextLines.push("⚠️ **MANDATORY STEPS SKIPPED:**");
|
|
3381
|
+
for (const step of missing) {
|
|
3382
|
+
contextLines.push(` ❌ ${step}`);
|
|
3383
|
+
}
|
|
3384
|
+
contextLines.push("");
|
|
3385
|
+
contextLines.push("These steps are critical for swarm coordination.");
|
|
3386
|
+
contextLines.push("Consider running `hivemind_find` before future completions.");
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
if (skippedRecommended.length > 0 && missing.length === 0) {
|
|
3390
|
+
contextLines.push("📝 **Recommended steps not observed:**");
|
|
3391
|
+
for (const step of skippedRecommended) {
|
|
3392
|
+
contextLines.push(` - ${step}`);
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
if (missing.length === 0 && skippedRecommended.length === 0) {
|
|
3397
|
+
contextLines.push("✅ **All mandatory and recommended steps completed!**");
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
// Emit compliance event for analytics
|
|
3401
|
+
try {
|
|
3402
|
+
const swarmMail = await getSwarmMailLibSQL(projectPath);
|
|
3403
|
+
const db = await swarmMail.getDatabase(projectPath);
|
|
3404
|
+
|
|
3405
|
+
await db.execute({
|
|
3406
|
+
sql: `INSERT INTO swarm_events (event_type, project_path, agent_name, epic_id, bead_id, payload, created_at)
|
|
3407
|
+
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`,
|
|
3408
|
+
args: [
|
|
3409
|
+
"worker_compliance",
|
|
3410
|
+
projectPath,
|
|
3411
|
+
"worker",
|
|
3412
|
+
"",
|
|
3413
|
+
"",
|
|
3414
|
+
JSON.stringify({
|
|
3415
|
+
session_id: sessionId,
|
|
3416
|
+
mandatory_skipped: missing.length,
|
|
3417
|
+
recommended_skipped: skippedRecommended.length,
|
|
3418
|
+
score: Math.round(((mandatoryTools.length - missing.length) / mandatoryTools.length) * 100),
|
|
3419
|
+
}),
|
|
3420
|
+
],
|
|
3421
|
+
});
|
|
3422
|
+
} catch {
|
|
3423
|
+
// Non-fatal
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
if (contextLines.length > 0) {
|
|
3427
|
+
writeClaudeHookOutput("PreToolUse:swarm_complete", contextLines.join("\n"), { suppressOutput: missing.length === 0 });
|
|
3428
|
+
}
|
|
3429
|
+
} catch (error) {
|
|
3430
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3434
|
+
/**
|
|
3435
|
+
* Claude hook: post-complete reminder for workers
|
|
3436
|
+
*
|
|
3437
|
+
* Runs AFTER swarm_complete. Reminds to store learnings if any were discovered.
|
|
3438
|
+
*/
|
|
3439
|
+
async function claudePostComplete() {
|
|
3440
|
+
try {
|
|
3441
|
+
const input = await readHookInput<ClaudeHookInput & { tool_output?: string }>();
|
|
3442
|
+
const contextLines: string[] = [];
|
|
3443
|
+
|
|
3444
|
+
contextLines.push("✅ Task completed. If you discovered anything valuable during this work:");
|
|
3445
|
+
contextLines.push("```");
|
|
3446
|
+
contextLines.push("hivemind_store(");
|
|
3447
|
+
contextLines.push(' information="<what you learned, WHY it matters>",');
|
|
3448
|
+
contextLines.push(' tags="<domain, pattern-type>"');
|
|
3449
|
+
contextLines.push(")");
|
|
3450
|
+
contextLines.push("```");
|
|
3451
|
+
contextLines.push("**The swarm's collective intelligence grows when agents share learnings.**");
|
|
3452
|
+
|
|
3453
|
+
writeClaudeHookOutput("PostToolUse:swarm_complete", contextLines.join("\n"), { suppressOutput: true });
|
|
3454
|
+
} catch (error) {
|
|
3455
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
/**
|
|
3460
|
+
* Track when a mandatory tool is called.
|
|
3461
|
+
*
|
|
3462
|
+
* Creates a session-specific marker file that records tool usage.
|
|
3463
|
+
* These markers are checked at swarm_complete to calculate compliance.
|
|
3464
|
+
*/
|
|
3465
|
+
async function claudeTrackTool(toolName: string) {
|
|
3466
|
+
if (!toolName) return;
|
|
3467
|
+
|
|
3468
|
+
try {
|
|
3469
|
+
const input = await readHookInput<ClaudeHookInput>();
|
|
3470
|
+
const projectPath = resolveClaudeProjectPath(input);
|
|
3471
|
+
|
|
3472
|
+
// Get or create session tracking directory
|
|
3473
|
+
const trackingDir = join(projectPath, ".claude", ".worker-tracking");
|
|
3474
|
+
const sessionId = (input as { session_id?: string }).session_id || `unknown-${Date.now()}`;
|
|
3475
|
+
const sessionDir = join(trackingDir, sessionId.slice(0, 8)); // Use first 8 chars of session ID
|
|
3476
|
+
|
|
3477
|
+
if (!existsSync(sessionDir)) {
|
|
3478
|
+
mkdirSync(sessionDir, { recursive: true });
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3481
|
+
// Write marker file for this tool
|
|
3482
|
+
const markerPath = join(sessionDir, `${toolName}.marker`);
|
|
3483
|
+
writeFileSync(markerPath, new Date().toISOString());
|
|
3484
|
+
|
|
3485
|
+
// Also emit an event for long-term analytics (non-blocking)
|
|
3486
|
+
try {
|
|
3487
|
+
const swarmMail = await getSwarmMailLibSQL(projectPath);
|
|
3488
|
+
const db = await swarmMail.getDatabase(projectPath);
|
|
3489
|
+
|
|
3490
|
+
await db.execute({
|
|
3491
|
+
sql: `INSERT INTO swarm_events (event_type, project_path, agent_name, epic_id, bead_id, payload, created_at)
|
|
3492
|
+
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`,
|
|
3493
|
+
args: [
|
|
3494
|
+
"worker_tool_call",
|
|
3495
|
+
projectPath,
|
|
3496
|
+
"worker", // We don't have agent name in hook context
|
|
3497
|
+
"",
|
|
3498
|
+
"",
|
|
3499
|
+
JSON.stringify({ tool: toolName, session_id: sessionId }),
|
|
3500
|
+
],
|
|
3501
|
+
});
|
|
3502
|
+
} catch {
|
|
3503
|
+
// Non-fatal - tracking is best-effort
|
|
3504
|
+
}
|
|
3505
|
+
} catch (error) {
|
|
3506
|
+
// Silent failure - don't interrupt the tool call
|
|
3507
|
+
console.error(`[track-tool] ${error instanceof Error ? error.message : String(error)}`);
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
|
|
3511
|
+
/**
|
|
3512
|
+
* Check worker compliance - which mandatory tools were called.
|
|
3513
|
+
*
|
|
3514
|
+
* Returns compliance data based on session tracking markers.
|
|
3515
|
+
*/
|
|
3516
|
+
async function claudeCompliance() {
|
|
3517
|
+
try {
|
|
3518
|
+
const input = await readHookInput<ClaudeHookInput>();
|
|
3519
|
+
const projectPath = resolveClaudeProjectPath(input);
|
|
3520
|
+
|
|
3521
|
+
const trackingDir = join(projectPath, ".claude", ".worker-tracking");
|
|
3522
|
+
const sessionId = (input as { session_id?: string }).session_id || "";
|
|
3523
|
+
const sessionDir = join(trackingDir, sessionId.slice(0, 8));
|
|
3524
|
+
|
|
3525
|
+
const mandatoryTools = ["swarmmail_init", "hivemind_find", "skills_use"];
|
|
3526
|
+
const recommendedTools = ["hivemind_store"];
|
|
3527
|
+
|
|
3528
|
+
const compliance: Record<string, boolean> = {};
|
|
3529
|
+
|
|
3530
|
+
for (const tool of [...mandatoryTools, ...recommendedTools]) {
|
|
3531
|
+
const markerPath = join(sessionDir, `${tool}.marker`);
|
|
3532
|
+
compliance[tool] = existsSync(markerPath);
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
const mandatoryCount = mandatoryTools.filter(t => compliance[t]).length;
|
|
3536
|
+
const score = Math.round((mandatoryCount / mandatoryTools.length) * 100);
|
|
3537
|
+
|
|
3538
|
+
console.log(JSON.stringify({
|
|
3539
|
+
session_id: sessionId,
|
|
3540
|
+
compliance,
|
|
3541
|
+
mandatory_score: score,
|
|
3542
|
+
mandatory_met: mandatoryCount,
|
|
3543
|
+
mandatory_total: mandatoryTools.length,
|
|
3544
|
+
stored_learnings: compliance.hivemind_store,
|
|
3545
|
+
}));
|
|
3546
|
+
} catch (error) {
|
|
3547
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
|
|
3551
|
+
/**
|
|
3552
|
+
* Query worker compliance stats across all sessions.
|
|
3553
|
+
*/
|
|
3554
|
+
async function showWorkerCompliance() {
|
|
3555
|
+
const projectPath = process.cwd();
|
|
3556
|
+
|
|
3557
|
+
try {
|
|
3558
|
+
// Use shared executeQuery (handles DB connection internally)
|
|
3559
|
+
const toolUsageSql = `SELECT
|
|
3560
|
+
json_extract(payload, '$.tool') as tool,
|
|
3561
|
+
COUNT(*) as count,
|
|
3562
|
+
COUNT(DISTINCT json_extract(payload, '$.session_id')) as sessions
|
|
3563
|
+
FROM swarm_events
|
|
3564
|
+
WHERE event_type = 'worker_tool_call'
|
|
3565
|
+
AND created_at > datetime('now', '-7 days')
|
|
3566
|
+
GROUP BY tool
|
|
3567
|
+
ORDER BY count DESC`;
|
|
3568
|
+
|
|
3569
|
+
const toolResult = await executeQueryCLI(projectPath, toolUsageSql);
|
|
3570
|
+
const rows = toolResult.rows;
|
|
3571
|
+
|
|
3572
|
+
console.log(yellow(BANNER));
|
|
3573
|
+
console.log(cyan("\n📊 Worker Tool Usage (Last 7 Days)\n"));
|
|
3574
|
+
|
|
3575
|
+
if (rows.length === 0) {
|
|
3576
|
+
console.log(dim("No worker tool usage data found."));
|
|
3577
|
+
console.log(dim("Data is collected when workers run with the Claude Code plugin."));
|
|
3578
|
+
return;
|
|
3579
|
+
}
|
|
3580
|
+
|
|
3581
|
+
console.log(dim("Tool Calls Sessions"));
|
|
3582
|
+
console.log(dim("─".repeat(45)));
|
|
3583
|
+
|
|
3584
|
+
for (const row of rows) {
|
|
3585
|
+
const tool = String(row.tool).padEnd(22);
|
|
3586
|
+
const count = String(row.count).padStart(6);
|
|
3587
|
+
const sessions = String(row.sessions).padStart(8);
|
|
3588
|
+
console.log(`${tool} ${count} ${sessions}`);
|
|
3589
|
+
}
|
|
3590
|
+
|
|
3591
|
+
// Calculate compliance rate
|
|
3592
|
+
const hivemindFinds = rows.find(r => r.tool === "hivemind_find");
|
|
3593
|
+
const completesSql = `SELECT COUNT(*) as count FROM swarm_events
|
|
3594
|
+
WHERE event_type = 'worker_completed'
|
|
3595
|
+
AND created_at > datetime('now', '-7 days')`;
|
|
3596
|
+
const completesResult = await executeQueryCLI(projectPath, completesSql);
|
|
3597
|
+
|
|
3598
|
+
const completes = Number(completesResult.rows[0]?.count || 0);
|
|
3599
|
+
const finds = Number(hivemindFinds?.count || 0);
|
|
3600
|
+
|
|
3601
|
+
if (completes > 0) {
|
|
3602
|
+
const rate = Math.round((Math.min(finds, completes) / completes) * 100);
|
|
3603
|
+
console.log(dim("\n─".repeat(45)));
|
|
3604
|
+
console.log(`\n${green("Hivemind compliance rate:")} ${rate}% (${finds} queries / ${completes} completions)`);
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3607
|
+
} catch (error) {
|
|
3608
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
3609
|
+
if (msg.includes("no such table")) {
|
|
3610
|
+
console.log(yellow(BANNER));
|
|
3611
|
+
console.log(cyan("\n📊 Worker Tool Usage\n"));
|
|
3612
|
+
console.log(dim("No tracking data yet."));
|
|
3613
|
+
console.log(dim("Compliance tracking starts when workers run with the Claude Code plugin hooks."));
|
|
3614
|
+
console.log(dim("\nThe swarm_events table will be created on first tracked tool call."));
|
|
3615
|
+
} else {
|
|
3616
|
+
console.error("Error fetching compliance data:", msg);
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3289
3621
|
async function init() {
|
|
3290
3622
|
p.intro("swarm init v" + VERSION);
|
|
3291
3623
|
|
|
@@ -3633,16 +3965,16 @@ async function query() {
|
|
|
3633
3965
|
const projectPath = process.cwd();
|
|
3634
3966
|
|
|
3635
3967
|
try {
|
|
3636
|
-
let
|
|
3968
|
+
let result: QueryResult;
|
|
3637
3969
|
|
|
3638
3970
|
if (parsed.preset) {
|
|
3639
3971
|
// Execute preset query
|
|
3640
3972
|
p.log.step(`Executing preset: ${parsed.preset}`);
|
|
3641
|
-
|
|
3973
|
+
result = await executePreset(projectPath, parsed.preset);
|
|
3642
3974
|
} else if (parsed.query) {
|
|
3643
3975
|
// Execute custom SQL
|
|
3644
3976
|
p.log.step("Executing custom SQL");
|
|
3645
|
-
|
|
3977
|
+
result = await executeQueryCLI(projectPath, parsed.query);
|
|
3646
3978
|
} else {
|
|
3647
3979
|
p.log.error("No query specified. Use --sql or --preset");
|
|
3648
3980
|
p.outro("Aborted");
|
|
@@ -3653,14 +3985,14 @@ async function query() {
|
|
|
3653
3985
|
let output: string;
|
|
3654
3986
|
switch (parsed.format) {
|
|
3655
3987
|
case "csv":
|
|
3656
|
-
output = formatAsCSV(
|
|
3988
|
+
output = formatAsCSV(result);
|
|
3657
3989
|
break;
|
|
3658
3990
|
case "json":
|
|
3659
|
-
output = formatAsJSON(
|
|
3991
|
+
output = formatAsJSON(result);
|
|
3660
3992
|
break;
|
|
3661
3993
|
case "table":
|
|
3662
3994
|
default:
|
|
3663
|
-
output = formatAsTable(
|
|
3995
|
+
output = formatAsTable(result);
|
|
3664
3996
|
break;
|
|
3665
3997
|
}
|
|
3666
3998
|
|
|
@@ -3668,7 +4000,7 @@ async function query() {
|
|
|
3668
4000
|
console.log(output);
|
|
3669
4001
|
console.log();
|
|
3670
4002
|
|
|
3671
|
-
p.outro(`Found ${
|
|
4003
|
+
p.outro(`Found ${result.rowCount} result(s)`);
|
|
3672
4004
|
} catch (error) {
|
|
3673
4005
|
p.log.error("Query failed");
|
|
3674
4006
|
p.log.message(error instanceof Error ? error.message : String(error));
|
|
@@ -4032,6 +4364,7 @@ ${cyan("Commands:")}
|
|
|
4032
4364
|
swarm eval Eval-driven development commands
|
|
4033
4365
|
swarm query SQL analytics with presets (--sql, --preset, --format)
|
|
4034
4366
|
swarm dashboard Live terminal UI with worker status (--epic, --refresh)
|
|
4367
|
+
swarm compliance Worker tool usage compliance stats (hivemind, skills, etc)
|
|
4035
4368
|
swarm replay Event replay with timing (--speed, --type, --agent, --since, --until)
|
|
4036
4369
|
swarm export Export events (--format otlp/csv/json, --epic, --output)
|
|
4037
4370
|
swarm tree Visualize cell hierarchy as ASCII tree (--status, --epic, --json)
|
|
@@ -4118,6 +4451,7 @@ ${cyan("Observability Commands:")}
|
|
|
4118
4451
|
swarm export --format csv Export as CSV
|
|
4119
4452
|
swarm export --epic <id> Export specific epic only
|
|
4120
4453
|
swarm export --output <file> Write to file instead of stdout
|
|
4454
|
+
swarm compliance Show worker tool usage compliance stats
|
|
4121
4455
|
swarm tree Show all cells as tree
|
|
4122
4456
|
swarm tree --status open Show only open cells
|
|
4123
4457
|
swarm tree --epic <id> Show specific epic subtree
|
|
@@ -4142,6 +4476,11 @@ ${cyan("Claude Code:")}
|
|
|
4142
4476
|
swarm claude init Create project-local .claude config
|
|
4143
4477
|
swarm claude session-start Hook: session start context
|
|
4144
4478
|
swarm claude user-prompt Hook: prompt submit context
|
|
4479
|
+
swarm claude pre-edit Hook: pre-Edit/Write (hivemind reminder)
|
|
4480
|
+
swarm claude pre-complete Hook: pre-swarm_complete (compliance check)
|
|
4481
|
+
swarm claude post-complete Hook: post-swarm_complete (store learnings)
|
|
4482
|
+
swarm claude track-tool <name> Hook: track mandatory tool usage
|
|
4483
|
+
swarm claude compliance Hook: show session compliance data
|
|
4145
4484
|
swarm claude pre-compact Hook: pre-compaction handler
|
|
4146
4485
|
swarm claude session-end Hook: session cleanup
|
|
4147
4486
|
|
|
@@ -7449,6 +7788,9 @@ switch (command) {
|
|
|
7449
7788
|
case "dashboard":
|
|
7450
7789
|
await dashboard();
|
|
7451
7790
|
break;
|
|
7791
|
+
case "compliance":
|
|
7792
|
+
await showWorkerCompliance();
|
|
7793
|
+
break;
|
|
7452
7794
|
case "replay":
|
|
7453
7795
|
await replay();
|
|
7454
7796
|
break;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Swarm Plugin for Claude Code
|
|
2
|
+
|
|
3
|
+
Multi-agent task decomposition and coordination for Claude Code.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
The swarm CLI must be installed globally:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g opencode-swarm-plugin
|
|
11
|
+
# or
|
|
12
|
+
bun add -g opencode-swarm-plugin
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Verify installation:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
swarm version
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### Via Marketplace (Recommended)
|
|
24
|
+
|
|
25
|
+
Add the marketplace to your Claude Code settings, then install:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
claude /plugin install swarm
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Via Plugin Directory (Development)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
claude --plugin-dir /path/to/opencode-swarm-plugin/packages/opencode-swarm-plugin/claude-plugin
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
### Start a Swarm
|
|
40
|
+
|
|
41
|
+
Use the `/swarm:swarm` command to decompose a task into parallel subtasks:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
/swarm:swarm Add user authentication with OAuth support
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The coordinator will:
|
|
48
|
+
1. Query hivemind for past learnings
|
|
49
|
+
2. Clarify scope if needed
|
|
50
|
+
3. Decompose into parallel subtasks
|
|
51
|
+
4. Spawn workers for each subtask
|
|
52
|
+
5. Review completed work
|
|
53
|
+
6. Store learnings for future swarms
|
|
54
|
+
|
|
55
|
+
### Other Commands
|
|
56
|
+
|
|
57
|
+
| Command | Description |
|
|
58
|
+
|---------|-------------|
|
|
59
|
+
| `/swarm:swarm <task>` | Decompose and execute a multi-agent task |
|
|
60
|
+
| `/swarm:status` | Check worker progress, inbox, reservations |
|
|
61
|
+
| `/swarm:inbox` | Review inter-agent messages |
|
|
62
|
+
| `/swarm:hive` | Query and manage tasks (cells) |
|
|
63
|
+
| `/swarm:handoff` | End session, release locks, sync state |
|
|
64
|
+
|
|
65
|
+
### Skills (Auto-Invoked)
|
|
66
|
+
|
|
67
|
+
The plugin includes skills that Claude uses automatically:
|
|
68
|
+
|
|
69
|
+
- **swarm-coordination** - Multi-agent workflow guidance
|
|
70
|
+
- **always-on-guidance** - Model-specific defaults and best practices
|
|
71
|
+
|
|
72
|
+
## Available Tools
|
|
73
|
+
|
|
74
|
+
### Coordinator Tools
|
|
75
|
+
|
|
76
|
+
| Tool | Purpose |
|
|
77
|
+
|------|---------|
|
|
78
|
+
| `hivemind_find` | Query past learnings before decomposing |
|
|
79
|
+
| `hivemind_store` | Store discovered patterns |
|
|
80
|
+
| `swarm_decompose` | Break task into subtasks |
|
|
81
|
+
| `swarm_spawn_subtask` | Launch worker for subtask |
|
|
82
|
+
| `swarm_spawn_researcher` | Launch read-only researcher |
|
|
83
|
+
| `swarm_review` | Review worker output |
|
|
84
|
+
| `swarm_status` | Check epic progress |
|
|
85
|
+
| `hive_create_epic` | Create epic with subtasks |
|
|
86
|
+
| `hive_query` | Query task database |
|
|
87
|
+
| `swarmmail_*` | Inter-agent messaging |
|
|
88
|
+
|
|
89
|
+
### Worker Tools
|
|
90
|
+
|
|
91
|
+
| Tool | Purpose |
|
|
92
|
+
|------|---------|
|
|
93
|
+
| `hivemind_find` | Query learnings before starting |
|
|
94
|
+
| `hivemind_store` | Store what you learn |
|
|
95
|
+
| `swarm_progress` | Report progress (25/50/75%) |
|
|
96
|
+
| `swarm_checkpoint` | Save context before risky ops |
|
|
97
|
+
| `swarm_complete` | Signal task completion |
|
|
98
|
+
| `hive_update` | Update task status |
|
|
99
|
+
| `hive_close` | Close completed task |
|
|
100
|
+
| `swarmmail_reserve` | Reserve files exclusively |
|
|
101
|
+
| `swarmmail_send` | Message other agents |
|
|
102
|
+
|
|
103
|
+
## Architecture
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
Coordinator (Opus)
|
|
107
|
+
├── Queries hivemind for past learnings
|
|
108
|
+
├── Decomposes task into subtasks
|
|
109
|
+
├── Spawns workers (Sonnet)
|
|
110
|
+
├── Reviews each worker before spawning next
|
|
111
|
+
└── Stores coordination learnings
|
|
112
|
+
|
|
113
|
+
Workers (Sonnet)
|
|
114
|
+
├── Query hivemind before starting
|
|
115
|
+
├── Reserve files to prevent conflicts
|
|
116
|
+
├── Execute scoped subtask
|
|
117
|
+
├── Report progress at 25/50/75%
|
|
118
|
+
└── Store domain learnings
|
|
119
|
+
|
|
120
|
+
Researchers (Opus, read-only)
|
|
121
|
+
├── Fetch documentation
|
|
122
|
+
├── Analyze dependencies
|
|
123
|
+
└── Store findings in hivemind
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Troubleshooting
|
|
127
|
+
|
|
128
|
+
### MCP Server Not Connecting
|
|
129
|
+
|
|
130
|
+
Ensure swarm is installed globally and in your PATH:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
which swarm
|
|
134
|
+
swarm mcp-serve # Should start without errors
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Tools Not Available
|
|
138
|
+
|
|
139
|
+
Check that the MCP server is running:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
claude mcp list
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The `swarm-tools` server should show as connected.
|
|
146
|
+
|
|
147
|
+
### File Conflicts
|
|
148
|
+
|
|
149
|
+
If multiple agents are editing the same file, use file reservations:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
swarmmail_reserve(paths: ["src/**/*.ts"], exclusive: true)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Context Exhaustion
|
|
156
|
+
|
|
157
|
+
Use checkpoints before large operations:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
swarm_checkpoint(reason: "Before refactor")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Development
|
|
164
|
+
|
|
165
|
+
### Testing Locally
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# From the plugin directory
|
|
169
|
+
claude --plugin-dir .
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Building
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
cd packages/opencode-swarm-plugin
|
|
176
|
+
bun run build
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Running Tests
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
bun test
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT
|