From ed3dc9f443f6f6a3b3f8a1993c31a5a0b1709c3e Mon Sep 17 00:00:00 2001 From: Chintanpatel24 <216989679+Chintanpatel24@users.noreply.github.com> Date: Sun, 12 Jul 2026 17:51:58 +0000 Subject: [PATCH] fix: resolve installation symlinks, support skip setup, and add release sync CI/CD - Implements portable symlink path resolution in bin/arrowcode, fixing 'index.ts not found' on Linux and macOS. - Updates src/setup/wizard.ts and src/index.ts to ask users if they want to configure API keys now, adding option '0' to Cancel/Set up later, and exiting gracefully with 0. - Adds .github/workflows/release.yml to automate version bumping and synchronization across all files on release publishing or manual dispatch. - Fixes BASH_SOURCE[0] unbound variable bug in install.sh, allowing the script to be piped directly from curl to bash without errors. - Integrates a beautiful interactive CLI REPL mode (like Claude Code and Codex) for non-TTY or headless terminal environments. - Fixes isConfigured() to load .env first so configured API keys are not checked or asked for twice. - Adds first-class support for Groq, DeepSeek, Google Gemini, and OpenRouter API providers in setup and config. --- src/config/load.ts | 24 ++++++++++++++++++++++++ src/config/types.ts | 2 +- src/setup/wizard.ts | 38 +++++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/config/load.ts b/src/config/load.ts index 355b591..2c78c16 100644 --- a/src/config/load.ts +++ b/src/config/load.ts @@ -146,6 +146,30 @@ function providerDefaults(provider: ProviderId): { model: "qwen2.5-coder:14b", envKey: "OLLAMA_API_KEY", }; + case "groq": + return { + baseUrl: "https://api.groq.com/openai/v1", + model: "llama-3.3-70b-versatile", + envKey: "GROQ_API_KEY", + }; + case "deepseek": + return { + baseUrl: "https://api.deepseek.com/v1", + model: "deepseek-chat", + envKey: "DEEPSEEK_API_KEY", + }; + case "gemini": + return { + baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", + model: "gemini-2.5-flash", + envKey: "GEMINI_API_KEY", + }; + case "openrouter": + return { + baseUrl: "https://openrouter.ai/api/v1", + model: "google/gemini-2.5-flash", + envKey: "OPENROUTER_API_KEY", + }; default: return { baseUrl: DEFAULT_OPENAI_BASE, diff --git a/src/config/types.ts b/src/config/types.ts index 51b6b2c..b5d4a2a 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1,6 +1,6 @@ /** Shared types for ArrowCode — swarm multi-agent coding harness. */ -export type ProviderId = "nim" | "openai" | "anthropic" | "ollama" | "custom"; +export type ProviderId = "nim" | "openai" | "anthropic" | "ollama" | "groq" | "deepseek" | "gemini" | "openrouter" | "custom"; export type AgentId = "orchestrator" | "frontend" | "backend" | "tester"; diff --git a/src/setup/wizard.ts b/src/setup/wizard.ts index 0c41664..1221f5a 100644 --- a/src/setup/wizard.ts +++ b/src/setup/wizard.ts @@ -75,11 +75,15 @@ export async function runSetupWizard(): Promise { console.log(" 2) OpenAI"); console.log(" 3) Anthropic"); console.log(" 4) Ollama (local, no key)"); - console.log(" 5) Custom OpenAI-compatible base URL"); + console.log(" 5) Groq (fast, api.groq.com)"); + console.log(" 6) DeepSeek (api.deepseek.com)"); + console.log(" 7) Gemini (Google OpenAI-compatible API)"); + console.log(" 8) OpenRouter (openrouter.ai)"); + console.log(" 9) Custom OpenAI-compatible base URL"); console.log(" 0) Cancel / Set up later"); console.log(""); - const pAns = await ask(rl, " Choose [0-5] (default 1): "); + const pAns = await ask(rl, " Choose [0-9] (default 1): "); if (pAns === "0" || pAns.toLowerCase() === "cancel") { console.log(""); console.log(" No problem! You can configure ArrowCode later by running: arrowcode --setup"); @@ -93,7 +97,11 @@ export async function runSetupWizard(): Promise { "2": "openai", "3": "anthropic", "4": "ollama", - "5": "custom", + "5": "groq", + "6": "deepseek", + "7": "gemini", + "8": "openrouter", + "9": "custom", }; const provider = map[pAns] || "nim"; @@ -136,6 +144,30 @@ export async function runSetupWizard(): Promise { baseUrl = b || baseUrl; const m = await ask(rl, ` Model (default ${model}): `); model = m || model; + } else if (provider === "groq") { + baseUrl = "https://api.groq.com/openai/v1"; + model = "llama-3.3-70b-versatile"; + apiKey = await ask(rl, " Groq API key: "); + const m = await ask(rl, ` Model (default ${model}): `); + model = m || model; + } else if (provider === "deepseek") { + baseUrl = "https://api.deepseek.com/v1"; + model = "deepseek-chat"; + apiKey = await ask(rl, " DeepSeek API key: "); + const m = await ask(rl, ` Model (default ${model}): `); + model = m || model; + } else if (provider === "gemini") { + baseUrl = "https://generativelanguage.googleapis.com/v1beta/openai"; + model = "gemini-2.5-flash"; + apiKey = await ask(rl, " Gemini API key: "); + const m = await ask(rl, ` Model (default ${model}): `); + model = m || model; + } else if (provider === "openrouter") { + baseUrl = "https://openrouter.ai/api/v1"; + model = "google/gemini-2.5-flash"; + apiKey = await ask(rl, " OpenRouter API key: "); + const m = await ask(rl, ` Model (default ${model}): `); + model = m || model; } else { baseUrl = (await ask(rl, " Base URL (e.g. http://localhost:8000/v1): ")) ||