opencode-orchestrator 0.4.8 → 0.4.10

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/index.d.ts CHANGED
@@ -93,12 +93,12 @@ declare const OrchestratorPlugin: (input: PluginInput) => Promise<{
93
93
  check_background: {
94
94
  description: string;
95
95
  args: {
96
- taskId: import("zod").ZodString;
97
- tailLines: import("zod").ZodOptional<import("zod").ZodNumber>;
96
+ task_id: import("zod").ZodString;
97
+ tail_lines: import("zod").ZodOptional<import("zod").ZodNumber>;
98
98
  };
99
99
  execute(args: {
100
- taskId: string;
101
- tailLines?: number | undefined;
100
+ task_id: string;
101
+ tail_lines?: number | undefined;
102
102
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
103
103
  };
104
104
  list_background: {
@@ -106,22 +106,22 @@ declare const OrchestratorPlugin: (input: PluginInput) => Promise<{
106
106
  args: {
107
107
  status: import("zod").ZodOptional<import("zod").ZodEnum<{
108
108
  running: "running";
109
+ all: "all";
109
110
  done: "done";
110
111
  error: "error";
111
- all: "all";
112
112
  }>>;
113
113
  };
114
114
  execute(args: {
115
- status?: "running" | "done" | "error" | "all" | undefined;
115
+ status?: "running" | "all" | "done" | "error" | undefined;
116
116
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
117
117
  };
118
118
  kill_background: {
119
119
  description: string;
120
120
  args: {
121
- taskId: import("zod").ZodString;
121
+ task_id: import("zod").ZodString;
122
122
  };
123
123
  execute(args: {
124
- taskId: string;
124
+ task_id: string;
125
125
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
126
126
  };
127
127
  };
package/dist/index.js CHANGED
@@ -13319,197 +13319,9 @@ Returns matches grouped by pattern, with file paths and line numbers.
13319
13319
  }
13320
13320
  });
13321
13321
 
13322
- // src/core/background.ts
13323
- import { spawn as spawn2 } from "child_process";
13324
- import { randomBytes } from "crypto";
13325
- var BackgroundTaskManager = class _BackgroundTaskManager {
13326
- static _instance;
13327
- tasks = /* @__PURE__ */ new Map();
13328
- debugMode = true;
13329
- // Enable debug mode
13330
- constructor() {
13331
- }
13332
- static get instance() {
13333
- if (!_BackgroundTaskManager._instance) {
13334
- _BackgroundTaskManager._instance = new _BackgroundTaskManager();
13335
- }
13336
- return _BackgroundTaskManager._instance;
13337
- }
13338
- /**
13339
- * Generate a unique task ID in the format job_xxxxxxxx
13340
- */
13341
- generateId() {
13342
- const hex3 = randomBytes(4).toString("hex");
13343
- return `job_${hex3}`;
13344
- }
13345
- /**
13346
- * Debug logging helper
13347
- */
13348
- debug(taskId, message) {
13349
- if (this.debugMode) {
13350
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().substring(11, 23);
13351
- console.log(`[BG-DEBUG ${timestamp}] ${taskId}: ${message}`);
13352
- }
13353
- }
13354
- /**
13355
- * Run a command in the background
13356
- */
13357
- run(options) {
13358
- const id = this.generateId();
13359
- const { command, cwd = process.cwd(), timeout = 3e5, label } = options;
13360
- const isWindows = process.platform === "win32";
13361
- const shell = isWindows ? "cmd.exe" : "/bin/sh";
13362
- const shellFlag = isWindows ? "/c" : "-c";
13363
- const task = {
13364
- id,
13365
- command,
13366
- args: [shellFlag, command],
13367
- cwd,
13368
- label,
13369
- status: "running",
13370
- output: "",
13371
- errorOutput: "",
13372
- exitCode: null,
13373
- startTime: Date.now(),
13374
- timeout
13375
- };
13376
- this.tasks.set(id, task);
13377
- this.debug(id, `Starting: ${command} (cwd: ${cwd})`);
13378
- try {
13379
- const proc = spawn2(shell, task.args, {
13380
- cwd,
13381
- stdio: ["ignore", "pipe", "pipe"],
13382
- detached: false
13383
- });
13384
- task.process = proc;
13385
- proc.stdout?.on("data", (data) => {
13386
- const text = data.toString();
13387
- task.output += text;
13388
- this.debug(id, `stdout: ${text.substring(0, 100)}${text.length > 100 ? "..." : ""}`);
13389
- });
13390
- proc.stderr?.on("data", (data) => {
13391
- const text = data.toString();
13392
- task.errorOutput += text;
13393
- this.debug(id, `stderr: ${text.substring(0, 100)}${text.length > 100 ? "..." : ""}`);
13394
- });
13395
- proc.on("close", (code) => {
13396
- task.exitCode = code;
13397
- task.endTime = Date.now();
13398
- task.status = code === 0 ? "done" : "error";
13399
- task.process = void 0;
13400
- const duration3 = ((task.endTime - task.startTime) / 1e3).toFixed(2);
13401
- this.debug(id, `Completed with code ${code} in ${duration3}s`);
13402
- });
13403
- proc.on("error", (err) => {
13404
- task.status = "error";
13405
- task.errorOutput += `
13406
- Process error: ${err.message}`;
13407
- task.endTime = Date.now();
13408
- task.process = void 0;
13409
- this.debug(id, `Error: ${err.message}`);
13410
- });
13411
- setTimeout(() => {
13412
- if (task.status === "running" && task.process) {
13413
- this.debug(id, `Timeout after ${timeout}ms, killing process`);
13414
- task.process.kill("SIGKILL");
13415
- task.status = "timeout";
13416
- task.endTime = Date.now();
13417
- task.errorOutput += `
13418
- Process killed: timeout after ${timeout}ms`;
13419
- }
13420
- }, timeout);
13421
- } catch (err) {
13422
- task.status = "error";
13423
- task.errorOutput = `Failed to spawn: ${err instanceof Error ? err.message : String(err)}`;
13424
- task.endTime = Date.now();
13425
- this.debug(id, `Spawn failed: ${task.errorOutput}`);
13426
- }
13427
- return task;
13428
- }
13429
- /**
13430
- * Get task by ID
13431
- */
13432
- get(taskId) {
13433
- return this.tasks.get(taskId);
13434
- }
13435
- /**
13436
- * Get all tasks
13437
- */
13438
- getAll() {
13439
- return Array.from(this.tasks.values());
13440
- }
13441
- /**
13442
- * Get tasks by status
13443
- */
13444
- getByStatus(status) {
13445
- return this.getAll().filter((t) => t.status === status);
13446
- }
13447
- /**
13448
- * Clear completed/failed tasks
13449
- */
13450
- clearCompleted() {
13451
- let count = 0;
13452
- for (const [id, task] of this.tasks) {
13453
- if (task.status !== "running" && task.status !== "pending") {
13454
- this.tasks.delete(id);
13455
- count++;
13456
- }
13457
- }
13458
- return count;
13459
- }
13460
- /**
13461
- * Kill a running task
13462
- */
13463
- kill(taskId) {
13464
- const task = this.tasks.get(taskId);
13465
- if (task?.process) {
13466
- task.process.kill("SIGKILL");
13467
- task.status = "error";
13468
- task.errorOutput += "\nKilled by user";
13469
- task.endTime = Date.now();
13470
- this.debug(taskId, "Killed by user");
13471
- return true;
13472
- }
13473
- return false;
13474
- }
13475
- /**
13476
- * Format duration for display
13477
- */
13478
- formatDuration(task) {
13479
- const end = task.endTime || Date.now();
13480
- const seconds = (end - task.startTime) / 1e3;
13481
- if (seconds < 60) {
13482
- return `${seconds.toFixed(1)}s`;
13483
- }
13484
- const minutes = Math.floor(seconds / 60);
13485
- const remainingSeconds = seconds % 60;
13486
- return `${minutes}m ${remainingSeconds.toFixed(0)}s`;
13487
- }
13488
- /**
13489
- * Get status emoji
13490
- */
13491
- getStatusEmoji(status) {
13492
- switch (status) {
13493
- case "pending":
13494
- return "\u23F8\uFE0F";
13495
- case "running":
13496
- return "\u23F3";
13497
- case "done":
13498
- return "\u2705";
13499
- case "error":
13500
- return "\u274C";
13501
- case "timeout":
13502
- return "\u23F0";
13503
- default:
13504
- return "\u2753";
13505
- }
13506
- }
13507
- };
13508
- var backgroundTaskManager = BackgroundTaskManager.instance;
13509
-
13510
13322
  // src/tools/background.ts
13511
13323
  var runBackgroundTool = tool({
13512
- description: `Run a shell command in the background and get a task ID.
13324
+ description: `Run a shell command in background and get a task ID.
13513
13325
 
13514
13326
  <purpose>
13515
13327
  Execute long-running commands (builds, tests, etc.) without blocking.
@@ -13535,26 +13347,7 @@ The command runs asynchronously - use check_background to get results.
13535
13347
  label: tool.schema.string().optional().describe("Human-readable label for this task")
13536
13348
  },
13537
13349
  async execute(args) {
13538
- const { command, cwd, timeout, label } = args;
13539
- const task = backgroundTaskManager.run({
13540
- command,
13541
- cwd: cwd || process.cwd(),
13542
- timeout: timeout || 3e5,
13543
- label
13544
- });
13545
- const displayLabel = label ? ` (${label})` : "";
13546
- return `\u{1F680} **Background Task Started**${displayLabel}
13547
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
13548
- | Property | Value |
13549
- |----------|-------|
13550
- | **Task ID** | \`${task.id}\` |
13551
- | **Command** | \`${command}\` |
13552
- | **Status** | ${backgroundTaskManager.getStatusEmoji(task.status)} ${task.status} |
13553
- | **Working Dir** | ${task.cwd} |
13554
- | **Timeout** | ${(task.timeout / 1e3).toFixed(0)}s |
13555
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
13556
-
13557
- \u{1F4CC} **Next Step**: Use \`check_background\` with task ID \`${task.id}\` to get results.`;
13350
+ return callRustTool("run_background", args);
13558
13351
  }
13559
13352
  });
13560
13353
  var checkBackgroundTool = tool({
@@ -13572,75 +13365,11 @@ Use this after run_background to get results.
13572
13365
  - Full output (stdout + stderr)
13573
13366
  </output_includes>`,
13574
13367
  args: {
13575
- taskId: tool.schema.string().describe("Task ID from run_background (e.g., job_a1b2c3d4)"),
13576
- tailLines: tool.schema.number().optional().describe("Limit output to last N lines (default: show all)")
13368
+ task_id: tool.schema.string().describe("Task ID from run_background (e.g., job_a1b2c3d4)"),
13369
+ tail_lines: tool.schema.number().optional().describe("Limit output to last N lines (default: show all)")
13577
13370
  },
13578
13371
  async execute(args) {
13579
- const { taskId, tailLines } = args;
13580
- const task = backgroundTaskManager.get(taskId);
13581
- if (!task) {
13582
- const allTasks = backgroundTaskManager.getAll();
13583
- if (allTasks.length === 0) {
13584
- return `\u274C Task \`${taskId}\` not found. No background tasks exist.`;
13585
- }
13586
- const taskList = allTasks.map((t) => `- \`${t.id}\`: ${t.command.substring(0, 30)}...`).join("\n");
13587
- return `\u274C Task \`${taskId}\` not found.
13588
-
13589
- **Available tasks:**
13590
- ${taskList}`;
13591
- }
13592
- const duration3 = backgroundTaskManager.formatDuration(task);
13593
- const statusEmoji = backgroundTaskManager.getStatusEmoji(task.status);
13594
- let output = task.output;
13595
- let stderr = task.errorOutput;
13596
- if (tailLines && tailLines > 0) {
13597
- const outputLines = output.split("\n");
13598
- const stderrLines = stderr.split("\n");
13599
- output = outputLines.slice(-tailLines).join("\n");
13600
- stderr = stderrLines.slice(-tailLines).join("\n");
13601
- }
13602
- const maxLen = 1e4;
13603
- if (output.length > maxLen) {
13604
- output = `[...truncated ${output.length - maxLen} chars...]
13605
- ` + output.substring(output.length - maxLen);
13606
- }
13607
- if (stderr.length > maxLen) {
13608
- stderr = `[...truncated ${stderr.length - maxLen} chars...]
13609
- ` + stderr.substring(stderr.length - maxLen);
13610
- }
13611
- const labelDisplay = task.label ? ` (${task.label})` : "";
13612
- let result = `${statusEmoji} **Task ${task.id}**${labelDisplay}
13613
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
13614
- | Property | Value |
13615
- |----------|-------|
13616
- | **Command** | \`${task.command}\` |
13617
- | **Status** | ${statusEmoji} **${task.status.toUpperCase()}** |
13618
- | **Duration** | ${duration3}${task.status === "running" ? " (ongoing)" : ""} |
13619
- ${task.exitCode !== null ? `| **Exit Code** | ${task.exitCode} |` : ""}
13620
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`;
13621
- if (output.trim()) {
13622
- result += `
13623
-
13624
- \u{1F4E4} **Output (stdout)**:
13625
- \`\`\`
13626
- ${output.trim()}
13627
- \`\`\``;
13628
- }
13629
- if (stderr.trim()) {
13630
- result += `
13631
-
13632
- \u26A0\uFE0F **Errors (stderr)**:
13633
- \`\`\`
13634
- ${stderr.trim()}
13635
- \`\`\``;
13636
- }
13637
- if (task.status === "running") {
13638
- result += `
13639
-
13640
- \u23F3 Task still running... Check again later with:
13641
- \`check_background({ taskId: "${task.id}" })\``;
13642
- }
13643
- return result;
13372
+ return callRustTool("check_background", args);
13644
13373
  }
13645
13374
  });
13646
13375
  var listBackgroundTool = tool({
@@ -13654,39 +13383,7 @@ Useful to check what's in progress before starting new tasks.
13654
13383
  status: tool.schema.enum(["all", "running", "done", "error"]).optional().describe("Filter by status (default: all)")
13655
13384
  },
13656
13385
  async execute(args) {
13657
- const { status = "all" } = args;
13658
- let tasks;
13659
- if (status === "all") {
13660
- tasks = backgroundTaskManager.getAll();
13661
- } else {
13662
- tasks = backgroundTaskManager.getByStatus(status);
13663
- }
13664
- if (tasks.length === 0) {
13665
- return `\u{1F4CB} **No background tasks** ${status !== "all" ? `with status "${status}"` : ""}
13666
-
13667
- Use \`run_background\` to start a new background task.`;
13668
- }
13669
- tasks.sort((a, b) => b.startTime - a.startTime);
13670
- const rows = tasks.map((task) => {
13671
- const emoji3 = backgroundTaskManager.getStatusEmoji(task.status);
13672
- const duration3 = backgroundTaskManager.formatDuration(task);
13673
- const cmdShort = task.command.length > 25 ? task.command.substring(0, 22) + "..." : task.command;
13674
- const labelPart = task.label ? ` [${task.label}]` : "";
13675
- return `| \`${task.id}\` | ${emoji3} ${task.status.padEnd(7)} | ${cmdShort.padEnd(25)}${labelPart} | ${duration3.padStart(8)} |`;
13676
- }).join("\n");
13677
- const runningCount = tasks.filter((t) => t.status === "running").length;
13678
- const doneCount = tasks.filter((t) => t.status === "done").length;
13679
- const errorCount = tasks.filter((t) => t.status === "error" || t.status === "timeout").length;
13680
- return `\u{1F4CB} **Background Tasks** (${tasks.length} total)
13681
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
13682
- | \u23F3 Running: ${runningCount} | \u2705 Done: ${doneCount} | \u274C Error/Timeout: ${errorCount} |
13683
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
13684
-
13685
- | Task ID | Status | Command | Duration |
13686
- |---------|--------|---------|----------|
13687
- ${rows}
13688
-
13689
- \u{1F4A1} Use \`check_background({ taskId: "job_xxxxx" })\` to see full output.`;
13386
+ return callRustTool("list_background", args);
13690
13387
  }
13691
13388
  });
13692
13389
  var killBackgroundTool = tool({
@@ -13696,24 +13393,10 @@ var killBackgroundTool = tool({
13696
13393
  Stop a background task that is taking too long or no longer needed.
13697
13394
  </purpose>`,
13698
13395
  args: {
13699
- taskId: tool.schema.string().describe("Task ID to kill (e.g., job_a1b2c3d4)")
13396
+ task_id: tool.schema.string().describe("Task ID to kill (e.g., job_a1b2c3d4)")
13700
13397
  },
13701
13398
  async execute(args) {
13702
- const { taskId } = args;
13703
- const task = backgroundTaskManager.get(taskId);
13704
- if (!task) {
13705
- return `\u274C Task \`${taskId}\` not found.`;
13706
- }
13707
- if (task.status !== "running") {
13708
- return `\u26A0\uFE0F Task \`${taskId}\` is not running (status: ${task.status}).`;
13709
- }
13710
- const killed = backgroundTaskManager.kill(taskId);
13711
- if (killed) {
13712
- return `\u{1F6D1} Task \`${taskId}\` has been killed.
13713
- Command: \`${task.command}\`
13714
- Duration before kill: ${backgroundTaskManager.formatDuration(task)}`;
13715
- }
13716
- return `\u26A0\uFE0F Could not kill task \`${taskId}\`. It may have already finished.`;
13399
+ return callRustTool("kill_background", args);
13717
13400
  }
13718
13401
  });
13719
13402
 
@@ -1,9 +1,3 @@
1
- /**
2
- * Background Task Tools for OpenCode Orchestrator
3
- *
4
- * These tools allow the AI to run commands in the background and check their results later.
5
- * This is useful for long-running builds, tests, or other operations.
6
- */
7
1
  export declare const runBackgroundTool: {
8
2
  description: string;
9
3
  args: {
@@ -22,12 +16,12 @@ export declare const runBackgroundTool: {
22
16
  export declare const checkBackgroundTool: {
23
17
  description: string;
24
18
  args: {
25
- taskId: import("zod").ZodString;
26
- tailLines: import("zod").ZodOptional<import("zod").ZodNumber>;
19
+ task_id: import("zod").ZodString;
20
+ tail_lines: import("zod").ZodOptional<import("zod").ZodNumber>;
27
21
  };
28
22
  execute(args: {
29
- taskId: string;
30
- tailLines?: number | undefined;
23
+ task_id: string;
24
+ tail_lines?: number | undefined;
31
25
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
32
26
  };
33
27
  export declare const listBackgroundTool: {
@@ -35,21 +29,21 @@ export declare const listBackgroundTool: {
35
29
  args: {
36
30
  status: import("zod").ZodOptional<import("zod").ZodEnum<{
37
31
  running: "running";
32
+ all: "all";
38
33
  done: "done";
39
34
  error: "error";
40
- all: "all";
41
35
  }>>;
42
36
  };
43
37
  execute(args: {
44
- status?: "running" | "done" | "error" | "all" | undefined;
38
+ status?: "running" | "all" | "done" | "error" | undefined;
45
39
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
46
40
  };
47
41
  export declare const killBackgroundTool: {
48
42
  description: string;
49
43
  args: {
50
- taskId: import("zod").ZodString;
44
+ task_id: import("zod").ZodString;
51
45
  };
52
46
  execute(args: {
53
- taskId: string;
47
+ task_id: string;
54
48
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
55
49
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "opencode-orchestrator",
3
3
  "displayName": "OpenCode Orchestrator",
4
4
  "description": "Distributed Cognitive Architecture for OpenCode. Turns simple prompts into specialized multi-agent workflows (Planner, Coder, Reviewer).",
5
- "version": "0.4.8",
5
+ "version": "0.4.10",
6
6
  "author": "agnusdei1207",
7
7
  "license": "MIT",
8
8
  "repository": {