@vibecontrols/vibe-plugin-ai-codex 2026.601.1 → 2026.731.1
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 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -17,8 +17,8 @@ you can set the \`dangerouslyAllowBrowser\` option to \`true\`, e.g.,
|
|
|
17
17
|
new OpenAI({ apiKey, dangerouslyAllowBrowser: true });
|
|
18
18
|
|
|
19
19
|
https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety
|
|
20
|
-
`);super({baseURL:options.baseURL,timeout:options.timeout??600000,httpAgent:options.httpAgent,maxRetries:options.maxRetries,fetch:options.fetch});this.completions=new Completions3(this),this.chat=new Chat(this),this.embeddings=new Embeddings(this),this.files=new Files2(this),this.images=new Images(this),this.audio=new Audio(this),this.moderations=new Moderations(this),this.models=new Models(this),this.fineTuning=new FineTuning(this),this.graders=new Graders2(this),this.vectorStores=new VectorStores(this),this.beta=new Beta(this),this.batches=new Batches(this),this.uploads=new Uploads(this),this.responses=new Responses(this),this.evals=new Evals(this),this.containers=new Containers(this),this._options=options,this.apiKey=apiKey,this.organization=organization,this.project=project}defaultQuery(){return this._options.defaultQuery}defaultHeaders(opts){return{...super.defaultHeaders(opts),"OpenAI-Organization":this.organization,"OpenAI-Project":this.project,...this._options.defaultHeaders}}authHeaders(opts){return{Authorization:`Bearer ${this.apiKey}`}}stringifyQuery(query){return stringify(query,{arrayFormat:"brackets"})}};_a=OpenAI;OpenAI.OpenAI=_a;OpenAI.DEFAULT_TIMEOUT=600000;OpenAI.OpenAIError=OpenAIError;OpenAI.APIError=APIError;OpenAI.APIConnectionError=APIConnectionError;OpenAI.APIConnectionTimeoutError=APIConnectionTimeoutError;OpenAI.APIUserAbortError=APIUserAbortError;OpenAI.NotFoundError=NotFoundError;OpenAI.ConflictError=ConflictError;OpenAI.RateLimitError=RateLimitError;OpenAI.BadRequestError=BadRequestError;OpenAI.AuthenticationError=AuthenticationError;OpenAI.InternalServerError=InternalServerError;OpenAI.PermissionDeniedError=PermissionDeniedError;OpenAI.UnprocessableEntityError=UnprocessableEntityError;OpenAI.toFile=toFile;OpenAI.fileFromPath=fileFromPath;OpenAI.Completions=Completions3;OpenAI.Chat=Chat;OpenAI.ChatCompletionsPage=ChatCompletionsPage;OpenAI.Embeddings=Embeddings;OpenAI.Files=Files2;OpenAI.FileObjectsPage=FileObjectsPage;OpenAI.Images=Images;OpenAI.Audio=Audio;OpenAI.Moderations=Moderations;OpenAI.Models=Models;OpenAI.ModelsPage=ModelsPage;OpenAI.FineTuning=FineTuning;OpenAI.Graders=Graders2;OpenAI.VectorStores=VectorStores;OpenAI.VectorStoresPage=VectorStoresPage;OpenAI.VectorStoreSearchResponsesPage=VectorStoreSearchResponsesPage;OpenAI.Beta=Beta;OpenAI.Batches=Batches;OpenAI.BatchesPage=BatchesPage;OpenAI.Uploads=Uploads;OpenAI.Responses=Responses;OpenAI.Evals=Evals;OpenAI.EvalListResponsesPage=EvalListResponsesPage;OpenAI.Containers=Containers;OpenAI.ContainerListResponsesPage=ContainerListResponsesPage;AzureOpenAI=class AzureOpenAI extends OpenAI{constructor({baseURL=readEnv("OPENAI_BASE_URL"),apiKey=readEnv("AZURE_OPENAI_API_KEY"),apiVersion=readEnv("OPENAI_API_VERSION"),endpoint,deployment,azureADTokenProvider,dangerouslyAllowBrowser,...opts}={}){if(!apiVersion)throw new OpenAIError("The OPENAI_API_VERSION environment variable is missing or empty; either provide it, or instantiate the AzureOpenAI client with an apiVersion option, like new AzureOpenAI({ apiVersion: 'My API Version' }).");if(typeof azureADTokenProvider==="function")dangerouslyAllowBrowser=!0;if(!azureADTokenProvider&&!apiKey)throw new OpenAIError("Missing credentials. Please pass one of `apiKey` and `azureADTokenProvider`, or set the `AZURE_OPENAI_API_KEY` environment variable.");if(azureADTokenProvider&&apiKey)throw new OpenAIError("The `apiKey` and `azureADTokenProvider` arguments are mutually exclusive; only one can be passed at a time.");if(apiKey??(apiKey=API_KEY_SENTINEL),opts.defaultQuery={...opts.defaultQuery,"api-version":apiVersion},!baseURL){if(!endpoint)endpoint=process.env.AZURE_OPENAI_ENDPOINT;if(!endpoint)throw new OpenAIError("Must provide one of the `baseURL` or `endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable");baseURL=`${endpoint}/openai`}else if(endpoint)throw new OpenAIError("baseURL and endpoint are mutually exclusive");super({apiKey,baseURL,...opts,...dangerouslyAllowBrowser!==void 0?{dangerouslyAllowBrowser}:{}});this.apiVersion="",this._azureADTokenProvider=azureADTokenProvider,this.apiVersion=apiVersion,this.deploymentName=deployment}buildRequest(options,props={}){if(_deployments_endpoints.has(options.path)&&options.method==="post"&&options.body!==void 0){if(!isObj(options.body))throw Error("Expected request body to be an object");let model=this.deploymentName||options.body.model||options.__metadata?.model;if(model!==void 0&&!this.baseURL.includes("/deployments"))options.path=`/deployments/${model}${options.path}`}return super.buildRequest(options,props)}async _getAzureADToken(){if(typeof this._azureADTokenProvider==="function"){let token=await this._azureADTokenProvider();if(!token||typeof token!=="string")throw new OpenAIError(`Expected 'azureADTokenProvider' argument to return a string but it returned ${token}`);return token}return}authHeaders(opts){return{}}async prepareOptions(opts){if(opts.headers?.["api-key"])return super.prepareOptions(opts);let token=await this._getAzureADToken();if(opts.headers??(opts.headers={}),token)opts.headers.Authorization=`Bearer ${token}`;else if(this.apiKey!==API_KEY_SENTINEL)opts.headers["api-key"]=this.apiKey;else throw new OpenAIError("Unable to handle auth");return super.prepareOptions(opts)}};_deployments_endpoints=new Set(["/completions","/chat/completions","/embeddings","/audio/transcriptions","/audio/translations","/audio/speech","/images/generations","/images/edits"]),openai_default=OpenAI});import{Elysia as Elysia2}from"elysia";import{Elysia}from"elysia";function createLifecycleHooks(spec){let{name,onInit,onShutdown,onNuke,telemetryEventName,skipPlatforms}=spec;return{onServerStart:async(_app,hostServices)=>{if(skipPlatforms&&skipPlatforms.includes(process.platform)){process.stderr.write(`[${name}] skipping init on unsupported platform '${process.platform}'
|
|
21
|
-
`);return}if(onInit)await onInit(hostServices);if(telemetryEventName)hostServices.telemetry?.emit(telemetryEventName,{plugin:name})},onServerStop:async(hostServices)=>{if(onShutdown)await onShutdown(hostServices)},onNuke:async(hostServices,ctx)=>{if(onNuke)return onNuke(hostServices,ctx)}}}var TelemetryEmitter=class{constructor(pluginName,pluginVersion,hostServices){this.pluginName=pluginName,this.pluginVersion=pluginVersion,this.hostServices=hostServices}pluginName;pluginVersion;hostServices;emit(eventName,payload){let target=this.hostServices?.telemetry;if(!target)return;target.emit(eventName,{plugin:this.pluginName,version:this.pluginVersion,timestamp:new Date().toISOString(),...payload??{}})}emitReady(context){this.emit(`${this.pluginName}.ready`,context)}emitError(error,context){this.emit(`${this.pluginName}.error`,{message:error.message,...context??{}})}emitEvent(type,payload){this.emit(type,payload)}},BoundLogger=class{constructor(logger,source){this.logger=logger,this.source=source}logger;source;info(message,meta){this.logger?.info?.(this.source,message,meta)}warn(message,meta){this.logger?.warn?.(this.source,message,meta)}error(message,meta){this.logger?.error?.(this.source,message,meta)}debug(message,meta){this.logger?.debug?.(this.source,message,meta)}};var CONTEXT_PROVIDER_TYPE="context",REGISTRY_KEY=Symbol.for("@vibecontrols/plugin-sdk:contextProviders@1");function getRegistry(){let slots=globalThis,existing=slots[REGISTRY_KEY];if(existing)return existing;let created=new Map;return slots[REGISTRY_KEY]=created,created}function registerContextProvider(provider,hostServices){if(!provider||typeof provider.name!=="string"||provider.name.length===0)throw Error("ContextProvider.name is required");if(typeof provider.getContext!=="function")throw Error("ContextProvider.getContext must be a function");getRegistry().set(provider.name,provider),hostServices?.serviceRegistry?.registerProvider?.(CONTEXT_PROVIDER_TYPE,provider,provider.name)}function listContextProviders(){return Array.from(getRegistry().values())}function getContextProvider(name){return getRegistry().get(name)}var ProviderRegistry=class{constructor(hostServices){this.hostServices=hostServices}hostServices;registerContextProvider(provider){registerContextProvider(provider,this.hostServices)}listContextProviders(){return listContextProviders()}getContextProvider(name){return getContextProvider(name)}getServiceRegistry(){return this.hostServices?.serviceRegistry}registerProvider(type,name,provider){this.hostServices?.serviceRegistry?.registerProvider?.(type,provider,name)}getProvider(type,name){let reg=this.hostServices?.serviceRegistry;if(!reg)return;if(name===void 0)return reg.getProvider?.(type);if(reg.getProviderByName)return reg.getProviderByName(type,name);if(!reg.listProvidersForType)return;if(!(reg.listProvidersForType(type)??[]).some((entry)=>typeof entry==="string"?entry===name:entry.pluginName===name))return;return reg.getProvider?.(type)}listProviders(type){return(this.hostServices?.serviceRegistry?.listProvidersForType?.(type)??[]).map((entry)=>typeof entry==="string"?entry:entry.pluginName)}withCliContribution(contribution){let contributors=this.hostServices?.cliContributors;if(!contributors)return;for(let section of contribution.statusSections??[])contributors.addStatusSection?.(section);for(let check of contribution.doctorChecks??[])contributors.addDoctorCheck?.(check)}};var PROVIDER_NAME="codex",CLI_COMMAND="codex";function platformExeName(base){return process.platform==="win32"?`${base}.exe`:base}function resolveCliBin(){let found=typeof Bun<"u"&&typeof Bun.which==="function"?Bun.which(CLI_COMMAND,{PATH:process.env.PATH}):null;if(found)return found;return platformExeName(CLI_COMMAND)}var CLI_BIN=resolveCliBin(),DISPLAY_NAME="OpenAI Codex",DEFAULT_MODEL="gpt-4.1-mini",DEFAULT_MAX_TOKENS=16384,API_PREFIX=`/api/ai-${PROVIDER_NAME}`,SUPPORTED_MODES=["sdk","cli"],CLI_INSTALL_COMMAND=["npm","install","-g","@openai/codex"],CODEX_MODELS=[{id:"codex-mini-latest",name:"Codex Mini",provider:PROVIDER_NAME,contextWindow:200000,maxOutputTokens:1e5,supportsVision:!1,supportsStreaming:!0,inputPricePerMToken:1.5,outputPricePerMToken:6},{id:"gpt-4.1",name:"GPT-4.1",provider:PROVIDER_NAME,contextWindow:1047576,maxOutputTokens:32768,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:2,outputPricePerMToken:8},{id:"gpt-4.1-mini",name:"GPT-4.1 Mini",provider:PROVIDER_NAME,contextWindow:1047576,maxOutputTokens:32768,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:0.4,outputPricePerMToken:1.6},{id:"gpt-4.1-nano",name:"GPT-4.1 Nano",provider:PROVIDER_NAME,contextWindow:1047576,maxOutputTokens:32768,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:0.1,outputPricePerMToken:0.4},{id:"o4-mini",name:"o4-mini",provider:PROVIDER_NAME,contextWindow:200000,maxOutputTokens:1e5,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:1.1,outputPricePerMToken:4.4}];class CodexSdkAdapter{mode="sdk";client=null;async getClient(){if(this.client)return this.client;try{let mod=await Promise.resolve().then(() => (init_openai(),exports_openai)),OpenAI2=mod.default??mod;return this.client=new OpenAI2({apiKey:process.env.OPENAI_API_KEY}),this.client}catch{throw Error("Failed to load openai SDK. Install it with: bun add openai")}}async sendPrompt(prompt,config,_signal){let client=await this.getClient(),startTime=Date.now(),params={model:config.model||DEFAULT_MODEL,input:prompt};if(config.systemPrompt)params.instructions=config.systemPrompt;if(config.maxTokens)params.max_output_tokens=config.maxTokens;let response=await client.responses.create(params),durationMs=Date.now()-startTime;return{content:this.extractResponseText(response),model:response.model,inputTokens:response.usage.input_tokens,outputTokens:response.usage.output_tokens,durationMs,metadata:{provider:PROVIDER_NAME,mode:"sdk"}}}async streamPrompt(prompt,config,onChunk,_signal){let client=await this.getClient(),startTime=Date.now(),model=config.model||DEFAULT_MODEL,params={model,input:prompt,stream:!0};if(config.systemPrompt)params.instructions=config.systemPrompt;if(config.maxTokens)params.max_output_tokens=config.maxTokens;let stream=client.responses.create(params),collectedText=[],finalModel=model,inputTokens=0,outputTokens=0;for await(let event of stream)if(event.type==="response.output_text.delta"&&event.delta)collectedText.push(event.delta),onChunk({type:"text",content:event.delta});else if(event.type==="response.completed"){let completed=event;if(completed.response)finalModel=completed.response.model,inputTokens=completed.response.usage.input_tokens,outputTokens=completed.response.usage.output_tokens}let durationMs=Date.now()-startTime,content=collectedText.join("");if(inputTokens===0&&outputTokens===0)inputTokens=Math.ceil(prompt.length/4),outputTokens=Math.ceil(content.length/4);return onChunk({type:"done",content:""}),{content,model:finalModel,inputTokens,outputTokens,durationMs,metadata:{provider:PROVIDER_NAME,mode:"sdk"}}}async healthCheck(){try{return await this.getClient(),{ok:!0,message:`${DISPLAY_NAME} SDK ready (API key configured)`}}catch(err){return{ok:!1,message:err instanceof Error?err.message:"SDK initialization failed"}}}extractResponseText(response){let parts=[];for(let output of response.output)if(output.type==="message"&&output.content){for(let block of output.content)if(block.type==="output_text"&&block.text)parts.push(block.text)}return parts.join("")}}function permissionFlags(mode){switch(mode){case"plan":return["-a","untrusted","--sandbox","read-only"];case"fullAuto":return["-a","never","--sandbox","workspace-write"];case"acceptEdits":default:return["-a","on-request","--sandbox","workspace-write"]}}class CodexCliAdapter{mode="cli";buildCliArgs(config,prompt){let args=["--quiet",...permissionFlags(config.permissionMode)];if(config.model)args.push("--model",config.model);return args.push(prompt),args}async sendPrompt(prompt,config){let startTime=Date.now(),args=this.buildCliArgs(config,prompt),proc=Bun.spawn([CLI_BIN,...args],{stdout:"pipe",stderr:"pipe",cwd:config.workingDirectory||process.cwd(),timeout:config.providerConfig?.timeoutMs||300000}),stdout=await new Response(proc.stdout).text(),stderr=await new Response(proc.stderr).text(),exitCode=await proc.exited,durationMs=Date.now()-startTime;if(exitCode!==0&&!stdout)throw Error(`${DISPLAY_NAME} CLI exited with code ${exitCode}: ${stderr}`);let content=stdout.trim()||stderr.trim(),inputTokens=Math.ceil(prompt.length/4),outputTokens=Math.ceil(content.length/4),model=config.model||DEFAULT_MODEL;return{content,model,inputTokens,outputTokens,durationMs,metadata:{exitCode,provider:PROVIDER_NAME,mode:"cli"}}}async streamPrompt(prompt,config,onChunk){let result=await this.sendPrompt(prompt,config);return onChunk({type:"text",content:result.content}),onChunk({type:"done",content:""}),result}async healthCheck(){try{let proc=Bun.spawnSync([CLI_BIN,"--version"],{timeout:5000,stdout:"pipe",stderr:"ignore"});if(proc.exitCode===0)return{ok:!0,message:`${DISPLAY_NAME} CLI ${proc.stdout.toString().trim()}`};return{ok:!1,message:`${DISPLAY_NAME} CLI not available (exit code ${proc.exitCode})`}}catch{return{ok:!1,message:`${DISPLAY_NAME} CLI not installed or not in PATH`}}}}class CodexProvider{name=PROVIDER_NAME;sessions=new Map;logIngester=null;hostServices=null;logger=null;activeMode=null;adapter=null;setHostServices(hs){this.hostServices=hs,this.logger=new BoundLogger(hs.logger,`${PROVIDER_NAME}-provider`);let registry2=new ProviderRegistry(hs);this.logIngester=registry2.getProvider("ai","log-ingester")??null}getSupportedModes(){return[...SUPPORTED_MODES]}getDisplayName(){return DISPLAY_NAME}getPrereqApiPrefix(){return API_PREFIX}getMode(){if(this.activeMode)return this.activeMode;return this.detectMode()}setMode(mode){if(!SUPPORTED_MODES.includes(mode))throw Error(`${DISPLAY_NAME} does not support ${mode} mode`);this.activeMode=mode,this.adapter=null,this.log("info",`Mode explicitly set to: ${mode}`)}detectMode(){if(process.env.OPENAI_API_KEY)return"sdk";try{if(Bun.which(CLI_COMMAND,{PATH:process.env.PATH}))return"cli"}catch{}return"sdk"}getAdapter(){if(this.adapter)return this.adapter;let mode=this.getMode();return this.adapter=mode==="sdk"?new CodexSdkAdapter:new CodexCliAdapter,this.activeMode=mode,this.log("info",`Adapter initialized in ${mode} mode`),this.adapter}async createSession(config){let id=config.providerConfig?.sessionId||crypto.randomUUID(),now=new Date().toISOString(),existing=this.sessions.get(id);if(existing)return existing.status="active",existing.updatedAt=now,this.toAISession(existing);let session={id,config,status:"active",stats:{inputTokens:0,outputTokens:0,requestCount:0,estimatedCostUsd:0},abortController:null,files:[],createdAt:now,updatedAt:now};return this.sessions.set(id,session),this.log("info",`Session created: ${id} (${config.name})`),this.toAISession(session)}async sendPrompt(sessionId,prompt,context){let session=this.getSession(sessionId);session.status="processing",session.updatedAt=new Date().toISOString();let abortController=new AbortController;session.abortController=abortController;let fullPrompt=this.buildFullPrompt(prompt,context,session.files);this.logIngester?.append({sessionId,type:"input",content:prompt});try{let result=await this.getAdapter().sendPrompt(fullPrompt,session.config,abortController.signal);return this.updateSessionStats(session,result.inputTokens,result.outputTokens),this.logIngester?.append({sessionId,type:"output",content:result.content,tokenCount:result.outputTokens,model:result.model,durationMs:result.durationMs}),{content:result.content,model:result.model,inputTokens:result.inputTokens,outputTokens:result.outputTokens,durationMs:result.durationMs,metadata:result.metadata}}catch(err){session.status="error",session.updatedAt=new Date().toISOString();let errorMsg=err instanceof Error?err.message:"Unknown error";throw this.logIngester?.append({sessionId,type:"error",content:errorMsg}),err}finally{session.abortController=null}}async streamPrompt(sessionId,prompt,context,onChunk){let session=this.getSession(sessionId);session.status="processing",session.updatedAt=new Date().toISOString();let abortController=new AbortController;session.abortController=abortController;let fullPrompt=this.buildFullPrompt(prompt,context,session.files);this.logIngester?.append({sessionId,type:"input",content:prompt});try{let adapter=this.getAdapter(),chunkHandler=onChunk??((_c)=>{}),result=await adapter.streamPrompt(fullPrompt,session.config,chunkHandler,abortController.signal);return this.updateSessionStats(session,result.inputTokens,result.outputTokens),this.logIngester?.append({sessionId,type:"output",content:result.content,tokenCount:result.outputTokens,model:result.model,durationMs:result.durationMs}),{content:result.content,model:result.model,inputTokens:result.inputTokens,outputTokens:result.outputTokens,durationMs:result.durationMs,metadata:result.metadata}}catch(err){session.status="error",session.updatedAt=new Date().toISOString();let errorMsg=err instanceof Error?err.message:"Unknown error";throw this.logIngester?.append({sessionId,type:"error",content:errorMsg}),err}finally{session.abortController=null}}async listModels(){return[...CODEX_MODELS]}async cancelRequest(sessionId){let session=this.sessions.get(sessionId);if(!session)throw Error(`Session ${sessionId} not found`);if(session.abortController)session.abortController.abort(),session.abortController=null,session.status="active",session.updatedAt=new Date().toISOString(),this.log("info",`Request cancelled for session: ${sessionId}`)}getCapabilities(){let mode=this.getMode();return{streaming:mode==="sdk",vision:mode==="sdk",fileAttachments:!0,toolUse:!1,mcpSupport:!1,voiceMode:!1,cancelSupport:mode==="sdk",modelListing:!0}}async attachFiles(sessionId,files){let session=this.getSession(sessionId);session.files.push(...files),session.updatedAt=new Date().toISOString(),this.log("debug",`Attached ${files.length} file(s) to session ${sessionId}`)}async getSessionLogs(_sessionId,_filter){return[]}async getUsageStats(sessionId){return this.sessions.get(sessionId)?.stats??{inputTokens:0,outputTokens:0,requestCount:0,estimatedCostUsd:0}}async configureSession(sessionId,config){let session=this.getSession(sessionId);Object.assign(session.config,config),session.updatedAt=new Date().toISOString()}async destroySession(sessionId){let session=this.sessions.get(sessionId);if(session){if(session.abortController)session.abortController.abort(),session.abortController=null;session.status="terminated",session.files=[],session.updatedAt=new Date().toISOString(),this.log("info",`Session terminated: ${sessionId}`)}}async listSessions(){return Array.from(this.sessions.values()).map((s)=>this.toAISession(s))}async getSessionStatus(sessionId){return this.sessions.get(sessionId)?.status??"terminated"}async healthCheck(){return this.getAdapter().healthCheck()}getCliLaunchSpec(){let env={},apiKey=process.env.OPENAI_API_KEY?.trim();if(apiKey)env.OPENAI_API_KEY=apiKey;return{binary:CLI_COMMAND,env}}async sdkOneShot(opts){let adapter=new CodexSdkAdapter,config={name:"vibe-ai-sdk",agentType:PROVIDER_NAME,model:opts.model??DEFAULT_MODEL,maxTokens:opts.maxTokens??DEFAULT_MAX_TOKENS,providerConfig:opts.extras},result=await adapter.sendPrompt(opts.prompt,config);return{text:result.content,usage:{inputTokens:result.inputTokens,outputTokens:result.outputTokens,model:result.model,durationMs:result.durationMs}}}getSession(sessionId){let session=this.sessions.get(sessionId);if(!session)throw Error(`Session ${sessionId} not found`);if(session.status==="terminated")throw Error("Session is terminated");return session}buildFullPrompt(prompt,context,files){let fullPrompt=prompt;if(context&&context.length>0){let contextStr=context.map((c)=>`--- Context (${c.type}): ---
|
|
20
|
+
`);super({baseURL:options.baseURL,timeout:options.timeout??600000,httpAgent:options.httpAgent,maxRetries:options.maxRetries,fetch:options.fetch});this.completions=new Completions3(this),this.chat=new Chat(this),this.embeddings=new Embeddings(this),this.files=new Files2(this),this.images=new Images(this),this.audio=new Audio(this),this.moderations=new Moderations(this),this.models=new Models(this),this.fineTuning=new FineTuning(this),this.graders=new Graders2(this),this.vectorStores=new VectorStores(this),this.beta=new Beta(this),this.batches=new Batches(this),this.uploads=new Uploads(this),this.responses=new Responses(this),this.evals=new Evals(this),this.containers=new Containers(this),this._options=options,this.apiKey=apiKey,this.organization=organization,this.project=project}defaultQuery(){return this._options.defaultQuery}defaultHeaders(opts){return{...super.defaultHeaders(opts),"OpenAI-Organization":this.organization,"OpenAI-Project":this.project,...this._options.defaultHeaders}}authHeaders(opts){return{Authorization:`Bearer ${this.apiKey}`}}stringifyQuery(query){return stringify(query,{arrayFormat:"brackets"})}};_a=OpenAI;OpenAI.OpenAI=_a;OpenAI.DEFAULT_TIMEOUT=600000;OpenAI.OpenAIError=OpenAIError;OpenAI.APIError=APIError;OpenAI.APIConnectionError=APIConnectionError;OpenAI.APIConnectionTimeoutError=APIConnectionTimeoutError;OpenAI.APIUserAbortError=APIUserAbortError;OpenAI.NotFoundError=NotFoundError;OpenAI.ConflictError=ConflictError;OpenAI.RateLimitError=RateLimitError;OpenAI.BadRequestError=BadRequestError;OpenAI.AuthenticationError=AuthenticationError;OpenAI.InternalServerError=InternalServerError;OpenAI.PermissionDeniedError=PermissionDeniedError;OpenAI.UnprocessableEntityError=UnprocessableEntityError;OpenAI.toFile=toFile;OpenAI.fileFromPath=fileFromPath;OpenAI.Completions=Completions3;OpenAI.Chat=Chat;OpenAI.ChatCompletionsPage=ChatCompletionsPage;OpenAI.Embeddings=Embeddings;OpenAI.Files=Files2;OpenAI.FileObjectsPage=FileObjectsPage;OpenAI.Images=Images;OpenAI.Audio=Audio;OpenAI.Moderations=Moderations;OpenAI.Models=Models;OpenAI.ModelsPage=ModelsPage;OpenAI.FineTuning=FineTuning;OpenAI.Graders=Graders2;OpenAI.VectorStores=VectorStores;OpenAI.VectorStoresPage=VectorStoresPage;OpenAI.VectorStoreSearchResponsesPage=VectorStoreSearchResponsesPage;OpenAI.Beta=Beta;OpenAI.Batches=Batches;OpenAI.BatchesPage=BatchesPage;OpenAI.Uploads=Uploads;OpenAI.Responses=Responses;OpenAI.Evals=Evals;OpenAI.EvalListResponsesPage=EvalListResponsesPage;OpenAI.Containers=Containers;OpenAI.ContainerListResponsesPage=ContainerListResponsesPage;AzureOpenAI=class AzureOpenAI extends OpenAI{constructor({baseURL=readEnv("OPENAI_BASE_URL"),apiKey=readEnv("AZURE_OPENAI_API_KEY"),apiVersion=readEnv("OPENAI_API_VERSION"),endpoint,deployment,azureADTokenProvider,dangerouslyAllowBrowser,...opts}={}){if(!apiVersion)throw new OpenAIError("The OPENAI_API_VERSION environment variable is missing or empty; either provide it, or instantiate the AzureOpenAI client with an apiVersion option, like new AzureOpenAI({ apiVersion: 'My API Version' }).");if(typeof azureADTokenProvider==="function")dangerouslyAllowBrowser=!0;if(!azureADTokenProvider&&!apiKey)throw new OpenAIError("Missing credentials. Please pass one of `apiKey` and `azureADTokenProvider`, or set the `AZURE_OPENAI_API_KEY` environment variable.");if(azureADTokenProvider&&apiKey)throw new OpenAIError("The `apiKey` and `azureADTokenProvider` arguments are mutually exclusive; only one can be passed at a time.");if(apiKey??(apiKey=API_KEY_SENTINEL),opts.defaultQuery={...opts.defaultQuery,"api-version":apiVersion},!baseURL){if(!endpoint)endpoint=process.env.AZURE_OPENAI_ENDPOINT;if(!endpoint)throw new OpenAIError("Must provide one of the `baseURL` or `endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable");baseURL=`${endpoint}/openai`}else if(endpoint)throw new OpenAIError("baseURL and endpoint are mutually exclusive");super({apiKey,baseURL,...opts,...dangerouslyAllowBrowser!==void 0?{dangerouslyAllowBrowser}:{}});this.apiVersion="",this._azureADTokenProvider=azureADTokenProvider,this.apiVersion=apiVersion,this.deploymentName=deployment}buildRequest(options,props={}){if(_deployments_endpoints.has(options.path)&&options.method==="post"&&options.body!==void 0){if(!isObj(options.body))throw Error("Expected request body to be an object");let model=this.deploymentName||options.body.model||options.__metadata?.model;if(model!==void 0&&!this.baseURL.includes("/deployments"))options.path=`/deployments/${model}${options.path}`}return super.buildRequest(options,props)}async _getAzureADToken(){if(typeof this._azureADTokenProvider==="function"){let token=await this._azureADTokenProvider();if(!token||typeof token!=="string")throw new OpenAIError(`Expected 'azureADTokenProvider' argument to return a string but it returned ${token}`);return token}return}authHeaders(opts){return{}}async prepareOptions(opts){if(opts.headers?.["api-key"])return super.prepareOptions(opts);let token=await this._getAzureADToken();if(opts.headers??(opts.headers={}),token)opts.headers.Authorization=`Bearer ${token}`;else if(this.apiKey!==API_KEY_SENTINEL)opts.headers["api-key"]=this.apiKey;else throw new OpenAIError("Unable to handle auth");return super.prepareOptions(opts)}};_deployments_endpoints=new Set(["/completions","/chat/completions","/embeddings","/audio/transcriptions","/audio/translations","/audio/speech","/images/generations","/images/edits"]),openai_default=OpenAI});import{mkdirSync}from"fs";import{tmpdir}from"os";import{join}from"path";import{Elysia as Elysia2}from"elysia";import{Elysia}from"elysia";function createLifecycleHooks(spec){let{name,onInit,onShutdown,onNuke,telemetryEventName,skipPlatforms}=spec;return{onServerStart:async(_app,hostServices)=>{if(skipPlatforms&&skipPlatforms.includes(process.platform)){process.stderr.write(`[${name}] skipping init on unsupported platform '${process.platform}'
|
|
21
|
+
`);return}if(onInit)await onInit(hostServices);if(telemetryEventName)hostServices.telemetry?.emit(telemetryEventName,{plugin:name})},onServerStop:async(hostServices)=>{if(onShutdown)await onShutdown(hostServices)},onNuke:async(hostServices,ctx)=>{if(onNuke)return onNuke(hostServices,ctx)}}}var TelemetryEmitter=class{constructor(pluginName,pluginVersion,hostServices){this.pluginName=pluginName,this.pluginVersion=pluginVersion,this.hostServices=hostServices}pluginName;pluginVersion;hostServices;emit(eventName,payload){let target=this.hostServices?.telemetry;if(!target)return;target.emit(eventName,{plugin:this.pluginName,version:this.pluginVersion,timestamp:new Date().toISOString(),...payload??{}})}emitReady(context){this.emit(`${this.pluginName}.ready`,context)}emitError(error,context){this.emit(`${this.pluginName}.error`,{message:error.message,...context??{}})}emitEvent(type,payload){this.emit(type,payload)}},BoundLogger=class{constructor(logger,source){this.logger=logger,this.source=source}logger;source;info(message,meta){this.logger?.info?.(this.source,message,meta)}warn(message,meta){this.logger?.warn?.(this.source,message,meta)}error(message,meta){this.logger?.error?.(this.source,message,meta)}debug(message,meta){this.logger?.debug?.(this.source,message,meta)}};var CONTEXT_PROVIDER_TYPE="context",REGISTRY_KEY=Symbol.for("@vibecontrols/plugin-sdk:contextProviders@1");function getRegistry(){let slots=globalThis,existing=slots[REGISTRY_KEY];if(existing)return existing;let created=new Map;return slots[REGISTRY_KEY]=created,created}function registerContextProvider(provider,hostServices){if(!provider||typeof provider.name!=="string"||provider.name.length===0)throw Error("ContextProvider.name is required");if(typeof provider.getContext!=="function")throw Error("ContextProvider.getContext must be a function");getRegistry().set(provider.name,provider),hostServices?.serviceRegistry?.registerProvider?.(CONTEXT_PROVIDER_TYPE,provider,provider.name)}function listContextProviders(){return Array.from(getRegistry().values())}function getContextProvider(name){return getRegistry().get(name)}var ProviderRegistry=class{constructor(hostServices){this.hostServices=hostServices}hostServices;registerContextProvider(provider){registerContextProvider(provider,this.hostServices)}listContextProviders(){return listContextProviders()}getContextProvider(name){return getContextProvider(name)}getServiceRegistry(){return this.hostServices?.serviceRegistry}registerProvider(type,name,provider){this.hostServices?.serviceRegistry?.registerProvider?.(type,provider,name)}getProvider(type,name){let reg=this.hostServices?.serviceRegistry;if(!reg)return;if(name===void 0)return reg.getProvider?.(type);if(reg.getProviderByName)return reg.getProviderByName(type,name);if(!reg.listProvidersForType)return;if(!(reg.listProvidersForType(type)??[]).some((entry)=>typeof entry==="string"?entry===name:entry.pluginName===name))return;return reg.getProvider?.(type)}listProviders(type){return(this.hostServices?.serviceRegistry?.listProvidersForType?.(type)??[]).map((entry)=>typeof entry==="string"?entry:entry.pluginName)}withCliContribution(contribution){let contributors=this.hostServices?.cliContributors;if(!contributors)return;for(let section of contribution.statusSections??[])contributors.addStatusSection?.(section);for(let check of contribution.doctorChecks??[])contributors.addDoctorCheck?.(check)}};var PROVIDER_NAME="codex",CLI_COMMAND="codex";function platformExeName(base){return process.platform==="win32"?`${base}.exe`:base}function resolveCliBin(){let found=typeof Bun<"u"&&typeof Bun.which==="function"?Bun.which(CLI_COMMAND,{PATH:process.env.PATH}):null;if(found)return found;return platformExeName(CLI_COMMAND)}var CLI_BIN=resolveCliBin(),DISPLAY_NAME="OpenAI Codex",DEFAULT_MODEL="gpt-4.1-mini",DEFAULT_MAX_TOKENS=16384,API_PREFIX=`/api/ai-${PROVIDER_NAME}`,SUPPORTED_MODES=["sdk","cli"],CLI_NPM_PACKAGE="@openai/codex",CODEX_MODELS=[{id:"codex-mini-latest",name:"Codex Mini",provider:PROVIDER_NAME,contextWindow:200000,maxOutputTokens:1e5,supportsVision:!1,supportsStreaming:!0,inputPricePerMToken:1.5,outputPricePerMToken:6},{id:"gpt-4.1",name:"GPT-4.1",provider:PROVIDER_NAME,contextWindow:1047576,maxOutputTokens:32768,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:2,outputPricePerMToken:8},{id:"gpt-4.1-mini",name:"GPT-4.1 Mini",provider:PROVIDER_NAME,contextWindow:1047576,maxOutputTokens:32768,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:0.4,outputPricePerMToken:1.6},{id:"gpt-4.1-nano",name:"GPT-4.1 Nano",provider:PROVIDER_NAME,contextWindow:1047576,maxOutputTokens:32768,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:0.1,outputPricePerMToken:0.4},{id:"o4-mini",name:"o4-mini",provider:PROVIDER_NAME,contextWindow:200000,maxOutputTokens:1e5,supportsVision:!0,supportsStreaming:!0,inputPricePerMToken:1.1,outputPricePerMToken:4.4}];class CodexSdkAdapter{mode="sdk";client=null;resolveApiKey;constructor(resolveApiKey){this.resolveApiKey=resolveApiKey}async getClient(){if(this.client)return this.client;let apiKey=(await this.resolveApiKey())?.trim();if(!apiKey)throw Error("OPENAI_API_KEY is required for SDK mode. Set it in the AI provider credentials (stored in the agent config) or export it in the agent environment.");let OpenAI2;try{let mod=await Promise.resolve().then(() => (init_openai(),exports_openai));OpenAI2=mod.default??mod}catch{throw Error("Failed to load openai SDK. Install it with: bun add openai")}return this.client=new OpenAI2({apiKey}),this.client}async sendPrompt(prompt,config,_signal){let client=await this.getClient(),startTime=Date.now(),params={model:config.model||DEFAULT_MODEL,input:prompt};if(config.systemPrompt)params.instructions=config.systemPrompt;if(config.maxTokens)params.max_output_tokens=config.maxTokens;let response=await client.responses.create(params),durationMs=Date.now()-startTime;return{content:this.extractResponseText(response),model:response.model,inputTokens:response.usage.input_tokens,outputTokens:response.usage.output_tokens,durationMs,metadata:{provider:PROVIDER_NAME,mode:"sdk"}}}async streamPrompt(prompt,config,onChunk,_signal){let client=await this.getClient(),startTime=Date.now(),model=config.model||DEFAULT_MODEL,params={model,input:prompt,stream:!0};if(config.systemPrompt)params.instructions=config.systemPrompt;if(config.maxTokens)params.max_output_tokens=config.maxTokens;let stream=client.responses.create(params),collectedText=[],finalModel=model,inputTokens=0,outputTokens=0;for await(let event of stream)if(event.type==="response.output_text.delta"&&event.delta)collectedText.push(event.delta),onChunk({type:"text",content:event.delta});else if(event.type==="response.completed"){let completed=event;if(completed.response)finalModel=completed.response.model,inputTokens=completed.response.usage.input_tokens,outputTokens=completed.response.usage.output_tokens}let durationMs=Date.now()-startTime,content=collectedText.join("");if(inputTokens===0&&outputTokens===0)inputTokens=Math.ceil(prompt.length/4),outputTokens=Math.ceil(content.length/4);return onChunk({type:"done",content:""}),{content,model:finalModel,inputTokens,outputTokens,durationMs,metadata:{provider:PROVIDER_NAME,mode:"sdk"}}}async healthCheck(){try{return await this.getClient(),{ok:!0,message:`${DISPLAY_NAME} SDK ready (API key configured)`}}catch(err){return{ok:!1,message:err instanceof Error?err.message:"SDK initialization failed"}}}extractResponseText(response){let parts=[];for(let output of response.output)if(output.type==="message"&&output.content){for(let block of output.content)if(block.type==="output_text"&&block.text)parts.push(block.text)}return parts.join("")}}function permissionFlags(mode){switch(mode){case"plan":return["--sandbox","read-only"];case"fullAuto":return["--dangerously-bypass-approvals-and-sandbox"];case"acceptEdits":default:return["--sandbox","workspace-write"]}}class CodexCliAdapter{mode="cli";resolveApiKey;loggedInKey=null;constructor(resolveApiKey){this.resolveApiKey=resolveApiKey}codexHome(){let home=process.env.CODEX_HOME?.trim()||join(tmpdir(),"vibe-codex-home");try{mkdirSync(home,{recursive:!0})}catch{}return home}async ensureAuth(home){let apiKey=(await this.resolveApiKey())?.trim();if(!apiKey||apiKey===this.loggedInKey)return;let proc=Bun.spawn([CLI_BIN,"login","--with-api-key"],{stdin:"pipe",stdout:"ignore",stderr:"pipe",env:{...process.env,CODEX_HOME:home},timeout:30000});proc.stdin.write(apiKey),await proc.stdin.end();let exitCode=await proc.exited;if(exitCode===0)this.loggedInKey=apiKey;else{let stderr=await new Response(proc.stderr).text();throw Error(`Codex CLI login failed (exit ${exitCode}): ${stderr.trim()}`)}}buildCliArgs(config,prompt){let args=["exec","--skip-git-repo-check","--color","never",...permissionFlags(config.permissionMode)];if(config.model)args.push("--model",config.model);return args.push(prompt),args}async spawnEnv(home){let env={...process.env,CODEX_HOME:home},apiKey=(await this.resolveApiKey())?.trim();if(apiKey)env.OPENAI_API_KEY=apiKey;return env}async sendPrompt(prompt,config){let startTime=Date.now(),args=this.buildCliArgs(config,prompt),home=this.codexHome();await this.ensureAuth(home);let proc=Bun.spawn([CLI_BIN,...args],{stdout:"pipe",stderr:"pipe",cwd:config.workingDirectory||process.cwd(),env:await this.spawnEnv(home),timeout:config.providerConfig?.timeoutMs||300000}),stdout=await new Response(proc.stdout).text(),stderr=await new Response(proc.stderr).text(),exitCode=await proc.exited,durationMs=Date.now()-startTime;if(exitCode!==0&&!stdout)throw Error(`${DISPLAY_NAME} CLI exited with code ${exitCode}: ${stderr}`);let content=stdout.trim()||stderr.trim(),inputTokens=Math.ceil(prompt.length/4),outputTokens=Math.ceil(content.length/4),model=config.model||DEFAULT_MODEL;return{content,model,inputTokens,outputTokens,durationMs,metadata:{exitCode,provider:PROVIDER_NAME,mode:"cli"}}}async streamPrompt(prompt,config,onChunk){let result=await this.sendPrompt(prompt,config);return onChunk({type:"text",content:result.content}),onChunk({type:"done",content:""}),result}async healthCheck(){try{let proc=Bun.spawnSync([CLI_BIN,"--version"],{timeout:5000,stdout:"pipe",stderr:"ignore"});if(proc.exitCode===0)return{ok:!0,message:`${DISPLAY_NAME} CLI ${proc.stdout.toString().trim()}`};return{ok:!1,message:`${DISPLAY_NAME} CLI not available (exit code ${proc.exitCode})`}}catch{return{ok:!1,message:`${DISPLAY_NAME} CLI not installed or not in PATH`}}}}class CodexProvider{name=PROVIDER_NAME;sessions=new Map;logIngester=null;hostServices=null;logger=null;activeMode=null;adapter=null;cachedApiKey;setHostServices(hs){this.hostServices=hs,this.logger=new BoundLogger(hs.logger,`${PROVIDER_NAME}-provider`);let registry2=new ProviderRegistry(hs);this.logIngester=registry2.getProvider("ai","log-ingester")??null,Promise.resolve(hs.getConfig?.("OPENAI_API_KEY")).then((apiKey)=>{let trimmed=apiKey?.trim();if(trimmed)this.cachedApiKey=trimmed}).catch(()=>{})}async resolveApiKey(){let envKey=process.env.OPENAI_API_KEY?.trim();if(envKey)return envKey;if(this.cachedApiKey)return this.cachedApiKey;if(this.hostServices?.getConfig)try{let apiKey=(await this.hostServices.getConfig("OPENAI_API_KEY"))?.trim();if(apiKey)return this.cachedApiKey=apiKey,apiKey}catch{return}return}getSupportedModes(){return[...SUPPORTED_MODES]}getDisplayName(){return DISPLAY_NAME}getPrereqApiPrefix(){return API_PREFIX}getMode(){if(this.activeMode)return this.activeMode;return this.detectMode()}setMode(mode){if(!SUPPORTED_MODES.includes(mode))throw Error(`${DISPLAY_NAME} does not support ${mode} mode`);this.activeMode=mode,this.adapter=null,this.log("info",`Mode explicitly set to: ${mode}`)}detectMode(){if(process.env.OPENAI_API_KEY?.trim()||this.cachedApiKey)return"sdk";try{if(Bun.which(CLI_COMMAND,{PATH:process.env.PATH}))return"cli"}catch{}return"sdk"}getAdapter(){if(this.adapter)return this.adapter;let mode=this.getMode();return this.adapter=mode==="sdk"?new CodexSdkAdapter(()=>this.resolveApiKey()):new CodexCliAdapter(()=>this.resolveApiKey()),this.activeMode=mode,this.log("info",`Adapter initialized in ${mode} mode`),this.adapter}async createSession(config){let id=config.providerConfig?.sessionId||crypto.randomUUID(),now=new Date().toISOString(),existing=this.sessions.get(id);if(existing)return existing.status="active",existing.updatedAt=now,this.toAISession(existing);let session={id,config,status:"active",stats:{inputTokens:0,outputTokens:0,requestCount:0,estimatedCostUsd:0},abortController:null,files:[],createdAt:now,updatedAt:now};return this.sessions.set(id,session),this.log("info",`Session created: ${id} (${config.name})`),this.toAISession(session)}async sendPrompt(sessionId,prompt,context){let session=this.getSession(sessionId);session.status="processing",session.updatedAt=new Date().toISOString();let abortController=new AbortController;session.abortController=abortController;let fullPrompt=this.buildFullPrompt(prompt,context,session.files);this.logIngester?.append({sessionId,type:"input",content:prompt});try{let result=await this.getAdapter().sendPrompt(fullPrompt,session.config,abortController.signal);return this.updateSessionStats(session,result.inputTokens,result.outputTokens),this.logIngester?.append({sessionId,type:"output",content:result.content,tokenCount:result.outputTokens,model:result.model,durationMs:result.durationMs}),{content:result.content,model:result.model,inputTokens:result.inputTokens,outputTokens:result.outputTokens,durationMs:result.durationMs,metadata:result.metadata}}catch(err){session.status="error",session.updatedAt=new Date().toISOString();let errorMsg=err instanceof Error?err.message:"Unknown error";throw this.logIngester?.append({sessionId,type:"error",content:errorMsg}),err}finally{session.abortController=null}}async streamPrompt(sessionId,prompt,context,onChunk){let session=this.getSession(sessionId);session.status="processing",session.updatedAt=new Date().toISOString();let abortController=new AbortController;session.abortController=abortController;let fullPrompt=this.buildFullPrompt(prompt,context,session.files);this.logIngester?.append({sessionId,type:"input",content:prompt});try{let adapter=this.getAdapter(),chunkHandler=onChunk??((_c)=>{}),result=await adapter.streamPrompt(fullPrompt,session.config,chunkHandler,abortController.signal);return this.updateSessionStats(session,result.inputTokens,result.outputTokens),this.logIngester?.append({sessionId,type:"output",content:result.content,tokenCount:result.outputTokens,model:result.model,durationMs:result.durationMs}),{content:result.content,model:result.model,inputTokens:result.inputTokens,outputTokens:result.outputTokens,durationMs:result.durationMs,metadata:result.metadata}}catch(err){session.status="error",session.updatedAt=new Date().toISOString();let errorMsg=err instanceof Error?err.message:"Unknown error";throw this.logIngester?.append({sessionId,type:"error",content:errorMsg}),err}finally{session.abortController=null}}async listModels(){return[...CODEX_MODELS]}async cancelRequest(sessionId){let session=this.sessions.get(sessionId);if(!session)throw Error(`Session ${sessionId} not found`);if(session.abortController)session.abortController.abort(),session.abortController=null,session.status="active",session.updatedAt=new Date().toISOString(),this.log("info",`Request cancelled for session: ${sessionId}`)}getCapabilities(){let mode=this.getMode();return{streaming:mode==="sdk",vision:mode==="sdk",fileAttachments:!0,toolUse:!1,mcpSupport:!1,voiceMode:!1,cancelSupport:mode==="sdk",modelListing:!0}}async attachFiles(sessionId,files){let session=this.getSession(sessionId);session.files.push(...files),session.updatedAt=new Date().toISOString(),this.log("debug",`Attached ${files.length} file(s) to session ${sessionId}`)}async getSessionLogs(_sessionId,_filter){return[]}async getUsageStats(sessionId){return this.sessions.get(sessionId)?.stats??{inputTokens:0,outputTokens:0,requestCount:0,estimatedCostUsd:0}}async configureSession(sessionId,config){let session=this.getSession(sessionId);Object.assign(session.config,config),session.updatedAt=new Date().toISOString()}async destroySession(sessionId){let session=this.sessions.get(sessionId);if(session){if(session.abortController)session.abortController.abort(),session.abortController=null;session.status="terminated",session.files=[],session.updatedAt=new Date().toISOString(),this.log("info",`Session terminated: ${sessionId}`)}}async listSessions(){return Array.from(this.sessions.values()).map((s)=>this.toAISession(s))}async getSessionStatus(sessionId){return this.sessions.get(sessionId)?.status??"terminated"}async healthCheck(){return this.getAdapter().healthCheck()}getCliLaunchSpec(){let env={},apiKey=process.env.OPENAI_API_KEY?.trim()||this.cachedApiKey;if(apiKey)env.OPENAI_API_KEY=apiKey;return{binary:CLI_COMMAND,env}}async sdkOneShot(opts){let adapter=new CodexSdkAdapter(()=>this.resolveApiKey()),config={name:"vibe-ai-sdk",agentType:PROVIDER_NAME,model:opts.model??DEFAULT_MODEL,maxTokens:opts.maxTokens??DEFAULT_MAX_TOKENS,providerConfig:opts.extras},result=await adapter.sendPrompt(opts.prompt,config);return{text:result.content,usage:{inputTokens:result.inputTokens,outputTokens:result.outputTokens,model:result.model,durationMs:result.durationMs}}}getSession(sessionId){let session=this.sessions.get(sessionId);if(!session)throw Error(`Session ${sessionId} not found`);if(session.status==="terminated")throw Error("Session is terminated");return session}buildFullPrompt(prompt,context,files){let fullPrompt=prompt;if(context&&context.length>0){let contextStr=context.map((c)=>`--- Context (${c.type}): ---
|
|
22
22
|
${c.content}`).join(`
|
|
23
23
|
|
|
24
24
|
`);fullPrompt=`${prompt}
|
|
@@ -28,4 +28,4 @@ ${textContent}`}).join(`
|
|
|
28
28
|
|
|
29
29
|
`);fullPrompt=`${fullPrompt}
|
|
30
30
|
|
|
31
|
-
${fileStr}`}return fullPrompt}updateSessionStats(session,inputTokens,outputTokens){let model=session.config.model||DEFAULT_MODEL,modelInfo=CODEX_MODELS.find((m)=>m.id===model);if(session.stats.inputTokens+=inputTokens,session.stats.outputTokens+=outputTokens,session.stats.requestCount+=1,modelInfo){let cost=inputTokens/1e6*modelInfo.inputPricePerMToken+outputTokens/1e6*modelInfo.outputPricePerMToken;session.stats.estimatedCostUsd+=cost}if(!session.stats.modelBreakdown)session.stats.modelBreakdown={};let breakdown=session.stats.modelBreakdown[model]??{inputTokens:0,outputTokens:0,requestCount:0};breakdown.inputTokens+=inputTokens,breakdown.outputTokens+=outputTokens,breakdown.requestCount+=1,session.stats.modelBreakdown[model]=breakdown,session.status="active",session.updatedAt=new Date().toISOString()}toAISession(s){return{id:s.id,name:s.config.name,status:s.status,agentType:s.config.agentType,provider:PROVIDER_NAME,config:s.config,stats:s.stats,createdAt:s.createdAt,updatedAt:s.updatedAt}}log(level,msg){this.logger?.[level](msg)}}function getCliVersion(){try{let proc=Bun.spawnSync([CLI_BIN,"--version"],{timeout:5000,stdout:"pipe",stderr:"ignore"});if(proc.exitCode===0)return proc.stdout.toString().trim()}catch{}return null}function createPrereqsRoutes(){return new Elysia2({prefix:"/prereqs"}).get("/status",()=>{let version=getCliVersion();return{satisfied:Boolean(version),missing:version?[]:[{name:CLI_COMMAND,kind:"npm",requiresSudo:!1,description:`${DISPLAY_NAME} CLI for CLI mode`}]}}).post("/install",()=>{if(getCliVersion())return{ok:!0,installed:[CLI_COMMAND],pendingSudo:[],errors:[]};let
|
|
31
|
+
${fileStr}`}return fullPrompt}updateSessionStats(session,inputTokens,outputTokens){let model=session.config.model||DEFAULT_MODEL,modelInfo=CODEX_MODELS.find((m)=>m.id===model);if(session.stats.inputTokens+=inputTokens,session.stats.outputTokens+=outputTokens,session.stats.requestCount+=1,modelInfo){let cost=inputTokens/1e6*modelInfo.inputPricePerMToken+outputTokens/1e6*modelInfo.outputPricePerMToken;session.stats.estimatedCostUsd+=cost}if(!session.stats.modelBreakdown)session.stats.modelBreakdown={};let breakdown=session.stats.modelBreakdown[model]??{inputTokens:0,outputTokens:0,requestCount:0};breakdown.inputTokens+=inputTokens,breakdown.outputTokens+=outputTokens,breakdown.requestCount+=1,session.stats.modelBreakdown[model]=breakdown,session.status="active",session.updatedAt=new Date().toISOString()}toAISession(s){return{id:s.id,name:s.config.name,status:s.status,agentType:s.config.agentType,provider:PROVIDER_NAME,config:s.config,stats:s.stats,createdAt:s.createdAt,updatedAt:s.updatedAt}}log(level,msg){this.logger?.[level](msg)}}function getCliVersion(){try{let proc=Bun.spawnSync([CLI_BIN,"--version"],{timeout:5000,stdout:"pipe",stderr:"ignore"});if(proc.exitCode===0)return proc.stdout.toString().trim()}catch{}return null}function installGlobalNpmCli(pkgSpec){let candidates=[["bun","install","-g",pkgSpec],["npm","install","-g",pkgSpec]],lastError="";for(let cmd of candidates){let exe=cmd[0];if(!Bun.which(exe,{PATH:process.env.PATH}))continue;try{let proc=Bun.spawnSync(cmd,{timeout:180000,stdout:"pipe",stderr:"pipe"});if(proc.exitCode===0)return{ok:!0,message:cmd.join(" ")};lastError=proc.stderr.toString().trim()||`${exe} exited ${proc.exitCode}`}catch(err){lastError=err instanceof Error?err.message:String(err)}}return{ok:!1,message:lastError||`No global installer (bun/npm) found. Run manually: bun install -g ${pkgSpec}`}}function createPrereqsRoutes(){return new Elysia2({prefix:"/prereqs"}).get("/status",()=>{let version=getCliVersion();return{satisfied:Boolean(version),missing:version?[]:[{name:CLI_COMMAND,kind:"npm",requiresSudo:!1,description:`${DISPLAY_NAME} CLI for CLI mode`}]}}).post("/install",()=>{if(getCliVersion())return{ok:!0,installed:[CLI_COMMAND],pendingSudo:[],errors:[]};let result=installGlobalNpmCli(CLI_NPM_PACKAGE);if(result.ok)return{ok:!0,installed:[CLI_COMMAND],pendingSudo:[],errors:[]};return{ok:!1,installed:[],pendingSudo:[],errors:[{name:CLI_COMMAND,message:result.message}]}})}var PLUGIN_NAME="codex",PLUGIN_VERSION="1.0.0",provider=new CodexProvider,lifecycle=createLifecycleHooks({name:PLUGIN_NAME,telemetryEventName:"ai.provider.ready",onInit:(hostServices)=>{provider.setHostServices(hostServices),new TelemetryEmitter(PLUGIN_NAME,PLUGIN_VERSION,hostServices).emit("ai.provider.ready",{provider:PLUGIN_NAME})},onShutdown:()=>{for(let[id]of provider.sessions)provider.destroySession(id).catch(()=>{})}}),createPlugin=(_ctx)=>({capabilities:{secrets:"read",subprocess:!0,gateway:!1,telemetry:!0},name:PLUGIN_NAME,version:PLUGIN_VERSION,description:"OpenAI Codex AI agent provider for VibeControls (dual-mode: SDK + CLI)",tags:["provider","integration"],apiPrefix:API_PREFIX,prerequisites:[{name:CLI_COMMAND,kind:"npm",requiresSudo:!1}],providers:{ai:provider},createRoutes:()=>createPrereqsRoutes(),onServerStart:lifecycle.onServerStart,onServerStop:lifecycle.onServerStop});export{permissionFlags,createPlugin};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibecontrols/vibe-plugin-ai-codex",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.731.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"description": "OpenAI Codex AI agent provider for VibeControls Agent",
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
"lint": "eslint ./src",
|
|
19
19
|
"format": "bunx prettier . --write",
|
|
20
20
|
"format:check": "bunx prettier . --check",
|
|
21
|
-
"type:check": "tsc --noEmit",
|
|
21
|
+
"type:check": "bash scripts/build-limits.sh tsc --noEmit",
|
|
22
22
|
"clean": "rimraf dist",
|
|
23
23
|
"prebuild": "bun run clean",
|
|
24
24
|
"prepublishOnly": "bun run build",
|
|
25
|
-
"sanity": "bun run format:check && bun run lint && bun run type:check && bun run build"
|
|
25
|
+
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run format:check && bun run lint && bun run type:check && bun run build'"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@vibecontrols/plugin-sdk": "2026.601.1",
|