diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 753becc267..59608f7570 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -1,40 +1,17 @@ import yargs from "yargs" import { hideBin } from "yargs/helpers" -import { RunCommand } from "./cli/cmd/run" -import { GenerateCommand } from "./cli/cmd/generate" import { Log } from "./util/log" -import { ConsoleCommand } from "./cli/cmd/account" -import { ProvidersCommand } from "./cli/cmd/providers" -import { AgentCommand } from "./cli/cmd/agent" -import { UpgradeCommand } from "./cli/cmd/upgrade" -import { UninstallCommand } from "./cli/cmd/uninstall" -import { ModelsCommand } from "./cli/cmd/models" import { UI } from "./cli/ui" import { Installation } from "./installation" import { NamedError } from "@opencode-ai/util/error" import { FormatError } from "./cli/error" -import { ServeCommand } from "./cli/cmd/serve" import { Filesystem } from "./util/filesystem" -import { DebugCommand } from "./cli/cmd/debug" -import { StatsCommand } from "./cli/cmd/stats" -import { McpCommand } from "./cli/cmd/mcp" -import { GithubCommand } from "./cli/cmd/github" -import { ExportCommand } from "./cli/cmd/export" -import { ImportCommand } from "./cli/cmd/import" -import { AttachCommand } from "./cli/cmd/tui/attach" -import { TuiThreadCommand } from "./cli/cmd/tui/thread" -import { AcpCommand } from "./cli/cmd/acp" import { EOL } from "os" -import { WebCommand } from "./cli/cmd/web" -import { PrCommand } from "./cli/cmd/pr" -import { SessionCommand } from "./cli/cmd/session" -import { DbCommand } from "./cli/cmd/db" import path from "path" import { Global } from "./global" import { JsonMigration } from "./storage/json-migration" import { Database } from "./storage/db" import { errorMessage } from "./util/error" -import { PluginCommand } from "./cli/cmd/plug" import { Heap } from "./cli/heap" import { drizzle } from "drizzle-orm/bun-sqlite" @@ -52,6 +29,156 @@ process.on("uncaughtException", (e) => { const args = hideBin(process.argv) +type Mode = + | "all" + | "none" + | "tui" + | "attach" + | "run" + | "acp" + | "mcp" + | "generate" + | "debug" + | "console" + | "providers" + | "agent" + | "upgrade" + | "uninstall" + | "serve" + | "web" + | "models" + | "stats" + | "export" + | "import" + | "github" + | "pr" + | "session" + | "plugin" + | "db" + +const map = new Map([ + ["attach", "attach"], + ["run", "run"], + ["acp", "acp"], + ["mcp", "mcp"], + ["generate", "generate"], + ["debug", "debug"], + ["console", "console"], + ["providers", "providers"], + ["auth", "providers"], + ["agent", "agent"], + ["upgrade", "upgrade"], + ["uninstall", "uninstall"], + ["serve", "serve"], + ["web", "web"], + ["models", "models"], + ["stats", "stats"], + ["export", "export"], + ["import", "import"], + ["github", "github"], + ["pr", "pr"], + ["session", "session"], + ["plugin", "plugin"], + ["plug", "plugin"], + ["db", "db"], +]) + +function flag(arg: string, name: string) { + return arg === `--${name}` || arg === `--no-${name}` || arg.startsWith(`--${name}=`) +} + +function value(arg: string, name: string) { + return arg === `--${name}` || arg.startsWith(`--${name}=`) +} + +// Match the root parser closely enough to decide which top-level module to load. +function pick(argv: string[]): Mode { + for (let i = 0; i < argv.length; i++) { + const arg = argv[i] + if (!arg) continue + if (arg === "--") return "tui" + if (arg === "completion") return "all" + if (arg === "--help" || arg === "-h") return "all" + if (arg === "--version" || arg === "-v") return "none" + if (flag(arg, "print-logs") || flag(arg, "pure")) continue + if (value(arg, "log-level")) { + if (arg === "--log-level") i += 1 + continue + } + if (arg.startsWith("-") && !arg.startsWith("--")) { + if (arg.includes("h")) return "all" + if (arg.includes("v")) return "none" + return "tui" + } + if (arg.startsWith("-")) return "tui" + return map.get(arg) ?? "tui" + } + + return "tui" +} + +const mode = pick(args) +const all = mode === "all" +const none = mode === "none" + +function load(on: boolean, get: () => Promise): Promise { + if (!on) { + return Promise.resolve(undefined) + } + + return get() +} + +const [ + TuiThreadCommand, + AttachCommand, + RunCommand, + AcpCommand, + McpCommand, + GenerateCommand, + DebugCommand, + ConsoleCommand, + ProvidersCommand, + AgentCommand, + UpgradeCommand, + UninstallCommand, + ServeCommand, + WebCommand, + ModelsCommand, + StatsCommand, + ExportCommand, + ImportCommand, + GithubCommand, + PrCommand, + SessionCommand, + PluginCommand, + DbCommand, +] = await Promise.all([ + load(!none && (all || mode === "tui"), () => import("./cli/cmd/tui/thread").then((x) => x.TuiThreadCommand)), + load(!none && (all || mode === "attach"), () => import("./cli/cmd/tui/attach").then((x) => x.AttachCommand)), + load(!none && (all || mode === "run"), () => import("./cli/cmd/run").then((x) => x.RunCommand)), + load(!none && (all || mode === "acp"), () => import("./cli/cmd/acp").then((x) => x.AcpCommand)), + load(!none && (all || mode === "mcp"), () => import("./cli/cmd/mcp").then((x) => x.McpCommand)), + load(!none && (all || mode === "generate"), () => import("./cli/cmd/generate").then((x) => x.GenerateCommand)), + load(!none && (all || mode === "debug"), () => import("./cli/cmd/debug").then((x) => x.DebugCommand)), + load(!none && (all || mode === "console"), () => import("./cli/cmd/account").then((x) => x.ConsoleCommand)), + load(!none && (all || mode === "providers"), () => import("./cli/cmd/providers").then((x) => x.ProvidersCommand)), + load(!none && (all || mode === "agent"), () => import("./cli/cmd/agent").then((x) => x.AgentCommand)), + load(!none && (all || mode === "upgrade"), () => import("./cli/cmd/upgrade").then((x) => x.UpgradeCommand)), + load(!none && (all || mode === "uninstall"), () => import("./cli/cmd/uninstall").then((x) => x.UninstallCommand)), + load(!none && (all || mode === "serve"), () => import("./cli/cmd/serve").then((x) => x.ServeCommand)), + load(!none && (all || mode === "web"), () => import("./cli/cmd/web").then((x) => x.WebCommand)), + load(!none && (all || mode === "models"), () => import("./cli/cmd/models").then((x) => x.ModelsCommand)), + load(!none && (all || mode === "stats"), () => import("./cli/cmd/stats").then((x) => x.StatsCommand)), + load(!none && (all || mode === "export"), () => import("./cli/cmd/export").then((x) => x.ExportCommand)), + load(!none && (all || mode === "import"), () => import("./cli/cmd/import").then((x) => x.ImportCommand)), + load(!none && (all || mode === "github"), () => import("./cli/cmd/github").then((x) => x.GithubCommand)), + load(!none && (all || mode === "pr"), () => import("./cli/cmd/pr").then((x) => x.PrCommand)), + load(!none && (all || mode === "session"), () => import("./cli/cmd/session").then((x) => x.SessionCommand)), + load(!none && (all || mode === "plugin"), () => import("./cli/cmd/plug").then((x) => x.PluginCommand)), + load(!none && (all || mode === "db"), () => import("./cli/cmd/db").then((x) => x.DbCommand)), +]) + function show(out: string) { const text = out.trimStart() if (!text.startsWith("opencode ")) { @@ -148,29 +275,100 @@ const cli = yargs(args) }) .usage("") .completion("completion", "generate shell completion script") - .command(AcpCommand) - .command(McpCommand) - .command(TuiThreadCommand) - .command(AttachCommand) - .command(RunCommand) - .command(GenerateCommand) - .command(DebugCommand) - .command(ConsoleCommand) - .command(ProvidersCommand) - .command(AgentCommand) - .command(UpgradeCommand) - .command(UninstallCommand) - .command(ServeCommand) - .command(WebCommand) - .command(ModelsCommand) - .command(StatsCommand) - .command(ExportCommand) - .command(ImportCommand) - .command(GithubCommand) - .command(PrCommand) - .command(SessionCommand) - .command(PluginCommand) - .command(DbCommand) + +if (TuiThreadCommand) { + cli.command(TuiThreadCommand) +} + +if (AttachCommand) { + cli.command(AttachCommand) +} + +if (AcpCommand) { + cli.command(AcpCommand) +} + +if (McpCommand) { + cli.command(McpCommand) +} + +if (RunCommand) { + cli.command(RunCommand) +} + +if (GenerateCommand) { + cli.command(GenerateCommand) +} + +if (DebugCommand) { + cli.command(DebugCommand) +} + +if (ConsoleCommand) { + cli.command(ConsoleCommand) +} + +if (ProvidersCommand) { + cli.command(ProvidersCommand) +} + +if (AgentCommand) { + cli.command(AgentCommand) +} + +if (UpgradeCommand) { + cli.command(UpgradeCommand) +} + +if (UninstallCommand) { + cli.command(UninstallCommand) +} + +if (ServeCommand) { + cli.command(ServeCommand) +} + +if (WebCommand) { + cli.command(WebCommand) +} + +if (ModelsCommand) { + cli.command(ModelsCommand) +} + +if (StatsCommand) { + cli.command(StatsCommand) +} + +if (ExportCommand) { + cli.command(ExportCommand) +} + +if (ImportCommand) { + cli.command(ImportCommand) +} + +if (GithubCommand) { + cli.command(GithubCommand) +} + +if (PrCommand) { + cli.command(PrCommand) +} + +if (SessionCommand) { + cli.command(SessionCommand) +} + +if (PluginCommand) { + cli.command(PluginCommand) +} + +if (DbCommand) { + cli.command(DbCommand) +} + +cli .fail((msg, err) => { if ( msg?.startsWith("Unknown argument") ||