opcrew 0.1.3 → 0.1.5
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/cli.js +185 -47
- package/dist/opencode-plugin.js +172 -68
- package/dist/skills/skills/write-adr/SKILL.md +114 -0
- package/dist/skills/skills/write-adr/templates/adr-template.md +13 -0
- package/dist/skills/write-adr/SKILL.md +114 -0
- package/dist/skills/write-adr/templates/adr-template.md +13 -0
- package/docs/knowledge/decisions/20260329-002-strict-agent-boundaries.md +51 -0
- package/docs/knowledge/decisions/20260329-003-plugin-factory-pattern.md +83 -0
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -5,23 +5,23 @@
|
|
|
5
5
|
import process from "process";
|
|
6
6
|
|
|
7
7
|
// src/cli/install.ts
|
|
8
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
9
|
-
import
|
|
8
|
+
import { mkdir, writeFile, cp, rm } from "fs/promises";
|
|
9
|
+
import path2 from "path";
|
|
10
10
|
// src/core/tools/translations.ts
|
|
11
11
|
var CLAUDE_TOOLS = {
|
|
12
|
-
read: "
|
|
13
|
-
write: "
|
|
14
|
-
edit: "
|
|
15
|
-
glob: "
|
|
16
|
-
grep: "
|
|
17
|
-
execute: "
|
|
18
|
-
websearch: "
|
|
19
|
-
webfetch: "
|
|
20
|
-
delegate: "
|
|
21
|
-
todo: "
|
|
22
|
-
test: "
|
|
23
|
-
logbook: "
|
|
24
|
-
skill: "
|
|
12
|
+
read: "Read",
|
|
13
|
+
write: "Write",
|
|
14
|
+
edit: "Edit",
|
|
15
|
+
glob: "Glob",
|
|
16
|
+
grep: "Grep",
|
|
17
|
+
execute: "Bash",
|
|
18
|
+
websearch: "WebSearch",
|
|
19
|
+
webfetch: "WebFetch",
|
|
20
|
+
delegate: "Agent",
|
|
21
|
+
todo: "TodoWrite",
|
|
22
|
+
test: "Bash",
|
|
23
|
+
logbook: "",
|
|
24
|
+
skill: "Skill"
|
|
25
25
|
};
|
|
26
26
|
var OPENCODE_TOOLS = {
|
|
27
27
|
read: "read",
|
|
@@ -61,7 +61,7 @@ function translateTools(canonicalTools, platform) {
|
|
|
61
61
|
};
|
|
62
62
|
const translationMap = maps[platform];
|
|
63
63
|
const translated = canonicalTools.map((tool) => translationMap[tool]);
|
|
64
|
-
return [...new Set(translated)];
|
|
64
|
+
return [...new Set(translated)].filter((tool) => tool !== "");
|
|
65
65
|
}
|
|
66
66
|
// src/core/Agent.ts
|
|
67
67
|
class OpCrewAgent {
|
|
@@ -69,11 +69,28 @@ class OpCrewAgent {
|
|
|
69
69
|
constructor(config) {
|
|
70
70
|
this.config = config;
|
|
71
71
|
}
|
|
72
|
+
getAllowedTools() {
|
|
73
|
+
return this.config.allowedTools ?? this.config.tools ?? [];
|
|
74
|
+
}
|
|
75
|
+
hasTool(tool) {
|
|
76
|
+
return this.getAllowedTools().includes(tool);
|
|
77
|
+
}
|
|
78
|
+
validateToolUsage(tool) {
|
|
79
|
+
if (!this.hasTool(tool)) {
|
|
80
|
+
const allowedList = this.getAllowedTools().join(", ") || "(none)";
|
|
81
|
+
throw new Error(`Tool '${tool}' is not allowed for agent '${this.config.name}'. ` + `Allowed tools: [${allowedList}]`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
getForbiddenTools(allAvailableTools) {
|
|
85
|
+
const allowedSet = new Set(this.getAllowedTools());
|
|
86
|
+
return allAvailableTools.filter((tool) => !allowedSet.has(tool));
|
|
87
|
+
}
|
|
72
88
|
compileToMarkdown() {
|
|
73
|
-
const translatedTools = translateTools(this.
|
|
89
|
+
const translatedTools = translateTools(this.getAllowedTools(), "claude");
|
|
90
|
+
const lowerName = this.config.name.toLowerCase();
|
|
74
91
|
const frontmatter = `---
|
|
75
|
-
name: ${
|
|
76
|
-
|
|
92
|
+
name: ${lowerName}
|
|
93
|
+
description: ${this.config.description}
|
|
77
94
|
tools: [${translatedTools.join(", ")}]
|
|
78
95
|
---`;
|
|
79
96
|
return `${frontmatter}
|
|
@@ -84,7 +101,7 @@ ${this.buildMarkdownBody()}`;
|
|
|
84
101
|
Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
|
|
85
102
|
Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
|
|
86
103
|
Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
|
|
87
|
-
Reviewer: { edit: "deny", bash: "
|
|
104
|
+
Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
|
|
88
105
|
Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
|
|
89
106
|
};
|
|
90
107
|
const permission = permissionByRole[this.config.role];
|
|
@@ -100,7 +117,7 @@ permission:
|
|
|
100
117
|
${this.buildMarkdownBody()}`;
|
|
101
118
|
}
|
|
102
119
|
compileToCodexMarkdown() {
|
|
103
|
-
const translatedTools = translateTools(this.
|
|
120
|
+
const translatedTools = translateTools(this.getAllowedTools(), "codex");
|
|
104
121
|
const frontmatter = `---
|
|
105
122
|
name: ${this.config.name}
|
|
106
123
|
role: ${this.config.role}
|
|
@@ -125,102 +142,126 @@ Refer to \`.opcrew/logbook.json\` for the current voyage status.
|
|
|
125
142
|
// src/crew/Captain.ts
|
|
126
143
|
var Captain = new OpCrewAgent({
|
|
127
144
|
name: "Captain",
|
|
145
|
+
description: "Orchestrator agent that coordinates work delegation and verification. Use for complex multi-step tasks requiring coordination between specialists.",
|
|
128
146
|
role: "Orchestrator",
|
|
129
147
|
mode: "primary",
|
|
130
148
|
instructions: [
|
|
149
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
|
|
131
150
|
"You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
|
|
132
|
-
"
|
|
151
|
+
"Workstream Fan-out: divide missions into independent Workstreams (e.g., Logic, Testing, Documentation) to enable parallel specialists.",
|
|
133
152
|
"Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
|
|
134
|
-
"
|
|
153
|
+
"Collision Prevention: ensure no two Boatswains are assigned the same file or symbol in parallel. Launch workstreams only if they are logically decoupled.",
|
|
135
154
|
"Escalate blockers immediately and re-sequence work to unblock the critical path.",
|
|
136
155
|
"Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
|
|
137
156
|
"Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
|
|
138
157
|
"Delegation mandate: ALWAYS delegate work to specialists using the task tool. Never perform file edits, code changes, or direct execution yourself.",
|
|
139
158
|
"Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
|
|
140
|
-
"Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
|
|
141
159
|
"Verification gate: delegate verification to Quartermaster; ensure diagnostics/tests run and evidence is logged before marking complete.",
|
|
160
|
+
"Conflict Resolution: if specialists disagree on implementation, make the final call based on project documentation.",
|
|
142
161
|
"Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
|
|
143
162
|
"Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
|
|
144
163
|
],
|
|
145
|
-
tools: ["read", "logbook", "delegate"]
|
|
164
|
+
tools: ["read", "logbook", "delegate", "skill"]
|
|
146
165
|
});
|
|
147
166
|
|
|
148
167
|
// src/crew/Navigator.ts
|
|
149
168
|
var Navigator = new OpCrewAgent({
|
|
150
169
|
name: "Navigator",
|
|
170
|
+
description: "Planning specialist that decomposes work into atomic tasks with clear inputs, outputs, and ownership. Use when you need to chart an implementation path or create a structured plan.",
|
|
151
171
|
role: "Planner",
|
|
152
172
|
mode: "subagent",
|
|
153
173
|
instructions: [
|
|
174
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, websearch, logbook, todo, skill. Using any other tool is a violation.",
|
|
154
175
|
"Chart the implementation path based on the Captain's intent and constraints.",
|
|
155
176
|
"Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
|
|
177
|
+
"Workstream Decomposition: break the plan into atomic, parallel tracks. Define File Ownership (e.g., Boatswain-A owns src/, Boatswain-B owns tests/).",
|
|
178
|
+
"Survey the Stack: identify the project's native build system (BUILD_CMD), test runner (TEST_CMD), and style guide immediately.",
|
|
179
|
+
"Documentation Maintenance: plan for updates to docs/project-map.md and docs/glossary.md; assign these to a specific workstream.",
|
|
180
|
+
"Dependency Graphing: flag Blocking Tasks where one workstream depends on the output of another; sequence these to avoid idle agents.",
|
|
181
|
+
"Execution Manifest: for every task, specify Target File, Affected Symbols, Invariants, and the exact Verification Command.",
|
|
156
182
|
"Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
|
|
157
183
|
"Maintain a current project map (key files, modules, and ownership boundaries).",
|
|
158
184
|
"Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
|
|
159
185
|
"Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
|
|
160
186
|
"Create and manage todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
|
|
161
187
|
"Mandate parallel discovery for unknowns: launch multiple explore/librarian threads and consolidate findings.",
|
|
188
|
+
"Discovery Primitives: use language-agnostic tools (grep, find, tree) to map dependencies before proposing edits.",
|
|
162
189
|
"Delegate external research to Scout when you need information from outside the project: libraries, APIs, best practices, or documentation.",
|
|
163
190
|
"Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
|
|
164
191
|
"Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
|
|
165
192
|
],
|
|
166
|
-
tools: ["read", "websearch", "logbook", "todo"]
|
|
193
|
+
tools: ["read", "websearch", "logbook", "todo", "skill"]
|
|
167
194
|
});
|
|
168
195
|
|
|
169
196
|
// src/crew/Boatswain.ts
|
|
170
197
|
var Boatswain = new OpCrewAgent({
|
|
171
198
|
name: "Boatswain",
|
|
199
|
+
description: "Execution specialist that implements approved plans with precise edits. Use when you need to make code changes, run tests, or execute implementation steps.",
|
|
172
200
|
role: "Executor",
|
|
173
201
|
mode: "subagent",
|
|
174
202
|
instructions: [
|
|
175
|
-
"
|
|
203
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, edit, write, test, todo, glob, grep, skill. Using any other tool is a violation.",
|
|
204
|
+
"Scope Guarding: ONLY touch files assigned to your Workstream ID. If you must edit a file owned by another agent, escalate to Captain for a plan revision.",
|
|
176
205
|
"Follow existing patterns, naming, and formatting; avoid speculative changes.",
|
|
206
|
+
"Context Anchoring: before editing, read the surrounding code to match indentation, casing, and comment styles. Maintain the project's local laws.",
|
|
207
|
+
"Parallel Execution: implement the Navigator's Manifest exactly. Update code, tests, and documentation (docs/project-map.md or docs/glossary.md) as assigned.",
|
|
177
208
|
"Keep diffs lean and standards-compliant; update only what the plan calls for.",
|
|
178
|
-
"
|
|
179
|
-
"Log completion status, assumptions, and blockers immediately for the Captain.",
|
|
209
|
+
"Atomic Verification: run the assigned TEST_CMD for your scope. Record stdout/stderr logs in the logbook immediately.",
|
|
180
210
|
"Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
|
|
181
|
-
"
|
|
211
|
+
"LSP/Compiler Check: use native diagnostics to ensure no syntax errors were introduced in touched files.",
|
|
182
212
|
"Update docs/knowledge when execution changes assumptions, definitions, or operational steps.",
|
|
183
|
-
"Update todo task status immediately upon completion of each task."
|
|
213
|
+
"Update todo task status immediately upon completion of each task.",
|
|
214
|
+
"Status Discipline: update your specific task status in logbook.json as you work; do not wait for other workstreams to finish."
|
|
184
215
|
],
|
|
185
|
-
tools: ["read", "edit", "test", "todo"]
|
|
216
|
+
tools: ["read", "edit", "write", "test", "todo", "glob", "grep", "skill"]
|
|
186
217
|
});
|
|
187
218
|
|
|
188
219
|
// src/crew/Quartermaster.ts
|
|
189
220
|
var Quartermaster = new OpCrewAgent({
|
|
190
221
|
name: "Quartermaster",
|
|
222
|
+
description: "Quality assurance specialist that reviews diffs, verifies tests pass, and ensures conventions are followed. Use proactively after code changes to verify quality.",
|
|
191
223
|
role: "Reviewer",
|
|
192
224
|
mode: "subagent",
|
|
193
225
|
instructions: [
|
|
226
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, grep, execute, write, skill. Using any other tool is a violation.",
|
|
194
227
|
"Inspect each diff for regression risks, scope drift, and missing context.",
|
|
195
|
-
"
|
|
196
|
-
"
|
|
228
|
+
"Integration Audit: once all parallel Boatswains report Complete, verify the combined diff for logic conflicts or signature mismatches.",
|
|
229
|
+
"Documentation Gate: REJECT approval if code changed but docs/project-map.md or docs/glossary.md were not updated to reflect the new state.",
|
|
230
|
+
"Evidence Verification: ensure every workstream provided terminal logs proving their respective tests or build commands passed.",
|
|
231
|
+
"Traceability: confirm the final implementation matches the Navigator's original Invariants.",
|
|
197
232
|
"Escalate unresolved quality gaps to the Captain before approval.",
|
|
198
233
|
"Require rework when verification is missing or conventions are violated.",
|
|
199
234
|
"Reject approvals lacking evidence (diagnostics/tests/build logs) or missing todo/task tracking.",
|
|
235
|
+
"Regression Check: require a full project TEST_CMD run (if available) to ensure integrated workstreams didn't break the system.",
|
|
200
236
|
"Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
|
|
201
237
|
"Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
|
|
202
238
|
],
|
|
203
|
-
tools: ["read", "grep", "execute", "write"]
|
|
239
|
+
tools: ["read", "grep", "execute", "write", "skill"]
|
|
204
240
|
});
|
|
205
241
|
|
|
206
242
|
// src/crew/Scout.ts
|
|
207
243
|
var Scout = new OpCrewAgent({
|
|
208
244
|
name: "Scout",
|
|
245
|
+
description: "Research specialist for external information gathering - web searches, documentation lookup, API references, and best practices. Use when you need information from outside the project.",
|
|
209
246
|
role: "Researcher",
|
|
210
247
|
mode: "subagent",
|
|
211
248
|
instructions: [
|
|
249
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
|
|
212
250
|
"You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
|
|
213
251
|
"Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
|
|
214
252
|
"Never modify project files - your job is to gather intelligence, not execute changes.",
|
|
215
253
|
"Provide concise, actionable findings with clear sources and citations.",
|
|
254
|
+
"Rosetta Stone Summaries: when researching a new language, explain concepts via analogy - 'This is the [Go] equivalent of [Python's] Decorators.'",
|
|
216
255
|
"When researching libraries or frameworks, include: version info, installation methods, key APIs, and gotchas.",
|
|
217
256
|
"Compare alternatives when relevant: pros/cons, trade-offs, and recommendations with rationale.",
|
|
218
257
|
"Flag deprecated or outdated information; always verify against official sources when possible.",
|
|
219
258
|
"Summarize findings in a structured format: problem, findings, recommendations, sources.",
|
|
259
|
+
"Glossary Contribution: propose new terms or external definitions for the Boatswain to add to docs/glossary.md.",
|
|
220
260
|
"If research reveals the task is more complex than expected, escalate to Navigator for replanning.",
|
|
221
|
-
"
|
|
261
|
+
"Environment Discovery: research specific error messages or build tool quirks if the Boatswain hits a blocker.",
|
|
262
|
+
"Knowledge Caching: store research summaries in docs/research/ for future crew reference."
|
|
222
263
|
],
|
|
223
|
-
tools: ["websearch", "webfetch", "read"]
|
|
264
|
+
tools: ["websearch", "webfetch", "read", "skill"]
|
|
224
265
|
});
|
|
225
266
|
|
|
226
267
|
// src/crew/index.ts
|
|
@@ -232,10 +273,66 @@ var crew = [
|
|
|
232
273
|
Scout
|
|
233
274
|
];
|
|
234
275
|
|
|
276
|
+
// src/skills.ts
|
|
277
|
+
import { readdir, readFile } from "fs/promises";
|
|
278
|
+
import path from "path";
|
|
279
|
+
import { fileURLToPath } from "url";
|
|
280
|
+
var __dirname2 = path.dirname(fileURLToPath(import.meta.url));
|
|
281
|
+
async function loadSkills() {
|
|
282
|
+
const skillsDir = path.join(__dirname2, "skills");
|
|
283
|
+
try {
|
|
284
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
285
|
+
const skills = [];
|
|
286
|
+
for (const entry of entries) {
|
|
287
|
+
if (!entry.isDirectory())
|
|
288
|
+
continue;
|
|
289
|
+
const skillPath = path.join(skillsDir, entry.name);
|
|
290
|
+
const skillMdPath = path.join(skillPath, "SKILL.md");
|
|
291
|
+
try {
|
|
292
|
+
const content = await readFile(skillMdPath, "utf-8");
|
|
293
|
+
const { name, description } = parseSkillFrontmatter(content);
|
|
294
|
+
skills.push({
|
|
295
|
+
name: name || entry.name,
|
|
296
|
+
description: description || "",
|
|
297
|
+
sourcePath: skillPath
|
|
298
|
+
});
|
|
299
|
+
} catch {
|
|
300
|
+
console.warn(`Warning: No SKILL.md found in ${skillPath}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return skills;
|
|
304
|
+
} catch {
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function parseSkillFrontmatter(content) {
|
|
309
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
310
|
+
if (!frontmatterMatch) {
|
|
311
|
+
return {};
|
|
312
|
+
}
|
|
313
|
+
const frontmatter = frontmatterMatch[1];
|
|
314
|
+
const result = {};
|
|
315
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
316
|
+
if (nameMatch) {
|
|
317
|
+
result.name = nameMatch[1].trim();
|
|
318
|
+
}
|
|
319
|
+
const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
|
|
320
|
+
if (descMatch) {
|
|
321
|
+
result.description = descMatch[1].trim();
|
|
322
|
+
}
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
async function getSkillContent(skillName) {
|
|
326
|
+
const skillMdPath = path.join(__dirname2, "skills", skillName, "SKILL.md");
|
|
327
|
+
return readFile(skillMdPath, "utf-8");
|
|
328
|
+
}
|
|
329
|
+
|
|
235
330
|
// src/cli/install.ts
|
|
236
|
-
var
|
|
237
|
-
var
|
|
238
|
-
var
|
|
331
|
+
var CLAUDE_AGENTS_DIR = path2.join(".claude", "agents");
|
|
332
|
+
var CLAUDE_SKILLS_DIR = path2.join(".claude", "skills");
|
|
333
|
+
var OPENCODE_AGENTS_DIR = path2.join(".opencode", "agents");
|
|
334
|
+
var OPENCODE_SKILLS_DIR = path2.join(".opencode", "skills");
|
|
335
|
+
var CODEX_FILE = path2.join(".codex", "instructions.md");
|
|
239
336
|
async function ensureDir(targetDir) {
|
|
240
337
|
await mkdir(targetDir, { recursive: true });
|
|
241
338
|
}
|
|
@@ -244,26 +341,67 @@ async function installToTool(tool) {
|
|
|
244
341
|
await installForCodex();
|
|
245
342
|
return;
|
|
246
343
|
}
|
|
247
|
-
const
|
|
248
|
-
|
|
344
|
+
const agentsDir = tool === "claude" ? CLAUDE_AGENTS_DIR : OPENCODE_AGENTS_DIR;
|
|
345
|
+
const skillsDir = tool === "claude" ? CLAUDE_SKILLS_DIR : OPENCODE_SKILLS_DIR;
|
|
346
|
+
await ensureDir(agentsDir);
|
|
249
347
|
for (const agent of crew) {
|
|
250
348
|
const filename = `${agent.config.name.toLowerCase()}.md`;
|
|
251
|
-
const filePath =
|
|
349
|
+
const filePath = path2.join(agentsDir, filename);
|
|
252
350
|
const content = tool === "opencode" ? agent.compileToOpenCodeMarkdown() : agent.compileToMarkdown();
|
|
253
351
|
await writeFile(filePath, content);
|
|
254
|
-
console.log(`Synced ${agent.config.name} to ${
|
|
352
|
+
console.log(`Synced ${agent.config.name} to ${agentsDir}`);
|
|
353
|
+
}
|
|
354
|
+
await installSkills(skillsDir, tool);
|
|
355
|
+
}
|
|
356
|
+
async function installSkills(targetDir, tool) {
|
|
357
|
+
const skills = await loadSkills();
|
|
358
|
+
if (skills.length === 0) {
|
|
359
|
+
console.log("No skills found to install.");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
await ensureDir(targetDir);
|
|
363
|
+
for (const skill of skills) {
|
|
364
|
+
const skillDestDir = path2.join(targetDir, skill.name);
|
|
365
|
+
await rm(skillDestDir, { recursive: true, force: true });
|
|
366
|
+
await cp(skill.sourcePath, skillDestDir, { recursive: true });
|
|
367
|
+
console.log(`Synced skill ${skill.name} to ${targetDir}`);
|
|
255
368
|
}
|
|
256
369
|
}
|
|
257
370
|
async function installForCodex() {
|
|
258
|
-
const codexDir =
|
|
371
|
+
const codexDir = path2.dirname(CODEX_FILE);
|
|
259
372
|
await ensureDir(codexDir);
|
|
260
|
-
const
|
|
373
|
+
const agentsContent = crew.map((agent) => agent.compileToCodexMarkdown()).join(`
|
|
261
374
|
|
|
262
375
|
---
|
|
263
376
|
|
|
264
377
|
`);
|
|
265
|
-
await
|
|
378
|
+
const skills = await loadSkills();
|
|
379
|
+
let skillsContent = "";
|
|
380
|
+
if (skills.length > 0) {
|
|
381
|
+
const skillContents = await Promise.all(skills.map(async (skill) => {
|
|
382
|
+
const content = await getSkillContent(skill.name);
|
|
383
|
+
return `## Skill: ${skill.name}
|
|
384
|
+
|
|
385
|
+
${content}`;
|
|
386
|
+
}));
|
|
387
|
+
skillsContent = `
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
# Skills
|
|
392
|
+
|
|
393
|
+
` + skillContents.join(`
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
`);
|
|
398
|
+
}
|
|
399
|
+
const fullContent = agentsContent + skillsContent;
|
|
400
|
+
await writeFile(CODEX_FILE, fullContent);
|
|
266
401
|
console.log(`Synced Codex instructions to ${CODEX_FILE}`);
|
|
402
|
+
if (skills.length > 0) {
|
|
403
|
+
console.log(`Synced ${skills.length} skill(s) to Codex instructions`);
|
|
404
|
+
}
|
|
267
405
|
}
|
|
268
406
|
|
|
269
407
|
// src/cli/index.ts
|
package/dist/opencode-plugin.js
CHANGED
|
@@ -15,19 +15,19 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
// src/core/tools/translations.ts
|
|
17
17
|
var CLAUDE_TOOLS = {
|
|
18
|
-
read: "
|
|
19
|
-
write: "
|
|
20
|
-
edit: "
|
|
21
|
-
glob: "
|
|
22
|
-
grep: "
|
|
23
|
-
execute: "
|
|
24
|
-
websearch: "
|
|
25
|
-
webfetch: "
|
|
26
|
-
delegate: "
|
|
27
|
-
todo: "
|
|
28
|
-
test: "
|
|
29
|
-
logbook: "
|
|
30
|
-
skill: "
|
|
18
|
+
read: "Read",
|
|
19
|
+
write: "Write",
|
|
20
|
+
edit: "Edit",
|
|
21
|
+
glob: "Glob",
|
|
22
|
+
grep: "Grep",
|
|
23
|
+
execute: "Bash",
|
|
24
|
+
websearch: "WebSearch",
|
|
25
|
+
webfetch: "WebFetch",
|
|
26
|
+
delegate: "Agent",
|
|
27
|
+
todo: "TodoWrite",
|
|
28
|
+
test: "Bash",
|
|
29
|
+
logbook: "",
|
|
30
|
+
skill: "Skill"
|
|
31
31
|
};
|
|
32
32
|
var OPENCODE_TOOLS = {
|
|
33
33
|
read: "read",
|
|
@@ -67,7 +67,7 @@ function translateTools(canonicalTools, platform) {
|
|
|
67
67
|
};
|
|
68
68
|
const translationMap = maps[platform];
|
|
69
69
|
const translated = canonicalTools.map((tool) => translationMap[tool]);
|
|
70
|
-
return [...new Set(translated)];
|
|
70
|
+
return [...new Set(translated)].filter((tool) => tool !== "");
|
|
71
71
|
}
|
|
72
72
|
// src/core/Agent.ts
|
|
73
73
|
class OpCrewAgent {
|
|
@@ -75,11 +75,28 @@ class OpCrewAgent {
|
|
|
75
75
|
constructor(config) {
|
|
76
76
|
this.config = config;
|
|
77
77
|
}
|
|
78
|
+
getAllowedTools() {
|
|
79
|
+
return this.config.allowedTools ?? this.config.tools ?? [];
|
|
80
|
+
}
|
|
81
|
+
hasTool(tool) {
|
|
82
|
+
return this.getAllowedTools().includes(tool);
|
|
83
|
+
}
|
|
84
|
+
validateToolUsage(tool) {
|
|
85
|
+
if (!this.hasTool(tool)) {
|
|
86
|
+
const allowedList = this.getAllowedTools().join(", ") || "(none)";
|
|
87
|
+
throw new Error(`Tool '${tool}' is not allowed for agent '${this.config.name}'. ` + `Allowed tools: [${allowedList}]`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
getForbiddenTools(allAvailableTools) {
|
|
91
|
+
const allowedSet = new Set(this.getAllowedTools());
|
|
92
|
+
return allAvailableTools.filter((tool) => !allowedSet.has(tool));
|
|
93
|
+
}
|
|
78
94
|
compileToMarkdown() {
|
|
79
|
-
const translatedTools = translateTools(this.
|
|
95
|
+
const translatedTools = translateTools(this.getAllowedTools(), "claude");
|
|
96
|
+
const lowerName = this.config.name.toLowerCase();
|
|
80
97
|
const frontmatter = `---
|
|
81
|
-
name: ${
|
|
82
|
-
|
|
98
|
+
name: ${lowerName}
|
|
99
|
+
description: ${this.config.description}
|
|
83
100
|
tools: [${translatedTools.join(", ")}]
|
|
84
101
|
---`;
|
|
85
102
|
return `${frontmatter}
|
|
@@ -90,7 +107,7 @@ ${this.buildMarkdownBody()}`;
|
|
|
90
107
|
Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
|
|
91
108
|
Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
|
|
92
109
|
Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
|
|
93
|
-
Reviewer: { edit: "deny", bash: "
|
|
110
|
+
Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
|
|
94
111
|
Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
|
|
95
112
|
};
|
|
96
113
|
const permission = permissionByRole[this.config.role];
|
|
@@ -106,7 +123,7 @@ permission:
|
|
|
106
123
|
${this.buildMarkdownBody()}`;
|
|
107
124
|
}
|
|
108
125
|
compileToCodexMarkdown() {
|
|
109
|
-
const translatedTools = translateTools(this.
|
|
126
|
+
const translatedTools = translateTools(this.getAllowedTools(), "codex");
|
|
110
127
|
const frontmatter = `---
|
|
111
128
|
name: ${this.config.name}
|
|
112
129
|
role: ${this.config.role}
|
|
@@ -131,102 +148,126 @@ Refer to \`.opcrew/logbook.json\` for the current voyage status.
|
|
|
131
148
|
// src/crew/Captain.ts
|
|
132
149
|
var Captain = new OpCrewAgent({
|
|
133
150
|
name: "Captain",
|
|
151
|
+
description: "Orchestrator agent that coordinates work delegation and verification. Use for complex multi-step tasks requiring coordination between specialists.",
|
|
134
152
|
role: "Orchestrator",
|
|
135
153
|
mode: "primary",
|
|
136
154
|
instructions: [
|
|
155
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
|
|
137
156
|
"You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
|
|
138
|
-
"
|
|
157
|
+
"Workstream Fan-out: divide missions into independent Workstreams (e.g., Logic, Testing, Documentation) to enable parallel specialists.",
|
|
139
158
|
"Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
|
|
140
|
-
"
|
|
159
|
+
"Collision Prevention: ensure no two Boatswains are assigned the same file or symbol in parallel. Launch workstreams only if they are logically decoupled.",
|
|
141
160
|
"Escalate blockers immediately and re-sequence work to unblock the critical path.",
|
|
142
161
|
"Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
|
|
143
162
|
"Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
|
|
144
163
|
"Delegation mandate: ALWAYS delegate work to specialists using the task tool. Never perform file edits, code changes, or direct execution yourself.",
|
|
145
164
|
"Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
|
|
146
|
-
"Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
|
|
147
165
|
"Verification gate: delegate verification to Quartermaster; ensure diagnostics/tests run and evidence is logged before marking complete.",
|
|
166
|
+
"Conflict Resolution: if specialists disagree on implementation, make the final call based on project documentation.",
|
|
148
167
|
"Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
|
|
149
168
|
"Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
|
|
150
169
|
],
|
|
151
|
-
tools: ["read", "logbook", "delegate"]
|
|
170
|
+
tools: ["read", "logbook", "delegate", "skill"]
|
|
152
171
|
});
|
|
153
172
|
|
|
154
173
|
// src/crew/Navigator.ts
|
|
155
174
|
var Navigator = new OpCrewAgent({
|
|
156
175
|
name: "Navigator",
|
|
176
|
+
description: "Planning specialist that decomposes work into atomic tasks with clear inputs, outputs, and ownership. Use when you need to chart an implementation path or create a structured plan.",
|
|
157
177
|
role: "Planner",
|
|
158
178
|
mode: "subagent",
|
|
159
179
|
instructions: [
|
|
180
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, websearch, logbook, todo, skill. Using any other tool is a violation.",
|
|
160
181
|
"Chart the implementation path based on the Captain's intent and constraints.",
|
|
161
182
|
"Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
|
|
183
|
+
"Workstream Decomposition: break the plan into atomic, parallel tracks. Define File Ownership (e.g., Boatswain-A owns src/, Boatswain-B owns tests/).",
|
|
184
|
+
"Survey the Stack: identify the project's native build system (BUILD_CMD), test runner (TEST_CMD), and style guide immediately.",
|
|
185
|
+
"Documentation Maintenance: plan for updates to docs/project-map.md and docs/glossary.md; assign these to a specific workstream.",
|
|
186
|
+
"Dependency Graphing: flag Blocking Tasks where one workstream depends on the output of another; sequence these to avoid idle agents.",
|
|
187
|
+
"Execution Manifest: for every task, specify Target File, Affected Symbols, Invariants, and the exact Verification Command.",
|
|
162
188
|
"Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
|
|
163
189
|
"Maintain a current project map (key files, modules, and ownership boundaries).",
|
|
164
190
|
"Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
|
|
165
191
|
"Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
|
|
166
192
|
"Create and manage todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
|
|
167
193
|
"Mandate parallel discovery for unknowns: launch multiple explore/librarian threads and consolidate findings.",
|
|
194
|
+
"Discovery Primitives: use language-agnostic tools (grep, find, tree) to map dependencies before proposing edits.",
|
|
168
195
|
"Delegate external research to Scout when you need information from outside the project: libraries, APIs, best practices, or documentation.",
|
|
169
196
|
"Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
|
|
170
197
|
"Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
|
|
171
198
|
],
|
|
172
|
-
tools: ["read", "websearch", "logbook", "todo"]
|
|
199
|
+
tools: ["read", "websearch", "logbook", "todo", "skill"]
|
|
173
200
|
});
|
|
174
201
|
|
|
175
202
|
// src/crew/Boatswain.ts
|
|
176
203
|
var Boatswain = new OpCrewAgent({
|
|
177
204
|
name: "Boatswain",
|
|
205
|
+
description: "Execution specialist that implements approved plans with precise edits. Use when you need to make code changes, run tests, or execute implementation steps.",
|
|
178
206
|
role: "Executor",
|
|
179
207
|
mode: "subagent",
|
|
180
208
|
instructions: [
|
|
181
|
-
"
|
|
209
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, edit, write, test, todo, glob, grep, skill. Using any other tool is a violation.",
|
|
210
|
+
"Scope Guarding: ONLY touch files assigned to your Workstream ID. If you must edit a file owned by another agent, escalate to Captain for a plan revision.",
|
|
182
211
|
"Follow existing patterns, naming, and formatting; avoid speculative changes.",
|
|
212
|
+
"Context Anchoring: before editing, read the surrounding code to match indentation, casing, and comment styles. Maintain the project's local laws.",
|
|
213
|
+
"Parallel Execution: implement the Navigator's Manifest exactly. Update code, tests, and documentation (docs/project-map.md or docs/glossary.md) as assigned.",
|
|
183
214
|
"Keep diffs lean and standards-compliant; update only what the plan calls for.",
|
|
184
|
-
"
|
|
185
|
-
"Log completion status, assumptions, and blockers immediately for the Captain.",
|
|
215
|
+
"Atomic Verification: run the assigned TEST_CMD for your scope. Record stdout/stderr logs in the logbook immediately.",
|
|
186
216
|
"Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
|
|
187
|
-
"
|
|
217
|
+
"LSP/Compiler Check: use native diagnostics to ensure no syntax errors were introduced in touched files.",
|
|
188
218
|
"Update docs/knowledge when execution changes assumptions, definitions, or operational steps.",
|
|
189
|
-
"Update todo task status immediately upon completion of each task."
|
|
219
|
+
"Update todo task status immediately upon completion of each task.",
|
|
220
|
+
"Status Discipline: update your specific task status in logbook.json as you work; do not wait for other workstreams to finish."
|
|
190
221
|
],
|
|
191
|
-
tools: ["read", "edit", "test", "todo"]
|
|
222
|
+
tools: ["read", "edit", "write", "test", "todo", "glob", "grep", "skill"]
|
|
192
223
|
});
|
|
193
224
|
|
|
194
225
|
// src/crew/Quartermaster.ts
|
|
195
226
|
var Quartermaster = new OpCrewAgent({
|
|
196
227
|
name: "Quartermaster",
|
|
228
|
+
description: "Quality assurance specialist that reviews diffs, verifies tests pass, and ensures conventions are followed. Use proactively after code changes to verify quality.",
|
|
197
229
|
role: "Reviewer",
|
|
198
230
|
mode: "subagent",
|
|
199
231
|
instructions: [
|
|
232
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: read, grep, execute, write, skill. Using any other tool is a violation.",
|
|
200
233
|
"Inspect each diff for regression risks, scope drift, and missing context.",
|
|
201
|
-
"
|
|
202
|
-
"
|
|
234
|
+
"Integration Audit: once all parallel Boatswains report Complete, verify the combined diff for logic conflicts or signature mismatches.",
|
|
235
|
+
"Documentation Gate: REJECT approval if code changed but docs/project-map.md or docs/glossary.md were not updated to reflect the new state.",
|
|
236
|
+
"Evidence Verification: ensure every workstream provided terminal logs proving their respective tests or build commands passed.",
|
|
237
|
+
"Traceability: confirm the final implementation matches the Navigator's original Invariants.",
|
|
203
238
|
"Escalate unresolved quality gaps to the Captain before approval.",
|
|
204
239
|
"Require rework when verification is missing or conventions are violated.",
|
|
205
240
|
"Reject approvals lacking evidence (diagnostics/tests/build logs) or missing todo/task tracking.",
|
|
241
|
+
"Regression Check: require a full project TEST_CMD run (if available) to ensure integrated workstreams didn't break the system.",
|
|
206
242
|
"Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
|
|
207
243
|
"Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
|
|
208
244
|
],
|
|
209
|
-
tools: ["read", "grep", "execute", "write"]
|
|
245
|
+
tools: ["read", "grep", "execute", "write", "skill"]
|
|
210
246
|
});
|
|
211
247
|
|
|
212
248
|
// src/crew/Scout.ts
|
|
213
249
|
var Scout = new OpCrewAgent({
|
|
214
250
|
name: "Scout",
|
|
251
|
+
description: "Research specialist for external information gathering - web searches, documentation lookup, API references, and best practices. Use when you need information from outside the project.",
|
|
215
252
|
role: "Researcher",
|
|
216
253
|
mode: "subagent",
|
|
217
254
|
instructions: [
|
|
255
|
+
"TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
|
|
218
256
|
"You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
|
|
219
257
|
"Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
|
|
220
258
|
"Never modify project files - your job is to gather intelligence, not execute changes.",
|
|
221
259
|
"Provide concise, actionable findings with clear sources and citations.",
|
|
260
|
+
"Rosetta Stone Summaries: when researching a new language, explain concepts via analogy - 'This is the [Go] equivalent of [Python's] Decorators.'",
|
|
222
261
|
"When researching libraries or frameworks, include: version info, installation methods, key APIs, and gotchas.",
|
|
223
262
|
"Compare alternatives when relevant: pros/cons, trade-offs, and recommendations with rationale.",
|
|
224
263
|
"Flag deprecated or outdated information; always verify against official sources when possible.",
|
|
225
264
|
"Summarize findings in a structured format: problem, findings, recommendations, sources.",
|
|
265
|
+
"Glossary Contribution: propose new terms or external definitions for the Boatswain to add to docs/glossary.md.",
|
|
226
266
|
"If research reveals the task is more complex than expected, escalate to Navigator for replanning.",
|
|
227
|
-
"
|
|
267
|
+
"Environment Discovery: research specific error messages or build tool quirks if the Boatswain hits a blocker.",
|
|
268
|
+
"Knowledge Caching: store research summaries in docs/research/ for future crew reference."
|
|
228
269
|
],
|
|
229
|
-
tools: ["websearch", "webfetch", "read"]
|
|
270
|
+
tools: ["websearch", "webfetch", "read", "skill"]
|
|
230
271
|
});
|
|
231
272
|
|
|
232
273
|
// src/crew/index.ts
|
|
@@ -12680,65 +12721,128 @@ The logbook tracks:
|
|
|
12680
12721
|
});
|
|
12681
12722
|
|
|
12682
12723
|
// 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;
|
|
12683
12740
|
var permissionByRole = {
|
|
12684
12741
|
Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
|
|
12685
12742
|
Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
|
|
12686
12743
|
Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
|
|
12687
|
-
Reviewer: { edit: "deny", bash: "
|
|
12744
|
+
Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
|
|
12688
12745
|
Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
|
|
12689
12746
|
};
|
|
12690
12747
|
function toAgentId(agent) {
|
|
12691
12748
|
return agent.config.name.toLowerCase().replace(/\s+/g, "-");
|
|
12692
12749
|
}
|
|
12693
|
-
function buildPrompt(agent) {
|
|
12750
|
+
function buildPrompt(agent, availableTools) {
|
|
12694
12751
|
const instructionsList = agent.config.instructions.map((instruction) => `- ${instruction}`).join(`
|
|
12695
12752
|
`);
|
|
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)"}`;
|
|
12696
12758
|
return `# ${agent.config.name}
|
|
12759
|
+
|
|
12760
|
+
${toolBoundariesSection}
|
|
12761
|
+
|
|
12697
12762
|
${instructionsList}
|
|
12698
12763
|
|
|
12699
12764
|
## Shared Context
|
|
12700
12765
|
Refer to \`.opcrew/logbook.json\` for the current voyage status.
|
|
12701
12766
|
`;
|
|
12702
12767
|
}
|
|
12703
|
-
function toOpenCodeAgentConfig(agent) {
|
|
12768
|
+
function toOpenCodeAgentConfig(agent, availableTools) {
|
|
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
|
+
}
|
|
12704
12775
|
return {
|
|
12705
12776
|
description: agent.config.name,
|
|
12706
12777
|
mode: agent.config.mode,
|
|
12707
|
-
prompt: buildPrompt(agent),
|
|
12778
|
+
prompt: buildPrompt(agent, availableTools),
|
|
12708
12779
|
permission: permissionByRole[agent.config.role]
|
|
12709
12780
|
};
|
|
12710
12781
|
}
|
|
12711
|
-
|
|
12712
|
-
|
|
12713
|
-
|
|
12714
|
-
|
|
12715
|
-
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
}
|
|
12719
|
-
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
|
|
12723
|
-
|
|
12724
|
-
|
|
12725
|
-
|
|
12726
|
-
|
|
12727
|
-
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
|
|
12733
|
-
|
|
12734
|
-
|
|
12735
|
-
|
|
12736
|
-
|
|
12737
|
-
|
|
12782
|
+
function createOpCrewPlugin(options = {}) {
|
|
12783
|
+
const {
|
|
12784
|
+
tools: customTools = {},
|
|
12785
|
+
skills,
|
|
12786
|
+
availableTools = DEFAULT_CANONICAL_TOOLS,
|
|
12787
|
+
includeDefaultTools = true,
|
|
12788
|
+
crew: customCrew = crew
|
|
12789
|
+
} = options;
|
|
12790
|
+
const defaultTools = includeDefaultTools ? { edit_logbook: editLogbookTool } : {};
|
|
12791
|
+
const mergedTools = {
|
|
12792
|
+
...defaultTools,
|
|
12793
|
+
...customTools
|
|
12794
|
+
};
|
|
12795
|
+
const _skills = skills;
|
|
12796
|
+
return async ({ client }) => {
|
|
12797
|
+
await client.app.log({
|
|
12798
|
+
body: {
|
|
12799
|
+
service: "opcrew",
|
|
12800
|
+
level: "info",
|
|
12801
|
+
message: "OpenCode plugin initialized"
|
|
12802
|
+
}
|
|
12803
|
+
});
|
|
12804
|
+
return {
|
|
12805
|
+
config: async (config2) => {
|
|
12806
|
+
const agents = config2.agent ?? {};
|
|
12807
|
+
agents["build"] = { ...agents["build"], disable: true };
|
|
12808
|
+
for (const agent of customCrew) {
|
|
12809
|
+
const agentId = toAgentId(agent);
|
|
12810
|
+
const allowedTools = agent.getAllowedTools();
|
|
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
|
+
};
|
|
12738
12838
|
};
|
|
12739
|
-
}
|
|
12839
|
+
}
|
|
12840
|
+
var OpCrewPlugin = createOpCrewPlugin();
|
|
12740
12841
|
var opencode_plugin_default = OpCrewPlugin;
|
|
12741
12842
|
export {
|
|
12742
12843
|
opencode_plugin_default as default,
|
|
12743
|
-
|
|
12844
|
+
createOpCrewPlugin,
|
|
12845
|
+
OpCrewPlugin,
|
|
12846
|
+
DEFAULT_CANONICAL_TOOLS,
|
|
12847
|
+
ALL_AVAILABLE_TOOLS
|
|
12744
12848
|
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: write-adr
|
|
3
|
+
description: Guides the crew to write Architecture Decision Records (ADRs). Use when making material decisions that should be documented, when asked to create an ADR, or when a decision with long-term impact is made.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Write ADR Skill
|
|
7
|
+
|
|
8
|
+
This skill guides the OpCrew to write well-structured Architecture Decision Records (ADRs) following the project's conventions.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
Use this skill when:
|
|
13
|
+
- Making a material decision that affects the project's architecture, conventions, or workflows
|
|
14
|
+
- A decision has long-term impact and should be preserved for future reference
|
|
15
|
+
- Explicitly asked to create or write an ADR
|
|
16
|
+
- Changing a previous architectural decision
|
|
17
|
+
- Introducing new patterns, tools, or approaches that others should follow
|
|
18
|
+
|
|
19
|
+
## What is an ADR?
|
|
20
|
+
|
|
21
|
+
An Architecture Decision Record (ADR) captures a significant architectural decision along with its context and consequences. ADRs:
|
|
22
|
+
|
|
23
|
+
- Create a decision log that's reviewable in Git
|
|
24
|
+
- Help future team members understand *why* decisions were made
|
|
25
|
+
- Prevent "why did we do this?" questions months later
|
|
26
|
+
- Make decisions explicit and traceable
|
|
27
|
+
|
|
28
|
+
## ADR Structure
|
|
29
|
+
|
|
30
|
+
OpCrew ADRs use four sections:
|
|
31
|
+
|
|
32
|
+
### 1. Status
|
|
33
|
+
The current state of the decision:
|
|
34
|
+
- **Proposed** - Under discussion, not yet finalized
|
|
35
|
+
- **Accepted** - Approved and in effect
|
|
36
|
+
- **Deprecated** - Still in effect but should be avoided for new work
|
|
37
|
+
- **Superseded** - Replaced by a newer ADR (link to it)
|
|
38
|
+
|
|
39
|
+
### 2. Context
|
|
40
|
+
What is the issue or situation motivating this decision?
|
|
41
|
+
- Describe the problem or opportunity
|
|
42
|
+
- Include relevant constraints and requirements
|
|
43
|
+
- Explain why a decision is needed now
|
|
44
|
+
|
|
45
|
+
### 3. Decision
|
|
46
|
+
What is the change being made or proposed?
|
|
47
|
+
- State the decision clearly and concisely
|
|
48
|
+
- Be specific about what is being done
|
|
49
|
+
- Include any alternatives considered (briefly)
|
|
50
|
+
|
|
51
|
+
### 4. Consequences
|
|
52
|
+
What becomes easier or more difficult because of this change?
|
|
53
|
+
- List positive outcomes
|
|
54
|
+
- Acknowledge trade-offs and limitations
|
|
55
|
+
- Note any follow-up actions required
|
|
56
|
+
|
|
57
|
+
## Filename Convention
|
|
58
|
+
|
|
59
|
+
ADRs are stored in `docs/knowledge/decisions/` with this format:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
YYYYMMDD-NNN-slug.md
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- `YYYYMMDD` - Date the ADR is created
|
|
66
|
+
- `NNN` - Sequential number (001, 002, 003...)
|
|
67
|
+
- `slug` - Short kebab-case description
|
|
68
|
+
|
|
69
|
+
**Examples:**
|
|
70
|
+
- `20260328-001-knowledge-base-source-of-truth.md`
|
|
71
|
+
- `20260329-002-agent-configuration-standard.md`
|
|
72
|
+
|
|
73
|
+
## Step-by-Step Workflow
|
|
74
|
+
|
|
75
|
+
1. **Identify the decision** - Is this a material decision worth documenting?
|
|
76
|
+
2. **Check existing ADRs** - Look in `docs/knowledge/decisions/` for related decisions
|
|
77
|
+
3. **Determine the next sequence number** - Look at existing files and increment
|
|
78
|
+
4. **Create the file** - Use the template and filename convention
|
|
79
|
+
5. **Write the ADR** - Fill in all four sections with clear, concise content
|
|
80
|
+
6. **Review** - Ensure the ADR captures the full context and rationale
|
|
81
|
+
7. **Commit** - Include the ADR in your commit with related changes
|
|
82
|
+
|
|
83
|
+
## Example ADR
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
# Knowledge Base Source of Truth
|
|
87
|
+
|
|
88
|
+
## Status
|
|
89
|
+
Accepted
|
|
90
|
+
|
|
91
|
+
## Context
|
|
92
|
+
We need a maintainable way to preserve project decisions, conventions, and operational guidance for agents and humans.
|
|
93
|
+
|
|
94
|
+
## Decision
|
|
95
|
+
Use the filesystem as the canonical knowledge base in `docs/knowledge/`. Keep decisions as ADRs, project map and glossary as living docs, and runbooks for operational procedures.
|
|
96
|
+
|
|
97
|
+
## Consequences
|
|
98
|
+
- Decisions become reviewable and diffable in Git.
|
|
99
|
+
- Agents must read/update these docs as part of workflow conventions.
|
|
100
|
+
- A database can be added later only as a derived index, not as the source of truth.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Tips for Good ADRs
|
|
104
|
+
|
|
105
|
+
- **Be concise** - ADRs should be readable in 2-3 minutes
|
|
106
|
+
- **Focus on why** - The context and rationale matter more than the details
|
|
107
|
+
- **Write for the future** - Assume the reader doesn't have your current context
|
|
108
|
+
- **Include trade-offs** - Every decision has downsides; acknowledge them
|
|
109
|
+
- **Link related ADRs** - If this supersedes or relates to another ADR, mention it
|
|
110
|
+
- **Keep it current** - Update status if the decision changes
|
|
111
|
+
|
|
112
|
+
## Template Location
|
|
113
|
+
|
|
114
|
+
Use the template at `templates/adr-template.md` as a starting point.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# [Title]
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
[Proposed | Accepted | Deprecated | Superseded]
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
[What is the issue that we're seeing that is motivating this decision or change?]
|
|
8
|
+
|
|
9
|
+
## Decision
|
|
10
|
+
[What is the change that we're proposing and/or doing?]
|
|
11
|
+
|
|
12
|
+
## Consequences
|
|
13
|
+
[What becomes easier or more difficult to do because of this change?]
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: write-adr
|
|
3
|
+
description: Guides the crew to write Architecture Decision Records (ADRs). Use when making material decisions that should be documented, when asked to create an ADR, or when a decision with long-term impact is made.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Write ADR Skill
|
|
7
|
+
|
|
8
|
+
This skill guides the OpCrew to write well-structured Architecture Decision Records (ADRs) following the project's conventions.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
Use this skill when:
|
|
13
|
+
- Making a material decision that affects the project's architecture, conventions, or workflows
|
|
14
|
+
- A decision has long-term impact and should be preserved for future reference
|
|
15
|
+
- Explicitly asked to create or write an ADR
|
|
16
|
+
- Changing a previous architectural decision
|
|
17
|
+
- Introducing new patterns, tools, or approaches that others should follow
|
|
18
|
+
|
|
19
|
+
## What is an ADR?
|
|
20
|
+
|
|
21
|
+
An Architecture Decision Record (ADR) captures a significant architectural decision along with its context and consequences. ADRs:
|
|
22
|
+
|
|
23
|
+
- Create a decision log that's reviewable in Git
|
|
24
|
+
- Help future team members understand *why* decisions were made
|
|
25
|
+
- Prevent "why did we do this?" questions months later
|
|
26
|
+
- Make decisions explicit and traceable
|
|
27
|
+
|
|
28
|
+
## ADR Structure
|
|
29
|
+
|
|
30
|
+
OpCrew ADRs use four sections:
|
|
31
|
+
|
|
32
|
+
### 1. Status
|
|
33
|
+
The current state of the decision:
|
|
34
|
+
- **Proposed** - Under discussion, not yet finalized
|
|
35
|
+
- **Accepted** - Approved and in effect
|
|
36
|
+
- **Deprecated** - Still in effect but should be avoided for new work
|
|
37
|
+
- **Superseded** - Replaced by a newer ADR (link to it)
|
|
38
|
+
|
|
39
|
+
### 2. Context
|
|
40
|
+
What is the issue or situation motivating this decision?
|
|
41
|
+
- Describe the problem or opportunity
|
|
42
|
+
- Include relevant constraints and requirements
|
|
43
|
+
- Explain why a decision is needed now
|
|
44
|
+
|
|
45
|
+
### 3. Decision
|
|
46
|
+
What is the change being made or proposed?
|
|
47
|
+
- State the decision clearly and concisely
|
|
48
|
+
- Be specific about what is being done
|
|
49
|
+
- Include any alternatives considered (briefly)
|
|
50
|
+
|
|
51
|
+
### 4. Consequences
|
|
52
|
+
What becomes easier or more difficult because of this change?
|
|
53
|
+
- List positive outcomes
|
|
54
|
+
- Acknowledge trade-offs and limitations
|
|
55
|
+
- Note any follow-up actions required
|
|
56
|
+
|
|
57
|
+
## Filename Convention
|
|
58
|
+
|
|
59
|
+
ADRs are stored in `docs/knowledge/decisions/` with this format:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
YYYYMMDD-NNN-slug.md
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- `YYYYMMDD` - Date the ADR is created
|
|
66
|
+
- `NNN` - Sequential number (001, 002, 003...)
|
|
67
|
+
- `slug` - Short kebab-case description
|
|
68
|
+
|
|
69
|
+
**Examples:**
|
|
70
|
+
- `20260328-001-knowledge-base-source-of-truth.md`
|
|
71
|
+
- `20260329-002-agent-configuration-standard.md`
|
|
72
|
+
|
|
73
|
+
## Step-by-Step Workflow
|
|
74
|
+
|
|
75
|
+
1. **Identify the decision** - Is this a material decision worth documenting?
|
|
76
|
+
2. **Check existing ADRs** - Look in `docs/knowledge/decisions/` for related decisions
|
|
77
|
+
3. **Determine the next sequence number** - Look at existing files and increment
|
|
78
|
+
4. **Create the file** - Use the template and filename convention
|
|
79
|
+
5. **Write the ADR** - Fill in all four sections with clear, concise content
|
|
80
|
+
6. **Review** - Ensure the ADR captures the full context and rationale
|
|
81
|
+
7. **Commit** - Include the ADR in your commit with related changes
|
|
82
|
+
|
|
83
|
+
## Example ADR
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
# Knowledge Base Source of Truth
|
|
87
|
+
|
|
88
|
+
## Status
|
|
89
|
+
Accepted
|
|
90
|
+
|
|
91
|
+
## Context
|
|
92
|
+
We need a maintainable way to preserve project decisions, conventions, and operational guidance for agents and humans.
|
|
93
|
+
|
|
94
|
+
## Decision
|
|
95
|
+
Use the filesystem as the canonical knowledge base in `docs/knowledge/`. Keep decisions as ADRs, project map and glossary as living docs, and runbooks for operational procedures.
|
|
96
|
+
|
|
97
|
+
## Consequences
|
|
98
|
+
- Decisions become reviewable and diffable in Git.
|
|
99
|
+
- Agents must read/update these docs as part of workflow conventions.
|
|
100
|
+
- A database can be added later only as a derived index, not as the source of truth.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Tips for Good ADRs
|
|
104
|
+
|
|
105
|
+
- **Be concise** - ADRs should be readable in 2-3 minutes
|
|
106
|
+
- **Focus on why** - The context and rationale matter more than the details
|
|
107
|
+
- **Write for the future** - Assume the reader doesn't have your current context
|
|
108
|
+
- **Include trade-offs** - Every decision has downsides; acknowledge them
|
|
109
|
+
- **Link related ADRs** - If this supersedes or relates to another ADR, mention it
|
|
110
|
+
- **Keep it current** - Update status if the decision changes
|
|
111
|
+
|
|
112
|
+
## Template Location
|
|
113
|
+
|
|
114
|
+
Use the template at `templates/adr-template.md` as a starting point.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# [Title]
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
[Proposed | Accepted | Deprecated | Superseded]
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
[What is the issue that we're seeing that is motivating this decision or change?]
|
|
8
|
+
|
|
9
|
+
## Decision
|
|
10
|
+
[What is the change that we're proposing and/or doing?]
|
|
11
|
+
|
|
12
|
+
## Consequences
|
|
13
|
+
[What becomes easier or more difficult to do because of this change?]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Strict Agent Tool Boundaries
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Accepted
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
OpenCrew agents currently have tool assignments defined declaratively in their configuration, but these assignments are NOT technically enforced. The existing permission system only covers three operations (edit, bash, webfetch) at the platform level, while tool assignments like `read`, `write`, `delegate`, `logbook`, etc. are purely instructional.
|
|
8
|
+
|
|
9
|
+
This creates several problems:
|
|
10
|
+
1. **Role confusion**: Captain could theoretically use tools meant for Boatswain (like `edit`)
|
|
11
|
+
2. **Accountability gaps**: No verification that agents stay within their designated scope
|
|
12
|
+
3. **Debugging difficulty**: When something goes wrong, it's unclear which agent overstepped
|
|
13
|
+
4. **Security risk**: An agent could access tools it shouldn't have access to
|
|
14
|
+
|
|
15
|
+
The principle "Captain never writes code - that's Boatswain's job" is currently enforced only through instructions, not technical barriers.
|
|
16
|
+
|
|
17
|
+
## Decision
|
|
18
|
+
Implement strict technical enforcement of agent tool boundaries through:
|
|
19
|
+
|
|
20
|
+
1. **Tool Allowlist per Agent**: Each agent definition will include an explicit `allowedTools` array that is validated at runtime
|
|
21
|
+
2. **Plugin-Level Enforcement**: The OpenCode plugin will filter available tools based on the agent's allowlist before registration
|
|
22
|
+
3. **Instruction Injection**: Agent instructions will be auto-generated with explicit "ALLOWED TOOLS" and "FORBIDDEN TOOLS" sections
|
|
23
|
+
4. **Runtime Validation**: A guard function will validate tool usage before each invocation
|
|
24
|
+
|
|
25
|
+
Agent tool boundaries:
|
|
26
|
+
- **Captain (Orchestrator)**: read, logbook, delegate, skill
|
|
27
|
+
- **Navigator (Planner)**: read, websearch, logbook, todo, skill
|
|
28
|
+
- **Boatswain (Executor)**: read, edit, write, test, todo, glob, grep, skill
|
|
29
|
+
- **Quartermaster (Reviewer)**: read, grep, execute, write, skill
|
|
30
|
+
- **Scout (Researcher)**: websearch, webfetch, read, skill
|
|
31
|
+
|
|
32
|
+
## Consequences
|
|
33
|
+
|
|
34
|
+
**Benefits:**
|
|
35
|
+
- Clear separation of concerns - each agent has a defined operational scope
|
|
36
|
+
- Easier debugging - tool usage violations are caught immediately
|
|
37
|
+
- Better security - no accidental or intentional tool misuse
|
|
38
|
+
- Self-documenting - agent capabilities are explicit in code
|
|
39
|
+
- Improved trust - users can rely on agents staying in their lane
|
|
40
|
+
|
|
41
|
+
**Trade-offs:**
|
|
42
|
+
- More rigid system - changing tool access requires code changes
|
|
43
|
+
- Potential friction - if an agent legitimately needs a new tool, must update config
|
|
44
|
+
- Implementation overhead - validation logic adds complexity
|
|
45
|
+
|
|
46
|
+
**Follow-up Actions:**
|
|
47
|
+
- Update Agent.ts with tool enforcement methods
|
|
48
|
+
- Add allowedTools array to each agent definition
|
|
49
|
+
- Create guard functions in src/core/guards.ts
|
|
50
|
+
- Update opencode-plugin.ts to filter tools at registration
|
|
51
|
+
- Write tests for boundary enforcement
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Plugin Factory Pattern for Configuration
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Accepted
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
The OpenCrew plugin (`src/opencode-plugin.ts`) previously hardcoded all configuration:
|
|
8
|
+
- Tools (`edit_logbook`) were imported and registered directly
|
|
9
|
+
- `ALL_AVAILABLE_TOOLS` was defined inline
|
|
10
|
+
- The crew of agents was imported from a fixed location
|
|
11
|
+
- Skills were not configurable through the plugin
|
|
12
|
+
|
|
13
|
+
This made it difficult to:
|
|
14
|
+
1. Add custom tools without modifying the plugin source
|
|
15
|
+
2. Extend the available tools list for custom tool types
|
|
16
|
+
3. Use a custom crew configuration
|
|
17
|
+
4. Configure the plugin for different deployment scenarios
|
|
18
|
+
|
|
19
|
+
The `Plugin` type from `@opencode-ai/plugin` is a function signature `(input: PluginInput) => Promise<Hooks>`, which doesn't accept custom configuration parameters directly.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
Implement a **Factory Pattern** for the OpCrew plugin:
|
|
23
|
+
|
|
24
|
+
1. **`OpCrewPluginOptions` interface** - Configuration object with:
|
|
25
|
+
- `tools?: Record<string, ToolDefinition>` - Custom tools to register
|
|
26
|
+
- `skills?: SkillConfig[]` - Skills to make available
|
|
27
|
+
- `availableTools?: CanonicalTool[]` - Canonical tools for boundary enforcement
|
|
28
|
+
- `includeDefaultTools?: boolean` - Whether to include default tools (default: true)
|
|
29
|
+
- `crew?: OpCrewAgent[]` - Custom crew of agents
|
|
30
|
+
|
|
31
|
+
2. **`createOpCrewPlugin(options)` factory function** - Creates a configured Plugin instance
|
|
32
|
+
|
|
33
|
+
3. **`DEFAULT_CANONICAL_TOOLS` export** - The default list for extension
|
|
34
|
+
|
|
35
|
+
4. **Backwards compatibility** - Default export `OpCrewPlugin` uses default options
|
|
36
|
+
|
|
37
|
+
### Usage Examples
|
|
38
|
+
|
|
39
|
+
**Default (backwards compatible):**
|
|
40
|
+
```typescript
|
|
41
|
+
import { OpCrewPlugin } from 'opcrew';
|
|
42
|
+
export default OpCrewPlugin;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**With custom tools:**
|
|
46
|
+
```typescript
|
|
47
|
+
import { createOpCrewPlugin } from 'opcrew';
|
|
48
|
+
import { myTool } from './my-tool';
|
|
49
|
+
|
|
50
|
+
export default createOpCrewPlugin({
|
|
51
|
+
tools: { my_tool: myTool },
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Full customization:**
|
|
56
|
+
```typescript
|
|
57
|
+
import { createOpCrewPlugin, DEFAULT_CANONICAL_TOOLS } from 'opcrew';
|
|
58
|
+
|
|
59
|
+
export default createOpCrewPlugin({
|
|
60
|
+
tools: { custom_tool: myTool },
|
|
61
|
+
availableTools: [...DEFAULT_CANONICAL_TOOLS, 'custom_tool'],
|
|
62
|
+
includeDefaultTools: false,
|
|
63
|
+
crew: [customAgent],
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Consequences
|
|
68
|
+
|
|
69
|
+
**Benefits:**
|
|
70
|
+
- Extensibility: Users can add custom tools without forking
|
|
71
|
+
- Flexibility: Different configurations for different environments
|
|
72
|
+
- Testability: Easier to test with mock configurations
|
|
73
|
+
- Backwards compatible: Existing usage continues to work
|
|
74
|
+
|
|
75
|
+
**Trade-offs:**
|
|
76
|
+
- Slightly more complex API surface
|
|
77
|
+
- Need to document configuration options
|
|
78
|
+
- Type definitions must be exported for consumers
|
|
79
|
+
|
|
80
|
+
**Follow-up:**
|
|
81
|
+
- Document the configuration API in README
|
|
82
|
+
- Consider adding validation for configuration options
|
|
83
|
+
- Update package.json exports if needed
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opcrew",
|
|
3
3
|
"description": "OpenCrew agents and OpenCode plugin",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
5
5
|
"main": "./dist/opencode-plugin.js",
|
|
6
6
|
"module": "./dist/opencode-plugin.js",
|
|
7
7
|
"type": "module",
|
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
"opcrew": "./dist/cli.js"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
|
-
"build": "bun run build:plugin && bun run build:cli",
|
|
32
|
+
"build": "bun run build:plugin && bun run build:cli && bun run build:skills",
|
|
33
33
|
"build:plugin": "bun build src/opencode-plugin.ts --outdir dist --target bun",
|
|
34
34
|
"build:cli": "bun build src/cli/index.ts --outfile dist/cli.js --target bun",
|
|
35
|
+
"build:skills": "cp -r src/skills dist/skills",
|
|
35
36
|
"prepack": "bun run build",
|
|
36
37
|
"test": "bun test",
|
|
37
38
|
"build:types": "bunx tsc -p tsconfig.build.json"
|