@yuandc/aica 0.1.15 → 0.1.17

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.
package/dist/acp/agent.js CHANGED
@@ -1 +1 @@
1
- import r from"node:fs";import{createAgentProvider as t}from"./providers/registry.js";async function a(e){if(!r.existsSync(e.cwd)||!r.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);if(e.requireSessionResume&&!e.acpSessionId)throw new Error("导入的历史 Session 缺少 Provider Session ID,禁止创建新的会话。");const o=await t({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId??null,timeoutMs:e.timeoutMs});try{const s=await o.sendPrompt({...e,providerSessionId:e.acpSessionId??null});return{...s,acpSessionId:s.providerSessionId}}finally{await o.close().catch(()=>{})}}async function d(e){const o=await t({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId,timeoutMs:e.timeoutMs});if(!o.compactContext)throw await o.close().catch(()=>{}),new Error(`Provider does not support context compaction: ${e.agentType||"codex"}`);try{const s=await o.compactContext(e);return{...s,acpSessionId:s.providerSessionId}}finally{await o.close().catch(()=>{})}}export{d as compactAgentContext,a as sendAgentPrompt};
1
+ import t from"node:fs";import{createAgentProvider as i}from"./providers/registry.js";async function d(e){if(!t.existsSync(e.cwd)||!t.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);if(e.requireSessionResume&&!e.acpSessionId)throw new Error("导入的历史 Session 缺少 Provider Session ID,禁止创建新的会话。");const o=await i({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId??null,timeoutMs:e.timeoutMs});try{const r=await o.sendPrompt({...e,providerSessionId:e.acpSessionId??null});return{...r,acpSessionId:r.providerSessionId}}finally{await o.close().catch(()=>{})}}async function a(e){const o=await i({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId,timeoutMs:e.timeoutMs});if(!o.compactContext)throw await o.close().catch(()=>{}),new Error(`Provider does not support context compaction: ${e.agentType||"codex"}`);try{const r=await o.compactContext(e);return{...r,acpSessionId:r.providerSessionId}}finally{await o.close().catch(()=>{})}}async function w(e){if(!t.existsSync(e.cwd)||!t.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);if(!e.sourceProviderSessionId.trim())throw new Error("Source ACP session ID is required for fork");const s=i({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"});if(!s.forkSession)throw new Error(`Provider does not support native session fork: ${e.agentType||"codex"}`);return{acpSessionId:(await s.forkSession(e)).providerSessionId}}export{a as compactAgentContext,w as forkAgentSession,d as sendAgentPrompt};
@@ -1 +1 @@
1
- import{JsonLineRpcClient as n}from"./json-rpc.js";class l{onSessionUpdate;onClientRequest;rpc;constructor(e,s,o){this.onSessionUpdate=s,this.onClientRequest=o,this.rpc=new n(e,{peerName:"ACP server",includeJsonRpc:!0,onNotification:(r,t,i)=>{r==="session/update"&&this.onSessionUpdate(t,i)},onRequest:async(r,t,i)=>{if(this.onClientRequest)return this.onClientRequest(r,t,i);throw new Error(`Unsupported ACP client request: ${r}`)}})}initialize(e=6e4){return this.rpc.request("initialize",{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!1,writeTextFile:!1},terminal:!1},clientInfo:{name:"aca",version:"0.1.0"}},e)}newSession(e,s=12e4){return this.rpc.request("session/new",{cwd:e.cwd,mcpServers:e.mcpServers??[],...e.config?{config:e.config}:{}},s)}resumeSession(e,s=12e4){return this.rpc.request("session/resume",{sessionId:e.sessionId,cwd:e.cwd,mcpServers:e.mcpServers??[],...e.config?{config:e.config}:{}},s)}loadSession(e,s=12e4){return this.rpc.request("session/load",{sessionId:e.sessionId,cwd:e.cwd,mcpServers:e.mcpServers??[],...e.config?{config:e.config}:{}},s)}closeSession(e,s=3e4){return this.rpc.request("session/close",{sessionId:e},s)}listSessions(e={},s=6e4){return this.rpc.request("session/list",e,s)}deleteSession(e,s=6e4){return this.rpc.request("session/delete",{sessionId:e},s)}forkSession(e,s=12e4){return this.rpc.request("session/fork",{sessionId:e.sessionId,...e.cwd?{cwd:e.cwd}:{},...e.mcpServers?{mcpServers:e.mcpServers}:{}},s)}setSessionConfigOption(e,s=6e4){return this.rpc.request("session/set_config_option",e,s)}setSessionMode(e,s=6e4){return this.rpc.request("session/set_mode",e,s)}prompt(e,s){return this.rpc.request("session/prompt",e,s)}compactSession(e,s=600*1e3){return this.rpc.request("session/compact",e,s)}cancel(e){this.rpc.notify("session/cancel",{sessionId:e})}authenticate(e,s=12e4){return this.rpc.request("authenticate",e,s)}logout(e={},s=6e4){return this.rpc.request("logout",e,s)}listProviders(e={},s=6e4){return this.rpc.request("providers/list",e,s)}setProvider(e,s=6e4){return this.rpc.request("providers/set",e,s)}disableProvider(e,s=6e4){return this.rpc.request("providers/disable",e,s)}}export{l as AcpClient};
1
+ import{JsonLineRpcClient as n}from"./json-rpc.js";class l{onSessionUpdate;onClientRequest;rpc;constructor(e,s,o){this.onSessionUpdate=s,this.onClientRequest=o,this.rpc=new n(e,{peerName:"ACP server",includeJsonRpc:!0,onNotification:(r,i,t)=>{r==="session/update"&&this.onSessionUpdate(i,t)},onRequest:async(r,i,t)=>{if(this.onClientRequest)return this.onClientRequest(r,i,t);throw new Error(`Unsupported ACP client request: ${r}`)}})}initialize(e=6e4){return this.rpc.request("initialize",{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!1,writeTextFile:!1},terminal:!1},clientInfo:{name:"aca",version:"0.1.0"}},e)}newSession(e,s=12e4){return this.rpc.request("session/new",{cwd:e.cwd,mcpServers:e.mcpServers??[],...e.config?{config:e.config}:{}},s)}resumeSession(e,s=12e4){return this.rpc.request("session/resume",{sessionId:e.sessionId,cwd:e.cwd,mcpServers:e.mcpServers??[],...e.config?{config:e.config}:{}},s)}loadSession(e,s=12e4){return this.rpc.request("session/load",{sessionId:e.sessionId,cwd:e.cwd,mcpServers:e.mcpServers??[],...e.config?{config:e.config}:{}},s)}closeSession(e,s=3e4){return this.rpc.request("session/close",{sessionId:e},s)}listSessions(e={},s=6e4){return this.rpc.request("session/list",e,s)}deleteSession(e,s=6e4){return this.rpc.request("session/delete",{sessionId:e},s)}forkSession(e,s=12e4){return this.rpc.request("session/fork",{sessionId:e.sessionId,cwd:e.cwd,...e.mcpServers?{mcpServers:e.mcpServers}:{},...e.config?{config:e.config}:{}},s)}setSessionConfigOption(e,s=6e4){return this.rpc.request("session/set_config_option",e,s)}setSessionMode(e,s=6e4){return this.rpc.request("session/set_mode",e,s)}prompt(e,s){return this.rpc.request("session/prompt",e,s)}compactSession(e,s=600*1e3){return this.rpc.request("session/compact",e,s)}cancel(e){this.rpc.notify("session/cancel",{sessionId:e})}authenticate(e,s=12e4){return this.rpc.request("authenticate",e,s)}logout(e={},s=6e4){return this.rpc.request("logout",e,s)}listProviders(e={},s=6e4){return this.rpc.request("providers/list",e,s)}setProvider(e,s=6e4){return this.rpc.request("providers/set",e,s)}disableProvider(e,s=6e4){return this.rpc.request("providers/disable",e,s)}}export{l as AcpClient};
@@ -1,27 +1,27 @@
1
- import{readFileSync as rt}from"node:fs";import{applyPatch as st,parsePatch as ut,reversePatch as it}from"diff";import{createPlanEvent as z}from"../../plan-events.js";import{codexPlanUpdateFromNotification as F}from"./plan-events.js";const S=new Set,A=new Set;function Kt(t,e,n={}){switch(t){case"item/agentMessage/delta":{const r=a(e,"delta"),o=a(e,"itemId"),s=o?n.agentMessagePhases?.get(o):"";return r?s==="commentary"?[y("agent_progress_chunk",r)]:s&&s!=="final_answer"?[]:[y("agent_message_chunk",r)]:[]}case"item/reasoning/summaryTextDelta":case"item/reasoning/textDelta":{const r=a(e,"delta");return r?[y("agent_thought_chunk",r)]:[]}case"turn/plan/updated":{const r=n.planDeltas?.fromSnapshot(e)??F(e);return r?[r]:[]}case"item/plan/delta":{const r=n.planDeltas?.fromDelta(e);return r?[r]:[]}case"item/started":case"item/completed":{const r=m(e,"item"),o=a(r,"type");if(!r||!o||o==="userMessage"||o==="agentMessage"||o==="reasoning")return[];const s=j(t,r);return s?[s]:[t==="item/started"?xt(r):kt(r)]}case"item/commandExecution/outputDelta":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=c(e,["delta","data","output","text"]);return!r&&!o?[]:[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:I(r,o)}]}case"item/commandExecution/terminalInteraction":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=a(e,"stdin");return r?[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:I(r,`
1
+ import{readFileSync as st}from"node:fs";import{applyPatch as ut,parsePatch as it,reversePatch as lt}from"diff";import{createPlanEvent as F}from"../../plan-events.js";import{codexPlanUpdateFromNotification as O}from"./plan-events.js";const A=new Set,v=new Set;function Yt(t,e,n={}){switch(t){case"item/agentMessage/delta":{const r=a(e,"delta"),o=a(e,"itemId"),s=o?n.agentMessagePhases?.get(o):"";return r?s==="commentary"?[_("agent_progress_chunk",r)]:s&&s!=="final_answer"?[]:[_("agent_message_chunk",r)]:[]}case"item/reasoning/summaryTextDelta":case"item/reasoning/textDelta":{const r=a(e,"delta");return r?[_("agent_thought_chunk",r)]:[]}case"turn/plan/updated":{const r=n.planDeltas?.fromSnapshot(e)??O(e);return r?[r]:[]}case"item/plan/delta":{const r=n.planDeltas?.fromDelta(e);return r?[r]:[]}case"item/started":case"item/completed":{const r=y(e,"item"),o=a(r,"type");if(!r||!o||o==="userMessage"||o==="agentMessage"||o==="reasoning")return[];const s=E(t,r);return s?[s]:[t==="item/started"?kt(r):St(r)]}case"item/commandExecution/outputDelta":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=c(e,["delta","data","output","text"]);return!r&&!o?[]:[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:U(r,o)}]}case"item/commandExecution/terminalInteraction":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=a(e,"stdin");return r?[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:U(r,`
2
2
  ${o}
3
- `)}]:[]}case"item/mcpToolCall/progress":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=a(e,"message").trim();return!r||!o?[]:[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:{mcp_output_delta:{data:o,terminal_id:r}}}]}case"turn/diff/updated":{const r=a(e,"diff");return r?[{sessionUpdate:"tool_call_update",toolCallId:a(e,"turnId")||"codex.diff",kind:"edit",title:"Diff updated",status:"completed",content:[{type:"diff",oldText:null,newText:r}],rawOutput:{diff:r}}]:[]}case"thread/tokenUsage/updated":return[{sessionUpdate:"usage_update",_meta:{codex:e}}];case"thread/name/updated":return[{sessionUpdate:"session_info_update",title:a(e,"threadName")||null}];case"thread/status/changed":return[b({threadStatus:a(e,"status")})];case"thread/archived":return[b({archived:!0})];case"thread/unarchived":return[b({archived:!1})];case"thread/closed":return[b({closed:!0})];case"account/rateLimits/updated":return[q(e)];case"account/updated":return[b({account:d(e)??e})];case"configWarning":{const r=a(e,"summary"),o=a(e,"details");return[y("agent_message_chunk",`Config warning: ${r}${o?`
3
+ `)}]:[]}case"item/mcpToolCall/progress":{const r=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),o=a(e,"message").trim();return!r||!o?[]:[{sessionUpdate:"tool_call_update",toolCallId:r,kind:"execute",status:"in_progress",_meta:{mcp_output_delta:{data:o,terminal_id:r}}}]}case"turn/diff/updated":{const r=a(e,"diff");return r?[{sessionUpdate:"tool_call_update",toolCallId:a(e,"turnId")||"codex.diff",kind:"edit",title:"Diff updated",status:"completed",content:[{type:"diff",oldText:null,newText:r}],rawOutput:{diff:r}}]:[]}case"thread/tokenUsage/updated":return[{sessionUpdate:"usage_update",_meta:{codex:e}}];case"thread/name/updated":return[{sessionUpdate:"session_info_update",title:a(e,"threadName")||null}];case"thread/status/changed":return[I({threadStatus:a(e,"status")})];case"thread/archived":return[I({archived:!0})];case"thread/unarchived":return[I({archived:!1})];case"thread/closed":return[I({closed:!0})];case"account/rateLimits/updated":return[V(e)];case"account/updated":return[I({account:d(e)??e})];case"configWarning":{const r=a(e,"summary"),o=a(e,"details");return[_("agent_message_chunk",`Config warning: ${r}${o?`
4
4
 
5
5
  ${o}`:""}
6
6
 
7
- `)]}case"warning":return[y("agent_message_chunk",`Warning: ${a(e,"message")}
7
+ `)]}case"warning":return[_("agent_message_chunk",`Warning: ${a(e,"message")}
8
8
 
9
- `)];case"model/rerouted":return[y("agent_thought_chunk",`Model rerouted from ${a(e,"fromModel")} to ${a(e,"toModel")} (${a(e,"reason")}).
9
+ `)];case"model/rerouted":return[_("agent_thought_chunk",`Model rerouted from ${a(e,"fromModel")} to ${a(e,"toModel")} (${a(e,"reason")}).
10
10
 
11
- `)];case"thread/compacted":return[y("agent_message_chunk",`*Context compacted to fit the model's context window.*
11
+ `)];case"thread/compacted":return[_("agent_message_chunk",`*Context compacted to fit the model's context window.*
12
12
 
13
- `)];case"fuzzyFileSearch/sessionUpdated":return[G(e)];case"fuzzyFileSearch/sessionCompleted":return[N(e)];case"item/autoApprovalReview/started":return[U(e,"started")];case"item/autoApprovalReview/completed":return[U(e,"completed")];case"error":return[{sessionUpdate:"tool_call_update",toolCallId:"codex.error",kind:"other",status:"failed",title:"Codex error",rawOutput:e}];default:return O(t,e),[]}}function Yt(t,e,n,r={}){switch(t){case"item/agentMessage/delta":{const o=a(e,"delta"),s=a(e,"itemId"),u=s?r.agentMessagePhases?.get(s):"";if(!o||u&&u!=="commentary"&&u!=="final_answer")break;const l=u==="commentary"?"agent_progress_chunk":"agent_message_chunk",f=u==="commentary"?"progress":"message";n.pushStatus("thinking",u==="commentary"?"处理中":"生成回复中",w(o),t),n.pushUpdate({type:l,label:f,text:o,raw:{method:t,params:e,update:y(l,o)},atMs:Date.now()});break}case"item/reasoning/summaryTextDelta":case"item/reasoning/textDelta":{const o=a(e,"delta");n.pushStatus("thinking","思考中",w(o),t),n.pushUpdate({type:"agent_thought_chunk",label:"thought",...o?{text:o}:{},raw:{method:t,params:e},atMs:Date.now()});break}case"turn/plan/updated":{const o=r.planDeltas?.fromSnapshot(e)??F(e);if(!o)break;n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate(z({update:o,method:t,params:e}));break}case"item/plan/delta":{const o=r.planDeltas?.fromDelta(e);if(!o)break;n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate(z({update:o,method:t,params:e}));break}case"item/started":case"item/completed":{const o=m(e,"item"),s=a(o,"type"),u=j(t,o);if(!u){const _=v(s);(s==="reasoning"||s==="agentMessage")&&n.pushStatus(R(s),_,ct(o),t);break}const l=dt(t,e,o),f=lt(s,u);n.pushStatus(R(s),$(s),void 0,t),n.pushUpdate({type:t==="item/started"?"tool_call":"tool_call_update",label:f,status:c(u,["status"])||(t==="item/started"?"in_progress":"completed"),toolCallId:a(o,"id"),raw:{method:t,params:e,tool:l,update:u},atMs:Date.now()});break}case"item/commandExecution/outputDelta":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),s=c(e,["delta","data","output","text"]);if(!o&&!s)break;n.pushStatus("exploring","执行命令",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:I(o,s)}},atMs:Date.now()});break}case"item/commandExecution/terminalInteraction":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),u=`
13
+ `)];case"fuzzyFileSearch/sessionUpdated":return[N(e)];case"fuzzyFileSearch/sessionCompleted":return[L(e)];case"item/autoApprovalReview/started":return[x(e,"started")];case"item/autoApprovalReview/completed":return[x(e,"completed")];case"error":return[{sessionUpdate:"tool_call_update",toolCallId:"codex.error",kind:"other",status:"failed",title:"Codex error",rawOutput:e}];default:return R(t,e),[]}}function te(t,e,n,r={}){switch(t){case"item/agentMessage/delta":{const o=a(e,"delta"),s=a(e,"itemId"),u=s?r.agentMessagePhases?.get(s):"";if(!o||u&&u!=="commentary"&&u!=="final_answer")break;const l=u==="commentary"?"agent_progress_chunk":"agent_message_chunk",f=u==="commentary"?"progress":"message";n.pushStatus("thinking",u==="commentary"?"处理中":"生成回复中",w(o),t),n.pushUpdate({type:l,label:f,text:o,raw:{method:t,params:e,update:_(l,o)},atMs:Date.now()});break}case"item/reasoning/summaryTextDelta":case"item/reasoning/textDelta":{const o=a(e,"delta");n.pushStatus("thinking","思考中",w(o),t),n.pushUpdate({type:"agent_thought_chunk",label:"thought",...o?{text:o}:{},raw:{method:t,params:e},atMs:Date.now()});break}case"turn/plan/updated":{const o=r.planDeltas?.fromSnapshot(e)??O(e);if(!o)break;n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate(F({update:o,method:t,params:e}));break}case"item/plan/delta":{const o=r.planDeltas?.fromDelta(e);if(!o)break;n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate(F({update:o,method:t,params:e}));break}case"item/started":case"item/completed":{const o=y(e,"item"),s=a(o,"type"),u=E(t,o);if(!u){const g=$(s);(s==="reasoning"||s==="agentMessage")&&n.pushStatus(j(s),g,dt(o),t);break}const l=ft(t,e,o),f=ct(s,u);n.pushStatus(j(s),T(s),void 0,t),n.pushUpdate({type:t==="item/started"?"tool_call":"tool_call_update",label:f,status:c(u,["status"])||(t==="item/started"?"in_progress":"completed"),toolCallId:a(o,"id"),raw:{method:t,params:e,tool:l,update:u},atMs:Date.now()});break}case"item/commandExecution/outputDelta":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),s=c(e,["delta","data","output","text"]);if(!o&&!s)break;n.pushStatus("exploring","执行命令",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:U(o,s)}},atMs:Date.now()});break}case"item/commandExecution/terminalInteraction":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),u=`
14
14
  ${a(e,"stdin")}
15
- `;if(!o)break;n.pushStatus("exploring","执行命令",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:I(o,u)}},atMs:Date.now()});break}case"item/mcpToolCall/progress":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),s=a(e,"message").trim();if(!o||!s)break;n.pushStatus("exploring","调用工具",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:{mcp_output_delta:{data:s,terminal_id:o}}}},atMs:Date.now()});break}case"turn/diff/updated":n.pushStatus("exploring","编辑文件中","diff",t),n.pushUpdate({type:"diff",label:"diff",text:a(e,"diff"),raw:{method:t,params:e},atMs:Date.now()});break;case"thread/tokenUsage/updated":n.pushUpdate({type:"usage_update",label:"usage",raw:{method:t,params:e},atMs:Date.now()});break;case"thread/name/updated":T(n,{method:t,params:e,type:"session_info_update",label:"session_info",update:{sessionUpdate:"session_info_update",title:a(e,"threadName")||null}});break;case"thread/status/changed":C(n,t,e,{threadStatus:a(e,"status")});break;case"thread/archived":C(n,t,e,{archived:!0});break;case"thread/unarchived":C(n,t,e,{archived:!1});break;case"thread/closed":C(n,t,e,{closed:!0});break;case"account/rateLimits/updated":T(n,{method:t,params:e,type:"session_info_update",label:"rate_limit",update:q(e)});break;case"configWarning":{const o=a(e,"summary"),s=a(e,"details"),u=`Config warning: ${o}${s?`
15
+ `;if(!o)break;n.pushStatus("exploring","执行命令",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:U(o,u)}},atMs:Date.now()});break}case"item/mcpToolCall/progress":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),s=a(e,"message").trim();if(!o||!s)break;n.pushStatus("exploring","调用工具",void 0,t),n.pushUpdate({type:"tool_call_update",label:"tool update",toolCallId:o,raw:{method:t,params:e,update:{sessionUpdate:"tool_call_update",toolCallId:o,_meta:{mcp_output_delta:{data:s,terminal_id:o}}}},atMs:Date.now()});break}case"turn/diff/updated":n.pushStatus("exploring","编辑文件中","diff",t),n.pushUpdate({type:"diff",label:"diff",text:a(e,"diff"),raw:{method:t,params:e},atMs:Date.now()});break;case"thread/tokenUsage/updated":n.pushUpdate({type:"usage_update",label:"usage",raw:{method:t,params:e},atMs:Date.now()});break;case"thread/name/updated":D(n,{method:t,params:e,type:"session_info_update",label:"session_info",update:{sessionUpdate:"session_info_update",title:a(e,"threadName")||null}});break;case"thread/status/changed":b(n,t,e,{threadStatus:a(e,"status")});break;case"thread/archived":b(n,t,e,{archived:!0});break;case"thread/unarchived":b(n,t,e,{archived:!1});break;case"thread/closed":b(n,t,e,{closed:!0});break;case"account/rateLimits/updated":D(n,{method:t,params:e,type:"session_info_update",label:"rate_limit",update:V(e)});break;case"configWarning":{const o=a(e,"summary"),s=a(e,"details"),u=`Config warning: ${o}${s?`
16
16
 
17
17
  ${s}`:""}
18
18
 
19
- `;n.pushUpdate({type:"agent_message_chunk",label:"message",text:u,raw:{method:t,params:e,update:y("agent_message_chunk",u)},atMs:Date.now()});break}case"warning":{const o=`Warning: ${a(e,"message")}
19
+ `;n.pushUpdate({type:"agent_message_chunk",label:"message",text:u,raw:{method:t,params:e,update:_("agent_message_chunk",u)},atMs:Date.now()});break}case"warning":{const o=`Warning: ${a(e,"message")}
20
20
 
21
- `;n.pushUpdate({type:"agent_message_chunk",label:"message",text:o,raw:{method:t,params:e,update:y("agent_message_chunk",o)},atMs:Date.now()});break}case"model/rerouted":{const o=`Model rerouted from ${a(e,"fromModel")} to ${a(e,"toModel")} (${a(e,"reason")}).
21
+ `;n.pushUpdate({type:"agent_message_chunk",label:"message",text:o,raw:{method:t,params:e,update:_("agent_message_chunk",o)},atMs:Date.now()});break}case"model/rerouted":{const o=`Model rerouted from ${a(e,"fromModel")} to ${a(e,"toModel")} (${a(e,"reason")}).
22
22
 
23
- `;n.pushStatus("thinking","模型已切换",w(o),t),n.pushUpdate({type:"agent_thought_chunk",label:"thought",text:o,raw:{method:t,params:e,update:y("agent_thought_chunk",o)},atMs:Date.now()});break}case"thread/compacted":{const o=`*Context compacted to fit the model's context window.*
23
+ `;n.pushStatus("thinking","模型已切换",w(o),t),n.pushUpdate({type:"agent_thought_chunk",label:"thought",text:o,raw:{method:t,params:e,update:_("agent_thought_chunk",o)},atMs:Date.now()});break}case"thread/compacted":{const o=`*Context compacted to fit the model's context window.*
24
24
 
25
- `;n.pushStatus("thinking","上下文已压缩",void 0,t),n.pushUpdate({type:"agent_message_chunk",label:"message",text:o,raw:{method:t,params:e,update:y("agent_message_chunk",o)},atMs:Date.now()});break}case"fuzzyFileSearch/sessionUpdated":{const o=G(e);n.pushStatus("exploring",a(o,"title")||"Search",pt(e),t),n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:a(o,"title")||"Search",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"fuzzyFileSearch/sessionCompleted":{const o=N(e);n.pushUpdate({type:"tool_call_update",label:"Search",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"item/autoApprovalReview/started":{const o=U(e,"started");n.pushStatus("exploring","Guardian Review",wt(e),t),n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:"Guardian Review",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"item/autoApprovalReview/completed":{const o=U(e,"completed");n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:"Guardian Review",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"account/updated":C(n,t,e,{account:d(e)??e});break;case"turn/started":n.pushStatus("thinking","思考中",void 0,t);break;case"turn/completed":n.pushStatus("completed","已完成",void 0,t);break;case"error":n.pushStatus("failed","执行失败",w(JSON.stringify(e)),t),n.pushUpdate({type:"error",label:"error",text:w(JSON.stringify(e)),raw:{method:t,params:e},atMs:Date.now()});break;default:O(t,e);break}}function O(t,e){if(process.env.ACA_CODEX_PROTOCOL_DEBUG!=="1")return;const n=d(e);console.debug("[codex] unhandled notification",{method:t,keys:n?Object.keys(n).slice(0,20):[],itemType:a(m(n,"item"),"type")||void 0})}function te(t){return(Array.isArray(t?.items)?t.items:[]).map(n=>a(n,"type")!=="agentMessage"?"":a(n,"text")).filter(Boolean).join(`
26
- `).trim()}function v(t){switch(t){case"commandExecution":return"执行命令中";case"fileChange":return"编辑文件中";case"mcpToolCall":case"dynamicToolCall":return"调用工具中";case"webSearch":return"搜索中";case"imageGeneration":return"生成图片中";case"reasoning":return"思考中";case"agentMessage":return"生成回复中";default:return"处理中"}}function $(t){switch(t){case"commandExecution":return"执行命令";case"fileChange":return"编辑文件";case"mcpToolCall":case"dynamicToolCall":return"调用工具";case"webSearch":case"fuzzyFileSearch":return"搜索";case"imageView":return"查看图片";case"imageGeneration":return"生成图片";default:return v(t)}}function lt(t,e){const n=c(e,["kind"]);return n==="read"?c(e,["title"])||"读取文件":n==="search"?c(e,["title"])||"搜索":n==="edit"?"编辑文件":n==="execute"?"执行命令":n==="think"?"思考中":n==="other"&&c(e,["title"])||$(t)}function R(t){return t==="imageGeneration"?"image_generation":t==="reasoning"||t==="agentMessage"||t==="plan"?"thinking":"exploring"}function ct(t){if(t)for(const e of["command","path","tool","server","query","text"]){const n=a(t,e);if(n)return w(n)}}function dt(t,e,n){const r=a(n,"type"),o=a(n,"id")||a(e,"itemId"),s=c(n,["rawInput","raw_input","command","query","path","text","input"]),u=r==="commandExecution"?c(n,["command","rawInput","raw_input"]):"",l=et(n),f=c(n,["path","filePath","file_path","relativePath","absolutePath"])||l.path,_=c(n,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),k=g(n,"commandActions")||g(n,"command_actions")||g(n,"actions")||M(n),nt=qt(r,_,n),at=Wt(r,{command:u,path:f,rawInput:s,item:n}),ot=w(Vt(u,f,s,_));return i({id:o,type:r,method:t,displayName:at,rawInput:s,raw_input:s,command:u,path:f,action:c(n,["action","changeType","operation"])||l.action,commandActions:k,command_actions:k.length>0?k:void 0,aggregatedOutput:_,aggregated_output:_,formatted_output:nt,summary:ot})}function j(t,e){if(!e)return null;switch(a(e,"type")){case"commandExecution":return t==="item/started"?Ct(e):bt(e);case"fileChange":return t==="item/started"?It(e):Ut(e);case"mcpToolCall":return t==="item/started"?St(e):At(e);case"dynamicToolCall":return t==="item/started"?vt(e):$t(e);case"webSearch":return t==="item/started"?Tt(e):Dt(e);case"imageView":return zt(e);case"imageGeneration":return t==="item/started"?Mt(e):Pt(e);default:return null}}function T(t,e){t.pushUpdate({type:e.type,label:e.label,raw:{method:e.method,params:e.params,update:e.update},atMs:Date.now()})}function C(t,e,n,r){T(t,{method:e,params:n,type:"session_info_update",label:"session_info",update:{sessionUpdate:"session_info_update",_meta:{codex:r}}})}function b(t){return{sessionUpdate:"session_info_update",_meta:{codex:t}}}function y(t,e){return{sessionUpdate:t,content:{type:"text",text:e}}}function E(t){return`fuzzyFileSearch.${t}`}function G(t){const e=a(t,"sessionId"),n=E(e),r=!S.has(n);S.add(n);const o=a(t,"query"),s=X(o,""),u=ft(t);return i(r?{sessionUpdate:"tool_call",toolCallId:n,kind:"search",title:s,status:"in_progress",locations:u,rawInput:{query:o}}:{sessionUpdate:"tool_call_update",toolCallId:n,title:s,status:"in_progress",locations:u})}function N(t){const e=a(t,"sessionId"),n=E(e);return S.delete(n),{sessionUpdate:"tool_call_update",toolCallId:n,status:"completed"}}function ft(t){const n=(g(d(t),"files")??[]).map(r=>{const o=d(r);if(!o)return"";const s=a(o,"path"),u=a(o,"root");return s?s.startsWith("/")||!u?s:`${u.replace(/\/+$/,"")}/${s.replace(/^\/+/,"")}`:""}).filter(Boolean).map(r=>({path:r}));return n.length>0?n:void 0}function pt(t){const e=a(t,"query"),r=(g(d(t),"files")??[]).length;if(e&&r)return`${e} · ${r} files`;if(e)return e;if(r)return`${r} files`}function ht(t){return`guardian_assessment:${t}`}function U(t,e){const n=a(t,"reviewId"),r=ht(n),o=e==="started"&&!A.has(n);e==="started"&&A.add(n),e==="completed"&&A.delete(n);const s=m(t,"review")??{},u={sessionUpdate:o?"tool_call":"tool_call_update",toolCallId:r,status:gt(a(s,"status")),content:_t(s,m(t,"action")),...o?{kind:"think",title:"Guardian Review",rawInput:t}:{rawOutput:t}};return i(u)}function gt(t){switch(t){case"inProgress":return"in_progress";case"approved":return"completed";case"denied":case"aborted":case"timedOut":return"failed";default:return t||"in_progress"}}function _t(t,e){const n=[`Status: ${L(a(t,"status"))}`],r=B(e);r&&n.push(`Action: ${r}`);const o=a(t,"riskLevel");o&&n.push(`Risk: ${o}`);const s=a(t,"userAuthorization");s&&n.push(`Authorization: ${s}`);const u=a(t,"rationale").trim();return u&&n.push(`Rationale: ${u}`),[{type:"content",content:{type:"text",text:n.join(`
27
- `)}}]}function L(t){switch(t){case"inProgress":return"In progress";case"approved":return"Approved";case"denied":return"Denied";case"aborted":return"Aborted";case"timedOut":return"Timed out";default:return t||"Unknown"}}function B(t){if(!t)return"";const e=a(t,"type");if(e==="command")return[W(a(t,"source")),a(t,"command")].filter(Boolean).join(" ");if(e==="execve"){const n=g(t,"argv")?.map(s=>p(s)).filter(Boolean)??[],r=a(t,"program"),o=n.length>0?n:[r].filter(Boolean);return[W(a(t,"source")),yt(o)].filter(Boolean).join(" ")}if(e==="applyPatch"){const n=g(t,"files")?.map(r=>p(r)).filter(Boolean)??[];return n.length===1?`apply_patch touching ${n[0]}`:`apply_patch touching ${n.length} files`}if(e==="networkAccess"){const n=a(t,"target")||a(t,"host");return n?`network access to ${n}`:"network access"}if(e==="mcpToolCall"){const n=a(t,"connectorName")||a(t,"server");return`MCP ${a(t,"toolName")} on ${n}`.trim()}return e==="requestPermissions"?a(t,"reason")||"request additional permissions":e}function W(t){return t==="shell"?"shell":t==="unifiedExec"?"exec":t}function yt(t){return t.map(mt).join(" ")}function mt(t){return t.length===0?"''":/^[A-Za-z0-9_/:=+.,@%-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}function wt(t){const e=m(t,"review"),n=e?L(a(e,"status")):"",r=B(m(t,"action"));return[n,r].filter(Boolean).join(" · ")||void 0}function q(t){const e=m(t,"rateLimits")??{},n=m(e,"primary"),r=m(e,"secondary");return i({sessionUpdate:"session_info_update",_meta:{rateLimits:i({planName:a(e,"planType"),limitName:a(e,"limitName"),limitId:a(e,"limitId"),fiveHour:P(n,"usedPercent")??null,sevenDay:P(r,"usedPercent")??null,fiveHourResetAt:a(n,"resetsAt")||null,sevenDayResetAt:a(r,"resetsAt")||null,raw:e})}})}function Ct(t){const e=a(t,"id"),n=a(t,"cwd"),r=a(t,"command"),o=Q(t),s=o.length===1?d(o[0]):null;if(s){const u=a(s,"type");if(u==="read"){const l=a(s,"path")||a(s,"name");return i({sessionUpdate:"tool_call",toolCallId:e,status:h(a(t,"status")),kind:"read",title:`Read file '${l}'`,locations:l?[{path:l}]:void 0})}if(u==="search"){const l=a(s,"query"),f=a(s,"path");return i({sessionUpdate:"tool_call",toolCallId:e,status:h(a(t,"status")),kind:"search",title:X(l,f)})}if(u==="listFiles"){const l=a(s,"path");return i({sessionUpdate:"tool_call",toolCallId:e,status:h(a(t,"status")),kind:"read",title:l?`List files in '${l}'`:"List files"})}}return jt({sessionUpdate:"tool_call",toolCallId:e,status:h(a(t,"status")),kind:"execute",title:Gt(r),rawInput:i({command:r,cwd:n})},e,n)}function bt(t){const e=a(t,"id"),n=c(t,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),r=P(t,"exitCode"),o={sessionUpdate:"tool_call_update",toolCallId:e,status:h(a(t,"status")),rawOutput:i({formatted_output:n,exit_code:r})};return Et(t)&&(o._meta={...n?I(e,n):{},terminal_exit:{exit_code:r,signal:null,terminal_id:e}}),i(o)}function It(t){const e=a(t,"id"),n=K(t);return i({sessionUpdate:"tool_call",toolCallId:e,title:"Editing files",kind:"edit",status:h(a(t,"status")),content:n,locations:Nt(t),rawInput:{changes:M(t)}})}function Ut(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:h(a(t,"status")),content:K(t)})}function xt(t){const e=c(t,["tool","name","server"]);return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:h(a(t,"status")),rawInput:d(t)})}function kt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:h(a(t,"status")),rawOutput:d(t)})}function St(t){const e=a(t,"server"),n=a(t,"tool");return i({...V(t,`mcp.${e}.${n}`,J(e,n,t.arguments),H(t.result,t.error)),_meta:{is_mcp_tool_call:!0}})}function At(t){const e=a(t,"server"),n=a(t,"tool");return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:h(a(t,"status")),rawInput:J(e,n,t.arguments),rawOutput:H(t.result,t.error)})}function vt(t){return V(t,a(t,"tool"),{arguments:t.arguments},void 0)}function $t(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:h(a(t,"status"))})}function V(t,e,n,r){return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:h(a(t,"status")),rawInput:n,rawOutput:r})}function J(t,e,n){return{server:t,tool:e,arguments:n}}function H(t,e){if(!(t===null&&e===null)&&!(t===void 0&&e===void 0))return{result:t,error:e}}function Tt(t){return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"search",title:Z(t),status:h(a(t,"status")),rawInput:d(t)})}function Dt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),title:Z(t),status:h(a(t,"status")),rawInput:d(t)})}function Mt(t){return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"other",title:"Image generation",status:"in_progress",rawInput:{id:a(t,"id")}})}function Pt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:Ft(a(t,"status")),content:Ot(t),rawOutput:Rt(t)})}function zt(t){const e=a(t,"path");return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"read",title:`View Image ${e}`,status:"completed",content:[{type:"content",content:{type:"resource_link",name:e,uri:e}}],locations:[{path:e}],rawInput:{path:e}})}function Ft(t){return t==="completed"?"completed":t==="failed"?"failed":"in_progress"}function Ot(t){const e=d(t.result),n=c(e,["url","uri","path"]);if(n)return[{type:"content",content:{type:"resource_link",name:n,uri:n}}]}function Rt(t){const e={status:t.status,revisedPrompt:t.revisedPrompt,result:t.result};return"savedPath"in t&&(e.savedPath=t.savedPath??null),e}function jt(t,e,n){return i({...t,content:[{type:"terminal",terminalId:e}],_meta:{terminal_info:{cwd:n,terminal_id:e}}})}function Et(t){const e=Q(t),n=e.length===1?d(e[0]):null;return!n||a(n,"type")==="unknown"}function Q(t){return g(t,"commandActions")||g(t,"command_actions")||g(t,"actions")||[]}function h(t){switch(t){case"inProgress":case"in_progress":case"started":case"":return"in_progress";case"completed":return"completed";case"failed":case"declined":case"cancelled":return"failed";default:return t}}function Gt(t){const e=t.replace(/^(?:\/bin\/)?(?:bash|zsh|sh)\s+(?:-[lc]+\s+)?/,"");return e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function I(t,e){return{terminal_output_delta:{data:e,terminal_id:t}}}function X(t,e){return t&&e?`Search for '${t}' in ${e}`:t?`Search for '${t}'`:e?`Search in '${e}'`:"Search"}function Z(t){const e=d(t.action);if(!e){const r=a(t,"query");return r?`Web search: ${r}`:"Web search"}const n=a(e,"type");if(n==="search"){const r=g(e,"queries")?.map(s=>p(s)).filter(Boolean)??[],o=a(e,"query")||(r.length>0?r.join(", "):"")||a(t,"query");return o?`Web search: ${o}`:"Web search"}if(n==="openPage"){const r=a(e,"url");return r?`Open page: ${r}`:"Open page"}if(n==="findInPage"){const r=a(e,"pattern")?` for '${a(e,"pattern")}'`:"",o=a(e,"url")?` in ${a(e,"url")}`:"";return`Find in page${r}${o}`.trim()}return"Web search"}function Nt(t){const e=M(t).map(n=>d(n)).map(n=>a(n,"path")).filter(Boolean).map(n=>({path:n}));return e.length>0?e:void 0}function K(t){const n=(g(t,"changes")??[]).map(r=>{const o=d(r);if(!o)return null;const s=p(o.path),u=o.kind&&typeof o.kind=="object"&&!Array.isArray(o.kind)?p(o.kind.type):p(o.kind),l=p(o.diff);return u==="add"?i({type:"diff",oldText:null,newText:l,path:s,_meta:{kind:"add"}}):u==="delete"?i({type:"diff",oldText:l,newText:"",path:s,_meta:{kind:"delete"}}):Lt(o,s,l,u)}).filter(Boolean);return n.length>0?n:void 0}function Lt(t,e,n,r){const o=t.kind&&typeof t.kind=="object"&&!Array.isArray(t.kind)?p(t.kind.move_path):"",s=Bt(n),u=Y(e);if(u!==null){const l=D(u,s);if(l!==!1)return x(o||e,u,l,r||"update");const f=tt(s);if(f){const _=D(u,f);if(_!==!1)return x(e,_,u,r||"update")}}if(o){const l=Y(o),f=tt(s);if(l!==null&&f){const _=D(l,f);if(_!==!1)return x(o,_,l,r||"update")}}return x(o||e,null,s,r||"update")}function x(t,e,n,r){return i({type:"diff",oldText:e,newText:n,path:t,_meta:{kind:r}})}function Y(t){try{return rt(t,"utf8")}catch{return null}}function Bt(t){return t.replace(/\n\nMoved to: .*$/,"")}function tt(t){try{const[e]=ut(t);return e?it(e):null}catch{return null}}function D(t,e){try{return st(t,e)}catch{return!1}}function Wt(t,e){if(t==="commandExecution")return"执行命令";if(t==="fileChange")return e.path?`编辑文件: ${Jt(e.path)}`:"编辑文件";if(t==="webSearch")return e.rawInput?`搜索: ${w(e.rawInput)}`:"搜索";if(t==="mcpToolCall"||t==="dynamicToolCall"){const n=c(e.item,["tool","name","server"]);return n?`调用工具: ${n}`:"调用工具"}return v(t)}function qt(t,e,n){if(e)return e;if(t==="fileChange"){const r=et(n),o=c(n,["path","filePath","file_path","relativePath","absolutePath"])||r.path;return[c(n,["action","changeType","operation"])||r.action,o].filter(Boolean).join(" ")}return""}function et(t){const e=g(t,"changes")??[];for(const n of e){if(!n||typeof n!="object"||Array.isArray(n))continue;const r=n,o=p(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?p(r.kind.type):p(r.kind);if(o||s)return{path:o,action:s}}return{path:"",action:""}}function M(t){return(g(t,"changes")??[]).map(n=>{if(!n||typeof n!="object"||Array.isArray(n))return null;const r=n,o=p(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?p(r.kind.type):p(r.kind);return!o&&!s?null:i({type:s||"edit",path:o})}).filter(Boolean).slice(0,50)}function c(t,e){if(!t)return"";for(const n of e){const r=p(t[n]);if(r)return r}return""}function p(t){if(typeof t=="string"&&t.trim())return t.trim();if(typeof t=="number"||typeof t=="boolean")return String(t);if(t&&typeof t=="object")try{const e=JSON.stringify(t);return e.length>2?e:""}catch{return""}return""}function g(t,e){const n=t?.[e];return Array.isArray(n)?n.slice(0,50):null}function Vt(...t){return t.find(e=>e.trim())||""}function Jt(t){return t.replace(/\\/g,"/").split("/").filter(Boolean).pop()||t}function i(t){for(const e of Object.keys(t)){const n=t[e];(n===void 0||n===""||Array.isArray(n)&&n.length===0)&&delete t[e]}return t}function m(t,e){if(!t||typeof t!="object"||Array.isArray(t))return null;const n=t[e];return!n||typeof n!="object"||Array.isArray(n)?null:n}function d(t){return!t||typeof t!="object"||Array.isArray(t)?null:t}function a(t,e){if(!t||typeof t!="object"||Array.isArray(t))return"";const n=t[e];return typeof n=="string"?n:""}function P(t,e){if(!t||typeof t!="object"||Array.isArray(t))return;const n=t[e];return typeof n=="number"&&Number.isFinite(n)?n:void 0}function w(t){if(typeof t!="string")return;const e=t.replace(/\s+/g," ").trim();if(e)return e.length>120?`${e.slice(0,117)}...`:e}export{Kt as codexAcpSessionUpdatesFromNotification,te as extractAssistantTextFromTurn,Yt as mapCodexNotification};
25
+ `;n.pushStatus("thinking","上下文已压缩",void 0,t),n.pushUpdate({type:"agent_message_chunk",label:"message",text:o,raw:{method:t,params:e,update:_("agent_message_chunk",o)},atMs:Date.now()});break}case"fuzzyFileSearch/sessionUpdated":{const o=N(e);n.pushStatus("exploring",a(o,"title")||"Search",ht(e),t),n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:a(o,"title")||"Search",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"fuzzyFileSearch/sessionCompleted":{const o=L(e);n.pushUpdate({type:"tool_call_update",label:"Search",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"item/autoApprovalReview/started":{const o=x(e,"started");n.pushStatus("exploring","Guardian Review",Ct(e),t),n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:"Guardian Review",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"item/autoApprovalReview/completed":{const o=x(e,"completed");n.pushUpdate({type:o.sessionUpdate==="tool_call"?"tool_call":"tool_call_update",label:"Guardian Review",status:a(o,"status"),toolCallId:a(o,"toolCallId"),raw:{method:t,params:e,update:o},atMs:Date.now()});break}case"account/updated":b(n,t,e,{account:d(e)??e});break;case"turn/started":n.pushStatus("thinking","思考中",void 0,t);break;case"turn/completed":n.pushStatus("completed","已完成",void 0,t);break;case"error":n.pushStatus("failed","执行失败",w(JSON.stringify(e)),t),n.pushUpdate({type:"error",label:"error",text:w(JSON.stringify(e)),raw:{method:t,params:e},atMs:Date.now()});break;default:R(t,e);break}}function R(t,e){if(process.env.ACA_CODEX_PROTOCOL_DEBUG!=="1")return;const n=d(e);console.debug("[codex] unhandled notification",{method:t,keys:n?Object.keys(n).slice(0,20):[],itemType:a(y(n,"item"),"type")||void 0})}function ee(t){return(Array.isArray(t?.items)?t.items:[]).map(n=>a(n,"type")!=="agentMessage"?"":a(n,"text")).filter(Boolean).join(`
26
+ `).trim()}function $(t){switch(t){case"commandExecution":return"执行命令中";case"fileChange":return"编辑文件中";case"mcpToolCall":case"dynamicToolCall":return"调用工具中";case"webSearch":return"搜索中";case"imageGeneration":return"生成图片中";case"reasoning":return"思考中";case"agentMessage":return"生成回复中";default:return"处理中"}}function T(t){switch(t){case"commandExecution":return"执行命令";case"fileChange":return"编辑文件";case"mcpToolCall":case"dynamicToolCall":return"调用工具";case"webSearch":case"fuzzyFileSearch":return"搜索";case"imageView":return"查看图片";case"imageGeneration":return"生成图片";default:return $(t)}}function ct(t,e){const n=c(e,["kind"]);return n==="read"?c(e,["title"])||"读取文件":n==="search"?c(e,["title"])||"搜索":n==="edit"?"编辑文件":n==="execute"?"执行命令":n==="think"?"思考中":n==="other"&&c(e,["title"])||T(t)}function j(t){return t==="imageGeneration"?"image_generation":t==="reasoning"||t==="agentMessage"||t==="plan"?"thinking":"exploring"}function dt(t){if(t)for(const e of["command","path","tool","server","query","text"]){const n=a(t,e);if(n)return w(n)}}function ft(t,e,n){const r=a(n,"type"),o=a(n,"id")||a(e,"itemId"),s=c(n,["rawInput","raw_input","command","query","path","text","input"]),u=r==="commandExecution"?c(n,["command","rawInput","raw_input"]):"",l=nt(n),f=c(n,["path","filePath","file_path","relativePath","absolutePath"])||l.path,g=c(n,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),S=h(n,"commandActions")||h(n,"command_actions")||h(n,"actions")||P(n),at=Vt(r,g,n),ot=qt(r,{command:u,path:f,rawInput:s,item:n}),rt=w(Jt(u,f,s,g));return i({id:o,type:r,method:t,displayName:ot,rawInput:s,raw_input:s,command:u,path:f,action:c(n,["action","changeType","operation"])||l.action,commandActions:S,command_actions:S.length>0?S:void 0,aggregatedOutput:g,aggregated_output:g,formatted_output:at,summary:rt})}function E(t,e){if(!e)return null;switch(a(e,"type")){case"commandExecution":return t==="item/started"?bt(e):It(e);case"fileChange":return t==="item/started"?Ut(e):xt(e);case"mcpToolCall":return t==="item/started"?At(e):vt(e);case"dynamicToolCall":return t==="item/started"?$t(e):Tt(e);case"webSearch":return t==="item/started"?Dt(e):Mt(e);case"imageView":return Ft(e);case"imageGeneration":return t==="item/started"?Pt(e):zt(e);default:return null}}function D(t,e){t.pushUpdate({type:e.type,label:e.label,raw:{method:e.method,params:e.params,update:e.update},atMs:Date.now()})}function b(t,e,n,r){D(t,{method:e,params:n,type:"session_info_update",label:"session_info",update:{sessionUpdate:"session_info_update",_meta:{codex:r}}})}function I(t){return{sessionUpdate:"session_info_update",_meta:{codex:t}}}function _(t,e){return{sessionUpdate:t,content:{type:"text",text:e}}}function G(t){return`fuzzyFileSearch.${t}`}function N(t){const e=a(t,"sessionId"),n=G(e),r=!A.has(n);A.add(n);const o=a(t,"query"),s=Z(o,""),u=pt(t);return i(r?{sessionUpdate:"tool_call",toolCallId:n,kind:"search",title:s,status:"in_progress",locations:u,rawInput:{query:o}}:{sessionUpdate:"tool_call_update",toolCallId:n,title:s,status:"in_progress",locations:u})}function L(t){const e=a(t,"sessionId"),n=G(e);return A.delete(n),{sessionUpdate:"tool_call_update",toolCallId:n,status:"completed"}}function pt(t){const n=(h(d(t),"files")??[]).map(r=>{const o=d(r);if(!o)return"";const s=a(o,"path"),u=a(o,"root");return s?s.startsWith("/")||!u?s:`${u.replace(/\/+$/,"")}/${s.replace(/^\/+/,"")}`:""}).filter(Boolean).map(r=>({path:r}));return n.length>0?n:void 0}function ht(t){const e=a(t,"query"),r=(h(d(t),"files")??[]).length;if(e&&r)return`${e} · ${r} files`;if(e)return e;if(r)return`${r} files`}function gt(t){return`guardian_assessment:${t}`}function x(t,e){const n=a(t,"reviewId"),r=gt(n),o=e==="started"&&!v.has(n);e==="started"&&v.add(n),e==="completed"&&v.delete(n);const s=y(t,"review")??{},u={sessionUpdate:o?"tool_call":"tool_call_update",toolCallId:r,status:_t(a(s,"status")),content:yt(s,y(t,"action")),...o?{kind:"think",title:"Guardian Review",rawInput:t}:{rawOutput:t}};return i(u)}function _t(t){switch(t){case"inProgress":return"in_progress";case"approved":return"completed";case"denied":case"aborted":case"timedOut":return"failed";default:return t||"in_progress"}}function yt(t,e){const n=[`Status: ${B(a(t,"status"))}`],r=W(e);r&&n.push(`Action: ${r}`);const o=a(t,"riskLevel");o&&n.push(`Risk: ${o}`);const s=a(t,"userAuthorization");s&&n.push(`Authorization: ${s}`);const u=a(t,"rationale").trim();return u&&n.push(`Rationale: ${u}`),[{type:"content",content:{type:"text",text:n.join(`
27
+ `)}}]}function B(t){switch(t){case"inProgress":return"In progress";case"approved":return"Approved";case"denied":return"Denied";case"aborted":return"Aborted";case"timedOut":return"Timed out";default:return t||"Unknown"}}function W(t){if(!t)return"";const e=a(t,"type");if(e==="command")return[q(a(t,"source")),a(t,"command")].filter(Boolean).join(" ");if(e==="execve"){const n=h(t,"argv")?.map(s=>p(s)).filter(Boolean)??[],r=a(t,"program"),o=n.length>0?n:[r].filter(Boolean);return[q(a(t,"source")),mt(o)].filter(Boolean).join(" ")}if(e==="applyPatch"){const n=h(t,"files")?.map(r=>p(r)).filter(Boolean)??[];return n.length===1?`apply_patch touching ${n[0]}`:`apply_patch touching ${n.length} files`}if(e==="networkAccess"){const n=a(t,"target")||a(t,"host");return n?`network access to ${n}`:"network access"}if(e==="mcpToolCall"){const n=a(t,"connectorName")||a(t,"server");return`MCP ${a(t,"toolName")} on ${n}`.trim()}return e==="requestPermissions"?a(t,"reason")||"request additional permissions":e}function q(t){return t==="shell"?"shell":t==="unifiedExec"?"exec":t}function mt(t){return t.map(wt).join(" ")}function wt(t){return t.length===0?"''":/^[A-Za-z0-9_/:=+.,@%-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}function Ct(t){const e=y(t,"review"),n=e?B(a(e,"status")):"",r=W(y(t,"action"));return[n,r].filter(Boolean).join(" · ")||void 0}function V(t){const e=y(t,"rateLimits")??{},n=y(e,"primary"),r=y(e,"secondary");return i({sessionUpdate:"session_info_update",_meta:{rateLimits:i({planName:a(e,"planType"),limitName:a(e,"limitName"),limitId:a(e,"limitId"),fiveHour:z(n,"usedPercent")??null,sevenDay:z(r,"usedPercent")??null,fiveHourResetAt:a(n,"resetsAt")||null,sevenDayResetAt:a(r,"resetsAt")||null,raw:e})}})}function bt(t){const e=a(t,"id"),n=a(t,"cwd"),r=a(t,"command"),o=X(t),s=o.length===1?d(o[0]):null;if(s){const u=a(s,"type");if(u==="read"){const l=a(s,"path")||a(s,"name");return i({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"read",title:`Read file '${l}'`,locations:l?[{path:l}]:void 0})}if(u==="search"){const l=a(s,"query"),f=a(s,"path");return i({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"search",title:Z(l,f)})}if(u==="listFiles"){const l=a(s,"path");return i({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"read",title:l?`List files in '${l}'`:"List files"})}}return Et({sessionUpdate:"tool_call",toolCallId:e,status:m(a(t,"status")),kind:"execute",title:Nt(r),rawInput:i({command:r,cwd:n})},e,n)}function It(t){const e=a(t,"id"),n=c(t,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),r=z(t,"exitCode"),o={sessionUpdate:"tool_call_update",toolCallId:e,status:C(a(t,"status"),r),rawOutput:i({formatted_output:n,exit_code:r})};return Gt(t)&&(o._meta={...n?U(e,n):{},terminal_exit:{exit_code:r,signal:null,terminal_id:e}}),i(o)}function Ut(t){const e=a(t,"id"),n=Y(t);return i({sessionUpdate:"tool_call",toolCallId:e,title:"Editing files",kind:"edit",status:m(a(t,"status")),content:n,locations:Lt(t),rawInput:{changes:P(t)}})}function xt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:C(a(t,"status")),content:Y(t)})}function kt(t){const e=c(t,["tool","name","server"]);return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:m(a(t,"status")),rawInput:d(t)})}function St(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:C(a(t,"status")),rawOutput:d(t)})}function At(t){const e=a(t,"server"),n=a(t,"tool");return i({...J(t,`mcp.${e}.${n}`,H(e,n,t.arguments),Q(t.result,t.error)),_meta:{is_mcp_tool_call:!0}})}function vt(t){const e=a(t,"server"),n=a(t,"tool");return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:C(a(t,"status")),rawInput:H(e,n,t.arguments),rawOutput:Q(t.result,t.error)})}function $t(t){return J(t,a(t,"tool"),{arguments:t.arguments},void 0)}function Tt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:C(a(t,"status"))})}function J(t,e,n,r){return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:m(a(t,"status")),rawInput:n,rawOutput:r})}function H(t,e,n){return{server:t,tool:e,arguments:n}}function Q(t,e){if(!(t===null&&e===null)&&!(t===void 0&&e===void 0))return{result:t,error:e}}function Dt(t){return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"search",title:K(t),status:m(a(t,"status")),rawInput:d(t)})}function Mt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),title:K(t),status:C(a(t,"status")),rawInput:d(t)})}function Pt(t){return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"other",title:"Image generation",status:"in_progress",rawInput:{id:a(t,"id")}})}function zt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:Ot(a(t,"status")),content:Rt(t),rawOutput:jt(t)})}function Ft(t){const e=a(t,"path");return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"read",title:`View Image ${e}`,status:"completed",content:[{type:"content",content:{type:"resource_link",name:e,uri:e}}],locations:[{path:e}],rawInput:{path:e}})}function Ot(t){return C(t)}function Rt(t){const e=d(t.result),n=c(e,["url","uri","path"]);if(n)return[{type:"content",content:{type:"resource_link",name:n,uri:n}}]}function jt(t){const e={status:t.status,revisedPrompt:t.revisedPrompt,result:t.result};return"savedPath"in t&&(e.savedPath=t.savedPath??null),e}function Et(t,e,n){return i({...t,content:[{type:"terminal",terminalId:e}],_meta:{terminal_info:{cwd:n,terminal_id:e}}})}function Gt(t){const e=X(t),n=e.length===1?d(e[0]):null;return!n||a(n,"type")==="unknown"}function X(t){return h(t,"commandActions")||h(t,"command_actions")||h(t,"actions")||[]}function m(t){switch(t){case"inProgress":case"in_progress":case"started":case"":return"in_progress";case"completed":return"completed";case"failed":case"declined":return"failed";case"cancelled":case"canceled":return"cancelled";default:return t}}function C(t,e){const n=m(t);return n==="failed"||n==="cancelled"?n:e!=null?e===0?"completed":"failed":n==="in_progress"?"completed":n}function Nt(t){const e=t.replace(/^(?:\/bin\/)?(?:bash|zsh|sh)\s+(?:-[lc]+\s+)?/,"");return e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function U(t,e){return{terminal_output_delta:{data:e,terminal_id:t}}}function Z(t,e){return t&&e?`Search for '${t}' in ${e}`:t?`Search for '${t}'`:e?`Search in '${e}'`:"Search"}function K(t){const e=d(t.action);if(!e){const r=a(t,"query");return r?`Web search: ${r}`:"Web search"}const n=a(e,"type");if(n==="search"){const r=h(e,"queries")?.map(s=>p(s)).filter(Boolean)??[],o=a(e,"query")||(r.length>0?r.join(", "):"")||a(t,"query");return o?`Web search: ${o}`:"Web search"}if(n==="openPage"){const r=a(e,"url");return r?`Open page: ${r}`:"Open page"}if(n==="findInPage"){const r=a(e,"pattern")?` for '${a(e,"pattern")}'`:"",o=a(e,"url")?` in ${a(e,"url")}`:"";return`Find in page${r}${o}`.trim()}return"Web search"}function Lt(t){const e=P(t).map(n=>d(n)).map(n=>a(n,"path")).filter(Boolean).map(n=>({path:n}));return e.length>0?e:void 0}function Y(t){const n=(h(t,"changes")??[]).map(r=>{const o=d(r);if(!o)return null;const s=p(o.path),u=o.kind&&typeof o.kind=="object"&&!Array.isArray(o.kind)?p(o.kind.type):p(o.kind),l=p(o.diff);return u==="add"?i({type:"diff",oldText:null,newText:l,path:s,_meta:{kind:"add"}}):u==="delete"?i({type:"diff",oldText:l,newText:"",path:s,_meta:{kind:"delete"}}):Bt(o,s,l,u)}).filter(Boolean);return n.length>0?n:void 0}function Bt(t,e,n,r){const o=t.kind&&typeof t.kind=="object"&&!Array.isArray(t.kind)?p(t.kind.move_path):"",s=Wt(n),u=tt(e);if(u!==null){const l=M(u,s);if(l!==!1)return k(o||e,u,l,r||"update");const f=et(s);if(f){const g=M(u,f);if(g!==!1)return k(e,g,u,r||"update")}}if(o){const l=tt(o),f=et(s);if(l!==null&&f){const g=M(l,f);if(g!==!1)return k(o,g,l,r||"update")}}return k(o||e,null,s,r||"update")}function k(t,e,n,r){return i({type:"diff",oldText:e,newText:n,path:t,_meta:{kind:r}})}function tt(t){try{return st(t,"utf8")}catch{return null}}function Wt(t){return t.replace(/\n\nMoved to: .*$/,"")}function et(t){try{const[e]=it(t);return e?lt(e):null}catch{return null}}function M(t,e){try{return ut(t,e)}catch{return!1}}function qt(t,e){if(t==="commandExecution")return"执行命令";if(t==="fileChange")return e.path?`编辑文件: ${Ht(e.path)}`:"编辑文件";if(t==="webSearch")return e.rawInput?`搜索: ${w(e.rawInput)}`:"搜索";if(t==="mcpToolCall"||t==="dynamicToolCall"){const n=c(e.item,["tool","name","server"]);return n?`调用工具: ${n}`:"调用工具"}return $(t)}function Vt(t,e,n){if(e)return e;if(t==="fileChange"){const r=nt(n),o=c(n,["path","filePath","file_path","relativePath","absolutePath"])||r.path;return[c(n,["action","changeType","operation"])||r.action,o].filter(Boolean).join(" ")}return""}function nt(t){const e=h(t,"changes")??[];for(const n of e){if(!n||typeof n!="object"||Array.isArray(n))continue;const r=n,o=p(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?p(r.kind.type):p(r.kind);if(o||s)return{path:o,action:s}}return{path:"",action:""}}function P(t){return(h(t,"changes")??[]).map(n=>{if(!n||typeof n!="object"||Array.isArray(n))return null;const r=n,o=p(r.path),s=r.kind&&typeof r.kind=="object"&&!Array.isArray(r.kind)?p(r.kind.type):p(r.kind);return!o&&!s?null:i({type:s||"edit",path:o})}).filter(Boolean).slice(0,50)}function c(t,e){if(!t)return"";for(const n of e){const r=p(t[n]);if(r)return r}return""}function p(t){if(typeof t=="string"&&t.trim())return t.trim();if(typeof t=="number"||typeof t=="boolean")return String(t);if(t&&typeof t=="object")try{const e=JSON.stringify(t);return e.length>2?e:""}catch{return""}return""}function h(t,e){const n=t?.[e];return Array.isArray(n)?n.slice(0,50):null}function Jt(...t){return t.find(e=>e.trim())||""}function Ht(t){return t.replace(/\\/g,"/").split("/").filter(Boolean).pop()||t}function i(t){for(const e of Object.keys(t)){const n=t[e];(n===void 0||n===""||Array.isArray(n)&&n.length===0)&&delete t[e]}return t}function y(t,e){if(!t||typeof t!="object"||Array.isArray(t))return null;const n=t[e];return!n||typeof n!="object"||Array.isArray(n)?null:n}function d(t){return!t||typeof t!="object"||Array.isArray(t)?null:t}function a(t,e){if(!t||typeof t!="object"||Array.isArray(t))return"";const n=t[e];return typeof n=="string"?n:""}function z(t,e){if(!t||typeof t!="object"||Array.isArray(t))return;const n=t[e];return typeof n=="number"&&Number.isFinite(n)?n:void 0}function w(t){if(typeof t!="string")return;const e=t.replace(/\s+/g," ").trim();if(e)return e.length>120?`${e.slice(0,117)}...`:e}export{Yt as codexAcpSessionUpdatesFromNotification,ee as extractAssistantTextFromTurn,te as mapCodexNotification};
@@ -1,5 +1,5 @@
1
- import{JsonLineRpcClient as R}from"../../client/json-rpc.js";import{startCodexAppServer as q}from"../codex/codex-process.js";import{codexAcpSessionUpdatesFromNotification as _}from"../codex/events.js";import{CodexPlanDeltaState as M}from"../codex/plan-events.js";import{isCodexApprovalRequest as b,resolveCodexApprovalRequest as k}from"../codex/permissions.js";import{buildCodexContinuityInstructions as E,codexTokenUsageFromNotification as F,decideCodexContextMaintenance as v,readCodexContextMaintenancePolicy as A,rolloutFileSize as U}from"./context-maintenance.js";class j{lineBuffer="";started=null;rpc=null;codexStartupPromise=null;initialized=!1;currentSessionId=null;currentCwd=process.cwd();promptActive=!1;currentTurnId=null;nextParentRequestId=1;pendingParentRequests=new Map;completedTurns=new Map;pendingTurnCompletions=new Map;agentMessagePhases=new Map;planDeltas=new M;config={};sessionAliases=new Map;currentAffectedFiles=new Set;latestTokenUsage=null;currentRolloutPath=null;threadTurnCount=0;currentPromptText="";currentAssistantText="";previousUserText="";previousAssistantText="";previousAffectedFiles=new Set;maintenanceActive=!1;pendingCompaction=null;shutdownPromise=null;constructor(){process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>this.handleInput(String(t)));const e=()=>{this.shutdown().finally(()=>process.exit(0))};process.stdin.once("end",e),process.stdin.once("close",e),process.stdin.once("error",e),process.once("SIGTERM",()=>{this.shutdown().finally(()=>process.exit(0))}),process.once("SIGINT",()=>{this.shutdown().finally(()=>process.exit(130))})}handleInput(e){this.lineBuffer+=e;const t=this.lineBuffer.split(`
2
- `);this.lineBuffer=t.pop()??"";for(const s of t){const r=s.trim();if(!r)continue;let o;try{o=JSON.parse(r)}catch{continue}this.handleMessage(o)}}async handleMessage(e){if("id"in e&&("result"in e||"error"in e)&&typeof e.method!="string"){this.handleParentResponse(e);return}const t=typeof e.method=="string"?e.method:"",s=e.id;if(t){if(s===void 0){await this.handleNotification(t,u(e.params));return}try{const r=await this.handleRequest(t,u(e.params));this.write({jsonrpc:"2.0",id:s,result:r})}catch(r){this.write({jsonrpc:"2.0",id:s,error:{code:-32603,message:r instanceof Error?r.message:String(r)}})}}}async handleNotification(e,t){e==="session/cancel"&&await this.cancel(t)}async handleRequest(e,t){switch(e){case"initialize":return this.initializeResponse();case"session/new":return this.newSession(t);case"session/resume":case"session/load":return this.resumeSession(t);case"session/prompt":return this.prompt(t);case"session/compact":return this.manualCompact(t);case"session/cancel":return await this.cancel(t),{};case"session/close":return await this.closeSession(t),{};case"session/set_config_option":return this.setConfigOption(t);case"session/set_mode":return this.setMode(t);case"fs/read_text_file":case"fs/write_text_file":case"terminal/create":case"terminal/output":case"terminal/wait_for_exit":case"terminal/kill":case"terminal/release":return{};default:throw new Error(`Unsupported ACP method: ${e}`)}}initializeResponse(){return{protocolVersion:1,agentCapabilities:{loadSession:!0,sessionCapabilities:{resume:!0,close:!0}}}}async newSession(e){const t=a(e,"cwd")||process.cwd();this.applyInitialConfig(e),await this.ensureCodex(t);const s=await this.requireRpc().request("thread/start",{cwd:t,approvalsReviewer:"user",...this.codexConfig(),ephemeral:!1,threadSource:"aca-codex-acp"},6e4),r=T(s);if(!r)throw new Error("Codex thread/start did not return thread id");return this.currentSessionId=r,this.currentCwd=t,this.captureThreadMetadata(s),this.sessionResponse(r)}async resumeSession(e){const t=a(e,"sessionId");if(!t)throw new Error("sessionId is required");const s=a(e,"cwd")||this.currentCwd;this.applyInitialConfig(e),await this.ensureCodex(s);const r=await this.requireRpc().request("thread/resume",{threadId:t,cwd:s,approvalsReviewer:"user",...this.codexConfig()},6e4);return this.currentSessionId=T(r)||t,this.currentCwd=s,this.captureThreadMetadata(r),this.sessionResponse(this.currentSessionId)}async prompt(e){const t=a(e,"sessionId")||this.currentSessionId;let s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");const r=Array.isArray(e.prompt)?e.prompt:[],o=this.requireRpc();this.currentSessionId=s,this.promptActive=!0,this.currentTurnId=null,this.currentPromptText=$(r),this.currentAssistantText="",this.currentAffectedFiles.clear(),this.agentMessagePhases.clear(),this.planDeltas.reset();let i;try{i=await o.request("turn/start",{threadId:s,clientUserMessageId:`aca-acp-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:N(r),cwd:this.currentCwd,...D(this.config)},P());const c=String(i?.turn?.id??"");this.currentTurnId=c||null;const l=c?await this.waitForTurnCompleted(c,P()):i?.turn;this.threadTurnCount+=1,this.previousUserText=this.currentPromptText,this.previousAssistantText=this.currentAssistantText,this.previousAffectedFiles.clear();for(const d of this.currentAffectedFiles)this.previousAffectedFiles.add(d);return{stopReason:"end_turn",sessionId:this.currentSessionId,turn:l,_meta:{acaContextUsage:W(this.latestTokenUsage)}}}finally{this.promptActive=!1,this.currentTurnId=null}}async cancel(e){const t=a(e,"sessionId")||this.currentSessionId;if(!(!t||!this.rpc)&&(await this.rpc.request("turn/interrupt",{threadId:t}).catch(()=>{}),this.currentTurnId)){const s=this.pendingTurnCompletions.get(this.currentTurnId);s&&(this.pendingTurnCompletions.delete(this.currentTurnId),clearTimeout(s.timer),s.reject(new Error("Codex prompt cancelled")))}}async manualCompact(e){const t=a(e,"sessionId")||this.currentSessionId,s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");if(this.promptActive||this.maintenanceActive)throw new Error("Codex session is busy");this.currentSessionId=s;const r=A(),o=await this.maintainContext("manual",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{force:!0,allowRollover:e.allowRollover===!0,compactTimeoutMs:B(e,r.compactTimeoutMs)}),i=String(o.action||"");if(i==="compact_failed"||i==="rollover_failed"){const c=String(o.compactError||"Codex 上下文压缩未完成");throw new Error(`Codex 上下文压缩失败:${c}`)}return{sessionId:this.currentSessionId,maintenance:o,contextUsage:z(o)}}async closeSession(e){await this.shutdown()}async ensureCodex(e){if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;if(this.codexStartupPromise){await this.codexStartupPromise;return}const t=(async()=>{if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;const s=q(e),r=new R(s.child,{peerName:"Codex app-server",onNotification:(o,i)=>this.handleCodexNotification(o,i),onRequest:async(o,i)=>this.handleCodexRequest(o,i)});this.started=s,this.rpc=r,this.initialized=!1,await r.request("initialize",{clientInfo:{name:"aca-codex-acp",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},6e4),this.initialized=!0})();this.codexStartupPromise=t;try{await t}catch(s){throw this.rpc&&this.started&&!this.initialized&&await C(this.started.child,1e3),this.rpc=null,this.started=null,s}finally{this.codexStartupPromise===t&&(this.codexStartupPromise=null)}}handleCodexNotification(e,t){if(this.captureContextNotification(e,t),!this.maintenanceActive&&!(!this.promptActive&&e!=="turn/completed")){this.rpc?.refreshPendingRequestTimeout("turn/start"),this.captureAgentMessagePhase(e,t),e==="turn/completed"&&this.resolveTurnCompleted(t);for(const s of _(e,t,{agentMessagePhases:this.agentMessagePhases,planDeltas:this.planDeltas}))this.captureUpdateEvidence(s),this.notify("session/update",{sessionId:this.currentSessionId,update:s})}}async handleCodexRequest(e,t){if(b(e))return k(e,t,async s=>{const r=await this.requestParent("session/request_permission",{sessionId:this.currentSessionId,request:{...s,params:t,method:e}}),o=u(r),i=u(o.outcome);return i.outcome==="selected"&&typeof i.optionId=="string"?{outcome:{outcome:"selected",optionId:i.optionId}}:{outcome:{outcome:"cancelled"}}});if(L(e)){const s=await this.requestParent("elicitation/create",{sessionId:this.currentSessionId,request:{...u(t),method:e}}),r=u(s),o=u(r.outcome);return o.outcome==="submitted"?{outcome:{outcome:"submitted",value:typeof o.value=="string"?o.value:""}}:{outcome:{outcome:"cancelled"}}}return{}}captureAgentMessagePhase(e,t){if(e!=="item/started"&&e!=="item/completed")return;const s=h(t,"item");if(a(s,"type")!=="agentMessage")return;const r=a(s,"id");r&&this.agentMessagePhases.set(r,a(s,"phase"))}waitForTurnCompleted(e,t){const s=this.completedTurns.get(e);return s?Promise.resolve(s):new Promise((r,o)=>{const i=setTimeout(()=>{this.pendingTurnCompletions.delete(e),o(new Error("Codex app-server request timed out while waiting for turn/completed"))},t);i.unref(),this.pendingTurnCompletions.set(e,{resolve:r,reject:o,timer:i})})}resolveTurnCompleted(e){const t=h(e,"turn"),s=a(t,"id");if(!s)return;this.completedTurns.set(s,t);const r=this.pendingTurnCompletions.get(s);if(r){if(this.pendingTurnCompletions.delete(s),clearTimeout(r.timer),a(t,"status")==="failed"){r.reject(new Error(`Codex turn failed: ${JSON.stringify(t.error??{})}`));return}r.resolve(t)}}async shutdown(){return this.shutdownPromise?this.shutdownPromise:(this.shutdownPromise=this.performShutdown(),this.shutdownPromise)}async performShutdown(){this.pendingCompaction&&(clearTimeout(this.pendingCompaction.timer),this.pendingCompaction.reject(new Error("Codex ACP adapter closed")),this.pendingCompaction=null);for(const t of this.pendingParentRequests.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingParentRequests.clear();for(const t of this.pendingTurnCompletions.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingTurnCompletions.clear();const e=this.started?.child;!e||e.exitCode!==null||e.signalCode!==null||(e.stdin.end(),!await C(e,2e3)&&(e.kill("SIGTERM"),!await C(e,1e3)&&(e.kill("SIGKILL"),await C(e,1e3))))}sessionResponse(e){return{sessionId:e,modes:{currentModeId:"workspace-write",availableModes:[{id:"read-only",name:"Read Only"},{id:"workspace-write",name:"Workspace Write"},{id:"danger-full-access",name:"Full Access"}]},configOptions:[{id:"model",category:"model",type:"string"},{id:"approvalPolicy",category:"approval",type:"string"},{id:"sandbox",category:"mode",type:"string"}]}}requireRpc(){if(!this.rpc)throw new Error("Codex app-server is not started");return this.rpc}notify(e,t){this.write({jsonrpc:"2.0",method:e,params:t})}requestParent(e,t,s=600*1e3){const r=this.nextParentRequestId++;return new Promise((o,i)=>{const c=setTimeout(()=>{this.pendingParentRequests.delete(r),i(new Error(`ACP client request timed out: ${e}`))},s);c.unref(),this.pendingParentRequests.set(r,{resolve:o,reject:i,timer:c}),this.write({jsonrpc:"2.0",id:r,method:e,params:t})})}handleParentResponse(e){const t=Number(e.id),s=this.pendingParentRequests.get(t);if(s){if(this.pendingParentRequests.delete(t),clearTimeout(s.timer),"error"in e){const r=u(e.error);s.reject(new Error(a(r,"message")||"ACP client request failed"));return}s.resolve(e.result)}}setConfigOption(e){const t=a(e,"configId"),s=e.value;if(!t)throw new Error("configId is required");if(typeof s!="string"&&typeof s!="boolean")throw new Error("config value must be string or boolean");return this.config[t]=s,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"config_option_update",configId:t,value:s}}),{}}setMode(e){const t=a(e,"modeId");if(!t)throw new Error("modeId is required");return this.config.sandbox=t,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"current_mode_update",modeId:t}}),{}}applyInitialConfig(e){const t=h(e,"config");for(const[s,r]of Object.entries(t))(typeof r=="string"||typeof r=="boolean")&&(this.config[s]=r)}codexConfig(){return{...typeof this.config.model=="string"&&this.config.model?{model:this.config.model}:{},approvalPolicy:typeof this.config.approvalPolicy=="string"?this.config.approvalPolicy:"on-request",sandbox:typeof this.config.sandbox=="string"?this.config.sandbox:"workspace-write"}}captureContextNotification(e,t){if(e==="thread/tokenUsage/updated"&&(this.latestTokenUsage=F(t)??this.latestTokenUsage),e==="thread/compacted"&&this.pendingCompaction&&this.resolveCompaction(),e==="item/completed"){const s=h(t,"item"),r=a(u(t),"threadId");a(s,"type")==="contextCompaction"&&(!r||r===this.currentSessionId)&&this.resolveCompaction(),a(s,"type")==="agentMessage"&&a(s,"phase")==="final_answer"&&(this.currentAssistantText=f(s)||this.currentAssistantText)}}resolveCompaction(){if(!this.pendingCompaction)return;const e=this.pendingCompaction;this.pendingCompaction=null,clearTimeout(e.timer),e.resolve()}captureUpdateEvidence(e){String(e.sessionUpdate||"")==="agent_message_chunk"&&(this.currentAssistantText+=f(e.content)),x(e,this.currentAffectedFiles)}captureThreadMetadata(e){const t=h(e,"thread");this.currentRolloutPath=a(t,"path")||null,this.threadTurnCount=Array.isArray(t.turns)?t.turns.length:0;const s=O(t.turns);s.userRequest&&(this.previousUserText=s.userRequest),s.assistantResponse&&(this.previousAssistantText=s.assistantResponse),this.previousAffectedFiles.clear();for(const r of s.affectedFiles)this.previousAffectedFiles.add(r);this.latestTokenUsage=null}async maintainContext(e,t,s={}){const r=A(),o=this.contextState(),i=v(o,r);if(!i.compact&&!s.force||!this.currentSessionId)return this.maintenanceResult({stage:e,action:"none",reasons:i.reasons,beforeState:o});const c=this.currentSessionId;this.notifyContextStatus("正在整理会话上下文",S(o)),this.maintenanceActive=!0;let l=!1,d="",g=o,m=i,I=!1,y="";try{const p=o.usage?.observedAtMs??0;await this.compactThread(c,s.compactTimeoutMs??r.compactTimeoutMs),await this.waitForTokenUsageAfter(p,2e3)}catch(p){l=!0,d=p instanceof Error?p.message:String(p)}try{if(g=this.contextState(),m=v(g,r,{compactAttempted:!0,compactFailed:l}),m.rollover&&s.allowRollover!==!1){this.notifyContextStatus("正在创建轻量会话",m.reasons.join(", "));try{await this.rotateThread(c,t),I=!0}catch(p){y=p instanceof Error?p.message:String(p),this.notifyContextStatus("轻量会话创建失败",y)}}else l||this.notifyContextStatus("会话上下文已压缩",S(g))}finally{this.maintenanceActive=!1}return this.maintenanceResult({action:I?"rollover":y?"rollover_failed":l?"compact_failed":"compact",stage:e,reasons:m.reasons,beforeState:o,afterState:g,compactError:[d,y].filter(Boolean).join("; "),previousThreadId:c,rolloverRecommended:m.rollover&&s.allowRollover===!1})}compactThread(e,t){return this.pendingCompaction?Promise.reject(new Error("Codex context compaction is already running")):new Promise((s,r)=>{const o=setTimeout(()=>{this.pendingCompaction?.timer===o&&(this.pendingCompaction=null),r(new Error("Codex thread compaction timed out"))},t);o.unref(),this.pendingCompaction={resolve:s,reject:r,timer:o},this.requireRpc().request("thread/compact/start",{threadId:e},t).catch(i=>{this.pendingCompaction?.timer===o&&(this.pendingCompaction=null,clearTimeout(o),r(i instanceof Error?i:new Error(String(i))))})})}async rotateThread(e,t){const s=E({previousThreadId:e,cwd:this.currentCwd,userRequest:t.userRequest,assistantResponse:t.assistantResponse,affectedFiles:t.affectedFiles}),r=await this.requireRpc().request("thread/start",{cwd:this.currentCwd,approvalsReviewer:"user",...this.codexConfig(),developerInstructions:s,ephemeral:!1,threadSource:"aca-codex-acp-rollover"},6e4),o=T(r);if(!o)throw new Error("Codex rollover thread/start did not return thread id");this.sessionAliases.set(e,o),this.currentSessionId=o,this.captureThreadMetadata(r)}async waitForTokenUsageAfter(e,t){const s=Date.now()+t;for(;Date.now()<s;){if((this.latestTokenUsage?.observedAtMs??0)>e)return;await G(50)}}resolveSessionAlias(e){if(!e)return null;let t=e;const s=new Set;for(;this.sessionAliases.has(t)&&!s.has(t);)s.add(t),t=this.sessionAliases.get(t)??t;return t}contextState(){return{usage:this.latestTokenUsage,rolloutBytes:U(this.currentRolloutPath),turnCount:this.threadTurnCount}}maintenanceResult(e){return{stage:e.stage,action:e.action,reasons:e.reasons,previousThreadId:e.previousThreadId??null,sessionId:this.currentSessionId,before:e.beforeState,after:e.afterState??null,compactError:e.compactError||null,rolloverRecommended:e.rolloverRecommended===!0}}notifyContextStatus(e,t){this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"aca_context_maintenance",label:e,detail:t}})}write(e){process.stdout.write(`${JSON.stringify(e)}
1
+ import{JsonLineRpcClient as P}from"../../client/json-rpc.js";import{startCodexAppServer as q}from"../codex/codex-process.js";import{codexAcpSessionUpdatesFromNotification as _}from"../codex/events.js";import{CodexPlanDeltaState as M}from"../codex/plan-events.js";import{isCodexApprovalRequest as k,resolveCodexApprovalRequest as b}from"../codex/permissions.js";import{buildCodexContinuityInstructions as E,codexTokenUsageFromNotification as F,decideCodexContextMaintenance as v,readCodexContextMaintenancePolicy as A,rolloutFileSize as U}from"./context-maintenance.js";class j{lineBuffer="";started=null;rpc=null;codexStartupPromise=null;initialized=!1;currentSessionId=null;currentCwd=process.cwd();promptActive=!1;currentTurnId=null;nextParentRequestId=1;pendingParentRequests=new Map;completedTurns=new Map;pendingTurnCompletions=new Map;agentMessagePhases=new Map;planDeltas=new M;config={};sessionAliases=new Map;currentAffectedFiles=new Set;latestTokenUsage=null;currentRolloutPath=null;threadTurnCount=0;currentPromptText="";currentAssistantText="";previousUserText="";previousAssistantText="";previousAffectedFiles=new Set;maintenanceActive=!1;pendingCompaction=null;shutdownPromise=null;constructor(){process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>this.handleInput(String(t)));const e=()=>{this.shutdown().finally(()=>process.exit(0))};process.stdin.once("end",e),process.stdin.once("close",e),process.stdin.once("error",e),process.once("SIGTERM",()=>{this.shutdown().finally(()=>process.exit(0))}),process.once("SIGINT",()=>{this.shutdown().finally(()=>process.exit(130))})}handleInput(e){this.lineBuffer+=e;const t=this.lineBuffer.split(`
2
+ `);this.lineBuffer=t.pop()??"";for(const s of t){const r=s.trim();if(!r)continue;let o;try{o=JSON.parse(r)}catch{continue}this.handleMessage(o)}}async handleMessage(e){if("id"in e&&("result"in e||"error"in e)&&typeof e.method!="string"){this.handleParentResponse(e);return}const t=typeof e.method=="string"?e.method:"",s=e.id;if(t){if(s===void 0){await this.handleNotification(t,u(e.params));return}try{const r=await this.handleRequest(t,u(e.params));this.write({jsonrpc:"2.0",id:s,result:r})}catch(r){this.write({jsonrpc:"2.0",id:s,error:{code:-32603,message:r instanceof Error?r.message:String(r)}})}}}async handleNotification(e,t){e==="session/cancel"&&await this.cancel(t)}async handleRequest(e,t){switch(e){case"initialize":return this.initializeResponse();case"session/new":return this.newSession(t);case"session/resume":case"session/load":return this.resumeSession(t);case"session/fork":return this.forkSession(t);case"session/prompt":return this.prompt(t);case"session/compact":return this.manualCompact(t);case"session/cancel":return await this.cancel(t),{};case"session/close":return await this.closeSession(t),{};case"session/set_config_option":return this.setConfigOption(t);case"session/set_mode":return this.setMode(t);case"fs/read_text_file":case"fs/write_text_file":case"terminal/create":case"terminal/output":case"terminal/wait_for_exit":case"terminal/kill":case"terminal/release":return{};default:throw new Error(`Unsupported ACP method: ${e}`)}}initializeResponse(){return{protocolVersion:1,agentCapabilities:{loadSession:!0,sessionCapabilities:{resume:!0,close:!0}}}}async newSession(e){const t=a(e,"cwd")||process.cwd();this.applyInitialConfig(e),await this.ensureCodex(t);const s=await this.requireRpc().request("thread/start",{cwd:t,approvalsReviewer:"user",...this.codexConfig(),ephemeral:!1,threadSource:"aca-codex-acp"},6e4),r=C(s);if(!r)throw new Error("Codex thread/start did not return thread id");return this.currentSessionId=r,this.currentCwd=t,this.captureThreadMetadata(s),this.sessionResponse(r)}async resumeSession(e){const t=a(e,"sessionId");if(!t)throw new Error("sessionId is required");const s=a(e,"cwd")||this.currentCwd;this.applyInitialConfig(e),await this.ensureCodex(s);const r=await this.requireRpc().request("thread/resume",{threadId:t,cwd:s,approvalsReviewer:"user",...this.codexConfig()},6e4);return this.currentSessionId=C(r)||t,this.currentCwd=s,this.captureThreadMetadata(r),this.sessionResponse(this.currentSessionId)}async forkSession(e){const t=a(e,"sessionId");if(!t)throw new Error("sessionId is required");const s=a(e,"cwd")||this.currentCwd;this.applyInitialConfig(e),await this.ensureCodex(s);const r=await this.requireRpc().request("thread/fork",{threadId:t,cwd:s,approvalsReviewer:"user",ephemeral:!1,threadSource:"aca-codex-acp-fork",...this.codexConfig()},12e4),o=C(r);if(!o)throw new Error("Codex thread/fork did not return thread id");return this.currentSessionId=o,this.currentCwd=s,this.captureThreadMetadata(r),this.sessionResponse(o)}async prompt(e){const t=a(e,"sessionId")||this.currentSessionId;let s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");const r=Array.isArray(e.prompt)?e.prompt:[],o=this.requireRpc();this.currentSessionId=s,this.promptActive=!0,this.currentTurnId=null,this.currentPromptText=$(r),this.currentAssistantText="",this.currentAffectedFiles.clear(),this.agentMessagePhases.clear(),this.planDeltas.reset();let i;try{i=await o.request("turn/start",{threadId:s,clientUserMessageId:`aca-acp-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:N(r),cwd:this.currentCwd,...D(this.config)},R());const c=String(i?.turn?.id??"");this.currentTurnId=c||null;const l=c?await this.waitForTurnCompleted(c,R()):i?.turn;this.threadTurnCount+=1,this.previousUserText=this.currentPromptText,this.previousAssistantText=this.currentAssistantText,this.previousAffectedFiles.clear();for(const d of this.currentAffectedFiles)this.previousAffectedFiles.add(d);return{stopReason:"end_turn",sessionId:this.currentSessionId,turn:l,_meta:{acaContextUsage:W(this.latestTokenUsage)}}}finally{this.promptActive=!1,this.currentTurnId=null}}async cancel(e){const t=a(e,"sessionId")||this.currentSessionId;if(!(!t||!this.rpc)&&(await this.rpc.request("turn/interrupt",{threadId:t}).catch(()=>{}),this.currentTurnId)){const s=this.pendingTurnCompletions.get(this.currentTurnId);s&&(this.pendingTurnCompletions.delete(this.currentTurnId),clearTimeout(s.timer),s.reject(new Error("Codex prompt cancelled")))}}async manualCompact(e){const t=a(e,"sessionId")||this.currentSessionId,s=this.resolveSessionAlias(t);if(!s)throw new Error("sessionId is required");if(this.promptActive||this.maintenanceActive)throw new Error("Codex session is busy");this.currentSessionId=s;const r=A(),o=await this.maintainContext("manual",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{force:!0,allowRollover:e.allowRollover===!0,compactTimeoutMs:B(e,r.compactTimeoutMs)}),i=String(o.action||"");if(i==="compact_failed"||i==="rollover_failed"){const c=String(o.compactError||"Codex 上下文压缩未完成");throw new Error(`Codex 上下文压缩失败:${c}`)}return{sessionId:this.currentSessionId,maintenance:o,contextUsage:z(o)}}async closeSession(e){await this.shutdown()}async ensureCodex(e){if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;if(this.codexStartupPromise){await this.codexStartupPromise;return}const t=(async()=>{if(this.rpc&&this.started&&this.started.child.exitCode===null&&this.started.child.signalCode===null)return;const s=q(e),r=new P(s.child,{peerName:"Codex app-server",onNotification:(o,i)=>this.handleCodexNotification(o,i),onRequest:async(o,i)=>this.handleCodexRequest(o,i)});this.started=s,this.rpc=r,this.initialized=!1,await r.request("initialize",{clientInfo:{name:"aca-codex-acp",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},6e4),this.initialized=!0})();this.codexStartupPromise=t;try{await t}catch(s){throw this.rpc&&this.started&&!this.initialized&&await T(this.started.child,1e3),this.rpc=null,this.started=null,s}finally{this.codexStartupPromise===t&&(this.codexStartupPromise=null)}}handleCodexNotification(e,t){if(this.captureContextNotification(e,t),!this.maintenanceActive&&!(!this.promptActive&&e!=="turn/completed")){this.rpc?.refreshPendingRequestTimeout("turn/start"),this.captureAgentMessagePhase(e,t),e==="turn/completed"&&this.resolveTurnCompleted(t);for(const s of _(e,t,{agentMessagePhases:this.agentMessagePhases,planDeltas:this.planDeltas}))this.captureUpdateEvidence(s),this.notify("session/update",{sessionId:this.currentSessionId,update:s})}}async handleCodexRequest(e,t){if(k(e))return b(e,t,async s=>{const r=await this.requestParent("session/request_permission",{sessionId:this.currentSessionId,request:{...s,params:t,method:e}}),o=u(r),i=u(o.outcome);return i.outcome==="selected"&&typeof i.optionId=="string"?{outcome:{outcome:"selected",optionId:i.optionId}}:{outcome:{outcome:"cancelled"}}});if(L(e)){const s=await this.requestParent("elicitation/create",{sessionId:this.currentSessionId,request:{...u(t),method:e}}),r=u(s),o=u(r.outcome);return o.outcome==="submitted"?{outcome:{outcome:"submitted",value:typeof o.value=="string"?o.value:""}}:{outcome:{outcome:"cancelled"}}}return{}}captureAgentMessagePhase(e,t){if(e!=="item/started"&&e!=="item/completed")return;const s=h(t,"item");if(a(s,"type")!=="agentMessage")return;const r=a(s,"id");r&&this.agentMessagePhases.set(r,a(s,"phase"))}waitForTurnCompleted(e,t){const s=this.completedTurns.get(e);return s?Promise.resolve(s):new Promise((r,o)=>{const i=setTimeout(()=>{this.pendingTurnCompletions.delete(e),o(new Error("Codex app-server request timed out while waiting for turn/completed"))},t);i.unref(),this.pendingTurnCompletions.set(e,{resolve:r,reject:o,timer:i})})}resolveTurnCompleted(e){const t=h(e,"turn"),s=a(t,"id");if(!s)return;this.completedTurns.set(s,t);const r=this.pendingTurnCompletions.get(s);if(r){if(this.pendingTurnCompletions.delete(s),clearTimeout(r.timer),a(t,"status")==="failed"){r.reject(new Error(`Codex turn failed: ${JSON.stringify(t.error??{})}`));return}r.resolve(t)}}async shutdown(){return this.shutdownPromise?this.shutdownPromise:(this.shutdownPromise=this.performShutdown(),this.shutdownPromise)}async performShutdown(){this.pendingCompaction&&(clearTimeout(this.pendingCompaction.timer),this.pendingCompaction.reject(new Error("Codex ACP adapter closed")),this.pendingCompaction=null);for(const t of this.pendingParentRequests.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingParentRequests.clear();for(const t of this.pendingTurnCompletions.values())clearTimeout(t.timer),t.reject(new Error("Codex ACP adapter closed"));this.pendingTurnCompletions.clear();const e=this.started?.child;!e||e.exitCode!==null||e.signalCode!==null||(e.stdin.end(),!await T(e,2e3)&&(e.kill("SIGTERM"),!await T(e,1e3)&&(e.kill("SIGKILL"),await T(e,1e3))))}sessionResponse(e){return{sessionId:e,modes:{currentModeId:"workspace-write",availableModes:[{id:"read-only",name:"Read Only"},{id:"workspace-write",name:"Workspace Write"},{id:"danger-full-access",name:"Full Access"}]},configOptions:[{id:"model",category:"model",type:"string"},{id:"approvalPolicy",category:"approval",type:"string"},{id:"sandbox",category:"mode",type:"string"}]}}requireRpc(){if(!this.rpc)throw new Error("Codex app-server is not started");return this.rpc}notify(e,t){this.write({jsonrpc:"2.0",method:e,params:t})}requestParent(e,t,s=600*1e3){const r=this.nextParentRequestId++;return new Promise((o,i)=>{const c=setTimeout(()=>{this.pendingParentRequests.delete(r),i(new Error(`ACP client request timed out: ${e}`))},s);c.unref(),this.pendingParentRequests.set(r,{resolve:o,reject:i,timer:c}),this.write({jsonrpc:"2.0",id:r,method:e,params:t})})}handleParentResponse(e){const t=Number(e.id),s=this.pendingParentRequests.get(t);if(s){if(this.pendingParentRequests.delete(t),clearTimeout(s.timer),"error"in e){const r=u(e.error);s.reject(new Error(a(r,"message")||"ACP client request failed"));return}s.resolve(e.result)}}setConfigOption(e){const t=a(e,"configId"),s=e.value;if(!t)throw new Error("configId is required");if(typeof s!="string"&&typeof s!="boolean")throw new Error("config value must be string or boolean");return this.config[t]=s,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"config_option_update",configId:t,value:s}}),{}}setMode(e){const t=a(e,"modeId");if(!t)throw new Error("modeId is required");return this.config.sandbox=t,this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"current_mode_update",modeId:t}}),{}}applyInitialConfig(e){const t=h(e,"config");for(const[s,r]of Object.entries(t))(typeof r=="string"||typeof r=="boolean")&&(this.config[s]=r)}codexConfig(){return{...typeof this.config.model=="string"&&this.config.model?{model:this.config.model}:{},approvalPolicy:typeof this.config.approvalPolicy=="string"?this.config.approvalPolicy:"on-request",sandbox:typeof this.config.sandbox=="string"?this.config.sandbox:"workspace-write"}}captureContextNotification(e,t){if(e==="thread/tokenUsage/updated"&&(this.latestTokenUsage=F(t)??this.latestTokenUsage),e==="thread/compacted"&&this.pendingCompaction&&this.resolveCompaction(),e==="item/completed"){const s=h(t,"item"),r=a(u(t),"threadId");a(s,"type")==="contextCompaction"&&(!r||r===this.currentSessionId)&&this.resolveCompaction(),a(s,"type")==="agentMessage"&&a(s,"phase")==="final_answer"&&(this.currentAssistantText=f(s)||this.currentAssistantText)}}resolveCompaction(){if(!this.pendingCompaction)return;const e=this.pendingCompaction;this.pendingCompaction=null,clearTimeout(e.timer),e.resolve()}captureUpdateEvidence(e){String(e.sessionUpdate||"")==="agent_message_chunk"&&(this.currentAssistantText+=f(e.content)),x(e,this.currentAffectedFiles)}captureThreadMetadata(e){const t=h(e,"thread");this.currentRolloutPath=a(t,"path")||null,this.threadTurnCount=Array.isArray(t.turns)?t.turns.length:0;const s=O(t.turns);s.userRequest&&(this.previousUserText=s.userRequest),s.assistantResponse&&(this.previousAssistantText=s.assistantResponse),this.previousAffectedFiles.clear();for(const r of s.affectedFiles)this.previousAffectedFiles.add(r);this.latestTokenUsage=null}async maintainContext(e,t,s={}){const r=A(),o=this.contextState(),i=v(o,r);if(!i.compact&&!s.force||!this.currentSessionId)return this.maintenanceResult({stage:e,action:"none",reasons:i.reasons,beforeState:o});const c=this.currentSessionId;this.notifyContextStatus("正在整理会话上下文",S(o)),this.maintenanceActive=!0;let l=!1,d="",g=o,m=i,I=!1,y="";try{const p=o.usage?.observedAtMs??0;await this.compactThread(c,s.compactTimeoutMs??r.compactTimeoutMs),await this.waitForTokenUsageAfter(p,2e3)}catch(p){l=!0,d=p instanceof Error?p.message:String(p)}try{if(g=this.contextState(),m=v(g,r,{compactAttempted:!0,compactFailed:l}),m.rollover&&s.allowRollover!==!1){this.notifyContextStatus("正在创建轻量会话",m.reasons.join(", "));try{await this.rotateThread(c,t),I=!0}catch(p){y=p instanceof Error?p.message:String(p),this.notifyContextStatus("轻量会话创建失败",y)}}else l||this.notifyContextStatus("会话上下文已压缩",S(g))}finally{this.maintenanceActive=!1}return this.maintenanceResult({action:I?"rollover":y?"rollover_failed":l?"compact_failed":"compact",stage:e,reasons:m.reasons,beforeState:o,afterState:g,compactError:[d,y].filter(Boolean).join("; "),previousThreadId:c,rolloverRecommended:m.rollover&&s.allowRollover===!1})}compactThread(e,t){return this.pendingCompaction?Promise.reject(new Error("Codex context compaction is already running")):new Promise((s,r)=>{const o=setTimeout(()=>{this.pendingCompaction?.timer===o&&(this.pendingCompaction=null),r(new Error("Codex thread compaction timed out"))},t);o.unref(),this.pendingCompaction={resolve:s,reject:r,timer:o},this.requireRpc().request("thread/compact/start",{threadId:e},t).catch(i=>{this.pendingCompaction?.timer===o&&(this.pendingCompaction=null,clearTimeout(o),r(i instanceof Error?i:new Error(String(i))))})})}async rotateThread(e,t){const s=E({previousThreadId:e,cwd:this.currentCwd,userRequest:t.userRequest,assistantResponse:t.assistantResponse,affectedFiles:t.affectedFiles}),r=await this.requireRpc().request("thread/start",{cwd:this.currentCwd,approvalsReviewer:"user",...this.codexConfig(),developerInstructions:s,ephemeral:!1,threadSource:"aca-codex-acp-rollover"},6e4),o=C(r);if(!o)throw new Error("Codex rollover thread/start did not return thread id");this.sessionAliases.set(e,o),this.currentSessionId=o,this.captureThreadMetadata(r)}async waitForTokenUsageAfter(e,t){const s=Date.now()+t;for(;Date.now()<s;){if((this.latestTokenUsage?.observedAtMs??0)>e)return;await G(50)}}resolveSessionAlias(e){if(!e)return null;let t=e;const s=new Set;for(;this.sessionAliases.has(t)&&!s.has(t);)s.add(t),t=this.sessionAliases.get(t)??t;return t}contextState(){return{usage:this.latestTokenUsage,rolloutBytes:U(this.currentRolloutPath),turnCount:this.threadTurnCount}}maintenanceResult(e){return{stage:e.stage,action:e.action,reasons:e.reasons,previousThreadId:e.previousThreadId??null,sessionId:this.currentSessionId,before:e.beforeState,after:e.afterState??null,compactError:e.compactError||null,rolloverRecommended:e.rolloverRecommended===!0}}notifyContextStatus(e,t){this.notify("session/update",{sessionId:this.currentSessionId,update:{sessionUpdate:"aca_context_maintenance",label:e,detail:t}})}write(e){process.stdout.write(`${JSON.stringify(e)}
3
3
  `)}}function N(n){return n.map(e=>{const t=u(e);if(t.type==="image"){const s=a(t,"uri");if(s)return{type:"localImage",path:s};const r=a(t,"data");return{type:"image",url:`data:${a(t,"mimeType")||"image/png"};base64,${r}`}}return{type:"text",text:a(t,"text"),text_elements:[]}})}function $(n){return n.map(e=>a(u(e),"text")).filter(Boolean).join(`
4
4
 
5
- `)}function D(n){const e={};typeof n.model=="string"&&n.model&&(e.model=n.model),typeof n.approvalPolicy=="string"&&n.approvalPolicy&&(e.approvalPolicy=n.approvalPolicy),typeof n.sandbox=="string"&&n.sandbox&&(e.sandbox=n.sandbox);const t=n.reasoning_effort??n.reasoningEffort??n.model_reasoning_effort??n.modelReasoningEffort??n.effort;return typeof t=="string"&&t&&(e.effort=t),e}function T(n){const e=h(n,"thread");return a(e,"id")||null}function h(n,e){const t=u(n);return u(t[e])}function u(n){return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}function f(n){if(typeof n=="string")return n;if(Array.isArray(n))return n.map(f).filter(Boolean).join("");if(!n||typeof n!="object")return"";const e=u(n);for(const t of["text","message","content","output_text"]){const s=f(e[t]);if(s)return s}return""}function x(n,e){if(Array.isArray(n)){for(const o of n)x(o,e);return}const t=u(n),s=a(t,"type").toLowerCase(),r=a(t,"path");if(r&&["diff","resource_link","content"].includes(s)&&e.add(r),Array.isArray(t.locations))for(const o of t.locations){const i=a(u(o),"path");i&&e.add(i)}for(const o of[t.content,t.update,t.rawInput,t.rawOutput])o&&o!==n&&x(o,e)}function O(n){if(!Array.isArray(n)||n.length===0)return{userRequest:"",assistantResponse:"",affectedFiles:[]};const e=n.at(-1),t=new Set;x(e,t);let s="",r="";const o=i=>{if(Array.isArray(i)){for(const d of i)o(d);return}if(!i||typeof i!="object")return;const c=u(i),l=a(c,"type").toLowerCase();l==="usermessage"&&(s=f(c)||s),l==="agentmessage"&&(r=f(c)||r);for(const d of["items","content","input"])c[d]&&o(c[d])};return o(e),{userRequest:s,assistantResponse:r,affectedFiles:[...t]}}function B(n,e){const t=w(n,"timeoutMs");return!Number.isFinite(t)||t<=0?e:Math.max(3e4,Math.min(59e4,t-1e4))}function z(n){const e=String(n.action||"none"),t=u(n.after),s=u(n.before),r=u(t.usage),o=u(s.usage),i=Object.keys(r).length>0?r:o,c=w(i,"contextWindow");if(e==="rollover")return{usedTokens:0,inputTokens:0,contextWindow:c,ratio:0,observedAtMs:Date.now(),state:"new_thread",maintenanceAction:e};if(Object.keys(i).length===0)return null;const l=w(i,"totalTokens"),d=w(i,"inputTokens");return{usedTokens:l||d,inputTokens:d,contextWindow:c,ratio:c>0?(l||d)/c:0,observedAtMs:w(i,"observedAtMs")||Date.now(),state:e==="compact"?"compacted":"active",maintenanceAction:e}}function W(n){return n?{usedTokens:n.totalTokens||n.inputTokens,inputTokens:n.inputTokens,contextWindow:n.contextWindow,ratio:n.contextWindow>0?(n.totalTokens||n.inputTokens)/n.contextWindow:0,observedAtMs:n.observedAtMs,state:"active",maintenanceAction:null}:null}function S(n){const e=n.usage?`${n.usage.inputTokens} tokens`:"token unknown",t=n.rolloutBytes>0?`${Math.round(n.rolloutBytes/1024/1024)}MB rollout`:"rollout unknown";return`${e}, ${t}, ${n.turnCount} turns`}function w(n,e){const t=u(n)[e];return typeof t=="number"&&Number.isFinite(t)?t:0}function a(n,e){const s=u(n)[e];return typeof s=="string"?s:""}function L(n){const e=n.toLowerCase();return e.includes("elicitation")||e.includes("requestuserinput")||e.includes("request_user_input")||e.includes("input/request")}function P(){const n=Number.parseInt(process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(n)&&n>=3e4?n:360*60*1e3}function C(n,e){return n.exitCode!==null||n.signalCode!==null?Promise.resolve(!0):new Promise(t=>{const s=setTimeout(()=>t(!1),e);s.unref(),n.once("close",()=>{clearTimeout(s),t(!0)})})}function G(n){return new Promise(e=>setTimeout(e,n))}function J(){new j}const K=process.argv[1]||"";/(?:^|[\\/])adapter\.(?:js|ts)$/.test(K)&&J();export{J as runCodexAcpAdapter};
5
+ `)}function D(n){const e={};typeof n.model=="string"&&n.model&&(e.model=n.model),typeof n.approvalPolicy=="string"&&n.approvalPolicy&&(e.approvalPolicy=n.approvalPolicy),typeof n.sandbox=="string"&&n.sandbox&&(e.sandbox=n.sandbox);const t=n.reasoning_effort??n.reasoningEffort??n.model_reasoning_effort??n.modelReasoningEffort??n.effort;return typeof t=="string"&&t&&(e.effort=t),e}function C(n){const e=h(n,"thread");return a(e,"id")||null}function h(n,e){const t=u(n);return u(t[e])}function u(n){return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}function f(n){if(typeof n=="string")return n;if(Array.isArray(n))return n.map(f).filter(Boolean).join("");if(!n||typeof n!="object")return"";const e=u(n);for(const t of["text","message","content","output_text"]){const s=f(e[t]);if(s)return s}return""}function x(n,e){if(Array.isArray(n)){for(const o of n)x(o,e);return}const t=u(n),s=a(t,"type").toLowerCase(),r=a(t,"path");if(r&&["diff","resource_link","content"].includes(s)&&e.add(r),Array.isArray(t.locations))for(const o of t.locations){const i=a(u(o),"path");i&&e.add(i)}for(const o of[t.content,t.update,t.rawInput,t.rawOutput])o&&o!==n&&x(o,e)}function O(n){if(!Array.isArray(n)||n.length===0)return{userRequest:"",assistantResponse:"",affectedFiles:[]};const e=n.at(-1),t=new Set;x(e,t);let s="",r="";const o=i=>{if(Array.isArray(i)){for(const d of i)o(d);return}if(!i||typeof i!="object")return;const c=u(i),l=a(c,"type").toLowerCase();l==="usermessage"&&(s=f(c)||s),l==="agentmessage"&&(r=f(c)||r);for(const d of["items","content","input"])c[d]&&o(c[d])};return o(e),{userRequest:s,assistantResponse:r,affectedFiles:[...t]}}function B(n,e){const t=w(n,"timeoutMs");return!Number.isFinite(t)||t<=0?e:Math.max(3e4,Math.min(59e4,t-1e4))}function z(n){const e=String(n.action||"none"),t=u(n.after),s=u(n.before),r=u(t.usage),o=u(s.usage),i=Object.keys(r).length>0?r:o,c=w(i,"contextWindow");if(e==="rollover")return{usedTokens:0,inputTokens:0,contextWindow:c,ratio:0,observedAtMs:Date.now(),state:"new_thread",maintenanceAction:e};if(Object.keys(i).length===0)return null;const l=w(i,"totalTokens"),d=w(i,"inputTokens");return{usedTokens:l||d,inputTokens:d,contextWindow:c,ratio:c>0?(l||d)/c:0,observedAtMs:w(i,"observedAtMs")||Date.now(),state:e==="compact"?"compacted":"active",maintenanceAction:e}}function W(n){return n?{usedTokens:n.totalTokens||n.inputTokens,inputTokens:n.inputTokens,contextWindow:n.contextWindow,ratio:n.contextWindow>0?(n.totalTokens||n.inputTokens)/n.contextWindow:0,observedAtMs:n.observedAtMs,state:"active",maintenanceAction:null}:null}function S(n){const e=n.usage?`${n.usage.inputTokens} tokens`:"token unknown",t=n.rolloutBytes>0?`${Math.round(n.rolloutBytes/1024/1024)}MB rollout`:"rollout unknown";return`${e}, ${t}, ${n.turnCount} turns`}function w(n,e){const t=u(n)[e];return typeof t=="number"&&Number.isFinite(t)?t:0}function a(n,e){const s=u(n)[e];return typeof s=="string"?s:""}function L(n){const e=n.toLowerCase();return e.includes("elicitation")||e.includes("requestuserinput")||e.includes("request_user_input")||e.includes("input/request")}function R(){const n=Number.parseInt(process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(n)&&n>=3e4?n:360*60*1e3}function T(n,e){return n.exitCode!==null||n.signalCode!==null?Promise.resolve(!0):new Promise(t=>{const s=setTimeout(()=>t(!1),e);s.unref(),n.once("close",()=>{clearTimeout(s),t(!0)})})}function G(n){return new Promise(e=>setTimeout(e,n))}function J(){new j}const K=process.argv[1]||"";/(?:^|[\\/])adapter\.(?:js|ts)$/.test(K)&&J();export{J as runCodexAcpAdapter};
@@ -1 +1 @@
1
- import m from"node:fs";import{promptBlocksToAcpContent as b}from"../../client/acp-content.js";import{eventFromAcpSessionUpdate as y,statusFromAcpSessionUpdate as C}from"../../client/acp-events.js";import{defaultAcpRuntimePool as I}from"../../client/acp-runtime-pool.js";import{resolveCodexAcpLaunch as v}from"./launch.js";import{CodexPromptPerformanceTracker as A,readCodexContextMaintenancePolicy as x}from"./context-maintenance.js";const P={sessionResume:!0,imageInput:!0,fileAttachment:!0,filesystem:!0,terminal:!0,permissionRequest:!0,configOptions:!0,usage:!0,contextUsage:!0,contextCompaction:!0,plan:!0,diff:!0};class F{id="codex-acp";name="Codex ACP";capabilities=P;async createSession(e){return new k(e.cwd,e.providerSessionId??null,e.timeoutMs)}}class k{cwd;providerSessionId;defaultTimeoutMs;lease=null;sessionResponse=null;statusCallback=null;updateCallback=null;permissionCallback=null;userInputCallback=null;abortHandler=null;statusTimeline=[];updates=[];content="";performanceTracker=null;constructor(e,s,t=q()){this.cwd=e,this.providerSessionId=s,this.defaultTimeoutMs=t}async sendPrompt(e){if(!m.existsSync(e.cwd)||!m.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.userInputCallback=e.onUserInputRequest??null,this.attachAbortSignal(e.signal),this.content="",this.updates.length=0,this.statusTimeline.length=0,this.performanceTracker=new A(s);let t=null,r=null,n=this.providerSessionId,i,c=null;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const a=await this.acquireRuntime(e.cwd);this.lease=a,t=a.client,r=a.started,await this.initialize(a),n=await this.establishSession(a,e),await this.applyConfig(t,n,e),this.emitStatus("thinking","思考中"),c=this.startSlowStatusTimer(),i=await this.promptWithAbort(t,{sessionId:n,prompt:b(e.prompt,e.promptBlocks),timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal});const d=w(i);d&&d!==n&&(n=d,this.providerSessionId=d,a.setProviderSession({providerSessionId:d,sessionResponse:this.sessionResponse}))}finally{c&&clearInterval(c),this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}return this.emitStatus("completed","已完成"),{providerSessionId:n,cliType:"builtin",agentType:"codex",effectiveConfig:{model:e.model??null,mode:e.mode??null,configOptionValues:e.configOptionValues??null,command:r.command,processPid:r.child.pid??null,provider:"codex-acp",protocol:"acp"},command:r.command,args:r.args,cwd:e.cwd,exitCode:r.child.exitCode,signal:r.child.signalCode,durationMs:Date.now()-s,stdout:t.rpc.stdout,stderr:t.rpc.stderr,content:this.content.trim(),updates:[...this.updates],statusTimeline:[...this.statusTimeline],performance:this.performanceTracker?.snapshot(),contextUsage:O(i),promptResponse:i}}async compactContext(e){if(!m.existsSync(e.cwd)||!m.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.attachAbortSignal(e.signal);let t=this.providerSessionId,r;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const i=await this.acquireRuntime(e.cwd);this.lease=i,await this.initialize(i),t=await this.establishSession(i,e),await this.applyConfig(i.client,t,e);const c=E(e.timeoutMs);r=await this.compactWithAbort(i.client,{sessionId:t,allowRollover:e.allowRollover===!0,timeoutMs:c,signal:e.signal});const a=w(r);a&&a!==t&&(t=a,this.providerSessionId=a,i.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}))}catch(i){if(this.lease&&T(i,e.signal)){const c=this.lease;this.lease=null,await c.dispose().catch(()=>{})}throw this.emitStatus("failed","上下文压缩失败",i instanceof Error?i.message:String(i)),i}finally{this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}const n=l(r)??{};return{providerSessionId:t||this.providerSessionId||"",contextUsage:S(n.contextUsage),maintenance:l(n.maintenance)??{},durationMs:Date.now()-s}}async cancel(){this.providerSessionId&&this.lease?.client.cancel(this.providerSessionId)}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null,this.userInputCallback=null,this.abortHandler&&(this.abortHandler=null),this.releaseLease()}async acquireRuntime(e){const s=v();return I.acquire({providerId:"codex-acp",cwd:e,providerSessionId:this.providerSessionId,command:s.command,args:s.args,onSessionUpdate:t=>this.handleSessionUpdate(t),onClientRequest:async(t,r)=>{if(t==="session/request_permission")return this.requestPermission(r);if(t==="elicitation/create"||t==="session/request_user_input")return this.requestUserInput(r);throw new Error(`Unsupported Codex ACP client request: ${t}`)}})}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,s){const t=e.client,r=M(s);if(e.providerSessionId&&e.sessionEstablished)return this.providerSessionId=e.providerSessionId,this.sessionResponse=e.sessionResponse,e.providerSessionId;if(this.providerSessionId)try{this.emitStatus("resuming","Codex ACP 会话恢复中","session/load");const c=await t.loadSession({sessionId:this.providerSessionId,cwd:s.cwd,config:r},6e4);this.sessionResponse=l(c);const a=f(c)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}),a}catch(c){if(s.requireSessionResume){const a=c instanceof Error?c.message:String(c);throw new Error(`无法恢复导入的 Codex ACP Session ${this.providerSessionId}:${a}`)}this.providerSessionId=null}this.emitStatus("acp","Codex ACP 会话创建中","session/new");const n=await t.newSession({cwd:s.cwd,config:r},12e4);this.sessionResponse=l(n);const i=f(n);if(!i)throw new Error("Codex ACP session/new did not return sessionId");return this.providerSessionId=i,e.setProviderSession({providerSessionId:i,sessionResponse:this.sessionResponse}),i}async applyConfig(e,s,t){t.model&&await e.setSessionConfigOption({sessionId:s,configId:"model",value:t.model},6e4).catch(()=>{});const r=h(t.mode);r&&await e.setSessionConfigOption({sessionId:s,configId:"approvalPolicy",value:r},6e4).catch(()=>{});const n=p(t.mode);n&&await e.setSessionConfigOption({sessionId:s,configId:"sandbox",value:n},6e4).catch(()=>{});for(const[i,c]of Object.entries(t.configOptionValues??{}))["model","mode","sandbox","approvalPolicy"].includes(i)||await e.setSessionConfigOption({sessionId:s,configId:i,value:c},6e4).catch(()=>{})}handleSessionUpdate(e){this.performanceTracker?.recordEvent(),this.updates.push({method:"session/update",params:e});const s=y(e);s&&(s.type==="agent_message_chunk"&&(this.content+=s.text??""),this.updateCallback?.(s));const t=C(e);t&&this.emitStatus(t.phase,t.label,t.detail,t.updateType)}startSlowStatusTimer(){const e=x().slowEventThresholdMs,s=setInterval(()=>{const t=this.performanceTracker,r=Date.now();if(!t?.shouldReportSlow(r,e))return;const n=t.snapshot(r),i=Math.max(1,Math.round(n.silentForMs/6e4));this.emitStatus("thinking","模型长时间处理中",`已 ${i} 分钟没有收到新的 ACP 事件`,"aca.performance.slow")},Math.min(3e4,Math.max(1e3,Math.floor(e/4))));return s.unref(),s}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("Codex ACP prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}async promptWithAbort(e,s){const t=e.prompt({sessionId:s.sessionId,prompt:s.prompt},s.timeoutMs);if(!s.signal)return t;if(s.signal.aborted)throw await this.lease?.dispose().catch(()=>{}),new Error("Codex ACP prompt cancelled");let r=null;const n=new Promise((i,c)=>{r=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP prompt cancelled"))},s.signal?.addEventListener("abort",r,{once:!0})});try{return await Promise.race([t,n])}finally{r&&s.signal.removeEventListener("abort",r)}}async compactWithAbort(e,s){const t=e.compactSession({sessionId:s.sessionId,allowRollover:s.allowRollover,timeoutMs:s.timeoutMs},s.timeoutMs);if(!s.signal)return t;if(s.signal.aborted)throw await this.lease?.dispose().catch(()=>{}),new Error("Codex ACP 上下文压缩已取消");let r=null;const n=new Promise((i,c)=>{r=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP 上下文压缩已取消"))},s.signal?.addEventListener("abort",r,{once:!0})});try{return await Promise.race([t,n])}finally{r&&s.signal.removeEventListener("abort",r)}}async requestPermission(e){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s,n=(Array.isArray(t.options)?t.options:[]).map((i,c)=>{const a=i&&typeof i=="object"&&!Array.isArray(i)?i:{};return{optionId:String(a.optionId??a.id??c),kind:String(a.kind??"choice"),...typeof a.label=="string"?{label:a.label}:{}}});return this.emitStatus("requestPermission","等待授权",R(t),"session/request_permission"),this.permissionCallback({requestId:String(t.requestId??t.id??`codex-acp-permission-${Date.now()}`),params:e,options:n})}async requestUserInput(e){if(!this.userInputCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s;return this.emitStatus("requestPermission","等待输入",_(t),"elicitation/create"),this.userInputCallback({requestId:String(t.requestId??t.id??`codex-acp-input-${Date.now()}`),prompt:String(t.prompt??t.message??t.question??""),params:e,...typeof t.defaultValue=="string"?{defaultValue:t.defaultValue}:{}})}emitStatus(e,s,t,r){const n={phase:e,label:s,...t?{detail:t}:{},...r?{updateType:r}:{},atMs:Date.now()},i=this.statusTimeline[this.statusTimeline.length-1];i&&i.phase===n.phase&&i.label===n.label&&i.detail===n.detail&&i.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}releaseLease(){this.lease?.release(),this.lease=null}}function T(o,e){if(e?.aborted)return!0;const s=o instanceof Error?o.message:String(o||"");return/compact.*timed out|request timed out.*compact|adapter closed|aborted|cancelled/i.test(s)}function f(o){if(!o||typeof o!="object"||Array.isArray(o))return null;const e=o.sessionId;return typeof e=="string"&&e.trim()?e.trim():null}function l(o){return o&&typeof o=="object"&&!Array.isArray(o)?o:null}function p(o){const e=String(o||"").trim();return e?e==="read-only"?"read-only":["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"danger-full-access":"workspace-write":null}function h(o){const e=String(o||"").trim();return e?["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"never":e==="acceptEdits"||e==="accept-edits"?"on-failure":"on-request":null}function M(o){return{...o.model?{model:o.model}:{},...h(o.mode)?{approvalPolicy:h(o.mode)}:{},...p(o.mode)?{sandbox:p(o.mode)}:{},...o.configOptionValues??{}}}function R(o){const e=o.params&&typeof o.params=="object"&&!Array.isArray(o.params)?o.params:o;for(const s of["command","cwd","reason","grantRoot","method"]){const t=e[s];if(typeof t=="string"&&t.trim())return g(t)}}function _(o){for(const e of["prompt","message","question","title"]){const s=o[e];if(typeof s=="string"&&s.trim())return g(s)}}function g(o){const e=o.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function q(){const o=Number.parseInt(process.env.ACA_CODEX_ACP_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(o)&&o>=3e4?o:360*60*1e3}function E(o){const e=Number.isInteger(o)?Number(o):Number.parseInt(process.env.ACA_CODEX_ACP_COMPACT_TIMEOUT_MS??"",10);return Number.isFinite(e)&&e>=3e4?Math.min(e,6e5):12e4}function w(o){if(!o||typeof o!="object"||Array.isArray(o))return null;const e=o;return typeof e.sessionId=="string"&&e.sessionId.trim()?e.sessionId:null}function O(o){const e=l(o),s=l(e?._meta);return S(s?.acaContextUsage)}function S(o){const e=l(o);if(!e)return null;const s=u(e.contextWindow),t=u(e.usedTokens),r=u(e.inputTokens),n=String(e.state||"unknown"),i=["active","compacted","new_thread"].includes(n)?n:"unknown";return{usedTokens:t,inputTokens:r,contextWindow:s,ratio:s>0?Math.max(0,u(e.ratio)||t/s):0,observedAtMs:u(e.observedAtMs)||Date.now(),state:i,maintenanceAction:typeof e.maintenanceAction=="string"?e.maintenanceAction:null}}function u(o){return typeof o=="number"&&Number.isFinite(o)&&o>=0?o:0}export{F as CodexAcpProvider,P as codexAcpCapabilities};
1
+ import d from"node:fs";import{promptBlocksToAcpContent as I}from"../../client/acp-content.js";import{eventFromAcpSessionUpdate as v,statusFromAcpSessionUpdate as A}from"../../client/acp-events.js";import{defaultAcpRuntimePool as w}from"../../client/acp-runtime-pool.js";import{resolveCodexAcpLaunch as S}from"./launch.js";import{CodexPromptPerformanceTracker as x,readCodexContextMaintenancePolicy as P}from"./context-maintenance.js";const k={sessionResume:!0,imageInput:!0,fileAttachment:!0,filesystem:!0,terminal:!0,permissionRequest:!0,configOptions:!0,usage:!0,contextUsage:!0,contextCompaction:!0,plan:!0,diff:!0};class F{id="codex-acp";name="Codex ACP";capabilities=k;async createSession(e){return new M(e.cwd,e.providerSessionId??null,e.timeoutMs)}async forkSession(e){if(!d.existsSync(e.cwd)||!d.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=e.sourceProviderSessionId.trim(),t=await w.acquire({providerId:"codex-acp",cwd:e.cwd,providerSessionId:s,...S(),onSessionUpdate:()=>{}});try{t.initialized||(await t.client.initialize(6e4),t.markInitialized()),e.onStatus?.({phase:"forking",label:"正在分叉 Codex 会话",detail:s,updateType:"session/fork",atMs:Date.now()});const r=await t.client.forkSession({sessionId:s,cwd:e.cwd,config:g(e)},e.timeoutMs??12e4),n=p(r);if(!n)throw new Error("Codex ACP session/fork did not return sessionId");return{providerSessionId:n}}finally{t.release()}}}class M{cwd;providerSessionId;defaultTimeoutMs;lease=null;sessionResponse=null;statusCallback=null;updateCallback=null;permissionCallback=null;userInputCallback=null;abortHandler=null;statusTimeline=[];updates=[];content="";performanceTracker=null;constructor(e,s,t=q()){this.cwd=e,this.providerSessionId=s,this.defaultTimeoutMs=t}async sendPrompt(e){if(!d.existsSync(e.cwd)||!d.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.userInputCallback=e.onUserInputRequest??null,this.attachAbortSignal(e.signal),this.content="",this.updates.length=0,this.statusTimeline.length=0,this.performanceTracker=new x(s);let t=null,r=null,n=this.providerSessionId,i,c=null;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const a=await this.acquireRuntime(e.cwd);this.lease=a,t=a.client,r=a.started,await this.initialize(a),n=await this.establishSession(a,e),await this.applyConfig(t,n,e),this.emitStatus("thinking","思考中"),c=this.startSlowStatusTimer(),i=await this.promptWithAbort(t,{sessionId:n,prompt:I(e.prompt,e.promptBlocks),timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal});const u=b(i);u&&u!==n&&(n=u,this.providerSessionId=u,a.setProviderSession({providerSessionId:u,sessionResponse:this.sessionResponse}))}finally{c&&clearInterval(c),this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}return this.emitStatus("completed","已完成"),{providerSessionId:n,cliType:"builtin",agentType:"codex",effectiveConfig:{model:e.model??null,mode:e.mode??null,configOptionValues:e.configOptionValues??null,command:r.command,processPid:r.child.pid??null,provider:"codex-acp",protocol:"acp"},command:r.command,args:r.args,cwd:e.cwd,exitCode:r.child.exitCode,signal:r.child.signalCode,durationMs:Date.now()-s,stdout:t.rpc.stdout,stderr:t.rpc.stderr,content:this.content.trim(),updates:[...this.updates],statusTimeline:[...this.statusTimeline],performance:this.performanceTracker?.snapshot(),contextUsage:U(i),promptResponse:i}}async compactContext(e){if(!d.existsSync(e.cwd)||!d.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.attachAbortSignal(e.signal);let t=this.providerSessionId,r;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const i=await this.acquireRuntime(e.cwd);this.lease=i,await this.initialize(i),t=await this.establishSession(i,e),await this.applyConfig(i.client,t,e);const c=E(e.timeoutMs);r=await this.compactWithAbort(i.client,{sessionId:t,allowRollover:e.allowRollover===!0,timeoutMs:c,signal:e.signal});const a=b(r);a&&a!==t&&(t=a,this.providerSessionId=a,i.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}))}catch(i){if(this.lease&&T(i,e.signal)){const c=this.lease;this.lease=null,await c.dispose().catch(()=>{})}throw this.emitStatus("failed","上下文压缩失败",i instanceof Error?i.message:String(i)),i}finally{this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}const n=l(r)??{};return{providerSessionId:t||this.providerSessionId||"",contextUsage:C(n.contextUsage),maintenance:l(n.maintenance)??{},durationMs:Date.now()-s}}async cancel(){this.providerSessionId&&this.lease?.client.cancel(this.providerSessionId)}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null,this.userInputCallback=null,this.abortHandler&&(this.abortHandler=null),this.releaseLease()}async acquireRuntime(e){const s=S();return w.acquire({providerId:"codex-acp",cwd:e,providerSessionId:this.providerSessionId,command:s.command,args:s.args,onSessionUpdate:t=>this.handleSessionUpdate(t),onClientRequest:async(t,r)=>{if(t==="session/request_permission")return this.requestPermission(r);if(t==="elicitation/create"||t==="session/request_user_input")return this.requestUserInput(r);throw new Error(`Unsupported Codex ACP client request: ${t}`)}})}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,s){const t=e.client,r=g(s);if(e.providerSessionId&&e.sessionEstablished)return this.providerSessionId=e.providerSessionId,this.sessionResponse=e.sessionResponse,e.providerSessionId;if(this.providerSessionId)try{this.emitStatus("resuming","Codex ACP 会话恢复中","session/load");const c=await t.loadSession({sessionId:this.providerSessionId,cwd:s.cwd,config:r},6e4);this.sessionResponse=l(c);const a=p(c)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}),a}catch(c){if(s.requireSessionResume){const a=c instanceof Error?c.message:String(c);throw new Error(`无法恢复导入的 Codex ACP Session ${this.providerSessionId}:${a}`)}this.providerSessionId=null}this.emitStatus("acp","Codex ACP 会话创建中","session/new");const n=await t.newSession({cwd:s.cwd,config:r},12e4);this.sessionResponse=l(n);const i=p(n);if(!i)throw new Error("Codex ACP session/new did not return sessionId");return this.providerSessionId=i,e.setProviderSession({providerSessionId:i,sessionResponse:this.sessionResponse}),i}async applyConfig(e,s,t){t.model&&await e.setSessionConfigOption({sessionId:s,configId:"model",value:t.model},6e4).catch(()=>{});const r=f(t.mode);r&&await e.setSessionConfigOption({sessionId:s,configId:"approvalPolicy",value:r},6e4).catch(()=>{});const n=h(t.mode);n&&await e.setSessionConfigOption({sessionId:s,configId:"sandbox",value:n},6e4).catch(()=>{});for(const[i,c]of Object.entries(t.configOptionValues??{}))["model","mode","sandbox","approvalPolicy"].includes(i)||await e.setSessionConfigOption({sessionId:s,configId:i,value:c},6e4).catch(()=>{})}handleSessionUpdate(e){this.performanceTracker?.recordEvent(),this.updates.push({method:"session/update",params:e});const s=v(e);s&&(s.type==="agent_message_chunk"&&(this.content+=s.text??""),this.updateCallback?.(s));const t=A(e);t&&this.emitStatus(t.phase,t.label,t.detail,t.updateType)}startSlowStatusTimer(){const e=P().slowEventThresholdMs,s=setInterval(()=>{const t=this.performanceTracker,r=Date.now();if(!t?.shouldReportSlow(r,e))return;const n=t.snapshot(r),i=Math.max(1,Math.round(n.silentForMs/6e4));this.emitStatus("thinking","模型长时间处理中",`已 ${i} 分钟没有收到新的 ACP 事件`,"aca.performance.slow")},Math.min(3e4,Math.max(1e3,Math.floor(e/4))));return s.unref(),s}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("Codex ACP prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}async promptWithAbort(e,s){const t=e.prompt({sessionId:s.sessionId,prompt:s.prompt},s.timeoutMs);if(!s.signal)return t;if(s.signal.aborted)throw await this.lease?.dispose().catch(()=>{}),new Error("Codex ACP prompt cancelled");let r=null;const n=new Promise((i,c)=>{r=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP prompt cancelled"))},s.signal?.addEventListener("abort",r,{once:!0})});try{return await Promise.race([t,n])}finally{r&&s.signal.removeEventListener("abort",r)}}async compactWithAbort(e,s){const t=e.compactSession({sessionId:s.sessionId,allowRollover:s.allowRollover,timeoutMs:s.timeoutMs},s.timeoutMs);if(!s.signal)return t;if(s.signal.aborted)throw await this.lease?.dispose().catch(()=>{}),new Error("Codex ACP 上下文压缩已取消");let r=null;const n=new Promise((i,c)=>{r=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP 上下文压缩已取消"))},s.signal?.addEventListener("abort",r,{once:!0})});try{return await Promise.race([t,n])}finally{r&&s.signal.removeEventListener("abort",r)}}async requestPermission(e){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s,n=(Array.isArray(t.options)?t.options:[]).map((i,c)=>{const a=i&&typeof i=="object"&&!Array.isArray(i)?i:{};return{optionId:String(a.optionId??a.id??c),kind:String(a.kind??"choice"),...typeof a.label=="string"?{label:a.label}:{}}});return this.emitStatus("requestPermission","等待授权",_(t),"session/request_permission"),this.permissionCallback({requestId:String(t.requestId??t.id??`codex-acp-permission-${Date.now()}`),params:e,options:n})}async requestUserInput(e){if(!this.userInputCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s;return this.emitStatus("requestPermission","等待输入",R(t),"elicitation/create"),this.userInputCallback({requestId:String(t.requestId??t.id??`codex-acp-input-${Date.now()}`),prompt:String(t.prompt??t.message??t.question??""),params:e,...typeof t.defaultValue=="string"?{defaultValue:t.defaultValue}:{}})}emitStatus(e,s,t,r){const n={phase:e,label:s,...t?{detail:t}:{},...r?{updateType:r}:{},atMs:Date.now()},i=this.statusTimeline[this.statusTimeline.length-1];i&&i.phase===n.phase&&i.label===n.label&&i.detail===n.detail&&i.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}releaseLease(){this.lease?.release(),this.lease=null}}function T(o,e){if(e?.aborted)return!0;const s=o instanceof Error?o.message:String(o||"");return/compact.*timed out|request timed out.*compact|adapter closed|aborted|cancelled/i.test(s)}function p(o){if(!o||typeof o!="object"||Array.isArray(o))return null;const e=o.sessionId;return typeof e=="string"&&e.trim()?e.trim():null}function l(o){return o&&typeof o=="object"&&!Array.isArray(o)?o:null}function h(o){const e=String(o||"").trim();return e?e==="read-only"?"read-only":["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"danger-full-access":"workspace-write":null}function f(o){const e=String(o||"").trim();return e?["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"never":e==="acceptEdits"||e==="accept-edits"?"on-failure":"on-request":null}function g(o){return{...o.model?{model:o.model}:{},...f(o.mode)?{approvalPolicy:f(o.mode)}:{},...h(o.mode)?{sandbox:h(o.mode)}:{},...o.configOptionValues??{}}}function _(o){const e=o.params&&typeof o.params=="object"&&!Array.isArray(o.params)?o.params:o;for(const s of["command","cwd","reason","grantRoot","method"]){const t=e[s];if(typeof t=="string"&&t.trim())return y(t)}}function R(o){for(const e of["prompt","message","question","title"]){const s=o[e];if(typeof s=="string"&&s.trim())return y(s)}}function y(o){const e=o.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function q(){const o=Number.parseInt(process.env.ACA_CODEX_ACP_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(o)&&o>=3e4?o:360*60*1e3}function E(o){const e=Number.isInteger(o)?Number(o):Number.parseInt(process.env.ACA_CODEX_ACP_COMPACT_TIMEOUT_MS??"",10);return Number.isFinite(e)&&e>=3e4?Math.min(e,6e5):12e4}function b(o){if(!o||typeof o!="object"||Array.isArray(o))return null;const e=o;return typeof e.sessionId=="string"&&e.sessionId.trim()?e.sessionId:null}function U(o){const e=l(o),s=l(e?._meta);return C(s?.acaContextUsage)}function C(o){const e=l(o);if(!e)return null;const s=m(e.contextWindow),t=m(e.usedTokens),r=m(e.inputTokens),n=String(e.state||"unknown"),i=["active","compacted","new_thread"].includes(n)?n:"unknown";return{usedTokens:t,inputTokens:r,contextWindow:s,ratio:s>0?Math.max(0,m(e.ratio)||t/s):0,observedAtMs:m(e.observedAtMs)||Date.now(),state:i,maintenanceAction:typeof e.maintenanceAction=="string"?e.maintenanceAction:null}}function m(o){return typeof o=="number"&&Number.isFinite(o)&&o>=0?o:0}export{F as CodexAcpProvider,k as codexAcpCapabilities};
@@ -1 +1 @@
1
- import{Command as R}from"commander";import _ from"node:fs";import v from"node:os";import f from"node:path";import t from"node:process";import{randomUUID as W}from"node:crypto";import{Logger as $}from"../core/logger.js";import{loadCredentials as N,saveApiKeyCredential as O}from"../core/auth.js";import{getRuntimeStatePath as x}from"../core/paths.js";import{writeJsonFile as L}from"../core/fs.js";import{HEARTBEAT_INTERVAL_MS as M,startHeartbeatLoop as U}from"../core/heartbeat.js";import{startJobWorkerLoop as j}from"../core/job-worker.js";import{startFileTransferWorkerLoop as F}from"../core/file-transfer-worker.js";import{startMachineFilesystemWorkerLoop as H}from"../core/machine-filesystem-worker.js";import{cleanupOrphanedAcpProcesses as K}from"../core/acp-orphan-cleanup.js";import{defaultAcpRuntimePool as S}from"../acp/client/acp-runtime-pool.js";import{isProcessAlive as l,readPidFile as h,writePidFile as V,removePidFile as y}from"../core/process.js";import{applyRuntimePathOptions as C}from"../core/runtime-options.js";import{loadAcaConfig as B,updateAcaConfig as b}from"../core/aca-config.js";import{acaServerRequest as G}from"../core/aca-server-client.js";import{ACA_WORKER_INSTANCE_ENV as P,ACA_WORKER_PID_ENV as J,ACA_WORKER_START_TICKS_ENV as q,readProcessStartTicks as z}from"../core/process-identity.js";import{printStartTips as Q,spawnDaemon as X}from"./daemon.js";function Pe(){return new R("start").description("Start agent service in native mode").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica or AICA_HOME)").option("--aica-config <path>","Config file path (defaults to <aica-home>/config.json)").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--server <url>","ACA Server URL override").option("--machine-id <id>","Machine ID override for this runtime").option("--machine-name <name>","Machine name to register (defaults to hostname)").option("--cli-types <types...>","Specify CLI types to register, `claude` or `codex`").option("--debug","enable debug output").option("--heartbeat-log","output current timestamp every 5 seconds").option("--auth <api-key>","Use a CLI API key for non-interactive authentication").option("--token <enrollment-token>","Use a one-time Web-generated token to register this machine").option("-b, --background","在后台启动 Worker").action(async e=>{if(e.background){await Y(e);return}await te(e)})}async function Y(e){C(e);const r=h();if(r&&l(r))throw new Error(`Worker 已在后台运行,PID ${r}。`);r&&y();const a=X(Z());if(a.unref(),!a.pid)throw new Error("后台 Worker 启动失败:未获得进程 PID。");if(!await ee(a.pid,3e3)&&!l(a.pid))throw new Error(`后台 Worker 启动失败,请检查 ${f.join(t.env.AICA_HOME||t.env.ACA_HOME||f.join(v.homedir(),".aica"),"logs")}。`);console.log(`Worker 已在后台启动,PID ${a.pid}。`),Q()}function Z(){const e=t.argv.findIndex((r,a)=>a>=2&&r==="start");return e<0?[]:t.argv.slice(e+1).filter(r=>r!=="--background"&&r!=="-b")}async function ee(e,r){const a=Date.now();for(;Date.now()-a<r;){if(h()===e)return!0;if(!l(e))return!1;await new Promise(i=>setTimeout(i,50))}return h()===e}async function te(e){C(e);const r=t.env[P]||W(),a=z(t.pid)||"";t.env[P]=r,t.env[J]=String(t.pid),t.env[q]=a;const i=new $("start",e.debug?"debug":"info"),E=B(),u={...e.server?.trim()?{serverUrl:e.server.trim()}:{},...e.machineId?{machineId:e.machineId.trim()}:{},...e.machineName?{machineName:e.machineName.trim()}:{}};let s=Object.keys(u).length>0?b(u):E;const c=e.machineName?.trim()||s.machineName||v.hostname();if(e.token?.trim()){const n=await G("POST","/api/auth/machine-enroll",{token:e.token.trim(),machineId:s.machineId,machineName:c},{serverUrl:s.serverUrl});s=b({machineId:n.machineId,machineName:c,token:n.token,username:n.username}),i.info(`Machine enrollment completed for user ${n.username}`)}const D=e.auth?O(e.auth,c):N();V(t.pid),T({pid:t.pid,workerInstanceId:r,workerStartTicks:a,phase:"running",startupStage:"local-compatible",machineId:s.machineId||D?.machine?.machineId||"local-machine",machineName:c,cliTypes:e.cliTypes??re(),startedAt:new Date().toISOString(),heartbeatIntervalMs:M,issues:[{severity:"info",message:"aca is running in aca-server compatibility mode; ACP execution happens on this machine."}]}),i.info(`Starting aca local-compatible service on machine ${c}`),i.info(`PID ${t.pid}`);const m=await K();m.terminated>0&&i.warn(`terminated ${m.terminated} orphaned ACP process(es): ${m.pids.join(",")}`);let g=!1,d,w,I,A;const k=async n=>{if(g)return;g=!0,i.info("Shutting down"),d&&clearInterval(d),I?.stop(),A?.stop(),await w?.stop().catch(o=>i.warn(`job worker shutdown failed: ${o instanceof Error?o.message:String(o)}`));const p=S.stats();await S.disposeAll().catch(o=>i.warn(`ACP runtime shutdown failed: ${o instanceof Error?o.message:String(o)}`)),i.info(`ACP runtimes stopped total=${p.total} inUse=${p.inUse} idle=${p.idle}`),T({pid:t.pid,phase:"stopped",stoppedAt:new Date().toISOString(),issues:[]}),y(),t.exit(n)};t.once("SIGINT",()=>{k(130)}),t.once("SIGTERM",()=>{k(0)}),e.heartbeatLog&&setInterval(()=>i.info(`heartbeat: ${new Date().toISOString()}`),5e3),d=U(i),w=j(i),I=F(i),A=H(i),await new Promise(()=>{})}function re(){return["codex","claude"].filter(e=>ie(e))}function ie(e){const r=t.env.PATH||"";for(const a of r.split(":"))try{if(a&&_.existsSync(f.join(a,e)))return!0}catch{}return!1}function T(e){L(x(),e)}export{Pe as createStartCommand};
1
+ import{Command as _}from"commander";import $ from"node:fs";import k from"node:os";import p from"node:path";import r from"node:process";import{randomUUID as W}from"node:crypto";import{Logger as N}from"../core/logger.js";import{loadCredentials as O,saveApiKeyCredential as j}from"../core/auth.js";import{getRuntimeStatePath as L}from"../core/paths.js";import{writeJsonFile as x}from"../core/fs.js";import{HEARTBEAT_INTERVAL_MS as M,startHeartbeatLoop as U}from"../core/heartbeat.js";import{startJobWorkerLoop as F}from"../core/job-worker.js";import{startFileTransferWorkerLoop as H}from"../core/file-transfer-worker.js";import{startMachineFilesystemWorkerLoop as K}from"../core/machine-filesystem-worker.js";import{cleanupOrphanedAcpProcesses as V}from"../core/acp-orphan-cleanup.js";import{defaultAcpRuntimePool as S}from"../acp/client/acp-runtime-pool.js";import{isProcessAlive as f,readPidFile as h,writePidFile as B,removePidFile as y}from"../core/process.js";import{applyRuntimePathOptions as b}from"../core/runtime-options.js";import{loadAcaConfig as C,updateAcaConfig as P}from"../core/aca-config.js";import{acaServerRequest as G}from"../core/aca-server-client.js";import{restoreProjectsAfterLogin as J}from"../core/project-recovery.js";import{ACA_WORKER_INSTANCE_ENV as E,ACA_WORKER_PID_ENV as q,ACA_WORKER_START_TICKS_ENV as z,readProcessStartTicks as Q}from"../core/process-identity.js";import{printStartTips as X,spawnDaemon as Y}from"./daemon.js";function Te(){return new _("start").description("Start agent service in native mode").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica or AICA_HOME)").option("--aica-config <path>","Config file path (defaults to <aica-home>/config.json)").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--server <url>","ACA Server URL override").option("--machine-id <id>","Machine ID override for this runtime").option("--machine-name <name>","Machine name to register (defaults to hostname)").option("--cli-types <types...>","Specify CLI types to register, `claude` or `codex`").option("--debug","enable debug output").option("--heartbeat-log","output current timestamp every 5 seconds").option("--auth <api-key>","Use a CLI API key for non-interactive authentication").option("--token <enrollment-token>","Use a one-time Web-generated token to register this machine").option("-b, --background","在后台启动 Worker").action(async e=>{if(e.background){await Z(e);return}await re(e)})}async function Z(e){b(e);const a=h();if(a&&f(a))throw new Error(`Worker 已在后台运行,PID ${a}。`);a&&y();const i=Y(ee());if(i.unref(),!i.pid)throw new Error("后台 Worker 启动失败:未获得进程 PID。");if(!await te(i.pid,3e3)&&!f(i.pid))throw new Error(`后台 Worker 启动失败,请检查 ${p.join(r.env.AICA_HOME||r.env.ACA_HOME||p.join(k.homedir(),".aica"),"logs")}。`);console.log(`Worker 已在后台启动,PID ${i.pid}。`),X()}function ee(){const e=r.argv.findIndex((a,i)=>i>=2&&a==="start");return e<0?[]:r.argv.slice(e+1).filter(a=>a!=="--background"&&a!=="-b")}async function te(e,a){const i=Date.now();for(;Date.now()-i<a;){if(h()===e)return!0;if(!f(e))return!1;await new Promise(t=>setTimeout(t,50))}return h()===e}async function re(e){b(e);const a=r.env[E]||W(),i=Q(r.pid)||"";r.env[E]=a,r.env[q]=String(r.pid),r.env[z]=i;const t=new N("start",e.debug?"debug":"info"),D=C(),u={...e.server?.trim()?{serverUrl:e.server.trim()}:{},...e.machineId?{machineId:e.machineId.trim()}:{},...e.machineName?{machineName:e.machineName.trim()}:{}};let c=Object.keys(u).length>0?P(u):D;const m=e.machineName?.trim()||c.machineName||k.hostname();if(e.token?.trim()){const s=await G("POST","/api/auth/machine-enroll",{token:e.token.trim(),machineId:c.machineId,machineName:m},{serverUrl:c.serverUrl});c=P({machineId:s.machineId,machineName:m,token:s.token,username:s.username}),t.info(`Machine enrollment completed for user ${s.username}`);try{const o=await J();o.restored>0&&t.info(`restored ${o.restored} local project(s) after machine enrollment`),o.unavailable>0&&t.warn(`skipped ${o.unavailable} unavailable project path(s) during machine enrollment recovery`),c=C()}catch(o){t.warn(`project recovery after machine enrollment failed: ${o instanceof Error?o.message:String(o)}`)}}const R=e.auth?j(e.auth,m):O();B(r.pid),T({pid:r.pid,workerInstanceId:a,workerStartTicks:i,phase:"running",startupStage:"local-compatible",machineId:c.machineId||R?.machine?.machineId||"local-machine",machineName:m,cliTypes:e.cliTypes??ae(),startedAt:new Date().toISOString(),heartbeatIntervalMs:M,issues:[{severity:"info",message:"aca is running in aca-server compatibility mode; ACP execution happens on this machine."}]}),t.info(`Starting aca local-compatible service on machine ${m}`),t.info(`PID ${r.pid}`);const d=await V();d.terminated>0&&t.warn(`terminated ${d.terminated} orphaned ACP process(es): ${d.pids.join(",")}`);let g=!1,l,w,v,I;const A=async s=>{if(g)return;g=!0,t.info("Shutting down"),l&&clearInterval(l),v?.stop(),I?.stop(),await w?.stop().catch(n=>t.warn(`job worker shutdown failed: ${n instanceof Error?n.message:String(n)}`));const o=S.stats();await S.disposeAll().catch(n=>t.warn(`ACP runtime shutdown failed: ${n instanceof Error?n.message:String(n)}`)),t.info(`ACP runtimes stopped total=${o.total} inUse=${o.inUse} idle=${o.idle}`),T({pid:r.pid,phase:"stopped",stoppedAt:new Date().toISOString(),issues:[]}),y(),r.exit(s)};r.once("SIGINT",()=>{A(130)}),r.once("SIGTERM",()=>{A(0)}),e.heartbeatLog&&setInterval(()=>t.info(`heartbeat: ${new Date().toISOString()}`),5e3),l=U(t),w=F(t),v=H(t),I=K(t),await new Promise(()=>{})}function ae(){return["codex","claude"].filter(e=>ie(e))}function ie(e){const a=r.env.PATH||"";for(const i of a.split(":"))try{if(i&&$.existsSync(p.join(i,e)))return!0}catch{}return!1}function T(e){x(L(),e)}export{Te as createStartCommand};
@@ -1,4 +1,4 @@
1
- import{Command as p}from"commander";import u from"node:os";import h from"node:readline/promises";import{stdin as a,stdout as i}from"node:process";import{acaServerRequest as f}from"../core/aca-server-client.js";import{applyRuntimePathOptions as d}from"../core/runtime-options.js";import{DEFAULT_ACA_SERVER_URL as l,ensureMachineIdentity as w,updateAcaConfig as g}from"../core/aca-config.js";import{getAcaConfigPath as A}from"../core/paths.js";function D(){return new p("login").description("登录 ACA Server 并生成 Worker 认证配置").option("--server <url>","ACA Server URL").option("--username <name>","用户名").option("--password <password>","密码;不传入时交互式输入").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--machine-id <id>","Machine ID").option("--machine-name <name>","Machine display name").action(async e=>{d(e);const r=e.server?.trim()||process.env.ACA_DEFAULT_SERVER_URL||l,c=e.username?.trim()||await R("用户名: "),n=e.password??await E("密码: ");if(!c)throw new Error("用户名不能为空。");if(!n)throw new Error("密码不能为空。");const o=w({machineId:e.machineId?.trim(),machineName:e.machineName?.trim()||u.hostname()}),t=await f("POST","/api/auth/login",{username:c,password:n,machineId:o.machineId,machineName:o.machineName},{serverUrl:r}),s=g({serverUrl:r,token:t.token,username:t.username,machineId:o.machineId,machineName:o.machineName,defaultWorkspaceId:"default"});console.log(`登录成功:${t.username}`),console.log(`认证配置已保存:${A()}`),console.log(`机器:${s.machineName} (${s.machineId})`)})}async function R(e){if(!a.isTTY||!i.isTTY)throw new Error("非交互环境请使用 --username 和 --password 参数。");const r=h.createInterface({input:a,output:i});try{return(await r.question(e)).trim()}finally{r.close()}}async function E(e){if(!a.isTTY||!i.isTTY||!a.setRawMode)throw new Error("非交互环境请使用 --password 参数。");return i.write(e),a.setRawMode(!0),a.resume(),new Promise((r,c)=>{let n="";const o=s=>{const m=s.toString("utf8");if(m===""){t(),i.write(`
2
- `),c(new Error("已取消登录。"));return}if(m==="\r"||m===`
3
- `){t(),i.write(`
4
- `),r(n);return}if(m===""){n=n.slice(0,-1);return}n+=m},t=()=>{a.setRawMode?.(!1),a.pause(),a.off("data",o)};a.on("data",o)})}export{D as createWorkerAuthCommand};
1
+ import{Command as p}from"commander";import f from"node:os";import u from"node:readline/promises";import{stdin as a,stdout as s}from"node:process";import{acaServerRequest as h}from"../core/aca-server-client.js";import{applyRuntimePathOptions as d}from"../core/runtime-options.js";import{DEFAULT_ACA_SERVER_URL as l,ensureMachineIdentity as w,updateAcaConfig as g}from"../core/aca-config.js";import{getAcaConfigPath as A}from"../core/paths.js";import{restoreProjectsAfterLogin as v}from"../core/project-recovery.js";function D(){return new p("login").description("登录 ACA Server 并生成 Worker 认证配置").option("--server <url>","ACA Server URL").option("--username <name>","用户名").option("--password <password>","密码;不传入时交互式输入").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--machine-id <id>","Machine ID").option("--machine-name <name>","Machine display name").action(async r=>{d(r);const o=r.server?.trim()||process.env.ACA_DEFAULT_SERVER_URL||l,c=r.username?.trim()||await R("用户名: "),n=r.password??await E("密码: ");if(!c)throw new Error("用户名不能为空。");if(!n)throw new Error("密码不能为空。");const t=w({machineId:r.machineId?.trim(),machineName:r.machineName?.trim()||f.hostname()}),i=await h("POST","/api/auth/login",{username:c,password:n,machineId:t.machineId,machineName:t.machineName},{serverUrl:o}),m=g({serverUrl:o,token:i.token,username:i.username,machineId:t.machineId,machineName:t.machineName,defaultWorkspaceId:"default"});console.log(`登录成功:${i.username}`),console.log(`认证配置已保存:${A()}`),console.log(`机器:${m.machineName} (${m.machineId})`);try{const e=await v();e.restored>0&&console.log(`已恢复 ${e.restored} 个本机项目${e.unavailable>0?`,跳过 ${e.unavailable} 个不存在的路径`:""}。`)}catch(e){console.warn(`项目恢复失败,可重新登录后重试:${e instanceof Error?e.message:String(e)}`)}})}async function R(r){if(!a.isTTY||!s.isTTY)throw new Error("非交互环境请使用 --username 和 --password 参数。");const o=u.createInterface({input:a,output:s});try{return(await o.question(r)).trim()}finally{o.close()}}async function E(r){if(!a.isTTY||!s.isTTY||!a.setRawMode)throw new Error("非交互环境请使用 --password 参数。");return s.write(r),a.setRawMode(!0),a.resume(),new Promise((o,c)=>{let n="";const t=m=>{const e=m.toString("utf8");if(e===""){i(),s.write(`
2
+ `),c(new Error("已取消登录。"));return}if(e==="\r"||e===`
3
+ `){i(),s.write(`
4
+ `),o(n);return}if(e===""){n=n.slice(0,-1);return}n+=e},i=()=>{a.setRawMode?.(!1),a.pause(),a.off("data",t)};a.on("data",t)})}export{D as createWorkerAuthCommand};
@@ -1 +1 @@
1
- import{Command as c}from"commander";import p from"node:path";import{acaServerRequest as i}from"../core/aca-server-client.js";import{applyRuntimePathOptions as n}from"../core/runtime-options.js";import{loadAcaConfig as s,upsertLocalProject as d}from"../core/aca-config.js";function k(){return new c("project").description("Manage remote projects without local SQLite").addCommand(new c("add").description("Register a local project on ACA Server").argument("<root>","Project root path").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--name <name>","Project name").option("--workspace <id>","ACA workspace ID").option("--type <project|chat-room>","Project type","project").action(async(t,o)=>{if(n(o),o.type!=="project"&&o.type!=="chat-room")throw new Error("Project type must be 'project' or 'chat-room'.");const r=s(),e=p.resolve(t),m=o.name?.trim()||p.basename(e),a=(await i("POST","/api/projects",{workspaceId:o.workspace||r.defaultWorkspaceId,name:m,rootPath:e,source:"aica",projectType:o.type==="chat-room"?"chat_room":"project"})).item;d({projectId:a.project_id,workspaceId:a.workspace_id,name:a.name,rootPath:a.root_path}),console.log(`${a.project_id} ${a.name} ${a.root_path}`)})).addCommand(new c("list").description("List projects from ACA Server").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--workspace <id>","ACA workspace ID").action(async t=>{n(t);const o=t.workspace?`?workspaceId=${encodeURIComponent(t.workspace)}`:"",r=await i("GET",`/api/projects${o}`);for(const e of r.items)console.log(`${e.project_id} workspace=${e.workspace_id} name=${e.name} root=${e.root_path}`)}))}export{k as createWorkerProjectCommand};
1
+ import{Command as c}from"commander";import p from"node:fs";import i from"node:path";import{acaServerRequest as n}from"../core/aca-server-client.js";import{applyRuntimePathOptions as m}from"../core/runtime-options.js";import{loadAcaConfig as d,upsertLocalProject as h}from"../core/aca-config.js";function u(){return new c("project").description("Manage remote projects without local SQLite").addCommand(new c("add").description("Register a local project on ACA Server").argument("<root>","Project root path").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--name <name>","Project name").option("--workspace <id>","ACA workspace ID").option("--type <project|chat-room>","Project type","project").action(async(t,o)=>{if(m(o),o.type!=="project"&&o.type!=="chat-room")throw new Error("Project type must be 'project' or 'chat-room'.");const r=d(),e=p.realpathSync.native(i.resolve(t));if(!p.statSync(e).isDirectory())throw new Error("项目根目录必须是目录。");const s=o.name?.trim()||i.basename(e),a=(await n("POST","/api/projects",{workspaceId:o.workspace||r.defaultWorkspaceId,name:s,rootPath:e,source:"aica",projectType:o.type==="chat-room"?"chat_room":"project"})).item;h({projectId:a.project_id,workspaceId:a.workspace_id,name:a.name,rootPath:a.root_path}),console.log(`${a.project_id} ${a.name} ${a.root_path}`)})).addCommand(new c("list").description("List projects from ACA Server").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--workspace <id>","ACA workspace ID").action(async t=>{m(t);const o=t.workspace?`?workspaceId=${encodeURIComponent(t.workspace)}`:"",r=await n("GET",`/api/projects${o}`);for(const e of r.items)console.log(`${e.project_id} workspace=${e.workspace_id} name=${e.name} root=${e.root_path}`)}))}export{u as createWorkerProjectCommand};
@@ -1 +1 @@
1
- import{readJsonFile as f,writeJsonFile as s}from"./fs.js";import{getAcaConfigPath as d}from"./paths.js";import{randomUUID as u}from"node:crypto";import m from"node:os";const p="https://aca.kinghon.com.cn:8843/";function o(){const e=f(d())??{};return{serverUrl:e.serverUrl||process.env.ACA_DEFAULT_SERVER_URL||p,token:e.token,username:e.username,machineId:e.machineId||u(),machineName:e.machineName||m.hostname(),defaultWorkspaceId:e.defaultWorkspaceId||"default",defaultProjectId:e.defaultProjectId,projects:Array.isArray(e.projects)?e.projects:[]}}function P(e={}){const t=f(d())??{},n={...o(),...e.machineId?{machineId:e.machineId}:{},...e.machineName?{machineName:e.machineName}:{}};return(!t.machineId||e.machineId||e.machineName)&&i(n),{machineId:n.machineId,machineName:n.machineName}}function i(e){s(d(),e)}function A(e){const t={...o(),...e};return i(t),t}function x(e){const t=o(),n=t.projects.filter(c=>c.projectId!==e.projectId&&c.name!==e.name);n.push(e);const r={...t,defaultWorkspaceId:e.workspaceId,defaultProjectId:e.projectId,projects:n};return i(r),r}function g(e){const t=o(),n=t.projects.filter(a=>a.projectId!==e&&a.name!==e),r=t.defaultProjectId===e||t.projects.find(a=>a.name===e)?.projectId===t.defaultProjectId?n[0]?.projectId:t.defaultProjectId,c={...t,defaultProjectId:r,projects:n};return i(c),c}function U(e){const t=o();return!e&&t.defaultProjectId?t.projects.find(n=>n.projectId===t.defaultProjectId)??null:e?t.projects.find(n=>n.projectId===e||n.name===e)??null:t.projects[0]??null}export{p as DEFAULT_ACA_SERVER_URL,P as ensureMachineIdentity,U as findLocalProject,o as loadAcaConfig,g as removeLocalProject,i as saveAcaConfig,A as updateAcaConfig,x as upsertLocalProject};
1
+ import{readJsonFile as l,writeJsonFile as h}from"./fs.js";import{getAcaConfigPath as f}from"./paths.js";import{randomUUID as I}from"node:crypto";import j from"node:os";import m from"node:path";const P="https://aca.kinghon.com.cn:8843/";function s(){const t=l(f())??{};return{serverUrl:t.serverUrl||process.env.ACA_DEFAULT_SERVER_URL||P,token:t.token,username:t.username,machineId:t.machineId||I(),machineName:t.machineName||j.hostname(),defaultWorkspaceId:t.defaultWorkspaceId||"default",defaultProjectId:t.defaultProjectId,projects:Array.isArray(t.projects)?t.projects:[]}}function w(t={}){const o=l(f())??{},e={...s(),...t.machineId?{machineId:t.machineId}:{},...t.machineName?{machineName:t.machineName}:{}};return(!o.machineId||t.machineId||t.machineName)&&d(e),{machineId:e.machineId,machineName:e.machineName}}function d(t){h(f(),t)}function U(t){const o={...s(),...t};return d(o),o}function C(t){const o=s(),e=i(t.rootPath),c=o.projects.filter(r=>r.projectId!==t.projectId&&i(r.rootPath)!==e);c.push(t);const n={...o,defaultWorkspaceId:t.workspaceId,defaultProjectId:t.projectId,projects:c};return d(n),n}function E(t){const o=s(),e=o.projects.length===0,c=[...o.projects],n=new Set(c.map(a=>i(a.rootPath)));for(const a of t){const u=i(a.rootPath);n.has(u)||(c.push(a),n.add(u))}const r=t.find(a=>n.has(i(a.rootPath))),p={...o,defaultWorkspaceId:e?r?.workspaceId||"default":o.defaultWorkspaceId,defaultProjectId:e?r?.projectId:o.defaultProjectId,projects:c};return d(p),p}function i(t){const o=process.platform==="win32"?m.win32:m.posix,e=o.normalize(t),c=o.parse(e).root,n=e.length>c.length?e.replace(/[\\/]+$/,""):e;return process.platform==="win32"?n.toLocaleLowerCase("en-US"):n}function R(t){const o=s(),e=o.projects.filter(r=>r.projectId!==t&&r.name!==t),c=o.defaultProjectId===t||o.projects.find(r=>r.name===t)?.projectId===o.defaultProjectId?e[0]?.projectId:o.defaultProjectId,n={...o,defaultProjectId:c,projects:e};return d(n),n}function _(t){const o=s();return!t&&o.defaultProjectId?o.projects.find(e=>e.projectId===o.defaultProjectId)??null:t?o.projects.find(e=>e.projectId===t||e.name===t)??null:o.projects[0]??null}export{P as DEFAULT_ACA_SERVER_URL,i as comparableLocalProjectPath,w as ensureMachineIdentity,_ as findLocalProject,s as loadAcaConfig,R as removeLocalProject,E as restoreLocalProjects,d as saveAcaConfig,U as updateAcaConfig,C as upsertLocalProject};
@@ -1 +1 @@
1
- const h=1024,_=new Set(["agent_message_chunk","agent_progress_chunk","agent_thought_chunk","user_message_chunk"]),T=new Set(["usage_update","session_info_update"]);function C(t,e){const n=t.at(-1);if(!n)return t.push(e),!1;if(S(n,e)){const r=`${n.text??""}${e.text??""}`;if(r.length<=1024)return n.text=r,n.raw=f(n.raw,e.raw,r),!0}if(E(n,e)){const r=d(n.raw);return n.label=e.label,n.text=e.text,n.status=e.status,n.toolCallId=e.toolCallId,n.raw=f(n.raw,e.raw,e.text,r),!0}return t.push(e),!1}function S(t,e){return _.has(t.eventType)&&t.eventType===e.eventType&&t.turnId===e.turnId&&t.label===e.label&&t.status===e.status&&!t.toolCallId&&!e.toolCallId&&typeof t.text=="string"&&typeof e.text=="string"}function E(t,e){if(t.eventType!==e.eventType||t.turnId!==e.turnId)return!1;if(T.has(t.eventType))return!0;if(t.eventType!=="config_option_update")return!1;const n=c(t.raw),r=c(e.raw);return!!n&&n===r}function c(t){const e=w(t);for(const n of["configId","optionId","id","key","name"])if(typeof e?.[n]=="string"&&e[n].trim())return e[n].trim();return""}function f(t,e,n,r=d(t)){const u=a(e);if(!u)return e;const p=x(e),y=l(t)+l(e),s={...u,acaSequence:r,acaSequenceEnd:p,sourceEventCount:y};if(n!==void 0){const o=a(u.update);o&&(s.update={...o,content:{type:"text",text:n}})}return s}function w(t){return a(a(t)?.update)}function d(t){const e=a(t)?.acaSequence;return typeof e=="number"?e:void 0}function x(t){const e=a(t),n=e?.acaSequenceEnd;return typeof n=="number"?n:typeof e?.acaSequence=="number"?e.acaSequence:void 0}function l(t){const e=a(t)?.sourceEventCount;return typeof e=="number"&&e>0?e:1}function a(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:null}export{C as appendCoalescedAcpEvent};
1
+ const x=1024,b=2048,T=new Set(["agent_message_chunk","agent_progress_chunk","agent_thought_chunk","user_message_chunk"]),w=new Set(["usage_update","session_info_update"]);function q(e,t){const a=e.at(-1);if(!a)return e.push(t),!1;if(S(a,t)){const n=`${a.text??""}${t.text??""}`;if(n.length<=1024)return a.text=n,a.raw=o(a.raw,t.raw,n),!0}if(I(a,t))return E(a,t),!0;if(A(a,t)){const n=p(a.raw);return a.label=t.label,a.text=t.text,a.status=t.status,a.toolCallId=t.toolCallId,a.raw=o(a.raw,t.raw,t.text,n),!0}return e.push(t),!1}function I(e,t){if(e.eventType!=="tool_call_update"||t.eventType!=="tool_call_update"||!e.toolCallId||e.toolCallId!==t.toolCallId||e.turnId!==t.turnId||e.status!=="in_progress"||t.status!=="in_progress")return!1;const a=d(e.raw),n=d(t.raw);return!a||!n||a.terminalId!==n.terminalId?!1:a.data.length+n.data.length<=2048}function E(e,t){const a=d(e.raw),n=d(t.raw);if(!a||!n)return;e.label=t.label??e.label,e.raw=o(e.raw,t.raw,void 0);const u=r(e.raw),l=r(u?.update),s=r(l?._meta);!u||!l||!s||(u.update={...l,_meta:{...s,terminal_output_delta:{...n.raw,data:a.data+n.data}}})}function d(e){const t=r(r(e)?.update),a=r(r(t?._meta)?.terminal_output_delta);if(!a)return null;const n=typeof a?.data=="string"?a.data:"",u=typeof a?.terminal_id=="string"?a.terminal_id:"";return n&&u?{data:n,terminalId:u,raw:a}:null}function S(e,t){return T.has(e.eventType)&&e.eventType===t.eventType&&e.turnId===t.turnId&&e.label===t.label&&e.status===t.status&&!e.toolCallId&&!t.toolCallId&&typeof e.text=="string"&&typeof t.text=="string"}function A(e,t){if(e.eventType!==t.eventType||e.turnId!==t.turnId)return!1;if(w.has(e.eventType))return!0;if(e.eventType!=="config_option_update")return!1;const a=_(e.raw),n=_(t.raw);return!!a&&a===n}function _(e){const t=C(e);for(const a of["configId","optionId","id","key","name"])if(typeof t?.[a]=="string"&&t[a].trim())return t[a].trim();return""}function o(e,t,a,n=p(e)){const u=r(t);if(!u)return t;const l=h(t),s=y(e)+y(t),f={...u,acaSequence:n,acaSequenceEnd:l,sourceEventCount:s};if(a!==void 0){const c=r(u.update);c&&(f.update={...c,content:{type:"text",text:a}})}return f}function C(e){return r(r(e)?.update)}function p(e){const t=r(e)?.acaSequence;return typeof t=="number"?t:void 0}function h(e){const t=r(e),a=t?.acaSequenceEnd;return typeof a=="number"?a:typeof t?.acaSequence=="number"?t.acaSequence:void 0}function y(e){const t=r(e)?.sourceEventCount;return typeof t=="number"&&t>0?t:1}function r(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}export{q as appendCoalescedAcpEvent};
@@ -1 +1 @@
1
- import s from"node:fs";import d from"node:os";import i from"node:path";import{Readable as w}from"node:stream";import{acaServerRequest as f,acaServerStreamRequest as h}from"./aca-server-client.js";import{loadAcaConfig as x}from"./aca-config.js";import{getAcaHome as p}from"./paths.js";import{startLongPollWorker as y}from"./long-poll-worker.js";const b=25e3;function P(e){return y({run:async()=>{const t=x();if(!t.token)throw new Error("Worker 尚未配置认证令牌");const a=await f("GET",`/api/client/file-requests/claim?machineId=${encodeURIComponent(t.machineId)}&waitMs=${b}`);if(a.item)try{await S(a.item,t,e)}catch(n){const o=n instanceof Error?n.message:String(n);e.warn(`file request failed request=${a.item.requestId}: ${o}`);try{await j(a.item.requestId,o)}catch(r){e.warn(`file request fail callback failed request=${a.item.requestId}: ${r instanceof Error?r.message:String(r)}`)}}},onError:(t,a)=>e.warn(`file transfer worker failed, retry in ${a}ms: ${t instanceof Error?t.message:String(t)}`)})}async function j(e,t){await f("POST",`/api/client/file-requests/${encodeURIComponent(e)}/fail`,{message:t})}async function S(e,t,a){const n=t.projects.find(g=>g.projectId===e.projectId),o=u(e.projectRoot||n?.rootPath||"");if(!o)throw new Error(`file request ${e.requestId} project root is unknown`);const r=e.purpose==="temp-image"?"temp-image":e.purpose==="project-preview"?"project-preview":"project-file",c=r==="temp-image"?v(e.path):I(o,e.path),m=s.statSync(c);if(!m.isFile())throw new Error(`file request ${e.requestId} target is not a file`);if(m.size>e.maxBytes)throw new Error(`file request ${e.requestId} target is too large (${m.size} bytes)`);const l=r==="temp-image"?E(c):$(c);a.info(`streaming file request=${e.requestId} path=${c}`),await h("POST",`/api/client/file-requests/${encodeURIComponent(e.requestId)}/stream`,w.toWeb(s.createReadStream(c)),{"content-type":"application/octet-stream","x-aca-file-name":encodeURIComponent(i.basename(c)),"x-aca-file-size":String(m.size),"x-aca-file-mime":l})}function I(e,t){const a=s.realpathSync(u(e)),n=i.isAbsolute(t)?t:i.join(a,t),o=s.realpathSync(n),r=i.relative(a,o);if(r===""||r.startsWith("..")||i.isAbsolute(r))throw new Error("requested file is outside project root");return o}function v(e){const t=R(e);if(!i.isAbsolute(t))throw new Error("temporary image path must be absolute");const a=s.lstatSync(t);if(a.isSymbolicLink())throw new Error("temporary image cannot be a symbolic link");if(!a.isFile())throw new Error("temporary image target is not a regular file");const n=s.realpathSync(d.tmpdir()),o=s.realpathSync(t),r=i.relative(n,o);if(r===""||r.startsWith("..")||i.isAbsolute(r))throw new Error("temporary image is outside the system temp directory");return o}function E(e){const t=i.extname(e).toLowerCase(),a=Buffer.alloc(16),n=s.openSync(e,"r");let o=0;try{o=s.readSync(n,a,0,a.length,0)}finally{s.closeSync(n)}const r=a.subarray(0,o);if(t===".png"&&r.length>=8&&r.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])))return"image/png";if([".jpg",".jpeg"].includes(t)&&r.length>=3&&r[0]===255&&r[1]===216&&r[2]===255)return"image/jpeg";if(t===".gif"&&r.length>=6&&["GIF87a","GIF89a"].includes(r.subarray(0,6).toString("ascii")))return"image/gif";if(t===".webp"&&r.length>=12&&r.subarray(0,4).toString("ascii")==="RIFF"&&r.subarray(8,12).toString("ascii")==="WEBP")return"image/webp";throw new Error("temporary file is not a supported raster image")}function R(e){const t=String(e||"").trim();if(!t.startsWith("file://"))return t;try{return decodeURIComponent(new URL(t).pathname)}catch{throw new Error("temporary image path is invalid")}}function u(e){return e?e==="~"?i.dirname(p()):e.startsWith("~/")?i.join(i.dirname(p()),e.slice(2)):e:""}function $(e){switch(i.extname(e).toLowerCase()){case".pdf":return"application/pdf";case".md":case".markdown":return"text/markdown; charset=utf-8";case".txt":case".log":return"text/plain; charset=utf-8";case".html":case".htm":return"text/html; charset=utf-8";case".css":return"text/css; charset=utf-8";case".js":case".mjs":return"text/javascript; charset=utf-8";case".json":case".map":return"application/json; charset=utf-8";case".xml":return"application/xml; charset=utf-8";case".svg":return"image/svg+xml; charset=utf-8";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".gif":return"image/gif";case".webp":return"image/webp";case".avif":return"image/avif";case".ico":return"image/x-icon";case".bmp":return"image/bmp";case".woff":return"font/woff";case".woff2":return"font/woff2";case".ttf":return"font/ttf";case".otf":return"font/otf";case".eot":return"application/vnd.ms-fontobject";case".mp4":return"video/mp4";case".webm":return"video/webm";case".mp3":return"audio/mpeg";case".wav":return"audio/wav";case".ogg":return"audio/ogg";case".webmanifest":return"application/manifest+json; charset=utf-8";case".zip":return"application/zip";case".docx":return"application/vnd.openxmlformats-officedocument.wordprocessingml.document";case".xlsx":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";default:return"application/octet-stream"}}export{E as detectSafeTempImageMime,$ as mimeForPath,I as resolveProjectFile,v as resolveTempImageFile,P as startFileTransferWorkerLoop};
1
+ import i from"node:fs";import g from"node:os";import s from"node:path";import{Readable as d}from"node:stream";import{acaServerRequest as p,acaServerStreamRequest as w}from"./aca-server-client.js";import{loadAcaConfig as h}from"./aca-config.js";import{expandWorkerRuntimePath as x}from"./worker-runtime-paths.js";import{startLongPollWorker as y}from"./long-poll-worker.js";const b=25e3;function U(e){return y({run:async()=>{const t=h();if(!t.token)throw new Error("Worker 尚未配置认证令牌");const a=await p("GET",`/api/client/file-requests/claim?machineId=${encodeURIComponent(t.machineId)}&waitMs=${b}`);if(a.item)try{await S(a.item,t,e)}catch(n){const o=n instanceof Error?n.message:String(n);e.warn(`file request failed request=${a.item.requestId}: ${o}`);try{await j(a.item.requestId,o)}catch(r){e.warn(`file request fail callback failed request=${a.item.requestId}: ${r instanceof Error?r.message:String(r)}`)}}},onError:(t,a)=>e.warn(`file transfer worker failed, retry in ${a}ms: ${t instanceof Error?t.message:String(t)}`)})}async function j(e,t){await p("POST",`/api/client/file-requests/${encodeURIComponent(e)}/fail`,{message:t})}async function S(e,t,a){const n=t.projects.find(l=>l.projectId===e.projectId),o=f(e.projectRoot||n?.rootPath||"");if(!o)throw new Error(`file request ${e.requestId} project root is unknown`);const r=e.purpose==="temp-image"?"temp-image":e.purpose==="project-preview"?"project-preview":"project-file",c=r==="temp-image"?I(e.path):v(o,e.path),m=i.statSync(c);if(!m.isFile())throw new Error(`file request ${e.requestId} target is not a file`);if(m.size>e.maxBytes)throw new Error(`file request ${e.requestId} target is too large (${m.size} bytes)`);const u=r==="temp-image"?R(c):$(c);a.info(`streaming file request=${e.requestId} path=${c}`),await w("POST",`/api/client/file-requests/${encodeURIComponent(e.requestId)}/stream`,d.toWeb(i.createReadStream(c)),{"content-type":"application/octet-stream","x-aca-file-name":encodeURIComponent(s.basename(c)),"x-aca-file-size":String(m.size),"x-aca-file-mime":u})}function v(e,t){const a=i.realpathSync(f(e)),n=s.isAbsolute(t)?t:s.join(a,t),o=i.realpathSync(n),r=s.relative(a,o);if(r===""||r.startsWith("..")||s.isAbsolute(r))throw new Error("requested file is outside project root");return o}function I(e){const t=E(e);if(!s.isAbsolute(t))throw new Error("temporary image path must be absolute");const a=i.lstatSync(t);if(a.isSymbolicLink())throw new Error("temporary image cannot be a symbolic link");if(!a.isFile())throw new Error("temporary image target is not a regular file");const n=i.realpathSync(g.tmpdir()),o=i.realpathSync(t),r=s.relative(n,o);if(r===""||r.startsWith("..")||s.isAbsolute(r))throw new Error("temporary image is outside the system temp directory");return o}function R(e){const t=s.extname(e).toLowerCase(),a=Buffer.alloc(16),n=i.openSync(e,"r");let o=0;try{o=i.readSync(n,a,0,a.length,0)}finally{i.closeSync(n)}const r=a.subarray(0,o);if(t===".png"&&r.length>=8&&r.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])))return"image/png";if([".jpg",".jpeg"].includes(t)&&r.length>=3&&r[0]===255&&r[1]===216&&r[2]===255)return"image/jpeg";if(t===".gif"&&r.length>=6&&["GIF87a","GIF89a"].includes(r.subarray(0,6).toString("ascii")))return"image/gif";if(t===".webp"&&r.length>=12&&r.subarray(0,4).toString("ascii")==="RIFF"&&r.subarray(8,12).toString("ascii")==="WEBP")return"image/webp";throw new Error("temporary file is not a supported raster image")}function E(e){const t=String(e||"").trim();if(!t.startsWith("file://"))return t;try{return decodeURIComponent(new URL(t).pathname)}catch{throw new Error("temporary image path is invalid")}}function f(e){return x(e)}function $(e){switch(s.extname(e).toLowerCase()){case".pdf":return"application/pdf";case".md":case".markdown":return"text/markdown; charset=utf-8";case".txt":case".log":return"text/plain; charset=utf-8";case".html":case".htm":return"text/html; charset=utf-8";case".css":return"text/css; charset=utf-8";case".js":case".mjs":return"text/javascript; charset=utf-8";case".json":case".map":return"application/json; charset=utf-8";case".xml":return"application/xml; charset=utf-8";case".svg":return"image/svg+xml; charset=utf-8";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".gif":return"image/gif";case".webp":return"image/webp";case".avif":return"image/avif";case".ico":return"image/x-icon";case".bmp":return"image/bmp";case".woff":return"font/woff";case".woff2":return"font/woff2";case".ttf":return"font/ttf";case".otf":return"font/otf";case".eot":return"application/vnd.ms-fontobject";case".mp4":return"video/mp4";case".webm":return"video/webm";case".mp3":return"audio/mpeg";case".wav":return"audio/wav";case".ogg":return"audio/ogg";case".webmanifest":return"application/manifest+json; charset=utf-8";case".zip":return"application/zip";case".docx":return"application/vnd.openxmlformats-officedocument.wordprocessingml.document";case".xlsx":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";default:return"application/octet-stream"}}export{R as detectSafeTempImageMime,$ as mimeForPath,v as resolveProjectFile,I as resolveTempImageFile,U as startFileTransferWorkerLoop};
@@ -1,6 +1,6 @@
1
- import W from"node:crypto";import x from"node:fs";import S from"node:path";import{compactAgentContext as V,sendAgentPrompt as q}from"../acp/agent.js";import{acaServerDownload as D,acaServerRequest as b}from"./aca-server-client.js";import{loadAcaConfig as H}from"./aca-config.js";import{prepareLocalWorktree as G}from"./worktree.js";import{getAcaHome as $}from"./paths.js";import{collectAffectedFiles as N,extractAffectedFilePathsFromAcpRaw as K}from"./affected-files.js";import{resolveJobPermissionPolicy as X}from"./job-permission-policy.js";import{appendCoalescedAcpEvent as Z}from"./acp-event-coalescer.js";import{shouldUploadAcpEvent as Q}from"./acp-event-upload-filter.js";const Y=1500,ee=5e3,M=1e3,te=320,ne=64,O=900,oe=1e4,ie=0,ae=12e3;function re(e){return e?e==="~"?S.dirname($()):e.startsWith("~/")?S.join(S.dirname($()),e.slice(2)):e:""}function se(e){const t=e.project_metadata;return t&&typeof t=="object"&&!Array.isArray(t)&&t.kind==="chat"?!0:typeof e.project_root_path=="string"&&(e.project_root_path.startsWith("~/.aca/chats/")||/(^|\/)\.aca\/chats\//.test(e.project_root_path))}function qe(e,t={}){let n=!1,o=null,i=null;const a=new Set,c=new Set,u=new Map,s=async()=>{if(n)return;const r=ce();if(U(a.size,r))try{const m=t.loadConfig?.()??H();if(!m.token)return;for(;!n&&U(a.size,r);){const A=t.claimNextJob?await t.claimNextJob(m):await b("POST","/api/client/jobs/claim",{machineId:m.machineId,workspaceId:m.defaultWorkspaceId});if(!A.item)break;const d=A.item;if(n){await(t.cancelClaimedJob?t.cancelClaimedJob(d,m):P(d.job_id,m.machineId,"cancelled")).catch(()=>{});break}const f=d.session_id;c.has(f)&&e.warn(`claimed job=${d.job_id} for already active session=${f}; running anyway to avoid leaving it stuck`),a.add(d.job_id),c.add(f);const I=new AbortController,C=(t.runJob??ue)(d,m,e,I).catch(p=>{e.warn(`job ${d.job_id} failed outside handler: ${p instanceof Error?p.message:String(p)}`)}).finally(()=>{a.delete(d.job_id),c.delete(f),u.delete(d.job_id)});u.set(d.job_id,{controller:I,promise:C})}}catch(m){n||e.warn(`job worker failed: ${m instanceof Error?m.message:String(m)}`)}},w=()=>{if(n||o)return;const r=s();o=r,r.finally(()=>{o===r&&(o=null)})};w();const T=setInterval(()=>{w()},t.claimIntervalMs??Y);return{timer:T,stop:()=>i||(i=(async()=>{if(n)return;n=!0,clearInterval(T);for(const m of u.values())m.controller.abort();await o?.catch(()=>{});for(const m of u.values())m.controller.abort();const r=[...u.values()].map(m=>m.promise);r.length!==0&&await Promise.race([Promise.allSettled(r).then(()=>{}),E(ae)])})(),i)}}function ce(){const e=process.env.ACA_MAX_CONCURRENT_JOBS||process.env.ACA_MAX_CONCURRENT_PROJECT_JOBS||"",t=Number.parseInt(e,10);return!e.trim()||!Number.isFinite(t)||t<0?ie:t===0?0:Math.max(1,Math.min(t,8))}function U(e,t){return t===0||e<t}function le(){const e=Number.parseInt(process.env.ACA_ACP_EVENT_BATCH_INTERVAL_MS||"",10);return Number.isFinite(e)?Math.max(40,Math.min(e,2e3)):te}async function ue(e,t,n,o){const i=e.job_id,a=e.session_id,c=e.workspace_id,u=e.project_id??null,s=e.input??{},w=String(s.control?.type||"").toLowerCase();if(!w&&!s.message?.trim()&&(s.attachments??[]).length===0){await P(i,t.machineId,"job input missing message");return}const T=t.projects.find(p=>p.projectId===u),r=re(T?.rootPath||e.project_root_path||"");if(!r){await P(i,t.machineId,"job project root is unknown");return}se(e)&&x.mkdirSync(r,{recursive:!0}),n.info(`claimed job=${i} session=${a} project=${T?.name??u??"unknown"}`);const m=setInterval(()=>{b("POST",`/api/client/jobs/${encodeURIComponent(i)}/heartbeat`,{machineId:t.machineId}).catch(()=>{}),xe(i,o).catch(()=>{})},ee);let A=0;const d=be(i,t.machineId),f=ye(i,t.machineId),I=new Set;let C=null;try{await f.sendNow({phase:"initializing",label:"准备工作区",detail:e.worktree_id?"worktree":"project root"}).catch(()=>{});const p=G({projectId:u,sessionId:a,projectRoot:r,worktree:e});C=p,await ve(i,t.machineId,p);const g=de(s.acpRun);if(w==="compact"){if(!e.acp_session_id)throw new Error("Current session does not have an ACP context to compact");const l=await V({agentType:R(g.agentType,"codex"),cliType:R(g.cliType,"builtin"),acpSessionId:e.acp_session_id,cwd:p.cwd,model:s.model,mode:s.mode,configOptionValues:s.configOptionValues,timeoutMs:s.timeoutMs,allowRollover:s.control?.allowRollover===!0,signal:o.signal,onStatus:y=>{f.report({phase:y.phase,label:y.label,detail:y.detail,updateType:y.updateType,raw:y})}});await f.flush(),await b("POST",`/api/client/jobs/${encodeURIComponent(i)}/complete`,{machineId:t.machineId,acpSessionId:l.acpSessionId,suppressTurn:!0,result:{ok:!0,control:{type:"compact",allowRollover:s.control?.allowRollover===!0},acpSessionId:l.acpSessionId,durationMs:l.durationMs,usage:l.contextUsage,maintenance:l.maintenance,worktree:k(p)}}),n.info(`completed context compact job=${i}`);return}const _=await Te({cwd:p.cwd,sessionId:a,jobId:i,attachments:s.attachments??[]});_.length>0&&(n.info(`materialized ${_.length} attachment(s) for job=${i}`),await f.sendNow({phase:"initializing",label:"附件已写入本机",detail:_.map(l=>l.relativePath).join(", "),raw:{attachments:z(_)}}).catch(()=>{}));const j=_e(s,_),F=ge(j,_),h=await q({agentType:R(g.agentType,"codex"),cliType:R(g.cliType,"builtin"),acpSessionId:e.acp_session_id??null,requireSessionResume:me(e.session_raw),prompt:j,promptBlocks:F,cwd:p.cwd,model:s.model,mode:s.mode,configOptionValues:s.configOptionValues,canExecuteTools:s.canExecuteTools,timeoutMs:s.timeoutMs,contextWindow:fe(g.contextWindow),signal:o.signal,onStatus:l=>{f.report({phase:l.phase,label:l.label,detail:l.detail,updateType:l.updateType,raw:l})},onUpdate:l=>{A+=1;for(const L of K(l.raw))I.add(L);const y={turnId:e.user_turn_id??null,eventType:l.type,label:l.label,text:l.text,status:l.status,toolCallId:l.toolCallId,raw:Ie(l.raw,A)};Q(y)&&d.push(y)},onPermissionRequest:l=>{const y=X(s,l);return y?Promise.resolve(y):Re(i,t.machineId,l,o.signal)},onUserInputRequest:l=>ke(i,t.machineId,l,o.signal)});await d.flush(),await f.flush();const J=N({cwd:p.cwd,evidencePaths:I}),v=he(h.promptResponse);if(!(we(v)||!!h.content)){await P(i,t.machineId,`${h.agentType} stopped: ${v??"unknown"}`,{acpSessionId:h.acpSessionId,stopReason:v,exitCode:h.exitCode,stderr:Ee(h.stderr,4e3),worktree:k(p)});return}await b("POST",`/api/client/jobs/${encodeURIComponent(i)}/complete`,{machineId:t.machineId,acpSessionId:h.acpSessionId,assistantText:h.content,result:{ok:!0,acpSessionId:h.acpSessionId,stopReason:v,durationMs:h.durationMs,acpRun:s.acpRun??null,effectiveConfig:h.effectiveConfig??null,performance:h.performance??null,usage:h.contextUsage??null,updateCount:h.updates.length,statusTimeline:h.statusTimeline,worktree:k(p),attachments:z(_),files:J}}),n.info(`completed job=${i}`)}catch(p){await d.flush(),await f.flush();const g=o.signal.aborted?"cancelled":p instanceof Error?p.message:String(p),_=C?N({cwd:C.cwd,evidencePaths:I}):[];await P(i,t.machineId,pe(g),{rawError:g,files:_})}finally{await d.flush(),await f.flush(),clearInterval(m)}}function me(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e.importedProviderSession;return!!(t&&typeof t=="object"&&!Array.isArray(t)&&t.strictResume===!0)}function pe(e){return/ACP request timed out/i.test(e)?"ACP 长时间没有完成,请稍后重试,或点击停止后重新发送。":/MimoCode request timed out/i.test(e)?"MimoCode 长时间没有完成,请稍后重试,或点击停止后重新发送。":e.replace(/\bsession\/prompt\b/g,"ACP 请求")}function de(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function fe(e){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:void 0}function R(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function he(e){if(!e||typeof e!="object"||Array.isArray(e))return;const t=e;if(typeof t.stopReason=="string")return t.stopReason;if(typeof t.reason=="string")return t.reason;const n=t.part;if(n&&typeof n=="object"&&!Array.isArray(n)&&typeof n.reason=="string")return n.reason}function we(e){return e?["end_turn","stop","completed","complete"].includes(e):!1}function be(e,t){let n=[],o=null,i=Promise.resolve();const a=async s=>{s.length!==0&&await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/events/batch`,{machineId:t,events:s})},c=()=>{o&&(clearTimeout(o),o=null);const s=n;return n=[],i=i.then(()=>a(s)).catch(()=>{}),i},u=()=>{o||(o=setTimeout(()=>{c()},le()),o.unref())};return{push(s){if(Z(n,s),n.length>=ne){c();return}u()},flush:c}}function ye(e,t){let n=null,o=0,i="",a=null,c=Promise.resolve();const u=r=>JSON.stringify({phase:r.phase??"",label:r.label??"",detail:r.detail??"",updateType:r.updateType??""}),s=async r=>{await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/presence`,{machineId:t,phase:r.phase,label:r.label,detail:r.detail,updateType:r.updateType,raw:r.raw}),o=Date.now(),i=u(r)},w=()=>{if(a&&(clearTimeout(a),a=null),!n)return c;const r=n;return n=null,c=c.then(()=>s(r)).catch(()=>{}),c},T=r=>{a||(a=setTimeout(()=>{w()},r),a.unref())};return{report(r){const m=Date.now(),d=u(r)!==i,f=m-o>=oe;if(!d&&!f)return;n=r;const I=m-o;if(I>=O||o===0){w();return}T(O-I)},sendNow(r){return n=r,w()},flush:w}}function Ie(e,t){return e&&typeof e=="object"&&!Array.isArray(e)?{...e,acaSequence:t}:{value:e,acaSequence:t}}function _e(e,t=[]){const n=e?.message?.trim()??"";if(t.length===0)return n;const i=["用户随消息上传了以下附件,aca 已将附件写入本机工作区。需要读取附件时请直接使用下面的 localPath;图片附件也已作为 ACP image block 随本轮请求传入。",...t.map((a,c)=>`${c+1}. ${a.name} (${a.kind}, ${a.mimeType}, ${Pe(a.size)})
2
- localPath: ${a.path}
3
- workspacePath: ${a.relativePath}`)].join(`
1
+ import L from"node:crypto";import E from"node:fs";import x from"node:path";import{compactAgentContext as W,forkAgentSession as V,sendAgentPrompt as q}from"../acp/agent.js";import{acaServerDownload as D,acaServerRequest as y}from"./aca-server-client.js";import{loadAcaConfig as H}from"./aca-config.js";import{prepareLocalWorktree as G}from"./worktree.js";import{expandWorkerRuntimePath as K}from"./worker-runtime-paths.js";import{collectAffectedFiles as M,extractAffectedFilePathsFromAcpRaw as X}from"./affected-files.js";import{resolveJobPermissionPolicy as Z}from"./job-permission-policy.js";import{appendCoalescedAcpEvent as Q}from"./acp-event-coalescer.js";import{shouldUploadAcpEvent as Y}from"./acp-event-upload-filter.js";const ee=1500,te=5e3,N=1e3,ne=200,oe=64,O=900,ae=1e4,ie=0,re=12e3;function se(e){return K(e)}function ce(e){const t=e.project_metadata;return t&&typeof t=="object"&&!Array.isArray(t)&&t.kind==="chat"?!0:typeof e.project_root_path=="string"&&(e.project_root_path.startsWith("~/.aica/chats/")||e.project_root_path.startsWith("~/.aca/chats/")||/(^|\/)\.aica\/chats\//.test(e.project_root_path)||/(^|\/)\.aca\/chats\//.test(e.project_root_path))}function He(e,t={}){let n=!1,a=null,o=null;const r=new Set,l=new Set,u=new Map,i=async()=>{if(n)return;const s=le();if(U(r.size,s))try{const p=t.loadConfig?.()??H();if(!p.token)return;for(;!n&&U(r.size,s);){const A=t.claimNextJob?await t.claimNextJob(p):await y("POST","/api/client/jobs/claim",{machineId:p.machineId,workspaceId:p.defaultWorkspaceId});if(!A.item)break;const f=A.item;if(n){await(t.cancelClaimedJob?t.cancelClaimedJob(f,p):k(f.job_id,p.machineId,"cancelled")).catch(()=>{});break}const m=f.session_id;l.has(m)&&e.warn(`claimed job=${f.job_id} for already active session=${m}; running anyway to avoid leaving it stuck`),r.add(f.job_id),l.add(m);const _=new AbortController,P=(t.runJob??pe)(f,p,e,_).catch(d=>{e.warn(`job ${f.job_id} failed outside handler: ${d instanceof Error?d.message:String(d)}`)}).finally(()=>{r.delete(f.job_id),l.delete(m),u.delete(f.job_id)});u.set(f.job_id,{controller:_,promise:P})}}catch(p){n||e.warn(`job worker failed: ${p instanceof Error?p.message:String(p)}`)}},h=()=>{if(n||a)return;const s=i();a=s,s.finally(()=>{a===s&&(a=null)})};h();const S=setInterval(()=>{h()},t.claimIntervalMs??ee);return{timer:S,stop:()=>o||(o=(async()=>{if(n)return;n=!0,clearInterval(S);for(const p of u.values())p.controller.abort();await a?.catch(()=>{});for(const p of u.values())p.controller.abort();const s=[...u.values()].map(p=>p.promise);s.length!==0&&await Promise.race([Promise.allSettled(s).then(()=>{}),j(re)])})(),o)}}function le(){const e=process.env.ACA_MAX_CONCURRENT_JOBS||process.env.ACA_MAX_CONCURRENT_PROJECT_JOBS||"",t=Number.parseInt(e,10);return!e.trim()||!Number.isFinite(t)||t<0?ie:t===0?0:Math.max(1,Math.min(t,8))}function U(e,t){return t===0||e<t}function ue(){const e=Number.parseInt(process.env.ACA_ACP_EVENT_BATCH_INTERVAL_MS||"",10);return Number.isFinite(e)?Math.max(40,Math.min(e,2e3)):ne}async function pe(e,t,n,a){const o=e.job_id,r=e.session_id,l=e.workspace_id,u=e.project_id??null,i=e.input??{},h=String(i.control?.type||"").toLowerCase();if(!h&&!i.message?.trim()&&(i.attachments??[]).length===0){await k(o,t.machineId,"job input missing message");return}const S=t.projects.find(d=>d.projectId===u),s=se(S?.rootPath||e.project_root_path||"");if(!s){await k(o,t.machineId,"job project root is unknown");return}ce(e)&&E.mkdirSync(s,{recursive:!0}),n.info(`claimed job=${o} session=${r} project=${S?.name??u??"unknown"}`);const p=setInterval(()=>{y("POST",`/api/client/jobs/${encodeURIComponent(o)}/heartbeat`,{machineId:t.machineId}).catch(()=>{}),je(o,a).catch(()=>{})},te);let A=0;const f=ye(o,t.machineId),m=_e(o,t.machineId),_=new Set;let P=null;try{await m.sendNow({phase:"initializing",label:"准备工作区",detail:e.worktree_id?"worktree":"project root"}).catch(()=>{});const d=G({projectId:u,sessionId:r,projectRoot:s,worktree:e});P=d,await Re(o,t.machineId,d);const I=fe(i.acpRun);if(h==="compact"){if(!e.acp_session_id)throw new Error("Current session does not have an ACP context to compact");const c=await W({agentType:C(I.agentType,"codex"),cliType:C(I.cliType,"builtin"),acpSessionId:e.acp_session_id,cwd:d.cwd,model:i.model,mode:i.mode,configOptionValues:i.configOptionValues,timeoutMs:i.timeoutMs,allowRollover:i.control?.allowRollover===!0,signal:a.signal,onStatus:b=>{m.report({phase:b.phase,label:b.label,detail:b.detail,updateType:b.updateType,raw:b})}});await m.flush(),await y("POST",`/api/client/jobs/${encodeURIComponent(o)}/complete`,{machineId:t.machineId,acpSessionId:c.acpSessionId,suppressTurn:!0,result:{ok:!0,control:{type:"compact",allowRollover:i.control?.allowRollover===!0},acpSessionId:c.acpSessionId,durationMs:c.durationMs,usage:c.contextUsage,maintenance:c.maintenance,worktree:v(d)}}),n.info(`completed context compact job=${o}`);return}if(h==="fork"){const c=String(i.control?.sourceAcpSessionId||"").trim();if(!c)throw new Error("Source session does not have a Codex ACP context to fork");await m.sendNow({phase:"forking",label:"正在分叉 Codex 会话",detail:i.control?.sourceSessionId?`源会话 ${i.control.sourceSessionId}`:void 0}).catch(()=>{});const b=await V({agentType:C(I.agentType,"codex"),cliType:C(I.cliType,"builtin"),sourceProviderSessionId:c,cwd:d.cwd,model:i.model,mode:i.mode,configOptionValues:i.configOptionValues,timeoutMs:i.timeoutMs,signal:a.signal,onStatus:g=>{m.report({phase:g.phase,label:g.label,detail:g.detail,updateType:g.updateType,raw:g})}});await m.flush(),await y("POST",`/api/client/jobs/${encodeURIComponent(o)}/complete`,{machineId:t.machineId,acpSessionId:b.acpSessionId,suppressTurn:!0,result:{ok:!0,control:{type:"fork",sourceSessionId:i.control?.sourceSessionId||null},acpSessionId:b.acpSessionId,worktree:v(d)}}),n.info(`completed Codex session fork job=${o}`);return}const T=await Ae({cwd:d.cwd,sessionId:r,jobId:o,attachments:i.attachments??[]});T.length>0&&(n.info(`materialized ${T.length} attachment(s) for job=${o}`),await m.sendNow({phase:"initializing",label:"附件已写入本机",detail:T.map(c=>c.relativePath).join(", "),raw:{attachments:z(T)}}).catch(()=>{}));const $=Se(i,T),F=ge($,T),w=await q({agentType:C(I.agentType,"codex"),cliType:C(I.cliType,"builtin"),acpSessionId:e.acp_session_id??null,requireSessionResume:de(e.session_raw),prompt:$,promptBlocks:F,cwd:d.cwd,model:i.model,mode:i.mode,configOptionValues:i.configOptionValues,canExecuteTools:i.canExecuteTools,timeoutMs:i.timeoutMs,contextWindow:he(I.contextWindow),signal:a.signal,onStatus:c=>{m.report({phase:c.phase,label:c.label,detail:c.detail,updateType:c.updateType,raw:c})},onUpdate:c=>{A+=1;for(const g of X(c.raw))_.add(g);const b={turnId:e.user_turn_id??null,eventType:c.type,label:c.label,text:c.text,status:c.status,toolCallId:c.toolCallId,raw:Te(c.raw,A)};Y(b)&&f.push(b)},onPermissionRequest:c=>{const b=Z(i,c);return b?Promise.resolve(b):xe(o,t.machineId,c,a.signal)},onUserInputRequest:c=>Ee(o,t.machineId,c,a.signal)});await f.flush(),await m.flush();const J=M({cwd:d.cwd,evidencePaths:_}),R=we(w.promptResponse);if(!(be(R)||!!w.content)){await k(o,t.machineId,`${w.agentType} stopped: ${R??"unknown"}`,{acpSessionId:w.acpSessionId,stopReason:R,exitCode:w.exitCode,stderr:$e(w.stderr,4e3),worktree:v(d)});return}await y("POST",`/api/client/jobs/${encodeURIComponent(o)}/complete`,{machineId:t.machineId,acpSessionId:w.acpSessionId,assistantText:w.content,result:{ok:!0,acpSessionId:w.acpSessionId,stopReason:R,durationMs:w.durationMs,acpRun:i.acpRun??null,effectiveConfig:w.effectiveConfig??null,performance:w.performance??null,usage:w.contextUsage??null,updateCount:w.updates.length,statusTimeline:w.statusTimeline,worktree:v(d),attachments:z(T),files:J}}),n.info(`completed job=${o}`)}catch(d){await f.flush(),await m.flush();const I=a.signal.aborted?"cancelled":d instanceof Error?d.message:String(d),T=P?M({cwd:P.cwd,evidencePaths:_}):[];await k(o,t.machineId,me(I),{rawError:I,files:T})}finally{await f.flush(),await m.flush(),clearInterval(p)}}function de(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e.importedProviderSession;return!!(t&&typeof t=="object"&&!Array.isArray(t)&&t.strictResume===!0)}function me(e){return/ACP request timed out/i.test(e)?"ACP 长时间没有完成,请稍后重试,或点击停止后重新发送。":/MimoCode request timed out/i.test(e)?"MimoCode 长时间没有完成,请稍后重试,或点击停止后重新发送。":e.replace(/\bsession\/prompt\b/g,"ACP 请求")}function fe(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function he(e){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:void 0}function C(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function we(e){if(!e||typeof e!="object"||Array.isArray(e))return;const t=e;if(typeof t.stopReason=="string")return t.stopReason;if(typeof t.reason=="string")return t.reason;const n=t.part;if(n&&typeof n=="object"&&!Array.isArray(n)&&typeof n.reason=="string")return n.reason}function be(e){return e?["end_turn","stop","completed","complete"].includes(e):!1}function ye(e,t){let n=[],a=null,o=Promise.resolve();const r=async i=>{i.length!==0&&await y("POST",`/api/client/jobs/${encodeURIComponent(e)}/events/batch`,{machineId:t,events:i})},l=()=>{a&&(clearTimeout(a),a=null);const i=n;return n=[],o=o.then(()=>r(i)).catch(()=>{}),o},u=()=>{a||(a=setTimeout(()=>{l()},ue()),a.unref())};return{push(i){if(Q(n,i),Ie(i)||n.length>=oe){l();return}u()},flush:l}}function Ie(e){return e.eventType==="tool_call"?!0:e.eventType!=="tool_call_update"?!1:["completed","failed","cancelled"].includes(String(e.status||"").toLowerCase())}function _e(e,t){let n=null,a=0,o="",r=null,l=Promise.resolve();const u=s=>JSON.stringify({phase:s.phase??"",label:s.label??"",detail:s.detail??"",updateType:s.updateType??""}),i=async s=>{await y("POST",`/api/client/jobs/${encodeURIComponent(e)}/presence`,{machineId:t,phase:s.phase,label:s.label,detail:s.detail,updateType:s.updateType,raw:s.raw}),a=Date.now(),o=u(s)},h=()=>{if(r&&(clearTimeout(r),r=null),!n)return l;const s=n;return n=null,l=l.then(()=>i(s)).catch(()=>{}),l},S=s=>{r||(r=setTimeout(()=>{h()},s),r.unref())};return{report(s){const p=Date.now(),f=u(s)!==o,m=p-a>=ae;if(!f&&!m)return;n=s;const _=p-a;if(_>=O||a===0){h();return}S(O-_)},sendNow(s){return n=s,h()},flush:h}}function Te(e,t){return e&&typeof e=="object"&&!Array.isArray(e)?{...e,acaSequence:t}:{value:e,acaSequence:t}}function Se(e,t=[]){const n=e?.message?.trim()??"";if(t.length===0)return n;const o=["用户随消息上传了以下附件,aca 已将附件写入本机工作区。需要读取附件时请直接使用下面的 localPath;图片附件也已作为 ACP image block 随本轮请求传入。",...t.map((r,l)=>`${l+1}. ${r.name} (${r.kind}, ${r.mimeType}, ${ke(r.size)})
2
+ localPath: ${r.path}
3
+ workspacePath: ${r.relativePath}`)].join(`
4
4
  `);return n?`${n}
5
5
 
6
- ${i}`:i}function ge(e,t){const n=[{type:"text",text:e}];for(const o of t)o.kind!=="image"||!o.mimeType.startsWith("image/")||n.push({type:"image",data:o.base64,mimeType:o.mimeType,uri:o.path});return n}async function Te(e){if(e.attachments.length===0)return[];const t=S.join(e.cwd,".aca","attachments",B(e.sessionId),B(e.jobId));x.mkdirSync(t,{recursive:!0});const n=[];for(const[o,i]of e.attachments.entries()){const a=i.attachmentId?{mimeType:i.mimeType||"application/octet-stream",bytes:await D(`/api/client/attachments/${encodeURIComponent(i.attachmentId)}`)}:Se(i.dataUrl??""),c=i.mimeType||a.mimeType||"application/octet-stream",u=i.kind==="image"||c.startsWith("image/")?"image":"file",s=Ae(i.name||`attachment-${o+1}`,c),w=S.join(t,`${String(o+1).padStart(2,"0")}-${s}`);x.writeFileSync(w,a.bytes),n.push({name:i.name||s,mimeType:c,size:a.bytes.byteLength,kind:u,path:w,relativePath:S.relative(e.cwd,w),base64:a.bytes.toString("base64"),sha256:W.createHash("sha256").update(a.bytes).digest("hex")})}return n}function Se(e){const t=e.indexOf(",");if(!e.startsWith("data:")||t<0)throw new Error("attachment dataUrl is not a data URL");const n=e.slice(5,t),o=e.slice(t+1),i=n.split(";").filter(Boolean),a=i[0]?.includes("/")?i[0]:"application/octet-stream";if(!i.includes("base64"))throw new Error("attachment dataUrl is not base64 encoded");return{mimeType:a,bytes:Buffer.from(o,"base64")}}function Ae(e,t){const n=S.basename(e).replace(/[<>:"/\\|?*\x00-\x1F]/g,"_").trim(),o=`attachment${Ce(t)}`;return(!n||n==="."||n===".."?o:n).slice(0,180)}function Ce(e){switch(e.toLowerCase()){case"image/png":return".png";case"image/jpeg":return".jpg";case"image/webp":return".webp";case"image/gif":return".gif";case"text/plain":return".txt";case"application/json":return".json";case"text/markdown":case"text/x-markdown":return".md";case"application/pdf":return".pdf";case"application/msword":return".doc";case"application/vnd.openxmlformats-officedocument.wordprocessingml.document":return".docx";case"application/vnd.ms-excel":return".xls";case"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":return".xlsx";case"application/vnd.ms-powerpoint":return".ppt";case"application/vnd.openxmlformats-officedocument.presentationml.presentation":return".pptx";case"application/zip":return".zip";case"application/x-7z-compressed":return".7z";case"application/x-rar-compressed":case"application/vnd.rar":return".rar";case"application/gzip":return".gz";case"application/x-tar":return".tar";default:return""}}function B(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"item"}function z(e){return e.map(t=>({name:t.name,kind:t.kind,mimeType:t.mimeType,size:t.size,path:t.path,relativePath:t.relativePath,sha256:t.sha256}))}function Pe(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB"];let n=e,o=0;for(;n>=1024&&o<t.length-1;)n/=1024,o+=1;return`${n>=10||o===0?n.toFixed(0):n.toFixed(1)} ${t[o]}`}async function ve(e,t,n){!n.usedWorktree||!n.worktreeId||await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/worktree`,{machineId:t,baseCommit:n.baseCommit??null,worktreePath:n.cwd,status:n.status??"active",raw:n.raw??k(n)})}function k(e){return{usedWorktree:e.usedWorktree,worktreeId:e.worktreeId??null,cwd:e.cwd,status:e.status??null,baseCommit:e.baseCommit??null,branchName:e.branchName??null,baseBranch:e.baseBranch??null}}async function Re(e,t,n,o){const a=(await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:n})).item.permission_id;for(;!o.aborted;){await E(M);const c=await b("GET",`/api/client/permissions/${encodeURIComponent(a)}`);if(c.item.status==="resolved"&&c.item.response){const u=c.item.response.outcome;return u.outcome==="selected"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function ke(e,t,n,o){const a=(await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:{kind:"elicitation",...n}})).item.permission_id;for(;!o.aborted;){await E(M);const c=await b("GET",`/api/client/permissions/${encodeURIComponent(a)}`);if(c.item.status==="resolved"&&c.item.response){const u=c.item.response.outcome;return u.outcome==="submitted"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function xe(e,t){if(t.signal.aborted)return;const n=await b("GET",`/api/client/jobs/${encodeURIComponent(e)}`);Number(n.item.cancel_requested??0)===1&&t.abort()}async function P(e,t,n,o){await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/fail`,{machineId:t,error:n,result:o})}function E(e){return new Promise(t=>setTimeout(t,e))}function Ee(e,t){return e.length<=t?e:`${e.slice(0,t)}...`}export{qe as startJobWorkerLoop};
6
+ ${o}`:o}function ge(e,t){const n=[{type:"text",text:e}];for(const a of t)a.kind!=="image"||!a.mimeType.startsWith("image/")||n.push({type:"image",data:a.base64,mimeType:a.mimeType,uri:a.path});return n}async function Ae(e){if(e.attachments.length===0)return[];const t=x.join(e.cwd,".aca","attachments",B(e.sessionId),B(e.jobId));E.mkdirSync(t,{recursive:!0});const n=[];for(const[a,o]of e.attachments.entries()){const r=o.attachmentId?{mimeType:o.mimeType||"application/octet-stream",bytes:await D(`/api/client/attachments/${encodeURIComponent(o.attachmentId)}`)}:Ce(o.dataUrl??""),l=o.mimeType||r.mimeType||"application/octet-stream",u=o.kind==="image"||l.startsWith("image/")?"image":"file",i=Pe(o.name||`attachment-${a+1}`,l),h=x.join(t,`${String(a+1).padStart(2,"0")}-${i}`);E.writeFileSync(h,r.bytes),n.push({name:o.name||i,mimeType:l,size:r.bytes.byteLength,kind:u,path:h,relativePath:x.relative(e.cwd,h),base64:r.bytes.toString("base64"),sha256:L.createHash("sha256").update(r.bytes).digest("hex")})}return n}function Ce(e){const t=e.indexOf(",");if(!e.startsWith("data:")||t<0)throw new Error("attachment dataUrl is not a data URL");const n=e.slice(5,t),a=e.slice(t+1),o=n.split(";").filter(Boolean),r=o[0]?.includes("/")?o[0]:"application/octet-stream";if(!o.includes("base64"))throw new Error("attachment dataUrl is not base64 encoded");return{mimeType:r,bytes:Buffer.from(a,"base64")}}function Pe(e,t){const n=x.basename(e).replace(/[<>:"/\\|?*\x00-\x1F]/g,"_").trim(),a=`attachment${ve(t)}`;return(!n||n==="."||n===".."?a:n).slice(0,180)}function ve(e){switch(e.toLowerCase()){case"image/png":return".png";case"image/jpeg":return".jpg";case"image/webp":return".webp";case"image/gif":return".gif";case"text/plain":return".txt";case"application/json":return".json";case"text/markdown":case"text/x-markdown":return".md";case"application/pdf":return".pdf";case"application/msword":return".doc";case"application/vnd.openxmlformats-officedocument.wordprocessingml.document":return".docx";case"application/vnd.ms-excel":return".xls";case"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":return".xlsx";case"application/vnd.ms-powerpoint":return".ppt";case"application/vnd.openxmlformats-officedocument.presentationml.presentation":return".pptx";case"application/zip":return".zip";case"application/x-7z-compressed":return".7z";case"application/x-rar-compressed":case"application/vnd.rar":return".rar";case"application/gzip":return".gz";case"application/x-tar":return".tar";default:return""}}function B(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"item"}function z(e){return e.map(t=>({name:t.name,kind:t.kind,mimeType:t.mimeType,size:t.size,path:t.path,relativePath:t.relativePath,sha256:t.sha256}))}function ke(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB"];let n=e,a=0;for(;n>=1024&&a<t.length-1;)n/=1024,a+=1;return`${n>=10||a===0?n.toFixed(0):n.toFixed(1)} ${t[a]}`}async function Re(e,t,n){!n.usedWorktree||!n.worktreeId||await y("POST",`/api/client/jobs/${encodeURIComponent(e)}/worktree`,{machineId:t,baseCommit:n.baseCommit??null,worktreePath:n.cwd,status:n.status??"active",raw:n.raw??v(n)})}function v(e){return{usedWorktree:e.usedWorktree,worktreeId:e.worktreeId??null,cwd:e.cwd,status:e.status??null,baseCommit:e.baseCommit??null,branchName:e.branchName??null,baseBranch:e.baseBranch??null}}async function xe(e,t,n,a){const r=(await y("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:n})).item.permission_id;for(;!a.aborted;){await j(N);const l=await y("GET",`/api/client/permissions/${encodeURIComponent(r)}`);if(l.item.status==="resolved"&&l.item.response){const u=l.item.response.outcome;return u.outcome==="selected"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function Ee(e,t,n,a){const r=(await y("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:{kind:"elicitation",...n}})).item.permission_id;for(;!a.aborted;){await j(N);const l=await y("GET",`/api/client/permissions/${encodeURIComponent(r)}`);if(l.item.status==="resolved"&&l.item.response){const u=l.item.response.outcome;return u.outcome==="submitted"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function je(e,t){if(t.signal.aborted)return;const n=await y("GET",`/api/client/jobs/${encodeURIComponent(e)}`);Number(n.item.cancel_requested??0)===1&&t.abort()}async function k(e,t,n,a){await y("POST",`/api/client/jobs/${encodeURIComponent(e)}/fail`,{machineId:t,error:n,result:a})}function j(e){return new Promise(t=>setTimeout(t,e))}function $e(e,t){return e.length<=t?e:`${e.slice(0,t)}...`}export{He as startJobWorkerLoop};
@@ -1,5 +1,5 @@
1
- import{execFileSync as h}from"node:child_process";import{randomUUID as L}from"node:crypto";import l from"node:fs";import k from"node:os";import c from"node:path";import{acaServerRequest as y}from"./aca-server-client.js";import{loadAcaConfig as O,upsertLocalProject as W}from"./aca-config.js";import{startLongPollWorker as B}from"./long-poll-worker.js";const U=25e3,S=300,z=3e4;let b=null;function $t(t){return B({run:async()=>{const e=O();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await y("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${U}`);if(r.item)try{const o=await K(r.item);await y("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:o})}catch(o){const i=o instanceof Error?o.message:String(o);t.warn(`machine filesystem request failed request=${r.item.requestId}: ${i}`),await y("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/fail`,{message:i}).catch(()=>{})}},onError:(e,r)=>t.warn(`machine filesystem worker failed, retry in ${r}ms: ${e instanceof Error?e.message:String(e)}`)})}async function K(t){if(t.operation==="filesystem_roots")return at();if(t.operation==="list_directory")return ct({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return pt(t.payload);if(t.operation==="list_project_directory")return X(t.payload);if(t.operation==="get_project_git_status")return $(t.payload);if(t.operation==="get_project_git_diff")return Y(t.payload);if(t.operation==="get_project_git_log")return Q(t.payload);if(t.operation==="get_project_git_commit")return Z(t.payload);if(t.operation==="get_worktree_status")return P(t.payload);if(t.operation==="commit_worktree")return J(t.payload);if(t.operation==="cleanup_worktree")return V(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function P(t){const e=j(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=m(e);if(!p(r))return{exists:!0,isRepository:!1,dirty:rt(r),changedFiles:null,ahead:0};const o=$({rootPath:r}),i=String(t.baseCommit||"").trim(),s=i&&/^[0-9a-f]{7,64}$/i.test(i)?et(r,i):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function J(t){const e=m(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!p(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");h("git",["-C",e,"add","-A"],{stdio:"pipe",timeout:3e4});try{return h("git",["-C",e,"diff","--cached","--quiet"],{stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...P(t)}}catch(o){if(Number(o.status)!==1)throw o}return h("git",["-C",e,"commit","-m",r],{stdio:"pipe",timeout:6e4}),{committed:!0,commit:f(e,["rev-parse","HEAD"],8*1024).trim(),...P(t)}}function V(t){const e=j(String(t.worktreePath||"")),r=m(String(t.projectRoot||""));if(d(e)===d(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=m(e),i=String(t.branchName||"").trim(),s=p(o)&&p(r);if(s){if(h("git",["-C",r,"worktree","remove","--force",o],{stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&i)try{h("git",["-C",r,"branch","-D",i],{stdio:"pipe",timeout:3e4})}catch(n){const a=String(n.stderr||n);if(!/not found|not exist/i.test(a))throw n}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&i)}}function X(t){const e=m(String(t.rootPath||"")),r=x(String(t.relativePath||"")),o=wt(e,r,!0),i=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),n=l.readdirSync(o,{withFileTypes:!0}).filter(u=>!u.isSymbolicLink()).map(u=>({name:u.name,path:gt(e,c.join(o,u.name)),type:u.isDirectory()?"directory":u.isFile()?"file":"other",hidden:u.name.startsWith("."),extension:u.isFile()?c.extname(u.name).slice(1).toLowerCase():""})).filter(u=>u.type!=="other").sort((u,g)=>u.type!==g.type?u.type==="directory"?-1:1:u.name.localeCompare(g.name,void 0,{numeric:!0,sensitivity:"base"})),a=n.slice(i,i+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:a,total:n.length,nextOffset:i+a.length<n.length?i+a.length:null}}const D=500,_=2*1024*1024,w=2*1024*1024;function $(t){const e=m(String(t.rootPath||""));if(!p(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=f(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],_).split("\0").filter(Boolean).slice(0,D),i=o.map(a=>tt(a)).filter(a=>!!a),s=v(f(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],_));for(const a of i){const u=s.get(a.path);if(u)a.additions=u.additions,a.deletions=u.deletions;else if(a.status==="untracked"){const g=R(e,a.path);a.additions=g.additions,a.deletions=g.deletions}}const n=st(e);return{isRepository:!0,branch:nt(e),files:i,ahead:n.ahead,behind:n.behind,truncated:o.length>=D}}function Y(t){const e=m(String(t.rootPath||"")),r=x(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!p(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=N(e,r),i=ot(e,r),s=i?f(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],w):T(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],w),n=i?v(f(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):R(e,r);return{isRepository:!0,path:r,diff:I(s),additions:n?.additions??0,deletions:n?.deletions??0,truncated:s.length>w}}function Q(t){const e=m(String(t.rootPath||""));if(!p(e))return{isRepository:!1,items:[]};if(!it(e))return{isRepository:!0,items:[]};const r=Math.min(200,Math.max(20,Number(t.limit||100)));return{isRepository:!0,items:f(e,["log",`--max-count=${r}`,"--date=iso-strict","--pretty=format:%H%x1f%h%x1f%an%x1f%ae%x1f%aI%x1f%D%x1f%s%x1f%b%x1e"],_).split("").map(n=>q(n)).filter(n=>!!n),limit:r}}function Z(t){const e=m(String(t.rootPath||"")),r=String(t.commit||"").trim();if(!/^[0-9a-f]{7,64}$/i.test(r))throw new Error("Git 提交标识无效。");if(!p(e))return{isRepository:!1,commit:r,diff:"",additions:0,deletions:0};f(e,["cat-file","-e",`${r}^{commit}`],8*1024);const o=f(e,["show","--no-ext-diff","--no-color","--format=","--stat","--patch","--unified=40",r],w),i=[...v(f(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],_)).values()];return{isRepository:!0,commit:r,diff:I(o),additions:i.reduce((s,n)=>s+(n.additions||0),0),deletions:i.reduce((s,n)=>s+(n.deletions||0),0),changedFiles:i.length,truncated:o.length>w}}function q(t){const e=t.replace(/^\s+|\s+$/g,"");if(!e)return null;const r=e.split(""),o=String(r[0]||"").trim();return o?{hash:o,shortHash:String(r[1]||o.slice(0,8)).trim(),authorName:String(r[2]||"").trim(),authorEmail:String(r[3]||"").trim(),authoredAt:String(r[4]||"").trim(),refs:String(r[5]||"").trim(),subject:String(r[6]||"").trim(),body:r.slice(7).join("").trim()}:null}function tt(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=x(t.slice(3));return o?{path:o,status:e==="?"&&r==="?"?"untracked":e==="U"||r==="U"?"conflicted":e==="D"||r==="D"?"deleted":e==="A"||r==="A"?"added":e==="R"||r==="R"?"renamed":"modified",indexStatus:e,worktreeStatus:r,staged:e!==" "&&e!=="?",additions:null,deletions:null}:null}function v(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=C(r);if(!o||!o.path)continue;const i=x(o.path);i&&e.set(i,{additions:o.additions,deletions:o.deletions})}return e}function R(t,e){const r=N(t,e),i=T(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=C(i);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function C(t){const e=t.indexOf(" "),r=e<0?-1:t.indexOf(" ",e+1);if(e<0||r<0)return null;const o=t.slice(0,e),i=t.slice(e+1,r);return{additions:/^\d+$/.test(o)?Number(o):null,deletions:/^\d+$/.test(i)?Number(i):null,path:t.slice(r+1)}}function p(t){try{return f(t,["rev-parse","--is-inside-work-tree"],8*1024).trim()==="true"}catch(e){if(String(e.code||"")==="ENOENT")throw new Error("设备未安装 Git。");return!1}}function et(t,e){try{const r=f(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function rt(t){try{return l.readdirSync(t).length>0}catch{return!1}}function ot(t,e){try{return f(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function it(t){try{return f(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function nt(t){try{return f(t,["symbolic-ref","--quiet","--short","HEAD"],8*1024).trim()||null}catch{try{return`HEAD (${f(t,["rev-parse","--short","HEAD"],8*1024).trim()})`}catch{return null}}}function st(t){try{const e=f(t,["rev-list","--left-right","--count","HEAD...@{upstream}"],8192).trim().split(/\s+/).map(Number);return{ahead:Number.isFinite(e[0])?e[0]:0,behind:Number.isFinite(e[1])?e[1]:0}}catch{return{ahead:0,behind:0}}}function N(t,e){const r=c.resolve(t,...e.split("/")),o=c.relative(t,r);if(o.startsWith("..")||c.isAbsolute(o))throw new Error("Diff 路径超出项目范围。");return r}function f(t,e,r){return h("git",["-C",t,...e],{encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function T(t,e,r){try{return f(t,e,r)}catch(o){const i=String(o.stdout||"");if(i)return i;if(Number(o.status)===1)return"";throw o}}function I(t){return t.length<=w?t:`${t.slice(0,w)}
1
+ import{execFileSync as h}from"node:child_process";import{randomUUID as L}from"node:crypto";import l from"node:fs";import k from"node:os";import c from"node:path";import{acaServerRequest as y}from"./aca-server-client.js";import{loadAcaConfig as O,upsertLocalProject as W}from"./aca-config.js";import{startLongPollWorker as B}from"./long-poll-worker.js";import{expandWorkerRuntimePath as U}from"./worker-runtime-paths.js";const z=25e3,S=300,K=3e4;let b=null;function Ct(t){return B({run:async()=>{const e=O();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await y("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${z}`);if(r.item)try{const o=await J(r.item);await y("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:o})}catch(o){const n=o instanceof Error?o.message:String(o);t.warn(`machine filesystem request failed request=${r.item.requestId}: ${n}`),await y("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/fail`,{message:n}).catch(()=>{})}},onError:(e,r)=>t.warn(`machine filesystem worker failed, retry in ${r}ms: ${e instanceof Error?e.message:String(e)}`)})}async function J(t){if(t.operation==="filesystem_roots")return ct();if(t.operation==="list_directory")return ut({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return ht(t.payload);if(t.operation==="list_project_directory")return Y(t.payload);if(t.operation==="get_project_git_status")return $(t.payload);if(t.operation==="get_project_git_diff")return Q(t.payload);if(t.operation==="get_project_git_log")return Z(t.payload);if(t.operation==="get_project_git_commit")return q(t.payload);if(t.operation==="get_worktree_status")return P(t.payload);if(t.operation==="commit_worktree")return V(t.payload);if(t.operation==="cleanup_worktree")return X(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function P(t){const e=j(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=m(e);if(!p(r))return{exists:!0,isRepository:!1,dirty:ot(r),changedFiles:null,ahead:0};const o=$({rootPath:r}),n=String(t.baseCommit||"").trim(),s=n&&/^[0-9a-f]{7,64}$/i.test(n)?rt(r,n):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function V(t){const e=m(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!p(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");h("git",["-C",e,"add","-A"],{stdio:"pipe",timeout:3e4});try{return h("git",["-C",e,"diff","--cached","--quiet"],{stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...P(t)}}catch(o){if(Number(o.status)!==1)throw o}return h("git",["-C",e,"commit","-m",r],{stdio:"pipe",timeout:6e4}),{committed:!0,commit:f(e,["rev-parse","HEAD"],8*1024).trim(),...P(t)}}function X(t){const e=j(String(t.worktreePath||"")),r=m(String(t.projectRoot||""));if(d(e)===d(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=m(e),n=String(t.branchName||"").trim(),s=p(o)&&p(r);if(s){if(h("git",["-C",r,"worktree","remove","--force",o],{stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&n)try{h("git",["-C",r,"branch","-D",n],{stdio:"pipe",timeout:3e4})}catch(i){const a=String(i.stderr||i);if(!/not found|not exist/i.test(a))throw i}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&n)}}function Y(t){const e=m(String(t.rootPath||"")),r=_(String(t.relativePath||"")),o=gt(e,r,!0),n=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),i=l.readdirSync(o,{withFileTypes:!0}).filter(u=>!u.isSymbolicLink()).map(u=>({name:u.name,path:yt(e,c.join(o,u.name)),type:u.isDirectory()?"directory":u.isFile()?"file":"other",hidden:u.name.startsWith("."),extension:u.isFile()?c.extname(u.name).slice(1).toLowerCase():""})).filter(u=>u.type!=="other").sort((u,g)=>u.type!==g.type?u.type==="directory"?-1:1:u.name.localeCompare(g.name,void 0,{numeric:!0,sensitivity:"base"})),a=i.slice(n,n+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:a,total:i.length,nextOffset:n+a.length<i.length?n+a.length:null}}const D=500,x=2*1024*1024,w=2*1024*1024;function $(t){const e=m(String(t.rootPath||""));if(!p(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=f(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],x).split("\0").filter(Boolean).slice(0,D),n=o.map(a=>et(a)).filter(a=>!!a),s=v(f(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],x));for(const a of n){const u=s.get(a.path);if(u)a.additions=u.additions,a.deletions=u.deletions;else if(a.status==="untracked"){const g=R(e,a.path);a.additions=g.additions,a.deletions=g.deletions}}const i=at(e);return{isRepository:!0,branch:st(e),files:n,ahead:i.ahead,behind:i.behind,truncated:o.length>=D}}function Q(t){const e=m(String(t.rootPath||"")),r=_(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!p(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=N(e,r),n=nt(e,r),s=n?f(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],w):T(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],w),i=n?v(f(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):R(e,r);return{isRepository:!0,path:r,diff:I(s),additions:i?.additions??0,deletions:i?.deletions??0,truncated:s.length>w}}function Z(t){const e=m(String(t.rootPath||""));if(!p(e))return{isRepository:!1,items:[]};if(!it(e))return{isRepository:!0,items:[]};const r=Math.min(200,Math.max(20,Number(t.limit||100)));return{isRepository:!0,items:f(e,["log",`--max-count=${r}`,"--date=iso-strict","--pretty=format:%H%x1f%h%x1f%an%x1f%ae%x1f%aI%x1f%D%x1f%s%x1f%b%x1e"],x).split("").map(i=>tt(i)).filter(i=>!!i),limit:r}}function q(t){const e=m(String(t.rootPath||"")),r=String(t.commit||"").trim();if(!/^[0-9a-f]{7,64}$/i.test(r))throw new Error("Git 提交标识无效。");if(!p(e))return{isRepository:!1,commit:r,diff:"",additions:0,deletions:0};f(e,["cat-file","-e",`${r}^{commit}`],8*1024);const o=f(e,["show","--no-ext-diff","--no-color","--format=","--stat","--patch","--unified=40",r],w),n=[...v(f(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],x)).values()];return{isRepository:!0,commit:r,diff:I(o),additions:n.reduce((s,i)=>s+(i.additions||0),0),deletions:n.reduce((s,i)=>s+(i.deletions||0),0),changedFiles:n.length,truncated:o.length>w}}function tt(t){const e=t.replace(/^\s+|\s+$/g,"");if(!e)return null;const r=e.split(""),o=String(r[0]||"").trim();return o?{hash:o,shortHash:String(r[1]||o.slice(0,8)).trim(),authorName:String(r[2]||"").trim(),authorEmail:String(r[3]||"").trim(),authoredAt:String(r[4]||"").trim(),refs:String(r[5]||"").trim(),subject:String(r[6]||"").trim(),body:r.slice(7).join("").trim()}:null}function et(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=_(t.slice(3));return o?{path:o,status:e==="?"&&r==="?"?"untracked":e==="U"||r==="U"?"conflicted":e==="D"||r==="D"?"deleted":e==="A"||r==="A"?"added":e==="R"||r==="R"?"renamed":"modified",indexStatus:e,worktreeStatus:r,staged:e!==" "&&e!=="?",additions:null,deletions:null}:null}function v(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=C(r);if(!o||!o.path)continue;const n=_(o.path);n&&e.set(n,{additions:o.additions,deletions:o.deletions})}return e}function R(t,e){const r=N(t,e),n=T(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=C(n);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function C(t){const e=t.indexOf(" "),r=e<0?-1:t.indexOf(" ",e+1);if(e<0||r<0)return null;const o=t.slice(0,e),n=t.slice(e+1,r);return{additions:/^\d+$/.test(o)?Number(o):null,deletions:/^\d+$/.test(n)?Number(n):null,path:t.slice(r+1)}}function p(t){try{return f(t,["rev-parse","--is-inside-work-tree"],8*1024).trim()==="true"}catch(e){if(String(e.code||"")==="ENOENT")throw new Error("设备未安装 Git。");return!1}}function rt(t,e){try{const r=f(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function ot(t){try{return l.readdirSync(t).length>0}catch{return!1}}function nt(t,e){try{return f(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function it(t){try{return f(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function st(t){try{return f(t,["symbolic-ref","--quiet","--short","HEAD"],8*1024).trim()||null}catch{try{return`HEAD (${f(t,["rev-parse","--short","HEAD"],8*1024).trim()})`}catch{return null}}}function at(t){try{const e=f(t,["rev-list","--left-right","--count","HEAD...@{upstream}"],8192).trim().split(/\s+/).map(Number);return{ahead:Number.isFinite(e[0])?e[0]:0,behind:Number.isFinite(e[1])?e[1]:0}}catch{return{ahead:0,behind:0}}}function N(t,e){const r=c.resolve(t,...e.split("/")),o=c.relative(t,r);if(o.startsWith("..")||c.isAbsolute(o))throw new Error("Diff 路径超出项目范围。");return r}function f(t,e,r){return h("git",["-C",t,...e],{encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function T(t,e,r){try{return f(t,e,r)}catch(o){const n=String(o.stdout||"");if(n)return n;if(Number(o.status)===1)return"";throw o}}function I(t){return t.length<=w?t:`${t.slice(0,w)}
2
2
 
3
- [Diff 内容过大,已截断]`}function at(){const t=process.platform,e=A(t);return{platform:t,roots:e}}function ct(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?dt(t.directoryPath,!!t.includeHidden):ft(t.directoryPath,!!t.includeHidden)}function d(t,e=process.platform){const r=e==="win32"?c.win32:c.posix,o=r.normalize(t),i=r.parse(o).root,s=o.length>i.length?o.replace(/[\\/]+$/,""):o;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function ut(){const t=l.realpathSync(k.homedir()),e=[{id:"home",label:"用户目录",path:t,kind:"home",available:!0}];return t!==c.parse(t).root&&e.push({id:"root",label:"文件系统",path:"/",kind:"root",available:!0}),e}function A(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?lt():ut();return b={platform:t,roots:e,expiresAtMs:Date.now()+z},e}function lt(){const t=l.realpathSync.native(k.homedir()),e=new Map;e.set(d(t,"win32"),{id:"home",label:"用户目录",path:t,kind:"home",available:!0});try{const r=["$items = Get-CimInstance Win32_LogicalDisk | ForEach-Object {"," [PSCustomObject]@{ Name = $_.DeviceID; Root = ($_.DeviceID + '\\\\'); DriveType = $_.DriveType; VolumeName = $_.VolumeName }","}","@($items) | ConvertTo-Json -Compress"].join(`
4
- `),o=H(M(r));for(const i of o){const s=String(i.Root||"");if(!s)continue;const n=Number(i.DriveType||0),a=String(i.Name||s.replace(/[\\/]+$/,"")),u=String(i.VolumeName||"").trim();e.set(d(s,"win32"),{id:`drive-${a.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:u?`${u} (${a})`:_t(a,n),path:s,kind:bt(n),available:!0})}}catch{const r=c.win32.parse(t).root;e.set(d(r,"win32"),{id:"drive-system",label:`系统盘 (${r.replace(/\\$/,"")})`,path:r,kind:"fixed",available:!0})}return[...e.values()]}function ft(t,e){const r=E(t),i=l.readdirSync(r,{withFileTypes:!0}).filter(n=>n.isDirectory()&&!n.isSymbolicLink()&&(e||!n.name.startsWith("."))),s=i.slice(0,S).map(n=>({name:n.name,path:c.join(r,n.name),kind:"directory",hidden:n.name.startsWith("."),hasChildren:!0}));return s.sort((n,a)=>n.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"})),F(r,s,i.length>S,"linux")}function dt(t,e){const r=E(t),o=["$items = Get-ChildItem -LiteralPath $env:ACA_MACHINE_FS_PATH -Directory -Force -ErrorAction Stop | ForEach-Object {"," [PSCustomObject]@{ Name = $_.Name; FullName = $_.FullName; Attributes = $_.Attributes.ToString() }","}","@($items) | ConvertTo-Json -Compress"].join(`
5
- `),i=H(M(o,{ACA_MACHINE_FS_PATH:r})),s=i.map(n=>{const a=String(n.Attributes||"");return{name:String(n.Name||""),path:String(n.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(a),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(a)}}).filter(n=>n.name&&n.path&&!n.reparsePoint&&(e||!n.hidden)).slice(0,S).sort((n,a)=>n.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"}));return F(r,s,i.length>S,"win32")}function F(t,e,r,o){const i=o==="win32"?c.win32:c.posix,s=i.parse(t).root,n=d(t,o)===d(s,o)?null:i.dirname(t);return{platform:o,path:t,parentPath:n,breadcrumbs:mt(t,o),readable:G(t,l.constants.R_OK),writable:G(t,l.constants.W_OK),items:e,truncated:r}}function mt(t,e){const r=e==="win32"?c.win32:c.posix,o=r.parse(t),i=t.slice(o.root.length).split(/[\\/]+/).filter(Boolean),s=[{label:o.root.replace(/[\\/]+$/,"")||o.root,path:o.root}];let n=o.root;for(const a of i)n=r.join(n,a),s.push({label:a,path:n});return s}async function pt(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),o=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const i=E(String(t.path||""));l.accessSync(i,l.constants.R_OK|l.constants.W_OK);const n=(await y("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(u=>d(u.root_path)===d(i)),a=n||(await y("POST","/api/projects",{projectId:L(),workspaceId:e,name:r,rootPath:i,source:"aica",projectType:o})).item;return W(ht(a)),{project:a,duplicate:!!n}}function ht(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function E(t){if(!t.trim()||!c.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(yt(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return St(r),r}function m(t){const e=j(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function j(t){if(!t.trim()||!c.isAbsolute(t))throw new Error("项目根目录无效。");return c.resolve(t)}function x(t){const e=t.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");if(!e)return"";if(e.includes("\0")||e.split("/").some(r=>!r||r==="."||r===".."))throw new Error("项目相对路径无效。");return e}function wt(t,e,r){const o=e?c.join(t,...e.split("/")):t,i=l.realpathSync.native(o),s=c.relative(t,i);if(s.startsWith("..")||c.isAbsolute(s))throw new Error("目录超出项目范围。");const n=l.statSync(i);if(r&&!n.isDirectory())throw new Error("请求路径不是目录。");return i}function gt(t,e){return c.relative(t,e).split(c.sep).join("/")}function yt(t){const e=process.platform==="win32"?c.win32:c.posix;if(!A(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function St(t){const e=process.platform==="win32"?c.win32:c.posix;if(!A(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function G(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function M(t,e={}){return h("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",t],{encoding:"utf8",windowsHide:!0,timeout:8e3,maxBuffer:4*1024*1024,env:{...process.env,...e}}).replace(/^\uFEFF/,"").trim()}function H(t){if(!t)return[];const e=JSON.parse(t);return Array.isArray(e)?e.filter(r=>!!(r&&typeof r=="object")):e&&typeof e=="object"?[e]:[]}function bt(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function _t(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{V as cleanupWorktree,J as commitWorktree,d as comparableMachinePath,Z as getProjectGitCommit,Y as getProjectGitDiff,Q as getProjectGitLog,$ as getProjectGitStatus,P as getWorktreeStatus,ct as listMachineDirectory,at as listMachineFilesystemRoots,X as listProjectDirectory,$t as startMachineFilesystemWorkerLoop};
3
+ [Diff 内容过大,已截断]`}function ct(){const t=process.platform,e=A(t);return{platform:t,roots:e}}function ut(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?mt(t.directoryPath,!!t.includeHidden):dt(t.directoryPath,!!t.includeHidden)}function d(t,e=process.platform){const r=e==="win32"?c.win32:c.posix,o=r.normalize(t),n=r.parse(o).root,s=o.length>n.length?o.replace(/[\\/]+$/,""):o;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function lt(){const t=l.realpathSync(k.homedir()),e=[{id:"home",label:"用户目录",path:t,kind:"home",available:!0}];return t!==c.parse(t).root&&e.push({id:"root",label:"文件系统",path:"/",kind:"root",available:!0}),e}function A(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?ft():lt();return b={platform:t,roots:e,expiresAtMs:Date.now()+K},e}function ft(){const t=l.realpathSync.native(k.homedir()),e=new Map;e.set(d(t,"win32"),{id:"home",label:"用户目录",path:t,kind:"home",available:!0});try{const r=["$items = Get-CimInstance Win32_LogicalDisk | ForEach-Object {"," [PSCustomObject]@{ Name = $_.DeviceID; Root = ($_.DeviceID + '\\\\'); DriveType = $_.DriveType; VolumeName = $_.VolumeName }","}","@($items) | ConvertTo-Json -Compress"].join(`
4
+ `),o=H(M(r));for(const n of o){const s=String(n.Root||"");if(!s)continue;const i=Number(n.DriveType||0),a=String(n.Name||s.replace(/[\\/]+$/,"")),u=String(n.VolumeName||"").trim();e.set(d(s,"win32"),{id:`drive-${a.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:u?`${u} (${a})`:_t(a,i),path:s,kind:xt(i),available:!0})}}catch{const r=c.win32.parse(t).root;e.set(d(r,"win32"),{id:"drive-system",label:`系统盘 (${r.replace(/\\$/,"")})`,path:r,kind:"fixed",available:!0})}return[...e.values()]}function dt(t,e){const r=E(t),n=l.readdirSync(r,{withFileTypes:!0}).filter(i=>i.isDirectory()&&!i.isSymbolicLink()&&(e||!i.name.startsWith("."))),s=n.slice(0,S).map(i=>({name:i.name,path:c.join(r,i.name),kind:"directory",hidden:i.name.startsWith("."),hasChildren:!0}));return s.sort((i,a)=>i.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"})),F(r,s,n.length>S,"linux")}function mt(t,e){const r=E(t),o=["$items = Get-ChildItem -LiteralPath $env:ACA_MACHINE_FS_PATH -Directory -Force -ErrorAction Stop | ForEach-Object {"," [PSCustomObject]@{ Name = $_.Name; FullName = $_.FullName; Attributes = $_.Attributes.ToString() }","}","@($items) | ConvertTo-Json -Compress"].join(`
5
+ `),n=H(M(o,{ACA_MACHINE_FS_PATH:r})),s=n.map(i=>{const a=String(i.Attributes||"");return{name:String(i.Name||""),path:String(i.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(a),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(a)}}).filter(i=>i.name&&i.path&&!i.reparsePoint&&(e||!i.hidden)).slice(0,S).sort((i,a)=>i.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"}));return F(r,s,n.length>S,"win32")}function F(t,e,r,o){const n=o==="win32"?c.win32:c.posix,s=n.parse(t).root,i=d(t,o)===d(s,o)?null:n.dirname(t);return{platform:o,path:t,parentPath:i,breadcrumbs:pt(t,o),readable:G(t,l.constants.R_OK),writable:G(t,l.constants.W_OK),items:e,truncated:r}}function pt(t,e){const r=e==="win32"?c.win32:c.posix,o=r.parse(t),n=t.slice(o.root.length).split(/[\\/]+/).filter(Boolean),s=[{label:o.root.replace(/[\\/]+$/,"")||o.root,path:o.root}];let i=o.root;for(const a of n)i=r.join(i,a),s.push({label:a,path:i});return s}async function ht(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),o=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const n=E(String(t.path||""));l.accessSync(n,l.constants.R_OK|l.constants.W_OK);const i=(await y("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(u=>d(u.root_path)===d(n)),a=i||(await y("POST","/api/projects",{projectId:L(),workspaceId:e,name:r,rootPath:n,source:"aica",projectType:o})).item;return W(wt(a)),{project:a,duplicate:!!i}}function wt(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function E(t){if(!t.trim()||!c.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(St(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return bt(r),r}function m(t){const e=j(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function j(t){const e=U(t);if(!e||!c.isAbsolute(e))throw new Error("项目根目录无效。");return c.resolve(e)}function _(t){const e=t.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");if(!e)return"";if(e.includes("\0")||e.split("/").some(r=>!r||r==="."||r===".."))throw new Error("项目相对路径无效。");return e}function gt(t,e,r){const o=e?c.join(t,...e.split("/")):t,n=l.realpathSync.native(o),s=c.relative(t,n);if(s.startsWith("..")||c.isAbsolute(s))throw new Error("目录超出项目范围。");const i=l.statSync(n);if(r&&!i.isDirectory())throw new Error("请求路径不是目录。");return n}function yt(t,e){return c.relative(t,e).split(c.sep).join("/")}function St(t){const e=process.platform==="win32"?c.win32:c.posix;if(!A(process.platform).some(o=>{const n=String(o.path||"");if(!n)return!1;const s=e.relative(n,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function bt(t){const e=process.platform==="win32"?c.win32:c.posix;if(!A(process.platform).some(o=>{const n=String(o.path||"");if(!n)return!1;const s=e.relative(n,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function G(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function M(t,e={}){return h("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",t],{encoding:"utf8",windowsHide:!0,timeout:8e3,maxBuffer:4*1024*1024,env:{...process.env,...e}}).replace(/^\uFEFF/,"").trim()}function H(t){if(!t)return[];const e=JSON.parse(t);return Array.isArray(e)?e.filter(r=>!!(r&&typeof r=="object")):e&&typeof e=="object"?[e]:[]}function xt(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function _t(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{X as cleanupWorktree,V as commitWorktree,d as comparableMachinePath,q as getProjectGitCommit,Q as getProjectGitDiff,Z as getProjectGitLog,$ as getProjectGitStatus,P as getWorktreeStatus,ut as listMachineDirectory,ct as listMachineFilesystemRoots,Y as listProjectDirectory,Ct as startMachineFilesystemWorkerLoop};
@@ -0,0 +1 @@
1
+ import m from"node:fs";import{acaServerRequest as l}from"./aca-server-client.js";import{comparableLocalProjectPath as f,loadAcaConfig as h,restoreLocalProjects as u}from"./aca-config.js";import{sendHeartbeat as g}from"./heartbeat.js";async function y(){const a=h();if(a.projects.length>0)return{restored:0,unavailable:0,skipped:"existing_projects"};const d=await l("GET",`/api/users/me/project-recovery?machineName=${encodeURIComponent(a.machineName)}`),e=[],i=new Set;let r=0;for(const t of d.items??[]){const c=String(t.root_path||"").trim(),o=String(t.project_id||"").trim(),s=String(t.workspace_id||"").trim();if(!(!c||!o||!s))try{const n=m.realpathSync.native(c);if(!m.statSync(n).isDirectory())throw new Error("not_directory");const p=f(n);if(i.has(p))continue;i.add(p),e.push({projectId:o,workspaceId:s,name:String(t.name||o),rootPath:n})}catch{r+=1}}return e.length===0?{restored:0,unavailable:r,skipped:"no_candidates"}:(u(e),await g(void 0,{includeProviderDetails:!1}),{restored:e.length,unavailable:r,skipped:null})}export{y as restoreProjectsAfterLogin};
@@ -1 +1 @@
1
- import i from"node:fs";import c from"node:os";import o from"node:path";import{getAcaConfigPath as t,getAcaHome as a,getCredentialsPath as m}from"./paths.js";function l(e){const n=e.aicaHome||e.acaHome;n&&(process.env.AICA_HOME=o.resolve(n));const s=e.aicaConfig||e.acaConfig;s&&(process.env.AICA_CONFIG=o.resolve(s)),f()}function f(){const e=o.resolve(process.env.AICA_LEGACY_HOME||o.join(c.homedir(),".aca")),n=o.resolve(a()),s=o.resolve(o.join(c.homedir(),".aica"));e===n||n!==s||(!process.env.AICA_CONFIG&&!process.env.ACA_CONFIG&&r(o.join(e,"config.json"),t()),!process.env.AICA_CREDENTIALS&&!process.env.ACA_CREDENTIALS&&r(o.join(e,"credentials.json"),m()))}function r(e,n){i.existsSync(n)||!i.existsSync(e)||(i.mkdirSync(o.dirname(n),{recursive:!0}),i.copyFileSync(e,n,i.constants.COPYFILE_EXCL))}export{l as applyRuntimePathOptions};
1
+ import i from"node:fs";import c from"node:os";import n from"node:path";import{getAcaConfigPath as y,getAcaHome as A,getCredentialsPath as v}from"./paths.js";function p(e){const r=e.aicaHome||e.acaHome;r&&(process.env.AICA_HOME=n.resolve(r));const o=e.aicaConfig||e.acaConfig;o&&(process.env.AICA_CONFIG=n.resolve(o)),C()}function C(){const e=n.resolve(process.env.AICA_LEGACY_HOME||n.join(c.homedir(),".aca")),r=n.resolve(A()),o=n.resolve(n.join(c.homedir(),".aica"));e===r||r!==o||(!process.env.AICA_CONFIG&&!process.env.ACA_CONFIG&&s(n.join(e,"config.json"),y()),!process.env.AICA_CREDENTIALS&&!process.env.ACA_CREDENTIALS&&s(n.join(e,"credentials.json"),v()),a(n.join(e,"chats"),n.join(r,"chats")),a(n.join(e,"worktrees"),n.join(r,"worktrees")))}function s(e,r){i.existsSync(r)||!i.existsSync(e)||(i.mkdirSync(n.dirname(r),{recursive:!0}),m(e,r))}function a(e,r){if(!(!i.existsSync(e)||!i.statSync(e).isDirectory())){i.mkdirSync(r,{recursive:!0});for(const o of i.readdirSync(e)){const f=n.join(e,o),t=n.join(r,o);i.existsSync(t)||m(f,t)}try{i.readdirSync(e).length===0&&i.rmdirSync(e)}catch{}}}function m(e,r){try{i.renameSync(e,r)}catch(o){if(o.code!=="EXDEV")throw o;i.cpSync(e,r,{recursive:!0,errorOnExist:!0}),i.rmSync(e,{recursive:!0,force:!0})}}export{p as applyRuntimePathOptions};
@@ -0,0 +1 @@
1
+ import e from"node:os";import i from"node:path";import{getAcaHome as a}from"./paths.js";const o="~/.aica/chats";function h(r){const t=r.trim();return t?t==="~"?e.homedir():t==="~/.aica"||t==="~/.aca"?a():t.startsWith("~/.aica/")?i.join(a(),t.slice(8)):t.startsWith("~/.aca/")?i.join(a(),t.slice(7)):t.startsWith("~/")||t.startsWith("~\\")?i.join(e.homedir(),t.slice(2)):t:""}function u(r){return`${o}/${r}`}export{o as WORKER_CHAT_ROOT_TEMPLATE,h as expandWorkerRuntimePath,u as workerChatRootPath};
@@ -1 +1 @@
1
- import{execFileSync as m}from"node:child_process";import w from"node:crypto";import a from"node:fs";import s from"node:path";import{getAcaHome as f}from"./paths.js";function S(e){const t=e.worktree.worktree_id;if(!t||e.worktree.worktree_status==="disabled")return{cwd:e.projectRoot,usedWorktree:!1};const c=e.worktree.worktree_path?s.resolve(e.worktree.worktree_path):null;if(e.worktree.worktree_status==="active"&&c&&a.existsSync(c))return{cwd:c,usedWorktree:!0,worktreeId:t,status:"active",baseCommit:e.worktree.worktree_base_commit??null,branchName:e.worktree.worktree_branch_name??null,baseBranch:e.worktree.worktree_base_branch??null};const r=s.resolve(e.projectRoot),l=k(e.projectId??"project"),d=k(e.sessionId),o=s.join(f(),"worktrees",l,d),i=e.worktree.worktree_base_branch||"HEAD",n=e.worktree.worktree_branch_name||`aca/session-${d}`,u=b(r);return a.mkdirSync(s.dirname(o),{recursive:!0}),a.existsSync(o)?{cwd:o,usedWorktree:!0,worktreeId:t,status:"active",baseCommit:u,branchName:n,baseBranch:i,raw:{source:"aca-client",reusedExistingPath:!0,projectRoot:r}}:u?(m("git",["worktree","add","-B",n,o,i],{cwd:r,stdio:"pipe"}),{cwd:o,usedWorktree:!0,worktreeId:t,status:"active",baseCommit:u,branchName:n,baseBranch:i,raw:{source:"aca-client",mode:"git-worktree",projectRoot:r}}):(a.mkdirSync(o,{recursive:!0}),h(r,o),{cwd:o,usedWorktree:!0,worktreeId:t,status:"fallback-directory",baseCommit:null,branchName:n,baseBranch:i,raw:{source:"aca-client",mode:"fallback-directory",projectRoot:r,fallbackReason:"git repository has no commits"}})}function b(e){try{return m("git",["rev-parse","HEAD"],{cwd:e,encoding:"utf8",stdio:"pipe"}).trim()||null}catch{return null}}function h(e,t){a.cpSync(e,t,{recursive:!0,filter:c=>{const r=s.relative(e,c);if(!r)return!0;const l=r.split(s.sep)[0];return![".git","node_modules","dist",".aca",".aica"].includes(l)}})}function k(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,80)||w.randomUUID()}export{S as prepareLocalWorktree};
1
+ import{execFileSync as d}from"node:child_process";import w from"node:crypto";import c from"node:fs";import a from"node:path";import{getAcaHome as f}from"./paths.js";import{expandWorkerRuntimePath as h}from"./worker-runtime-paths.js";function x(e){const t=e.worktree.worktree_id;if(!t||e.worktree.worktree_status==="disabled")return{cwd:e.projectRoot,usedWorktree:!1};const s=e.worktree.worktree_path?a.resolve(h(e.worktree.worktree_path)):null;if(e.worktree.worktree_status==="active"&&s&&c.existsSync(s))return{cwd:s,usedWorktree:!0,worktreeId:t,status:"active",baseCommit:e.worktree.worktree_base_commit??null,branchName:e.worktree.worktree_branch_name??null,baseBranch:e.worktree.worktree_base_branch??null};const r=a.resolve(e.projectRoot),l=k(e.projectId??"project"),u=k(e.sessionId),o=a.join(f(),"worktrees",l,u),i=e.worktree.worktree_base_branch||"HEAD",n=e.worktree.worktree_branch_name||`aca/session-${u}`,m=b(r);return c.mkdirSync(a.dirname(o),{recursive:!0}),c.existsSync(o)?{cwd:o,usedWorktree:!0,worktreeId:t,status:"active",baseCommit:m,branchName:n,baseBranch:i,raw:{source:"aca-client",reusedExistingPath:!0,projectRoot:r}}:m?(d("git",["worktree","add","-B",n,o,i],{cwd:r,stdio:"pipe"}),{cwd:o,usedWorktree:!0,worktreeId:t,status:"active",baseCommit:m,branchName:n,baseBranch:i,raw:{source:"aca-client",mode:"git-worktree",projectRoot:r}}):(c.mkdirSync(o,{recursive:!0}),p(r,o),{cwd:o,usedWorktree:!0,worktreeId:t,status:"fallback-directory",baseCommit:null,branchName:n,baseBranch:i,raw:{source:"aca-client",mode:"fallback-directory",projectRoot:r,fallbackReason:"git repository has no commits"}})}function b(e){try{return d("git",["rev-parse","HEAD"],{cwd:e,encoding:"utf8",stdio:"pipe"}).trim()||null}catch{return null}}function p(e,t){c.cpSync(e,t,{recursive:!0,filter:s=>{const r=a.relative(e,s);if(!r)return!0;const l=r.split(a.sep)[0];return![".git","node_modules","dist",".aca",".aica"].includes(l)}})}function k(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,80)||w.randomUUID()}export{x as prepareLocalWorktree};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{Command as a}from"commander";import m from"node:path";import{createStartCommand as n}from"./commands/start.js";import{createDaemonCommand as t}from"./commands/daemon.js";import{createWorkerAuthCommand as s}from"./commands/worker-auth.js";import{createWorkerCodexCommand as c}from"./commands/worker-codex.js";import{createWorkerProjectCommand as i}from"./commands/worker-project.js";import{DEFAULT_ACA_SERVER_URL as d}from"./core/aca-config.js";process.env.ACA_DEFAULT_SERVER_URL||=d;async function p(r=process.argv){const o=new a;o.name("aica").description("AICA remote Agent worker").version("0.1.15").enablePositionalOptions(),o.addCommand(n()),o.addCommand(t()),o.addCommand(s()),o.addCommand(i()),o.addCommand(c()),await o.parseAsync(r)}const C=process.argv[1]||"",e=m.basename(C).replace(/\.(?:js|ts|cjs|mjs)$/i,"");(e==="worker-cli"||e==="aica"||e==="aca")&&p().catch(r=>{const o=r instanceof Error?r.message:String(r);console.error(o),process.exitCode=1});export{p as runWorkerCli};
2
+ import{Command as a}from"commander";import m from"node:path";import{createStartCommand as n}from"./commands/start.js";import{createDaemonCommand as t}from"./commands/daemon.js";import{createWorkerAuthCommand as s}from"./commands/worker-auth.js";import{createWorkerCodexCommand as c}from"./commands/worker-codex.js";import{createWorkerProjectCommand as i}from"./commands/worker-project.js";import{DEFAULT_ACA_SERVER_URL as d}from"./core/aca-config.js";process.env.ACA_DEFAULT_SERVER_URL||=d;async function p(r=process.argv){const o=new a;o.name("aica").description("AICA remote Agent worker").version("0.1.17").enablePositionalOptions(),o.addCommand(n()),o.addCommand(t()),o.addCommand(s()),o.addCommand(i()),o.addCommand(c()),await o.parseAsync(r)}const C=process.argv[1]||"",e=m.basename(C).replace(/\.(?:js|ts|cjs|mjs)$/i,"");(e==="worker-cli"||e==="aica"||e==="aca")&&p().catch(r=>{const o=r instanceof Error?r.message:String(r);console.error(o),process.exitCode=1});export{p as runWorkerCli};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",