opcrew 0.1.6 → 0.1.8

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