chore: merge dev into v2 (#34788)

Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Affan Ali <93028901+affanali2k3@users.noreply.github.com>
Co-authored-by: affanali2k3 <affanalikhanxx@gmail.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Jay V <air@live.ca>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Ben Guthrie <benjee.012@gmail.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com>
Co-authored-by: Max Anderson <max.a.anderson95@gmail.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: Dustin Deus <deusdustin@gmail.com>
Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com>
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
Co-authored-by: runvip <164729189+runvip@users.noreply.github.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Julian Coy <julian@ex-machina.co>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
This commit is contained in:
James Long
2026-07-01 17:12:00 -04:00
committed by GitHub
parent 932a40cfd9
commit 8c94e9005f
590 changed files with 15772 additions and 5530 deletions
+2 -1
View File
@@ -7,8 +7,9 @@ export const ScrapCommand = cmd({
builder: (yargs) => yargs,
async handler() {
const { Project } = await import("@/project/project")
const { AppNodeBuilder } = await import("@opencode-ai/core/effect/app-node-builder")
const { makeRuntime } = await import("@opencode-ai/core/effect/runtime")
const runtime = makeRuntime(Project.Service, Project.defaultLayer)
const runtime = makeRuntime(Project.Service, AppNodeBuilder.build(Project.node))
const list = await runtime.runPromise((project) => project.list())
process.stdout.write(JSON.stringify(list, null, 2) + EOL)
},
+1 -1
View File
@@ -761,7 +761,7 @@ export const McpDebugCommand = effectCmd({
}
if (response.status === 401) {
prompts.log.warn("Server returned 401 Unauthorized")
prompts.log.info("Initial unauthenticated check returned 401, so this server requires OAuth")
// Try to discover OAuth metadata
const oauthConfig = typeof serverConfig.oauth === "object" ? serverConfig.oauth : undefined
+22 -2
View File
@@ -233,11 +233,27 @@ export const RunCommand = effectCmd({
hidden: true,
describe: "cap visible interactive replay to the newest N messages",
})
.option("dangerously-skip-permissions", {
.option("interactive", {
alias: ["i"],
type: "boolean",
describe: "run in direct interactive split-footer mode",
default: false,
})
.option("auto", {
type: "boolean",
describe: "auto-approve permissions that are not explicitly denied (dangerous!)",
default: false,
})
.option("yolo", {
type: "boolean",
hidden: true,
default: false,
})
.option("dangerously-skip-permissions", {
type: "boolean",
hidden: true,
default: false,
})
.option("demo", {
type: "boolean",
default: false,
@@ -255,6 +271,7 @@ export const RunCommand = effectCmd({
yield* Effect.promise(async () => {
const rawMessage = [...args.message, ...(args["--"] || [])].join(" ")
const interactive = args.mini
const auto = args.auto || args.yolo || args["dangerously-skip-permissions"]
const thinking = interactive ? (args.thinking ?? true) : (args.thinking ?? false)
const die = (message: string): never => {
UI.error(message)
@@ -780,7 +797,7 @@ export const RunCommand = effectCmd({
const permission = event.properties
if (permission.sessionID !== sessionID) continue
if (args["dangerously-skip-permissions"]) {
if (auto) {
await client.permission.reply({
requestID: permission.id,
reply: "once",
@@ -981,9 +998,12 @@ export async function runMini(input: MiniCommandInput) {
variant: undefined,
thinking: undefined,
mini: true,
interactive: false,
replay: input.replay ?? true,
"replay-limit": input.replayLimit,
replayLimit: input.replayLimit,
auto: false,
yolo: false,
"dangerously-skip-permissions": false,
dangerouslySkipPermissions: false,
demo: input.demo ?? false,
@@ -8,6 +8,7 @@
// variant and the persisted file.
import path from "path"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { Context, Effect, Layer } from "effect"
import { makeRuntime } from "@/effect/run-service"
import { Global } from "@opencode-ai/core/global"
@@ -135,7 +136,7 @@ function state(value: unknown): ModelState {
}
}
function createLayer(fs = FSUtil.defaultLayer) {
function createLayer(fs = AppNodeBuilder.build(FSUtil.node)) {
return Layer.fresh(
Layer.effect(
Service,
@@ -196,7 +197,7 @@ function createLayer(fs = FSUtil.defaultLayer) {
}
/** @internal Exported for testing. */
export function createVariantRuntime(fs = FSUtil.defaultLayer): VariantRuntime {
export function createVariantRuntime(fs = AppNodeBuilder.build(FSUtil.node)): VariantRuntime {
const runtime = makeRuntime(Service, createLayer(fs))
return {
resolveSavedVariant: (model) => runtime.runPromise((svc) => svc.resolveSavedVariant(model)).catch(() => undefined),
+18 -1
View File
@@ -6,11 +6,12 @@ import { fileURLToPath } from "url"
import { UI } from "@/cli/ui"
import { errorMessage } from "@opencode-ai/tui/util/error"
import { withTimeout } from "@/util/timeout"
import { withNetworkOptions, resolveNetworkOptionsNoConfig } from "@/cli/network"
import { withNetworkOptions, resolveNetworkOptionsNoConfig, hasArg } from "@/cli/network"
import { Filesystem } from "@/util/filesystem"
import { OpenCode } from "@opencode-ai/client"
import { createOpencodeClient } from "@opencode-ai/sdk/v2"
import { writeHeapSnapshot } from "v8"
import { ServerAuth } from "@/server/auth"
import { validateSession } from "../tui/validate-session"
import { win32InstallCtrlCGuard } from "@opencode-ai/tui/terminal-win32"
@@ -74,6 +75,21 @@ export const TuiThreadCommand = cmd({
type: "string",
describe: "agent to use",
})
.option("auto", {
type: "boolean",
describe: "auto-approve permissions that are not explicitly denied (dangerous!)",
default: false,
})
.option("yolo", {
type: "boolean",
hidden: true,
default: false,
})
.option("dangerously-skip-permissions", {
type: "boolean",
hidden: true,
default: false,
})
.option("mini", {
type: "boolean",
describe: "start the minimal interactive interface",
@@ -221,6 +237,7 @@ export const TuiThreadCommand = cmd({
model: args.model,
prompt,
fork: args.fork,
auto: args.auto || args.yolo || args["dangerously-skip-permissions"],
},
}),
)
+20 -4
View File
@@ -37,6 +37,22 @@ export type NetworkOptions = InferredOptionTypes<typeof options>
export function withNetworkOptions<T>(yargs: Argv<T>) {
return yargs.options(options)
}
export function hasArg(name: string) {
return networkArgs().some((arg) => arg === name || arg.startsWith(name + "="))
}
function hasBooleanArg(name: string) {
return networkArgs().some(
(arg) => arg === name || arg === name + "=true" || arg === name + "=false" || arg === "--no-" + name.slice(2),
)
}
function networkArgs() {
const separator = process.argv.indexOf("--")
return process.argv.slice(2, separator === -1 ? undefined : separator)
}
export const resolveNetworkOptions = Effect.fn("Cli.resolveNetworkOptions")(function* (args: NetworkOptions) {
const { Config } = yield* Effect.promise(() => import("@/config/config"))
const config = yield* Config.Service.use((cfg) => cfg.getGlobal())
@@ -44,10 +60,10 @@ export const resolveNetworkOptions = Effect.fn("Cli.resolveNetworkOptions")(func
})
export function resolveNetworkOptionsNoConfig(args: NetworkOptions, config?: ConfigV1.Info) {
const portExplicitlySet = process.argv.includes("--port")
const hostnameExplicitlySet = process.argv.includes("--hostname")
const mdnsExplicitlySet = process.argv.includes("--mdns")
const mdnsDomainExplicitlySet = process.argv.includes("--mdns-domain")
const portExplicitlySet = hasArg("--port")
const hostnameExplicitlySet = hasArg("--hostname")
const mdnsExplicitlySet = hasBooleanArg("--mdns")
const mdnsDomainExplicitlySet = hasArg("--mdns-domain")
const mdns = mdnsExplicitlySet ? args.mdns : (config?.server?.mdns ?? args.mdns)
const mdnsDomain = mdnsDomainExplicitlySet ? args["mdns-domain"] : (config?.server?.mdnsDomain ?? args["mdns-domain"])
const port = portExplicitlySet ? args.port : (config?.server?.port ?? args.port)
+2 -1
View File
@@ -1,7 +1,8 @@
import { run as runTui, type TuiInput } from "@opencode-ai/tui"
import { Global } from "@opencode-ai/core/global"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { Effect } from "effect"
export function run(input: TuiInput) {
return runTui(input).pipe(Effect.provide(Global.defaultLayer))
return runTui(input).pipe(Effect.provide(AppNodeBuilder.build(Global.node)))
}