feat(mini): migrate mini to v2 (#34895)

feat(run): migrate non-interactive prompts to V2
feat(run): route mini prompts through V2
fix(run): use current session contracts
fix(run): fix V2 prompt turns
feat(cli): add mini subcommand
feat(run): use settled execution events
fix(run): handle remote prompt file attachments
feat(run): send prompt files as attachments
feat(run): use current APIs for run state
fix(run): adopt app-node runtime deps
feat(run): track subagent sessions
feat(run): move catalogs and default model onto current APIs
This commit is contained in:
Simon Klee
2026-07-02 12:06:49 +02:00
committed by GitHub
parent 140224b0fc
commit f016392368
61 changed files with 5203 additions and 7105 deletions
+24 -18
View File
@@ -5,8 +5,7 @@
// argv parsing → server boot → SDK call → event consumption → exit code (like
// the original /event race or #27371's invalid-model hang).
//
// Configuration flows through opencode's built-in test affordances:
// - OPENCODE_CONFIG_CONTENT : provider config inline, no files to find
// Configuration flows through an isolated global opencode.json under the temp home:
// - OPENCODE_TEST_HOME : pins os.homedir() → tmpdir
// - OPENCODE_DISABLE_PROJECT_CONFIG : skip walking up for opencode.json
// - OPENCODE_PURE : skip external plugin discovery + install
@@ -59,15 +58,16 @@ function forkStderrDrain(stream: ReadableStream<Uint8Array>, into: string[]) {
)
}
function isolatedEnv(home: string, configJson: string): Record<string, string> {
function isolatedEnv(home: string): Record<string, string> {
return {
OPENCODE_TEST_HOME: home,
PWD: home,
HOME: home,
XDG_CONFIG_HOME: path.join(home, ".config"),
XDG_DATA_HOME: path.join(home, ".local/share"),
XDG_STATE_HOME: path.join(home, ".local/state"),
XDG_CACHE_HOME: path.join(home, ".cache"),
OPENCODE_CONFIG_CONTENT: configJson,
OPENCODE_CONFIG_DIR: path.join(home, ".opencode-config"),
OPENCODE_DISABLE_PROJECT_CONFIG: "1",
OPENCODE_PURE: "1",
OPENCODE_DISABLE_AUTOUPDATE: "1",
@@ -89,7 +89,11 @@ export type RunHandle = {
readonly result: Effect.Effect<RunResult>
}
export type SpawnOpts = { readonly timeoutMs?: number; readonly env?: Record<string, string> }
export type SpawnOpts = {
readonly timeoutMs?: number
readonly env?: Record<string, string>
readonly config?: ReturnType<typeof testProviderConfig> & Record<string, unknown>
}
// Typed equivalent of constructing argv for `opencode run`. New flags should
// land here so tests stay grep-able and refactor-safe.
@@ -201,10 +205,15 @@ export function withCliFixture<A, E>(
.pipe(Effect.retry(Schedule.spaced("50 millis").pipe(Schedule.both(Schedule.recurs(20)))), Effect.ignore),
)
const configJson = JSON.stringify(testProviderConfig(llm.url))
const env = isolatedEnv(home, configJson)
const env = isolatedEnv(home)
const writeConfig = (config?: SpawnOpts["config"]) =>
fs
.writeWithDirs(path.join(env.OPENCODE_CONFIG_DIR, "opencode.json"), JSON.stringify(config ?? testProviderConfig(llm.url)))
.pipe(Effect.orDie)
yield* writeConfig()
const spawn = Effect.fn("opencode.spawn")(function* (args: string[], opts?: SpawnOpts) {
yield* writeConfig(opts?.config)
const start = Date.now()
const timeoutMs = opts?.timeoutMs ?? 30_000
// stdin: "ignore" so the child doesn't see a piped stdin and block
@@ -212,7 +221,7 @@ export function withCliFixture<A, E>(
// consumed as the prompt). The old Process.run wrapper defaulted to
// ignore; ChildProcess.make defaults to pipe, so we set it explicitly.
const command = ChildProcess.make("bun", ["run", "--conditions=browser", cliEntry, ...args], {
cwd: home,
cwd: opencodeRoot,
env: { ...env, ...opts?.env },
extendEnv: true,
stdin: "ignore",
@@ -250,6 +259,7 @@ export function withCliFixture<A, E>(
const runArgs = (message: string, opts?: RunOpts) => {
const argv: string[] = ["run"]
if (!opts?.extraArgs?.includes("--attach")) argv.push("--dir", home)
if (opts?.printLogs) argv.push("--print-logs")
argv.push("--model", opts?.model ?? testModelID)
if (opts?.agent) argv.push("--agent", opts.agent)
@@ -264,13 +274,8 @@ export function withCliFixture<A, E>(
if (!opts?.permission) return opts
return {
...opts,
env: {
...opts.env,
OPENCODE_CONFIG_CONTENT: JSON.stringify({
...testProviderConfig(llm.url),
permission: opts.permission,
}),
},
env: opts.env,
config: { ...testProviderConfig(llm.url), permission: opts.permission },
}
}
@@ -281,10 +286,11 @@ export function withCliFixture<A, E>(
const startRun = Effect.fn("opencode.startRun")(function* (message: string, opts?: RunOpts) {
const start = Date.now()
const options = runOpts(opts)
yield* writeConfig(options?.config)
const proc = yield* Effect.acquireRelease(
Effect.sync(() =>
Bun.spawn(["bun", "run", "--conditions=browser", cliEntry, ...runArgs(message, opts)], {
cwd: home,
cwd: opencodeRoot,
env: { ...process.env, ...env, ...options?.env },
stdin: "ignore",
stdout: "pipe",
@@ -325,7 +331,7 @@ export function withCliFixture<A, E>(
const proc = yield* Effect.acquireRelease(
Effect.sync(() =>
Bun.spawn(["bun", "run", "--conditions=browser", cliEntry, ...argv], {
cwd: home,
cwd: opencodeRoot,
env: { ...process.env, ...env, ...opts?.env },
stdout: "pipe",
stderr: "pipe",
@@ -396,7 +402,7 @@ export function withCliFixture<A, E>(
const proc = yield* Effect.acquireRelease(
Effect.sync(() =>
Bun.spawn(["bun", "run", "--conditions=browser", cliEntry, ...argv], {
cwd: opts?.cwd ?? home,
cwd: opencodeRoot,
env: { ...process.env, ...env, ...opts?.env },
stdin: "pipe",
stdout: "pipe",