Compare commits

..

8 Commits

Author SHA1 Message Date
opencode 744a17379b release: v1.14.50 2026-05-14 03:03:12 +00:00
Kit Langton cda8cc7285 test(httpapi): simplify event stream regression coverage (#27427) 2026-05-14 02:18:40 +00:00
Kit Langton b928a1fff9 fix(httpapi): preserve event stream context (#27425)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: James Long <longster@gmail.com>
2026-05-13 22:02:30 -04:00
Kit Langton 04286d0415 docs(effect): plan Instance deletion path (#27424) 2026-05-13 21:58:54 -04:00
opencode-agent[bot] 33bb33ba90 chore: generate 2026-05-14 01:55:00 +00:00
Sebastian b0ade40265 flip back to markdown renderable (#27421) 2026-05-14 03:53:48 +02:00
Kit Langton 681594b551 refactor(storage): remove not found wire serializer (#27416) 2026-05-13 21:39:50 -04:00
Kit Langton edf7649400 fix(session): type busy errors (#27410) 2026-05-14 01:28:04 +00:00
50 changed files with 157 additions and 156 deletions
+17 -17
View File
@@ -29,7 +29,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -84,7 +84,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -119,7 +119,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -146,7 +146,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@ai-sdk/anthropic": "3.0.64",
"@ai-sdk/openai": "3.0.48",
@@ -168,7 +168,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -192,7 +192,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.14.49",
"version": "1.14.50",
"bin": {
"opencode": "./bin/opencode",
},
@@ -253,7 +253,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@@ -307,7 +307,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@@ -337,7 +337,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -353,7 +353,7 @@
},
"packages/http-recorder": {
"name": "@opencode-ai/http-recorder",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@effect/platform-node": "catalog:",
"effect": "catalog:",
@@ -366,7 +366,7 @@
},
"packages/llm": {
"name": "@opencode-ai/llm",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@smithy/eventstream-codec": "4.2.14",
"@smithy/util-utf8": "4.2.2",
@@ -384,7 +384,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.14.49",
"version": "1.14.50",
"bin": {
"opencode": "./bin/opencode",
},
@@ -520,7 +520,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"effect": "catalog:",
@@ -558,7 +558,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"cross-spawn": "catalog:",
},
@@ -573,7 +573,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -608,7 +608,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -657,7 +657,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.14.49",
"version": "1.14.50",
"description": "",
"type": "module",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.14.49",
"version": "1.14.50",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.14.49",
"version": "1.14.50",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.14.49",
"version": "1.14.50",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.14.49",
"version": "1.14.50",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.14.49",
"version": "1.14.50",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",
-6
View File
@@ -5,11 +5,6 @@ function truthy(key: string) {
return value === "true" || value === "1"
}
function falsy(key: string) {
const value = process.env[key]?.toLowerCase()
return value === "false" || value === "0"
}
function number(key: string) {
const value = process.env[key]
if (!value) return undefined
@@ -72,7 +67,6 @@ export const Flag = {
OPENCODE_EXPERIMENTAL_LSP_TOOL: OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_LSP_TOOL"),
OPENCODE_EXPERIMENTAL_PLAN_MODE: OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_PLAN_MODE"),
OPENCODE_EXPERIMENTAL_SCOUT: OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_SCOUT"),
OPENCODE_EXPERIMENTAL_MARKDOWN: !falsy("OPENCODE_EXPERIMENTAL_MARKDOWN"),
OPENCODE_ENABLE_PARALLEL: truthy("OPENCODE_ENABLE_PARALLEL") || truthy("OPENCODE_EXPERIMENTAL_PARALLEL"),
OPENCODE_MODELS_URL: process.env["OPENCODE_MODELS_URL"],
OPENCODE_MODELS_PATH: process.env["OPENCODE_MODELS_PATH"],
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.14.49",
"version": "1.14.50",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.14.49",
"version": "1.14.50",
"private": true,
"type": "module",
"license": "MIT",
+6 -6
View File
@@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The open source coding agent."
version = "1.14.49"
version = "1.14.50"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/anomalyco/opencode"
@@ -11,26 +11,26 @@ name = "OpenCode"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.49/opencode-darwin-arm64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.50/opencode-darwin-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.darwin-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.49/opencode-darwin-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.50/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.49/opencode-linux-arm64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.50/opencode-linux-arm64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.49/opencode-linux-x64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.50/opencode-linux-x64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.49/opencode-windows-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.50/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.14.49",
"version": "1.14.50",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.14.49",
"version": "1.14.50",
"name": "@opencode-ai/http-recorder",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.14.49",
"version": "1.14.50",
"name": "@opencode-ai/llm",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.14.49",
"version": "1.14.50",
"name": "opencode",
"type": "module",
"license": "MIT",
+57
View File
@@ -224,6 +224,63 @@ Goal:
explicit context where practical.
- Delete `project/instance.ts` only after ambient Instance coupling is gone.
Important distinction:
- `InstanceState.context`, `InstanceState.directory`, and
`InstanceState.workspaceID` are acceptable inside normal Effect service
code when `InstanceRef` / `WorkspaceRef` are provided by the runtime.
- The deletion blockers are the fallback and callback paths that rely on
ambient ALS: direct `Instance.*` reads, `InstanceState.bind(...)`,
`AppRuntime.runPromise(...)` re-entry from plain JS, and bridge restore
code that installs legacy ALS before invoking callbacks.
Current bottom-up inventory from `dev`:
- Direct `Instance.*` value readers:
[`tool/repo_overview.ts`](../../src/tool/repo_overview.ts),
[`control-plane/adapters/worktree.ts`](../../src/control-plane/adapters/worktree.ts),
[`cli/bootstrap.ts`](../../src/cli/bootstrap.ts).
- `InstanceState.bind(...)` callback boundaries:
[`file/watcher.ts`](../../src/file/watcher.ts) native watcher callback,
[`storage/db.ts`](../../src/storage/db.ts) transaction/effect callbacks,
[`session/llm.ts`](../../src/session/llm.ts) workflow approval callback.
- `AppRuntime.runPromise(...)` / re-entry from plain JS:
[`project/with-instance.ts`](../../src/project/with-instance.ts),
[`project/instance-runtime.ts`](../../src/project/instance-runtime.ts),
[`control-plane/adapters/worktree.ts`](../../src/control-plane/adapters/worktree.ts),
[`cli/effect-cmd.ts`](../../src/cli/effect-cmd.ts), plus global/non-instance
callsites such as CLI upgrade and ACP agent defaults.
- Intentional bridge users to classify, not delete blindly:
workspace adapters in [`control-plane/workspace.ts`](../../src/control-plane/workspace.ts),
MCP, command execution, plugins, pty lifecycle, bus scope cleanup, task
cancellation, and HTTP lifecycle reload/dispose paths.
- Core fallback layer to shrink last:
[`effect/run-service.ts`](../../src/effect/run-service.ts),
[`effect/bridge.ts`](../../src/effect/bridge.ts), and
[`effect/instance-state.ts`](../../src/effect/instance-state.ts).
Recommended PR order:
- [ ] `INST-1` Remove direct `Instance.*` value readers. Start with
`repo_overview`, `worktree` adapter, and `cli/bootstrap`; pass context
explicitly or obtain it from an Effect boundary.
- [ ] `INST-2` Move type-only `InstanceContext` imports from
[`project/instance.ts`](../../src/project/instance.ts) to
[`project/instance-context.ts`](../../src/project/instance-context.ts).
- [ ] `INST-3` Audit each `InstanceState.bind(...)` callback from the inside
out: list what the callback calls (`Bus.publish`, database effects,
permission/session services), then replace ambient capture with explicit
`InstanceRef` / `WorkspaceRef` provision or an `EffectBridge` call.
- [ ] `INST-4` Classify `AppRuntime.runPromise(...)` callsites as global,
instance-scoped with explicit refs, or bridge-required. Eliminate the
instance-scoped callsites that rely on `run-service.attach()` falling
back to `Instance.current`.
- [ ] `INST-5` After consumers are explicit, remove `Instance.current` fallback
from `InstanceState.context` and `run-service.attach()`.
- [ ] `INST-6` Move any remaining `restore` / `bind` compatibility helpers to
the boundary that still needs them, then delete
[`project/instance.ts`](../../src/project/instance.ts).
## Lower Priority Tracks
- `PROC` / `FS` — continue AppProcess and AppFileSystem migrations as
@@ -1528,14 +1528,14 @@ function TextPart(props: { last: boolean; part: TextPart; message: AssistantMess
return (
<Show when={props.part.text.trim()}>
<box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0}>
<code
filetype="markdown"
drawUnstyledText={false}
streaming={true}
<markdown
syntaxStyle={syntax()}
streaming={true}
internalBlockMode="top-level"
content={props.part.text.trim()}
conceal={ctx.conceal()}
fg={theme.text}
fg={theme.markdownText}
bg={theme.background}
/>
</box>
</Show>
+7 -12
View File
@@ -4,11 +4,12 @@ export interface Runner<A, E = never> {
readonly state: State<A, E>
readonly busy: boolean
readonly ensureRunning: (work: Effect.Effect<A, E>) => Effect.Effect<A, E>
readonly startShell: (work: Effect.Effect<A, E>, ready?: Latch.Latch) => Effect.Effect<A, E>
readonly startShell: (work: Effect.Effect<A, E>, ready?: Latch.Latch) => Effect.Effect<A, E | Busy>
readonly cancel: Effect.Effect<void>
}
export class Cancelled extends Schema.TaggedErrorClass<Cancelled>()("RunnerCancelled", {}) {}
export class Busy extends Schema.TaggedErrorClass<Busy>()("RunnerBusy", {}) {}
interface RunHandle<A, E> {
id: number
@@ -41,12 +42,11 @@ export const make = <A, E = never>(
onIdle?: Effect.Effect<void>
onBusy?: Effect.Effect<void>
onInterrupt?: Effect.Effect<A, E>
busy?: () => never
},
): Runner<A, E> => {
const ref = SynchronizedRef.makeUnsafe<State<A, E>>({ _tag: "Idle" })
const idle = opts?.onIdle ?? Effect.void
const busy = opts?.onBusy ?? Effect.void
const onBusy = opts?.onBusy ?? Effect.void
const onInterrupt = opts?.onInterrupt
let ids = 0
@@ -137,20 +137,15 @@ export const make = <A, E = never>(
}),
).pipe(Effect.flatten)
const startShell = (work: Effect.Effect<A, E>, ready?: Latch.Latch) =>
const startShell = (work: Effect.Effect<A, E>, ready?: Latch.Latch): Effect.Effect<A, E | Busy> =>
SynchronizedRef.modifyEffect(
ref,
Effect.fnUntraced(function* (st) {
if (st._tag !== "Idle") {
return [
Effect.sync(() => {
if (opts?.busy) opts.busy()
throw new Error("Runner is busy")
}),
st,
] as const
const reject: Effect.Effect<A, E | Busy> = Effect.fail(new Busy())
return [reject, st] as const
}
yield* busy
yield* onBusy
const id = next()
const cancelled = yield* Deferred.make<void>()
const fiber = yield* work.pipe(Effect.ensuring(finishShell(id)), Effect.forkChild)
@@ -58,13 +58,10 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session",
const bus = yield* Bus.Service
const scope = yield* Scope.Scope
const mapBusy = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | HttpApiError.BadRequest, R> =>
effect.pipe(
Effect.catchCause((cause): Effect.Effect<never, E | HttpApiError.BadRequest> => {
if (Cause.squash(cause) instanceof Session.BusyError) return Effect.fail(new HttpApiError.BadRequest({}))
return Effect.failCause(cause)
}),
)
const mapBusy = <A, R>(
effect: Effect.Effect<A, Session.BusyError, R>,
): Effect.Effect<A, HttpApiError.BadRequest, R> =>
effect.pipe(Effect.catchTag("SessionBusyError", () => Effect.fail(new HttpApiError.BadRequest({}))))
const list = Effect.fn("SessionHttpApi.list")(function* (ctx: { query: typeof ListQuery.Type }) {
return yield* session.list({
+7 -7
View File
@@ -167,7 +167,7 @@ export interface Interface {
readonly cancel: (sessionID: SessionID) => Effect.Effect<void>
readonly prompt: (input: PromptInput) => Effect.Effect<MessageV2.WithParts>
readonly loop: (input: LoopInput) => Effect.Effect<MessageV2.WithParts>
readonly shell: (input: ShellInput) => Effect.Effect<MessageV2.WithParts>
readonly shell: (input: ShellInput) => Effect.Effect<MessageV2.WithParts, Session.BusyError>
readonly command: (input: CommandInput) => Effect.Effect<MessageV2.WithParts>
readonly resolvePromptParts: (template: string) => Effect.Effect<PromptInput["parts"]>
}
@@ -1864,12 +1864,12 @@ NOTE: At any point in time through this workflow you should feel free to ask the
return yield* state.ensureRunning(input.sessionID, lastAssistant(input.sessionID), runLoop(input.sessionID))
})
const shell: (input: ShellInput) => Effect.Effect<MessageV2.WithParts> = Effect.fn("SessionPrompt.shell")(
function* (input: ShellInput) {
const ready = yield* Latch.make()
return yield* state.startShell(input.sessionID, lastAssistant(input.sessionID), shellImpl(input, ready), ready)
},
)
const shell: (input: ShellInput) => Effect.Effect<MessageV2.WithParts, Session.BusyError> = Effect.fn(
"SessionPrompt.shell",
)(function* (input: ShellInput) {
const ready = yield* Latch.make()
return yield* state.startShell(input.sessionID, lastAssistant(input.sessionID), shellImpl(input, ready), ready)
})
const command = Effect.fn("SessionPrompt.command")(function* (input: CommandInput) {
yield* elog.info("command", { sessionID: input.sessionID, command: input.command, agent: input.agent })
+2 -2
View File
@@ -20,8 +20,8 @@ export const RevertInput = Schema.Struct({
export type RevertInput = Schema.Schema.Type<typeof RevertInput>
export interface Interface {
readonly revert: (input: RevertInput) => Effect.Effect<Session.Info>
readonly unrevert: (input: { sessionID: SessionID }) => Effect.Effect<Session.Info>
readonly revert: (input: RevertInput) => Effect.Effect<Session.Info, Session.BusyError>
readonly unrevert: (input: { sessionID: SessionID }) => Effect.Effect<Session.Info, Session.BusyError>
readonly cleanup: (session: Session.Info) => Effect.Effect<void>
}
+10 -7
View File
@@ -7,7 +7,7 @@ import { SessionID } from "./schema"
import { SessionStatus } from "./status"
export interface Interface {
readonly assertNotBusy: (sessionID: SessionID) => Effect.Effect<void>
readonly assertNotBusy: (sessionID: SessionID) => Effect.Effect<void, Session.BusyError>
readonly cancel: (sessionID: SessionID) => Effect.Effect<void>
readonly ensureRunning: (
sessionID: SessionID,
@@ -19,7 +19,7 @@ export interface Interface {
onInterrupt: Effect.Effect<MessageV2.WithParts>,
work: Effect.Effect<MessageV2.WithParts>,
ready?: Latch.Latch,
) => Effect.Effect<MessageV2.WithParts>
) => Effect.Effect<MessageV2.WithParts, Session.BusyError>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/SessionRunState") {}
@@ -60,9 +60,6 @@ export const layer = Layer.effect(
}),
onBusy: status.set(sessionID, { type: "busy" }),
onInterrupt,
busy: () => {
throw new Session.BusyError(sessionID)
},
})
data.runners.set(sessionID, next)
return next
@@ -71,7 +68,7 @@ export const layer = Layer.effect(
const assertNotBusy = Effect.fn("SessionRunState.assertNotBusy")(function* (sessionID: SessionID) {
const data = yield* InstanceState.get(state)
const existing = data.runners.get(sessionID)
if (existing?.busy) throw new Session.BusyError(sessionID)
if (existing?.busy) yield* busyError(sessionID)
})
const cancel = Effect.fn("SessionRunState.cancel")(function* (sessionID: SessionID) {
@@ -98,7 +95,9 @@ export const layer = Layer.effect(
work: Effect.Effect<MessageV2.WithParts>,
ready?: Latch.Latch,
) {
return yield* (yield* runner(sessionID, onInterrupt)).startShell(work, ready)
return yield* (yield* runner(sessionID, onInterrupt))
.startShell(work, ready)
.pipe(Effect.catchTag("RunnerBusy", () => Effect.fail(busyError(sessionID))))
})
return Service.of({ assertNotBusy, cancel, ensureRunning, startShell })
@@ -107,4 +106,8 @@ export const layer = Layer.effect(
export const defaultLayer = layer.pipe(Layer.provide(SessionStatus.defaultLayer))
function busyError(sessionID: SessionID) {
return new Session.BusyError({ sessionID })
}
export * as SessionRunState from "./run-state"
+3 -5
View File
@@ -442,11 +442,9 @@ export const getUsage = (input: { model: Provider.Model; usage: LanguageModelUsa
}
}
export class BusyError extends Error {
constructor(public readonly sessionID: string) {
super(`Session ${sessionID} is busy`)
}
}
export class BusyError extends Schema.TaggedErrorClass<BusyError>()("SessionBusyError", {
sessionID: SessionID,
}) {}
export type NotFound = NotFoundError
-7
View File
@@ -20,13 +20,6 @@ export class NotFoundError extends Schema.TaggedErrorClass<NotFoundError>()("Not
static isInstance(input: unknown): input is NotFoundError {
return input instanceof NotFoundError
}
toObject() {
return {
name: "NotFoundError" as const,
data: { message: this.message },
}
}
}
export type Error = AppFileSystem.Error | NotFoundError
+2 -23
View File
@@ -1,5 +1,5 @@
import { describe, expect } from "bun:test"
import { Deferred, Effect, Exit, Fiber, Latch, Ref, Scope } from "effect"
import { Cause, Deferred, Effect, Exit, Fiber, Latch, Ref, Scope } from "effect"
import { Runner } from "@/effect/runner"
import { it } from "../lib/effect"
@@ -302,34 +302,13 @@ describe("Runner", () => {
const exit = yield* runner.startShell(Effect.succeed("second")).pipe(Effect.exit)
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Runner.Busy)
yield* Deferred.succeed(gate, undefined)
yield* Fiber.await(sh)
}),
)
it.live(
"shell rejects via busy callback and cancel still stops the first shell",
Effect.gen(function* () {
const s = yield* Scope.Scope
const runner = Runner.make<string>(s, {
busy: () => {
throw new Error("busy")
},
})
const sh = yield* runner.startShell(Effect.never.pipe(Effect.as("aborted"))).pipe(Effect.forkChild)
yield* waitForState(runner, "Shell")
const exit = yield* runner.startShell(Effect.succeed("second")).pipe(Effect.exit)
expect(Exit.isFailure(exit)).toBe(true)
yield* runner.cancel
const done = yield* Fiber.await(sh)
expect(Exit.isFailure(done)).toBe(true)
}),
)
it.live(
"cancel interrupts shell",
Effect.gen(function* () {
@@ -1119,7 +1119,7 @@ it.instance(
)
it.instance(
"assertNotBusy throws BusyError when loop running",
"assertNotBusy fails with BusyError when loop running",
() =>
Effect.gen(function* () {
const { llm } = yield* useServerConfig(providerCfg)
@@ -1138,6 +1138,7 @@ it.instance(
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) {
expect(Cause.squash(exit.cause)).toBeInstanceOf(Session.BusyError)
expect(Cause.squash(exit.cause)).toMatchObject({ _tag: "SessionBusyError", sessionID: chat.id })
}
yield* prompt.cancel(chat.id)
@@ -1181,6 +1182,7 @@ it.instance(
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) {
expect(Cause.squash(exit.cause)).toBeInstanceOf(Session.BusyError)
expect(Cause.squash(exit.cause)).toMatchObject({ _tag: "SessionBusyError", sessionID: chat.id })
}
yield* prompt.cancel(chat.id)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.14.49",
"version": "1.14.50",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.14.49",
"version": "1.14.50",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.14.49",
"version": "1.14.50",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.14.49",
"version": "1.14.50",
"type": "module",
"license": "MIT",
"exports": {
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.14.49",
"version": "1.14.50",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
-1
View File
@@ -607,5 +607,4 @@ opencode upgrade v0.1.48
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | تعطيل مراقب الملفات |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | تفعيل ميزات Exa التجريبية |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | تمكين TY LSP لملفات python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | تفعيل ميزات markdown تجريبية |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | تفعيل وضع الخطة |
-1
View File
@@ -605,5 +605,4 @@ Ove varijable okruženja omogućavaju eksperimentalne karakteristike koje se mog
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Onemogući praćenje datoteka |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Omogući eksperimentalne Exa funkcije |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Omogući TY LSP za python datoteke |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Omogući eksperimentalne Markdown funkcije |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Omogući Plan mod |
-1
View File
@@ -723,5 +723,4 @@ These environment variables enable experimental features that may change or be r
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Disable file watcher |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Enable experimental Exa features |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Enable TY LSP for python files |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Enable experimental markdown features |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Enable plan mode |
+14 -15
View File
@@ -595,18 +595,17 @@ OpenCode kan konfigureres ved hjælp af miljøvariabler.
Disse miljøvariabler muliggør eksperimentelle funktioner, der kan ændres eller fjernes.
| Variabel | Skriv | Beskrivelse |
| ----------------------------------------------- | ------- | ------------------------------------------ |
| `OPENCODE_EXPERIMENTAL` | boolean | Aktiver alle eksperimentelle funktioner |
| `OPENCODE_EXPERIMENTAL_ICON_DISCOVERY` | boolean | Aktiver ikonopdagelse |
| `OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT` | boolean | Deaktiver kopi ved valg i TUI |
| `OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS` | nummer | Standard timeout for bash-kommandoer i ms |
| `OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX` | nummer | Maks. output-tokens for LLM-svar |
| `OPENCODE_EXPERIMENTAL_FILEWATCHER` | boolean | Aktiver filovervågning for hele dir |
| `OPENCODE_EXPERIMENTAL_OXFMT` | boolean | Aktiver oxfmt formatter |
| `OPENCODE_EXPERIMENTAL_LSP_TOOL` | boolean | Aktive eksperimenter LSP værktøj |
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Deaktiver filovervågning |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Aktive eksperimenter Exa-funktioner |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Aktiver TY LSP for python-filer |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Aktive eksperimentelle markdown-funktioner |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Aktiver plantilstand |
| Variabel | Skriv | Beskrivelse |
| ----------------------------------------------- | ------- | ----------------------------------------- |
| `OPENCODE_EXPERIMENTAL` | boolean | Aktiver alle eksperimentelle funktioner |
| `OPENCODE_EXPERIMENTAL_ICON_DISCOVERY` | boolean | Aktiver ikonopdagelse |
| `OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT` | boolean | Deaktiver kopi ved valg i TUI |
| `OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS` | nummer | Standard timeout for bash-kommandoer i ms |
| `OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX` | nummer | Maks. output-tokens for LLM-svar |
| `OPENCODE_EXPERIMENTAL_FILEWATCHER` | boolean | Aktiver filovervågning for hele dir |
| `OPENCODE_EXPERIMENTAL_OXFMT` | boolean | Aktiver oxfmt formatter |
| `OPENCODE_EXPERIMENTAL_LSP_TOOL` | boolean | Aktive eksperimenter LSP værktøj |
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Deaktiver filovervågning |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Aktive eksperimenter Exa-funktioner |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Aktiver TY LSP for python-filer |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Aktiver plantilstand |
-1
View File
@@ -607,5 +607,4 @@ Diese Umgebungsvariablen ermöglichen experimentelle Funktionen, die sich änder
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolescher Wert | Dateiüberwachung deaktivieren |
| `OPENCODE_EXPERIMENTAL_EXA` | boolescher Wert | Experimentelle Exa-Funktionen aktivieren |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolescher Wert | TY LSP für Python-Dateien aktivieren |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolescher Wert | Experimentelle Markdown-Funktionen aktivieren |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolescher Wert | Planmodus aktivieren |
-1
View File
@@ -607,5 +607,4 @@ Estas variables de entorno habilitan funciones experimentales que pueden cambiar
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | booleano | Deshabilitar el observador de archivos |
| `OPENCODE_EXPERIMENTAL_EXA` | booleano | Habilitar funciones experimentales de Exa |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | booleano | Habilitar Habilitar TY LSP para archivos python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | booleano | Habilitar funciones de Markdown experimentales |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | booleano | Habilitar modo de plan |
-1
View File
@@ -608,5 +608,4 @@ Ces variables d'environnement activent des fonctionnalités expérimentales qui
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | booléen | Désactiver l'observateur de fichiers |
| `OPENCODE_EXPERIMENTAL_EXA` | booléen | Activer les fonctionnalités Exa expérimentales |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | booléen | Activer TY LSP pour les fichiers python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | booléen | Activer les fonctionnalités Markdown expérimentales |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | booléen | Activer le mode plan |
-1
View File
@@ -608,5 +608,4 @@ Queste variabili d'ambiente abilitano funzionalità sperimentali che potrebbero
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Disabilita file watcher |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Abilita funzionalità Exa sperimentali |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Abilita TY LSP per i file python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Abilita markdown sperimentale |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Abilita plan mode |
-1
View File
@@ -607,5 +607,4 @@ OpenCode は環境変数を使用して構成できます。
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | ブール値 | ファイルウォッチャーを無効にする |
| `OPENCODE_EXPERIMENTAL_EXA` | ブール値 | 実験的な Exa 機能を有効にする |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | ブール値 | python ファイルの TY LSP を有効にする |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | ブール値 | 試験的な Markdown 機能を有効にする |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | ブール値 | プランモードを有効にする |
-1
View File
@@ -607,5 +607,4 @@ OpenCode는 환경 변수로도 구성할 수 있습니다.
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | 파일 감시 비활성화 |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | 실험적 Exa 기능 활성화 |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | python 파일에 대해 TY LSP 활성화 |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | 실험적 Markdown 기능 활성화 |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Plan mode 활성화 |
-1
View File
@@ -608,5 +608,4 @@ Disse miljøvariablene muliggjør eksperimentelle funksjoner som kan endres elle
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolsk | Deaktiver filovervåking |
| `OPENCODE_EXPERIMENTAL_EXA` | boolsk | Aktiver eksperimentelle Exa-funksjoner |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolsk | Aktiver TY LSP for python-filer |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolsk | Aktiver eksperimentelle Markdown-funksjoner |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolsk | Aktiver planmodus |
-1
View File
@@ -608,5 +608,4 @@ Te zmienne włączają funkcje eksperymentalne, które mogą ulec zmianie lub zo
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Wyłącz obserwatora plików |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Włącz funkcje eksperymentalne Exa |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Włącz TY LSP dla plików python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Włącz funkcje eksperymentalne Markdown |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Włącz tryb planowania |
@@ -607,5 +607,4 @@ Essas variáveis de ambiente habilitam recursos experimentais que podem mudar ou
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Desabilitar monitoramento de arquivos |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Habilitar recursos experimentais do Exa |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Habilitar TY LSP para arquivos python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Habilitar recursos experimentais de markdown |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Habilitar modo de plano |
-1
View File
@@ -608,5 +608,4 @@ opencode можно настроить с помощью переменных с
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | логическое значение | Отключить просмотрщик файлов |
| `OPENCODE_EXPERIMENTAL_EXA` | логическое значение | Включить экспериментальные функции Exa |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | логическое значение | Включить TY LSP для файлов python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | логическое значение | Включить экспериментальные функции Markdown |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | логическое значение | Включить режим плана |
-1
View File
@@ -609,5 +609,4 @@ OpenCode สามารถกำหนดค่าโดยใช้ตัว
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | Boolean | ปิดใช้งานตัวเฝ้าดูไฟล์ |
| `OPENCODE_EXPERIMENTAL_EXA` | Boolean | ฟีเจอร์ Exa ทดลอง |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | Boolean | เปิดใช้งาน TY LSP สำหรับไฟล์ python |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | Boolean | ใช้ Markdown renderer แบบทดลอง |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | Boolean | เปิดใช้งาน Plan mode |
-1
View File
@@ -608,5 +608,4 @@ Bu ortam değişkenleri değişebilecek veya kaldırılabilecek deneysel özelli
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Dosya izleyiciyi devre dışı bırak |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Deneysel Exa özelliklerini etkinleştirin |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | python dosyaları için TY LSP'yi etkinleştir |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Deneysel işaretleme özelliklerini etkinleştir |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Plan modunu etkinleştir |
+2 -2
View File
@@ -596,7 +596,7 @@ OpenCode 可以通过环境变量进行配置。
这些环境变量用于启用可能会更改或移除的实验性功能。
| 变量 | 类型 | 描述 |
| ----------------------------------------------- | ------- | ------------------------------- | --- | -------------------------------- | ------- | ------------------------ |
| ----------------------------------------------- | ------- | ------------------------------- |
| `OPENCODE_EXPERIMENTAL` | boolean | 启用所有实验性功能 |
| `OPENCODE_EXPERIMENTAL_ICON_DISCOVERY` | boolean | 启用图标发现 |
| `OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT` | boolean | 禁用 TUI 中的选中即复制 |
@@ -607,5 +607,5 @@ OpenCode 可以通过环境变量进行配置。
| `OPENCODE_EXPERIMENTAL_LSP_TOOL` | boolean | 启用实验性 LSP 工具 |
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | 禁用文件监听器 |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | 启用实验性 Exa 功能 |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | 为 python 文件启用 TY LSP | | `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | 启用实验性 Markdown 功能 |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | 为 python 文件启用 TY LSP |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | 启用计划模式 |
@@ -608,5 +608,4 @@ OpenCode 可以透過環境變數進行設定。
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | 停用檔案監看器 |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | 啟用實驗性 Exa 功能 |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | 為 python 檔案啟用 TY LSP |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | 啟用實驗性 Markdown 功能 |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | 啟用計畫模式 |
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.14.49",
"version": "1.14.50",
"publisher": "sst-dev",
"repository": {
"type": "git",