summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2026-04-25 14:22:49 -0400
committerDax Raad <[email protected]>2026-04-25 14:23:17 -0400
commit3eee2f6afa5c7fde20d0e838143832b681795d9f (patch)
treee2ee4385e034a921504e782eba5cfb2822879b4b /packages
parentff4b60e1f3d2ad83a74785443dd041ed4e7814bf (diff)
downloadopencode-3eee2f6afa5c7fde20d0e838143832b681795d9f.tar.gz
opencode-3eee2f6afa5c7fde20d0e838143832b681795d9f.zip
core: move cross-spawn-spawner from opencode to core package
Moved the cross-spawn-spawner module from packages/opencode to packages/core to enable code sharing across the monorepo. This consolidates the process spawning infrastructure into the core package so other packages can use cross-platform child process spawning without duplicating the implementation. Updated all import statements across the codebase to reference the new location (@opencode-ai/core/effect/cross-spawn-spawner). Removed the local copy from the opencode package along with its tests.
Diffstat (limited to 'packages')
-rw-r--r--packages/core/package.json6
-rw-r--r--packages/core/src/effect/cross-spawn-spawner.ts (renamed from packages/opencode/src/effect/cross-spawn-spawner.ts)0
-rw-r--r--packages/core/test/effect/cross-spawn-spawner.test.ts (renamed from packages/opencode/test/effect/cross-spawn-spawner.test.ts)18
-rw-r--r--packages/opencode/src/file/ripgrep.ts2
-rw-r--r--packages/opencode/src/format/index.ts2
-rw-r--r--packages/opencode/src/git/index.ts2
-rw-r--r--packages/opencode/src/installation/index.ts2
-rw-r--r--packages/opencode/src/mcp/index.ts2
-rw-r--r--packages/opencode/src/npm/index.ts2
-rw-r--r--packages/opencode/src/project/project.ts2
-rw-r--r--packages/opencode/src/session/prompt.ts2
-rw-r--r--packages/opencode/src/snapshot/index.ts2
-rw-r--r--packages/opencode/src/tool/registry.ts2
-rw-r--r--packages/opencode/src/worktree/index.ts2
-rw-r--r--packages/opencode/test/auth/auth.test.ts2
-rw-r--r--packages/opencode/test/bus/bus-effect.test.ts2
-rw-r--r--packages/opencode/test/config/config.test.ts2
-rw-r--r--packages/opencode/test/format/format.test.ts2
-rw-r--r--packages/opencode/test/lsp/index.test.ts2
-rw-r--r--packages/opencode/test/lsp/lifecycle.test.ts2
-rw-r--r--packages/opencode/test/permission/next.test.ts2
-rw-r--r--packages/opencode/test/project/project.test.ts2
-rw-r--r--packages/opencode/test/project/worktree-remove.test.ts2
-rw-r--r--packages/opencode/test/project/worktree.test.ts2
-rw-r--r--packages/opencode/test/session/compaction.test.ts2
-rw-r--r--packages/opencode/test/session/processor-effect.test.ts2
-rw-r--r--packages/opencode/test/session/prompt.test.ts2
-rw-r--r--packages/opencode/test/session/revert-compact.test.ts2
-rw-r--r--packages/opencode/test/session/snapshot-tool-race.test.ts2
-rw-r--r--packages/opencode/test/share/share-next.test.ts2
-rw-r--r--packages/opencode/test/skill/skill.test.ts2
-rw-r--r--packages/opencode/test/storage/storage.test.ts2
-rw-r--r--packages/opencode/test/tool/bash.test.ts2
-rw-r--r--packages/opencode/test/tool/glob.test.ts2
-rw-r--r--packages/opencode/test/tool/grep.test.ts2
-rw-r--r--packages/opencode/test/tool/lsp.test.ts2
-rw-r--r--packages/opencode/test/tool/question.test.ts2
-rw-r--r--packages/opencode/test/tool/read.test.ts2
-rw-r--r--packages/opencode/test/tool/registry.test.ts2
-rw-r--r--packages/opencode/test/tool/skill.test.ts2
-rw-r--r--packages/opencode/test/tool/task.test.ts2
-rw-r--r--packages/opencode/test/tool/write.test.ts2
42 files changed, 55 insertions, 47 deletions
diff --git a/packages/core/package.json b/packages/core/package.json
index a244ea8b4..bd826de35 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -18,23 +18,21 @@
"imports": {},
"devDependencies": {
"@tsconfig/bun": "catalog:",
- "@types/semver": "catalog:",
"@types/bun": "catalog:",
- "@types/npmcli__arborist": "6.3.3"
+ "@types/cross-spawn": "catalog:"
},
"dependencies": {
"@effect/opentelemetry": "catalog:",
"@effect/platform-node": "catalog:",
- "@npmcli/arborist": "catalog:",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1",
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
"@opentelemetry/sdk-trace-base": "2.6.1",
"effect": "catalog:",
+ "cross-spawn": "catalog:",
"glob": "13.0.5",
"mime-types": "3.0.2",
"minimatch": "10.2.5",
- "semver": "catalog:",
"xdg-basedir": "5.1.0",
"zod": "catalog:"
},
diff --git a/packages/opencode/src/effect/cross-spawn-spawner.ts b/packages/core/src/effect/cross-spawn-spawner.ts
index ad8d4126d..ad8d4126d 100644
--- a/packages/opencode/src/effect/cross-spawn-spawner.ts
+++ b/packages/core/src/effect/cross-spawn-spawner.ts
diff --git a/packages/opencode/test/effect/cross-spawn-spawner.test.ts b/packages/core/test/effect/cross-spawn-spawner.test.ts
index b4e52529c..d53725797 100644
--- a/packages/opencode/test/effect/cross-spawn-spawner.test.ts
+++ b/packages/core/test/effect/cross-spawn-spawner.test.ts
@@ -1,11 +1,11 @@
import { describe, expect } from "bun:test"
import fs from "node:fs/promises"
+import os from "node:os"
import path from "node:path"
import { Effect, Exit, Stream } from "effect"
import type * as PlatformError from "effect/PlatformError"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
-import { tmpdir } from "../fixture/fixture"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { testEffect } from "../lib/effect"
const live = CrossSpawnSpawner.defaultLayer
@@ -39,11 +39,21 @@ function alive(pid: number) {
}
}
+async function tmpdir() {
+ const dir = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-core-test-"))
+ return {
+ path: dir,
+ async [Symbol.asyncDispose]() {
+ await fs.rm(dir, { recursive: true, force: true })
+ },
+ }
+}
+
async function gone(pid: number, timeout = 5_000) {
const end = Date.now() + timeout
while (Date.now() < end) {
if (!alive(pid)) return true
- await Bun.sleep(50)
+ await new Promise((resolve) => setTimeout(resolve, 50))
}
return !alive(pid)
}
@@ -395,7 +405,7 @@ describe("cross-spawn spawner", () => {
const file = path.join(dir, "echo cmd.cmd")
yield* Effect.promise(() => fs.mkdir(dir, { recursive: true }))
- yield* Effect.promise(() => Bun.write(file, "@echo off\r\nif %~1==--stdio exit /b 0\r\nexit /b 7\r\n"))
+ yield* Effect.promise(() => fs.writeFile(file, "@echo off\r\nif %~1==--stdio exit /b 0\r\nexit /b 7\r\n"))
const code = yield* ChildProcessSpawner.ChildProcessSpawner.use((svc) =>
svc.exitCode(
diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts
index ab725b731..dd794ef6f 100644
--- a/packages/opencode/src/file/ripgrep.ts
+++ b/packages/opencode/src/file/ripgrep.ts
@@ -6,7 +6,7 @@ import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/
import { ChildProcess } from "effect/unstable/process"
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Global } from "@opencode-ai/core/global"
import { Log } from "@/util"
import { sanitizedProcessEnv } from "@opencode-ai/core/util/opencode-process"
diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts
index 4284a2cf6..2c5943c7d 100644
--- a/packages/opencode/src/format/index.ts
+++ b/packages/opencode/src/format/index.ts
@@ -1,6 +1,6 @@
import { Effect, Layer, Context, Schema } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { InstanceState } from "@/effect"
import path from "path"
import { mergeDeep } from "remeda"
diff --git a/packages/opencode/src/git/index.ts b/packages/opencode/src/git/index.ts
index 719b5607f..d2e04910a 100644
--- a/packages/opencode/src/git/index.ts
+++ b/packages/opencode/src/git/index.ts
@@ -1,4 +1,4 @@
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Effect, Layer, Context, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts
index 1a39d3c61..55c4092e2 100644
--- a/packages/opencode/src/installation/index.ts
+++ b/packages/opencode/src/installation/index.ts
@@ -1,6 +1,6 @@
import { Effect, Layer, Schema, Context, Stream } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { withTransientReadRetry } from "@/util/effect-http-client"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import path from "path"
diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts
index 23862db63..9652a1258 100644
--- a/packages/opencode/src/mcp/index.ts
+++ b/packages/opencode/src/mcp/index.ts
@@ -29,7 +29,7 @@ import { Effect, Exit, Layer, Option, Context, Schema, Stream } from "effect"
import { EffectBridge } from "@/effect"
import { InstanceState } from "@/effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { zod as effectZod } from "@/util/effect-zod"
import { withStatics } from "@/util/schema"
diff --git a/packages/opencode/src/npm/index.ts b/packages/opencode/src/npm/index.ts
index ca67491d0..23368b29b 100644
--- a/packages/opencode/src/npm/index.ts
+++ b/packages/opencode/src/npm/index.ts
@@ -14,7 +14,7 @@ import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
-import * as CrossSpawnSpawner from "../effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
export class InstallFailedError extends Schema.TaggedErrorClass<InstallFailedError>()("NpmInstallFailedError", {
add: Schema.Array(Schema.String).pipe(Schema.optional),
diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts
index e622464b4..c437fedb2 100644
--- a/packages/opencode/src/project/project.ts
+++ b/packages/opencode/src/project/project.ts
@@ -12,7 +12,7 @@ import { Effect, Layer, Path, Scope, Context, Stream, Types, Schema } from "effe
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { NodePath } from "@effect/platform-node"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { zod } from "@/util/effect-zod"
import { withStatics } from "@/util/schema"
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index 708961168..87f914a80 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -27,7 +27,7 @@ import { LSP } from "../lsp"
import { Flag } from "@opencode-ai/core/flag/flag"
import { ulid } from "ulid"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import * as Stream from "effect/Stream"
import { Command } from "../command"
import { pathToFileURL, fileURLToPath } from "url"
diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts
index 3701b8210..32d65633c 100644
--- a/packages/opencode/src/snapshot/index.ts
+++ b/packages/opencode/src/snapshot/index.ts
@@ -3,7 +3,7 @@ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { formatPatch, structuredPatch } from "diff"
import path from "path"
import z from "zod"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { InstanceState } from "@/effect"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Hash } from "@opencode-ai/core/util/hash"
diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts
index b7fa696c8..422fd8e3a 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -34,7 +34,7 @@ import { pathToFileURL } from "url"
import { Effect, Layer, Context } from "effect"
import { FetchHttpClient, HttpClient } from "effect/unstable/http"
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Ripgrep } from "../file/ripgrep"
import { Format } from "../format"
import { InstanceState } from "@/effect"
diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts
index b89ac32a9..f39d9ad04 100644
--- a/packages/opencode/src/worktree/index.ts
+++ b/packages/opencode/src/worktree/index.ts
@@ -18,7 +18,7 @@ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { NodePath } from "@effect/platform-node"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { BootstrapRuntime } from "@/effect/bootstrap-runtime"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { InstanceState } from "@/effect"
const log = Log.create({ service: "worktree" })
diff --git a/packages/opencode/test/auth/auth.test.ts b/packages/opencode/test/auth/auth.test.ts
index 864649d7a..8688eafaf 100644
--- a/packages/opencode/test/auth/auth.test.ts
+++ b/packages/opencode/test/auth/auth.test.ts
@@ -1,7 +1,7 @@
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { Auth } from "../../src/auth"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/bus/bus-effect.test.ts b/packages/opencode/test/bus/bus-effect.test.ts
index 3d602ae6f..d8b4a275b 100644
--- a/packages/opencode/test/bus/bus-effect.test.ts
+++ b/packages/opencode/test/bus/bus-effect.test.ts
@@ -3,7 +3,7 @@ import { Deferred, Effect, Layer, Schema, Stream } from "effect"
import { Bus } from "../../src/bus"
import { BusEvent } from "../../src/bus/bus-event"
import { Instance } from "../../src/project/instance"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts
index 8512236a3..bdd361e7a 100644
--- a/packages/opencode/test/config/config.test.ts
+++ b/packages/opencode/test/config/config.test.ts
@@ -13,7 +13,7 @@ import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Env } from "../../src/env"
import { provideTmpdirInstance } from "../fixture/fixture"
import { tmpdir } from "../fixture/fixture"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { testEffect } from "../lib/effect"
/** Infra layer that provides FileSystem, Path, ChildProcessSpawner for test fixtures */
diff --git a/packages/opencode/test/format/format.test.ts b/packages/opencode/test/format/format.test.ts
index 2f6f235aa..544359c60 100644
--- a/packages/opencode/test/format/format.test.ts
+++ b/packages/opencode/test/format/format.test.ts
@@ -3,7 +3,7 @@ import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Format } from "../../src/format"
import * as Formatter from "../../src/format/formatter"
diff --git a/packages/opencode/test/lsp/index.test.ts b/packages/opencode/test/lsp/index.test.ts
index d138f56e3..8cb098826 100644
--- a/packages/opencode/test/lsp/index.test.ts
+++ b/packages/opencode/test/lsp/index.test.ts
@@ -3,7 +3,7 @@ import path from "path"
import { Effect, Layer } from "effect"
import { LSP } from "../../src/lsp"
import { LSPServer } from "../../src/lsp"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/lsp/lifecycle.test.ts b/packages/opencode/test/lsp/lifecycle.test.ts
index 13f21c93c..98ac600f4 100644
--- a/packages/opencode/test/lsp/lifecycle.test.ts
+++ b/packages/opencode/test/lsp/lifecycle.test.ts
@@ -3,7 +3,7 @@ import path from "path"
import { Effect, Layer } from "effect"
import { LSP } from "../../src/lsp"
import { LSPServer } from "../../src/lsp"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/permission/next.test.ts b/packages/opencode/test/permission/next.test.ts
index b58c716d8..80601cd9a 100644
--- a/packages/opencode/test/permission/next.test.ts
+++ b/packages/opencode/test/permission/next.test.ts
@@ -2,7 +2,7 @@ import { afterEach, test, expect } from "bun:test"
import os from "os"
import { Cause, Effect, Exit, Fiber, Layer } from "effect"
import { Bus } from "../../src/bus"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Permission } from "../../src/permission"
import { PermissionID } from "../../src/permission/schema"
import { Instance } from "../../src/project/instance"
diff --git a/packages/opencode/test/project/project.test.ts b/packages/opencode/test/project/project.test.ts
index c61df3548..6579b414f 100644
--- a/packages/opencode/test/project/project.test.ts
+++ b/packages/opencode/test/project/project.test.ts
@@ -10,7 +10,7 @@ import { Effect, Layer, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { NodePath } from "@effect/platform-node"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
void Log.init({ print: false })
diff --git a/packages/opencode/test/project/worktree-remove.test.ts b/packages/opencode/test/project/worktree-remove.test.ts
index 5fb2beb28..b0cb626b1 100644
--- a/packages/opencode/test/project/worktree-remove.test.ts
+++ b/packages/opencode/test/project/worktree-remove.test.ts
@@ -3,7 +3,7 @@ import { describe, expect } from "bun:test"
import * as fs from "fs/promises"
import path from "path"
import { Effect, Layer } from "effect"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Worktree } from "../../src/worktree"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/project/worktree.test.ts b/packages/opencode/test/project/worktree.test.ts
index c0fe63551..b20914c96 100644
--- a/packages/opencode/test/project/worktree.test.ts
+++ b/packages/opencode/test/project/worktree.test.ts
@@ -3,7 +3,7 @@ import { afterEach, describe, expect } from "bun:test"
import * as fs from "fs/promises"
import path from "path"
import { Cause, Effect, Exit, Layer } from "effect"
-import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Instance } from "../../src/project/instance"
import { Worktree } from "../../src/worktree"
import { provideInstance, provideTmpdirInstance } from "../fixture/fixture"
diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts
index 4fe9c1551..79bdfe41f 100644
--- a/packages/opencode/test/session/compaction.test.ts
+++ b/packages/opencode/test/session/compaction.test.ts
@@ -25,7 +25,7 @@ import * as SessionProcessorModule from "../../src/session/processor"
import { Snapshot } from "../../src/snapshot"
import { ProviderTest } from "../fake/provider"
import { testEffect } from "../lib/effect"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
void Log.init({ print: false })
diff --git a/packages/opencode/test/session/processor-effect.test.ts b/packages/opencode/test/session/processor-effect.test.ts
index 74ce91307..d665022fd 100644
--- a/packages/opencode/test/session/processor-effect.test.ts
+++ b/packages/opencode/test/session/processor-effect.test.ts
@@ -19,7 +19,7 @@ import { SessionStatus } from "../../src/session/status"
import { SessionSummary } from "../../src/session/summary"
import { Snapshot } from "../../src/snapshot"
import { Log } from "../../src/util"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideTmpdirServer } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
import { raw, reply, TestLLMServer } from "../lib/llm-server"
diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts
index 451f1d004..288ca8f99 100644
--- a/packages/opencode/test/session/prompt.test.ts
+++ b/packages/opencode/test/session/prompt.test.ts
@@ -38,7 +38,7 @@ import { Snapshot } from "../../src/snapshot"
import { ToolRegistry } from "../../src/tool"
import { Truncate } from "../../src/tool"
import { Log } from "../../src/util"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Ripgrep } from "../../src/file/ripgrep"
import { Format } from "../../src/format"
import { provideTmpdirInstance, provideTmpdirServer } from "../fixture/fixture"
diff --git a/packages/opencode/test/session/revert-compact.test.ts b/packages/opencode/test/session/revert-compact.test.ts
index f28fb94c0..213e59632 100644
--- a/packages/opencode/test/session/revert-compact.test.ts
+++ b/packages/opencode/test/session/revert-compact.test.ts
@@ -9,7 +9,7 @@ import { MessageV2 } from "../../src/session/message-v2"
import { Snapshot } from "../../src/snapshot"
import { Log } from "../../src/util"
import { MessageID, PartID, SessionID } from "../../src/session/schema"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/session/snapshot-tool-race.test.ts b/packages/opencode/test/session/snapshot-tool-race.test.ts
index c7e352262..8c8c4da3b 100644
--- a/packages/opencode/test/session/snapshot-tool-race.test.ts
+++ b/packages/opencode/test/session/snapshot-tool-race.test.ts
@@ -52,7 +52,7 @@ import { Snapshot } from "../../src/snapshot"
import { ToolRegistry } from "../../src/tool"
import { Truncate } from "../../src/tool"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Ripgrep } from "../../src/file/ripgrep"
import { Format } from "../../src/format"
diff --git a/packages/opencode/test/share/share-next.test.ts b/packages/opencode/test/share/share-next.test.ts
index e217300d0..41763fe97 100644
--- a/packages/opencode/test/share/share-next.test.ts
+++ b/packages/opencode/test/share/share-next.test.ts
@@ -6,7 +6,7 @@ import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstab
import { AccessToken, AccountID, OrgID, RefreshToken } from "../../src/account/schema"
import { Account } from "../../src/account/account"
import { AccountRepo } from "../../src/account/repo"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Bus } from "../../src/bus"
import { Config } from "../../src/config"
import { Provider } from "../../src/provider"
diff --git a/packages/opencode/test/skill/skill.test.ts b/packages/opencode/test/skill/skill.test.ts
index 21c6c7e65..13f25be5b 100644
--- a/packages/opencode/test/skill/skill.test.ts
+++ b/packages/opencode/test/skill/skill.test.ts
@@ -1,7 +1,7 @@
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { Skill } from "../../src/skill"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideInstance, provideTmpdirInstance, tmpdir } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
import path from "path"
diff --git a/packages/opencode/test/storage/storage.test.ts b/packages/opencode/test/storage/storage.test.ts
index 6be653ecb..f1b245f9b 100644
--- a/packages/opencode/test/storage/storage.test.ts
+++ b/packages/opencode/test/storage/storage.test.ts
@@ -2,7 +2,7 @@ import { describe, expect } from "bun:test"
import path from "path"
import { Effect, Exit, Layer } from "effect"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Git } from "../../src/git"
import { Global } from "@opencode-ai/core/global"
import { Storage } from "../../src/storage"
diff --git a/packages/opencode/test/tool/bash.test.ts b/packages/opencode/test/tool/bash.test.ts
index fd35c9aeb..23f18f989 100644
--- a/packages/opencode/test/tool/bash.test.ts
+++ b/packages/opencode/test/tool/bash.test.ts
@@ -11,7 +11,7 @@ import type { Permission } from "../../src/permission"
import { Agent } from "../../src/agent/agent"
import { Truncate } from "../../src/tool"
import { SessionID, MessageID } from "../../src/session/schema"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Plugin } from "../../src/plugin"
diff --git a/packages/opencode/test/tool/glob.test.ts b/packages/opencode/test/tool/glob.test.ts
index c37e7b35f..8d496509a 100644
--- a/packages/opencode/test/tool/glob.test.ts
+++ b/packages/opencode/test/tool/glob.test.ts
@@ -3,7 +3,7 @@ import path from "path"
import { Cause, Effect, Exit, Layer } from "effect"
import { GlobTool } from "../../src/tool/glob"
import { SessionID, MessageID } from "../../src/session/schema"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Ripgrep } from "../../src/file/ripgrep"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Truncate } from "../../src/tool"
diff --git a/packages/opencode/test/tool/grep.test.ts b/packages/opencode/test/tool/grep.test.ts
index a279574e1..3e147dddc 100644
--- a/packages/opencode/test/tool/grep.test.ts
+++ b/packages/opencode/test/tool/grep.test.ts
@@ -4,7 +4,7 @@ import { Effect, Layer } from "effect"
import { GrepTool } from "../../src/tool/grep"
import { provideInstance, provideTmpdirInstance } from "../fixture/fixture"
import { SessionID, MessageID } from "../../src/session/schema"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Truncate } from "../../src/tool"
import { Agent } from "../../src/agent/agent"
import { Ripgrep } from "../../src/file/ripgrep"
diff --git a/packages/opencode/test/tool/lsp.test.ts b/packages/opencode/test/tool/lsp.test.ts
index b9d48e69a..07de4a0da 100644
--- a/packages/opencode/test/tool/lsp.test.ts
+++ b/packages/opencode/test/tool/lsp.test.ts
@@ -2,7 +2,7 @@ import { afterEach, describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import path from "path"
import { Agent } from "../../src/agent/agent"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { LSP } from "../../src/lsp"
import { Permission } from "../../src/permission"
diff --git a/packages/opencode/test/tool/question.test.ts b/packages/opencode/test/tool/question.test.ts
index 17718b2b3..53c413186 100644
--- a/packages/opencode/test/tool/question.test.ts
+++ b/packages/opencode/test/tool/question.test.ts
@@ -4,7 +4,7 @@ import { QuestionTool } from "../../src/tool/question"
import { Question } from "../../src/question"
import { SessionID, MessageID } from "../../src/session/schema"
import { Agent } from "../../src/agent/agent"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Truncate } from "../../src/tool"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/tool/read.test.ts b/packages/opencode/test/tool/read.test.ts
index 7c3bf51fe..27e6b71c5 100644
--- a/packages/opencode/test/tool/read.test.ts
+++ b/packages/opencode/test/tool/read.test.ts
@@ -2,7 +2,7 @@ import { afterEach, describe, expect } from "bun:test"
import { Cause, Effect, Exit, Layer } from "effect"
import path from "path"
import { Agent } from "../../src/agent/agent"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { LSP } from "../../src/lsp"
import { Permission } from "../../src/permission"
diff --git a/packages/opencode/test/tool/registry.test.ts b/packages/opencode/test/tool/registry.test.ts
index dbb89e09a..54c1d7706 100644
--- a/packages/opencode/test/tool/registry.test.ts
+++ b/packages/opencode/test/tool/registry.test.ts
@@ -3,7 +3,7 @@ import path from "path"
import fs from "fs/promises"
import { Effect, Layer } from "effect"
import { Instance } from "../../src/project/instance"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { ToolRegistry } from "../../src/tool"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
diff --git a/packages/opencode/test/tool/skill.test.ts b/packages/opencode/test/tool/skill.test.ts
index b12940e4d..c67121e3c 100644
--- a/packages/opencode/test/tool/skill.test.ts
+++ b/packages/opencode/test/tool/skill.test.ts
@@ -1,4 +1,4 @@
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Effect, Layer } from "effect"
import { afterEach, describe, expect } from "bun:test"
import path from "path"
diff --git a/packages/opencode/test/tool/task.test.ts b/packages/opencode/test/tool/task.test.ts
index b94dd5208..1eaa0cfc8 100644
--- a/packages/opencode/test/tool/task.test.ts
+++ b/packages/opencode/test/tool/task.test.ts
@@ -2,7 +2,7 @@ import { afterEach, describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { Agent } from "../../src/agent/agent"
import { Config } from "../../src/config"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { Instance } from "../../src/project/instance"
import { Session } from "../../src/session"
import { MessageV2 } from "../../src/session/message-v2"
diff --git a/packages/opencode/test/tool/write.test.ts b/packages/opencode/test/tool/write.test.ts
index 0714d2d02..706ddb372 100644
--- a/packages/opencode/test/tool/write.test.ts
+++ b/packages/opencode/test/tool/write.test.ts
@@ -12,7 +12,7 @@ import { Truncate } from "../../src/tool"
import { Tool } from "../../src/tool"
import { Agent } from "../../src/agent/agent"
import { SessionID, MessageID } from "../../src/session/schema"
-import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
+import { CrossSpawnSpawner } from "@opencode-ai/core/effect/cross-spawn-spawner"
import { provideTmpdirInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"