From 810c0eba1a7348036f8bdf61e6632d0c36c6876c Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 28 Oct 2026 06:17:33 +0000 Subject: [PATCH 1/4] release: v1.19.5 --- bun.lock | 56 ++++++++++----------- packages/app/package.json | 2 +- packages/cli/package.json | 2 +- packages/codemode/package.json | 2 +- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/console/support/package.json | 2 +- packages/core/package.json | 2 +- packages/desktop/package.json | 2 +- packages/effect-drizzle-sqlite/package.json | 2 +- packages/effect-sqlite-node/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/function/package.json | 2 +- packages/http-recorder/package.json | 2 +- packages/llm/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/server/package.json | 2 +- packages/session-ui/package.json | 2 +- packages/slack/package.json | 2 +- packages/stats/app/package.json | 2 +- packages/stats/core/package.json | 2 +- packages/stats/server/package.json | 2 +- packages/tui/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 30 files changed, 57 insertions(+), 57 deletions(-) diff --git a/bun.lock b/bun.lock index 9dc3520f7a8a..45098943436d 100644 --- a/bun.lock +++ b/bun.lock @@ -29,7 +29,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@corvu/drawer": "catalog:", "@dnd-kit/abstract": "0.5.0", @@ -96,7 +96,7 @@ }, "packages/cli": { "name": "@opencode-ai/cli", - "version": "1.19.4", + "version": "1.19.5", "bin": { "lildax": "./bin/lildax.cjs", }, @@ -144,7 +144,7 @@ }, "packages/codemode": { "name": "@opencode-ai/codemode", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "acorn": "8.15.0", "effect": "catalog:", @@ -158,7 +158,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -195,7 +195,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -222,7 +222,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@ai-sdk/anthropic": "3.0.82", "@ai-sdk/openai": "3.0.48", @@ -245,7 +245,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -269,7 +269,7 @@ }, "packages/console/support": { "name": "@opencode-ai/console-support", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@opencode-ai/console-core": "workspace:*", @@ -289,7 +289,7 @@ }, "packages/core": { "name": "@opencode-ai/core", - "version": "1.19.4", + "version": "1.19.5", "bin": { "opencode": "./bin/opencode", }, @@ -384,7 +384,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@zip.js/zip.js": "2.7.62", "drizzle-orm": "catalog:", @@ -438,7 +438,7 @@ }, "packages/effect-drizzle-sqlite": { "name": "@opencode-ai/effect-drizzle-sqlite", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "drizzle-orm": "catalog:", "effect": "catalog:", @@ -452,7 +452,7 @@ }, "packages/effect-sqlite-node": { "name": "@opencode-ai/effect-sqlite-node", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "effect": "catalog:", }, @@ -464,7 +464,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@hono/standard-validator": "catalog:", "@opencode-ai/core": "workspace:*", @@ -496,7 +496,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -512,7 +512,7 @@ }, "packages/http-recorder": { "name": "@opencode-ai/http-recorder", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@effect/platform-node": "4.0.0-beta.83", "@effect/platform-node-shared": "4.0.0-beta.83", @@ -543,7 +543,7 @@ }, "packages/llm": { "name": "@opencode-ai/llm", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@opencode-ai/schema": "workspace:*", "@smithy/eventstream-codec": "4.2.14", @@ -562,7 +562,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.19.4", + "version": "1.19.5", "bin": { "opencode": "./bin/opencode", }, @@ -692,7 +692,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode-ai/sdk": "workspace:*", @@ -768,7 +768,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "cross-spawn": "catalog:", }, @@ -783,7 +783,7 @@ }, "packages/server": { "name": "@opencode-ai/server", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@opencode-ai/core": "workspace:*", "@opencode-ai/protocol": "workspace:*", @@ -798,7 +798,7 @@ }, "packages/session-ui": { "name": "@opencode-ai/session-ui", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz", @@ -838,7 +838,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -851,7 +851,7 @@ }, "packages/stats/app": { "name": "@opencode-ai/stats-app", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@ibm/plex": "6.4.1", "@kobalte/core": "catalog:", @@ -878,7 +878,7 @@ }, "packages/stats/core": { "name": "@opencode-ai/stats-core", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@planetscale/database": "1.19.0", "drizzle-orm": "catalog:", @@ -896,7 +896,7 @@ }, "packages/stats/server": { "name": "@opencode-ai/stats-server", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@effect/platform-node": "catalog:", "@opencode-ai/stats-core": "workspace:*", @@ -937,7 +937,7 @@ }, "packages/tui": { "name": "@opencode-ai/tui", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@opencode-ai/core": "workspace:*", "@opencode-ai/plugin": "workspace:*", @@ -963,7 +963,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@kobalte/core": "catalog:", "@pierre/diffs": "catalog:", @@ -1014,7 +1014,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/app/package.json b/packages/app/package.json index b4d0cf7318b9..4d82ca3cc8c8 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.19.4", + "version": "1.19.5", "description": "", "type": "module", "exports": { diff --git a/packages/cli/package.json b/packages/cli/package.json index 0b82144239e5..a95e969d5629 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/cli", - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "bin": { diff --git a/packages/codemode/package.json b/packages/codemode/package.json index cbfa3abe40f1..de91203432d1 100644 --- a/packages/codemode/package.json +++ b/packages/codemode/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/codemode", - "version": "1.19.4", + "version": "1.19.5", "description": "Effect-native confined code execution over schema-described tools", "private": true, "type": "module", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index b42879e863a1..31384ce953c8 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 5184b0531a5c..187bd3b75551 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 59213927c8f8..304dd296ec4d 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.19.4", + "version": "1.19.5", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 9e4a1be45185..1e8848b21436 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.19.4", + "version": "1.19.5", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/console/support/package.json b/packages/console/support/package.json index b31a9aa6d8eb..d3bcd328cf9c 100644 --- a/packages/console/support/package.json +++ b/packages/console/support/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-support", - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/core/package.json b/packages/core/package.json index 7a81417dc1be..28d896c5875c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.19.4", + "version": "1.19.5", "name": "@opencode-ai/core", "type": "module", "license": "MIT", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index be2abb261452..f44162e47e44 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/effect-drizzle-sqlite/package.json b/packages/effect-drizzle-sqlite/package.json index acbf37ba5604..1c5947f6fd01 100644 --- a/packages/effect-drizzle-sqlite/package.json +++ b/packages/effect-drizzle-sqlite/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.19.4", + "version": "1.19.5", "name": "@opencode-ai/effect-drizzle-sqlite", "type": "module", "license": "MIT", diff --git a/packages/effect-sqlite-node/package.json b/packages/effect-sqlite-node/package.json index daab30a5b2bf..f09c38d369ac 100644 --- a/packages/effect-sqlite-node/package.json +++ b/packages/effect-sqlite-node/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.19.4", + "version": "1.19.5", "name": "@opencode-ai/effect-sqlite-node", "type": "module", "license": "MIT", diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 2a03aae74ddb..0d79b3a00c26 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/function/package.json b/packages/function/package.json index 945307bca668..6d53b7ea3964 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.19.4", + "version": "1.19.5", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/http-recorder/package.json b/packages/http-recorder/package.json index 7e9297e59cef..f004531a6afe 100644 --- a/packages/http-recorder/package.json +++ b/packages/http-recorder/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.19.4", + "version": "1.19.5", "name": "@opencode-ai/http-recorder", "description": "Record and replay Effect HTTP client traffic with deterministic cassettes", "type": "module", diff --git a/packages/llm/package.json b/packages/llm/package.json index 18c3c2d99d05..ec51ca5fed6c 100644 --- a/packages/llm/package.json +++ b/packages/llm/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.19.4", + "version": "1.19.5", "name": "@opencode-ai/llm", "type": "module", "license": "MIT", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 56074f1d76b0..f7acdb6d8465 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.19.4", + "version": "1.19.5", "name": "opencode", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 38933b5bdaa9..5b17c2ecd748 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index ba9454f44ad2..2934585388e4 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 4426fac017a9..584085d6b56f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/server", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/session-ui/package.json b/packages/session-ui/package.json index 1bbb1a3a0e62..68f72c921ef1 100644 --- a/packages/session-ui/package.json +++ b/packages/session-ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/session-ui", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/slack/package.json b/packages/slack/package.json index 1130de9582f2..a3bad906568f 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/stats/app/package.json b/packages/stats/app/package.json index 59a7cb8507e2..4d4800bf0f08 100644 --- a/packages/stats/app/package.json +++ b/packages/stats/app/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/stats-app", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/stats/core/package.json b/packages/stats/core/package.json index fcb2a53ca783..a012eb940839 100644 --- a/packages/stats/core/package.json +++ b/packages/stats/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/stats-core", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/stats/server/package.json b/packages/stats/server/package.json index 96c1c6fd7e9a..454cb2f660c3 100644 --- a/packages/stats/server/package.json +++ b/packages/stats/server/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/stats-server", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/tui/package.json b/packages/tui/package.json index 5d49be09eeb6..d2f5915d36eb 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/tui", - "version": "1.19.4", + "version": "1.19.5", "private": true, "type": "module", "license": "MIT", diff --git a/packages/ui/package.json b/packages/ui/package.json index 273659bd011e..575b35f3163e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.19.4", + "version": "1.19.5", "type": "module", "license": "MIT", "repository": { diff --git a/packages/web/package.json b/packages/web/package.json index e2ed9f6484f6..d915afbaa09f 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -2,7 +2,7 @@ "name": "@opencode-ai/web", "type": "module", "license": "MIT", - "version": "1.19.4", + "version": "1.19.5", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 92c689628a4e..e2dae344f4e1 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.19.4", + "version": "1.19.5", "publisher": "sst-dev", "repository": { "type": "git", From e2302dba8d0d4931a3b6592d0fe48f28a7978931 Mon Sep 17 00:00:00 2001 From: KalininVD <76688980+KalininVD@users.noreply.github.com> Date: Wed, 28 Oct 2026 18:19:08 +0300 Subject: [PATCH 2/4] test(opencode): reproduce shell signal termination timeout Exercise SIGTERM, SIGSEGV and SIGKILL with real shell processes, preserving stdout/stderr and requiring a result before the command timeout. These regression tests currently fail because signal exits are ignored by the success-only race. --- packages/opencode/test/tool/shell.test.ts | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/opencode/test/tool/shell.test.ts b/packages/opencode/test/tool/shell.test.ts index 02c31ad81531..66c65a3034dd 100644 --- a/packages/opencode/test/tool/shell.test.ts +++ b/packages/opencode/test/tool/shell.test.ts @@ -1092,6 +1092,33 @@ describe("tool.shell abort", () => { ) } + if (process.platform !== "win32") { + for (const signal of ["TERM", "SEGV", "KILL"]) { + it.live(`reports SIG${signal} without waiting for the command timeout`, () => + runIn( + projectRoot, + Effect.gen(function* () { + const result = yield* run({ + command: `ulimit -c 0; printf 'before-stdout\\n'; printf 'before-stderr\\n' >&2; kill -${signal} $$`, + timeout: 10_000, + }).pipe( + Effect.timeoutOrElse({ + duration: "3 seconds", + orElse: () => Effect.die(new Error("Signal termination was not reported promptly")), + }), + ) + expect(result.output).toContain("before-stdout") + expect(result.output).toContain("before-stderr") + expect(result.output).toContain(`SIG${signal}`) + expect(result.output).not.toContain("exceeding timeout") + expect(result.output).not.toContain("User aborted") + expect(result.metadata.exit).toBeNull() + }), + ), + ) + } + } + it.live("returns non-zero exit code", () => runIn( projectRoot, From 1ff1293c7a720231fd37b86b632d279b4f5417cf Mon Sep 17 00:00:00 2001 From: KalininVD <76688980+KalininVD@users.noreply.github.com> Date: Wed, 28 Oct 2026 18:24:55 +0300 Subject: [PATCH 3/4] fix(opencode): report shell signal exits without waiting for timeout Treat a failed exitCode effect as a terminal outcome before racing it against timeout and cancellation. Preserve captured output and the termination cause instead of trying to kill an already-exited process. Add a subprocess CLI regression proving that JSON tool output contains the signal and the session can continue. Fixes anomalyco/opencode#59925. --- packages/opencode/src/tool/shell.ts | 30 +++++++------ .../opencode/test/cli/run/run-process.test.ts | 44 +++++++++++++++++++ 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/packages/opencode/src/tool/shell.ts b/packages/opencode/src/tool/shell.ts index 1e4423e01774..7be55168c7b1 100644 --- a/packages/opencode/src/tool/shell.ts +++ b/packages/opencode/src/tool/shell.ts @@ -444,8 +444,6 @@ export const ShellTool = Tool.define( let file = "" let sink: ReturnType | undefined let cut = false - let expired = false - let aborted = false const closeSink = Effect.fnUntraced(function* () { const stream = sink @@ -478,7 +476,7 @@ export const ShellTool = Tool.define( }, }) - const code: number | null = yield* Effect.scoped( + const exit = yield* Effect.scoped( Effect.gen(function* () { yield* Effect.addFinalizer(closeSink) const handle = yield* spawner.spawn(cmd(input.shell, input.command, input.cwd, input.env)) @@ -540,31 +538,35 @@ export const ShellTool = Tool.define( const timeout = Effect.sleep(`${input.timeout + 100} millis`) const exit = yield* Effect.raceAll([ - handle.exitCode.pipe(Effect.map((code) => ({ kind: "exit" as const, code }))), + // Signal termination fails exitCode; raceAll only settles on success. + handle.exitCode.pipe( + Effect.match({ + onSuccess: (code: number) => ({ kind: "exit" as const, code }), + onFailure: (error) => ({ kind: "error" as const, code: null, error }), + }), + ), abort.pipe(Effect.map(() => ({ kind: "abort" as const, code: null }))), timeout.pipe(Effect.map(() => ({ kind: "timeout" as const, code: null }))), ]) - if (exit.kind === "abort") { - aborted = true - yield* handle.kill({ forceKillAfter: "3 seconds" }).pipe(Effect.orDie) - } - if (exit.kind === "timeout") { - expired = true + if (exit.kind === "abort" || exit.kind === "timeout") { yield* handle.kill({ forceKillAfter: "3 seconds" }).pipe(Effect.orDie) } - return exit.kind === "exit" ? exit.code : null + return exit }), ).pipe(Effect.orDie) const meta: string[] = [] - if (expired) { + if (exit.kind === "timeout") { meta.push( `shell tool terminated command after exceeding timeout ${input.timeout} ms. If this command is expected to take longer and is not waiting for interactive input, retry with a larger timeout value in milliseconds.`, ) } - if (aborted) meta.push("User aborted the command") + if (exit.kind === "abort") meta.push("User aborted the command") + if (exit.kind === "error") { + meta.push(exit.error.cause instanceof Error ? exit.error.cause.message : exit.error.message) + } const raw = list.map((item) => item.text).join("") const end = tail(raw, limits.maxLines, limits.maxBytes) if (end.cut) cut = true @@ -586,7 +588,7 @@ export const ShellTool = Tool.define( title: input.command, metadata: { output: last || preview(output), - exit: code, + exit: exit.code, truncated: cut, ...(cut && file ? { outputPath: file } : {}), }, diff --git a/packages/opencode/test/cli/run/run-process.test.ts b/packages/opencode/test/cli/run/run-process.test.ts index c6ccdc80cd41..b05dd754da20 100644 --- a/packages/opencode/test/cli/run/run-process.test.ts +++ b/packages/opencode/test/cli/run/run-process.test.ts @@ -214,6 +214,50 @@ describe("opencode run (non-interactive subprocess)", () => { 60_000, ) + if (process.platform !== "win32") { + cliIt.live( + "--format json preserves signal termination output and continues", + ({ llm, opencode }) => + Effect.gen(function* () { + yield* llm.push( + reply().tool("bash", { + command: "printf 'before-signal\\n'; kill -TERM $$", + description: "Terminate the tool shell with SIGTERM", + timeout: 10_000, + }), + ) + yield* llm.text("continued after signal") + + const result = yield* opencode.run("exercise signal termination", { + format: "json", + permission: { bash: "allow" }, + }) + + opencode.expectExit(result, 0) + const events = opencode.parseJsonEvents(result.stdout) + expect(events.find((event) => event.type === "tool_use")?.part).toEqual( + expect.objectContaining({ + tool: "bash", + state: expect.objectContaining({ + status: "completed", + output: expect.stringContaining("before-signal"), + metadata: expect.objectContaining({ exit: null }), + }), + }), + ) + expect(events.find((event) => event.type === "tool_use")?.part).toEqual( + expect.objectContaining({ + state: expect.objectContaining({ output: expect.stringContaining("SIGTERM") }), + }), + ) + expect(result.stdout).toContain("continued after signal") + expect(result.stdout).not.toContain("ChildProcess.kill") + expect(result.stdout).not.toContain("exceeding timeout") + }), + 60_000, + ) + } + cliIt.concurrent( "--format json records an unknown stream finish and continuation", ({ llm, opencode }) => From 61965f5c8b8d134c88e52493bcaf1cfc10776f7d Mon Sep 17 00:00:00 2001 From: KalininVD <76688980+KalininVD@users.noreply.github.com> Date: Wed, 28 Oct 2026 19:12:27 +0300 Subject: [PATCH 4/4] fix(opencode): include shell signals in TUI output --- packages/opencode/src/tool/shell.ts | 2 +- .../opencode/test/cli/run/run-process.test.ts | 23 +++++++------------ packages/opencode/test/tool/shell.test.ts | 1 + 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/opencode/src/tool/shell.ts b/packages/opencode/src/tool/shell.ts index 7be55168c7b1..1674695938ae 100644 --- a/packages/opencode/src/tool/shell.ts +++ b/packages/opencode/src/tool/shell.ts @@ -587,7 +587,7 @@ export const ShellTool = Tool.define( return { title: input.command, metadata: { - output: last || preview(output), + output: exit.kind === "error" ? preview(output) : last || preview(output), exit: exit.code, truncated: cut, ...(cut && file ? { outputPath: file } : {}), diff --git a/packages/opencode/test/cli/run/run-process.test.ts b/packages/opencode/test/cli/run/run-process.test.ts index b05dd754da20..fdb8ad5ed166 100644 --- a/packages/opencode/test/cli/run/run-process.test.ts +++ b/packages/opencode/test/cli/run/run-process.test.ts @@ -235,21 +235,14 @@ describe("opencode run (non-interactive subprocess)", () => { opencode.expectExit(result, 0) const events = opencode.parseJsonEvents(result.stdout) - expect(events.find((event) => event.type === "tool_use")?.part).toEqual( - expect.objectContaining({ - tool: "bash", - state: expect.objectContaining({ - status: "completed", - output: expect.stringContaining("before-signal"), - metadata: expect.objectContaining({ exit: null }), - }), - }), - ) - expect(events.find((event) => event.type === "tool_use")?.part).toEqual( - expect.objectContaining({ - state: expect.objectContaining({ output: expect.stringContaining("SIGTERM") }), - }), - ) + expect(events.find((event) => event.type === "tool_use")?.part).toMatchObject({ + tool: "bash", + state: { + status: "completed", + output: expect.stringMatching(/before-signal[\s\S]*SIGTERM/), + metadata: { exit: null, output: expect.stringContaining("SIGTERM") }, + }, + }) expect(result.stdout).toContain("continued after signal") expect(result.stdout).not.toContain("ChildProcess.kill") expect(result.stdout).not.toContain("exceeding timeout") diff --git a/packages/opencode/test/tool/shell.test.ts b/packages/opencode/test/tool/shell.test.ts index 66c65a3034dd..951de1ec88ee 100644 --- a/packages/opencode/test/tool/shell.test.ts +++ b/packages/opencode/test/tool/shell.test.ts @@ -1110,6 +1110,7 @@ describe("tool.shell abort", () => { expect(result.output).toContain("before-stdout") expect(result.output).toContain("before-stderr") expect(result.output).toContain(`SIG${signal}`) + expect(result.metadata.output).toBe(result.output) expect(result.output).not.toContain("exceeding timeout") expect(result.output).not.toContain("User aborted") expect(result.metadata.exit).toBeNull()