From 7ee298817498321af80d733de378dc41bd514565 Mon Sep 17 00:00:00 2001 From: Stephanie Schofield Date: Wed, 7 Jan 2026 14:23:56 -0600 Subject: [PATCH 1/5] feat: Add settings for Bash permissions and update server routes for OpenAI compatibility --- .claude/settings.local.json | 7 +++++++ README.md | 34 +++++++++++++++++++++++++++++----- src/server.ts | 7 ++++--- 3 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..b0879ba --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(echo:*)" + ] + } +} diff --git a/README.md b/README.md index f83b636..7ca9369 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,36 @@ A proxy server that enables **Claude Code** and **Cursor IDE** to use GitHub Cop ## 🤖 Configuration with Claude Code -1. Start the proxy server: `npm start` -2. Open http://localhost:3000 in your browser -3. Complete GitHub authentication +1. Start the proxy server: + ```bash + npm start + ``` + You should see the authentication portal at http://localhost:3000 + +2. Complete GitHub authentication by pasting your auth code in the browser + +3. Enter `claude` in your terminal to start Claude Code + 4. Configure Claude Code to use the proxy: - - Set the API base URL to `http://localhost:3000` - - The proxy handles authentication via GitHub OAuth + ```bash + claude config set api_base_url http://localhost:3000 + ``` + +5. Press `Ctrl+C` twice to quit Claude + +6. Enter `claude` again to restart with the new configuration + +### How to Verify It's Working + +✅ **Server logs show 200 responses**: Look for `POST /v1/messages - 200` in the server output + +✅ **Token usage is tracked**: You'll see `Tracked request for session ... +XX tokens` + +✅ **Model being used**: Shows `"model": "claude-opus-4.5"` or `"claude-sonnet-4.5"` + +✅ **Claude Code gets responses**: Your commands should complete without errors + +✅ **Usage stats**: Check http://localhost:3000/usage.html in your browser to see how many tokens you've used ### Supported Claude Models diff --git a/src/server.ts b/src/server.ts index 99ee71b..443f52c 100644 --- a/src/server.ts +++ b/src/server.ts @@ -34,10 +34,11 @@ app.get('/health', (req, res) => { // Routes app.use('/auth', authRoutes); // Apply rate limiting to API endpoints -// OpenAI-compatible routes (for Cursor IDE) -app.use('/v1', rateLimiter(), openaiRoutes); -// Anthropic-compatible routes (for Claude Code) - mounted at /anthropic/v1 +// Anthropic-compatible routes (for Claude Code) - mounted at both /v1 and /anthropic/v1 +app.use('/v1', rateLimiter(), anthropicRoutes); app.use('/anthropic/v1', rateLimiter(), anthropicRoutes); +// OpenAI-compatible routes (for Cursor IDE) - mounted at /openai/v1 +app.use('/openai/v1', rateLimiter(), openaiRoutes); app.use('/usage', usageRoutes); // Home page - redirect to auth page From c4e8ba0d4afc89695fc535102dd6d6d00be699e6 Mon Sep 17 00:00:00 2001 From: Stephanie Schofield Date: Wed, 7 Jan 2026 14:27:43 -0600 Subject: [PATCH 2/5] feat: Add .claude/settings.local.json to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 59f90e6..a65d3d8 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,6 @@ temp/ # Docker volumes docker-volumes/ + +# Claude local settings +.claude/settings.local.json From fe19a564952d97482bb3ca1f22fc3466cf00a267 Mon Sep 17 00:00:00 2001 From: Stephanie Schofield Date: Wed, 7 Jan 2026 21:37:22 -0600 Subject: [PATCH 3/5] fix: resolve Jest TypeScript parsing issues - Add isolatedModules: true to tsconfig.json (required for NodeNext module) - Update Jest config to use ESM preset and experimental VM modules - Fix convertMessagesToCopilotPrompt to preserve message order - Fix detectLanguageFromMessages regex to handle punctuation after file extensions - Update test script to use Node.js experimental VM modules flag All tests now passing (11/11) --- jest.config.js | 8 +++++++- package.json | 2 +- src/services/copilot-service.ts | 22 +++++++++++----------- tsconfig.json | 3 ++- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/jest.config.js b/jest.config.js index d60ed5c..64ee4c0 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ export default { - preset: 'ts-jest', + preset: 'ts-jest/presets/default-esm', testEnvironment: 'node', extensionsToTreatAsEsm: ['.ts'], moduleNameMapper: { @@ -11,7 +11,13 @@ export default { 'ts-jest', { useESM: true, + tsconfig: { + module: 'NodeNext', + moduleResolution: 'NodeNext', + isolatedModules: true, + }, }, ], }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], }; diff --git a/package.json b/package.json index 1e872f4..aac639e 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "start": "node dist/index.js", "dev": "ts-node src/index.ts", "lint": "eslint src/**/*.ts", - "test": "jest", + "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", "prepare": "husky" }, "repository": { diff --git a/src/services/copilot-service.ts b/src/services/copilot-service.ts index 91693dd..94942e8 100644 --- a/src/services/copilot-service.ts +++ b/src/services/copilot-service.ts @@ -20,32 +20,32 @@ export function convertMessagesToCopilotPrompt(messages: OpenAIMessage[]): strin return ''; } - let systemPrompt = ''; - let userPrompts = ''; - let assistantResponses = ''; + let prompt = ''; - // Process messages in order to construct a coherent prompt + // Process messages in order to preserve conversational flow for (const message of messages) { if (!message.role || !message.content) continue; switch (message.role) { case 'system': - systemPrompt += message.content + '\n\n'; + prompt += message.content + '\n\n'; break; case 'user': - userPrompts += 'User: ' + message.content + '\n\n'; + prompt += 'User: ' + message.content + '\n\n'; break; case 'assistant': - assistantResponses += 'Assistant: ' + message.content + '\n\n'; + prompt += 'Assistant: ' + message.content + '\n\n'; break; } } - // Ensure it ends with a user message to prompt a response + // Ensure it ends with "Assistant: " to prompt a response if last message is from user const lastMessage = messages[messages.length - 1]; - const needsAssistantPrompt = lastMessage.role !== 'user'; + if (lastMessage.role === 'user') { + prompt += 'Assistant: '; + } - return systemPrompt + userPrompts + assistantResponses + (needsAssistantPrompt ? '' : 'Assistant: '); + return prompt; } /** @@ -73,7 +73,7 @@ export function detectLanguageFromMessages(messages: OpenAIMessage[]): string { } // Check for file extensions in the message - const fileExtensionMatch = content.match(/\.([a-zA-Z0-9]+)(?:\s|"|')/); + const fileExtensionMatch = content.match(/\.([a-zA-Z0-9]+)(?:\s|"|'|$|\?|!|,|\.)/); if (fileExtensionMatch && fileExtensionMatch[1]) { const ext = fileExtensionMatch[1].toLowerCase(); const extToLang: Record = { diff --git a/tsconfig.json b/tsconfig.json index f2daf97..d45d46a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "rootDir": "src", "declaration": true, "sourceMap": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "isolatedModules": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts"] From 167c37aae6382d504b935de1339bbf9043e86ff8 Mon Sep 17 00:00:00 2001 From: Stephanie Schofield Date: Wed, 7 Jan 2026 21:39:38 -0600 Subject: [PATCH 4/5] fix: remove deprecated Husky v9 shell script wrappers - Delete obsolete .husky/_ directory no longer needed in v9+ --- .husky/commit-msg | 3 --- .husky/pre-commit | 3 --- 2 files changed, 6 deletions(-) diff --git a/.husky/commit-msg b/.husky/commit-msg index e810522..0a4b97d 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - npx --no -- commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit index 75fac8e..3867a0f 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - npm run lint From be6caf1596bbdeb2c4dbf5c54928cc8236a15750 Mon Sep 17 00:00:00 2001 From: Stephanie Schofield Date: Fri, 9 Jan 2026 10:10:56 -0600 Subject: [PATCH 5/5] feat: enhance build process by adding asset copying step --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index aac639e..080ee71 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Proxy server that lets Cursor IDE use GitHub Copilot APIs", "main": "dist/index.js", "scripts": { - "build": "tsc", + "build": "tsc && npm run copy-assets", + "copy-assets": "node -e \"require('fs').cpSync('src/public', 'dist/public', {recursive: true})\"", "start": "node dist/index.js", "dev": "ts-node src/index.ts", "lint": "eslint src/**/*.ts",