grix-connector 4.2.7 → 4.2.9

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.
@@ -1,3 +1,3 @@
1
- import{execFileSync as I}from"node:child_process";import{stat as M}from"node:fs/promises";import{resolveCommandPath as w,spawnCommand as A,killProcessGroup as b}from"../../core/runtime/spawn.js";import{createInterface as C}from"node:readline";import{EventEmitter as k}from"node:events";import{join as _,resolve as E}from"node:path";import{homedir as P}from"node:os";import{fileURLToPath as T}from"node:url";import{InternalApiServer as x}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as $,LEGACY_MCP_SERVER_NAMES as N}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as R}from"../shared/inbound-message-id-injector.js";import{insertBeforeTrailingMessageReferences as B}from"../../core/protocol/message-reference.js";import{IdentityInjector as D}from"../shared/identity-injector.js";import{compactToolInputForWire as L}from"../shared/tool-wire-payload.js";import{syncDefaultSkillsToDir as U}from"../../default-skills/index.js";import{buildSimpleProbeReport as j}from"../shared/probe-util.js";import{getCachedCodeWhaleModels as O,primeCodeWhaleModels as G}from"./model-list.js";import{writeCodeWhaleGrixConfig as H}from"./codewhale-provider-config.js";import{log as o}from"../../core/log/index.js";import{SessionBindingStore as W}from"../../core/persistence/session-binding-store.js";const q=120*1e3,f=1800*1e3,F=5*1e3;function J(g){try{return process.kill(g,0),!0}catch(e){return e.code==="EPERM"}}class me extends k{type="codewhale";config;callbacks;alive=!1;stopped=!1;internalApi=null;deepSeekSessionId=null;activeEventId=null;activeSessionId=null;chunkSeq=0;activeClientMsgId=null;idleTimer=null;lastProgressAt=0;activeProcess=null;identity;inboundMessageIds=new R;bindingStore=null;aibotSessionId="";cwd;provider;agentName="";grixConfigPath="";lastUsage=null;currentModel=null;toolNamesById=new Map;auditCaptures=new Map;completedAuditBoundaries=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t,this.identity=new D("codewhale-adapter",t.getAgentProfile);const i=e.options??{};this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof W?i.bindingStore:null;const n=String(i.model??"").trim();if(n&&(this.currentModel=n),this.provider=i.provider,this.agentName=String(i.agentName??"").trim(),this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const s=this.bindingStore.getCodeWhaleThreadId(this.aibotSessionId);s&&(this.deepSeekSessionId=s)}}resolveCwd(){if(this.bindingStore&&this.aibotSessionId){const e=this.bindingStore.get(this.aibotSessionId);if(e?.cwd)return e.cwd}return process.cwd()}async start(){this.alive=!0,await this.applyGrixProviderConfig(),await this.startInternalApiAndRegisterMcp(),G(this.config.command||"codewhale"),this.notifyBindingReady(),o.info("codewhale-adapter","Ready (exec mode)")}async applyGrixProviderConfig(){if(!this.provider){this.grixConfigPath="";return}try{this.grixConfigPath=await H(this.agentName,this.provider)??"",this.grixConfigPath?o.info("codewhale-adapter",`Grix provider config written to ${this.grixConfigPath}`):o.warn("codewhale-adapter","provider config incomplete (baseUrl/model required); Grix provider not applied")}catch(e){this.grixConfigPath="",o.warn("codewhale-adapter",`Failed to write Grix provider config: ${e instanceof Error?e.message:String(e)}`)}}async stop(){this.stopped=!0,this.alive=!1,this.stopComposing(),this.clearIdleTimer(),this.killActiveProcess(),this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.internalApi&&(await this.internalApi.stop(),this.internalApi=null)}isAlive(){return this.alive}async createSession(e){const t=this.deepSeekSessionId??`ds-${Date.now()}`;return this.notifyBindingReady(),t}async resumeSession(e,t){}onAgentProfileChanged(){this.identity.onProfileChanged()}async destroySession(e){this.identity.forgetSession(e),this.inboundMessageIds.forgetSession(e),this.deepSeekSessionId=null,this.persistSessionId(void 0)}sendPrompt(e){const t=new y(e.adapterSessionId);return this.runMessage(e,t).catch(i=>{t.emitError(i instanceof Error?i:new Error(String(i)))}),t}async cancel(e){this.killActiveProcess()}setPermissionHandler(e){}async ping(e){if(this.stopped||!this.alive)return!1;const t=this.activeProcess;return!(t?.pid&&!J(t.pid))}getStatus(){return{alive:this.alive,busy:this.activeEventId!==null,sessions:this.deepSeekSessionId?1:0}}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}clearActiveEventForShutdown(){this.clearIdleTimer(),this.killActiveProcess(),this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.activeEventId=null}takeAuditBoundary(e){const t=this.completedAuditBoundaries.get(e);return t&&this.completedAuditBoundaries.delete(e),t}getMcpConfig(){if(!this.internalApi)return null;const e=E(T(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:$(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async probe(e){const t=this.getStatus();return j(this.config.command||"codewhale",{alive:t.alive,busy:t.busy,started:this.alive},e)}getUsageSnapshot(){return this.lastUsage}async startInternalApiAndRegisterMcp(){try{this.internalApi=new x,this.internalApi.setInvokeHandler(async(a,p,h,c)=>this.callbacks.agentInvoke(a,p,c)),await this.internalApi.start(0),o.info("codewhale-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t={...process.env,...this.config.env},i=typeof t.PATH=="string"?t.PATH:void 0,n=w(this.config.command||"codewhale",i);for(const a of[...N,e.name])try{I(n,["mcp","remove",a],{env:t,timeout:1e4,stdio:"ignore",windowsHide:!0})}catch{}const s=["mcp","add",e.name,"--command",e.command];for(const a of e.args)s.push("--arg",a);I(n,s,{env:t,timeout:1e4,stdio:"ignore",windowsHide:!0}),o.info("codewhale-adapter",`Registered MCP server: ${e.name}`);const d=_(P(),".codewhale","skills"),r=U(d);r.length>0&&o.info("codewhale-adapter",`Synced connector skills to ${d}: [${r.join(", ")}]`)}catch(e){o.warn("codewhale-adapter",`Failed to register MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}getSupportedCommands(){return[{name:"status",description:"Show session and working directory status"}]}async execCommand(e,t,i){return e==="status"?{status:"ok",message:`Session: ${this.deepSeekSessionId??"none"}, CWD: ${this.cwd}`,data:{sessionId:this.deepSeekSessionId,cwd:this.cwd,alive:this.alive}}:{status:"unsupported",message:`Unknown command: ${e}`}}async handleLocalAction(e){const t=e.action_type??"",i=e.params??{};switch(t){case"get_context":return this.callbacks.sendLocalActionResult(e.action_id,"ok",{sessionId:this.deepSeekSessionId,cwd:this.cwd,model:this.currentModel,model_id:this.currentModel,available_models:this.availableModelsMeta()}),{handled:!0,kind:"get_context"};case"set_model":{const n=String(i.model_id??"").trim();return n?(this.currentModel=n,this.callbacks.sendLocalActionResult(e.action_id,"ok",{outcome:"model_set",modelId:n,model_id:n,available_models:this.availableModelsMeta()}),o.info("codewhale-adapter",`Model set to: ${n}`),{handled:!0,kind:"set_model"}):(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"invalid_params","model_id is required"),{handled:!0,kind:"set_model"})}default:return{handled:!1,kind:""}}}availableModelsMeta(){return O(this.config.command||"codewhale").map(e=>({id:e.id,displayName:e.displayName}))}deliverInboundEvent(e){if(this.activeEventId){o.info("codewhale-adapter",`Event ${e.event_id}: rejected, busy with ${this.activeEventId}`),this.callbacks.sendEventResult(e.event_id,"failed","agent busy");return}const t=this.inboundMessageIds.inject(e.session_id,e.content,e.msg_id);this.startNewMessage(e,t)}deliverStopEvent(e,t){this.activeEventId===e&&(this.killActiveProcess(),this.callbacks.sendEventResult(e,"canceled","stopped by user"),this.clearActive())}startNewMessage(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,this.chunkSeq=0,this.activeClientMsgId=`ds-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.beginAuditCapture(e),this.startComposing();const i={adapterSessionId:this.deepSeekSessionId??"",text:t,contextMessages:e.context_messages_json?JSON.parse(e.context_messages_json).map(s=>({senderId:s.sender_id??"unknown",content:s.content})):void 0},n=new y(this.deepSeekSessionId??"");this.runMessage(i,n,e.event_id,e.session_id).catch(s=>{o.error("codewhale-adapter",`Message failed: ${s}`),this.callbacks.sendEventResult(e.event_id,"failed",s instanceof Error?s.message:String(s)),this.clearActive()}),this.resetIdleTimer(e.event_id)}buildExecArgs(e){const t=[];if(this.grixConfigPath){t.push("--config",this.grixConfigPath);const n=this.provider?.baseUrl?.trim();n&&t.push("--base-url",n)}const i=[...this.config.args??[]];return t.push("exec"),i.includes("--output-format")||t.push("--output-format","stream-json"),t.push(...i),this.currentModel&&t.push("--model",this.currentModel),this.deepSeekSessionId&&t.push("--resume",this.deepSeekSessionId),t.push("--",e),t}async runMessage(e,t,i,n){let s=e.text;if(e.contextMessages&&e.contextMessages.length>0){const c=e.contextMessages.map(l=>`[${l.senderId??"unknown"}]: ${l.content}`).join(`
1
+ import{execFileSync as I}from"node:child_process";import{stat as M}from"node:fs/promises";import{resolveCommandPath as w,spawnCommand as A,killProcessGroup as k}from"../../core/runtime/spawn.js";import{createInterface as C}from"node:readline";import{EventEmitter as b}from"node:events";import{join as _,resolve as E}from"node:path";import{homedir as P}from"node:os";import{fileURLToPath as T}from"node:url";import{InternalApiServer as x}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as $,LEGACY_MCP_SERVER_NAMES as N}from"../../core/mcp/server-name.js";import{InboundMessageIdInjector as R}from"../shared/inbound-message-id-injector.js";import{insertBeforeTrailingMessageReferences as B}from"../../core/protocol/message-reference.js";import{IdentityInjector as D}from"../shared/identity-injector.js";import{compactToolInputForWire as L}from"../shared/tool-wire-payload.js";import{syncDefaultSkillsToDir as j}from"../../default-skills/index.js";import{buildSimpleProbeReport as O}from"../shared/probe-util.js";import{getCachedCodeWhaleModels as U,primeCodeWhaleModels as G}from"./model-list.js";import{writeCodeWhaleGrixConfig as H}from"./codewhale-provider-config.js";import{log as o}from"../../core/log/index.js";import{SessionBindingStore as W}from"../../core/persistence/session-binding-store.js";const q=120*1e3,f=1800*1e3,F=5*1e3;function J(g){try{return process.kill(g,0),!0}catch(e){return e.code==="EPERM"}}class me extends b{type="codewhale";config;callbacks;alive=!1;stopped=!1;internalApi=null;deepSeekSessionId=null;activeEventId=null;activeSessionId=null;chunkSeq=0;activeClientMsgId=null;idleTimer=null;lastProgressAt=0;activeProcess=null;identity;inboundMessageIds=new R;bindingStore=null;aibotSessionId="";cwd;provider;agentName="";grixConfigPath="";lastUsage=null;currentModel=null;toolNamesById=new Map;auditCaptures=new Map;completedAuditBoundaries=new Map;constructor(e,t){super(),this.config=e,this.callbacks=t,this.identity=new D("codewhale-adapter",t.getAgentProfile);const i=e.options??{};this.aibotSessionId=String(i.aibotSessionId??"").trim(),this.bindingStore=i.bindingStore instanceof W?i.bindingStore:null;const n=String(i.model??"").trim();if(n&&(this.currentModel=n),this.provider=i.provider,this.agentName=String(i.agentName??"").trim(),this.cwd=this.resolveCwd(),this.bindingStore&&this.aibotSessionId){const s=this.bindingStore.getCodeWhaleThreadId(this.aibotSessionId);s&&(this.deepSeekSessionId=s)}}resolveCwd(){if(this.bindingStore&&this.aibotSessionId){const e=this.bindingStore.get(this.aibotSessionId);if(e?.cwd)return e.cwd}return process.cwd()}async start(){this.alive=!0,await this.applyGrixProviderConfig(),await this.startInternalApiAndRegisterMcp(),G(this.config.command||"codewhale"),this.notifyBindingReady(),o.info("codewhale-adapter","Ready (exec mode)")}async applyGrixProviderConfig(){if(!this.provider){this.grixConfigPath="";return}try{this.grixConfigPath=await H(this.agentName,this.provider)??"",this.grixConfigPath?o.info("codewhale-adapter",`Grix provider config written to ${this.grixConfigPath}`):o.warn("codewhale-adapter","provider config incomplete (baseUrl/model required); Grix provider not applied")}catch(e){this.grixConfigPath="",o.warn("codewhale-adapter",`Failed to write Grix provider config: ${e instanceof Error?e.message:String(e)}`)}}async stop(){this.stopped=!0,this.alive=!1,this.stopComposing(),this.clearIdleTimer(),this.killActiveProcess(),this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.internalApi&&(await this.internalApi.stop(),this.internalApi=null)}isAlive(){return this.alive}async createSession(e){const t=this.deepSeekSessionId??`ds-${Date.now()}`;return this.notifyBindingReady(),t}async resumeSession(e,t){}onAgentProfileChanged(){this.identity.onProfileChanged()}async destroySession(e){this.identity.forgetSession(e),this.inboundMessageIds.forgetSession(e),this.deepSeekSessionId=null,this.persistSessionId(void 0)}sendPrompt(e){const t=new y(e.adapterSessionId);return this.runMessage(e,t).catch(i=>{t.emitError(i instanceof Error?i:new Error(String(i)))}),t}async cancel(e){this.killActiveProcess()}setPermissionHandler(e){}async ping(e){if(this.stopped||!this.alive)return!1;const t=this.activeProcess;return!(t?.pid&&!J(t.pid))}getStatus(){return{alive:this.alive,busy:this.activeEventId!==null,sessions:this.deepSeekSessionId?1:0}}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}clearActiveEventForShutdown(){this.clearIdleTimer(),this.killActiveProcess(),this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.activeEventId=null}takeAuditBoundary(e){const t=this.completedAuditBoundaries.get(e);return t&&this.completedAuditBoundaries.delete(e),t}getMcpConfig(){if(!this.internalApi)return null;const e=E(T(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:$(this.callbacks.getAgentId?.()),command:process.execPath,args:[e,"--api-url",this.internalApi.url]}}async probe(e){const t=this.getStatus();return O(this.config.command||"codewhale",{alive:t.alive,busy:t.busy,started:this.alive},e)}getUsageSnapshot(){return this.lastUsage}async startInternalApiAndRegisterMcp(){try{this.internalApi=new x,this.internalApi.setInvokeHandler(async(a,p,h,c)=>this.callbacks.agentInvoke(a,p,c)),await this.internalApi.start(0),o.info("codewhale-adapter",`Internal API started at ${this.internalApi.url}`);const e=this.getMcpConfig(),t={...process.env,...this.config.env},i=typeof t.PATH=="string"?t.PATH:void 0,n=w(this.config.command||"codewhale",i);for(const a of[...N,e.name])try{I(n,["mcp","remove",a],{env:t,timeout:1e4,stdio:"ignore",windowsHide:!0})}catch{}const s=["mcp","add",e.name,"--command",e.command];for(const a of e.args)s.push("--arg",a);I(n,s,{env:t,timeout:1e4,stdio:"ignore",windowsHide:!0}),o.info("codewhale-adapter",`Registered MCP server: ${e.name}`);const d=_(P(),".codewhale","skills"),r=j(d);r.length>0&&o.info("codewhale-adapter",`Synced connector skills to ${d}: [${r.join(", ")}]`)}catch(e){o.warn("codewhale-adapter",`Failed to register MCP tools (non-fatal): ${e instanceof Error?e.message:String(e)}`)}}getSupportedCommands(){return[{name:"status",description:"Show session and working directory status"}]}async execCommand(e,t,i){return e==="status"?{status:"ok",message:`Session: ${this.deepSeekSessionId??"none"}, CWD: ${this.cwd}`,data:{sessionId:this.deepSeekSessionId,cwd:this.cwd,alive:this.alive}}:{status:"unsupported",message:`Unknown command: ${e}`}}async handleLocalAction(e){const t=e.action_type??"",i=e.params??{};switch(t){case"get_context":return this.callbacks.sendLocalActionResult(e.action_id,"ok",{sessionId:this.deepSeekSessionId,cwd:this.cwd,model:this.currentModel,model_id:this.currentModel,available_models:this.availableModelsMeta()}),{handled:!0,kind:"get_context"};case"set_model":{const n=String(i.model_id??"").trim();return n?(this.currentModel=n,this.callbacks.sendLocalActionResult(e.action_id,"ok",{outcome:"model_set",modelId:n,model_id:n,available_models:this.availableModelsMeta()}),o.info("codewhale-adapter",`Model set to: ${n}`),{handled:!0,kind:"set_model"}):(this.callbacks.sendLocalActionResult(e.action_id,"failed",void 0,"invalid_params","model_id is required"),{handled:!0,kind:"set_model"})}default:return{handled:!1,kind:""}}}availableModelsMeta(){return U(this.config.command||"codewhale").map(e=>({id:e.id,displayName:e.displayName}))}deliverInboundEvent(e){if(this.activeEventId){o.info("codewhale-adapter",`Event ${e.event_id}: rejected, busy with ${this.activeEventId}`),this.callbacks.sendEventResult(e.event_id,"failed","agent busy");return}const t=this.inboundMessageIds.inject(e.session_id,e.content,e.msg_id);this.startNewMessage(e,t)}deliverStopEvent(e,t){this.activeEventId===e&&(this.killActiveProcess(),this.callbacks.sendEventResult(e,"canceled","stopped by user"),this.clearActive())}startNewMessage(e,t){this.activeEventId=e.event_id,this.activeSessionId=e.session_id,this.chunkSeq=0,this.activeClientMsgId=`ds-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.beginAuditCapture(e),this.startComposing();const i={adapterSessionId:this.deepSeekSessionId??"",text:t,contextMessages:e.context_messages_json?JSON.parse(e.context_messages_json).map(s=>({senderId:s.sender_id??"unknown",content:s.content})):void 0},n=new y(this.deepSeekSessionId??"");this.runMessage(i,n,e.event_id,e.session_id).catch(s=>{o.error("codewhale-adapter",`Message failed: ${s}`),this.callbacks.sendEventResult(e.event_id,"failed",s instanceof Error?s.message:String(s)),this.clearActive()}),this.resetIdleTimer(e.event_id)}buildExecArgs(e){const t=[];this.grixConfigPath&&t.push("--config",this.grixConfigPath);const i=[...this.config.args??[]];return t.push("exec"),i.includes("--output-format")||t.push("--output-format","stream-json"),t.push(...i),this.currentModel&&t.push("--model",this.currentModel),this.deepSeekSessionId&&t.push("--resume",this.deepSeekSessionId),t.push("--",e),t}async runMessage(e,t,i,n){let s=e.text;if(e.contextMessages&&e.contextMessages.length>0){const c=e.contextMessages.map(l=>`[${l.senderId??"unknown"}]: ${l.content}`).join(`
2
2
  `);s=B(s,`[Conversation context]
3
- ${c}`)}s=this.identity.injectOnce(n??e.adapterSessionId,s);const d=this.config.command||"codewhale",r=this.buildExecArgs(s),a={...process.env,...this.config.env},p=w(d,typeof a.PATH=="string"?a.PATH:void 0);o.info("codewhale-adapter",`Spawning: ${p} ${r.slice(0,5).join(" ")}...`);try{if(!(await M(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(c){throw String(c?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):c}const h=A(p,r,{cwd:this.cwd,env:a}).process;return this.activeProcess=h,h.stderr?.on("data",c=>{const l=c.toString().trim();l&&o.info("codewhale-adapter",`[codewhale stderr] ${l}`)}),new Promise((c,l)=>{let m=!1,v="";const S=()=>{this.activeProcess=null};h.on("error",u=>{m||(m=!0,S(),l(u))}),h.on("exit",u=>{if(v.trim()&&this.handleOutputLine(v.trim(),i),v="",m){S();return}if(m=!0,S(),u!==0&&i&&this.activeEventId===i){l(new Error(`codewhale exec exited with code ${u}`));return}t.emitDone({status:"completed"}),c()}),C({input:h.stdout}).on("line",u=>{u.trim()&&this.handleOutputLine(u.trim(),i)}),h.stdin?.end()})}handleOutputLine(e,t){let i;try{i=JSON.parse(e)}catch{o.error("codewhale-adapter",`Invalid JSON: ${e.slice(0,200)}`);return}switch(t&&this.captureAuditEvent(t,e,i),i.type){case"content":{const s=i.content;s&&t&&this.activeEventId===t&&this.activeSessionId&&(this.chunkSeq++,this.callbacks.sendStreamChunk(t,this.activeSessionId,s,this.chunkSeq,!1,this.activeClientMsgId??void 0),this.startComposing(),this.resetIdleTimer(t));break}case"session_capture":{const s=i.content;s&&(this.deepSeekSessionId=s,this.persistSessionId(s),o.info("codewhale-adapter",`Session captured: ${s}`));break}case"metadata":{const s=i.meta;if(s){o.info("codewhale-adapter",`Metadata: model=${s.model}, tokens_in=${s.input_tokens}, tokens_out=${s.output_tokens}`);const d=Number(s.input_tokens??0),r=Number(s.output_tokens??0);if(d>0||r>0){const a=this.lastUsage;this.lastUsage={sampledAt:new Date().toISOString(),turns:(a?.turns??0)+1,total:{input:(a?.total.input??0)+d,output:(a?.total.output??0)+r}}}}break}case"tool_use":{const s=typeof i.name=="string"?i.name.trim():"",d=typeof i.id=="string"?i.id.trim():"",r=L(i.input);s&&t&&this.activeEventId===t&&this.activeSessionId&&(d&&this.toolNamesById.set(d,s),o.info("codewhale-adapter",`Tool use: ${s}`),this.callbacks.sendToolUse(t,this.activeSessionId,s,r),this.resetIdleTimer(t));break}case"tool_result":{const s=typeof i.id=="string"?i.id.trim():"",r=(typeof i.name=="string"?i.name.trim():"")||(s?this.toolNamesById.get(s):void 0)||"tool";s&&this.toolNamesById.delete(s);const a=typeof i.status=="string"?i.status.trim().toLowerCase():"",p=a==="failed"||a==="failure"||a==="error";t&&this.activeEventId===t&&this.activeSessionId&&(p&&this.callbacks.sendToolResult(t,this.activeSessionId,r,"(failed)"),this.resetIdleTimer(t));break}case"done":{this.handleMessageCompleted(t);break}default:break}}handleMessageCompleted(e){if(this.stopComposing(),e&&this.activeEventId===e){const t=this.activeSessionId??"",i=this.activeClientMsgId??void 0;t&&(this.chunkSeq++,this.callbacks.sendStreamChunk(e,t,"",this.chunkSeq,!0,i)),this.callbacks.sendEventResult(e,"responded"),this.clearActive()}}killActiveProcess(){const e=this.activeProcess;this.activeProcess=null,e?.pid&&(b(e,"SIGTERM"),setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{b(e,"SIGKILL")}catch{}},5e3).unref())}notifyBindingReady(){if(!this.aibotSessionId||!this.cwd)return;const e=this.availableModelsMeta(),t=this.currentModel??e[0]?.id??"";this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd,{model_id:t,available_models:e})}persistSessionId(e){!this.bindingStore||!this.aibotSessionId||this.bindingStore.setCodeWhaleThreadId(this.aibotSessionId,e)}startComposing(){}stopComposing(){}resetIdleTimer(e){this.lastProgressAt=Date.now(),this.armIdleTimer(e)}armIdleTimer(e){this.clearIdleTimer();const t=this.lastProgressAt+f-Date.now(),i=Math.max(0,Math.min(q,t));this.idleTimer=setTimeout(()=>{this.onIdleTimeout(e)},i)}async onIdleTimeout(e){if(this.activeEventId!==e)return;if(Date.now()-this.lastProgressAt>=f){this.failIdleRun(e,`liveness budget exhausted after ${f/6e4}min`);return}let i=!1;try{i=await this.ping(F)}catch{i=!1}if(this.activeEventId===e){if(i){o.info("codewhale-adapter",`Idle timer: process alive, extending until liveness cap (${f/6e4}min): ${e}`),this.armIdleTimer(e);return}this.failIdleRun(e,"process not alive")}}failIdleRun(e,t){this.activeEventId===e&&(o.error("codewhale-adapter",`Idle timeout (${t}): ${e}`),this.killActiveProcess(),this.callbacks.sendEventResult(e,"failed",`idle timeout: ${t}`),this.clearActive(),this.emit("stuck"))}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}clearActive(){const e=this.activeEventId;e&&this.snapshotAuditBoundary(e),this.stopComposing(),this.activeEventId=null,this.activeSessionId=null,this.chunkSeq=0,this.activeClientMsgId=null,this.toolNamesById.clear(),this.lastProgressAt=0,this.clearIdleTimer(),e&&this.emit("eventDone",e)}beginAuditCapture(e){!e.audit?.enabled||this.auditCaptures.has(e.event_id)||this.auditCaptures.set(e.event_id,{events:[]})}captureAuditEvent(e,t,i){const n=this.auditCaptures.get(e);n&&n.events.push({sequence:n.events.length,observedAt:new Date().toISOString(),rawLine:t,event:structuredClone(i)})}snapshotAuditBoundary(e){const t=this.auditCaptures.get(e);t&&(this.completedAuditBoundaries.set(e,{adapterType:"codewhale",providerSessionId:this.deepSeekSessionId??void 0,codeWhaleEvidence:{events:t.events}}),this.auditCaptures.delete(e))}}class y extends k{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){o.warn("codewhale-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}export{me as CodeWhaleAdapter};
3
+ ${c}`)}s=this.identity.injectOnce(n??e.adapterSessionId,s);const d=this.config.command||"codewhale",r=this.buildExecArgs(s),a={...process.env,...this.config.env},p=w(d,typeof a.PATH=="string"?a.PATH:void 0);o.info("codewhale-adapter",`Spawning: ${p} ${r.slice(0,5).join(" ")}...`);try{if(!(await M(this.cwd)).isDirectory())throw new Error(`Bound path is not a directory: ${this.cwd}`)}catch(c){throw String(c?.code??"")==="ENOENT"?new Error(`Bound directory does not exist: ${this.cwd}. Please rebind with /grix open <valid-directory>.`):c}const h=A(p,r,{cwd:this.cwd,env:a}).process;return this.activeProcess=h,h.stderr?.on("data",c=>{const l=c.toString().trim();l&&o.info("codewhale-adapter",`[codewhale stderr] ${l}`)}),new Promise((c,l)=>{let m=!1,v="";const S=()=>{this.activeProcess=null};h.on("error",u=>{m||(m=!0,S(),l(u))}),h.on("exit",u=>{if(v.trim()&&this.handleOutputLine(v.trim(),i),v="",m){S();return}if(m=!0,S(),u!==0&&i&&this.activeEventId===i){l(new Error(`codewhale exec exited with code ${u}`));return}t.emitDone({status:"completed"}),c()}),C({input:h.stdout}).on("line",u=>{u.trim()&&this.handleOutputLine(u.trim(),i)}),h.stdin?.end()})}handleOutputLine(e,t){let i;try{i=JSON.parse(e)}catch{o.error("codewhale-adapter",`Invalid JSON: ${e.slice(0,200)}`);return}switch(t&&this.captureAuditEvent(t,e,i),i.type){case"content":{const s=i.content;s&&t&&this.activeEventId===t&&this.activeSessionId&&(this.chunkSeq++,this.callbacks.sendStreamChunk(t,this.activeSessionId,s,this.chunkSeq,!1,this.activeClientMsgId??void 0),this.startComposing(),this.resetIdleTimer(t));break}case"session_capture":{const s=i.content;s&&(this.deepSeekSessionId=s,this.persistSessionId(s),o.info("codewhale-adapter",`Session captured: ${s}`));break}case"metadata":{const s=i.meta;if(s){o.info("codewhale-adapter",`Metadata: model=${s.model}, tokens_in=${s.input_tokens}, tokens_out=${s.output_tokens}`);const d=Number(s.input_tokens??0),r=Number(s.output_tokens??0);if(d>0||r>0){const a=this.lastUsage;this.lastUsage={sampledAt:new Date().toISOString(),turns:(a?.turns??0)+1,total:{input:(a?.total.input??0)+d,output:(a?.total.output??0)+r}}}}break}case"tool_use":{const s=typeof i.name=="string"?i.name.trim():"",d=typeof i.id=="string"?i.id.trim():"",r=L(i.input);s&&t&&this.activeEventId===t&&this.activeSessionId&&(d&&this.toolNamesById.set(d,s),o.info("codewhale-adapter",`Tool use: ${s}`),this.callbacks.sendToolUse(t,this.activeSessionId,s,r),this.resetIdleTimer(t));break}case"tool_result":{const s=typeof i.id=="string"?i.id.trim():"",r=(typeof i.name=="string"?i.name.trim():"")||(s?this.toolNamesById.get(s):void 0)||"tool";s&&this.toolNamesById.delete(s);const a=typeof i.status=="string"?i.status.trim().toLowerCase():"",p=a==="failed"||a==="failure"||a==="error";t&&this.activeEventId===t&&this.activeSessionId&&(p&&this.callbacks.sendToolResult(t,this.activeSessionId,r,"(failed)"),this.resetIdleTimer(t));break}case"done":{this.handleMessageCompleted(t);break}default:break}}handleMessageCompleted(e){if(this.stopComposing(),e&&this.activeEventId===e){const t=this.activeSessionId??"",i=this.activeClientMsgId??void 0;t&&(this.chunkSeq++,this.callbacks.sendStreamChunk(e,t,"",this.chunkSeq,!0,i)),this.callbacks.sendEventResult(e,"responded"),this.clearActive()}}killActiveProcess(){const e=this.activeProcess;this.activeProcess=null,e?.pid&&(k(e,"SIGTERM"),setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{k(e,"SIGKILL")}catch{}},5e3).unref())}notifyBindingReady(){if(!this.aibotSessionId||!this.cwd)return;const e=this.availableModelsMeta(),t=this.currentModel??e[0]?.id??"";this.callbacks.sendUpdateBindingCard(this.aibotSessionId,"ready",this.cwd,{model_id:t,available_models:e})}persistSessionId(e){!this.bindingStore||!this.aibotSessionId||this.bindingStore.setCodeWhaleThreadId(this.aibotSessionId,e)}startComposing(){}stopComposing(){}resetIdleTimer(e){this.lastProgressAt=Date.now(),this.armIdleTimer(e)}armIdleTimer(e){this.clearIdleTimer();const t=this.lastProgressAt+f-Date.now(),i=Math.max(0,Math.min(q,t));this.idleTimer=setTimeout(()=>{this.onIdleTimeout(e)},i)}async onIdleTimeout(e){if(this.activeEventId!==e)return;if(Date.now()-this.lastProgressAt>=f){this.failIdleRun(e,`liveness budget exhausted after ${f/6e4}min`);return}let i=!1;try{i=await this.ping(F)}catch{i=!1}if(this.activeEventId===e){if(i){o.info("codewhale-adapter",`Idle timer: process alive, extending until liveness cap (${f/6e4}min): ${e}`),this.armIdleTimer(e);return}this.failIdleRun(e,"process not alive")}}failIdleRun(e,t){this.activeEventId===e&&(o.error("codewhale-adapter",`Idle timeout (${t}): ${e}`),this.killActiveProcess(),this.callbacks.sendEventResult(e,"failed",`idle timeout: ${t}`),this.clearActive(),this.emit("stuck"))}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null)}clearActive(){const e=this.activeEventId;e&&this.snapshotAuditBoundary(e),this.stopComposing(),this.activeEventId=null,this.activeSessionId=null,this.chunkSeq=0,this.activeClientMsgId=null,this.toolNamesById.clear(),this.lastProgressAt=0,this.clearIdleTimer(),e&&this.emit("eventDone",e)}beginAuditCapture(e){!e.audit?.enabled||this.auditCaptures.has(e.event_id)||this.auditCaptures.set(e.event_id,{events:[]})}captureAuditEvent(e,t,i){const n=this.auditCaptures.get(e);n&&n.events.push({sequence:n.events.length,observedAt:new Date().toISOString(),rawLine:t,event:structuredClone(i)})}snapshotAuditBoundary(e){const t=this.auditCaptures.get(e);t&&(this.completedAuditBoundaries.set(e,{adapterType:"codewhale",providerSessionId:this.deepSeekSessionId??void 0,codeWhaleEvidence:{events:t.events}}),this.auditCaptures.delete(e))}}class y extends b{adapterSessionId;constructor(e){super(),this.adapterSessionId=e}emitDone(e){this.emit("done",e)}emitError(e){if(this.listenerCount("error")===0){o.warn("codewhale-adapter",`Prompt handle error (no listeners): ${e.message}`);return}this.emit("error",e)}async cancel(){}}export{me as CodeWhaleAdapter};
@@ -1,2 +1,2 @@
1
- import{mkdir as c,writeFile as d}from"node:fs/promises";import{homedir as f}from"node:os";import{join as n}from"node:path";const l="openai";function u(e){return(e??"default").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"default"}function s(e){return n(f(),".grix","runtime","native-provider",u(e),"codewhale")}async function _(e,r){const a=r.baseUrl?.trim(),t=r.model?.trim();if(!a||!t)return;const o=s(e),i=n(o,"config.toml"),m=[`provider = ${JSON.stringify(l)}`,`default_text_model = ${JSON.stringify(t)}`,'auth_mode = "api_key"',""].join(`
2
- `);return await c(o,{recursive:!0}),await d(i,m,{encoding:"utf8",mode:384}),i}export{s as codewhaleGrixConfigDir,_ as writeCodeWhaleGrixConfig};
1
+ import{mkdir as l,writeFile as s}from"node:fs/promises";import{homedir as m}from"node:os";import{join as a}from"node:path";import{PROVIDER_ENV_SPECS as u}from"../../core/config/provider-env.js";const d="openai",c=u.codewhale?.apiKey;function p(e){return(e??"default").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"default"}function _(e){return a(m(),".grix","runtime","native-provider",p(e),"codewhale")}async function v(e,r){const i=r.baseUrl?.trim(),o=r.model?.trim();if(!i||!o)return;if(!c)throw new Error("codewhale provider env spec declares no api key variable; refusing to write an unbound relay route");const t=_(e),n=a(t,"config.toml"),f=[`provider = ${JSON.stringify(d)}`,`default_text_model = ${JSON.stringify(o)}`,'auth_mode = "api_key"',"",`[providers.${d}]`,`base_url = ${JSON.stringify(i)}`,`api_key_env = ${JSON.stringify(c)}`,""].join(`
2
+ `);return await l(t,{recursive:!0}),await s(n,f,{encoding:"utf8",mode:384}),n}export{_ as codewhaleGrixConfigDir,v as writeCodeWhaleGrixConfig};
@@ -1,6 +1,6 @@
1
- import{execFile as j}from"node:child_process";import{createHash as A,randomUUID as R}from"node:crypto";import{closeSync as V,copyFileSync as p,cpSync as S,existsSync as d,mkdirSync as y,openSync as N,readFileSync as h,rmSync as f,statSync as m,writeFileSync as b}from"node:fs";import{join as o,resolve as I}from"node:path";import{fileURLToPath as D}from"node:url";import{promisify as O}from"node:util";import{log as G}from"../../core/log/index.js";import{resolveCliPath as _}from"../../core/util/cli-probe.js";import{bridgeDiscoveryDirectory as C,discoverDshBridgeEndpoints as M,resolveDshProfileIdentity as T}from"./profile-resolver.js";const J=O(j),L=2*1024*1024,u="@grix/dsh-bridge",F="deepseek-harness-bridge-installer",w=2,z=1e3;class se{options;command;identity;constructor(e={}){this.options=e,this.command=e.command?.trim()||"dsh",this.identity=T({dshHome:e.dshHome,profileName:e.profileName})}async status(){const e=await _(this.command),r=this.bridgeAsset(),t=this.readInstalledBridgeVersion(),n=r.version,s=M(this.identity),a=s[0]?.bridgeVersion??null,l=s[0]?.dshVersion??null,B=e?await q(e,this.options.dshHome):null;let c;return e?d(this.identity.profileRoot)?t?t!==n||this.installedBridgeContentStale(r)?c="bridge_update_required":s.length===0||a!==t||this.runningBridgePredatesInstalledContent(s[0])?c="profile_restart_required":c="ready":c="bridge_missing":c="profile_missing":c="dsh_missing",{readiness:c,command:this.command,commandPath:e,dshVersion:B,runningDshVersion:l,identity:this.identity,installedBridgeVersion:t,bundledBridgeVersion:n,runningBridgeVersion:a,endpointCount:s.length}}async install(){const e=await _(this.command);if(!e)throw Object.assign(new Error(`${this.command} not found`),{code:"dsh_missing"});const r=this.bridgeAsset();return E(this.identity,async()=>{await g(e,["--profile",this.identity.profileName,"--dump-config"],this.options.dshHome);const t=this.readInstalledBridgeVersion();if(t===r.version&&!this.installedBridgeContentStale(r))return this.status();const n=o(this.identity.dshHome,"assets","grix-dsh-bridge");y(n,{recursive:!0,mode:448});const s=this.captureInstallBackup(n,t),a=o(n,`grix-dsh-bridge-${r.version}.tgz`);p(r.tarball,a);try{if(t===r.version&&d(this.bridgePackageRoot())&&(await g(e,["plugin","--profile",this.identity.profileName,"remove",u],this.options.dshHome),d(this.bridgePackageRoot())))throw Object.assign(new Error(`dsh plugin remove left ${u} in place; refusing to attest an unverified reinstall`),{code:"bridge_install_failed"});await this.runPluginAdd(e,a),await g(e,["--profile",this.identity.profileName,"--dump-config"],this.options.dshHome);const l=this.readInstalledBridgeVersion();if(l!==r.version)throw Object.assign(new Error(`Bridge package did not land on disk (installed ${l??"none"}, expected ${r.version})`),{code:"bridge_install_failed"});this.writeInstalledBridgeIntegrity(r.integrity)}catch(l){await this.rollbackInstall(e,n,s,t);try{f(a,{force:!0})}catch{}throw Object.assign(new Error(`Bridge install failed: ${P(l)}`),{code:"bridge_install_failed"})}return this.discardInstallBackup(s),this.status()})}async uninstall(){const e=await _(this.command);if(!e)throw Object.assign(new Error(`${this.command} not found`),{code:"dsh_missing"});return E(this.identity,async()=>(this.readInstalledBridgeVersion()&&await g(e,["plugin","--profile",this.identity.profileName,"remove",u],this.options.dshHome),this.status()))}async runPluginAdd(e,r){const t=["plugin","--profile",this.identity.profileName,"add",r];let n;for(let s=1;s<=w;s++)try{await g(e,t,this.options.dshHome);return}catch(a){n=a,G.warn(F,`dsh plugin add attempt ${s}/${w} failed for profile ${this.identity.profileName}
2
- ${X(a)}`),s<w&&await new Promise(l=>setTimeout(l,z))}throw n}bridgePackageRoot(){return o(this.identity.profileRoot,"node_modules","@grix","dsh-bridge")}profilePackageJsonPath(){return o(this.identity.profileRoot,"package.json")}captureInstallBackup(e,r){const t=o(e,"rollback",`${Date.now()}-${R()}`);y(t,{recursive:!0,mode:448});const n=this.bridgePackageRoot(),s=d(n);s&&S(n,o(t,"dsh-bridge"),{recursive:!0});const a=this.profilePackageJsonPath(),l=d(a);l&&p(a,o(t,"package.json"));const B=["pnpm-lock.yaml","package-lock.json","yarn.lock"];for(const c of B){const v=o(this.identity.profileRoot,c);d(v)&&p(v,o(t,c))}return b(o(t,"manifest.json"),`${JSON.stringify({priorVersion:r,hadBridge:s,hadPackageJson:l})}
1
+ import{execFile as A}from"node:child_process";import{createHash as R,randomUUID as V}from"node:crypto";import{closeSync as N,copyFileSync as p,cpSync as S,existsSync as d,mkdirSync as y,openSync as O,readFileSync as h,rmSync as f,statSync as m,writeFileSync as b}from"node:fs";import{join as o,resolve as I}from"node:path";import{fileURLToPath as D}from"node:url";import{promisify as G}from"node:util";import{log as C}from"../../core/log/index.js";import{resolveCliPath as B}from"../../core/util/cli-probe.js";import{bridgeDiscoveryDirectory as M,discoverDshBridgeEndpoints as T,resolveDshProfileIdentity as J}from"./profile-resolver.js";const L=G(A),F=2*1024*1024,u="@grix/dsh-bridge",z="deepseek-harness-bridge-installer",w=2,U=1e3;class se{options;command;identity;constructor(e={}){this.options=e,this.command=e.command?.trim()||"dsh",this.identity=J({dshHome:e.dshHome,profileName:e.profileName})}async status(){const e=await B(this.command),r=this.bridgeAsset(),t=this.readInstalledBridgeVersion(),n=r.version,s=T(this.identity),a=s[0]?.bridgeVersion??null,l=s[0]?.dshVersion??null,_=e?await j(e,this.options.dshHome):null;let c;return e?d(this.identity.profileRoot)?t?t!==n||this.installedBridgeContentStale(r)?c="bridge_update_required":s.length===0||a!==t||this.runningBridgePredatesInstalledContent(s[0])?c="profile_restart_required":c="ready":c="bridge_missing":c="profile_missing":c="dsh_missing",{readiness:c,command:this.command,commandPath:e,dshVersion:_,runningDshVersion:l,identity:this.identity,installedBridgeVersion:t,bundledBridgeVersion:n,runningBridgeVersion:a,endpointCount:s.length}}async install(){const e=await B(this.command);if(!e)throw Object.assign(new Error(`${this.command} not found`),{code:"dsh_missing"});const r=this.bridgeAsset();return E(this.identity,async()=>{await g(e,["--profile",this.identity.profileName,"--dump-config"],this.options.dshHome);const t=this.readInstalledBridgeVersion();if(t===r.version&&!this.installedBridgeContentStale(r))return this.status();const n=o(this.identity.dshHome,"assets","grix-dsh-bridge");y(n,{recursive:!0,mode:448});const s=this.captureInstallBackup(n,t),a=o(n,`grix-dsh-bridge-${r.version}.tgz`);p(r.tarball,a);try{if(t===r.version&&d(this.bridgePackageRoot())&&(await g(e,["plugin","--profile",this.identity.profileName,"remove",u],this.options.dshHome),d(this.bridgePackageRoot())))throw Object.assign(new Error(`dsh plugin remove left ${u} in place; refusing to attest an unverified reinstall`),{code:"bridge_install_failed"});await this.runPluginAdd(e,a),await g(e,["--profile",this.identity.profileName,"--dump-config"],this.options.dshHome);const l=this.readInstalledBridgeVersion();if(l!==r.version)throw Object.assign(new Error(`Bridge package did not land on disk (installed ${l??"none"}, expected ${r.version})`),{code:"bridge_install_failed"});this.writeInstalledBridgeIntegrity(r.integrity)}catch(l){await this.rollbackInstall(e,n,s,t);try{f(a,{force:!0})}catch{}throw Object.assign(new Error(`Bridge install failed: ${P(l)}`),{code:"bridge_install_failed"})}return this.discardInstallBackup(s),this.status()})}async uninstall(){const e=await B(this.command);if(!e)throw Object.assign(new Error(`${this.command} not found`),{code:"dsh_missing"});return E(this.identity,async()=>(this.readInstalledBridgeVersion()&&await g(e,["plugin","--profile",this.identity.profileName,"remove",u],this.options.dshHome),this.status()))}async runPluginAdd(e,r){const t=["plugin","--profile",this.identity.profileName,"add",r];let n;for(let s=1;s<=w;s++)try{await g(e,t,this.options.dshHome);return}catch(a){n=a,C.warn(z,`dsh plugin add attempt ${s}/${w} failed for profile ${this.identity.profileName}
2
+ ${X(a)}`),s<w&&await new Promise(l=>setTimeout(l,U))}throw n}bridgePackageRoot(){return o(this.identity.profileRoot,"node_modules","@grix","dsh-bridge")}profilePackageJsonPath(){return o(this.identity.profileRoot,"package.json")}captureInstallBackup(e,r){const t=o(e,"rollback",`${Date.now()}-${V()}`);y(t,{recursive:!0,mode:448});const n=this.bridgePackageRoot(),s=d(n);s&&S(n,o(t,"dsh-bridge"),{recursive:!0});const a=this.profilePackageJsonPath(),l=d(a);l&&p(a,o(t,"package.json"));const _=["pnpm-lock.yaml","package-lock.json","yarn.lock"];for(const c of _){const v=o(this.identity.profileRoot,c);d(v)&&p(v,o(t,c))}return b(o(t,"manifest.json"),`${JSON.stringify({priorVersion:r,hadBridge:s,hadPackageJson:l})}
3
3
  `,{mode:384}),{root:t,priorVersion:r,hadBridge:s,hadPackageJson:l}}async rollbackInstall(e,r,t,n){const s=n?o(r,`grix-dsh-bridge-${n}.tgz`):null;if(s&&d(s)&&await g(e,["plugin","--profile",this.identity.profileName,"add",s],this.options.dshHome).then(()=>!0).catch(()=>!1)){this.discardInstallBackup(t);return}if(t.hadBridge&&d(o(t.root,"dsh-bridge"))){this.restoreFilesystemBackup(t),this.discardInstallBackup(t);return}n?t.hadPackageJson&&this.restoreFilesystemBackup(t):(await g(e,["plugin","--profile",this.identity.profileName,"remove",u],this.options.dshHome).catch(()=>{}),this.cleanHalfInstalledBridge()),this.discardInstallBackup(t)}restoreFilesystemBackup(e){const r=this.bridgePackageRoot(),t=o(e.root,"dsh-bridge");e.hadBridge&&d(t)&&(f(r,{recursive:!0,force:!0}),y(o(this.identity.profileRoot,"node_modules","@grix"),{recursive:!0,mode:448}),S(t,r,{recursive:!0})),e.hadPackageJson&&d(o(e.root,"package.json"))&&p(o(e.root,"package.json"),this.profilePackageJsonPath());for(const n of["pnpm-lock.yaml","package-lock.json","yarn.lock"]){const s=o(e.root,n);d(s)&&p(s,o(this.identity.profileRoot,n))}}cleanHalfInstalledBridge(){try{f(this.bridgePackageRoot(),{recursive:!0,force:!0})}catch{}const e=this.profilePackageJsonPath();if(d(e))try{const r=JSON.parse(h(e,"utf8"));let t=!1;for(const n of["dependencies","devDependencies","optionalDependencies","peerDependencies"]){const s=r[n];s&&typeof s=="object"&&!Array.isArray(s)&&u in s&&(delete s[u],t=!0)}t&&b(e,`${JSON.stringify(r,null,2)}
4
4
  `,{mode:384})}catch{}}discardInstallBackup(e){try{f(e.root,{recursive:!0,force:!0})}catch{}}readInstalledBridgeVersion(){const e=o(this.bridgePackageRoot(),"package.json");try{const r=JSON.parse(h(e,"utf8"));return typeof r.version=="string"?r.version:null}catch{return null}}installedIntegrityPath(){return o(this.bridgePackageRoot(),".grix-bridge-integrity")}readInstalledBridgeIntegrity(){try{const e=h(this.installedIntegrityPath(),"utf8").trim();return e.startsWith("sha512-")?e:null}catch{return null}}writeInstalledBridgeIntegrity(e){b(this.installedIntegrityPath(),`${e}
5
- `,{encoding:"utf8",mode:384})}installedBridgeContentStale(e=this.bridgeAsset()){return d(this.bridgePackageRoot())?this.readInstalledBridgeIntegrity()!==e.integrity:!0}runningBridgePredatesInstalledContent(e){try{const r=m(this.installedIntegrityPath()).mtimeMs,t=Date.parse(e.startedAt);return Number.isFinite(t)?r>t:!0}catch{return!1}}bridgeAsset(){return this.options.tarballPath?x(I(this.options.tarballPath)):$()}}function ne(i){if(i.readiness==="ready")return null;const e=i.identity.profileName,r=`dsh --profile ${e}`,t=i.endpointCount>0&&i.runningBridgeVersion&&i.installedBridgeVersion&&i.runningBridgeVersion!==i.installedBridgeVersion?`Grix Bridge in DSH profile "${e}" is running version ${i.runningBridgeVersion}, but ${i.installedBridgeVersion} is installed on disk. dsh does not hot-load plugin upgrades: stop the running profile process, then start it again with: ${r}`:`Grix Bridge is installed in DSH profile "${e}", but no live Bridge endpoint is available. dsh does not hot-load plugins: stop the running profile process, then start it again with: ${r}`,n={dsh_missing:"dsh is not installed or not on PATH. Install DeepSeek Harness (dsh), then retry.",profile_missing:`DSH profile "${e}" does not exist yet. Create/boot it once with: ${r}`,bridge_missing:`Grix Bridge is not installed in DSH profile "${e}". Install it from the DeepSeek Harness toolbar (or the dsh_install_bridge action), then restart the profile if it is already running.`,bridge_update_required:`Grix Bridge in DSH profile "${e}" needs an update (installed ${i.installedBridgeVersion??"none"}, expected ${i.bundledBridgeVersion}${i.installedBridgeVersion===i.bundledBridgeVersion?", content hash mismatch":""}). Update from the toolbar, then restart the profile \u2014 dsh does not hot-load plugin upgrades.`,profile_restart_required:t};return Object.assign(new Error(n[i.readiness]),{code:i.readiness})}function oe(){return $().tarball}function $(){const i=[D(new URL("../../assets/dsh-bridge/",import.meta.url)),D(new URL("../../../dist/assets/dsh-bridge/",import.meta.url))].find(t=>d(o(t,"manifest.json")));if(!i)throw Object.assign(new Error("Bundled Grix DSH Bridge asset is unavailable; run the Connector build first"),{code:"bridge_asset_missing"});const e=JSON.parse(h(o(i,"manifest.json"),"utf8"));if(typeof e.tarball!="string"||!e.tarball||typeof e.bridgeVersion!="string"||!e.bridgeVersion)throw Object.assign(new Error("Invalid Grix DSH Bridge asset manifest"),{code:"bridge_asset_invalid"});const r=x(o(i,e.tarball),e.bridgeVersion);if(Number(e.size)!==m(r.tarball).size)throw Object.assign(new Error("Grix DSH Bridge asset size mismatch"),{code:"bridge_asset_invalid"});if(typeof e.integrity=="string"&&e.integrity.startsWith("sha512-")&&e.integrity!==r.integrity)throw Object.assign(new Error("Grix DSH Bridge asset integrity mismatch"),{code:"bridge_asset_invalid"});return r}function x(i,e){if(!d(i)||!m(i).isFile())throw Object.assign(new Error(`Grix DSH Bridge asset is missing: ${i}`),{code:"bridge_asset_missing"});if(m(i).size>L)throw Object.assign(new Error("Grix DSH Bridge asset exceeds the 2 MiB safety limit"),{code:"bridge_asset_invalid"});const r=e??/grix-dsh-bridge-([0-9A-Za-z.+-]+)\.tgz$/.exec(i)?.[1];if(!r)throw Object.assign(new Error("Cannot determine Grix DSH Bridge version"),{code:"bridge_asset_invalid"});const t=`sha512-${A("sha512").update(h(i)).digest("base64")}`;return{tarball:i,version:r,integrity:t}}async function E(i,e){const r=C(i);y(r,{recursive:!0,mode:448});const t=o(r,"install.lock");let n=H(t);if(n===null){let s=0;try{s=Number(h(t,"utf8").trim())}catch{}let a=!1;try{a=s===0&&Date.now()-m(t).mtimeMs>5*6e4}catch{}if(a||Number.isSafeInteger(s)&&s>0&&!U(s)){try{f(t,{force:!0})}catch{}n=H(t)}}if(n===null)throw Object.assign(new Error(`Another Grix DSH Bridge install is active for profile ${i.profileName}`),{code:"bridge_install_busy"});try{return b(n,`${process.pid}
6
- `,"utf8"),await e()}finally{V(n);try{f(t,{force:!0})}catch{}}}function H(i){try{return N(i,"wx",384)}catch(e){if(e.code==="EEXIST")return null;throw Object.assign(new Error(`Cannot acquire Grix DSH Bridge install lock: ${P(e)}`),{code:"bridge_install_failed"})}}function U(i){try{return process.kill(i,0),!0}catch(e){return e.code==="EPERM"}}async function q(i,e){try{return(await g(i,["--version"],e)).trim().split(/\s+/)[0]||null}catch{return null}}async function g(i,e,r){try{return(await J(i,e,{env:{...process.env,...r?{DSH_HOME:I(r)}:{}},timeout:6e4,maxBuffer:8388608})).stdout}catch(t){const n=t&&typeof t=="object"?t:{};throw Object.assign(new Error(P(t)),{code:"dsh_command_failed",stderr:typeof n.stderr=="string"?k(n.stderr):void 0})}}function k(i){return i.replace(/(api[_-]?key|authorization|bearer)\s*[:=]\s*\S+/gi,"$1=[REDACTED]")}function P(i){const e=i&&typeof i=="object"?i:{};return k(String(e.stderr??e.message??i??"unknown error")).replace(/[\r\n]+/g," ").slice(0,1024)}function X(i){const e=i&&typeof i=="object"?i:{};return k(String(e.stderr??e.message??i??"unknown error")).slice(0,8*1024)}export{se as DshBridgeInstaller,oe as defaultBridgeTarball,ne as errorForDshBridgeReadiness};
5
+ `,{encoding:"utf8",mode:384})}installedBridgeContentStale(e=this.bridgeAsset()){return d(this.bridgePackageRoot())?this.readInstalledBridgeIntegrity()!==e.integrity:!0}runningBridgePredatesInstalledContent(e){try{const r=m(this.installedIntegrityPath()).mtimeMs,t=Date.parse(e.startedAt);return Number.isFinite(t)?r>t:!0}catch{return!1}}bridgeAsset(){return this.options.tarballPath?x(I(this.options.tarballPath)):$()}}function ne(i){if(i.readiness==="ready")return null;const e=i.identity.profileName,r=`dsh --profile ${e}`,t=i.endpointCount>0&&i.runningBridgeVersion&&i.installedBridgeVersion&&i.runningBridgeVersion!==i.installedBridgeVersion?`Grix Bridge in DSH profile "${e}" is running version ${i.runningBridgeVersion}, but ${i.installedBridgeVersion} is installed on disk. dsh does not hot-load plugin upgrades: stop the running profile process, then start it again with: ${r}`:`Grix Bridge is installed in DSH profile "${e}", but no live Bridge endpoint is available. dsh does not hot-load plugins: stop the running profile process, then start it again with: ${r}`,n={dsh_missing:"dsh is not installed or not on PATH. Install DeepSeek Harness (dsh), then retry.",profile_missing:`DSH profile "${e}" does not exist yet. Create/boot it once with: ${r}`,bridge_missing:`Grix Bridge is not installed in DSH profile "${e}". Install it from the DeepSeek Harness toolbar (or the dsh_install_bridge action), then restart the profile if it is already running.`,bridge_update_required:`Grix Bridge in DSH profile "${e}" needs an update (installed ${i.installedBridgeVersion??"none"}, expected ${i.bundledBridgeVersion}${i.installedBridgeVersion===i.bundledBridgeVersion?", content hash mismatch":""}). Update from the toolbar, then restart the profile \u2014 dsh does not hot-load plugin upgrades.`,profile_restart_required:t};return Object.assign(new Error(n[i.readiness]),{code:i.readiness})}function oe(){return $().tarball}function $(){const i=[D(new URL("../../assets/dsh-bridge/",import.meta.url)),D(new URL("../../../dist/assets/dsh-bridge/",import.meta.url))].find(t=>d(o(t,"manifest.json")));if(!i)throw Object.assign(new Error("Bundled Grix DSH Bridge asset is unavailable; run the Connector build first"),{code:"bridge_asset_missing"});const e=JSON.parse(h(o(i,"manifest.json"),"utf8"));if(typeof e.tarball!="string"||!e.tarball||typeof e.bridgeVersion!="string"||!e.bridgeVersion)throw Object.assign(new Error("Invalid Grix DSH Bridge asset manifest"),{code:"bridge_asset_invalid"});const r=x(o(i,e.tarball),e.bridgeVersion);if(Number(e.size)!==m(r.tarball).size)throw Object.assign(new Error("Grix DSH Bridge asset size mismatch"),{code:"bridge_asset_invalid"});if(typeof e.integrity=="string"&&e.integrity.startsWith("sha512-")&&e.integrity!==r.integrity)throw Object.assign(new Error("Grix DSH Bridge asset integrity mismatch"),{code:"bridge_asset_invalid"});return r}function x(i,e){if(!d(i)||!m(i).isFile())throw Object.assign(new Error(`Grix DSH Bridge asset is missing: ${i}`),{code:"bridge_asset_missing"});if(m(i).size>F)throw Object.assign(new Error("Grix DSH Bridge asset exceeds the 2 MiB safety limit"),{code:"bridge_asset_invalid"});const r=e??/grix-dsh-bridge-([0-9A-Za-z.+-]+)\.tgz$/.exec(i)?.[1];if(!r)throw Object.assign(new Error("Cannot determine Grix DSH Bridge version"),{code:"bridge_asset_invalid"});const t=`sha512-${R("sha512").update(h(i)).digest("base64")}`;return{tarball:i,version:r,integrity:t}}async function E(i,e){const r=M(i);y(r,{recursive:!0,mode:448});const t=o(r,"install.lock");let n=H(t);if(n===null){let s=0;try{s=Number(h(t,"utf8").trim())}catch{}let a=!1;try{a=s===0&&Date.now()-m(t).mtimeMs>5*6e4}catch{}if(a||Number.isSafeInteger(s)&&s>0&&!q(s)){try{f(t,{force:!0})}catch{}n=H(t)}}if(n===null)throw Object.assign(new Error(`Another Grix DSH Bridge install is active for profile ${i.profileName}`),{code:"bridge_install_busy"});try{return b(n,`${process.pid}
6
+ `,"utf8"),await e()}finally{N(n);try{f(t,{force:!0})}catch{}}}function H(i){try{return O(i,"wx",384)}catch(e){if(e.code==="EEXIST")return null;throw Object.assign(new Error(`Cannot acquire Grix DSH Bridge install lock: ${P(e)}`),{code:"bridge_install_failed"})}}function q(i){try{return process.kill(i,0),!0}catch(e){return e.code==="EPERM"}}async function ae(i,e){const r=await B(i?.trim()||"dsh");return r?j(r,e):null}async function j(i,e){try{return(await g(i,["--version"],e)).trim().split(/\s+/)[0]||null}catch{return null}}async function g(i,e,r){try{return(await L(i,e,{env:{...process.env,...r?{DSH_HOME:I(r)}:{}},timeout:6e4,maxBuffer:8388608})).stdout}catch(t){const n=t&&typeof t=="object"?t:{};throw Object.assign(new Error(P(t)),{code:"dsh_command_failed",stderr:typeof n.stderr=="string"?k(n.stderr):void 0})}}function k(i){return i.replace(/(api[_-]?key|authorization|bearer)\s*[:=]\s*\S+/gi,"$1=[REDACTED]")}function P(i){const e=i&&typeof i=="object"?i:{};return k(String(e.stderr??e.message??i??"unknown error")).replace(/[\r\n]+/g," ").slice(0,1024)}function X(i){const e=i&&typeof i=="object"?i:{};return k(String(e.stderr??e.message??i??"unknown error")).slice(0,8*1024)}export{se as DshBridgeInstaller,oe as defaultBridgeTarball,ne as errorForDshBridgeReadiness,ae as readDshCliVersion};
@@ -1,8 +1,8 @@
1
- import{mkdir as k,readFile as F,writeFile as W}from"node:fs/promises";import{join as $}from"node:path";import{log as S}from"../../core/log/index.js";import{DEFAULT_DSH_MODELS as G}from"./toolbar-state.js";const B="grix",g="GRIX_PROVIDER_API_KEY",j="settings.yaml",A=".credentials.yaml",_="dsh-provider",x="llm-pi-ai",L=new Map;function D(t,n){const r=(L.get(t)??Promise.resolve()).then(n,n);return L.set(t,r.catch(()=>{})),r}function l(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}class p extends Error{code="yaml_incomplete";constructor(n){super(n),this.name="IncompleteYamlError"}}async function w(t){try{return l(T(await F(t,"utf8")))}catch(n){if(n.code==="ENOENT")return{};throw n}}async function q(t){const n=$(t,A);return D(n,async()=>l((await w(n)).refs))}const K=1;function P(t){t.version===void 0&&(t.version=K);const n=l(t.refs);return t.refs=n,n}function Y(t){const n=t.baseUrl?.trim(),r=t.model?.trim();if(!n||!r)return;const s=new Map;s.set(r,{id:r,name:r,contextWindow:1e6});for(const e of G)s.has(e.id)||s.set(e.id,{id:e.id,name:e.displayName,contextWindow:e.contextWindow});return{displayName:"Grix",apiKeyEnv:g,api:"openai-completions",baseURL:n,compat:{thinkingFormat:"deepseek"},models:[...s.values()]}}function I(t){return l(t).apiKeyEnv===g}function M(t,n){const r=l(t);if(r.displayName!==n.displayName||r.apiKeyEnv!==n.apiKeyEnv||r.api!==n.api||r.baseURL!==n.baseURL||l(r.compat).thinkingFormat!==l(n.compat).thinkingFormat)return!1;const s=Array.isArray(n.models)?n.models:[],e=Array.isArray(r.models)?r.models:[];if(s.length!==e.length)return!1;const o=new Map(e.map(i=>[String(i.id??""),i]));return s.every(i=>{const c=o.get(String(i.id??""));return!!c&&c.name===i.name&&Number(c.contextWindow)===Number(i.contextWindow)})}function J(t){return!!t&&!!Y(t)&&!!t.apiKey?.trim()}async function Q(t,n,r){const s=Y(r),e=r.apiKey?.trim();if(!s||!e||!n.trim())return"skipped";const o=$(t,j),i=$(t,A);return D(o,async()=>{let c,a;try{c=await w(o),a=await w(i)}catch(y){if(y instanceof p)return S.warn(_,`Refusing to rewrite incomplete DSH YAML: ${y.message}`),"skipped";throw y}const f=l(c[x]),d=l(f.providers),u=d[n];if(u!==void 0&&!I(u))return"skipped";const h=P(a);return I(u)&&M(u,s)&&h[g]===e?"unchanged":(d[n]=s,f.providers=d,c[x]=f,h[g]=e,await k(t,{recursive:!0,mode:448}),await W(o,b(c),{encoding:"utf8",mode:384}),await W(i,b(a),{encoding:"utf8",mode:384}),S.info(_,`Wrote Grix provider providerId=${n} baseURL=${s.baseURL} api=openai-completions apiKeyEnv=${g} path=${o}`),"written")})}async function Z(t,n){const r=$(t,j),s=$(t,A);return D(r,async()=>{let e,o;try{e=await w(r),o=await w(s)}catch(f){if(f instanceof p)return S.warn(_,`Refusing to rewrite incomplete DSH YAML: ${f.message}`),!1;throw f}const i=l(e[x]),c=l(i.providers);if(!I(c[n]))return!1;delete c[n],i.providers=c,e[x]=i;const a=P(o);return delete a[g],Object.keys(a).length===0&&delete o.refs,await W(r,b(e),{encoding:"utf8",mode:384}),await W(s,b(o),{encoding:"utf8",mode:384}),!0})}function T(t){const n=t.replace(/^\uFEFF/,"");U(n);const r=V(n,0);return l(r.value)}function U(t){const n=t.split(/\r?\n/);for(let r=0;r<n.length;r++){const s=n[r]??"";if(s.includes(" "))throw new p(`tab indent at line ${r+1}`);const e=s.trim();if(!e||e.startsWith("#"))continue;if(e==="---"||e==="..."||e.startsWith("%"))throw new p(`document marker at line ${r+1}`);if((s.length-s.trimStart().length)%2!==0)throw new p(`odd indent at line ${r+1}`);const i=e.startsWith("- ")?e.slice(2):e;if(i.startsWith("&")||i.startsWith("*")||i.startsWith("!!")||i.startsWith("|")||i.startsWith(">"))throw new p(`unsupported yaml construct at line ${r+1}`);const c=i.indexOf(":");if(!e.startsWith("- ")&&c===-1)throw new p(`non-mapping line ${r+1}`);const a=c===-1?i:i.slice(c+1).trim();if(a&&a!=="[]"&&a!=="{}"&&!(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a.startsWith("{")||a.startsWith("[")||a.startsWith("|")||a.startsWith(">")||a.startsWith("&")||a.startsWith("*")||a.startsWith("!!")))throw new p(`unsupported inline yaml at line ${r+1}`)}}function b(t){const n=m(t,0);return n?`${n}
2
- `:""}function V(t,n){const r=t.split(/\r?\n/),s=[];for(let o=n;o<r.length;o++){const i=r[o]??"";if(!i.trim()||i.trimStart().startsWith("#"))continue;const c=i.length-i.trimStart().length;s.push({indent:c,content:i.trim()})}if(s.length===0)return{value:{},nextLine:r.length};const e=E(s,0,s[0].indent);if(e.next<s.length)throw new p("unconsumed yaml lines");return{value:e.value,nextLine:r.length}}function E(t,n,r){if(n>=t.length||t[n].indent<r)return{value:{},next:n};if(t[n].content.startsWith("- ")){const o=[];let i=n;for(;i<t.length&&t[i].indent===r&&t[i].content.startsWith("- ");){const c=t[i].content.slice(2),a=c.indexOf(":");if(a===-1){o.push(O(c)),i+=1;continue}const f=c.slice(0,a).trim(),d=c.slice(a+1).trim(),u=r+2;if(d){const y=E(t,i+1,u),N=l(y.value);N[f]=O(d),o.push(N),i=y.next;continue}const h=E(t,i+1,u);o.push({[f]:h.value}),i=h.next}return{value:o,next:i}}const s={};let e=n;for(;e<t.length&&t[e].indent===r&&!t[e].content.startsWith("- ");){const o=t[e].content.indexOf(":");if(o===-1)throw new p(`non-mapping entry: ${t[e].content}`);const i=t[e].content.slice(0,o).trim(),c=t[e].content.slice(o+1).trim();if(c){s[i]=O(c),e+=1;continue}const a=E(t,e+1,r+2);s[i]=a.value,e=a.next}return{value:s,next:e}}function O(t){return t==="~"||t==="null"?null:t==="true"?!0:t==="false"?!1:t==="[]"?[]:t==="{}"?{}:t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\"/g,'"'):/^-?\d+(?:\.\d+)?$/.test(t)?Number(t):t}function m(t,n){if(t==null)return"null";if(typeof t=="boolean"||typeof t=="number")return String(t);if(typeof t=="string")return C(t);if(Array.isArray(t))return t.length===0?"[]":t.map(e=>{if(e&&typeof e=="object"&&!Array.isArray(e)){const o=Object.entries(e);if(o.length===0)return`${" ".repeat(n)}- {}`;const[i,c]=o[0],f=R(c)?`${" ".repeat(n)}- ${i}: ${m(c,0)}`:`${" ".repeat(n)}- ${i}:
3
- ${m(c,n+4)}`,d=o.slice(1).map(([u,h])=>R(h)?`${" ".repeat(n+2)}${u}: ${m(h,0)}`:`${" ".repeat(n+2)}${u}:
4
- ${m(h,n+4)}`);return[f,...d].join(`
5
- `)}return`${" ".repeat(n)}- ${m(e,0)}`}).join(`
6
- `);const r=l(t),s=Object.keys(r);return s.length===0?"{}":s.map(e=>{const o=r[e];if(R(o))return`${" ".repeat(n)}${e}: ${m(o,0)}`;const i=m(o,n+2);return`${" ".repeat(n)}${e}:
7
- ${i}`}).join(`
8
- `)}function R(t){return t==null||typeof t=="string"||typeof t=="number"||typeof t=="boolean"||Array.isArray(t)&&t.length===0?!0:!!t&&typeof t=="object"&&!Array.isArray(t)&&Object.keys(t).length===0}function C(t){return t===""||/[:#{}[\],&*!|>'"%@`]|^\s|\s$|^(?:true|false|null|~)$/i.test(t)||/^-?\d+(?:\.\d+)?$/.test(t)?JSON.stringify(t):t}export{A as DSH_CREDENTIALS_FILE,g as DSH_GRIX_API_KEY_ENV,B as DSH_GRIX_PROVIDER_ID,j as DSH_SETTINGS_FILE,p as IncompleteYamlError,J as isDshGrixProviderConfigured,T as parseYamlMapping,q as readDshCredentials,Z as removeDshGrixProvider,b as stringifyYamlMapping,Q as writeDshGrixProvider};
1
+ import{chmod as C,mkdir as K,readFile as V,writeFile as A}from"node:fs/promises";import{join as w}from"node:path";import{log as $}from"../../core/log/index.js";import{DEFAULT_DSH_MODELS as U}from"./toolbar-state.js";import{compareDshVersions as v}from"./dsh-version.js";const ot="grix",g="GRIX_PROVIDER_API_KEY",P="settings.yaml",I=".credentials.yaml",x="dsh-provider",W="llm-pi-ai",F=new Map;function D(t,e){const r=(F.get(t)??Promise.resolve()).then(e,e);return F.set(t,r.catch(()=>{})),r}function f(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}class p extends Error{code="yaml_incomplete";constructor(e){super(e),this.name="IncompleteYamlError"}}async function E(t){try{return f(J(await V(t,"utf8")))}catch(e){if(e.code==="ENOENT")return{};throw e}}const H="0.1.1-rc.1";function ct(t){const e=v(t,H);return e!==null&&e<0?"flat":"refs"}function b(t){return"version"in t||"refs"in t?"refs":"flat"}async function at(t){const e=w(t,I);return D(e,async()=>{const r=await E(e);return b(r)==="refs"?f(r.refs):r})}const X=1;function G(t,e){const o={...b(t)==="refs"?f(t.refs):t};if(e==="flat")return Object.keys(f(t.records)).length>0?null:{doc:o,entries:o};const n={version:X,refs:o};return t.records!==void 0&&(n.records=t.records),{doc:n,entries:o}}const z=Object.freeze({thinkingFormat:"deepseek",supportsDeveloperRole:!1,maxTokensField:"max_tokens"}),B=Object.freeze({off:null,high:"high",max:"max"});function M(t){const e=t.baseUrl?.trim(),r=t.model?.trim();if(!e||!r)return;const o=()=>({...B}),n=new Map;n.set(r,{id:r,name:r,contextWindow:1e6,reasoningEfforts:o()});for(const i of U)n.has(i.id)||n.set(i.id,{id:i.id,name:i.displayName,contextWindow:i.contextWindow,reasoningEfforts:o()});return{displayName:"Grix",apiKeyEnv:g,api:"openai-completions",baseURL:e,compat:{...z},models:[...n.values()]}}function N(t){return f(t).apiKeyEnv===g}function q(t,e){const r=f(t);if(r.displayName!==e.displayName||r.apiKeyEnv!==e.apiKeyEnv||r.api!==e.api||r.baseURL!==e.baseURL||!T(r.compat,e.compat))return!1;const o=Array.isArray(e.models)?e.models:[],n=Array.isArray(r.models)?r.models:[];if(o.length!==n.length)return!1;const i=new Map(n.map(s=>[String(s.id??""),s]));return o.every(s=>{const a=i.get(String(s.id??""));return!!a&&a.name===s.name&&Number(a.contextWindow)===Number(s.contextWindow)&&T(a.reasoningEfforts,s.reasoningEfforts)})}function T(t,e){const r=f(t),o=f(e),n=new Set([...Object.keys(r),...Object.keys(o)]);for(const i of n)if((r[i]??null)!==(o[i]??null))return!1;return!0}async function Y(t,e){await A(t,e,{encoding:"utf8",mode:384}),await C(t,384)}function ft(t){return!!t&&!!M(t)&&!!t.apiKey?.trim()}async function lt(t,e,r,o){const n=M(r),i=r.apiKey?.trim();if(!n||!i||!e.trim())return"skipped";const s=w(t,P),a=w(t,I);return D(s,async()=>{let c,l;try{c=await E(s),l=await E(a)}catch(R){if(R instanceof p)return $.warn(x,`Refusing to rewrite incomplete DSH YAML: ${R.message}`),"skipped";throw R}const u=f(c[W]),h=f(u.providers),d=h[e];if(d!==void 0&&!N(d))return"skipped";const S=b(l)===o,y=G(l,o);if(!y)return $.warn(x,'Refusing to flatten .credentials.yaml: it carries a "records" section this dsh cannot read'),"skipped";const k=y.entries;return S&&N(d)&&q(d,n)&&k[g]===i?"unchanged":(h[e]=n,u.providers=h,c[W]=u,k[g]=i,await K(t,{recursive:!0,mode:448}),await A(s,_(c),{encoding:"utf8",mode:384}),await Y(a,_(y.doc)),$.info(x,`Wrote Grix provider providerId=${e} baseURL=${n.baseURL} api=openai-completions apiKeyEnv=${g} credentialsLayout=${o} path=${s}`),"written")})}async function ut(t,e){const r=w(t,P),o=w(t,I);return D(r,async()=>{let n,i;try{n=await E(r),i=await E(o)}catch(u){if(u instanceof p)return $.warn(x,`Refusing to rewrite incomplete DSH YAML: ${u.message}`),!1;throw u}const s=f(n[W]),a=f(s.providers);if(!N(a[e]))return!1;delete a[e],s.providers=a,n[W]=s;const c=b(i),l=G(i,c);return l?(delete l.entries[g],c==="refs"&&Object.keys(l.entries).length===0&&delete l.doc.refs,await A(r,_(n),{encoding:"utf8",mode:384}),await Y(o,_(l.doc)),!0):($.warn(x,'Refusing to flatten .credentials.yaml: it carries a "records" section this dsh cannot read'),!1)})}function J(t){const e=t.replace(/^\uFEFF/,"");Q(e);const r=Z(e,0);return f(r.value)}function Q(t){const e=t.split(/\r?\n/);for(let r=0;r<e.length;r++){const o=e[r]??"";if(o.includes(" "))throw new p(`tab indent at line ${r+1}`);const n=o.trim();if(!n||n.startsWith("#"))continue;if(n==="---"||n==="..."||n.startsWith("%"))throw new p(`document marker at line ${r+1}`);if((o.length-o.trimStart().length)%2!==0)throw new p(`odd indent at line ${r+1}`);const s=n.startsWith("- ")?n.slice(2):n;if(s.startsWith("&")||s.startsWith("*")||s.startsWith("!!")||s.startsWith("|")||s.startsWith(">"))throw new p(`unsupported yaml construct at line ${r+1}`);const a=s.indexOf(":");if(!n.startsWith("- ")&&a===-1)throw new p(`non-mapping line ${r+1}`);const c=a===-1?s:s.slice(a+1).trim();if(c&&c!=="[]"&&c!=="{}"&&!(c.startsWith('"')&&c.endsWith('"')||c.startsWith("'")&&c.endsWith("'"))&&(c.startsWith("{")||c.startsWith("[")||c.startsWith("|")||c.startsWith(">")||c.startsWith("&")||c.startsWith("*")||c.startsWith("!!")))throw new p(`unsupported inline yaml at line ${r+1}`)}}function _(t){const e=m(t,0);return e?`${e}
2
+ `:""}function Z(t,e){const r=t.split(/\r?\n/),o=[];for(let i=e;i<r.length;i++){const s=r[i]??"";if(!s.trim()||s.trimStart().startsWith("#"))continue;const a=s.length-s.trimStart().length;o.push({indent:a,content:s.trim()})}if(o.length===0)return{value:{},nextLine:r.length};const n=O(o,0,o[0].indent);if(n.next<o.length)throw new p("unconsumed yaml lines");return{value:n.value,nextLine:r.length}}function O(t,e,r){if(e>=t.length||t[e].indent<r)return{value:{},next:e};if(t[e].content.startsWith("- ")){const i=[];let s=e;for(;s<t.length&&t[s].indent===r&&t[s].content.startsWith("- ");){const a=t[s].content.slice(2),c=a.indexOf(":");if(c===-1){i.push(j(a)),s+=1;continue}const l=a.slice(0,c).trim(),u=a.slice(c+1).trim(),h=r+2;if(u){const S=O(t,s+1,h),y=f(S.value);y[l]=j(u),i.push(y),s=S.next;continue}const d=O(t,s+1,h);i.push({[l]:d.value}),s=d.next}return{value:i,next:s}}const o={};let n=e;for(;n<t.length&&t[n].indent===r&&!t[n].content.startsWith("- ");){const i=t[n].content.indexOf(":");if(i===-1)throw new p(`non-mapping entry: ${t[n].content}`);const s=t[n].content.slice(0,i).trim(),a=t[n].content.slice(i+1).trim();if(a){o[s]=j(a),n+=1;continue}const c=O(t,n+1,r+2);o[s]=c.value,n=c.next}return{value:o,next:n}}function j(t){return t==="~"||t==="null"?null:t==="true"?!0:t==="false"?!1:t==="[]"?[]:t==="{}"?{}:t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\"/g,'"'):/^-?\d+(?:\.\d+)?$/.test(t)?Number(t):t}function m(t,e){if(t==null)return"null";if(typeof t=="boolean"||typeof t=="number")return String(t);if(typeof t=="string")return tt(t);if(Array.isArray(t))return t.length===0?"[]":t.map(n=>{if(n&&typeof n=="object"&&!Array.isArray(n)){const i=Object.entries(n);if(i.length===0)return`${" ".repeat(e)}- {}`;const[s,a]=i[0],l=L(a)?`${" ".repeat(e)}- ${s}: ${m(a,0)}`:`${" ".repeat(e)}- ${s}:
3
+ ${m(a,e+4)}`,u=i.slice(1).map(([h,d])=>L(d)?`${" ".repeat(e+2)}${h}: ${m(d,0)}`:`${" ".repeat(e+2)}${h}:
4
+ ${m(d,e+4)}`);return[l,...u].join(`
5
+ `)}return`${" ".repeat(e)}- ${m(n,0)}`}).join(`
6
+ `);const r=f(t),o=Object.keys(r);return o.length===0?"{}":o.map(n=>{const i=r[n];if(L(i))return`${" ".repeat(e)}${n}: ${m(i,0)}`;const s=m(i,e+2);return`${" ".repeat(e)}${n}:
7
+ ${s}`}).join(`
8
+ `)}function L(t){return t==null||typeof t=="string"||typeof t=="number"||typeof t=="boolean"||Array.isArray(t)&&t.length===0?!0:!!t&&typeof t=="object"&&!Array.isArray(t)&&Object.keys(t).length===0}function tt(t){return t===""||/[:#{}[\],&*!|>'"%@`]|^\s|\s$|^(?:true|false|null|~)$/i.test(t)||/^-?\d+(?:\.\d+)?$/.test(t)?JSON.stringify(t):t}export{I as DSH_CREDENTIALS_FILE,H as DSH_CREDENTIALS_REFS_MIN_VERSION,g as DSH_GRIX_API_KEY_ENV,ot as DSH_GRIX_PROVIDER_ID,P as DSH_SETTINGS_FILE,p as IncompleteYamlError,ct as dshCredentialsLayoutFor,ft as isDshGrixProviderConfigured,J as parseYamlMapping,at as readDshCredentials,ut as removeDshGrixProvider,_ as stringifyYamlMapping,lt as writeDshGrixProvider};
@@ -0,0 +1 @@
1
+ function d(t){const e=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(String(t??"").trim());return e?{major:Number(e[1]),minor:Number(e[2]),patch:Number(e[3]),...e[4]?{prerelease:e[4]}:{}}:null}function a(t,e){const r=d(t),n=d(e);return!r||!n?null:r.major-n.major||r.minor-n.minor||r.patch-n.patch||f(r.prerelease,n.prerelease)}function f(t,e){if(t===e)return 0;if(t===void 0)return 1;if(e===void 0)return-1;const r=t.split("."),n=e.split(".");for(let s=0;s<Math.max(r.length,n.length);s+=1){const i=r[s],u=n[s];if(i===u)continue;if(i===void 0)return-1;if(u===void 0)return 1;const o=/^\d+$/.test(i),c=/^\d+$/.test(u);return o&&c?Number(i)-Number(u):o!==c?o?-1:1:i<u?-1:1}return 0}export{a as compareDshVersions,d as parseDshVersion};