grix-connector 4.6.10 → 4.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,19 @@
1
- import{spawn as R}from"node:child_process";import{randomUUID as P}from"node:crypto";import{EventEmitter as T}from"node:events";import{existsSync as A,readFileSync as I,statSync as G,mkdirSync as $,writeFileSync as M,realpathSync as L}from"node:fs";import{homedir as _}from"node:os";import{join as m,dirname as O,resolve as j}from"node:path";import{fileURLToPath as D}from"node:url";import{log as a}from"../../core/log/index.js";import{killProcessGroup as y}from"../../core/runtime/spawn.js";import{InternalApiServer as B}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as N,pruneLegacyMcpServerEntries as K}from"../../core/mcp/server-name.js";import{syncDefaultSkillsToDir as W}from"../../default-skills/index.js";import{buildSimpleProbeReport as Q}from"../shared/probe-util.js";import{getAgyModelCatalog as V,resolveAgyModelFlag as Y}from"./model-list.js";const c="agy-adapter";function q(g){try{return process.kill(g,0),!0}catch(t){return t.code==="EPERM"}}function F(g){try{return L(g)}catch{return g}}const k=m(_(),".gemini","antigravity-cli","log"),H="CLI store manager shutting down",U=5e3,w=15e3,J="30m",C=m(_(),".gemini","antigravity-cli","cache","last_conversations.json"),z=["\u4F60\u63A5\u5165\u7684\u662F Grix \u804A\u5929\u3002\u7528\u6237\u6D88\u606F\u88AB\u5305\u5728 <channel ...> \u6807\u7B7E\u91CC\uFF0C\u6807\u7B7E\u5C5E\u6027\u643A\u5E26\u672C\u8F6E\u4E0A\u4E0B\u6587\uFF1A","chat_id\uFF08\u5F53\u524D\u4F1A\u8BDD\uFF09\u3001agent_id\uFF08\u5F53\u524D Agent\uFF09\u3001event_id\uFF08\u672C\u8F6E\u4E8B\u4EF6\uFF09\u3001message_id\uFF08\u7528\u6237\u8FD9\u6761\u6D88\u606F\u7684 ID\uFF09\u3001user_id\uFF08\u53D1\u9001\u8005\uFF09\u3002","\u91CD\u8981\uFF1A\u4F60\u7684\u56DE\u590D\u5FC5\u987B\u8C03\u7528 grix \u7684 `grix_message_send` \u5DE5\u5177\u53D1\u9001\uFF08sessionId \u53D6\u81EA channel \u7684 chat_id\uFF0Ccontent \u4E3A\u4F60\u7684\u56DE\u590D\u5185\u5BB9\uFF09\uFF0C","\u4E0D\u8981\u53EA\u628A\u7B54\u6848\u6253\u5370\u5230\u6807\u51C6\u8F93\u51FA\u2014\u2014\u53EA\u6709\u8C03\u7528\u5DE5\u5177\u624D\u4F1A\u628A\u6D88\u606F\u771F\u6B63\u53D1\u7ED9\u7528\u6237\u3002","grix_message_send \u4F1A\u8FD4\u56DE\u4F60\u521A\u53D1\u51FA\u6D88\u606F\u7684 msg_id\u3002\u9700\u8981\u65F6\u4F60\u53EF\u4EE5\u7528\u8FD9\u4E2A ID \u505A\u540E\u7EED\u64CD\u4F5C\uFF0C\u4F8B\u5982\u8C03\u7528 grix_message_unsend\uFF08\u4F20 msgId\uFF09\u64A4\u56DE\u67D0\u6761\u6D88\u606F\u3002","\u8FDB\u7A0B\u5B89\u5168\uFF1A\u542F\u52A8\u4E34\u65F6\u6216\u6F14\u793A\u670D\u52A1\u65F6\u5FC5\u987B\u8BB0\u5F55\u5176 PID\uFF0C\u505C\u6B62\u65F6\u53EA\u7EC8\u6B62\u5DF2\u786E\u8BA4\u5C5E\u4E8E\u672C\u4EFB\u52A1\u7684\u8BE5 PID \u6216\u5176\u4E13\u5C5E\u8FDB\u7A0B\u7EC4\u3002","\u7981\u6B62\u4F7F\u7528 `pkill`\u3001`killall` \u6216\u5176\u4ED6\u6309\u540D\u79F0/\u547D\u4EE4\u884C\u6A21\u5F0F\u6279\u91CF\u6740\u8FDB\u7A0B\u7684\u547D\u4EE4\uFF1B\u7EDD\u4E0D\u80FD\u7EC8\u6B62 Grix MCP\u3001\u5F53\u524D agy \u6216\u5176\u7236\u8FDB\u7A0B\u3001connector \u6216\u5176\u4ED6\u65E0\u5173\u8FDB\u7A0B\u3002"].join(""),X=new Set(["send_msg","grix_reply"]),Z=new Set(["send_msg","grix_reply","delete_msg","session_send","grix_complete","grix_composing","grix_event_ack"]);function b(g){try{return structuredClone(g)}catch{return}}class gt extends T{type="agy";config;callbacks;runtimeResolver;alive=!1;stopped=!1;internalApi=null;activeEventId=null;activeEventSessionId=null;activeProcess=null;completedEventIds=new Set;activeEventSentViaTool=!1;auditCaptures=new Map;completedAuditBoundaries=new Map;watchdogPollTimer=null;watchdogGraceTimer=null;watchdogKilledActiveProcess=!1;sessionConversationMap=new Map;conversationOutputCache=new Map;eventQueue=[];systemInstructionInjectedSessions=new Set;identityInjectedSessions=new Set;constructor(t,e,i){super(),this.config=t,this.callbacks=e,this.runtimeResolver=i}async start(){this.alive||(this.alive=!0,this.stopped=!1,await this.startInternalApiAndInjectMcp(),a.info(c,"AgyAdapter started"))}async startInternalApiAndInjectMcp(){try{this.internalApi=new B,this.internalApi.setInvokeHandler(async(n,d,h,p)=>this.handleToolInvoke(n,d,p)),await this.internalApi.start(0),a.info(c,`Internal API started at ${this.internalApi.url}`);const t=this.getMcpConfig(),e=m(_(),".gemini","config","mcp_config.json");$(O(e),{recursive:!0});let i={};try{A(e)&&(i=JSON.parse(I(e,"utf8")))}catch{}const s=i.mcpServers&&typeof i.mcpServers=="object"?i.mcpServers:{};K(s,this.internalApi.url),s[t.name]={command:t.command,args:t.args},i.mcpServers=s,M(e,`${JSON.stringify(i,null,2)}
2
- `,"utf8"),a.info(c,`MCP config injected into ${e}`);const r=m(_(),".gemini","skills"),o=W(r);o.length>0&&a.info(c,`Synced connector skills to ${r}: [${o.join(", ")}]`)}catch(t){a.warn(c,`Failed to start MCP tools (non-fatal): ${t instanceof Error?t.message:String(t)}`)}}async handleToolInvoke(t,e,i){let s=e;Z.has(t)&&this.activeEventSessionId&&(s.session_id==null||s.session_id==="")&&(s={...s,session_id:this.activeEventSessionId});const r=this.activeEventId?this.auditCaptures.get(this.activeEventId):void 0,o=r?{sequence:r.toolInvocations.length,observedAt:new Date().toISOString(),action:t,params:b(s)}:void 0;r&&o&&r.toolInvocations.push(o);try{const n=await this.callbacks.agentInvoke(t,s,i);return o&&(o.completedAt=new Date().toISOString(),o.result=b(n)),X.has(t)&&this.activeEventId&&(this.activeEventSentViaTool=!0),n}catch(n){throw o&&(o.completedAt=new Date().toISOString(),o.error=n instanceof Error?n.message:String(n)),n}}async stop(){if(!this.stopped){if(this.stopped=!0,this.alive=!1,this.stopTurnWatchdog(),this.watchdogKilledActiveProcess=!1,this.activeProcess){try{y(this.activeProcess,"SIGKILL")}catch{}this.activeProcess=null}if(this.activeEventId&&this.activeEventSessionId)try{this.callbacks.sendEventResult(this.activeEventId,"canceled","adapter stopped")}catch{}if(this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.activeEventId=null,this.activeEventSessionId=null,this.internalApi){try{await this.internalApi.stop()}catch{}this.internalApi=null}this.emit("exit",0),a.info(c,"AgyAdapter stopped")}}isAlive(){return this.alive}async createSession(t){return t.cwd??P()}async resumeSession(t,e){}async destroySession(t){this.systemInstructionInjectedSessions.delete(t),this.identityInjectedSessions.delete(t)}onAgentProfileChanged(){this.identityInjectedSessions.clear()}sendPrompt(t){const e=new T;return e.adapterSessionId=t.adapterSessionId,e.cancel=async()=>{e.emit("done",{status:"canceled"})},e}async cancel(t){}cancelCurrentRun(){if(!this.activeEventId||!this.activeProcess)return;const t=this.activeEventId;a.info(c,`cancelCurrentRun: killing process group for event ${t}`);try{y(this.activeProcess,"SIGKILL")}catch{}this.activeProcess=null,this.callbacks.sendEventResult(t,"canceled","restarted by user"),this.clearActiveEvent(t),this.drainQueue()}deliverInboundEvent(t){if(!this.stopped){if(this.completedEventIds.has(t.event_id)){a.debug(c,`Skipping duplicate event: ${t.event_id}`);return}if(this.callbacks.sendEventAck(t.event_id,t.session_id),this.activeEventId){a.info(c,`Queuing event ${t.event_id} (active: ${this.activeEventId})`),this.eventQueue.push(t);return}this.processEvent(t)}}deliverStopEvent(t,e){if(this.activeEventId===t&&this.activeProcess){a.info(c,`Stopping event ${t}`);try{y(this.activeProcess,"SIGKILL")}catch{}this.activeProcess=null,this.callbacks.sendEventResult(t,"canceled","stopped by user"),this.clearActiveEvent(t),this.drainQueue()}}setPermissionHandler(){}async ping(t){if(this.stopped||!this.alive||!this.internalApi)return!1;const e=this.activeProcess;if(!e)return!0;if(!e.pid||!q(e.pid))return!1;const i=!!(e.stdout&&!e.stdout.destroyed),s=!!(e.stderr&&!e.stderr.destroyed);return i&&s}getStatus(){return{alive:this.alive,busy:this.activeEventId!==null,sessions:this.sessionConversationMap.size}}async probe(t){const e=this.getStatus();return Q(this.config.command||"agy",{alive:e.alive,busy:e.busy,started:e.alive},t)}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}takeAuditBoundary(t){const e=this.completedAuditBoundaries.get(t);return e&&this.completedAuditBoundaries.delete(t),e}snapshotAuditBoundary(t){const e=this.auditCaptures.get(t);if(!e)return;this.auditCaptures.delete(t);let i;if(e.logPath)try{i=G(e.logPath).size}catch{}const s=this.sessionConversationMap.get(e.sessionId)??e.conversationId;this.completedAuditBoundaries.set(t,{adapterType:"agy",...s?{providerSessionId:s}:{},...e.cwd?{cwd:e.cwd}:{},...e.logPath?{transcriptPath:e.logPath,transcriptStartOffset:e.logStartOffset??0,transcriptEndOffset:i??0}:{},agyEvidence:{...e.prompt===void 0?{}:{prompt:e.prompt},...e.stdout===void 0?{}:{stdout:e.stdout},...e.stderr===void 0?{}:{stderr:e.stderr},...e.exitCode===void 0?{}:{exitCode:e.exitCode},...e.response===void 0?{}:{response:e.response},toolInvocations:e.toolInvocations}})}clearActiveEventForShutdown(){if(this.activeProcess)try{y(this.activeProcess,"SIGKILL")}catch{}this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.stopTurnWatchdog(),this.watchdogKilledActiveProcess=!1,this.activeEventId=null,this.activeEventSessionId=null,this.activeProcess=null,this.activeEventSentViaTool=!1}getMcpConfig(){if(!this.internalApi)return null;const t=j(D(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:N(this.callbacks.getAgentId?.()),command:process.execPath,args:[t,"--api-url",this.internalApi.url]}}processEvent(t){const{event_id:e,session_id:i}=t,s=this.runtimeResolver(i);if(!s.cwd){a.warn(c,`No working directory for session ${i}, event should have been intercepted by bridge`),this.callbacks.forceCompleteInternalEvent(e,i);return}this.activeEventId=e,this.activeEventSessionId=i,this.activeEventSentViaTool=!1,this.emit("eventStarted",e,i),a.info(c,`Processing event ${e} for session ${i}`);const r=this.buildAgyPrompt(t);t.audit?.enabled===!0&&this.auditCaptures.set(e,{sessionId:i,...s.cwd?{cwd:s.cwd}:{},...s.conversationId?{conversationId:s.conversationId}:{},prompt:r,toolInvocations:[]}),this.spawnAgyPrint(e,i,r,s)}buildAgyPrompt(t){const i=[["chat_id",t.session_id],["agent_id",this.callbacks.getAgentId?.()],["event_id",t.event_id],["message_id",t.msg_id],["user_id",t.sender_id],["quoted_message_id",t.quoted_message_id]].filter(([,d])=>d!=null&&d!=="").map(([d,h])=>`${d}="${h}"`).join(" "),s=this.renderContextBlock(t),r=s?`${t.content}
1
+ import{spawn as L}from"node:child_process";import{randomUUID as P}from"node:crypto";import{EventEmitter as T}from"node:events";import{existsSync as I,readFileSync as m,statSync as R,mkdirSync as $,writeFileSync as O,realpathSync as G}from"node:fs";import{homedir as _}from"node:os";import{join as y,dirname as j,resolve as D}from"node:path";import{fileURLToPath as N}from"node:url";import{log as a}from"../../core/log/index.js";import{killProcessGroup as A}from"../../core/runtime/spawn.js";import{InternalApiServer as W}from"../../core/mcp/internal-api-server.js";import{resolveMcpServerName as B,pruneLegacyMcpServerEntries as K}from"../../core/mcp/server-name.js";import{syncDefaultSkillsToDir as Y}from"../../default-skills/index.js";import{buildSimpleProbeReport as V}from"../shared/probe-util.js";import{getAgyModelCatalog as Q,resolveAgyModelFlag as F}from"./model-list.js";const c="agy-adapter";function U(p){try{return process.kill(p,0),!0}catch(t){return t.code==="EPERM"}}function q(p){try{return G(p)}catch{return p}}const k=y(_(),".gemini","antigravity-cli","log"),H="CLI store manager shutting down",J=5e3,w=15e3,C=480*1e3,z=["fetchAvailableModels","loadCodeAssist","token refreshed","ListExperiments","experiment refresh","Experiments refreshed","Reloading system slash commands","Slash commands unchanged","doRefreshQuota"];function X(p,t){const e=Number(process.env[p]);return Number.isFinite(e)&&e>0?e:t}const Z="30m",b=y(_(),".gemini","antigravity-cli","cache","last_conversations.json"),tt=["\u4F60\u63A5\u5165\u7684\u662F Grix \u804A\u5929\u3002\u7528\u6237\u6D88\u606F\u88AB\u5305\u5728 <channel ...> \u6807\u7B7E\u91CC\uFF0C\u6807\u7B7E\u5C5E\u6027\u643A\u5E26\u672C\u8F6E\u4E0A\u4E0B\u6587\uFF1A","chat_id\uFF08\u5F53\u524D\u4F1A\u8BDD\uFF09\u3001agent_id\uFF08\u5F53\u524D Agent\uFF09\u3001event_id\uFF08\u672C\u8F6E\u4E8B\u4EF6\uFF09\u3001message_id\uFF08\u7528\u6237\u8FD9\u6761\u6D88\u606F\u7684 ID\uFF09\u3001user_id\uFF08\u53D1\u9001\u8005\uFF09\u3002","\u91CD\u8981\uFF1A\u4F60\u7684\u56DE\u590D\u5FC5\u987B\u8C03\u7528 grix \u7684 `grix_message_send` \u5DE5\u5177\u53D1\u9001\uFF08sessionId \u53D6\u81EA channel \u7684 chat_id\uFF0Ccontent \u4E3A\u4F60\u7684\u56DE\u590D\u5185\u5BB9\uFF09\uFF0C","\u4E0D\u8981\u53EA\u628A\u7B54\u6848\u6253\u5370\u5230\u6807\u51C6\u8F93\u51FA\u2014\u2014\u53EA\u6709\u8C03\u7528\u5DE5\u5177\u624D\u4F1A\u628A\u6D88\u606F\u771F\u6B63\u53D1\u7ED9\u7528\u6237\u3002","grix_message_send \u4F1A\u8FD4\u56DE\u4F60\u521A\u53D1\u51FA\u6D88\u606F\u7684 msg_id\u3002\u9700\u8981\u65F6\u4F60\u53EF\u4EE5\u7528\u8FD9\u4E2A ID \u505A\u540E\u7EED\u64CD\u4F5C\uFF0C\u4F8B\u5982\u8C03\u7528 grix_message_unsend\uFF08\u4F20 msgId\uFF09\u64A4\u56DE\u67D0\u6761\u6D88\u606F\u3002","\u8FDB\u7A0B\u5B89\u5168\uFF1A\u542F\u52A8\u4E34\u65F6\u6216\u6F14\u793A\u670D\u52A1\u65F6\u5FC5\u987B\u8BB0\u5F55\u5176 PID\uFF0C\u505C\u6B62\u65F6\u53EA\u7EC8\u6B62\u5DF2\u786E\u8BA4\u5C5E\u4E8E\u672C\u4EFB\u52A1\u7684\u8BE5 PID \u6216\u5176\u4E13\u5C5E\u8FDB\u7A0B\u7EC4\u3002","\u7981\u6B62\u4F7F\u7528 `pkill`\u3001`killall` \u6216\u5176\u4ED6\u6309\u540D\u79F0/\u547D\u4EE4\u884C\u6A21\u5F0F\u6279\u91CF\u6740\u8FDB\u7A0B\u7684\u547D\u4EE4\uFF1B\u7EDD\u4E0D\u80FD\u7EC8\u6B62 Grix MCP\u3001\u5F53\u524D agy \u6216\u5176\u7236\u8FDB\u7A0B\u3001connector \u6216\u5176\u4ED6\u65E0\u5173\u8FDB\u7A0B\u3002"].join(""),et=new Set(["send_msg","grix_reply"]),st=new Set(["send_msg","grix_reply","delete_msg","session_send","grix_complete","grix_composing","grix_event_ack"]);function x(p){try{return structuredClone(p)}catch{return}}class mt extends T{type="agy";config;callbacks;runtimeResolver;alive=!1;stopped=!1;internalApi=null;activeEventId=null;activeEventSessionId=null;activeProcess=null;completedEventIds=new Set;activeEventSentViaTool=!1;auditCaptures=new Map;completedAuditBoundaries=new Map;watchdogPollTimer=null;watchdogGraceTimer=null;watchdogKilledActiveProcess=!1;lastActivityAt=0;watchLogOffset=0;inactivityTimeoutMs=C;inactivityWarned=!1;sessionConversationMap=new Map;conversationOutputCache=new Map;eventQueue=[];systemInstructionInjectedSessions=new Set;identityInjectedSessions=new Set;constructor(t,e,i){super(),this.config=t,this.callbacks=e,this.runtimeResolver=i}async start(){this.alive||(this.alive=!0,this.stopped=!1,await this.startInternalApiAndInjectMcp(),a.info(c,"AgyAdapter started"))}async startInternalApiAndInjectMcp(){try{this.internalApi=new W,this.internalApi.setInvokeHandler(async(n,l,h,f)=>this.handleToolInvoke(n,l,f)),await this.internalApi.start(0),a.info(c,`Internal API started at ${this.internalApi.url}`);const t=this.getMcpConfig(),e=y(_(),".gemini","config","mcp_config.json");$(j(e),{recursive:!0});let i={};try{I(e)&&(i=JSON.parse(m(e,"utf8")))}catch{}const s=i.mcpServers&&typeof i.mcpServers=="object"?i.mcpServers:{};K(s,this.internalApi.url),s[t.name]={command:t.command,args:t.args},i.mcpServers=s,O(e,`${JSON.stringify(i,null,2)}
2
+ `,"utf8"),a.info(c,`MCP config injected into ${e}`);const r=y(_(),".gemini","skills"),o=Y(r);o.length>0&&a.info(c,`Synced connector skills to ${r}: [${o.join(", ")}]`)}catch(t){a.warn(c,`Failed to start MCP tools (non-fatal): ${t instanceof Error?t.message:String(t)}`)}}async handleToolInvoke(t,e,i){this.touchActivity();let s=e;st.has(t)&&this.activeEventSessionId&&(s.session_id==null||s.session_id==="")&&(s={...s,session_id:this.activeEventSessionId});const r=this.activeEventId?this.auditCaptures.get(this.activeEventId):void 0,o=r?{sequence:r.toolInvocations.length,observedAt:new Date().toISOString(),action:t,params:x(s)}:void 0;r&&o&&r.toolInvocations.push(o);try{const n=await this.callbacks.agentInvoke(t,s,i);return o&&(o.completedAt=new Date().toISOString(),o.result=x(n)),et.has(t)&&this.activeEventId&&(this.activeEventSentViaTool=!0),n}catch(n){throw o&&(o.completedAt=new Date().toISOString(),o.error=n instanceof Error?n.message:String(n)),n}}async stop(){if(!this.stopped){if(this.stopped=!0,this.alive=!1,this.stopTurnWatchdog(),this.watchdogKilledActiveProcess=!1,this.inactivityWarned=!1,this.activeProcess){try{A(this.activeProcess,"SIGKILL")}catch{}this.activeProcess=null}if(this.activeEventId&&this.activeEventSessionId)try{this.callbacks.sendEventResult(this.activeEventId,"canceled","adapter stopped")}catch{}if(this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.activeEventId=null,this.activeEventSessionId=null,this.internalApi){try{await this.internalApi.stop()}catch{}this.internalApi=null}this.emit("exit",0),a.info(c,"AgyAdapter stopped")}}isAlive(){return this.alive}async createSession(t){return t.cwd??P()}async resumeSession(t,e){}async destroySession(t){this.systemInstructionInjectedSessions.delete(t),this.identityInjectedSessions.delete(t)}onAgentProfileChanged(){this.identityInjectedSessions.clear()}sendPrompt(t){const e=new T;return e.adapterSessionId=t.adapterSessionId,e.cancel=async()=>{e.emit("done",{status:"canceled"})},e}async cancel(t){}cancelCurrentRun(){if(!this.activeEventId||!this.activeProcess)return;const t=this.activeEventId;a.info(c,`cancelCurrentRun: killing process group for event ${t}`);try{A(this.activeProcess,"SIGKILL")}catch{}this.activeProcess=null,this.callbacks.sendEventResult(t,"canceled","restarted by user"),this.clearActiveEvent(t),this.drainQueue()}deliverInboundEvent(t){if(!this.stopped){if(this.completedEventIds.has(t.event_id)){a.debug(c,`Skipping duplicate event: ${t.event_id}`);return}if(this.callbacks.sendEventAck(t.event_id,t.session_id),this.activeEventId){a.info(c,`Queuing event ${t.event_id} (active: ${this.activeEventId})`),this.eventQueue.push(t);return}this.processEvent(t)}}deliverStopEvent(t,e){if(this.activeEventId===t&&this.activeProcess){a.info(c,`Stopping event ${t}`);try{A(this.activeProcess,"SIGKILL")}catch{}this.activeProcess=null,this.callbacks.sendEventResult(t,"canceled","stopped by user"),this.clearActiveEvent(t),this.drainQueue()}}setPermissionHandler(){}async ping(t){if(this.stopped||!this.alive||!this.internalApi)return!1;const e=this.activeProcess;if(!e)return!0;if(!e.pid||!U(e.pid))return!1;const i=!!(e.stdout&&!e.stdout.destroyed),s=!!(e.stderr&&!e.stderr.destroyed);return i&&s}getStatus(){return{alive:this.alive,busy:this.activeEventId!==null,sessions:this.sessionConversationMap.size}}async probe(t){const e=this.getStatus();return V(this.config.command||"agy",{alive:e.alive,busy:e.busy,started:e.alive},t)}getActiveEventIds(){return this.activeEventId?[this.activeEventId]:[]}takeAuditBoundary(t){const e=this.completedAuditBoundaries.get(t);return e&&this.completedAuditBoundaries.delete(t),e}snapshotAuditBoundary(t){const e=this.auditCaptures.get(t);if(!e)return;this.auditCaptures.delete(t);let i;if(e.logPath)try{i=R(e.logPath).size}catch{}const s=this.sessionConversationMap.get(e.sessionId)??e.conversationId;this.completedAuditBoundaries.set(t,{adapterType:"agy",...s?{providerSessionId:s}:{},...e.cwd?{cwd:e.cwd}:{},...e.logPath?{transcriptPath:e.logPath,transcriptStartOffset:e.logStartOffset??0,transcriptEndOffset:i??0}:{},agyEvidence:{...e.prompt===void 0?{}:{prompt:e.prompt},...e.stdout===void 0?{}:{stdout:e.stdout},...e.stderr===void 0?{}:{stderr:e.stderr},...e.exitCode===void 0?{}:{exitCode:e.exitCode},...e.response===void 0?{}:{response:e.response},toolInvocations:e.toolInvocations}})}clearActiveEventForShutdown(){if(this.activeProcess)try{A(this.activeProcess,"SIGKILL")}catch{}this.activeEventId&&this.snapshotAuditBoundary(this.activeEventId),this.stopTurnWatchdog(),this.watchdogKilledActiveProcess=!1,this.inactivityWarned=!1,this.activeEventId=null,this.activeEventSessionId=null,this.activeProcess=null,this.activeEventSentViaTool=!1}getMcpConfig(){if(!this.internalApi)return null;const t=D(N(import.meta.url),"../../../mcp/acp-mcp-server.js");return{name:B(this.callbacks.getAgentId?.()),command:process.execPath,args:[t,"--api-url",this.internalApi.url]}}processEvent(t){const{event_id:e,session_id:i}=t,s=this.runtimeResolver(i);if(!s.cwd){a.warn(c,`No working directory for session ${i}, event should have been intercepted by bridge`),this.callbacks.forceCompleteInternalEvent(e,i);return}this.activeEventId=e,this.activeEventSessionId=i,this.activeEventSentViaTool=!1,this.emit("eventStarted",e,i),a.info(c,`Processing event ${e} for session ${i}`);const r=this.buildAgyPrompt(t);t.audit?.enabled===!0&&this.auditCaptures.set(e,{sessionId:i,...s.cwd?{cwd:s.cwd}:{},...s.conversationId?{conversationId:s.conversationId}:{},prompt:r,toolInvocations:[]}),this.spawnAgyPrint(e,i,r,s)}buildAgyPrompt(t){const i=[["chat_id",t.session_id],["agent_id",this.callbacks.getAgentId?.()],["event_id",t.event_id],["message_id",t.msg_id],["user_id",t.sender_id],["quoted_message_id",t.quoted_message_id]].filter(([,l])=>l!=null&&l!=="").map(([l,h])=>`${l}="${h}"`).join(" "),s=this.renderContextBlock(t),r=s?`${t.content}
3
3
 
4
4
  [Conversation context]
5
5
  ${s}`:t.content,o=`<channel source="grix-agy" ${i}>
6
6
  ${r}
7
7
  </channel>`,n=[];if((!t.session_id||!this.systemInstructionInjectedSessions.has(t.session_id))&&(t.session_id&&this.systemInstructionInjectedSessions.add(t.session_id),n.push(`[grix-system-instructions]
8
- ${z}
9
- [/grix-system-instructions]`)),!t.session_id||!this.identityInjectedSessions.has(t.session_id)){const d=this.buildIdentityBlock().trim();d&&(t.session_id&&this.identityInjectedSessions.add(t.session_id),n.push(d))}return n.length>0?`${o}
8
+ ${tt}
9
+ [/grix-system-instructions]`)),!t.session_id||!this.identityInjectedSessions.has(t.session_id)){const l=this.buildIdentityBlock().trim();l&&(t.session_id&&this.identityInjectedSessions.add(t.session_id),n.push(l))}return n.length>0?`${o}
10
10
 
11
11
  ${n.join(`
12
12
 
13
13
  `)}`:o}buildIdentityBlock(){const t=this.callbacks.getAgentProfile?.(),e=t?.agentName?.trim()??"",i=t?.introduction?.trim()??"";if(!e&&!i)return"";const s=["[system-identity]"];return e&&s.push(`\u4F60\u7684\u540D\u5B57\u662F"${e}"\u3002`),i&&s.push(`\u4F60\u7684\u81EA\u6211\u4ECB\u7ECD\uFF1A${i}`),s.push("\u8FD9\u662F\u5E26\u5916\u6307\u4EE4\uFF1B\u4E0D\u8981\u5728\u56DE\u590D\u4E2D\u590D\u8FF0\u6216\u5F15\u7528\u672C\u6BB5\u3002"),s.push("[/system-identity]"),`${s.join(`
14
14
  `)}
15
15
 
16
- `}renderContextBlock(t){const e=t.context_messages_json;if(!e)return"";let i;try{const n=JSON.parse(e);if(!Array.isArray(n))return"";i=n}catch{return""}const s=String(t.session_type??"")==="2",r=String(t.msg_id??""),o=[];for(const n of i){const d=String(n?.msg_id??"");if(d&&d===r)continue;const h=String(n?.content??"").trim();if(!h)continue;const p=String(n?.sender_id??"");if(h.startsWith("[\u5F15\u7528\u6D88\u606F]")){const f=h.slice(6).replace(/^\s*\n?/,"").trim();o.push(s&&p?`[\u5F15\u7528\u6D88\u606F] (\u6765\u81EA ${p})\uFF1A${f}`:`[\u5F15\u7528\u6D88\u606F]\uFF1A${f}`)}else o.push(s&&p?`[${p}]\uFF1A${h}`:h)}return o.join(`
17
- `)}spawnAgyPrint(t,e,i,s){try{$(k,{recursive:!0})}catch(l){const u=l instanceof Error?l.message:String(l),S=`unable to prepare agy log directory: ${u}`;a.error(c,`Log setup failed for event ${t}: ${u}`),this.handleProcessResult(t,e,"",S,s);return}const r=m(k,`grix-${P()}.log`),o=this.buildPrintArgs(i,s,r),n={...process.env,...this.config.env??{}};a.info(c,`Spawning: agy ${o.map(l=>l.includes(" ")?`"${l}"`:l).join(" ")}`);const d=R(this.config.command,o,{cwd:s.cwd,env:n,stdio:["pipe","pipe","pipe"],detached:process.platform!=="win32"});this.activeProcess=d;const h=[],p=[];d.stdout?.on("data",l=>{h.push(l)}),d.stderr?.on("data",l=>{p.push(l)}),d.on("error",l=>{a.error(c,`Process spawn error for event ${t}: ${l.message}`),this.handleProcessResult(t,e,"",`spawn error: ${l.message}`,s)}),d.on("close",l=>{if(a.info(c,`Process exited for event ${t} with code ${l}`),this.activeEventId!==t)return;this.stopTurnWatchdog();const u=Buffer.concat(h).toString("utf-8"),S=Buffer.concat(p).toString("utf-8"),E=this.auditCaptures.get(t);E&&(E.stdout=u,E.stderr=S,E.exitCode=l);const x=this.watchdogKilledActiveProcess&&l===null;if(this.watchdogKilledActiveProcess=!1,x)u.trim()||this.activeEventSentViaTool?this.handleProcessResult(t,e,u,"",s):setTimeout(()=>{const v=this.extractLogError(r);this.handleProcessResult(t,e,u,v,s)},300);else if(l!==0){const v=S.trim()||`process exited with code ${l}`;this.handleProcessResult(t,e,u,v,s)}else u.trim()?this.handleProcessResult(t,e,u,"",s):this.activeEventSentViaTool?this.handleProcessResult(t,e,u,"",s):setTimeout(()=>{const v=this.extractLogError(r);this.handleProcessResult(t,e,u,v,s)},300)}),d.stdin?.end();const f=this.auditCaptures.get(t);f&&(f.logPath=r,f.logStartOffset=0),this.startTurnWatchdog(t,r)}startTurnWatchdog(t,e){this.stopTurnWatchdog(),this.watchdogPollTimer=setInterval(()=>{if(this.activeEventId!==t||!this.activeProcess){this.stopTurnWatchdog();return}this.watchLogHasTurnEndMarker(e)&&(this.watchdogPollTimer&&(clearInterval(this.watchdogPollTimer),this.watchdogPollTimer=null),a.warn(c,`Turn end marker logged for event ${t} but process still alive; grace ${w}ms before kill`),this.watchdogGraceTimer=setTimeout(()=>{if(this.watchdogGraceTimer=null,!(this.activeEventId!==t||!this.activeProcess)){a.warn(c,`agy process still alive ${w}ms after turn end (shutdown deadlock); killing process group for event ${t}`),this.watchdogKilledActiveProcess=!0;try{y(this.activeProcess,"SIGKILL")}catch{}}},w),this.watchdogGraceTimer.unref())},U),this.watchdogPollTimer.unref()}stopTurnWatchdog(){this.watchdogPollTimer&&(clearInterval(this.watchdogPollTimer),this.watchdogPollTimer=null),this.watchdogGraceTimer&&(clearTimeout(this.watchdogGraceTimer),this.watchdogGraceTimer=null)}watchLogHasTurnEndMarker(t){try{return I(t,"utf-8").includes(H)}catch{return!1}}buildPrintArgs(t,e,i){const s=["--print-timeout",J,"--log-file",i],r=e.modelId?Y(e.modelId,V()):"";return r&&s.push("--model",r),e.cwd&&s.push("--add-dir",e.cwd),s.push("--dangerously-skip-permissions"),e.conversationId&&s.push("--conversation",e.conversationId),s.push("-p",t),s}readAgyConversationId(t){try{if(A(C)){const e=JSON.parse(I(C,"utf-8"));return e[F(t)]||e[t]||void 0}}catch(e){a.debug(c,`readAgyConversationId: ${e}`)}}extractLogError(t){try{if(!A(t))return a.info(c,`extractLogError: log file not found: ${t}`),"agy completed without output";const e=I(t,"utf-8");if(!e)return a.info(c,`extractLogError: log file is empty: ${t}`),"agy completed without output";const i=e.split(`
18
- `).filter(s=>s.startsWith("E")).map(s=>{const r=s.indexOf("] ");return r>=0?s.slice(r+2):s}).filter(s=>s.length>0);if(i.length>0){const s=i[i.length-1];return a.info(c,`Extracted error from agy log: ${s.slice(0,120)}`),s.length>500?s.slice(0,500)+"...":s}return"agy completed without output (possible auth or quota issue)"}catch(e){return a.info(c,`extractLogError: ${e}`),"agy completed without output"}}handleProcessResult(t,e,i,s,r){if(this.activeEventId===t){if(s&&!i.trim()){a.error(c,`Event ${t} failed: ${s}`);const n=s.includes("RESOURCE_EXHAUSTED")||s.includes("quota")?"The agy API quota has been exhausted. Please try again later.":`agy execution failed: ${s}`;this.callbacks.sendStreamChunk(t,e,n,1,!0,`agy-${t}`),this.callbacks.sendEventResult(t,"failed",s)}else{const o=i.trim();if(o){const n=r.cwd,d=n?this.extractDelta(o,n):o;n&&this.conversationOutputCache.set(n,o);const h=this.auditCaptures.get(t);h&&(h.response=d),d&&!this.activeEventSentViaTool&&this.callbacks.sendStreamChunk(t,e,d,1,!0,`agy-${t}`)}if(r.cwd){const n=this.readAgyConversationId(r.cwd);n&&n!==r.conversationId&&(this.sessionConversationMap.set(e,n),this.callbacks.persistConversationId(e,n))}this.callbacks.sendEventResult(t,"responded")}this.clearActiveEvent(t),this.drainQueue()}}extractDelta(t,e){const i=this.conversationOutputCache.get(e);return i&&t.startsWith(i)?t.slice(i.length).trim():t}clearActiveEvent(t){const e=t??this.activeEventId;if(e){if(this.completedEventIds.add(e),this.completedEventIds.size>1e3){const i=Array.from(this.completedEventIds);this.completedEventIds.clear();for(let s=500;s<i.length;s++)this.completedEventIds.add(i[s])}this.snapshotAuditBoundary(e)}this.activeEventId=null,this.activeEventSessionId=null,this.activeProcess=null,this.activeEventSentViaTool=!1,this.stopTurnWatchdog(),this.watchdogKilledActiveProcess=!1,e&&this.emit("eventDone",e)}drainQueue(){if(this.stopped||this.activeEventId)return;const t=this.eventQueue.shift();t&&(a.info(c,`Draining queued event ${t.event_id}`),this.processEvent(t))}}export{gt as AgyAdapter};
16
+ `}renderContextBlock(t){const e=t.context_messages_json;if(!e)return"";let i;try{const n=JSON.parse(e);if(!Array.isArray(n))return"";i=n}catch{return""}const s=String(t.session_type??"")==="2",r=String(t.msg_id??""),o=[];for(const n of i){const l=String(n?.msg_id??"");if(l&&l===r)continue;const h=String(n?.content??"").trim();if(!h)continue;const f=String(n?.sender_id??"");if(h.startsWith("[\u5F15\u7528\u6D88\u606F]")){const g=h.slice(6).replace(/^\s*\n?/,"").trim();o.push(s&&f?`[\u5F15\u7528\u6D88\u606F] (\u6765\u81EA ${f})\uFF1A${g}`:`[\u5F15\u7528\u6D88\u606F]\uFF1A${g}`)}else o.push(s&&f?`[${f}]\uFF1A${h}`:h)}return o.join(`
17
+ `)}spawnAgyPrint(t,e,i,s){try{$(k,{recursive:!0})}catch(d){const u=d instanceof Error?d.message:String(d),S=`unable to prepare agy log directory: ${u}`;a.error(c,`Log setup failed for event ${t}: ${u}`),this.handleProcessResult(t,e,"",S,s);return}const r=y(k,`grix-${P()}.log`),o=this.buildPrintArgs(i,s,r),n={...process.env,...this.config.env??{}};a.info(c,`Spawning: agy ${o.map(d=>d.includes(" ")?`"${d}"`:d).join(" ")}`);const l=L(this.config.command,o,{cwd:s.cwd,env:n,stdio:["pipe","pipe","pipe"],detached:process.platform!=="win32"});this.activeProcess=l,this.lastActivityAt=Date.now(),this.watchLogOffset=0,this.inactivityWarned=!1,this.inactivityTimeoutMs=X("GRIX_AGY_INACTIVITY_TIMEOUT_MS",C);const h=[],f=[];l.stdout?.on("data",d=>{h.push(d),this.touchActivity()}),l.stderr?.on("data",d=>{f.push(d),this.touchActivity()}),l.on("error",d=>{a.error(c,`Process spawn error for event ${t}: ${d.message}`),this.handleProcessResult(t,e,"",`spawn error: ${d.message}`,s)}),l.on("close",d=>{if(a.info(c,`Process exited for event ${t} with code ${d}`),this.activeEventId!==t)return;this.stopTurnWatchdog();const u=Buffer.concat(h).toString("utf-8"),S=Buffer.concat(f).toString("utf-8"),E=this.auditCaptures.get(t);E&&(E.stdout=u,E.stderr=S,E.exitCode=d);const M=this.watchdogKilledActiveProcess&&d===null;if(this.watchdogKilledActiveProcess=!1,M)u.trim()||this.activeEventSentViaTool?this.handleProcessResult(t,e,u,"",s):setTimeout(()=>{const v=this.extractLogError(r);this.handleProcessResult(t,e,u,v,s)},300);else if(d!==0){const v=S.trim()||`process exited with code ${d}`;this.handleProcessResult(t,e,u,v,s)}else u.trim()?this.handleProcessResult(t,e,u,"",s):this.activeEventSentViaTool?this.handleProcessResult(t,e,u,"",s):setTimeout(()=>{const v=this.extractLogError(r);this.handleProcessResult(t,e,u,v,s)},300)}),l.stdin?.end();const g=this.auditCaptures.get(t);g&&(g.logPath=r,g.logStartOffset=0),this.startTurnWatchdog(t,r)}startTurnWatchdog(t,e){this.stopTurnWatchdog(),this.watchdogPollTimer=setInterval(()=>{if(this.activeEventId!==t||!this.activeProcess){this.stopTurnWatchdog();return}if(this.watchLogHasTurnEndMarker(e)){this.watchdogPollTimer&&(clearInterval(this.watchdogPollTimer),this.watchdogPollTimer=null),a.warn(c,`Turn end marker logged for event ${t} but process still alive; grace ${w}ms before kill`),this.watchdogGraceTimer=setTimeout(()=>{if(this.watchdogGraceTimer=null,!(this.activeEventId!==t||!this.activeProcess)){a.warn(c,`agy process still alive ${w}ms after turn end (shutdown deadlock); killing process group for event ${t}`),this.watchdogKilledActiveProcess=!0;try{A(this.activeProcess,"SIGKILL")}catch{}}},w),this.watchdogGraceTimer.unref();return}if(this.scanTurnLogActivity(e),this.inactivityWarned)return;const i=Date.now()-this.lastActivityAt;if(i<this.inactivityTimeoutMs)return;this.inactivityWarned=!0;const s=Math.max(1,Math.round(i/6e4));a.warn(c,`No activity for ${Math.round(i/1e3)}s on event ${t} (threshold ${Math.round(this.inactivityTimeoutMs/1e3)}s); upstream turn appears stalled, notifying user (process left running)`),this.callbacks.sendStreamChunk(t,this.activeEventSessionId??"",`\u26A0\uFE0F \u672C\u8F6E\u5DF2\u7EA6 ${s} \u5206\u949F\u6CA1\u6709\u4EFB\u4F55\u54CD\u5E94\uFF0C\u4E0A\u6E38\u7591\u4F3C\u6302\u6B7B\u3002\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF08\u4E0A\u6E38\u6062\u590D\u540E\u4F1A\u7EE7\u7EED\uFF09\uFF0C\u4F60\u53EF\u4EE5\u56DE\u590D /stop \u7EC8\u6B62\uFF0C\u6216\u7EE7\u7EED\u7B49\u5F85\uFF0830 \u5206\u949F\u4E0A\u9650\u540E\u5C06\u81EA\u52A8\u5224\u5931\u8D25\uFF09\u3002`,1,!1,`agy-stall-${t}`)},J),this.watchdogPollTimer.unref()}stopTurnWatchdog(){this.watchdogPollTimer&&(clearInterval(this.watchdogPollTimer),this.watchdogPollTimer=null),this.watchdogGraceTimer&&(clearTimeout(this.watchdogGraceTimer),this.watchdogGraceTimer=null)}touchActivity(){this.lastActivityAt=Date.now()}scanTurnLogActivity(t){let e;try{e=m(t)}catch{return}if(e.length<=this.watchLogOffset){this.watchLogOffset=e.length;return}const i=e.subarray(this.watchLogOffset).toString("utf-8");this.watchLogOffset=e.length;for(const s of i.split(`
18
+ `))if(s.trim()&&!z.some(r=>s.includes(r))){a.debug(c,`turn log activity: ${s.slice(0,120)}`),this.touchActivity();return}}watchLogHasTurnEndMarker(t){try{return m(t,"utf-8").includes(H)}catch{return!1}}buildPrintArgs(t,e,i){const s=["--print-timeout",Z,"--log-file",i],r=e.modelId?F(e.modelId,Q()):"";return r&&s.push("--model",r),e.cwd&&s.push("--add-dir",e.cwd),s.push("--dangerously-skip-permissions"),e.conversationId&&s.push("--conversation",e.conversationId),s.push("-p",t),s}readAgyConversationId(t){try{if(I(b)){const e=JSON.parse(m(b,"utf-8"));return e[q(t)]||e[t]||void 0}}catch(e){a.debug(c,`readAgyConversationId: ${e}`)}}extractLogError(t){try{if(!I(t))return a.info(c,`extractLogError: log file not found: ${t}`),"agy completed without output";const e=m(t,"utf-8");if(!e)return a.info(c,`extractLogError: log file is empty: ${t}`),"agy completed without output";const i=e.split(`
19
+ `).filter(s=>s.startsWith("E")).map(s=>{const r=s.indexOf("] ");return r>=0?s.slice(r+2):s}).filter(s=>s.length>0);if(i.length>0){const s=i[i.length-1];return a.info(c,`Extracted error from agy log: ${s.slice(0,120)}`),s.length>500?s.slice(0,500)+"...":s}return"agy completed without output (possible auth or quota issue)"}catch(e){return a.info(c,`extractLogError: ${e}`),"agy completed without output"}}handleProcessResult(t,e,i,s,r){if(this.activeEventId===t){if(this.inactivityWarned&&this.callbacks.sendStreamChunk(t,e,"",2,!0,`agy-stall-${t}`),s&&!i.trim()){a.error(c,`Event ${t} failed: ${s}`);const n=s.includes("RESOURCE_EXHAUSTED")||s.includes("quota")?"The agy API quota has been exhausted. Please try again later.":`agy execution failed: ${s}`;this.callbacks.sendStreamChunk(t,e,n,1,!0,`agy-${t}`),this.callbacks.sendEventResult(t,"failed",s)}else{const o=i.trim();if(o){const n=r.cwd,l=n?this.extractDelta(o,n):o;n&&this.conversationOutputCache.set(n,o);const h=this.auditCaptures.get(t);h&&(h.response=l),l&&!this.activeEventSentViaTool&&this.callbacks.sendStreamChunk(t,e,l,1,!0,`agy-${t}`)}if(r.cwd){const n=this.readAgyConversationId(r.cwd);n&&n!==r.conversationId&&(this.sessionConversationMap.set(e,n),this.callbacks.persistConversationId(e,n))}this.callbacks.sendEventResult(t,"responded")}this.clearActiveEvent(t),this.drainQueue()}}extractDelta(t,e){const i=this.conversationOutputCache.get(e);return i&&t.startsWith(i)?t.slice(i.length).trim():t}clearActiveEvent(t){const e=t??this.activeEventId;if(e){if(this.completedEventIds.add(e),this.completedEventIds.size>1e3){const i=Array.from(this.completedEventIds);this.completedEventIds.clear();for(let s=500;s<i.length;s++)this.completedEventIds.add(i[s])}this.snapshotAuditBoundary(e)}this.activeEventId=null,this.activeEventSessionId=null,this.activeProcess=null,this.activeEventSentViaTool=!1,this.stopTurnWatchdog(),this.watchdogKilledActiveProcess=!1,this.inactivityWarned=!1,e&&this.emit("eventDone",e)}drainQueue(){if(this.stopped||this.activeEventId)return;const t=this.eventQueue.shift();t&&(a.info(c,`Draining queued event ${t.event_id}`),this.processEvent(t))}}export{mt as AgyAdapter};