opcrew 0.1.5 → 0.1.6
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/dist/opencode-plugin.js +134 -96
- package/package.json +1 -1
package/dist/opencode-plugin.js
CHANGED
|
@@ -12720,26 +12720,109 @@ The logbook tracks:
|
|
|
12720
12720
|
}
|
|
12721
12721
|
});
|
|
12722
12722
|
|
|
12723
|
+
// src/skills.ts
|
|
12724
|
+
import { readdir, readFile } from "fs/promises";
|
|
12725
|
+
import path from "path";
|
|
12726
|
+
import { fileURLToPath } from "url";
|
|
12727
|
+
var __dirname2 = path.dirname(fileURLToPath(import.meta.url));
|
|
12728
|
+
async function loadSkills() {
|
|
12729
|
+
const skillsDir = path.join(__dirname2, "skills");
|
|
12730
|
+
try {
|
|
12731
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
12732
|
+
const skills = [];
|
|
12733
|
+
for (const entry of entries) {
|
|
12734
|
+
if (!entry.isDirectory())
|
|
12735
|
+
continue;
|
|
12736
|
+
const skillPath = path.join(skillsDir, entry.name);
|
|
12737
|
+
const skillMdPath = path.join(skillPath, "SKILL.md");
|
|
12738
|
+
try {
|
|
12739
|
+
const content = await readFile(skillMdPath, "utf-8");
|
|
12740
|
+
const { name, description } = parseSkillFrontmatter(content);
|
|
12741
|
+
skills.push({
|
|
12742
|
+
name: name || entry.name,
|
|
12743
|
+
description: description || "",
|
|
12744
|
+
sourcePath: skillPath
|
|
12745
|
+
});
|
|
12746
|
+
} catch {
|
|
12747
|
+
console.warn(`Warning: No SKILL.md found in ${skillPath}`);
|
|
12748
|
+
}
|
|
12749
|
+
}
|
|
12750
|
+
return skills;
|
|
12751
|
+
} catch {
|
|
12752
|
+
return [];
|
|
12753
|
+
}
|
|
12754
|
+
}
|
|
12755
|
+
function parseSkillFrontmatter(content) {
|
|
12756
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
12757
|
+
if (!frontmatterMatch) {
|
|
12758
|
+
return {};
|
|
12759
|
+
}
|
|
12760
|
+
const frontmatter = frontmatterMatch[1];
|
|
12761
|
+
const result = {};
|
|
12762
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
12763
|
+
if (nameMatch) {
|
|
12764
|
+
result.name = nameMatch[1].trim();
|
|
12765
|
+
}
|
|
12766
|
+
const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
|
|
12767
|
+
if (descMatch) {
|
|
12768
|
+
result.description = descMatch[1].trim();
|
|
12769
|
+
}
|
|
12770
|
+
return result;
|
|
12771
|
+
}
|
|
12772
|
+
async function getSkillContent(skillName) {
|
|
12773
|
+
const skillMdPath = path.join(__dirname2, "skills", skillName, "SKILL.md");
|
|
12774
|
+
return readFile(skillMdPath, "utf-8");
|
|
12775
|
+
}
|
|
12776
|
+
|
|
12777
|
+
// src/tools/skill.ts
|
|
12778
|
+
var skillTool = tool({
|
|
12779
|
+
description: `Load and manage agent skills dynamically.
|
|
12780
|
+
|
|
12781
|
+
Actions:
|
|
12782
|
+
- list: List all available skills with names and descriptions
|
|
12783
|
+
- load: Load a specific skill's full content (SKILL.md)
|
|
12784
|
+
|
|
12785
|
+
Skills provide specialized instructions and workflows for specific tasks.
|
|
12786
|
+
Use this tool when you recognize that a task matches one of the available skills.`,
|
|
12787
|
+
args: {
|
|
12788
|
+
action: tool.schema.enum(["list", "load"]).describe("Action to perform"),
|
|
12789
|
+
name: tool.schema.string().optional().describe("Skill name (required for 'load' action)")
|
|
12790
|
+
},
|
|
12791
|
+
async execute(args) {
|
|
12792
|
+
switch (args.action) {
|
|
12793
|
+
case "list": {
|
|
12794
|
+
const skills = await loadSkills();
|
|
12795
|
+
if (skills.length === 0) {
|
|
12796
|
+
return "No skills available.";
|
|
12797
|
+
}
|
|
12798
|
+
const formattedList = skills.map((skill) => `- **${skill.name}**: ${skill.description}`).join(`
|
|
12799
|
+
`);
|
|
12800
|
+
return `Available skills:
|
|
12801
|
+
|
|
12802
|
+
${formattedList}`;
|
|
12803
|
+
}
|
|
12804
|
+
case "load": {
|
|
12805
|
+
if (!args.name) {
|
|
12806
|
+
return "Error: name is required for 'load' action";
|
|
12807
|
+
}
|
|
12808
|
+
try {
|
|
12809
|
+
const content = await getSkillContent(args.name);
|
|
12810
|
+
return content;
|
|
12811
|
+
} catch (error45) {
|
|
12812
|
+
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
12813
|
+
return `Error: Failed to load skill '${args.name}': ${message}`;
|
|
12814
|
+
}
|
|
12815
|
+
}
|
|
12816
|
+
default:
|
|
12817
|
+
return `Error: Unknown action: ${args.action}`;
|
|
12818
|
+
}
|
|
12819
|
+
}
|
|
12820
|
+
});
|
|
12821
|
+
|
|
12723
12822
|
// src/opencode-plugin.ts
|
|
12724
|
-
var DEFAULT_CANONICAL_TOOLS = [
|
|
12725
|
-
"read",
|
|
12726
|
-
"write",
|
|
12727
|
-
"edit",
|
|
12728
|
-
"glob",
|
|
12729
|
-
"grep",
|
|
12730
|
-
"execute",
|
|
12731
|
-
"websearch",
|
|
12732
|
-
"webfetch",
|
|
12733
|
-
"delegate",
|
|
12734
|
-
"todo",
|
|
12735
|
-
"test",
|
|
12736
|
-
"logbook",
|
|
12737
|
-
"skill"
|
|
12738
|
-
];
|
|
12739
|
-
var ALL_AVAILABLE_TOOLS = DEFAULT_CANONICAL_TOOLS;
|
|
12740
12823
|
var permissionByRole = {
|
|
12741
12824
|
Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
|
|
12742
|
-
Planner: { edit: "deny", bash: "
|
|
12825
|
+
Planner: { edit: "deny", bash: "allow", webfetch: "allow" },
|
|
12743
12826
|
Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
|
|
12744
12827
|
Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
|
|
12745
12828
|
Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
|
|
@@ -12747,102 +12830,57 @@ var permissionByRole = {
|
|
|
12747
12830
|
function toAgentId(agent) {
|
|
12748
12831
|
return agent.config.name.toLowerCase().replace(/\s+/g, "-");
|
|
12749
12832
|
}
|
|
12750
|
-
function buildPrompt(agent
|
|
12833
|
+
function buildPrompt(agent) {
|
|
12751
12834
|
const instructionsList = agent.config.instructions.map((instruction) => `- ${instruction}`).join(`
|
|
12752
12835
|
`);
|
|
12753
|
-
const allowedTools = agent.getAllowedTools();
|
|
12754
|
-
const forbiddenTools = agent.getForbiddenTools(availableTools);
|
|
12755
|
-
const toolBoundariesSection = `## TOOL BOUNDARIES
|
|
12756
|
-
- **Allowed:** ${allowedTools.length > 0 ? allowedTools.join(", ") : "(none)"}
|
|
12757
|
-
- **Forbidden:** ${forbiddenTools.length > 0 ? forbiddenTools.join(", ") : "(none)"}`;
|
|
12758
12836
|
return `# ${agent.config.name}
|
|
12759
|
-
|
|
12760
|
-
${toolBoundariesSection}
|
|
12761
|
-
|
|
12762
12837
|
${instructionsList}
|
|
12763
12838
|
|
|
12764
12839
|
## Shared Context
|
|
12765
12840
|
Refer to \`.opcrew/logbook.json\` for the current voyage status.
|
|
12766
12841
|
`;
|
|
12767
12842
|
}
|
|
12768
|
-
function toOpenCodeAgentConfig(agent
|
|
12769
|
-
const allowedTools = agent.getAllowedTools();
|
|
12770
|
-
const validTools = allowedTools.every((tool3) => availableTools.includes(tool3));
|
|
12771
|
-
if (!validTools) {
|
|
12772
|
-
const invalidTools = allowedTools.filter((tool3) => !availableTools.includes(tool3));
|
|
12773
|
-
throw new Error(`Agent '${agent.config.name}' has invalid tools in allowlist: [${invalidTools.join(", ")}]. ` + `Valid tools: [${availableTools.join(", ")}]`);
|
|
12774
|
-
}
|
|
12843
|
+
function toOpenCodeAgentConfig(agent) {
|
|
12775
12844
|
return {
|
|
12776
12845
|
description: agent.config.name,
|
|
12777
12846
|
mode: agent.config.mode,
|
|
12778
|
-
prompt: buildPrompt(agent
|
|
12847
|
+
prompt: buildPrompt(agent),
|
|
12779
12848
|
permission: permissionByRole[agent.config.role]
|
|
12780
12849
|
};
|
|
12781
12850
|
}
|
|
12782
|
-
|
|
12783
|
-
|
|
12784
|
-
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
}
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12807
|
-
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
const forbiddenTools = agent.getForbiddenTools(availableTools);
|
|
12812
|
-
await client.app.log({
|
|
12813
|
-
body: {
|
|
12814
|
-
service: "opcrew",
|
|
12815
|
-
level: "info",
|
|
12816
|
-
message: `Registering agent '${agent.config.name}' with tool boundaries`,
|
|
12817
|
-
extra: {
|
|
12818
|
-
agentId,
|
|
12819
|
-
allowedTools,
|
|
12820
|
-
forbiddenTools
|
|
12821
|
-
}
|
|
12822
|
-
}
|
|
12823
|
-
});
|
|
12824
|
-
agents[agentId] = toOpenCodeAgentConfig(agent, availableTools);
|
|
12825
|
-
}
|
|
12826
|
-
config2.agent = agents;
|
|
12827
|
-
await client.app.log({
|
|
12828
|
-
body: {
|
|
12829
|
-
service: "opcrew",
|
|
12830
|
-
level: "info",
|
|
12831
|
-
message: "Crew agents registered",
|
|
12832
|
-
extra: { agents: Object.keys(agents) }
|
|
12833
|
-
}
|
|
12834
|
-
});
|
|
12835
|
-
},
|
|
12836
|
-
tool: mergedTools
|
|
12837
|
-
};
|
|
12851
|
+
var OpCrewPlugin = async ({ client }) => {
|
|
12852
|
+
await client.app.log({
|
|
12853
|
+
body: {
|
|
12854
|
+
service: "opcrew",
|
|
12855
|
+
level: "info",
|
|
12856
|
+
message: "OpenCode plugin initialized"
|
|
12857
|
+
}
|
|
12858
|
+
});
|
|
12859
|
+
return {
|
|
12860
|
+
config: async (config2) => {
|
|
12861
|
+
const agents = config2.agent ?? {};
|
|
12862
|
+
agents["build"] = { ...agents["build"], disable: true };
|
|
12863
|
+
for (const agent of crew) {
|
|
12864
|
+
agents[toAgentId(agent)] = toOpenCodeAgentConfig(agent);
|
|
12865
|
+
}
|
|
12866
|
+
config2.agents = agents;
|
|
12867
|
+
await client.app.log({
|
|
12868
|
+
body: {
|
|
12869
|
+
service: "opcrew",
|
|
12870
|
+
level: "info",
|
|
12871
|
+
message: "Crew agents registered",
|
|
12872
|
+
extra: { agents: Object.keys(agents) }
|
|
12873
|
+
}
|
|
12874
|
+
});
|
|
12875
|
+
},
|
|
12876
|
+
tool: {
|
|
12877
|
+
edit_logbook: editLogbookTool,
|
|
12878
|
+
skill: skillTool
|
|
12879
|
+
}
|
|
12838
12880
|
};
|
|
12839
|
-
}
|
|
12840
|
-
var OpCrewPlugin = createOpCrewPlugin();
|
|
12881
|
+
};
|
|
12841
12882
|
var opencode_plugin_default = OpCrewPlugin;
|
|
12842
12883
|
export {
|
|
12843
12884
|
opencode_plugin_default as default,
|
|
12844
|
-
|
|
12845
|
-
OpCrewPlugin,
|
|
12846
|
-
DEFAULT_CANONICAL_TOOLS,
|
|
12847
|
-
ALL_AVAILABLE_TOOLS
|
|
12885
|
+
OpCrewPlugin
|
|
12848
12886
|
};
|