Files
Numman AliandHanzo Dev 3890872781 feat: Add CODEX_MODE with bridge prompt and reorganize lib/ structure
## CODEX_MODE Implementation

Added configurable CODEX_MODE that replaces OpenCode system prompts with
a Codex-OpenCode bridge prompt for better Codex CLI parity.

**Key Features:**
- Enabled by default for optimal Codex CLI compatibility
- Configurable via ~/.opencode/openai-codex-auth-config.json
- Environment variable override support (CODEX_MODE=0 or CODEX_MODE=1)
- Priority: env var > config file > default (true)

**Bridge Prompt:**
- ~450 tokens (~90% reduction vs full OpenCode prompt)
- Critical tool replacements (apply_patch → edit, update_plan → todowrite)
- Available tools list and verification checklist
- OpenCode working style guidelines

**Configuration:**
```json
{
  "codexMode": true  // default
}
```

## Library Reorganization

Restructured lib/ into semantic subfolders:

```
lib/
├── auth/              # OAuth authentication
│   ├── auth.ts
│   ├── browser.ts
│   └── server.ts
├── prompts/           # System prompts
│   ├── codex.ts
│   └── codex-opencode-bridge.ts
├── request/           # Request handling
│   ├── fetch-helpers.ts
│   ├── request-transformer.ts
│   └── response-handler.ts
├── config.ts          # Plugin configuration
├── constants.ts
├── logger.ts
├── types.ts
└── oauth-success.html
```

## Files Changed

**New Files:**
- lib/config.ts - Plugin configuration loading
- lib/prompts/codex-opencode-bridge.ts - Bridge prompt
- test/plugin-config.test.ts - 12 new tests

**Modified:**
- lib/request/request-transformer.ts - CODEX_MODE parameter
- lib/request/fetch-helpers.ts - Pass codexMode through pipeline
- index.ts - Load config and determine codexMode
- lib/types.ts - Add PluginConfig type
- README.md - Document CODEX_MODE configuration

**Reorganized:**
- lib/*.ts → lib/{auth,prompts,request}/*.ts
- Updated all imports across codebase and tests

## Testing

- 123 total tests (added 12 new tests for config loading)
- All tests passing
- Comprehensive CODEX_MODE coverage:
  - Config file loading (exists, missing, invalid)
  - Priority order testing
  - Environment variable override
  - Bridge prompt vs tool remap behavior

## Documentation

Updated README.md:
- Added "Plugin Configuration" section
- Documented CODEX_MODE setting and priority
- Updated features list (123 tests, CODEX_MODE)
- Updated "How It Works" section

Co-authored-by: Hanzo Dev <[email protected]>
2025-10-03 22:31:34 +01:00

81 lines
2.3 KiB
TypeScript

import http from "node:http";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { OAuthServerInfo } from "../types.js";
// Resolve path to oauth-success.html (one level up from auth/ subfolder)
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const successHtml = fs.readFileSync(path.join(__dirname, "..", "oauth-success.html"), "utf-8");
/**
* Start a small local HTTP server that waits for /auth/callback and returns the code
* @param options - OAuth state for validation
* @returns Promise that resolves to server info
*/
export function startLocalOAuthServer({ state }: { state: string }): Promise<OAuthServerInfo> {
const server = http.createServer((req, res) => {
try {
const url = new URL(req.url || "", "http://localhost");
if (url.pathname !== "/auth/callback") {
res.statusCode = 404;
res.end("Not found");
return;
}
if (url.searchParams.get("state") !== state) {
res.statusCode = 400;
res.end("State mismatch");
return;
}
const code = url.searchParams.get("code");
if (!code) {
res.statusCode = 400;
res.end("Missing authorization code");
return;
}
res.statusCode = 200;
res.setHeader("Content-Type", "text/html; charset=utf-8");
res.end(successHtml);
(server as http.Server & { _lastCode?: string })._lastCode = code;
} catch {
res.statusCode = 500;
res.end("Internal error");
}
});
return new Promise((resolve) => {
server
.listen(1455, "127.0.0.1", () => {
resolve({
port: 1455,
close: () => server.close(),
waitForCode: async () => {
const poll = () => new Promise<void>((r) => setTimeout(r, 100));
for (let i = 0; i < 600; i++) {
const lastCode = (server as http.Server & { _lastCode?: string })._lastCode;
if (lastCode) return { code: lastCode };
await poll();
}
return null;
},
});
})
.on("error", (err: NodeJS.ErrnoException) => {
console.error(
"[openai-codex-plugin] Failed to bind http://127.0.0.1:1455 (",
err?.code,
") Falling back to manual paste.",
);
resolve({
port: 1455,
close: () => {
try {
server.close();
} catch {}
},
waitForCode: async () => null,
});
});
});
}