opencode-worker 0.1.4 → 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/README.md CHANGED
@@ -14,7 +14,7 @@ A set-but-empty `--opencode-bin`/`OPENCODE_WORKER_BIN` fails with `BIN_EMPTY` in
14
14
  - `HOME` and `XDG_{CONFIG,DATA,CACHE,STATE}_HOME` point into `<dir>/.opencode-worker/`.
15
15
  - Generated config: `model` = `small_model` = requested model, `enabled_providers: ["opencode"]`, `permission.external_directory: "deny"`.
16
16
  - Models outside the `opencode` provider are rejected (`PROVIDER_NOT_ALLOWED`); there is no fallback.
17
- - Timeout (default 180 s): SIGTERM, then SIGKILL after 5 s.
17
+ - Job timeout: default 900 s (15 min). Set it once per install with `OPENCODE_WORKER_TIMEOUT_SEC` (CLI and MCP server), or per job with `--timeout` / `worker_start.timeoutSec`. On expiry: SIGTERM, then SIGKILL after 5 s; an `alarm()` 10 s later also kills the worker if this process itself died.
18
18
  - Fixed flags: `run --pure --auto --format json --agent <agent> --model <model> --variant <variant>`.
19
19
 
20
20
  Defaults: model `opencode/deepseek-v4.1-flash-free`, variant `low`, agent `build`.
@@ -22,8 +22,9 @@ Defaults: model `opencode/deepseek-v4.1-flash-free`, variant `low`, agent `build
22
22
  ## CLI
23
23
 
24
24
  ```sh
25
- opencode-worker run --dir ./task --timeout 180 "Fix add() in calculator.py and run the tests"
26
- opencode-worker run --dir ./task -f prompt.md --variant high
25
+ opencode-worker run --dir ./task "Fix add() in calculator.py and run the tests"
26
+ opencode-worker run --dir ./task --timeout 1800 -f prompt.md --variant high
27
+ OPENCODE_WORKER_TIMEOUT_SEC=1800 opencode-worker run --dir ./task "…"
27
28
  ```
28
29
 
29
30
  Exit codes: `0` ok, `1` worker failed (timeout, nonzero exit, error event, model mismatch), `2` usage/setup error.
@@ -58,19 +59,21 @@ Recommended flow: `worker_start` → `worker_wait` (repeat while it returns `sta
58
59
  "opencode-worker": {
59
60
  "command": "npx",
60
61
  "args": ["-y", "opencode-worker", "mcp"],
61
- "env": { "OPENCODE_WORKER_BIN": "/path/to/opencode" }
62
+ "env": { "OPENCODE_WORKER_BIN": "/path/to/opencode", "OPENCODE_WORKER_TIMEOUT_SEC": "1800" }
62
63
  }
63
64
  }
64
65
  }
65
66
  ```
66
67
 
68
+ `OPENCODE_WORKER_TIMEOUT_SEC` is optional (default 900); it is the job limit, independent of the per-call `worker_wait` limit.
69
+
67
70
  ### Client setup
68
71
 
69
72
  Claude Code (tools must be allowed in `-p` mode; put the prompt right after `-p`, because `--allowedTools` and `--mcp-config` are variadic and swallow trailing arguments):
70
73
 
71
74
  ```sh
72
- claude mcp add opencode-worker -e OPENCODE_WORKER_BIN=/path/to/opencode -- npx -y opencode-worker mcp
73
- claude -p "…" --allowedTools "mcp__opencode-worker__worker_start,mcp__opencode-worker__worker_status,mcp__opencode-worker__worker_result"
75
+ claude mcp add opencode-worker -e OPENCODE_WORKER_BIN=/path/to/opencode -e OPENCODE_WORKER_TIMEOUT_SEC=1800 -- npx -y opencode-worker mcp
76
+ claude -p "…" --allowedTools "mcp__opencode-worker__worker_start,mcp__opencode-worker__worker_wait,mcp__opencode-worker__worker_status,mcp__opencode-worker__worker_result"
74
77
  ```
75
78
 
76
79
  Codex (`~/.codex/config.toml`); without the approval mode, `codex exec` rejects MCP calls under `approval: never`:
@@ -79,7 +82,7 @@ Codex (`~/.codex/config.toml`); without the approval mode, `codex exec` rejects
79
82
  [mcp_servers.opencode-worker]
80
83
  command = "npx"
81
84
  args = ["-y", "opencode-worker", "mcp"]
82
- env = { OPENCODE_WORKER_BIN = "/path/to/opencode" }
85
+ env = { OPENCODE_WORKER_BIN = "/path/to/opencode", OPENCODE_WORKER_TIMEOUT_SEC = "1800" }
83
86
  default_tools_approval_mode = "approve"
84
87
  ```
85
88
 
@@ -13,7 +13,7 @@ Options (run):
13
13
  --model <id> default ${DEFAULTS.model} (provider must be one of ${DEFAULTS.providers.join(",")})
14
14
  --variant <v> default ${DEFAULTS.variant}
15
15
  --agent <name> default ${DEFAULTS.agent}
16
- --timeout <sec> default ${DEFAULTS.timeoutSec}
16
+ --timeout <sec> default $OPENCODE_WORKER_TIMEOUT_SEC, else ${DEFAULTS.timeoutSec}
17
17
  --opencode-bin <path> default $OPENCODE_WORKER_BIN, then PATH
18
18
  -f, --prompt-file <f> Read prompt from file
19
19
 
package/lib/mcp.mjs CHANGED
@@ -45,7 +45,7 @@ const runSchema = {
45
45
  model: { type: "string", description: `default ${DEFAULTS.model}` },
46
46
  variant: { type: "string", description: `default ${DEFAULTS.variant}` },
47
47
  agent: { type: "string", description: `default ${DEFAULTS.agent}` },
48
- timeoutSec: { type: "number", description: `default ${DEFAULTS.timeoutSec}` },
48
+ timeoutSec: { type: "number", description: `Job time limit in seconds; omit to use the server default ($OPENCODE_WORKER_TIMEOUT_SEC, else ${DEFAULTS.timeoutSec})` },
49
49
  },
50
50
  required: ["dir", "prompt"],
51
51
  };
package/lib/worker.mjs CHANGED
@@ -7,7 +7,7 @@ export const DEFAULTS = {
7
7
  model: "opencode/deepseek-v4.1-flash-free",
8
8
  variant: "low",
9
9
  agent: "build",
10
- timeoutSec: 180,
10
+ timeoutSec: 900,
11
11
  providers: ["opencode"],
12
12
  };
13
13
  const STATE_DIR = ".opencode-worker";
@@ -132,6 +132,16 @@ function actualModels(stateRoot, sessionID) {
132
132
  });
133
133
  }
134
134
 
135
+ /** Job timeout default: OPENCODE_WORKER_TIMEOUT_SEC if set, else DEFAULTS.timeoutSec. */
136
+ export function defaultTimeoutSec() {
137
+ const raw = process.env.OPENCODE_WORKER_TIMEOUT_SEC;
138
+ if (raw === undefined) return DEFAULTS.timeoutSec;
139
+ const n = Number(raw);
140
+ if (raw.trim() === "" || !(Number.isFinite(n) && n > 0))
141
+ throw new WorkerError("BAD_CONFIG", `OPENCODE_WORKER_TIMEOUT_SEC must be a positive number of seconds, got '${raw}'`);
142
+ return n;
143
+ }
144
+
135
145
  /**
136
146
  * Run one OpenCode worker task.
137
147
  * @param {{dir:string,prompt:string,model?:string,variant?:string,agent?:string,timeoutSec?:number,opencodeBin?:string,signal?:AbortSignal}} o
@@ -143,7 +153,8 @@ export async function runWorker(o) {
143
153
  const model = o.model ?? DEFAULTS.model;
144
154
  const variant = o.variant ?? DEFAULTS.variant;
145
155
  const agent = o.agent ?? DEFAULTS.agent;
146
- const timeoutSec = o.timeoutSec ?? DEFAULTS.timeoutSec;
156
+ const timeoutSec = o.timeoutSec ?? defaultTimeoutSec();
157
+ if (!(Number.isFinite(timeoutSec) && timeoutSec > 0)) throw new WorkerError("BAD_ARGS", `timeoutSec must be a positive number, got ${o.timeoutSec}`);
147
158
  const provider = model.split("/")[0];
148
159
  if (!DEFAULTS.providers.includes(provider))
149
160
  throw new WorkerError("PROVIDER_NOT_ALLOWED", `provider '${provider}' not in ${JSON.stringify(DEFAULTS.providers)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-worker",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Run the official OpenCode CLI as an isolated, time-boxed worker. CLI + MCP stdio server.",
5
5
  "repository": {
6
6
  "type": "git",