@yuandc/aica 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{STANDARD_AGENT_EVENT_TYPES as g,createAgentMessageChunk as h,createAgentProgressChunk as _,createAgentThoughtChunk as y,createToolCall as A,createToolCallUpdate as k,firstString as o,normalizeToolKind as m,normalizeToolStatus as b}from"../standard-events.js";function l(n){if(!n||typeof n!="object"||Array.isArray(n))return null;const t=n,e=t.update;return!e||typeof e!="object"||Array.isArray(e)?null:{sessionId:typeof t.sessionId=="string"?t.sessionId:void 0,update:e}}function w(n){const t=l(n);if(!t)return null;const e=String(t.update.sessionUpdate||"");return e==="agent_message_chunk"?h({text:r(t.update.content),method:"session/update",params:n}):e==="agent_progress_chunk"?_({text:r(t.update.content),method:"session/update",params:n}):e==="agent_thought_chunk"?y({text:r(t.update.content),method:"session/update",params:n}):e==="tool_call"||e==="tool_call_update"?x(e,t.update,n):g.has(e)?{type:e,label:T(e),...r(t.update.content)?{text:r(t.update.content)}:{},raw:{method:"session/update",params:n,update:t.update},atMs:Date.now()}:null}function C(n){const t=l(n);if(!t)return null;const e=String(t.update.sessionUpdate||"");return e==="agent_message_chunk"?{phase:"thinking",label:"回复中",detail:i(r(t.update.content)),updateType:e}:e==="agent_progress_chunk"?{phase:"thinking",label:"处理中",detail:i(r(t.update.content)),updateType:e}:e==="agent_thought_chunk"?{phase:"thinking",label:"思考中",detail:i(r(t.update.content)),updateType:e}:e==="tool_call"||e==="tool_call_update"?{phase:"exploring",label:"执行工具",detail:o(t.update.title,t.update.kind),updateType:e}:e==="plan"||e==="plan_update"?{phase:"thinking",label:"规划中",updateType:e}:e==="aca_context_maintenance"?{phase:"thinking",label:o(t.update.label)||"正在整理会话上下文",detail:o(t.update.detail),updateType:e}:null}function r(n){if(typeof n=="string")return n;if(!n||typeof n!="object"||Array.isArray(n))return"";const t=n;return typeof t.text=="string"?t.text:""}function x(n,t,e){const u=o(t.toolCallId,t.id)||`acp.${Date.now()}`,c=m(o(t.kind,t.title)),p=b(o(t.status)),d=t.rawInput??t.input,f=t.rawOutput??t.output,s={method:"session/update",params:e,toolCallId:u,kind:c,title:o(t.title,t.kind),status:p,rawInput:d,rawOutput:f,content:t.content,locations:Array.isArray(t.locations)?t.locations.filter(a=>!!(a&&typeof a=="object"&&!Array.isArray(a))):void 0,meta:t._meta&&typeof t._meta=="object"&&!Array.isArray(t._meta)?t._meta:void 0};return n==="tool_call"?A(s):k(s)}function T(n){return n.replace(/_/g," ")}function i(n){const t=n.replace(/\s+/g," ").trim();if(t)return t.length>120?`${t.slice(0,117)}...`:t}export{l as acpSessionUpdateFromParams,w as eventFromAcpSessionUpdate,C as statusFromAcpSessionUpdate,r as textFromAcpContent};
1
+ import{createPlanEvent as h,normalizePlanSessionUpdate as g}from"../plan-events.js";import{STANDARD_AGENT_EVENT_TYPES as _,createAgentMessageChunk as y,createAgentProgressChunk as A,createAgentThoughtChunk as m,createToolCall as k,createToolCallUpdate as b,firstString as r,normalizeToolKind as x,normalizeToolStatus as T}from"../standard-events.js";function u(n){if(!n||typeof n!="object"||Array.isArray(n))return null;const t=n,e=t.update;return!e||typeof e!="object"||Array.isArray(e)?null:{sessionId:typeof t.sessionId=="string"?t.sessionId:void 0,update:e}}function I(n){const t=u(n);if(!t)return null;const e=String(t.update.sessionUpdate||"");if(e==="agent_message_chunk")return y({text:o(t.update.content),method:"session/update",params:n});if(e==="agent_progress_chunk")return A({text:o(t.update.content),method:"session/update",params:n});if(e==="agent_thought_chunk")return m({text:o(t.update.content),method:"session/update",params:n});if(e==="tool_call"||e==="tool_call_update")return S(e,t.update,n);if(e==="plan"||e==="plan_update"||e==="plan_removed"){const a=g(t.update);return a?h({update:a,method:"session/update",params:n}):null}return _.has(e)?{type:e,label:U(e),...o(t.update.content)?{text:o(t.update.content)}:{},raw:{method:"session/update",params:n,update:t.update},atMs:Date.now()}:null}function E(n){const t=u(n);if(!t)return null;const e=String(t.update.sessionUpdate||"");return e==="agent_message_chunk"?{phase:"thinking",label:"回复中",detail:l(o(t.update.content)),updateType:e}:e==="agent_progress_chunk"?{phase:"thinking",label:"处理中",detail:l(o(t.update.content)),updateType:e}:e==="agent_thought_chunk"?{phase:"thinking",label:"思考中",detail:l(o(t.update.content)),updateType:e}:e==="tool_call"||e==="tool_call_update"?{phase:"exploring",label:"执行工具",detail:r(t.update.title,t.update.kind),updateType:e}:e==="plan"||e==="plan_update"?{phase:"thinking",label:"规划中",updateType:e}:e==="aca_context_maintenance"?{phase:"thinking",label:r(t.update.label)||"正在整理会话上下文",detail:r(t.update.detail),updateType:e}:null}function o(n){if(typeof n=="string")return n;if(!n||typeof n!="object"||Array.isArray(n))return"";const t=n;return typeof t.text=="string"?t.text:""}function S(n,t,e){const a=r(t.toolCallId,t.id)||`acp.${Date.now()}`,c=x(r(t.kind,t.title)),p=T(r(t.status)),d=t.rawInput??t.input,f=t.rawOutput??t.output,s={method:"session/update",params:e,toolCallId:a,kind:c,title:r(t.title,t.kind),status:p,rawInput:d,rawOutput:f,content:t.content,locations:Array.isArray(t.locations)?t.locations.filter(i=>!!(i&&typeof i=="object"&&!Array.isArray(i))):void 0,meta:t._meta&&typeof t._meta=="object"&&!Array.isArray(t._meta)?t._meta:void 0};return n==="tool_call"?k(s):b(s)}function U(n){return n.replace(/_/g," ")}function l(n){const t=n.replace(/\s+/g," ").trim();if(t)return t.length>120?`${t.slice(0,117)}...`:t}export{u as acpSessionUpdateFromParams,I as eventFromAcpSessionUpdate,E as statusFromAcpSessionUpdate,o as textFromAcpContent};
@@ -0,0 +1 @@
1
+ function x(n){const e=String(n.sessionUpdate||"");if(e==="plan_removed")return{sessionUpdate:"plan_removed",planId:c(n)};if(e!=="plan"&&e!=="plan_update")return null;const t=a(n.plan),r=g(n.entries,n.items,n.steps,n.todos,Array.isArray(n.plan)?n.plan:void 0,t?.entries,t?.items,t?.steps,t?.todos),o=i(n.markdown,l(n.content),t?.markdown,l(t?.content)),s=r?r.map(p).filter(d=>!!d).slice(0,50):u(o||"").slice(0,50);return{sessionUpdate:"plan",planId:c(n),entries:s,explanation:i(n.explanation,t?.explanation),markdown:o}}function w(n){const e=n.update.explanation||n.update.markdown;return{type:n.update.sessionUpdate,label:"plan",...e?{text:e}:{},raw:{method:n.method,params:n.params,update:n.update},atMs:n.atMs??Date.now()}}function f(n){const e=String(n||"pending").replace(/([a-z])([A-Z])/g,"$1_$2").replace(/[-\s]+/g,"_").toLowerCase();return["done","complete","completed","success"].includes(e)?"completed":["inprogress","in_progress","active","running"].includes(e)?"in_progress":["failed","error"].includes(e)?"failed":["cancelled","canceled"].includes(e)?"cancelled":"pending"}function p(n){const e=a(n);if(!e)return null;const t=i(e.content,e.step,e.text,e.title);if(!t)return null;const r=m(e.priority);return y({id:i(e.id,e.entryId,e.taskId),content:t.slice(0,4e3),status:f(e.status??e.state),priority:r})}function u(n){const e=[];for(const t of n.split(/\r?\n/)){const r=/^\s*(?:[-*]|\d+\.)\s+(?:\[([ xX~-])\]\s*)?(.+?)\s*$/.exec(t);if(!r)continue;const o=String(r[1]||"").toLowerCase(),s=String(r[2]||"").trim();s&&e.push({content:s.slice(0,4e3),status:o==="x"?"completed":o==="~"?"in_progress":o==="-"?"cancelled":"pending"})}return e}function c(n){const e=a(n.plan);return i(n.planId,n.plan_id,n.id,e?.id)}function m(n){const e=String(n||"").toLowerCase();return e==="low"||e==="medium"||e==="high"?e:void 0}function l(n){return typeof n=="string"?n.trim()||void 0:i(a(n)?.text)}function g(...n){return n.find(Array.isArray)}function i(...n){for(const e of n)if(typeof e=="string"&&e.trim())return e.trim()}function a(n){return n&&typeof n=="object"&&!Array.isArray(n)?n:null}function y(n){for(const e of Object.keys(n))n[e]===void 0&&delete n[e];return n}export{w as createPlanEvent,x as normalizePlanSessionUpdate,f as normalizePlanStatus};
@@ -1,6 +1,6 @@
1
- import{readFileSync as at}from"node:fs";import{applyPatch as ot,parsePatch as rt,reversePatch as st}from"diff";const S=new Set,A=new Set;function Ht(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":case"item/plan/delta":return[{sessionUpdate:t==="item/plan/delta"?"plan":"plan_update",content:{type:"text",text:Y(e)}}];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=F(t,r);return s?[s]:[t==="item/started"?bt(r):Ut(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:b(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:b(r,`
1
+ import{readFileSync as at}from"node:fs";import{applyPatch as ot,parsePatch as rt,reversePatch as st}from"diff";import{createPlanEvent as ut}from"../../plan-events.js";import{codexPlanUpdateFromNotification as z}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=z(e);return r?[r]:[]}case"item/plan/delta":return[];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=O(t,r);return s?[s]:[t==="item/started"?Ut(r):xt(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:b(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:b(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[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[B(e)];case"account/updated":return[I({account:f(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[W(e)];case"account/updated":return[I({account:f(e)??e})];case"configWarning":{const r=a(e,"summary"),o=a(e,"details");return[y("agent_message_chunk",`Config warning: ${r}${o?`
4
4
 
5
5
  ${o}`:""}
6
6
 
@@ -10,19 +10,18 @@ ${o}`:""}
10
10
 
11
11
  `)];case"thread/compacted":return[y("agent_message_chunk",`*Context compacted to fit the model's context window.*
12
12
 
13
- `)];case"fuzzyFileSearch/sessionUpdated":return[j(e)];case"fuzzyFileSearch/sessionCompleted":return[R(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[]}}function Qt(t,e,n,r={}){switch(t){case"item/agentMessage/delta":{const o=a(e,"delta"),s=a(e,"itemId"),i=s?r.agentMessagePhases?.get(s):"";if(!o||i&&i!=="commentary"&&i!=="final_answer")break;const l=i==="commentary"?"agent_progress_chunk":"agent_message_chunk",d=i==="commentary"?"progress":"message";n.pushStatus("thinking",i==="commentary"?"处理中":"生成回复中",w(o),t),n.pushUpdate({type:l,label:d,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":case"item/plan/delta":{n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate({type:t==="item/plan/delta"?"plan":"plan_update",label:"plan",text:Y(e),raw:{method:t,params:e},atMs:Date.now()});break}case"item/started":case"item/completed":{const o=m(e,"item"),s=a(o,"type"),i=F(t,o);if(!i){const _=v(s);(s==="reasoning"||s==="agentMessage")&&n.pushStatus(z(s),_,ut(o),t);break}const l=lt(t,e,o),d=it(s,i);n.pushStatus(z(s),$(s),void 0,t),n.pushUpdate({type:t==="item/started"?"tool_call":"tool_call_update",label:d,status:c(i,["status"])||(t==="item/started"?"in_progress":"completed"),toolCallId:a(o,"id"),raw:{method:t,params:e,tool:l,update:i},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:b(o,s)}},atMs:Date.now()});break}case"item/commandExecution/terminalInteraction":{const o=a(e,"itemId")||a(e,"id")||a(e,"toolCallId"),i=`
13
+ `)];case"fuzzyFileSearch/sessionUpdated":return[j(e)];case"fuzzyFileSearch/sessionCompleted":return[E(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[]}}function Xt(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",d=u==="commentary"?"progress":"message";n.pushStatus("thinking",u==="commentary"?"处理中":"生成回复中",w(o),t),n.pushUpdate({type:l,label:d,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=z(e);if(!o)break;n.pushStatus("thinking","规划中",void 0,t),n.pushUpdate(ut({update:o,method:t,params:e}));break}case"item/plan/delta":break;case"item/started":case"item/completed":{const o=m(e,"item"),s=a(o,"type"),u=O(t,o);if(!u){const _=v(s);(s==="reasoning"||s==="agentMessage")&&n.pushStatus(F(s),_,lt(o),t);break}const l=ct(t,e,o),d=it(s,u);n.pushStatus(F(s),$(s),void 0,t),n.pushUpdate({type:t==="item/started"?"tool_call":"tool_call_update",label:d,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:b(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:b(o,i)}},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:B(e)});break;case"configWarning":{const o=a(e,"summary"),s=a(e,"details"),i=`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:b(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:W(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:i,raw:{method:t,params:e,update:y("agent_message_chunk",i)},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:y("agent_message_chunk",u)},atMs:Date.now()});break}case"warning":{const o=`Warning: ${a(e,"message")}
20
20
 
21
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")}).
22
22
 
23
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.*
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=j(e);n.pushStatus("exploring",a(o,"title")||"Search",dt(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=R(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",yt(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:f(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:break}}function Zt(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 it(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 z(t){return t==="imageGeneration"?"image_generation":t==="reasoning"||t==="agentMessage"||t==="plan"?"thinking":"exploring"}function ut(t){if(t)for(const e of["command","path","tool","server","query","text"]){const n=a(t,e);if(n)return w(n)}}function lt(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"]),i=r==="commandExecution"?c(n,["command","rawInput","raw_input"]):"",l=X(n),d=c(n,["path","filePath","file_path","relativePath","absolutePath"])||l.path,_=c(n,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),k=h(n,"commandActions")||h(n,"command_actions")||h(n,"actions")||D(n),tt=Lt(r,_,n),et=Bt(r,{command:i,path:d,rawInput:s,item:n}),nt=w(Wt(i,d,s,_));return u({id:o,type:r,method:t,displayName:et,rawInput:s,raw_input:s,command:i,path:d,action:c(n,["action","changeType","operation"])||l.action,commandActions:k,command_actions:k.length>0?k:void 0,aggregatedOutput:_,aggregated_output:_,formatted_output:tt,summary:nt})}function F(t,e){if(!e)return null;switch(a(e,"type")){case"commandExecution":return t==="item/started"?mt(e):wt(e);case"fileChange":return t==="item/started"?Ct(e):It(e);case"mcpToolCall":return t==="item/started"?xt(e):kt(e);case"dynamicToolCall":return t==="item/started"?St(e):At(e);case"webSearch":return t==="item/started"?vt(e):$t(e);case"imageView":return Dt(e);case"imageGeneration":return t==="item/started"?Tt(e):Mt(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 I(t){return{sessionUpdate:"session_info_update",_meta:{codex:t}}}function y(t,e){return{sessionUpdate:t,content:{type:"text",text:e}}}function O(t){return`fuzzyFileSearch.${t}`}function j(t){const e=a(t,"sessionId"),n=O(e),r=!S.has(n);S.add(n);const o=a(t,"query"),s=J(o,""),i=ct(t);return u(r?{sessionUpdate:"tool_call",toolCallId:n,kind:"search",title:s,status:"in_progress",locations:i,rawInput:{query:o}}:{sessionUpdate:"tool_call_update",toolCallId:n,title:s,status:"in_progress",locations:i})}function R(t){const e=a(t,"sessionId"),n=O(e);return S.delete(n),{sessionUpdate:"tool_call_update",toolCallId:n,status:"completed"}}function ct(t){const n=(h(f(t),"files")??[]).map(r=>{const o=f(r);if(!o)return"";const s=a(o,"path"),i=a(o,"root");return s?s.startsWith("/")||!i?s:`${i.replace(/\/+$/,"")}/${s.replace(/^\/+/,"")}`:""}).filter(Boolean).map(r=>({path:r}));return n.length>0?n:void 0}function dt(t){const e=a(t,"query"),r=(h(f(t),"files")??[]).length;if(e&&r)return`${e} · ${r} files`;if(e)return e;if(r)return`${r} files`}function pt(t){return`guardian_assessment:${t}`}function U(t,e){const n=a(t,"reviewId"),r=pt(n),o=e==="started"&&!A.has(n);e==="started"&&A.add(n),e==="completed"&&A.delete(n);const s=m(t,"review")??{},i={sessionUpdate:o?"tool_call":"tool_call_update",toolCallId:r,status:ft(a(s,"status")),content:gt(s,m(t,"action")),...o?{kind:"think",title:"Guardian Review",rawInput:t}:{rawOutput:t}};return u(i)}function ft(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 gt(t,e){const n=[`Status: ${G(a(t,"status"))}`],r=E(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 i=a(t,"rationale").trim();return i&&n.push(`Rationale: ${i}`),[{type:"content",content:{type:"text",text:n.join(`
27
- `)}}]}function G(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 E(t){if(!t)return"";const e=a(t,"type");if(e==="command")return[N(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[N(a(t,"source")),ht(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 N(t){return t==="shell"?"shell":t==="unifiedExec"?"exec":t}function ht(t){return t.map(_t).join(" ")}function _t(t){return t.length===0?"''":/^[A-Za-z0-9_/:=+.,@%-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}function yt(t){const e=m(t,"review"),n=e?G(a(e,"status")):"",r=E(m(t,"action"));return[n,r].filter(Boolean).join(" · ")||void 0}function B(t){const e=m(t,"rateLimits")??{},n=m(e,"primary"),r=m(e,"secondary");return u({sessionUpdate:"session_info_update",_meta:{rateLimits:u({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 mt(t){const e=a(t,"id"),n=a(t,"cwd"),r=a(t,"command"),o=V(t),s=o.length===1?f(o[0]):null;if(s){const i=a(s,"type");if(i==="read"){const l=a(s,"path")||a(s,"name");return u({sessionUpdate:"tool_call",toolCallId:e,status:g(a(t,"status")),kind:"read",title:`Read file '${l}'`,locations:l?[{path:l}]:void 0})}if(i==="search"){const l=a(s,"query"),d=a(s,"path");return u({sessionUpdate:"tool_call",toolCallId:e,status:g(a(t,"status")),kind:"search",title:J(l,d)})}if(i==="listFiles"){const l=a(s,"path");return u({sessionUpdate:"tool_call",toolCallId:e,status:g(a(t,"status")),kind:"read",title:l?`List files in '${l}'`:"List files"})}}return Ot({sessionUpdate:"tool_call",toolCallId:e,status:g(a(t,"status")),kind:"execute",title:Rt(r),rawInput:u({command:r,cwd:n})},e,n)}function wt(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:g(a(t,"status")),rawOutput:u({formatted_output:n,exit_code:r})};return jt(t)&&(o._meta={...n?b(e,n):{},terminal_exit:{exit_code:r,signal:null,terminal_id:e}}),u(o)}function Ct(t){const e=a(t,"id"),n=Q(t);return u({sessionUpdate:"tool_call",toolCallId:e,title:"Editing files",kind:"edit",status:g(a(t,"status")),content:n,locations:Gt(t),rawInput:{changes:D(t)}})}function It(t){return u({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:g(a(t,"status")),content:Q(t)})}function bt(t){const e=c(t,["tool","name","server"]);return u({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:g(a(t,"status")),rawInput:f(t)})}function Ut(t){return u({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:g(a(t,"status")),rawOutput:f(t)})}function xt(t){const e=a(t,"server"),n=a(t,"tool");return u({...L(t,`mcp.${e}.${n}`,W(e,n,t.arguments),q(t.result,t.error)),_meta:{is_mcp_tool_call:!0}})}function kt(t){const e=a(t,"server"),n=a(t,"tool");return u({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:g(a(t,"status")),rawInput:W(e,n,t.arguments),rawOutput:q(t.result,t.error)})}function St(t){return L(t,a(t,"tool"),{arguments:t.arguments},void 0)}function At(t){return u({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:g(a(t,"status"))})}function L(t,e,n,r){return u({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"execute",title:e,status:g(a(t,"status")),rawInput:n,rawOutput:r})}function W(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 vt(t){return u({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"search",title:H(t),status:g(a(t,"status")),rawInput:f(t)})}function $t(t){return u({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),title:H(t),status:g(a(t,"status")),rawInput:f(t)})}function Tt(t){return u({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"other",title:"Image generation",status:"in_progress",rawInput:{id:a(t,"id")}})}function Mt(t){return u({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:Pt(a(t,"status")),content:zt(t),rawOutput:Ft(t)})}function Dt(t){const e=a(t,"path");return u({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 Pt(t){return t==="completed"?"completed":t==="failed"?"failed":"in_progress"}function zt(t){const e=f(t.result),n=c(e,["url","uri","path"]);if(n)return[{type:"content",content:{type:"resource_link",name:n,uri:n}}]}function Ft(t){const e={status:t.status,revisedPrompt:t.revisedPrompt,result:t.result};return"savedPath"in t&&(e.savedPath=t.savedPath??null),e}function Ot(t,e,n){return u({...t,content:[{type:"terminal",terminalId:e}],_meta:{terminal_info:{cwd:n,terminal_id:e}}})}function jt(t){const e=V(t),n=e.length===1?f(e[0]):null;return!n||a(n,"type")==="unknown"}function V(t){return h(t,"commandActions")||h(t,"command_actions")||h(t,"actions")||[]}function g(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 Rt(t){const e=t.replace(/^(?:\/bin\/)?(?:bash|zsh|sh)\s+(?:-[lc]+\s+)?/,"");return e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function b(t,e){return{terminal_output_delta:{data:e,terminal_id:t}}}function J(t,e){return t&&e?`Search for '${t}' in ${e}`:t?`Search for '${t}'`:e?`Search in '${e}'`:"Search"}function H(t){const e=f(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 Gt(t){const e=D(t).map(n=>f(n)).map(n=>a(n,"path")).filter(Boolean).map(n=>({path:n}));return e.length>0?e:void 0}function Q(t){const n=(h(t,"changes")??[]).map(r=>{const o=f(r);if(!o)return null;const s=p(o.path),i=o.kind&&typeof o.kind=="object"&&!Array.isArray(o.kind)?p(o.kind.type):p(o.kind),l=p(o.diff);return i==="add"?u({type:"diff",oldText:null,newText:l,path:s,_meta:{kind:"add"}}):i==="delete"?u({type:"diff",oldText:l,newText:"",path:s,_meta:{kind:"delete"}}):Et(o,s,l,i)}).filter(Boolean);return n.length>0?n:void 0}function Et(t,e,n,r){const o=t.kind&&typeof t.kind=="object"&&!Array.isArray(t.kind)?p(t.kind.move_path):"",s=Nt(n),i=Z(e);if(i!==null){const l=M(i,s);if(l!==!1)return x(o||e,i,l,r||"update");const d=K(s);if(d){const _=M(i,d);if(_!==!1)return x(e,_,i,r||"update")}}if(o){const l=Z(o),d=K(s);if(l!==null&&d){const _=M(l,d);if(_!==!1)return x(o,_,l,r||"update")}}return x(o||e,null,s,r||"update")}function x(t,e,n,r){return u({type:"diff",oldText:e,newText:n,path:t,_meta:{kind:r}})}function Z(t){try{return at(t,"utf8")}catch{return null}}function Nt(t){return t.replace(/\n\nMoved to: .*$/,"")}function K(t){try{const[e]=rt(t);return e?st(e):null}catch{return null}}function M(t,e){try{return ot(t,e)}catch{return!1}}function Bt(t,e){if(t==="commandExecution")return"执行命令";if(t==="fileChange")return e.path?`编辑文件: ${qt(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 Lt(t,e,n){if(e)return e;if(t==="fileChange"){const r=X(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 X(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 D(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:u({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 Wt(...t){return t.find(e=>e.trim())||""}function qt(t){return t.replace(/\\/g,"/").split("/").filter(Boolean).pop()||t}function u(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){const e=a(t,"explanation"),r=(Array.isArray(t?.plan)?t.plan:[]).map(o=>a(o,"text")).filter(Boolean);return[e,...r].filter(Boolean).join(`
28
- `)||void 0}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 f(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{Ht as codexAcpSessionUpdatesFromNotification,Zt as extractAssistantTextFromTurn,Qt 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:y("agent_message_chunk",o)},atMs:Date.now()});break}case"fuzzyFileSearch/sessionUpdated":{const o=j(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=E(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",mt(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:f(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:break}}function Yt(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 it(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 F(t){return t==="imageGeneration"?"image_generation":t==="reasoning"||t==="agentMessage"||t==="plan"?"thinking":"exploring"}function lt(t){if(t)for(const e of["command","path","tool","server","query","text"]){const n=a(t,e);if(n)return w(n)}}function ct(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=Y(n),d=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")||P(n),tt=qt(r,_,n),et=Wt(r,{command:u,path:d,rawInput:s,item:n}),nt=w(Bt(u,d,s,_));return i({id:o,type:r,method:t,displayName:et,rawInput:s,raw_input:s,command:u,path:d,action:c(n,["action","changeType","operation"])||l.action,commandActions:k,command_actions:k.length>0?k:void 0,aggregatedOutput:_,aggregated_output:_,formatted_output:tt,summary:nt})}function O(t,e){if(!e)return null;switch(a(e,"type")){case"commandExecution":return t==="item/started"?wt(e):Ct(e);case"fileChange":return t==="item/started"?It(e):bt(e);case"mcpToolCall":return t==="item/started"?kt(e):St(e);case"dynamicToolCall":return t==="item/started"?At(e):vt(e);case"webSearch":return t==="item/started"?$t(e):Tt(e);case"imageView":return Dt(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 I(t){return{sessionUpdate:"session_info_update",_meta:{codex:t}}}function y(t,e){return{sessionUpdate:t,content:{type:"text",text:e}}}function R(t){return`fuzzyFileSearch.${t}`}function j(t){const e=a(t,"sessionId"),n=R(e),r=!S.has(n);S.add(n);const o=a(t,"query"),s=H(o,""),u=dt(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 E(t){const e=a(t,"sessionId"),n=R(e);return S.delete(n),{sessionUpdate:"tool_call_update",toolCallId:n,status:"completed"}}function dt(t){const n=(g(f(t),"files")??[]).map(r=>{const o=f(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(f(t),"files")??[]).length;if(e&&r)return`${e} · ${r} files`;if(e)return e;if(r)return`${r} files`}function ft(t){return`guardian_assessment:${t}`}function U(t,e){const n=a(t,"reviewId"),r=ft(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:ht(a(s,"status")),content:gt(s,m(t,"action")),...o?{kind:"think",title:"Guardian Review",rawInput:t}:{rawOutput:t}};return i(u)}function ht(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 gt(t,e){const n=[`Status: ${G(a(t,"status"))}`],r=N(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 G(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 N(t){if(!t)return"";const e=a(t,"type");if(e==="command")return[L(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[L(a(t,"source")),_t(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 L(t){return t==="shell"?"shell":t==="unifiedExec"?"exec":t}function _t(t){return t.map(yt).join(" ")}function yt(t){return t.length===0?"''":/^[A-Za-z0-9_/:=+.,@%-]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}function mt(t){const e=m(t,"review"),n=e?G(a(e,"status")):"",r=N(m(t,"action"));return[n,r].filter(Boolean).join(" · ")||void 0}function W(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:D(n,"usedPercent")??null,sevenDay:D(r,"usedPercent")??null,fiveHourResetAt:a(n,"resetsAt")||null,sevenDayResetAt:a(r,"resetsAt")||null,raw:e})}})}function wt(t){const e=a(t,"id"),n=a(t,"cwd"),r=a(t,"command"),o=J(t),s=o.length===1?f(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"),d=a(s,"path");return i({sessionUpdate:"tool_call",toolCallId:e,status:h(a(t,"status")),kind:"search",title:H(l,d)})}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 Rt({sessionUpdate:"tool_call",toolCallId:e,status:h(a(t,"status")),kind:"execute",title:Et(r),rawInput:i({command:r,cwd:n})},e,n)}function Ct(t){const e=a(t,"id"),n=c(t,["aggregatedOutput","aggregated_output","formattedOutput","formatted_output","output","stdout","stderr"]),r=D(t,"exitCode"),o={sessionUpdate:"tool_call_update",toolCallId:e,status:h(a(t,"status")),rawOutput:i({formatted_output:n,exit_code:r})};return jt(t)&&(o._meta={...n?b(e,n):{},terminal_exit:{exit_code:r,signal:null,terminal_id:e}}),i(o)}function It(t){const e=a(t,"id"),n=Z(t);return i({sessionUpdate:"tool_call",toolCallId:e,title:"Editing files",kind:"edit",status:h(a(t,"status")),content:n,locations:Gt(t),rawInput:{changes:P(t)}})}function bt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:h(a(t,"status")),content:Z(t)})}function Ut(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:f(t)})}function xt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:h(a(t,"status")),rawOutput:f(t)})}function kt(t){const e=a(t,"server"),n=a(t,"tool");return i({...q(t,`mcp.${e}.${n}`,B(e,n,t.arguments),V(t.result,t.error)),_meta:{is_mcp_tool_call:!0}})}function St(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:B(e,n,t.arguments),rawOutput:V(t.result,t.error)})}function At(t){return q(t,a(t,"tool"),{arguments:t.arguments},void 0)}function vt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),status:h(a(t,"status"))})}function q(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 B(t,e,n){return{server:t,tool:e,arguments:n}}function V(t,e){if(!(t===null&&e===null)&&!(t===void 0&&e===void 0))return{result:t,error:e}}function $t(t){return i({sessionUpdate:"tool_call",toolCallId:a(t,"id"),kind:"search",title:Q(t),status:h(a(t,"status")),rawInput:f(t)})}function Tt(t){return i({sessionUpdate:"tool_call_update",toolCallId:a(t,"id"),title:Q(t),status:h(a(t,"status")),rawInput:f(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:zt(a(t,"status")),content:Ft(t),rawOutput:Ot(t)})}function Dt(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 zt(t){return t==="completed"?"completed":t==="failed"?"failed":"in_progress"}function Ft(t){const e=f(t.result),n=c(e,["url","uri","path"]);if(n)return[{type:"content",content:{type:"resource_link",name:n,uri:n}}]}function Ot(t){const e={status:t.status,revisedPrompt:t.revisedPrompt,result:t.result};return"savedPath"in t&&(e.savedPath=t.savedPath??null),e}function Rt(t,e,n){return i({...t,content:[{type:"terminal",terminalId:e}],_meta:{terminal_info:{cwd:n,terminal_id:e}}})}function jt(t){const e=J(t),n=e.length===1?f(e[0]):null;return!n||a(n,"type")==="unknown"}function J(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 Et(t){const e=t.replace(/^(?:\/bin\/)?(?:bash|zsh|sh)\s+(?:-[lc]+\s+)?/,"");return e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function b(t,e){return{terminal_output_delta:{data:e,terminal_id:t}}}function H(t,e){return t&&e?`Search for '${t}' in ${e}`:t?`Search for '${t}'`:e?`Search in '${e}'`:"Search"}function Q(t){const e=f(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 Gt(t){const e=P(t).map(n=>f(n)).map(n=>a(n,"path")).filter(Boolean).map(n=>({path:n}));return e.length>0?e:void 0}function Z(t){const n=(g(t,"changes")??[]).map(r=>{const o=f(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"}}):Nt(o,s,l,u)}).filter(Boolean);return n.length>0?n:void 0}function Nt(t,e,n,r){const o=t.kind&&typeof t.kind=="object"&&!Array.isArray(t.kind)?p(t.kind.move_path):"",s=Lt(n),u=K(e);if(u!==null){const l=M(u,s);if(l!==!1)return x(o||e,u,l,r||"update");const d=X(s);if(d){const _=M(u,d);if(_!==!1)return x(e,_,u,r||"update")}}if(o){const l=K(o),d=X(s);if(l!==null&&d){const _=M(l,d);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 K(t){try{return at(t,"utf8")}catch{return null}}function Lt(t){return t.replace(/\n\nMoved to: .*$/,"")}function X(t){try{const[e]=rt(t);return e?st(e):null}catch{return null}}function M(t,e){try{return ot(t,e)}catch{return!1}}function Wt(t,e){if(t==="commandExecution")return"执行命令";if(t==="fileChange")return e.path?`编辑文件: ${Vt(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=Y(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 Y(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 P(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 Bt(...t){return t.find(e=>e.trim())||""}function Vt(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 f(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 D(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,Yt as extractAssistantTextFromTurn,Xt as mapCodexNotification};
@@ -0,0 +1 @@
1
+ import{normalizePlanSessionUpdate as i}from"../../plan-events.js";function p(r){const n=e(r);if(!n)return null;const o=Array.isArray(n.plan)?n.plan:[];return i({sessionUpdate:"plan",planId:t(n.planId,n.turnId),entries:o,explanation:t(n.explanation)})}function t(...r){for(const n of r)if(typeof n=="string"&&n.trim())return n.trim()}function e(r){return r&&typeof r=="object"&&!Array.isArray(r)?r:null}export{p as codexPlanUpdateFromNotification};
@@ -1 +1 @@
1
- import c from"node:fs";import{JsonLineRpcClient as u}from"../../client/json-rpc.js";import{startCodexAppServer as h}from"./codex-process.js";import{extractAssistantTextFromTurn as p,mapCodexNotification as m}from"./events.js";import{isCodexApprovalRequest as f,resolveCodexApprovalRequest as g}from"./permissions.js";const C=1500,w={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 _{id="native-codex";name="Native Codex";capabilities=w;async createSession(e){return new v(e.cwd,e.providerSessionId??null,e.timeoutMs)}}class v{cwd;providerSessionId;defaultTimeoutMs;started;rpc;initialized=!1;content="";promptActive=!1;updates=[];statusTimeline=[];statusCallback=null;updateCallback=null;permissionCallback=null;abortHandler=null;completedTurns=new Map;pendingTurnCompletions=new Map;agentMessagePhases=new Map;constructor(e,s,t=I()){this.cwd=e,this.providerSessionId=s,this.defaultTimeoutMs=t,this.started=h(e),this.rpc=new u(this.started.child,{onNotification:(i,n)=>this.handleNotification(i,n),onRequest:(i,n)=>this.handleReverseRequest(i,n)})}async sendPrompt(e){const s=Date.now(),t=l(e.mode);this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.attachAbortSignal(e.signal),this.emitStatus("initializing","Codex 初始化中","initialize"),await this.initialize();const i=await this.establishThread(e);this.emitStatus("thinking","思考中"),this.content="",this.updates.length=0,this.agentMessagePhases.clear(),this.promptActive=!0;let n,a;try{n=await this.rpc.request("turn/start",{threadId:i,clientUserMessageId:`aca-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:T(e.prompt,e.promptBlocks),cwd:e.cwd,...e.model?{model:e.model}:{},...x(e.configOptionValues)},e.timeoutMs??this.defaultTimeoutMs);const o=String(n?.turn?.id??"");a=o?await this.waitForTurnCompleted(o,e.timeoutMs??this.defaultTimeoutMs):n?.turn}finally{this.promptActive=!1}const d=this.content.trim()||p(a);return this.emitStatus("completed","已完成"),{providerSessionId:i,cliType:"builtin",agentType:"codex",effectiveConfig:t,command:this.started.command,args:this.started.args,cwd:this.cwd,exitCode:this.rpc.exitCode,signal:this.rpc.signal,durationMs:Date.now()-s,stdout:this.rpc.stdout,stderr:this.rpc.stderr,content:d,updates:this.updates,statusTimeline:this.statusTimeline,promptResponse:n}}async cancel(){try{this.providerSessionId&&this.started.child.exitCode===null&&this.started.child.signalCode===null&&await this.rpc.request("turn/interrupt",{threadId:this.providerSessionId},C).catch(()=>{})}finally{await this.close()}}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null;for(const e of this.pendingTurnCompletions.values())clearTimeout(e.timer),e.reject(new Error("Codex app-server session closed"));this.pendingTurnCompletions.clear(),this.abortHandler&&(this.abortHandler=null),await this.closeCodexProcess()}async closeCodexProcess(){this.started.child.exitCode!==null||this.started.child.signalCode!==null||(this.started.child.stdin.end(),!await this.waitForProcessClose(2e3)&&(this.started.child.kill("SIGTERM"),!await this.waitForProcessClose(1e3)&&(this.started.child.kill("SIGKILL"),await this.waitForProcessClose(1e3))))}waitForProcessClose(e){return this.started.child.exitCode!==null||this.started.child.signalCode!==null?Promise.resolve(!0):new Promise(s=>{const t=setTimeout(()=>s(!1),e);t.unref(),this.started.child.once("close",()=>{clearTimeout(t),s(!0)})})}async initialize(){this.initialized||(await this.rpc.request("initialize",{clientInfo:{name:"aca",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}}),this.initialized=!0)}async establishThread(e){const s=l(e.mode);if(this.providerSessionId)try{this.emitStatus("resuming","Codex 会话恢复中","thread/resume");const n=await this.rpc.request("thread/resume",{threadId:this.providerSessionId,cwd:e.cwd,...e.model?{model:e.model}:{},approvalsReviewer:"user",...s},6e4);return this.providerSessionId=String(n?.thread?.id??this.providerSessionId),this.providerSessionId}catch{this.providerSessionId=null}this.emitStatus("acp","Codex 启动中","thread/start");const i=(await this.rpc.request("thread/start",{cwd:e.cwd,...e.model?{model:e.model}:{},approvalsReviewer:"user",...s,ephemeral:!1,threadSource:"aca"},6e4))?.thread?.id;if(!i)throw new Error("Codex app-server thread/start did not return thread id");return this.providerSessionId=i,i}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("ACP prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}handleNotification(e,s){!this.promptActive&&!P(e)||(this.rpc.refreshPendingRequestTimeout("turn/start"),this.updates.push({method:e,params:s}),this.captureAgentMessagePhase(e,s),this.appendFinalAnswerDelta(e,s),e==="turn/completed"&&this.resolveTurnCompleted(s),m(e,s,{pushUpdate:t=>this.updateCallback?.(t),pushStatus:(t,i,n,a)=>this.emitStatus(t,i,n,a)},{agentMessagePhases:this.agentMessagePhases}))}captureAgentMessagePhase(e,s){if(e!=="item/started"&&e!=="item/completed")return;const t=s?.item;t?.type!=="agentMessage"||!t.id||this.agentMessagePhases.set(t.id,t.phase??"")}appendFinalAnswerDelta(e,s){if(e!=="item/agentMessage/delta")return;const t=s;if(!t.itemId||typeof t.delta!="string")return;const i=this.agentMessagePhases.get(t.itemId);(i==="final_answer"||!i)&&(this.content+=t.delta)}waitForTurnCompleted(e,s){const t=this.completedTurns.get(e);return t?Promise.resolve(t):new Promise((i,n)=>{const a=setTimeout(()=>{this.pendingTurnCompletions.delete(e),n(new Error("Codex app-server request timed out while waiting for turn/completed"))},s);a.unref(),this.pendingTurnCompletions.set(e,{resolve:i,reject:n,timer:a})})}resolveTurnCompleted(e){const s=e?.turn,t=s?.id;if(!t)return;this.completedTurns.set(t,s);const i=this.pendingTurnCompletions.get(t);if(i){if(this.pendingTurnCompletions.delete(t),clearTimeout(i.timer),s.status==="failed"){i.reject(new Error(`Codex turn failed: ${JSON.stringify(s.error??{})}`));return}i.resolve(s)}}async handleReverseRequest(e,s){return f(e)?(this.emitStatus("requestPermission","等待授权",y(s),e),g(e,s,this.permissionCallback)):{}}emitStatus(e,s,t,i){const n={phase:e,label:s,...t?{detail:t}:{},...i?{updateType:i}:{},atMs:Date.now()},a=this.statusTimeline[this.statusTimeline.length-1];a&&a.phase===n.phase&&a.label===n.label&&a.detail===n.detail&&a.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}}function T(r,e){return(e?.length?e:[{type:"text",text:r}]).map(t=>t.type==="image"?t.uri&&c.existsSync(t.uri)?{type:"localImage",path:t.uri}:{type:"image",url:`data:${t.mimeType};base64,${t.data}`}:{type:"text",text:t.text,text_elements:[]})}function l(r){const e=String(r||"").trim();return e==="read-only"?{approvalPolicy:"on-request",sandbox:"read-only"}:e==="acceptEdits"||e==="accept-edits"?{approvalPolicy:"on-failure",sandbox:"workspace-write"}:["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?{approvalPolicy:"never",sandbox:"danger-full-access"}:{approvalPolicy:"on-request",sandbox:"workspace-write"}}function x(r){if(!r)return{};const e={},s=r.reasoningEffort??r.model_reasoning_effort;return typeof s=="string"&&s&&(e.effort=s),e}function y(r){if(!r||typeof r!="object"||Array.isArray(r))return;const e=r;for(const s of["command","cwd","reason","grantRoot"]){const t=e[s];if(typeof t=="string"&&t.trim())return S(t)}}function S(r){const e=r.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function P(r){return r.startsWith("thread/")?!0:["account/rateLimits/updated","account/updated","configWarning","warning","model/rerouted","thread/compacted"].includes(r)}function I(){const r=Number.parseInt(process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(r)&&r>=3e4?r:360*60*1e3}export{_ as NativeCodexProvider,w as nativeCodexCapabilities};
1
+ import c from"node:fs";import{JsonLineRpcClient as u}from"../../client/json-rpc.js";import{startCodexAppServer as h}from"./codex-process.js";import{extractAssistantTextFromTurn as p,mapCodexNotification as m}from"./events.js";import{isCodexApprovalRequest as f,resolveCodexApprovalRequest as g}from"./permissions.js";const C=1500,w={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 _{id="native-codex";name="Native Codex";capabilities=w;async createSession(e){return new v(e.cwd,e.providerSessionId??null,e.timeoutMs)}}class v{cwd;providerSessionId;defaultTimeoutMs;started;rpc;initialized=!1;content="";promptActive=!1;updates=[];statusTimeline=[];statusCallback=null;updateCallback=null;permissionCallback=null;abortHandler=null;completedTurns=new Map;pendingTurnCompletions=new Map;agentMessagePhases=new Map;constructor(e,s,t=I()){this.cwd=e,this.providerSessionId=s,this.defaultTimeoutMs=t,this.started=h(e),this.rpc=new u(this.started.child,{onNotification:(r,n)=>this.handleNotification(r,n),onRequest:(r,n)=>this.handleReverseRequest(r,n)})}async sendPrompt(e){const s=Date.now(),t=d(e.mode);this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.attachAbortSignal(e.signal),this.emitStatus("initializing","Codex 初始化中","initialize"),await this.initialize();const r=await this.establishThread(e);this.emitStatus("thinking","思考中"),this.content="",this.updates.length=0,this.agentMessagePhases.clear(),this.promptActive=!0;let n,a;try{n=await this.rpc.request("turn/start",{threadId:r,clientUserMessageId:`aca-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:T(e.prompt,e.promptBlocks),cwd:e.cwd,...e.model?{model:e.model}:{},...x(e.configOptionValues)},e.timeoutMs??this.defaultTimeoutMs);const o=String(n?.turn?.id??"");a=o?await this.waitForTurnCompleted(o,e.timeoutMs??this.defaultTimeoutMs):n?.turn}finally{this.promptActive=!1}const l=this.content.trim()||p(a);return this.emitStatus("completed","已完成"),{providerSessionId:r,cliType:"builtin",agentType:"codex",effectiveConfig:t,command:this.started.command,args:this.started.args,cwd:this.cwd,exitCode:this.rpc.exitCode,signal:this.rpc.signal,durationMs:Date.now()-s,stdout:this.rpc.stdout,stderr:this.rpc.stderr,content:l,updates:this.updates,statusTimeline:this.statusTimeline,promptResponse:n}}async cancel(){try{this.providerSessionId&&this.started.child.exitCode===null&&this.started.child.signalCode===null&&await this.rpc.request("turn/interrupt",{threadId:this.providerSessionId},C).catch(()=>{})}finally{await this.close()}}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null;for(const e of this.pendingTurnCompletions.values())clearTimeout(e.timer),e.reject(new Error("Codex app-server session closed"));this.pendingTurnCompletions.clear(),this.abortHandler&&(this.abortHandler=null),await this.closeCodexProcess()}async closeCodexProcess(){this.started.child.exitCode!==null||this.started.child.signalCode!==null||(this.started.child.stdin.end(),!await this.waitForProcessClose(2e3)&&(this.started.child.kill("SIGTERM"),!await this.waitForProcessClose(1e3)&&(this.started.child.kill("SIGKILL"),await this.waitForProcessClose(1e3))))}waitForProcessClose(e){return this.started.child.exitCode!==null||this.started.child.signalCode!==null?Promise.resolve(!0):new Promise(s=>{const t=setTimeout(()=>s(!1),e);t.unref(),this.started.child.once("close",()=>{clearTimeout(t),s(!0)})})}async initialize(){this.initialized||(await this.rpc.request("initialize",{clientInfo:{name:"aca",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}}),this.initialized=!0)}async establishThread(e){const s=d(e.mode);if(this.providerSessionId)try{this.emitStatus("resuming","Codex 会话恢复中","thread/resume");const n=await this.rpc.request("thread/resume",{threadId:this.providerSessionId,cwd:e.cwd,...e.model?{model:e.model}:{},approvalsReviewer:"user",...s},6e4);return this.providerSessionId=String(n?.thread?.id??this.providerSessionId),this.providerSessionId}catch{this.providerSessionId=null}this.emitStatus("acp","Codex 启动中","thread/start");const r=(await this.rpc.request("thread/start",{cwd:e.cwd,...e.model?{model:e.model}:{},approvalsReviewer:"user",...s,ephemeral:!1,threadSource:"aca"},6e4))?.thread?.id;if(!r)throw new Error("Codex app-server thread/start did not return thread id");return this.providerSessionId=r,r}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("ACP prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}handleNotification(e,s){!this.promptActive&&!P(e)||(this.rpc.refreshPendingRequestTimeout("turn/start"),this.updates.push({method:e,params:s}),this.captureAgentMessagePhase(e,s),this.appendFinalAnswerDelta(e,s),e==="turn/completed"&&this.resolveTurnCompleted(s),m(e,s,{pushUpdate:t=>this.updateCallback?.(t),pushStatus:(t,r,n,a)=>this.emitStatus(t,r,n,a)},{agentMessagePhases:this.agentMessagePhases}))}captureAgentMessagePhase(e,s){if(e!=="item/started"&&e!=="item/completed")return;const t=s?.item;t?.type!=="agentMessage"||!t.id||this.agentMessagePhases.set(t.id,t.phase??"")}appendFinalAnswerDelta(e,s){if(e!=="item/agentMessage/delta")return;const t=s;if(!t.itemId||typeof t.delta!="string")return;const r=this.agentMessagePhases.get(t.itemId);(r==="final_answer"||!r)&&(this.content+=t.delta)}waitForTurnCompleted(e,s){const t=this.completedTurns.get(e);return t?Promise.resolve(t):new Promise((r,n)=>{const a=setTimeout(()=>{this.pendingTurnCompletions.delete(e),n(new Error("Codex app-server request timed out while waiting for turn/completed"))},s);a.unref(),this.pendingTurnCompletions.set(e,{resolve:r,reject:n,timer:a})})}resolveTurnCompleted(e){const s=e?.turn,t=s?.id;if(!t)return;this.completedTurns.set(t,s);const r=this.pendingTurnCompletions.get(t);if(r){if(this.pendingTurnCompletions.delete(t),clearTimeout(r.timer),s.status==="failed"){r.reject(new Error(`Codex turn failed: ${JSON.stringify(s.error??{})}`));return}r.resolve(s)}}async handleReverseRequest(e,s){return f(e)?(this.emitStatus("requestPermission","等待授权",y(s),e),g(e,s,this.permissionCallback)):{}}emitStatus(e,s,t,r){const n={phase:e,label:s,...t?{detail:t}:{},...r?{updateType:r}:{},atMs:Date.now()},a=this.statusTimeline[this.statusTimeline.length-1];a&&a.phase===n.phase&&a.label===n.label&&a.detail===n.detail&&a.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}}function T(i,e){return(e?.length?e:[{type:"text",text:i}]).map(t=>t.type==="image"?t.uri&&c.existsSync(t.uri)?{type:"localImage",path:t.uri}:{type:"image",url:`data:${t.mimeType};base64,${t.data}`}:{type:"text",text:t.text,text_elements:[]})}function d(i){const e=String(i||"").trim();return e==="read-only"?{approvalPolicy:"on-request",sandbox:"read-only"}:e==="acceptEdits"||e==="accept-edits"?{approvalPolicy:"on-failure",sandbox:"workspace-write"}:["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?{approvalPolicy:"never",sandbox:"danger-full-access"}:{approvalPolicy:"on-request",sandbox:"workspace-write"}}function x(i){if(!i)return{};const e={},s=i.reasoning_effort??i.reasoningEffort??i.model_reasoning_effort??i.modelReasoningEffort??i.effort;return typeof s=="string"&&s&&(e.effort=s),e}function y(i){if(!i||typeof i!="object"||Array.isArray(i))return;const e=i;for(const s of["command","cwd","reason","grantRoot"]){const t=e[s];if(typeof t=="string"&&t.trim())return S(t)}}function S(i){const e=i.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function P(i){return i.startsWith("thread/")?!0:["account/rateLimits/updated","account/updated","configWarning","warning","model/rerouted","thread/compacted"].includes(i)}function I(){const i=Number.parseInt(process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(i)&&i>=3e4?i:360*60*1e3}export{_ as NativeCodexProvider,w as nativeCodexCapabilities};
@@ -1,5 +1,5 @@
1
- import{JsonLineRpcClient as P}from"../../client/json-rpc.js";import{startCodexAppServer as R}from"../codex/codex-process.js";import{codexAcpSessionUpdatesFromNotification as q}from"../codex/events.js";import{isCodexApprovalRequest as b,resolveCodexApprovalRequest as _}from"../codex/permissions.js";import{buildCodexContinuityInstructions as M,codexTokenUsageFromNotification as k,decideCodexContextMaintenance as v,readCodexContextMaintenancePolicy as E,rolloutFileSize as F}from"./context-maintenance.js";class U{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;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 i;try{i=JSON.parse(r)}catch{continue}this.handleMessage(i)}}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,c(e.params));return}try{const r=await this.handleRequest(t,c(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:[],i=this.requireRpc();this.currentSessionId=s,this.promptActive=!0,this.currentTurnId=null,this.currentPromptText=N(r),this.currentAssistantText="",this.currentAffectedFiles.clear(),this.agentMessagePhases.clear();let o;try{o=await i.request("turn/start",{threadId:s,clientUserMessageId:`aca-acp-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:j(r),cwd:this.currentCwd,...O(this.config)},S());const u=String(o?.turn?.id??"");this.currentTurnId=u||null;const l=u?await this.waitForTurnCompleted(u,S()):o?.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:z(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=await this.maintainContext("manual",{userRequest:this.previousUserText,assistantResponse:this.previousAssistantText,affectedFiles:[...this.previousAffectedFiles]},{force:!0,allowRollover:e.allowRollover===!0});return{sessionId:this.currentSessionId,maintenance:r,contextUsage:B(r)}}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=R(e),r=new P(s.child,{peerName:"Codex app-server",onNotification:(i,o)=>this.handleCodexNotification(i,o),onRequest:async(i,o)=>this.handleCodexRequest(i,o)});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 q(e,t,{agentMessagePhases:this.agentMessagePhases}))this.captureUpdateEvidence(s),this.notify("session/update",{sessionId:this.currentSessionId,update:s})}}async handleCodexRequest(e,t){if(b(e))return _(e,t,async s=>{const r=await this.requestParent("session/request_permission",{sessionId:this.currentSessionId,request:{...s,params:t,method:e}}),i=c(r),o=c(i.outcome);return o.outcome==="selected"&&typeof o.optionId=="string"?{outcome:{outcome:"selected",optionId:o.optionId}}:{outcome:{outcome:"cancelled"}}});if(D(e)){const s=await this.requestParent("elicitation/create",{sessionId:this.currentSessionId,request:{...c(t),method:e}}),r=c(s),i=c(r.outcome);return i.outcome==="submitted"?{outcome:{outcome:"submitted",value:typeof i.value=="string"?i.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,i)=>{const o=setTimeout(()=>{this.pendingTurnCompletions.delete(e),i(new Error("Codex app-server request timed out while waiting for turn/completed"))},t);o.unref(),this.pendingTurnCompletions.set(e,{resolve:r,reject:i,timer:o})})}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((i,o)=>{const u=setTimeout(()=>{this.pendingParentRequests.delete(r),o(new Error(`ACP client request timed out: ${e}`))},s);u.unref(),this.pendingParentRequests.set(r,{resolve:i,reject:o,timer:u}),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=c(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=k(t)??this.latestTokenUsage),e==="thread/compacted"&&this.pendingCompaction){const s=this.pendingCompaction;this.pendingCompaction=null,clearTimeout(s.timer),s.resolve()}if(e==="item/completed"){const s=h(t,"item");a(s,"type")==="agentMessage"&&a(s,"phase")==="final_answer"&&(this.currentAssistantText=f(s)||this.currentAssistantText)}}captureUpdateEvidence(e){String(e.sessionUpdate||"")==="agent_message_chunk"&&(this.currentAssistantText+=f(e.content)),y(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=$(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=E(),i=this.contextState(),o=v(i,r);if(!o.compact&&!s.force||!this.currentSessionId)return this.maintenanceResult({stage:e,action:"none",reasons:o.reasons,beforeState:i});const u=this.currentSessionId;this.notifyContextStatus("正在整理会话上下文",A(i)),this.maintenanceActive=!0;let l=!1,d="",w=i,m=o,I=!1,g="";try{const p=i.usage?.observedAtMs??0;await this.compactThread(u,r.compactTimeoutMs),await this.waitForTokenUsageAfter(p,2e3)}catch(p){l=!0,d=p instanceof Error?p.message:String(p)}try{if(w=this.contextState(),m=v(w,r,{compactAttempted:!0,compactFailed:l}),m.rollover&&s.allowRollover!==!1){this.notifyContextStatus("正在创建轻量会话",m.reasons.join(", "));try{await this.rotateThread(u,t),I=!0}catch(p){g=p instanceof Error?p.message:String(p),this.notifyContextStatus("轻量会话创建失败",g)}}else l||this.notifyContextStatus("会话上下文已压缩",A(w))}finally{this.maintenanceActive=!1}return this.maintenanceResult({action:I?"rollover":g?"rollover_failed":l?"compact_failed":"compact",stage:e,reasons:m.reasons,beforeState:i,afterState:w,compactError:[d,g].filter(Boolean).join("; "),previousThreadId:u,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 i=setTimeout(()=>{this.pendingCompaction?.timer===i&&(this.pendingCompaction=null),r(new Error("Codex thread compaction timed out"))},t);i.unref(),this.pendingCompaction={resolve:s,reject:r,timer:i},this.requireRpc().request("thread/compact/start",{threadId:e},t).catch(o=>{this.pendingCompaction?.timer===i&&(this.pendingCompaction=null,clearTimeout(i),r(o instanceof Error?o:new Error(String(o))))})})}async rotateThread(e,t){const s=M({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),i=T(r);if(!i)throw new Error("Codex rollover thread/start did not return thread id");this.sessionAliases.set(e,i),this.currentSessionId=i,this.captureThreadMetadata(r)}async waitForTokenUsageAfter(e,t){const s=Date.now()+t;for(;Date.now()<s;){if((this.latestTokenUsage?.observedAtMs??0)>e)return;await W(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:F(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
- `)}}function j(n){return n.map(e=>{const t=c(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(n){return n.map(e=>a(c(e),"text")).filter(Boolean).join(`
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{isCodexApprovalRequest as M,resolveCodexApprovalRequest as b}from"../codex/permissions.js";import{buildCodexContinuityInstructions as k,codexTokenUsageFromNotification as E,decideCodexContextMaintenance as v,readCodexContextMaintenancePolicy as A,rolloutFileSize as F}from"./context-maintenance.js";class U{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;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=N(r),this.currentAssistantText="",this.currentAffectedFiles.clear(),this.agentMessagePhases.clear();let i;try{i=await o.request("turn/start",{threadId:s,clientUserMessageId:`aca-acp-${Date.now()}-${Math.random().toString(16).slice(2)}`,input:j(r),cwd:this.currentCwd,...$(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:D(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}))this.captureUpdateEvidence(s),this.notify("session/update",{sessionId:this.currentSessionId,update:s})}}async handleCodexRequest(e,t){if(M(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(W(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=E(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=k({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 L(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:F(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
+ `)}}function j(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(n){return n.map(e=>a(u(e),"text")).filter(Boolean).join(`
4
4
 
5
- `)}function O(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.reasoningEffort??n.model_reasoning_effort??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=c(n);return c(t[e])}function c(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=c(n);for(const t of["text","message","content","output_text"]){const s=f(e[t]);if(s)return s}return""}function y(n,e){if(Array.isArray(n)){for(const i of n)y(i,e);return}const t=c(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 i of t.locations){const o=a(c(i),"path");o&&e.add(o)}for(const i of[t.content,t.update,t.rawInput,t.rawOutput])i&&i!==n&&y(i,e)}function $(n){if(!Array.isArray(n)||n.length===0)return{userRequest:"",assistantResponse:"",affectedFiles:[]};const e=n.at(-1),t=new Set;y(e,t);let s="",r="";const i=o=>{if(Array.isArray(o)){for(const d of o)i(d);return}if(!o||typeof o!="object")return;const u=c(o),l=a(u,"type").toLowerCase();l==="usermessage"&&(s=f(u)||s),l==="agentmessage"&&(r=f(u)||r);for(const d of["items","content","input"])u[d]&&i(u[d])};return i(e),{userRequest:s,assistantResponse:r,affectedFiles:[...t]}}function B(n){const e=String(n.action||"none"),t=c(n.after),s=c(n.before),r=c(t.usage),i=c(s.usage),o=Object.keys(r).length>0?r:i,u=x(o,"contextWindow");if(e==="rollover")return{usedTokens:0,inputTokens:0,contextWindow:u,ratio:0,observedAtMs:Date.now(),state:"new_thread",maintenanceAction:e};if(Object.keys(o).length===0)return null;const l=x(o,"totalTokens"),d=x(o,"inputTokens");return{usedTokens:l||d,inputTokens:d,contextWindow:u,ratio:u>0?(l||d)/u:0,observedAtMs:x(o,"observedAtMs")||Date.now(),state:e==="compact"?"compacted":"active",maintenanceAction:e}}function z(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 A(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 x(n,e){const t=c(n)[e];return typeof t=="number"&&Number.isFinite(t)?t:0}function a(n,e){const s=c(n)[e];return typeof s=="string"?s:""}function D(n){const e=n.toLowerCase();return e.includes("elicitation")||e.includes("requestuserinput")||e.includes("request_user_input")||e.includes("input/request")}function S(){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 W(n){return new Promise(e=>setTimeout(e,n))}function L(){new U}const G=process.argv[1]||"";/(?:^|[\\/])adapter\.(?:js|ts)$/.test(G)&&L();export{L as runCodexAcpAdapter};
5
+ `)}function $(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 D(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 W(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 L(n){return new Promise(e=>setTimeout(e,n))}function G(){new U}const J=process.argv[1]||"";/(?:^|[\\/])adapter\.(?:js|ts)$/.test(J)&&G();export{G as runCodexAcpAdapter};
@@ -1 +1 @@
1
- import p from"node:fs";import{promptBlocksToAcpContent as y}from"../../client/acp-content.js";import{eventFromAcpSessionUpdate as b,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 L{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,t,s=_()){this.cwd=e,this.providerSessionId=t,this.defaultTimeoutMs=s}async sendPrompt(e){if(!p.existsSync(e.cwd)||!p.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const t=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(t);let s=null,n=null,r=this.providerSessionId,i,a=null;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const c=await this.acquireRuntime(e.cwd);this.lease=c,s=c.client,n=c.started,await this.initialize(c),r=await this.establishSession(c,e),await this.applyConfig(s,r,e),this.emitStatus("thinking","思考中"),a=this.startSlowStatusTimer(),i=await this.promptWithAbort(s,{sessionId:r,prompt:y(e.prompt,e.promptBlocks),timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal});const d=S(i);d&&d!==r&&(r=d,this.providerSessionId=d,c.setProviderSession({providerSessionId:d,sessionResponse:this.sessionResponse}))}finally{a&&clearInterval(a),this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}return this.emitStatus("completed","已完成"),{providerSessionId:r,cliType:"builtin",agentType:"codex",effectiveConfig:{model:e.model??null,mode:e.mode??null,configOptionValues:e.configOptionValues??null,command:n.command,processPid:n.child.pid??null,provider:"codex-acp",protocol:"acp"},command:n.command,args:n.args,cwd:e.cwd,exitCode:n.child.exitCode,signal:n.child.signalCode,durationMs:Date.now()-t,stdout:s.rpc.stdout,stderr:s.rpc.stderr,content:this.content.trim(),updates:[...this.updates],statusTimeline:[...this.statusTimeline],performance:this.performanceTracker?.snapshot(),contextUsage:E(i),promptResponse:i}}async compactContext(e){if(!p.existsSync(e.cwd)||!p.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const t=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.attachAbortSignal(e.signal);let s=this.providerSessionId,n;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const i=await this.acquireRuntime(e.cwd);this.lease=i,await this.initialize(i),s=await this.establishSession(i,e),await this.applyConfig(i.client,s,e),n=await i.client.compactSession({sessionId:s,allowRollover:e.allowRollover===!0},e.timeoutMs??600*1e3);const a=S(n);a&&a!==s&&(s=a,this.providerSessionId=a,i.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}))}catch(i){if(this.lease&&T(i,e.signal)){const a=this.lease;this.lease=null,await a.dispose().catch(()=>{})}throw i}finally{this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}const r=l(n)??{};return{providerSessionId:s||this.providerSessionId||"",contextUsage:w(r.contextUsage),maintenance:l(r.maintenance)??{},durationMs:Date.now()-t}}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 t=v();return I.acquire({providerId:"codex-acp",cwd:e,providerSessionId:this.providerSessionId,command:t.command,args:t.args,onSessionUpdate:s=>this.handleSessionUpdate(s),onClientRequest:async(s,n)=>{if(s==="session/request_permission")return this.requestPermission(n);if(s==="elicitation/create"||s==="session/request_user_input")return this.requestUserInput(n);throw new Error(`Unsupported Codex ACP client request: ${s}`)}})}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,t){const s=e.client,n=R(t);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 a=await s.loadSession({sessionId:this.providerSessionId,cwd:t.cwd,config:n},6e4);this.sessionResponse=l(a);const c=f(a)||this.providerSessionId;return this.providerSessionId=c,e.setProviderSession({providerSessionId:c,sessionResponse:this.sessionResponse}),c}catch{this.providerSessionId=null}this.emitStatus("acp","Codex ACP 会话创建中","session/new");const r=await s.newSession({cwd:t.cwd,config:n},12e4);this.sessionResponse=l(r);const i=f(r);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,t,s){s.model&&await e.setSessionConfigOption({sessionId:t,configId:"model",value:s.model},6e4).catch(()=>{});const n=h(s.mode);n&&await e.setSessionConfigOption({sessionId:t,configId:"approvalPolicy",value:n},6e4).catch(()=>{});const r=m(s.mode);r&&await e.setSessionConfigOption({sessionId:t,configId:"sandbox",value:r},6e4).catch(()=>{});for(const[i,a]of Object.entries(s.configOptionValues??{}))["model","mode","sandbox","approvalPolicy"].includes(i)||await e.setSessionConfigOption({sessionId:t,configId:i,value:a},6e4).catch(()=>{})}handleSessionUpdate(e){this.performanceTracker?.recordEvent(),this.updates.push({method:"session/update",params:e});const t=b(e);t&&(t.type==="agent_message_chunk"&&(this.content+=t.text??""),this.updateCallback?.(t));const s=C(e);s&&this.emitStatus(s.phase,s.label,s.detail,s.updateType)}startSlowStatusTimer(){const e=x().slowEventThresholdMs,t=setInterval(()=>{const s=this.performanceTracker,n=Date.now();if(!s?.shouldReportSlow(n,e))return;const r=s.snapshot(n),i=Math.max(1,Math.round(r.silentForMs/6e4));this.emitStatus("thinking","模型长时间处理中",`已 ${i} 分钟没有收到新的 ACP 事件`,"aca.performance.slow")},Math.min(3e4,Math.max(1e3,Math.floor(e/4))));return t.unref(),t}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,t){const s=e.prompt({sessionId:t.sessionId,prompt:t.prompt},t.timeoutMs);if(!t.signal)return s;if(t.signal.aborted)throw await this.lease?.dispose().catch(()=>{}),new Error("Codex ACP prompt cancelled");let n=null;const r=new Promise((i,a)=>{n=()=>{e.cancel(t.sessionId),this.lease?.dispose().catch(()=>{}),a(new Error("Codex ACP prompt cancelled"))},t.signal?.addEventListener("abort",n,{once:!0})});try{return await Promise.race([s,r])}finally{n&&t.signal.removeEventListener("abort",n)}}async requestPermission(e){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},s=t.request&&typeof t.request=="object"&&!Array.isArray(t.request)?t.request:t,r=(Array.isArray(s.options)?s.options:[]).map((i,a)=>{const c=i&&typeof i=="object"&&!Array.isArray(i)?i:{};return{optionId:String(c.optionId??c.id??a),kind:String(c.kind??"choice"),...typeof c.label=="string"?{label:c.label}:{}}});return this.emitStatus("requestPermission","等待授权",q(s),"session/request_permission"),this.permissionCallback({requestId:String(s.requestId??s.id??`codex-acp-permission-${Date.now()}`),params:e,options:r})}async requestUserInput(e){if(!this.userInputCallback)return{outcome:{outcome:"cancelled"}};const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{},s=t.request&&typeof t.request=="object"&&!Array.isArray(t.request)?t.request:t;return this.emitStatus("requestPermission","等待输入",M(s),"elicitation/create"),this.userInputCallback({requestId:String(s.requestId??s.id??`codex-acp-input-${Date.now()}`),prompt:String(s.prompt??s.message??s.question??""),params:e,...typeof s.defaultValue=="string"?{defaultValue:s.defaultValue}:{}})}emitStatus(e,t,s,n){const r={phase:e,label:t,...s?{detail:s}:{},...n?{updateType:n}:{},atMs:Date.now()},i=this.statusTimeline[this.statusTimeline.length-1];i&&i.phase===r.phase&&i.label===r.label&&i.detail===r.detail&&i.updateType===r.updateType||(this.statusTimeline.push(r),this.statusCallback?.(r))}releaseLease(){this.lease?.release(),this.lease=null}}function T(o,e){if(e?.aborted)return!0;const t=o instanceof Error?o.message:String(o||"");return/compact.*timed out|request timed out.*compact|adapter closed|aborted|cancelled/i.test(t)}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 m(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 R(o){return{...o.model?{model:o.model}:{},...h(o.mode)?{approvalPolicy:h(o.mode)}:{},...m(o.mode)?{sandbox:m(o.mode)}:{},...o.configOptionValues??{}}}function q(o){const e=o.params&&typeof o.params=="object"&&!Array.isArray(o.params)?o.params:o;for(const t of["command","cwd","reason","grantRoot","method"]){const s=e[t];if(typeof s=="string"&&s.trim())return g(s)}}function M(o){for(const e of["prompt","message","question","title"]){const t=o[e];if(typeof t=="string"&&t.trim())return g(t)}}function g(o){const e=o.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function _(){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 S(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 E(o){const e=l(o),t=l(e?._meta);return w(t?.acaContextUsage)}function w(o){const e=l(o);if(!e)return null;const t=u(e.contextWindow),s=u(e.usedTokens),n=u(e.inputTokens),r=String(e.state||"unknown"),i=["active","compacted","new_thread"].includes(r)?r:"unknown";return{usedTokens:s,inputTokens:n,contextWindow:t,ratio:t>0?Math.max(0,u(e.ratio)||s/t):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{L as CodexAcpProvider,P as codexAcpCapabilities};
1
+ import m from"node:fs";import{promptBlocksToAcpContent as S}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,n=null,r=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,n=a.started,await this.initialize(a),r=await this.establishSession(a,e),await this.applyConfig(t,r,e),this.emitStatus("thinking","思考中"),c=this.startSlowStatusTimer(),i=await this.promptWithAbort(t,{sessionId:r,prompt:S(e.prompt,e.promptBlocks),timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal});const d=b(i);d&&d!==r&&(r=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:r,cliType:"builtin",agentType:"codex",effectiveConfig:{model:e.model??null,mode:e.mode??null,configOptionValues:e.configOptionValues??null,command:n.command,processPid:n.child.pid??null,provider:"codex-acp",protocol:"acp"},command:n.command,args:n.args,cwd:e.cwd,exitCode:n.child.exitCode,signal:n.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,n;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);n=await this.compactWithAbort(i.client,{sessionId:t,allowRollover:e.allowRollover===!0,timeoutMs:c,signal:e.signal});const a=b(n);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 r=l(n)??{};return{providerSessionId:t||this.providerSessionId||"",contextUsage:w(r.contextUsage),maintenance:l(r.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,n)=>{if(t==="session/request_permission")return this.requestPermission(n);if(t==="elicitation/create"||t==="session/request_user_input")return this.requestUserInput(n);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,n=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:n},6e4);this.sessionResponse=l(c);const a=f(c)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}),a}catch{this.providerSessionId=null}this.emitStatus("acp","Codex ACP 会话创建中","session/new");const r=await t.newSession({cwd:s.cwd,config:n},12e4);this.sessionResponse=l(r);const i=f(r);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 n=h(t.mode);n&&await e.setSessionConfigOption({sessionId:s,configId:"approvalPolicy",value:n},6e4).catch(()=>{});const r=p(t.mode);r&&await e.setSessionConfigOption({sessionId:s,configId:"sandbox",value:r},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,n=Date.now();if(!t?.shouldReportSlow(n,e))return;const r=t.snapshot(n),i=Math.max(1,Math.round(r.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 n=null;const r=new Promise((i,c)=>{n=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP prompt cancelled"))},s.signal?.addEventListener("abort",n,{once:!0})});try{return await Promise.race([t,r])}finally{n&&s.signal.removeEventListener("abort",n)}}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 n=null;const r=new Promise((i,c)=>{n=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP 上下文压缩已取消"))},s.signal?.addEventListener("abort",n,{once:!0})});try{return await Promise.race([t,r])}finally{n&&s.signal.removeEventListener("abort",n)}}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,r=(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:r})}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,n){const r={phase:e,label:s,...t?{detail:t}:{},...n?{updateType:n}:{},atMs:Date.now()},i=this.statusTimeline[this.statusTimeline.length-1];i&&i.phase===r.phase&&i.label===r.label&&i.detail===r.detail&&i.updateType===r.updateType||(this.statusTimeline.push(r),this.statusCallback?.(r))}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 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 O(o){const e=l(o),s=l(e?._meta);return w(s?.acaContextUsage)}function w(o){const e=l(o);if(!e)return null;const s=u(e.contextWindow),t=u(e.usedTokens),n=u(e.inputTokens),r=String(e.state||"unknown"),i=["active","compacted","new_thread"].includes(r)?r:"unknown";return{usedTokens:t,inputTokens:n,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 +1 @@
1
- import{Command as y}from"commander";import b from"node:fs";import T from"node:os";import P from"node:path";import t from"node:process";import{randomUUID as R}from"node:crypto";import{Logger as E}from"../core/logger.js";import{loadCredentials as k,saveApiKeyCredential as _}from"../core/auth.js";import{getRuntimeStatePath as N}from"../core/paths.js";import{writeJsonFile as D}from"../core/fs.js";import{HEARTBEAT_INTERVAL_MS as L,startHeartbeatLoop as O}from"../core/heartbeat.js";import{startJobWorkerLoop as $}from"../core/job-worker.js";import{startFileTransferWorkerLoop as W}from"../core/file-transfer-worker.js";import{startMachineFilesystemWorkerLoop as x}from"../core/machine-filesystem-worker.js";import{cleanupOrphanedAcpProcesses as M}from"../core/acp-orphan-cleanup.js";import{defaultAcpRuntimePool as A}from"../acp/client/acp-runtime-pool.js";import{writePidFile as U,removePidFile as j}from"../core/process.js";import{applyRuntimePathOptions as F}from"../core/runtime-options.js";import{loadAcaConfig as K,updateAcaConfig as V}from"../core/aca-config.js";import{ACA_WORKER_INSTANCE_ENV as I,ACA_WORKER_PID_ENV as H,ACA_WORKER_START_TICKS_ENV as G,readProcessStartTicks as J}from"../core/process-identity.js";function ge(){return new y("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").action(async e=>{await B(e)})}async function B(e){F(e);const r=t.env[I]||R(),o=J(t.pid)||"";t.env[I]=r,t.env[H]=String(t.pid),t.env[G]=o;const a=new E("start",e.debug?"debug":"info"),v=K(),p={...e.server?.trim()?{serverUrl:e.server.trim()}:{},...e.machineId?{machineId:e.machineId.trim()}:{},...e.machineName?{machineName:e.machineName.trim()}:{}},d=Object.keys(p).length>0?V(p):v,n=e.machineName?.trim()||d.machineName||T.hostname(),w=e.auth?_(e.auth,n):k();U(t.pid),S({pid:t.pid,workerInstanceId:r,workerStartTicks:o,phase:"running",startupStage:"local-compatible",machineId:d.machineId||w?.machine?.machineId||"local-machine",machineName:n,cliTypes:e.cliTypes??q(),startedAt:new Date().toISOString(),heartbeatIntervalMs:L,issues:[{severity:"info",message:"aca is running in aca-server compatibility mode; ACP execution happens on this machine."}]}),a.info(`Starting aca local-compatible service on machine ${n}`),a.info(`PID ${t.pid}`);const s=await M();s.terminated>0&&a.warn(`terminated ${s.terminated} orphaned ACP process(es): ${s.pids.join(",")}`);let f=!1,c,l,h,u;const g=async C=>{if(f)return;f=!0,a.info("Shutting down"),c&&clearInterval(c),h?.stop(),u?.stop(),await l?.stop().catch(i=>a.warn(`job worker shutdown failed: ${i instanceof Error?i.message:String(i)}`));const m=A.stats();await A.disposeAll().catch(i=>a.warn(`ACP runtime shutdown failed: ${i instanceof Error?i.message:String(i)}`)),a.info(`ACP runtimes stopped total=${m.total} inUse=${m.inUse} idle=${m.idle}`),S({pid:t.pid,phase:"stopped",stoppedAt:new Date().toISOString(),issues:[]}),j(),t.exit(C)};t.once("SIGINT",()=>{g(130)}),t.once("SIGTERM",()=>{g(0)}),e.heartbeatLog&&setInterval(()=>a.info(`heartbeat: ${new Date().toISOString()}`),5e3),c=O(a),l=$(a),h=W(a),u=x(a),await new Promise(()=>{})}function q(){return["codex","claude"].filter(e=>z(e))}function z(e){const r=t.env.PATH||"";for(const o of r.split(":"))try{if(o&&b.existsSync(P.join(o,e)))return!0}catch{}return!1}function S(e){D(N(),e)}export{ge as createStartCommand};
1
+ import{Command as k}from"commander";import b from"node:fs";import T from"node:os";import P from"node:path";import t from"node:process";import{randomUUID as R}from"node:crypto";import{Logger as E}from"../core/logger.js";import{loadCredentials as _,saveApiKeyCredential as N}from"../core/auth.js";import{getRuntimeStatePath as D}from"../core/paths.js";import{writeJsonFile as O}from"../core/fs.js";import{HEARTBEAT_INTERVAL_MS as $,startHeartbeatLoop as L}from"../core/heartbeat.js";import{startJobWorkerLoop as U}from"../core/job-worker.js";import{startFileTransferWorkerLoop as W}from"../core/file-transfer-worker.js";import{startMachineFilesystemWorkerLoop as M}from"../core/machine-filesystem-worker.js";import{cleanupOrphanedAcpProcesses as x}from"../core/acp-orphan-cleanup.js";import{defaultAcpRuntimePool as S}from"../acp/client/acp-runtime-pool.js";import{writePidFile as j,removePidFile as F}from"../core/process.js";import{applyRuntimePathOptions as K}from"../core/runtime-options.js";import{loadAcaConfig as V,updateAcaConfig as v}from"../core/aca-config.js";import{acaServerRequest as H}from"../core/aca-server-client.js";import{ACA_WORKER_INSTANCE_ENV as A,ACA_WORKER_PID_ENV as G,ACA_WORKER_START_TICKS_ENV as J,readProcessStartTicks as q}from"../core/process-identity.js";function Se(){return new k("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").action(async e=>{await B(e)})}async function B(e){K(e);const s=t.env[A]||R(),o=q(t.pid)||"";t.env[A]=s,t.env[G]=String(t.pid),t.env[J]=o;const a=new E("start",e.debug?"debug":"info"),C=V(),l={...e.server?.trim()?{serverUrl:e.server.trim()}:{},...e.machineId?{machineId:e.machineId.trim()}:{},...e.machineName?{machineName:e.machineName.trim()}:{}};let n=Object.keys(l).length>0?v(l):C;const m=e.machineName?.trim()||n.machineName||T.hostname();if(e.token?.trim()){const r=await H("POST","/api/auth/machine-enroll",{token:e.token.trim(),machineId:n.machineId,machineName:m},{serverUrl:n.serverUrl});n=v({machineId:r.machineId,machineName:m,token:r.token,username:r.username}),a.info(`Machine enrollment completed for user ${r.username}`)}const y=e.auth?N(e.auth,m):_();j(t.pid),w({pid:t.pid,workerInstanceId:s,workerStartTicks:o,phase:"running",startupStage:"local-compatible",machineId:n.machineId||y?.machine?.machineId||"local-machine",machineName:m,cliTypes:e.cliTypes??z(),startedAt:new Date().toISOString(),heartbeatIntervalMs:$,issues:[{severity:"info",message:"aca is running in aca-server compatibility mode; ACP execution happens on this machine."}]}),a.info(`Starting aca local-compatible service on machine ${m}`),a.info(`PID ${t.pid}`);const c=await x();c.terminated>0&&a.warn(`terminated ${c.terminated} orphaned ACP process(es): ${c.pids.join(",")}`);let f=!1,p,h,u,g;const I=async r=>{if(f)return;f=!0,a.info("Shutting down"),p&&clearInterval(p),u?.stop(),g?.stop(),await h?.stop().catch(i=>a.warn(`job worker shutdown failed: ${i instanceof Error?i.message:String(i)}`));const d=S.stats();await S.disposeAll().catch(i=>a.warn(`ACP runtime shutdown failed: ${i instanceof Error?i.message:String(i)}`)),a.info(`ACP runtimes stopped total=${d.total} inUse=${d.inUse} idle=${d.idle}`),w({pid:t.pid,phase:"stopped",stoppedAt:new Date().toISOString(),issues:[]}),F(),t.exit(r)};t.once("SIGINT",()=>{I(130)}),t.once("SIGTERM",()=>{I(0)}),e.heartbeatLog&&setInterval(()=>a.info(`heartbeat: ${new Date().toISOString()}`),5e3),p=L(a),h=U(a),u=W(a),g=M(a),await new Promise(()=>{})}function z(){return["codex","claude"].filter(e=>Q(e))}function Q(e){const s=t.env.PATH||"";for(const o of s.split(":"))try{if(o&&b.existsSync(P.join(o,e)))return!0}catch{}return!1}function w(e){O(D(),e)}export{Se as createStartCommand};
@@ -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 I=1024,S=new Set(["agent_message_chunk","agent_progress_chunk","agent_thought_chunk","user_message_chunk"]),w=new Set(["usage_update","session_info_update"]);function C(t,e){const n=t.at(-1);if(!n)return t.push(e),!1;if(E(n,e)){const r=`${n.text??""}${e.text??""}`;if(r.length<=1024)return n.text=r,n.raw=d(n.raw,e.raw,r),!0}if(x(n,e)){const r=p(n.raw);return n.label=e.label,n.text=e.text,n.status=e.status,n.toolCallId=e.toolCallId,n.raw=d(n.raw,e.raw,e.text,r),!0}return t.push(e),!1}function E(t,e){return S.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 x(t,e){if(t.eventType!==e.eventType||t.turnId!==e.turnId)return!1;if(w.has(t.eventType))return!0;if(t.eventType==="plan")return f(t.raw)===f(e.raw);if(t.eventType!=="config_option_update")return!1;const n=c(t.raw),r=c(e.raw);return!!n&&n===r}function f(t){const e=l(t);for(const n of["planId","plan_id","id"])if(typeof e?.[n]=="string"&&e[n].trim())return e[n].trim();return"default"}function c(t){const e=l(t);for(const n of["configId","optionId","id","key","name"])if(typeof e?.[n]=="string"&&e[n].trim())return e[n].trim();return""}function d(t,e,n,r=p(t)){const u=a(e);if(!u)return e;const _=h(e),T=y(t)+y(e),s={...u,acaSequence:r,acaSequenceEnd:_,sourceEventCount:T};if(n!==void 0){const o=a(u.update);o&&(s.update={...o,content:{type:"text",text:n}})}return s}function l(t){return a(a(t)?.update)}function p(t){const e=a(t)?.acaSequence;return typeof e=="number"?e:void 0}function h(t){const e=a(t),n=e?.acaSequenceEnd;return typeof n=="number"?n:typeof e?.acaSequence=="number"?e.acaSequence:void 0}function y(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};
@@ -0,0 +1 @@
1
+ import{closeAcpProcess as g}from"../acp/client/acp-process.js";import{JsonLineRpcClient as y}from"../acp/client/json-rpc.js";import{startCodexAppServer as E}from"../acp/providers/codex/codex-process.js";const A=360*60*1e3,m=2e4,R=8;let d=null,f=null,u=0;async function b(){const e=Date.now();if(d&&d.expiresAtMs>e)return d;if(u>e)return null;if(f)return f;f=h().finally(()=>{f=null});const t=await f;return t?(d=t,u=0):u=e+300*1e3,t}function x(e,t=Date.now()){const a=c(e),o=(Array.isArray(a.data)?a.data:[]).map(n=>C(c(n))).filter(n=>!!n);if(!o.length)return null;const i=o.find(n=>n.isDefault)?.modelId||o[0].modelId,l=w(o),p=[{id:"read-only",name:"Read-only",description:"Requires approval to edit files and run commands."},{id:"agent",name:"Agent",description:"Read and edit files, and run commands."},{id:"agent-full-access",name:"Agent (full access)",description:"Edit files and run commands with full access."}];return{expiresAtMs:t+A,defaultModel:i,capabilities:{source:"codex-app-server",fetchedAt:t,modelCatalogAuthoritative:!0,contextUsage:!0,contextCompaction:!0,modes:p,models:o.map(n=>({modelId:n.modelId,name:n.name,description:n.description,metadata:{defaultReasoningEffort:n.defaultReasoningEffort,supportedReasoningEfforts:n.supportedReasoningEfforts}})),configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:p.map(n=>({value:n.id,name:n.name,description:n.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:i,options:o.map(n=>({value:n.modelId,name:n.name,description:n.description}))},{id:"reasoning_effort",name:"Reasoning effort",category:"thought_level",type:"select",currentValue:o.find(n=>n.modelId===i)?.defaultReasoningEffort||l[0]?.value,options:l}]}}}async function h(){const e=E(process.cwd()),t=new y(e.child,{peerName:"Codex app-server"});try{await t.request("initialize",{clientInfo:{name:"aica-worker",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},m);const a=[];let r=null;for(let o=0;o<R;o+=1){const i=c(await t.request("model/list",{limit:100,...r?{cursor:r}:{}},m));if(Array.isArray(i.data)&&a.push(...i.data),r=typeof i.nextCursor=="string"&&i.nextCursor?i.nextCursor:null,!r)break}return x({data:a})}catch{return null}finally{await g(e.child).catch(()=>{})}}function C(e){if(e.hidden===!0)return null;const t=s(e.model,e.id);if(!t)return null;const a=(Array.isArray(e.supportedReasoningEfforts)?e.supportedReasoningEfforts:[]).map(o=>{const i=c(o),l=s(i.reasoningEffort,i.reasoning_effort,i.value);return l?{reasoningEffort:l,description:s(i.description)||""}:null}).filter(o=>!!o),r=s(e.defaultReasoningEffort,e.default_reasoning_effort)||a[0]?.reasoningEffort||"";return{modelId:t,name:s(e.displayName,e.name,t)||t,description:s(e.description)||"",isDefault:e.isDefault===!0,defaultReasoningEffort:r,supportedReasoningEfforts:a}}function w(e){const t=new Map;for(const a of e)for(const r of a.supportedReasoningEfforts)t.has(r.reasoningEffort)||t.set(r.reasoningEffort,{value:r.reasoningEffort,name:M(r.reasoningEffort),description:r.description});return[...t.values()]}function M(e){return e.toLowerCase()==="xhigh"?"X High":e.replace(/[-_]+/g," ").replace(/\b\w/g,t=>t.toUpperCase())}function c(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function s(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return null}export{x as codexCapabilitiesFromModelList,b as readCodexCapabilities};
@@ -1,3 +1,3 @@
1
- import{execFileSync as g}from"node:child_process";import m from"node:os";import{readJsonFile as M,writeJsonFile as I}from"./fs.js";import{getRuntimeStatePath as y}from"./paths.js";import{acaServerRequest as v}from"./aca-server-client.js";import{loadAcaConfig as x}from"./aca-config.js";import{providerHealthSnapshot as w}from"./provider-health.js";const C=3e4,O=360*60*1e3,_=360*60*1e3;let l=null,p=null;async function k(e=x()){return e.token?await v("POST","/api/heartbeat",{machineId:e.machineId,machineName:e.machineName,machineInfo:{platform:m.platform(),architecture:m.arch(),osRelease:m.release(),acaVersion:S(),hostname:m.hostname()},workspaceId:e.defaultWorkspaceId,agentConfigs:E(e),projects:e.projects.map(o=>({projectId:o.projectId,workspaceId:o.workspaceId,name:o.name,rootPath:o.rootPath}))}):{ok:!1,skipped:!0,reason:"not_logged_in"}}function E(e){const t=w();return[{agentId:`${e.machineId}:builtin:codex`,workspaceId:e.defaultWorkspaceId,name:"Codex",agentType:"codex",cliType:"builtin",machineId:e.machineId,model:"gpt-5.5",mode:"agent-full-access",raw:{providerStatus:t.codex,capabilities:D()}},{agentId:`${e.machineId}:builtin:mimo`,workspaceId:e.defaultWorkspaceId,name:"MimoCode",agentType:"mimo",cliType:"builtin",machineId:e.machineId,model:"mimo/mimo-auto",mode:"agent-full-access",raw:{providerStatus:t.mimo,capabilities:V()}},{agentId:`${e.machineId}:builtin:opencode`,workspaceId:e.defaultWorkspaceId,name:"OpenCode",agentType:"opencode",cliType:"builtin",machineId:e.machineId,model:process.env.ACA_OPENCODE_DEFAULT_MODEL||null,mode:"agent-full-access",raw:{providerStatus:t.opencode,capabilities:H()}}]}function S(){return process.env.ACA_VERSION?.trim()||"0.1.0"}function D(){const e=[{id:"read-only",name:"Read-only",description:"Requires approval to edit files and run commands."},{id:"agent",name:"Agent",description:"Read and edit files, and run commands."},{id:"agent-full-access",name:"Agent (full access)",description:"Edit files and run commands with full access."}],t=[{modelId:"gpt-5.5",name:"gpt-5.5",description:"Latest frontier Codex model"},{modelId:"gpt-5.4",name:"gpt-5.4",description:"Frontier Codex model"},{modelId:"gpt-5.4-mini",name:"gpt-5.4-mini",description:"Smaller, faster Codex model"}],o=[{value:"low",name:"Low",description:"Fastest responses"},{value:"medium",name:"Medium",description:"Balanced reasoning"},{value:"high",name:"High",description:"More reasoning for difficult tasks"},{value:"xhigh",name:"X High",description:"Extra reasoning for complex tasks"}];return{source:"aca-static",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!0,modes:e,models:t,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:e.map(n=>({value:n.id,name:n.name,description:n.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:"gpt-5.5",options:t.map(n=>({value:n.modelId,name:n.name,description:n.description}))},{id:"reasoning_effort",name:"Reasoning effort",category:"thought_level",type:"select",currentValue:"medium",options:o}]}}function N(){const e=[{id:"agent",name:"Agent",description:"Run MimoCode with normal workspace permissions."},{id:"agent-full-access",name:"Agent (full access)",description:"Run MimoCode and auto-approve supported local permissions."}],t=[{modelId:"mimo/mimo-auto",name:"MiMo Auto (free)",description:"MiMo Auto free model"},{modelId:"xiaomi/mimo-v2.5",name:"mimo-v2.5",description:"MimoCode v2.5"},{modelId:"xiaomi/mimo-v2.5-pro",name:"mimo-v2.5-pro",description:"MimoCode v2.5 Pro"},{modelId:"xiaomi/mimo-v2.5-pro-ultraspeed",name:"mimo-v2.5-pro-ultraspeed",description:"MimoCode v2.5 Pro UltraSpeed"}],o=[{value:"minimal",name:"Minimal",description:"Fastest responses"},{value:"high",name:"High",description:"More reasoning for difficult tasks"},{value:"max",name:"Max",description:"Maximum reasoning when supported"}];return{source:"aca-static",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:e,models:t,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:e.map(n=>({value:n.id,name:n.name,description:n.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:"mimo/mimo-auto",options:t.map(n=>({value:n.modelId,name:n.name,description:n.description}))},{id:"variant",name:"Variant",category:"thought_level",type:"select",currentValue:"high",options:o}]}}function V(){const e=Date.now();if(l&&l.expiresAtMs>e)return l.capabilities;const t=U()??N();return l={expiresAtMs:e+O,capabilities:t},t}function j(){const e=[{id:"plan",name:"Plan",description:"Inspect the project and propose changes."},{id:"build",name:"Build",description:"Read and edit files, and run commands when approved."},{id:"agent-full-access",name:"Agent (full access)",description:"Run OpenCode with ACA full-access mode mapping."}],t=[{modelId:"",name:"Default",description:"Use the model selected by OpenCode configuration."}];return{source:"aca-static",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:e,models:t,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:e.map(o=>({value:o.id,name:o.name,description:o.description}))},{id:"model",name:"Model",category:"model",type:"text",currentValue:process.env.ACA_OPENCODE_DEFAULT_MODEL||"",options:t.map(o=>({value:o.modelId,name:o.name,description:o.description}))}]}}function H(){const e=Date.now();if(p&&p.expiresAtMs>e)return p.capabilities;const t=R()??j();return p={expiresAtMs:e+_,capabilities:t},t}function R(){try{const e=process.env.ACA_OPENCODE_COMMAND||"opencode",t=g(e,["models","--verbose"],{encoding:"utf8",timeout:15e3,maxBuffer:8*1024*1024,stdio:["ignore","pipe","pipe"]}),o=T(t);if(!o.length)return null;const n=[{id:"plan",name:"Plan",description:"Inspect the project and propose changes."},{id:"build",name:"Build",description:"Read and edit files, and run commands when approved."},{id:"agent-full-access",name:"Agent (full access)",description:"Run OpenCode with ACA full-access mode mapping."}],a=L(o);return{source:"opencode-cli",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:n,models:o.map(i=>({modelId:i.modelId,name:i.displayName,description:i.description,metadata:i.metadata})),configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:n.map(i=>({value:i.id,name:i.name,description:i.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:a,options:o.map(i=>({value:i.modelId,name:i.displayName,description:i.description}))}]}}catch{return null}}function T(e){const t=e.split(/\r?\n/),o=[];let n=0;for(;n<t.length;){const a=t[n]?.trim()??"";if(n+=1,!/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(a))continue;const i=[];let c=0,d=!1;for(;n<t.length;){const s=t[n]??"";if(n+=1,!(!d&&!s.trim().startsWith("{"))&&(d=!0,i.push(s),c+=u(s,"{")-u(s,"}"),d&&c<=0))break}const r=b(i.join(`
2
- `));if(!r)continue;const f=A(r.name,r.id,a)??a;o.push({modelId:a,displayName:$(f,r),description:P(r),metadata:r})}return o}function L(e){const t=process.env.ACA_OPENCODE_DEFAULT_MODEL?.trim();return t&&e.some(o=>o.modelId===t)?t:e.find(o=>o.modelId==="opencode/big-pickle")?.modelId||e.find(o=>/free$/i.test(o.modelId))?.modelId||e[0]?.modelId||""}function $(e,t){return F(t)&&!/\bfree\b/i.test(e)?`${e} (free)`:e}function F(e){const t=e.cost;if(!t||typeof t!="object"||Array.isArray(t))return!1;const o=t,n=o.cache&&typeof o.cache=="object"&&!Array.isArray(o.cache)?o.cache:{};return[o.input,o.output,n.read,n.write].every(a=>Number(a??0)===0)}function P(e){const t=e.limit&&typeof e.limit=="object"&&!Array.isArray(e.limit)?e.limit:{},o=Number(t.context??0),n=Number(t.output??0);return o>0&&n>0?`Context ${o}, output ${n}`:o>0?`Context ${o}`:"OpenCode model"}function U(){try{const e=process.env.ACA_MIMO_COMMAND||"mimo",t=g(e,["models","--verbose"],{encoding:"utf8",timeout:15e3,maxBuffer:2*1024*1024,stdio:["ignore","pipe","pipe"]}),o=B(t);if(!o.length)return null;const n=[{id:"agent",name:"Agent",description:"Run MimoCode with normal workspace permissions."},{id:"agent-full-access",name:"Agent (full access)",description:"Run MimoCode and auto-approve supported local permissions."}],a=W(o);return{source:"mimo-cli",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:n,models:o.map(i=>({modelId:i.modelId,name:i.displayName,description:i.description,metadata:i.metadata})),configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:n.map(i=>({value:i.id,name:i.name,description:i.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:o.some(i=>i.modelId==="mimo/mimo-auto")?"mimo/mimo-auto":o[0]?.modelId,options:o.map(i=>({value:i.modelId,name:i.displayName,description:i.description}))},{id:"variant",name:"Variant",category:"thought_level",type:"select",currentValue:a.some(i=>i.value==="high")?"high":a[0]?.value,options:a}]}}catch{return null}}function B(e){const t=e.split(/\r?\n/),o=[];let n=0;for(;n<t.length;){const a=t[n]?.trim()??"";if(n+=1,!/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(a))continue;const i=[];let c=0,d=!1;for(;n<t.length;){const s=t[n]??"";if(n+=1,!(!d&&!s.trim().startsWith("{"))&&(d=!0,i.push(s),c+=u(s,"{")-u(s,"}"),d&&c<=0))break}const r=b(i.join(`
3
- `));if(!r)continue;const f=A(r.name,r.id,a)??a;o.push({modelId:a,displayName:z(f,r),description:q(r),metadata:r})}return o}function W(e){const t=new Set;for(const a of e){const i=a.metadata.variants;if(!(!i||typeof i!="object"||Array.isArray(i)))for(const c of Object.keys(i))t.add(c)}const o=["minimal","low","medium","high","max"].filter(a=>t.has(a));return(o.length?o:["minimal","high","max"]).map(a=>({value:a,name:X(a),description:a==="high"?"More reasoning for difficult tasks":a==="max"?"Maximum reasoning when supported":"Fastest responses"}))}function z(e,t){return J(t)&&!/\bfree\b/i.test(e)?`${e} (free)`:e}function J(e){const t=e.cost;if(!t||typeof t!="object"||Array.isArray(t))return!1;const o=t,n=o.cache&&typeof o.cache=="object"&&!Array.isArray(o.cache)?o.cache:{};return[o.input,o.output,n.read,n.write].every(a=>Number(a??0)===0)}function q(e){const t=e.limit&&typeof e.limit=="object"&&!Array.isArray(e.limit)?e.limit:{},o=Number(t.context??0);return o>0?`Context ${o}`:"MimoCode model"}function b(e){try{const t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:null}catch{return null}}function A(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim()}function X(e){return e.slice(0,1).toUpperCase()+e.slice(1)}function u(e,t){let o=0;for(const n of e)n===t&&(o+=1);return o}function oe(e){const t=async()=>{const o=new Date().toISOString();try{const n=await k();if(n.skipped){h({lastHeartbeatAt:o,lastHeartbeatStatus:"skipped",lastHeartbeatReason:n.reason??"unknown"}),e.debug(`heartbeat skipped: ${n.reason??"unknown"}`);return}h({lastHeartbeatAt:o,lastHeartbeatStatus:"ok",lastHeartbeatProjectCount:n.projectCount??null,presenceExpiresAtMs:n.presenceExpiresAtMs??null}),e.debug(`heartbeat ok projects=${n.projectCount??0}`)}catch(n){const a=n instanceof Error?n.message:String(n);h({lastHeartbeatAt:o,lastHeartbeatStatus:"error",lastHeartbeatError:a}),e.warn(`heartbeat failed: ${a}`)}};return t(),setInterval(()=>{t()},C)}function h(e){const t=M(y())??{};I(y(),{...t,heartbeatIntervalMs:C,...e})}export{C as HEARTBEAT_INTERVAL_MS,k as sendHeartbeat,oe as startHeartbeatLoop};
1
+ import{execFileSync as g}from"node:child_process";import m from"node:os";import{readJsonFile as M,writeJsonFile as I}from"./fs.js";import{getRuntimeStatePath as C}from"./paths.js";import{acaServerRequest as v}from"./aca-server-client.js";import{loadAcaConfig as x}from"./aca-config.js";import{providerHealthSnapshot as w}from"./provider-health.js";import{readCodexCapabilities as O}from"./codex-capabilities.js";const y=3e4,_=360*60*1e3,k=360*60*1e3;let l=null,p=null;async function E(e=x()){return e.token?await v("POST","/api/heartbeat",{machineId:e.machineId,machineName:e.machineName,machineInfo:{platform:m.platform(),architecture:m.arch(),osRelease:m.release(),acaVersion:D(),hostname:m.hostname()},workspaceId:e.defaultWorkspaceId,agentConfigs:await S(e),projects:e.projects.map(o=>({projectId:o.projectId,workspaceId:o.workspaceId,name:o.name,rootPath:o.rootPath}))}):{ok:!1,skipped:!0,reason:"not_logged_in"}}async function S(e){const t=w(),o=await O(),n=o?.capabilities??N();return[{agentId:`${e.machineId}:builtin:codex`,workspaceId:e.defaultWorkspaceId,name:"Codex",agentType:"codex",cliType:"builtin",machineId:e.machineId,model:o?.defaultModel||"gpt-5.5",mode:"agent-full-access",raw:{providerStatus:t.codex,capabilities:n}},{agentId:`${e.machineId}:builtin:mimo`,workspaceId:e.defaultWorkspaceId,name:"MimoCode",agentType:"mimo",cliType:"builtin",machineId:e.machineId,model:"mimo/mimo-auto",mode:"agent-full-access",raw:{providerStatus:t.mimo,capabilities:j()}},{agentId:`${e.machineId}:builtin:opencode`,workspaceId:e.defaultWorkspaceId,name:"OpenCode",agentType:"opencode",cliType:"builtin",machineId:e.machineId,model:process.env.ACA_OPENCODE_DEFAULT_MODEL||null,mode:"agent-full-access",raw:{providerStatus:t.opencode,capabilities:R()}}]}function D(){return process.env.ACA_VERSION?.trim()||"0.1.0"}function N(){const e=[{id:"read-only",name:"Read-only",description:"Requires approval to edit files and run commands."},{id:"agent",name:"Agent",description:"Read and edit files, and run commands."},{id:"agent-full-access",name:"Agent (full access)",description:"Edit files and run commands with full access."}],t=[{modelId:"gpt-5.5",name:"gpt-5.5",description:"Latest frontier Codex model"},{modelId:"gpt-5.4",name:"gpt-5.4",description:"Frontier Codex model"},{modelId:"gpt-5.4-mini",name:"gpt-5.4-mini",description:"Smaller, faster Codex model"}],o=[{value:"low",name:"Low",description:"Fastest responses"},{value:"medium",name:"Medium",description:"Balanced reasoning"},{value:"high",name:"High",description:"More reasoning for difficult tasks"},{value:"xhigh",name:"X High",description:"Extra reasoning for complex tasks"}];return{source:"aca-static",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!0,modes:e,models:t,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:e.map(n=>({value:n.id,name:n.name,description:n.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:"gpt-5.5",options:t.map(n=>({value:n.modelId,name:n.name,description:n.description}))},{id:"reasoning_effort",name:"Reasoning effort",category:"thought_level",type:"select",currentValue:"medium",options:o}]}}function V(){const e=[{id:"agent",name:"Agent",description:"Run MimoCode with normal workspace permissions."},{id:"agent-full-access",name:"Agent (full access)",description:"Run MimoCode and auto-approve supported local permissions."}],t=[{modelId:"mimo/mimo-auto",name:"MiMo Auto (free)",description:"MiMo Auto free model"},{modelId:"xiaomi/mimo-v2.5",name:"mimo-v2.5",description:"MimoCode v2.5"},{modelId:"xiaomi/mimo-v2.5-pro",name:"mimo-v2.5-pro",description:"MimoCode v2.5 Pro"},{modelId:"xiaomi/mimo-v2.5-pro-ultraspeed",name:"mimo-v2.5-pro-ultraspeed",description:"MimoCode v2.5 Pro UltraSpeed"}],o=[{value:"minimal",name:"Minimal",description:"Fastest responses"},{value:"high",name:"High",description:"More reasoning for difficult tasks"},{value:"max",name:"Max",description:"Maximum reasoning when supported"}];return{source:"aca-static",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:e,models:t,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:e.map(n=>({value:n.id,name:n.name,description:n.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:"mimo/mimo-auto",options:t.map(n=>({value:n.modelId,name:n.name,description:n.description}))},{id:"variant",name:"Variant",category:"thought_level",type:"select",currentValue:"high",options:o}]}}function j(){const e=Date.now();if(l&&l.expiresAtMs>e)return l.capabilities;const t=B()??V();return l={expiresAtMs:e+_,capabilities:t},t}function H(){const e=[{id:"plan",name:"Plan",description:"Inspect the project and propose changes."},{id:"build",name:"Build",description:"Read and edit files, and run commands when approved."},{id:"agent-full-access",name:"Agent (full access)",description:"Run OpenCode with ACA full-access mode mapping."}],t=[{modelId:"",name:"Default",description:"Use the model selected by OpenCode configuration."}];return{source:"aca-static",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:e,models:t,configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:e.map(o=>({value:o.id,name:o.name,description:o.description}))},{id:"model",name:"Model",category:"model",type:"text",currentValue:process.env.ACA_OPENCODE_DEFAULT_MODEL||"",options:t.map(o=>({value:o.modelId,name:o.name,description:o.description}))}]}}function R(){const e=Date.now();if(p&&p.expiresAtMs>e)return p.capabilities;const t=T()??H();return p={expiresAtMs:e+k,capabilities:t},t}function T(){try{const e=process.env.ACA_OPENCODE_COMMAND||"opencode",t=g(e,["models","--verbose"],{encoding:"utf8",timeout:15e3,maxBuffer:8*1024*1024,stdio:["ignore","pipe","pipe"]}),o=L(t);if(!o.length)return null;const n=[{id:"plan",name:"Plan",description:"Inspect the project and propose changes."},{id:"build",name:"Build",description:"Read and edit files, and run commands when approved."},{id:"agent-full-access",name:"Agent (full access)",description:"Run OpenCode with ACA full-access mode mapping."}],a=$(o);return{source:"opencode-cli",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:n,models:o.map(i=>({modelId:i.modelId,name:i.displayName,description:i.description,metadata:i.metadata})),configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:n.map(i=>({value:i.id,name:i.name,description:i.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:a,options:o.map(i=>({value:i.modelId,name:i.displayName,description:i.description}))}]}}catch{return null}}function L(e){const t=e.split(/\r?\n/),o=[];let n=0;for(;n<t.length;){const a=t[n]?.trim()??"";if(n+=1,!/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(a))continue;const i=[];let c=0,d=!1;for(;n<t.length;){const r=t[n]??"";if(n+=1,!(!d&&!r.trim().startsWith("{"))&&(d=!0,i.push(r),c+=u(r,"{")-u(r,"}"),d&&c<=0))break}const s=b(i.join(`
2
+ `));if(!s)continue;const f=A(s.name,s.id,a)??a;o.push({modelId:a,displayName:F(f,s),description:U(s),metadata:s})}return o}function $(e){const t=process.env.ACA_OPENCODE_DEFAULT_MODEL?.trim();return t&&e.some(o=>o.modelId===t)?t:e.find(o=>o.modelId==="opencode/big-pickle")?.modelId||e.find(o=>/free$/i.test(o.modelId))?.modelId||e[0]?.modelId||""}function F(e,t){return P(t)&&!/\bfree\b/i.test(e)?`${e} (free)`:e}function P(e){const t=e.cost;if(!t||typeof t!="object"||Array.isArray(t))return!1;const o=t,n=o.cache&&typeof o.cache=="object"&&!Array.isArray(o.cache)?o.cache:{};return[o.input,o.output,n.read,n.write].every(a=>Number(a??0)===0)}function U(e){const t=e.limit&&typeof e.limit=="object"&&!Array.isArray(e.limit)?e.limit:{},o=Number(t.context??0),n=Number(t.output??0);return o>0&&n>0?`Context ${o}, output ${n}`:o>0?`Context ${o}`:"OpenCode model"}function B(){try{const e=process.env.ACA_MIMO_COMMAND||"mimo",t=g(e,["models","--verbose"],{encoding:"utf8",timeout:15e3,maxBuffer:2*1024*1024,stdio:["ignore","pipe","pipe"]}),o=W(t);if(!o.length)return null;const n=[{id:"agent",name:"Agent",description:"Run MimoCode with normal workspace permissions."},{id:"agent-full-access",name:"Agent (full access)",description:"Run MimoCode and auto-approve supported local permissions."}],a=z(o);return{source:"mimo-cli",fetchedAt:Date.now(),contextUsage:!0,contextCompaction:!1,modes:n,models:o.map(i=>({modelId:i.modelId,name:i.displayName,description:i.description,metadata:i.metadata})),configOptions:[{id:"mode",name:"Mode",category:"mode",type:"select",currentValue:"agent-full-access",options:n.map(i=>({value:i.id,name:i.name,description:i.description}))},{id:"model",name:"Model",category:"model",type:"select",currentValue:o.some(i=>i.modelId==="mimo/mimo-auto")?"mimo/mimo-auto":o[0]?.modelId,options:o.map(i=>({value:i.modelId,name:i.displayName,description:i.description}))},{id:"variant",name:"Variant",category:"thought_level",type:"select",currentValue:a.some(i=>i.value==="high")?"high":a[0]?.value,options:a}]}}catch{return null}}function W(e){const t=e.split(/\r?\n/),o=[];let n=0;for(;n<t.length;){const a=t[n]?.trim()??"";if(n+=1,!/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(a))continue;const i=[];let c=0,d=!1;for(;n<t.length;){const r=t[n]??"";if(n+=1,!(!d&&!r.trim().startsWith("{"))&&(d=!0,i.push(r),c+=u(r,"{")-u(r,"}"),d&&c<=0))break}const s=b(i.join(`
3
+ `));if(!s)continue;const f=A(s.name,s.id,a)??a;o.push({modelId:a,displayName:J(f,s),description:X(s),metadata:s})}return o}function z(e){const t=new Set;for(const a of e){const i=a.metadata.variants;if(!(!i||typeof i!="object"||Array.isArray(i)))for(const c of Object.keys(i))t.add(c)}const o=["minimal","low","medium","high","max"].filter(a=>t.has(a));return(o.length?o:["minimal","high","max"]).map(a=>({value:a,name:G(a),description:a==="high"?"More reasoning for difficult tasks":a==="max"?"Maximum reasoning when supported":"Fastest responses"}))}function J(e,t){return q(t)&&!/\bfree\b/i.test(e)?`${e} (free)`:e}function q(e){const t=e.cost;if(!t||typeof t!="object"||Array.isArray(t))return!1;const o=t,n=o.cache&&typeof o.cache=="object"&&!Array.isArray(o.cache)?o.cache:{};return[o.input,o.output,n.read,n.write].every(a=>Number(a??0)===0)}function X(e){const t=e.limit&&typeof e.limit=="object"&&!Array.isArray(e.limit)?e.limit:{},o=Number(t.context??0);return o>0?`Context ${o}`:"MimoCode model"}function b(e){try{const t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:null}catch{return null}}function A(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim()}function G(e){return e.slice(0,1).toUpperCase()+e.slice(1)}function u(e,t){let o=0;for(const n of e)n===t&&(o+=1);return o}function ie(e){const t=async()=>{const o=new Date().toISOString();try{const n=await E();if(n.skipped){h({lastHeartbeatAt:o,lastHeartbeatStatus:"skipped",lastHeartbeatReason:n.reason??"unknown"}),e.debug(`heartbeat skipped: ${n.reason??"unknown"}`);return}h({lastHeartbeatAt:o,lastHeartbeatStatus:"ok",lastHeartbeatProjectCount:n.projectCount??null,presenceExpiresAtMs:n.presenceExpiresAtMs??null}),e.debug(`heartbeat ok projects=${n.projectCount??0}`)}catch(n){const a=n instanceof Error?n.message:String(n);h({lastHeartbeatAt:o,lastHeartbeatStatus:"error",lastHeartbeatError:a}),e.warn(`heartbeat failed: ${a}`)}};return t(),setInterval(()=>{t()},y)}function h(e){const t=M(C())??{};I(C(),{...t,heartbeatIntervalMs:y,...e})}export{y as HEARTBEAT_INTERVAL_MS,E as sendHeartbeat,ie as startHeartbeatLoop};
@@ -1,3 +1,5 @@
1
- import{execFileSync as j}from"node:child_process";import{randomUUID as v}from"node:crypto";import m from"node:fs";import S from"node:os";import a from"node:path";import{acaServerRequest as u}from"./aca-server-client.js";import{loadAcaConfig as $,upsertLocalProject as C}from"./aca-config.js";import{startLongPollWorker as E}from"./long-poll-worker.js";const x=25e3,h=300,A=3e4;let d=null;function ot(t){return E({run:async()=>{const e=$();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await u("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${x}`);if(r.item)try{const n=await I(r.item);await u("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:n})}catch(n){const o=n instanceof Error?n.message:String(n);t.warn(`machine filesystem request failed request=${r.item.requestId}: ${o}`),await u("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/fail`,{message:o}).catch(()=>{})}},onError:(e,r)=>t.warn(`machine filesystem worker failed, retry in ${r}ms: ${e instanceof Error?e.message:String(e)}`)})}async function I(t){if(t.operation==="filesystem_roots")return D();if(t.operation==="list_directory")return T({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return L(t.payload);if(t.operation==="list_project_directory")return k(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function k(t){const e=H(String(t.rootPath||"")),r=B(String(t.relativePath||"")),n=K(e,r,!0),o=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),i=m.readdirSync(n,{withFileTypes:!0}).filter(l=>!l.isSymbolicLink()).map(l=>({name:l.name,path:U(e,a.join(n,l.name)),type:l.isDirectory()?"directory":l.isFile()?"file":"other",hidden:l.name.startsWith("."),extension:l.isFile()?a.extname(l.name).slice(1).toLowerCase():""})).filter(l=>l.type!=="other").sort((l,y)=>l.type!==y.type?l.type==="directory"?-1:1:l.name.localeCompare(y.name,void 0,{numeric:!0,sensitivity:"base"})),c=i.slice(o,o+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:c,total:i.length,nextOffset:o+c.length<i.length?o+c.length:null}}function D(){const t=process.platform,e=f(t);return{platform:t,roots:e}}function T(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?N(t.directoryPath,!!t.includeHidden):M(t.directoryPath,!!t.includeHidden)}function p(t,e=process.platform){const r=e==="win32"?a.win32:a.posix,n=r.normalize(t),o=r.parse(n).root,s=n.length>o.length?n.replace(/[\\/]+$/,""):n;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function F(){const t=m.realpathSync(S.homedir()),e=[{id:"home",label:"用户目录",path:t,kind:"home",available:!0}];return t!==a.parse(t).root&&e.push({id:"root",label:"文件系统",path:"/",kind:"root",available:!0}),e}function f(t){if(d?.platform===t&&d.expiresAtMs>Date.now())return d.roots;const e=t==="win32"?R():F();return d={platform:t,roots:e,expiresAtMs:Date.now()+A},e}function R(){const t=m.realpathSync.native(S.homedir()),e=new Map;e.set(p(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(`
2
- `),n=P(_(r));for(const o of n){const s=String(o.Root||"");if(!s)continue;const i=Number(o.DriveType||0),c=String(o.Name||s.replace(/[\\/]+$/,"")),l=String(o.VolumeName||"").trim();e.set(p(s,"win32"),{id:`drive-${c.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:l?`${l} (${c})`:V(c,i),path:s,kind:J(i),available:!0})}}catch{const r=a.win32.parse(t).root;e.set(p(r,"win32"),{id:"drive-system",label:`系统盘 (${r.replace(/\\$/,"")})`,path:r,kind:"fixed",available:!0})}return[...e.values()]}function M(t,e){const r=w(t),o=m.readdirSync(r,{withFileTypes:!0}).filter(i=>i.isDirectory()&&!i.isSymbolicLink()&&(e||!i.name.startsWith("."))),s=o.slice(0,h).map(i=>({name:i.name,path:a.join(r,i.name),kind:"directory",hidden:i.name.startsWith("."),hasChildren:!0}));return s.sort((i,c)=>i.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"})),b(r,s,o.length>h,"linux")}function N(t,e){const r=w(t),n=["$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(`
3
- `),o=P(_(n,{ACA_MACHINE_FS_PATH:r})),s=o.map(i=>{const c=String(i.Attributes||"");return{name:String(i.Name||""),path:String(i.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(c),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(c)}}).filter(i=>i.name&&i.path&&!i.reparsePoint&&(e||!i.hidden)).slice(0,h).sort((i,c)=>i.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"}));return b(r,s,o.length>h,"win32")}function b(t,e,r,n){const o=n==="win32"?a.win32:a.posix,s=o.parse(t).root,i=p(t,n)===p(s,n)?null:o.dirname(t);return{platform:n,path:t,parentPath:i,breadcrumbs:O(t,n),readable:g(t,m.constants.R_OK),writable:g(t,m.constants.W_OK),items:e,truncated:r}}function O(t,e){const r=e==="win32"?a.win32:a.posix,n=r.parse(t),o=t.slice(n.root.length).split(/[\\/]+/).filter(Boolean),s=[{label:n.root.replace(/[\\/]+$/,"")||n.root,path:n.root}];let i=n.root;for(const c of o)i=r.join(i,c),s.push({label:c,path:i});return s}async function L(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),n=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const o=w(String(t.path||""));m.accessSync(o,m.constants.R_OK|m.constants.W_OK);const i=(await u("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(l=>p(l.root_path)===p(o)),c=i||(await u("POST","/api/projects",{projectId:v(),workspaceId:e,name:r,rootPath:o,source:"aica",projectType:n})).item;return C(W(c)),{project:c,duplicate:!!i}}function W(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function w(t){if(!t.trim()||!a.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(z(t),!m.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=m.realpathSync.native(t);return G(r),r}function H(t){if(!t.trim()||!a.isAbsolute(t))throw new Error("项目根目录无效。");const e=m.realpathSync.native(t);if(!m.statSync(e).isDirectory())throw new Error("项目根目录不存在。");return e}function B(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 K(t,e,r){const n=e?a.join(t,...e.split("/")):t,o=m.realpathSync.native(n),s=a.relative(t,o);if(s.startsWith("..")||a.isAbsolute(s))throw new Error("目录超出项目范围。");const i=m.statSync(o);if(r&&!i.isDirectory())throw new Error("请求路径不是目录。");return o}function U(t,e){return a.relative(t,e).split(a.sep).join("/")}function z(t){const e=process.platform==="win32"?a.win32:a.posix;if(!f(process.platform).some(n=>{const o=String(n.path||"");if(!o)return!1;const s=e.relative(o,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function G(t){const e=process.platform==="win32"?a.win32:a.posix;if(!f(process.platform).some(n=>{const o=String(n.path||"");if(!o)return!1;const s=e.relative(o,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function g(t,e){try{return m.accessSync(t,e),!0}catch{return!1}}function _(t,e={}){return j("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 P(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 J(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function V(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{p as comparableMachinePath,T as listMachineDirectory,D as listMachineFilesystemRoots,k as listProjectDirectory,ot as startMachineFilesystemWorkerLoop};
1
+ import{execFileSync as E}from"node:child_process";import{randomUUID as F}from"node:crypto";import u from"node:fs";import j from"node:os";import c from"node:path";import{acaServerRequest as h}from"./aca-server-client.js";import{loadAcaConfig as M,upsertLocalProject as G}from"./aca-config.js";import{startLongPollWorker as L}from"./long-poll-worker.js";const H=25e3,g=300,O=3e4;let y=null;function Pt(t){return L({run:async()=>{const e=M();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await h("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${H}`);if(r.item)try{const o=await W(r.item);await h("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 h("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 W(t){if(t.operation==="filesystem_roots")return tt();if(t.operation==="list_directory")return et({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return at(t.payload);if(t.operation==="list_project_directory")return B(t.payload);if(t.operation==="get_project_git_status")return U(t.payload);if(t.operation==="get_project_git_diff")return z(t.payload);if(t.operation==="get_project_git_log")return K(t.payload);if(t.operation==="get_project_git_commit")return J(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function B(t){const e=w(String(t.rootPath||"")),r=x(String(t.relativePath||"")),o=lt(e,r,!0),n=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),i=u.readdirSync(o,{withFileTypes:!0}).filter(l=>!l.isSymbolicLink()).map(l=>({name:l.name,path:ut(e,c.join(o,l.name)),type:l.isDirectory()?"directory":l.isFile()?"file":"other",hidden:l.name.startsWith("."),extension:l.isFile()?c.extname(l.name).slice(1).toLowerCase():""})).filter(l=>l.type!=="other").sort((l,p)=>l.type!==p.type?l.type==="directory"?-1:1:l.name.localeCompare(p.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 A=500,S=2*1024*1024,d=2*1024*1024;function U(t){const e=w(String(t.rootPath||""));if(!_(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=f(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],S).split("\0").filter(Boolean).slice(0,A),n=o.map(a=>X(a)).filter(a=>!!a),s=b(f(e,["diff","--no-ext-diff","--numstat","HEAD","--","."],S));for(const a of n){const l=s.get(a.path);if(l)a.additions=l.additions,a.deletions=l.deletions;else if(a.status==="untracked"){const p=$(e,a.path);a.additions=p.additions,a.deletions=p.deletions}}const i=q(e);return{isRepository:!0,branch:Z(e),files:n,ahead:i.ahead,behind:i.behind,truncated:o.length>=A}}function z(t){const e=w(String(t.rootPath||"")),r=x(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!_(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=D(e,r),n=Y(e,r),s=n?f(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],d):R(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],d),i=n?b(f(e,["diff","--no-ext-diff","--numstat","HEAD","--",r],32*1024)).get(r):$(e,r);return{isRepository:!0,path:r,diff:N(s),additions:i?.additions??0,deletions:i?.deletions??0,truncated:s.length>d}}function K(t){const e=w(String(t.rootPath||""));if(!_(e))return{isRepository:!1,items:[]};if(!Q(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"],S).split("").map(i=>V(i)).filter(i=>!!i),limit:r}}function J(t){const e=w(String(t.rootPath||"")),r=String(t.commit||"").trim();if(!/^[0-9a-f]{7,64}$/i.test(r))throw new Error("Git 提交标识无效。");if(!_(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],d),n=[...b(f(e,["show","--no-ext-diff","--numstat","--format=",r],S)).values()];return{isRepository:!0,commit:r,diff:N(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>d}}function V(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 X(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 b(t){const e=new Map;for(const r of t.split(/\r?\n/)){const o=r.split(" ");if(o.length<3)continue;const n=/^\d+$/.test(o[0])?Number(o[0]):null,s=/^\d+$/.test(o[1])?Number(o[1]):null,i=x(o.slice(2).join(" "));i&&e.set(i,{additions:n,deletions:s})}return e}function $(t,e){const r=D(t,e),o=R(t,["diff","--no-ext-diff","--no-index","--numstat","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024);return b(o).values().next().value||{additions:null,deletions:null}}function _(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 Y(t,e){try{return f(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function Q(t){try{return f(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function Z(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 q(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 D(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 E("git",["-C",t,...e],{encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function R(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 N(t){return t.length<=d?t:`${t.slice(0,d)}
2
+
3
+ [Diff 内容过大,已截断]`}function tt(){const t=process.platform,e=P(t);return{platform:t,roots:e}}function et(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?it(t.directoryPath,!!t.includeHidden):nt(t.directoryPath,!!t.includeHidden)}function m(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 rt(){const t=u.realpathSync(j.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 P(t){if(y?.platform===t&&y.expiresAtMs>Date.now())return y.roots;const e=t==="win32"?ot():rt();return y={platform:t,roots:e,expiresAtMs:Date.now()+O},e}function ot(){const t=u.realpathSync.native(j.homedir()),e=new Map;e.set(m(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=k(T(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(/[\\/]+$/,"")),l=String(n.VolumeName||"").trim();e.set(m(s,"win32"),{id:`drive-${a.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:l?`${l} (${a})`:pt(a,i),path:s,kind:mt(i),available:!0})}}catch{const r=c.win32.parse(t).root;e.set(m(r,"win32"),{id:"drive-system",label:`系统盘 (${r.replace(/\\$/,"")})`,path:r,kind:"fixed",available:!0})}return[...e.values()]}function nt(t,e){const r=v(t),n=u.readdirSync(r,{withFileTypes:!0}).filter(i=>i.isDirectory()&&!i.isSymbolicLink()&&(e||!i.name.startsWith("."))),s=n.slice(0,g).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"})),C(r,s,n.length>g,"linux")}function it(t,e){const r=v(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=k(T(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,g).sort((i,a)=>i.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"}));return C(r,s,n.length>g,"win32")}function C(t,e,r,o){const n=o==="win32"?c.win32:c.posix,s=n.parse(t).root,i=m(t,o)===m(s,o)?null:n.dirname(t);return{platform:o,path:t,parentPath:i,breadcrumbs:st(t,o),readable:I(t,u.constants.R_OK),writable:I(t,u.constants.W_OK),items:e,truncated:r}}function st(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 at(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=v(String(t.path||""));u.accessSync(n,u.constants.R_OK|u.constants.W_OK);const i=(await h("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(l=>m(l.root_path)===m(n)),a=i||(await h("POST","/api/projects",{projectId:F(),workspaceId:e,name:r,rootPath:n,source:"aica",projectType:o})).item;return G(ct(a)),{project:a,duplicate:!!i}}function ct(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function v(t){if(!t.trim()||!c.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(ft(t),!u.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=u.realpathSync.native(t);return dt(r),r}function w(t){if(!t.trim()||!c.isAbsolute(t))throw new Error("项目根目录无效。");const e=u.realpathSync.native(t);if(!u.statSync(e).isDirectory())throw new Error("项目根目录不存在。");return e}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 lt(t,e,r){const o=e?c.join(t,...e.split("/")):t,n=u.realpathSync.native(o),s=c.relative(t,n);if(s.startsWith("..")||c.isAbsolute(s))throw new Error("目录超出项目范围。");const i=u.statSync(n);if(r&&!i.isDirectory())throw new Error("请求路径不是目录。");return n}function ut(t,e){return c.relative(t,e).split(c.sep).join("/")}function ft(t){const e=process.platform==="win32"?c.win32:c.posix;if(!P(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 dt(t){const e=process.platform==="win32"?c.win32:c.posix;if(!P(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 I(t,e){try{return u.accessSync(t,e),!0}catch{return!1}}function T(t,e={}){return E("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 k(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 mt(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function pt(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{m as comparableMachinePath,J as getProjectGitCommit,z as getProjectGitDiff,K as getProjectGitLog,U as getProjectGitStatus,et as listMachineDirectory,tt as listMachineFilesystemRoots,B as listProjectDirectory,Pt as startMachineFilesystemWorkerLoop};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{Command as a}from"commander";import n from"node:path";import{createStartCommand as m}from"./commands/start.js";import{createWorkerAuthCommand as t}from"./commands/worker-auth.js";import{createWorkerProjectCommand as s}from"./commands/worker-project.js";import{DEFAULT_ACA_SERVER_URL as c}from"./core/aca-config.js";process.env.ACA_DEFAULT_SERVER_URL||=c;async function i(r=process.argv){const o=new a;o.name("aica").description("AICA remote Agent worker").version("0.1.4").enablePositionalOptions(),o.addCommand(m()),o.addCommand(t()),o.addCommand(s()),await o.parseAsync(r)}const d=process.argv[1]||"",e=n.basename(d).replace(/\.(?:js|ts|cjs|mjs)$/i,"");(e==="worker-cli"||e==="aica"||e==="aca")&&i().catch(r=>{const o=r instanceof Error?r.message:String(r);console.error(o),process.exitCode=1});export{i as runWorkerCli};
2
+ import{Command as a}from"commander";import n from"node:path";import{createStartCommand as m}from"./commands/start.js";import{createWorkerAuthCommand as t}from"./commands/worker-auth.js";import{createWorkerProjectCommand as s}from"./commands/worker-project.js";import{DEFAULT_ACA_SERVER_URL as c}from"./core/aca-config.js";process.env.ACA_DEFAULT_SERVER_URL||=c;async function i(r=process.argv){const o=new a;o.name("aica").description("AICA remote Agent worker").version("0.1.6").enablePositionalOptions(),o.addCommand(m()),o.addCommand(t()),o.addCommand(s()),await o.parseAsync(r)}const d=process.argv[1]||"",e=n.basename(d).replace(/\.(?:js|ts|cjs|mjs)$/i,"");(e==="worker-cli"||e==="aica"||e==="aca")&&i().catch(r=>{const o=r instanceof Error?r.message:String(r);console.error(o),process.exitCode=1});export{i as runWorkerCli};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",