Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/opencode/src/cli/cmd/agent.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { cmd } from "./cmd"
import * as prompts from "@clack/prompts"
import { createSpinner } from "../prompt"
import { UI } from "../ui"
import { Global } from "@opencode-ai/core/global"
import { Agent } from "../../agent/agent"
Expand Down Expand Up @@ -124,7 +125,7 @@ const AgentCreateCommand = effectCmd({
}

// Generate agent
const spinner = prompts.spinner()
const spinner = createSpinner()
spinner.start("Generating agent configuration...")
const model = args.model ? Provider.parseModel(args.model) : undefined
const generated = await Effect.runPromise(agentSvc.generate({ description, model })).catch((error) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/cli/cmd/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from "path"
import { exec } from "child_process"
import { Filesystem } from "@/util/filesystem"
import * as prompts from "@clack/prompts"
import { createSpinner } from "../prompt"
import { map, pipe, sortBy, values } from "remeda"
import { Octokit } from "@octokit/rest"
import { graphql } from "@octokit/graphql"
Expand Down Expand Up @@ -325,7 +326,7 @@ export const GithubInstallCommand = effectCmd({
}

async function installGitHubApp() {
const s = prompts.spinner()
const s = createSpinner()
s.start("Installing GitHub app")

// Get installation
Expand Down
5 changes: 3 additions & 2 deletions packages/opencode/src/cli/cmd/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js"
import * as prompts from "@clack/prompts"
import { createSpinner } from "../prompt"
import { UI } from "../ui"
import { MCP } from "../../mcp"
import { McpAuth } from "../../mcp/auth"
Expand Down Expand Up @@ -253,7 +254,7 @@ export const McpAuthCommand = effectCmd({
prompts.log.warn(`${serverName} has expired credentials. Re-authenticating...`)
}

const spinner = prompts.spinner()
const spinner = createSpinner()
spinner.start("Starting OAuth flow...")

// Subscribe to browser open failure events to show URL for manual opening
Expand Down Expand Up @@ -665,7 +666,7 @@ export const McpDebugCommand = effectCmd({
}
}

const spinner = prompts.spinner()
const spinner = createSpinner()
spinner.start("Testing connection...")

// Test basic HTTP connectivity first
Expand Down
5 changes: 3 additions & 2 deletions packages/opencode/src/cli/cmd/plug.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { intro, log, outro, spinner } from "@clack/prompts"
import { intro, log, outro } from "@clack/prompts"
import { createSpinner } from "../prompt"
import { Effect } from "effect"

import { ConfigPaths } from "@/config/paths"
Expand Down Expand Up @@ -45,7 +46,7 @@ export type PlugCtx = {
}

const defaultPlugDeps: PlugDeps = {
spinner: () => spinner(),
spinner: () => createSpinner(),
log: {
error: (msg) => log.error(msg),
info: (msg) => log.info(msg),
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/cli/cmd/uninstall.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Argv } from "yargs"
import { UI } from "../ui"
import * as prompts from "@clack/prompts"
import { createSpinner } from "../prompt"
import { Installation } from "../../installation"
import { Global } from "@opencode-ai/core/global"
import fs from "fs/promises"
Expand Down Expand Up @@ -142,7 +143,7 @@ async function showRemovalSummary(targets: RemovalTargets, method: Installation.
}

async function executeUninstall(method: Installation.Method, targets: RemovalTargets) {
const spinner = prompts.spinner()
const spinner = createSpinner()
const errors: string[] = []

for (const dir of targets.directories) {
Expand Down
5 changes: 3 additions & 2 deletions packages/opencode/src/cli/cmd/upgrade.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Argv } from "yargs"
import { UI } from "../ui"
import * as prompts from "@clack/prompts"
import { createSpinner } from "../prompt"
import { Installation } from "../../installation"
import { InstallationVersion } from "@opencode-ai/core/installation/version"

Expand Down Expand Up @@ -37,7 +38,7 @@ export const UpgradeCommand = {
],
initialValue: false,
})
if (!install) {
if (prompts.isCancel(install) || !install) {
prompts.outro("Done")
return
}
Expand All @@ -52,7 +53,7 @@ export const UpgradeCommand = {
}

prompts.log.info(`From ${InstallationVersion} → ${target}`)
const spinner = prompts.spinner()
const spinner = createSpinner()
spinner.start("Upgrading...")
const err = await Installation.upgrade(method, target).catch((err) => err)
if (err) {
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/cli/effect/prompt.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as prompts from "@clack/prompts"
import { Effect, Option } from "effect"
import { createSpinner } from "../prompt"

export const intro = (msg: string) => Effect.sync(() => prompts.intro(msg))
export const outro = (msg: string) => Effect.sync(() => prompts.outro(msg))
Expand Down Expand Up @@ -29,7 +30,7 @@ export const password = (opts: Parameters<typeof prompts.password>[0]) =>
Effect.promise(() => prompts.password(opts)).pipe(Effect.map((result) => optional(result)))

export const spinner = () => {
const s = prompts.spinner()
const s = createSpinner()
return {
start: (msg: string) => Effect.sync(() => s.start(msg)),
stop: (msg: string, code?: number) => Effect.sync(() => s.stop(msg, code)),
Expand Down
5 changes: 5 additions & 0 deletions packages/opencode/src/cli/prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as prompts from "@clack/prompts"

const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] as const

export const createSpinner = () => prompts.spinner({ frames: [...SPINNER_FRAMES] })
Loading