Skip to content

Commit eb77fa9

Browse files
committed
fix
1 parent c66a9e7 commit eb77fa9

2 files changed

Lines changed: 23 additions & 15 deletions

File tree

packages/opencode/src/session/prompt.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ import { NamedError } from "@opencode-ai/shared/util/error"
3636
import { SessionProcessor } from "./processor"
3737
import { Tool } from "@/tool"
3838
import { Permission } from "@/permission"
39+
import { Instance } from "@/project/instance"
3940
import { SessionStatus } from "./status"
4041
import { LLM } from "./llm"
4142
import { Shell } from "@/shell/shell"
4243
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
4344
import { Truncate } from "@/tool"
4445
import { decodeDataUrl } from "@/util/data-url"
4546
import { Process } from "@/util"
46-
import { Cause, Effect, Exit, Layer, Option, Scope, Context } from "effect"
47+
import { Cause, Effect, Exit, Fiber, Layer, Option, Scope, Context } from "effect"
4748
import { EffectLogger } from "@/effect"
4849
import { InstanceState } from "@/effect"
4950
import { TaskTool, type TaskPromptOps } from "@/tool/task"
@@ -816,7 +817,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
816817

817818
return yield* Effect.gen(function* () {
818819
try {
819-
const cfg = yield* Effect.promise(() => SandboxSpawn.settings())
820+
const cfg = yield* Effect.promise(Instance.bind(() => SandboxSpawn.settings()))
820821
const blocked = SandboxSpawn.excludedText(input.command, cfg.excluded_commands)
821822
if (blocked) {
822823
throw new SandboxSpawn.CommandError(blocked.command, blocked.rule)
@@ -910,7 +911,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
910911
})
911912
const exit = yield* Effect.gen(function* () {
912913
const handle = yield* spawner.spawn(proc)
913-
yield* Effect.forkScoped(
914+
const stdout = yield* Effect.forkScoped(
914915
Stream.runForEach(Stream.decodeText(handle.stdout), (chunk) =>
915916
Effect.sync(() => {
916917
output += chunk
@@ -921,7 +922,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
921922
}),
922923
),
923924
)
924-
yield* Effect.forkScoped(
925+
const err = yield* Effect.forkScoped(
925926
Stream.runForEach(Stream.decodeText(handle.stderr), (chunk) =>
926927
Effect.sync(() => {
927928
stderr += chunk
@@ -933,7 +934,11 @@ NOTE: At any point in time through this workflow you should feel free to ask the
933934
}),
934935
),
935936
)
936-
return yield* handle.exitCode
937+
938+
const code = yield* handle.exitCode
939+
yield* Fiber.await(stdout)
940+
yield* Fiber.await(err)
941+
return code
937942
}).pipe(
938943
Effect.scoped,
939944
Effect.onInterrupt(() =>

packages/opencode/src/tool/bash.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { Shell } from "@/shell/shell"
1717
import { BashArity } from "@/permission/arity"
1818
import * as Truncate from "./truncate"
1919
import { Plugin } from "@/plugin"
20-
import { Cause, Effect, Exit, Stream } from "effect"
20+
import { Cause, Effect, Exit, Fiber, Stream } from "effect"
2121
import { ChildProcess } from "effect/unstable/process"
2222
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
2323
import { SandboxSpawn } from "@/sandbox/spawn"
@@ -424,7 +424,6 @@ export const BashTool = Tool.define(
424424
const fs = yield* AppFileSystem.Service
425425
const trunc = yield* Truncate.Service
426426
const plugin = yield* Plugin.Service
427-
const sandbox = yield* Effect.promise(() => SandboxSpawn.settings())
428427

429428
const cygpath = Effect.fn("BashTool.cygpath")(function* (shell: string, text: string) {
430429
const lines = yield* spawner
@@ -610,18 +609,17 @@ export const BashTool = Tool.define(
610609
Effect.gen(function* () {
611610
const handle = yield* spawner.spawn(proc)
612611

613-
yield* Effect.forkScoped(
612+
const out = yield* Effect.forkScoped(
614613
Stream.runForEach(Stream.decodeText(handle.stdout), (chunk) => {
615614
return write(chunk)
616615
}),
617616
)
618-
yield* Effect.forkScoped(
617+
const err = yield* Effect.forkScoped(
619618
Stream.runForEach(Stream.decodeText(handle.stderr), (chunk) => {
620619
stderr += chunk
621620
return write(chunk)
622621
}),
623622
)
624-
625623
const abort = Effect.callback<void>((resume) => {
626624
if (ctx.abort.aborted) return resume(Effect.void)
627625
const handler = () => resume(Effect.void)
@@ -646,6 +644,9 @@ export const BashTool = Tool.define(
646644
yield* handle.kill({ forceKillAfter: "3 seconds" }).pipe(Effect.orDie)
647645
}
648646

647+
yield* Fiber.await(out)
648+
yield* Fiber.await(err)
649+
649650
return exit.kind === "exit" ? exit.code : null
650651
}),
651652
).pipe(Effect.orDie)
@@ -794,24 +795,26 @@ export const BashTool = Tool.define(
794795
Effect.sync(() => {
795796
const shell = Shell.acceptable()
796797
const name = Shell.name(shell)
798+
let dir = process.cwd()
799+
try {
800+
dir = Instance.directory
801+
} catch {}
797802
const chain =
798803
name === "powershell"
799804
? "If the commands depend on each other and must run sequentially, avoid '&&' in this shell because Windows PowerShell 5.1 does not support it. Use PowerShell conditionals such as `cmd1; if ($?) { cmd2 }` when later commands must depend on earlier success."
800805
: "If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together (e.g., `git add . && git commit -m \"message\" && git push`). For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead."
801806
log.info("bash tool using shell", { shell })
802807

803808
return {
804-
description: DESCRIPTION.replaceAll("${directory}", Instance.directory)
809+
description: DESCRIPTION.replaceAll("${directory}", dir)
805810
.replaceAll("${os}", process.platform)
806811
.replaceAll("${shell}", name)
807812
.replaceAll("${chaining}", chain)
808813
.replaceAll("${maxLines}", String(Truncate.MAX_LINES))
809814
.replaceAll("${maxBytes}", String(Truncate.MAX_BYTES))
810815
.replaceAll(
811816
"${unsandboxed}",
812-
sandbox.allow_unsandboxed_retry
813-
? "\n\nIf you know a command needs to run outside the sandbox before the first attempt, put `# opencode:unsandboxed <reason>` on the first non-empty line of the command. This asks for the separate `bash:unsandboxed` permission before execution while keeping the normal bash tool schema unchanged."
814-
: "",
817+
"\n\nIf sandbox settings allow unsandboxed retries and you know a command needs to run outside the sandbox before the first attempt, put `# opencode:unsandboxed <reason>` on the first non-empty line of the command. This asks for the separate `bash:unsandboxed` permission before execution while keeping the normal bash tool schema unchanged.",
815818
),
816819
parameters: Parameters,
817820
execute: (params: z.infer<typeof Parameters>, ctx: Tool.Context) =>
@@ -825,7 +828,7 @@ export const BashTool = Tool.define(
825828
throw new Error(`Invalid timeout value: ${params.timeout}. Timeout must be a positive number.`)
826829
}
827830
const timeout = params.timeout ?? DEFAULT_TIMEOUT
828-
const cfg = yield* Effect.promise(() => SandboxSpawn.settings())
831+
const cfg = yield* Effect.promise(Instance.bind(() => SandboxSpawn.settings()))
829832
const ps = PS.has(name)
830833
const root = yield* parse(command, ps)
831834
const scan = yield* collect(root, cwd, ps, shell, cfg.excluded_commands)

0 commit comments

Comments
 (0)