opencode-swarm-plugin 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +9 -10
- package/.turbo/turbo-test.log +347 -341
- package/CHANGELOG.md +260 -0
- package/README.md +127 -182
- package/bin/swarm.test.ts +31 -0
- package/bin/swarm.ts +247 -12
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +530 -5
- package/dist/observability-tools.d.ts +116 -0
- package/dist/observability-tools.d.ts.map +1 -0
- package/dist/plugin.js +530 -5
- package/dist/skills.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +59 -0
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm.d.ts +17 -0
- package/dist/swarm.d.ts.map +1 -1
- package/examples/plugin-wrapper-template.ts +297 -8
- package/package.json +3 -2
- package/src/index.ts +25 -1
- package/src/observability-tools.test.ts +346 -0
- package/src/observability-tools.ts +594 -0
- package/src/skills.integration.test.ts +137 -1
- package/src/skills.test.ts +42 -1
- package/src/skills.ts +8 -4
- package/src/swarm-orchestrate.test.ts +123 -0
- package/src/swarm-orchestrate.ts +183 -0
- package/src/swarm-prompts.test.ts +389 -0
- package/src/swarm-prompts.ts +228 -0
- package/src/swarm-research.integration.test.ts +544 -0
- package/src/swarm-research.test.ts +698 -0
- package/src/swarm-research.ts +472 -0
- package/src/swarm.ts +6 -3
package/dist/index.js
CHANGED
|
@@ -26558,7 +26558,7 @@ var init_skills = __esm(() => {
|
|
|
26558
26558
|
"skills"
|
|
26559
26559
|
];
|
|
26560
26560
|
skills_list = tool({
|
|
26561
|
-
description: `List all available skills in the project.
|
|
26561
|
+
description: `[DEPRECATED] List all available skills in the project.
|
|
26562
26562
|
|
|
26563
26563
|
Skills are specialized instructions that help with specific domains or tasks.
|
|
26564
26564
|
Use this tool to discover what skills are available, then use skills_use to
|
|
@@ -26569,6 +26569,7 @@ Returns skill names, descriptions, and whether they have executable scripts.`,
|
|
|
26569
26569
|
tag: tool.schema.string().optional().describe("Optional tag to filter skills by")
|
|
26570
26570
|
},
|
|
26571
26571
|
async execute(args) {
|
|
26572
|
+
console.warn("[DEPRECATED] skills_list is deprecated. OpenCode now provides native skills support. This tool will be removed in a future version.");
|
|
26572
26573
|
const skills = await discoverSkills();
|
|
26573
26574
|
let refs = Array.from(skills.values());
|
|
26574
26575
|
if (args.tag) {
|
|
@@ -26591,7 +26592,7 @@ ${formatted}`;
|
|
|
26591
26592
|
}
|
|
26592
26593
|
});
|
|
26593
26594
|
skills_use = tool({
|
|
26594
|
-
description: `Activate a skill by loading its full instructions.
|
|
26595
|
+
description: `[DEPRECATED] Activate a skill by loading its full instructions.
|
|
26595
26596
|
|
|
26596
26597
|
After calling this tool, follow the skill's instructions for the current task.
|
|
26597
26598
|
Skills provide domain-specific guidance and best practices.
|
|
@@ -26602,6 +26603,7 @@ If the skill has scripts, you can run them with skills_execute.`,
|
|
|
26602
26603
|
include_scripts: tool.schema.boolean().optional().describe("Also list available scripts (default: true)")
|
|
26603
26604
|
},
|
|
26604
26605
|
async execute(args) {
|
|
26606
|
+
console.warn("[DEPRECATED] skills_use is deprecated. OpenCode now provides native skills support. This tool will be removed in a future version.");
|
|
26605
26607
|
const skill = await getSkill(args.name);
|
|
26606
26608
|
if (!skill) {
|
|
26607
26609
|
const available = await listSkills();
|
|
@@ -26634,7 +26636,7 @@ Run scripts with skills_execute tool.`;
|
|
|
26634
26636
|
}
|
|
26635
26637
|
});
|
|
26636
26638
|
skills_execute = tool({
|
|
26637
|
-
description: `Execute a script from a skill's scripts/ directory.
|
|
26639
|
+
description: `[DEPRECATED] Execute a script from a skill's scripts/ directory.
|
|
26638
26640
|
|
|
26639
26641
|
Some skills include helper scripts for common operations.
|
|
26640
26642
|
Use skills_use first to see available scripts, then execute them here.
|
|
@@ -26646,6 +26648,7 @@ Scripts run in the skill's directory with the project directory as an argument.`
|
|
|
26646
26648
|
args: tool.schema.array(tool.schema.string()).optional().describe("Additional arguments to pass to the script")
|
|
26647
26649
|
},
|
|
26648
26650
|
async execute(args, ctx) {
|
|
26651
|
+
console.warn("[DEPRECATED] skills_execute is deprecated. OpenCode now provides native skills support. This tool will be removed in a future version.");
|
|
26649
26652
|
const skill = await getSkill(args.skill);
|
|
26650
26653
|
if (!skill) {
|
|
26651
26654
|
return `Skill '${args.skill}' not found.`;
|
|
@@ -26691,7 +26694,7 @@ ${output}`;
|
|
|
26691
26694
|
}
|
|
26692
26695
|
});
|
|
26693
26696
|
skills_read = tool({
|
|
26694
|
-
description: `Read a resource file from a skill's directory.
|
|
26697
|
+
description: `[DEPRECATED] Read a resource file from a skill's directory.
|
|
26695
26698
|
|
|
26696
26699
|
Skills may include additional files like:
|
|
26697
26700
|
- examples.md - Example usage
|
|
@@ -26704,6 +26707,7 @@ Use this to access supplementary skill resources.`,
|
|
|
26704
26707
|
file: tool.schema.string().describe("Relative path to the file within the skill directory")
|
|
26705
26708
|
},
|
|
26706
26709
|
async execute(args) {
|
|
26710
|
+
console.warn("[DEPRECATED] skills_read is deprecated. OpenCode now provides native skills support. This tool will be removed in a future version.");
|
|
26707
26711
|
const skill = await getSkill(args.skill);
|
|
26708
26712
|
if (!skill) {
|
|
26709
26713
|
return `Skill '${args.skill}' not found.`;
|
|
@@ -35545,6 +35549,115 @@ Other cell operations:
|
|
|
35545
35549
|
**Memory is the swarm's collective intelligence. Query it. Feed it.**
|
|
35546
35550
|
|
|
35547
35551
|
Begin now.`;
|
|
35552
|
+
var RESEARCHER_PROMPT = `You are a swarm researcher gathering documentation for: **{research_id}**
|
|
35553
|
+
|
|
35554
|
+
## [IDENTITY]
|
|
35555
|
+
Agent: (assigned at spawn)
|
|
35556
|
+
Research Task: {research_id}
|
|
35557
|
+
Epic: {epic_id}
|
|
35558
|
+
|
|
35559
|
+
## [MISSION]
|
|
35560
|
+
Gather comprehensive documentation for the specified technologies to inform task decomposition.
|
|
35561
|
+
|
|
35562
|
+
**COORDINATOR PROVIDED THESE TECHNOLOGIES TO RESEARCH:**
|
|
35563
|
+
{tech_stack}
|
|
35564
|
+
|
|
35565
|
+
You do NOT discover what to research - the coordinator already decided that.
|
|
35566
|
+
You DO discover what TOOLS are available to fetch documentation.
|
|
35567
|
+
|
|
35568
|
+
## [OUTPUT MODE]
|
|
35569
|
+
{check_upgrades}
|
|
35570
|
+
|
|
35571
|
+
## [WORKFLOW]
|
|
35572
|
+
|
|
35573
|
+
### Step 1: Initialize (MANDATORY FIRST)
|
|
35574
|
+
\`\`\`
|
|
35575
|
+
swarmmail_init(project_path="{project_path}", task_description="{research_id}: Documentation research")
|
|
35576
|
+
\`\`\`
|
|
35577
|
+
|
|
35578
|
+
### Step 2: Discover Available Documentation Tools
|
|
35579
|
+
Check what's available for fetching docs:
|
|
35580
|
+
- **next-devtools**: \`nextjs_docs\` for Next.js documentation
|
|
35581
|
+
- **context7**: Library documentation lookup (\`use context7\` in prompts)
|
|
35582
|
+
- **fetch**: General web fetching for official docs sites
|
|
35583
|
+
- **pdf-brain**: Internal knowledge base search
|
|
35584
|
+
|
|
35585
|
+
**Don't assume** - check which tools exist in your environment.
|
|
35586
|
+
|
|
35587
|
+
### Step 3: Read Installed Versions
|
|
35588
|
+
For each technology in the tech stack:
|
|
35589
|
+
1. Check package.json (or equivalent) for installed version
|
|
35590
|
+
2. Record exact version numbers
|
|
35591
|
+
3. Note any version constraints (^, ~, etc.)
|
|
35592
|
+
|
|
35593
|
+
### Step 4: Fetch Documentation
|
|
35594
|
+
For EACH technology in the list:
|
|
35595
|
+
- Use the most appropriate tool (Next.js → nextjs_docs, libraries → context7, others → fetch)
|
|
35596
|
+
- Fetch documentation for the INSTALLED version (not latest, unless --check-upgrades)
|
|
35597
|
+
- Focus on: API changes, breaking changes, migration guides, best practices
|
|
35598
|
+
- Extract key patterns, gotchas, and compatibility notes
|
|
35599
|
+
|
|
35600
|
+
**If --check-upgrades mode:**
|
|
35601
|
+
- ALSO fetch docs for the LATEST version
|
|
35602
|
+
- Compare installed vs latest
|
|
35603
|
+
- Note breaking changes, new features, migration complexity
|
|
35604
|
+
|
|
35605
|
+
### Step 5: Store Detailed Findings
|
|
35606
|
+
For EACH technology, store in semantic-memory:
|
|
35607
|
+
\`\`\`
|
|
35608
|
+
semantic-memory_store(
|
|
35609
|
+
information="<technology-name> <version>: <key patterns, gotchas, API changes, compatibility notes>",
|
|
35610
|
+
tags="research, <tech-name>, documentation, {epic_id}"
|
|
35611
|
+
)
|
|
35612
|
+
\`\`\`
|
|
35613
|
+
|
|
35614
|
+
**Why store individually?** Future agents can search by technology name.
|
|
35615
|
+
|
|
35616
|
+
### Step 6: Broadcast Summary
|
|
35617
|
+
Send condensed findings to coordinator:
|
|
35618
|
+
\`\`\`
|
|
35619
|
+
swarmmail_send(
|
|
35620
|
+
to=["coordinator"],
|
|
35621
|
+
subject="Research Complete: {research_id}",
|
|
35622
|
+
body="<brief summary - see semantic-memory for details>",
|
|
35623
|
+
thread_id="{epic_id}"
|
|
35624
|
+
)
|
|
35625
|
+
\`\`\`
|
|
35626
|
+
|
|
35627
|
+
### Step 7: Return Structured Output
|
|
35628
|
+
Output JSON with:
|
|
35629
|
+
\`\`\`json
|
|
35630
|
+
{
|
|
35631
|
+
"technologies": [
|
|
35632
|
+
{
|
|
35633
|
+
"name": "string",
|
|
35634
|
+
"installed_version": "string",
|
|
35635
|
+
"latest_version": "string | null", // Only if --check-upgrades
|
|
35636
|
+
"key_patterns": ["string"],
|
|
35637
|
+
"gotchas": ["string"],
|
|
35638
|
+
"breaking_changes": ["string"], // Only if --check-upgrades
|
|
35639
|
+
"memory_id": "string" // ID of semantic-memory entry
|
|
35640
|
+
}
|
|
35641
|
+
],
|
|
35642
|
+
"summary": "string" // Condensed summary for shared_context
|
|
35643
|
+
}
|
|
35644
|
+
\`\`\`
|
|
35645
|
+
|
|
35646
|
+
## [CRITICAL REQUIREMENTS]
|
|
35647
|
+
|
|
35648
|
+
**NON-NEGOTIABLE:**
|
|
35649
|
+
1. Step 1 (swarmmail_init) MUST be first
|
|
35650
|
+
2. Research ONLY the technologies the coordinator specified
|
|
35651
|
+
3. Fetch docs for INSTALLED versions (unless --check-upgrades)
|
|
35652
|
+
4. Store detailed findings in semantic-memory (one per technology)
|
|
35653
|
+
5. Return condensed summary for coordinator (full details in memory)
|
|
35654
|
+
6. Use appropriate doc tools (nextjs_docs for Next.js, context7 for libraries, etc.)
|
|
35655
|
+
|
|
35656
|
+
**Output goes TWO places:**
|
|
35657
|
+
- **semantic-memory**: Detailed findings (searchable by future agents)
|
|
35658
|
+
- **Return JSON**: Condensed summary (for coordinator's shared_context)
|
|
35659
|
+
|
|
35660
|
+
Begin research now.`;
|
|
35548
35661
|
var COORDINATOR_POST_WORKER_CHECKLIST = `
|
|
35549
35662
|
## ⚠️ MANDATORY: Post-Worker Review (DO THIS IMMEDIATELY)
|
|
35550
35663
|
|
|
@@ -35633,6 +35746,12 @@ For each criterion, assess passed/failed and provide brief feedback:
|
|
|
35633
35746
|
|
|
35634
35747
|
If any criterion fails, the overall evaluation fails and retry_suggestion
|
|
35635
35748
|
should describe what needs to be fixed.`;
|
|
35749
|
+
function formatResearcherPrompt(params) {
|
|
35750
|
+
const techList = params.tech_stack.map((t) => `- ${t}`).join(`
|
|
35751
|
+
`);
|
|
35752
|
+
const upgradesMode = params.check_upgrades ? "**UPGRADE COMPARISON MODE**: Fetch docs for BOTH installed AND latest versions. Compare and note breaking changes." : "**DEFAULT MODE**: Fetch docs for INSTALLED versions only (from lockfiles).";
|
|
35753
|
+
return RESEARCHER_PROMPT.replace(/{research_id}/g, params.research_id).replace(/{epic_id}/g, params.epic_id).replace("{tech_stack}", techList).replace("{project_path}", params.project_path).replace("{check_upgrades}", upgradesMode);
|
|
35754
|
+
}
|
|
35636
35755
|
function formatSubtaskPromptV2(params) {
|
|
35637
35756
|
const fileList = params.files.length > 0 ? params.files.map((f) => `- \`${f}\``).join(`
|
|
35638
35757
|
`) : "(no specific files - use judgment)";
|
|
@@ -35782,6 +35901,48 @@ var swarm_spawn_subtask = tool({
|
|
|
35782
35901
|
}, null, 2);
|
|
35783
35902
|
}
|
|
35784
35903
|
});
|
|
35904
|
+
var swarm_spawn_researcher = tool({
|
|
35905
|
+
description: "Prepare a research task for spawning. Returns prompt for gathering technology documentation. Researcher fetches docs and stores findings in semantic-memory.",
|
|
35906
|
+
args: {
|
|
35907
|
+
research_id: tool.schema.string().describe("Unique ID for this research task"),
|
|
35908
|
+
epic_id: tool.schema.string().describe("Parent epic ID"),
|
|
35909
|
+
tech_stack: tool.schema.array(tool.schema.string()).describe("Explicit list of technologies to research (from coordinator)"),
|
|
35910
|
+
project_path: tool.schema.string().describe("Absolute project path for swarmmail_init"),
|
|
35911
|
+
check_upgrades: tool.schema.boolean().optional().describe("If true, compare installed vs latest versions (default: false)")
|
|
35912
|
+
},
|
|
35913
|
+
async execute(args) {
|
|
35914
|
+
const prompt = formatResearcherPrompt({
|
|
35915
|
+
research_id: args.research_id,
|
|
35916
|
+
epic_id: args.epic_id,
|
|
35917
|
+
tech_stack: args.tech_stack,
|
|
35918
|
+
project_path: args.project_path,
|
|
35919
|
+
check_upgrades: args.check_upgrades ?? false
|
|
35920
|
+
});
|
|
35921
|
+
return JSON.stringify({
|
|
35922
|
+
prompt,
|
|
35923
|
+
research_id: args.research_id,
|
|
35924
|
+
epic_id: args.epic_id,
|
|
35925
|
+
tech_stack: args.tech_stack,
|
|
35926
|
+
project_path: args.project_path,
|
|
35927
|
+
check_upgrades: args.check_upgrades ?? false,
|
|
35928
|
+
subagent_type: "swarm/researcher",
|
|
35929
|
+
expected_output: {
|
|
35930
|
+
technologies: [
|
|
35931
|
+
{
|
|
35932
|
+
name: "string",
|
|
35933
|
+
installed_version: "string",
|
|
35934
|
+
latest_version: "string | null",
|
|
35935
|
+
key_patterns: ["string"],
|
|
35936
|
+
gotchas: ["string"],
|
|
35937
|
+
breaking_changes: ["string"],
|
|
35938
|
+
memory_id: "string"
|
|
35939
|
+
}
|
|
35940
|
+
],
|
|
35941
|
+
summary: "string"
|
|
35942
|
+
}
|
|
35943
|
+
}, null, 2);
|
|
35944
|
+
}
|
|
35945
|
+
});
|
|
35785
35946
|
var swarm_evaluation_prompt = tool({
|
|
35786
35947
|
description: "Generate self-evaluation prompt for a completed subtask",
|
|
35787
35948
|
args: {
|
|
@@ -35893,6 +36054,7 @@ ${args.context}` : `## Additional Context
|
|
|
35893
36054
|
var promptTools = {
|
|
35894
36055
|
swarm_subtask_prompt,
|
|
35895
36056
|
swarm_spawn_subtask,
|
|
36057
|
+
swarm_spawn_researcher,
|
|
35896
36058
|
swarm_evaluation_prompt,
|
|
35897
36059
|
swarm_plan_prompt
|
|
35898
36060
|
};
|
|
@@ -50706,6 +50868,368 @@ var memoryTools = {
|
|
|
50706
50868
|
"semantic-memory_check": semantic_memory_check
|
|
50707
50869
|
};
|
|
50708
50870
|
|
|
50871
|
+
// src/observability-tools.ts
|
|
50872
|
+
init_dist();
|
|
50873
|
+
import {
|
|
50874
|
+
agentActivity,
|
|
50875
|
+
checkpointFrequency,
|
|
50876
|
+
failedDecompositions,
|
|
50877
|
+
getSwarmMailLibSQL as getSwarmMailLibSQL4,
|
|
50878
|
+
humanFeedback,
|
|
50879
|
+
lockContention,
|
|
50880
|
+
messageLatency,
|
|
50881
|
+
recoverySuccess,
|
|
50882
|
+
scopeViolations,
|
|
50883
|
+
strategySuccessRates,
|
|
50884
|
+
taskDuration
|
|
50885
|
+
} from "swarm-mail";
|
|
50886
|
+
function parseSince(since) {
|
|
50887
|
+
const now = Date.now();
|
|
50888
|
+
const match11 = since.match(/^(\d+)([dhm])$/);
|
|
50889
|
+
if (!match11) {
|
|
50890
|
+
throw new Error(`Invalid since format: ${since}. Use "7d", "24h", or "1h"`);
|
|
50891
|
+
}
|
|
50892
|
+
const [, value, unit] = match11;
|
|
50893
|
+
const num = Number.parseInt(value, 10);
|
|
50894
|
+
switch (unit) {
|
|
50895
|
+
case "d":
|
|
50896
|
+
return now - num * 24 * 60 * 60 * 1000;
|
|
50897
|
+
case "h":
|
|
50898
|
+
return now - num * 60 * 60 * 1000;
|
|
50899
|
+
case "m":
|
|
50900
|
+
return now - num * 60 * 1000;
|
|
50901
|
+
default:
|
|
50902
|
+
throw new Error(`Unknown unit: ${unit}`);
|
|
50903
|
+
}
|
|
50904
|
+
}
|
|
50905
|
+
async function executeQuery(swarmMail, query) {
|
|
50906
|
+
const db = await swarmMail.getDatabase();
|
|
50907
|
+
const result = await db.query(query.sql, Object.values(query.parameters || {}));
|
|
50908
|
+
return result.rows;
|
|
50909
|
+
}
|
|
50910
|
+
function formatSummary(queryType, results) {
|
|
50911
|
+
if (results.length === 0) {
|
|
50912
|
+
return `No ${queryType} data found.`;
|
|
50913
|
+
}
|
|
50914
|
+
const count = results.length;
|
|
50915
|
+
const preview = results.slice(0, 3);
|
|
50916
|
+
return `${queryType}: ${count} result(s). Top 3: ${JSON.stringify(preview, null, 2).slice(0, 400)}`;
|
|
50917
|
+
}
|
|
50918
|
+
function capResults(results) {
|
|
50919
|
+
return results.slice(0, 50);
|
|
50920
|
+
}
|
|
50921
|
+
var swarm_analytics = tool({
|
|
50922
|
+
description: "Query pre-built analytics for swarm coordination. Returns structured data about failed decompositions, strategy success rates, lock contention, agent activity, message latency, scope violations, task duration, checkpoint frequency, recovery success, and human feedback.",
|
|
50923
|
+
args: {
|
|
50924
|
+
query: tool.schema.enum([
|
|
50925
|
+
"failed-decompositions",
|
|
50926
|
+
"strategy-success-rates",
|
|
50927
|
+
"lock-contention",
|
|
50928
|
+
"agent-activity",
|
|
50929
|
+
"message-latency",
|
|
50930
|
+
"scope-violations",
|
|
50931
|
+
"task-duration",
|
|
50932
|
+
"checkpoint-frequency",
|
|
50933
|
+
"recovery-success",
|
|
50934
|
+
"human-feedback"
|
|
50935
|
+
]).describe("Type of analytics query to run"),
|
|
50936
|
+
since: tool.schema.string().optional().describe("Time filter: '7d', '24h', '1h' (optional)"),
|
|
50937
|
+
format: tool.schema.enum(["json", "summary"]).optional().describe("Output format: 'json' (default) or 'summary' (context-efficient)")
|
|
50938
|
+
},
|
|
50939
|
+
async execute(args2) {
|
|
50940
|
+
try {
|
|
50941
|
+
const projectPath = process.cwd();
|
|
50942
|
+
const db = await getSwarmMailLibSQL4(projectPath);
|
|
50943
|
+
const filters = {
|
|
50944
|
+
project_key: projectPath
|
|
50945
|
+
};
|
|
50946
|
+
if (args2.since) {
|
|
50947
|
+
filters.since = parseSince(args2.since);
|
|
50948
|
+
}
|
|
50949
|
+
let query;
|
|
50950
|
+
switch (args2.query) {
|
|
50951
|
+
case "failed-decompositions":
|
|
50952
|
+
query = failedDecompositions(filters);
|
|
50953
|
+
break;
|
|
50954
|
+
case "strategy-success-rates":
|
|
50955
|
+
query = strategySuccessRates(filters);
|
|
50956
|
+
break;
|
|
50957
|
+
case "lock-contention":
|
|
50958
|
+
query = lockContention(filters);
|
|
50959
|
+
break;
|
|
50960
|
+
case "agent-activity":
|
|
50961
|
+
query = agentActivity(filters);
|
|
50962
|
+
break;
|
|
50963
|
+
case "message-latency":
|
|
50964
|
+
query = messageLatency(filters);
|
|
50965
|
+
break;
|
|
50966
|
+
case "scope-violations":
|
|
50967
|
+
query = scopeViolations.buildQuery ? scopeViolations.buildQuery(filters) : scopeViolations;
|
|
50968
|
+
break;
|
|
50969
|
+
case "task-duration":
|
|
50970
|
+
query = taskDuration.buildQuery ? taskDuration.buildQuery(filters) : taskDuration;
|
|
50971
|
+
break;
|
|
50972
|
+
case "checkpoint-frequency":
|
|
50973
|
+
query = checkpointFrequency.buildQuery ? checkpointFrequency.buildQuery(filters) : checkpointFrequency;
|
|
50974
|
+
break;
|
|
50975
|
+
case "recovery-success":
|
|
50976
|
+
query = recoverySuccess.buildQuery ? recoverySuccess.buildQuery(filters) : recoverySuccess;
|
|
50977
|
+
break;
|
|
50978
|
+
case "human-feedback":
|
|
50979
|
+
query = humanFeedback.buildQuery ? humanFeedback.buildQuery(filters) : humanFeedback;
|
|
50980
|
+
break;
|
|
50981
|
+
default:
|
|
50982
|
+
return JSON.stringify({
|
|
50983
|
+
error: `Unknown query type: ${args2.query}`
|
|
50984
|
+
});
|
|
50985
|
+
}
|
|
50986
|
+
const results = await executeQuery(db, query);
|
|
50987
|
+
if (args2.format === "summary") {
|
|
50988
|
+
return formatSummary(args2.query, results);
|
|
50989
|
+
}
|
|
50990
|
+
return JSON.stringify({
|
|
50991
|
+
query: args2.query,
|
|
50992
|
+
filters,
|
|
50993
|
+
count: results.length,
|
|
50994
|
+
results
|
|
50995
|
+
}, null, 2);
|
|
50996
|
+
} catch (error45) {
|
|
50997
|
+
return JSON.stringify({
|
|
50998
|
+
error: error45 instanceof Error ? error45.message : String(error45)
|
|
50999
|
+
});
|
|
51000
|
+
}
|
|
51001
|
+
}
|
|
51002
|
+
});
|
|
51003
|
+
var swarm_query = tool({
|
|
51004
|
+
description: "Execute raw SQL queries against the swarm event store. Context-safe: results capped at 50 rows. Useful for custom analytics and debugging.",
|
|
51005
|
+
args: {
|
|
51006
|
+
sql: tool.schema.string().describe("SQL query to execute (SELECT only for safety)"),
|
|
51007
|
+
format: tool.schema.enum(["json", "table"]).optional().describe("Output format: 'json' (default) or 'table' (visual)")
|
|
51008
|
+
},
|
|
51009
|
+
async execute(args2) {
|
|
51010
|
+
try {
|
|
51011
|
+
const projectPath = process.cwd();
|
|
51012
|
+
const swarmMail = await getSwarmMailLibSQL4(projectPath);
|
|
51013
|
+
const db = await swarmMail.getDatabase();
|
|
51014
|
+
if (!args2.sql.trim().toLowerCase().startsWith("select")) {
|
|
51015
|
+
return JSON.stringify({
|
|
51016
|
+
error: "Only SELECT queries are allowed for safety"
|
|
51017
|
+
});
|
|
51018
|
+
}
|
|
51019
|
+
const result = await db.query(args2.sql, []);
|
|
51020
|
+
const rows = result.rows;
|
|
51021
|
+
const cappedRows = capResults(rows);
|
|
51022
|
+
if (args2.format === "table") {
|
|
51023
|
+
if (cappedRows.length === 0) {
|
|
51024
|
+
return "No results";
|
|
51025
|
+
}
|
|
51026
|
+
const headers = Object.keys(cappedRows[0]);
|
|
51027
|
+
const headerRow = headers.join(" | ");
|
|
51028
|
+
const separator = headers.map(() => "---").join(" | ");
|
|
51029
|
+
const dataRows = cappedRows.map((row) => headers.map((h) => row[h]).join(" | "));
|
|
51030
|
+
return [headerRow, separator, ...dataRows].join(`
|
|
51031
|
+
`);
|
|
51032
|
+
}
|
|
51033
|
+
return JSON.stringify({
|
|
51034
|
+
count: cappedRows.length,
|
|
51035
|
+
total: rows.length,
|
|
51036
|
+
capped: rows.length > 50,
|
|
51037
|
+
results: cappedRows
|
|
51038
|
+
}, null, 2);
|
|
51039
|
+
} catch (error45) {
|
|
51040
|
+
return JSON.stringify({
|
|
51041
|
+
error: error45 instanceof Error ? error45.message : String(error45)
|
|
51042
|
+
});
|
|
51043
|
+
}
|
|
51044
|
+
}
|
|
51045
|
+
});
|
|
51046
|
+
var swarm_diagnose = tool({
|
|
51047
|
+
description: "Auto-diagnose issues for a specific epic or task. Returns structured diagnosis with blockers, conflicts, slow tasks, errors, and timeline.",
|
|
51048
|
+
args: {
|
|
51049
|
+
epic_id: tool.schema.string().optional().describe("Epic ID to diagnose"),
|
|
51050
|
+
bead_id: tool.schema.string().optional().describe("Task ID to diagnose"),
|
|
51051
|
+
include: tool.schema.array(tool.schema.enum([
|
|
51052
|
+
"blockers",
|
|
51053
|
+
"conflicts",
|
|
51054
|
+
"slow_tasks",
|
|
51055
|
+
"errors",
|
|
51056
|
+
"timeline"
|
|
51057
|
+
])).optional().describe("What to include in diagnosis (default: all)")
|
|
51058
|
+
},
|
|
51059
|
+
async execute(args2) {
|
|
51060
|
+
try {
|
|
51061
|
+
const projectPath = process.cwd();
|
|
51062
|
+
const swarmMail = await getSwarmMailLibSQL4(projectPath);
|
|
51063
|
+
const db = await swarmMail.getDatabase();
|
|
51064
|
+
const diagnosis = [];
|
|
51065
|
+
const include = args2.include || [
|
|
51066
|
+
"blockers",
|
|
51067
|
+
"conflicts",
|
|
51068
|
+
"slow_tasks",
|
|
51069
|
+
"errors",
|
|
51070
|
+
"timeline"
|
|
51071
|
+
];
|
|
51072
|
+
if (include.includes("blockers")) {
|
|
51073
|
+
const blockerQuery = `
|
|
51074
|
+
SELECT json_extract(data, '$.agent_name') as agent,
|
|
51075
|
+
json_extract(data, '$.bead_id') as bead_id,
|
|
51076
|
+
timestamp
|
|
51077
|
+
FROM events
|
|
51078
|
+
WHERE type = 'task_blocked'
|
|
51079
|
+
${args2.epic_id ? "AND json_extract(data, '$.epic_id') = ?" : ""}
|
|
51080
|
+
${args2.bead_id ? "AND json_extract(data, '$.bead_id') = ?" : ""}
|
|
51081
|
+
ORDER BY timestamp DESC
|
|
51082
|
+
LIMIT 10
|
|
51083
|
+
`;
|
|
51084
|
+
const params = [];
|
|
51085
|
+
if (args2.epic_id)
|
|
51086
|
+
params.push(args2.epic_id);
|
|
51087
|
+
if (args2.bead_id)
|
|
51088
|
+
params.push(args2.bead_id);
|
|
51089
|
+
const blockers = await db.query(blockerQuery, params);
|
|
51090
|
+
if (blockers.rows.length > 0) {
|
|
51091
|
+
diagnosis.push({
|
|
51092
|
+
type: "blockers",
|
|
51093
|
+
message: `Found ${blockers.rows.length} blocked task(s)`,
|
|
51094
|
+
severity: "high"
|
|
51095
|
+
});
|
|
51096
|
+
}
|
|
51097
|
+
}
|
|
51098
|
+
if (include.includes("errors")) {
|
|
51099
|
+
const errorQuery = `
|
|
51100
|
+
SELECT type, json_extract(data, '$.error_count') as error_count
|
|
51101
|
+
FROM events
|
|
51102
|
+
WHERE type = 'subtask_outcome'
|
|
51103
|
+
AND json_extract(data, '$.success') = 'false'
|
|
51104
|
+
${args2.epic_id ? "AND json_extract(data, '$.epic_id') = ?" : ""}
|
|
51105
|
+
${args2.bead_id ? "AND json_extract(data, '$.bead_id') = ?" : ""}
|
|
51106
|
+
LIMIT 10
|
|
51107
|
+
`;
|
|
51108
|
+
const params = [];
|
|
51109
|
+
if (args2.epic_id)
|
|
51110
|
+
params.push(args2.epic_id);
|
|
51111
|
+
if (args2.bead_id)
|
|
51112
|
+
params.push(args2.bead_id);
|
|
51113
|
+
const errors3 = await db.query(errorQuery, params);
|
|
51114
|
+
if (errors3.rows.length > 0) {
|
|
51115
|
+
diagnosis.push({
|
|
51116
|
+
type: "errors",
|
|
51117
|
+
message: `Found ${errors3.rows.length} failed task(s)`,
|
|
51118
|
+
severity: "high"
|
|
51119
|
+
});
|
|
51120
|
+
}
|
|
51121
|
+
}
|
|
51122
|
+
let timeline = [];
|
|
51123
|
+
if (include.includes("timeline")) {
|
|
51124
|
+
const timelineQuery = `
|
|
51125
|
+
SELECT timestamp, type, json_extract(data, '$.agent_name') as agent
|
|
51126
|
+
FROM events
|
|
51127
|
+
${args2.epic_id ? "WHERE json_extract(data, '$.epic_id') = ?" : ""}
|
|
51128
|
+
${args2.bead_id ? (args2.epic_id ? "AND" : "WHERE") + " json_extract(data, '$.bead_id') = ?" : ""}
|
|
51129
|
+
ORDER BY timestamp DESC
|
|
51130
|
+
LIMIT 20
|
|
51131
|
+
`;
|
|
51132
|
+
const params = [];
|
|
51133
|
+
if (args2.epic_id)
|
|
51134
|
+
params.push(args2.epic_id);
|
|
51135
|
+
if (args2.bead_id)
|
|
51136
|
+
params.push(args2.bead_id);
|
|
51137
|
+
const events = await db.query(timelineQuery, params);
|
|
51138
|
+
timeline = events.rows;
|
|
51139
|
+
}
|
|
51140
|
+
return JSON.stringify({
|
|
51141
|
+
epic_id: args2.epic_id,
|
|
51142
|
+
bead_id: args2.bead_id,
|
|
51143
|
+
diagnosis,
|
|
51144
|
+
timeline: include.includes("timeline") ? timeline : undefined
|
|
51145
|
+
}, null, 2);
|
|
51146
|
+
} catch (error45) {
|
|
51147
|
+
return JSON.stringify({
|
|
51148
|
+
error: error45 instanceof Error ? error45.message : String(error45)
|
|
51149
|
+
});
|
|
51150
|
+
}
|
|
51151
|
+
}
|
|
51152
|
+
});
|
|
51153
|
+
var swarm_insights = tool({
|
|
51154
|
+
description: "Generate learning insights from swarm coordination metrics. Analyzes success rates, duration, conflicts, and retries to provide actionable recommendations.",
|
|
51155
|
+
args: {
|
|
51156
|
+
scope: tool.schema.enum(["epic", "project", "recent"]).describe("Scope of analysis: 'epic', 'project', or 'recent'"),
|
|
51157
|
+
epic_id: tool.schema.string().optional().describe("Epic ID (required if scope='epic')"),
|
|
51158
|
+
metrics: tool.schema.array(tool.schema.enum([
|
|
51159
|
+
"success_rate",
|
|
51160
|
+
"avg_duration",
|
|
51161
|
+
"conflict_rate",
|
|
51162
|
+
"retry_rate"
|
|
51163
|
+
])).describe("Metrics to analyze")
|
|
51164
|
+
},
|
|
51165
|
+
async execute(args2) {
|
|
51166
|
+
try {
|
|
51167
|
+
if (args2.scope === "epic" && !args2.epic_id) {
|
|
51168
|
+
return JSON.stringify({
|
|
51169
|
+
error: "epic_id is required when scope='epic'"
|
|
51170
|
+
});
|
|
51171
|
+
}
|
|
51172
|
+
const projectPath = process.cwd();
|
|
51173
|
+
const swarmMail = await getSwarmMailLibSQL4(projectPath);
|
|
51174
|
+
const db = await swarmMail.getDatabase();
|
|
51175
|
+
const insights = [];
|
|
51176
|
+
if (args2.metrics.includes("success_rate")) {
|
|
51177
|
+
const query = `
|
|
51178
|
+
SELECT
|
|
51179
|
+
SUM(CASE WHEN json_extract(data, '$.success') = 'true' THEN 1 ELSE 0 END) as successes,
|
|
51180
|
+
COUNT(*) as total
|
|
51181
|
+
FROM events
|
|
51182
|
+
WHERE type = 'subtask_outcome'
|
|
51183
|
+
${args2.epic_id ? "AND json_extract(data, '$.epic_id') = ?" : ""}
|
|
51184
|
+
`;
|
|
51185
|
+
const result = await db.query(query, args2.epic_id ? [args2.epic_id] : []);
|
|
51186
|
+
const row = result.rows[0];
|
|
51187
|
+
if (row && row.total > 0) {
|
|
51188
|
+
const rate = row.successes / row.total * 100;
|
|
51189
|
+
insights.push({
|
|
51190
|
+
metric: "success_rate",
|
|
51191
|
+
value: `${rate.toFixed(1)}%`,
|
|
51192
|
+
insight: rate < 50 ? "Low success rate - review decomposition strategy" : rate < 80 ? "Moderate success rate - monitor for patterns" : "Good success rate - maintain current approach"
|
|
51193
|
+
});
|
|
51194
|
+
}
|
|
51195
|
+
}
|
|
51196
|
+
if (args2.metrics.includes("avg_duration")) {
|
|
51197
|
+
const query = `
|
|
51198
|
+
SELECT AVG(CAST(json_extract(data, '$.duration_ms') AS REAL)) as avg_duration
|
|
51199
|
+
FROM events
|
|
51200
|
+
WHERE type = 'subtask_outcome'
|
|
51201
|
+
${args2.epic_id ? "AND json_extract(data, '$.epic_id') = ?" : ""}
|
|
51202
|
+
`;
|
|
51203
|
+
const result = await db.query(query, args2.epic_id ? [args2.epic_id] : []);
|
|
51204
|
+
const row = result.rows[0];
|
|
51205
|
+
if (row?.avg_duration) {
|
|
51206
|
+
const avgMinutes = (row.avg_duration / 60000).toFixed(1);
|
|
51207
|
+
insights.push({
|
|
51208
|
+
metric: "avg_duration",
|
|
51209
|
+
value: `${avgMinutes} min`,
|
|
51210
|
+
insight: row.avg_duration > 600000 ? "Tasks taking >10min - consider smaller decomposition" : "Task duration is reasonable"
|
|
51211
|
+
});
|
|
51212
|
+
}
|
|
51213
|
+
}
|
|
51214
|
+
return JSON.stringify({
|
|
51215
|
+
scope: args2.scope,
|
|
51216
|
+
epic_id: args2.epic_id,
|
|
51217
|
+
insights
|
|
51218
|
+
}, null, 2);
|
|
51219
|
+
} catch (error45) {
|
|
51220
|
+
return JSON.stringify({
|
|
51221
|
+
error: error45 instanceof Error ? error45.message : String(error45)
|
|
51222
|
+
});
|
|
51223
|
+
}
|
|
51224
|
+
}
|
|
51225
|
+
});
|
|
51226
|
+
var observabilityTools = {
|
|
51227
|
+
swarm_analytics,
|
|
51228
|
+
swarm_query,
|
|
51229
|
+
swarm_diagnose,
|
|
51230
|
+
swarm_insights
|
|
51231
|
+
};
|
|
51232
|
+
|
|
50709
51233
|
// src/output-guardrails.ts
|
|
50710
51234
|
var DEFAULT_GUARDRAIL_CONFIG = {
|
|
50711
51235
|
defaultMaxChars: 32000,
|
|
@@ -51647,7 +52171,8 @@ var SwarmPlugin = async (input) => {
|
|
|
51647
52171
|
...repoCrawlTools,
|
|
51648
52172
|
...skillsTools,
|
|
51649
52173
|
...mandateTools,
|
|
51650
|
-
...memoryTools
|
|
52174
|
+
...memoryTools,
|
|
52175
|
+
...observabilityTools
|
|
51651
52176
|
},
|
|
51652
52177
|
event: async ({ event }) => {
|
|
51653
52178
|
if (event.type === "session.idle") {
|