opencode-aicodewith-auth 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ export declare const PLUGIN_NAME = "opencode-aicodewith-auth";
2
+ export declare const PROVIDER_ID = "aicodewith";
3
+ export declare const AUTH_METHOD_LABEL = "AICodewith API Key";
4
+ export declare const CODEX_BASE_URL = "https://api.aicodewith.com/chatgpt/v1";
5
+ export declare const AICODEWITH_ANTHROPIC_BASE_URL = "https://api.aicodewith.com";
6
+ export declare const AICODEWITH_GEMINI_BASE_URL = "https://api.aicodewith.com/gemini_cli";
7
+ export declare const GEMINI_USER_AGENT = "GeminiCLI/v25.2.1 (darwin; arm64)";
8
+ export declare const GEMINI_API_CLIENT = "google-genai-sdk/1.30.0 gl-node/v25.2.1";
9
+ export declare const GEMINI_PRIVILEGED_USER_ID_ENV = "AICODEWITH_GEMINI_USER_ID";
10
+ export declare const USER_AGENT = "codex_cli_rs/0.77.0 (Mac OS 26.2.0; arm64) iTerm.app/3.6.6";
11
+ export declare const ORIGINATOR = "codex_cli_rs";
12
+ export declare const HEADER_NAMES: {
13
+ readonly AUTHORIZATION: "authorization";
14
+ readonly ORIGINATOR: "originator";
15
+ readonly SESSION_ID: "session_id";
16
+ readonly CONVERSATION_ID: "conversation_id";
17
+ readonly USER_AGENT: "user-agent";
18
+ readonly ACCEPT: "accept";
19
+ readonly CONTENT_TYPE: "content-type";
20
+ readonly OPENAI_BETA: "openai-beta";
21
+ readonly CHATGPT_ACCOUNT_ID: "chatgpt-account-id";
22
+ readonly X_GOOG_API_KEY: "x-goog-api-key";
23
+ readonly X_GOOG_API_CLIENT: "x-goog-api-client";
24
+ readonly X_GEMINI_PRIVILEGED_USER_ID: "x-gemini-api-privileged-user-id";
25
+ };
@@ -0,0 +1,5 @@
1
+ export declare const LOGGING_ENABLED: boolean;
2
+ export declare const DEBUG_ENABLED: boolean;
3
+ export declare function logRequest(stage: string, data: Record<string, unknown>): void;
4
+ export declare function logDebug(message: string, data?: unknown): void;
5
+ export declare function logWarn(message: string, data?: unknown): void;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Codex-OpenCode Bridge Prompt
3
+ *
4
+ * This prompt bridges Codex CLI instructions to the OpenCode environment.
5
+ * It incorporates critical tool mappings, available tools list, substitution rules,
6
+ * and verification checklist to ensure proper tool usage.
7
+ *
8
+ * Token Count: ~450 tokens (~90% reduction vs full OpenCode prompt)
9
+ */
10
+ export declare const CODEX_OPENCODE_BRIDGE = "# Codex Running in OpenCode\n\nYou are running Codex through OpenCode, an open-source terminal coding assistant. OpenCode provides different tools but follows Codex operating principles.\n\n## CRITICAL: Tool Replacements\n\n<critical_rule priority=\"0\">\n\u274C APPLY_PATCH DOES NOT EXIST \u2192 \u2705 USE \"edit\" INSTEAD\n- NEVER use: apply_patch, applyPatch\n- ALWAYS use: edit tool for ALL file modifications\n- Before modifying files: Verify you're using \"edit\", NOT \"apply_patch\"\n</critical_rule>\n\n<critical_rule priority=\"0\">\n\u274C UPDATE_PLAN DOES NOT EXIST \u2192 \u2705 USE \"todowrite\" INSTEAD\n- NEVER use: update_plan, updatePlan, read_plan, readPlan\n- ALWAYS use: todowrite for task/plan updates, todoread to read plans\n- Before plan operations: Verify you're using \"todowrite\", NOT \"update_plan\"\n</critical_rule>\n\n## Available OpenCode Tools\n\n**File Operations:**\n- `write` - Create new files\n - Overwriting existing files requires a prior Read in this session; default to ASCII unless the file already uses Unicode.\n- `edit` - Modify existing files (REPLACES apply_patch)\n - Requires a prior Read in this session; preserve exact indentation; ensure `oldString` uniquely matches or use `replaceAll`; edit fails if ambiguous or missing.\n- `read` - Read file contents\n\n**Search/Discovery:**\n- `grep` - Search file contents (tool, not bash grep); use `include` to filter patterns; set `path` only when not searching workspace root; for cross-file match counts use bash with `rg`.\n- `glob` - Find files by pattern; defaults to workspace cwd unless `path` is set.\n- `list` - List directories (requires absolute paths)\n\n**Execution:**\n- `bash` - Run shell commands\n - No workdir parameter; do not include it in tool calls.\n - Always include a short description for the command.\n - Do not use cd; use absolute paths in commands.\n - Quote paths containing spaces with double quotes.\n - Chain multiple commands with ';' or '&&'; avoid newlines.\n - Use Grep/Glob tools for searches; only use bash with `rg` when you need counts or advanced features.\n - Do not use `ls`/`cat` in bash; use `list`/`read` tools instead.\n - For deletions (rm), verify by listing parent dir with `list`.\n\n**Network:**\n- `webfetch` - Fetch web content\n - Use fully-formed URLs (http/https; http auto-upgrades to https).\n - Always set `format` to one of: text | markdown | html; prefer markdown unless otherwise required.\n - Read-only; short cache window.\n\n**Task Management:**\n- `todowrite` - Manage tasks/plans (REPLACES update_plan)\n- `todoread` - Read current plan\n\n## Substitution Rules\n\nBase instruction says: You MUST use instead:\napply_patch \u2192 edit\nupdate_plan \u2192 todowrite\nread_plan \u2192 todoread\n\n**Path Usage:** Use per-tool conventions to avoid conflicts:\n- Tool calls: `read`, `edit`, `write`, `list` require absolute paths.\n- Searches: `grep`/`glob` default to the workspace cwd; prefer relative include patterns; set `path` only when a different root is needed.\n- Presentation: In assistant messages, show workspace-relative paths; use absolute paths only inside tool calls.\n- Tool schema overrides general path preferences\u2014do not convert required absolute paths to relative.\n\n## Verification Checklist\n\nBefore file/plan modifications:\n1. Am I using \"edit\" NOT \"apply_patch\"?\n2. Am I using \"todowrite\" NOT \"update_plan\"?\n3. Is this tool in the approved list above?\n4. Am I following each tool's path requirements?\n\nIf ANY answer is NO \u2192 STOP and correct before proceeding.\n\n## OpenCode Working Style\n\n**Communication:**\n- Send brief preambles (8-12 words) before tool calls, building on prior context\n- Provide progress updates during longer tasks\n\n**Execution:**\n- Keep working autonomously until query is fully resolved before yielding\n- Don't return to user with partial solutions\n\n**Code Approach:**\n- New projects: Be ambitious and creative\n- Existing codebases: Surgical precision - modify only what's requested unless explicitly instructed to do otherwise\n\n**Testing:**\n- If tests exist: Start specific to your changes, then broader validation\n\n## Advanced Tools\n\n**Task Tool (Sub-Agents):**\n- Use the Task tool (functions.task) to launch sub-agents\n- Check the Task tool description for current agent types and their capabilities\n- Useful for complex analysis, specialized workflows, or tasks requiring isolated context\n- The agent list is dynamically generated - refer to tool schema for available agents\n\n**Parallelization:**\n- When multiple independent tool calls are needed, use multi_tool_use.parallel to run them concurrently.\n- Reserve sequential calls for ordered or data-dependent steps.\n\n**MCP Tools:**\n- Model Context Protocol servers provide additional capabilities\n- MCP tools are prefixed: `mcp__<server-name>__<tool-name>`\n- Check your available tools for MCP integrations\n- Use when the tool's functionality matches your task needs\n\n## What Remains from Codex\n \nSandbox policies, approval mechanisms, final answer formatting, git commit protocols, and file reference formats all follow Codex instructions. In approval policy \"never\", never request escalations.\n\n## Approvals & Safety\n- Assume workspace-write filesystem, network enabled, approval on-failure unless explicitly stated otherwise.\n- When a command fails due to sandboxing or permissions, retry with escalated permissions if allowed by policy, including a one-line justification.\n- Treat destructive commands (e.g., `rm`, `git reset --hard`) as requiring explicit user request or approval.\n- When uncertain, prefer non-destructive verification first (e.g., confirm file existence with `list`, then delete with `bash`).";
11
+ export interface CodexOpenCodeBridgeMeta {
12
+ estimatedTokens: number;
13
+ reductionVsCurrent: string;
14
+ reductionVsToolRemap: string;
15
+ protects: string[];
16
+ omits: string[];
17
+ }
18
+ export declare const CODEX_OPENCODE_BRIDGE_META: CodexOpenCodeBridgeMeta;
@@ -0,0 +1,3 @@
1
+ export type ModelFamily = "gpt-5.2-codex" | "codex-max" | "codex" | "gpt-5.2" | "gpt-5.1";
2
+ export declare function getModelFamily(normalizedModel: string): ModelFamily;
3
+ export declare function getCodexInstructions(normalizedModel?: string): Promise<string>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * OpenCode Codex Prompt Fetcher
3
+ *
4
+ * Fetches and caches the codex.txt system prompt from OpenCode's GitHub repository.
5
+ * Uses ETag-based caching to efficiently track updates.
6
+ */
7
+ /**
8
+ * Fetch OpenCode's codex.txt prompt with ETag-based caching
9
+ * Uses HTTP conditional requests to efficiently check for updates
10
+ *
11
+ * Rate limit protection: Only checks GitHub if cache is older than 15 minutes
12
+ * @returns The codex.txt content
13
+ */
14
+ export declare function getOpenCodeCodexPrompt(): Promise<string>;
15
+ /**
16
+ * Get first N characters of the cached OpenCode prompt for verification
17
+ * @param chars Number of characters to get (default: 50)
18
+ * @returns First N characters or null if not cached
19
+ */
20
+ export declare function getCachedPromptPrefix(chars?: number): Promise<string | null>;
@@ -0,0 +1,11 @@
1
+ import type { RequestBody } from "../types";
2
+ export declare function extractRequestUrl(input: Request | string | URL): string;
3
+ export declare function transformRequestForCodex(init?: RequestInit): Promise<{
4
+ body: RequestBody;
5
+ updatedInit: RequestInit;
6
+ } | undefined>;
7
+ export declare function createAicodewithHeaders(init: RequestInit | undefined, apiKey: string, opts?: {
8
+ promptCacheKey?: string;
9
+ }): Headers;
10
+ export declare function handleErrorResponse(response: Response): Promise<Response>;
11
+ export declare function handleSuccessResponse(response: Response, isStreaming: boolean): Promise<Response>;
@@ -0,0 +1,5 @@
1
+ import type { InputItem } from "../../types";
2
+ export declare const getContentText: (item: InputItem) => string;
3
+ export declare function isOpenCodeSystemPrompt(item: InputItem, cachedPrompt: string | null): boolean;
4
+ export declare function filterOpenCodeSystemPromptsWithCachedPrompt(input: InputItem[] | undefined, cachedPrompt: string | null): InputItem[] | undefined;
5
+ export declare const normalizeOrphanedToolOutputs: (input: InputItem[]) => InputItem[];
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Model Configuration Map
3
+ *
4
+ * Maps model config IDs to their normalized API model names.
5
+ * Only includes exact config IDs that OpenCode will pass to the plugin.
6
+ */
7
+ /**
8
+ * Map of config model IDs to normalized API model names
9
+ *
10
+ * Key: The model ID as specified in opencode.json config
11
+ * Value: The normalized model name to send to the API
12
+ */
13
+ export declare const MODEL_MAP: Record<string, string>;
14
+ /**
15
+ * Get normalized model name from config ID
16
+ *
17
+ * @param modelId - Model ID from config (e.g., "gpt-5.1-codex-low")
18
+ * @returns Normalized model name (e.g., "gpt-5.1-codex") or undefined if not found
19
+ */
20
+ export declare function getNormalizedModel(modelId: string): string | undefined;
21
+ /**
22
+ * Check if a model ID is in the model map
23
+ *
24
+ * @param modelId - Model ID to check
25
+ * @returns True if model is in the map
26
+ */
27
+ export declare function isKnownModel(modelId: string): boolean;
@@ -0,0 +1,7 @@
1
+ import type { ConfigOptions, InputItem, ReasoningConfig, RequestBody } from "../types";
2
+ export declare function normalizeModel(model: string | undefined): string;
3
+ export declare function filterInput(input: InputItem[] | undefined): InputItem[] | undefined;
4
+ export declare function filterOpenCodeSystemPrompts(input: InputItem[] | undefined): Promise<InputItem[] | undefined>;
5
+ export declare function addCodexBridgeMessage(input: InputItem[] | undefined, hasTools: boolean): InputItem[] | undefined;
6
+ export declare function getReasoningConfig(modelName: string | undefined, userConfig?: ConfigOptions): ReasoningConfig;
7
+ export declare function transformRequestBody(body: RequestBody, codexInstructions: string): Promise<RequestBody>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Convert SSE stream response to JSON for generateText()
3
+ * @param response - Fetch response with SSE stream
4
+ * @param headers - Response headers
5
+ * @returns Response with JSON body
6
+ */
7
+ export declare function convertSseToJson(response: Response, headers: Headers): Promise<Response>;
8
+ /**
9
+ * Ensure response has content-type header
10
+ * @param headers - Response headers
11
+ * @returns Headers with content-type set
12
+ */
13
+ export declare function ensureContentType(headers: Headers): Headers;
@@ -0,0 +1,56 @@
1
+ export interface ConfigOptions {
2
+ reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
3
+ reasoningSummary?: "auto" | "concise" | "detailed" | "off" | "on";
4
+ textVerbosity?: "low" | "medium" | "high";
5
+ include?: string[];
6
+ }
7
+ export interface ReasoningConfig {
8
+ effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
9
+ summary: "auto" | "concise" | "detailed" | "off" | "on";
10
+ }
11
+ export interface InputItem {
12
+ id?: string;
13
+ type: string;
14
+ role: string;
15
+ content?: unknown;
16
+ [key: string]: unknown;
17
+ }
18
+ export interface RequestBody {
19
+ model: string;
20
+ store?: boolean;
21
+ stream?: boolean;
22
+ instructions?: string;
23
+ input?: InputItem[];
24
+ tools?: unknown;
25
+ reasoning?: Partial<ReasoningConfig>;
26
+ text?: {
27
+ verbosity?: "low" | "medium" | "high";
28
+ };
29
+ include?: string[];
30
+ providerOptions?: {
31
+ openai?: Partial<ConfigOptions> & {
32
+ store?: boolean;
33
+ include?: string[];
34
+ };
35
+ [key: string]: unknown;
36
+ };
37
+ prompt_cache_key?: string;
38
+ max_output_tokens?: number;
39
+ max_completion_tokens?: number;
40
+ [key: string]: unknown;
41
+ }
42
+ export interface SSEEventData {
43
+ type: string;
44
+ response?: unknown;
45
+ [key: string]: unknown;
46
+ }
47
+ export interface CacheMetadata {
48
+ etag: string | null;
49
+ tag: string;
50
+ lastChecked: number;
51
+ url: string;
52
+ }
53
+ export interface GitHubRelease {
54
+ tag_name: string;
55
+ [key: string]: unknown;
56
+ }
@@ -0,0 +1,26 @@
1
+ import type { LanguageModelV2 } from "@ai-sdk/provider";
2
+ import type { FetchFunction } from "@ai-sdk/provider-utils";
3
+ export type AicodewithProviderSettings = {
4
+ apiKey?: string;
5
+ baseURL?: string;
6
+ headers?: Record<string, string>;
7
+ fetch?: FetchFunction;
8
+ anthropic?: {
9
+ apiKey?: string;
10
+ baseURL?: string;
11
+ headers?: Record<string, string>;
12
+ };
13
+ google?: {
14
+ apiKey?: string;
15
+ baseURL?: string;
16
+ headers?: Record<string, string>;
17
+ };
18
+ };
19
+ export interface AicodewithProvider {
20
+ (modelId: string): LanguageModelV2;
21
+ chat(modelId: string): LanguageModelV2;
22
+ responses(modelId: string): LanguageModelV2;
23
+ languageModel(modelId: string): LanguageModelV2;
24
+ }
25
+ export declare function createAicodewith(options?: AicodewithProviderSettings): AicodewithProvider;
26
+ export declare const aicodewith: AicodewithProvider;
@@ -0,0 +1,63 @@
1
+ // @bun
2
+ // provider.ts
3
+ import { createAnthropic } from "@ai-sdk/anthropic";
4
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
5
+ import { createOpenAI } from "@ai-sdk/openai";
6
+ var isClaude = (modelId) => modelId.startsWith("claude-");
7
+ var isGemini = (modelId) => modelId.startsWith("gemini-");
8
+ var isResponses = (modelId) => modelId.startsWith("gpt-") || modelId.startsWith("codex");
9
+ var normalizeModelId = (modelId) => String(modelId).trim();
10
+ function createAicodewith(options = {}) {
11
+ const openai = createOpenAI({
12
+ apiKey: options.apiKey,
13
+ baseURL: options.baseURL,
14
+ headers: options.headers,
15
+ fetch: options.fetch
16
+ });
17
+ const openaiLanguageModel = typeof openai.languageModel === "function" ? openai.languageModel : openai.chat;
18
+ const openaiChatModel = typeof openai.chat === "function" ? openai.chat : openaiLanguageModel;
19
+ const anthropic = createAnthropic({
20
+ apiKey: options.anthropic?.apiKey ?? options.apiKey,
21
+ baseURL: options.anthropic?.baseURL,
22
+ headers: options.anthropic?.headers ?? options.headers,
23
+ fetch: options.fetch
24
+ });
25
+ const google = createGoogleGenerativeAI({
26
+ apiKey: options.google?.apiKey ?? options.apiKey,
27
+ baseURL: options.google?.baseURL,
28
+ headers: options.google?.headers ?? options.headers,
29
+ fetch: options.fetch
30
+ });
31
+ const createModel = (modelId) => {
32
+ const id = normalizeModelId(modelId);
33
+ if (isClaude(id))
34
+ return anthropic.languageModel(id);
35
+ if (isGemini(id))
36
+ return google.languageModel(id);
37
+ if (isResponses(id) && typeof openai.responses === "function")
38
+ return openai.responses(id);
39
+ return openaiLanguageModel(id);
40
+ };
41
+ const provider = (modelId) => createModel(modelId);
42
+ provider.languageModel = createModel;
43
+ provider.chat = (modelId) => {
44
+ const id = normalizeModelId(modelId);
45
+ if (isClaude(id))
46
+ return anthropic.languageModel(id);
47
+ if (isGemini(id))
48
+ return google.languageModel(id);
49
+ return openaiChatModel(id);
50
+ };
51
+ provider.responses = (modelId) => {
52
+ const id = normalizeModelId(modelId);
53
+ if (isClaude(id) || isGemini(id))
54
+ return provider.chat(id);
55
+ return openai.responses(id);
56
+ };
57
+ return provider;
58
+ }
59
+ var aicodewith = createAicodewith();
60
+ export {
61
+ createAicodewith,
62
+ aicodewith
63
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "opencode-aicodewith-auth",
3
+ "version": "0.1.0",
4
+ "description": "OpenCode plugin for AICodewith authentication - Access GPT-5.2, Claude, and Gemini models through AICodewith API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./provider": {
14
+ "types": "./dist/provider.d.ts",
15
+ "import": "./dist/provider.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "bun build index.ts provider.ts --outdir dist --target bun --format esm --external @ai-sdk/anthropic --external @ai-sdk/google --external @ai-sdk/openai --external @ai-sdk/provider --external @ai-sdk/provider-utils --external @opencode-ai/plugin --external @opencode-ai/sdk && tsc --emitDeclarationOnly",
23
+ "clean": "rm -rf dist",
24
+ "prepublishOnly": "bun run clean && bun run build",
25
+ "typecheck": "tsc --noEmit",
26
+ "postinstall": "bun ./scripts/install-opencode-aicodewith.js"
27
+ },
28
+ "keywords": [
29
+ "opencode",
30
+ "plugin",
31
+ "aicodewith",
32
+ "gpt-5",
33
+ "claude",
34
+ "gemini",
35
+ "ai",
36
+ "llm",
37
+ "authentication"
38
+ ],
39
+ "author": "",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/DaneelOlivaw1/opencode-aicodewith-auth.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/DaneelOlivaw1/opencode-aicodewith-auth/issues"
47
+ },
48
+ "homepage": "https://github.com/DaneelOlivaw1/opencode-aicodewith-auth#readme",
49
+ "dependencies": {
50
+ "@ai-sdk/anthropic": "2.0.56",
51
+ "@ai-sdk/google": "2.0.49",
52
+ "@ai-sdk/openai": "2.0.71",
53
+ "@ai-sdk/provider": "2.0.0",
54
+ "@ai-sdk/provider-utils": "3.0.19"
55
+ },
56
+ "peerDependencies": {
57
+ "@opencode-ai/plugin": "^1.0.150"
58
+ },
59
+ "devDependencies": {
60
+ "typescript": "^5.7.0",
61
+ "@types/node": "^22.0.0"
62
+ }
63
+ }