opencode-swarm-plugin 0.12.23 → 0.12.25
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 +98 -2
- package/examples/plugin-wrapper-template.ts +119 -0
- package/package.json +1 -1
package/bin/swarm.ts
CHANGED
|
@@ -623,6 +623,66 @@ async function doctor() {
|
|
|
623
623
|
const requiredMissing = required.filter((r) => !r.available);
|
|
624
624
|
const optionalMissing = optional.filter((r) => !r.available);
|
|
625
625
|
|
|
626
|
+
// Check skills
|
|
627
|
+
p.log.step("Skills:");
|
|
628
|
+
const configDir = join(homedir(), ".config", "opencode");
|
|
629
|
+
const globalSkillsPath = join(configDir, "skills");
|
|
630
|
+
const bundledSkillsPath = join(__dirname, "..", "global-skills");
|
|
631
|
+
|
|
632
|
+
// Global skills directory
|
|
633
|
+
if (existsSync(globalSkillsPath)) {
|
|
634
|
+
try {
|
|
635
|
+
const { readdirSync } = require("fs");
|
|
636
|
+
const skills = readdirSync(globalSkillsPath, { withFileTypes: true })
|
|
637
|
+
.filter((d: { isDirectory: () => boolean }) => d.isDirectory())
|
|
638
|
+
.map((d: { name: string }) => d.name);
|
|
639
|
+
if (skills.length > 0) {
|
|
640
|
+
p.log.success(`Global skills (${skills.length}): ${skills.join(", ")}`);
|
|
641
|
+
} else {
|
|
642
|
+
p.log.warn("Global skills directory exists but is empty");
|
|
643
|
+
}
|
|
644
|
+
} catch {
|
|
645
|
+
p.log.warn("Global skills directory: " + globalSkillsPath);
|
|
646
|
+
}
|
|
647
|
+
} else {
|
|
648
|
+
p.log.warn("No global skills directory (run 'swarm setup' to create)");
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Bundled skills
|
|
652
|
+
if (existsSync(bundledSkillsPath)) {
|
|
653
|
+
try {
|
|
654
|
+
const { readdirSync } = require("fs");
|
|
655
|
+
const bundled = readdirSync(bundledSkillsPath, { withFileTypes: true })
|
|
656
|
+
.filter((d: { isDirectory: () => boolean }) => d.isDirectory())
|
|
657
|
+
.map((d: { name: string }) => d.name);
|
|
658
|
+
p.log.success(
|
|
659
|
+
`Bundled skills (${bundled.length}): ${bundled.join(", ")}`,
|
|
660
|
+
);
|
|
661
|
+
} catch {
|
|
662
|
+
p.log.warn("Could not read bundled skills");
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Project skills (check current directory)
|
|
667
|
+
const projectSkillsDirs = [".opencode/skills", ".claude/skills", "skills"];
|
|
668
|
+
for (const dir of projectSkillsDirs) {
|
|
669
|
+
if (existsSync(dir)) {
|
|
670
|
+
try {
|
|
671
|
+
const { readdirSync } = require("fs");
|
|
672
|
+
const skills = readdirSync(dir, { withFileTypes: true })
|
|
673
|
+
.filter((d: { isDirectory: () => boolean }) => d.isDirectory())
|
|
674
|
+
.map((d: { name: string }) => d.name);
|
|
675
|
+
if (skills.length > 0) {
|
|
676
|
+
p.log.success(
|
|
677
|
+
`Project skills in ${dir}/ (${skills.length}): ${skills.join(", ")}`,
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
} catch {
|
|
681
|
+
// Ignore
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
626
686
|
if (requiredMissing.length > 0) {
|
|
627
687
|
p.outro(
|
|
628
688
|
"Missing " +
|
|
@@ -977,7 +1037,8 @@ async function setup() {
|
|
|
977
1037
|
p.log.step("Setting up OpenCode integration...");
|
|
978
1038
|
|
|
979
1039
|
// Create directories if needed
|
|
980
|
-
|
|
1040
|
+
const skillsDir = join(configDir, "skills");
|
|
1041
|
+
for (const dir of [pluginDir, commandDir, agentDir, skillsDir]) {
|
|
981
1042
|
if (!existsSync(dir)) {
|
|
982
1043
|
mkdirSync(dir, { recursive: true });
|
|
983
1044
|
}
|
|
@@ -995,8 +1056,24 @@ async function setup() {
|
|
|
995
1056
|
writeFileSync(workerAgentPath, getWorkerAgent(workerModel as string));
|
|
996
1057
|
p.log.success("Worker agent: " + workerAgentPath);
|
|
997
1058
|
|
|
1059
|
+
p.log.success("Skills directory: " + skillsDir);
|
|
1060
|
+
|
|
1061
|
+
// Show bundled skills info
|
|
1062
|
+
const bundledSkillsPath = join(__dirname, "..", "global-skills");
|
|
1063
|
+
if (existsSync(bundledSkillsPath)) {
|
|
1064
|
+
try {
|
|
1065
|
+
const { readdirSync } = require("fs");
|
|
1066
|
+
const bundled = readdirSync(bundledSkillsPath, { withFileTypes: true })
|
|
1067
|
+
.filter((d: { isDirectory: () => boolean }) => d.isDirectory())
|
|
1068
|
+
.map((d: { name: string }) => d.name);
|
|
1069
|
+
p.log.message(dim(" Bundled skills: " + bundled.join(", ")));
|
|
1070
|
+
} catch {
|
|
1071
|
+
// Ignore
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
998
1075
|
p.note(
|
|
999
|
-
'cd your-project\nbd init\nopencode\n/swarm "your task"',
|
|
1076
|
+
'cd your-project\nbd init\nopencode\n/swarm "your task"\n\nSkills: Use skills_list to see available skills',
|
|
1000
1077
|
"Next steps",
|
|
1001
1078
|
);
|
|
1002
1079
|
|
|
@@ -1078,6 +1155,25 @@ async function init() {
|
|
|
1078
1155
|
}
|
|
1079
1156
|
}
|
|
1080
1157
|
|
|
1158
|
+
// Offer to create project skills directory
|
|
1159
|
+
const createSkillsDir = await p.confirm({
|
|
1160
|
+
message: "Create project skills directory (.opencode/skills/)?",
|
|
1161
|
+
initialValue: false,
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
if (!p.isCancel(createSkillsDir) && createSkillsDir) {
|
|
1165
|
+
const skillsPath = ".opencode/skills";
|
|
1166
|
+
if (!existsSync(skillsPath)) {
|
|
1167
|
+
mkdirSync(skillsPath, { recursive: true });
|
|
1168
|
+
p.log.success("Created " + skillsPath + "/");
|
|
1169
|
+
p.log.message(
|
|
1170
|
+
dim(" Add SKILL.md files here for project-specific skills"),
|
|
1171
|
+
);
|
|
1172
|
+
} else {
|
|
1173
|
+
p.log.warn(skillsPath + "/ already exists");
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1081
1177
|
p.outro("Project initialized! Use '/swarm' in OpenCode to get started.");
|
|
1082
1178
|
} else {
|
|
1083
1179
|
s.stop("Failed to initialize beads");
|
|
@@ -666,6 +666,115 @@ const swarm_evaluation_prompt = tool({
|
|
|
666
666
|
execute: (args, ctx) => execTool("swarm_evaluation_prompt", args, ctx),
|
|
667
667
|
});
|
|
668
668
|
|
|
669
|
+
// =============================================================================
|
|
670
|
+
// Skills Tools
|
|
671
|
+
// =============================================================================
|
|
672
|
+
|
|
673
|
+
const skills_list = tool({
|
|
674
|
+
description:
|
|
675
|
+
"List all available skills from global, project, and bundled sources",
|
|
676
|
+
args: {
|
|
677
|
+
source: tool.schema
|
|
678
|
+
.enum(["all", "global", "project", "bundled"])
|
|
679
|
+
.optional()
|
|
680
|
+
.describe("Filter by source (default: all)"),
|
|
681
|
+
},
|
|
682
|
+
execute: (args, ctx) => execTool("skills_list", args, ctx),
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
const skills_read = tool({
|
|
686
|
+
description: "Read a skill's full content including SKILL.md and references",
|
|
687
|
+
args: {
|
|
688
|
+
name: tool.schema.string().describe("Skill name"),
|
|
689
|
+
},
|
|
690
|
+
execute: (args, ctx) => execTool("skills_read", args, ctx),
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
const skills_use = tool({
|
|
694
|
+
description:
|
|
695
|
+
"Get skill content formatted for injection into agent context. Use this when you need to apply a skill's knowledge to the current task.",
|
|
696
|
+
args: {
|
|
697
|
+
name: tool.schema.string().describe("Skill name"),
|
|
698
|
+
context: tool.schema
|
|
699
|
+
.string()
|
|
700
|
+
.optional()
|
|
701
|
+
.describe("Optional context about how the skill will be used"),
|
|
702
|
+
},
|
|
703
|
+
execute: (args, ctx) => execTool("skills_use", args, ctx),
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
const skills_create = tool({
|
|
707
|
+
description: "Create a new skill with SKILL.md template",
|
|
708
|
+
args: {
|
|
709
|
+
name: tool.schema.string().describe("Skill name (kebab-case)"),
|
|
710
|
+
description: tool.schema.string().describe("Brief skill description"),
|
|
711
|
+
scope: tool.schema
|
|
712
|
+
.enum(["global", "project"])
|
|
713
|
+
.optional()
|
|
714
|
+
.describe("Where to create (default: project)"),
|
|
715
|
+
tags: tool.schema
|
|
716
|
+
.array(tool.schema.string())
|
|
717
|
+
.optional()
|
|
718
|
+
.describe("Skill tags for discovery"),
|
|
719
|
+
},
|
|
720
|
+
execute: (args, ctx) => execTool("skills_create", args, ctx),
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
const skills_update = tool({
|
|
724
|
+
description: "Update an existing skill's SKILL.md content",
|
|
725
|
+
args: {
|
|
726
|
+
name: tool.schema.string().describe("Skill name"),
|
|
727
|
+
content: tool.schema.string().describe("New SKILL.md content"),
|
|
728
|
+
},
|
|
729
|
+
execute: (args, ctx) => execTool("skills_update", args, ctx),
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
const skills_delete = tool({
|
|
733
|
+
description: "Delete a skill (project skills only)",
|
|
734
|
+
args: {
|
|
735
|
+
name: tool.schema.string().describe("Skill name"),
|
|
736
|
+
},
|
|
737
|
+
execute: (args, ctx) => execTool("skills_delete", args, ctx),
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
const skills_init = tool({
|
|
741
|
+
description: "Initialize skills directory in current project",
|
|
742
|
+
args: {
|
|
743
|
+
path: tool.schema
|
|
744
|
+
.string()
|
|
745
|
+
.optional()
|
|
746
|
+
.describe("Custom path (default: .opencode/skills)"),
|
|
747
|
+
},
|
|
748
|
+
execute: (args, ctx) => execTool("skills_init", args, ctx),
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
const skills_add_script = tool({
|
|
752
|
+
description: "Add an executable script to a skill",
|
|
753
|
+
args: {
|
|
754
|
+
skill_name: tool.schema.string().describe("Skill name"),
|
|
755
|
+
script_name: tool.schema.string().describe("Script filename"),
|
|
756
|
+
content: tool.schema.string().describe("Script content"),
|
|
757
|
+
executable: tool.schema
|
|
758
|
+
.boolean()
|
|
759
|
+
.optional()
|
|
760
|
+
.describe("Make executable (default: true)"),
|
|
761
|
+
},
|
|
762
|
+
execute: (args, ctx) => execTool("skills_add_script", args, ctx),
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
const skills_execute = tool({
|
|
766
|
+
description: "Execute a skill's script",
|
|
767
|
+
args: {
|
|
768
|
+
skill_name: tool.schema.string().describe("Skill name"),
|
|
769
|
+
script_name: tool.schema.string().describe("Script to execute"),
|
|
770
|
+
args: tool.schema
|
|
771
|
+
.array(tool.schema.string())
|
|
772
|
+
.optional()
|
|
773
|
+
.describe("Script arguments"),
|
|
774
|
+
},
|
|
775
|
+
execute: (args, ctx) => execTool("skills_execute", args, ctx),
|
|
776
|
+
});
|
|
777
|
+
|
|
669
778
|
// =============================================================================
|
|
670
779
|
// Plugin Export
|
|
671
780
|
// =============================================================================
|
|
@@ -716,6 +825,16 @@ export const SwarmPlugin: Plugin = async (
|
|
|
716
825
|
swarm_spawn_subtask,
|
|
717
826
|
swarm_complete_subtask,
|
|
718
827
|
swarm_evaluation_prompt,
|
|
828
|
+
// Skills
|
|
829
|
+
skills_list,
|
|
830
|
+
skills_read,
|
|
831
|
+
skills_use,
|
|
832
|
+
skills_create,
|
|
833
|
+
skills_update,
|
|
834
|
+
skills_delete,
|
|
835
|
+
skills_init,
|
|
836
|
+
skills_add_script,
|
|
837
|
+
skills_execute,
|
|
719
838
|
},
|
|
720
839
|
};
|
|
721
840
|
};
|
package/package.json
CHANGED