UNPKG

@jovan158/vantage

Version:

See and control what your coding agent does

59 lines (58 loc) • 3.05 kB
// GitHub Copilot CLI talks to the Copilot API, or — with a model provider of // your own (BYOK) — to COPILOT_PROVIDER_BASE_URL. COPILOT_API_URL moves the // first, and Vantage wraps the second, so either reaches the proxy. // // Hooks come for one session from a plugin directory (--plugin-dir). Under // Claude Code's PascalCase event names Copilot sends Claude's payload, with // Claude's tool names (Bash, Read, Edit, …), and takes its answer. import fs from "node:fs"; import path from "node:path"; const COPILOT_API = "https://api.githubcopilot.com"; // The plugin that registers Vantage's hooks for the session. export function copilotPlugin(dir, hook, events) { fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(path.join(dir, "plugin.json"), JSON.stringify({ name: "vantage", version: "1.0.0", description: "Vantage: rules, budgets and alerts for this session" }, null, 2)); const entry = { type: "command", exec: hook.command, args: hook.args, timeoutSec: 600 }; const hooks = {}; if (events.tool) hooks.PreToolUse = [{ matcher: "*", ...entry }]; if (events.stop) hooks.Stop = [entry]; fs.writeFileSync(path.join(dir, "hooks.json"), JSON.stringify({ version: 1, hooks }, null, 2)); } export const copilot = { key: "copilot", id: "copilot", name: "Copilot CLI", short: "Copilot", command: "copilot", install: "npm install -g @github/copilot", capabilities: { enforce: "ask", chatAlerts: true }, routes: (env) => env.COPILOT_PROVIDER_BASE_URL ? [{ prefix: "/copilot-byok", upstream: env.VANTAGE_UPSTREAM ?? env.COPILOT_PROVIDER_BASE_URL }] : [{ prefix: "/copilot", upstream: env.VANTAGE_UPSTREAM ?? env.COPILOT_API_URL ?? COPILOT_API }], prepare(ctx) { const env = ctx.env.COPILOT_PROVIDER_BASE_URL ? { COPILOT_PROVIDER_BASE_URL: `${ctx.proxyUrl}/copilot-byok` } : { COPILOT_API_URL: `${ctx.proxyUrl}/copilot` }; const args = []; if (ctx.enforce || ctx.chatAlerts) { const dir = path.join(ctx.sessionDir, "copilot-plugin"); copilotPlugin(dir, ctx.hook, { tool: ctx.enforce, stop: ctx.chatAlerts }); args.push("--plugin-dir", dir); } // Extra instruction directories are searched for *.instructions.md. let memory = false; if (ctx.memory) { const dir = path.join(ctx.sessionDir, "copilot-instructions"); fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(path.join(dir, "vantage-memory.instructions.md"), ctx.memory); const existing = ctx.env.COPILOT_CUSTOM_INSTRUCTIONS_DIRS; env.COPILOT_CUSTOM_INSTRUCTIONS_DIRS = existing ? `${existing}${path.delimiter}${dir}` : dir; memory = true; } return { args, env, notes: [], memory }; }, // -p / --prompt runs one prompt and exits; -i opens the chat with it. isInteractive: (args) => !args.some((a) => a === "-p" || a === "--prompt" || a.startsWith("--prompt=")), };