grix-connector 3.26.2 → 3.26.3

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,4 +1,4 @@
1
- import{randomUUID as I}from"node:crypto";const M="x-grix-openai-wire-compat",z="chat-completions";function _(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function B(t){return Array.isArray(t)?t[0]?.trim().toLowerCase()??"":t?.trim().toLowerCase()??""}const A=["<||DSML||tool_calls>","<|DSML|tool_calls>","<||DSML||tools_commands_exec>","<|DSML|tools_commands_exec>","<||DSML||:","<|DSML|:"];function T(t){return t.replaceAll("\uFF5C","|")}function C(t){return t.replaceAll("&quot;",'"').replaceAll("&apos;","'").replaceAll("&#39;","'").replaceAll("&lt;","<").replaceAll("&gt;",">").replaceAll("&amp;","&")}function L(t){const e=T(t),n=/<\|{1,2}DSML\|{1,2}:([\s\S]*?)<\/\|{1,2}DSML\|{1,2}>/.exec(e);if(n&&typeof n.index=="number"){const a=C(n[1].trim());if(a)return{calls:[{name:"exec_command",arguments:JSON.stringify({cmd:a})}],visibleText:`${t.slice(0,n.index)}${t.slice(n.index+n[0].length)}`}}const s=/<\|{1,2}DSML\|{1,2}tools_commands_exec>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}tools_commands_exec>/.exec(e);if(s&&typeof s.index=="number"){const a=/<\|{1,2}DSML\|{1,2}tools_commands_exec_cmd>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}tools_commands_exec_cmd>/.exec(s[1]),m=a?C(a[1].trim()):"";if(m)return{calls:[{name:"exec_command",arguments:JSON.stringify({cmd:m})}],visibleText:`${t.slice(0,s.index)}${t.slice(s.index+s[0].length)}`}}const i=/<\|{1,2}DSML\|{1,2}tool_calls>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}tool_calls>/.exec(e);if(!i||typeof i.index!="number")return null;const o=[],p=/<\|{1,2}DSML\|{1,2}invoke\b([^>]*)>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}invoke>/g;for(const a of i[1].matchAll(p)){const m=/\bname\s*=\s*["']([^"']+)["']/.exec(a[1])?.[1]?.trim();if(!m)continue;const u={},l=/<\|{1,2}DSML\|{1,2}parameter\b([^>]*)>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}parameter>/g;for(const r of a[2].matchAll(l)){const d=/\bname\s*=\s*["']([^"']+)["']/.exec(r[1])?.[1]?.trim();if(!d)continue;const f=C(r[2].trim());if(/\bstring\s*=\s*["']true["']/i.test(r[1])){u[d]=f;continue}try{u[d]=JSON.parse(f)}catch{u[d]=f}}o.push({name:C(m),arguments:JSON.stringify(u)})}return o.length===0?null:{calls:o,visibleText:`${t.slice(0,i.index)}${t.slice(i.index+i[0].length)}`}}function j(t){const e=T(t),n=Math.min(e.length,Math.max(...A.map(s=>s.length-1)));for(let s=n;s>0;s-=1){const i=e.slice(-s);if(A.some(o=>o.startsWith(i)))return s}return 0}function c(t){return typeof t=="string"?t:""}function h(t){if(!(typeof t>"u"))try{return JSON.parse(JSON.stringify(t))}catch{return}}function J(t){const e=c(t).trim();return e?[`Runtime model disclosure: the actual upstream model selected for this turn is "${e}".`,"If the user asks what model is being used, answer with this exact model id instead of inferring from Codex CLI, OpenAI, or fallback model lists."].join(" "):null}function U(){return{instructions:null,max_output_tokens:null,parallel_tool_calls:void 0,previous_response_id:null,reasoning:{effort:null,summary:null},store:!1,temperature:1,text:{format:{type:"text"}},tool_choice:"auto",tools:[],top_p:1,truncation:"disabled",user:null,metadata:{}}}function W(t){const e=U();return _(t)?{instructions:typeof t.instructions>"u"?e.instructions:h(t.instructions),max_output_tokens:typeof t.max_output_tokens>"u"?e.max_output_tokens:h(t.max_output_tokens),parallel_tool_calls:typeof t.parallel_tool_calls>"u"?e.parallel_tool_calls:h(t.parallel_tool_calls),previous_response_id:typeof t.previous_response_id>"u"?e.previous_response_id:h(t.previous_response_id),reasoning:typeof t.reasoning>"u"?e.reasoning:h(t.reasoning),store:typeof t.store>"u"?e.store:h(t.store),temperature:typeof t.temperature>"u"?e.temperature:h(t.temperature),text:typeof t.text>"u"?e.text:h(t.text),tool_choice:typeof t.tool_choice>"u"?e.tool_choice:h(t.tool_choice),tools:typeof t.tools>"u"?e.tools:h(t.tools),top_p:typeof t.top_p>"u"?e.top_p:h(t.top_p),truncation:typeof t.truncation>"u"?e.truncation:h(t.truncation),user:typeof t.user>"u"?e.user:h(t.user),metadata:typeof t.metadata>"u"?e.metadata:h(t.metadata)}:e}function R(t,e){const n=e.prompt_tokens??t.usage?.input_tokens,s=e.completion_tokens??t.usage?.output_tokens;t.usage={input_tokens:n,output_tokens:s,total_tokens:e.total_tokens??(typeof n=="number"&&typeof s=="number"?n+s:t.usage?.total_tokens),input_tokens_details:typeof e.prompt_tokens_details>"u"?t.usage?.input_tokens_details:e.prompt_tokens_details,output_tokens_details:typeof e.completion_tokens_details>"u"?t.usage?.output_tokens_details:e.completion_tokens_details}}function E(t){if(typeof t=="string")return t;if(Array.isArray(t))return t.map(n=>E(n)).filter(Boolean).join("");if(!_(t))return"";const e=c(t.type);return(e==="text"||e==="output_text"||e==="input_text")&&typeof t.text=="string"?t.text:""}function H(t){if(typeof t=="string")return t;if(t===null||typeof t>"u")return"";try{return JSON.stringify(t)}catch{return String(t)}}function V(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>{if(!_(e))return"";const n=c(e.type);return(n==="summary_text"||n==="text")&&typeof e.text=="string"?e.text:""}).filter(Boolean).join(""):""}function X(t){return t==="developer"?"system":t==="system"||t==="user"||t==="assistant"||t==="tool"?t:"user"}function F(t){if(typeof t=="string")return t;if(!Array.isArray(t))return null;const e=[],n=[];let s=!1;for(const i of t){if(!_(i))continue;const o=c(i.type);if((o==="input_text"||o==="output_text"||o==="text")&&typeof i.text=="string"){n.push(i.text),e.push({type:"text",text:i.text});continue}if(o==="input_image"){const p=i.image_url;typeof p=="string"&&p.trim()?(e.push({type:"image_url",image_url:{url:p}}),s=!0):_(p)&&(e.push({type:"image_url",image_url:p}),s=!0)}}return e.length===0?null:s?e:n.join("")}function S(t,e,n="",s=null){if(e.length===0)return!1;const i={role:"assistant",content:s,tool_calls:[...e]};return n.trim()&&(i.reasoning_content=n),t.push(i),e.length=0,!0}function G(t){if(!_(t)||c(t.type)!=="function")return t;const e=c(t.name);return e?{type:"function",function:{name:e}}:t}function w(t){if(!Array.isArray(t))return;const e=t.flatMap(n=>{if(!_(n)||c(n.type)!=="function")return[];const s=c(n.name);if(!s)return[];const i={name:s};return typeof n.description=="string"&&n.description.trim()&&(i.description=n.description),(_(n.parameters)||Array.isArray(n.parameters))&&(i.parameters=n.parameters),typeof n.strict=="boolean"&&(i.strict=n.strict),[{type:"function",function:i}]});return e.length>0?e:void 0}function k(t,e){return{id:t.id,type:"reasoning",status:e,summary:t.text.length>0?[{type:"summary_text",text:t.text}]:[],content:[]}}function P(t,e,n=null){const s=t.requestContext,i=[];t.reasoningItem?.done&&i.push({outputIndex:t.reasoningItem.outputIndex,item:k(t.reasoningItem,"completed")}),t.textItem?.done&&i.push({outputIndex:t.textItem.outputIndex,item:{id:t.textItem.id,type:"message",status:"completed",role:"assistant",content:[{type:"output_text",text:t.textItem.text,annotations:[]}]}});for(const o of[...t.toolCallsByIndex.values()].sort((p,a)=>p.outputIndex-a.outputIndex))o.done&&i.push({outputIndex:o.outputIndex,item:{id:o.id,type:"function_call",status:"completed",call_id:o.callId,name:o.name,arguments:o.arguments}});return{id:t.responseId,object:"response",created_at:t.createdAt,status:e,error:n,incomplete_details:null,instructions:s.instructions??null,max_output_tokens:s.max_output_tokens??null,model:t.model,output:i.sort((o,p)=>o.outputIndex-p.outputIndex).map(o=>o.item),output_text:t.textItem?.text??"",parallel_tool_calls:typeof s.parallel_tool_calls=="boolean"?s.parallel_tool_calls:t.toolCallsByIndex.size>1,previous_response_id:s.previous_response_id??null,reasoning:_(s.reasoning)?s.reasoning:{effort:null,summary:null},store:typeof s.store=="boolean"?s.store:!1,temperature:typeof s.temperature=="number"?s.temperature:1,text:_(s.text)?s.text:{format:{type:"text"}},tool_choice:typeof s.tool_choice>"u"?"auto":s.tool_choice,tools:Array.isArray(s.tools)?s.tools:[],top_p:typeof s.top_p=="number"?s.top_p:1,truncation:typeof s.truncation=="string"?s.truncation:"disabled",usage:{input_tokens:t.usage?.input_tokens??0,output_tokens:t.usage?.output_tokens??0,total_tokens:t.usage?.total_tokens??0,...typeof t.usage?.input_tokens_details<"u"?{input_tokens_details:t.usage.input_tokens_details}:{},...typeof t.usage?.output_tokens_details<"u"?{output_tokens_details:t.usage.output_tokens_details}:{}},user:s.user??null,metadata:_(s.metadata)?s.metadata:{}}}function y(t){const e=t.sequenceNumber;return t.sequenceNumber+=1,e}function x(t){return t.eventSequence+=1,`compat-${t.eventSequence}`}function $(t){return t.createdEmitted?[]:(t.createdEmitted=!0,[{type:"response.created",sequence_number:y(t),response:P(t,"in_progress")}])}function v(t){return t.textItem||(t.textItem={id:`msg_${I()}`,outputIndex:t.nextOutputIndex,text:"",added:!1,done:!1},t.nextOutputIndex+=1),t.textItem}function N(t){return t.reasoningItem||(t.reasoningItem={id:`rs_${I()}`,outputIndex:t.nextOutputIndex,text:"",added:!1,done:!1},t.nextOutputIndex+=1),t.reasoningItem}function O(t,e){const n=t.toolCallsByIndex.get(e);if(n)return n;const s={id:`fc_${I()}`,callId:`call_${I()}`,name:`tool_${e}`,arguments:"",outputIndex:t.nextOutputIndex,added:!1,done:!1};return t.nextOutputIndex+=1,t.toolCallsByIndex.set(e,s),s}function K(t){return typeof t=="string"?t:E(t)}function Y(t,e,n){return(e??"GET").toUpperCase()!=="POST"||!new URL(n,"http://grix.internal").pathname.endsWith("/responses")?!1:B(t[M])===z}function Z(t){const e={...t};return delete e[M],delete e["X-Grix-OpenAI-Wire-Compat"],e}function q(t){const e=new URL(t,"http://grix.internal");return e.pathname=e.pathname.replace(/\/responses$/,"/chat/completions"),`${e.pathname}${e.search}`}function tt(t,e){const n=_(t)?t:{},s=[],i=[];let o="";const p=c(n.instructions);p&&s.push({role:"system",content:p});const a=J(n.model);a&&s.push({role:"system",content:a});const m=Array.isArray(n.input)?n.input:[];for(const r of m){if(!_(r))continue;const d=c(r.type);if(d==="message"||!d&&r.role){const f=X(c(r.role)),g=F(r.content);if(f==="assistant"&&i.length>0){S(s,i,o,g),o="";continue}(S(s,i,o)||f!=="assistant")&&(o="");const b={role:f,content:g};f==="assistant"&&o.trim()&&(b.reasoning_content=o,o=""),s.push(b);continue}if(d==="reasoning"){o+=V(r.summary);continue}if(d==="function_call"){const f=c(r.name);if(!f)continue;i.push({id:c(r.call_id)||`call_${I()}`,type:"function",function:{name:f,arguments:c(r.arguments)}});continue}d==="function_call_output"&&(S(s,i,o),o="",s.push({role:"tool",tool_call_id:c(r.call_id),content:H(r.output)}))}S(s,i,o);const u={model:n.model,messages:s,stream:n.stream===!0},l=w(n.tools);return l&&(u.tools=l),!e?.omitToolChoice&&typeof n.tool_choice<"u"&&(u.tool_choice=G(n.tool_choice)),typeof n.parallel_tool_calls=="boolean"&&(u.parallel_tool_calls=n.parallel_tool_calls),typeof n.max_output_tokens=="number"&&(u.max_tokens=n.max_output_tokens),typeof n.temperature=="number"&&(u.temperature=n.temperature),typeof n.top_p=="number"&&(u.top_p=n.top_p),u}class et{state;constructor(e){this.state={responseId:e?.responseId?.trim()||`resp_${I()}`,model:e?.model?.trim()||"",createdAt:e?.createdAt??Math.floor(Date.now()/1e3),sequenceNumber:0,eventSequence:0,nextOutputIndex:0,requestContext:W(e?.requestBody),reasoningItem:null,textItem:null,textProbeBuffer:"",dsmlTextBuffer:null,toolCallsByIndex:new Map,createdEmitted:!1,completedEmitted:!1}}consumeChatCompletionChunk(e){const n=_(e)?e:{};typeof n.id=="string"&&n.id.trim()&&(this.state.responseId=n.id),typeof n.model=="string"&&n.model.trim()&&(this.state.model=n.model),typeof n.created=="number"&&(this.state.createdAt=n.created),n.usage&&R(this.state,n.usage);const s=$(this.state);for(const i of n.choices??[]){const o=i.delta,p=c(o?.reasoning_content);if(p.length>0){const u=N(this.state);u.added||(u.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:u.outputIndex,item:k(u,"in_progress")})),u.text+=p,s.push({type:"response.reasoning_summary_text.delta",item_id:u.id,output_index:u.outputIndex,summary_index:0,delta:p,sequence_number:y(this.state)})}const a=o?.content??"";this.state.reasoningItem?.added&&!this.state.reasoningItem.done&&(typeof a=="string"&&a.length>0||(o?.tool_calls?.length??0)>0)&&s.push(...this.completePendingReasoningSummary()),typeof a=="string"&&a.length>0&&s.push(...this.consumeTextDelta(a));const m=o?.tool_calls??[];m.length>0&&s.push(...this.flushTextCompatibilityBuffers(!1));for(const u of m){const l=typeof u.index=="number"&&Number.isFinite(u.index)?u.index:0,r=O(this.state,l);typeof u.id=="string"&&u.id.trim()&&(r.callId=u.id);const d=u.function,f=c(d?.name);f&&(r.name=r.name.startsWith("tool_")&&r.arguments.length===0?f:r.name===f?r.name:`${r.name}${f}`),r.added||(r.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:r.outputIndex,item:{id:r.id,type:"function_call",status:"in_progress",call_id:r.callId,name:r.name,arguments:""}}));const g=c(d?.arguments);g&&(r.arguments+=g,s.push({type:"response.function_call_arguments.delta",event_id:x(this.state),response_id:this.state.responseId,item_id:r.id,output_index:r.outputIndex,call_id:r.callId,delta:g}))}i.finish_reason&&(s.push(...this.flushTextCompatibilityBuffers(!0)),s.push(...this.completePendingReasoningSummary()),s.push(...this.completePendingItems()))}return s}consumeChatCompletion(e){const n=_(e)?e:{};typeof n.id=="string"&&n.id.trim()&&(this.state.responseId=n.id),typeof n.model=="string"&&n.model.trim()&&(this.state.model=n.model),typeof n.created=="number"&&(this.state.createdAt=n.created),n.usage&&R(this.state,n.usage);const s=$(this.state),o=n.choices?.[0],p=_(o?.message)?o.message:{},a=c(p.reasoning_content);if(a.length>0){const l=N(this.state);l.added||(l.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:l.outputIndex,item:k(l,"in_progress")})),l.text+=a,s.push({type:"response.reasoning_summary_text.delta",item_id:l.id,output_index:l.outputIndex,summary_index:0,delta:a,sequence_number:y(this.state)})}let m=K(p.content),u=Array.isArray(p.tool_calls)?p.tool_calls:[];if(m&&u.length===0){const l=L(m);l&&(m=l.visibleText,u=l.calls.map(r=>({id:`call_${I()}`,type:"function",function:{name:r.name,arguments:r.arguments}})))}if(a.length>0&&(m||u.length>0)&&s.push(...this.completePendingReasoningSummary()),m){const l=v(this.state);l.added||(l.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:l.outputIndex,item:{id:l.id,type:"message",status:"in_progress",role:"assistant",content:[]}})),l.text+=m,s.push({type:"response.output_text.delta",sequence_number:y(this.state),output_index:l.outputIndex,item_id:l.id,content_index:0,delta:m,logprobs:[]})}return u.forEach((l,r)=>{if(!_(l))return;const d=O(this.state,r),f=c(l.id);f&&(d.callId=f);const g=_(l.function)?l.function:{},D=c(g.name);D&&(d.name=D),d.added||(d.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:d.outputIndex,item:{id:d.id,type:"function_call",status:"in_progress",call_id:d.callId,name:d.name,arguments:""}}));const b=c(g.arguments);b&&(d.arguments=b,s.push({type:"response.function_call_arguments.delta",event_id:x(this.state),response_id:this.state.responseId,item_id:d.id,output_index:d.outputIndex,call_id:d.callId,delta:b}))}),s.push(...this.completePendingItems()),s}hasSemanticOutput(){return(this.state.textItem?.text.trim().length??0)>0||(this.state.reasoningItem?.text.trim().length??0)>0?!0:[...this.state.toolCallsByIndex.values()].some(e=>e.name.trim().length>0||e.arguments.trim().length>0)}finalize(){if(this.state.completedEmitted)return[];const e=[...this.flushTextCompatibilityBuffers(!0),...this.completePendingReasoningSummary(),...this.completePendingItems()];return this.state.completedEmitted=!0,this.hasSemanticOutput()?(e.push({type:"response.completed",sequence_number:y(this.state),response:P(this.state,"completed")}),e):(e.push({type:"response.failed",sequence_number:y(this.state),response:P(this.state,"failed",{code:"server_error",message:"Upstream model completed without producing any output."})}),e)}emitTextDelta(e){if(!e)return[];const n=v(this.state),s=[];return n.added||(n.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:n.outputIndex,item:{id:n.id,type:"message",status:"in_progress",role:"assistant",content:[]}})),n.text+=e,s.push({type:"response.output_text.delta",sequence_number:y(this.state),output_index:n.outputIndex,item_id:n.id,content_index:0,delta:e,logprobs:[]}),s}consumeTextDelta(e){if(this.state.dsmlTextBuffer!==null)return this.state.dsmlTextBuffer+=e,[];this.state.textProbeBuffer+=e;const n=T(this.state.textProbeBuffer),s=A.map(a=>n.indexOf(a)).filter(a=>a>=0);if(s.length>0){const a=Math.min(...s),m=this.state.textProbeBuffer.slice(0,a);return this.state.dsmlTextBuffer=this.state.textProbeBuffer.slice(a),this.state.textProbeBuffer="",this.emitTextDelta(m)}const i=j(this.state.textProbeBuffer),o=this.state.textProbeBuffer.length-i;if(o<=0)return[];const p=this.state.textProbeBuffer.slice(0,o);return this.state.textProbeBuffer=this.state.textProbeBuffer.slice(o),this.emitTextDelta(p)}emitParsedDsmlToolCalls(e){const n=[];return e.forEach((s,i)=>{const o=O(this.state,i);o.name=s.name,o.arguments=s.arguments,o.added||(o.added=!0,n.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:o.outputIndex,item:{id:o.id,type:"function_call",status:"in_progress",call_id:o.callId,name:o.name,arguments:""}})),n.push({type:"response.function_call_arguments.delta",event_id:x(this.state),response_id:this.state.responseId,item_id:o.id,output_index:o.outputIndex,call_id:o.callId,delta:o.arguments})}),n}flushTextCompatibilityBuffers(e){const n=[];if(this.state.dsmlTextBuffer!==null){const s=this.state.dsmlTextBuffer;this.state.dsmlTextBuffer=null;const i=e&&this.state.toolCallsByIndex.size===0?L(s):null;i?(n.push(...this.emitParsedDsmlToolCalls(i.calls)),n.push(...this.emitTextDelta(i.visibleText))):n.push(...this.emitTextDelta(s))}return this.state.textProbeBuffer&&(n.push(...this.emitTextDelta(this.state.textProbeBuffer)),this.state.textProbeBuffer=""),n}completePendingReasoningSummary(){const e=this.state.reasoningItem;return!e?.added||e.done?[]:(e.done=!0,[{type:"response.reasoning_summary_text.done",item_id:e.id,output_index:e.outputIndex,summary_index:0,text:e.text,sequence_number:y(this.state)},{type:"response.output_item.done",event_id:x(this.state),response_id:this.state.responseId,output_index:e.outputIndex,item:k(e,"completed")}])}completePendingItems(){const e=[];for(const n of[...this.state.toolCallsByIndex.values()].sort((s,i)=>s.outputIndex-i.outputIndex))!n.added||n.done||(n.done=!0,e.push({type:"response.function_call_arguments.done",event_id:x(this.state),response_id:this.state.responseId,item_id:n.id,output_index:n.outputIndex,call_id:n.callId,arguments:n.arguments}),e.push({type:"response.output_item.done",event_id:x(this.state),response_id:this.state.responseId,output_index:n.outputIndex,item:{id:n.id,type:"function_call",status:"completed",call_id:n.callId,name:n.name,arguments:n.arguments}}));return this.state.textItem?.added&&!this.state.textItem.done&&(this.state.textItem.done=!0,e.push({type:"response.output_text.done",event_id:x(this.state),response_id:this.state.responseId,output_index:this.state.textItem.outputIndex,item_id:this.state.textItem.id,content_index:0,text:this.state.textItem.text,logprobs:[],sequence_number:y(this.state)}),e.push({type:"response.output_item.done",event_id:x(this.state),response_id:this.state.responseId,output_index:this.state.textItem.outputIndex,item:{id:this.state.textItem.id,type:"message",status:"completed",role:"assistant",content:[{type:"output_text",text:this.state.textItem.text,annotations:[]}]}})),e}}function nt(t){return Buffer.from(`data: ${JSON.stringify(t)}
1
+ import{randomUUID as I}from"node:crypto";const M="x-grix-openai-wire-compat",z="chat-completions";function _(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function B(t){return Array.isArray(t)?t[0]?.trim().toLowerCase()??"":t?.trim().toLowerCase()??""}const A=["<||DSML||tool_calls>","<|DSML|tool_calls>","<||DSML||tools_commands_exec>","<|DSML|tools_commands_exec>","<||DSML||:","<|DSML|:"];function T(t){return t.replaceAll("\uFF5C","|")}function C(t){return t.replaceAll("&quot;",'"').replaceAll("&apos;","'").replaceAll("&#39;","'").replaceAll("&lt;","<").replaceAll("&gt;",">").replaceAll("&amp;","&")}function L(t){const e=T(t),n=/<\|{1,2}DSML\|{1,2}:([\s\S]*?)<\/\|{1,2}DSML\|{1,2}>/.exec(e);if(n&&typeof n.index=="number"){const a=C(n[1].trim());if(a)return{calls:[{name:"exec_command",arguments:JSON.stringify({cmd:a})}],visibleText:`${t.slice(0,n.index)}${t.slice(n.index+n[0].length)}`}}const s=/<\|{1,2}DSML\|{1,2}tools_commands_exec>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}tools_commands_exec>/.exec(e);if(s&&typeof s.index=="number"){const a=/<\|{1,2}DSML\|{1,2}tools_commands_exec_cmd>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}tools_commands_exec_cmd>/.exec(s[1]),m=a?C(a[1].trim()):"";if(m)return{calls:[{name:"exec_command",arguments:JSON.stringify({cmd:m})}],visibleText:`${t.slice(0,s.index)}${t.slice(s.index+s[0].length)}`}}const i=/<\|{1,2}DSML\|{1,2}tool_calls>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}tool_calls>/.exec(e);if(!i||typeof i.index!="number")return null;const o=[],p=/<\|{1,2}DSML\|{1,2}invoke\b([^>]*)>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}invoke>/g;for(const a of i[1].matchAll(p)){const m=/\bname\s*=\s*["']([^"']+)["']/.exec(a[1])?.[1]?.trim();if(!m)continue;const u={},l=/<\|{1,2}DSML\|{1,2}parameter\b([^>]*)>([\s\S]*?)<\/\|{1,2}DSML\|{1,2}parameter>/g;for(const r of a[2].matchAll(l)){const d=/\bname\s*=\s*["']([^"']+)["']/.exec(r[1])?.[1]?.trim();if(!d)continue;const f=C(r[2].trim());if(/\bstring\s*=\s*["']true["']/i.test(r[1])){u[d]=f;continue}try{u[d]=JSON.parse(f)}catch{u[d]=f}}o.push({name:C(m),arguments:JSON.stringify(u)})}return o.length===0?null:{calls:o,visibleText:`${t.slice(0,i.index)}${t.slice(i.index+i[0].length)}`}}function j(t){const e=T(t),n=Math.min(e.length,Math.max(...A.map(s=>s.length-1)));for(let s=n;s>0;s-=1){const i=e.slice(-s);if(A.some(o=>o.startsWith(i)))return s}return 0}function c(t){return typeof t=="string"?t:""}function h(t){if(!(typeof t>"u"))try{return JSON.parse(JSON.stringify(t))}catch{return}}function J(t){const e=c(t).trim();return e?[`Runtime model disclosure: the actual upstream model selected for this turn is "${e}".`,"If the user asks what model is being used, answer with this exact model id instead of inferring from Codex CLI, OpenAI, or fallback model lists."].join(" "):null}function U(){return{instructions:null,max_output_tokens:null,parallel_tool_calls:void 0,previous_response_id:null,reasoning:{effort:null,summary:null},store:!1,temperature:1,text:{format:{type:"text"}},tool_choice:"auto",tools:[],top_p:1,truncation:"disabled",user:null,metadata:{}}}function W(t){const e=U();return _(t)?{instructions:typeof t.instructions>"u"?e.instructions:h(t.instructions),max_output_tokens:typeof t.max_output_tokens>"u"?e.max_output_tokens:h(t.max_output_tokens),parallel_tool_calls:typeof t.parallel_tool_calls>"u"?e.parallel_tool_calls:h(t.parallel_tool_calls),previous_response_id:typeof t.previous_response_id>"u"?e.previous_response_id:h(t.previous_response_id),reasoning:typeof t.reasoning>"u"?e.reasoning:h(t.reasoning),store:typeof t.store>"u"?e.store:h(t.store),temperature:typeof t.temperature>"u"?e.temperature:h(t.temperature),text:typeof t.text>"u"?e.text:h(t.text),tool_choice:typeof t.tool_choice>"u"?e.tool_choice:h(t.tool_choice),tools:typeof t.tools>"u"?e.tools:h(t.tools),top_p:typeof t.top_p>"u"?e.top_p:h(t.top_p),truncation:typeof t.truncation>"u"?e.truncation:h(t.truncation),user:typeof t.user>"u"?e.user:h(t.user),metadata:typeof t.metadata>"u"?e.metadata:h(t.metadata)}:e}function R(t,e){const n=e.prompt_tokens??t.usage?.input_tokens,s=e.completion_tokens??t.usage?.output_tokens;t.usage={input_tokens:n,output_tokens:s,total_tokens:e.total_tokens??(typeof n=="number"&&typeof s=="number"?n+s:t.usage?.total_tokens),input_tokens_details:typeof e.prompt_tokens_details>"u"?t.usage?.input_tokens_details:e.prompt_tokens_details,output_tokens_details:typeof e.completion_tokens_details>"u"?t.usage?.output_tokens_details:e.completion_tokens_details}}function E(t){if(typeof t=="string")return t;if(Array.isArray(t))return t.map(n=>E(n)).filter(Boolean).join("");if(!_(t))return"";const e=c(t.type);return(e==="text"||e==="output_text"||e==="input_text")&&typeof t.text=="string"?t.text:""}function H(t){if(typeof t=="string")return t;if(t===null||typeof t>"u")return"";try{return JSON.stringify(t)}catch{return String(t)}}function V(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>{if(!_(e))return"";const n=c(e.type);return(n==="summary_text"||n==="text")&&typeof e.text=="string"?e.text:""}).filter(Boolean).join(""):""}function X(t){return t==="developer"?"system":t==="system"||t==="user"||t==="assistant"||t==="tool"?t:"user"}function F(t){if(typeof t=="string")return t;if(!Array.isArray(t))return null;const e=[],n=[];let s=!1;for(const i of t){if(!_(i))continue;const o=c(i.type);if((o==="input_text"||o==="output_text"||o==="text")&&typeof i.text=="string"){n.push(i.text),e.push({type:"text",text:i.text});continue}if(o==="input_image"){const p=i.image_url;typeof p=="string"&&p.trim()?(e.push({type:"image_url",image_url:{url:p}}),s=!0):_(p)&&(e.push({type:"image_url",image_url:p}),s=!0)}}return e.length===0?null:s?e:n.join("")}function S(t,e,n="",s=null){if(e.length===0)return!1;const i={role:"assistant",content:s,reasoning_content:n,tool_calls:[...e]};return t.push(i),e.length=0,!0}function G(t){if(!_(t)||c(t.type)!=="function")return t;const e=c(t.name);return e?{type:"function",function:{name:e}}:t}function w(t){if(!Array.isArray(t))return;const e=t.flatMap(n=>{if(!_(n)||c(n.type)!=="function")return[];const s=c(n.name);if(!s)return[];const i={name:s};return typeof n.description=="string"&&n.description.trim()&&(i.description=n.description),(_(n.parameters)||Array.isArray(n.parameters))&&(i.parameters=n.parameters),typeof n.strict=="boolean"&&(i.strict=n.strict),[{type:"function",function:i}]});return e.length>0?e:void 0}function k(t,e){return{id:t.id,type:"reasoning",status:e,summary:t.text.length>0?[{type:"summary_text",text:t.text}]:[],content:[]}}function P(t,e,n=null){const s=t.requestContext,i=[];t.reasoningItem?.done&&i.push({outputIndex:t.reasoningItem.outputIndex,item:k(t.reasoningItem,"completed")}),t.textItem?.done&&i.push({outputIndex:t.textItem.outputIndex,item:{id:t.textItem.id,type:"message",status:"completed",role:"assistant",content:[{type:"output_text",text:t.textItem.text,annotations:[]}]}});for(const o of[...t.toolCallsByIndex.values()].sort((p,a)=>p.outputIndex-a.outputIndex))o.done&&i.push({outputIndex:o.outputIndex,item:{id:o.id,type:"function_call",status:"completed",call_id:o.callId,name:o.name,arguments:o.arguments}});return{id:t.responseId,object:"response",created_at:t.createdAt,status:e,error:n,incomplete_details:null,instructions:s.instructions??null,max_output_tokens:s.max_output_tokens??null,model:t.model,output:i.sort((o,p)=>o.outputIndex-p.outputIndex).map(o=>o.item),output_text:t.textItem?.text??"",parallel_tool_calls:typeof s.parallel_tool_calls=="boolean"?s.parallel_tool_calls:t.toolCallsByIndex.size>1,previous_response_id:s.previous_response_id??null,reasoning:_(s.reasoning)?s.reasoning:{effort:null,summary:null},store:typeof s.store=="boolean"?s.store:!1,temperature:typeof s.temperature=="number"?s.temperature:1,text:_(s.text)?s.text:{format:{type:"text"}},tool_choice:typeof s.tool_choice>"u"?"auto":s.tool_choice,tools:Array.isArray(s.tools)?s.tools:[],top_p:typeof s.top_p=="number"?s.top_p:1,truncation:typeof s.truncation=="string"?s.truncation:"disabled",usage:{input_tokens:t.usage?.input_tokens??0,output_tokens:t.usage?.output_tokens??0,total_tokens:t.usage?.total_tokens??0,...typeof t.usage?.input_tokens_details<"u"?{input_tokens_details:t.usage.input_tokens_details}:{},...typeof t.usage?.output_tokens_details<"u"?{output_tokens_details:t.usage.output_tokens_details}:{}},user:s.user??null,metadata:_(s.metadata)?s.metadata:{}}}function y(t){const e=t.sequenceNumber;return t.sequenceNumber+=1,e}function x(t){return t.eventSequence+=1,`compat-${t.eventSequence}`}function $(t){return t.createdEmitted?[]:(t.createdEmitted=!0,[{type:"response.created",sequence_number:y(t),response:P(t,"in_progress")}])}function v(t){return t.textItem||(t.textItem={id:`msg_${I()}`,outputIndex:t.nextOutputIndex,text:"",added:!1,done:!1},t.nextOutputIndex+=1),t.textItem}function N(t){return t.reasoningItem||(t.reasoningItem={id:`rs_${I()}`,outputIndex:t.nextOutputIndex,text:"",added:!1,done:!1},t.nextOutputIndex+=1),t.reasoningItem}function O(t,e){const n=t.toolCallsByIndex.get(e);if(n)return n;const s={id:`fc_${I()}`,callId:`call_${I()}`,name:`tool_${e}`,arguments:"",outputIndex:t.nextOutputIndex,added:!1,done:!1};return t.nextOutputIndex+=1,t.toolCallsByIndex.set(e,s),s}function K(t){return typeof t=="string"?t:E(t)}function Y(t,e,n){return(e??"GET").toUpperCase()!=="POST"||!new URL(n,"http://grix.internal").pathname.endsWith("/responses")?!1:B(t[M])===z}function Z(t){const e={...t};return delete e[M],delete e["X-Grix-OpenAI-Wire-Compat"],e}function q(t){const e=new URL(t,"http://grix.internal");return e.pathname=e.pathname.replace(/\/responses$/,"/chat/completions"),`${e.pathname}${e.search}`}function tt(t,e){const n=_(t)?t:{},s=[],i=[];let o="";const p=c(n.instructions);p&&s.push({role:"system",content:p});const a=J(n.model);a&&s.push({role:"system",content:a});const m=Array.isArray(n.input)?n.input:[];for(const r of m){if(!_(r))continue;const d=c(r.type);if(d==="message"||!d&&r.role){const f=X(c(r.role)),g=F(r.content);if(f==="assistant"&&i.length>0){S(s,i,o,g),o="";continue}(S(s,i,o)||f!=="assistant")&&(o="");const b={role:f,content:g};f==="assistant"&&o.trim()&&(b.reasoning_content=o,o=""),s.push(b);continue}if(d==="reasoning"){o+=V(r.summary);continue}if(d==="function_call"){const f=c(r.name);if(!f)continue;i.push({id:c(r.call_id)||`call_${I()}`,type:"function",function:{name:f,arguments:c(r.arguments)}});continue}d==="function_call_output"&&(S(s,i,o),o="",s.push({role:"tool",tool_call_id:c(r.call_id),content:H(r.output)}))}S(s,i,o);const u={model:n.model,messages:s,stream:n.stream===!0},l=w(n.tools);return l&&(u.tools=l),!e?.omitToolChoice&&typeof n.tool_choice<"u"&&(u.tool_choice=G(n.tool_choice)),typeof n.parallel_tool_calls=="boolean"&&(u.parallel_tool_calls=n.parallel_tool_calls),typeof n.max_output_tokens=="number"&&(u.max_tokens=n.max_output_tokens),typeof n.temperature=="number"&&(u.temperature=n.temperature),typeof n.top_p=="number"&&(u.top_p=n.top_p),u}class et{state;constructor(e){this.state={responseId:e?.responseId?.trim()||`resp_${I()}`,model:e?.model?.trim()||"",createdAt:e?.createdAt??Math.floor(Date.now()/1e3),sequenceNumber:0,eventSequence:0,nextOutputIndex:0,requestContext:W(e?.requestBody),reasoningItem:null,textItem:null,textProbeBuffer:"",dsmlTextBuffer:null,toolCallsByIndex:new Map,createdEmitted:!1,completedEmitted:!1}}consumeChatCompletionChunk(e){const n=_(e)?e:{};typeof n.id=="string"&&n.id.trim()&&(this.state.responseId=n.id),typeof n.model=="string"&&n.model.trim()&&(this.state.model=n.model),typeof n.created=="number"&&(this.state.createdAt=n.created),n.usage&&R(this.state,n.usage);const s=$(this.state);for(const i of n.choices??[]){const o=i.delta,p=c(o?.reasoning_content);if(p.length>0){const u=N(this.state);u.added||(u.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:u.outputIndex,item:k(u,"in_progress")})),u.text+=p,s.push({type:"response.reasoning_summary_text.delta",item_id:u.id,output_index:u.outputIndex,summary_index:0,delta:p,sequence_number:y(this.state)})}const a=o?.content??"";this.state.reasoningItem?.added&&!this.state.reasoningItem.done&&(typeof a=="string"&&a.length>0||(o?.tool_calls?.length??0)>0)&&s.push(...this.completePendingReasoningSummary()),typeof a=="string"&&a.length>0&&s.push(...this.consumeTextDelta(a));const m=o?.tool_calls??[];m.length>0&&s.push(...this.flushTextCompatibilityBuffers(!1));for(const u of m){const l=typeof u.index=="number"&&Number.isFinite(u.index)?u.index:0,r=O(this.state,l);typeof u.id=="string"&&u.id.trim()&&(r.callId=u.id);const d=u.function,f=c(d?.name);f&&(r.name=r.name.startsWith("tool_")&&r.arguments.length===0?f:r.name===f?r.name:`${r.name}${f}`),r.added||(r.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:r.outputIndex,item:{id:r.id,type:"function_call",status:"in_progress",call_id:r.callId,name:r.name,arguments:""}}));const g=c(d?.arguments);g&&(r.arguments+=g,s.push({type:"response.function_call_arguments.delta",event_id:x(this.state),response_id:this.state.responseId,item_id:r.id,output_index:r.outputIndex,call_id:r.callId,delta:g}))}i.finish_reason&&(s.push(...this.flushTextCompatibilityBuffers(!0)),s.push(...this.completePendingReasoningSummary()),s.push(...this.completePendingItems()))}return s}consumeChatCompletion(e){const n=_(e)?e:{};typeof n.id=="string"&&n.id.trim()&&(this.state.responseId=n.id),typeof n.model=="string"&&n.model.trim()&&(this.state.model=n.model),typeof n.created=="number"&&(this.state.createdAt=n.created),n.usage&&R(this.state,n.usage);const s=$(this.state),o=n.choices?.[0],p=_(o?.message)?o.message:{},a=c(p.reasoning_content);if(a.length>0){const l=N(this.state);l.added||(l.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:l.outputIndex,item:k(l,"in_progress")})),l.text+=a,s.push({type:"response.reasoning_summary_text.delta",item_id:l.id,output_index:l.outputIndex,summary_index:0,delta:a,sequence_number:y(this.state)})}let m=K(p.content),u=Array.isArray(p.tool_calls)?p.tool_calls:[];if(m&&u.length===0){const l=L(m);l&&(m=l.visibleText,u=l.calls.map(r=>({id:`call_${I()}`,type:"function",function:{name:r.name,arguments:r.arguments}})))}if(a.length>0&&(m||u.length>0)&&s.push(...this.completePendingReasoningSummary()),m){const l=v(this.state);l.added||(l.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:l.outputIndex,item:{id:l.id,type:"message",status:"in_progress",role:"assistant",content:[]}})),l.text+=m,s.push({type:"response.output_text.delta",sequence_number:y(this.state),output_index:l.outputIndex,item_id:l.id,content_index:0,delta:m,logprobs:[]})}return u.forEach((l,r)=>{if(!_(l))return;const d=O(this.state,r),f=c(l.id);f&&(d.callId=f);const g=_(l.function)?l.function:{},D=c(g.name);D&&(d.name=D),d.added||(d.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:d.outputIndex,item:{id:d.id,type:"function_call",status:"in_progress",call_id:d.callId,name:d.name,arguments:""}}));const b=c(g.arguments);b&&(d.arguments=b,s.push({type:"response.function_call_arguments.delta",event_id:x(this.state),response_id:this.state.responseId,item_id:d.id,output_index:d.outputIndex,call_id:d.callId,delta:b}))}),s.push(...this.completePendingItems()),s}hasSemanticOutput(){return(this.state.textItem?.text.trim().length??0)>0||(this.state.reasoningItem?.text.trim().length??0)>0?!0:[...this.state.toolCallsByIndex.values()].some(e=>e.name.trim().length>0||e.arguments.trim().length>0)}finalize(){if(this.state.completedEmitted)return[];const e=[...this.flushTextCompatibilityBuffers(!0),...this.completePendingReasoningSummary(),...this.completePendingItems()];return this.state.completedEmitted=!0,this.hasSemanticOutput()?(e.push({type:"response.completed",sequence_number:y(this.state),response:P(this.state,"completed")}),e):(e.push({type:"response.failed",sequence_number:y(this.state),response:P(this.state,"failed",{code:"server_error",message:"Upstream model completed without producing any output."})}),e)}emitTextDelta(e){if(!e)return[];const n=v(this.state),s=[];return n.added||(n.added=!0,s.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:n.outputIndex,item:{id:n.id,type:"message",status:"in_progress",role:"assistant",content:[]}})),n.text+=e,s.push({type:"response.output_text.delta",sequence_number:y(this.state),output_index:n.outputIndex,item_id:n.id,content_index:0,delta:e,logprobs:[]}),s}consumeTextDelta(e){if(this.state.dsmlTextBuffer!==null)return this.state.dsmlTextBuffer+=e,[];this.state.textProbeBuffer+=e;const n=T(this.state.textProbeBuffer),s=A.map(a=>n.indexOf(a)).filter(a=>a>=0);if(s.length>0){const a=Math.min(...s),m=this.state.textProbeBuffer.slice(0,a);return this.state.dsmlTextBuffer=this.state.textProbeBuffer.slice(a),this.state.textProbeBuffer="",this.emitTextDelta(m)}const i=j(this.state.textProbeBuffer),o=this.state.textProbeBuffer.length-i;if(o<=0)return[];const p=this.state.textProbeBuffer.slice(0,o);return this.state.textProbeBuffer=this.state.textProbeBuffer.slice(o),this.emitTextDelta(p)}emitParsedDsmlToolCalls(e){const n=[];return e.forEach((s,i)=>{const o=O(this.state,i);o.name=s.name,o.arguments=s.arguments,o.added||(o.added=!0,n.push({type:"response.output_item.added",event_id:x(this.state),response_id:this.state.responseId,output_index:o.outputIndex,item:{id:o.id,type:"function_call",status:"in_progress",call_id:o.callId,name:o.name,arguments:""}})),n.push({type:"response.function_call_arguments.delta",event_id:x(this.state),response_id:this.state.responseId,item_id:o.id,output_index:o.outputIndex,call_id:o.callId,delta:o.arguments})}),n}flushTextCompatibilityBuffers(e){const n=[];if(this.state.dsmlTextBuffer!==null){const s=this.state.dsmlTextBuffer;this.state.dsmlTextBuffer=null;const i=e&&this.state.toolCallsByIndex.size===0?L(s):null;i?(n.push(...this.emitParsedDsmlToolCalls(i.calls)),n.push(...this.emitTextDelta(i.visibleText))):n.push(...this.emitTextDelta(s))}return this.state.textProbeBuffer&&(n.push(...this.emitTextDelta(this.state.textProbeBuffer)),this.state.textProbeBuffer=""),n}completePendingReasoningSummary(){const e=this.state.reasoningItem;return!e?.added||e.done?[]:(e.done=!0,[{type:"response.reasoning_summary_text.done",item_id:e.id,output_index:e.outputIndex,summary_index:0,text:e.text,sequence_number:y(this.state)},{type:"response.output_item.done",event_id:x(this.state),response_id:this.state.responseId,output_index:e.outputIndex,item:k(e,"completed")}])}completePendingItems(){const e=[];for(const n of[...this.state.toolCallsByIndex.values()].sort((s,i)=>s.outputIndex-i.outputIndex))!n.added||n.done||(n.done=!0,e.push({type:"response.function_call_arguments.done",event_id:x(this.state),response_id:this.state.responseId,item_id:n.id,output_index:n.outputIndex,call_id:n.callId,arguments:n.arguments}),e.push({type:"response.output_item.done",event_id:x(this.state),response_id:this.state.responseId,output_index:n.outputIndex,item:{id:n.id,type:"function_call",status:"completed",call_id:n.callId,name:n.name,arguments:n.arguments}}));return this.state.textItem?.added&&!this.state.textItem.done&&(this.state.textItem.done=!0,e.push({type:"response.output_text.done",event_id:x(this.state),response_id:this.state.responseId,output_index:this.state.textItem.outputIndex,item_id:this.state.textItem.id,content_index:0,text:this.state.textItem.text,logprobs:[],sequence_number:y(this.state)}),e.push({type:"response.output_item.done",event_id:x(this.state),response_id:this.state.responseId,output_index:this.state.textItem.outputIndex,item:{id:this.state.textItem.id,type:"message",status:"completed",role:"assistant",content:[{type:"output_text",text:this.state.textItem.text,annotations:[]}]}})),e}}function nt(t){return Buffer.from(`data: ${JSON.stringify(t)}
2
2
 
3
3
  `,"utf8")}function st(t){const e=t.replaceAll(`\r
4
4
  `,`
@@ -1 +1 @@
1
- import{mkdir as m,writeFile as S,rm as y}from"node:fs/promises";import{join as h}from"node:path";import{createHash as $}from"node:crypto";import{log as r}from"../log/index.js";import{readSkillManifest as v,writeSkillManifest as O}from"./manifest.js";const _=6e4,p=15e3;class B{configs;skillsDir;timer=null;running=!1;rerunPending=!1;stopped=!1;fetchImpl;intervalMs;onSyncSuccessHandler=null;constructor(t,s,n={}){this.configs=t,this.skillsDir=s,this.intervalMs=n.intervalMs??_,this.fetchImpl=n.fetchImpl??fetch}async start(){this.stopped=!1,await this.syncOnce().catch(t=>r.warn("skill-sync",`initial sync failed: ${c(t)}`)),this.timer=setInterval(()=>{this.syncOnce().catch(t=>r.warn("skill-sync",`sync failed: ${c(t)}`))},this.intervalMs),this.timer.unref?.()}stop(){this.stopped=!0,this.rerunPending=!1,this.timer&&(clearInterval(this.timer),this.timer=null)}setOnSyncSuccess(t){this.onSyncSuccessHandler=t}triggerSync(){if(this.running){this.rerunPending=!0;return}this.syncOnce().catch(t=>r.warn("skill-sync",`triggered sync failed: ${c(t)}`))}async syncOnce(){if(!this.running){this.running=!0;try{const t=await this.pickReachable();if(!t)return;const{cfg:s,remote:n}=t;await m(this.skillsDir,{recursive:!0});const e=await v(this.skillsDir),o=JSON.stringify(e),k=new Set(n.map(i=>i.name));for(const i of n){const a=e.skills[i.name],f=i.owner_id==="0";if(a&&a.digest===i.digest){e.skills[i.name]={...a,id:i.id,version:i.version,owner_id:i.owner_id,system:f};continue}const u=D(i.name);if(!u){r.warn("skill-sync",`skip skill with unsafe name: ${i.name}`);continue}const d=await this.fetchContent(s,i.id);if(d!==null)try{await m(h(this.skillsDir,u),{recursive:!0}),await S(h(this.skillsDir,u,"SKILL.md"),d,"utf8"),e.skills[i.name]={id:i.id,version:i.version,digest:i.digest,dir:u,owner_id:i.owner_id,system:f},a&&a.dir!==u&&!this.dirSharedByOthers(e,i.name,a.dir)&&await y(h(this.skillsDir,a.dir),{recursive:!0,force:!0}).catch(()=>{})}catch(g){r.warn("skill-sync",`write skill "${i.name}" failed: ${c(g)}`)}}for(const i of Object.keys(e.skills)){if(k.has(i))continue;const a=e.skills[i];this.dirSharedByOthers(e,i,a.dir)||await y(h(this.skillsDir,a.dir),{recursive:!0,force:!0}).catch(()=>{}),delete e.skills[i]}if(!(JSON.stringify(e)!==o))return;await O(this.skillsDir,e);try{this.onSyncSuccessHandler?.()}catch(i){r.warn("skill-sync",`onSyncSuccess handler failed: ${c(i)}`)}}finally{this.running=!1,this.rerunPending&&(this.rerunPending=!1,(this.timer!==null||!this.stopped)&&this.syncOnce().catch(t=>r.warn("skill-sync",`rerun sync failed: ${c(t)}`)))}}}dirSharedByOthers(t,s,n){return Object.entries(t.skills).some(([e,o])=>e!==s&&o.dir===n)}async pickReachable(){for(const t of this.configs){if(!t.apiKey||!t.wsUrl)continue;const s=await this.fetchList(t);if(s!==null)return{cfg:t,remote:s}}return null}async fetchList(t){const s=`${w(t.wsUrl)}/v1/agent-api/skills`;try{const n=await this.fetchImpl(s,{headers:{Authorization:`Bearer ${t.apiKey}`},signal:AbortSignal.timeout(p)});if(!n.ok)return r.warn("skill-sync",`list returned ${n.status}`),null;const e=await n.json();return e.code!==0?null:e.data?.items??[]}catch(n){return r.warn("skill-sync",`list error: ${c(n)}`),null}}async fetchContent(t,s){const n=`${w(t.wsUrl)}/v1/agent-api/skills/${encodeURIComponent(s)}/content`;try{const e=await this.fetchImpl(n,{headers:{Authorization:`Bearer ${t.apiKey}`},signal:AbortSignal.timeout(p)});if(!e.ok)return r.warn("skill-sync",`content ${s} returned ${e.status}`),null;const o=await e.json();return o.code!==0?null:typeof o.data?.content=="string"?o.data.content:null}catch(e){return r.warn("skill-sync",`content ${s} error: ${c(e)}`),null}}}function w(l){return new URL(l.replace(/^wss:/,"https:").replace(/^ws:/,"http:")).origin}function D(l){const t=l.trim().replace(/[/\\]/g,"_").replace(/[<>:"|?*\u0000-\u001f]/g,"_").replace(/^\.+/,"").replace(/[. ]+$/,"");return!t||t.includes("..")||/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i.test(t)?null:t!==l?`${t}-${$("sha1").update(l).digest("hex").slice(0,8)}`:t}function c(l){return l instanceof Error?l.message:String(l)}export{B as SkillSyncer};
1
+ import{mkdir as y,writeFile as v,rm as w}from"node:fs/promises";import{join as d}from"node:path";import{createHash as _}from"node:crypto";import{log as l}from"../log/index.js";import{readSkillManifest as O,writeSkillManifest as I}from"./manifest.js";const D=6e4,p=15e3;class R{configs;skillsDir;timer=null;running=!1;rerunPending=!1;stopped=!1;fetchImpl;intervalMs;onSyncSuccessHandler=null;constructor(t,r,i={}){this.configs=t,this.skillsDir=r,this.intervalMs=i.intervalMs??D,this.fetchImpl=i.fetchImpl??fetch}async start(){this.stopped=!1,await this.syncOnce().catch(t=>l.warn("skill-sync",`initial sync failed: ${c(t)}`)),this.timer=setInterval(()=>{this.syncOnce().catch(t=>l.warn("skill-sync",`sync failed: ${c(t)}`))},this.intervalMs),this.timer.unref?.()}stop(){this.stopped=!0,this.rerunPending=!1,this.timer&&(clearInterval(this.timer),this.timer=null)}setOnSyncSuccess(t){this.onSyncSuccessHandler=t}triggerSync(){if(this.running){this.rerunPending=!0;return}this.syncOnce().catch(t=>l.warn("skill-sync",`triggered sync failed: ${c(t)}`))}async syncOnce(){if(!this.running){this.running=!0;try{const t=await this.pickReachable();if(!t)return;const{cfg:r,remote:i}=t;await y(this.skillsDir,{recursive:!0});const n=await O(this.skillsDir),o=JSON.stringify(n),g=new Set(i.map(e=>e.name));for(const e of i){const s=n.skills[e.name];if(s&&s.digest===e.digest){const f=e.owner_id!==void 0?e.owner_id:s.owner_id,$=f==="0",h={...s,id:e.id,version:e.version,...f!==void 0?{owner_id:f}:{},system:$};(s.id!==h.id||s.version!==h.version||s.owner_id!==h.owner_id||s.system!==h.system)&&(n.skills[e.name]=h);continue}const S=e.owner_id==="0",u=M(e.name);if(!u){l.warn("skill-sync",`skip skill with unsafe name: ${e.name}`);continue}const m=await this.fetchContent(r,e.id);if(m!==null)try{await y(d(this.skillsDir,u),{recursive:!0}),await v(d(this.skillsDir,u,"SKILL.md"),m,"utf8"),n.skills[e.name]={id:e.id,version:e.version,digest:e.digest,dir:u,...e.owner_id!==void 0?{owner_id:e.owner_id}:{},system:S},s&&s.dir!==u&&!this.dirSharedByOthers(n,e.name,s.dir)&&await w(d(this.skillsDir,s.dir),{recursive:!0,force:!0}).catch(()=>{})}catch(f){l.warn("skill-sync",`write skill "${e.name}" failed: ${c(f)}`)}}for(const e of Object.keys(n.skills)){if(g.has(e))continue;const s=n.skills[e];this.dirSharedByOthers(n,e,s.dir)||await w(d(this.skillsDir,s.dir),{recursive:!0,force:!0}).catch(()=>{}),delete n.skills[e]}if(!(JSON.stringify(n)!==o))return;await I(this.skillsDir,n);try{this.onSyncSuccessHandler?.()}catch(e){l.warn("skill-sync",`onSyncSuccess handler failed: ${c(e)}`)}}finally{this.running=!1,this.rerunPending&&(this.rerunPending=!1,(this.timer!==null||!this.stopped)&&this.syncOnce().catch(t=>l.warn("skill-sync",`rerun sync failed: ${c(t)}`)))}}}dirSharedByOthers(t,r,i){return Object.entries(t.skills).some(([n,o])=>n!==r&&o.dir===i)}async pickReachable(){for(const t of this.configs){if(!t.apiKey||!t.wsUrl)continue;const r=await this.fetchList(t);if(r!==null)return{cfg:t,remote:r}}return null}async fetchList(t){const r=`${k(t.wsUrl)}/v1/agent-api/skills`;try{const i=await this.fetchImpl(r,{headers:{Authorization:`Bearer ${t.apiKey}`},signal:AbortSignal.timeout(p)});if(!i.ok)return l.warn("skill-sync",`list returned ${i.status}`),null;const n=await i.json();return n.code!==0?null:n.data?.items??[]}catch(i){return l.warn("skill-sync",`list error: ${c(i)}`),null}}async fetchContent(t,r){const i=`${k(t.wsUrl)}/v1/agent-api/skills/${encodeURIComponent(r)}/content`;try{const n=await this.fetchImpl(i,{headers:{Authorization:`Bearer ${t.apiKey}`},signal:AbortSignal.timeout(p)});if(!n.ok)return l.warn("skill-sync",`content ${r} returned ${n.status}`),null;const o=await n.json();return o.code!==0?null:typeof o.data?.content=="string"?o.data.content:null}catch(n){return l.warn("skill-sync",`content ${r} error: ${c(n)}`),null}}}function k(a){return new URL(a.replace(/^wss:/,"https:").replace(/^ws:/,"http:")).origin}function M(a){const t=a.trim().replace(/[/\\]/g,"_").replace(/[<>:"|?*\u0000-\u001f]/g,"_").replace(/^\.+/,"").replace(/[. ]+$/,"");return!t||t.includes("..")||/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i.test(t)?null:t!==a?`${t}-${_("sha1").update(a).digest("hex").slice(0,8)}`:t}function c(a){return a instanceof Error?a.message:String(a)}export{R as SkillSyncer};
@@ -1,2 +1,2 @@
1
- import{execFile as C,execFileSync as h}from"node:child_process";import{promisify as j}from"node:util";import{existsSync as c,mkdirSync as P,mkdtempSync as G,readFileSync as k,renameSync as f,rmSync as d,statfsSync as Y,symlinkSync as J,unlinkSync as $,writeFileSync as K}from"node:fs";import{basename as x,join as l,relative as H,resolve as g,sep as D}from"node:path";import{GRIX_PATHS as F}from"../log/index.js";import{appendRotatingFileSync as W}from"../log/rotation.js";import{getMachineName as X}from"../util/host-info.js";import{resolveInstallId as z}from"../util/install-id.js";import{npmInstallWithMirror as N,NPM_REGISTRIES as q}from"../installer/npm-registry.js";const Q=j(C);class a extends Error{code;constructor(t,r){super(r),this.name="UpgradeError",this.code=t}}const M=".grix-upgrade-backup",Z=".grix-upgrade-failed";function R(){return l(F.log,"upgrade.log")}function _(){return l(F.data,"upgrade-pending.json")}function ge(){return c(_())}function S(){const e=_();if(!c(e))return null;try{return JSON.parse(k(e,"utf-8"))}catch{return null}}function me(e,t){const r={from_version:e,target_version:t,upgraded_at:new Date().toISOString(),crash_count:0},i=_();A(i,r)}function A(e,t){const r=e+".tmp";K(r,JSON.stringify(t),"utf-8"),f(r,e)}function E(e,t){const r=g(e);return g(t)===`${r}${M}`&&r.includes(`${D}node_modules${D}`)&&x(r).length>0}function ee(e,t){const r=S();!r||!E(e,t)||(r.package_dir=g(e),r.backup_dir=g(t),A(_(),r))}function he(e=S()){const t=e?.package_dir,r=e?.backup_dir;if(!(!t||!r||!E(t,r)))try{d(r,{recursive:!0,force:!0})}catch{}}function _e(e=S()){const t=e?.package_dir,r=e?.backup_dir;if(!t||!r||!E(t,r)||!c(r))return!1;const i=`${t}${Z}`;try{return d(i,{recursive:!0,force:!0}),c(t)&&f(t,i),f(r,t),d(i,{recursive:!0,force:!0}),p(`atomic rollback restored ${t}`),!0}catch(n){try{!c(t)&&c(i)&&f(i,t)}catch{}return p(`atomic rollback failed: ${n instanceof Error?n.message:String(n)}`),!1}}function ye(){const e=_();if(c(e))try{$(e)}catch{}}function p(e){const t=`[${new Date().toISOString()}] ${e}
2
- `;try{W(R(),t)}catch{}}function ke(e=4096){const t=R();if(!c(t))return"";try{const r=k(t,"utf-8");return r.length<=e?r:r.slice(-e)}catch{return""}}function L(){try{const e=process.platform==="win32";return h(e?"cmd.exe":"npm",e?["/c","npm","--version"]:["--version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("NPM_NOT_FOUND","npm is not available or timed out")}}const m=1e6;function O(){if(process.platform==="win32")return m;let e;try{e=h("npm",["prefix","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{return m}try{const t=Y(e),r=Math.floor(Number(t.bavail)*Number(t.bsize)/(1024*1024));return!Number.isFinite(r)||r<0?m:Math.min(r,m)}catch{return m}}function ve(){let e;try{e=L()}catch(r){return{ok:!1,errorCode:"NPM_NOT_FOUND",errorMsg:r instanceof Error?r.message:"npm not available"}}const t=O();return t<100?{ok:!1,errorCode:"DISK_FULL",errorMsg:`Only ${t}MB free disk space (need >= 100MB)`,npmVersion:e,diskFreeMb:t}:{ok:!0,npmVersion:e,diskFreeMb:t}}function Se(){let e="";try{e=L()}catch{}let t=m;try{t=O()}catch{}return{npm_version:e,node_version:process.version,disk_free_mb:t,platform:process.platform,arch:process.arch,host_name:X(),install_id:z()}}function w(e,t,r){const i=l(e,"package.json");let n;try{n=JSON.parse(k(i,"utf-8"))}catch{throw new a("VERSION_VERIFY_FAILED",`Unable to read staged package metadata: ${i}`)}if(n.name!==t||n.version?.replace(/^v(?=\d)/,"")!==r)throw new a("VERSION_MISMATCH",`Staged package ${String(n.name)}@${String(n.version)} does not match ${t}@${r}`);return n}function te(e){return typeof e.bin=="string"?[[x(e.name),e.bin]]:!e.bin||typeof e.bin!="object"?[]:Object.entries(e.bin).filter(t=>typeof t[1]=="string")}function I(e,t){const r=te(t);if(r.length===0)throw new a("VERSION_VERIFY_FAILED",`Staged package ${t.name} has no executable bin`);for(const[,i]of r){const n=l(e,i);if(!c(n))throw new a("VERSION_VERIFY_FAILED",`Staged package entrypoint is missing: ${n}`)}return r}function re(e,t,r){if(process.platform==="win32")return;const i=l(e,"bin");P(i,{recursive:!0});for(const[n,o]of r){const s=l(i,n);if(c(s))continue;const u=`${s}.grix-upgrade-${process.pid}`;try{$(u)}catch{}J(H(i,l(t,o)),u),f(u,s)}}function ne(e){const t=g(e.activePackageDir),r=g(e.stagedPackageDir),i=`${t}${M}`,n=w(r,e.packageName,e.version),o=I(r,n);c(i)&&(c(t)?d(i,{recursive:!0,force:!0}):f(i,t)),ee(t,i);let s=!1;try{c(t)&&(f(t,i),s=!0),f(r,t);const u=w(t,e.packageName,e.version),v=I(t,u);return re(e.npmPrefix,t,v),{packageDir:t,backupDir:i}}catch(u){try{c(t)&&d(t,{recursive:!0,force:!0}),s&&c(i)&&f(i,t)}catch{}throw u}}function b(e){try{return h("npm",e,{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("NPM_NOT_FOUND",`Unable to resolve npm ${e.join(" ")}`)}}async function ie(e,t,r){const i=`${e}@${t}`,n=b(["prefix","-g"]),o=b(["root","-g"]);P(n,{recursive:!0});const s=G(l(n,".grix-upgrade-stage-"));try{p(`staging npm install ${i} under ${s}`);const{registry:u}=await N(i,r,10*1024*1024,{prefix:s}),v=b(["root","-g","--prefix",s]),y=l(v,e),U=w(y,e,t),T=I(y,U),V=l(y,T[0][1]);h(process.execPath,[V,"--version"],{encoding:"utf-8",timeout:15e3,maxBuffer:2*1024*1024});const B=ne({packageName:e,version:t,npmPrefix:n,activePackageDir:l(o,e),stagedPackageDir:y});p(`atomic package switch succeeded via ${u}; backup=${B.backupDir}`)}finally{try{d(s,{recursive:!0,force:!0})}catch{}}}async function Ee(e,t,r=12e4){const i=`${e}@${t}`;p(`npm install -g ${i} starting (atomic staging with mirror fallback)`);try{if(process.platform==="win32"){const{registry:n}=await N(i,r,10485760);p(`npm install succeeded via ${n}`)}else await ie(e,t,r)}catch(n){if(n instanceof a)throw n;const o=n instanceof Error?n.message:String(n);throw p(`npm install failed: ${o}`),/timed out|ETIMEDOUT/i.test(o)?new a("NPM_TIMEOUT",`npm install timed out after ${r/1e3}s (tried all mirrors): ${o}`):o.includes("EACCES")||o.includes("permission denied")?new a("NPM_INSTALL_FAILED",`Permission denied: ${o}`):o.includes("ENOSPC")||o.includes("no space left")?new a("DISK_FULL",`Disk full: ${o}`):o.includes("404")||o.includes("not found")?new a("NPM_INSTALL_FAILED",`Package not found: ${o}`):new a("NPM_INSTALL_FAILED",o)}}function we(e){let t;try{const i=process.platform==="win32";t=h(i?"cmd.exe":"npm",i?["/c","npm","root","-g"]:["root","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("VERSION_VERIFY_FAILED","Unable to resolve the global npm package directory")}let r;try{const i=l(t,"grix-connector","package.json"),n=JSON.parse(k(i,"utf-8"));if(n.name!=="grix-connector"||typeof n.version!="string"||!n.version.trim())throw new Error("invalid package metadata");r=n.version.trim().replace(/^v(?=\d)/,"")}catch{throw new a("VERSION_VERIFY_FAILED","Unable to read the installed grix-connector version")}if(r!==e)throw new a("VERSION_MISMATCH",`Installed version ${r} does not match expected ${e}`);return r}async function Ie(e,t){let r=!1;for(const i of q)try{const{stdout:n}=await Q("npm",["view",`${e}@${t}`,"version","--registry",i.url,"--no-audit","--no-fund"],{timeout:8e3});if(n.trim())return!0}catch(n){const o=n,s=o.stderr||o.message||String(n);/ETARGET|No matching version|notarget|E404/i.test(s)&&(r=!0)}return!r}export{a as UpgradeError,O as checkDiskSpace,L as checkNpmAvailable,he as cleanupPendingBackup,Se as collectEnvInfo,ne as commitStagedGlobalPackage,ke as getUpgradeLogTail,Ie as isVersionAvailable,Ee as npmInstall,ge as pendingExists,ve as preflightCheck,S as readPending,ye as removePending,_e as rollbackPendingInstall,p as upgradeLog,we as verifyInstalledVersion,me as writePending};
1
+ import{execFile as C,execFileSync as h}from"node:child_process";import{promisify as j}from"node:util";import{existsSync as c,mkdirSync as P,mkdtempSync as G,readFileSync as k,renameSync as f,rmSync as g,statfsSync as Y,symlinkSync as J,unlinkSync as $,writeFileSync as K}from"node:fs";import{basename as x,join as l,relative as H,resolve as d,sep as D}from"node:path";import{GRIX_PATHS as F}from"../log/index.js";import{appendRotatingFileSync as W}from"../log/rotation.js";import{getMachineName as X}from"../util/host-info.js";import{resolveInstallId as z}from"../util/install-id.js";import{npmInstallWithMirror as N,probeRegistries as q}from"../installer/npm-registry.js";const Q=j(C);class a extends Error{code;constructor(t,r){super(r),this.name="UpgradeError",this.code=t}}const M=".grix-upgrade-backup",Z=".grix-upgrade-failed";function A(){return l(F.log,"upgrade.log")}function _(){return l(F.data,"upgrade-pending.json")}function de(){return c(_())}function S(){const e=_();if(!c(e))return null;try{return JSON.parse(k(e,"utf-8"))}catch{return null}}function me(e,t){const r={from_version:e,target_version:t,upgraded_at:new Date().toISOString(),crash_count:0},i=_();L(i,r)}function L(e,t){const r=e+".tmp";K(r,JSON.stringify(t),"utf-8"),f(r,e)}function w(e,t){const r=d(e);return d(t)===`${r}${M}`&&r.includes(`${D}node_modules${D}`)&&x(r).length>0}function ee(e,t){const r=S();!r||!w(e,t)||(r.package_dir=d(e),r.backup_dir=d(t),L(_(),r))}function he(e=S()){const t=e?.package_dir,r=e?.backup_dir;if(!(!t||!r||!w(t,r)))try{g(r,{recursive:!0,force:!0})}catch{}}function _e(e=S()){const t=e?.package_dir,r=e?.backup_dir;if(!t||!r||!w(t,r)||!c(r))return!1;const i=`${t}${Z}`;try{return g(i,{recursive:!0,force:!0}),c(t)&&f(t,i),f(r,t),g(i,{recursive:!0,force:!0}),p(`atomic rollback restored ${t}`),!0}catch(n){try{!c(t)&&c(i)&&f(i,t)}catch{}return p(`atomic rollback failed: ${n instanceof Error?n.message:String(n)}`),!1}}function ye(){const e=_();if(c(e))try{$(e)}catch{}}function p(e){const t=`[${new Date().toISOString()}] ${e}
2
+ `;try{W(A(),t)}catch{}}function ke(e=4096){const t=A();if(!c(t))return"";try{const r=k(t,"utf-8");return r.length<=e?r:r.slice(-e)}catch{return""}}function O(){try{const e=process.platform==="win32";return h(e?"cmd.exe":"npm",e?["/c","npm","--version"]:["--version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("NPM_NOT_FOUND","npm is not available or timed out")}}const m=1e6;function R(){if(process.platform==="win32")return m;let e;try{e=h("npm",["prefix","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{return m}try{const t=Y(e),r=Math.floor(Number(t.bavail)*Number(t.bsize)/(1024*1024));return!Number.isFinite(r)||r<0?m:Math.min(r,m)}catch{return m}}function ve(){let e;try{e=O()}catch(r){return{ok:!1,errorCode:"NPM_NOT_FOUND",errorMsg:r instanceof Error?r.message:"npm not available"}}const t=R();return t<100?{ok:!1,errorCode:"DISK_FULL",errorMsg:`Only ${t}MB free disk space (need >= 100MB)`,npmVersion:e,diskFreeMb:t}:{ok:!0,npmVersion:e,diskFreeMb:t}}function Se(){let e="";try{e=O()}catch{}let t=m;try{t=R()}catch{}return{npm_version:e,node_version:process.version,disk_free_mb:t,platform:process.platform,arch:process.arch,host_name:X(),install_id:z()}}function b(e,t,r){const i=l(e,"package.json");let n;try{n=JSON.parse(k(i,"utf-8"))}catch{throw new a("VERSION_VERIFY_FAILED",`Unable to read staged package metadata: ${i}`)}if(n.name!==t||n.version?.replace(/^v(?=\d)/,"")!==r)throw new a("VERSION_MISMATCH",`Staged package ${String(n.name)}@${String(n.version)} does not match ${t}@${r}`);return n}function te(e){return typeof e.bin=="string"?[[x(e.name),e.bin]]:!e.bin||typeof e.bin!="object"?[]:Object.entries(e.bin).filter(t=>typeof t[1]=="string")}function E(e,t){const r=te(t);if(r.length===0)throw new a("VERSION_VERIFY_FAILED",`Staged package ${t.name} has no executable bin`);for(const[,i]of r){const n=l(e,i);if(!c(n))throw new a("VERSION_VERIFY_FAILED",`Staged package entrypoint is missing: ${n}`)}return r}function re(e,t,r){if(process.platform==="win32")return;const i=l(e,"bin");P(i,{recursive:!0});for(const[n,o]of r){const s=l(i,n);if(c(s))continue;const u=`${s}.grix-upgrade-${process.pid}`;try{$(u)}catch{}J(H(i,l(t,o)),u),f(u,s)}}function ne(e){const t=d(e.activePackageDir),r=d(e.stagedPackageDir),i=`${t}${M}`,n=b(r,e.packageName,e.version),o=E(r,n);c(i)&&(c(t)?g(i,{recursive:!0,force:!0}):f(i,t)),ee(t,i);let s=!1;try{c(t)&&(f(t,i),s=!0),f(r,t);const u=b(t,e.packageName,e.version),v=E(t,u);return re(e.npmPrefix,t,v),{packageDir:t,backupDir:i}}catch(u){try{c(t)&&g(t,{recursive:!0,force:!0}),s&&c(i)&&f(i,t)}catch{}throw u}}function I(e){try{return h("npm",e,{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("NPM_NOT_FOUND",`Unable to resolve npm ${e.join(" ")}`)}}async function ie(e,t,r){const i=`${e}@${t}`,n=I(["prefix","-g"]),o=I(["root","-g"]);P(n,{recursive:!0});const s=G(l(n,".grix-upgrade-stage-"));try{p(`staging npm install ${i} under ${s}`);const{registry:u}=await N(i,r,10*1024*1024,{prefix:s}),v=I(["root","-g","--prefix",s]),y=l(v,e),U=b(y,e,t),T=E(y,U),V=l(y,T[0][1]);h(process.execPath,[V,"--version"],{encoding:"utf-8",timeout:15e3,maxBuffer:2*1024*1024});const B=ne({packageName:e,version:t,npmPrefix:n,activePackageDir:l(o,e),stagedPackageDir:y});p(`atomic package switch succeeded via ${u}; backup=${B.backupDir}`)}finally{try{g(s,{recursive:!0,force:!0})}catch{}}}async function we(e,t,r=12e4){const i=`${e}@${t}`;p(`npm install -g ${i} starting (atomic staging with mirror fallback)`);try{if(process.platform==="win32"){const{registry:n}=await N(i,r,10485760);p(`npm install succeeded via ${n}`)}else await ie(e,t,r)}catch(n){if(n instanceof a)throw n;const o=n instanceof Error?n.message:String(n);throw p(`npm install failed: ${o}`),/timed out|ETIMEDOUT/i.test(o)?new a("NPM_TIMEOUT",`npm install timed out after ${r/1e3}s (tried all mirrors): ${o}`):o.includes("EACCES")||o.includes("permission denied")?new a("NPM_INSTALL_FAILED",`Permission denied: ${o}`):o.includes("ENOSPC")||o.includes("no space left")?new a("DISK_FULL",`Disk full: ${o}`):o.includes("404")||o.includes("not found")?new a("NPM_INSTALL_FAILED",`Package not found: ${o}`):new a("NPM_INSTALL_FAILED",o)}}function be(e){let t;try{const i=process.platform==="win32";t=h(i?"cmd.exe":"npm",i?["/c","npm","root","-g"]:["root","-g"],{encoding:"utf-8",timeout:1e4}).trim()}catch{throw new a("VERSION_VERIFY_FAILED","Unable to resolve the global npm package directory")}let r;try{const i=l(t,"grix-connector","package.json"),n=JSON.parse(k(i,"utf-8"));if(n.name!=="grix-connector"||typeof n.version!="string"||!n.version.trim())throw new Error("invalid package metadata");r=n.version.trim().replace(/^v(?=\d)/,"")}catch{throw new a("VERSION_VERIFY_FAILED","Unable to read the installed grix-connector version")}if(r!==e)throw new a("VERSION_MISMATCH",`Installed version ${r} does not match expected ${e}`);return r}async function Ee(e,t){let r=!1;for(const i of await q())try{const{stdout:n}=await Q("npm",["view",`${e}@${t}`,"version","--registry",i.url,"--no-audit","--no-fund"],{timeout:8e3});if(n.trim())return!0}catch(n){const o=n,s=o.stderr||o.message||String(n);/ETARGET|No matching version|notarget|E404/i.test(s)&&(r=!0)}return!r}export{a as UpgradeError,R as checkDiskSpace,O as checkNpmAvailable,he as cleanupPendingBackup,Se as collectEnvInfo,ne as commitStagedGlobalPackage,ke as getUpgradeLogTail,Ee as isVersionAvailable,we as npmInstall,de as pendingExists,ve as preflightCheck,S as readPending,ye as removePending,_e as rollbackPendingInstall,p as upgradeLog,be as verifyInstalledVersion,me as writePending};
package/dist/log.js CHANGED
@@ -1,3 +1,3 @@
1
- import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as t}from"node:path";import{homedir as m}from"node:os";const i=t(m(),".grix"),s={base:i,config:t(i,"config"),log:t(i,"log"),data:t(i,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=t(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...n){const e=`${c()} [${o}] ${r}${n.length?" "+n.map(String).join(" "):""}`;console.log(e),a?.write(e+`
2
- `)},error(o,r,...n){const e=`${c()} [${o}] ERROR ${r}${n.length?" "+n.map(String).join(" "):""}`;console.error(e),a?.write(e+`
1
+ import{createWriteStream as g,mkdirSync as l,existsSync as f}from"node:fs";import{join as i}from"node:path";import{homedir as m}from"node:os";const n=i(m(),".grix"),s={base:n,config:i(n,"config"),log:i(n,"log"),data:i(n,"data")};function S(){for(const o of Object.values(s))f(o)||l(o,{recursive:!0})}let a=null;function $(){const o=new Date().toISOString().slice(0,10),r=i(s.log,`grix-acp-${o}.log`);a=g(r,{flags:"a"})}function c(){return new Date().toISOString().slice(11,19)}const u={info(o,r,...t){const e=`${c()} [${o}] ${r}${t.length?" "+t.map(String).join(" "):""}`;console.log(e),a?.write(e+`
2
+ `)},error(o,r,...t){const e=`${c()} [${o}] ERROR ${r}${t.length?" "+t.map(String).join(" "):""}`;console.error(e),a?.write(e+`
3
3
  `)}};export{s as GRIX_PATHS,S as ensureGrixDirs,$ as initLogger,u as log};
package/dist/manager.js CHANGED
@@ -1,2 +1,2 @@
1
- import{readFileSync as Z,readdirSync as ee,writeFileSync as te}from"node:fs";import{join as A}from"node:path";import{homedir as ne}from"node:os";import{AgentInstance as D}from"./bridge/bridge.js";import{buildSharedInstanceConfig as re,diffSharedOwners as ae,sharedInstanceKey as ie,SharedOwnersCache as se}from"./manager-share-config.js";import{isAgentDeletedError as O}from"./core/aibot/errors.js";import{GRIX_PATHS as _,log as p}from"./core/log/index.js";import{resolveClientVersion as oe}from"./core/util/client-version.js";import{UpgradeChecker as ce}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as le}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as de}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as pe}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as me}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as ue}from"./core/skill-sync/library-skills.js";import{AUDIT_LOCAL_ACTION_TYPES as ge}from"./core/aibot/types.js";import{buildReportedSkills as fe,logDefaultSkillsCheck as he,cleanupProjectedSkills as N}from"./default-skills/index.js";import{supportsKiroCwRelay as q,supportsNonMitmRelayConfig as _e}from"./core/config/provider-env.js";import{ensureKiroRelay as H,stopKiroRelay as L}from"./core/proxy/kiro-relay.js";import{resolveCopilotCommand as U}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as B}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ye,resolveCliPath as we}from"./core/util/cli-probe.js";import{AgentInstaller as ve}from"./core/installer/installer.js";import{reportInstallFailure as Se}from"./core/observability/sentry.js";import{createDefaultAuditProducer as Ae}from"./audit/runtime/default-audit-recorder.js";import{normalizeCodexConfigOverrides as ke}from"./adapter/codex/config-overrides.js";import{resolveCodexDirectHome as be}from"./adapter/codex/direct-home.js";const Ce=8e3;function xe(){const n=U();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:B()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:n.command},{clientType:"agy",command:"agy"}]}async function $e(){return Promise.all(xe().map(async n=>{const e=await we(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await ye(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function Ie(n){switch(n){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:B()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=U();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${n}`)}}function k(n,e){return String(n??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function Te(n){return A(_.data,`session-bindings-${k(n,"unknown")}.json`)}function Ee(n,e){return A(_.data,`session-bindings-${k(n,e)}.json`)}function Re(n,e){return A(_.data,`active-events-${k(n,e)}.json`)}function Pe(n,e){const t=k(n,"agent"),r=k(e,"unknown");return A(_.data,`terminal-outbox-${t}-${r}.json`)}function je(...n){const e=[],t=new Set;for(const r of n)for(const a of r??[]){const o=String(a??"").trim(),i=o.toLowerCase();!o||t.has(i)||(t.add(i),e.push(o))}return e.length>0?e:void 0}function Me(n,e){const t={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},r=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??r.maxConcurrent??1,maxQueued:e?.max_queued??r.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??r.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function De(n,e={}){const t=oe(),r=String(n.client_type??"").trim().toLowerCase(),a=Ie(r),o=String(n.ws_url??"").trim(),i="get_session_usage",m="get_rate_limits",c="get_agent_global_config",s=ge;if(!n.name?.trim())throw new Error("agent name is required");if(!o)throw new Error(`agent ${n.name}: ws_url is required`);if(!n.agent_id?.trim())throw new Error(`agent ${n.name}: agent_id is required`);if(!n.api_key?.trim())throw new Error(`agent ${n.name}: api_key is required`);const l=a.adapterType,u=l==="acp",w=r==="qwen",d={...a.options??{}};if(n.codex_config_overrides!==void 0){if(l!=="codex")throw new Error(`agent ${n.name}: codex_config_overrides is only supported for client_type=codex`);ke(n.codex_config_overrides,`agent ${n.name}: codex_config_overrides`),d.codexConfigOverrides=n.codex_config_overrides}if(l==="codex"&&n.provider?.wire_api!==void 0){const f=n.provider;if(f.wire_api!=="responses"||!f.base_url?.trim()||!f.api_key?.trim()||!f.model?.trim()||!f.catalog_version?.trim()||!f.catalog_sha256?.trim()||!f.catalog_json?.trim())throw Object.assign(new Error(`agent ${n.name}: incomplete Codex direct relay config`),{code:"INVALID_CODEX_DIRECT_CONFIG"});const M=be(_.data,n.name);d.codexHome=M,d.codexDirect={codexHome:M,config:{baseUrl:f.base_url.trim(),model:f.model.trim(),...f.reasoning_effort?.trim()?{reasoningEffort:f.reasoning_effort.trim()}:{},token:f.api_key.trim()},catalog:{version:f.catalog_version.trim(),sha256:f.catalog_sha256.trim(),json:f.catalog_json}}}const h=l==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",i,m]}:null,y=l==="claude"?{localActions:["session_control","set_mode","set_model","set_reasoning_effort","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",i,m]}:null,g=w?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",i],adapterHint:"qwen/base"}:null,S=l==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",i,m]}:null,v=l==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,C=l==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder","thread_compact","claude_interaction_reply",m]}:null,T=l==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",i]}:null,x=l==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","claude_interaction_reply","file_list","create_folder"]}:null,$=l==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,E=new Set(["hermes","reasonix","kimi","copilot"]),Q=u&&!E.has(r),K=u&&!w?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",...Q?[i]:[]]}:null,W=r==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",i,m]}:null,z=l==="codex"||l==="claude"||l==="opencode"||r==="gemini"?["session_control","set_model","set_mode",...l==="claude"?["set_reasoning_effort"]:[]]:void 0,G=l==="cursor"||l==="opencode"||l==="openhuman"||l==="agy"||u&&E.has(r)?[m]:[i,m];u&&d.raw_transport===void 0&&(d.raw_transport=r==="gemini");const V=`${r}/base`,I=pe(l,r),J=I==="kiro"?void 0:process.cwd(),R=fe({mode:I,projectDir:J}),P=R.filter(f=>f.source==="connector").map(f=>f.name);P.length>0&&!e.quiet&&p.info("manager",`[${n.name}] injecting connector skills: [${P.join(", ")}]`);const j=me(R,_.skills);let X=j.length>0?j:void 0;const Y=ue({skillsDir:_.skills,mode:I,home:ne()});return{name:n.name,adapterType:l,aibot:{url:o,agentId:n.agent_id,apiKey:n.api_key,clientType:r,clientVersion:t,adapterHint:a.adapterHint??g?.adapterHint??S?.adapterHint??v?.adapterHint??C?.adapterHint??x?.adapterHint??$?.adapterHint??V,capabilities:h?.capabilities??T?.capabilities??S?.capabilities??v?.capabilities??C?.capabilities??x?.capabilities??$?.capabilities??g?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:je(h?.localActions??T?.localActions??y?.localActions??S?.localActions??v?.localActions??C?.localActions??x?.localActions??$?.localActions??g?.localActions??W?.localActions??K?.localActions??["exec_approve","exec_reject"],z,G,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload","skill_enable","skill_disable","skill_refresh",...s]),skills:X,librarySkills:Y,terminalOutboxPath:Pe(n.name,n.agent_id)},agent:{command:a.command,args:[...a.args??[],...n.args??[]],env:n.env,clientType:r,...n.provider?{provider:{...n.provider.provider_id?.trim()?{providerId:n.provider.provider_id.trim()}:{},...n.provider.base_url?.trim()?{baseUrl:n.provider.base_url.trim()}:{},...n.provider.quota_base_url?.trim()?{quotaBaseUrl:n.provider.quota_base_url.trim()}:{},...n.provider.api_key?.trim()?{apiKey:n.provider.api_key.trim()}:{},...n.provider.model?.trim()?{model:n.provider.model.trim()}:{},...n.provider.fast_model?.trim()?{fastModel:n.provider.fast_model.trim()}:{},...n.provider.effort?.trim()?{effort:n.provider.effort.trim()}:{}}}:{}},adapterOptions:d,acpAuthMethod:d.auth_method,acpInitialMode:d.initial_mode,acpMcpTools:d.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:Te(n.agent_id),legacyBindingsPath:Ee(n.name,n.agent_id),activeEventStorePath:Re(n.name,n.agent_id),...a.enableSessionBinding||u?{enableSessionBinding:!0}:{},...a.autoInjectArgs||r==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...a.autoInjectArgs??{},...r==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize,poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:Me(l,n.event_queue),logDir:_.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Oe(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):Ce}function F(n){const e=[],t=[],r=[],a=ee(n).filter(o=>o.endsWith(".json")).sort();for(const o of a)try{const i=JSON.parse(Z(A(n,o),"utf-8"));if(i===null||typeof i!="object"||Array.isArray(i)||!("agents"in i)){r.push(o);continue}if(!Array.isArray(i.agents)){t.push({file:o,error:"agents is not an array"});continue}if(i.agents.length===0){t.push({file:o,error:"agents array is empty"});continue}for(const m of i.agents)e.push({entry:m,file:o})}catch(i){t.push({file:o,error:i instanceof Error?i.message:String(i)})}return{entries:e,fileErrors:t,skipped:r}}function b(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(b).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${b(e[r])}`).join(",")}}`}function Ne(n,e){return b(n)===b(e)}class mt{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=_.config;sharedOwnersCache=new se(_.data);installer=new ve;relaySecretResolver;auditProducer=Ae();async start(e){const t=e??_.config;this.configDir=t,p.info("manager",`Loading configs from ${t}`),he(),N(),this.globalConfigStore=new de(A(_.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:r,fileErrors:a,skipped:o}=F(t);for(const s of a)p.error("manager",`Failed to load ${s.file}: ${s.error}`);for(const s of o)p.info("manager",`Skipped ${s}: not an agent config (no "agents" key)`);if(r.length===0&&a.length===0&&o.length===0){p.warn("manager",`No config files found in ${t}; daemon idle (waiting for config). Add agents under this directory then run: grix-connector reload`);return}const i=[];let m=a.length;for(const{entry:s,file:l}of r)try{const u=this.toRuntimeInstanceConfig(s);i.push({config:u,entry:s,file:l}),p.info("manager",`Loaded ${u.name} (${u.adapterType??"acp"}) from ${l}`)}catch(u){const w=typeof s?.name=="string"?s.name:"<unknown>";p.error("manager",`Invalid agent config in ${l} (name=${w}): ${u}`),m++}let c=0;if(i.length>0){const s=Oe();p.info("manager",`Starting ${i.length} agent(s), startup wait=${s}ms`);const l=d=>{this.instances=this.instances.filter(h=>h!==d)},u=i.map(({config:d,entry:h,file:y})=>{const g=this.createConfiguredInstance(d);return this.instances.push(g),this.configMap.set(d.name,d),this.rawConfigMap.set(d.name,{entry:h,file:y}),{config:d,instance:g,startPromise:this.prepareProviderRuntime(d,h).then(()=>g.start())}}),w=await Promise.all(u.map(async d=>{const h=await new Promise(y=>{let g=!1;const S=setTimeout(()=>{g||(g=!0,y({kind:"timeout"}))},s);d.startPromise.then(()=>{g||(g=!0,clearTimeout(S),y({kind:"started"}))}).catch(v=>{g||(g=!0,clearTimeout(S),y({kind:"failed",error:v}))})});return{task:d,outcome:h}}));for(const{task:d,outcome:h}of w){if(h.kind==="started"){this.restoreCachedSharedInstances(d.config);continue}if(h.kind==="failed"){if(O(h.error)){this.onAgentDeletedByPlatform(d.config.name);continue}l(d.instance),p.error("manager",`Failed to start ${d.config.name}: ${h.error}`);continue}c++,p.warn("manager",`Startup pending for ${d.config.name}, continue retrying in background`),d.startPromise.then(()=>{p.info("manager",`Delayed start succeeded: ${d.config.name}`),this.restoreCachedSharedInstances(d.config)}).catch(y=>{if(O(y)){this.onAgentDeletedByPlatform(d.config.name);return}l(d.instance),p.error("manager",`Delayed start failed: ${d.config.name}: ${y}`)})}if(this.instances.length>0){const d=Math.max(0,this.instances.length-c);p.info("manager",`${d}/${i.length} agent(s) running now`)}c>0&&p.warn("manager",`${c} agent(s) still connecting in background`)}if(this.instances.length===0&&i.length>0)throw new Error("All agent configurations failed to start");await this.ensureAuxServices()}async ensureAuxServices(){if(this.configMap.size===0)return;const e=[...this.configMap.values()].map(t=>({apiKey:t.aibot.apiKey,wsUrl:t.aibot.url}));this.upgradeChecker||(this.upgradeChecker=new ce(e,()=>this.instances.some(t=>t.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(t=>t.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),this.skillSyncer||(this.skillSyncer=new le(e,_.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshAllInstanceSkills()),await this.skillSyncer.start())}refreshAllInstanceSkills(){for(const e of this.instances)try{e.forceRefreshSkills()}catch(t){p.warn("manager",`forceRefreshSkills failed for ${e.name}: ${t}`)}for(const e of this.sharedInstances.values())try{e.forceRefreshSkills()}catch(t){p.warn("manager",`forceRefreshSkills failed for shared instance: ${t}`)}}async stop(){p.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(t=>t.stop()),...e.map(t=>t.stop())]),await this.globalConfigStore?.flush(),await this.auditProducer.stop({timeoutMs:5e3}).catch(()=>!1),this.instances=[],N(),p.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const a=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,a)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:r,toRemove:a}=ae(e.name,this.sharedInstances.keys(),t);for(const o of r){if(this.stopping)break;const i=ie(e.name,o);try{const m=re(e,o),c=new D(m,this.globalConfigStore,this.auditProducer);this.sharedInstances.set(i,c),await c.start(),c.forceRefreshSkills(),p.info("manager",`shared instance started: ${i}`)}catch(m){this.sharedInstances.delete(i);const c=m instanceof Error?m.message:String(m);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,o),p.warn("manager",`shared instance auth rejected, removed from cache: ${i}`)):p.error("manager",`start shared instance failed ${i}: ${m}`)}}for(const{key:o}of a){const i=this.sharedInstances.get(o);i&&(this.sharedInstances.delete(o),i.stop().catch(m=>p.error("manager",`stop shared instance failed ${o}: ${m}`)),p.info("manager",`shared instance stopped: ${o}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(p.info("manager",`restoring ${t.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,t))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),await this.ensureAuxServices(),p.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const r=this.toRuntimeInstanceConfig(e);if(this.instances.some(a=>a.name===r.name))throw new Error(`Agent "${r.name}" already exists`);await this.startInstanceFromConfig(r,e,t)}createConfiguredInstance(e){const t=new D(e,this.globalConfigStore,this.auditProducer);return t.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),t.setShareSetHandler(r=>this.onShareSet(e,r)),t.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),t.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),t.setProviderConfigHandler(r=>this.setAgentProvider(e.name,r)),t.setRelayStateApplyPorts({getLocalState:()=>this.relayStateApplier?.getLocalState(e.name)??{enabled:!1},applyEnable:(r,a)=>{const o=this.relayStateApplier;return o?o.applyEnable(e.name,r,a):Promise.reject(new Error("relay state applier is not configured"))},applyDisable:()=>{const r=this.relayStateApplier;return r?r.applyDisable(e.name):Promise.reject(new Error("relay state applier is not configured"))}}),t.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),t.setProviderResolver(()=>this.getAgentProvider(e.name)),t}async prepareProviderRuntime(e,t){const r=this.resolveAgentProvider(t.provider);q(t.client_type)&&r?.base_url?.trim()&&r?.api_key?.trim()&&r?.model?.trim()&&await H(e.name,{baseUrl:r.base_url.trim(),apiKey:r.api_key.trim(),model:r.model.trim()})}async startInstanceFromConfig(e,t,r){await this.prepareProviderRuntime(e,t);const a=this.createConfiguredInstance(e);await a.start(),this.instances.push(a),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:r}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(t=>t.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),p.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const r=this.instances.findIndex(m=>m.name===e),a=r===-1?void 0:this.instances[r];r!==-1&&this.instances.splice(r,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const o=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),o&&await o.catch(()=>{});const i=`${e}#shared:`;for(const[m,c]of[...this.sharedInstances.entries()])m.startsWith(i)&&(this.sharedInstances.delete(m),c.stop().catch(s=>p.error("manager",`stop shared instance failed ${m}: ${s}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),a&&await a.stop(),t?.keepShareCache||await L(e).catch(()=>{})}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(r=>r.name===e)))return;p.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),p.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(t){p.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=A(this.configDir,"agents.json");try{const t=[];for(const[,a]of this.configMap){const o=this.rawConfigMap.get(a.name)?.entry.provider;t.push({name:a.name,ws_url:a.aibot.url,agent_id:a.aibot.agentId,api_key:a.aibot.apiKey,client_type:a.aibot.clientType,...o?{provider:o}:{}})}te(e,JSON.stringify({agents:t},null,4)+`
2
- `,"utf-8")}catch(t){p.error("manager",`Failed to persist agents config: ${t}`)}}isAgentBusy(e){return this.instances.find(r=>r.name===e)?.hasPendingWork()??!1}getAgentsWithStaleRelayEnv(){return this.instances.filter(e=>e.hasStaleRelayEnv()).map(e=>e.name)}markAgentRelayEnvStale(e){const t=this.instances.find(r=>r.name===e);return t?(t.markRelayEnvStale(),!0):!1}relayEnvSettledHandler;setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}relayStateApplier;setRelayStateApplier(e){this.relayStateApplier=e}reportRelayStateLocalChange(e){this.instances.find(r=>r.name===e)?.reportRelayStateLocalChange()}setRelaySecretResolver(e){this.relaySecretResolver=e}resolveAgentProvider(e){if(!e?.api_key_ref?.trim())return e;const t=e.api_key_ref.trim(),r=this.relaySecretResolver?.(t);if(!r)throw Object.assign(new Error(`relay credential "${t}" is unavailable`),{code:"RELAY_SECRET_UNAVAILABLE"});return{...e,api_key:r}}toRuntimeInstanceConfig(e,t={}){const r=this.resolveAgentProvider(e.provider);return De(r===e.provider?e:{...e,provider:r},t)}getAgentProvider(e){return this.resolveAgentProvider(this.rawConfigMap.get(e)?.entry.provider)}async restartAgent(e){const t=this.rawConfigMap.get(e);if(!t)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.replaceInstance(e,t.entry,t.file),p.info("manager",`Restarted agent: ${e}`)}async setAgentProvider(e,t,r){const a=this.rawConfigMap.get(e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});const o=String(a.entry.client_type??"").trim().toLowerCase();q(o)&&(t?.base_url?.trim()&&t?.api_key?.trim()&&t?.model?.trim()?await H(e,{baseUrl:t.base_url.trim(),apiKey:t.api_key.trim(),model:t.model.trim()}):await L(e));const i=t?.api_key_ref?.trim()?Object.fromEntries(Object.entries(t).filter(([c])=>c!=="api_key")):t,m={...a.entry,provider:i};if(r?.deferRestart){this.rawConfigMap.set(e,{...a,entry:m}),this.instances.find(c=>c.name===e)?.markRelayEnvStale(),this.persistAgentsConfig(),p.info("manager",`Updated provider config for agent (deferred restart): ${e}`);return}await this.replaceInstance(e,m,a.file),this.persistAgentsConfig(),p.info("manager",`Updated provider config for agent: ${e}`)}hasDirectRelayConfig(e){const t=this.rawConfigMap.get(e)?.entry.provider;return!!(t?.api_key_ref?.trim()||t?.api_key?.trim())}getDirectRelayConfigAgentNames(){return[...this.rawConfigMap.entries()].filter(([,e])=>!!e.entry.provider&&(_e(e.entry.client_type)||["claude","codex"].includes(String(e.entry.client_type??"").trim().toLowerCase()))).map(([e])=>e)}async fetchRelayCredential(e,t){const r=this.instances.find(a=>a.name===e);if(!r)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return r.fetchRelayCredential(t)}async clearDirectProviderConfigs(){const e=this.getDirectRelayConfigAgentNames(),t=[];for(const r of e)try{await this.setAgentProvider(r,void 0,{deferRestart:this.isAgentBusy(r)}),t.push(r)}catch(a){p.warn("manager",`Failed to clear provider config for "${r}": ${a instanceof Error?a.message:String(a)}`)}return t}async replaceInstance(e,t,r){const a=this.toRuntimeInstanceConfig(t);await this.removeAgentInternal(e,{keepShareCache:!0}),await this.startInstanceFromConfig(a,t,r),this.restoreCachedSharedInstances(a)}async reload(){const e=this.reloadChain.catch(()=>{}).then(()=>this.doReload());return this.reloadChain=e.catch(()=>{}),e}async doReload(){if(this.stopping)throw Object.assign(new Error("manager is stopping"),{code:"RELOAD_UNSAFE"});const{entries:e,fileErrors:t,skipped:r}=F(this.configDir);for(const c of r)p.info("manager",`reload: skipped ${c}: not an agent config (no "agents" key)`);if(t.length>0){const c=t.map(s=>`${s.file}: ${s.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${t.length} config file(s) failed to parse [${c}]`),{code:"RELOAD_UNSAFE"})}if(e.length===0)throw Object.assign(new Error("reload aborted: no valid agent config found"),{code:"RELOAD_UNSAFE"});const a=[];for(const{entry:c}of e)try{this.toRuntimeInstanceConfig(c,{quiet:!0})}catch(s){const l=c?.name,u=typeof l=="string"&&l.trim()?l:"<unknown>";a.push({name:u,error:s instanceof Error?s.message:String(s)})}if(a.length>0){const c=a.map(s=>`${s.name}: ${s.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${a.length} agent config(s) invalid [${c}]`),{code:"RELOAD_UNSAFE"})}const o=new Map;for(const c of e){const s=String(c.entry?.name??"").trim();s&&(o.has(s)&&p.warn("manager",`reload: duplicate agent name "${s}", last one wins`),o.set(s,c))}const i={added:[],removed:[],restarted:[],unchanged:[],failed:[]},m=new Set(this.rawConfigMap.keys());for(const c of m)if(!o.has(c))try{await this.removeAgentInternal(c),i.removed.push(c)}catch(s){i.failed.push({name:c,error:s instanceof Error?s.message:String(s)})}for(const[c,s]of o){const l=this.rawConfigMap.get(c);if(l)if(Ne(l.entry,s.entry))this.rawConfigMap.set(c,s),i.unchanged.push(c);else try{await this.replaceInstance(c,s.entry,s.file),i.restarted.push(c)}catch(u){i.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}else try{await this.addAgentInternal(s.entry,s.file),i.added.push(c)}catch(u){i.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}}return p.info("manager",`reload done: +${i.added.length} -${i.removed.length} ~${i.restarted.length} =${i.unchanged.length} !${i.failed.length}`),await this.ensureAuxServices(),i}async checkUpgrade(){return this.upgradeChecker?this.upgradeChecker.checkForUpdate():{available:!1}}triggerUpgrade(){this.upgradeChecker?.triggerCheck()}async probeAll(e={}){return qe(this.instances,e)}async probeOne(e,t={}){return He(this.instances,e,t)}listInstallable(){return this.installer.listInstallable()}async installAgent(e){const t=await this.installer.install(e);return Se(t),t}getInstallProgress(e){return this.installer.getProgress(e)??null}}async function qe(n,e){const t=e.concurrency??4,r=Date.now(),a=new Array(n.length);await new Promise(s=>{let l=0,u=0;const w=n.length;if(w===0){s();return}function d(g){const S=n[g];S.probe(e).then(v=>{a[g]=v,h()},v=>{a[g]={agent_name:S.name,client_type:"unknown",adapter_type:"acp",ok:!1,status:"error",probed_at:Date.now(),duration_ms:0,cached:!1,cli:{command:"",installed:!1,path:null,version:null,error:{code:"internal",message:v?.message??String(v)}},conversation:{attempted:!1,ok:!1,latency_ms:null},config:{model:null,base_url:null,source:{model:"unknown",base_url:"unknown"}},process:{started:!1,alive:!1,busy:!1}},h()})}function h(){u++,l<w?d(l++):u===w&&s()}const y=Math.min(t,w);for(let g=0;g<y;g++)d(l++)});const o=a.filter(s=>s.status==="healthy").length,i=a.filter(s=>s.status==="degraded").length,m=a.filter(s=>s.status==="unavailable").length,c=await $e();return{ok:o===a.length&&a.length>0,total:a.length,healthy:o,degraded:i,unavailable:m,installed_clients:c,agents:a,probed_at:r,duration_ms:Date.now()-r}}async function He(n,e,t){const r=n.find(a=>a.name===e);if(!r)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return r.probe(t)}export{mt as Manager,$e as probeInstalledClientCommands,qe as probeInstances,He as probeOneInstance};
1
+ import{readFileSync as Z,readdirSync as ee,writeFileSync as te}from"node:fs";import{join as A}from"node:path";import{homedir as ne}from"node:os";import{AgentInstance as D}from"./bridge/bridge.js";import{buildSharedInstanceConfig as re,diffSharedOwners as ae,sharedInstanceKey as ie,SharedOwnersCache as se}from"./manager-share-config.js";import{isAgentDeletedError as O}from"./core/aibot/errors.js";import{GRIX_PATHS as _,log as d}from"./core/log/index.js";import{resolveClientVersion as oe}from"./core/util/client-version.js";import{UpgradeChecker as ce}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as le}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as de}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as pe}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as me}from"./core/skill-sync/sync-state.js";import{buildLibrarySkills as ue}from"./core/skill-sync/library-skills.js";import{AUDIT_LOCAL_ACTION_TYPES as ge}from"./core/aibot/types.js";import{buildReportedSkills as fe,logDefaultSkillsCheck as he,cleanupProjectedSkills as L}from"./default-skills/index.js";import{supportsKiroCwRelay as N,supportsNonMitmRelayConfig as _e}from"./core/config/provider-env.js";import{ensureKiroRelay as H,stopKiroRelay as q}from"./core/proxy/kiro-relay.js";import{resolveCopilotCommand as U}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as B}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ye,resolveCliPath as we}from"./core/util/cli-probe.js";import{AgentInstaller as Se}from"./core/installer/installer.js";import{reportInstallFailure as ve}from"./core/observability/sentry.js";import{createDefaultAuditProducer as Ae}from"./audit/runtime/default-audit-recorder.js";import{normalizeCodexConfigOverrides as ke}from"./adapter/codex/config-overrides.js";import{resolveCodexDirectHome as be}from"./adapter/codex/direct-home.js";const Ce=8e3;function $e(){const r=U();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:B()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:r.command},{clientType:"agy",command:"agy"}]}async function xe(){return Promise.all($e().map(async r=>{const e=await we(r.command);if(!e)return{client_type:r.clientType,command:r.command,installed:!1,path:null,version:null};const t=await ye(e,r.versionArgs??["--version"]);return{client_type:r.clientType,command:r.command,installed:!0,path:e,version:t.version,error:t.error}}))}function Ie(r){switch(r){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:B()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=U();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${r}`)}}function k(r,e){return String(r??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function Te(r){return A(_.data,`session-bindings-${k(r,"unknown")}.json`)}function Ee(r,e){return A(_.data,`session-bindings-${k(r,e)}.json`)}function Pe(r,e){return A(_.data,`active-events-${k(r,e)}.json`)}function Re(r,e){const t=k(r,"agent"),n=k(e,"unknown");return A(_.data,`terminal-outbox-${t}-${n}.json`)}function je(...r){const e=[],t=new Set;for(const n of r)for(const a of n??[]){const s=String(a??"").trim(),i=s.toLowerCase();!s||t.has(i)||(t.add(i),e.push(s))}return e.length>0?e:void 0}function Me(r,e){const t={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},n=t[r]??t.acp;return{maxConcurrent:e?.max_concurrent??n.maxConcurrent??1,maxQueued:e?.max_queued??n.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??n.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function De(r,e={}){const t=oe(),n=String(r.client_type??"").trim().toLowerCase(),a=Ie(n),s=String(r.ws_url??"").trim(),i="get_session_usage",l="get_rate_limits",c="get_agent_global_config",o=ge;if(!r.name?.trim())throw new Error("agent name is required");if(!s)throw new Error(`agent ${r.name}: ws_url is required`);if(!r.agent_id?.trim())throw new Error(`agent ${r.name}: agent_id is required`);if(!r.api_key?.trim())throw new Error(`agent ${r.name}: api_key is required`);const p=a.adapterType,u=p==="acp",w=n==="qwen",m={...a.options??{}};if(r.codex_config_overrides!==void 0){if(p!=="codex")throw new Error(`agent ${r.name}: codex_config_overrides is only supported for client_type=codex`);ke(r.codex_config_overrides,`agent ${r.name}: codex_config_overrides`),m.codexConfigOverrides=r.codex_config_overrides}if(p==="codex"&&r.provider?.wire_api!==void 0){const f=r.provider;if(f.wire_api!=="responses"||!f.base_url?.trim()||!f.api_key?.trim()||!f.model?.trim()||!f.catalog_version?.trim()||!f.catalog_sha256?.trim()||!f.catalog_json?.trim())throw Object.assign(new Error(`agent ${r.name}: incomplete Codex direct relay config`),{code:"INVALID_CODEX_DIRECT_CONFIG"});const M=be(_.data,r.name);m.codexHome=M,m.codexDirect={codexHome:M,config:{baseUrl:f.base_url.trim(),model:f.model.trim(),...f.reasoning_effort?.trim()?{reasoningEffort:f.reasoning_effort.trim()}:{},token:f.api_key.trim()},catalog:{version:f.catalog_version.trim(),sha256:f.catalog_sha256.trim(),json:f.catalog_json}}}const h=p==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",i,l]}:null,y=p==="claude"?{localActions:["session_control","set_mode","set_model","set_reasoning_effort","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",i,l]}:null,g=w?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",i],adapterHint:"qwen/base"}:null,v=p==="pi"?{adapterHint:"pi/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",i,l]}:null,S=p==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,C=p==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder","thread_compact","claude_interaction_reply",l]}:null,T=p==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",i]}:null,$=p==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","claude_interaction_reply","file_list","create_folder"]}:null,x=p==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder"]}:null,E=new Set(["hermes","reasonix","kimi","copilot"]),K=u&&!E.has(n),Q=u&&!w?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",...K?[i]:[]]}:null,W=n==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",i,l]}:null,G=p==="codex"||p==="claude"||p==="opencode"||n==="gemini"?["session_control","set_model","set_mode",...p==="claude"?["set_reasoning_effort"]:[]]:void 0,z=p==="cursor"||p==="opencode"||p==="openhuman"||p==="agy"||u&&E.has(n)?[l]:[i,l];u&&m.raw_transport===void 0&&(m.raw_transport=n==="gemini");const V=`${n}/base`,I=pe(p,n),J=I==="kiro"?void 0:process.cwd(),P=fe({mode:I,projectDir:J}),R=P.filter(f=>f.source==="connector").map(f=>f.name);R.length>0&&!e.quiet&&d.info("manager",`[${r.name}] injecting connector skills: [${R.join(", ")}]`);const j=me(P,_.skills);let X=j.length>0?j:void 0;const Y=ue({skillsDir:_.skills,mode:I,home:ne()});return{name:r.name,adapterType:p,aibot:{url:s,agentId:r.agent_id,apiKey:r.api_key,clientType:n,clientVersion:t,adapterHint:a.adapterHint??g?.adapterHint??v?.adapterHint??S?.adapterHint??C?.adapterHint??$?.adapterHint??x?.adapterHint??V,capabilities:h?.capabilities??T?.capabilities??v?.capabilities??S?.capabilities??C?.capabilities??$?.capabilities??x?.capabilities??g?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:je(h?.localActions??T?.localActions??y?.localActions??v?.localActions??S?.localActions??C?.localActions??$?.localActions??x?.localActions??g?.localActions??W?.localActions??Q?.localActions??["exec_approve","exec_reject"],G,z,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload","skill_enable","skill_disable","skill_refresh",...o]),skills:X,librarySkills:Y,terminalOutboxPath:Re(r.name,r.agent_id)},agent:{command:a.command,args:[...a.args??[],...r.args??[]],env:r.env,clientType:n,...r.provider?{provider:{...r.provider.provider_id?.trim()?{providerId:r.provider.provider_id.trim()}:{},...r.provider.base_url?.trim()?{baseUrl:r.provider.base_url.trim()}:{},...r.provider.quota_base_url?.trim()?{quotaBaseUrl:r.provider.quota_base_url.trim()}:{},...r.provider.api_key?.trim()?{apiKey:r.provider.api_key.trim()}:{},...r.provider.model?.trim()?{model:r.provider.model.trim()}:{},...r.provider.fast_model?.trim()?{fastModel:r.provider.fast_model.trim()}:{},...r.provider.effort?.trim()?{effort:r.provider.effort.trim()}:{}}}:{}},adapterOptions:m,acpAuthMethod:m.auth_method,acpInitialMode:m.initial_mode,acpMcpTools:m.acp_mcp_tools,promptTimeoutMs:r.prompt_timeout_ms,bindingsPath:Te(r.agent_id),legacyBindingsPath:Ee(r.name,r.agent_id),activeEventStorePath:Pe(r.name,r.agent_id),...a.enableSessionBinding||u?{enableSessionBinding:!0}:{},...a.autoInjectArgs||n==="reasonix"&&r.provider?.model?.trim()?{autoInjectArgs:{...a.autoInjectArgs??{},...n==="reasonix"&&r.provider?.model?.trim()?{model:r.provider.model.trim()}:{}}}:{},poolMaxSize:r.pool?.maxSize,poolIdleTimeoutMs:r.pool?.idleTimeoutMs,eventQueue:Me(p,r.event_queue),logDir:_.log,providerBaseUrl:r.provider_base_url?.trim()||void 0,providerApiKey:r.provider_api_key?.trim()||void 0}}function Oe(){const r=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(r);return Number.isFinite(e)&&e>=500?Math.floor(e):Ce}function F(r){const e=[],t=[],n=[],a=ee(r).filter(s=>s.endsWith(".json")).sort();for(const s of a)try{const i=JSON.parse(Z(A(r,s),"utf-8"));if(i===null||typeof i!="object"||Array.isArray(i)||!("agents"in i)){n.push(s);continue}if(!Array.isArray(i.agents)){t.push({file:s,error:"agents is not an array"});continue}if(i.agents.length===0){t.push({file:s,error:"agents array is empty"});continue}for(const l of i.agents)e.push({entry:l,file:s})}catch(i){t.push({file:s,error:i instanceof Error?i.message:String(i)})}return{entries:e,fileErrors:t,skipped:n}}function b(r){if(r===null||typeof r!="object")return JSON.stringify(r)??"null";if(Array.isArray(r))return`[${r.map(b).join(",")}]`;const e=r;return`{${Object.keys(e).sort().map(n=>`${JSON.stringify(n)}:${b(e[n])}`).join(",")}}`}function Le(r,e){return b(r)===b(e)}class mt{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=_.config;sharedOwnersCache=new se(_.data);installer=new Se;relaySecretResolver;auditProducer=Ae();async start(e){const t=e??_.config;this.configDir=t,d.info("manager",`Loading configs from ${t}`),he(),L(),this.globalConfigStore=new de(A(_.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:n,fileErrors:a,skipped:s}=F(t);for(const o of a)d.error("manager",`Failed to load ${o.file}: ${o.error}`);for(const o of s)d.info("manager",`Skipped ${o}: not an agent config (no "agents" key)`);if(n.length===0&&a.length===0&&s.length===0){d.warn("manager",`No config files found in ${t}; daemon idle (waiting for config). Add agents under this directory then run: grix-connector reload`);return}const i=[];let l=a.length;for(const{entry:o,file:p}of n)try{const u=this.toRuntimeInstanceConfig(o);i.push({config:u,entry:o,file:p}),d.info("manager",`Loaded ${u.name} (${u.adapterType??"acp"}) from ${p}`)}catch(u){const w=typeof o?.name=="string"?o.name:"<unknown>";d.error("manager",`Invalid agent config in ${p} (name=${w}): ${u}`),l++}let c=0;if(i.length>0){const o=Oe();d.info("manager",`Starting ${i.length} agent(s), startup wait=${o}ms`);const p=m=>{this.instances=this.instances.filter(h=>h!==m)},u=i.map(({config:m,entry:h,file:y})=>{const g=this.createConfiguredInstance(m);return this.instances.push(g),this.configMap.set(m.name,m),this.rawConfigMap.set(m.name,{entry:h,file:y}),{config:m,instance:g,startPromise:this.prepareProviderRuntime(m,h).then(()=>g.start())}}),w=await Promise.all(u.map(async m=>{const h=await new Promise(y=>{let g=!1;const v=setTimeout(()=>{g||(g=!0,y({kind:"timeout"}))},o);m.startPromise.then(()=>{g||(g=!0,clearTimeout(v),y({kind:"started"}))}).catch(S=>{g||(g=!0,clearTimeout(v),y({kind:"failed",error:S}))})});return{task:m,outcome:h}}));for(const{task:m,outcome:h}of w){if(h.kind==="started"){this.restoreCachedSharedInstances(m.config);continue}if(h.kind==="failed"){if(O(h.error)){this.onAgentDeletedByPlatform(m.config.name);continue}p(m.instance),d.error("manager",`Failed to start ${m.config.name}: ${h.error}`);continue}c++,d.warn("manager",`Startup pending for ${m.config.name}, continue retrying in background`),m.startPromise.then(()=>{d.info("manager",`Delayed start succeeded: ${m.config.name}`),this.restoreCachedSharedInstances(m.config)}).catch(y=>{if(O(y)){this.onAgentDeletedByPlatform(m.config.name);return}p(m.instance),d.error("manager",`Delayed start failed: ${m.config.name}: ${y}`)})}if(this.instances.length>0){const m=Math.max(0,this.instances.length-c);d.info("manager",`${m}/${i.length} agent(s) running now`)}c>0&&d.warn("manager",`${c} agent(s) still connecting in background`)}if(this.instances.length===0&&i.length>0)throw new Error("All agent configurations failed to start");await this.ensureAuxServices()}async ensureAuxServices(){if(this.configMap.size===0)return;const e=[...this.configMap.values()].map(t=>({apiKey:t.aibot.apiKey,wsUrl:t.aibot.url}));this.upgradeChecker||(this.upgradeChecker=new ce(e,()=>this.instances.some(t=>t.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(t=>t.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),this.skillSyncer||(this.skillSyncer=new le(e,_.skills),this.skillSyncer.setOnSyncSuccess(()=>this.refreshOwnerLibrarySkills()),await this.skillSyncer.start())}refreshOwnerLibrarySkills(){const e=new Map,t=n=>{let a;try{a=n.skillsSyncGroupKey()}catch(i){d.warn("manager",`skillsSyncGroupKey failed for ${n.name}: ${i}`);return}const s=e.get(a)??[];s.push(n),e.set(a,s)};for(const n of this.instances)t(n);for(const n of this.sharedInstances.values())t(n);for(const[n,a]of e){let s=!1;const i=[];for(const l of a){if(s){i.push(l);continue}let c=!1;try{c=l.forceRefreshSkills(void 0,{force:!0,ownerLibrarySync:!0})===!0}catch(o){d.warn("manager",`owner library skills reporter threw group=${n} agent=${l.name}: ${o}`)}if(c){s=!0;continue}d.warn("manager",`owner library skills reporter failed group=${n} agent=${l.name}; trying next`)}if(!s){d.warn("manager",`owner library skills: no reporter succeeded group=${n}`);continue}for(const l of i)try{l.adoptSkillsWireHashFromDisk()}catch(c){d.warn("manager",`adoptSkillsWireHashFromDisk failed for ${l.name}: ${c}`)}}}async stop(){d.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(t=>t.stop()),...e.map(t=>t.stop())]),await this.globalConfigStore?.flush(),await this.auditProducer.stop({timeoutMs:5e3}).catch(()=>!1),this.instances=[],L(),d.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const a=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,a)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:n,toRemove:a}=ae(e.name,this.sharedInstances.keys(),t);for(const s of n){if(this.stopping)break;const i=ie(e.name,s);try{const l=re(e,s),c=new D(l,this.globalConfigStore,this.auditProducer);this.sharedInstances.set(i,c),await c.start(),c.forceRefreshSkills(void 0,{force:!0}),d.info("manager",`shared instance started: ${i}`)}catch(l){this.sharedInstances.delete(i);const c=l instanceof Error?l.message:String(l);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,s),d.warn("manager",`shared instance auth rejected, removed from cache: ${i}`)):d.error("manager",`start shared instance failed ${i}: ${l}`)}}for(const{key:s}of a){const i=this.sharedInstances.get(s);i&&(this.sharedInstances.delete(s),i.stop().catch(l=>d.error("manager",`stop shared instance failed ${s}: ${l}`)),d.info("manager",`shared instance stopped: ${s}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(d.info("manager",`restoring ${t.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,t))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),await this.ensureAuxServices(),d.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const n=this.toRuntimeInstanceConfig(e);if(this.instances.some(a=>a.name===n.name))throw new Error(`Agent "${n.name}" already exists`);await this.startInstanceFromConfig(n,e,t)}createConfiguredInstance(e){const t=new D(e,this.globalConfigStore,this.auditProducer);return t.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),t.setShareSetHandler(n=>this.onShareSet(e,n)),t.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),t.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),t.setProviderConfigHandler(n=>this.setAgentProvider(e.name,n)),t.setRelayStateApplyPorts({getLocalState:()=>this.relayStateApplier?.getLocalState(e.name)??{enabled:!1},applyEnable:(n,a)=>{const s=this.relayStateApplier;return s?s.applyEnable(e.name,n,a):Promise.reject(new Error("relay state applier is not configured"))},applyDisable:()=>{const n=this.relayStateApplier;return n?n.applyDisable(e.name):Promise.reject(new Error("relay state applier is not configured"))}}),t.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),t.setProviderResolver(()=>this.getAgentProvider(e.name)),t}async prepareProviderRuntime(e,t){const n=this.resolveAgentProvider(t.provider);N(t.client_type)&&n?.base_url?.trim()&&n?.api_key?.trim()&&n?.model?.trim()&&await H(e.name,{baseUrl:n.base_url.trim(),apiKey:n.api_key.trim(),model:n.model.trim()})}async startInstanceFromConfig(e,t,n){await this.prepareProviderRuntime(e,t);const a=this.createConfiguredInstance(e);await a.start(),this.instances.push(a),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:n}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(t=>t.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),d.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const n=this.instances.findIndex(l=>l.name===e),a=n===-1?void 0:this.instances[n];n!==-1&&this.instances.splice(n,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const s=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),s&&await s.catch(()=>{});const i=`${e}#shared:`;for(const[l,c]of[...this.sharedInstances.entries()])l.startsWith(i)&&(this.sharedInstances.delete(l),c.stop().catch(o=>d.error("manager",`stop shared instance failed ${l}: ${o}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),a&&await a.stop(),t?.keepShareCache||await q(e).catch(()=>{})}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(n=>n.name===e)))return;d.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),d.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(t){d.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=A(this.configDir,"agents.json");try{const t=[];for(const[,a]of this.configMap){const s=this.rawConfigMap.get(a.name)?.entry.provider;t.push({name:a.name,ws_url:a.aibot.url,agent_id:a.aibot.agentId,api_key:a.aibot.apiKey,client_type:a.aibot.clientType,...s?{provider:s}:{}})}te(e,JSON.stringify({agents:t},null,4)+`
2
+ `,"utf-8")}catch(t){d.error("manager",`Failed to persist agents config: ${t}`)}}isAgentBusy(e){return this.instances.find(n=>n.name===e)?.hasPendingWork()??!1}getAgentsWithStaleRelayEnv(){return this.instances.filter(e=>e.hasStaleRelayEnv()).map(e=>e.name)}markAgentRelayEnvStale(e){const t=this.instances.find(n=>n.name===e);return t?(t.markRelayEnvStale(),!0):!1}relayEnvSettledHandler;setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}relayStateApplier;setRelayStateApplier(e){this.relayStateApplier=e}reportRelayStateLocalChange(e){this.instances.find(n=>n.name===e)?.reportRelayStateLocalChange()}setRelaySecretResolver(e){this.relaySecretResolver=e}resolveAgentProvider(e){if(!e?.api_key_ref?.trim())return e;const t=e.api_key_ref.trim(),n=this.relaySecretResolver?.(t);if(!n)throw Object.assign(new Error(`relay credential "${t}" is unavailable`),{code:"RELAY_SECRET_UNAVAILABLE"});return{...e,api_key:n}}toRuntimeInstanceConfig(e,t={}){const n=this.resolveAgentProvider(e.provider);return De(n===e.provider?e:{...e,provider:n},t)}getAgentProvider(e){return this.resolveAgentProvider(this.rawConfigMap.get(e)?.entry.provider)}async restartAgent(e){const t=this.rawConfigMap.get(e);if(!t)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.replaceInstance(e,t.entry,t.file),d.info("manager",`Restarted agent: ${e}`)}async setAgentProvider(e,t,n){const a=this.rawConfigMap.get(e);if(!a)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});const s=String(a.entry.client_type??"").trim().toLowerCase();N(s)&&(t?.base_url?.trim()&&t?.api_key?.trim()&&t?.model?.trim()?await H(e,{baseUrl:t.base_url.trim(),apiKey:t.api_key.trim(),model:t.model.trim()}):await q(e));const i=t?.api_key_ref?.trim()?Object.fromEntries(Object.entries(t).filter(([c])=>c!=="api_key")):t,l={...a.entry,provider:i};if(n?.deferRestart){this.rawConfigMap.set(e,{...a,entry:l}),this.instances.find(c=>c.name===e)?.markRelayEnvStale(),this.persistAgentsConfig(),d.info("manager",`Updated provider config for agent (deferred restart): ${e}`);return}await this.replaceInstance(e,l,a.file),this.persistAgentsConfig(),d.info("manager",`Updated provider config for agent: ${e}`)}hasDirectRelayConfig(e){const t=this.rawConfigMap.get(e)?.entry.provider;return!!(t?.api_key_ref?.trim()||t?.api_key?.trim())}getDirectRelayConfigAgentNames(){return[...this.rawConfigMap.entries()].filter(([,e])=>!!e.entry.provider&&(_e(e.entry.client_type)||["claude","codex"].includes(String(e.entry.client_type??"").trim().toLowerCase()))).map(([e])=>e)}async fetchRelayCredential(e,t){const n=this.instances.find(a=>a.name===e);if(!n)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return n.fetchRelayCredential(t)}async clearDirectProviderConfigs(){const e=this.getDirectRelayConfigAgentNames(),t=[];for(const n of e)try{await this.setAgentProvider(n,void 0,{deferRestart:this.isAgentBusy(n)}),t.push(n)}catch(a){d.warn("manager",`Failed to clear provider config for "${n}": ${a instanceof Error?a.message:String(a)}`)}return t}async replaceInstance(e,t,n){const a=this.toRuntimeInstanceConfig(t);await this.removeAgentInternal(e,{keepShareCache:!0}),await this.startInstanceFromConfig(a,t,n),this.restoreCachedSharedInstances(a)}async reload(){const e=this.reloadChain.catch(()=>{}).then(()=>this.doReload());return this.reloadChain=e.catch(()=>{}),e}async doReload(){if(this.stopping)throw Object.assign(new Error("manager is stopping"),{code:"RELOAD_UNSAFE"});const{entries:e,fileErrors:t,skipped:n}=F(this.configDir);for(const c of n)d.info("manager",`reload: skipped ${c}: not an agent config (no "agents" key)`);if(t.length>0){const c=t.map(o=>`${o.file}: ${o.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${t.length} config file(s) failed to parse [${c}]`),{code:"RELOAD_UNSAFE"})}if(e.length===0)throw Object.assign(new Error("reload aborted: no valid agent config found"),{code:"RELOAD_UNSAFE"});const a=[];for(const{entry:c}of e)try{this.toRuntimeInstanceConfig(c,{quiet:!0})}catch(o){const p=c?.name,u=typeof p=="string"&&p.trim()?p:"<unknown>";a.push({name:u,error:o instanceof Error?o.message:String(o)})}if(a.length>0){const c=a.map(o=>`${o.name}: ${o.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${a.length} agent config(s) invalid [${c}]`),{code:"RELOAD_UNSAFE"})}const s=new Map;for(const c of e){const o=String(c.entry?.name??"").trim();o&&(s.has(o)&&d.warn("manager",`reload: duplicate agent name "${o}", last one wins`),s.set(o,c))}const i={added:[],removed:[],restarted:[],unchanged:[],failed:[]},l=new Set(this.rawConfigMap.keys());for(const c of l)if(!s.has(c))try{await this.removeAgentInternal(c),i.removed.push(c)}catch(o){i.failed.push({name:c,error:o instanceof Error?o.message:String(o)})}for(const[c,o]of s){const p=this.rawConfigMap.get(c);if(p)if(Le(p.entry,o.entry))this.rawConfigMap.set(c,o),i.unchanged.push(c);else try{await this.replaceInstance(c,o.entry,o.file),i.restarted.push(c)}catch(u){i.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}else try{await this.addAgentInternal(o.entry,o.file),i.added.push(c)}catch(u){i.failed.push({name:c,error:u instanceof Error?u.message:String(u)})}}return d.info("manager",`reload done: +${i.added.length} -${i.removed.length} ~${i.restarted.length} =${i.unchanged.length} !${i.failed.length}`),await this.ensureAuxServices(),i}async checkUpgrade(){return this.upgradeChecker?this.upgradeChecker.checkForUpdate():{available:!1}}triggerUpgrade(){this.upgradeChecker?.triggerCheck()}async probeAll(e={}){return Ne(this.instances,e)}async probeOne(e,t={}){return He(this.instances,e,t)}listInstallable(){return this.installer.listInstallable()}async installAgent(e){const t=await this.installer.install(e);return ve(t),t}getInstallProgress(e){return this.installer.getProgress(e)??null}}async function Ne(r,e){const t=e.concurrency??4,n=Date.now(),a=new Array(r.length);await new Promise(o=>{let p=0,u=0;const w=r.length;if(w===0){o();return}function m(g){const v=r[g];v.probe(e).then(S=>{a[g]=S,h()},S=>{a[g]={agent_name:v.name,client_type:"unknown",adapter_type:"acp",ok:!1,status:"error",probed_at:Date.now(),duration_ms:0,cached:!1,cli:{command:"",installed:!1,path:null,version:null,error:{code:"internal",message:S?.message??String(S)}},conversation:{attempted:!1,ok:!1,latency_ms:null},config:{model:null,base_url:null,source:{model:"unknown",base_url:"unknown"}},process:{started:!1,alive:!1,busy:!1}},h()})}function h(){u++,p<w?m(p++):u===w&&o()}const y=Math.min(t,w);for(let g=0;g<y;g++)m(p++)});const s=a.filter(o=>o.status==="healthy").length,i=a.filter(o=>o.status==="degraded").length,l=a.filter(o=>o.status==="unavailable").length,c=await xe();return{ok:s===a.length&&a.length>0,total:a.length,healthy:s,degraded:i,unavailable:l,installed_clients:c,agents:a,probed_at:n,duration_ms:Date.now()-n}}async function He(r,e,t){const n=r.find(a=>a.name===e);if(!n)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return n.probe(t)}export{mt as Manager,xe as probeInstalledClientCommands,Ne as probeInstances,He as probeOneInstance};
@@ -1 +1 @@
1
- import*as i from"node:net";const e={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function n(o){const u={bind:o?.bind??e.bind,port:o?.port??e.port,endpoint:o?.endpoint??e.endpoint,sessionTimeoutMs:o?.sessionTimeoutMs??e.sessionTimeoutMs,invokeTimeoutMs:o?.invokeTimeoutMs??e.invokeTimeoutMs,allowedOrigins:o?.allowedOrigins,allowedHosts:o?.allowedHosts};return s(u.bind),u.port!==0&&t(u.port),r(u.sessionTimeoutMs),u}function s(o){if(!o||!i.isIPv4(o)&&!i.isIPv6(o))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${o}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function t(o){if(!Number.isInteger(o)||o<1||o>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(o){if(!Number.isInteger(o)||o<1e3||o>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{n as createDefaultGatewayConfig};
1
+ import*as n from"node:net";const i={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function s(u){const e={bind:u?.bind??i.bind,port:u?.port??i.port,endpoint:u?.endpoint??i.endpoint,sessionTimeoutMs:u?.sessionTimeoutMs??i.sessionTimeoutMs,invokeTimeoutMs:u?.invokeTimeoutMs??i.invokeTimeoutMs,allowedOrigins:u?.allowedOrigins,allowedHosts:u?.allowedHosts};return t(e.bind),e.port!==0&&o(e.port),r(e.sessionTimeoutMs),e}function t(u){if(!u||!n.isIPv4(u)&&!n.isIPv6(u))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${u}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function o(u){if(!Number.isInteger(u)||u<1||u>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(u){if(!Number.isInteger(u)||u<1e3||u>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${u} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{s as createDefaultGatewayConfig};
@@ -1 +1 @@
1
- const r=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
1
+ const a=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
@@ -1 +1 @@
1
- function a(t){const o=new Set([`http://127.0.0.1:${t.serverPort}`,`http://localhost:${t.serverPort}`,...t.allowedOrigins]),e=new Set([`127.0.0.1:${t.serverPort}`,`localhost:${t.serverPort}`,...t.allowedHosts]);return{validateRequest(s){const r=i(s,o);if(!r.ok)return r;const n=l(s,e);return n.ok?{ok:!0}:n}}}function i(t,o){const e=t.headers.origin;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${e}`}:{ok:!0}}function l(t,o){const e=t.headers.host;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${e}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
1
+ function a(e){const t=new Set([`http://127.0.0.1:${e.serverPort}`,`http://localhost:${e.serverPort}`,...e.allowedOrigins]),o=new Set([`127.0.0.1:${e.serverPort}`,`localhost:${e.serverPort}`,...e.allowedHosts]);return{validateRequest(s){const r=i(s,t);if(!r.ok)return r;const n=l(s,o);return n.ok?{ok:!0}:n}}}function i(e,t){const o=e.headers.origin;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${o}`}:{ok:!0}}function l(e,t){const o=e.headers.host;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${o}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
@@ -1 +1 @@
1
- import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(t,e,r,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,r);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(t.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${t.status}`);if(p(e))return this.executeEventTool(t,e,r);const o=i(e,r);try{const u=await t.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(t){if(t==null||typeof t!="object")return this.successResult(t??null);const e=t,r=typeof e.code=="number"?e.code:0;if(r===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${r}]: ${n}`)}successResult(t){return{content:[{type:"text",text:JSON.stringify(t)}],isError:!1}}errorResult(t){return{content:[{type:"text",text:t}],isError:!0}}async executeEventTool(t,e,r){return e==="grix_access_control"?this.executeAccessControl(t,r):d(t,e,r)}async executeAccessControl(t,e){const r=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[r];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${r}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await t.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
1
+ import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(r,e,t,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,t);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(r.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${r.status}`);if(p(e))return this.executeEventTool(r,e,t);const o=i(e,t);try{const u=await r.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(r){if(r==null||typeof r!="object")return this.successResult(r??null);const e=r,t=typeof e.code=="number"?e.code:0;if(t===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${t}]: ${n}`)}successResult(r){return{content:[{type:"text",text:JSON.stringify(r)}],isError:!1}}errorResult(r){return{content:[{type:"text",text:r}],isError:!0}}async executeEventTool(r,e,t){return e==="grix_access_control"?this.executeAccessControl(r,t):d(r,e,t)}async executeAccessControl(r,e){const t=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[t];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${t}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await r.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
@@ -1 +1 @@
1
- import{TOOLS as s,EVENT_TOOLS as t}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...s.filter(o=>e.has(o.name)),...t.filter(o=>r.has(o.name))],this.toolMap=new Map(this.tools.map(o=>[o.name,o]))}getTools(){return this.tools}getTool(o){return this.toolMap.get(o)}hasTool(o){return this.toolMap.has(o)}}export{a as ToolRegistryImpl};
1
+ import{TOOLS as o,EVENT_TOOLS as s}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...o.filter(t=>e.has(t.name)),...s.filter(t=>r.has(t.name))],this.toolMap=new Map(this.tools.map(t=>[t.name,t]))}getTools(){return this.tools}getTool(t){return this.toolMap.get(t)}hasTool(t){return this.toolMap.has(t)}}export{a as ToolRegistryImpl};
@@ -1 +1 @@
1
- const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(u,t){const e=C[u];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${u}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,r]of Object.entries(t)){if(r==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,r,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(u,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${u} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${u} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const r=t[i];if(e.items.type==="string"&&typeof r!="string")return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.type==="integer"){if(typeof r!="number"||!Number.isInteger(r))return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.enum&&!e.items.enum.includes(r))return`\u53C2\u6570 ${u}[${i}] \u503C ${r} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
1
+ const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(r,t){const e=C[r];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${r}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,u]of Object.entries(t)){if(u==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,u,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(r,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${r} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${r} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${r} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${r} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${r} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${r} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${r} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const u=t[i];if(e.items.type==="string"&&typeof u!="string")return`\u53C2\u6570 ${r}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof u}`;if(e.items.type==="integer"){if(typeof u!="number"||!Number.isInteger(u))return`\u53C2\u6570 ${r}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof u}`;if(e.items.enum&&!e.items.enum.includes(u))return`\u53C2\u6570 ${r}[${i}] \u503C ${u} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "3.26.2",
3
+ "version": "3.26.3",
4
4
  "description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,6 +8,8 @@
8
8
  "grix-connector": "dist/grix.js"
9
9
  },
10
10
  "files": [
11
+ "NOTICE",
12
+ "LICENSE",
11
13
  "dist",
12
14
  "!dist/**/*.map",
13
15
  "!dist/**/*.d.ts",
@@ -76,7 +78,7 @@
76
78
  "bugs": {
77
79
  "url": "https://github.com/askie/grix-connector/issues"
78
80
  },
79
- "license": "MIT",
81
+ "license": "Apache-2.0",
80
82
  "devDependencies": {
81
83
  "@types/node": "^25.6.0",
82
84
  "@types/node-forge": "^1.3.14",