@yuandc/aica 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/acp/agent.js CHANGED
@@ -1 +1 @@
1
- import s from"node:fs";import{createAgentProvider as r}from"./providers/registry.js";async function a(e){if(!s.existsSync(e.cwd)||!s.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const o=await r({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId??null,timeoutMs:e.timeoutMs});try{const t=await o.sendPrompt({...e,providerSessionId:e.acpSessionId??null});return{...t,acpSessionId:t.providerSessionId}}finally{await o.close().catch(()=>{})}}async function d(e){const o=await r({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId,timeoutMs:e.timeoutMs});if(!o.compactContext)throw await o.close().catch(()=>{}),new Error(`Provider does not support context compaction: ${e.agentType||"codex"}`);try{const t=await o.compactContext(e);return{...t,acpSessionId:t.providerSessionId}}finally{await o.close().catch(()=>{})}}export{d as compactAgentContext,a as sendAgentPrompt};
1
+ import r from"node:fs";import{createAgentProvider as t}from"./providers/registry.js";async function a(e){if(!r.existsSync(e.cwd)||!r.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);if(e.requireSessionResume&&!e.acpSessionId)throw new Error("导入的历史 Session 缺少 Provider Session ID,禁止创建新的会话。");const o=await t({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId??null,timeoutMs:e.timeoutMs});try{const s=await o.sendPrompt({...e,providerSessionId:e.acpSessionId??null});return{...s,acpSessionId:s.providerSessionId}}finally{await o.close().catch(()=>{})}}async function d(e){const o=await t({agentType:e.agentType||"codex",cliType:e.cliType||"builtin"}).createSession({cwd:e.cwd,providerSessionId:e.acpSessionId,timeoutMs:e.timeoutMs});if(!o.compactContext)throw await o.close().catch(()=>{}),new Error(`Provider does not support context compaction: ${e.agentType||"codex"}`);try{const s=await o.compactContext(e);return{...s,acpSessionId:s.providerSessionId}}finally{await o.close().catch(()=>{})}}export{d as compactAgentContext,a as sendAgentPrompt};
@@ -1 +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:(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
+ 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:(n,r)=>this.handleNotification(n,r),onRequest:(n,r)=>this.handleReverseRequest(n,r)})}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 n=await this.establishThread(e);this.emitStatus("thinking","思考中"),this.content="",this.updates.length=0,this.agentMessagePhases.clear(),this.promptActive=!0;let r,a;try{r=await this.rpc.request("turn/start",{threadId:n,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(r?.turn?.id??"");a=o?await this.waitForTurnCompleted(o,e.timeoutMs??this.defaultTimeoutMs):r?.turn}finally{this.promptActive=!1}const l=this.content.trim()||p(a);return this.emitStatus("completed","已完成"),{providerSessionId:n,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:r}}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 r=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(r?.thread?.id??this.providerSessionId),this.providerSessionId}catch(r){if(e.requireSessionResume){const a=r instanceof Error?r.message:String(r);throw new Error(`无法恢复导入的 Codex Session ${this.providerSessionId}:${a}`)}this.providerSessionId=null}this.emitStatus("acp","Codex 启动中","thread/start");const n=(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(!n)throw new Error("Codex app-server thread/start did not return thread id");return this.providerSessionId=n,n}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,n,r,a)=>this.emitStatus(t,n,r,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 n=this.agentMessagePhases.get(t.itemId);(n==="final_answer"||!n)&&(this.content+=t.delta)}waitForTurnCompleted(e,s){const t=this.completedTurns.get(e);return t?Promise.resolve(t):new Promise((n,r)=>{const a=setTimeout(()=>{this.pendingTurnCompletions.delete(e),r(new Error("Codex app-server request timed out while waiting for turn/completed"))},s);a.unref(),this.pendingTurnCompletions.set(e,{resolve:n,reject:r,timer:a})})}resolveTurnCompleted(e){const s=e?.turn,t=s?.id;if(!t)return;this.completedTurns.set(t,s);const n=this.pendingTurnCompletions.get(t);if(n){if(this.pendingTurnCompletions.delete(t),clearTimeout(n.timer),s.status==="failed"){n.reject(new Error(`Codex turn failed: ${JSON.stringify(s.error??{})}`));return}n.resolve(s)}}async handleReverseRequest(e,s){return f(e)?(this.emitStatus("requestPermission","等待授权",S(s),e),g(e,s,this.permissionCallback)):{}}emitStatus(e,s,t,n){const r={phase:e,label:s,...t?{detail:t}:{},...n?{updateType:n}:{},atMs:Date.now()},a=this.statusTimeline[this.statusTimeline.length-1];a&&a.phase===r.phase&&a.label===r.label&&a.detail===r.detail&&a.updateType===r.updateType||(this.statusTimeline.push(r),this.statusCallback?.(r))}}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 S(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 y(t)}}function y(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};
@@ -0,0 +1,7 @@
1
+ import h from"node:fs";import{closeAcpProcess as C}from"../../client/acp-process.js";import{JsonLineRpcClient as k}from"../../client/json-rpc.js";import{createPlanEvent as _,normalizePlanSessionUpdate as b}from"../../plan-events.js";import{startCodexAppServer as E}from"./codex-process.js";import{codexAcpSessionUpdatesFromNotification as $}from"./events.js";const A=6e4,D=128*1024,L=2*1024*1024,j=5*1024*1024;async function X(t){const e=t.sessionId.trim();if(!e)throw new Error("Codex Session ID 不能为空。");const n=Math.max(1,Math.min(20,Math.trunc(t.turnLimit))),r=E(process.cwd()),o=new k(r.child,{peerName:"Codex app-server"});try{await o.request("initialize",{clientInfo:{name:"aica-session-import",version:"0.1.0"},capabilities:{experimentalApi:!0,requestAttestation:!1}},A);const s=p(await o.request("thread/read",{threadId:e,includeTurns:!1},A))||{},a=p(s.thread);if(!a||i(a.id)!==e)throw new Error(`找不到 Codex Session:${e}`);const d=i(a.cwd);if(!d||!h.existsSync(d)||!h.statSync(d).isDirectory())throw new Error(`Codex Session 的工作目录不存在:${d||"unknown"}`);const u=t.detailMode==="diagnostic"?"full":"summary",f=p(await o.request("thread/turns/list",{threadId:e,limit:n,sortDirection:"desc",itemsView:u},A))||{};return R({thread:a,turns:Array.isArray(f.data)?f.data:[]},{...t,sessionId:e,turnLimit:n})}finally{await C(r.child).catch(()=>{})}}function R(t,e){const n=p(t.thread)||{},r=e.sessionId.trim(),o=Math.max(1,Math.min(20,Math.trunc(e.turnLimit))),s=i(n.cwd);if(!s||!h.existsSync(s)||!h.statSync(s).isDirectory())throw new Error(`Codex Session 的工作目录不存在:${s||"unknown"}`);const a=t.turns.map(p).filter(g).slice(0,o).reverse(),d=V(e.detailMode==="diagnostic"?j:L),u=a.map(c=>({sourceTurn:c,importedTurn:B(c,d)})).filter(c=>!!c.importedTurn);if(e.detailMode==="diagnostic")for(const{sourceTurn:c,importedTurn:w}of u){const M=(Array.isArray(c.items)?c.items:[]).map(p).filter(g);w.events=M.flatMap((S,I)=>N(S,w.startedAtMs+I,e.diffEnabled,d))}const f=u.map(c=>c.importedTurn),m=i(n.preview);return{provider:"codex",providerSessionId:r,cwd:h.realpathSync(s),title:l(i(n.name)||m||"Codex 历史会话",120),preview:l(m,240),sourceCreatedAtMs:y(n.createdAt),sourceUpdatedAtMs:y(n.updatedAt),sourceCliVersion:l(i(n.cliVersion),80),detailMode:e.detailMode,turnLimit:o,turns:f,truncated:d.truncated}}function B(t,e){const n=i(t.id);if(!n)return null;const r=(Array.isArray(t.items)?t.items:[]).map(p).filter(g),o=e.takeText(r.filter(u=>u.type==="userMessage").map(U).filter(Boolean).join(`
2
+
3
+ `)),s=e.takeText(r.filter(u=>u.type==="agentMessage"&&(!u.phase||u.phase==="final_answer")).map(u=>i(u.text)).filter(Boolean).join(`
4
+
5
+ `)),a=y(t.startedAt)||Date.now(),d=y(t.completedAt)||a;return!o&&!s?null:{sourceTurnId:n,status:l(i(t.status)||"completed",40),startedAtMs:a,completedAtMs:Math.max(a,d),userText:o,assistantText:s,events:[]}}function N(t,e,n,r){const o=i(t.type),s=i(t.id);if(o==="reasoning"){const f=r.takeText(P(t.summary).join(`
6
+ `));return f?r.takeEvent({eventType:"agent_thought_chunk",label:"thought",text:f,raw:{method:"history/item",params:{itemId:s},update:{sessionUpdate:"agent_thought_chunk",content:{type:"text",text:f}}},atMs:e}):[]}if(o==="plan"){const f=r.takeText(i(t.text)),m=b({sessionUpdate:"plan",planId:s,markdown:f});if(!m)return[];const c=_({update:m,method:"history/item",params:{itemId:s},atMs:e});return r.takeEvent({eventType:c.type,label:c.label,...c.text?{text:c.text}:{},...c.status?{status:c.status}:{},...c.toolCallId?{toolCallId:c.toolCallId}:{},raw:c.raw,atMs:c.atMs})}if(["userMessage","agentMessage","hookPrompt"].includes(o))return[];const a=q(t,n),d=$("item/completed",{item:a})[0];if(!d)return[];const u=i(d.status)||O(i(t.status));return r.takeEvent({eventType:"tool_call_update",label:z(o,a),...u?{status:u}:{},...s?{toolCallId:s}:{},raw:{method:"history/item",params:{item:a},update:d},atMs:e})}function U(t){return(Array.isArray(t.content)?t.content:[]).map(n=>{const r=p(n);return r?r.type==="text"?i(r.text):r.type==="localImage"?`[历史图片:${i(r.path)||"本地文件未导入"}]`:r.type==="image"?"[历史图片:远程内容未导入]":r.type==="skill"?`[Skill:${i(r.name)||i(r.path)}]`:r.type==="mention"?`[引用:${i(r.name)||i(r.path)}]`:"[历史内容未导入]":""}).filter(Boolean).join(`
7
+ `)}function q(t,e){const n=x(t,65536);return!e&&n.type==="fileChange"&&Array.isArray(n.changes)&&(n.changes=n.changes.map(r=>{const o=p(r);return o?{path:o.path,kind:o.kind,diff:""}:r})),n}function z(t,e){return t==="commandExecution"?l(i(e.command)||"执行命令",160):t==="fileChange"?"文件修改":t==="webSearch"?l(i(e.query)?`Web Search: ${i(e.query)}`:"Web Search",160):t==="mcpToolCall"?l(`MCP: ${i(e.server)}.${i(e.tool)}`,160):t==="dynamicToolCall"?l(i(e.tool)||"工具调用",160):t==="imageView"?l(`查看图片:${i(e.path)}`,160):t==="imageGeneration"?"生成图片":l(t||"过程记录",160)}function O(t){const e=t.toLowerCase();return["completed","success","succeeded"].includes(e)?"completed":["failed","error","declined"].includes(e)?"failed":["cancelled","canceled"].includes(e)?"cancelled":e||"completed"}function V(t){let e=t,n=0;const r={truncated:!1,takeText(o){const s=l(o,D);if(s.length<o.length&&(r.truncated=!0),e<=0)return s&&(r.truncated=!0),"";const a=s.slice(0,e);return a.length<s.length&&(r.truncated=!0),e-=a.length,a},takeEvent(o){if(n>=300)return r.truncated=!0,[];const s=JSON.stringify(o).length;return s>e?(r.truncated=!0,[]):(e-=s,n+=1,[o])}};return r}function x(t,e,n=0){if(!t||typeof t!="object"||Array.isArray(t))return{};const r={};for(const[o,s]of Object.entries(t))typeof s=="string"?r[o]=l(s,e):Array.isArray(s)?r[o]=s.slice(0,100).map(a=>T(a,e,n+1)):r[o]=T(s,e,n+1);return r}function T(t,e,n){return n>8?"[内容层级过深,已截断]":typeof t=="string"?l(t,e):Array.isArray(t)?t.slice(0,100).map(r=>T(r,e,n+1)):t&&typeof t=="object"?x(t,e,n):t}function p(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:null}function g(t){return!!t}function i(t){return typeof t=="string"?t.trim():""}function P(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"&&!!e.trim()):[]}function y(t){const e=Number(t);return Number.isFinite(e)&&e>0?Math.trunc(e*1e3):0}function l(t,e){return t.length<=e?t:t.slice(0,e)}export{R as buildCodexSessionImport,X as extractCodexSession};
@@ -1 +1 @@
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
+ import m from"node:fs";import{promptBlocksToAcpContent as b}from"../../client/acp-content.js";import{eventFromAcpSessionUpdate as y,statusFromAcpSessionUpdate as C}from"../../client/acp-events.js";import{defaultAcpRuntimePool as I}from"../../client/acp-runtime-pool.js";import{resolveCodexAcpLaunch as v}from"./launch.js";import{CodexPromptPerformanceTracker as A,readCodexContextMaintenancePolicy as x}from"./context-maintenance.js";const P={sessionResume:!0,imageInput:!0,fileAttachment:!0,filesystem:!0,terminal:!0,permissionRequest:!0,configOptions:!0,usage:!0,contextUsage:!0,contextCompaction:!0,plan:!0,diff:!0};class F{id="codex-acp";name="Codex ACP";capabilities=P;async createSession(e){return new k(e.cwd,e.providerSessionId??null,e.timeoutMs)}}class k{cwd;providerSessionId;defaultTimeoutMs;lease=null;sessionResponse=null;statusCallback=null;updateCallback=null;permissionCallback=null;userInputCallback=null;abortHandler=null;statusTimeline=[];updates=[];content="";performanceTracker=null;constructor(e,s,t=q()){this.cwd=e,this.providerSessionId=s,this.defaultTimeoutMs=t}async sendPrompt(e){if(!m.existsSync(e.cwd)||!m.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.permissionCallback=e.onPermissionRequest??null,this.userInputCallback=e.onUserInputRequest??null,this.attachAbortSignal(e.signal),this.content="",this.updates.length=0,this.statusTimeline.length=0,this.performanceTracker=new A(s);let t=null,r=null,n=this.providerSessionId,i,c=null;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const a=await this.acquireRuntime(e.cwd);this.lease=a,t=a.client,r=a.started,await this.initialize(a),n=await this.establishSession(a,e),await this.applyConfig(t,n,e),this.emitStatus("thinking","思考中"),c=this.startSlowStatusTimer(),i=await this.promptWithAbort(t,{sessionId:n,prompt:b(e.prompt,e.promptBlocks),timeoutMs:e.timeoutMs??this.defaultTimeoutMs,signal:e.signal});const d=w(i);d&&d!==n&&(n=d,this.providerSessionId=d,a.setProviderSession({providerSessionId:d,sessionResponse:this.sessionResponse}))}finally{c&&clearInterval(c),this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}return this.emitStatus("completed","已完成"),{providerSessionId:n,cliType:"builtin",agentType:"codex",effectiveConfig:{model:e.model??null,mode:e.mode??null,configOptionValues:e.configOptionValues??null,command:r.command,processPid:r.child.pid??null,provider:"codex-acp",protocol:"acp"},command:r.command,args:r.args,cwd:e.cwd,exitCode:r.child.exitCode,signal:r.child.signalCode,durationMs:Date.now()-s,stdout:t.rpc.stdout,stderr:t.rpc.stderr,content:this.content.trim(),updates:[...this.updates],statusTimeline:[...this.statusTimeline],performance:this.performanceTracker?.snapshot(),contextUsage:O(i),promptResponse:i}}async compactContext(e){if(!m.existsSync(e.cwd)||!m.statSync(e.cwd).isDirectory())throw new Error(`Project root does not exist or is not a directory: ${e.cwd}`);const s=Date.now();this.statusCallback=e.onStatus??null,this.updateCallback=e.onUpdate??null,this.attachAbortSignal(e.signal);let t=this.providerSessionId,r;try{this.emitStatus("initializing","Codex ACP 启动中","codex-acp");const i=await this.acquireRuntime(e.cwd);this.lease=i,await this.initialize(i),t=await this.establishSession(i,e),await this.applyConfig(i.client,t,e);const c=E(e.timeoutMs);r=await this.compactWithAbort(i.client,{sessionId:t,allowRollover:e.allowRollover===!0,timeoutMs:c,signal:e.signal});const a=w(r);a&&a!==t&&(t=a,this.providerSessionId=a,i.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}))}catch(i){if(this.lease&&T(i,e.signal)){const c=this.lease;this.lease=null,await c.dispose().catch(()=>{})}throw this.emitStatus("failed","上下文压缩失败",i instanceof Error?i.message:String(i)),i}finally{this.abortHandler&&e.signal&&(e.signal.removeEventListener("abort",this.abortHandler),this.abortHandler=null),this.releaseLease()}const n=l(r)??{};return{providerSessionId:t||this.providerSessionId||"",contextUsage:S(n.contextUsage),maintenance:l(n.maintenance)??{},durationMs:Date.now()-s}}async cancel(){this.providerSessionId&&this.lease?.client.cancel(this.providerSessionId)}async close(){this.statusCallback=null,this.updateCallback=null,this.permissionCallback=null,this.userInputCallback=null,this.abortHandler&&(this.abortHandler=null),this.releaseLease()}async acquireRuntime(e){const s=v();return I.acquire({providerId:"codex-acp",cwd:e,providerSessionId:this.providerSessionId,command:s.command,args:s.args,onSessionUpdate:t=>this.handleSessionUpdate(t),onClientRequest:async(t,r)=>{if(t==="session/request_permission")return this.requestPermission(r);if(t==="elicitation/create"||t==="session/request_user_input")return this.requestUserInput(r);throw new Error(`Unsupported Codex ACP client request: ${t}`)}})}async initialize(e){e.initialized||(await e.client.initialize(6e4),e.markInitialized())}async establishSession(e,s){const t=e.client,r=M(s);if(e.providerSessionId&&e.sessionEstablished)return this.providerSessionId=e.providerSessionId,this.sessionResponse=e.sessionResponse,e.providerSessionId;if(this.providerSessionId)try{this.emitStatus("resuming","Codex ACP 会话恢复中","session/load");const c=await t.loadSession({sessionId:this.providerSessionId,cwd:s.cwd,config:r},6e4);this.sessionResponse=l(c);const a=f(c)||this.providerSessionId;return this.providerSessionId=a,e.setProviderSession({providerSessionId:a,sessionResponse:this.sessionResponse}),a}catch(c){if(s.requireSessionResume){const a=c instanceof Error?c.message:String(c);throw new Error(`无法恢复导入的 Codex ACP Session ${this.providerSessionId}:${a}`)}this.providerSessionId=null}this.emitStatus("acp","Codex ACP 会话创建中","session/new");const n=await t.newSession({cwd:s.cwd,config:r},12e4);this.sessionResponse=l(n);const i=f(n);if(!i)throw new Error("Codex ACP session/new did not return sessionId");return this.providerSessionId=i,e.setProviderSession({providerSessionId:i,sessionResponse:this.sessionResponse}),i}async applyConfig(e,s,t){t.model&&await e.setSessionConfigOption({sessionId:s,configId:"model",value:t.model},6e4).catch(()=>{});const r=h(t.mode);r&&await e.setSessionConfigOption({sessionId:s,configId:"approvalPolicy",value:r},6e4).catch(()=>{});const n=p(t.mode);n&&await e.setSessionConfigOption({sessionId:s,configId:"sandbox",value:n},6e4).catch(()=>{});for(const[i,c]of Object.entries(t.configOptionValues??{}))["model","mode","sandbox","approvalPolicy"].includes(i)||await e.setSessionConfigOption({sessionId:s,configId:i,value:c},6e4).catch(()=>{})}handleSessionUpdate(e){this.performanceTracker?.recordEvent(),this.updates.push({method:"session/update",params:e});const s=y(e);s&&(s.type==="agent_message_chunk"&&(this.content+=s.text??""),this.updateCallback?.(s));const t=C(e);t&&this.emitStatus(t.phase,t.label,t.detail,t.updateType)}startSlowStatusTimer(){const e=x().slowEventThresholdMs,s=setInterval(()=>{const t=this.performanceTracker,r=Date.now();if(!t?.shouldReportSlow(r,e))return;const n=t.snapshot(r),i=Math.max(1,Math.round(n.silentForMs/6e4));this.emitStatus("thinking","模型长时间处理中",`已 ${i} 分钟没有收到新的 ACP 事件`,"aca.performance.slow")},Math.min(3e4,Math.max(1e3,Math.floor(e/4))));return s.unref(),s}attachAbortSignal(e){if(e){if(this.abortHandler=()=>{this.cancel()},e.aborted)throw new Error("Codex ACP prompt cancelled");e.addEventListener("abort",this.abortHandler,{once:!0})}}async promptWithAbort(e,s){const t=e.prompt({sessionId:s.sessionId,prompt:s.prompt},s.timeoutMs);if(!s.signal)return t;if(s.signal.aborted)throw await this.lease?.dispose().catch(()=>{}),new Error("Codex ACP prompt cancelled");let r=null;const n=new Promise((i,c)=>{r=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP prompt cancelled"))},s.signal?.addEventListener("abort",r,{once:!0})});try{return await Promise.race([t,n])}finally{r&&s.signal.removeEventListener("abort",r)}}async compactWithAbort(e,s){const t=e.compactSession({sessionId:s.sessionId,allowRollover:s.allowRollover,timeoutMs:s.timeoutMs},s.timeoutMs);if(!s.signal)return t;if(s.signal.aborted)throw await this.lease?.dispose().catch(()=>{}),new Error("Codex ACP 上下文压缩已取消");let r=null;const n=new Promise((i,c)=>{r=()=>{e.cancel(s.sessionId),this.lease?.dispose().catch(()=>{}),c(new Error("Codex ACP 上下文压缩已取消"))},s.signal?.addEventListener("abort",r,{once:!0})});try{return await Promise.race([t,n])}finally{r&&s.signal.removeEventListener("abort",r)}}async requestPermission(e){if(!this.permissionCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s,n=(Array.isArray(t.options)?t.options:[]).map((i,c)=>{const a=i&&typeof i=="object"&&!Array.isArray(i)?i:{};return{optionId:String(a.optionId??a.id??c),kind:String(a.kind??"choice"),...typeof a.label=="string"?{label:a.label}:{}}});return this.emitStatus("requestPermission","等待授权",R(t),"session/request_permission"),this.permissionCallback({requestId:String(t.requestId??t.id??`codex-acp-permission-${Date.now()}`),params:e,options:n})}async requestUserInput(e){if(!this.userInputCallback)return{outcome:{outcome:"cancelled"}};const s=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=s.request&&typeof s.request=="object"&&!Array.isArray(s.request)?s.request:s;return this.emitStatus("requestPermission","等待输入",_(t),"elicitation/create"),this.userInputCallback({requestId:String(t.requestId??t.id??`codex-acp-input-${Date.now()}`),prompt:String(t.prompt??t.message??t.question??""),params:e,...typeof t.defaultValue=="string"?{defaultValue:t.defaultValue}:{}})}emitStatus(e,s,t,r){const n={phase:e,label:s,...t?{detail:t}:{},...r?{updateType:r}:{},atMs:Date.now()},i=this.statusTimeline[this.statusTimeline.length-1];i&&i.phase===n.phase&&i.label===n.label&&i.detail===n.detail&&i.updateType===n.updateType||(this.statusTimeline.push(n),this.statusCallback?.(n))}releaseLease(){this.lease?.release(),this.lease=null}}function T(o,e){if(e?.aborted)return!0;const s=o instanceof Error?o.message:String(o||"");return/compact.*timed out|request timed out.*compact|adapter closed|aborted|cancelled/i.test(s)}function f(o){if(!o||typeof o!="object"||Array.isArray(o))return null;const e=o.sessionId;return typeof e=="string"&&e.trim()?e.trim():null}function l(o){return o&&typeof o=="object"&&!Array.isArray(o)?o:null}function p(o){const e=String(o||"").trim();return e?e==="read-only"?"read-only":["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"danger-full-access":"workspace-write":null}function h(o){const e=String(o||"").trim();return e?["agent-full-access","full-access","bypassPermissions","danger-full-access"].includes(e)?"never":e==="acceptEdits"||e==="accept-edits"?"on-failure":"on-request":null}function M(o){return{...o.model?{model:o.model}:{},...h(o.mode)?{approvalPolicy:h(o.mode)}:{},...p(o.mode)?{sandbox:p(o.mode)}:{},...o.configOptionValues??{}}}function R(o){const e=o.params&&typeof o.params=="object"&&!Array.isArray(o.params)?o.params:o;for(const s of["command","cwd","reason","grantRoot","method"]){const t=e[s];if(typeof t=="string"&&t.trim())return g(t)}}function _(o){for(const e of["prompt","message","question","title"]){const s=o[e];if(typeof s=="string"&&s.trim())return g(s)}}function g(o){const e=o.replace(/\s+/g," ").trim();return e.length>120?`${e.slice(0,117)}...`:e}function q(){const o=Number.parseInt(process.env.ACA_CODEX_ACP_PROMPT_TIMEOUT_MS??process.env.ACA_ACP_PROMPT_TIMEOUT_MS??"",10);return Number.isInteger(o)&&o>=3e4?o:360*60*1e3}function E(o){const e=Number.isInteger(o)?Number(o):Number.parseInt(process.env.ACA_CODEX_ACP_COMPACT_TIMEOUT_MS??"",10);return Number.isFinite(e)&&e>=3e4?Math.min(e,6e5):12e4}function w(o){if(!o||typeof o!="object"||Array.isArray(o))return null;const e=o;return typeof e.sessionId=="string"&&e.sessionId.trim()?e.sessionId:null}function O(o){const e=l(o),s=l(e?._meta);return S(s?.acaContextUsage)}function S(o){const e=l(o);if(!e)return null;const s=u(e.contextWindow),t=u(e.usedTokens),r=u(e.inputTokens),n=String(e.state||"unknown"),i=["active","compacted","new_thread"].includes(n)?n:"unknown";return{usedTokens:t,inputTokens:r,contextWindow:s,ratio:s>0?Math.max(0,u(e.ratio)||t/s):0,observedAtMs:u(e.observedAtMs)||Date.now(),state:i,maintenanceAction:typeof e.maintenanceAction=="string"?e.maintenanceAction:null}}function u(o){return typeof o=="number"&&Number.isFinite(o)&&o>=0?o:0}export{F as CodexAcpProvider,P as codexAcpCapabilities};
@@ -0,0 +1,8 @@
1
+ import{Command as I}from"commander";import C from"node:crypto";import h from"node:fs";import P from"node:os";import f from"node:path";import x from"node:readline/promises";import{stdin as S,stdout as c}from"node:process";import{extractCodexSession as _}from"../acp/providers/codex/session-import.js";import{acaServerRequest as s}from"../core/aca-server-client.js";import{loadAcaConfig as l,upsertLocalProject as E}from"../core/aca-config.js";import{applyRuntimePathOptions as T}from"../core/runtime-options.js";function Z(){return new I("codex").description("管理本机 Codex 会话").addCommand(new I("import").description("将本机 Codex Session 导入 ACA Project").argument("<session-id>","Codex Session ID").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--path <path>","项目目录,支持相对路径;默认使用当前目录").option("--workspace <id>","新建 Project 时使用的 Workspace ID").option("--project-name <name>","自动创建 Project 时使用的名称").option("--turns <count>","导入最近多少个 Codex Turn,范围 1-20","20").option("--detail <mode>","详情模式:auto、compact、standard 或 diagnostic","auto").option("--title <name>","导入后的 ACA Session 标题").option("--dry-run","只读取和校验,不写入 ACA Server").option("-y, --yes","跳过交互确认,适用于脚本或非交互环境").action(b))}async function b(t,e){T(e);const o=l();if(!o.token)throw new Error("Worker 尚未登录,请先执行 aica login。");await R();const r=await N(o.machineId,t);if(r){console.log(`Codex Session 已存在:session=${r.sessionId} project=${r.projectId} title=${r.title||"未命名"}`);return}const i=k(e.path||process.cwd()),d=q(e.turns),p=await v(),a=D(e.detail,p),n=await _({sessionId:t,turnLimit:d,detailMode:a,diffEnabled:a==="diagnostic"&&p.diffEnabled===!0});M(i,n.cwd);const m=await W({targetPath:i,workspaceId:e.workspace,projectName:e.projectName,machineId:o.machineId}),g=e.title?.trim()||n.title;if(e.dryRun){console.log(JSON.stringify({dryRun:!0,action:m.action,projectId:m.project.project_id,projectName:m.project.name,providerSessionId:n.providerSessionId,path:i,detailMode:a,turns:n.turns.length,truncated:n.truncated,title:g},null,2));return}if(!e.yes&&!await G({sessionId:n.providerSessionId,targetPath:i,plan:m,turnCount:n.turns.length,detailMode:a})){console.log("已取消导入。");return}const u=await A(m);await L();const j=await s("POST","/api/codex-session-imports",{projectId:u.project_id,workspaceId:u.workspace_id,machineId:o.machineId,title:g,import:n}),$=j.item;console.log(`${j.imported?"已导入":"已存在"} session=${String($.session_id||"")} project=${u.project_id} turns=${n.turns.length} mode=${a}`)}async function N(t,e){const o=new URLSearchParams({machineId:t,providerSessionId:e.trim()});try{const r=await s("GET",`/api/codex-session-imports/status?${o.toString()}`);return r.exists?r.item:null}catch(r){const i=r instanceof Error?r.message:String(r);if(/\b404\b/.test(i))return null;throw r}}async function L(){const t=l();await s("POST","/api/heartbeat",{machineId:t.machineId,machineName:t.machineName,workspaceId:t.defaultWorkspaceId,projects:t.projects.map(e=>({projectId:e.projectId,workspaceId:e.workspaceId,name:e.name,rootPath:e.rootPath}))})}async function R(){try{await s("GET","/api/auth/me")}catch(t){const e=t instanceof Error?t.message:String(t);throw/\b401\b|unauthorized/i.test(e)?new Error("Worker 登录已失效,请先执行 aica login 重新登录。"):t}}async function v(){try{return(await s("GET","/api/process-details/capabilities")).item||{}}catch{return{}}}function D(t,e){const o=String(t||"auto").trim().toLowerCase();if(o==="auto")return e.mode==="diagnostic"?"diagnostic":e.mode==="compact"?"compact":"standard";if(o==="compact"||o==="standard"||o==="diagnostic")return o;throw new Error("--detail 必须是 auto、compact、standard 或 diagnostic。")}async function W(t){const e=l(),o=e.projects.find(a=>t.workspaceId&&a.workspaceId!==t.workspaceId?!1:w(a.rootPath)===t.targetPath),r=t.workspaceId||o?.workspaceId||e.defaultWorkspaceId,i=await s("GET",`/api/projects?workspaceId=${encodeURIComponent(r)}`);if(o){const a=i.items.find(n=>n.project_id===o.projectId&&w(n.root_path)===t.targetPath);if(a)return{action:"reuse",project:a}}const d=i.items.find(a=>w(a.root_path)===t.targetPath);if(d)return{action:"attach",project:d};const p=t.projectName?.trim()||o?.name||f.basename(t.targetPath);return{action:"create",project:{project_id:o?.projectId||O(r,t.machineId,t.targetPath,p),workspace_id:r,name:p,root_path:t.targetPath}}}async function A(t){if(t.action==="reuse")return t.project;if(t.action==="attach")return y(t.project),t.project;const e=await s("POST","/api/projects",{projectId:t.project.project_id,workspaceId:t.project.workspace_id,name:t.project.name,rootPath:t.project.root_path,source:"aica-codex-import",projectType:"project"});return y(e.item),e.item}function y(t){E({projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path})}function M(t,e){const o=h.realpathSync(e);if(t!==o)throw new Error(`指定目录与 Codex Session 工作目录不一致:path=${t} session=${o}`)}function k(t){const e=t==="~"?P.homedir():t.startsWith("~/")?f.join(P.homedir(),t.slice(2)):t,o=f.resolve(e);if(!h.existsSync(o)||!h.statSync(o).isDirectory())throw new Error(`Project 工作目录不存在:${o}`);return h.realpathSync(o)}function w(t){try{return k(t)}catch{return null}}function O(t,e,o,r){const i=r.toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"project",d=C.createHash("sha256").update(`${t}\0${e}\0${o}`).digest("hex").slice(0,12);return`aica-${i}-${d}`}async function G(t){if(!S.isTTY||!c.isTTY)throw new Error("当前为非交互环境,请确认参数无误后添加 --yes 执行导入。");const e=t.plan.action==="reuse"?`在已有 Project「${t.plan.project.name}」中创建 Session`:t.plan.action==="attach"?`将目录关联到已有 Project「${t.plan.project.name}」,再创建 Session`:`创建 Project「${t.plan.project.name}」,再创建 Session`;c.write(`
2
+ 即将导入 Codex Session:
3
+ `),c.write(` 项目路径:${t.targetPath}
4
+ `),c.write(` Session ID:${t.sessionId}
5
+ `),c.write(` 执行动作:${e}
6
+ `),c.write(` 历史范围:最近 ${t.turnCount} 个 Turn
7
+ `),c.write(` 详情模式:${t.detailMode}
8
+ `);const o=x.createInterface({input:S,output:c});try{const r=(await o.question("确认导入?[y/N] ")).trim().toLowerCase();return r==="y"||r==="yes"}finally{o.close()}}function q(t){const e=Number.parseInt(String(t||"20"),10);if(!Number.isInteger(e)||e<1||e>20)throw new Error("--turns 必须是 1 到 20 之间的整数。");return e}export{Z as createWorkerCodexCommand};
@@ -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};
@@ -1,6 +1,6 @@
1
- import W from"node:crypto";import x from"node:fs";import S from"node:path";import{compactAgentContext as V,sendAgentPrompt as q}from"../acp/agent.js";import{acaServerDownload as D,acaServerRequest as b}from"./aca-server-client.js";import{loadAcaConfig as H}from"./aca-config.js";import{prepareLocalWorktree as G}from"./worktree.js";import{getAcaHome as $}from"./paths.js";import{collectAffectedFiles as N,extractAffectedFilePathsFromAcpRaw as K}from"./affected-files.js";import{resolveJobPermissionPolicy as X}from"./job-permission-policy.js";import{appendCoalescedAcpEvent as Z}from"./acp-event-coalescer.js";import{shouldUploadAcpEvent as Q}from"./acp-event-upload-filter.js";const Y=1500,ee=5e3,M=1e3,te=320,ne=64,O=900,oe=1e4,ae=0,ie=12e3;function re(e){return e?e==="~"?S.dirname($()):e.startsWith("~/")?S.join(S.dirname($()),e.slice(2)):e:""}function se(e){const t=e.project_metadata;return t&&typeof t=="object"&&!Array.isArray(t)&&t.kind==="chat"?!0:typeof e.project_root_path=="string"&&(e.project_root_path.startsWith("~/.aca/chats/")||/(^|\/)\.aca\/chats\//.test(e.project_root_path))}function Ve(e,t={}){let n=!1,o=null,a=null;const i=new Set,c=new Set,u=new Map,s=async()=>{if(n)return;const r=ce();if(U(i.size,r))try{const m=t.loadConfig?.()??H();if(!m.token)return;for(;!n&&U(i.size,r);){const A=t.claimNextJob?await t.claimNextJob(m):await b("POST","/api/client/jobs/claim",{machineId:m.machineId,workspaceId:m.defaultWorkspaceId});if(!A.item)break;const d=A.item;if(n){await(t.cancelClaimedJob?t.cancelClaimedJob(d,m):P(d.job_id,m.machineId,"cancelled")).catch(()=>{});break}const f=d.session_id;c.has(f)&&e.warn(`claimed job=${d.job_id} for already active session=${f}; running anyway to avoid leaving it stuck`),i.add(d.job_id),c.add(f);const I=new AbortController,C=(t.runJob??ue)(d,m,e,I).catch(p=>{e.warn(`job ${d.job_id} failed outside handler: ${p instanceof Error?p.message:String(p)}`)}).finally(()=>{i.delete(d.job_id),c.delete(f),u.delete(d.job_id)});u.set(d.job_id,{controller:I,promise:C})}}catch(m){n||e.warn(`job worker failed: ${m instanceof Error?m.message:String(m)}`)}},w=()=>{if(n||o)return;const r=s();o=r,r.finally(()=>{o===r&&(o=null)})};w();const T=setInterval(()=>{w()},t.claimIntervalMs??Y);return{timer:T,stop:()=>a||(a=(async()=>{if(n)return;n=!0,clearInterval(T);for(const m of u.values())m.controller.abort();await o?.catch(()=>{});for(const m of u.values())m.controller.abort();const r=[...u.values()].map(m=>m.promise);r.length!==0&&await Promise.race([Promise.allSettled(r).then(()=>{}),E(ie)])})(),a)}}function ce(){const e=process.env.ACA_MAX_CONCURRENT_JOBS||process.env.ACA_MAX_CONCURRENT_PROJECT_JOBS||"",t=Number.parseInt(e,10);return!e.trim()||!Number.isFinite(t)||t<0?ae:t===0?0:Math.max(1,Math.min(t,8))}function U(e,t){return t===0||e<t}function le(){const e=Number.parseInt(process.env.ACA_ACP_EVENT_BATCH_INTERVAL_MS||"",10);return Number.isFinite(e)?Math.max(40,Math.min(e,2e3)):te}async function ue(e,t,n,o){const a=e.job_id,i=e.session_id,c=e.workspace_id,u=e.project_id??null,s=e.input??{},w=String(s.control?.type||"").toLowerCase();if(!w&&!s.message?.trim()&&(s.attachments??[]).length===0){await P(a,t.machineId,"job input missing message");return}const T=t.projects.find(p=>p.projectId===u),r=re(T?.rootPath||e.project_root_path||"");if(!r){await P(a,t.machineId,"job project root is unknown");return}se(e)&&x.mkdirSync(r,{recursive:!0}),n.info(`claimed job=${a} session=${i} project=${T?.name??u??"unknown"}`);const m=setInterval(()=>{b("POST",`/api/client/jobs/${encodeURIComponent(a)}/heartbeat`,{machineId:t.machineId}).catch(()=>{}),Re(a,o).catch(()=>{})},ee);let A=0;const d=we(a,t.machineId),f=be(a,t.machineId),I=new Set;let C=null;try{await f.sendNow({phase:"initializing",label:"准备工作区",detail:e.worktree_id?"worktree":"project root"}).catch(()=>{});const p=G({projectId:u,sessionId:i,projectRoot:r,worktree:e});C=p,await Pe(a,t.machineId,p);const g=pe(s.acpRun);if(w==="compact"){if(!e.acp_session_id)throw new Error("Current session does not have an ACP context to compact");const l=await V({agentType:k(g.agentType,"codex"),cliType:k(g.cliType,"builtin"),acpSessionId:e.acp_session_id,cwd:p.cwd,model:s.model,mode:s.mode,configOptionValues:s.configOptionValues,timeoutMs:s.timeoutMs,allowRollover:s.control?.allowRollover===!0,signal:o.signal,onStatus:y=>{f.report({phase:y.phase,label:y.label,detail:y.detail,updateType:y.updateType,raw:y})}});await f.flush(),await b("POST",`/api/client/jobs/${encodeURIComponent(a)}/complete`,{machineId:t.machineId,acpSessionId:l.acpSessionId,suppressTurn:!0,result:{ok:!0,control:{type:"compact",allowRollover:s.control?.allowRollover===!0},acpSessionId:l.acpSessionId,durationMs:l.durationMs,usage:l.contextUsage,maintenance:l.maintenance,worktree:R(p)}}),n.info(`completed context compact job=${a}`);return}const _=await ge({cwd:p.cwd,sessionId:i,jobId:a,attachments:s.attachments??[]});_.length>0&&(n.info(`materialized ${_.length} attachment(s) for job=${a}`),await f.sendNow({phase:"initializing",label:"附件已写入本机",detail:_.map(l=>l.relativePath).join(", "),raw:{attachments:z(_)}}).catch(()=>{}));const j=Ie(s,_),F=_e(j,_),h=await q({agentType:k(g.agentType,"codex"),cliType:k(g.cliType,"builtin"),acpSessionId:e.acp_session_id??null,prompt:j,promptBlocks:F,cwd:p.cwd,model:s.model,mode:s.mode,configOptionValues:s.configOptionValues,canExecuteTools:s.canExecuteTools,timeoutMs:s.timeoutMs,contextWindow:de(g.contextWindow),signal:o.signal,onStatus:l=>{f.report({phase:l.phase,label:l.label,detail:l.detail,updateType:l.updateType,raw:l})},onUpdate:l=>{A+=1;for(const L of K(l.raw))I.add(L);const y={turnId:e.user_turn_id??null,eventType:l.type,label:l.label,text:l.text,status:l.status,toolCallId:l.toolCallId,raw:ye(l.raw,A)};Q(y)&&d.push(y)},onPermissionRequest:l=>{const y=X(s,l);return y?Promise.resolve(y):ve(a,t.machineId,l,o.signal)},onUserInputRequest:l=>ke(a,t.machineId,l,o.signal)});await d.flush(),await f.flush();const J=N({cwd:p.cwd,evidencePaths:I}),v=fe(h.promptResponse);if(!(he(v)||!!h.content)){await P(a,t.machineId,`${h.agentType} stopped: ${v??"unknown"}`,{acpSessionId:h.acpSessionId,stopReason:v,exitCode:h.exitCode,stderr:xe(h.stderr,4e3),worktree:R(p)});return}await b("POST",`/api/client/jobs/${encodeURIComponent(a)}/complete`,{machineId:t.machineId,acpSessionId:h.acpSessionId,assistantText:h.content,result:{ok:!0,acpSessionId:h.acpSessionId,stopReason:v,durationMs:h.durationMs,acpRun:s.acpRun??null,effectiveConfig:h.effectiveConfig??null,performance:h.performance??null,usage:h.contextUsage??null,updateCount:h.updates.length,statusTimeline:h.statusTimeline,worktree:R(p),attachments:z(_),files:J}}),n.info(`completed job=${a}`)}catch(p){await d.flush(),await f.flush();const g=o.signal.aborted?"cancelled":p instanceof Error?p.message:String(p),_=C?N({cwd:C.cwd,evidencePaths:I}):[];await P(a,t.machineId,me(g),{rawError:g,files:_})}finally{await d.flush(),await f.flush(),clearInterval(m)}}function me(e){return/ACP request timed out/i.test(e)?"ACP 长时间没有完成,请稍后重试,或点击停止后重新发送。":/MimoCode request timed out/i.test(e)?"MimoCode 长时间没有完成,请稍后重试,或点击停止后重新发送。":e.replace(/\bsession\/prompt\b/g,"ACP 请求")}function pe(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function de(e){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:void 0}function k(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function fe(e){if(!e||typeof e!="object"||Array.isArray(e))return;const t=e;if(typeof t.stopReason=="string")return t.stopReason;if(typeof t.reason=="string")return t.reason;const n=t.part;if(n&&typeof n=="object"&&!Array.isArray(n)&&typeof n.reason=="string")return n.reason}function he(e){return e?["end_turn","stop","completed","complete"].includes(e):!1}function we(e,t){let n=[],o=null,a=Promise.resolve();const i=async s=>{s.length!==0&&await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/events/batch`,{machineId:t,events:s})},c=()=>{o&&(clearTimeout(o),o=null);const s=n;return n=[],a=a.then(()=>i(s)).catch(()=>{}),a},u=()=>{o||(o=setTimeout(()=>{c()},le()),o.unref())};return{push(s){if(Z(n,s),n.length>=ne){c();return}u()},flush:c}}function be(e,t){let n=null,o=0,a="",i=null,c=Promise.resolve();const u=r=>JSON.stringify({phase:r.phase??"",label:r.label??"",detail:r.detail??"",updateType:r.updateType??""}),s=async r=>{await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/presence`,{machineId:t,phase:r.phase,label:r.label,detail:r.detail,updateType:r.updateType,raw:r.raw}),o=Date.now(),a=u(r)},w=()=>{if(i&&(clearTimeout(i),i=null),!n)return c;const r=n;return n=null,c=c.then(()=>s(r)).catch(()=>{}),c},T=r=>{i||(i=setTimeout(()=>{w()},r),i.unref())};return{report(r){const m=Date.now(),d=u(r)!==a,f=m-o>=oe;if(!d&&!f)return;n=r;const I=m-o;if(I>=O||o===0){w();return}T(O-I)},sendNow(r){return n=r,w()},flush:w}}function ye(e,t){return e&&typeof e=="object"&&!Array.isArray(e)?{...e,acaSequence:t}:{value:e,acaSequence:t}}function Ie(e,t=[]){const n=e?.message?.trim()??"";if(t.length===0)return n;const a=["用户随消息上传了以下附件,aca 已将附件写入本机工作区。需要读取附件时请直接使用下面的 localPath;图片附件也已作为 ACP image block 随本轮请求传入。",...t.map((i,c)=>`${c+1}. ${i.name} (${i.kind}, ${i.mimeType}, ${Ce(i.size)})
2
- localPath: ${i.path}
3
- workspacePath: ${i.relativePath}`)].join(`
1
+ import W from"node:crypto";import x from"node:fs";import S from"node:path";import{compactAgentContext as V,sendAgentPrompt as q}from"../acp/agent.js";import{acaServerDownload as D,acaServerRequest as b}from"./aca-server-client.js";import{loadAcaConfig as H}from"./aca-config.js";import{prepareLocalWorktree as G}from"./worktree.js";import{getAcaHome as $}from"./paths.js";import{collectAffectedFiles as N,extractAffectedFilePathsFromAcpRaw as K}from"./affected-files.js";import{resolveJobPermissionPolicy as X}from"./job-permission-policy.js";import{appendCoalescedAcpEvent as Z}from"./acp-event-coalescer.js";import{shouldUploadAcpEvent as Q}from"./acp-event-upload-filter.js";const Y=1500,ee=5e3,M=1e3,te=320,ne=64,O=900,oe=1e4,ie=0,ae=12e3;function re(e){return e?e==="~"?S.dirname($()):e.startsWith("~/")?S.join(S.dirname($()),e.slice(2)):e:""}function se(e){const t=e.project_metadata;return t&&typeof t=="object"&&!Array.isArray(t)&&t.kind==="chat"?!0:typeof e.project_root_path=="string"&&(e.project_root_path.startsWith("~/.aca/chats/")||/(^|\/)\.aca\/chats\//.test(e.project_root_path))}function qe(e,t={}){let n=!1,o=null,i=null;const a=new Set,c=new Set,u=new Map,s=async()=>{if(n)return;const r=ce();if(U(a.size,r))try{const m=t.loadConfig?.()??H();if(!m.token)return;for(;!n&&U(a.size,r);){const A=t.claimNextJob?await t.claimNextJob(m):await b("POST","/api/client/jobs/claim",{machineId:m.machineId,workspaceId:m.defaultWorkspaceId});if(!A.item)break;const d=A.item;if(n){await(t.cancelClaimedJob?t.cancelClaimedJob(d,m):P(d.job_id,m.machineId,"cancelled")).catch(()=>{});break}const f=d.session_id;c.has(f)&&e.warn(`claimed job=${d.job_id} for already active session=${f}; running anyway to avoid leaving it stuck`),a.add(d.job_id),c.add(f);const I=new AbortController,C=(t.runJob??ue)(d,m,e,I).catch(p=>{e.warn(`job ${d.job_id} failed outside handler: ${p instanceof Error?p.message:String(p)}`)}).finally(()=>{a.delete(d.job_id),c.delete(f),u.delete(d.job_id)});u.set(d.job_id,{controller:I,promise:C})}}catch(m){n||e.warn(`job worker failed: ${m instanceof Error?m.message:String(m)}`)}},w=()=>{if(n||o)return;const r=s();o=r,r.finally(()=>{o===r&&(o=null)})};w();const T=setInterval(()=>{w()},t.claimIntervalMs??Y);return{timer:T,stop:()=>i||(i=(async()=>{if(n)return;n=!0,clearInterval(T);for(const m of u.values())m.controller.abort();await o?.catch(()=>{});for(const m of u.values())m.controller.abort();const r=[...u.values()].map(m=>m.promise);r.length!==0&&await Promise.race([Promise.allSettled(r).then(()=>{}),E(ae)])})(),i)}}function ce(){const e=process.env.ACA_MAX_CONCURRENT_JOBS||process.env.ACA_MAX_CONCURRENT_PROJECT_JOBS||"",t=Number.parseInt(e,10);return!e.trim()||!Number.isFinite(t)||t<0?ie:t===0?0:Math.max(1,Math.min(t,8))}function U(e,t){return t===0||e<t}function le(){const e=Number.parseInt(process.env.ACA_ACP_EVENT_BATCH_INTERVAL_MS||"",10);return Number.isFinite(e)?Math.max(40,Math.min(e,2e3)):te}async function ue(e,t,n,o){const i=e.job_id,a=e.session_id,c=e.workspace_id,u=e.project_id??null,s=e.input??{},w=String(s.control?.type||"").toLowerCase();if(!w&&!s.message?.trim()&&(s.attachments??[]).length===0){await P(i,t.machineId,"job input missing message");return}const T=t.projects.find(p=>p.projectId===u),r=re(T?.rootPath||e.project_root_path||"");if(!r){await P(i,t.machineId,"job project root is unknown");return}se(e)&&x.mkdirSync(r,{recursive:!0}),n.info(`claimed job=${i} session=${a} project=${T?.name??u??"unknown"}`);const m=setInterval(()=>{b("POST",`/api/client/jobs/${encodeURIComponent(i)}/heartbeat`,{machineId:t.machineId}).catch(()=>{}),xe(i,o).catch(()=>{})},ee);let A=0;const d=be(i,t.machineId),f=ye(i,t.machineId),I=new Set;let C=null;try{await f.sendNow({phase:"initializing",label:"准备工作区",detail:e.worktree_id?"worktree":"project root"}).catch(()=>{});const p=G({projectId:u,sessionId:a,projectRoot:r,worktree:e});C=p,await ve(i,t.machineId,p);const g=de(s.acpRun);if(w==="compact"){if(!e.acp_session_id)throw new Error("Current session does not have an ACP context to compact");const l=await V({agentType:R(g.agentType,"codex"),cliType:R(g.cliType,"builtin"),acpSessionId:e.acp_session_id,cwd:p.cwd,model:s.model,mode:s.mode,configOptionValues:s.configOptionValues,timeoutMs:s.timeoutMs,allowRollover:s.control?.allowRollover===!0,signal:o.signal,onStatus:y=>{f.report({phase:y.phase,label:y.label,detail:y.detail,updateType:y.updateType,raw:y})}});await f.flush(),await b("POST",`/api/client/jobs/${encodeURIComponent(i)}/complete`,{machineId:t.machineId,acpSessionId:l.acpSessionId,suppressTurn:!0,result:{ok:!0,control:{type:"compact",allowRollover:s.control?.allowRollover===!0},acpSessionId:l.acpSessionId,durationMs:l.durationMs,usage:l.contextUsage,maintenance:l.maintenance,worktree:k(p)}}),n.info(`completed context compact job=${i}`);return}const _=await Te({cwd:p.cwd,sessionId:a,jobId:i,attachments:s.attachments??[]});_.length>0&&(n.info(`materialized ${_.length} attachment(s) for job=${i}`),await f.sendNow({phase:"initializing",label:"附件已写入本机",detail:_.map(l=>l.relativePath).join(", "),raw:{attachments:z(_)}}).catch(()=>{}));const j=_e(s,_),F=ge(j,_),h=await q({agentType:R(g.agentType,"codex"),cliType:R(g.cliType,"builtin"),acpSessionId:e.acp_session_id??null,requireSessionResume:me(e.session_raw),prompt:j,promptBlocks:F,cwd:p.cwd,model:s.model,mode:s.mode,configOptionValues:s.configOptionValues,canExecuteTools:s.canExecuteTools,timeoutMs:s.timeoutMs,contextWindow:fe(g.contextWindow),signal:o.signal,onStatus:l=>{f.report({phase:l.phase,label:l.label,detail:l.detail,updateType:l.updateType,raw:l})},onUpdate:l=>{A+=1;for(const L of K(l.raw))I.add(L);const y={turnId:e.user_turn_id??null,eventType:l.type,label:l.label,text:l.text,status:l.status,toolCallId:l.toolCallId,raw:Ie(l.raw,A)};Q(y)&&d.push(y)},onPermissionRequest:l=>{const y=X(s,l);return y?Promise.resolve(y):Re(i,t.machineId,l,o.signal)},onUserInputRequest:l=>ke(i,t.machineId,l,o.signal)});await d.flush(),await f.flush();const J=N({cwd:p.cwd,evidencePaths:I}),v=he(h.promptResponse);if(!(we(v)||!!h.content)){await P(i,t.machineId,`${h.agentType} stopped: ${v??"unknown"}`,{acpSessionId:h.acpSessionId,stopReason:v,exitCode:h.exitCode,stderr:Ee(h.stderr,4e3),worktree:k(p)});return}await b("POST",`/api/client/jobs/${encodeURIComponent(i)}/complete`,{machineId:t.machineId,acpSessionId:h.acpSessionId,assistantText:h.content,result:{ok:!0,acpSessionId:h.acpSessionId,stopReason:v,durationMs:h.durationMs,acpRun:s.acpRun??null,effectiveConfig:h.effectiveConfig??null,performance:h.performance??null,usage:h.contextUsage??null,updateCount:h.updates.length,statusTimeline:h.statusTimeline,worktree:k(p),attachments:z(_),files:J}}),n.info(`completed job=${i}`)}catch(p){await d.flush(),await f.flush();const g=o.signal.aborted?"cancelled":p instanceof Error?p.message:String(p),_=C?N({cwd:C.cwd,evidencePaths:I}):[];await P(i,t.machineId,pe(g),{rawError:g,files:_})}finally{await d.flush(),await f.flush(),clearInterval(m)}}function me(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e.importedProviderSession;return!!(t&&typeof t=="object"&&!Array.isArray(t)&&t.strictResume===!0)}function pe(e){return/ACP request timed out/i.test(e)?"ACP 长时间没有完成,请稍后重试,或点击停止后重新发送。":/MimoCode request timed out/i.test(e)?"MimoCode 长时间没有完成,请稍后重试,或点击停止后重新发送。":e.replace(/\bsession\/prompt\b/g,"ACP 请求")}function de(e){return!e||typeof e!="object"||Array.isArray(e)?{}:e}function fe(e){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:void 0}function R(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function he(e){if(!e||typeof e!="object"||Array.isArray(e))return;const t=e;if(typeof t.stopReason=="string")return t.stopReason;if(typeof t.reason=="string")return t.reason;const n=t.part;if(n&&typeof n=="object"&&!Array.isArray(n)&&typeof n.reason=="string")return n.reason}function we(e){return e?["end_turn","stop","completed","complete"].includes(e):!1}function be(e,t){let n=[],o=null,i=Promise.resolve();const a=async s=>{s.length!==0&&await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/events/batch`,{machineId:t,events:s})},c=()=>{o&&(clearTimeout(o),o=null);const s=n;return n=[],i=i.then(()=>a(s)).catch(()=>{}),i},u=()=>{o||(o=setTimeout(()=>{c()},le()),o.unref())};return{push(s){if(Z(n,s),n.length>=ne){c();return}u()},flush:c}}function ye(e,t){let n=null,o=0,i="",a=null,c=Promise.resolve();const u=r=>JSON.stringify({phase:r.phase??"",label:r.label??"",detail:r.detail??"",updateType:r.updateType??""}),s=async r=>{await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/presence`,{machineId:t,phase:r.phase,label:r.label,detail:r.detail,updateType:r.updateType,raw:r.raw}),o=Date.now(),i=u(r)},w=()=>{if(a&&(clearTimeout(a),a=null),!n)return c;const r=n;return n=null,c=c.then(()=>s(r)).catch(()=>{}),c},T=r=>{a||(a=setTimeout(()=>{w()},r),a.unref())};return{report(r){const m=Date.now(),d=u(r)!==i,f=m-o>=oe;if(!d&&!f)return;n=r;const I=m-o;if(I>=O||o===0){w();return}T(O-I)},sendNow(r){return n=r,w()},flush:w}}function Ie(e,t){return e&&typeof e=="object"&&!Array.isArray(e)?{...e,acaSequence:t}:{value:e,acaSequence:t}}function _e(e,t=[]){const n=e?.message?.trim()??"";if(t.length===0)return n;const i=["用户随消息上传了以下附件,aca 已将附件写入本机工作区。需要读取附件时请直接使用下面的 localPath;图片附件也已作为 ACP image block 随本轮请求传入。",...t.map((a,c)=>`${c+1}. ${a.name} (${a.kind}, ${a.mimeType}, ${Pe(a.size)})
2
+ localPath: ${a.path}
3
+ workspacePath: ${a.relativePath}`)].join(`
4
4
  `);return n?`${n}
5
5
 
6
- ${a}`:a}function _e(e,t){const n=[{type:"text",text:e}];for(const o of t)o.kind!=="image"||!o.mimeType.startsWith("image/")||n.push({type:"image",data:o.base64,mimeType:o.mimeType,uri:o.path});return n}async function ge(e){if(e.attachments.length===0)return[];const t=S.join(e.cwd,".aca","attachments",B(e.sessionId),B(e.jobId));x.mkdirSync(t,{recursive:!0});const n=[];for(const[o,a]of e.attachments.entries()){const i=a.attachmentId?{mimeType:a.mimeType||"application/octet-stream",bytes:await D(`/api/client/attachments/${encodeURIComponent(a.attachmentId)}`)}:Te(a.dataUrl??""),c=a.mimeType||i.mimeType||"application/octet-stream",u=a.kind==="image"||c.startsWith("image/")?"image":"file",s=Se(a.name||`attachment-${o+1}`,c),w=S.join(t,`${String(o+1).padStart(2,"0")}-${s}`);x.writeFileSync(w,i.bytes),n.push({name:a.name||s,mimeType:c,size:i.bytes.byteLength,kind:u,path:w,relativePath:S.relative(e.cwd,w),base64:i.bytes.toString("base64"),sha256:W.createHash("sha256").update(i.bytes).digest("hex")})}return n}function Te(e){const t=e.indexOf(",");if(!e.startsWith("data:")||t<0)throw new Error("attachment dataUrl is not a data URL");const n=e.slice(5,t),o=e.slice(t+1),a=n.split(";").filter(Boolean),i=a[0]?.includes("/")?a[0]:"application/octet-stream";if(!a.includes("base64"))throw new Error("attachment dataUrl is not base64 encoded");return{mimeType:i,bytes:Buffer.from(o,"base64")}}function Se(e,t){const n=S.basename(e).replace(/[<>:"/\\|?*\x00-\x1F]/g,"_").trim(),o=`attachment${Ae(t)}`;return(!n||n==="."||n===".."?o:n).slice(0,180)}function Ae(e){switch(e.toLowerCase()){case"image/png":return".png";case"image/jpeg":return".jpg";case"image/webp":return".webp";case"image/gif":return".gif";case"text/plain":return".txt";case"application/json":return".json";case"text/markdown":case"text/x-markdown":return".md";case"application/pdf":return".pdf";case"application/msword":return".doc";case"application/vnd.openxmlformats-officedocument.wordprocessingml.document":return".docx";case"application/vnd.ms-excel":return".xls";case"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":return".xlsx";case"application/vnd.ms-powerpoint":return".ppt";case"application/vnd.openxmlformats-officedocument.presentationml.presentation":return".pptx";case"application/zip":return".zip";case"application/x-7z-compressed":return".7z";case"application/x-rar-compressed":case"application/vnd.rar":return".rar";case"application/gzip":return".gz";case"application/x-tar":return".tar";default:return""}}function B(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"item"}function z(e){return e.map(t=>({name:t.name,kind:t.kind,mimeType:t.mimeType,size:t.size,path:t.path,relativePath:t.relativePath,sha256:t.sha256}))}function Ce(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB"];let n=e,o=0;for(;n>=1024&&o<t.length-1;)n/=1024,o+=1;return`${n>=10||o===0?n.toFixed(0):n.toFixed(1)} ${t[o]}`}async function Pe(e,t,n){!n.usedWorktree||!n.worktreeId||await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/worktree`,{machineId:t,baseCommit:n.baseCommit??null,worktreePath:n.cwd,status:n.status??"active",raw:n.raw??R(n)})}function R(e){return{usedWorktree:e.usedWorktree,worktreeId:e.worktreeId??null,cwd:e.cwd,status:e.status??null,baseCommit:e.baseCommit??null,branchName:e.branchName??null,baseBranch:e.baseBranch??null}}async function ve(e,t,n,o){const i=(await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:n})).item.permission_id;for(;!o.aborted;){await E(M);const c=await b("GET",`/api/client/permissions/${encodeURIComponent(i)}`);if(c.item.status==="resolved"&&c.item.response){const u=c.item.response.outcome;return u.outcome==="selected"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function ke(e,t,n,o){const i=(await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:{kind:"elicitation",...n}})).item.permission_id;for(;!o.aborted;){await E(M);const c=await b("GET",`/api/client/permissions/${encodeURIComponent(i)}`);if(c.item.status==="resolved"&&c.item.response){const u=c.item.response.outcome;return u.outcome==="submitted"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function Re(e,t){if(t.signal.aborted)return;const n=await b("GET",`/api/client/jobs/${encodeURIComponent(e)}`);Number(n.item.cancel_requested??0)===1&&t.abort()}async function P(e,t,n,o){await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/fail`,{machineId:t,error:n,result:o})}function E(e){return new Promise(t=>setTimeout(t,e))}function xe(e,t){return e.length<=t?e:`${e.slice(0,t)}...`}export{Ve as startJobWorkerLoop};
6
+ ${i}`:i}function ge(e,t){const n=[{type:"text",text:e}];for(const o of t)o.kind!=="image"||!o.mimeType.startsWith("image/")||n.push({type:"image",data:o.base64,mimeType:o.mimeType,uri:o.path});return n}async function Te(e){if(e.attachments.length===0)return[];const t=S.join(e.cwd,".aca","attachments",B(e.sessionId),B(e.jobId));x.mkdirSync(t,{recursive:!0});const n=[];for(const[o,i]of e.attachments.entries()){const a=i.attachmentId?{mimeType:i.mimeType||"application/octet-stream",bytes:await D(`/api/client/attachments/${encodeURIComponent(i.attachmentId)}`)}:Se(i.dataUrl??""),c=i.mimeType||a.mimeType||"application/octet-stream",u=i.kind==="image"||c.startsWith("image/")?"image":"file",s=Ae(i.name||`attachment-${o+1}`,c),w=S.join(t,`${String(o+1).padStart(2,"0")}-${s}`);x.writeFileSync(w,a.bytes),n.push({name:i.name||s,mimeType:c,size:a.bytes.byteLength,kind:u,path:w,relativePath:S.relative(e.cwd,w),base64:a.bytes.toString("base64"),sha256:W.createHash("sha256").update(a.bytes).digest("hex")})}return n}function Se(e){const t=e.indexOf(",");if(!e.startsWith("data:")||t<0)throw new Error("attachment dataUrl is not a data URL");const n=e.slice(5,t),o=e.slice(t+1),i=n.split(";").filter(Boolean),a=i[0]?.includes("/")?i[0]:"application/octet-stream";if(!i.includes("base64"))throw new Error("attachment dataUrl is not base64 encoded");return{mimeType:a,bytes:Buffer.from(o,"base64")}}function Ae(e,t){const n=S.basename(e).replace(/[<>:"/\\|?*\x00-\x1F]/g,"_").trim(),o=`attachment${Ce(t)}`;return(!n||n==="."||n===".."?o:n).slice(0,180)}function Ce(e){switch(e.toLowerCase()){case"image/png":return".png";case"image/jpeg":return".jpg";case"image/webp":return".webp";case"image/gif":return".gif";case"text/plain":return".txt";case"application/json":return".json";case"text/markdown":case"text/x-markdown":return".md";case"application/pdf":return".pdf";case"application/msword":return".doc";case"application/vnd.openxmlformats-officedocument.wordprocessingml.document":return".docx";case"application/vnd.ms-excel":return".xls";case"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":return".xlsx";case"application/vnd.ms-powerpoint":return".ppt";case"application/vnd.openxmlformats-officedocument.presentationml.presentation":return".pptx";case"application/zip":return".zip";case"application/x-7z-compressed":return".7z";case"application/x-rar-compressed":case"application/vnd.rar":return".rar";case"application/gzip":return".gz";case"application/x-tar":return".tar";default:return""}}function B(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"item"}function z(e){return e.map(t=>({name:t.name,kind:t.kind,mimeType:t.mimeType,size:t.size,path:t.path,relativePath:t.relativePath,sha256:t.sha256}))}function Pe(e){if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KB","MB","GB"];let n=e,o=0;for(;n>=1024&&o<t.length-1;)n/=1024,o+=1;return`${n>=10||o===0?n.toFixed(0):n.toFixed(1)} ${t[o]}`}async function ve(e,t,n){!n.usedWorktree||!n.worktreeId||await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/worktree`,{machineId:t,baseCommit:n.baseCommit??null,worktreePath:n.cwd,status:n.status??"active",raw:n.raw??k(n)})}function k(e){return{usedWorktree:e.usedWorktree,worktreeId:e.worktreeId??null,cwd:e.cwd,status:e.status??null,baseCommit:e.baseCommit??null,branchName:e.branchName??null,baseBranch:e.baseBranch??null}}async function Re(e,t,n,o){const a=(await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:n})).item.permission_id;for(;!o.aborted;){await E(M);const c=await b("GET",`/api/client/permissions/${encodeURIComponent(a)}`);if(c.item.status==="resolved"&&c.item.response){const u=c.item.response.outcome;return u.outcome==="selected"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function ke(e,t,n,o){const a=(await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/permissions`,{machineId:t,request:{kind:"elicitation",...n}})).item.permission_id;for(;!o.aborted;){await E(M);const c=await b("GET",`/api/client/permissions/${encodeURIComponent(a)}`);if(c.item.status==="resolved"&&c.item.response){const u=c.item.response.outcome;return u.outcome==="submitted"?{outcome:u}:{outcome:{outcome:"cancelled"}}}}return{outcome:{outcome:"cancelled"}}}async function xe(e,t){if(t.signal.aborted)return;const n=await b("GET",`/api/client/jobs/${encodeURIComponent(e)}`);Number(n.item.cancel_requested??0)===1&&t.abort()}async function P(e,t,n,o){await b("POST",`/api/client/jobs/${encodeURIComponent(e)}/fail`,{machineId:t,error:n,result:o})}function E(e){return new Promise(t=>setTimeout(t,e))}function Ee(e,t){return e.length<=t?e:`${e.slice(0,t)}...`}export{qe as startJobWorkerLoop};
@@ -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 M}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 G,upsertLocalProject as L}from"./aca-config.js";import{startLongPollWorker as O}from"./long-poll-worker.js";const H=25e3,g=300,W=3e4;let y=null;function vt(t){return O({run:async()=>{const e=G();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 B(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 B(t){if(t.operation==="filesystem_roots")return et();if(t.operation==="list_directory")return rt({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return ct(t.payload);if(t.operation==="list_project_directory")return U(t.payload);if(t.operation==="get_project_git_status")return z(t.payload);if(t.operation==="get_project_git_diff")return K(t.payload);if(t.operation==="get_project_git_log")return J(t.payload);if(t.operation==="get_project_git_commit")return V(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function U(t){const e=w(String(t.rootPath||"")),r=_(String(t.relativePath||"")),o=ut(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:dt(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,f=2*1024*1024;function z(t){const e=w(String(t.rootPath||""));if(!b(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=d(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],S).split("\0").filter(Boolean).slice(0,A),n=o.map(a=>Y(a)).filter(a=>!!a),s=x(d(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","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=tt(e);return{isRepository:!0,branch:q(e),files:n,ahead:i.ahead,behind:i.behind,truncated:o.length>=A}}function K(t){const e=w(String(t.rootPath||"")),r=_(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!b(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=R(e,r),n=Q(e,r),s=n?d(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],f):N(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],f),i=n?x(d(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):$(e,r);return{isRepository:!0,path:r,diff:T(s),additions:i?.additions??0,deletions:i?.deletions??0,truncated:s.length>f}}function J(t){const e=w(String(t.rootPath||""));if(!b(e))return{isRepository:!1,items:[]};if(!Z(e))return{isRepository:!0,items:[]};const r=Math.min(200,Math.max(20,Number(t.limit||100)));return{isRepository:!0,items:d(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=>X(i)).filter(i=>!!i),limit:r}}function V(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(!b(e))return{isRepository:!1,commit:r,diff:"",additions:0,deletions:0};d(e,["cat-file","-e",`${r}^{commit}`],8*1024);const o=d(e,["show","--no-ext-diff","--no-color","--format=","--stat","--patch","--unified=40",r],f),n=[...x(d(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],S)).values()];return{isRepository:!0,commit:r,diff:T(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>f}}function X(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 Y(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=_(t.slice(3));return o?{path:o,status:e==="?"&&r==="?"?"untracked":e==="U"||r==="U"?"conflicted":e==="D"||r==="D"?"deleted":e==="A"||r==="A"?"added":e==="R"||r==="R"?"renamed":"modified",indexStatus:e,worktreeStatus:r,staged:e!==" "&&e!=="?",additions:null,deletions:null}:null}function x(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=D(r);if(!o||!o.path)continue;const n=_(o.path);n&&e.set(n,{additions:o.additions,deletions:o.deletions})}return e}function $(t,e){const r=R(t,e),n=N(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=D(n);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function D(t){const e=t.indexOf(" "),r=e<0?-1:t.indexOf(" ",e+1);if(e<0||r<0)return null;const o=t.slice(0,e),n=t.slice(e+1,r);return{additions:/^\d+$/.test(o)?Number(o):null,deletions:/^\d+$/.test(n)?Number(n):null,path:t.slice(r+1)}}function b(t){try{return d(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 Q(t,e){try{return d(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function Z(t){try{return d(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function q(t){try{return d(t,["symbolic-ref","--quiet","--short","HEAD"],8*1024).trim()||null}catch{try{return`HEAD (${d(t,["rev-parse","--short","HEAD"],8*1024).trim()})`}catch{return null}}}function tt(t){try{const e=d(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 R(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 d(t,e,r){return E("git",["-C",t,...e],{encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function N(t,e,r){try{return d(t,e,r)}catch(o){const n=String(o.stdout||"");if(n)return n;if(Number(o.status)===1)return"";throw o}}function T(t){return t.length<=f?t:`${t.slice(0,f)}
2
+
3
+ [Diff 内容过大,已截断]`}function et(){const t=process.platform,e=P(t);return{platform:t,roots:e}}function rt(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?st(t.directoryPath,!!t.includeHidden):it(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 ot(){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"?nt():ot();return y={platform:t,roots:e,expiresAtMs:Date.now()+W},e}function nt(){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=F(k(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})`:ht(a,i),path:s,kind:pt(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 it(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 st(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=F(k(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:at(t,o),readable:I(t,u.constants.R_OK),writable:I(t,u.constants.W_OK),items:e,truncated:r}}function at(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 ct(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:M(),workspaceId:e,name:r,rootPath:n,source:"aica",projectType:o})).item;return L(lt(a)),{project:a,duplicate:!!i}}function lt(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 mt(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 _(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 ut(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 dt(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 mt(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 k(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 F(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 pt(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function ht(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{m as comparableMachinePath,V as getProjectGitCommit,K as getProjectGitDiff,J as getProjectGitLog,z as getProjectGitStatus,rt as listMachineDirectory,et as listMachineFilesystemRoots,U as listProjectDirectory,vt 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.5").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 m from"node:path";import{createStartCommand as n}from"./commands/start.js";import{createWorkerAuthCommand as t}from"./commands/worker-auth.js";import{createWorkerCodexCommand as s}from"./commands/worker-codex.js";import{createWorkerProjectCommand as c}from"./commands/worker-project.js";import{DEFAULT_ACA_SERVER_URL as i}from"./core/aca-config.js";process.env.ACA_DEFAULT_SERVER_URL||=i;async function d(r=process.argv){const o=new a;o.name("aica").description("AICA remote Agent worker").version("0.1.7").enablePositionalOptions(),o.addCommand(n()),o.addCommand(t()),o.addCommand(c()),o.addCommand(s()),await o.parseAsync(r)}const p=process.argv[1]||"",e=m.basename(p).replace(/\.(?:js|ts|cjs|mjs)$/i,"");(e==="worker-cli"||e==="aica"||e==="aca")&&d().catch(r=>{const o=r instanceof Error?r.message:String(r);console.error(o),process.exitCode=1});export{d as runWorkerCli};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",