opcrew 0.1.6 → 0.1.7

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 CHANGED
@@ -5,7 +5,7 @@
5
5
  import process from "process";
6
6
 
7
7
  // src/cli/install.ts
8
- import { mkdir, writeFile, cp, rm } from "fs/promises";
8
+ import { mkdir, writeFile, cp, rm, stat } from "fs/promises";
9
9
  import path2 from "path";
10
10
  // src/core/tools/translations.ts
11
11
  var CLAUDE_TOOLS = {
@@ -94,7 +94,7 @@ description: ${this.config.description}
94
94
  tools: [${translatedTools.join(", ")}]
95
95
  ---`;
96
96
  return `${frontmatter}
97
- ${this.buildMarkdownBody()}`;
97
+ ${this.buildMarkdownBody("claude")}`;
98
98
  }
99
99
  compileToOpenCodeMarkdown() {
100
100
  const permissionByRole = {
@@ -114,7 +114,7 @@ permission:
114
114
  webfetch: ${permission.webfetch}
115
115
  ---`;
116
116
  return `${frontmatter}
117
- ${this.buildMarkdownBody()}`;
117
+ ${this.buildMarkdownBody("opencode")}`;
118
118
  }
119
119
  compileToCodexMarkdown() {
120
120
  const translatedTools = translateTools(this.getAllowedTools(), "codex");
@@ -124,13 +124,23 @@ role: ${this.config.role}
124
124
  tools: [${translatedTools.join(", ")}]
125
125
  ---`;
126
126
  return `${frontmatter}
127
- ${this.buildMarkdownBody()}`;
127
+ ${this.buildMarkdownBody("codex")}`;
128
128
  }
129
- buildMarkdownBody() {
129
+ buildToolBoundary(platform) {
130
+ const translatedTools = translateTools(this.getAllowedTools(), platform);
131
+ if (translatedTools.length === 0) {
132
+ return "TOOL BOUNDARY: No tools are available for this agent on this platform.";
133
+ }
134
+ const toolList = translatedTools.join(", ");
135
+ return `TOOL BOUNDARY: You are ONLY permitted to use these tools: ${toolList}. Using any other tool is a violation.`;
136
+ }
137
+ buildMarkdownBody(platform) {
138
+ const toolBoundary = this.buildToolBoundary(platform);
130
139
  const instructionsList = this.config.instructions.map((instruction) => `- ${instruction}`).join(`
131
140
  `);
132
141
  return `
133
142
  # ${this.config.name}
143
+ - ${toolBoundary}
134
144
  ${instructionsList}
135
145
 
136
146
  ## Shared Context
@@ -146,7 +156,6 @@ var Captain = new OpCrewAgent({
146
156
  role: "Orchestrator",
147
157
  mode: "primary",
148
158
  instructions: [
149
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
150
159
  "You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
151
160
  "Workstream Fan-out: divide missions into independent Workstreams (e.g., Logic, Testing, Documentation) to enable parallel specialists.",
152
161
  "Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
@@ -171,7 +180,6 @@ var Navigator = new OpCrewAgent({
171
180
  role: "Planner",
172
181
  mode: "subagent",
173
182
  instructions: [
174
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, websearch, logbook, todo, skill. Using any other tool is a violation.",
175
183
  "Chart the implementation path based on the Captain's intent and constraints.",
176
184
  "Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
177
185
  "Workstream Decomposition: break the plan into atomic, parallel tracks. Define File Ownership (e.g., Boatswain-A owns src/, Boatswain-B owns tests/).",
@@ -200,7 +208,6 @@ var Boatswain = new OpCrewAgent({
200
208
  role: "Executor",
201
209
  mode: "subagent",
202
210
  instructions: [
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
211
  "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.",
205
212
  "Follow existing patterns, naming, and formatting; avoid speculative changes.",
206
213
  "Context Anchoring: before editing, read the surrounding code to match indentation, casing, and comment styles. Maintain the project's local laws.",
@@ -223,7 +230,6 @@ var Quartermaster = new OpCrewAgent({
223
230
  role: "Reviewer",
224
231
  mode: "subagent",
225
232
  instructions: [
226
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, grep, execute, write, skill. Using any other tool is a violation.",
227
233
  "Inspect each diff for regression risks, scope drift, and missing context.",
228
234
  "Integration Audit: once all parallel Boatswains report Complete, verify the combined diff for logic conflicts or signature mismatches.",
229
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.",
@@ -246,7 +252,6 @@ var Scout = new OpCrewAgent({
246
252
  role: "Researcher",
247
253
  mode: "subagent",
248
254
  instructions: [
249
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
250
255
  "You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
251
256
  "Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
252
257
  "Never modify project files - your job is to gather intelligence, not execute changes.",
@@ -333,10 +338,70 @@ var CLAUDE_SKILLS_DIR = path2.join(".claude", "skills");
333
338
  var OPENCODE_AGENTS_DIR = path2.join(".opencode", "agents");
334
339
  var OPENCODE_SKILLS_DIR = path2.join(".opencode", "skills");
335
340
  var CODEX_FILE = path2.join(".codex", "instructions.md");
341
+ var OPCREW_DIR = ".opcrew";
342
+ var KNOWLEDGE_DIR = path2.join("docs", "knowledge");
343
+ var TEMPLATE_DIR = path2.join(import.meta.dir, "..", "templates");
336
344
  async function ensureDir(targetDir) {
337
345
  await mkdir(targetDir, { recursive: true });
338
346
  }
347
+ async function fileExists(filePath) {
348
+ try {
349
+ await stat(filePath);
350
+ return true;
351
+ } catch {
352
+ return false;
353
+ }
354
+ }
355
+ async function bootstrapLogbook() {
356
+ const logbookPath = path2.join(OPCREW_DIR, "logbook.json");
357
+ const schemaPath = path2.join(OPCREW_DIR, "logbook.schema.json");
358
+ await ensureDir(OPCREW_DIR);
359
+ if (await fileExists(logbookPath)) {
360
+ console.log(`Skipped ${logbookPath} (already exists)`);
361
+ } else {
362
+ const templatePath = path2.join(TEMPLATE_DIR, "logbook.template.json");
363
+ await cp(templatePath, logbookPath);
364
+ console.log(`Created ${logbookPath}`);
365
+ }
366
+ if (await fileExists(schemaPath)) {
367
+ console.log(`Skipped ${schemaPath} (already exists)`);
368
+ } else {
369
+ const schemaTemplatePath = path2.join(TEMPLATE_DIR, "logbook.schema.json");
370
+ await cp(schemaTemplatePath, schemaPath);
371
+ console.log(`Created ${schemaPath}`);
372
+ }
373
+ }
374
+ async function bootstrapKnowledgeBase() {
375
+ const decisionsDir = path2.join(KNOWLEDGE_DIR, "decisions");
376
+ const readmePath = path2.join(KNOWLEDGE_DIR, "README.md");
377
+ const glossaryPath = path2.join(KNOWLEDGE_DIR, "glossary.md");
378
+ const projectMapPath = path2.join(KNOWLEDGE_DIR, "project-map.md");
379
+ await ensureDir(decisionsDir);
380
+ if (await fileExists(readmePath)) {
381
+ console.log(`Skipped ${readmePath} (already exists)`);
382
+ } else {
383
+ const templatePath = path2.join(TEMPLATE_DIR, "knowledge", "README.md");
384
+ await cp(templatePath, readmePath);
385
+ console.log(`Created ${readmePath}`);
386
+ }
387
+ if (await fileExists(glossaryPath)) {
388
+ console.log(`Skipped ${glossaryPath} (already exists)`);
389
+ } else {
390
+ const templatePath = path2.join(TEMPLATE_DIR, "knowledge", "glossary.md");
391
+ await cp(templatePath, glossaryPath);
392
+ console.log(`Created ${glossaryPath}`);
393
+ }
394
+ if (await fileExists(projectMapPath)) {
395
+ console.log(`Skipped ${projectMapPath} (already exists)`);
396
+ } else {
397
+ const templatePath = path2.join(TEMPLATE_DIR, "knowledge", "project-map.md");
398
+ await cp(templatePath, projectMapPath);
399
+ console.log(`Created ${projectMapPath}`);
400
+ }
401
+ }
339
402
  async function installToTool(tool) {
403
+ await bootstrapLogbook();
404
+ await bootstrapKnowledgeBase();
340
405
  if (tool === "codex") {
341
406
  await installForCodex();
342
407
  return;
@@ -100,7 +100,7 @@ description: ${this.config.description}
100
100
  tools: [${translatedTools.join(", ")}]
101
101
  ---`;
102
102
  return `${frontmatter}
103
- ${this.buildMarkdownBody()}`;
103
+ ${this.buildMarkdownBody("claude")}`;
104
104
  }
105
105
  compileToOpenCodeMarkdown() {
106
106
  const permissionByRole = {
@@ -120,7 +120,7 @@ permission:
120
120
  webfetch: ${permission.webfetch}
121
121
  ---`;
122
122
  return `${frontmatter}
123
- ${this.buildMarkdownBody()}`;
123
+ ${this.buildMarkdownBody("opencode")}`;
124
124
  }
125
125
  compileToCodexMarkdown() {
126
126
  const translatedTools = translateTools(this.getAllowedTools(), "codex");
@@ -130,13 +130,23 @@ role: ${this.config.role}
130
130
  tools: [${translatedTools.join(", ")}]
131
131
  ---`;
132
132
  return `${frontmatter}
133
- ${this.buildMarkdownBody()}`;
133
+ ${this.buildMarkdownBody("codex")}`;
134
134
  }
135
- buildMarkdownBody() {
135
+ buildToolBoundary(platform) {
136
+ const translatedTools = translateTools(this.getAllowedTools(), platform);
137
+ if (translatedTools.length === 0) {
138
+ return "TOOL BOUNDARY: No tools are available for this agent on this platform.";
139
+ }
140
+ const toolList = translatedTools.join(", ");
141
+ return `TOOL BOUNDARY: You are ONLY permitted to use these tools: ${toolList}. Using any other tool is a violation.`;
142
+ }
143
+ buildMarkdownBody(platform) {
144
+ const toolBoundary = this.buildToolBoundary(platform);
136
145
  const instructionsList = this.config.instructions.map((instruction) => `- ${instruction}`).join(`
137
146
  `);
138
147
  return `
139
148
  # ${this.config.name}
149
+ - ${toolBoundary}
140
150
  ${instructionsList}
141
151
 
142
152
  ## Shared Context
@@ -152,7 +162,6 @@ var Captain = new OpCrewAgent({
152
162
  role: "Orchestrator",
153
163
  mode: "primary",
154
164
  instructions: [
155
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
156
165
  "You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
157
166
  "Workstream Fan-out: divide missions into independent Workstreams (e.g., Logic, Testing, Documentation) to enable parallel specialists.",
158
167
  "Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
@@ -177,7 +186,6 @@ var Navigator = new OpCrewAgent({
177
186
  role: "Planner",
178
187
  mode: "subagent",
179
188
  instructions: [
180
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, websearch, logbook, todo, skill. Using any other tool is a violation.",
181
189
  "Chart the implementation path based on the Captain's intent and constraints.",
182
190
  "Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
183
191
  "Workstream Decomposition: break the plan into atomic, parallel tracks. Define File Ownership (e.g., Boatswain-A owns src/, Boatswain-B owns tests/).",
@@ -206,7 +214,6 @@ var Boatswain = new OpCrewAgent({
206
214
  role: "Executor",
207
215
  mode: "subagent",
208
216
  instructions: [
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
217
  "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.",
211
218
  "Follow existing patterns, naming, and formatting; avoid speculative changes.",
212
219
  "Context Anchoring: before editing, read the surrounding code to match indentation, casing, and comment styles. Maintain the project's local laws.",
@@ -229,7 +236,6 @@ var Quartermaster = new OpCrewAgent({
229
236
  role: "Reviewer",
230
237
  mode: "subagent",
231
238
  instructions: [
232
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, grep, execute, write, skill. Using any other tool is a violation.",
233
239
  "Inspect each diff for regression risks, scope drift, and missing context.",
234
240
  "Integration Audit: once all parallel Boatswains report Complete, verify the combined diff for logic conflicts or signature mismatches.",
235
241
  "Documentation Gate: REJECT approval if code changed but docs/project-map.md or docs/glossary.md were not updated to reflect the new state.",
@@ -252,7 +258,6 @@ var Scout = new OpCrewAgent({
252
258
  role: "Researcher",
253
259
  mode: "subagent",
254
260
  instructions: [
255
- "TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
256
261
  "You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
257
262
  "Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
258
263
  "Never modify project files - your job is to gather intelligence, not execute changes.",