Created
June 25, 2026 09:10
-
-
Save vinciest/900d2712aad394e5c8f359e27be8ca89 to your computer and use it in GitHub Desktop.
Copilot CLI + RTK, put at ~/.copilot/extensions/rtk-rewrite/extension.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { spawn } from "node:child_process"; | |
| import { approveAll } from "@github/copilot-sdk"; | |
| import { joinSession } from "@github/copilot-sdk/extension"; | |
| // Pipes bash onPreToolUse events through rtk hook copilot, which rewrites | |
| // commands to their rtk-equivalent for token savings (e.g. git status → rtk git status). | |
| // Safe no-op if rtk is not installed or returns no rewrite. | |
| // | |
| // Input shape: app.js calls extensions via FCs() which produces { toolName, toolArgs } | |
| // per individual tool call. toolArgs may be a JSON string (OpenAI wire format) or | |
| // already-parsed object depending on CLI version — handle both defensively. | |
| function runRtk(input) { | |
| let toolInput; | |
| if (input.toolName) { | |
| if (input.toolName !== "bash") return Promise.resolve({}); | |
| toolInput = typeof input.toolArgs === "string" | |
| ? JSON.parse(input.toolArgs) | |
| : input.toolArgs; | |
| } else if (input.toolCalls) { | |
| const call = input.toolCalls.find(c => c.name === "bash"); | |
| if (!call) return Promise.resolve({}); | |
| try { toolInput = JSON.parse(call.args); } catch { return Promise.resolve({}); } | |
| } else { | |
| return Promise.resolve({}); | |
| } | |
| return new Promise((resolve) => { | |
| const proc = spawn("rtk", ["hook", "copilot"], { timeout: 5000 }); | |
| let stdout = ""; | |
| proc.stdout.on("data", (d) => (stdout += d)); | |
| proc.on("close", () => { | |
| try { | |
| const hook = JSON.parse(stdout)?.hookSpecificOutput; | |
| if (hook?.updatedInput) { | |
| // Merge back fields rtk drops (e.g. description) — CLI validates all required fields | |
| resolve({ permissionDecision: "allow", modifiedArgs: { ...toolInput, ...hook.updatedInput } }); | |
| } else { | |
| resolve({}); | |
| } | |
| } catch { resolve({}); } | |
| }); | |
| proc.on("error", () => resolve({})); | |
| proc.stdin.write(JSON.stringify({ tool_name: "bash", tool_input: toolInput })); | |
| proc.stdin.end(); | |
| }); | |
| } | |
| await joinSession({ | |
| onPermissionRequest: approveAll, | |
| hooks: { | |
| onPreToolUse: async (input) => runRtk(input), | |
| }, | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment