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
389 changes: 310 additions & 79 deletions README.md

Large diffs are not rendered by default.

241 changes: 104 additions & 137 deletions bun.lock

Large diffs are not rendered by default.

80 changes: 46 additions & 34 deletions install
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
APP=opencode
APP=closecode

MUTED='\033[0;2m'
RED='\033[0;31m'
ORANGE='\033[38;5;214m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

usage() {
cat <<EOF
OpenCode Installer
CloseCode Installer

Usage: install.sh [options]

Options:
-h, --help Display this help message
-v, --version <version> Install a specific version (e.g., 1.0.180)
-v, --version <version> Install a specific version (e.g., 1.0.0)
-b, --binary <path> Install from a local binary instead of downloading
--no-modify-path Don't modify shell config files (.zshrc, .bashrc, etc.)

Examples:
curl -fsSL https://opencode.ai/install | bash
curl -fsSL https://opencode.ai/install | bash -s -- --version 1.0.180
./install --binary /path/to/opencode
curl -fsSL https://raw.githubusercontent.com/windro-xdd/opencode/closecode-features/install | bash
curl -fsSL https://raw.githubusercontent.com/windro-xdd/opencode/closecode-features/install | bash -s -- --version 1.0.0
./install --binary /path/to/closecode
EOF
}

Expand Down Expand Up @@ -65,7 +66,7 @@ while [[ $# -gt 0 ]]; do
esac
done

INSTALL_DIR=$HOME/.opencode/bin
INSTALL_DIR=$HOME/.closecode/bin
mkdir -p "$INSTALL_DIR"

# If --binary is provided, skip all download/detection logic
Expand Down Expand Up @@ -167,8 +168,8 @@ else
fi

if [ -z "$requested_version" ]; then
url="https://github.com/anomalyco/opencode/releases/latest/download/$filename"
specific_version=$(curl -s https://api.github.com/repos/anomalyco/opencode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
url="https://github.com/windro-xdd/opencode/releases/latest/download/$filename"
specific_version=$(curl -s https://api.github.com/repos/windro-xdd/opencode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')

if [[ $? -ne 0 || -z "$specific_version" ]]; then
echo -e "${RED}Failed to fetch version information${NC}"
Expand All @@ -177,14 +178,14 @@ else
else
# Strip leading 'v' if present
requested_version="${requested_version#v}"
url="https://github.com/anomalyco/opencode/releases/download/v${requested_version}/$filename"
url="https://github.com/windro-xdd/opencode/releases/download/v${requested_version}/$filename"
specific_version=$requested_version

# Verify the release exists before downloading
http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/anomalyco/opencode/releases/tag/v${requested_version}")
http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/windro-xdd/opencode/releases/tag/v${requested_version}")
if [ "$http_status" = "404" ]; then
echo -e "${RED}Error: Release v${requested_version} not found${NC}"
echo -e "${MUTED}Available releases: https://github.com/anomalyco/opencode/releases${NC}"
echo -e "${MUTED}Available releases: https://github.com/windro-xdd/opencode/releases${NC}"
exit 1
fi
fi
Expand All @@ -205,11 +206,11 @@ print_message() {
}

check_version() {
if command -v opencode >/dev/null 2>&1; then
opencode_path=$(which opencode)
if command -v closecode >/dev/null 2>&1; then
closecode_path=$(which closecode)

## Check the installed version
installed_version=$(opencode --version 2>/dev/null || echo "")
installed_version=$(closecode --version 2>/dev/null || echo "")

if [[ "$installed_version" != "$specific_version" ]]; then
print_message info "${MUTED}Installed version: ${NC}$installed_version."
Expand Down Expand Up @@ -247,7 +248,7 @@ print_progress() {
local empty=$(printf "%*s" "$off" "")
empty=${empty// /・}

printf "\r${ORANGE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4
printf "\r${CYAN}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4
}

download_with_progress() {
Expand All @@ -261,7 +262,7 @@ download_with_progress() {
fi

local tmp_dir=${TMPDIR:-/tmp}
local basename="${tmp_dir}/opencode_install_$$"
local basename="${tmp_dir}/closecode_install_$$"
local tracefile="${basename}.trace"

rm -f "$tracefile"
Expand Down Expand Up @@ -311,8 +312,8 @@ download_with_progress() {
}

download_and_install() {
print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version"
local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$"
print_message info "\n${MUTED}Installing ${NC}closecode ${MUTED}version: ${NC}$specific_version"
local tmp_dir="${TMPDIR:-/tmp}/closecode_install_$$"
mkdir -p "$tmp_dir"

if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then
Expand All @@ -326,15 +327,15 @@ download_and_install() {
unzip -q "$tmp_dir/$filename" -d "$tmp_dir"
fi

mv "$tmp_dir/opencode" "$INSTALL_DIR"
chmod 755 "${INSTALL_DIR}/opencode"
mv "$tmp_dir/closecode" "$INSTALL_DIR"
chmod 755 "${INSTALL_DIR}/closecode"
rm -rf "$tmp_dir"
}

install_from_binary() {
print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}from: ${NC}$binary_path"
cp "$binary_path" "${INSTALL_DIR}/opencode"
chmod 755 "${INSTALL_DIR}/opencode"
print_message info "\n${MUTED}Installing ${NC}closecode ${MUTED}from: ${NC}$binary_path"
cp "$binary_path" "${INSTALL_DIR}/closecode"
chmod 755 "${INSTALL_DIR}/closecode"
}

if [ -n "$binary_path" ]; then
Expand All @@ -352,9 +353,9 @@ add_to_path() {
if grep -Fxq "$command" "$config_file"; then
print_message info "Command already exists in $config_file, skipping write."
elif [[ -w $config_file ]]; then
echo -e "\n# opencode" >> "$config_file"
echo -e "\n# closecode" >> "$config_file"
echo "$command" >> "$config_file"
print_message info "${MUTED}Successfully added ${NC}opencode ${MUTED}to \$PATH in ${NC}$config_file"
print_message info "${MUTED}Successfully added ${NC}closecode ${MUTED}to \$PATH in ${NC}$config_file"
else
print_message warning "Manually add the directory to $config_file (or similar):"
print_message info " $command"
Expand Down Expand Up @@ -430,17 +431,28 @@ if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then
fi

echo -e ""
echo -e "${MUTED}  ${NC} ▄ "
echo -e "${MUTED}█▀▀█ █▀▀█ █▀▀█ █▀▀▄ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█"
echo -e "${MUTED}█░░█ █░░█ █▀▀▀ █░░█ ${NC}█░░░ █░░█ █░░█ █▀▀▀"
echo -e "${MUTED}▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀"
echo -e "${CYAN} ██████╗██╗ ██████╗ ███████╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗${NC}"
echo -e "${CYAN} ██╔════╝██║ ██╔═══██╗██╔════╝██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝${NC}"
echo -e "${CYAN} ██║ ██║ ██║ ██║███████╗█████╗ ██║ ██║ ██║██║ ██║█████╗ ${NC}"
echo -e "${CYAN} ██║ ██║ ██║ ██║╚════██║██╔══╝ ██║ ██║ ██║██║ ██║██╔══╝ ${NC}"
echo -e "${CYAN} ╚██████╗███████╗╚██████╔╝███████║███████╗╚██████╗╚██████╔╝██████╔╝███████╗${NC}"
echo -e "${CYAN} ╚═════╝╚══════╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝${NC}"
echo -e ""
echo -e "${MUTED}Free Claude & Gemini via Antigravity Proxy${NC}"
echo -e ""
echo -e "${MUTED}OpenCode includes free models, to start:${NC}"
echo -e "${MUTED}Prerequisites:${NC}"
echo -e " 1. ${CYAN}Antigravity Claude Proxy${NC} running on localhost:8080"
echo -e " ${MUTED}https://github.com/Antigravity-Cloud/antigravity${NC}"
echo -e ""
echo -e "cd <project> ${MUTED}# Open directory${NC}"
echo -e "opencode ${MUTED}# Run command${NC}"
echo -e "${MUTED}To start:${NC}"
echo -e ""
echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/docs"
echo -e " cd <project> ${MUTED}# Open your project directory${NC}"
echo -e " closecode ${MUTED}# Run CloseCode${NC}"
echo -e ""
echo -e "${MUTED}Features:${NC}"
echo -e " ${CYAN}Plan${NC} - Conversational AI that routes to the right agent"
echo -e " ${CYAN}Build${NC} - Direct code execution for small tasks"
echo -e " ${CYAN}Brain${NC} - Orchestrator for large multi-domain projects"
echo -e ""
echo -e "${MUTED}For more information: ${NC}https://github.com/windro-xdd/opencode"
echo -e ""
84 changes: 84 additions & 0 deletions packages/opencode/bin/closedcode
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env node

const childProcess = require("child_process")
const fs = require("fs")
const path = require("path")
const os = require("os")

function run(target) {
const result = childProcess.spawnSync(target, process.argv.slice(2), {
stdio: "inherit",
})
if (result.error) {
console.error(result.error.message)
process.exit(1)
}
const code = typeof result.status === "number" ? result.status : 0
process.exit(code)
}

const envPath = process.env.CLOSEDCODE_BIN_PATH
if (envPath) {
run(envPath)
}

const scriptPath = fs.realpathSync(__filename)
const scriptDir = path.dirname(scriptPath)

const platformMap = {
darwin: "darwin",
linux: "linux",
win32: "windows",
}
const archMap = {
x64: "x64",
arm64: "arm64",
arm: "arm",
}

let platform = platformMap[os.platform()]
if (!platform) {
platform = os.platform()
}
let arch = archMap[os.arch()]
if (!arch) {
arch = os.arch()
}
const base = "closedcode-" + platform + "-" + arch
const binary = platform === "windows" ? "closedcode.exe" : "closedcode"

function findBinary(startDir) {
let current = startDir
for (;;) {
const modules = path.join(current, "node_modules")
if (fs.existsSync(modules)) {
const entries = fs.readdirSync(modules)
for (const entry of entries) {
if (!entry.startsWith(base)) {
continue
}
const candidate = path.join(modules, entry, "bin", binary)
if (fs.existsSync(candidate)) {
return candidate
}
}
}
const parent = path.dirname(current)
if (parent === current) {
return
}
current = parent
}
}

const resolved = findBinary(scriptDir)
if (!resolved) {
console.error(
'It seems that your package manager failed to install the right version of the closedcode CLI for your platform. You can try manually installing the "' +
base +
'" package',
)
process.exit(1)
}

run(resolved)
5 changes: 3 additions & 2 deletions packages/opencode/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.1.14",
"name": "opencode",
"name": "closedcode",
"type": "module",
"license": "MIT",
"private": true,
Expand All @@ -18,7 +18,7 @@
"deploy": "echo 'Deploying application...' && bun run build && echo 'Deployment completed successfully'"
},
"bin": {
"opencode": "./bin/opencode"
"closedcode": "./bin/closedcode"
},
"exports": {
"./*": "./src/*.ts"
Expand Down Expand Up @@ -96,6 +96,7 @@
"clipboardy": "4.0.0",
"decimal.js": "10.5.0",
"diff": "catalog:",
"express": "5.2.1",
"fuzzysort": "3.1.0",
"gray-matter": "4.0.3",
"hono": "catalog:",
Expand Down
14 changes: 12 additions & 2 deletions packages/opencode/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,11 @@ export namespace Agent {
})

export async function get(agent: string) {
return state().then((x) => x[agent])
const agents = await state()
// Direct key lookup first, then by display name
const result = agents[agent] ?? Object.values(agents).find((a) => a.name === agent)
if (!result) throw new Error(`Agent not found: ${agent}`)
return result
}

export async function list() {
Expand All @@ -241,7 +245,13 @@ export namespace Agent {
}

export async function defaultAgent() {
return state().then((x) => Object.keys(x)[0])
const cfg = await Config.get()
const agents = await state()
// Use configured default_agent if it exists, otherwise fall back to "build"
if (cfg.default_agent && agents[cfg.default_agent]) {
return cfg.default_agent
}
return "build"
}

export async function generate(input: { description: string; model?: { providerID: string; modelID: string } }) {
Expand Down
Loading