From b84681d5a4f12a14db3cd3c8cc3b8c979c7a645f Mon Sep 17 00:00:00 2001 From: decolua Date: Thu, 3 Sep 2026 23:27:04 +0700 Subject: [PATCH] feat(cli-tools): replace copilot mitm with vscode extension setup guide Co-Authored-By: Claude Code --- .../cli-tools/[toolId]/ToolDetailClient.js | 4 +- .../cli-tools/components/ToolSummaryCard.js | 5 +- src/app/api/cli-tools/all-statuses/route.js | 2 - src/shared/constants/cliTools.js | 54 ++++++++++--------- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js b/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js index 209a6d33..82211e48 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js +++ b/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js @@ -8,7 +8,7 @@ import { getModelsByProviderId, PROVIDER_ID_TO_ALIAS } from "@/shared/constants/ import { ClaudeToolCard, CodexToolCard, DroidToolCard, OpenClawToolCard, HermesToolCard, DefaultToolCard, OpenCodeToolCard, CoworkToolCard, - CopilotToolCard, ClineToolCard, KiloToolCard, DeepSeekTuiToolCard, + ClineToolCard, KiloToolCard, DeepSeekTuiToolCard, JcodeToolCard, GrokBuildToolCard, } from "../components"; @@ -156,8 +156,6 @@ export default function ToolDetailClient({ toolId, machineId }) { return ; case "hermes": return ; - case "copilot": - return ; case "cline": return ; case "kilo": diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/ToolSummaryCard.js b/src/app/(dashboard)/dashboard/cli-tools/components/ToolSummaryCard.js index 6e944d79..83d6c15b 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/components/ToolSummaryCard.js +++ b/src/app/(dashboard)/dashboard/cli-tools/components/ToolSummaryCard.js @@ -5,7 +5,8 @@ import Image from "next/image"; import { Card } from "@/shared/components"; // Derive simple connected/configured/not-installed status from API payload -function getStatus(status) { +function getStatus(status, tool) { + if (tool?.configType === "guide") return { label: "Guide", cls: "bg-blue-500/10 text-blue-600 dark:text-blue-400" }; if (!status) return { label: "Unknown", cls: "bg-gray-500/10 text-gray-500" }; if (!status.installed) return { label: "Not installed", cls: "bg-gray-500/10 text-gray-500" }; if (status.has9Router) return { label: "Connected", cls: "bg-green-500/10 text-green-600 dark:text-green-400" }; @@ -13,7 +14,7 @@ function getStatus(status) { } export default function ToolSummaryCard({ toolId, tool, status }) { - const s = getStatus(status); + const s = getStatus(status, tool); return ( diff --git a/src/app/api/cli-tools/all-statuses/route.js b/src/app/api/cli-tools/all-statuses/route.js index 5925e526..b4270163 100644 --- a/src/app/api/cli-tools/all-statuses/route.js +++ b/src/app/api/cli-tools/all-statuses/route.js @@ -8,7 +8,6 @@ import { GET as droidGet } from "../droid-settings/route"; import { GET as openclawGet } from "../openclaw-settings/route"; import { GET as hermesGet } from "../hermes-settings/route"; import { GET as coworkGet } from "../cowork-settings/route"; -import { GET as copilotGet } from "../copilot-settings/route"; import { GET as clineGet } from "../cline-settings/route"; import { GET as kiloGet } from "../kilo-settings/route"; import { GET as deepseekTuiGet } from "../deepseek-tui-settings/route"; @@ -24,7 +23,6 @@ const STATUS_GETTERS = { openclaw: openclawGet, hermes: hermesGet, cowork: coworkGet, - copilot: copilotGet, cline: clineGet, kilo: kiloGet, "deepseek-tui": deepseekTuiGet, diff --git a/src/shared/constants/cliTools.js b/src/shared/constants/cliTools.js index 9a388866..0f7c0236 100644 --- a/src/shared/constants/cliTools.js +++ b/src/shared/constants/cliTools.js @@ -30,32 +30,6 @@ export const MITM_TOOLS = { { id: "gemini-3-flash", name: "Gemini 3 Flash (Command)", alias: "gemini-3-flash" }, ], }, - copilot: { - id: "copilot", - name: "GitHub Copilot", - image: "/providers/copilot.png", - color: "#1F6FEB", - description: "GitHub Copilot IDE with MITM", - configType: "mitm", - mitmDomain: "api.individual.githubcopilot.com", - modelAliases: ["gpt-5-mini", "gpt-5.4-nano", "claude-haiku-4.5", "gpt-4o", "gpt-4.1"], - defaultModels: [ - // Verified via live MITM passthrough capture of the GitHub Copilot CLI: its model - // picker offers "GPT-5 mini" (default → wire id "gpt-5-mini"), "Claude Haiku 4.5" - // ("claude-haiku-4.5") and "Auto". "Auto" is NOT a wire id — Copilot dispatches - // concrete models dynamically (observed "gpt-5.4-nano" for light tasks and - // "claude-haiku-4.5"), so it needs no slot of its own. Without a slot for - // gpt-5-mini / gpt-5.4-nano, getMappedModel returns null and the /chat/completions - // call is passed through to GitHub Copilot instead of the configured provider — - // and gpt-5-mini is the CLI default, so the primary turn leaks (same class as the - // Kiro "auto" misrouting). gpt-4o / gpt-4.1 are kept for the VS Code Copilot Chat picker. - { id: "gpt-5-mini", name: "GPT-5 mini", alias: "gpt-5-mini" }, - { id: "gpt-5.4-nano", name: "GPT-5.4 nano", alias: "gpt-5.4-nano" }, - { id: "claude-haiku-4.5", name: "Claude Haiku 4.5", alias: "claude-haiku-4.5" }, - { id: "gpt-4o", name: "GPT-4o", alias: "gpt-4o" }, - { id: "gpt-4.1", name: "GPT-4.1", alias: "gpt-4.1" }, - ], - }, kiro: { id: "kiro", name: "Kiro", @@ -140,6 +114,34 @@ export const CLI_TOOLS = { description: "OpenAI Codex CLI", configType: "custom", }, + copilot: { + id: "copilot", + name: "GitHub Copilot", + image: "/providers/copilot.png", + color: "#1F6FEB", + description: "GitHub Copilot in VS Code via 9Router extension", + configType: "guide", + docsUrl: "https://marketplace.visualstudio.com/items?itemName=hotrungnhan.9router-for-github-copilot", + guideSteps: [ + { + step: 1, + title: "Install Extension", + desc: "In VS Code, open Extensions (Ctrl+Shift+X or Cmd+Shift+X), search for '9Router for Github Copilot' and click Install.", + }, + { + step: 2, + title: "Configure Server", + desc: "Press Cmd+Shift+P (or Ctrl+Shift+P), run '9Router: Configure Server', then enter your Server URL and API Key:", + value: "{{baseUrl}}", + copyable: true, + }, + { + step: 3, + title: "Select Model in Copilot Chat", + desc: "Open Copilot Chat, click the model picker at the bottom → 'Manage Models...' → check the 9Router models to use.", + }, + ], + }, opencode: { id: "opencode", name: "OpenCode",